diff --git a/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap b/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap index c2685e78ac..8c3f703c5f 100644 --- a/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap +++ b/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap @@ -149,6 +149,37 @@ Object { } `; +exports[`/admin/price-lists POST /admin/price-lists/:id updates price list prices (inser a new MA for a specific region) 1`] = ` +Array [ + Object { + "amount": 101, + "created_at": Any, + "currency_code": "eur", + "deleted_at": null, + "id": Any, + "max_quantity": null, + "min_quantity": null, + "price_list_id": "pl_with_some_ma", + "region_id": "region-pl", + "updated_at": Any, + "variant_id": "test-variant", + }, + Object { + "amount": 1001, + "created_at": Any, + "currency_code": "usd", + "deleted_at": null, + "id": "ma_test_4", + "max_quantity": null, + "min_quantity": null, + "price_list_id": "pl_with_some_ma", + "region_id": null, + "updated_at": Any, + "variant_id": "test-variant", + }, +] +`; + exports[`/admin/price-lists POST /admin/price-lists/:id updates the amount and currency of a price in the price list 1`] = ` Object { "amount": 250, @@ -291,3 +322,47 @@ Array [ }, ] `; + +exports[`/admin/price-lists POST /admin/price-lists/:id/prices/batch Adds a batch of new prices where a MA record have a \`region_id\` instead of \`currency_code\` 1`] = ` +Array [ + Object { + "amount": 70, + "created_at": Any, + "currency_code": "usd", + "deleted_at": null, + "id": "ma_test_4", + "max_quantity": null, + "min_quantity": null, + "price_list_id": "pl_with_some_ma", + "region_id": null, + "updated_at": Any, + "variant_id": "test-variant", + }, + Object { + "amount": 100, + "created_at": Any, + "currency_code": "eur", + "deleted_at": null, + "id": Any, + "max_quantity": null, + "min_quantity": null, + "price_list_id": "pl_with_some_ma", + "region_id": "region-pl", + "updated_at": Any, + "variant_id": "test-variant", + }, + Object { + "amount": 200, + "created_at": Any, + "currency_code": "usd", + "deleted_at": null, + "id": Any, + "max_quantity": null, + "min_quantity": null, + "price_list_id": "pl_with_some_ma", + "region_id": null, + "updated_at": Any, + "variant_id": "test-variant", + }, +] +`; diff --git a/integration-tests/api/__tests__/admin/price-list.js b/integration-tests/api/__tests__/admin/price-list.js index b1c39b9819..7291a4f956 100644 --- a/integration-tests/api/__tests__/admin/price-list.js +++ b/integration-tests/api/__tests__/admin/price-list.js @@ -509,6 +509,68 @@ describe("/admin/price-lists", () => { updated_at: expect.any(String), }) }) + + it("updates price list prices (inser a new MA for a specific region)", async () => { + const api = useApi() + + const payload = { + prices: [ + // update MA + { + id: "ma_test_4", + amount: 1001, + currency_code: "usd", + variant_id: "test-variant", + }, + // create MA + { + amount: 101, + variant_id: "test-variant", + region_id: "region-pl", + }, + ], + } + + const response = await api + .post("/admin/price-lists/pl_with_some_ma", payload, { + headers: { + Authorization: "Bearer test_token", + }, + }) + .catch((err) => { + console.warn(err.response.data) + }) + + expect(response.status).toEqual(200) + + expect(response.data.price_list.prices.length).toEqual(2) + expect(response.data.price_list.prices).toMatchSnapshot([ + { + id: expect.any(String), + currency_code: "eur", + amount: 101, + min_quantity: null, + max_quantity: null, + price_list_id: "pl_with_some_ma", + variant_id: "test-variant", + region_id: "region-pl", + created_at: expect.any(String), + updated_at: expect.any(String), + deleted_at: null, + }, + { + id: "ma_test_4", + currency_code: "usd", + amount: 1001, + price_list_id: "pl_with_some_ma", + variant_id: "test-variant", + region_id: null, + created_at: expect.any(String), + updated_at: expect.any(String), + deleted_at: null, + }, + ]) + }) }) describe("POST /admin/price-lists/:id/prices/batch", () => { @@ -573,7 +635,9 @@ describe("/admin/price-lists", () => { expect(response.status).toEqual(200) expect(response.data.price_list.prices.length).toEqual(6) - expect(response.data.price_list.prices).toMatchSnapshot([ + expect( + response.data.price_list.prices.sort((a, b) => b.amount - a.amount) + ).toMatchSnapshot([ { id: expect.any(String), price_list_id: "pl_no_customer_groups", @@ -725,6 +789,78 @@ describe("/admin/price-lists", () => { }, ]) }) + + it("Adds a batch of new prices where a MA record have a `region_id` instead of `currency_code`", async () => { + const api = useApi() + + const payload = { + prices: [ + { + amount: 100, + variant_id: "test-variant", + region_id: "region-pl", + }, + { + amount: 200, + variant_id: "test-variant", + currency_code: "usd", + }, + ], + } + + const response = await api + .post("/admin/price-lists/pl_with_some_ma/prices/batch", payload, { + headers: { + Authorization: "Bearer test_token", + }, + }) + .catch((err) => { + console.warn(err.response.data) + }) + + expect(response.status).toEqual(200) + + expect(response.data.price_list.prices.length).toEqual(3) // initially this PL has 1 MA record + expect(response.data.price_list.prices).toMatchSnapshot([ + { + id: "ma_test_4", + currency_code: "usd", + amount: 70, + price_list_id: "pl_with_some_ma", + variant_id: "test-variant", + region_id: null, + created_at: expect.any(String), + updated_at: expect.any(String), + deleted_at: null, + }, + { + id: expect.any(String), + currency_code: "eur", + amount: 100, + min_quantity: null, + max_quantity: null, + price_list_id: "pl_with_some_ma", + variant_id: "test-variant", + region_id: "region-pl", + created_at: expect.any(String), + updated_at: expect.any(String), + deleted_at: null, + }, + { + id: expect.any(String), + currency_code: "usd", + amount: 200, + min_quantity: null, + max_quantity: null, + price_list_id: "pl_with_some_ma", + variant_id: "test-variant", + region_id: null, + created_at: expect.any(String), + updated_at: expect.any(String), + deleted_at: null, + }, + ]) + }) }) describe("DELETE /admin/price-lists/:id", () => { diff --git a/integration-tests/api/helpers/price-list-seeder.js b/integration-tests/api/helpers/price-list-seeder.js index 984db87a88..f481176cc3 100644 --- a/integration-tests/api/helpers/price-list-seeder.js +++ b/integration-tests/api/helpers/price-list-seeder.js @@ -1,4 +1,4 @@ -const { PriceList, MoneyAmount } = require("@medusajs/medusa") +const { Region, PriceList, MoneyAmount } = require("@medusajs/medusa") module.exports = async (connection, data = {}) => { const manager = connection.manager @@ -15,6 +15,13 @@ module.exports = async (connection, data = {}) => { await manager.save(priceListNoCustomerGroups) + await manager.insert(Region, { + id: "region-pl", + name: "Test Region", + currency_code: "eur", + tax_rate: 0, + }) + const moneyAmount1 = await manager.create(MoneyAmount, { id: "ma_test_1", amount: 100, @@ -50,4 +57,27 @@ module.exports = async (connection, data = {}) => { }) await manager.save(moneyAmount3) + + const moneyAmount4 = await manager.create(MoneyAmount, { + id: "ma_test_4", + amount: 70, + currency_code: "usd", + variant_id: "test-variant", + }) + + await manager.save(moneyAmount4) + + const priceListWithMA = await manager.create(PriceList, { + id: "pl_with_some_ma", + name: "Weeken sale", + description: "Desc. of the list", + type: "sale", + status: "active", + starts_at: "2022-07-01T00:00:00.000Z", + ends_at: "2022-07-31T00:00:00.000Z", + }) + + priceListWithMA.prices = [moneyAmount4] + + await manager.save(priceListWithMA) } diff --git a/packages/medusa/src/services/price-list.ts b/packages/medusa/src/services/price-list.ts index 38bae29080..bb068a3ad4 100644 --- a/packages/medusa/src/services/price-list.ts +++ b/packages/medusa/src/services/price-list.ts @@ -12,14 +12,17 @@ import { CreatePriceListInput, FilterablePriceListProps, PriceListPriceCreateInput, + PriceListPriceUpdateInput, UpdatePriceListInput, } from "../types/price-list" import { formatException } from "../utils/exception-formatter" +import RegionService from "./region" import ProductService from "./product" type PriceListConstructorProps = { manager: EntityManager customerGroupService: CustomerGroupService + regionService: RegionService productService: ProductService priceListRepository: typeof PriceListRepository moneyAmountRepository: typeof MoneyAmountRepository @@ -32,6 +35,7 @@ type PriceListConstructorProps = { class PriceListService extends BaseService { private manager_: EntityManager private customerGroupService_: CustomerGroupService + private regionService_: RegionService private productService_: ProductService private priceListRepo_: typeof PriceListRepository private moneyAmountRepo_: typeof MoneyAmountRepository @@ -39,6 +43,7 @@ class PriceListService extends BaseService { constructor({ manager, customerGroupService, + regionService, productService, priceListRepository, moneyAmountRepository, @@ -47,6 +52,7 @@ class PriceListService extends BaseService { this.manager_ = manager this.customerGroupService_ = customerGroupService this.productService_ = productService + this.regionService_ = regionService this.priceListRepo_ = priceListRepository this.moneyAmountRepo_ = moneyAmountRepository } @@ -60,6 +66,7 @@ class PriceListService extends BaseService { manager: transactionManager, customerGroupService: this.customerGroupService_, productService: this.productService_, + regionService: this.regionService_, priceListRepository: this.priceListRepo_, moneyAmountRepository: this.moneyAmountRepo_, }) @@ -152,7 +159,8 @@ class PriceListService extends BaseService { await priceListRepo.save(priceList) if (prices) { - await moneyAmountRepo.updatePriceListPrices(id, prices) + const prices_ = await this.addCurrencyFromRegion(prices) + await moneyAmountRepo.updatePriceListPrices(id, prices_) } if (customer_groups) { @@ -184,7 +192,8 @@ class PriceListService extends BaseService { const priceList = await this.retrieve(id, { select: ["id"] }) - await moneyAmountRepo.addPriceListPrices(priceList.id, prices, replace) + const prices_ = await this.addCurrencyFromRegion(prices) + await moneyAmountRepo.addPriceListPrices(priceList.id, prices_, replace) const result = await this.retrieve(priceList.id, { relations: ["prices"], @@ -336,6 +345,31 @@ class PriceListService extends BaseService { return [productsWithPrices, count] }) } + + /** + * 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 = [] + + for (const p of prices) { + if (p.region_id) { + const region = await this.regionService_ + .withTransaction(this.manager_) + .retrieve(p.region_id) + + p.currency_code = region.currency_code + } + + prices_.push(p) + } + + return prices_ + } } export default PriceListService