fix(medusa): Idempotency workStage used within transaction (#2358)
This commit is contained in:
1 parent
3c5e31c645
commit
9deec0fc3c
14 files changed
+567
-576
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
fix(medusa): Idempotency workStage used within transaction
|
||||||
@@ -25,7 +25,7 @@ describe("Claims", () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||||
dbConnection = await initDb({ cwd })
|
dbConnection = await initDb({ cwd })
|
||||||
medusaProcess = await setupServer({ cwd })
|
medusaProcess = await setupServer({ cwd, verbose: true })
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@@ -202,6 +202,54 @@ describe("Claims", () => {
|
|||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test(" should throw and not have dangling claim order upon a claim creation without reasons on claim items", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
await adminSeeder(dbConnection)
|
||||||
|
|
||||||
|
const order = await createReturnableOrder(dbConnection)
|
||||||
|
const option = await simpleShippingOptionFactory(dbConnection, {
|
||||||
|
region_id: "test-region",
|
||||||
|
})
|
||||||
|
|
||||||
|
const err = await api
|
||||||
|
.post(
|
||||||
|
`/admin/orders/${order.id}/claims`,
|
||||||
|
{
|
||||||
|
type: "replace",
|
||||||
|
shipping_methods: [
|
||||||
|
{
|
||||||
|
option_id: option.id,
|
||||||
|
price: 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
additional_items: [{ variant_id: "test-variant", quantity: 1 }],
|
||||||
|
claim_items: [
|
||||||
|
{
|
||||||
|
item_id: "test-item",
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
const claimOrders = await dbConnection.manager.query(
|
||||||
|
`SELECT *
|
||||||
|
FROM claim_order
|
||||||
|
WHERE order_id = '${order.id}'`
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(err).toBeDefined()
|
||||||
|
expect(err.response.status).toBe(400)
|
||||||
|
expect(claimOrders).toEqual([])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const createReturnableOrder = async (dbConnection, options = {}) => {
|
const createReturnableOrder = async (dbConnection, options = {}) => {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { ClaimReason, ClaimType } from "../../../../models"
|
|
||||||
import {
|
import {
|
||||||
IsArray,
|
IsArray,
|
||||||
IsBoolean,
|
IsBoolean,
|
||||||
@@ -11,12 +10,13 @@ import {
|
|||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from "class-validator"
|
} from "class-validator"
|
||||||
import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "."
|
import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "."
|
||||||
|
import { ClaimReason, ClaimType } from "../../../../models"
|
||||||
|
|
||||||
import { AddressPayload } from "../../../../types/common"
|
|
||||||
import { ClaimTypeValue } from "../../../../types/claim"
|
|
||||||
import { EntityManager } from "typeorm"
|
|
||||||
import { MedusaError } from "medusa-core-utils"
|
|
||||||
import { Type } from "class-transformer"
|
import { Type } from "class-transformer"
|
||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
|
import { EntityManager } from "typeorm"
|
||||||
|
import { ClaimTypeValue } from "../../../../types/claim"
|
||||||
|
import { AddressPayload } from "../../../../types/common"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -223,150 +223,146 @@ export default async (req, res) => {
|
|||||||
while (inProgress) {
|
while (inProgress) {
|
||||||
switch (idempotencyKey.recovery_point) {
|
switch (idempotencyKey.recovery_point) {
|
||||||
case "started": {
|
case "started": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
.withTransaction(transactionManager)
|
||||||
const order = await orderService
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
.withTransaction(manager)
|
const order = await orderService
|
||||||
.retrieve(id, {
|
.withTransaction(manager)
|
||||||
relations: [
|
.retrieve(id, {
|
||||||
"customer",
|
relations: [
|
||||||
"shipping_address",
|
"customer",
|
||||||
"region",
|
"shipping_address",
|
||||||
"items",
|
"region",
|
||||||
"items.tax_lines",
|
"items",
|
||||||
"discounts",
|
"items.tax_lines",
|
||||||
"discounts.rule",
|
"discounts",
|
||||||
"claims",
|
"discounts.rule",
|
||||||
"claims.additional_items",
|
"claims",
|
||||||
"claims.additional_items.tax_lines",
|
"claims.additional_items",
|
||||||
"swaps",
|
"claims.additional_items.tax_lines",
|
||||||
"swaps.additional_items",
|
"swaps",
|
||||||
"swaps.additional_items.tax_lines",
|
"swaps.additional_items",
|
||||||
],
|
"swaps.additional_items.tax_lines",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await claimService.withTransaction(manager).create({
|
||||||
|
idempotency_key: idempotencyKey.idempotency_key,
|
||||||
|
order,
|
||||||
|
type: value.type,
|
||||||
|
shipping_address: value.shipping_address,
|
||||||
|
claim_items: value.claim_items,
|
||||||
|
return_shipping: value.return_shipping,
|
||||||
|
additional_items: value.additional_items,
|
||||||
|
shipping_methods: value.shipping_methods,
|
||||||
|
no_notification: value.no_notification,
|
||||||
|
metadata: value.metadata,
|
||||||
})
|
})
|
||||||
|
|
||||||
await claimService.withTransaction(manager).create({
|
return {
|
||||||
idempotency_key: idempotencyKey.idempotency_key,
|
recovery_point: "claim_created",
|
||||||
order,
|
}
|
||||||
type: value.type,
|
|
||||||
shipping_address: value.shipping_address,
|
|
||||||
claim_items: value.claim_items,
|
|
||||||
return_shipping: value.return_shipping,
|
|
||||||
additional_items: value.additional_items,
|
|
||||||
shipping_methods: value.shipping_methods,
|
|
||||||
no_notification: value.no_notification,
|
|
||||||
metadata: value.metadata,
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
return {
|
.catch((e) => {
|
||||||
recovery_point: "claim_created",
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case "claim_created": {
|
case "claim_created": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
.withTransaction(transactionManager)
|
||||||
let claim = await claimService.withTransaction(manager).list({
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
idempotency_key: idempotencyKey.idempotency_key,
|
let claim = await claimService.withTransaction(manager).list({
|
||||||
|
idempotency_key: idempotencyKey.idempotency_key,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!claim.length) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Claim not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
claim = claim[0]
|
||||||
|
|
||||||
|
if (claim.type === "refund") {
|
||||||
|
await claimService
|
||||||
|
.withTransaction(manager)
|
||||||
|
.processRefund(claim.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
recovery_point: "refund_handled",
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
})
|
||||||
if (!claim.length) {
|
.catch((e) => {
|
||||||
throw new MedusaError(
|
|
||||||
MedusaError.Types.INVALID_DATA,
|
|
||||||
`Claim not found`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
claim = claim[0]
|
|
||||||
|
|
||||||
if (claim.type === "refund") {
|
|
||||||
await claimService
|
|
||||||
.withTransaction(manager)
|
|
||||||
.processRefund(claim.id)
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
recovery_point: "refund_handled",
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case "refund_handled": {
|
case "refund_handled": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
.withTransaction(transactionManager)
|
||||||
let order = await orderService
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
.withTransaction(manager)
|
let order = await orderService
|
||||||
.retrieve(id, {
|
|
||||||
relations: ["items", "discounts"],
|
|
||||||
})
|
|
||||||
|
|
||||||
let claim = await claimService.withTransaction(manager).list(
|
|
||||||
{
|
|
||||||
idempotency_key: idempotencyKey.idempotency_key,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
relations: ["return_order"],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!claim.length) {
|
|
||||||
throw new MedusaError(
|
|
||||||
MedusaError.Types.INVALID_DATA,
|
|
||||||
`Claim not found`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
claim = claim[0]
|
|
||||||
|
|
||||||
if (claim.return_order) {
|
|
||||||
await returnService
|
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.fulfill(claim.return_order.id)
|
.retrieve(id, {
|
||||||
}
|
relations: ["items", "discounts"],
|
||||||
|
})
|
||||||
|
|
||||||
order = await orderService.withTransaction(manager).retrieve(id, {
|
let claim = await claimService.withTransaction(manager).list(
|
||||||
select: defaultAdminOrdersFields,
|
{
|
||||||
relations: defaultAdminOrdersRelations,
|
idempotency_key: idempotencyKey.idempotency_key,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
relations: ["return_order"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!claim.length) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Claim not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
claim = claim[0]
|
||||||
|
|
||||||
|
if (claim.return_order) {
|
||||||
|
await returnService
|
||||||
|
.withTransaction(manager)
|
||||||
|
.fulfill(claim.return_order.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
order = await orderService
|
||||||
|
.withTransaction(manager)
|
||||||
|
.retrieve(id, {
|
||||||
|
select: defaultAdminOrdersFields,
|
||||||
|
relations: defaultAdminOrdersRelations,
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
response_code: 200,
|
||||||
|
response_body: { order },
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
})
|
||||||
return {
|
.catch((e) => {
|
||||||
response_code: 200,
|
|
||||||
response_body: { order },
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -200,71 +200,68 @@ export default async (req, res) => {
|
|||||||
while (inProgress) {
|
while (inProgress) {
|
||||||
switch (idempotencyKey.recovery_point) {
|
switch (idempotencyKey.recovery_point) {
|
||||||
case "started": {
|
case "started": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
.withTransaction(transactionManager)
|
||||||
const order = await orderService
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
.withTransaction(manager)
|
const order = await orderService
|
||||||
.retrieve(id, {
|
.withTransaction(manager)
|
||||||
select: ["refunded_total", "total"],
|
.retrieve(id, {
|
||||||
relations: [
|
select: ["refunded_total", "total"],
|
||||||
"items",
|
relations: [
|
||||||
"items.tax_lines",
|
"items",
|
||||||
"swaps",
|
"items.tax_lines",
|
||||||
"swaps.additional_items",
|
"swaps",
|
||||||
"swaps.additional_items.tax_lines",
|
"swaps.additional_items",
|
||||||
],
|
"swaps.additional_items.tax_lines",
|
||||||
})
|
],
|
||||||
|
})
|
||||||
|
|
||||||
const swap = await swapService
|
const swap = await swapService
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.create(
|
.create(
|
||||||
order,
|
order,
|
||||||
validated.return_items,
|
validated.return_items,
|
||||||
validated.additional_items,
|
validated.additional_items,
|
||||||
validated.return_shipping,
|
validated.return_shipping,
|
||||||
{
|
{
|
||||||
idempotency_key: idempotencyKey.idempotency_key,
|
idempotency_key: idempotencyKey.idempotency_key,
|
||||||
no_notification: validated.no_notification,
|
no_notification: validated.no_notification,
|
||||||
allow_backorder: validated.allow_backorder,
|
allow_backorder: validated.allow_backorder,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
await swapService
|
await swapService
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.createCart(swap.id, validated.custom_shipping_options)
|
.createCart(swap.id, validated.custom_shipping_options)
|
||||||
|
|
||||||
const returnOrder = await returnService
|
const returnOrder = await returnService
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.retrieveBySwap(swap.id)
|
.retrieveBySwap(swap.id)
|
||||||
|
|
||||||
await returnService
|
await returnService
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.fulfill(returnOrder.id)
|
.fulfill(returnOrder.id)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
recovery_point: "swap_created",
|
recovery_point: "swap_created",
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
})
|
||||||
if (error) {
|
.catch((e) => {
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case "swap_created": {
|
case "swap_created": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(
|
.withTransaction(transactionManager)
|
||||||
idempotencyKey.idempotency_key,
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
async (transactionManager: EntityManager) => {
|
|
||||||
const swaps = await swapService
|
const swaps = await swapService
|
||||||
.withTransaction(transactionManager)
|
.withTransaction(transactionManager)
|
||||||
.list({
|
.list({
|
||||||
@@ -289,16 +286,12 @@ export default async (req, res) => {
|
|||||||
response_code: 200,
|
response_code: 200,
|
||||||
response_body: { order },
|
response_body: { order },
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
)
|
})
|
||||||
|
.catch((e) => {
|
||||||
if (error) {
|
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,125 +175,121 @@ export default async (req, res) => {
|
|||||||
while (inProgress) {
|
while (inProgress) {
|
||||||
switch (idempotencyKey.recovery_point) {
|
switch (idempotencyKey.recovery_point) {
|
||||||
case "started": {
|
case "started": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
.withTransaction(transactionManager)
|
||||||
const returnObj: ReturnObj = {
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
order_id: id,
|
const returnObj: ReturnObj = {
|
||||||
idempotency_key: idempotencyKey.idempotency_key,
|
order_id: id,
|
||||||
items: value.items,
|
idempotency_key: idempotencyKey.idempotency_key,
|
||||||
}
|
items: value.items,
|
||||||
|
|
||||||
if (value.return_shipping) {
|
|
||||||
returnObj.shipping_method = value.return_shipping
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDefined(value.refund) && value.refund < 0) {
|
|
||||||
returnObj.refund_amount = 0
|
|
||||||
} else {
|
|
||||||
if (value.refund && value.refund >= 0) {
|
|
||||||
returnObj.refund_amount = value.refund
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const order = await orderService
|
if (value.return_shipping) {
|
||||||
.withTransaction(manager)
|
returnObj.shipping_method = value.return_shipping
|
||||||
.retrieve(id)
|
}
|
||||||
|
|
||||||
const evaluatedNoNotification =
|
if (isDefined(value.refund) && value.refund < 0) {
|
||||||
value.no_notification !== undefined
|
returnObj.refund_amount = 0
|
||||||
? value.no_notification
|
} else {
|
||||||
: order.no_notification
|
if (value.refund && value.refund >= 0) {
|
||||||
returnObj.no_notification = evaluatedNoNotification
|
returnObj.refund_amount = value.refund
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const createdReturn = await returnService
|
const order = await orderService
|
||||||
.withTransaction(manager)
|
|
||||||
.create(returnObj)
|
|
||||||
|
|
||||||
if (value.return_shipping) {
|
|
||||||
await returnService
|
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.fulfill(createdReturn.id)
|
.retrieve(id)
|
||||||
}
|
|
||||||
|
|
||||||
await eventBus
|
const evaluatedNoNotification =
|
||||||
.withTransaction(manager)
|
value.no_notification !== undefined
|
||||||
.emit("order.return_requested", {
|
? value.no_notification
|
||||||
id,
|
: order.no_notification
|
||||||
return_id: createdReturn.id,
|
returnObj.no_notification = evaluatedNoNotification
|
||||||
no_notification: evaluatedNoNotification,
|
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
const createdReturn = await returnService
|
||||||
recovery_point: "return_requested",
|
.withTransaction(manager)
|
||||||
}
|
.create(returnObj)
|
||||||
})
|
|
||||||
|
|
||||||
if (error) {
|
if (value.return_shipping) {
|
||||||
|
await returnService
|
||||||
|
.withTransaction(manager)
|
||||||
|
.fulfill(createdReturn.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
await eventBus
|
||||||
|
.withTransaction(manager)
|
||||||
|
.emit("order.return_requested", {
|
||||||
|
id,
|
||||||
|
return_id: createdReturn.id,
|
||||||
|
no_notification: evaluatedNoNotification,
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
recovery_point: "return_requested",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case "return_requested": {
|
case "return_requested": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
.withTransaction(transactionManager)
|
||||||
let order: Order | Return = await orderService
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
.withTransaction(manager)
|
let order: Order | Return = await orderService
|
||||||
.retrieve(id, { relations: ["returns"] })
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If we are ready to receive immediately, we find the newly created return
|
|
||||||
* and register it as received.
|
|
||||||
*/
|
|
||||||
if (value.receive_now) {
|
|
||||||
const returns = await returnService
|
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.list({
|
.retrieve(id, { relations: ["returns"] })
|
||||||
idempotency_key: idempotencyKey.idempotency_key,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (!returns.length) {
|
/**
|
||||||
throw new MedusaError(
|
* If we are ready to receive immediately, we find the newly created return
|
||||||
MedusaError.Types.INVALID_DATA,
|
* and register it as received.
|
||||||
`Return not found`
|
*/
|
||||||
)
|
if (value.receive_now) {
|
||||||
|
const returns = await returnService
|
||||||
|
.withTransaction(manager)
|
||||||
|
.list({
|
||||||
|
idempotency_key: idempotencyKey.idempotency_key,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!returns.length) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Return not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const returnOrder = returns[0]
|
||||||
|
|
||||||
|
order = await returnService
|
||||||
|
.withTransaction(manager)
|
||||||
|
.receive(returnOrder.id, value.items, value.refund)
|
||||||
}
|
}
|
||||||
|
|
||||||
const returnOrder = returns[0]
|
order = await orderService
|
||||||
|
|
||||||
order = await returnService
|
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.receive(returnOrder.id, value.items, value.refund)
|
.retrieve(id, {
|
||||||
}
|
select: defaultAdminOrdersFields,
|
||||||
|
relations: defaultAdminOrdersRelations,
|
||||||
|
})
|
||||||
|
|
||||||
order = await orderService
|
return {
|
||||||
.withTransaction(manager)
|
response_code: 200,
|
||||||
.retrieve(id, {
|
response_body: { order },
|
||||||
select: defaultAdminOrdersFields,
|
}
|
||||||
relations: defaultAdminOrdersRelations,
|
})
|
||||||
})
|
})
|
||||||
|
.catch((e) => {
|
||||||
return {
|
|
||||||
response_code: 200,
|
|
||||||
response_body: { order },
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,12 +73,11 @@ export default async (req, res) => {
|
|||||||
while (inProgress) {
|
while (inProgress) {
|
||||||
switch (idempotencyKey.recovery_point) {
|
switch (idempotencyKey.recovery_point) {
|
||||||
case "started": {
|
case "started": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(
|
.withTransaction(transactionManager)
|
||||||
idempotencyKey.idempotency_key,
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
async (manager: EntityManager) => {
|
|
||||||
const cart = await cartService
|
const cart = await cartService
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.retrieveWithTotals(id, {}, { force_taxes: true })
|
.retrieveWithTotals(id, {}, { force_taxes: true })
|
||||||
@@ -87,16 +86,12 @@ export default async (req, res) => {
|
|||||||
response_code: 200,
|
response_code: 200,
|
||||||
response_body: { cart },
|
response_body: { cart },
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
)
|
})
|
||||||
|
.catch((e) => {
|
||||||
if (error) {
|
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key!
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,37 +79,35 @@ export default async (req, res) => {
|
|||||||
while (inProgress) {
|
while (inProgress) {
|
||||||
switch (idempotencyKey.recovery_point) {
|
switch (idempotencyKey.recovery_point) {
|
||||||
case "started": {
|
case "started": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(
|
.withTransaction(transactionManager)
|
||||||
idempotencyKey.idempotency_key,
|
.workStage(
|
||||||
async (stageManager) => {
|
idempotencyKey.idempotency_key,
|
||||||
await cartService
|
async (stageManager) => {
|
||||||
.withTransaction(stageManager)
|
await cartService
|
||||||
.setPaymentSessions(id)
|
.withTransaction(stageManager)
|
||||||
|
.setPaymentSessions(id)
|
||||||
|
|
||||||
const cart = await cartService
|
const cart = await cartService
|
||||||
.withTransaction(stageManager)
|
.withTransaction(stageManager)
|
||||||
.retrieveWithTotals(id, {
|
.retrieveWithTotals(id, {
|
||||||
select: defaultStoreCartFields,
|
select: defaultStoreCartFields,
|
||||||
relations: defaultStoreCartRelations,
|
relations: defaultStoreCartRelations,
|
||||||
})
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
response_code: 200,
|
response_code: 200,
|
||||||
response_body: { cart },
|
response_body: { cart },
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
})
|
||||||
|
.catch((e) => {
|
||||||
if (error) {
|
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import { MedusaError } from "medusa-core-utils"
|
|||||||
import { EntityManager } from "typeorm"
|
import { EntityManager } from "typeorm"
|
||||||
import EventBusService from "../../../../services/event-bus"
|
import EventBusService from "../../../../services/event-bus"
|
||||||
import IdempotencyKeyService from "../../../../services/idempotency-key"
|
import IdempotencyKeyService from "../../../../services/idempotency-key"
|
||||||
import OrderService from "../../../../services/order"
|
|
||||||
import ReturnService from "../../../../services/return"
|
import ReturnService from "../../../../services/return"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
@@ -142,7 +141,6 @@ export default async (req, res) => {
|
|||||||
res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key)
|
res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const orderService: OrderService = req.scope.resolve("orderService")
|
|
||||||
const returnService: ReturnService = req.scope.resolve("returnService")
|
const returnService: ReturnService = req.scope.resolve("returnService")
|
||||||
const eventBus: EventBusService = req.scope.resolve("eventBusService")
|
const eventBus: EventBusService = req.scope.resolve("eventBusService")
|
||||||
|
|
||||||
@@ -152,95 +150,84 @@ export default async (req, res) => {
|
|||||||
while (inProgress) {
|
while (inProgress) {
|
||||||
switch (idempotencyKey.recovery_point) {
|
switch (idempotencyKey.recovery_point) {
|
||||||
case "started": {
|
case "started": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
.withTransaction(transactionManager)
|
||||||
const order = await orderService
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
.withTransaction(manager)
|
const returnObj: any = {
|
||||||
.retrieve(returnDto.order_id, {
|
order_id: returnDto.order_id,
|
||||||
select: ["refunded_total", "total"],
|
idempotency_key: idempotencyKey.idempotency_key,
|
||||||
relations: ["items"],
|
items: returnDto.items,
|
||||||
})
|
}
|
||||||
|
|
||||||
const returnObj: any = {
|
if (returnDto.return_shipping) {
|
||||||
order_id: returnDto.order_id,
|
returnObj.shipping_method = returnDto.return_shipping
|
||||||
idempotency_key: idempotencyKey.idempotency_key,
|
}
|
||||||
items: returnDto.items,
|
|
||||||
}
|
|
||||||
|
|
||||||
if (returnDto.return_shipping) {
|
const createdReturn = await returnService
|
||||||
returnObj.shipping_method = returnDto.return_shipping
|
|
||||||
}
|
|
||||||
|
|
||||||
const createdReturn = await returnService
|
|
||||||
.withTransaction(manager)
|
|
||||||
.create(returnObj)
|
|
||||||
|
|
||||||
if (returnDto.return_shipping) {
|
|
||||||
await returnService
|
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.fulfill(createdReturn.id)
|
.create(returnObj)
|
||||||
}
|
|
||||||
|
|
||||||
await eventBus
|
if (returnDto.return_shipping) {
|
||||||
.withTransaction(manager)
|
await returnService
|
||||||
.emit("order.return_requested", {
|
.withTransaction(manager)
|
||||||
id: returnDto.order_id,
|
.fulfill(createdReturn.id)
|
||||||
return_id: createdReturn.id,
|
}
|
||||||
})
|
|
||||||
|
|
||||||
return {
|
await eventBus
|
||||||
recovery_point: "return_requested",
|
.withTransaction(manager)
|
||||||
}
|
.emit("order.return_requested", {
|
||||||
})
|
id: returnDto.order_id,
|
||||||
|
return_id: createdReturn.id,
|
||||||
|
})
|
||||||
|
|
||||||
if (error) {
|
return {
|
||||||
|
recovery_point: "return_requested",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case "return_requested": {
|
case "return_requested": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
.withTransaction(transactionManager)
|
||||||
const returnOrders = await returnService
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
.withTransaction(manager)
|
const returnOrders = await returnService
|
||||||
.list(
|
.withTransaction(manager)
|
||||||
{
|
.list(
|
||||||
idempotency_key: idempotencyKey.idempotency_key,
|
{
|
||||||
},
|
idempotency_key: idempotencyKey.idempotency_key,
|
||||||
{
|
},
|
||||||
relations: ["items", "items.reason"],
|
{
|
||||||
}
|
relations: ["items", "items.reason"],
|
||||||
)
|
}
|
||||||
if (!returnOrders.length) {
|
)
|
||||||
throw new MedusaError(
|
if (!returnOrders.length) {
|
||||||
MedusaError.Types.INVALID_DATA,
|
throw new MedusaError(
|
||||||
`Return not found`
|
MedusaError.Types.INVALID_DATA,
|
||||||
)
|
`Return not found`
|
||||||
}
|
)
|
||||||
const returnOrder = returnOrders[0]
|
}
|
||||||
|
const returnOrder = returnOrders[0]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
response_code: 200,
|
response_code: 200,
|
||||||
response_body: { return: returnOrder },
|
response_body: { return: returnOrder },
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
})
|
||||||
if (error) {
|
.catch((e) => {
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -173,74 +173,71 @@ export default async (req, res) => {
|
|||||||
while (inProgress) {
|
while (inProgress) {
|
||||||
switch (idempotencyKey.recovery_point) {
|
switch (idempotencyKey.recovery_point) {
|
||||||
case "started": {
|
case "started": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
.withTransaction(transactionManager)
|
||||||
const order = await orderService
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
.withTransaction(manager)
|
const order = await orderService
|
||||||
.retrieve(swapDto.order_id, {
|
.withTransaction(manager)
|
||||||
select: ["refunded_total", "total"],
|
.retrieve(swapDto.order_id, {
|
||||||
relations: [
|
select: ["refunded_total", "total"],
|
||||||
"items",
|
relations: [
|
||||||
"items.tax_lines",
|
"items",
|
||||||
"swaps",
|
"items.tax_lines",
|
||||||
"swaps.additional_items",
|
"swaps",
|
||||||
"swaps.additional_items.tax_lines",
|
"swaps.additional_items",
|
||||||
],
|
"swaps.additional_items.tax_lines",
|
||||||
})
|
],
|
||||||
|
})
|
||||||
|
|
||||||
let returnShipping
|
let returnShipping
|
||||||
if (swapDto.return_shipping_option) {
|
if (swapDto.return_shipping_option) {
|
||||||
returnShipping = {
|
returnShipping = {
|
||||||
option_id: swapDto.return_shipping_option,
|
option_id: swapDto.return_shipping_option,
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const swap = await swapService
|
|
||||||
.withTransaction(manager)
|
|
||||||
.create(
|
|
||||||
order,
|
|
||||||
swapDto.return_items,
|
|
||||||
swapDto.additional_items,
|
|
||||||
returnShipping,
|
|
||||||
{
|
|
||||||
idempotency_key: idempotencyKey.idempotency_key,
|
|
||||||
no_notification: true,
|
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
await swapService.withTransaction(manager).createCart(swap.id)
|
const swap = await swapService
|
||||||
const returnOrder = await returnService
|
.withTransaction(manager)
|
||||||
.withTransaction(manager)
|
.create(
|
||||||
.retrieveBySwap(swap.id)
|
order,
|
||||||
|
swapDto.return_items,
|
||||||
|
swapDto.additional_items,
|
||||||
|
returnShipping,
|
||||||
|
{
|
||||||
|
idempotency_key: idempotencyKey.idempotency_key,
|
||||||
|
no_notification: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
await returnService
|
await swapService.withTransaction(manager).createCart(swap.id)
|
||||||
.withTransaction(manager)
|
const returnOrder = await returnService
|
||||||
.fulfill(returnOrder.id)
|
.withTransaction(manager)
|
||||||
|
.retrieveBySwap(swap.id)
|
||||||
|
|
||||||
return {
|
await returnService
|
||||||
recovery_point: "swap_created",
|
.withTransaction(manager)
|
||||||
}
|
.fulfill(returnOrder.id)
|
||||||
})
|
|
||||||
|
|
||||||
if (error) {
|
return {
|
||||||
|
recovery_point: "swap_created",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case "swap_created": {
|
case "swap_created": {
|
||||||
await manager.transaction(async (transactionManager) => {
|
await manager
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(
|
.withTransaction(transactionManager)
|
||||||
idempotencyKey.idempotency_key,
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
async (transactionManager: EntityManager) => {
|
|
||||||
const swaps = await swapService
|
const swaps = await swapService
|
||||||
.withTransaction(transactionManager)
|
.withTransaction(transactionManager)
|
||||||
.list({
|
.list({
|
||||||
@@ -265,16 +262,12 @@ export default async (req, res) => {
|
|||||||
response_code: 200,
|
response_code: 200,
|
||||||
response_body: { swap },
|
response_body: { swap },
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
)
|
})
|
||||||
|
.catch((e) => {
|
||||||
if (error) {
|
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { MockManager } from "medusa-test-utils"
|
import { MockManager } from "medusa-test-utils"
|
||||||
|
|
||||||
export const IdempotencyKeyService = {
|
export const IdempotencyKeyService = {
|
||||||
withTransaction: function() {
|
withTransaction: function () {
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
initializeRequest: jest.fn().mockImplementation(() => {
|
initializeRequest: jest.fn().mockImplementation(() => {
|
||||||
@@ -18,15 +18,13 @@ export const IdempotencyKeyService = {
|
|||||||
|
|
||||||
if (recovery_point) {
|
if (recovery_point) {
|
||||||
return {
|
return {
|
||||||
key: { recovery_point },
|
recovery_point,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
key: {
|
recovery_point: "finished",
|
||||||
recovery_point: "finished",
|
response_body,
|
||||||
response_body,
|
response_code,
|
||||||
response_code,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -1,16 +1,6 @@
|
|||||||
import ClaimItemService from "./claim-item"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import EventBusService from "./event-bus"
|
import { DeepPartial, EntityManager } from "typeorm"
|
||||||
import FulfillmentProviderService from "./fulfillment-provider"
|
import { TransactionBaseService } from "../interfaces"
|
||||||
import FulfillmentService from "./fulfillment"
|
|
||||||
import InventoryService from "./inventory"
|
|
||||||
import LineItemService from "./line-item"
|
|
||||||
import PaymentProviderService from "./payment-provider"
|
|
||||||
import RegionService from "./region"
|
|
||||||
import ReturnService from "./return"
|
|
||||||
import ShippingOptionService from "./shipping-option"
|
|
||||||
import TaxProviderService from "./tax-provider"
|
|
||||||
import TotalsService from "./totals"
|
|
||||||
import { AddressRepository } from "../repositories/address"
|
|
||||||
import {
|
import {
|
||||||
ClaimFulfillmentStatus,
|
ClaimFulfillmentStatus,
|
||||||
ClaimOrder,
|
ClaimOrder,
|
||||||
@@ -20,15 +10,25 @@ import {
|
|||||||
LineItem,
|
LineItem,
|
||||||
ReturnItem,
|
ReturnItem,
|
||||||
} from "../models"
|
} from "../models"
|
||||||
|
import { AddressRepository } from "../repositories/address"
|
||||||
import { ClaimRepository } from "../repositories/claim"
|
import { ClaimRepository } from "../repositories/claim"
|
||||||
import { DeepPartial, EntityManager } from "typeorm"
|
|
||||||
import { LineItemRepository } from "../repositories/line-item"
|
import { LineItemRepository } from "../repositories/line-item"
|
||||||
import { MedusaError } from "medusa-core-utils"
|
|
||||||
import { ShippingMethodRepository } from "../repositories/shipping-method"
|
import { ShippingMethodRepository } from "../repositories/shipping-method"
|
||||||
import { TransactionBaseService } from "../interfaces"
|
|
||||||
import { buildQuery, isDefined, setMetadata } from "../utils"
|
|
||||||
import { FindConfig } from "../types/common"
|
|
||||||
import { CreateClaimInput, UpdateClaimInput } from "../types/claim"
|
import { CreateClaimInput, UpdateClaimInput } from "../types/claim"
|
||||||
|
import { FindConfig } from "../types/common"
|
||||||
|
import { buildQuery, isDefined, setMetadata } from "../utils"
|
||||||
|
import ClaimItemService from "./claim-item"
|
||||||
|
import EventBusService from "./event-bus"
|
||||||
|
import FulfillmentService from "./fulfillment"
|
||||||
|
import FulfillmentProviderService from "./fulfillment-provider"
|
||||||
|
import InventoryService from "./inventory"
|
||||||
|
import LineItemService from "./line-item"
|
||||||
|
import PaymentProviderService from "./payment-provider"
|
||||||
|
import RegionService from "./region"
|
||||||
|
import ReturnService from "./return"
|
||||||
|
import ShippingOptionService from "./shipping-option"
|
||||||
|
import TaxProviderService from "./tax-provider"
|
||||||
|
import TotalsService from "./totals"
|
||||||
|
|
||||||
type InjectedDependencies = {
|
type InjectedDependencies = {
|
||||||
manager: EntityManager
|
manager: EntityManager
|
||||||
|
|||||||
@@ -171,28 +171,23 @@ class IdempotencyKeyService extends TransactionBaseService {
|
|||||||
}
|
}
|
||||||
| never
|
| never
|
||||||
>
|
>
|
||||||
): Promise<{ key?: IdempotencyKey; error?: unknown }> {
|
): Promise<IdempotencyKey> {
|
||||||
try {
|
return await this.atomicPhase_(async (manager) => {
|
||||||
return await this.atomicPhase_(async (manager) => {
|
const { recovery_point, response_code, response_body } = await callback(
|
||||||
const { recovery_point, response_code, response_body } = await callback(
|
manager
|
||||||
manager
|
)
|
||||||
)
|
|
||||||
|
|
||||||
const data: DeepPartial<IdempotencyKey> = {
|
const data: DeepPartial<IdempotencyKey> = {
|
||||||
recovery_point: recovery_point ?? "finished",
|
recovery_point: recovery_point ?? "finished",
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!recovery_point) {
|
if (!recovery_point) {
|
||||||
data.response_body = response_body
|
data.response_body = response_body
|
||||||
data.response_code = response_code
|
data.response_code = response_code
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = await this.update(idempotencyKey, data)
|
return await this.update(idempotencyKey, data)
|
||||||
return { key }
|
})
|
||||||
}, "SERIALIZABLE")
|
|
||||||
} catch (err) {
|
|
||||||
return { error: err }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,21 +13,23 @@ const IdempotencyKeyServiceMock = {
|
|||||||
|
|
||||||
if (recovery_point) {
|
if (recovery_point) {
|
||||||
return {
|
return {
|
||||||
key: { idempotency_key: key, recovery_point },
|
idempotency_key: key,
|
||||||
|
recovery_point,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
key: {
|
recovery_point: "finished",
|
||||||
recovery_point: "finished",
|
response_body,
|
||||||
response_body,
|
response_code,
|
||||||
response_code,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return { error: err }
|
return { error: err }
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
update: jest.fn().mockImplementation((key, data) => {
|
||||||
|
return data
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
|
|
||||||
const toTest = [
|
const toTest = [
|
||||||
|
|||||||
@@ -63,12 +63,11 @@ class CartCompletionStrategy extends AbstractCartCompletionStrategy {
|
|||||||
while (inProgress) {
|
while (inProgress) {
|
||||||
switch (idempotencyKey.recovery_point) {
|
switch (idempotencyKey.recovery_point) {
|
||||||
case "started": {
|
case "started": {
|
||||||
await this.manager_.transaction(async (transactionManager) => {
|
await this.manager_
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(
|
.withTransaction(transactionManager)
|
||||||
idempotencyKey.idempotency_key,
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
async (manager: EntityManager) => {
|
|
||||||
const cart = await cartService
|
const cart = await cartService
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.retrieve(id)
|
.retrieve(id)
|
||||||
@@ -89,25 +88,20 @@ class CartCompletionStrategy extends AbstractCartCompletionStrategy {
|
|||||||
return {
|
return {
|
||||||
recovery_point: "tax_lines_created",
|
recovery_point: "tax_lines_created",
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
)
|
})
|
||||||
|
.catch((e) => {
|
||||||
if (error) {
|
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key as IdempotencyKey
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case "tax_lines_created": {
|
case "tax_lines_created": {
|
||||||
await this.manager_.transaction(async (transactionManager) => {
|
await this.manager_
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(
|
.withTransaction(transactionManager)
|
||||||
idempotencyKey.idempotency_key,
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
async (manager: EntityManager) => {
|
|
||||||
const cart = await cartService
|
const cart = await cartService
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.authorizePayment(id, {
|
.authorizePayment(id, {
|
||||||
@@ -138,26 +132,21 @@ class CartCompletionStrategy extends AbstractCartCompletionStrategy {
|
|||||||
return {
|
return {
|
||||||
recovery_point: "payment_authorized",
|
recovery_point: "payment_authorized",
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
)
|
})
|
||||||
|
.catch((e) => {
|
||||||
if (error) {
|
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key as IdempotencyKey
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case "payment_authorized": {
|
case "payment_authorized": {
|
||||||
await this.manager_.transaction(async (transactionManager) => {
|
await this.manager_
|
||||||
const { key, error } = await idempotencyKeyService
|
.transaction("SERIALIZABLE", async (transactionManager) => {
|
||||||
.withTransaction(transactionManager)
|
idempotencyKey = await idempotencyKeyService
|
||||||
.workStage(
|
.withTransaction(transactionManager)
|
||||||
idempotencyKey.idempotency_key,
|
.workStage(idempotencyKey.idempotency_key, async (manager) => {
|
||||||
async (manager: EntityManager) => {
|
|
||||||
const cart = await cartService
|
const cart = await cartService
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.retrieveWithTotals(id, {
|
.retrieveWithTotals(id, {
|
||||||
@@ -287,16 +276,12 @@ class CartCompletionStrategy extends AbstractCartCompletionStrategy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
)
|
})
|
||||||
|
.catch((e) => {
|
||||||
if (error) {
|
|
||||||
inProgress = false
|
inProgress = false
|
||||||
err = error
|
err = e
|
||||||
} else {
|
})
|
||||||
idempotencyKey = key as IdempotencyKey
|
|
||||||
}
|
|
||||||
})
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user