chore(medusa): Add transactions in mutating actions in store domain (#1858)
This commit is contained in:
committed by
GitHub
parent
3fbe8d7d08
commit
7cb8095ed4
@@ -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,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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user