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

This commit is contained in:
Adrien de Peretti authored and GitHub committed 2022-07-28 11:48:55 +02:00
1 parent 3fbe8d7d08
commit 7cb8095ed4
25 files changed
+214 -64

No files matched your search

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