feat:swap/claim on claim and claim on swap (#424)

This commit is contained in:
Sebastian Mateos Nicolajsen authored and GitHub committed 2021-10-14 18:21:38 +02:00
1 parent b6efa6f471
commit fbd08e0feb
18 files changed
+1745 -1678

No files matched your search

@@ -1,88 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _medusaInterfaces = require("medusa-interfaces");
function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
function _createSuper(Derived) { return function () { var Super = _getPrototypeOf(Derived), result; if (_isNativeReflectConstruct()) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var ManualFulfillmentService = /*#__PURE__*/function (_FulfillmentService) {
_inherits(ManualFulfillmentService, _FulfillmentService);
var _super = _createSuper(ManualFulfillmentService);
function ManualFulfillmentService() {
_classCallCheck(this, ManualFulfillmentService);
return _super.call(this);
}
_createClass(ManualFulfillmentService, [{
key: "getFulfillmentOptions",
value: function getFulfillmentOptions() {
return [{
id: "manual-fulfillment"
}];
}
}, {
key: "validateFulfillmentData",
value: function validateFulfillmentData(data, cart) {
return data;
}
}, {
key: "validateOption",
value: function validateOption(data) {
return true;
}
}, {
key: "canCalculate",
value: function canCalculate() {
return false;
}
}, {
key: "calculatePrice",
value: function calculatePrice() {
throw Error("Manual Fulfillment service cannot calculatePrice");
}
}, {
key: "createOrder",
value: function createOrder() {
// No data is being sent anywhere
return;
}
}]);
return ManualFulfillmentService;
}(_medusaInterfaces.FulfillmentService);
_defineProperty(ManualFulfillmentService, "identifier", "manual");
var _default = ManualFulfillmentService;
exports["default"] = _default;
@@ -27,6 +27,7 @@ const defaultRelations = [
"claims.additional_items",
"claims.fulfillments",
"claims.claim_items",
"claims.claim_items.item",
"claims.claim_items.images",
"swaps",
"swaps.return_order",
@@ -56,6 +57,7 @@ const defaultFields = [
"metadata",
"items.refundable",
"swaps.additional_items.refundable",
"claims.additional_items.refundable",
"shipping_total",
"discount_total",
"tax_total",
@@ -241,6 +241,7 @@ export const defaultRelations = [
"claims.additional_items",
"claims.fulfillments",
"claims.claim_items",
"claims.claim_items.item",
"claims.claim_items.images",
// "claims.claim_items.tags",
"swaps",
@@ -271,6 +272,7 @@ export const defaultFields = [
"metadata",
"items.refundable",
"swaps.additional_items.refundable",
"claims.additional_items.refundable",
"shipping_total",
"discount_total",
"tax_total",
@@ -108,7 +108,7 @@ export default async (req, res) => {
case "started": {
const { key, error } = await idempotencyKeyService.workStage(
idempotencyKey.idempotency_key,
async (manager) => {
async manager => {
const order = await orderService
.withTransaction(manager)
.retrieve(value.order_id, {
@@ -163,7 +163,7 @@ export default async (req, res) => {
case "swap_created": {
const { key, error } = await idempotencyKeyService.workStage(
idempotencyKey.idempotency_key,
async (manager) => {
async manager => {
const swaps = await swapService.list({
idempotency_key: idempotencyKey.idempotency_key,
})
+32 -30
View File
@@ -5,7 +5,7 @@ import { InventoryServiceMock } from "../__mocks__/inventory"
const eventBusService = {
emit: jest.fn(),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -161,7 +161,7 @@ describe("SwapService", () => {
const cartService = {
create: jest.fn().mockReturnValue(Promise.resolve({ id: "cart" })),
update: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -171,10 +171,10 @@ describe("SwapService", () => {
})
const lineItemService = {
create: jest.fn().mockImplementation(d => Promise.resolve(d)),
update: jest.fn().mockImplementation(d => Promise.resolve(d)),
create: jest.fn().mockImplementation((d) => Promise.resolve(d)),
update: jest.fn().mockImplementation((d) => Promise.resolve(d)),
retrieve: () => Promise.resolve({}),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -199,6 +199,8 @@ describe("SwapService", () => {
"order.swaps.additional_items",
"order.discounts",
"order.discounts.rule",
"order.claims",
"order.claims.additional_items",
"additional_items",
"return_order",
"return_order.items",
@@ -304,7 +306,7 @@ describe("SwapService", () => {
const swapRepo = MockRepository()
const returnService = {
create: jest.fn().mockReturnValue(Promise.resolve({ id: "ret" })),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -401,7 +403,7 @@ describe("SwapService", () => {
receiveReturn: jest
.fn()
.mockReturnValue(Promise.resolve({ test: "received" })),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -447,7 +449,7 @@ describe("SwapService", () => {
receiveReturn: jest
.fn()
.mockReturnValue(Promise.resolve({ status: "requires_action" })),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -525,7 +527,7 @@ describe("SwapService", () => {
{ items: [{ item_id: "1234", quantity: 2 }], data: "new" },
])
),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -546,7 +548,7 @@ describe("SwapService", () => {
const lineItemService = {
update: jest.fn(),
retrieve: () => Promise.resolve({}),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -621,11 +623,11 @@ describe("SwapService", () => {
describe("cancelFulfillment", () => {
const swapRepo = MockRepository({
findOneWithRelations: () => Promise.resolve({}),
save: f => Promise.resolve(f),
save: (f) => Promise.resolve(f),
})
const fulfillmentService = {
cancelFulfillment: jest.fn().mockImplementation(f => {
cancelFulfillment: jest.fn().mockImplementation((f) => {
switch (f) {
case IdMap.getId("no-swap"):
return Promise.resolve({})
@@ -635,7 +637,7 @@ describe("SwapService", () => {
})
}
}),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -689,14 +691,14 @@ describe("SwapService", () => {
data: "new",
})
}),
withTransaction: function() {
withTransaction: function () {
return this
},
}
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -737,14 +739,14 @@ describe("SwapService", () => {
const lineItemService = {
update: jest.fn(),
retrieve: () => Promise.resolve({}),
withTransaction: function() {
withTransaction: function () {
return this
},
}
const cartService = {
update: jest.fn(),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -820,7 +822,7 @@ describe("SwapService", () => {
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -835,7 +837,7 @@ describe("SwapService", () => {
updateShippingMethod: () => {
return Promise.resolve()
},
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -844,7 +846,7 @@ describe("SwapService", () => {
update: () => {
return Promise.resolve()
},
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -859,14 +861,14 @@ describe("SwapService", () => {
cancelPayment: jest.fn(() => {
return Promise.resolve()
}),
withTransaction: function() {
withTransaction: function () {
return this
},
}
const inventoryService = {
...InventoryServiceMock,
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -987,19 +989,19 @@ describe("SwapService", () => {
describe("success", () => {
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
withTransaction: function () {
return this
},
}
const paymentProviderService = {
capturePayment: jest.fn(g =>
capturePayment: jest.fn((g) =>
g.id === "good" ? Promise.resolve() : Promise.reject()
),
refundPayment: jest.fn(g =>
refundPayment: jest.fn((g) =>
g[0].id === "good" ? Promise.resolve() : Promise.reject()
),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -1127,7 +1129,7 @@ describe("SwapService", () => {
const eventBusService = {
emit: jest.fn().mockReturnValue(Promise.resolve()),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -1190,7 +1192,7 @@ describe("SwapService", () => {
const paymentProviderService = {
cancelPayment: jest.fn(() => Promise.resolve({})),
withTransaction: function() {
withTransaction: function () {
return this
},
}
@@ -1222,7 +1224,7 @@ describe("SwapService", () => {
return Promise.resolve(swap)
}
},
save: f => f,
save: (f) => f,
})
const swapService = new SwapService({
@@ -1271,7 +1273,7 @@ describe("SwapService", () => {
it.each([["fail-refund-1"], ["fail-refund-2"], ["fail-refund-3"]])(
"fails to cancel swap when contains refund",
async input => {
async (input) => {
await expect(swapService.cancel(IdMap.getId(input))).rejects.toThrow(
"Swap with a refund cannot be canceled"
)
+19
View File
@@ -286,6 +286,7 @@ class OrderService extends BaseService {
"refundable_amount",
"items.refundable",
"swaps.additional_items.refundable",
"claims.additional_items.refundable",
]
const totalsToSelect = select.filter((v) => totalFields.includes(v))
@@ -294,6 +295,8 @@ class OrderService extends BaseService {
relationSet.add("items")
relationSet.add("swaps")
relationSet.add("swaps.additional_items")
relationSet.add("claims")
relationSet.add("claims.additional_items")
relationSet.add("discounts")
relationSet.add("discounts.rule")
relationSet.add("discounts.rule.valid_for")
@@ -1407,6 +1410,22 @@ class OrderService extends BaseService {
}
}
if (
totalsFields.includes("claims.additional_items.refundable") &&
order.claims &&
order.claims.length
) {
for (const c of order.claims) {
c.additional_items = c.additional_items.map((i) => ({
...i,
refundable: this.totalsService_.getLineItemRefund(order, {
...i,
quantity: i.quantity - (i.returned_quantity || 0),
}),
}))
}
}
return order
}
+23 -6
View File
@@ -93,6 +93,12 @@ class ReturnService extends BaseService {
}
}
if (order.claims && order.claims.length) {
for (const c of order.claims) {
merged = [...merged, ...c.additional_items]
}
}
const toReturn = await Promise.all(
items.map(async data => {
const item = merged.find(i => i.id === data.item_id)
@@ -325,7 +331,13 @@ class ReturnService extends BaseService {
.withTransaction(manager)
.retrieve(orderId, {
select: ["refunded_total", "total", "refundable_amount"],
relations: ["swaps", "swaps.additional_items", "items"],
relations: [
"swaps",
"swaps.additional_items",
"claims",
"claims.additional_items",
"items",
],
})
const returnLines = await this.getFulfillmentItems_(
@@ -487,13 +499,18 @@ class ReturnService extends BaseService {
* @param {string[]} lineItems - the line items to return
* @return {Promise} the result of the update operation
*/
async receive(returnId, receivedItems, refundAmount, allowMismatch = false) {
async receive(
return_id,
received_items,
refund_amount,
allow_mismatch = false
) {
return this.atomicPhase_(async manager => {
const returnRepository = manager.getCustomRepository(
this.returnRepository_
)
const returnObj = await this.retrieve(returnId, {
const returnObj = await this.retrieve(return_id, {
relations: ["items", "swap", "swap.additional_items"],
})
@@ -537,7 +554,7 @@ class ReturnService extends BaseService {
const returnLines = await this.getFulfillmentItems_(
order,
receivedItems,
received_items,
this.validateReturnLineItem_
)
@@ -566,12 +583,12 @@ class ReturnService extends BaseService {
let returnStatus = "received"
const isMatching = newLines.every(l => l.is_requested)
if (!isMatching && !allowMismatch) {
if (!isMatching && !allow_mismatch) {
// Should update status
returnStatus = "requires_action"
}
const totalRefundableAmount = refundAmount || returnObj.refund_amount
const totalRefundableAmount = refund_amount || returnObj.refund_amount
const now = new Date()
const updateObj = {
+29 -23
View File
@@ -116,7 +116,7 @@ class SwapService extends BaseService {
"cart.total",
]
const totalsToSelect = select.filter(v => totalFields.includes(v))
const totalsToSelect = select.filter((v) => totalFields.includes(v))
if (totalsToSelect.length > 0) {
const relationSet = new Set(relations)
relationSet.add("cart")
@@ -127,7 +127,7 @@ class SwapService extends BaseService {
relationSet.add("cart.region")
relations = [...relationSet]
select = select.filter(v => !totalFields.includes(v))
select = select.filter((v) => !totalFields.includes(v))
}
return {
@@ -170,9 +170,8 @@ class SwapService extends BaseService {
const validatedId = this.validateId_(id)
const { totalsToSelect, ...newConfig } = this.transformQueryForTotals_(
config
)
const { totalsToSelect, ...newConfig } =
this.transformQueryForTotals_(config)
const query = this.buildQuery_({ id: validatedId }, newConfig)
@@ -251,7 +250,7 @@ class SwapService extends BaseService {
*/
validateReturnItems_(order, returnItems) {
return returnItems.map(({ item_id, quantity }) => {
const item = order.items.find(i => i.id === item_id)
const item = order.items.find((i) => i.id === item_id)
// The item must exist in the order
if (!item) {
@@ -303,7 +302,7 @@ class SwapService extends BaseService {
}
) {
const { no_notification, ...rest } = custom
return this.atomicPhase_(async manager => {
return this.atomicPhase_(async (manager) => {
if (
order.fulfillment_status === "not_fulfilled" ||
order.payment_status !== "captured"
@@ -318,7 +317,6 @@ class SwapService extends BaseService {
const line = await this.lineItemService_.retrieve(item.item_id, {
relations: ["order", "swap", "claim_order"],
})
console.log(line)
if (
line.order?.canceled_at ||
@@ -377,7 +375,7 @@ class SwapService extends BaseService {
}
async processDifference(swapId) {
return this.atomicPhase_(async manager => {
return this.atomicPhase_(async (manager) => {
const swap = await this.retrieve(swapId, {
relations: ["payment", "order", "order.payments"],
})
@@ -493,7 +491,7 @@ class SwapService extends BaseService {
}
async update(swapId, update) {
return this.atomicPhase_(async manager => {
return this.atomicPhase_(async (manager) => {
const swap = await this.retrieve(swapId)
if ("metadata" in update) {
@@ -525,7 +523,7 @@ class SwapService extends BaseService {
* the new cart.
*/
async createCart(swapId) {
return this.atomicPhase_(async manager => {
return this.atomicPhase_(async (manager) => {
const swap = await this.retrieve(swapId, {
relations: [
"order",
@@ -534,6 +532,8 @@ class SwapService extends BaseService {
"order.swaps.additional_items",
"order.discounts",
"order.discounts.rule",
"order.claims",
"order.claims.additional_items",
"additional_items",
"return_order",
"return_order.items",
@@ -607,7 +607,13 @@ class SwapService extends BaseService {
}
}
const lineItem = allItems.find(i => i.id === r.item_id)
if (order.claims && order.claims.length) {
for (const c of order.claims) {
allItems = [...allItems, ...c.additional_items]
}
}
const lineItem = allItems.find((i) => i.id === r.item_id)
const toCreate = {
cart_id: cart.id,
@@ -638,7 +644,7 @@ class SwapService extends BaseService {
*
*/
async registerCartCompletion(swapId) {
return this.atomicPhase_(async manager => {
return this.atomicPhase_(async (manager) => {
const swap = await this.retrieve(swapId, {
relations: [
"cart",
@@ -770,7 +776,7 @@ class SwapService extends BaseService {
* status.
*/
async receiveReturn(swapId, returnItems) {
return this.atomicPhase_(async manager => {
return this.atomicPhase_(async (manager) => {
const swap = await this.retrieve(swapId, { relations: ["return_order"] })
if (swap.canceled_at) {
@@ -811,7 +817,7 @@ class SwapService extends BaseService {
* @returns {Promise<Swap>} the canceled swap.
*/
async cancel(swapId) {
return this.atomicPhase_(async manager => {
return this.atomicPhase_(async (manager) => {
const swap = await this.retrieve(swapId, {
relations: ["payment", "fulfillments", "return_order"],
})
@@ -877,7 +883,7 @@ class SwapService extends BaseService {
) {
const { metadata, no_notification } = config
return this.atomicPhase_(async manager => {
return this.atomicPhase_(async (manager) => {
const swap = await this.retrieve(swapId, {
relations: [
"payment",
@@ -937,7 +943,7 @@ class SwapService extends BaseService {
is_swap: true,
no_notification: evaluatedNoNotification,
},
swap.additional_items.map(i => ({
swap.additional_items.map((i) => ({
item_id: i.id,
quantity: i.quantity,
})),
@@ -954,7 +960,7 @@ class SwapService extends BaseService {
// Update all line items to reflect fulfillment
for (const item of swap.additional_items) {
const fulfillmentItem = successfullyFulfilled.find(
f => item.id === f.item_id
(f) => item.id === f.item_id
)
if (fulfillmentItem) {
@@ -999,7 +1005,7 @@ class SwapService extends BaseService {
* @returns updated swap
*/
async cancelFulfillment(fulfillmentId) {
return this.atomicPhase_(async manager => {
return this.atomicPhase_(async (manager) => {
const canceled = await this.fulfillmentService_
.withTransaction(manager)
.cancelFulfillment(fulfillmentId)
@@ -1042,7 +1048,7 @@ class SwapService extends BaseService {
) {
const { metadata, no_notification } = config
return this.atomicPhase_(async manager => {
return this.atomicPhase_(async (manager) => {
const swap = await this.retrieve(swapId, {
relations: ["additional_items"],
})
@@ -1068,7 +1074,7 @@ class SwapService extends BaseService {
// Go through all the additional items in the swap
for (const i of swap.additional_items) {
const shipped = shipment.items.find(si => si.item_id === i.id)
const shipped = shipment.items.find((si) => si.item_id === i.id)
if (shipped) {
const shippedQty = (i.shipped_quantity || 0) + shipped.quantity
await this.lineItemService_.withTransaction(manager).update(i.id, {
@@ -1117,7 +1123,7 @@ class SwapService extends BaseService {
const keyPath = `metadata.${key}`
return this.swapModel_
.updateOne({ _id: validatedId }, { $unset: { [keyPath]: "" } })
.catch(err => {
.catch((err) => {
throw new MedusaError(MedusaError.Types.DB_ERROR, err.message)
})
}
@@ -1130,7 +1136,7 @@ class SwapService extends BaseService {
* @returns {Promise<Order>} the resulting order
*/
async registerReceived(id) {
return this.atomicPhase_(async manager => {
return this.atomicPhase_(async (manager) => {
const swap = await this.retrieve(id, {
relations: ["return_order", "return_order.items"],
})
+14
View File
@@ -1,6 +1,7 @@
import _ from "lodash"
import { BaseService } from "medusa-interfaces"
import { MedusaError } from "medusa-core-utils"
import carts from "../api/routes/store/carts"
/**
* A service that calculates total and subtotals for orders, carts etc..
@@ -158,6 +159,13 @@ class TotalsService extends BaseService {
}
}
if (order.claims && order.claims.length) {
for (const c of order.claims) {
const claimItemIds = c.additional_items.map(el => el.id)
itemIds = [...itemIds, ...claimItemIds]
}
}
const refunds = lineItems.map(i => {
if (!itemIds.includes(i.id)) {
throw new MedusaError(
@@ -253,6 +261,12 @@ class TotalsService extends BaseService {
}
}
if (cart.claims && cart.claims.length) {
for (const c of cart.claims) {
merged = [...merged, ...c.additional_items]
}
}
const { type, allocation, value } = discount.rule
if (allocation === "total") {
let percentage = 0