Files
medusa-store/integration-tests/http/__tests__/claims/claims.spec.ts
Stevche Radevski 702d338284 fix: Minor fixes and cleanup to the payments setup (#11356)
This PR adds a couple new statuses to the payment collection and payment webhook results. The payment collection will now be marked as "completed" once the captured amount is the full amount of the payment collection.

There are several things left to improve the payment setup, so non-happy-path cases are handled correctly.
1. Currently the payment session and payment models serve a very similar purpose. Part of the information is found on one, and the other part on the other model, without any clear reason for doing so. We can simplify the payment module and the data models simply by merging the two.
2. We need to handle failures more gracefully, such as setting the payment session status to failed when such a webhook comes in.
3. We should convert the payment collection status and the different amounts to calculated fields from the payment session, captures, and refunds, as they can easily be a source of inconsistencies.
2025-02-09 15:42:02 +00:00

1408 lines
38 KiB
TypeScript

import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
import {
ClaimReason,
ClaimType,
ContainerRegistrationKeys,
Modules,
RuleOperator,
} from "@medusajs/utils"
import {
adminHeaders,
createAdminUser,
} from "../../../helpers/create-admin-user"
import { setupTaxStructure } from "../../../modules/__tests__/fixtures"
jest.setTimeout(30000)
medusaIntegrationTestRunner({
testSuite: ({ dbConnection, getContainer, api }) => {
let baseClaim
let order, order2
let returnShippingOption
let outboundShippingOption
let shippingProfile
let fulfillmentSet
let returnReason
let inventoryItem
let inventoryItemExtra
let location
let productExtra
let item
const shippingProviderId = "manual_test-provider"
beforeEach(async () => {
const container = getContainer()
await createAdminUser(dbConnection, adminHeaders, container)
shippingProfile = (
await api.post(
`/admin/shipping-profiles`,
{
name: "Test",
type: "default",
},
adminHeaders
)
).data.shipping_profile
const region = (
await api.post(
"/admin/regions",
{
name: "test-region",
currency_code: "usd",
},
adminHeaders
)
).data.region
const customer = (
await api.post(
"/admin/customers",
{
first_name: "joe",
email: "joe@admin.com",
},
adminHeaders
)
).data.customer
const salesChannel = (
await api.post(
"/admin/sales-channels",
{
name: "Test channel",
},
adminHeaders
)
).data.sales_channel
const product = (
await api.post(
"/admin/products",
{
title: "Test product",
options: [{ title: "size", values: ["large", "small"] }],
shipping_profile_id: shippingProfile.id,
variants: [
{
title: "Test variant",
sku: "test-variant",
options: { size: "large" },
prices: [
{
currency_code: "usd",
amount: 10,
},
],
},
],
},
adminHeaders
)
).data.product
productExtra = (
await api.post(
"/admin/products",
{
title: "Extra product",
options: [{ title: "size", values: ["large", "small"] }],
shipping_profile_id: shippingProfile.id,
variants: [
{
title: "my variant",
sku: "variant-sku",
options: { size: "large" },
prices: [
{
currency_code: "usd",
amount: 50.25,
},
],
},
],
},
adminHeaders
)
).data.product
returnReason = (
await api.post(
"/admin/return-reasons",
{
value: "return-reason-test",
label: "Test return reason",
},
adminHeaders
)
).data.return_reason
const orderModule = container.resolve(Modules.ORDER)
order = await orderModule.createOrders({
region_id: region.id,
email: "foo@bar.com",
items: [
{
title: "Custom Item 2",
variant_id: product.variants[0].id,
quantity: 2,
unit_price: 25,
},
],
sales_channel_id: salesChannel.id,
shipping_address: {
first_name: "Test",
last_name: "Test",
address_1: "Test",
city: "Test",
country_code: "US",
postal_code: "12345",
phone: "12345",
},
billing_address: {
first_name: "Test",
last_name: "Test",
address_1: "Test",
city: "Test",
country_code: "US",
postal_code: "12345",
},
shipping_methods: [
{
name: "Test shipping method",
amount: 10,
data: {},
tax_lines: [
{
description: "shipping Tax 1",
tax_rate_id: "tax_usa_shipping",
code: "code",
rate: 10,
},
],
},
],
currency_code: "usd",
customer_id: customer.id,
transactions: [
{
amount: 61,
currency_code: "usd",
},
],
})
order2 = await orderModule.createOrders({
region_id: region.id,
email: "foo@bar2.com",
items: [
{
title: "Custom Iasdasd2",
quantity: 1,
unit_price: 20,
},
],
sales_channel_id: salesChannel.id,
shipping_address: {
first_name: "Test",
last_name: "Test",
address_1: "Test",
city: "Test",
country_code: "US",
postal_code: "12345",
phone: "12345",
},
billing_address: {
first_name: "Test",
last_name: "Test",
address_1: "Test",
city: "Test",
country_code: "US",
postal_code: "12345",
},
currency_code: "usd",
customer_id: customer.id,
})
location = (
await api.post(
`/admin/stock-locations`,
{
name: "Test location",
},
adminHeaders
)
).data.stock_location
location = (
await api.post(
`/admin/stock-locations/${location.id}/fulfillment-sets?fields=*fulfillment_sets`,
{
name: "Test",
type: "test-type",
},
adminHeaders
)
).data.stock_location
fulfillmentSet = (
await api.post(
`/admin/fulfillment-sets/${location.fulfillment_sets[0].id}/service-zones`,
{
name: "Test",
geo_zones: [{ type: "country", country_code: "us" }],
},
adminHeaders
)
).data.fulfillment_set
inventoryItem = (
await api.get(`/admin/inventory-items?sku=test-variant`, adminHeaders)
).data.inventory_items[0]
await api.post(
`/admin/inventory-items/${inventoryItem.id}/location-levels`,
{
location_id: location.id,
stocked_quantity: 10,
},
adminHeaders
)
inventoryItemExtra = (
await api.get(`/admin/inventory-items?sku=variant-sku`, adminHeaders)
).data.inventory_items[0]
await api.post(
`/admin/inventory-items/${inventoryItemExtra.id}/location-levels`,
{
location_id: location.id,
stocked_quantity: 10,
},
adminHeaders
)
const remoteLink = container.resolve(
ContainerRegistrationKeys.REMOTE_LINK
)
await remoteLink.create([
{
[Modules.STOCK_LOCATION]: {
stock_location_id: location.id,
},
[Modules.FULFILLMENT]: {
fulfillment_provider_id: shippingProviderId,
},
},
{
[Modules.STOCK_LOCATION]: {
stock_location_id: location.id,
},
[Modules.FULFILLMENT]: {
fulfillment_set_id: fulfillmentSet.id,
},
},
{
[Modules.SALES_CHANNEL]: {
sales_channel_id: salesChannel.id,
},
[Modules.STOCK_LOCATION]: {
stock_location_id: location.id,
},
},
{
[Modules.PRODUCT]: {
variant_id: product.variants[0].id,
},
[Modules.INVENTORY]: {
inventory_item_id: inventoryItem.id,
},
},
{
[Modules.PRODUCT]: {
variant_id: productExtra.variants[0].id,
},
[Modules.INVENTORY]: {
inventory_item_id: inventoryItemExtra.id,
},
},
])
const shippingOptionPayload = {
name: "Return shipping",
service_zone_id: fulfillmentSet.service_zones[0].id,
shipping_profile_id: shippingProfile.id,
provider_id: shippingProviderId,
price_type: "flat",
type: {
label: "Test type",
description: "Test description",
code: "test-code",
},
prices: [
{
currency_code: "usd",
amount: 15,
},
],
rules: [
{
operator: RuleOperator.EQ,
attribute: "is_return",
value: "true",
},
],
}
const outboundShippingOptionPayload = {
name: "Oubound shipping",
service_zone_id: fulfillmentSet.service_zones[0].id,
shipping_profile_id: shippingProfile.id,
provider_id: shippingProviderId,
price_type: "flat",
type: {
label: "Test type",
description: "Test description",
code: "test-code",
},
prices: [
{
currency_code: "usd",
amount: 20,
},
],
rules: [
{
operator: RuleOperator.EQ,
attribute: "is_return",
value: "false",
},
{
operator: RuleOperator.EQ,
attribute: "enabled_in_store",
value: "true",
},
],
}
returnShippingOption = (
await api.post(
"/admin/shipping-options",
shippingOptionPayload,
adminHeaders
)
).data.shipping_option
outboundShippingOption = (
await api.post(
"/admin/shipping-options",
outboundShippingOptionPayload,
adminHeaders
)
).data.shipping_option
item = order.items[0]
await setupTaxStructure(container.resolve(Modules.TAX))
})
describe("Claims lifecycle", () => {
let claimId
describe("with accurate order summary", () => {
it("should verify order summary at each level", async () => {
/* Case:
Purchased:
items: {
unit_price: 25,
qty: 2
tax_total: 0
total: 50
}
shipping_methods: {
unit_price: 10,
qty: 1
tax_total: 1
total: 11
}
*/
const orderResult = (
await api.get(`/admin/orders/${order.id}`, adminHeaders)
).data.order
expect(orderResult.summary).toEqual(
expect.objectContaining({
paid_total: 61,
difference_sum: 0,
refunded_total: 0,
transaction_total: 61,
pending_difference: 0,
current_order_total: 61,
original_order_total: 61,
})
)
/* TODO: Check summary after each of these events in order
- Add payment collection + payment + capture
- Fulfill items
- Submit inbound claim
- Fulfill claim items
- Make payment
- Submit outbound claim
- Make payment
- Fulfill claim items
*/
})
})
describe("with inbound and outbound items", () => {
beforeEach(async () => {
await api.post(
`/admin/orders/${order.id}/fulfillments`,
{
items: [
{
id: item.id,
quantity: 2,
},
],
},
adminHeaders
)
await api.post(
`/admin/orders/${order2.id}/fulfillments`,
{
items: [
{
id: order2.items[0].id,
quantity: 1,
},
],
},
adminHeaders
)
baseClaim = (
await api.post(
"/admin/claims",
{
order_id: order.id,
type: ClaimType.REPLACE,
description: "Base claim",
},
adminHeaders
)
).data.claim
let r2 = await api.post(
"/admin/claims",
{
order_id: order2.id,
type: ClaimType.REFUND,
},
adminHeaders
)
const claimId2 = r2.data.claim.id
const item2 = order2.items[0]
const {
data: {
order_preview: {
items: [previewItem],
},
},
} = await api.post(
`/admin/claims/${claimId2}/inbound/items`,
{ items: [{ id: item2.id, quantity: 1 }] },
adminHeaders
)
// Delete & recreate again to ensure it works for both delete and create
await api.delete(
`/admin/claims/${claimId2}/inbound/items/${previewItem.actions[0].id}`,
adminHeaders
)
const {
data: { return: returnData },
} = await api.post(
`/admin/claims/${claimId2}/inbound/items`,
{ items: [{ id: item2.id, quantity: 1 }] },
adminHeaders
)
await api.post(
`/admin/returns/${returnData.id}`,
{
location_id: location.id,
no_notification: true,
},
adminHeaders
)
const {
data: {
order_preview: { shipping_methods: inboundShippingMethods },
},
} = await api.post(
`/admin/claims/${claimId2}/inbound/shipping-method`,
{ shipping_option_id: returnShippingOption.id },
adminHeaders
)
const inboundShippingMethod = inboundShippingMethods.find(
(m) => m.shipping_option_id == returnShippingOption.id
)
// Delete & recreate again to ensure it works for both delete and create
await api.delete(
`/admin/claims/${claimId2}/inbound/shipping-method/${inboundShippingMethod.actions[0].id}`,
adminHeaders
)
await api.post(
`/admin/claims/${claimId2}/inbound/shipping-method`,
{ shipping_option_id: returnShippingOption.id },
adminHeaders
)
const testRes = await api.post(
`/admin/claims/${claimId2}/request`,
{},
adminHeaders
)
claimId = baseClaim.id
item = order.items[0]
let result = await api.post(
`/admin/claims/${claimId}/inbound/items`,
{
items: [
{
id: item.id,
reason_id: returnReason.id,
quantity: 2,
},
],
},
adminHeaders
)
await api.post(
`/admin/claims/${claimId}/inbound/shipping-method`,
{ shipping_option_id: returnShippingOption.id },
adminHeaders
)
// shipping Options w/ custom price
const {
data: {
order_preview: { shipping_methods: outboundShippingMethods },
},
} = await api.post(
`/admin/claims/${claimId}/outbound/shipping-method`,
{
shipping_option_id: outboundShippingOption.id,
custom_amount: 12.5,
},
adminHeaders
)
const outboundShippingMethod = outboundShippingMethods.find(
(m) => m.shipping_option_id == outboundShippingOption.id
)
expect(outboundShippingMethod.subtotal).toBe(12.5)
expect(outboundShippingMethod.is_custom_amount).toBe(true)
// Reset shipping custom price
const {
data: {
order_preview: { shipping_methods: outboundShippingMethods2 },
},
} = await api.post(
`/admin/claims/${claimId}/outbound/shipping-method/${outboundShippingMethod.actions[0].id}`,
{
custom_amount: null,
},
adminHeaders
)
const outboundShippingMethodReset = outboundShippingMethods2.find(
(m) => m.shipping_option_id == outboundShippingOption.id
)
expect(outboundShippingMethodReset.subtotal).toBe(20)
expect(outboundShippingMethodReset.is_custom_amount).toBe(false)
// Delete & recreate again to ensure it works for both delete and create
await api.delete(
`/admin/claims/${claimId}/outbound/shipping-method/${outboundShippingMethodReset.actions[0].id}`,
adminHeaders
)
await api.post(
`/admin/claims/${claimId}/outbound/shipping-method`,
{ shipping_option_id: outboundShippingOption.id },
adminHeaders
)
// updated the requested quantity
const updateReturnItemActionId =
result.data.order_preview.items[0].actions[0].id
result = await api.post(
`/admin/claims/${claimId}/inbound/items/${updateReturnItemActionId}`,
{
quantity: 1,
},
adminHeaders
)
// New Items
await api.post(
`/admin/claims/${claimId}/outbound/items`,
{
items: [
{
variant_id: productExtra.variants[0].id,
quantity: 2,
},
],
},
adminHeaders
)
// Claim Items
await api.post(
`/admin/claims/${claimId}/claim-items`,
{
items: [
{
id: item.id,
reason: ClaimReason.PRODUCTION_FAILURE,
quantity: 1,
},
],
},
adminHeaders
)
result = await api.post(
`/admin/claims/${claimId}/request`,
{},
adminHeaders
)
result = (
await api.get(
`/admin/claims?fields=*claim_items,*additional_items`,
adminHeaders
)
).data.claims
expect(result).toHaveLength(2)
expect(result[0].additional_items).toHaveLength(1)
expect(result[0].claim_items).toHaveLength(1)
expect(result[0].canceled_at).toBeNull()
const reservationsResponse = (
await api.get(
`/admin/reservations?location_id[]=${location.id}`,
adminHeaders
)
).data
expect(reservationsResponse.reservations).toHaveLength(1)
})
it("should complete flow with fulfilled items successfully", async () => {
const fulfillOrder = (
await api.get(`/admin/orders/${order.id}`, adminHeaders)
).data.order
const paymentCollections = fulfillOrder.payment_collections
expect(paymentCollections).toHaveLength(1)
expect(paymentCollections[0]).toEqual(
expect.objectContaining({
status: "not_paid",
amount: 109.5,
currency_code: "usd",
})
)
const fulfillableItem = fulfillOrder.items.find(
(item) => item.detail.fulfilled_quantity === 0
)
await api.post(
`/admin/orders/${order.id}/fulfillments`,
{
location_id: location.id,
items: [{ id: fulfillableItem.id, quantity: 1 }],
},
adminHeaders
)
})
it("should go through cancel flow successfully", async () => {
await api.post(`/admin/claims/${claimId}/cancel`, {}, adminHeaders)
const [claim] = (
await api.get(
`/admin/claims?fields=*claim_items,*additional_items`,
adminHeaders
)
).data.claims
expect(claim.canceled_at).toBeDefined()
const reservationsResponseAfterCanceling = (
await api.get(
`/admin/reservations?location_id[]=${location.id}`,
adminHeaders
)
).data
expect(reservationsResponseAfterCanceling.reservations).toHaveLength(
0
)
})
it("should create a payment collection successfully & mark as paid", async () => {
const paymentDelta = 109.5
const orderForPayment = (
await api.get(`/admin/orders/${order.id}`, adminHeaders)
).data.order
const paymentCollections = orderForPayment.payment_collections
expect(paymentCollections).toHaveLength(1)
expect(paymentCollections[0]).toEqual(
expect.objectContaining({
status: "not_paid",
amount: paymentDelta,
currency_code: "usd",
})
)
const createdPaymentCollection = (
await api.post(
`/admin/payment-collections`,
{ order_id: order.id, amount: 100 },
adminHeaders
)
).data.payment_collection
expect(createdPaymentCollection).toEqual(
expect.objectContaining({
currency_code: "usd",
amount: 100,
status: "not_paid",
})
)
const deleted = (
await api.delete(
`/admin/payment-collections/${createdPaymentCollection.id}`,
adminHeaders
)
).data
expect(deleted).toEqual({
id: createdPaymentCollection.id,
object: "payment-collection",
deleted: true,
})
const finalPaymentCollection = (
await api.post(
`/admin/payment-collections/${paymentCollections[0].id}/mark-as-paid`,
{ order_id: order.id },
adminHeaders
)
).data.payment_collection
expect(finalPaymentCollection).toEqual(
expect.objectContaining({
currency_code: "usd",
amount: paymentDelta,
status: "completed",
authorized_amount: paymentDelta,
captured_amount: paymentDelta,
refunded_amount: 0,
})
)
})
})
describe("with only outbound items", () => {
let orderResult
beforeEach(async () => {
await api.post(
`/admin/orders/${order.id}/fulfillments`,
{
items: [
{
id: item.id,
quantity: 2,
},
],
},
adminHeaders
)
await api.post(
`/admin/orders/${order2.id}/fulfillments`,
{
items: [
{
id: order2.items[0].id,
quantity: 1,
},
],
},
adminHeaders
)
baseClaim = (
await api.post(
"/admin/claims",
{
order_id: order.id,
type: ClaimType.REPLACE,
description: "Base claim",
},
adminHeaders
)
).data.claim
claimId = baseClaim.id
item = order.items[0]
const {
data: {
order_preview: { shipping_methods: outboundShippingMethods },
},
} = await api.post(
`/admin/claims/${claimId}/outbound/shipping-method`,
{ shipping_option_id: outboundShippingOption.id },
adminHeaders
)
const outboundShippingMethod = outboundShippingMethods.find(
(m) => m.shipping_option_id == outboundShippingOption.id
)
// Delete & recreate again to ensure it works for both delete and create
await api.delete(
`/admin/claims/${claimId}/outbound/shipping-method/${outboundShippingMethod.actions[0].id}`,
adminHeaders
)
await api.post(
`/admin/claims/${claimId}/outbound/shipping-method`,
{ shipping_option_id: outboundShippingOption.id },
adminHeaders
)
const { data } = await api.post(
`/admin/claims/${claimId}/outbound/items`,
{
items: [
{
variant_id: productExtra.variants[0].id,
quantity: 3,
},
],
},
adminHeaders
)
await api.post(
`/admin/claims/${claimId}/claim-items`,
{
items: [
{
id: item.id,
reason: ClaimReason.PRODUCTION_FAILURE,
quantity: 1,
},
],
},
adminHeaders
)
})
it("should complete flow with fulfilled items successfully", async () => {
await api.post(`/admin/claims/${claimId}/request`, {}, adminHeaders)
const claim = (
await api.get(
`/admin/claims/${claimId}?fields=*claim_items,*additional_items`,
adminHeaders
)
).data.claim
expect(claim.additional_items).toHaveLength(1)
expect(claim.claim_items).toHaveLength(1)
expect(claim.canceled_at).toBeNull()
const fulfillOrder = (
await api.get(`/admin/orders/${order.id}`, adminHeaders)
).data.order
const fulfillableItem = fulfillOrder.items.filter(
(item) => item.detail.fulfilled_quantity === 0
)
await api.post(
`/admin/orders/${order.id}/fulfillments`,
{
location_id: location.id,
items: [{ id: fulfillableItem[0].id, quantity: 1 }],
},
adminHeaders
)
orderResult = (
await api.get(`/admin/orders/${order.id}`, adminHeaders)
).data.order
expect(orderResult.fulfillment_status).toEqual("partially_fulfilled")
await api.post(
`/admin/orders/${order.id}/fulfillments`,
{
location_id: location.id,
items: [{ id: fulfillableItem[0].id, quantity: 2 }],
},
adminHeaders
)
orderResult = (
await api.get(
`/admin/orders/${order.id}?fields=*fulfillments,*fulfillments.items`,
adminHeaders
)
).data.order
expect(orderResult.fulfillment_status).toEqual("fulfilled")
await api.post(
`admin/orders/${order.id}/fulfillments/${orderResult.fulfillments[0].id}/shipments`,
{
items: orderResult.fulfillments[0]?.items?.map((i) => ({
id: i.line_item_id,
quantity: i.quantity,
})),
},
adminHeaders
)
orderResult = (
await api.get(
`/admin/orders/${order.id}?fields=*fulfillments,*fulfillments.items`,
adminHeaders
)
).data.order
expect(orderResult.fulfillment_status).toEqual("partially_shipped")
await api.post(
`admin/orders/${order.id}/fulfillments/${orderResult.fulfillments[1].id}/shipments`,
{
items: orderResult.fulfillments[1]?.items?.map((i) => ({
id: i.line_item_id,
quantity: i.quantity,
})),
},
adminHeaders
)
await api.post(
`admin/orders/${order.id}/fulfillments/${orderResult.fulfillments[2].id}/shipments`,
{
items: orderResult.fulfillments[2]?.items?.map((i) => ({
id: i.line_item_id,
quantity: i.quantity,
})),
},
adminHeaders
)
orderResult = (
await api.get(
`/admin/orders/${order.id}?fields=*fulfillments`,
adminHeaders
)
).data.order
expect(orderResult.fulfillment_status).toEqual("shipped")
})
it("should remove outbound shipping method when outbound items are completely removed", async () => {
orderResult = (
await api.get(`/admin/orders/${order.id}/preview`, adminHeaders)
).data.order
const claimItems = orderResult.items.filter(
(item) =>
!!item.actions?.find((action) => action.action === "ITEM_ADD")
)
const claimShippingMethods = orderResult.shipping_methods.filter(
(item) =>
!!item.actions?.find((action) => action.action === "SHIPPING_ADD")
)
expect(claimItems).toHaveLength(1)
expect(claimShippingMethods).toHaveLength(1)
await api.delete(
`/admin/claims/${claimId}/outbound/items/${claimItems[0].actions[0].id}`,
adminHeaders
)
orderResult = (
await api.get(`/admin/orders/${order.id}/preview`, adminHeaders)
).data.order
const updatedClaimItems = orderResult.items.filter(
(item) =>
!!item.actions?.find((action) => action.action === "ITEM_ADD")
)
const updatedClaimShippingMethods =
orderResult.shipping_methods.filter(
(item) =>
!!item.actions?.find(
(action) => action.action === "SHIPPING_ADD"
)
)
expect(updatedClaimItems).toHaveLength(0)
expect(updatedClaimShippingMethods).toHaveLength(0)
})
})
describe("with only inbound items", () => {
let orderResult
beforeEach(async () => {
await api.post(
`/admin/orders/${order.id}/fulfillments`,
{
items: [
{
id: item.id,
quantity: 2,
},
],
},
adminHeaders
)
baseClaim = (
await api.post(
"/admin/claims",
{
order_id: order.id,
type: ClaimType.REPLACE,
description: "Base claim",
},
adminHeaders
)
).data.claim
claimId = baseClaim.id
item = order.items[0]
await api.post(
`/admin/claims/${claimId}/inbound/items`,
{
items: [
{
id: item.id,
reason_id: returnReason.id,
quantity: 1,
},
],
},
adminHeaders
)
await api.post(
`/admin/claims/${claimId}/inbound/shipping-method`,
{ shipping_option_id: returnShippingOption.id },
adminHeaders
)
})
it("test inbound only", async () => {
// Claim Items
await api.post(
`/admin/claims/${claimId}/claim-items`,
{
items: [
{
id: item.id,
reason: ClaimReason.PRODUCTION_FAILURE,
quantity: 1,
},
],
},
adminHeaders
)
await api.post(`/admin/claims/${claimId}/request`, {}, adminHeaders)
const claims = (
await api.get(
`/admin/claims?fields=*claim_items,*additional_items`,
adminHeaders
)
).data.claims
expect(claims).toHaveLength(1)
expect(claims[0].additional_items).toHaveLength(0)
expect(claims[0].claim_items).toHaveLength(1)
expect(claims[0].canceled_at).toBeNull()
const orderCheck = (
await api.get(`/admin/orders/${order.id}`, adminHeaders)
).data.order
expect(orderCheck.summary).toEqual(
expect.objectContaining({
pending_difference: -11,
current_order_total: 50,
original_order_total: 60,
})
)
expect(true).toBe(true)
})
it("should remove inbound shipping method when inbound items are completely removed", async () => {
orderResult = (
await api.get(`/admin/orders/${order.id}/preview`, adminHeaders)
).data.order
const returnItems = orderResult.items.filter(
(item) =>
!!item.actions?.find((action) => action.action === "RETURN_ITEM")
)
const returnShippingMethods = orderResult.shipping_methods.filter(
(item) =>
!!item.actions?.find((action) => action.action === "SHIPPING_ADD")
)
expect(returnItems).toHaveLength(1)
expect(returnShippingMethods).toHaveLength(1)
await api.delete(
`/admin/claims/${claimId}/inbound/items/${returnItems[0].actions[0].id}`,
adminHeaders
)
orderResult = (
await api.get(`/admin/orders/${order.id}/preview`, adminHeaders)
).data.order
const updatedReturnItems = orderResult.items.filter(
(item) =>
!!item.actions?.find((action) => action.action === "RETURN_ITEM")
)
const updatedReturnShippingMethods =
orderResult.shipping_methods.filter(
(item) =>
!!item.actions?.find(
(action) => action.action === "SHIPPING_ADD"
)
)
expect(updatedReturnItems).toHaveLength(0)
expect(updatedReturnShippingMethods).toHaveLength(0)
})
})
})
describe("GET /admin/claims/:id", () => {
beforeEach(async () => {
await api.post(
`/admin/orders/${order.id}/fulfillments`,
{
items: [
{
id: item.id,
quantity: 2,
},
],
},
adminHeaders
)
await api.post(
`/admin/orders/${order2.id}/fulfillments`,
{
items: [
{
id: order2.items[0].id,
quantity: 1,
},
],
},
adminHeaders
)
baseClaim = (
await api.post(
"/admin/claims",
{
order_id: order.id,
type: ClaimType.REPLACE,
description: "Base claim",
},
adminHeaders
)
).data.claim
expect(baseClaim.created_by).toEqual(expect.any(String))
await api.post(
`/admin/claims/${baseClaim.id}/inbound/items`,
{
items: [
{
id: item.id,
reason_id: returnReason.id,
quantity: 1,
},
],
},
adminHeaders
)
await api.post(
`/admin/claims/${baseClaim.id}/inbound/shipping-method`,
{
shipping_option_id: returnShippingOption.id,
},
adminHeaders
)
// Claim Items
await api.post(
`/admin/claims/${baseClaim.id}/claim-items`,
{
items: [
{
id: item.id,
reason: ClaimReason.PRODUCTION_FAILURE,
quantity: 1,
},
],
},
adminHeaders
)
const { response } = await api.post(
`/admin/claims/${baseClaim.id}/request`,
{},
adminHeaders
)
})
it("should get an existing claim for given id", async () => {
let res = await api.get(`/admin/claims/${baseClaim.id}`, adminHeaders)
expect(res.status).toEqual(200)
expect(res.data.claim.id).toEqual(baseClaim.id)
let errorRes = await api
.get(`/admin/claims/invalid-claim-id`, adminHeaders)
.catch((e) => e)
expect(errorRes.response.status).toEqual(404)
expect(errorRes.response.data.message).toEqual(
"Claim with id: invalid-claim-id was not found"
)
})
it("should get an existing claim for given id", async () => {
let res = await api.get(`/admin/claims/${baseClaim.id}`, adminHeaders)
const keysInResponse = Object.keys(res.data.claim)
expect(res.status).toEqual(200)
expect(keysInResponse).toEqual(
expect.arrayContaining([
"id",
"created_at",
"updated_at",
"canceled_at",
"type",
"order_id",
"return_id",
"display_id",
"order_version",
"refund_amount",
"additional_items",
"claim_items",
])
)
})
it("should get claim with claim items", async () => {
let res = await api.get(
`/admin/claims/${baseClaim.id}?fields=id,*claim_items`,
adminHeaders
)
expect(res.status).toEqual(200)
expect(res.data.claim.id).toEqual(baseClaim.id)
expect(res.data.claim.claim_items).toEqual(
expect.arrayContaining([
expect.objectContaining({
item_id: item.id,
reason: ClaimReason.PRODUCTION_FAILURE,
}),
])
)
// additional items is one of the props that should be undefined
expect(res.data.claim.additional_items).toBeUndefined()
const resLineItems = await api.get(
`/admin/orders/${order.id}/line-items`,
adminHeaders
)
expect(resLineItems.data).toEqual(
expect.objectContaining({
order_items: [
expect.objectContaining({
order_id: order.id,
item_id: item.id,
version: 3,
item: expect.objectContaining({
title: "Custom Item 2",
unit_price: 25,
}),
history: {
version: {
from: 1,
to: 3,
},
},
}),
],
})
)
})
})
},
})