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 index eac06fe22e..042aa5aed2 100644 --- a/packages/medusa/src/api/routes/admin/products/__tests__/create-product.js +++ b/packages/medusa/src/api/routes/admin/products/__tests__/create-product.js @@ -1,6 +1,7 @@ import { IdMap } from "medusa-test-utils" import { request } from "../../../../../helpers/test-request" import { ProductServiceMock } from "../../../../../services/__mocks__/product" +import { ShippingProfileServiceMock } from "../../../../../services/__mocks__/shipping-profile" describe("POST /admin/products", () => { describe("successful creation", () => { @@ -38,8 +39,80 @@ describe("POST /admin/products", () => { description: "Test Description", tags: "hi,med,dig", handle: "test-product", + is_giftcard: false, }) }) + + 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.createDraft).toHaveBeenCalledTimes(1) + expect(ProductServiceMock.createDraft).toHaveBeenCalledWith({ + title: "Gift Card", + description: "make someone happy", + options: [{ title: "Denominations" }], + handle: "test-gift-card", + is_giftcard: true, + }) + }) + + it("calls profile service", () => { + expect( + ShippingProfileServiceMock.retrieveGiftCardDefault + ).toHaveBeenCalledTimes(1) + expect( + ShippingProfileServiceMock.retrieveGiftCardDefault + ).toHaveBeenCalledWith() + + expect(ShippingProfileServiceMock.addProduct).toHaveBeenCalledTimes(1) + expect(ShippingProfileServiceMock.addProduct).toHaveBeenCalledWith( + IdMap.getId("giftCardProfile"), + undefined + ) + }) }) describe("invalid data returns error details", () => { diff --git a/packages/medusa/src/api/routes/admin/products/create-product.js b/packages/medusa/src/api/routes/admin/products/create-product.js index d346c9e66f..df1e31f1cb 100644 --- a/packages/medusa/src/api/routes/admin/products/create-product.js +++ b/packages/medusa/src/api/routes/admin/products/create-product.js @@ -5,6 +5,7 @@ export default async (req, res) => { title: Validator.string().required(), description: Validator.string(), tags: Validator.string(), + is_giftcard: Validator.boolean().default(false), options: Validator.array().items({ title: Validator.string().required(), }), @@ -71,8 +72,13 @@ export default async (req, res) => { } // Add to default shipping profile - const { _id } = await shippingProfileService.retrieveDefault() - await shippingProfileService.addProduct(_id, newProduct._id) + if (value.is_giftcard) { + const { _id } = await shippingProfileService.retrieveGiftCardDefault() + await shippingProfileService.addProduct(_id, newProduct._id) + } else { + const { _id } = await shippingProfileService.retrieveDefault() + await shippingProfileService.addProduct(_id, newProduct._id) + } newProduct = await productService.decorate( newProduct, @@ -90,6 +96,7 @@ export default async (req, res) => { ) res.json({ product: newProduct }) } catch (err) { + console.log(err) throw err } } diff --git a/packages/medusa/src/api/routes/store/carts/create-line-item.js b/packages/medusa/src/api/routes/store/carts/create-line-item.js index 2d28d5212e..a52604b811 100644 --- a/packages/medusa/src/api/routes/store/carts/create-line-item.js +++ b/packages/medusa/src/api/routes/store/carts/create-line-item.js @@ -6,6 +6,7 @@ export default async (req, res) => { const schema = Validator.object().keys({ variant_id: Validator.string().required(), quantity: Validator.number().required(), + metadata: Validator.object().optional(), }) const { value, error } = schema.validate(req.body) @@ -21,7 +22,8 @@ export default async (req, res) => { const lineItem = await lineItemService.generate( value.variant_id, cart.region_id, - value.quantity + value.quantity, + value.metadata ) await cartService.addLineItem(cart._id, lineItem) diff --git a/packages/medusa/src/loaders/defaults.js b/packages/medusa/src/loaders/defaults.js index e5c3f5badf..de1ac5edf6 100644 --- a/packages/medusa/src/loaders/defaults.js +++ b/packages/medusa/src/loaders/defaults.js @@ -22,5 +22,7 @@ export default async ({ container }) => { fulfillment_providers: fulfilIds, payment_providers: payIds, }) + await profileService.createDefault() + await profileService.createGiftCardDefault() } diff --git a/packages/medusa/src/models/discount.js b/packages/medusa/src/models/discount.js index 763a9a7650..217a2a222c 100644 --- a/packages/medusa/src/models/discount.js +++ b/packages/medusa/src/models/discount.js @@ -8,6 +8,7 @@ class DiscountModel extends BaseModel { static schema = { code: { type: String, required: true, unique: true }, is_dynamic: { type: Boolean, default: false }, + is_giftcard: { type: Boolean, default: false }, discount_rule: { type: DiscountRule, required: true }, usage_count: { type: Number, default: 0 }, disabled: { type: Boolean, default: false }, diff --git a/packages/medusa/src/models/product.js b/packages/medusa/src/models/product.js index 300ecaba94..0735958943 100644 --- a/packages/medusa/src/models/product.js +++ b/packages/medusa/src/models/product.js @@ -14,6 +14,7 @@ class ProductModel extends BaseModel { description: { type: String, default: "" }, tags: { type: String, default: "" }, handle: { type: String, unique: true, sparse: true }, + is_giftcard: { type: Boolean, default: false }, images: { type: [String], default: [] }, thumbnail: { type: String, default: "" }, options: { type: [OptionSchema], default: [] }, diff --git a/packages/medusa/src/services/__mocks__/middleware.js b/packages/medusa/src/services/__mocks__/middleware.js index 509e887668..b3ccfafdd5 100644 --- a/packages/medusa/src/services/__mocks__/middleware.js +++ b/packages/medusa/src/services/__mocks__/middleware.js @@ -1,6 +1,7 @@ export const MiddlewareServiceMock = { usePostAuthentication: jest.fn(), usePreAuthentication: jest.fn(), + getRouters: jest.fn().mockReturnValue([]), } const mock = jest.fn().mockImplementation(() => { diff --git a/packages/medusa/src/services/__mocks__/product.js b/packages/medusa/src/services/__mocks__/product.js index e7514af73f..0f77e82ba7 100644 --- a/packages/medusa/src/services/__mocks__/product.js +++ b/packages/medusa/src/services/__mocks__/product.js @@ -31,7 +31,11 @@ export const products = { export const ProductServiceMock = { createDraft: jest.fn().mockImplementation(data => { - return Promise.resolve(products.product1) + if (data.title === "Test Product") { + return Promise.resolve(products.product1) + } + + return Promise.resolve({ ...data }) }), publish: jest.fn().mockImplementation(_ => { return Promise.resolve({ diff --git a/packages/medusa/src/services/__mocks__/shipping-profile.js b/packages/medusa/src/services/__mocks__/shipping-profile.js index 68f76af3d4..6e49c1dd81 100644 --- a/packages/medusa/src/services/__mocks__/shipping-profile.js +++ b/packages/medusa/src/services/__mocks__/shipping-profile.js @@ -31,6 +31,9 @@ export const ShippingProfileServiceMock = { } return Promise.resolve() }), + 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") }) }), diff --git a/packages/medusa/src/services/shipping-profile.js b/packages/medusa/src/services/shipping-profile.js index 18b22b24cc..52cc5ba5e8 100644 --- a/packages/medusa/src/services/shipping-profile.js +++ b/packages/medusa/src/services/shipping-profile.js @@ -97,6 +97,32 @@ class ShippingProfileService extends BaseService { return profile } + /** + * Retrieves the default gift card profile + * @return the shipping profile for gift cards + */ + async retrieveGiftCardProfile() { + return await this.profileModel_ + .findOne({ name: "default_gift_card_profile" }) + .catch(err => { + throw new MedusaError(MedusaError.Types.DB_ERROR, err.message) + }) + } + + /** + * Creates a default shipping profile, for gift cards if unless it already + * exists. + * @return {Promise} the shipping profile + */ + async createGiftCardDefault() { + const profile = await this.retrieveGiftCardProfile() + if (!profile) { + return this.profileModel_.create({ name: "default_gift_card_profile" }) + } + + return profile + } + /** * Creates a new shipping profile. * @param {ShippingProfile} profile - the shipping profile to create from