From 8fb5845874d2b1e7684221183b1ce058930d1754 Mon Sep 17 00:00:00 2001 From: Sebastian Rindom Date: Wed, 5 Feb 2020 16:20:04 +0100 Subject: [PATCH] Creates setRegion --- packages/medusa/src/models/__mocks__/cart.js | 105 +++++++++++++++- packages/medusa/src/models/cart.js | 2 +- .../src/services/__mocks__/product-variant.js | 19 +++ .../medusa/src/services/__tests__/cart.js | 116 ++++++++++++++++++ packages/medusa/src/services/cart.js | 108 ++++++++++++++-- 5 files changed, 334 insertions(+), 16 deletions(-) diff --git a/packages/medusa/src/models/__mocks__/cart.js b/packages/medusa/src/models/__mocks__/cart.js index c7b5945b9e..024783f93e 100644 --- a/packages/medusa/src/models/__mocks__/cart.js +++ b/packages/medusa/src/models/__mocks__/cart.js @@ -4,7 +4,7 @@ export const carts = { emptyCart: { _id: IdMap.getId("emptyCart"), title: "test", - region: IdMap.getId("testRegion"), + region_id: IdMap.getId("testRegion"), items: [], shippingAddress: {}, billingAddress: {}, @@ -12,9 +12,9 @@ export const carts = { customer_id: "", }, cartWithLine: { - _id: IdMap.getId("emptyCart"), + _id: IdMap.getId("cartWithLine"), title: "test", - region: IdMap.getId("testRegion"), + region_id: IdMap.getId("testRegion"), items: [ { _id: IdMap.getId("existingLine"), @@ -39,6 +39,99 @@ export const carts = { discounts: [], customer_id: "", }, + completeCart: { + _id: IdMap.getId("complete-cart"), + title: "test", + region_id: IdMap.getId("region-france"), + items: [], + payment_method: { + provider_id: "stripe", + data: { + yes: "sir", + }, + }, + shipping_method: { + provider_id: "gls", + data: { + yes: "sir", + }, + }, + shipping_address: { + first_name: "hi", + last_name: "you", + country_code: "DK", + city: "of lights", + address_1: "You bet street", + postal_code: "4242", + }, + billing_address: { + first_name: "hi", + last_name: "you", + country_code: "DK", + city: "of lights", + address_1: "You bet street", + postal_code: "4242", + }, + discounts: [], + customer_id: "", + }, + frCart: { + _id: IdMap.getId("fr-cart"), + title: "test", + 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, + }, + ], + shippingAddress: {}, + billingAddress: {}, + discounts: [], + customer_id: "", + }, } export const CartModelMock = { @@ -54,6 +147,12 @@ export const CartModelMock = { if (query._id === IdMap.getId("cartWithLine")) { return Promise.resolve(carts.cartWithLine) } + if (query._id === IdMap.getId("fr-cart")) { + return Promise.resolve(carts.frCart) + } + if (query._id === IdMap.getId("complete-cart")) { + return Promise.resolve(carts.completeCart) + } return Promise.resolve(undefined) }), } diff --git a/packages/medusa/src/models/cart.js b/packages/medusa/src/models/cart.js index 719cf18c8d..4deb50913c 100644 --- a/packages/medusa/src/models/cart.js +++ b/packages/medusa/src/models/cart.js @@ -17,7 +17,7 @@ class CartModel extends BaseModel { billing_address: { type: AddressSchema }, shipping_address: { type: AddressSchema }, items: { type: [LineItemSchema], default: [] }, - region: { type: String, required: true }, + region_id: { type: String }, discounts: { type: [String], default: [] }, customer_id: { type: String }, payment_method: { type: PaymentMethodSchema }, diff --git a/packages/medusa/src/services/__mocks__/product-variant.js b/packages/medusa/src/services/__mocks__/product-variant.js index 96e4f6a0a3..182dc61503 100644 --- a/packages/medusa/src/services/__mocks__/product-variant.js +++ b/packages/medusa/src/services/__mocks__/product-variant.js @@ -141,6 +141,25 @@ export const ProductVariantServiceMock = { return Promise.reject(new Error("Not found")) }), + 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) + } + } + + return Promise.reject(new Error("Not found")) + }), delete: jest.fn().mockReturnValue(Promise.resolve()), addOptionValue: jest.fn().mockImplementation((variantId, optionId, value) => { return Promise.resolve({}) diff --git a/packages/medusa/src/services/__tests__/cart.js b/packages/medusa/src/services/__tests__/cart.js index 1143837252..daa05f4f0c 100644 --- a/packages/medusa/src/services/__tests__/cart.js +++ b/packages/medusa/src/services/__tests__/cart.js @@ -452,4 +452,120 @@ describe("CartService", () => { expect(CartModelMock.updateOne).toHaveBeenCalledTimes(0) }) }) + + describe("setRegion", () => { + const cartService = new CartService({ + cartModel: CartModelMock, + regionService: RegionServiceMock, + productVariantService: ProductVariantServiceMock, + }) + + beforeEach(() => { + jest.clearAllMocks() + }) + + it("successfully set new region", async () => { + await cartService.setRegion( + IdMap.getId("fr-cart"), + IdMap.getId("region-us") + ) + + expect(CartModelMock.updateOne).toHaveBeenCalledTimes(1) + expect(CartModelMock.updateOne).toHaveBeenCalledWith( + { + _id: IdMap.getId("fr-cart"), + }, + { + $set: { + region_id: IdMap.getId("region-us"), + items: [ + { + _id: IdMap.getId("line"), + title: "merge line", + description: "This is a new line", + thumbnail: "test-img-yeah.com/thumb", + content: [ + { + unit_price: 10, + variant: { + _id: IdMap.getId("eur-8-us-10"), + }, + product: { + _id: IdMap.getId("product"), + }, + quantity: 1, + }, + { + unit_price: 12, + 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: 12, + variant: { + _id: IdMap.getId("eur-10-us-12"), + }, + product: { + _id: IdMap.getId("product"), + }, + quantity: 1, + }, + quantity: 10, + }, + ], + }, + } + ) + }) + + it("successfully set new region", async () => { + await cartService.setRegion( + IdMap.getId("complete-cart"), + IdMap.getId("region-us") + ) + + expect(CartModelMock.updateOne).toHaveBeenCalledTimes(1) + expect(CartModelMock.updateOne).toHaveBeenCalledWith( + { + _id: IdMap.getId("complete-cart"), + }, + { + $set: { + region_id: IdMap.getId("region-us"), + shipping_method: undefined, + payment_method: undefined, + shipping_address: { + first_name: "hi", + last_name: "you", + country_code: "", + city: "of lights", + address_1: "You bet street", + postal_code: "4242", + }, + billing_address: { + first_name: "hi", + last_name: "you", + country_code: "", + city: "of lights", + address_1: "You bet street", + postal_code: "4242", + }, + }, + } + ) + }) + }) }) diff --git a/packages/medusa/src/services/cart.js b/packages/medusa/src/services/cart.js index 33da5b0558..8d54e126dd 100644 --- a/packages/medusa/src/services/cart.js +++ b/packages/medusa/src/services/cart.js @@ -138,6 +138,38 @@ class CartService extends BaseService { ) } + /** + * Transforms some line item content to have unit_prices corresponding to a + * given region's pricing scheme. + * @param {(LineItemContent | LineItemContentArray)} - the content of the line + * item + * @param {string} regionId - the id of the region whose price we should + * update to + * @return {(LineItemContent | LineItemContentArray)} true if the inventory + * covers the line item. + */ + async updateContentPrice_(content, regionId) { + if (Array.isArray(content)) { + return await Promise.all( + content.map(async c => { + const unitPrice = await this.productVariantService_.getRegionPrice( + c.variant._id, + regionId + ) + c.unit_price = unitPrice + return c + }) + ) + } + + const unitPrice = await this.productVariantService_.getRegionPrice( + content.variant._id, + regionId + ) + content.unit_price = unitPrice + return content + } + /** * @param {Object} selector - the query object for find * @return {Promise} the result of the find operation @@ -348,18 +380,70 @@ class CartService extends BaseService { * @param {string} regionId - the id of the region to set the cart to * @return {Promise} the result of the update operation */ - setRegion(cartId, regionId) { - // Check if cart exists - // Check if region exists - // - // If the cart already has items, go through the items and update the prices - // based on new tax rate, new currency, region specific pricing. - // - // If addresses are set, clear the country code. - // - // If the cart has a shipping method, clear this. - // - // Update the region + async setRegion(cartId, regionId) { + const cart = await this.retrieve(cartId) + if (!cart) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + "The cart was not found" + ) + } + + const region = await this.regionService_.retrieve(regionId) + if (!region) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `The region: ${regionId} was not found` + ) + } + + let update = { + region_id: region._id, + } + + // If the cart contains items we want to change the unit_price field of each + // item to correspond to the price given in the region + if (cart.items.length) { + const newItems = await Promise.all( + cart.items.map(async lineItem => { + lineItem.content = await this.updateContentPrice_( + lineItem.content, + region._id + ) + return lineItem + }) + ) + + update.items = newItems + } + + // If the country code of a shipping address is set we need to clear it + let shippingAddress = cart.shipping_address + if (!_.isEmpty(shippingAddress) && shippingAddress.country_code) { + shippingAddress.country_code = "" + update.shipping_address = shippingAddress + } + + // If the country code of a billing address is set we need to clear it + let billingAddress = cart.billing_address + if (!_.isEmpty(billingAddress) && billingAddress.country_code) { + billingAddress.country_code = "" + update.billing_address = billingAddress + } + + // Shipping methods are determined by region so the user needs to find a + // new shipping method + if (!_.isEmpty(cart.shipping_method)) { + update.shipping_method = undefined + } + + // Payment methods are region specific so the user needs to find a + // new payment method + if (!_.isEmpty(cart.payment_method)) { + update.payment_method = undefined + } + + return this.cartModel_.updateOne({ _id: cart._id }, { $set: update }) } /**