diff --git a/packages/medusa-payment-klarna/src/subscribers/order.js b/packages/medusa-payment-klarna/src/subscribers/order.js deleted file mode 100644 index cb703722b8..0000000000 --- a/packages/medusa-payment-klarna/src/subscribers/order.js +++ /dev/null @@ -1,14 +0,0 @@ -class OrderSubscriber { - constructor({ klarnaProviderService, eventBusService }) { - this.klarnaProviderService_ = klarnaProviderService - - this.eventBus_ = eventBusService - - this.eventBus_.subscribe("order.completed", async (order) => { - const klarnaOrderId = order.payment_method.data.id - await this.klarnaProviderService_.acknowledgeOrder(klarnaOrderId) - }) - } -} - -export default OrderSubscriber diff --git a/packages/medusa-payment-stripe/src/subscribers/cart.js b/packages/medusa-payment-stripe/src/subscribers/cart.js index b1c694ad82..95356a0667 100644 --- a/packages/medusa-payment-stripe/src/subscribers/cart.js +++ b/packages/medusa-payment-stripe/src/subscribers/cart.js @@ -13,11 +13,6 @@ class CartSubscriber { this.eventBus_.subscribe("cart.customer_updated", async (cart) => { await this.onCustomerUpdated(cart) }) - - this.eventBus_.subscribe("order.completed", async (order) => { - const paymentData = order.payment_method.data - await this.stripeProviderService_.capturePayment(paymentData) - }) } async onCustomerUpdated(cart) { diff --git a/packages/medusa-plugin-brightpearl/loaders/inventory.js b/packages/medusa-plugin-brightpearl/loaders/inventory.js index c534686a7d..edbcb5c6bb 100644 --- a/packages/medusa-plugin-brightpearl/loaders/inventory.js +++ b/packages/medusa-plugin-brightpearl/loaders/inventory.js @@ -5,13 +5,57 @@ Object.defineProperty(exports, "__esModule", { }); exports["default"] = void 0; -var inventorySync = function inventorySync(container) { - var brightpearlService = container.resolve("brightpearlService"); - var eventBus = container.resolve("eventBusService"); - var pattern = "43 4,10,14,20 * * *"; // nice for tests "*/10 * * * * *" +function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } - eventBus.createCronJob("inventory-sync", {}, pattern, brightpearlService.syncInventory()); -}; +function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } + +var inventorySync = /*#__PURE__*/function () { + var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(container) { + var brightpearlService, eventBus, client, pattern; + return regeneratorRuntime.wrap(function _callee$(_context) { + while (1) { + switch (_context.prev = _context.next) { + case 0: + brightpearlService = container.resolve("brightpearlService"); + eventBus = container.resolve("eventBusService"); + _context.prev = 2; + _context.next = 5; + return brightpearlService.getClient(); + + case 5: + client = _context.sent; + pattern = "43 4,10,14,20 * * *"; // nice for tests "*/10 * * * * *" + + eventBus.createCronJob("inventory-sync", {}, pattern, brightpearlService.syncInventory()); + _context.next = 15; + break; + + case 10: + _context.prev = 10; + _context.t0 = _context["catch"](2); + + if (!(_context.t0.name === "not_allowed")) { + _context.next = 14; + break; + } + + return _context.abrupt("return"); + + case 14: + throw _context.t0; + + case 15: + case "end": + return _context.stop(); + } + } + }, _callee, null, [[2, 10]]); + })); + + return function inventorySync(_x) { + return _ref.apply(this, arguments); + }; +}(); var _default = inventorySync; exports["default"] = _default; \ No newline at end of file diff --git a/packages/medusa-plugin-brightpearl/loaders/webhooks.js b/packages/medusa-plugin-brightpearl/loaders/webhooks.js index 2373540143..b4616e9d82 100644 --- a/packages/medusa-plugin-brightpearl/loaders/webhooks.js +++ b/packages/medusa-plugin-brightpearl/loaders/webhooks.js @@ -11,21 +11,45 @@ function _asyncToGenerator(fn) { return function () { var self = this, args = ar var webhookLoader = /*#__PURE__*/function () { var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(container) { - var brightpearlService; + var brightpearlService, client; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: brightpearlService = container.resolve("brightpearlService"); - _context.next = 3; + _context.prev = 1; + _context.next = 4; + return brightpearlService.getClient(); + + case 4: + client = _context.sent; + _context.next = 7; return brightpearlService.verifyWebhooks(); - case 3: + case 7: + _context.next = 14; + break; + + case 9: + _context.prev = 9; + _context.t0 = _context["catch"](1); + + if (!(_context.t0.name === "not_allowed")) { + _context.next = 13; + break; + } + + return _context.abrupt("return"); + + case 13: + throw _context.t0; + + case 14: case "end": return _context.stop(); } } - }, _callee); + }, _callee, null, [[1, 9]]); })); return function webhookLoader(_x) { diff --git a/packages/medusa-plugin-brightpearl/src/loaders/inventory.js b/packages/medusa-plugin-brightpearl/src/loaders/inventory.js index 00f3751e02..97b44b189d 100644 --- a/packages/medusa-plugin-brightpearl/src/loaders/inventory.js +++ b/packages/medusa-plugin-brightpearl/src/loaders/inventory.js @@ -1,8 +1,22 @@ -const inventorySync = container => { +const inventorySync = async (container) => { const brightpearlService = container.resolve("brightpearlService") const eventBus = container.resolve("eventBusService") - const pattern = "43 4,10,14,20 * * *" // nice for tests "*/10 * * * * *" - eventBus.createCronJob("inventory-sync", {}, pattern, brightpearlService.syncInventory()) + + try { + const client = await brightpearlService.getClient() + const pattern = "43 4,10,14,20 * * *" // nice for tests "*/10 * * * * *" + eventBus.createCronJob( + "inventory-sync", + {}, + pattern, + brightpearlService.syncInventory() + ) + } catch (err) { + if (err.name === "not_allowed") { + return + } + throw err + } } export default inventorySync diff --git a/packages/medusa-plugin-brightpearl/src/loaders/webhooks.js b/packages/medusa-plugin-brightpearl/src/loaders/webhooks.js index ea78833176..eb9d1b0d24 100644 --- a/packages/medusa-plugin-brightpearl/src/loaders/webhooks.js +++ b/packages/medusa-plugin-brightpearl/src/loaders/webhooks.js @@ -1,6 +1,14 @@ const webhookLoader = async (container) => { const brightpearlService = container.resolve("brightpearlService") - await brightpearlService.verifyWebhooks() + try { + const client = await brightpearlService.getClient() + await brightpearlService.verifyWebhooks() + } catch (err) { + if (err.name === "not_allowed") { + return + } + throw err + } } export default webhookLoader diff --git a/packages/medusa-plugin-brightpearl/src/services/brightpearl.js b/packages/medusa-plugin-brightpearl/src/services/brightpearl.js index 50594f5e77..d5bc031e43 100644 --- a/packages/medusa-plugin-brightpearl/src/services/brightpearl.js +++ b/packages/medusa-plugin-brightpearl/src/services/brightpearl.js @@ -1,3 +1,4 @@ +import { MedusaError } from "medusa-core-utils" import { BaseService } from "medusa-interfaces" import Brightpearl from "../utils/brightpearl" 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 index 2b935fd227..4596b51715 100644 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/return-order.js +++ b/packages/medusa/src/api/routes/admin/orders/__tests__/return-order.js @@ -14,20 +14,7 @@ describe("POST /admin/orders/:id/return", () => { payload: { 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, - }, + item_id: IdMap.getId("existingLine"), quantity: 10, }, ], @@ -51,20 +38,7 @@ describe("POST /admin/orders/:id/return", () => { IdMap.getId("test-order"), [ { - _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, - }, + item_id: IdMap.getId("existingLine"), quantity: 10, }, ] diff --git a/packages/medusa/src/api/routes/admin/orders/return-order.js b/packages/medusa/src/api/routes/admin/orders/return-order.js index 0f7cc17b3b..46d35ec3b9 100644 --- a/packages/medusa/src/api/routes/admin/orders/return-order.js +++ b/packages/medusa/src/api/routes/admin/orders/return-order.js @@ -4,7 +4,13 @@ export default async (req, res) => { const { id } = req.params const schema = Validator.object().keys({ - items: Validator.array().required(), + items: Validator.array() + .items({ + item_id: Validator.string().required(), + quantity: Validator.number().required(), + }) + .required(), + refund: Validator.number().optional(), }) const { value, error } = schema.validate(req.body) diff --git a/packages/medusa/src/models/__mocks__/order.js b/packages/medusa/src/models/__mocks__/order.js index 5b8d16be3e..99ff8f1ea6 100644 --- a/packages/medusa/src/models/__mocks__/order.js +++ b/packages/medusa/src/models/__mocks__/order.js @@ -109,6 +109,9 @@ export const orders = { customer_id: IdMap.getId("test-customer"), payment_method: { provider_id: "default_provider", + data: { + hi: "hi", + }, }, shipping_methods: [ { @@ -133,6 +136,7 @@ export const orders = { orderToRefund: { _id: IdMap.getId("refund-order"), email: "oliver@test.dk", + tax_rate: 0.25, billing_address: { first_name: "Oli", last_name: "Medusa", diff --git a/packages/medusa/src/models/schemas/line-item.js b/packages/medusa/src/models/schemas/line-item.js index aafcc942d8..e434eb1c83 100644 --- a/packages/medusa/src/models/schemas/line-item.js +++ b/packages/medusa/src/models/schemas/line-item.js @@ -36,5 +36,6 @@ export default new mongoose.Schema({ content: { type: mongoose.Schema.Types.Mixed, required: true }, quantity: { type: Number, required: true }, returned: { type: Boolean, default: false }, + returned_quantity: { type: Number, default: 0 }, metadata: { type: mongoose.Schema.Types.Mixed, default: {} }, }) diff --git a/packages/medusa/src/services/__tests__/event-bus.js b/packages/medusa/src/services/__tests__/event-bus.js index 1c9e1f4c5f..14867ebc42 100644 --- a/packages/medusa/src/services/__tests__/event-bus.js +++ b/packages/medusa/src/services/__tests__/event-bus.js @@ -22,7 +22,7 @@ describe("EventBusService", () => { }) it("creates bull queue", () => { - expect(Bull).toHaveBeenCalledTimes(1) + expect(Bull).toHaveBeenCalledTimes(2) expect(Bull).toHaveBeenCalledWith("EventBusService:queue", "testhost") }) }) diff --git a/packages/medusa/src/services/__tests__/order.js b/packages/medusa/src/services/__tests__/order.js index feb9f78b7c..20af230dae 100644 --- a/packages/medusa/src/services/__tests__/order.js +++ b/packages/medusa/src/services/__tests__/order.js @@ -2,7 +2,10 @@ import { IdMap } from "medusa-test-utils" import { OrderModelMock, orders } from "../../models/__mocks__/order" import { carts } from "../../models/__mocks__/cart" import OrderService from "../order" -import { PaymentProviderServiceMock } from "../__mocks__/payment-provider" +import { + PaymentProviderServiceMock, + DefaultProviderMock, +} from "../__mocks__/payment-provider" import { DiscountServiceMock } from "../__mocks__/discount" import { FulfillmentProviderServiceMock } from "../__mocks__/fulfillment-provider" import { ShippingProfileServiceMock } from "../__mocks__/shipping-profile" @@ -53,6 +56,7 @@ describe("OrderService", () => { ...carts.completeCart, currency_code: "eur", cart_id: carts.completeCart._id, + tax_rate: 0.25, } delete order._id delete order.payment_sessions @@ -112,6 +116,7 @@ describe("OrderService", () => { ], currency_code: "eur", cart_id: carts.withGiftCard._id, + tax_rate: 0.25, } delete order._id @@ -359,6 +364,7 @@ describe("OrderService", () => { const orderService = new OrderService({ orderModel: OrderModelMock, paymentProviderService: PaymentProviderServiceMock, + eventBusService: EventBusServiceMock, }) beforeEach(async () => { @@ -439,6 +445,7 @@ describe("OrderService", () => { orderModel: OrderModelMock, paymentProviderService: PaymentProviderServiceMock, totalsService: TotalsServiceMock, + eventBusService: EventBusServiceMock, }) beforeEach(async () => { @@ -448,20 +455,7 @@ describe("OrderService", () => { it("calls order model functions", async () => { await orderService.return(IdMap.getId("processed-order"), [ { - _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, - }, + item_id: IdMap.getId("existingLine"), quantity: 10, }, ]) @@ -489,31 +483,75 @@ describe("OrderService", () => { returned_quantity: 10, thumbnail: "test-img-yeah.com/thumb", title: "merge line", + returned: true, }, ], fulfillment_status: "returned", }, } ) + + expect(DefaultProviderMock.refundPayment).toHaveBeenCalledTimes(1) + expect(DefaultProviderMock.refundPayment).toHaveBeenCalledWith( + { hi: "hi" }, + 1230 + ) }) - it("calls order model functions and sets partially_fulfilled", async () => { + it("return with custom refund", async () => { + await orderService.return( + IdMap.getId("processed-order"), + [ + { + item_id: IdMap.getId("existingLine"), + quantity: 10, + }, + ], + 102 + ) + + expect(OrderModelMock.updateOne).toHaveBeenCalledTimes(1) + expect(OrderModelMock.updateOne).toHaveBeenCalledWith( + { _id: IdMap.getId("processed-order") }, + { + $set: { + items: [ + { + _id: IdMap.getId("existingLine"), + content: { + product: { + _id: IdMap.getId("validId"), + }, + quantity: 1, + unit_price: 123, + variant: { + _id: IdMap.getId("can-cover"), + }, + }, + description: "This is a new line", + quantity: 10, + returned_quantity: 10, + thumbnail: "test-img-yeah.com/thumb", + title: "merge line", + returned: true, + }, + ], + fulfillment_status: "returned", + }, + } + ) + + expect(DefaultProviderMock.refundPayment).toHaveBeenCalledTimes(1) + expect(DefaultProviderMock.refundPayment).toHaveBeenCalledWith( + { hi: "hi" }, + 102 + ) + }) + + it("calls order model functions and sets partially_returned", async () => { await orderService.return(IdMap.getId("order-refund"), [ { - _id: IdMap.getId("existingLine"), - title: "merge line", - description: "This is a new line", - thumbnail: "test-img-yeah.com/thumb", - content: { - unit_price: 100, - variant: { - _id: IdMap.getId("eur-8-us-10"), - }, - product: { - _id: IdMap.getId("product"), - }, - quantity: 1, - }, + item_id: IdMap.getId("existingLine"), quantity: 2, }, ]) @@ -538,6 +576,7 @@ describe("OrderService", () => { }, description: "This is a new line", quantity: 10, + returned: false, returned_quantity: 2, thumbnail: "test-img-yeah.com/thumb", title: "merge line", @@ -560,7 +599,7 @@ describe("OrderService", () => { quantity: 10, }, ], - fulfillment_status: "partially_fulfilled", + fulfillment_status: "partially_returned", }, } ) @@ -568,7 +607,7 @@ describe("OrderService", () => { it("throws if payment is already processed", async () => { try { - await orderService.return(IdMap.getId("fulfilled-order")) + await orderService.return(IdMap.getId("fulfilled-order"), []) } catch (error) { expect(error.message).toEqual( "Can't return an order with payment unprocessed" @@ -578,7 +617,7 @@ describe("OrderService", () => { it("throws if return is attempted on unfulfilled order", async () => { try { - await orderService.return(IdMap.getId("not-fulfilled-order")) + await orderService.return(IdMap.getId("not-fulfilled-order"), []) } catch (error) { expect(error.message).toEqual( "Can't return an unfulfilled or already returned order" diff --git a/packages/medusa/src/services/__tests__/totals.js b/packages/medusa/src/services/__tests__/totals.js index 2a7a2ab75f..f43f9e57cc 100644 --- a/packages/medusa/src/services/__tests__/totals.js +++ b/packages/medusa/src/services/__tests__/totals.js @@ -193,7 +193,7 @@ describe("TotalsService", () => { description: "This is a new line", thumbnail: "test-img-yeah.com/thumb", content: { - unit_price: 123, + unit_price: 100, variant: { _id: IdMap.getId("can-cover"), }, @@ -206,7 +206,7 @@ describe("TotalsService", () => { }, ]) - expect(res).toEqual(1107) + expect(res).toEqual(1125) }) it("calculates refund with total fixed discount", async () => { @@ -218,7 +218,7 @@ describe("TotalsService", () => { description: "This is a new line", thumbnail: "test-img-yeah.com/thumb", content: { - unit_price: 123, + unit_price: 100, variant: { _id: IdMap.getId("can-cover"), }, @@ -231,7 +231,7 @@ describe("TotalsService", () => { }, ]) - expect(res).toEqual(359) + expect(res).toEqual(373.125) }) it("calculates refund with item fixed discount", async () => { @@ -243,7 +243,7 @@ describe("TotalsService", () => { description: "This is a new line", thumbnail: "test-img-yeah.com/thumb", content: { - unit_price: 123, + unit_price: 100, variant: { _id: IdMap.getId("eur-8-us-10"), }, @@ -256,7 +256,7 @@ describe("TotalsService", () => { }, ]) - expect(res).toEqual(363) + expect(res).toEqual(367.5) }) it("calculates refund with item percentage discount", async () => { @@ -268,7 +268,7 @@ describe("TotalsService", () => { description: "This is a new line", thumbnail: "test-img-yeah.com/thumb", content: { - unit_price: 123, + unit_price: 100, variant: { _id: IdMap.getId("eur-8-us-10"), }, @@ -281,7 +281,7 @@ describe("TotalsService", () => { }, ]) - expect(res).toEqual(332.1) + expect(res).toEqual(337.5) }) it("throws if line items to return is not in order", async () => { diff --git a/packages/medusa/src/services/order.js b/packages/medusa/src/services/order.js index c261b0cb44..f1c9b02037 100644 --- a/packages/medusa/src/services/order.js +++ b/packages/medusa/src/services/order.js @@ -7,6 +7,7 @@ class OrderService extends BaseService { GIFT_CARD_CREATED: "order.gift_card_created", PAYMENT_CAPTURED: "order.payment_captured", SHIPMENT_CREATED: "order.shipment_created", + ITEMS_RETURNED: "order.items_returned", PLACED: "order.placed", UPDATED: "order.updated", CANCELLED: "order.cancelled", @@ -218,28 +219,28 @@ class OrderService extends BaseService { */ async completeOrder(orderId) { const order = await this.retrieve(orderId) - this.orderModel_ + + // Capture the payment + await this.capturePayment(orderId) + + // Run all other registered events + const completeOrderJob = await this.eventBus_.emit( + OrderService.Events.COMPLETED, + result + ) + + await completeOrderJob.finished().catch(error => { + throw error + }) + + return this.orderModel_ .updateOne( { _id: order._id }, { $set: { status: "completed" }, } ) - .then(async result => { - const completeOrderJob = await this.eventBus_.emit( - OrderService.Events.COMPLETED, - result - ) - - return completeOrderJob - .finished() - .then(async () => { - return this.retrieve(order._id) - }) - .catch(error => { - throw error - }) - }) + .then(async result => {}) } /** @@ -672,9 +673,25 @@ class OrderService extends BaseService { * @param {string[]} lineItems - the line items to return * @return {Promise} the result of the update operation */ - async return(orderId, lineItems) { + async return(orderId, lineItems, refundAmount) { const order = await this.retrieve(orderId) + // Find the lines to return + const returnLines = lineItems.map(({ item_id, quantity }) => { + const item = order.items.find(i => i._id.equals(item_id)) + if (!item) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + "Return contains invalid line item" + ) + } + + return { + ...item, + quantity, + } + }) + if ( order.fulfillment_status === "not_fulfilled" || order.fulfillment_status === "returned" @@ -697,31 +714,50 @@ class OrderService extends BaseService { provider_id ) - const amount = this.totalsService_.getRefundTotal(order, lineItems) + const amount = + refundAmount || this.totalsService_.getRefundTotal(order, returnLines) await paymentProvider.refundPayment(data, amount) - lineItems.map(item => { - const returnedItem = order.items.find(({ _id }) => _id === item._id) - if (returnedItem) { - returnedItem.returned_quantity = item.quantity + let isFullReturn = true + const newItems = order.items.map(i => { + const isReturn = returnLines.find(r => r._id.equals(i._id)) + if (isReturn) { + let returned = false + if (i.quantity === isReturn.quantity) { + returned = true + } + return { + ...i, + returned_quantity: isReturn.quantity, + returned, + } + } else { + isFullReturn = false + return i } }) - const fullReturn = order.items.every( - item => item.quantity === item.returned_quantity - ) - - return this.orderModel_.updateOne( - { - _id: orderId, - }, - { - $set: { - items: order.items, - fulfillment_status: fullReturn ? "returned" : "partially_fulfilled", + return this.orderModel_ + .updateOne( + { + _id: orderId, }, - } - ) + { + $set: { + items: newItems, + fulfillment_status: isFullReturn + ? "returned" + : "partially_returned", + }, + } + ) + .then(result => { + this.eventBus_.emit(OrderService.Events.ITEMS_RETURNED, { + order: result, + items: returnLines, + }) + return result + }) } /** @@ -768,6 +804,14 @@ class OrderService extends BaseService { if (expandFields.includes("region")) { o.region = await this.regionService_.retrieve(order.region_id) } + + o.items = o.items.map(i => { + return { + ...i, + refundable: this.totalsService_.getLineItemRefund(o, i), + } + }) + return o } diff --git a/packages/medusa/src/services/totals.js b/packages/medusa/src/services/totals.js index 40ee9d98ce..976de7f863 100644 --- a/packages/medusa/src/services/totals.js +++ b/packages/medusa/src/services/totals.js @@ -80,6 +80,32 @@ class TotalsService extends BaseService { return (subtotal - discountTotal + shippingTotal) * tax_rate } + getLineItemRefund(order, lineItem) { + const { tax_rate, discounts } = order + const taxRate = tax_rate || 0 + + const discount = discounts.find( + ({ discount_rule }) => discount_rule.type !== "free_shipping" + ) + + if (!discount) { + return lineItem.content.unit_price * lineItem.quantity * (1 + taxRate) + } + + const lineDiscounts = this.getLineDiscounts(order, discount) + const discountedLine = lineDiscounts.find(line => + line.item._id.equals(lineItem._id) + ) + + const discountAmount = + (discountedLine.amount / discountedLine.item.quantity) * lineItem.quantity + + return ( + (lineItem.content.unit_price * lineItem.quantity - discountAmount) * + (1 + taxRate) + ) + } + /** * Calculates refund total of line items. * If any of the items to return have been discounted, we need to @@ -88,101 +114,9 @@ class TotalsService extends BaseService { * @param {[LineItem]} lineItems - * @return {int} the calculated subtotal */ - async getRefundTotal(order, lineItems) { - const discount = order.discounts.find( - ({ discount_rule }) => discount_rule.type !== "free_shipping" - ) - - if (_.differenceBy(lineItems, order.items, "_id").length !== 0) { - throw new MedusaError( - MedusaError.Types.INVALID_ARGUMENT, - "Line items does not exist on order" - ) - } - - const subtotal = this.getSubtotal({ items: lineItems }) - - const region = await this.regionService_.retrieve(order.region_id) - - // if nothing is discounted, return the subtotal of line items - if (!discount) { - return subtotal * (1 + region.tax_rate) - } - - const { value, type, allocation } = discount.discount_rule - - if (type === "percentage" && allocation === "total") { - const discountTotal = (subtotal / 100) * value - return subtotal - discountTotal - } - - if (type === "fixed" && allocation === "total") { - return subtotal - value - } - - if (type === "percentage" && allocation === "item") { - // Find discounted items - const itemPercentageDiscounts = await this.getAllocationItemDiscounts( - discount, - { items: lineItems }, - "percentage" - ) - - // Find discount total by taking each discounted item, reducing it by - // its discount value. Then summing all those items together. - const discountRefundTotal = _.sumBy( - itemPercentageDiscounts, - d => d.lineItem.content.unit_price * d.lineItem.quantity - d.amount - ) - - // Find the items that weren't discounted - const notDiscountedItems = _.differenceBy( - lineItems, - Array.from(itemPercentageDiscounts, el => el.lineItem), - "_id" - ) - - // If all items were discounted, we return the total of the discounted - // items - if (!notDiscountedItems) { - return discountRefundTotal - } - - // Otherwise, we find the total those not discounted - const notDiscRefundTotal = this.getSubtotal({ items: notDiscountedItems }) - - // Finally, return the sum of discounted and not discounted items - return notDiscRefundTotal + discountRefundTotal - } - - // See immediate `if`-statement above for a elaboration on the following - // calculations. This time with fixed discount type. - if (type === "fixed" && allocation === "item") { - const itemPercentageDiscounts = await this.getAllocationItemDiscounts( - discount, - { items: lineItems }, - "fixed" - ) - - const discountRefundTotal = _.sumBy( - itemPercentageDiscounts, - d => d.lineItem.content.unit_price * d.lineItem.quantity - d.amount - ) - - const notDiscountedItems = _.differenceBy( - lineItems, - Array.from(itemPercentageDiscounts, el => el.lineItem), - "_id" - ) - - if (!notDiscountedItems) { - return notDiscRefundTotal - } - - const notDiscRefundTotal = this.getSubtotal({ items: notDiscountedItems }) - - return notDiscRefundTotal + discountRefundTotal - } + getRefundTotal(order, lineItems) { + const refunds = lineItems.map(i => this.getLineItemRefund(order, i)) + return refunds.reduce((acc, next) => acc + next, 0) } /** @@ -225,7 +159,7 @@ class TotalsService extends BaseService { * @return {[{ string, string, int }]} array of triples of lineitem, variant * and applied discount */ - async getAllocationItemDiscounts(discount, cart) { + getAllocationItemDiscounts(discount, cart) { const discounts = [] for (const item of cart.items) { if (discount.discount_rule.valid_for.length > 0) { @@ -252,7 +186,7 @@ class TotalsService extends BaseService { return discounts } - async getLineDiscounts(cart, discount) { + getLineDiscounts(cart, discount) { const subtotal = this.getSubtotal(cart) const { type, allocation, value } = discount.discount_rule if (allocation === "total") { diff --git a/packages/medusa/src/subscribers/order.js b/packages/medusa/src/subscribers/order.js index 3f63381c65..aa2fd2c8a6 100644 --- a/packages/medusa/src/subscribers/order.js +++ b/packages/medusa/src/subscribers/order.js @@ -19,14 +19,6 @@ class OrderSubscriber { this.eventBus_ = eventBusService - this.eventBus_.subscribe("order.completed", async order => { - const paymentProvider = this.paymentProviderService_.retrieveProvider( - order.payment_method.provider_id - ) - - await paymentProvider.capturePayment(order._id) - }) - this.eventBus_.subscribe("order.placed", async order => { await this.customerService_.addOrder(order.customer_id, order._id)