chore(medusa): Add transactions in mutating actions 2 (#1853)

* chore(medusa): Add transaction on mutation actions

* chore(medusa): continue refactoring

* chore(medusa): continue refactoring

* chore(medusa): continue refactoring

* feat(medusa): update invite service mock to provide a withTransaction

* feat(medusa): Include pr feedback

* feat(medusa): Cleanup idempotent places

* feat(medusa): Cleanup idempotent places

* feat(medusa): Better Cleanup idempotent places

* feat(meudsa): cleanup transaction

* fix(medusa): Create cart transaction usage

* fix(medusa): Use the right variable

* fix(medusa): Use the right variable

* fix(medusa): Transaction usage in cart creation flow
This commit is contained in:
Adrien de Peretti
2022-08-02 10:04:43 +02:00
committed by GitHub
parent b54d5178c9
commit 051bb16dd7
68 changed files with 883 additions and 542 deletions
@@ -4,6 +4,7 @@ import { validator } from "../../../../utils/validator"
import { IsEmail, IsNotEmpty, IsString } from "class-validator"
import AuthService from "../../../../services/auth"
import { MedusaError } from "medusa-core-utils"
import { EntityManager } from "typeorm";
/**
* @oas [post] /auth
@@ -37,10 +38,13 @@ export default async (req, res) => {
const validated = await validator(AdminPostAuthReq, req.body)
const authService: AuthService = req.scope.resolve("authService")
const result = await authService.authenticate(
validated.email,
validated.password
)
const manager: EntityManager = req.scope.resolve("manager")
const result = await manager.transaction(async (transactionManager) => {
return await authService.withTransaction(transactionManager).authenticate(
validated.email,
validated.password
)
})
if (result.success && result.user) {
// Add JWT to cookie
@@ -1,4 +1,5 @@
import { BatchJobService } from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [post] /batch-jobs/{id}/cancel
@@ -24,7 +25,12 @@ export default async (req, res) => {
let batch_job = req.batch_job
const batchJobService: BatchJobService = req.scope.resolve("batchJobService")
batch_job = await batchJobService.cancel(batch_job)
const manager: EntityManager = req.scope.resolve("manager")
batch_job = await manager.transaction(async (transactionManager) => {
return await batchJobService
.withTransaction(transactionManager)
.cancel(batch_job)
})
res.json({ batch_job })
}
@@ -1,4 +1,5 @@
import { BatchJobService } from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [post] /batch-jobs/{id}/confirm
@@ -25,7 +26,12 @@ export default async (req, res) => {
let batch_job = req.batch_job
const batchJobService: BatchJobService = req.scope.resolve("batchJobService")
batch_job = await batchJobService.confirm(batch_job)
const manager: EntityManager = req.scope.resolve("manager")
batch_job = await manager.transaction(async (transactionManager) => {
return await batchJobService
.withTransaction(transactionManager)
.confirm(batch_job)
})
res.json({ batch_job })
}
@@ -2,6 +2,7 @@ import { IsBoolean, IsObject, IsOptional, IsString } from "class-validator"
import BatchJobService from "../../../../services/batch-job"
import { validator } from "../../../../utils/validator"
import { BatchJob } from "../../../../models"
import { EntityManager } from "typeorm"
/**
* @oas [post] /batch-jobs
@@ -36,9 +37,12 @@ export default async (req, res) => {
const userId = req.user.id ?? req.user.userId
const batch_job = await batchJobService.create({
...toCreate,
created_by: userId,
const manager: EntityManager = req.scope.resolve("manager")
const batch_job = await manager.transaction(async (transactionManager) => {
return await batchJobService.withTransaction(transactionManager).create({
...toCreate,
created_by: userId,
})
})
res.status(201).json({ batch_job })
@@ -1,6 +1,7 @@
import { ArrayNotEmpty, IsString } from "class-validator"
import ProductCollectionService from "../../../../services/product-collection"
import { Request, Response } from "express"
import { EntityManager } from "typeorm";
/**
* @oas [post] /collections/{id}/products/batch
@@ -37,10 +38,13 @@ export default async (req: Request, res: Response) => {
"productCollectionService"
)
const collection = await productCollectionService.addProducts(
id,
validatedBody.product_ids
)
const manager: EntityManager = req.scope.resolve("manager")
const collection = await manager.transaction(async (transactionManager) => {
return await productCollectionService.withTransaction(transactionManager).addProducts(
id,
validatedBody.product_ids
)
})
res.status(200).json({ collection })
}
@@ -1,6 +1,7 @@
import { IsNotEmpty, IsObject, IsOptional, IsString } from "class-validator"
import ProductCollectionService from "../../../../services/product-collection"
import { Request, Response } from "express"
import { EntityManager } from "typeorm";
/**
* @oas [post] /collections
@@ -43,7 +44,11 @@ export default async (req: Request, res: Response) => {
"productCollectionService"
)
const created = await productCollectionService.create(validatedBody)
const manager: EntityManager = req.scope.resolve("manager")
const created = await manager.transaction(async (transactionManager) => {
return await productCollectionService.withTransaction(transactionManager).create(validatedBody)
})
const collection = await productCollectionService.retrieve(created.id)
res.status(200).json({ collection })
@@ -1,5 +1,6 @@
import ProductCollectionService from "../../../../services/product-collection"
import { Request, Response } from "express"
import { EntityManager } from "typeorm";
/**
* @oas [delete] /collections/{id}
@@ -33,7 +34,12 @@ export default async (req: Request, res: Response) => {
const productCollectionService: ProductCollectionService = req.scope.resolve(
"productCollectionService"
)
await productCollectionService.delete(id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await productCollectionService.withTransaction(transactionManager).delete(id)
})
res.json({
id,
@@ -1,6 +1,7 @@
import { ArrayNotEmpty, IsString } from "class-validator"
import ProductCollectionService from "../../../../services/product-collection"
import { Request, Response } from "express"
import { EntityManager } from "typeorm";
/**
* @oas [delete] /collections/{id}/products/batch
@@ -37,7 +38,10 @@ export default async (req: Request, res: Response) => {
"productCollectionService"
)
await productCollectionService.removeProducts(id, validatedBody.product_ids)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await productCollectionService.withTransaction(transactionManager).removeProducts(id, validatedBody.product_ids)
})
res.json({
id,
@@ -1,6 +1,7 @@
import { IsObject, IsOptional, IsString } from "class-validator"
import ProductCollectionService from "../../../../services/product-collection"
import { Request, Response } from "express"
import { EntityManager } from "typeorm";
/**
* @oas [post] /collections/{id}
* operationId: "PostCollectionsCollection"
@@ -43,7 +44,11 @@ export default async (req: Request, res: Response) => {
"productCollectionService"
)
const updated = await productCollectionService.update(id, validatedBody)
const manager: EntityManager = req.scope.resolve("manager")
const updated = await manager.transaction(async (transactionManager) => {
return await productCollectionService.withTransaction(transactionManager).update(id, validatedBody)
})
const collection = await productCollectionService.retrieve(updated.id)
res.status(200).json({ collection })
@@ -4,6 +4,7 @@ import { CustomerGroupService } from "../../../../services"
import { CustomerGroupsBatchCustomer } from "../../../../types/customer-groups"
import { validator } from "../../../../utils/validator"
import { Request, Response } from "express"
import { EntityManager } from "typeorm"
/**
* @oas [post] /customer-groups/{id}/customers/batch
@@ -38,10 +39,18 @@ export default async (req: Request, res: Response) => {
"customerGroupService"
)
const customer_group = await customerGroupService.addCustomers(
id,
validated.customer_ids.map(({ id }) => id)
const manager: EntityManager = req.scope.resolve("manager")
const customer_group = await manager.transaction(
async (transactionManager) => {
return await customerGroupService
.withTransaction(transactionManager)
.addCustomers(
id,
validated.customer_ids.map(({ id }) => id)
)
}
)
res.status(200).json({ customer_group })
}
@@ -2,6 +2,7 @@ import { IsObject, IsOptional, IsString } from "class-validator"
import { CustomerGroupService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { Request, Response } from "express"
import { EntityManager } from "typeorm"
/**
* @oas [post] /customer-groups
@@ -32,7 +33,15 @@ export default async (req: Request, res: Response) => {
"customerGroupService"
)
const customerGroup = await customerGroupService.create(validated)
const manager: EntityManager = req.scope.resolve("manager")
const customerGroup = await manager.transaction(
async (transactionManager) => {
return await customerGroupService
.withTransaction(transactionManager)
.create(validated)
}
)
res.status(200).json({ customer_group: customerGroup })
}
@@ -1,5 +1,6 @@
import { CustomerGroupService } from "../../../../services"
import { Request, Response } from "express"
import { EntityManager } from "typeorm"
/**
* @oas [delete] /customer-groups/{id}
@@ -35,7 +36,12 @@ export default async (req: Request, res: Response) => {
"customerGroupService"
)
await customerGroupService.delete(id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await customerGroupService
.withTransaction(transactionManager)
.delete(id)
})
res.json({
id: id,
@@ -4,6 +4,7 @@ import { CustomerGroupService } from "../../../../services"
import { CustomerGroupsBatchCustomer } from "../../../../types/customer-groups"
import { validator } from "../../../../utils/validator"
import { Request, Response } from "express"
import { EntityManager } from "typeorm"
/**
* @oas [delete] /customer-groups/{id}/customers/batch
@@ -38,10 +39,18 @@ export default async (req: Request, res: Response) => {
"customerGroupService"
)
const customer_group = await customerGroupService.removeCustomer(
id,
validated.customer_ids.map(({ id }) => id)
const manager: EntityManager = req.scope.resolve("manager")
const customer_group = await manager.transaction(
async (transactionManager) => {
return await customerGroupService
.withTransaction(transactionManager)
.removeCustomer(
id,
validated.customer_ids.map(({ id }) => id)
)
}
)
res.status(200).json({ customer_group })
}
@@ -5,6 +5,7 @@ import { CustomerGroupService } from "../../../../services"
import { FindParams } from "../../../../types/common"
import { validator } from "../../../../utils/validator"
import { Request, Response } from "express"
import { EntityManager } from "typeorm"
/**
* @oas [post] /customer-groups/{id}
@@ -42,7 +43,12 @@ export default async (req: Request, res: Response) => {
"customerGroupService"
)
await customerGroupService.update(id, validatedBody)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await customerGroupService
.withTransaction(transactionManager)
.update(id, validatedBody)
})
let expandFields: string[] = []
if (validatedQuery.expand) {
@@ -1,6 +1,7 @@
import { IsEmail, IsObject, IsOptional, IsString } from "class-validator"
import { CustomerService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /customers
@@ -30,7 +31,12 @@ export default async (req, res) => {
const validated = await validator(AdminPostCustomersReq, req.body)
const customerService: CustomerService = req.scope.resolve("customerService")
const customer = await customerService.create(validated)
const manager: EntityManager = req.scope.resolve("manager")
const customer = await manager.transaction(async (transactionManager) => {
return await customerService
.withTransaction(transactionManager)
.create(validated)
})
res.status(201).json({ customer })
}
@@ -12,6 +12,7 @@ import { validator } from "../../../../utils/validator"
import { defaultAdminCustomersRelations } from "."
import { Type } from "class-transformer"
import { FindParams } from "../../../../types/common"
import { EntityManager } from "typeorm"
/**
* @oas [post] /customers/{id}
@@ -83,7 +84,12 @@ export default async (req, res) => {
)
}
await customerService.update(id, validatedBody)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await customerService
.withTransaction(transactionManager)
.update(id, validatedBody)
})
let expandFields: string[] = []
if (validatedQuery.expand) {
@@ -1,6 +1,7 @@
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
import { Discount } from "../../../.."
import DiscountService from "../../../../services/discount"
import { EntityManager } from "typeorm"
/**
* @oas [post] /discounts/{id}/regions/{region_id}
* operationId: "PostDiscountsDiscountRegionsRegion"
@@ -26,7 +27,13 @@ export default async (req, res) => {
const { discount_id, region_id } = req.params
const discountService: DiscountService = req.scope.resolve("discountService")
await discountService.addRegion(discount_id, region_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await discountService
.withTransaction(transactionManager)
.addRegion(discount_id, region_id)
})
const discount: Discount = await discountService.retrieve(discount_id, {
select: defaultAdminDiscountsFields,
@@ -1,12 +1,12 @@
import { IsOptional, IsString } from "class-validator"
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
import { Discount } from "../../../../models/discount"
import { DiscountConditionOperator } from "../../../../models/discount-condition"
import { Discount, DiscountConditionOperator } from "../../../../models"
import { DiscountService } from "../../../../services"
import DiscountConditionService from "../../../../services/discount-condition"
import { AdminUpsertConditionsReq } from "../../../../types/discount"
import { getRetrieveConfig } from "../../../../utils/get-query-config"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /discounts/{discount_id}/conditions
* operationId: "PostDiscountsDiscountConditions"
@@ -74,9 +74,14 @@ export default async (req, res) => {
let discount = await discountService.retrieve(discount_id)
await conditionService.upsertCondition({
...validatedCondition,
rule_id: discount.rule_id,
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await conditionService
.withTransaction(transactionManager)
.upsertCondition({
...validatedCondition,
rule_id: discount.rule_id,
})
})
const config = getRetrieveConfig<Discount>(
@@ -13,9 +13,12 @@ import {
ValidateNested,
} from "class-validator"
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
import { AllocationType, DiscountRuleType } from "../../../../models"
import { Discount } from "../../../../models/discount"
import { DiscountConditionOperator } from "../../../../models/discount-condition"
import {
AllocationType,
DiscountRuleType,
Discount,
DiscountConditionOperator,
} from "../../../../models"
import DiscountService from "../../../../services/discount"
import { AdminUpsertConditionsReq } from "../../../../types/discount"
import { getRetrieveConfig } from "../../../../utils/get-query-config"
@@ -23,6 +26,7 @@ import { validator } from "../../../../utils/validator"
import { IsGreaterThan } from "../../../../utils/validators/greater-than"
import { IsISO8601Duration } from "../../../../utils/validators/iso8601-duration"
import { AdminPostDiscountsDiscountParams } from "./update-discount"
import { EntityManager } from "typeorm"
/**
* @oas [post] /discounts
* operationId: "PostDiscounts"
@@ -92,7 +96,12 @@ export default async (req, res) => {
const discountService: DiscountService = req.scope.resolve("discountService")
const created = await discountService.create(validated)
const manager: EntityManager = req.scope.resolve("manager")
const created = await manager.transaction(async (transactionManager) => {
return await discountService
.withTransaction(transactionManager)
.create(validated)
})
const config = getRetrieveConfig<Discount>(
defaultAdminDiscountsFields,
@@ -8,6 +8,7 @@ import {
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
import DiscountService from "../../../../services/discount"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /discounts/{id}/dynamic-codes
* operationId: "PostDiscountsDiscountDynamicCodes"
@@ -40,10 +41,12 @@ export default async (req, res) => {
)
const discountService: DiscountService = req.scope.resolve("discountService")
const created = await discountService.createDynamicCode(
discount_id,
validated
)
const manager: EntityManager = req.scope.resolve("manager")
const created = await manager.transaction(async (transactionManager) => {
return await discountService
.withTransaction(transactionManager)
.createDynamicCode(discount_id, validated)
})
const discount = await discountService.retrieve(created.id, {
select: defaultAdminDiscountsFields,
@@ -6,6 +6,7 @@ import { DiscountService } from "../../../../services"
import DiscountConditionService from "../../../../services/discount-condition"
import { getRetrieveConfig } from "../../../../utils/get-query-config"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [delete] /discounts/{discount_id}/conditions/{condition_id}
@@ -79,7 +80,12 @@ export default async (req, res) => {
)
}
await conditionService.delete(condition_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await conditionService
.withTransaction(transactionManager)
.delete(condition_id)
})
const config = getRetrieveConfig<Discount>(
defaultAdminDiscountsFields,
@@ -1,4 +1,5 @@
import DiscountService from "../../../../services/discount"
import { EntityManager } from "typeorm"
/**
* @oas [delete] /discounts/{id}
@@ -30,7 +31,12 @@ export default async (req, res) => {
const { discount_id } = req.params
const discountService: DiscountService = req.scope.resolve("discountService")
await discountService.delete(discount_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await discountService
.withTransaction(transactionManager)
.delete(discount_id)
})
res.json({
id: discount_id,
@@ -1,5 +1,6 @@
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
import DiscountService from "../../../../services/discount"
import { EntityManager } from "typeorm"
/**
* @oas [delete] /discounts/{id}/dynamic-codes/{code}
@@ -26,7 +27,12 @@ export default async (req, res) => {
const { discount_id, code } = req.params
const discountService: DiscountService = req.scope.resolve("discountService")
await discountService.deleteDynamicCode(discount_id, code)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await discountService
.withTransaction(transactionManager)
.deleteDynamicCode(discount_id, code)
})
const discount = await discountService.retrieve(discount_id, {
select: defaultAdminDiscountsFields,
@@ -1,5 +1,6 @@
import DiscountService from "../../../../services/discount"
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
import { EntityManager } from "typeorm"
/**
* @oas [delete] /discounts/{id}/regions/{region_id}
* operationId: "DeleteDiscountsDiscountRegionsRegion"
@@ -25,7 +26,12 @@ export default async (req, res) => {
const { discount_id, region_id } = req.params
const discountService: DiscountService = req.scope.resolve("discountService")
await discountService.removeRegion(discount_id, region_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await discountService
.withTransaction(transactionManager)
.removeRegion(discount_id, region_id)
})
const discount = await discountService.retrieve(discount_id, {
select: defaultAdminDiscountsFields,
@@ -1,11 +1,12 @@
import { IsOptional, IsString } from "class-validator"
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
import { Discount } from "../../../../models/discount"
import { Discount } from "../../../../models"
import { DiscountService } from "../../../../services"
import DiscountConditionService from "../../../../services/discount-condition"
import { AdminUpsertConditionsReq } from "../../../../types/discount"
import { getRetrieveConfig } from "../../../../utils/get-query-config"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /discounts/{discount_id}/conditions/{condition_id}
* operationId: "PostDiscountsDiscountConditionsCondition"
@@ -82,7 +83,12 @@ export default async (req, res) => {
id: condition.id,
}
await conditionService.upsertCondition(updateObj)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await conditionService
.withTransaction(transactionManager)
.upsertCondition(updateObj)
})
const config = getRetrieveConfig<Discount>(
defaultAdminDiscountsFields,
@@ -14,14 +14,14 @@ import {
} from "class-validator"
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
import { AllocationType } from "../../../../models"
import { Discount } from "../../../../models/discount"
import { DiscountConditionOperator } from "../../../../models/discount-condition"
import { Discount, DiscountConditionOperator } from "../../../../models"
import DiscountService from "../../../../services/discount"
import { AdminUpsertConditionsReq } from "../../../../types/discount"
import { getRetrieveConfig } from "../../../../utils/get-query-config"
import { validator } from "../../../../utils/validator"
import { IsGreaterThan } from "../../../../utils/validators/greater-than"
import { IsISO8601Duration } from "../../../../utils/validators/iso8601-duration"
import { EntityManager } from "typeorm"
/**
* @oas [post] /discounts/{id}
@@ -84,7 +84,12 @@ export default async (req, res) => {
const discountService: DiscountService = req.scope.resolve("discountService")
await discountService.update(discount_id, validated)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await discountService
.withTransaction(transactionManager)
.update(discount_id, validated)
})
const config = getRetrieveConfig<Discount>(
defaultAdminDiscountsFields,
@@ -20,6 +20,7 @@ import { DraftOrder } from "../../../.."
import { DraftOrderService } from "../../../../services"
import { AddressPayload } from "../../../../types/common"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /draft-orders
* operationId: "PostDraftOrders"
@@ -127,7 +128,15 @@ export default async (req, res) => {
const draftOrderService: DraftOrderService =
req.scope.resolve("draftOrderService")
let draftOrder: DraftOrder = await draftOrderService.create(value)
const manager: EntityManager = req.scope.resolve("manager")
let draftOrder: DraftOrder = await manager.transaction(
async (transactionManager) => {
return await draftOrderService
.withTransaction(transactionManager)
.create(value)
}
)
draftOrder = await draftOrderService.retrieve(draftOrder.id, {
relations: defaultAdminDraftOrdersRelations,
@@ -90,12 +90,14 @@ export default async (req, res) => {
}
if (validated.variant_id) {
const line = await lineItemService.generate(
validated.variant_id,
draftOrder.cart.region_id,
validated.quantity,
{ metadata: validated.metadata, unit_price: validated.unit_price }
)
const line = await lineItemService
.withTransaction(manager)
.generate(
validated.variant_id,
draftOrder.cart.region_id,
validated.quantity,
{ metadata: validated.metadata, unit_price: validated.unit_price }
)
await cartService
.withTransaction(manager)
@@ -1,4 +1,5 @@
import { DraftOrderService } from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [delete] /draft-orders/{id}
* operationId: DeleteDraftOrdersDraftOrder
@@ -30,7 +31,13 @@ export default async (req, res) => {
const draftOrderService: DraftOrderService =
req.scope.resolve("draftOrderService")
await draftOrderService.delete(id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await draftOrderService
.withTransaction(transactionManager)
.delete(id)
})
res.json({
id,
@@ -70,7 +70,7 @@ export default async (req, res) => {
.withTransaction(manager)
.setPaymentSession(cart.id, "system")
await cartService.createTaxLines(cart.id)
await cartService.withTransaction(manager).createTaxLines(cart.id)
await cartService.withTransaction(manager).authorizePayment(cart.id)
@@ -15,6 +15,9 @@ import { CartService, DraftOrderService } from "../../../../services"
import { Type } from "class-transformer"
import { AddressPayload } from "../../../../types/common"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
import { DraftOrderStatus } from "../../../../models"
/**
* @oas [post] /admin/draft-orders/{id}
* operationId: PostDraftOrdersDraftOrder
@@ -80,21 +83,28 @@ export default async (req, res) => {
const draftOrder = await draftOrderService.retrieve(id)
if (draftOrder.status === "completed") {
if (draftOrder.status === DraftOrderStatus.COMPLETED) {
throw new MedusaError(
MedusaError.Types.NOT_ALLOWED,
"You are only allowed to update open draft orders"
)
}
if (validated.no_notification_order !== undefined) {
await draftOrderService.update(draftOrder.id, {
no_notification_order: validated.no_notification_order,
})
delete validated.no_notification_order
}
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
if (validated.no_notification_order !== undefined) {
await draftOrderService
.withTransaction(transactionManager)
.update(draftOrder.id, {
no_notification_order: validated.no_notification_order,
})
delete validated.no_notification_order
}
await cartService.update(draftOrder.cart_id, validated)
await cartService
.withTransaction(transactionManager)
.update(draftOrder.cart_id, validated)
})
draftOrder.cart = await cartService.retrieve(draftOrder.cart_id, {
relations: defaultAdminDraftOrdersCartRelations,
@@ -3,6 +3,7 @@ import { IsBoolean, IsDate, IsInt, IsOptional, IsString } from "class-validator"
import { defaultAdminGiftCardFields, defaultAdminGiftCardRelations } from "."
import { GiftCardService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /gift-cards
@@ -50,9 +51,12 @@ export default async (req, res) => {
const giftCardService: GiftCardService = req.scope.resolve("giftCardService")
const newly = await giftCardService.create({
...validated,
balance: validated.value,
const manager: EntityManager = req.scope.resolve("manager")
const newly = await manager.transaction(async (transactionManager) => {
return await giftCardService.withTransaction(transactionManager).create({
...validated,
balance: validated.value,
})
})
const giftCard = await giftCardService.retrieve(newly.id, {
@@ -1,3 +1,5 @@
import { EntityManager } from "typeorm"
/**
* @oas [delete] /gift-cards/{id}
* operationId: "DeleteGiftCardsGiftCard"
@@ -28,7 +30,10 @@ export default async (req, res) => {
const { id } = req.params
const giftCardService = req.scope.resolve("giftCardService")
await giftCardService.delete(id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await giftCardService.withTransaction(transactionManager).delete(id)
})
res.json({
id,
@@ -3,6 +3,7 @@ import { IsBoolean, IsDate, IsInt, IsOptional, IsString } from "class-validator"
import { defaultAdminGiftCardFields, defaultAdminGiftCardRelations } from "."
import { GiftCardService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /gift-cards/{id}
@@ -54,7 +55,12 @@ export default async (req, res) => {
const giftCardService: GiftCardService = req.scope.resolve("giftCardService")
await giftCardService.update(id, validated)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await giftCardService
.withTransaction(transactionManager)
.update(id, validated)
})
const giftCard = await giftCardService.retrieve(id, {
select: defaultAdminGiftCardFields,
@@ -2,6 +2,7 @@ import { Type } from "class-transformer"
import { IsNotEmpty, IsString, ValidateNested } from "class-validator"
import InviteService from "../../../../services/invite"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /invites/accept
@@ -47,7 +48,12 @@ export default async (req, res) => {
const inviteService: InviteService = req.scope.resolve("inviteService")
await inviteService.accept(validated.token, validated.user)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await inviteService
.withTransaction(transactionManager)
.accept(validated.token, validated.user)
})
res.sendStatus(200)
}
@@ -2,6 +2,7 @@ import { IsEmail, IsEnum } from "class-validator"
import { UserRoles } from "../../../../models/user"
import InviteService from "../../../../services/invite"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /invites
@@ -34,7 +35,13 @@ export default async (req, res) => {
const inviteService: InviteService = req.scope.resolve("inviteService")
await inviteService.create(validated.user, validated.role)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await inviteService
.withTransaction(transactionManager)
.create(validated.user, validated.role)
})
res.sendStatus(200)
}
export class AdminPostInvitesReq {
@@ -1,4 +1,5 @@
import InviteService from "../../../../services/invite"
import { EntityManager } from "typeorm"
/**
* @oas [delete] /invites/{invite_id}
@@ -18,7 +19,10 @@ export default async (req, res) => {
const { invite_id } = req.params
const inviteService: InviteService = req.scope.resolve("inviteService")
await inviteService.delete(invite_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
await inviteService.withTransaction(transactionManager).delete(invite_id)
})
res.status(200).send({
id: invite_id,
@@ -1,4 +1,5 @@
import InviteService from "../../../../services/invite"
import { EntityManager } from "typeorm"
/**
* @oas [post] /invites/{invite_id}/resend
@@ -18,7 +19,10 @@ export default async (req, res) => {
const { invite_id } = req.params
const inviteService: InviteService = req.scope.resolve("inviteService")
await inviteService.resend(invite_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
await inviteService.withTransaction(transactionManager).resend(invite_id)
})
res.sendStatus(200)
}
@@ -1,6 +1,7 @@
import { IsNotEmpty, IsString } from "class-validator"
import NoteService from "../../../../services/note"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /notes
@@ -42,11 +43,14 @@ export default async (req, res) => {
const noteService: NoteService = req.scope.resolve("noteService")
const result = await noteService.create({
resource_id: validated.resource_id,
resource_type: validated.resource_type,
value: validated.value,
author_id: userId,
const manager: EntityManager = req.scope.resolve("manager")
const result = await manager.transaction(async (transactionManager) => {
return await noteService.withTransaction(transactionManager).create({
resource_id: validated.resource_id,
resource_type: validated.resource_type,
value: validated.value,
author_id: userId,
})
})
res.status(200).json({ note: result })
@@ -1,4 +1,5 @@
import NoteService from "../../../../services/note"
import { EntityManager } from "typeorm"
/**
* @oas [delete] /notes/{id}
@@ -28,7 +29,10 @@ export default async (req, res) => {
const { id } = req.params
const noteService: NoteService = req.scope.resolve("noteService")
await noteService.delete(id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await noteService.withTransaction(transactionManager).delete(id)
})
res.status(200).json({ id, object: "note", deleted: true })
}
@@ -1,6 +1,7 @@
import { IsString } from "class-validator"
import NoteService from "../../../../services/note"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /notes/{id}
@@ -39,7 +40,12 @@ export default async (req, res) => {
const validated = await validator(AdminPostNotesNoteReq, req.body)
const noteService: NoteService = req.scope.resolve("noteService")
const note = await noteService.update(id, validated.value)
const manager: EntityManager = req.scope.resolve("manager")
const note = await manager.transaction(async (transactionManager) => {
return await noteService
.withTransaction(transactionManager)
.update(id, validated.value)
})
res.status(200).json({ note })
}
@@ -7,6 +7,7 @@ import {
import { validator } from "../../../../utils/validator"
import { NotificationService } from "../../../../services"
import { Notification } from "../../../../models"
import { EntityManager } from "typeorm"
/**
* @oas [post] /notifications/{id}/resend
@@ -54,7 +55,12 @@ export default async (req, res) => {
config.to = validatedBody.to
}
await notificationService.resend(id, config)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await notificationService
.withTransaction(transactionManager)
.resend(id, config)
})
const notification = await notificationService.retrieve(id, {
select: defaultAdminNotificationsFields as (keyof Notification)[],
@@ -8,6 +8,7 @@ import {
import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "."
import { OrderService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/shipping-methods
@@ -42,14 +43,14 @@ export default async (req, res) => {
const orderService: OrderService = req.scope.resolve("orderService")
await orderService.addShippingMethod(
id,
validated.option_id,
validated.data,
{
price: validated.price,
}
)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await orderService
.withTransaction(transactionManager)
.addShippingMethod(id, validated.option_id, validated.data, {
price: validated.price,
})
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -1,4 +1,5 @@
import { OrderService } from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/archive
@@ -25,7 +26,10 @@ export default async (req, res) => {
const orderService: OrderService = req.scope.resolve("orderService")
await orderService.archive(id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await orderService.withTransaction(transactionManager).archive(id)
})
const order = await orderService.retrieve(id, {
relations: ["region", "customer", "swaps"],
@@ -1,6 +1,7 @@
import { MedusaError } from "medusa-core-utils"
import { defaultAdminOrdersRelations, defaultAdminOrdersFields } from "."
import { ClaimService, OrderService } from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/claims/{claim_id}/cancel
@@ -38,7 +39,12 @@ export default async (req, res) => {
)
}
await claimService.cancel(claim_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await claimService
.withTransaction(transactionManager)
.cancel(claim_id)
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -5,6 +5,7 @@ import {
FulfillmentService,
OrderService,
} from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/claims/{claim_id}/fulfillments/{fulfillment_id}/cancel
@@ -54,7 +55,12 @@ export default async (req, res) => {
)
}
await claimService.cancelFulfillment(fulfillment_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await claimService
.withTransaction(transactionManager)
.cancelFulfillment(fulfillment_id)
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -5,6 +5,7 @@ import {
OrderService,
SwapService,
} from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/swaps/{swap_id}/fulfillments/{fulfillment_id}/cancel
@@ -54,7 +55,12 @@ export default async (req, res) => {
)
}
await swapService.cancelFulfillment(fulfillment_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await swapService
.withTransaction(transactionManager)
.cancelFulfillment(fulfillment_id)
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -1,6 +1,7 @@
import { MedusaError } from "medusa-core-utils"
import { defaultAdminOrdersRelations, defaultAdminOrdersFields } from "."
import { FulfillmentService, OrderService } from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/fulfillments/{fulfillment_id}/cancel
@@ -39,7 +40,12 @@ export default async (req, res) => {
)
}
await orderService.cancelFulfillment(fulfillment_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await orderService
.withTransaction(transactionManager)
.cancelFulfillment(fulfillment_id)
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -1,5 +1,6 @@
import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "."
import { OrderService } from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/cancel
@@ -25,7 +26,10 @@ export default async (req, res) => {
const { id } = req.params
const orderService: OrderService = req.scope.resolve("orderService")
await orderService.cancel(id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await orderService.withTransaction(transactionManager).cancel(id)
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -1,6 +1,7 @@
import { MedusaError } from "medusa-core-utils"
import { defaultAdminOrdersRelations, defaultAdminOrdersFields } from "."
import { OrderService, SwapService } from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/swaps/{swap_id}/cancel
@@ -38,7 +39,10 @@ export default async (req, res) => {
)
}
await swapService.cancel(swap_id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await swapService.withTransaction(transactionManager).cancel(swap_id)
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -1,5 +1,6 @@
import { defaultAdminOrdersRelations, defaultAdminOrdersFields } from "."
import { OrderService } from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/capture
@@ -26,7 +27,12 @@ export default async (req, res) => {
const orderService: OrderService = req.scope.resolve("orderService")
await orderService.capturePayment(id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await orderService
.withTransaction(transactionManager)
.capturePayment(id)
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -1,4 +1,5 @@
import { OrderService } from "../../../../services"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/complete
@@ -25,7 +26,12 @@ export default async (req, res) => {
const orderService: OrderService = req.scope.resolve("orderService")
await orderService.completeOrder(id)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await orderService
.withTransaction(transactionManager)
.completeOrder(id)
})
const order = await orderService.retrieve(id, {
relations: ["region", "customer", "swaps"],
@@ -2,6 +2,7 @@ import { IsArray, IsNotEmpty, IsOptional, IsString } from "class-validator"
import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "."
import { ClaimService, OrderService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/claims/{claim_id}/shipments
@@ -50,11 +51,16 @@ export default async (req, res) => {
const orderService: OrderService = req.scope.resolve("orderService")
const claimService: ClaimService = req.scope.resolve("claimService")
await claimService.createShipment(
claim_id,
validated.fulfillment_id,
validated.tracking_numbers?.map((n) => ({ tracking_number: n }))
)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await claimService
.withTransaction(transactionManager)
.createShipment(
claim_id,
validated.fulfillment_id,
validated.tracking_numbers?.map((n) => ({ tracking_number: n }))
)
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -16,6 +16,7 @@ import { AddressPayload } from "../../../../types/common"
import { validator } from "../../../../utils/validator"
import { ClaimTypeValue } from "../../../../types/claim"
import { ClaimType, ClaimReason } from "../../../../models"
import { EntityManager } from "typeorm"
/**
* @oas [post] /order/{id}/claims
@@ -136,17 +137,17 @@ export default async (req, res) => {
const value = await validator(AdminPostOrdersOrderClaimsReq, req.body)
const 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
@@ -165,147 +166,150 @@ 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(id, {
relations: [
"customer",
"shipping_address",
"region",
"items",
"items.tax_lines",
"discounts",
"discounts.rule",
"claims",
"claims.additional_items",
"claims.additional_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(id, {
relations: [
"customer",
"shipping_address",
"region",
"items",
"items.tax_lines",
"discounts",
"discounts.rule",
"claims",
"claims.additional_items",
"claims.additional_items.tax_lines",
"swaps",
"swaps.additional_items",
"swaps.additional_items.tax_lines",
],
})
await claimService.withTransaction(manager).create({
idempotency_key: idempotencyKey.idempotency_key,
order,
type: value.type,
shipping_address: value.shipping_address,
claim_items: value.claim_items,
return_shipping: value.return_shipping,
additional_items: value.additional_items,
shipping_methods: value.shipping_methods,
no_notification: value.no_notification,
metadata: value.metadata,
})
await claimService.withTransaction(manager).create({
idempotency_key: idempotencyKey.idempotency_key,
order,
type: value.type,
shipping_address: value.shipping_address,
claim_items: value.claim_items,
return_shipping: value.return_shipping,
additional_items: value.additional_items,
shipping_methods: value.shipping_methods,
no_notification: value.no_notification,
metadata: value.metadata,
return {
recovery_point: "claim_created",
}
})
return {
recovery_point: "claim_created",
}
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
})
break
}
case "claim_created": {
const { key, error } = await idempotencyKeyService.workStage(
idempotencyKey.idempotency_key,
async (manager) => {
let claim = await claimService.withTransaction(manager).list({
idempotency_key: idempotencyKey.idempotency_key,
await manager.transaction(async (transactionManager) => {
const { key, error } = await idempotencyKeyService
.withTransaction(transactionManager)
.workStage(idempotencyKey.idempotency_key, async (manager) => {
let claim = await claimService.withTransaction(manager).list({
idempotency_key: idempotencyKey.idempotency_key,
})
if (!claim.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Claim not found`
)
}
claim = claim[0]
if (claim.type === "refund") {
await claimService
.withTransaction(manager)
.processRefund(claim.id)
}
return {
recovery_point: "refund_handled",
}
})
if (!claim.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Claim not found`
)
}
claim = claim[0]
if (claim.type === "refund") {
await claimService
.withTransaction(manager)
.processRefund(claim.id)
}
return {
recovery_point: "refund_handled",
}
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
})
break
}
case "refund_handled": {
const { key, error } = await idempotencyKeyService.workStage(
idempotencyKey.idempotency_key,
async (manager) => {
let order = await orderService
.withTransaction(manager)
.retrieve(id, {
relations: ["items", "discounts"],
await manager.transaction(async (transactionManager) => {
const { key, error } = await idempotencyKeyService
.withTransaction(transactionManager)
.workStage(idempotencyKey.idempotency_key, async (manager) => {
let order = await orderService
.withTransaction(manager)
.retrieve(id, {
relations: ["items", "discounts"],
})
let claim = await claimService.withTransaction(manager).list(
{
idempotency_key: idempotencyKey.idempotency_key,
},
{
relations: ["return_order"],
}
)
if (!claim.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Claim not found`
)
}
claim = claim[0]
if (claim.return_order) {
await returnService
.withTransaction(manager)
.fulfill(claim.return_order.id)
}
order = await orderService.withTransaction(manager).retrieve(id, {
select: defaultAdminOrdersFields,
relations: defaultAdminOrdersRelations,
})
let claim = await claimService.withTransaction(manager).list(
{
idempotency_key: idempotencyKey.idempotency_key,
},
{
relations: ["return_order"],
return {
response_code: 200,
response_body: { order },
}
)
if (!claim.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Claim not found`
)
}
claim = claim[0]
if (claim.return_order) {
await returnService
.withTransaction(manager)
.fulfill(claim.return_order.id)
}
order = await orderService.withTransaction(manager).retrieve(id, {
select: defaultAdminOrdersFields,
relations: defaultAdminOrdersRelations,
})
return {
response_code: 200,
response_body: { order },
}
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
})
break
}
@@ -315,14 +319,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
}
}
@@ -12,6 +12,7 @@ import {
import { defaultAdminOrdersRelations, defaultAdminOrdersFields } from "."
import { OrderService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/fulfillments
* operationId: "PostOrdersOrderFulfillments"
@@ -66,9 +67,14 @@ export default async (req, res) => {
const orderService: OrderService = req.scope.resolve("orderService")
await orderService.createFulfillment(id, validated.items, {
metadata: validated.metadata,
no_notification: validated.no_notification,
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await orderService
.withTransaction(transactionManager)
.createFulfillment(id, validated.items, {
metadata: validated.metadata,
no_notification: validated.no_notification,
})
})
const order = await orderService.retrieve(id, {
@@ -9,6 +9,7 @@ import { defaultAdminOrdersRelations, defaultAdminOrdersFields } from "."
import { OrderService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { TrackingLink } from "../../../../models"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/shipment
* operationId: "PostOrdersOrderShipment"
@@ -54,17 +55,22 @@ export default async (req, res) => {
const orderService: OrderService = req.scope.resolve("orderService")
await orderService.createShipment(
id,
validated.fulfillment_id,
validated.tracking_numbers?.map((n) => ({
tracking_number: n,
})) as TrackingLink[],
{
metadata: {},
no_notification: validated.no_notification,
}
)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await orderService
.withTransaction(transactionManager)
.createShipment(
id,
validated.fulfillment_id,
validated.tracking_numbers?.map((n) => ({
tracking_number: n,
})) as TrackingLink[],
{
metadata: {},
no_notification: validated.no_notification,
}
)
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -8,6 +8,7 @@ import {
import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "."
import { OrderService, SwapService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/swaps/{swap_id}/shipments
* operationId: "PostOrdersOrderSwapsSwapShipments"
@@ -58,12 +59,15 @@ export default async (req, res) => {
const orderService: OrderService = req.scope.resolve("orderService")
const swapService: SwapService = req.scope.resolve("swapService")
await swapService.createShipment(
swap_id,
validated.fulfillment_id,
validated.tracking_numbers?.map((n) => ({ tracking_number: n })),
{ no_notification: validated.no_notification }
)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await swapService.withTransaction(transactionManager).createShipment(
swap_id,
validated.fulfillment_id,
validated.tracking_numbers?.map((n) => ({ tracking_number: n })),
{ no_notification: validated.no_notification }
)
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -115,17 +115,20 @@ export default async (req, res) => {
const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve(
"idempotencyKeyService"
)
const orderService: OrderService = req.scope.resolve("orderService")
const swapService: SwapService = req.scope.resolve("swapService")
const returnService: ReturnService = req.scope.resolve("returnService")
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
@@ -134,108 +137,111 @@ export default async (req, res) => {
res.setHeader("Access-Control-Expose-Headers", "Idempotency-Key")
res.setHeader("Idempotency-Key", idempotencyKey.idempotency_key)
const orderService: OrderService = req.scope.resolve("orderService")
const swapService: SwapService = req.scope.resolve("swapService")
const returnService: ReturnService = req.scope.resolve("returnService")
let inProgress = true
let err = false
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(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(id, {
select: ["refunded_total", "total"],
relations: [
"items",
"items.tax_lines",
"swaps",
"swaps.additional_items",
"swaps.additional_items.tax_lines",
],
})
const swap = await swapService
.withTransaction(manager)
.create(
order,
validated.return_items,
validated.additional_items,
validated.return_shipping,
{
idempotency_key: idempotencyKey.idempotency_key,
no_notification: validated.no_notification,
allow_backorder: validated.allow_backorder,
}
)
const swap = await swapService
.withTransaction(manager)
.create(
order,
validated.return_items,
validated.additional_items,
validated.return_shipping,
{
idempotency_key: idempotencyKey.idempotency_key,
no_notification: validated.no_notification,
allow_backorder: validated.allow_backorder,
}
)
await swapService
.withTransaction(manager)
.createCart(swap.id, validated.custom_shipping_options)
await swapService
.withTransaction(manager)
.createCart(swap.id, validated.custom_shipping_options)
const returnOrder = await returnService
.withTransaction(manager)
.retrieveBySwap(swap.id)
const returnOrder = await returnService
.withTransaction(manager)
.retrieveBySwap(swap.id)
await returnService.withTransaction(manager).fulfill(returnOrder.id)
await returnService
.withTransaction(manager)
.fulfill(returnOrder.id)
return {
recovery_point: "swap_created",
}
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 order = await orderService
.withTransaction(transactionManager)
.retrieve(id, {
select: defaultAdminOrdersFields,
relations: defaultAdminOrdersRelations,
})
const order = await orderService
.withTransaction(transactionManager)
.retrieve(id, {
select: defaultAdminOrdersFields,
relations: defaultAdminOrdersRelations,
})
return {
response_code: 200,
response_body: { order },
}
return {
response_code: 200,
response_body: { order },
}
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
})
break
}
@@ -245,14 +251,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
}
}
@@ -52,14 +52,14 @@ export default async (req, res) => {
metadata: validated.metadata,
no_notification: validated.no_notification,
})
const order = await orderService.withTransaction(manager).retrieve(id, {
select: defaultAdminOrdersFields,
relations: defaultAdminOrdersRelations,
})
res.status(200).json({ order })
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
relations: defaultAdminOrdersRelations,
})
res.status(200).json({ order })
}
export class AdminPostOrdersOrderSwapsSwapFulfillmentsReq {
@@ -8,6 +8,7 @@ import {
import { defaultAdminOrdersRelations, defaultAdminOrdersFields } from "."
import { OrderService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/refunds
@@ -56,15 +57,14 @@ export default async (req, res) => {
const orderService: OrderService = req.scope.resolve("orderService")
await orderService.createRefund(
id,
validated.amount,
validated.reason,
validated.note,
{
no_notification: validated.no_notification,
}
)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await orderService
.withTransaction(transactionManager)
.createRefund(id, validated.amount, validated.reason, validated.note, {
no_notification: validated.no_notification,
})
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -16,6 +16,7 @@ import {
} from "../../../../services"
import { OrdersReturnItem } from "../../../../types/orders"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}/returns
@@ -86,17 +87,17 @@ export default async (req, res) => {
const value = await validator(AdminPostOrdersOrderReturnsReq, req.body)
const 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
@@ -116,119 +117,123 @@ 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 returnObj: ReturnObj = {
order_id: id,
idempotency_key: idempotencyKey.idempotency_key,
items: value.items,
}
if (value.return_shipping) {
returnObj.shipping_method = value.return_shipping
}
if (typeof value.refund !== "undefined" && value.refund < 0) {
returnObj.refund_amount = 0
} else {
if (value.refund && value.refund >= 0) {
returnObj.refund_amount = value.refund
await manager.transaction(async (transactionManager) => {
const { key, error } = await idempotencyKeyService
.withTransaction(transactionManager)
.workStage(idempotencyKey.idempotency_key, async (manager) => {
const returnObj: ReturnObj = {
order_id: id,
idempotency_key: idempotencyKey.idempotency_key,
items: value.items,
}
}
const order = await orderService
.withTransaction(manager)
.retrieve(id)
if (value.return_shipping) {
returnObj.shipping_method = value.return_shipping
}
const evaluatedNoNotification =
value.no_notification !== undefined
? value.no_notification
: order.no_notification
returnObj.no_notification = evaluatedNoNotification
if (typeof value.refund !== "undefined" && value.refund < 0) {
returnObj.refund_amount = 0
} else {
if (value.refund && value.refund >= 0) {
returnObj.refund_amount = value.refund
}
}
const createdReturn = await returnService
.withTransaction(manager)
.create(returnObj)
if (value.return_shipping) {
await returnService
const order = await orderService
.withTransaction(manager)
.fulfill(createdReturn.id)
}
.retrieve(id)
await eventBus
.withTransaction(manager)
.emit("order.return_requested", {
id,
return_id: createdReturn.id,
no_notification: evaluatedNoNotification,
})
const evaluatedNoNotification =
value.no_notification !== undefined
? value.no_notification
: order.no_notification
returnObj.no_notification = evaluatedNoNotification
return {
recovery_point: "return_requested",
}
const createdReturn = await returnService
.withTransaction(manager)
.create(returnObj)
if (value.return_shipping) {
await returnService
.withTransaction(manager)
.fulfill(createdReturn.id)
}
await eventBus
.withTransaction(manager)
.emit("order.return_requested", {
id,
return_id: createdReturn.id,
no_notification: evaluatedNoNotification,
})
return {
recovery_point: "return_requested",
}
})
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 order = await orderService
.withTransaction(manager)
.retrieve(id, { relations: ["returns"] })
await manager.transaction(async (transactionManager) => {
const { key, error } = await idempotencyKeyService
.withTransaction(transactionManager)
.workStage(idempotencyKey.idempotency_key, async (manager) => {
let order = await orderService
.withTransaction(manager)
.retrieve(id, { relations: ["returns"] })
/**
* If we are ready to receive immediately, we find the newly created return
* and register it as received.
*/
if (value.receive_now) {
let ret = await returnService.withTransaction(manager).list({
idempotency_key: idempotencyKey.idempotency_key,
})
/**
* If we are ready to receive immediately, we find the newly created return
* and register it as received.
*/
if (value.receive_now) {
let ret = await returnService.withTransaction(manager).list({
idempotency_key: idempotencyKey.idempotency_key,
})
if (!ret.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Return not found`
)
if (!ret.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Return not found`
)
}
ret = ret[0]
order = await returnService
.withTransaction(manager)
.receive(ret.id, value.items, value.refund)
}
ret = ret[0]
order = await returnService
order = await orderService
.withTransaction(manager)
.receive(ret.id, value.items, value.refund)
}
.retrieve(id, {
select: defaultAdminOrdersFields,
relations: defaultAdminOrdersRelations,
})
order = await orderService.withTransaction(manager).retrieve(id, {
select: defaultAdminOrdersFields,
relations: defaultAdminOrdersRelations,
return {
response_code: 200,
response_body: { order },
}
})
return {
response_code: 200,
response_body: { order },
}
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
)
if (error) {
inProgress = false
err = error
} else {
idempotencyKey = key
}
})
break
}
@@ -238,14 +243,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
}
}
@@ -12,6 +12,7 @@ import {
import { defaultAdminOrdersRelations, defaultAdminOrdersFields } from "."
import { ClaimService, OrderService } from "../../../../services"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /order/{id}/claims/{claim_id}
@@ -104,7 +105,12 @@ export default async (req, res) => {
const orderService: OrderService = req.scope.resolve("orderService")
const claimService: ClaimService = req.scope.resolve("claimService")
await claimService.update(claim_id, validated)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await claimService
.withTransaction(transactionManager)
.update(claim_id, validated)
})
const data = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -13,6 +13,7 @@ import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "."
import { OrderService } from "../../../../services"
import { AddressPayload } from "../../../../types/common"
import { validator } from "../../../../utils/validator"
import { EntityManager } from "typeorm"
/**
* @oas [post] /orders/{id}
@@ -102,7 +103,12 @@ export default async (req, res) => {
const orderService: OrderService = req.scope.resolve("orderService")
await orderService.update(id, value)
const manager: EntityManager = req.scope.resolve("manager")
await manager.transaction(async (transactionManager) => {
return await orderService
.withTransaction(transactionManager)
.update(id, value)
})
const order = await orderService.retrieve(id, {
select: defaultAdminOrdersFields,
@@ -18,6 +18,7 @@ import { decorateLineItemsWithTotals } from "./decorate-line-items-with-totals"
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels";
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators";
import { FlagRouter } from "../../../../utils/flag-router"
import { Cart } from "../../../../models";
/**
* @oas [post] /carts
@@ -81,33 +82,32 @@ export default async (req, res) => {
const entityManager: EntityManager = req.scope.resolve("manager")
const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter")
await entityManager.transaction(async (manager) => {
let regionId: string
if (typeof validated.region_id !== "undefined") {
regionId = validated.region_id
} else {
const regions = await regionService
.withTransaction(manager)
.list({})
let regionId: string
if (typeof validated.region_id !== "undefined") {
regionId = validated.region_id
} else {
const regions = await regionService.list({})
if (!regions?.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`A region is required to create a cart`
)
}
regionId = regions[0].id
if (!regions?.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`A region is required to create a cart`
)
}
let cart = await cartService.withTransaction(manager).create({
regionId = regions[0].id
}
let cart: Cart
await entityManager.transaction(async (manager) => {
cart = await cartService.withTransaction(manager).create({
...validated,
context: {
...reqContext,
...validated.context,
},
region_id: regionId,
})
})
if (validated.items) {
await Promise.all(
@@ -117,7 +117,7 @@ export default async (req, res) => {
.generate(i.variant_id, regionId, i.quantity, {
customer_id: req.user?.customer_id,
})
await cartService
return await cartService
.withTransaction(manager)
.addLineItem(cart.id, lineItem, {
validateSalesChannels:
@@ -126,16 +126,16 @@ export default async (req, res) => {
})
)
}
cart = await cartService.withTransaction(manager).retrieve(cart.id, {
select: defaultStoreCartFields,
relations: defaultStoreCartRelations,
})
const data = await decorateLineItemsWithTotals(cart, req)
res.status(200).json({ cart: data })
})
cart = await cartService.retrieve(cart!.id, {
select: defaultStoreCartFields,
relations: defaultStoreCartRelations,
})
const data = await decorateLineItemsWithTotals(cart, req)
res.status(200).json({ cart: data })
}
export class Item {
@@ -1,4 +1,8 @@
export const InviteServiceMock = {
withTransaction: function () {
return this
},
list: jest.fn().mockImplementation((selector, config) => {
return Promise.resolve({})
}),
+1 -1
View File
@@ -340,7 +340,7 @@ class CartService extends TransactionBaseService<CartService> {
* @param data - the data to create the cart with
* @return the result of the create operation
*/
async create(data: CartCreateProps): Promise<Cart> {
async create(data: CartCreateProps): Promise<Cart | never> {
return await this.atomicPhase_(
async (transactionManager: EntityManager) => {
const cartRepo = transactionManager.getCustomRepository(
+3 -1
View File
@@ -66,7 +66,9 @@ class InventoryService extends BaseService {
return true
}
const variant = await this.productVariantService_.retrieve(variantId)
const variant = await this.productVariantService_
.withTransaction(this.manager_)
.retrieve(variantId)
const { inventory_quantity, allow_backorder, manage_inventory } = variant
const isCovered =
!manage_inventory || allow_backorder || inventory_quantity >= quantity
+28 -32
View File
@@ -63,32 +63,30 @@ class PricingService extends TransactionBaseService<PricingService> {
async collectPricingContext(
context: PriceSelectionContext
): Promise<PricingContext> {
return await this.atomicPhase_(async (manager: EntityManager) => {
let automaticTaxes = false
let taxRate = null
let currencyCode = context.currency_code
let automaticTaxes = false
let taxRate = null
let currencyCode = context.currency_code
if (context.region_id) {
const region = await this.regionService
.withTransaction(manager)
.retrieve(context.region_id, {
select: ["id", "currency_code", "automatic_taxes", "tax_rate"],
})
if (context.region_id) {
const region = await this.regionService
.withTransaction(this.manager_)
.retrieve(context.region_id, {
select: ["id", "currency_code", "automatic_taxes", "tax_rate"],
})
currencyCode = region.currency_code
automaticTaxes = region.automatic_taxes
taxRate = region.tax_rate
}
currencyCode = region.currency_code
automaticTaxes = region.automatic_taxes
taxRate = region.tax_rate
}
return {
price_selection: {
...context,
currency_code: currencyCode,
},
automatic_taxes: automaticTaxes,
tax_rate: taxRate,
}
})
return {
price_selection: {
...context,
currency_code: currencyCode,
},
automatic_taxes: automaticTaxes,
tax_rate: taxRate,
}
}
/**
@@ -229,17 +227,15 @@ class PricingService extends TransactionBaseService<PricingService> {
pricingContext.automatic_taxes &&
pricingContext.price_selection.region_id
) {
const { product_id } = await this.productVariantService.retrieve(
variantId,
{ select: ["id", "product_id"] }
)
productRates = await this.taxProviderService.getRegionRatesForProduct(
product_id,
{
const { product_id } = await this.productVariantService
.withTransaction(this.manager_)
.retrieve(variantId, { select: ["id", "product_id"] })
productRates = await this.taxProviderService
.withTransaction(this.manager_)
.getRegionRatesForProduct(product_id, {
id: pricingContext.price_selection.region_id,
tax_rate: pricingContext.tax_rate,
}
)
})
}
return await this.getProductVariantPricing_(