diff --git a/integration-tests/api/__tests__/admin/draft-order.js b/integration-tests/api/__tests__/admin/draft-order.js index ba2e9fb0b5..4144a598ff 100644 --- a/integration-tests/api/__tests__/admin/draft-order.js +++ b/integration-tests/api/__tests__/admin/draft-order.js @@ -141,6 +141,58 @@ describe("/admin/draft-orders", () => { expect(response.status).toEqual(200); }); + it("creates a draft order with product variant with custom price", async () => { + const api = useApi(); + + const payload = { + email: "oli@test.dk", + shipping_address_id: "oli-shipping", + items: [ + { + variant_id: "test-variant", + quantity: 2, + metadata: {}, + unit_price: 10000000, + }, + ], + region_id: "test-region", + customer_id: "oli-test", + shipping_methods: [ + { + option_id: "test-option", + }, + ], + }; + + const response = await api + .post("/admin/draft-orders", payload, { + headers: { + Authorization: "Bearer test_token", + }, + }) + .catch((err) => { + console.log(err); + }); + + const created = await api + .get(`/admin/draft-orders/${response.data.draft_order.id}`, { + headers: { + Authorization: "Bearer test_token", + }, + }) + .catch((err) => { + console.log(err); + }); + + expect(response.status).toEqual(200); + expect(created.data.draft_order.cart.items[0]).toEqual( + expect.objectContaining({ + variant_id: "test-variant", + unit_price: 10000000, + }) + ); + }); + it("creates a draft order with created shipping address", async () => { const api = useApi(); @@ -239,7 +291,6 @@ describe("/admin/draft-orders", () => { await adminSeeder(dbConnection); await draftOrderSeeder(dbConnection); } catch (err) { - console.log(err); throw err; } }); @@ -335,8 +386,6 @@ describe("/admin/draft-orders", () => { expect(response.status).toEqual(200); - console.log(response.data.draft_orders); - expect(response.data.draft_orders).toEqual([]); expect(response.data.count).toEqual(0); }); diff --git a/integration-tests/api/__tests__/store/draft-order.js b/integration-tests/api/__tests__/store/draft-order.js index 94e769219d..1389244436 100644 --- a/integration-tests/api/__tests__/store/draft-order.js +++ b/integration-tests/api/__tests__/store/draft-order.js @@ -46,11 +46,12 @@ describe("/store/carts (draft-orders)", () => { await manager.query(`DELETE FROM "shipping_method"`); await manager.query(`DELETE FROM "shipping_option"`); await manager.query(`DELETE FROM "discount"`); - await manager.query(`DELETE FROM "draft_order"`); await manager.query(`DELETE FROM "payment_provider"`); await manager.query(`DELETE FROM "payment_session"`); await manager.query(`UPDATE "payment" SET order_id=NULL`); + await manager.query(`UPDATE "draft_order" SET order_id=NULL`); await manager.query(`DELETE FROM "order"`); + await manager.query(`DELETE FROM "draft_order"`); await manager.query(`DELETE FROM "cart"`); await manager.query(`DELETE FROM "payment"`); await manager.query(`DELETE FROM "customer"`); diff --git a/packages/medusa/src/api/routes/admin/draft-orders/create-draft-order.js b/packages/medusa/src/api/routes/admin/draft-orders/create-draft-order.js index 1ec2e6261d..6108d32547 100644 --- a/packages/medusa/src/api/routes/admin/draft-orders/create-draft-order.js +++ b/packages/medusa/src/api/routes/admin/draft-orders/create-draft-order.js @@ -52,25 +52,18 @@ export default async (req, res) => { try { const draftOrderService = req.scope.resolve("draftOrderService") - const entityManager = req.scope.resolve("manager") - await entityManager.transaction(async manager => { - const requiresShipping = value.requires_shipping - delete value.requires_shipping + const requiresShipping = value.requires_shipping + delete value.requires_shipping - let draftOrder = await draftOrderService - .withTransaction(manager) - .create(value, requiresShipping) + let draftOrder = await draftOrderService.create(value, requiresShipping) - draftOrder = await draftOrderService - .withTransaction(manager) - .retrieve(draftOrder.id, { - relations: defaultRelations, - select: defaultFields, - }) - - res.status(200).json({ draft_order: draftOrder }) + draftOrder = await draftOrderService.retrieve(draftOrder.id, { + relations: defaultRelations, + select: defaultFields, }) + + res.status(200).json({ draft_order: draftOrder }) } catch (err) { throw err } diff --git a/packages/medusa/src/api/routes/admin/draft-orders/create-line-item.js b/packages/medusa/src/api/routes/admin/draft-orders/create-line-item.js index 0ec64ef24e..1f232f939f 100644 --- a/packages/medusa/src/api/routes/admin/draft-orders/create-line-item.js +++ b/packages/medusa/src/api/routes/admin/draft-orders/create-line-item.js @@ -43,7 +43,8 @@ export default async (req, res) => { value.variant_id, draftOrder.cart.region_id, value.quantity, - value.metadata + value.metadata, + value.unit_price ) await cartService diff --git a/packages/medusa/src/api/routes/admin/draft-orders/register-payment.js b/packages/medusa/src/api/routes/admin/draft-orders/register-payment.js index a48cc190d4..48beb64c71 100644 --- a/packages/medusa/src/api/routes/admin/draft-orders/register-payment.js +++ b/packages/medusa/src/api/routes/admin/draft-orders/register-payment.js @@ -8,11 +8,44 @@ export default async (req, res) => { try { const draftOrderService = req.scope.resolve("draftOrderService") + const paymentProviderService = req.scope.resolve("paymentProviderService") const orderService = req.scope.resolve("orderService") + const cartService = req.scope.resolve("cartService") + const entityManager = req.scope.resolve("manager") - const createdOrder = await draftOrderService.registerSystemPayment(id) + let result + await entityManager.transaction(async manager => { + const draftOrder = await draftOrderService + .withTransaction(manager) + .retrieve(id) - const order = await orderService.retrieve(createdOrder.id, { + const cart = await cartService + .withTransaction(manager) + .retrieve(draftOrder.cart_id, { + select: ["total"], + relations: ["discounts", "shipping_methods", "region", "items"], + }) + + await paymentProviderService + .withTransaction(manager) + .createSession("system", cart) + + await cartService + .withTransaction(manager) + .setPaymentSession(cart.id, "system") + + await cartService.withTransaction(manager).authorizePayment(cart.id) + + result = await orderService + .withTransaction(manager) + .createFromCart(cart.id) + + await draftOrderService + .withTransaction(manager) + .registerCartCompletion(draftOrder.id, result.id) + }) + + const order = await orderService.retrieve(result.id, { relations: defaultOrderRelations, select: defaultOrderFields, }) diff --git a/packages/medusa/src/api/routes/admin/draft-orders/update-draft-order.js b/packages/medusa/src/api/routes/admin/draft-orders/update-draft-order.js index 9652b9c11b..736bc89729 100644 --- a/packages/medusa/src/api/routes/admin/draft-orders/update-draft-order.js +++ b/packages/medusa/src/api/routes/admin/draft-orders/update-draft-order.js @@ -12,7 +12,6 @@ export default async (req, res) => { .optional(), billing_address: Validator.object().optional(), shipping_address: Validator.object().optional(), - discounts: Validator.array() .items({ code: Validator.string(), @@ -29,36 +28,24 @@ export default async (req, res) => { try { const draftOrderService = req.scope.resolve("draftOrderService") const cartService = req.scope.resolve("cartService") - const entityManager = req.scope.resolve("manager") - await entityManager.transaction(async manager => { - const draftOrder = await draftOrderService - .withTransaction(manager) - .retrieve(id) + const draftOrder = await draftOrderService.retrieve(id) - if ( - draftOrder.status === "completed" || - draftOrder.status === "awaiting" - ) { - throw new MedusaError( - MedusaError.Types.NOT_ALLOWED, - "You are only allowed to update open draft orders" - ) - } + if (draftOrder.status === "completed" || draftOrder.status === "awaiting") { + throw new MedusaError( + MedusaError.Types.NOT_ALLOWED, + "You are only allowed to update open draft orders" + ) + } - await cartService - .withTransaction(manager) - .update(draftOrder.cart_id, value) + await cartService.update(draftOrder.cart_id, value) - draftOrder.cart = await cartService - .withTransaction(manager) - .retrieve(draftOrder.cart_id, { - relations: defaultCartRelations, - select: defaultCartFields, - }) - - res.status(200).json({ draft_order: draftOrder }) + draftOrder.cart = await cartService.retrieve(draftOrder.cart_id, { + relations: defaultCartRelations, + select: defaultCartFields, }) + + res.status(200).json({ draft_order: draftOrder }) } catch (err) { throw err } diff --git a/packages/medusa/src/models/shipping-method.ts b/packages/medusa/src/models/shipping-method.ts index 08a6223858..19af8cae18 100644 --- a/packages/medusa/src/models/shipping-method.ts +++ b/packages/medusa/src/models/shipping-method.ts @@ -17,7 +17,6 @@ import { Cart } from "./cart" import { Swap } from "./swap" import { Return } from "./return" import { ShippingOption } from "./shipping-option" -import { DraftOrder } from "./draft-order" @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` diff --git a/packages/medusa/src/services/__tests__/draft-order.js b/packages/medusa/src/services/__tests__/draft-order.js index ba2b9f7f92..ae2aa2a5bf 100644 --- a/packages/medusa/src/services/__tests__/draft-order.js +++ b/packages/medusa/src/services/__tests__/draft-order.js @@ -179,7 +179,8 @@ describe("DraftOrderService", () => { "test-variant", "test-region", 2, - {} + {}, + undefined ) expect(lineItemService.create).toHaveBeenCalledTimes(1) @@ -216,123 +217,4 @@ describe("DraftOrderService", () => { } }) }) - - describe("registerSystemPayment", () => { - let result - - const shippingOptionService = { - update: jest.fn(), - withTransaction: function() { - return this - }, - } - - const lineItemService = { - update: jest.fn(), - withTransaction: function() { - return this - }, - } - - const cartService = { - retrieve: jest.fn().mockImplementation(data => - Promise.resolve({ - id: "test-cart", - total: 1000, - region_id: "test-region", - region: { - id: "test-region", - currency_code: "usd", - tax_rate: 0, - }, - items: [{ id: "test-item" }], - discounts: [], - email: "oli@test.dk", - customer_id: "test-customer", - draft_order_id: "test-draft-order", - metadata: {}, - }) - ), - withTransaction: function() { - return this - }, - } - - const draftOrderRepository = MockRepository({ - findOne: () => - Promise.resolve({ id: "test-draft-order", cart_id: "test-cart" }), - }) - const orderRepository = MockRepository({ - create: d => ({ id: "test-order", ...d }), - }) - const paymentRepository = MockRepository({ - create: d => ({ - ...d, - }), - }) - - const draftOrderService = new DraftOrderService({ - manager: MockManager, - cartService, - shippingOptionService, - lineItemService, - paymentRepository, - draftOrderRepository, - orderRepository, - eventBusService, - }) - - beforeEach(async () => { - jest.clearAllMocks() - }) - - it("registers system payment", async () => { - await draftOrderService.registerSystemPayment("test-draft-order") - - expect(cartService.retrieve).toHaveBeenCalledTimes(1) - expect(cartService.retrieve).toHaveBeenCalledWith("test-cart", { - relations: ["discounts", "shipping_methods", "region", "items"], - select: ["total"], - }) - - expect(paymentRepository.create).toHaveBeenCalledTimes(1) - expect(paymentRepository.create).toHaveBeenCalledWith({ - provider_id: "system", - amount: 1000, - currency_code: "usd", - data: {}, - }) - - expect(orderRepository.create).toHaveBeenCalledTimes(1) - expect(orderRepository.create).toHaveBeenCalledWith({ - cart_id: "test-cart", - discounts: [], - region_id: "test-region", - discounts: [], - email: "oli@test.dk", - customer_id: "test-customer", - draft_order_id: "test-draft-order", - tax_rate: 0, - payment_status: "awaiting", - currency_code: "usd", - metadata: {}, - payments: [ - { - provider_id: "system", - amount: 1000, - currency_code: "usd", - data: {}, - }, - ], - }) - - expect(draftOrderRepository.save).toHaveBeenCalledTimes(1) - expect(draftOrderRepository.save).toHaveBeenCalledWith({ - id: "test-draft-order", - cart_id: "test-cart", - order_id: "test-order", - status: "completed", - }) - }) - }) }) diff --git a/packages/medusa/src/services/cart.js b/packages/medusa/src/services/cart.js index cd9bf09ced..a79ac9ba30 100644 --- a/packages/medusa/src/services/cart.js +++ b/packages/medusa/src/services/cart.js @@ -998,6 +998,7 @@ class CartService extends BaseService { // The region must have the provider id in its providers array if ( + providerId !== "system" && !( cart.region.payment_providers.length && cart.region.payment_providers.find(({ id }) => providerId === id) diff --git a/packages/medusa/src/services/draft-order.js b/packages/medusa/src/services/draft-order.js index 261112df48..9de3d2d12a 100644 --- a/packages/medusa/src/services/draft-order.js +++ b/packages/medusa/src/services/draft-order.js @@ -290,7 +290,8 @@ class DraftOrderService extends BaseService { item.variant_id, data.region_id, item.quantity, - item.metadata + item.metadata, + item.unit_price ) const variant = await this.productVariantService_ @@ -327,88 +328,6 @@ class DraftOrderService extends BaseService { }) } - /** - * Registers a system payment and creates an order - * @param {string} doId - id of draft order to register payment for - * @return {Promise} the created order - */ - async registerSystemPayment(doId) { - return this.atomicPhase_(async manager => { - const draftOrder = await this.retrieve(doId) - - const draftOrderCart = await this.cartService_ - .withTransaction(manager) - .retrieve(draftOrder.cart_id, { - select: ["total"], - relations: ["discounts", "shipping_methods", "region", "items"], - }) - - const orderRepo = manager.getCustomRepository(this.orderRepository_) - const draftOrderRepo = manager.getCustomRepository( - this.draftOrderRepository_ - ) - - const paymentRepo = manager.getCustomRepository(this.paymentRepository_) - - const created = paymentRepo.create({ - provider_id: "system", - amount: draftOrderCart.total, - currency_code: draftOrderCart.region.currency_code, - data: {}, - }) - - const toCreate = { - payment_status: "awaiting", - discounts: draftOrderCart.discounts, - region_id: draftOrderCart.region_id, - email: draftOrderCart.email, - customer_id: draftOrderCart.customer_id, - draft_order_id: draftOrder.id, - cart_id: draftOrderCart.id, - tax_rate: draftOrderCart.region.tax_rate, - currency_code: draftOrderCart.region.currency_code, - metadata: draftOrderCart.metadata || {}, - payments: [created], - } - - if (draftOrderCart.shipping_address_id) { - toCreate.shipping_address_id = draftOrderCart.shipping_address_id - } - - if (draftOrderCart.billing_address_id) { - toCreate.billing_address_id = draftOrderCart.billing_address_id - } - - if (draftOrderCart.shipping_methods) { - toCreate.shipping_methods = draftOrderCart.shipping_methods - } - - const o = orderRepo.create(toCreate) - - const result = await orderRepo.save(o) - - if (draftOrderCart.shipping_methods) { - for (const method of draftOrderCart.shipping_methods) { - await this.shippingOptionService_ - .withTransaction(manager) - .updateShippingMethod(method.id, { order_id: result.id }) - } - } - - for (const item of draftOrderCart.items) { - await this.lineItemService_ - .withTransaction(manager) - .update(item.id, { order_id: result.id }) - } - - draftOrder.status = "completed" - draftOrder.order_id = result.id - await draftOrderRepo.save(draftOrder) - - return result - }) - } - /** * Registers a draft order as completed, when an order has been completed. * @param {string} doId - id of draft order to complete diff --git a/packages/medusa/src/services/line-item.js b/packages/medusa/src/services/line-item.js index 141b22853f..c1947b262e 100644 --- a/packages/medusa/src/services/line-item.js +++ b/packages/medusa/src/services/line-item.js @@ -89,17 +89,22 @@ class LineItemService extends BaseService { return lineItem } - async generate(variantId, regionId, quantity, metadata = {}) { + async generate(variantId, regionId, quantity, metadata = {}, unitPrice) { const variant = await this.productVariantService_.retrieve(variantId, { relations: ["product"], }) const region = await this.regionService_.retrieve(regionId) - const price = await this.productVariantService_.getRegionPrice( - variant.id, - region.id - ) + let price + if (unitPrice) { + price = unitPrice + } else { + price = await this.productVariantService_.getRegionPrice( + variant.id, + region.id + ) + } const toCreate = { unit_price: price, diff --git a/packages/medusa/src/services/order.js b/packages/medusa/src/services/order.js index 70a22fcc8c..2e6a6f9af6 100644 --- a/packages/medusa/src/services/order.js +++ b/packages/medusa/src/services/order.js @@ -41,6 +41,7 @@ class OrderService extends BaseService { cartService, addressRepository, giftCardService, + draftOrderService, eventBusService, }) { super() @@ -98,6 +99,9 @@ class OrderService extends BaseService { /** @private @constant {SwapService} */ this.swapService_ = swapService + + /** @private @constant {DraftOrderService} */ + this.draftOrderService_ = draftOrderService } withTransaction(manager) { @@ -120,9 +124,11 @@ class OrderService extends BaseService { cartService: this.cartService_, swapService: this.swapService_, giftCardService: this.giftCardService_, + draftOrderService: this.draftOrderService_, }) cloned.transactionManager_ = manager + cloned.manager_ = manager return cloned } @@ -482,7 +488,8 @@ class OrderService extends BaseService { } const orderRepo = manager.getCustomRepository(this.orderRepository_) - const o = await orderRepo.create({ + + const toCreate = { payment_status: "awaiting", discounts: cart.discounts, gift_cards: cart.gift_cards, @@ -496,7 +503,17 @@ class OrderService extends BaseService { tax_rate: region.tax_rate, currency_code: region.currency_code, metadata: cart.metadata || {}, - }) + } + + if (cart.type === "draft_order") { + const draft = await this.draftOrderService_ + .withTransaction(manager) + .retrieveByCartId(cart.id) + + toCreate.draft_order_id = draft.id + } + + const o = await orderRepo.create(toCreate) const result = await orderRepo.save(o) diff --git a/packages/medusa/src/services/payment-provider.js b/packages/medusa/src/services/payment-provider.js index d76e9cf00c..7a210ca8a2 100644 --- a/packages/medusa/src/services/payment-provider.js +++ b/packages/medusa/src/services/payment-provider.js @@ -27,6 +27,7 @@ class PaymentProviderService extends BaseService { const cloned = new PaymentProviderService(this.container_) cloned.transactionManager_ = manager + cloned.manager_ = manager return cloned } diff --git a/packages/medusa/src/services/system-payment-provider.js b/packages/medusa/src/services/system-payment-provider.js index 4e75535a98..fd59e3d619 100644 --- a/packages/medusa/src/services/system-payment-provider.js +++ b/packages/medusa/src/services/system-payment-provider.js @@ -11,6 +11,10 @@ class SystemProviderService extends BaseService { return {} } + async getStatus(_) { + return "authorized" + } + async getPaymentData(_) { return {} }