chore(medusa): Add transactions in mutating actions in store domain (#1858)

This commit is contained in:
Adrien de Peretti
2022-07-28 11:48:55 +02:00
committed by GitHub
parent 3fbe8d7d08
commit 7cb8095ed4
26 changed files with 437 additions and 287 deletions
@@ -3,6 +3,7 @@ import jwt from "jsonwebtoken"
import AuthService from "../../../../services/auth"
import CustomerService from "../../../../services/customer"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /auth
@@ -28,10 +29,13 @@ export default async (req, res) => {
const validated = await validator(StorePostAuthReq, req.body)
const authService: AuthService = req.scope.resolve("authService")
const result = await authService.authenticateCustomer(
validated.email,
validated.password
)
const manager: EntityManager = req.scope.resolve("manager")
const result = await manager.transaction(async (transactionManager) => {
return await authService
.withTransaction(transactionManager)
.authenticateCustomer(validated.email, validated.password)
})
if (!result.success) {
res.sendStatus(401)
return
@@ -31,17 +31,22 @@ export default async (req, res) => {
const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve(
"idempotencyKeyService"
)
const manager: EntityManager = req.scope.resolve("manager")
const headerKey = req.get("Idempotency-Key") || ""
let idempotencyKey: IdempotencyKey
let idempotencyKey!: IdempotencyKey
try {
idempotencyKey = await idempotencyKeyService.initializeRequest(
headerKey,
req.method,
req.params,
req.path
)
await manager.transaction(async (transactionManager) => {
idempotencyKey = await idempotencyKeyService
.withTransaction(transactionManager)
.initializeRequest(
headerKey,
req.method,
req.params,
req.path
)
})
} catch (error) {
console.log(error)
res.status(409).send("Failed to create idempotency key")
@@ -59,42 +64,46 @@ export default async (req, res) => {
while (inProgress) {
switch (idempotencyKey.recovery_point) {
case "started": {
const { key, error } = await idempotencyKeyService.workStage(
idempotencyKey.idempotency_key,
async (manager: EntityManager) => {
const cart = await cartService.withTransaction(manager).retrieve(
id,
{
relations: ["items", "items.adjustments"],
select: [
"total",
"subtotal",
"tax_total",
"discount_total",
"shipping_total",
"gift_card_total",
],
},
{ force_taxes: true }
await manager.transaction(async (transactionManager) => {
const { key, error } = await idempotencyKeyService
.withTransaction(transactionManager)
.workStage(
idempotencyKey.idempotency_key,
async (manager: EntityManager) => {
const cart = await cartService.withTransaction(manager).retrieve(
id,
{
relations: ["items", "items.adjustments"],
select: [
"total",
"subtotal",
"tax_total",
"discount_total",
"shipping_total",
"gift_card_total",
],
},
{ force_taxes: true }
)
const data = await decorateLineItemsWithTotals(cart, req, {
force_taxes: true,
})
return {
response_code: 200,
response_body: { cart: data },
}
}
)
const data = await decorateLineItemsWithTotals(cart, req, {
force_taxes: true,
})
return {
response_code: 200,
response_body: { cart: data },
}
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
})
break
}
@@ -104,14 +113,18 @@ export default async (req, res) => {
}
default:
idempotencyKey = await idempotencyKeyService.update(
idempotencyKey.idempotency_key,
{
recovery_point: "finished",
response_code: 500,
response_body: { message: "Unknown recovery point" },
}
)
await manager.transaction(async (transactionManager) => {
idempotencyKey = await idempotencyKeyService
.withTransaction(transactionManager)
.update(
idempotencyKey.idempotency_key,
{
recovery_point: "finished",
response_code: 500,
response_body: { message: "Unknown recovery point" },
}
)
})
break
}
}
@@ -1,6 +1,7 @@
import { ICartCompletionStrategy } from "../../../../interfaces"
import { IdempotencyKeyService } from "../../../../services"
import { IdempotencyKey } from "../../../../models/idempotency-key"
import { EntityManager } from "typeorm";
/**
* @oas [post] /carts/{id}/complete
@@ -50,12 +51,15 @@ export default async (req, res) => {
let idempotencyKey: IdempotencyKey
try {
idempotencyKey = await idempotencyKeyService.initializeRequest(
headerKey,
req.method,
req.params,
req.path
)
const manager: EntityManager = req.scope.resolve("manager")
idempotencyKey = await manager.transaction(async (transactionManager) => {
return await idempotencyKeyService.withTransaction(transactionManager).initializeRequest(
headerKey,
req.method,
req.params,
req.path
)
})
} catch (error) {
console.log(error)
res.status(409).send("Failed to create idempotency key")
@@ -1,6 +1,7 @@
import { defaultStoreCartFields, defaultStoreCartRelations } from "."
import { CartService } from "../../../../services"
import { decorateLineItemsWithTotals } from "./decorate-line-items-with-totals"
import { EntityManager } from "typeorm";
/**
* @oas [post] /carts/{id}/payment-sessions
@@ -26,7 +27,10 @@ export default async (req, res) => {
const cartService: CartService = req.scope.resolve("cartService")
await cartService.setPaymentSessions(id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await cartService.withTransaction(transactionManager).setPaymentSessions(id)
})
const cart = await cartService.retrieve(id, {
select: defaultStoreCartFields,
@@ -1,6 +1,7 @@
import { Request } from "express"
import { TotalsService } from "../../../../services"
import { Cart, LineItem } from "../../../../models"
import { EntityManager } from "typeorm";
export const decorateLineItemsWithTotals = async (
cart: Cart,
@@ -10,15 +11,20 @@ export const decorateLineItemsWithTotals = async (
const totalsService: TotalsService = req.scope.resolve("totalsService")
if (cart.items && cart.region) {
const items = await Promise.all(
cart.items.map(async (item: LineItem) => {
const itemTotals = await totalsService.getLineItemTotals(item, cart, {
include_tax: options.force_taxes || cart.region.automatic_taxes,
})
const manager: EntityManager = req.scope.resolve("manager")
const items = await manager.transaction(async (transactionManager) => {
return await Promise.all(
cart.items.map(async (item: LineItem) => {
const itemTotals = await totalsService
.withTransaction(transactionManager)
.getLineItemTotals(item, cart, {
include_tax: options.force_taxes || cart.region.automatic_taxes,
})
return Object.assign(item, itemTotals)
})
)
return Object.assign(item, itemTotals)
})
)
})
return Object.assign(cart, { items })
}
@@ -1,6 +1,7 @@
import { defaultStoreCartFields, defaultStoreCartRelations } from "."
import { CartService } from "../../../../services"
import { decorateLineItemsWithTotals } from "./decorate-line-items-with-totals"
import { EntityManager } from "typeorm";
/**
* @oas [delete] /carts/{id}/payment-sessions/{provider_id}
@@ -27,7 +28,11 @@ export default async (req, res) => {
const cartService: CartService = req.scope.resolve("cartService")
await cartService.deletePaymentSession(id, provider_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await cartService.withTransaction(transactionManager).deletePaymentSession(id, provider_id)
})
const cart = await cartService.retrieve(id, {
select: defaultStoreCartFields,
relations: defaultStoreCartRelations,
@@ -1,5 +1,6 @@
import { CartService } from "../../../../services"
import { decorateLineItemsWithTotals } from "./decorate-line-items-with-totals"
import { EntityManager } from "typeorm";
/**
* @oas [post] /carts/{id}/payment-sessions/{provider_id}/refresh
@@ -26,7 +27,10 @@ export default async (req, res) => {
const cartService: CartService = req.scope.resolve("cartService")
await cartService.refreshPaymentSession(id, provider_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await cartService.withTransaction(transactionManager).refreshPaymentSession(id, provider_id)
})
const cart = await cartService.retrieve(id, {
select: [
"subtotal",
@@ -3,6 +3,7 @@ import { defaultStoreCartFields, defaultStoreCartRelations } from "."
import { CartService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { decorateLineItemsWithTotals } from "./decorate-line-items-with-totals"
import { EntityManager } from "typeorm";
/**
* @oas [post] /carts/{id}/payment-session
@@ -34,8 +35,12 @@ export default async (req, res) => {
const cartService: CartService = req.scope.resolve("cartService")
let cart = await cartService.setPaymentSession(id, validated.provider_id)
cart = await cartService.retrieve(id, {
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await cartService.withTransaction(transactionManager).setPaymentSession(id, validated.provider_id)
})
const cart = await cartService.retrieve(id, {
select: defaultStoreCartFields,
relations: defaultStoreCartRelations,
})
@@ -11,6 +11,7 @@ import { CartService } from "../../../../services"
import { AddressPayload } from "../../../../types/common"
import { IsType } from "../../../../utils/validators/is-type"
import { decorateLineItemsWithTotals } from "./decorate-line-items-with-totals"
import { EntityManager } from "typeorm";
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators";
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels";
@@ -89,16 +90,20 @@ export default async (req, res) => {
const validated = req.validatedBody as StorePostCartsCartReq
const cartService: CartService = req.scope.resolve("cartService")
await cartService.update(id, validated)
const manager: EntityManager = req.scope.resolve("manager")
const updated = await cartService.retrieve(id, {
relations: ["payment_sessions", "shipping_methods"],
await manager.transaction(async (transactionManager) => {
await cartService.withTransaction(transactionManager).update(id, validated)
const updated = await cartService.withTransaction(transactionManager).retrieve(id, {
relations: ["payment_sessions", "shipping_methods"],
})
if (updated.payment_sessions?.length && !validated.region_id) {
await cartService.withTransaction(transactionManager).setPaymentSessions(id)
}
})
if (updated.payment_sessions?.length && !validated.region_id) {
await cartService.setPaymentSessions(id)
}
const cart = await cartService.retrieve(id, {
select: defaultStoreCartFields,
relations: defaultStoreCartRelations,
@@ -43,7 +43,7 @@ export default async (req, res) => {
if (validated.quantity === 0) {
await cartService.withTransaction(m).removeLineItem(id, line_id)
} else {
const cart = await cartService.retrieve(id, { relations: ["items"] })
const cart = await cartService.withTransaction(m).retrieve(id, { relations: ["items"] })
const existing = cart.items.find((i) => i.id === line_id)
if (!existing) {
@@ -3,6 +3,7 @@ import { defaultStoreCartFields, defaultStoreCartRelations } from "."
import { CartService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { decorateLineItemsWithTotals } from "./decorate-line-items-with-totals"
import { EntityManager } from "typeorm";
/**
* @oas [post] /carts/{id}/payment-sessions/{provider_id}
@@ -35,8 +36,11 @@ export default async (req, res) => {
const cartService: CartService = req.scope.resolve("cartService")
await cartService.setPaymentSession(id, provider_id)
await cartService.updatePaymentSession(id, validated.data)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
await cartService.withTransaction(transactionManager).setPaymentSession(id, provider_id)
await cartService.withTransaction(transactionManager).updatePaymentSession(id, validated.data)
})
const cart = await cartService.retrieve(id, {
select: defaultStoreCartFields,
@@ -4,6 +4,7 @@ import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "."
import CustomerService from "../../../../services/customer"
import { AddressCreatePayload } from "../../../../types/common"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /customers/me/addresses
@@ -44,8 +45,14 @@ export default async (req, res) => {
const customerService: CustomerService = req.scope.resolve("customerService")
let customer = await customerService.addAddress(id, validated.address)
customer = await customerService.retrieve(id, {
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await customerService
.withTransaction(transactionManager)
.addAddress(id, validated.address)
})
const customer = await customerService.retrieve(id, {
relations: defaultStoreCustomersRelations,
select: defaultStoreCustomersFields,
})
@@ -4,6 +4,7 @@ import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "."
import { Customer } from "../../../.."
import CustomerService from "../../../../services/customer"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /customers
@@ -32,7 +33,14 @@ export default async (req, res) => {
const validated = await validator(StorePostCustomersReq, req.body)
const customerService: CustomerService = req.scope.resolve("customerService")
let customer: Customer = await customerService.create(validated)
const manager: EntityManager = req.scope.resolve("manager")
let customer: Customer = await manager.transaction(
async (transactionManager) => {
return await customerService
.withTransaction(transactionManager)
.create(validated)
}
)
// Add JWT to cookie
const {
@@ -1,5 +1,6 @@
import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "."
import CustomerService from "../../../../services/customer"
import { EntityManager } from "typeorm"
/**
* @oas [delete] /customers/me/addresses/{address_id}
@@ -28,7 +29,12 @@ export default async (req, res) => {
const customerService: CustomerService = req.scope.resolve("customerService")
await customerService.removeAddress(id, address_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await customerService
.withTransaction(transactionManager)
.removeAddress(id, address_id)
})
const customer = await customerService.retrieve(id, {
relations: defaultStoreCustomersRelations,
@@ -1,6 +1,7 @@
import { IsEmail } from "class-validator"
import CustomerService from "../../../../services/customer"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /customers/password-token
@@ -28,7 +29,12 @@ export default async (req, res) => {
const customer = await customerService.retrieveByEmail(validated.email)
// Will generate a token and send it to the customer via an email provider
await customerService.generateResetPasswordToken(customer.id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await customerService
.withTransaction(transactionManager)
.generateResetPasswordToken(customer.id)
})
res.sendStatus(204)
}
@@ -2,6 +2,7 @@ import { IsEmail, IsString } from "class-validator"
import jwt, { JwtPayload } from "jsonwebtoken"
import CustomerService from "../../../../services/customer"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /customers/reset-password
@@ -44,8 +45,13 @@ export default async (req, res) => {
return
}
await customerService.update(customer.id, {
password: validated.password,
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await customerService
.withTransaction(transactionManager)
.update(customer.id, {
password: validated.password,
})
})
customer = await customerService.retrieve(customer.id)
@@ -2,6 +2,7 @@ import { defaultStoreCustomersFields, defaultStoreCustomersRelations } from "."
import CustomerService from "../../../../services/customer"
import { AddressPayload } from "../../../../types/common"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /customers/me/addresses/{address_id}
@@ -45,7 +46,12 @@ export default async (req, res) => {
"customerService"
) as CustomerService
await customerService.updateAddress(id, address_id, validated)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await customerService
.withTransaction(transactionManager)
.updateAddress(id, address_id, validated)
})
const customer = await customerService.retrieve(id, {
relations: defaultStoreCustomersRelations,
@@ -4,6 +4,7 @@ import CustomerService from "../../../../services/customer"
import { AddressPayload } from "../../../../types/common"
import { IsType } from "../../../../utils/validators/is-type"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /customers/me
@@ -56,7 +57,12 @@ export default async (req, res) => {
const validated = await validator(StorePostCustomersCustomerReq, req.body)
const customerService: CustomerService = req.scope.resolve("customerService")
await customerService.update(id, validated)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await customerService
.withTransaction(transactionManager)
.update(id, validated)
})
const customer = await customerService.retrieve(id, {
relations: defaultStoreCustomersRelations,
@@ -14,6 +14,7 @@ import IdempotencyKeyService from "../../../../services/idempotency-key"
import OrderService from "../../../../services/order"
import ReturnService from "../../../../services/return"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm";
/**
* @oas [post] /returns
@@ -72,17 +73,20 @@ export default async (req, res) => {
const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve(
"idempotencyKeyService"
)
const manager: EntityManager = req.scope.resolve("manager")
const headerKey = req.get("Idempotency-Key") || ""
let idempotencyKey
try {
idempotencyKey = await idempotencyKeyService.initializeRequest(
headerKey,
req.method,
req.params,
req.path
)
await manager.transaction(async (transactionManager) => {
idempotencyKey = await idempotencyKeyService.withTransaction(transactionManager).initializeRequest(
headerKey,
req.method,
req.params,
req.path
)
})
} catch (error) {
res.status(409).send("Failed to create idempotency key")
return
@@ -102,91 +106,99 @@ export default async (req, res) => {
while (inProgress) {
switch (idempotencyKey.recovery_point) {
case "started": {
const { key, error } = await idempotencyKeyService.workStage(
idempotencyKey.idempotency_key,
async (manager) => {
const order = await orderService
.withTransaction(manager)
.retrieve(returnDto.order_id, {
select: ["refunded_total", "total"],
relations: ["items"],
})
await manager.transaction(async (transactionManager) => {
const { key, error } = await idempotencyKeyService
.withTransaction(transactionManager)
.workStage(
idempotencyKey.idempotency_key,
async (manager) => {
const order = await orderService
.withTransaction(manager)
.retrieve(returnDto.order_id, {
select: ["refunded_total", "total"],
relations: ["items"],
})
const returnObj: any = {
order_id: returnDto.order_id,
idempotency_key: idempotencyKey.idempotency_key,
items: returnDto.items,
}
const returnObj: any = {
order_id: returnDto.order_id,
idempotency_key: idempotencyKey.idempotency_key,
items: returnDto.items,
}
if (returnDto.return_shipping) {
returnObj.shipping_method = returnDto.return_shipping
}
if (returnDto.return_shipping) {
returnObj.shipping_method = returnDto.return_shipping
}
const createdReturn = await returnService
.withTransaction(manager)
.create(returnObj)
const createdReturn = await returnService
.withTransaction(manager)
.create(returnObj)
if (returnDto.return_shipping) {
await returnService
.withTransaction(manager)
.fulfill(createdReturn.id)
}
if (returnDto.return_shipping) {
await returnService
.withTransaction(manager)
.fulfill(createdReturn.id)
}
await eventBus
.withTransaction(manager)
.emit("order.return_requested", {
id: returnDto.order_id,
return_id: createdReturn.id,
})
await eventBus
.withTransaction(manager)
.emit("order.return_requested", {
id: returnDto.order_id,
return_id: createdReturn.id,
})
return {
recovery_point: "return_requested",
}
return {
recovery_point: "return_requested",
}
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
})
break
}
case "return_requested": {
const { key, error } = await idempotencyKeyService.workStage(
idempotencyKey.idempotency_key,
async (manager) => {
let ret = await returnService.withTransaction(manager).list(
{
idempotency_key: idempotencyKey.idempotency_key,
},
{
relations: ["items", "items.reason"],
await manager.transaction(async (transactionManager) => {
const { key, error } = await idempotencyKeyService
.withTransaction(transactionManager)
.workStage(
idempotencyKey.idempotency_key,
async (manager) => {
let ret = await returnService.withTransaction(manager).list(
{
idempotency_key: idempotencyKey.idempotency_key,
},
{
relations: ["items", "items.reason"],
}
)
if (!ret.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Return not found`
)
}
ret = ret[0]
return {
response_code: 200,
response_body: { return: ret },
}
}
)
if (!ret.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Return not found`
)
}
ret = ret[0]
return {
response_code: 200,
response_body: { return: ret },
}
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
})
break
}
@@ -196,14 +208,18 @@ export default async (req, res) => {
}
default:
idempotencyKey = await idempotencyKeyService.update(
idempotencyKey.idempotency_key,
{
recovery_point: "finished",
response_code: 500,
response_body: { message: "Unknown recovery point" },
}
)
await manager.transaction(async (transactionManager) => {
idempotencyKey = await idempotencyKeyService
.withTransaction(transactionManager)
.update(
idempotencyKey.idempotency_key,
{
recovery_point: "finished",
response_code: 500,
response_body: { message: "Unknown recovery point" },
}
)
})
break
}
}
@@ -93,17 +93,17 @@ export default async (req, res) => {
const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve(
"idempotencyKeyService"
)
const manager: EntityManager = req.scope.resolve("manager")
const headerKey = req.get("Idempotency-Key") || ""
let idempotencyKey
try {
idempotencyKey = await idempotencyKeyService.initializeRequest(
headerKey,
req.method,
req.params,
req.path
)
await manager.transaction(async (transactionManager) => {
idempotencyKey = await idempotencyKeyService
.withTransaction(transactionManager)
.initializeRequest(headerKey, req.method, req.params, req.path)
})
} catch (error) {
res.status(409).send("Failed to create idempotency key")
return
@@ -122,101 +122,108 @@ export default async (req, res) => {
while (inProgress) {
switch (idempotencyKey.recovery_point) {
case "started": {
const { key, error } = await idempotencyKeyService.workStage(
idempotencyKey.idempotency_key,
async (manager) => {
const order = await orderService
.withTransaction(manager)
.retrieve(swapDto.order_id, {
select: ["refunded_total", "total"],
relations: [
"items",
"items.tax_lines",
"swaps",
"swaps.additional_items",
"swaps.additional_items.tax_lines",
],
})
await manager.transaction(async (transactionManager) => {
const { key, error } = await idempotencyKeyService
.withTransaction(transactionManager)
.workStage(idempotencyKey.idempotency_key, async (manager) => {
const order = await orderService
.withTransaction(manager)
.retrieve(swapDto.order_id, {
select: ["refunded_total", "total"],
relations: [
"items",
"items.tax_lines",
"swaps",
"swaps.additional_items",
"swaps.additional_items.tax_lines",
],
})
let returnShipping
if (swapDto.return_shipping_option) {
returnShipping = {
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,
let returnShipping
if (swapDto.return_shipping_option) {
returnShipping = {
option_id: swapDto.return_shipping_option,
}
)
}
await swapService.withTransaction(manager).createCart(swap.id)
const returnOrder = await returnService
.withTransaction(manager)
.retrieveBySwap(swap.id)
const swap = await swapService
.withTransaction(manager)
.create(
order,
swapDto.return_items,
swapDto.additional_items,
returnShipping,
{
idempotency_key: idempotencyKey.idempotency_key,
no_notification: true,
}
)
await returnService.withTransaction(manager).fulfill(returnOrder.id)
await swapService.withTransaction(manager).createCart(swap.id)
const returnOrder = await returnService
.withTransaction(manager)
.retrieveBySwap(swap.id)
return {
recovery_point: "swap_created",
}
await returnService
.withTransaction(manager)
.fulfill(returnOrder.id)
return {
recovery_point: "swap_created",
}
})
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
})
break
}
case "swap_created": {
const { key, error } = await idempotencyKeyService.workStage(
idempotencyKey.idempotency_key,
async (transactionManager: EntityManager) => {
const swaps = await swapService
.withTransaction(transactionManager)
.list({
idempotency_key: idempotencyKey.idempotency_key,
})
await manager.transaction(async (transactionManager) => {
const { key, error } = await idempotencyKeyService
.withTransaction(transactionManager)
.workStage(
idempotencyKey.idempotency_key,
async (transactionManager: EntityManager) => {
const swaps = await swapService
.withTransaction(transactionManager)
.list({
idempotency_key: idempotencyKey.idempotency_key,
})
if (!swaps.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Swap not found"
)
}
if (!swaps.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"Swap not found"
)
}
const swap = await swapService
.withTransaction(transactionManager)
.retrieve(swaps[0].id, {
select: defaultStoreSwapFields,
relations: defaultStoreSwapRelations,
})
const swap = await swapService
.withTransaction(transactionManager)
.retrieve(swaps[0].id, {
select: defaultStoreSwapFields,
relations: defaultStoreSwapRelations,
})
return {
response_code: 200,
response_body: { swap },
}
return {
response_code: 200,
response_body: { swap },
}
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
})
break
}
@@ -226,14 +233,15 @@ export default async (req, res) => {
}
default:
idempotencyKey = await idempotencyKeyService.update(
idempotencyKey.idempotency_key,
{
recovery_point: "finished",
response_code: 500,
response_body: { message: "Unknown recovery point" },
}
)
await manager.transaction(async (transactionManager) => {
idempotencyKey = await idempotencyKeyService
.withTransaction(transactionManager)
.update(idempotencyKey.idempotency_key, {
recovery_point: "finished",
response_code: 500,
response_body: { message: "Unknown recovery point" },
})
})
break
}
}
+1 -1
View File
@@ -1,4 +1,4 @@
import { EntityRepository, Repository } from "typeorm"
import { EntityRepository, Repository } from "typeorm"
import { ClaimOrder } from "../models/claim-order"
@EntityRepository(ClaimOrder)
@@ -117,6 +117,9 @@ describe("TaxProviderService", () => {
test("success", async () => {
container.taxRateService = {
withTransaction: function () {
return this
},
listByProduct: jest.fn(() => Promise.resolve([])),
}
@@ -155,6 +158,9 @@ describe("TaxProviderService", () => {
test("success - without product rates", async () => {
container.taxRateService = {
withTransaction: function () {
return this
},
listByProduct: jest.fn(() => Promise.resolve([])),
}
@@ -193,6 +199,9 @@ describe("TaxProviderService", () => {
test("success - with product rates", async () => {
container.taxRateService = {
withTransaction: function () {
return this
},
listByProduct: jest.fn(() =>
Promise.resolve([
{
@@ -1,12 +1,12 @@
import { MedusaError } from "medusa-core-utils"
import { BaseService } from "medusa-interfaces"
import { v4 } from "uuid"
import { TransactionBaseService } from "../interfaces"
const KEY_LOCKED_TIMEOUT = 1000
class IdempotencyKeyService extends BaseService {
class IdempotencyKeyService extends TransactionBaseService {
constructor({ manager, idempotencyKeyRepository }) {
super()
super({ manager, idempotencyKeyRepository })
/** @private @constant {EntityManager} */
this.manager_ = manager
+6 -4
View File
@@ -197,10 +197,12 @@ class SwapService extends BaseService {
}
if (cartRelations || cartSelects) {
const cart = await this.cartService_.retrieve(swap.cart_id, {
select: cartSelects,
relations: cartRelations,
})
const cart = await this.cartService_
.withTransaction(this.manager_)
.retrieve(swap.cart_id, {
select: cartSelects,
relations: cartRelations,
})
swap.cart = cart
}
+5 -3
View File
@@ -385,9 +385,11 @@ class TaxProviderService extends BaseService {
}
let toReturn: TaxServiceRate[] = []
const productRates = await this.taxRateService_.listByProduct(productId, {
region_id: region.id,
})
const productRates = await this.taxRateService_
.withTransaction(this.manager_)
.listByProduct(productId, {
region_id: region.id,
})
if (productRates.length > 0) {
toReturn = productRates.map((pr) => {
+21 -7
View File
@@ -1,6 +1,10 @@
import { MedusaError } from "medusa-core-utils"
import { BaseService } from "medusa-interfaces"
import { ITaxCalculationStrategy, TaxCalculationContext } from "../interfaces"
import {
ITaxCalculationStrategy,
TaxCalculationContext,
TransactionBaseService,
} from "../interfaces"
import { Cart } from "../models/cart"
import { Discount } from "../models/discount"
import { DiscountRuleType } from "../models/discount-rule"
@@ -18,6 +22,7 @@ import {
SubtotalOptions,
} from "../types/totals"
import TaxProviderService from "./tax-provider"
import { EntityManager } from "typeorm"
type ShippingMethodTotals = {
price: number
@@ -60,6 +65,7 @@ type GetLineItemTotalOptions = {
type TotalsServiceProps = {
taxProviderService: TaxProviderService
taxCalculationStrategy: ITaxCalculationStrategy
manager: EntityManager
}
type GetTotalsOptions = {
@@ -83,18 +89,27 @@ type CalculationContextOptions = {
* A service that calculates total and subtotals for orders, carts etc..
* @implements {BaseService}
*/
class TotalsService extends BaseService {
class TotalsService extends TransactionBaseService<TotalsService> {
protected manager_: EntityManager
protected transactionManager_: EntityManager
private taxProviderService_: TaxProviderService
private taxCalculationStrategy_: ITaxCalculationStrategy
constructor({
taxProviderService,
taxCalculationStrategy,
manager,
}: TotalsServiceProps) {
super()
super({
taxProviderService,
taxCalculationStrategy,
manager,
})
this.taxProviderService_ = taxProviderService
this.taxCalculationStrategy_ = taxCalculationStrategy
this.manager_ = manager
}
/**
@@ -757,10 +772,9 @@ class TotalsService extends BaseService {
}
taxLines = lineItem.tax_lines
} else {
const orderLines = await this.taxProviderService_.getTaxLines(
cartOrOrder.items,
calculationContext
)
const orderLines = await this.taxProviderService_
.withTransaction(this.manager_)
.getTaxLines(cartOrOrder.items, calculationContext)
taxLines = orderLines.filter((ol) => {
if ("item_id" in ol) {