chore(): Module Internal Events (#13296)
* chore(): Ensure the product module emits all necessary events * chore(): Ensure the product module emits all necessary events * Update events tests * more events and fixes * more tests and category fixes * more tests and category fixes * Add todo * update updateProduct_ event emitting and adjust test * Adjust update products implementation to rely on already computed events * rm unnecessary update variants events * Fix formatting in changeset for product events * refactor: Manage event emitting automatically (WIP) * refactor: Manage event emitting automatically (WIP) * chore(api-key): Add missing emit events and refactoring * chore(cart): Add missing emit events and refactoring * chore(customer): Add missing emit events and refactoring * chore(fufillment, utils): Add missing emit events and refactoring * chore(fufillment, utils): Add missing emit events and refactoring * chore(inventory): Add missing emit events and refactoring * chore(notification): Add missing emit events and refactoring * chore(utils): Remove medusa service event handling legacy * chore(product): Add missing emit events and refactoring * chore(order): Add missing emit events and refactoring * chore(payment): Add missing emit events and refactoring * chore(pricing, util): Add missing emit events and refactoring, fix internal service upsertWithReplace event dispatching * chore(promotions): Add missing emit events and refactoring * chore(region): Add missing emit events and refactoring * chore(sales-channel): Add missing emit events and refactoring * chore(settings): Add missing emit events and refactoring * chore(stock-location): Add missing emit events and refactoring * chore(store): Add missing emit events and refactoring * chore(taxes): Add missing emit events and refactoring * chore(user): Add missing emit events and refactoring * fix unit tests * rm changeset for regeneration * Create changeset for Medusa.js patch updates Add a changeset for patch updates to multiple Medusa.js modules. * rm unused product event builders * address feedback * remove old changeset * fix event action for token generated * fix user module events * fix import * fix promotion events * add new module integration tests shard * fix medusa service * revert shard * fix event action * fix pipeline * fix pipeline --------- Co-authored-by: Oli Juhl <59018053+olivermrbl@users.noreply.github.com>
This commit is contained in:
1 parent
afe21741c4
commit
e8822f3e69
55 files changed
+3614
-2353
No files matched your search
@@ -0,0 +1,15 @@
|
||||
---
|
||||
"@medusajs/api-key": patch
|
||||
"@medusajs/cart": patch
|
||||
"@medusajs/customer": patch
|
||||
"@medusajs/fulfillment": patch
|
||||
"@medusajs/inventory": patch
|
||||
"@medusajs/notification": patch
|
||||
"@medusajs/order": patch
|
||||
"@medusajs/payment": patch
|
||||
"@medusajs/pricing": patch
|
||||
"@medusajs/product": patch
|
||||
"@medusajs/utils": patch
|
||||
---
|
||||
|
||||
chore(): Module Internal Events
|
||||
@@ -9,12 +9,13 @@ import {
|
||||
import { composeMessage } from "./build-event-messages"
|
||||
|
||||
export class MessageAggregator implements IMessageAggregator {
|
||||
private messages: Message[] = []
|
||||
#messagesHash: Set<string> = new Set()
|
||||
#messages: Message[] = []
|
||||
|
||||
constructor() {}
|
||||
|
||||
count(): number {
|
||||
return this.messages.length
|
||||
return this.#messages.length
|
||||
}
|
||||
|
||||
save(msg: Message | Message[]): void {
|
||||
@@ -23,7 +24,19 @@ export class MessageAggregator implements IMessageAggregator {
|
||||
return
|
||||
}
|
||||
|
||||
this.messages.push(...messages)
|
||||
for (const message of messages) {
|
||||
try {
|
||||
const hash = JSON.stringify(message)
|
||||
if (!this.#messagesHash.has(hash)) {
|
||||
this.#messagesHash.add(hash)
|
||||
this.#messages.push(message)
|
||||
}
|
||||
} catch (e) {
|
||||
// noop: if the message is not serializable, we don't want to deduplicate it
|
||||
// It should not happen, but we don't want to fail the whole process
|
||||
this.#messages.push(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
saveRawMessageData<T>(
|
||||
@@ -55,15 +68,15 @@ export class MessageAggregator implements IMessageAggregator {
|
||||
const { groupBy, sortBy } = format ?? {}
|
||||
|
||||
if (sortBy) {
|
||||
this.messages.sort((a, b) => this.compareMessages(a, b, sortBy))
|
||||
this.#messages.sort((a, b) => this.compareMessages(a, b, sortBy))
|
||||
}
|
||||
|
||||
let messages: { [group: string]: Message[] } = {
|
||||
default: [...this.messages],
|
||||
default: [...this.#messages],
|
||||
}
|
||||
|
||||
if (groupBy) {
|
||||
messages = this.messages.reduce<{
|
||||
messages = this.#messages.reduce<{
|
||||
[key: string]: Message[]
|
||||
}>((acc, msg) => {
|
||||
const key = groupBy
|
||||
@@ -91,7 +104,8 @@ export class MessageAggregator implements IMessageAggregator {
|
||||
|
||||
clearMessages(): void {
|
||||
// Ensure no references are left over in case something rely on messages
|
||||
this.messages.length = 0
|
||||
this.#messages.length = 0
|
||||
this.#messagesHash.clear()
|
||||
}
|
||||
|
||||
private getValueFromPath(obj: any, path: string): any {
|
||||
|
||||
@@ -20,7 +20,7 @@ describe("Internal Module Service Factory", () => {
|
||||
findAndCount: jest.fn(),
|
||||
create: jest.fn(),
|
||||
update: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
delete: jest.fn().mockImplementation((ids) => Promise.resolve(ids)),
|
||||
softDelete: jest.fn(),
|
||||
restore: jest.fn(),
|
||||
upsert: jest.fn(),
|
||||
@@ -32,7 +32,7 @@ describe("Internal Module Service Factory", () => {
|
||||
findAndCount: jest.fn(),
|
||||
create: jest.fn(),
|
||||
update: jest.fn(),
|
||||
delete: jest.fn(),
|
||||
delete: jest.fn().mockImplementation((ids) => Promise.resolve(ids)),
|
||||
softDelete: jest.fn(),
|
||||
restore: jest.fn(),
|
||||
upsert: jest.fn(),
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import { Context } from "@medusajs/types"
|
||||
import { EventArgs, EventSubscriber } from "@mikro-orm/core"
|
||||
type Service = {
|
||||
interceptEntityMutationEvents: (
|
||||
event: "afterCreate" | "afterUpdate" | "afterUpsert" | "afterDelete",
|
||||
args: EventArgs<any>,
|
||||
context: Context
|
||||
) => void
|
||||
}
|
||||
|
||||
export type MedusaMikroOrmEventSubscriber = {
|
||||
new (context: Context): EventSubscriber
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a new mikro orm event subscriber for the given models
|
||||
* @param models
|
||||
* @returns
|
||||
*/
|
||||
export function createMedusaMikroOrmEventSubscriber(
|
||||
keys: string[],
|
||||
service: Service
|
||||
): MedusaMikroOrmEventSubscriber {
|
||||
const klass = class MikroOrmEventSubscriber implements EventSubscriber {
|
||||
#context: Context
|
||||
#service: Service = service
|
||||
|
||||
constructor(context: Context) {
|
||||
this.#context = context
|
||||
}
|
||||
|
||||
async afterCreate<T>(args: EventArgs<T>): Promise<void> {
|
||||
this.#service.interceptEntityMutationEvents(
|
||||
"afterCreate",
|
||||
args,
|
||||
this.#context
|
||||
)
|
||||
}
|
||||
|
||||
async afterUpdate<T>(args: EventArgs<T>): Promise<void> {
|
||||
this.#service.interceptEntityMutationEvents(
|
||||
"afterUpdate",
|
||||
args,
|
||||
this.#context
|
||||
)
|
||||
}
|
||||
|
||||
async afterUpsert<T>(args: EventArgs<T>): Promise<void> {
|
||||
this.#service.interceptEntityMutationEvents(
|
||||
"afterUpsert",
|
||||
args,
|
||||
this.#context
|
||||
)
|
||||
}
|
||||
|
||||
async afterDelete<T>(args: EventArgs<T>): Promise<void> {
|
||||
this.#service.interceptEntityMutationEvents(
|
||||
"afterDelete",
|
||||
args,
|
||||
this.#context
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(klass, "name", {
|
||||
value: keys.join(","),
|
||||
writable: false,
|
||||
})
|
||||
|
||||
return klass
|
||||
}
|
||||
@@ -21,3 +21,4 @@ export * from "./types/links-config"
|
||||
export * from "./types/medusa-service"
|
||||
export * from "./module-provider-registration-key"
|
||||
export * from "./modules-to-container-types"
|
||||
export * from "./create-medusa-mikro-orm-event-subscriber"
|
||||
@@ -9,7 +9,12 @@ import {
|
||||
PerformedActions,
|
||||
UpsertWithReplaceConfig,
|
||||
} from "@medusajs/types"
|
||||
import type { EntityClass, EntitySchema } from "@mikro-orm/core"
|
||||
import {
|
||||
EventType,
|
||||
type EntityClass,
|
||||
type EntityManager,
|
||||
type EntitySchema,
|
||||
} from "@mikro-orm/core"
|
||||
import {
|
||||
isDefined,
|
||||
isObject,
|
||||
@@ -27,23 +32,60 @@ import {
|
||||
InjectTransactionManager,
|
||||
MedusaContext,
|
||||
} from "./decorators"
|
||||
import { MedusaMikroOrmEventSubscriber } from "./create-medusa-mikro-orm-event-subscriber"
|
||||
|
||||
type InternalService = {
|
||||
new <TContainer extends object = object, TEntity extends object = any>(
|
||||
container: TContainer
|
||||
): ModulesSdkTypes.IMedusaInternalService<TEntity, TContainer>
|
||||
|
||||
setEventSubscriber(subscriber: MedusaMikroOrmEventSubscriber): void
|
||||
}
|
||||
|
||||
type SelectorAndData = {
|
||||
selector: FilterQuery<any> | BaseFilterable<FilterQuery<any>>
|
||||
data: any
|
||||
}
|
||||
|
||||
export function registerInternalServiceEventSubscriber(
|
||||
context: Context,
|
||||
subscriber?: MedusaMikroOrmEventSubscriber
|
||||
) {
|
||||
const manager = (context.transactionManager ??
|
||||
context.manager) as EntityManager
|
||||
if (manager && subscriber) {
|
||||
const subscriberInstance = new subscriber(context)
|
||||
// There is no public API to unregister subscribers or check if a subscriber is already
|
||||
// registered. This means that we need to manually check if the subscriber is already
|
||||
// registered, otherwise we will register the same subscriber twice.
|
||||
const hasListeners = (manager.getEventManager() as any).subscribers.some(
|
||||
(s) => s.constructor.name === subscriberInstance.constructor.name
|
||||
)
|
||||
if (!hasListeners) {
|
||||
manager.getEventManager().registerSubscriber(subscriberInstance)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const MedusaInternalServiceSymbol = Symbol.for(
|
||||
"MedusaInternalServiceSymbol"
|
||||
)
|
||||
|
||||
/**
|
||||
* Check if a value is a Medusa internal service
|
||||
* @param value
|
||||
*/
|
||||
export function isMedusaInternalService(value: any): value is InternalService {
|
||||
return (
|
||||
!!value?.[MedusaInternalServiceSymbol] ||
|
||||
!!value?.prototype?.[MedusaInternalServiceSymbol]
|
||||
)
|
||||
}
|
||||
|
||||
export function MedusaInternalService<
|
||||
TContainer extends object = object,
|
||||
TEntity extends object = any
|
||||
>(
|
||||
rawModel: any
|
||||
): {
|
||||
new (container: TContainer): ModulesSdkTypes.IMedusaInternalService<
|
||||
TEntity,
|
||||
TContainer
|
||||
>
|
||||
} {
|
||||
>(rawModel: any): InternalService {
|
||||
const model = DmlEntity.isDmlEntity(rawModel)
|
||||
? toMikroORMEntity(rawModel)
|
||||
: rawModel
|
||||
@@ -54,6 +96,10 @@ export function MedusaInternalService<
|
||||
class AbstractService_
|
||||
implements ModulesSdkTypes.IMedusaInternalService<TEntity, TContainer>
|
||||
{
|
||||
[MedusaInternalServiceSymbol] = true
|
||||
|
||||
#eventSubscriber?: MedusaMikroOrmEventSubscriber
|
||||
|
||||
readonly __container__: TContainer;
|
||||
[key: string]: any
|
||||
|
||||
@@ -62,6 +108,10 @@ export function MedusaInternalService<
|
||||
this[propertyRepositoryName] = container[injectedRepositoryName]
|
||||
}
|
||||
|
||||
setEventSubscriber(subscriber: MedusaMikroOrmEventSubscriber) {
|
||||
this.#eventSubscriber = subscriber
|
||||
}
|
||||
|
||||
static applyFreeTextSearchFilter(
|
||||
filters: FilterQuery & { q?: string },
|
||||
config: FindConfig<any>
|
||||
@@ -223,6 +273,11 @@ export function MedusaInternalService<
|
||||
| InferEntityType<TEntity>[]
|
||||
}
|
||||
|
||||
registerInternalServiceEventSubscriber(
|
||||
sharedContext,
|
||||
this.#eventSubscriber
|
||||
)
|
||||
|
||||
const data_ = Array.isArray(data) ? data : [data]
|
||||
const entities = await this[propertyRepositoryName].create(
|
||||
data_,
|
||||
@@ -260,6 +315,11 @@ export function MedusaInternalService<
|
||||
| InferEntityType<TEntity>[]
|
||||
}
|
||||
|
||||
registerInternalServiceEventSubscriber(
|
||||
sharedContext,
|
||||
this.#eventSubscriber
|
||||
)
|
||||
|
||||
let shouldReturnArray = false
|
||||
if (Array.isArray(input)) {
|
||||
shouldReturnArray = true
|
||||
@@ -419,6 +479,11 @@ export function MedusaInternalService<
|
||||
return []
|
||||
}
|
||||
|
||||
registerInternalServiceEventSubscriber(
|
||||
sharedContext,
|
||||
this.#eventSubscriber
|
||||
)
|
||||
|
||||
const primaryKeys = AbstractService_.retrievePrimaryKeys(model)
|
||||
|
||||
if (
|
||||
@@ -467,10 +532,29 @@ export function MedusaInternalService<
|
||||
return []
|
||||
}
|
||||
|
||||
return await this[propertyRepositoryName].delete(
|
||||
const deletedIds = await this[propertyRepositoryName].delete(
|
||||
deleteCriteria,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
// Delete are handled a bit differently since we are going to the DB directly, therefore
|
||||
// just like upsert with replace, we need to dispatch the events manually.
|
||||
if (deletedIds.length) {
|
||||
const manager = (sharedContext.transactionManager ??
|
||||
sharedContext.manager) as EntityManager
|
||||
const eventManager = manager.getEventManager()
|
||||
|
||||
deletedIds.forEach((id) => {
|
||||
eventManager.dispatchEvent(EventType.afterDelete, {
|
||||
entity: { id },
|
||||
meta: {
|
||||
className: model.name,
|
||||
} as Parameters<typeof eventManager.dispatchEvent>[2],
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return deletedIds
|
||||
}
|
||||
|
||||
@InjectTransactionManager(propertyRepositoryName)
|
||||
@@ -489,6 +573,11 @@ export function MedusaInternalService<
|
||||
return [[], {}]
|
||||
}
|
||||
|
||||
registerInternalServiceEventSubscriber(
|
||||
sharedContext,
|
||||
this.#eventSubscriber
|
||||
)
|
||||
|
||||
return await this[propertyRepositoryName].softDelete(
|
||||
idsOrFilter,
|
||||
sharedContext
|
||||
@@ -520,6 +609,11 @@ export function MedusaInternalService<
|
||||
data: any | any[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<TEntity> | InferEntityType<TEntity>[]> {
|
||||
registerInternalServiceEventSubscriber(
|
||||
sharedContext,
|
||||
this.#eventSubscriber
|
||||
)
|
||||
|
||||
const data_ = Array.isArray(data) ? data : [data]
|
||||
const entities = await this[propertyRepositoryName].upsert(
|
||||
data_,
|
||||
@@ -556,10 +650,74 @@ export function MedusaInternalService<
|
||||
entities: InferEntityType<TEntity> | InferEntityType<TEntity>[]
|
||||
performedActions: PerformedActions
|
||||
}> {
|
||||
registerInternalServiceEventSubscriber(
|
||||
sharedContext,
|
||||
this.#eventSubscriber
|
||||
)
|
||||
|
||||
const data_ = Array.isArray(data) ? data : [data]
|
||||
const { entities, performedActions } = await this[
|
||||
propertyRepositoryName
|
||||
].upsertWithReplace(data_, config, sharedContext)
|
||||
|
||||
const manager = (sharedContext.transactionManager ??
|
||||
sharedContext.manager) as EntityManager
|
||||
const eventManager = manager.getEventManager()
|
||||
|
||||
/**
|
||||
* Since the upsertWithReplace method is not emitting events, we need to do it manually
|
||||
* by dispatching the events manually.
|
||||
*/
|
||||
|
||||
const createdEntities = !!Object.keys(performedActions.created).length
|
||||
const updatedEntities = !!Object.keys(performedActions.updated).length
|
||||
const deletedEntities = !!Object.keys(performedActions.deleted).length
|
||||
|
||||
if (createdEntities) {
|
||||
Object.entries(
|
||||
performedActions.created as Record<string, any[]>
|
||||
).forEach(([modelName, entities]) => {
|
||||
entities.forEach((entity) => {
|
||||
eventManager.dispatchEvent(EventType.afterCreate, {
|
||||
entity,
|
||||
meta: {
|
||||
className: modelName,
|
||||
} as Parameters<typeof eventManager.dispatchEvent>[2],
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (updatedEntities) {
|
||||
Object.entries(
|
||||
performedActions.updated as Record<string, any[]>
|
||||
).forEach(([modelName, entities]) => {
|
||||
entities.forEach((entity) => {
|
||||
eventManager.dispatchEvent(EventType.afterUpdate, {
|
||||
entity,
|
||||
meta: {
|
||||
className: modelName,
|
||||
} as Parameters<typeof eventManager.dispatchEvent>[2],
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
if (deletedEntities) {
|
||||
Object.entries(
|
||||
performedActions.deleted as Record<string, any[]>
|
||||
).forEach(([modelName, entities]) => {
|
||||
entities.forEach((entity) => {
|
||||
eventManager.dispatchEvent(EventType.afterDelete, {
|
||||
entity,
|
||||
meta: {
|
||||
className: modelName,
|
||||
} as Parameters<typeof eventManager.dispatchEvent>[2],
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
entities: Array.isArray(data) ? entities : entities[0],
|
||||
performedActions,
|
||||
@@ -567,5 +725,7 @@ export function MedusaInternalService<
|
||||
}
|
||||
}
|
||||
|
||||
return AbstractService_ as any
|
||||
// We hide away the setEventSubscriber method from the public interface
|
||||
// as it is not meant to be used by the user.
|
||||
return AbstractService_ as unknown as InternalService
|
||||
}
|
||||
@@ -10,9 +10,9 @@ import {
|
||||
RestoreReturn,
|
||||
SoftDeleteReturn,
|
||||
} from "@medusajs/types"
|
||||
import { EventArgs } from "@mikro-orm/core"
|
||||
import {
|
||||
camelToSnakeCase,
|
||||
isString,
|
||||
lowerCaseFirst,
|
||||
mapObjectTo,
|
||||
MapToConfig,
|
||||
@@ -21,10 +21,12 @@ import {
|
||||
} from "../common"
|
||||
import { DmlEntity } from "../dml"
|
||||
import { CommonEvents } from "../event-bus"
|
||||
import { createMedusaMikroOrmEventSubscriber } from "./create-medusa-mikro-orm-event-subscriber"
|
||||
import { EmitEvents, InjectManager, MedusaContext } from "./decorators"
|
||||
import { Modules } from "./definition"
|
||||
import { moduleEventBuilderFactory } from "./event-builder-factory"
|
||||
import { buildModelsNameToLinkableKeysMap } from "./joiner-config-builder"
|
||||
import { isMedusaInternalService } from "./medusa-internal-service"
|
||||
import {
|
||||
BaseMethods,
|
||||
ExtractKeysFromConfig,
|
||||
@@ -137,37 +139,6 @@ export function MedusaService<
|
||||
? ModelConfigurationsToConfigTemplate<TModels>
|
||||
: ModelsConfig
|
||||
> {
|
||||
function emitSoftDeleteRestoreEvents(
|
||||
this: AbstractModuleService_,
|
||||
klassPrototype: any,
|
||||
cascadedModelsMap: Record<string, string[]>,
|
||||
action: string,
|
||||
sharedContext: Context
|
||||
) {
|
||||
const joinerConfig = (
|
||||
typeof this.__joinerConfig === "function"
|
||||
? this.__joinerConfig()
|
||||
: this.__joinerConfig
|
||||
) as ModuleJoinerConfig
|
||||
|
||||
const emittedEntities = new Set<string>()
|
||||
|
||||
Object.entries(cascadedModelsMap).forEach(([linkableKey, ids]) => {
|
||||
const entity = joinerConfig.linkableKeys?.[linkableKey]!
|
||||
if (entity && !emittedEntities.has(entity)) {
|
||||
emittedEntities.add(entity)
|
||||
const linkableKeyEntity = camelToSnakeCase(entity).toLowerCase()
|
||||
|
||||
klassPrototype.aggregatedEvents.bind(this)({
|
||||
action: action,
|
||||
object: linkableKeyEntity,
|
||||
data: { id: ids },
|
||||
context: sharedContext,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const buildAndAssignMethodImpl = function (
|
||||
klassPrototype: any,
|
||||
method: string,
|
||||
@@ -220,16 +191,9 @@ export function MedusaService<
|
||||
sharedContext: Context = {}
|
||||
): Promise<T | T[]> {
|
||||
const service = this.__container__[serviceRegistrationName]
|
||||
const models = await service.create(data, sharedContext)
|
||||
const models_ = await service.create(data, sharedContext)
|
||||
|
||||
klassPrototype.aggregatedEvents.bind(this)({
|
||||
action: CommonEvents.CREATED,
|
||||
object: camelToSnakeCase(modelName).toLowerCase(),
|
||||
data: models,
|
||||
context: sharedContext,
|
||||
})
|
||||
|
||||
return await this.baseRepository_.serialize<T | T[]>(models)
|
||||
return await this.baseRepository_.serialize<T | T[]>(models_)
|
||||
}
|
||||
|
||||
applyMethod(methodImplementation, 1)
|
||||
@@ -244,13 +208,6 @@ export function MedusaService<
|
||||
const service = this.__container__[serviceRegistrationName]
|
||||
const response = await service.update(data, sharedContext)
|
||||
|
||||
klassPrototype.aggregatedEvents.bind(this)({
|
||||
action: CommonEvents.UPDATED,
|
||||
object: camelToSnakeCase(modelName).toLowerCase(),
|
||||
data: response,
|
||||
context: sharedContext,
|
||||
})
|
||||
|
||||
return await this.baseRepository_.serialize<T | T[]>(response)
|
||||
}
|
||||
|
||||
@@ -300,19 +257,10 @@ export function MedusaService<
|
||||
? primaryKeyValues
|
||||
: [primaryKeyValues]
|
||||
|
||||
const ids = await this.__container__[serviceRegistrationName].delete(
|
||||
await this.__container__[serviceRegistrationName].delete(
|
||||
primaryKeyValues_,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
ids.map((id) =>
|
||||
klassPrototype.aggregatedEvents.bind(this)({
|
||||
action: CommonEvents.DELETED,
|
||||
object: camelToSnakeCase(modelName).toLowerCase(),
|
||||
data: isString(id) ? { id: id } : id,
|
||||
context: sharedContext,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
applyMethod(methodImplementation, 1)
|
||||
@@ -343,15 +291,6 @@ export function MedusaService<
|
||||
}
|
||||
)
|
||||
|
||||
if (mappedCascadedModelsMap) {
|
||||
emitSoftDeleteRestoreEvents.bind(this)(
|
||||
klassPrototype,
|
||||
mappedCascadedModelsMap,
|
||||
CommonEvents.DELETED,
|
||||
sharedContext
|
||||
)
|
||||
}
|
||||
|
||||
return mappedCascadedModelsMap ? mappedCascadedModelsMap : void 0
|
||||
}
|
||||
|
||||
@@ -384,15 +323,6 @@ export function MedusaService<
|
||||
}
|
||||
)
|
||||
|
||||
if (mappedCascadedModelsMap) {
|
||||
emitSoftDeleteRestoreEvents.bind(this)(
|
||||
klassPrototype,
|
||||
mappedCascadedModelsMap,
|
||||
CommonEvents.CREATED,
|
||||
sharedContext
|
||||
)
|
||||
}
|
||||
|
||||
return mappedCascadedModelsMap ? mappedCascadedModelsMap : void 0
|
||||
}
|
||||
|
||||
@@ -424,6 +354,41 @@ export function MedusaService<
|
||||
this.__container__ = container
|
||||
this.baseRepository_ = container.baseRepository
|
||||
|
||||
const joinerConfig = this.__joinerConfig?.()
|
||||
/**
|
||||
* Create a global subscriber to listen to all the entities mutations
|
||||
* and forward them to the module service interceptEntityMutationEvents
|
||||
* method.
|
||||
*
|
||||
* Assign the global subscriber to all internal services or class that extends it
|
||||
* such that it can attach it accordingly and forward the events to the module service.
|
||||
*/
|
||||
|
||||
if (joinerConfig?.serviceName !== "index") {
|
||||
let globalSubscriber!: ReturnType<
|
||||
typeof createMedusaMikroOrmEventSubscriber
|
||||
>
|
||||
|
||||
Object.keys(container)
|
||||
.filter((key) => {
|
||||
return key.endsWith("Service")
|
||||
})
|
||||
.forEach((key: string) => {
|
||||
globalSubscriber ??= createMedusaMikroOrmEventSubscriber(
|
||||
["__medusa_entities_subscriber__"],
|
||||
this
|
||||
)
|
||||
try {
|
||||
const service = container[key]
|
||||
if (isMedusaInternalService(service)) {
|
||||
service.setEventSubscriber(globalSubscriber)
|
||||
}
|
||||
} catch (error) {
|
||||
// Prevent circular issue which in that case would represent ourselves so we can skip
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const hasEventBusModuleService = Object.keys(this.__container__).find(
|
||||
(key) => key === Modules.EVENT_BUS
|
||||
)
|
||||
@@ -433,9 +398,72 @@ export function MedusaService<
|
||||
: undefined
|
||||
|
||||
this[MedusaServiceModelNameToLinkableKeysMapSymbol] =
|
||||
buildModelsNameToLinkableKeysMap(
|
||||
this.__joinerConfig?.()?.linkableKeys ?? {}
|
||||
)
|
||||
buildModelsNameToLinkableKeysMap(joinerConfig?.linkableKeys ?? {})
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal this method is meant to react to any event the orm might emit
|
||||
* when an entity is being mutated (created, updated, deleted).
|
||||
* The default implementation will handle all event to be emitted as part
|
||||
* of the message aggregator from the context.
|
||||
*
|
||||
* If you want to handle the event differently, you can override this method.
|
||||
*
|
||||
* @example
|
||||
*
|
||||
* class MyService extends ModulesSdkUtils.MedusaService(models) {
|
||||
* interceptEntityMutationEvents(event: "afterCreate" | "afterUpdate" | "afterUpsert" | "afterDelete", args: EventArgs<any>, context: Context) {
|
||||
* console.log("interceptEntityMutationEvents", event, args.entity)
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @param event - The event type
|
||||
* @param args - The event arguments
|
||||
* @param context - The context
|
||||
*/
|
||||
interceptEntityMutationEvents(
|
||||
event: "afterCreate" | "afterUpdate" | "afterUpsert" | "afterDelete",
|
||||
args: EventArgs<any>,
|
||||
context: Context
|
||||
) {
|
||||
let action = ""
|
||||
switch (event) {
|
||||
case "afterCreate":
|
||||
action = CommonEvents.CREATED
|
||||
break
|
||||
case "afterUpdate":
|
||||
const isSoftDeleted =
|
||||
!!args.changeSet?.entity.deleted_at &&
|
||||
!args.changeSet?.originalEntity?.deleted_at
|
||||
|
||||
const isRestored =
|
||||
!!args.changeSet?.originalEntity?.deleted_at &&
|
||||
!args.changeSet?.entity.deleted_at
|
||||
|
||||
action = CommonEvents.UPDATED
|
||||
|
||||
if (isSoftDeleted) {
|
||||
action = CommonEvents.DELETED
|
||||
}
|
||||
|
||||
if (isRestored) {
|
||||
action = CommonEvents.RESTORED
|
||||
}
|
||||
|
||||
break
|
||||
case "afterDelete":
|
||||
action = CommonEvents.DELETED
|
||||
break
|
||||
}
|
||||
|
||||
const object = camelToSnakeCase(args.meta.className).toLowerCase()
|
||||
|
||||
this.aggregatedEvents({
|
||||
action,
|
||||
object,
|
||||
data: { id: args.entity.id },
|
||||
context,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -463,6 +491,10 @@ export function MedusaService<
|
||||
data: { id: any } | { id: any }[]
|
||||
context: Context
|
||||
}) {
|
||||
if (!context.messageAggregator) {
|
||||
return
|
||||
}
|
||||
|
||||
const __joinerConfig = (
|
||||
typeof this.__joinerConfig === "function"
|
||||
? this.__joinerConfig()
|
||||
|
||||
@@ -3,13 +3,14 @@ import {
|
||||
Context,
|
||||
FindConfig,
|
||||
IDmlEntity,
|
||||
InferEntityForModuleService,
|
||||
InferEntityType,
|
||||
Pluralize,
|
||||
Prettify,
|
||||
RestoreReturn,
|
||||
SoftDeleteReturn,
|
||||
InferEntityType,
|
||||
InferEntityForModuleService,
|
||||
} from "@medusajs/types"
|
||||
import { EventArgs } from "@mikro-orm/core"
|
||||
import { DmlEntity } from "../../dml"
|
||||
|
||||
export type BaseMethods =
|
||||
@@ -318,4 +319,22 @@ export type MedusaServiceReturnType<ModelsConfig extends Record<string, any>> =
|
||||
data: { id: any } | { id: any }[]
|
||||
context: Context
|
||||
}): void
|
||||
|
||||
/**
|
||||
* this method is meant to react to any event the orm might emit
|
||||
* when an entity is being mutated (created, updated, deleted).
|
||||
* The default implementation will handle all event to be emitted as part
|
||||
* of the message aggregator from the context.
|
||||
*
|
||||
* If you want to handle the event differently, you can override this method.
|
||||
*
|
||||
* @param event - The event type
|
||||
* @param args - The event arguments
|
||||
* @param context - The context
|
||||
*/
|
||||
interceptEntityMutationEvents(
|
||||
event: "afterCreate" | "afterUpdate" | "afterUpsert" | "afterDelete",
|
||||
args: EventArgs<any>,
|
||||
context: Context
|
||||
): void
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
ApiKeyType,
|
||||
EmitEvents,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
isObject,
|
||||
@@ -65,11 +66,20 @@ export class ApiKeyModuleService
|
||||
return joinerConfig
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async deleteApiKeys(
|
||||
ids: string | string[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
return await this.deleteApiKeys_(ids, sharedContext)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async deleteApiKeys_(
|
||||
ids: string | string[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
const apiKeyIds = Array.isArray(ids) ? ids : [ids]
|
||||
|
||||
@@ -111,6 +121,7 @@ export class ApiKeyModuleService
|
||||
): Promise<ApiKeyTypes.ApiKeyDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
//@ts-expect-error
|
||||
async createApiKeys(
|
||||
data: ApiKeyTypes.CreateApiKeyDTO | ApiKeyTypes.CreateApiKeyDTO[],
|
||||
@@ -183,9 +194,20 @@ export class ApiKeyModuleService
|
||||
): Promise<ApiKeyTypes.ApiKeyDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertApiKeys(
|
||||
data: ApiKeyTypes.UpsertApiKeyDTO | ApiKeyTypes.UpsertApiKeyDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ApiKeyTypes.ApiKeyDTO | ApiKeyTypes.ApiKeyDTO[]> {
|
||||
const result = await this.upsertApiKeys_(data, sharedContext)
|
||||
|
||||
return await this.baseRepository_.serialize<ApiKeyTypes.ApiKeyDTO[]>(result)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertApiKeys_(
|
||||
data: ApiKeyTypes.UpsertApiKeyDTO | ApiKeyTypes.UpsertApiKeyDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ApiKeyTypes.ApiKeyDTO | ApiKeyTypes.ApiKeyDTO[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter(
|
||||
@@ -205,9 +227,7 @@ export class ApiKeyModuleService
|
||||
)
|
||||
const serializedResponse = await this.baseRepository_.serialize<
|
||||
ApiKeyTypes.ApiKeyDTO[]
|
||||
>(createdApiKeys, {
|
||||
populate: true,
|
||||
})
|
||||
>(createdApiKeys)
|
||||
|
||||
return serializedResponse.map(
|
||||
(key) =>
|
||||
@@ -226,10 +246,7 @@ export class ApiKeyModuleService
|
||||
|
||||
if (forUpdate.length) {
|
||||
const op = async () => {
|
||||
const updateResp = await this.updateApiKeys_(forUpdate, sharedContext)
|
||||
return await this.baseRepository_.serialize<ApiKeyTypes.ApiKeyDTO[]>(
|
||||
updateResp
|
||||
)
|
||||
return await this.updateApiKeys_(forUpdate, sharedContext)
|
||||
}
|
||||
|
||||
operations.push(op())
|
||||
@@ -253,6 +270,7 @@ export class ApiKeyModuleService
|
||||
): Promise<ApiKeyTypes.ApiKeyDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
//@ts-expect-error
|
||||
async updateApiKeys(
|
||||
idOrSelector: string | FilterableApiKeyProps,
|
||||
@@ -368,7 +386,9 @@ export class ApiKeyModuleService
|
||||
data: ApiKeyTypes.RevokeApiKeyDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ApiKeyTypes.ApiKeyDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async revoke(
|
||||
idOrSelector: string | FilterableApiKeyProps,
|
||||
data: ApiKeyTypes.RevokeApiKeyDTO,
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
createRawPropertiesFromBigNumber,
|
||||
decorateCartTotals,
|
||||
deduplicate,
|
||||
EmitEvents,
|
||||
generateEntityId,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
@@ -269,6 +270,7 @@ export default class CartModuleService
|
||||
): Promise<CartTypes.CartDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createCarts(
|
||||
data: CartTypes.CreateCartDTO[] | CartTypes.CreateCartDTO,
|
||||
@@ -340,6 +342,7 @@ export default class CartModuleService
|
||||
): Promise<CartTypes.CartDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateCarts(
|
||||
dataOrIdOrSelector:
|
||||
@@ -425,6 +428,7 @@ export default class CartModuleService
|
||||
): Promise<CartTypes.CartLineItemDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async addLineItems(
|
||||
cartIdOrData:
|
||||
| string
|
||||
@@ -504,6 +508,7 @@ export default class CartModuleService
|
||||
): Promise<CartTypes.CartLineItemDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateLineItems(
|
||||
lineItemIdOrDataOrSelector:
|
||||
@@ -606,6 +611,7 @@ export default class CartModuleService
|
||||
): Promise<CartTypes.CartAddressDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createAddresses(
|
||||
data: CartTypes.CreateAddressDTO[] | CartTypes.CreateAddressDTO,
|
||||
@@ -645,6 +651,7 @@ export default class CartModuleService
|
||||
): Promise<CartTypes.CartAddressDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateAddresses(
|
||||
data: CartTypes.UpdateAddressDTO[] | CartTypes.UpdateAddressDTO,
|
||||
@@ -685,6 +692,7 @@ export default class CartModuleService
|
||||
): Promise<CartTypes.CartShippingMethodDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async addShippingMethods(
|
||||
cartIdOrData:
|
||||
| string
|
||||
@@ -763,6 +771,7 @@ export default class CartModuleService
|
||||
): Promise<CartTypes.LineItemAdjustmentDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async addLineItemAdjustments(
|
||||
cartIdOrData:
|
||||
| string
|
||||
@@ -827,6 +836,7 @@ export default class CartModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertLineItemTaxLines(
|
||||
taxLines: (
|
||||
| CartTypes.CreateLineItemTaxLineDTO
|
||||
@@ -861,6 +871,7 @@ export default class CartModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertLineItemAdjustments(
|
||||
adjustments: (
|
||||
| CartTypes.CreateLineItemAdjustmentDTO
|
||||
@@ -895,6 +906,7 @@ export default class CartModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertShippingMethodTaxLines(
|
||||
taxLines: (
|
||||
| CartTypes.CreateShippingMethodTaxLineDTO
|
||||
@@ -929,6 +941,7 @@ export default class CartModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertShippingMethodAdjustments(
|
||||
adjustments: (
|
||||
| CartTypes.CreateShippingMethodAdjustmentDTO
|
||||
@@ -963,6 +976,7 @@ export default class CartModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async setLineItemAdjustments(
|
||||
cartId: string,
|
||||
adjustments: (
|
||||
@@ -1036,6 +1050,7 @@ export default class CartModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async setShippingMethodAdjustments(
|
||||
cartId: string,
|
||||
adjustments: (
|
||||
@@ -1122,6 +1137,7 @@ export default class CartModuleService
|
||||
): Promise<CartTypes.ShippingMethodAdjustmentDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async addShippingMethodAdjustments(
|
||||
cartIdOrData:
|
||||
| string
|
||||
@@ -1212,6 +1228,7 @@ export default class CartModuleService
|
||||
): Promise<CartTypes.LineItemTaxLineDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async addLineItemTaxLines(
|
||||
cartIdOrData:
|
||||
| string
|
||||
@@ -1275,6 +1292,7 @@ export default class CartModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async setLineItemTaxLines(
|
||||
cartId: string,
|
||||
taxLines: (
|
||||
@@ -1357,6 +1375,7 @@ export default class CartModuleService
|
||||
): Promise<CartTypes.ShippingMethodTaxLineDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async addShippingMethodTaxLines(
|
||||
cartIdOrData:
|
||||
| string
|
||||
@@ -1422,6 +1441,7 @@ export default class CartModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async setShippingMethodTaxLines(
|
||||
cartId: string,
|
||||
taxLines: (
|
||||
|
||||
@@ -14,13 +14,13 @@ import {
|
||||
} from "@medusajs/framework/types"
|
||||
|
||||
import {
|
||||
EmitEvents,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
isString,
|
||||
MedusaContext,
|
||||
MedusaService,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { EntityManager } from "@mikro-orm/core"
|
||||
import {
|
||||
Customer,
|
||||
CustomerAddress,
|
||||
@@ -101,6 +101,7 @@ export default class CustomerModuleService
|
||||
): Promise<CustomerTypes.CustomerDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async createCustomers(
|
||||
dataOrArray:
|
||||
| CustomerTypes.CreateCustomerDTO
|
||||
@@ -124,7 +125,7 @@ export default class CustomerModuleService
|
||||
| CustomerTypes.CreateCustomerDTO
|
||||
| CustomerTypes.CreateCustomerDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<CustomerTypes.CustomerDTO[]> {
|
||||
): Promise<InferEntityType<typeof Customer>[]> {
|
||||
const data = Array.isArray(dataOrArray) ? dataOrArray : [dataOrArray]
|
||||
const customerAttributes = data.map(({ addresses, ...rest }) => {
|
||||
return rest
|
||||
@@ -153,7 +154,7 @@ export default class CustomerModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return customers as unknown as CustomerTypes.CustomerDTO[]
|
||||
return customers
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -175,13 +176,33 @@ export default class CustomerModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<CustomerTypes.CustomerDTO[]>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateCustomers(
|
||||
idsOrSelector: string | string[] | CustomerTypes.FilterableCustomerProps,
|
||||
data: CustomerTypes.CustomerUpdatableFields,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
): Promise<CustomerTypes.CustomerDTO | CustomerTypes.CustomerDTO[]> {
|
||||
const customers = await this.updateCustomers_(
|
||||
idsOrSelector,
|
||||
data,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
CustomerTypes.CustomerDTO | CustomerTypes.CustomerDTO[]
|
||||
>(customers)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async updateCustomers_(
|
||||
idsOrSelector: string | string[] | CustomerTypes.FilterableCustomerProps,
|
||||
data: CustomerTypes.CustomerUpdatableFields,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<
|
||||
InferEntityType<typeof Customer>[] | InferEntityType<typeof Customer>
|
||||
> {
|
||||
let updateData:
|
||||
| CustomerTypes.UpdateCustomerDTO
|
||||
| CustomerTypes.UpdateCustomerDTO[]
|
||||
@@ -212,13 +233,7 @@ export default class CustomerModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
CustomerTypes.CustomerDTO | CustomerTypes.CustomerDTO[]
|
||||
>(customers, {
|
||||
populate: true,
|
||||
})
|
||||
|
||||
return serialized
|
||||
return customers
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -233,24 +248,43 @@ export default class CustomerModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<CustomerTypes.CustomerGroupDTO[]>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createCustomerGroups(
|
||||
dataOrArrayOfData:
|
||||
| CustomerTypes.CreateCustomerGroupDTO
|
||||
| CustomerTypes.CreateCustomerGroupDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
const groups = await this.customerGroupService_.create(
|
||||
): Promise<
|
||||
CustomerTypes.CustomerGroupDTO | CustomerTypes.CustomerGroupDTO[]
|
||||
> {
|
||||
const groups = await this.createCustomerGroups_(
|
||||
dataOrArrayOfData,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
CustomerTypes.CustomerGroupDTO | CustomerTypes.CustomerGroupDTO[]
|
||||
>(groups, {
|
||||
populate: true,
|
||||
})
|
||||
>(groups)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async createCustomerGroups_(
|
||||
dataOrArrayOfData:
|
||||
| CustomerTypes.CreateCustomerGroupDTO
|
||||
| CustomerTypes.CreateCustomerGroupDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<
|
||||
| InferEntityType<typeof CustomerGroup>[]
|
||||
| InferEntityType<typeof CustomerGroup>
|
||||
> {
|
||||
const groups = await this.customerGroupService_.create(
|
||||
dataOrArrayOfData,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return groups
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -272,7 +306,8 @@ export default class CustomerModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<CustomerTypes.CustomerGroupDTO[]>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateCustomerGroups(
|
||||
groupIdOrSelector:
|
||||
@@ -281,7 +316,32 @@ export default class CustomerModuleService
|
||||
| CustomerTypes.FilterableCustomerGroupProps,
|
||||
data: CustomerTypes.CustomerGroupUpdatableFields,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
): Promise<
|
||||
CustomerTypes.CustomerGroupDTO | CustomerTypes.CustomerGroupDTO[]
|
||||
> {
|
||||
const groups = await this.updateCustomerGroups_(
|
||||
groupIdOrSelector,
|
||||
data,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
CustomerTypes.CustomerGroupDTO | CustomerTypes.CustomerGroupDTO[]
|
||||
>(groups)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async updateCustomerGroups_(
|
||||
groupIdOrSelector:
|
||||
| string
|
||||
| string[]
|
||||
| CustomerTypes.FilterableCustomerGroupProps,
|
||||
data: CustomerTypes.CustomerGroupUpdatableFields,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<
|
||||
| InferEntityType<typeof CustomerGroup>[]
|
||||
| InferEntityType<typeof CustomerGroup>
|
||||
> {
|
||||
let updateData:
|
||||
| CustomerTypes.UpdateCustomerGroupDTO
|
||||
| CustomerTypes.UpdateCustomerGroupDTO[]
|
||||
@@ -311,15 +371,10 @@ export default class CustomerModuleService
|
||||
)
|
||||
|
||||
if (isString(groupIdOrSelector)) {
|
||||
return await this.baseRepository_.serialize<CustomerTypes.CustomerGroupDTO>(
|
||||
groups[0],
|
||||
{ populate: true }
|
||||
)
|
||||
return groups[0]
|
||||
}
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
CustomerTypes.CustomerGroupDTO[]
|
||||
>(groups, { populate: true })
|
||||
return groups
|
||||
}
|
||||
|
||||
async addCustomerToGroup(
|
||||
@@ -332,10 +387,21 @@ export default class CustomerModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<{ id: string }[]>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async addCustomerToGroup(
|
||||
data: CustomerTypes.GroupCustomerPair | CustomerTypes.GroupCustomerPair[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<{ id: string } | { id: string }[]> {
|
||||
const groupCustomers = await this.addCustomerToGroup_(data, sharedContext)
|
||||
|
||||
return groupCustomers
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async addCustomerToGroup_(
|
||||
data: CustomerTypes.GroupCustomerPair | CustomerTypes.GroupCustomerPair[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<{ id: string } | { id: string }[]> {
|
||||
const groupCustomers = await this.customerGroupCustomerService_.create(
|
||||
data,
|
||||
@@ -365,6 +431,7 @@ export default class CustomerModuleService
|
||||
): Promise<CustomerTypes.CustomerAddressDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createCustomerAddresses(
|
||||
data:
|
||||
@@ -419,7 +486,8 @@ export default class CustomerModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<CustomerTypes.CustomerAddressDTO[]>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateCustomerAddresses(
|
||||
addressIdOrSelector:
|
||||
@@ -428,7 +496,32 @@ export default class CustomerModuleService
|
||||
| CustomerTypes.FilterableCustomerAddressProps,
|
||||
data: CustomerTypes.UpdateCustomerAddressDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
): Promise<
|
||||
CustomerTypes.CustomerAddressDTO | CustomerTypes.CustomerAddressDTO[]
|
||||
> {
|
||||
const addresses = await this.updateCustomerAddresses_(
|
||||
addressIdOrSelector,
|
||||
data,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
CustomerTypes.CustomerAddressDTO | CustomerTypes.CustomerAddressDTO[]
|
||||
>(addresses)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async updateCustomerAddresses_(
|
||||
addressIdOrSelector:
|
||||
| string
|
||||
| string[]
|
||||
| CustomerTypes.FilterableCustomerAddressProps,
|
||||
data: CustomerTypes.UpdateCustomerAddressDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<
|
||||
| InferEntityType<typeof CustomerAddress>[]
|
||||
| InferEntityType<typeof CustomerAddress>
|
||||
> {
|
||||
let updateData:
|
||||
| CustomerTypes.UpdateCustomerAddressDTO[]
|
||||
| {
|
||||
@@ -459,17 +552,11 @@ export default class CustomerModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
await this.flush(sharedContext)
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
CustomerTypes.CustomerAddressDTO[]
|
||||
>(addresses, { populate: true })
|
||||
|
||||
if (isString(addressIdOrSelector)) {
|
||||
return serialized[0]
|
||||
return addresses[0]
|
||||
}
|
||||
|
||||
return serialized
|
||||
return addresses
|
||||
}
|
||||
|
||||
async removeCustomerFromGroup(
|
||||
@@ -481,10 +568,19 @@ export default class CustomerModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<void>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async removeCustomerFromGroup(
|
||||
data: CustomerTypes.GroupCustomerPair | CustomerTypes.GroupCustomerPair[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<void> {
|
||||
await this.removeCustomerFromGroup_(data, sharedContext)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async removeCustomerFromGroup_(
|
||||
data: CustomerTypes.GroupCustomerPair | CustomerTypes.GroupCustomerPair[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<void> {
|
||||
const pairs = Array.isArray(data) ? data : [data]
|
||||
const groupCustomers = await this.customerGroupCustomerService_.list({
|
||||
@@ -495,9 +591,4 @@ export default class CustomerModuleService
|
||||
sharedContext
|
||||
)
|
||||
}
|
||||
|
||||
private async flush(context: Context) {
|
||||
const em = (context.manager ?? context.transactionManager) as EntityManager
|
||||
await em.flush()
|
||||
}
|
||||
}
|
||||
+20
-34
@@ -219,7 +219,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "fulfillment_set",
|
||||
data: {
|
||||
id: expect.arrayContaining([fulfillmentSets[i].id]),
|
||||
id: fulfillmentSets[i].id,
|
||||
},
|
||||
}),
|
||||
]),
|
||||
@@ -338,7 +338,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "fulfillment_set",
|
||||
data: {
|
||||
id: expect.arrayContaining([fulfillmentSets[i].id]),
|
||||
id: fulfillmentSets[i].id,
|
||||
},
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -346,9 +346,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "service_zone",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
fulfillmentSets[i].service_zones[0].id,
|
||||
]),
|
||||
id: fulfillmentSets[i].service_zones[0].id,
|
||||
},
|
||||
}),
|
||||
]),
|
||||
@@ -514,7 +512,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "fulfillment_set",
|
||||
data: {
|
||||
id: expect.arrayContaining([fulfillmentSets[i].id]),
|
||||
id: fulfillmentSets[i].id,
|
||||
},
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -522,9 +520,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "service_zone",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
fulfillmentSets[i].service_zones[0].id,
|
||||
]),
|
||||
id: fulfillmentSets[i].service_zones[0].id,
|
||||
},
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -532,9 +528,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "geo_zone",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
fulfillmentSets[i].service_zones[0].geo_zones[0].id,
|
||||
]),
|
||||
id: fulfillmentSets[i].service_zones[0].geo_zones[0].id,
|
||||
},
|
||||
}),
|
||||
]),
|
||||
@@ -724,7 +718,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
})
|
||||
|
||||
expect(updatedFulfillmentSets).toHaveLength(2)
|
||||
expect(eventBusEmitSpy.mock.calls[1][0]).toHaveLength(1)
|
||||
expect(eventBusEmitSpy.mock.calls[1][0]).toHaveLength(2)
|
||||
|
||||
for (const data_ of updateData) {
|
||||
const currentFullfillmentSet = fullfillmentSets.find(
|
||||
@@ -746,7 +740,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "updated",
|
||||
object: "fulfillment_set",
|
||||
data: {
|
||||
id: expect.arrayContaining([currentFullfillmentSet.id]),
|
||||
id: currentFullfillmentSet.id,
|
||||
},
|
||||
}),
|
||||
]),
|
||||
@@ -1075,7 +1069,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
)
|
||||
|
||||
expect(updatedFulfillmentSets).toHaveLength(2)
|
||||
expect(eventBusEmitSpy.mock.calls[1][0]).toHaveLength(5)
|
||||
expect(eventBusEmitSpy.mock.calls[1][0]).toHaveLength(10)
|
||||
|
||||
for (const data_ of updateData) {
|
||||
const expectedFulfillmentSet = updatedFulfillmentSets.find(
|
||||
@@ -1116,7 +1110,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "updated",
|
||||
object: "fulfillment_set",
|
||||
data: {
|
||||
id: expect.arrayContaining([expectedFulfillmentSet.id]),
|
||||
id: expectedFulfillmentSet.id,
|
||||
},
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -1124,9 +1118,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "service_zone",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
expectedFulfillmentSet.service_zones[0].id,
|
||||
]),
|
||||
id: expectedFulfillmentSet.service_zones[0].id,
|
||||
},
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -1134,9 +1126,8 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "geo_zone",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
expectedFulfillmentSet.service_zones[0].geo_zones[0].id,
|
||||
]),
|
||||
id: expectedFulfillmentSet.service_zones[0].geo_zones[0]
|
||||
.id,
|
||||
},
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -1144,9 +1135,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "deleted",
|
||||
object: "service_zone",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
originalFulfillmentSet.service_zones[0].id,
|
||||
]),
|
||||
id: originalFulfillmentSet.service_zones[0].id,
|
||||
},
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -1154,9 +1143,8 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "deleted",
|
||||
object: "geo_zone",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
originalFulfillmentSet.service_zones[0].geo_zones[0].id,
|
||||
]),
|
||||
id: originalFulfillmentSet.service_zones[0].geo_zones[0]
|
||||
.id,
|
||||
},
|
||||
}),
|
||||
]),
|
||||
@@ -1245,7 +1233,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
)
|
||||
|
||||
expect(updatedFulfillmentSets).toHaveLength(2)
|
||||
expect(eventBusEmitSpy.mock.calls[1][0]).toHaveLength(3)
|
||||
expect(eventBusEmitSpy.mock.calls[1][0]).toHaveLength(6)
|
||||
|
||||
for (const data_ of updateData) {
|
||||
const expectedFulfillmentSet = updatedFulfillmentSets.find(
|
||||
@@ -1290,7 +1278,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "updated",
|
||||
object: "fulfillment_set",
|
||||
data: {
|
||||
id: expect.arrayContaining([expectedFulfillmentSet.id]),
|
||||
id: expectedFulfillmentSet.id,
|
||||
},
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -1298,7 +1286,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "service_zone",
|
||||
data: {
|
||||
id: expect.arrayContaining([createdServiceZone.id]),
|
||||
id: createdServiceZone.id,
|
||||
},
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -1306,9 +1294,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "geo_zone",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
createdServiceZone.geo_zones[0].id,
|
||||
]),
|
||||
id: createdServiceZone.geo_zones[0].id,
|
||||
},
|
||||
}),
|
||||
]),
|
||||
|
||||
+21
-15
@@ -152,15 +152,21 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
})
|
||||
)
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(5)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
expect.arrayContaining([
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.FULFILLMENT_CREATED,
|
||||
action: "created",
|
||||
object: "fulfillment",
|
||||
data: { id: fulfillment.id },
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.FULFILLMENT_UPDATED,
|
||||
action: "updated",
|
||||
object: "fulfillment",
|
||||
data: { id: fulfillment.id },
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.FULFILLMENT_ADDRESS_CREATED,
|
||||
action: "created",
|
||||
@@ -179,7 +185,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
object: "fulfillment_label",
|
||||
data: { id: fulfillment.labels[0].id },
|
||||
}),
|
||||
],
|
||||
]),
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
@@ -244,15 +250,21 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
})
|
||||
)
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(5)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
expect.arrayContaining([
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.FULFILLMENT_CREATED,
|
||||
action: "created",
|
||||
object: "fulfillment",
|
||||
data: { id: fulfillment.id },
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.FULFILLMENT_UPDATED,
|
||||
action: "updated",
|
||||
object: "fulfillment",
|
||||
data: { id: fulfillment.id },
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.FULFILLMENT_ADDRESS_CREATED,
|
||||
action: "created",
|
||||
@@ -271,7 +283,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
object: "fulfillment_label",
|
||||
data: { id: fulfillment.labels[0].id },
|
||||
}),
|
||||
],
|
||||
]),
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
@@ -383,15 +395,9 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
})
|
||||
)
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(3)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.FULFILLMENT_UPDATED,
|
||||
action: "updated",
|
||||
object: "fulfillment",
|
||||
data: { id: updatedFulfillment.id },
|
||||
}),
|
||||
expect.arrayContaining([
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.FULFILLMENT_LABEL_DELETED,
|
||||
action: "deleted",
|
||||
@@ -410,7 +416,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
object: "fulfillment_label",
|
||||
data: { id: label4.id },
|
||||
}),
|
||||
],
|
||||
]),
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
|
||||
+4
-4
@@ -154,7 +154,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
const geoZones = await service.createGeoZones(data)
|
||||
|
||||
expect(geoZones).toHaveLength(2)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(2)
|
||||
|
||||
let i = 0
|
||||
for (const data_ of data) {
|
||||
@@ -172,7 +172,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
eventName: FulfillmentEvents.GEO_ZONE_CREATED,
|
||||
action: "created",
|
||||
object: "geo_zone",
|
||||
data: { id: expect.arrayContaining([geoZones[i].id]) },
|
||||
data: { id: geoZones[i].id },
|
||||
}),
|
||||
]),
|
||||
{
|
||||
@@ -331,7 +331,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
const updatedGeoZones = await service.updateGeoZones(updateData)
|
||||
|
||||
expect(updatedGeoZones).toHaveLength(2)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(2)
|
||||
|
||||
for (const data_ of updateData) {
|
||||
const expectedGeoZone = updatedGeoZones.find(
|
||||
@@ -352,7 +352,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
eventName: FulfillmentEvents.GEO_ZONE_UPDATED,
|
||||
action: "updated",
|
||||
object: "geo_zone",
|
||||
data: { id: expect.arrayContaining([expectedGeoZone.id]) },
|
||||
data: { id: expectedGeoZone.id },
|
||||
}),
|
||||
]),
|
||||
{
|
||||
|
||||
+3
-3
@@ -371,7 +371,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
expect.arrayContaining([
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.GEO_ZONE_DELETED,
|
||||
action: "deleted",
|
||||
@@ -396,7 +396,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
object: "geo_zone",
|
||||
data: { id: usGeoZone.id },
|
||||
}),
|
||||
],
|
||||
]),
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
@@ -510,7 +510,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
|
||||
expect(updatedServiceZones).toHaveLength(2)
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(3) // Since the update only calls create and update which are already tested, only check the length
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(6) // Since the update only calls create and update which are already tested, only check the length
|
||||
|
||||
for (const data_ of updateData) {
|
||||
const expectedServiceZone = updatedServiceZones.find(
|
||||
|
||||
+95
-95
@@ -522,7 +522,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(3)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
expect.arrayContaining([
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.SHIPPING_OPTION_CREATED,
|
||||
action: "created",
|
||||
@@ -541,7 +541,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
object: "shipping_option_rule",
|
||||
data: { id: createdShippingOption.rules[0].id },
|
||||
}),
|
||||
],
|
||||
]),
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
@@ -582,7 +582,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
)
|
||||
|
||||
expect(createdShippingOptions).toHaveLength(2)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(3)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(6)
|
||||
|
||||
let i = 0
|
||||
for (const data_ of createData) {
|
||||
@@ -620,9 +620,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "shipping_option",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
createdShippingOptions[i].id,
|
||||
]),
|
||||
id: createdShippingOptions[i].id,
|
||||
},
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -630,9 +628,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "shipping_option_type",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
createdShippingOptions[i].type.id,
|
||||
]),
|
||||
id: createdShippingOptions[i].type.id,
|
||||
},
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -640,9 +636,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "shipping_option_rule",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
createdShippingOptions[i].rules[0].id,
|
||||
]),
|
||||
id: createdShippingOptions[i].rules[0].id,
|
||||
},
|
||||
}),
|
||||
]),
|
||||
@@ -823,7 +817,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
])
|
||||
)
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(5)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(4)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
expect.arrayContaining([
|
||||
buildExpectedEventMessageShape({
|
||||
@@ -832,12 +826,6 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
object: "shipping_option",
|
||||
data: { id: updatedShippingOption.id },
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.SHIPPING_OPTION_TYPE_DELETED,
|
||||
action: "deleted",
|
||||
object: "shipping_option_type",
|
||||
data: { id: shippingOption.type.id },
|
||||
}),
|
||||
buildExpectedEventMessageShape({
|
||||
eventName: FulfillmentEvents.SHIPPING_OPTION_TYPE_CREATED,
|
||||
action: "created",
|
||||
@@ -1374,14 +1362,16 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
])
|
||||
|
||||
// Test with full address including postal expression
|
||||
const shippingOptions = await service.listShippingOptionsForContext({
|
||||
address: {
|
||||
country_code: "US",
|
||||
province_code: "CA",
|
||||
city: "Los Angeles",
|
||||
postal_expression: "90210",
|
||||
},
|
||||
})
|
||||
const shippingOptions = await service.listShippingOptionsForContext(
|
||||
{
|
||||
address: {
|
||||
country_code: "US",
|
||||
province_code: "CA",
|
||||
city: "Los Angeles",
|
||||
postal_expression: "90210",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
expect(shippingOptions).toHaveLength(1)
|
||||
})
|
||||
@@ -1419,13 +1409,15 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
])
|
||||
|
||||
// Test with city but no postal expression
|
||||
const shippingOptions = await service.listShippingOptionsForContext({
|
||||
address: {
|
||||
country_code: "US",
|
||||
province_code: "CA",
|
||||
city: "San Francisco",
|
||||
},
|
||||
})
|
||||
const shippingOptions = await service.listShippingOptionsForContext(
|
||||
{
|
||||
address: {
|
||||
country_code: "US",
|
||||
province_code: "CA",
|
||||
city: "San Francisco",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
expect(shippingOptions).toHaveLength(1)
|
||||
})
|
||||
@@ -1462,12 +1454,14 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
])
|
||||
|
||||
// Test with province but no city
|
||||
const shippingOptions = await service.listShippingOptionsForContext({
|
||||
address: {
|
||||
country_code: "US",
|
||||
province_code: "NY",
|
||||
},
|
||||
})
|
||||
const shippingOptions = await service.listShippingOptionsForContext(
|
||||
{
|
||||
address: {
|
||||
country_code: "US",
|
||||
province_code: "NY",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
expect(shippingOptions).toHaveLength(1)
|
||||
})
|
||||
@@ -1503,11 +1497,13 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
])
|
||||
|
||||
// Test with only country
|
||||
const shippingOptions = await service.listShippingOptionsForContext({
|
||||
address: {
|
||||
country_code: "CA",
|
||||
},
|
||||
})
|
||||
const shippingOptions = await service.listShippingOptionsForContext(
|
||||
{
|
||||
address: {
|
||||
country_code: "CA",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
expect(shippingOptions).toHaveLength(1)
|
||||
})
|
||||
@@ -1758,14 +1754,16 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
])
|
||||
|
||||
// Address with undefined fields should still match if country matches
|
||||
const shippingOptions = await service.listShippingOptionsForContext({
|
||||
address: {
|
||||
country_code: "US",
|
||||
province_code: undefined,
|
||||
city: undefined,
|
||||
postal_expression: undefined,
|
||||
},
|
||||
})
|
||||
const shippingOptions = await service.listShippingOptionsForContext(
|
||||
{
|
||||
address: {
|
||||
country_code: "US",
|
||||
province_code: undefined,
|
||||
city: undefined,
|
||||
postal_expression: undefined,
|
||||
},
|
||||
}
|
||||
)
|
||||
expect(shippingOptions).toHaveLength(1)
|
||||
})
|
||||
|
||||
@@ -1831,26 +1829,27 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
})
|
||||
|
||||
// Create shipping options for each zone
|
||||
const [usOption, europeOption, canadaOption] = await service.createShippingOptions([
|
||||
generateCreateShippingOptionsData({
|
||||
name: "US Shipping",
|
||||
service_zone_id: fulfillmentSet.service_zones[0].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
generateCreateShippingOptionsData({
|
||||
name: "Europe Shipping",
|
||||
service_zone_id: fulfillmentSet.service_zones[1].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
generateCreateShippingOptionsData({
|
||||
name: "Canada Shipping",
|
||||
service_zone_id: fulfillmentSet.service_zones[2].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
])
|
||||
const [usOption, europeOption, canadaOption] =
|
||||
await service.createShippingOptions([
|
||||
generateCreateShippingOptionsData({
|
||||
name: "US Shipping",
|
||||
service_zone_id: fulfillmentSet.service_zones[0].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
generateCreateShippingOptionsData({
|
||||
name: "Europe Shipping",
|
||||
service_zone_id: fulfillmentSet.service_zones[1].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
generateCreateShippingOptionsData({
|
||||
name: "Canada Shipping",
|
||||
service_zone_id: fulfillmentSet.service_zones[2].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
])
|
||||
|
||||
// Test US ZIP code - should only match US zone
|
||||
let shippingOptions = await service.listShippingOptionsForContext({
|
||||
@@ -1970,26 +1969,27 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
})
|
||||
|
||||
// Create shipping options with different prices for each zone
|
||||
const [broadOption, californiaOption, laOption] = await service.createShippingOptions([
|
||||
generateCreateShippingOptionsData({
|
||||
name: "Standard US Shipping",
|
||||
service_zone_id: fulfillmentSet.service_zones[0].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
generateCreateShippingOptionsData({
|
||||
name: "California Express",
|
||||
service_zone_id: fulfillmentSet.service_zones[1].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
generateCreateShippingOptionsData({
|
||||
name: "LA Premium",
|
||||
service_zone_id: fulfillmentSet.service_zones[2].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
])
|
||||
const [broadOption, californiaOption, laOption] =
|
||||
await service.createShippingOptions([
|
||||
generateCreateShippingOptionsData({
|
||||
name: "Standard US Shipping",
|
||||
service_zone_id: fulfillmentSet.service_zones[0].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
generateCreateShippingOptionsData({
|
||||
name: "California Express",
|
||||
service_zone_id: fulfillmentSet.service_zones[1].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
generateCreateShippingOptionsData({
|
||||
name: "LA Premium",
|
||||
service_zone_id: fulfillmentSet.service_zones[2].id,
|
||||
shipping_profile_id: shippingProfile.id,
|
||||
provider_id: providerId,
|
||||
}),
|
||||
])
|
||||
|
||||
// Test LA ZIP code - should match all three zones
|
||||
let shippingOptions = await service.listShippingOptionsForContext({
|
||||
@@ -2001,7 +2001,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
},
|
||||
})
|
||||
expect(shippingOptions).toHaveLength(3)
|
||||
const laIds = shippingOptions.map(opt => opt.id)
|
||||
const laIds = shippingOptions.map((opt) => opt.id)
|
||||
expect(laIds).toContain(broadOption.id)
|
||||
expect(laIds).toContain(californiaOption.id)
|
||||
expect(laIds).toContain(laOption.id)
|
||||
@@ -2015,7 +2015,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
},
|
||||
})
|
||||
expect(shippingOptions).toHaveLength(2)
|
||||
const caIds = shippingOptions.map(opt => opt.id)
|
||||
const caIds = shippingOptions.map((opt) => opt.id)
|
||||
expect(caIds).toContain(broadOption.id)
|
||||
expect(caIds).toContain(californiaOption.id)
|
||||
expect(caIds).not.toContain(laOption.id)
|
||||
|
||||
+2
-4
@@ -100,7 +100,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
await service.createShippingProfiles(createData)
|
||||
|
||||
expect(createdShippingProfiles).toHaveLength(2)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(2)
|
||||
|
||||
let i = 0
|
||||
for (const data_ of createData) {
|
||||
@@ -118,9 +118,7 @@ moduleIntegrationTestRunner<IFulfillmentModuleService>({
|
||||
action: "created",
|
||||
object: "shipping_profile",
|
||||
data: {
|
||||
id: expect.arrayContaining([
|
||||
createdShippingProfiles[i].id,
|
||||
]),
|
||||
id: createdShippingProfiles[i].id,
|
||||
},
|
||||
}),
|
||||
]),
|
||||
|
||||
@@ -47,18 +47,9 @@ import {
|
||||
ShippingOptionType,
|
||||
ShippingProfile,
|
||||
} from "@models"
|
||||
import {
|
||||
buildCreatedFulfillmentEvents,
|
||||
buildCreatedFulfillmentSetEvents,
|
||||
buildCreatedServiceZoneEvents,
|
||||
eventBuilders,
|
||||
isContextValid,
|
||||
Rule,
|
||||
validateAndNormalizeRules,
|
||||
} from "@utils"
|
||||
import { isContextValid, Rule, validateAndNormalizeRules } from "@utils"
|
||||
import { joinerConfig } from "../joiner-config"
|
||||
import { UpdateShippingOptionsInput } from "../types/service"
|
||||
import { buildCreatedShippingOptionEvents } from "../utils/events"
|
||||
import FulfillmentProviderService from "./fulfillment-provider"
|
||||
|
||||
const generateMethodForModels = {
|
||||
@@ -70,7 +61,7 @@ const generateMethodForModels = {
|
||||
ShippingOptionRule,
|
||||
ShippingOptionType,
|
||||
FulfillmentProvider,
|
||||
// Not adding Fulfillment to not auto generate the methods under the hood and only provide the methods we want to expose8
|
||||
// Not adding Fulfillment to not auto generate the methods under the hood and only provide the methods we want to expose
|
||||
}
|
||||
|
||||
type InjectedDependencies = {
|
||||
@@ -339,11 +330,6 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
buildCreatedFulfillmentSetEvents({
|
||||
fulfillmentSets: createdFulfillmentSets,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return createdFulfillmentSets
|
||||
}
|
||||
|
||||
@@ -405,11 +391,6 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
buildCreatedServiceZoneEvents({
|
||||
serviceZones: createdServiceZones,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return createdServiceZones
|
||||
}
|
||||
|
||||
@@ -468,11 +449,6 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
buildCreatedShippingOptionEvents({
|
||||
shippingOptions: createdSO,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return createdSO
|
||||
}
|
||||
|
||||
@@ -487,7 +463,7 @@ export default class FulfillmentModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<FulfillmentTypes.ShippingProfileDTO>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createShippingProfiles(
|
||||
@@ -503,11 +479,6 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
eventBuilders.createdShippingProfile({
|
||||
data: createdShippingProfiles,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
| FulfillmentTypes.ShippingProfileDTO
|
||||
| FulfillmentTypes.ShippingProfileDTO[]
|
||||
@@ -561,11 +532,6 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
eventBuilders.createdGeoZone({
|
||||
data: createdGeoZones,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return await this.baseRepository_.serialize<FulfillmentTypes.GeoZoneDTO[]>(
|
||||
Array.isArray(data) ? createdGeoZones : createdGeoZones[0]
|
||||
)
|
||||
@@ -629,11 +595,6 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
eventBuilders.createdShippingOptionRule({
|
||||
data: createdSORules.map((sor) => ({ id: sor.id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return createdSORules
|
||||
}
|
||||
|
||||
@@ -679,11 +640,6 @@ export default class FulfillmentModuleService
|
||||
throw error
|
||||
}
|
||||
|
||||
buildCreatedFulfillmentEvents({
|
||||
fulfillments: [fulfillment],
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return await this.baseRepository_.serialize<FulfillmentTypes.FulfillmentDTO>(
|
||||
fulfillment
|
||||
)
|
||||
@@ -754,11 +710,6 @@ export default class FulfillmentModuleService
|
||||
throw error
|
||||
}
|
||||
|
||||
buildCreatedFulfillmentEvents({
|
||||
fulfillments: [fulfillment],
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return await this.baseRepository_.serialize<FulfillmentTypes.FulfillmentDTO>(
|
||||
fulfillment
|
||||
)
|
||||
@@ -943,15 +894,6 @@ export default class FulfillmentModuleService
|
||||
})
|
||||
|
||||
if (serviceZoneIdsToDelete.length) {
|
||||
eventBuilders.deletedServiceZone({
|
||||
data: serviceZoneIdsToDelete.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.deletedGeoZone({
|
||||
data: geoZoneIdsToDelete.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
await promiseAll([
|
||||
this.geoZoneService_.delete(
|
||||
{
|
||||
@@ -973,32 +915,6 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
eventBuilders.updatedFulfillmentSet({
|
||||
data: updatedFulfillmentSets,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
const createdServiceZoneIds: string[] = []
|
||||
const createdGeoZoneIds = updatedFulfillmentSets
|
||||
.flatMap((f) =>
|
||||
[...f.service_zones].flatMap((serviceZone) => {
|
||||
if (!existingServiceZoneIds.includes(serviceZone.id)) {
|
||||
createdServiceZoneIds.push(serviceZone.id)
|
||||
}
|
||||
return serviceZone.geo_zones.map((g) => g.id)
|
||||
})
|
||||
)
|
||||
.filter((id) => !existingGeoZoneIds.includes(id))
|
||||
|
||||
eventBuilders.createdServiceZone({
|
||||
data: createdServiceZoneIds.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.createdGeoZone({
|
||||
data: createdGeoZoneIds.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return Array.isArray(data)
|
||||
? updatedFulfillmentSets
|
||||
: updatedFulfillmentSets[0]
|
||||
@@ -1187,11 +1103,6 @@ export default class FulfillmentModuleService
|
||||
})
|
||||
|
||||
if (geoZoneIdsToDelete.length) {
|
||||
eventBuilders.deletedGeoZone({
|
||||
data: geoZoneIdsToDelete.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
await this.geoZoneService_.delete(
|
||||
{
|
||||
id: geoZoneIdsToDelete,
|
||||
@@ -1205,26 +1116,6 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
eventBuilders.updatedServiceZone({
|
||||
data: updatedServiceZones,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
const createdGeoZoneIds = updatedServiceZones
|
||||
.flatMap((serviceZone) => {
|
||||
return serviceZone.geo_zones.map((g) => g.id)
|
||||
})
|
||||
.filter((id) => !existingGeoZoneIds.includes(id))
|
||||
|
||||
eventBuilders.createdGeoZone({
|
||||
data: createdGeoZoneIds.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.updatedGeoZone({
|
||||
data: updatedGeoZoneIds.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return Array.isArray(data) ? updatedServiceZones : updatedServiceZones[0]
|
||||
}
|
||||
|
||||
@@ -1485,11 +1376,6 @@ export default class FulfillmentModuleService
|
||||
})
|
||||
|
||||
if (ruleIdsToDelete.length) {
|
||||
eventBuilders.deletedShippingOptionRule({
|
||||
data: ruleIdsToDelete.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
await this.shippingOptionRuleService_.delete(
|
||||
ruleIdsToDelete,
|
||||
sharedContext
|
||||
@@ -1501,71 +1387,11 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
this.handleShippingOptionUpdateEvents({
|
||||
shippingOptionsData: dataArray,
|
||||
updatedShippingOptions,
|
||||
optionTypeDeletedIds,
|
||||
updatedRuleIds,
|
||||
existingRuleIds,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return Array.isArray(data)
|
||||
? updatedShippingOptions
|
||||
: updatedShippingOptions[0]
|
||||
}
|
||||
|
||||
private handleShippingOptionUpdateEvents({
|
||||
shippingOptionsData,
|
||||
updatedShippingOptions,
|
||||
optionTypeDeletedIds,
|
||||
updatedRuleIds,
|
||||
existingRuleIds,
|
||||
sharedContext,
|
||||
}) {
|
||||
eventBuilders.updatedShippingOption({
|
||||
data: updatedShippingOptions,
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.deletedShippingOptionType({
|
||||
data: optionTypeDeletedIds.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
const createdOptionTypeIds = updatedShippingOptions
|
||||
.filter((so) => {
|
||||
const updateData = shippingOptionsData.find((sod) => sod.id === so.id)
|
||||
return isObject(updateData?.type) && !("id" in updateData.type)
|
||||
})
|
||||
.map((so) => so.type.id)
|
||||
|
||||
eventBuilders.createdShippingOptionType({
|
||||
data: createdOptionTypeIds.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
const createdRuleIds = updatedShippingOptions
|
||||
.flatMap((so) =>
|
||||
[...so.rules].map((rule) => {
|
||||
if (existingRuleIds.includes(rule.id)) {
|
||||
return
|
||||
}
|
||||
|
||||
return rule.id
|
||||
})
|
||||
)
|
||||
.filter((id): id is string => !!id)
|
||||
|
||||
eventBuilders.createdShippingOptionRule({
|
||||
data: createdRuleIds.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.updatedShippingOptionRule({
|
||||
data: updatedRuleIds.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
async upsertShippingOptions(
|
||||
data: FulfillmentTypes.UpsertShippingOptionDTO[],
|
||||
sharedContext?: Context
|
||||
@@ -1652,7 +1478,8 @@ export default class FulfillmentModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<FulfillmentTypes.ShippingOptionTypeDTO>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertShippingOptionTypes(
|
||||
data:
|
||||
| FulfillmentTypes.UpsertShippingOptionTypeDTO[]
|
||||
@@ -1662,12 +1489,7 @@ export default class FulfillmentModuleService
|
||||
| FulfillmentTypes.ShippingOptionTypeDTO[]
|
||||
| FulfillmentTypes.ShippingOptionTypeDTO
|
||||
> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
|
||||
const results = await this.shippingOptionTypeService_.upsert(
|
||||
input,
|
||||
sharedContext
|
||||
)
|
||||
const results = await this.updateShippingOptionTypes_(data, sharedContext)
|
||||
|
||||
const allTypes = await this.baseRepository_.serialize<
|
||||
| FulfillmentTypes.ShippingOptionTypeDTO[]
|
||||
@@ -1677,6 +1499,23 @@ export default class FulfillmentModuleService
|
||||
return Array.isArray(data) ? allTypes : allTypes[0]
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async updateShippingOptionTypes_(
|
||||
data:
|
||||
| FulfillmentTypes.UpsertShippingOptionTypeDTO[]
|
||||
| FulfillmentTypes.UpsertShippingOptionTypeDTO,
|
||||
sharedContext: Context
|
||||
): Promise<InferEntityType<typeof ShippingOptionType>[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
|
||||
const results = await this.shippingOptionTypeService_.upsert(
|
||||
input,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
updateShippingOptionTypes(
|
||||
id: string,
|
||||
@@ -1691,6 +1530,7 @@ export default class FulfillmentModuleService
|
||||
): Promise<FulfillmentTypes.ShippingOptionTypeDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateShippingOptionTypes(
|
||||
idOrSelector: string | FulfillmentTypes.FilterableShippingOptionTypeProps,
|
||||
@@ -1747,7 +1587,8 @@ export default class FulfillmentModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<FulfillmentTypes.ShippingProfileDTO>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateShippingProfiles(
|
||||
idOrSelector: string | FulfillmentTypes.FilterableShippingProfileProps,
|
||||
@@ -1756,6 +1597,25 @@ export default class FulfillmentModuleService
|
||||
): Promise<
|
||||
FulfillmentTypes.ShippingProfileDTO | FulfillmentTypes.ShippingProfileDTO[]
|
||||
> {
|
||||
const profiles = await this.updateShippingProfiles_(
|
||||
idOrSelector,
|
||||
data,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const updatedProfiles = await this.baseRepository_.serialize<
|
||||
FulfillmentTypes.ShippingProfileDTO[]
|
||||
>(profiles)
|
||||
|
||||
return isString(idOrSelector) ? updatedProfiles[0] : updatedProfiles
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async updateShippingProfiles_(
|
||||
idOrSelector: string | FulfillmentTypes.FilterableShippingProfileProps,
|
||||
data: FulfillmentTypes.UpdateShippingProfileDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof ShippingProfile>[]> {
|
||||
let normalizedInput: ({
|
||||
id: string
|
||||
} & FulfillmentTypes.UpdateShippingProfileDTO)[] = []
|
||||
@@ -1784,11 +1644,7 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const updatedProfiles = await this.baseRepository_.serialize<
|
||||
FulfillmentTypes.ShippingProfileDTO[]
|
||||
>(profiles)
|
||||
|
||||
return isString(idOrSelector) ? updatedProfiles[0] : updatedProfiles
|
||||
return profiles
|
||||
}
|
||||
|
||||
async upsertShippingProfiles(
|
||||
@@ -1800,7 +1656,8 @@ export default class FulfillmentModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<FulfillmentTypes.ShippingProfileDTO>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertShippingProfiles(
|
||||
data:
|
||||
| FulfillmentTypes.UpsertShippingProfileDTO[]
|
||||
@@ -1808,6 +1665,24 @@ export default class FulfillmentModuleService
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<
|
||||
FulfillmentTypes.ShippingProfileDTO[] | FulfillmentTypes.ShippingProfileDTO
|
||||
> {
|
||||
const profiles = await this.upsertShippingProfiles_(data, sharedContext)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
| FulfillmentTypes.ShippingProfileDTO[]
|
||||
| FulfillmentTypes.ShippingProfileDTO
|
||||
>(Array.isArray(data) ? profiles : profiles[0])
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertShippingProfiles_(
|
||||
data:
|
||||
| FulfillmentTypes.UpsertShippingProfileDTO[]
|
||||
| FulfillmentTypes.UpsertShippingProfileDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<
|
||||
| InferEntityType<typeof ShippingProfile>[]
|
||||
| InferEntityType<typeof ShippingProfile>
|
||||
> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter((prof) => !!prof.id)
|
||||
@@ -1831,13 +1706,7 @@ export default class FulfillmentModuleService
|
||||
)
|
||||
}
|
||||
|
||||
const result = [...created, ...updated]
|
||||
const allProfiles = await this.baseRepository_.serialize<
|
||||
| FulfillmentTypes.ShippingProfileDTO[]
|
||||
| FulfillmentTypes.ShippingProfileDTO
|
||||
>(result)
|
||||
|
||||
return Array.isArray(data) ? allProfiles : allProfiles[0]
|
||||
return [...created, ...updated]
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -1873,11 +1742,6 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
eventBuilders.updatedGeoZone({
|
||||
data: updatedGeoZones,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
FulfillmentTypes.GeoZoneDTO[]
|
||||
>(updatedGeoZones)
|
||||
@@ -1940,11 +1804,6 @@ export default class FulfillmentModuleService
|
||||
const updatedShippingOptionRules =
|
||||
await this.shippingOptionRuleService_.update(data_, sharedContext)
|
||||
|
||||
eventBuilders.updatedShippingOptionRule({
|
||||
data: updatedShippingOptionRules.map((rule) => ({ id: rule.id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return Array.isArray(data)
|
||||
? updatedShippingOptionRules
|
||||
: updatedShippingOptionRules[0]
|
||||
@@ -1980,9 +1839,6 @@ export default class FulfillmentModuleService
|
||||
)
|
||||
|
||||
const updatedLabelIds: string[] = []
|
||||
let deletedLabelIds: string[] = []
|
||||
|
||||
const existingLabelIds = existingFulfillment.labels.map((label) => label.id)
|
||||
|
||||
/**
|
||||
* @note
|
||||
@@ -1995,12 +1851,6 @@ export default class FulfillmentModuleService
|
||||
* and we also need to emit the events later on.
|
||||
*/
|
||||
if (isDefined(data.labels) && isPresent(data.labels)) {
|
||||
const dataLabelIds: string[] = data.labels
|
||||
.filter((label): label is { id: string } => "id" in label)
|
||||
.map((label) => label.id)
|
||||
|
||||
deletedLabelIds = arrayDifference(existingLabelIds, dataLabelIds)
|
||||
|
||||
for (let label of data.labels) {
|
||||
if (!("id" in label)) {
|
||||
continue
|
||||
@@ -2029,49 +1879,9 @@ export default class FulfillmentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
this.handleFulfillmentUpdateEvents(
|
||||
fulfillment,
|
||||
existingLabelIds,
|
||||
updatedLabelIds,
|
||||
deletedLabelIds,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return fulfillment
|
||||
}
|
||||
|
||||
private handleFulfillmentUpdateEvents(
|
||||
fulfillment: InferEntityType<typeof Fulfillment>,
|
||||
existingLabelIds: string[],
|
||||
updatedLabelIds: string[],
|
||||
deletedLabelIds: string[],
|
||||
sharedContext: Context
|
||||
) {
|
||||
eventBuilders.updatedFulfillment({
|
||||
data: [{ id: fulfillment.id }],
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
eventBuilders.deletedFulfillmentLabel({
|
||||
data: deletedLabelIds.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
eventBuilders.updatedFulfillmentLabel({
|
||||
data: updatedLabelIds.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
const createdLabels = fulfillment.labels.filter((label) => {
|
||||
return !existingLabelIds.includes(label.id)
|
||||
})
|
||||
|
||||
eventBuilders.createdFulfillmentLabel({
|
||||
data: createdLabels.map((label) => ({ id: label.id })),
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async cancelFulfillment(
|
||||
@@ -2106,11 +1916,6 @@ export default class FulfillmentModuleService
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
eventBuilders.updatedFulfillment({
|
||||
data: [{ id }],
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
const result = await this.baseRepository_.serialize<FulfillmentDTO>(
|
||||
@@ -2211,6 +2016,7 @@ export default class FulfillmentModuleService
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async deleteShippingProfiles(
|
||||
ids: string | string[],
|
||||
@@ -2226,6 +2032,7 @@ export default class FulfillmentModuleService
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async softDeleteShippingProfiles<
|
||||
TReturnableLinkableKeys extends string = string
|
||||
|
||||
+33
-7
@@ -436,17 +436,32 @@ moduleIntegrationTestRunner<IInventoryService>({
|
||||
|
||||
const updated = await service.updateReservationItems(update)
|
||||
|
||||
const inventoryLevel =
|
||||
await service.retrieveInventoryLevelByItemAndLocation(
|
||||
reservationItem.inventory_item_id,
|
||||
"location-1"
|
||||
)
|
||||
|
||||
expect(updated).toEqual(expect.objectContaining(update))
|
||||
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusSpy.mock.calls[0][0]).toHaveLength(2)
|
||||
expect(eventBusSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
[
|
||||
expect.arrayContaining([
|
||||
composeMessage(InventoryEvents.RESERVATION_ITEM_UPDATED, {
|
||||
data: { id: reservationItem.id },
|
||||
object: "reservation-item",
|
||||
object: "reservation_item",
|
||||
source: Modules.INVENTORY,
|
||||
action: CommonEvents.UPDATED,
|
||||
}),
|
||||
],
|
||||
composeMessage(InventoryEvents.INVENTORY_LEVEL_UPDATED, {
|
||||
data: { id: inventoryLevel.id },
|
||||
object: "inventory_level",
|
||||
source: Modules.INVENTORY,
|
||||
action: CommonEvents.UPDATED,
|
||||
}),
|
||||
]),
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
@@ -457,19 +472,30 @@ moduleIntegrationTestRunner<IInventoryService>({
|
||||
quantity: 10,
|
||||
}
|
||||
|
||||
eventBusSpy.mockClear()
|
||||
|
||||
const updated2 = await service.updateReservationItems(update2)
|
||||
|
||||
expect(updated2).toEqual(expect.objectContaining(update2))
|
||||
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusSpy.mock.calls[0][0]).toHaveLength(2)
|
||||
expect(eventBusSpy).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
[
|
||||
1,
|
||||
expect.arrayContaining([
|
||||
composeMessage(InventoryEvents.RESERVATION_ITEM_UPDATED, {
|
||||
data: { id: reservationItem.id },
|
||||
object: "reservation-item",
|
||||
object: "reservation_item",
|
||||
source: Modules.INVENTORY,
|
||||
action: CommonEvents.UPDATED,
|
||||
}),
|
||||
],
|
||||
composeMessage(InventoryEvents.INVENTORY_LEVEL_UPDATED, {
|
||||
data: { id: inventoryLevel.id },
|
||||
object: "inventory_level",
|
||||
source: Modules.INVENTORY,
|
||||
action: CommonEvents.UPDATED,
|
||||
}),
|
||||
]),
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
|
||||
@@ -15,19 +15,15 @@ import {
|
||||
import {
|
||||
arrayDifference,
|
||||
BigNumber,
|
||||
CommonEvents,
|
||||
EmitEvents,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
InventoryEvents,
|
||||
isDefined,
|
||||
isString,
|
||||
MathBN,
|
||||
MedusaContext,
|
||||
MedusaError,
|
||||
MedusaService,
|
||||
moduleEventBuilderFactory,
|
||||
Modules,
|
||||
partitionArray,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { InventoryItem, InventoryLevel, ReservationItem } from "@models"
|
||||
@@ -249,21 +245,9 @@ export default class InventoryModuleService
|
||||
const toCreate = Array.isArray(input) ? input : [input]
|
||||
const created = await this.createReservationItems_(toCreate, context)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.CREATED,
|
||||
object: "reservation-item",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.RESERVATION_ITEM_CREATED,
|
||||
})({
|
||||
data: created,
|
||||
sharedContext: context,
|
||||
})
|
||||
|
||||
const serializedReservations = await this.baseRepository_.serialize<
|
||||
InventoryTypes.ReservationItemDTO[] | InventoryTypes.ReservationItemDTO
|
||||
>(created, {
|
||||
populate: true,
|
||||
})
|
||||
>(created)
|
||||
|
||||
return Array.isArray(input)
|
||||
? serializedReservations
|
||||
@@ -350,21 +334,9 @@ export default class InventoryModuleService
|
||||
)
|
||||
const result = await this.createInventoryItems_(toCreate, context)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.CREATED,
|
||||
object: "inventory-item",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.INVENTORY_ITEM_CREATED,
|
||||
})({
|
||||
data: result,
|
||||
sharedContext: context,
|
||||
})
|
||||
|
||||
const serializedItems = await this.baseRepository_.serialize<
|
||||
InventoryTypes.InventoryItemDTO | InventoryTypes.InventoryItemDTO[]
|
||||
>(result, {
|
||||
populate: true,
|
||||
})
|
||||
>(result)
|
||||
|
||||
return Array.isArray(input) ? serializedItems : serializedItems[0]
|
||||
}
|
||||
@@ -374,7 +346,7 @@ export default class InventoryModuleService
|
||||
input: InventoryTypes.CreateInventoryItemInput[],
|
||||
@MedusaContext() context: Context = {}
|
||||
): Promise<InventoryTypes.InventoryItemDTO[]> {
|
||||
return await this.inventoryItemService_.create(input)
|
||||
return await this.inventoryItemService_.create(input, context)
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
@@ -405,21 +377,9 @@ export default class InventoryModuleService
|
||||
|
||||
const created = await this.createInventoryLevels_(toCreate, context)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.CREATED,
|
||||
object: "inventory-level",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.INVENTORY_LEVEL_CREATED,
|
||||
})({
|
||||
data: created,
|
||||
sharedContext: context,
|
||||
})
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
InventoryTypes.InventoryLevelDTO[] | InventoryTypes.InventoryLevelDTO
|
||||
>(created, {
|
||||
populate: true,
|
||||
})
|
||||
>(created)
|
||||
|
||||
return Array.isArray(input) ? serialized : serialized[0]
|
||||
}
|
||||
@@ -460,21 +420,9 @@ export default class InventoryModuleService
|
||||
|
||||
const result = await this.updateInventoryItems_(updates, context)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "inventory-item",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.INVENTORY_ITEM_UPDATED,
|
||||
})({
|
||||
data: result,
|
||||
sharedContext: context,
|
||||
})
|
||||
|
||||
const serializedItems = await this.baseRepository_.serialize<
|
||||
InventoryTypes.InventoryItemDTO | InventoryTypes.InventoryItemDTO[]
|
||||
>(result, {
|
||||
populate: true,
|
||||
})
|
||||
>(result)
|
||||
|
||||
return Array.isArray(input) ? serializedItems : serializedItems[0]
|
||||
}
|
||||
@@ -489,7 +437,7 @@ export default class InventoryModuleService
|
||||
return await this.inventoryItemService_.update(input, context)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async deleteInventoryItemLevelByLocationId(
|
||||
locationId: string | string[],
|
||||
@@ -500,16 +448,6 @@ export default class InventoryModuleService
|
||||
context
|
||||
)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.DELETED,
|
||||
object: "inventory-level",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.INVENTORY_LEVEL_DELETED,
|
||||
})({
|
||||
data: result[0],
|
||||
sharedContext: context,
|
||||
})
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -532,16 +470,6 @@ export default class InventoryModuleService
|
||||
context
|
||||
)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.DELETED,
|
||||
object: "inventory-level",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.INVENTORY_LEVEL_DELETED,
|
||||
})({
|
||||
data: { id: inventoryLevel.id },
|
||||
sharedContext: context,
|
||||
})
|
||||
|
||||
if (!inventoryLevel) {
|
||||
return
|
||||
}
|
||||
@@ -577,21 +505,9 @@ export default class InventoryModuleService
|
||||
|
||||
const levels = await this.updateInventoryLevels_(input, context)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "inventory-level",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.INVENTORY_LEVEL_UPDATED,
|
||||
})({
|
||||
data: levels,
|
||||
sharedContext: context,
|
||||
})
|
||||
|
||||
const updatedLevels = await this.baseRepository_.serialize<
|
||||
InventoryTypes.InventoryLevelDTO | InventoryTypes.InventoryLevelDTO[]
|
||||
>(levels, {
|
||||
populate: true,
|
||||
})
|
||||
>(levels)
|
||||
|
||||
return Array.isArray(updates) ? updatedLevels : updatedLevels[0]
|
||||
}
|
||||
@@ -659,21 +575,9 @@ export default class InventoryModuleService
|
||||
const update = Array.isArray(input) ? input : [input]
|
||||
const result = await this.updateReservationItems_(update, context)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "reservation-item",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.RESERVATION_ITEM_UPDATED,
|
||||
})({
|
||||
data: result,
|
||||
sharedContext: context,
|
||||
})
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
InventoryTypes.ReservationItemDTO | InventoryTypes.ReservationItemDTO[]
|
||||
>(result, {
|
||||
populate: true,
|
||||
})
|
||||
>(result)
|
||||
|
||||
return Array.isArray(input) ? serialized : serialized[0]
|
||||
}
|
||||
@@ -807,33 +711,47 @@ export default class InventoryModuleService
|
||||
return result
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async softDeleteReservationItems(
|
||||
ids: string | string[],
|
||||
config?: SoftDeleteReturn<string>,
|
||||
@MedusaContext() context: Context = {}
|
||||
): Promise<void> {
|
||||
return await this.softDeleteReservationItems_(ids, config, context)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async softDeleteReservationItems_(
|
||||
ids: string | string[],
|
||||
config?: SoftDeleteReturn<string>,
|
||||
@MedusaContext() context: Context = {}
|
||||
): Promise<void> {
|
||||
const reservations: InventoryTypes.ReservationItemDTO[] =
|
||||
await super.listReservationItems({ id: ids }, {}, context)
|
||||
|
||||
const result = await super.softDeleteReservationItems(
|
||||
{ id: ids },
|
||||
config,
|
||||
context
|
||||
)
|
||||
await super.softDeleteReservationItems({ id: ids }, config, context)
|
||||
|
||||
await this.adjustInventoryLevelsForReservationsDeletion(
|
||||
reservations,
|
||||
context
|
||||
)
|
||||
}
|
||||
|
||||
result
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async restoreReservationItems(
|
||||
ids: string | string[],
|
||||
config?: RestoreReturn<string>,
|
||||
@MedusaContext() context: Context = {}
|
||||
): Promise<void> {
|
||||
return await this.restoreReservationItems_(ids, config, context)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
// @ts-expect-error
|
||||
async restoreReservationItems(
|
||||
protected async restoreReservationItems_(
|
||||
ids: string | string[],
|
||||
config?: RestoreReturn<string>,
|
||||
@MedusaContext() context: Context = {}
|
||||
@@ -849,11 +767,19 @@ export default class InventoryModuleService
|
||||
)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async deleteReservationItemByLocationId(
|
||||
locationId: string | string[],
|
||||
@MedusaContext() context: Context = {}
|
||||
): Promise<void> {
|
||||
return await this.deleteReservationItemByLocationId_(locationId, context)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async deleteReservationItemByLocationId_(
|
||||
locationId: string | string[],
|
||||
@MedusaContext() context: Context = {}
|
||||
): Promise<void> {
|
||||
const reservations: InventoryTypes.ReservationItemDTO[] =
|
||||
await this.listReservationItems({ location_id: locationId }, {}, context)
|
||||
@@ -863,16 +789,6 @@ export default class InventoryModuleService
|
||||
context
|
||||
)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.DELETED,
|
||||
object: "reservation-item",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.RESERVATION_ITEM_DELETED,
|
||||
})({
|
||||
data: reservations,
|
||||
sharedContext: context,
|
||||
})
|
||||
|
||||
await this.adjustInventoryLevelsForReservationsDeletion(
|
||||
reservations,
|
||||
context
|
||||
@@ -885,11 +801,19 @@ export default class InventoryModuleService
|
||||
* @param context
|
||||
*/
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async deleteReservationItemsByLineItem(
|
||||
lineItemId: string | string[],
|
||||
@MedusaContext() context: Context = {}
|
||||
): Promise<void> {
|
||||
return await this.deleteReservationItemsByLineItem_(lineItemId, context)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async deleteReservationItemsByLineItem_(
|
||||
lineItemId: string | string[],
|
||||
@MedusaContext() context: Context = {}
|
||||
): Promise<void> {
|
||||
const reservations: InventoryTypes.ReservationItemDTO[] =
|
||||
await this.listReservationItems({ line_item_id: lineItemId }, {}, context)
|
||||
@@ -903,16 +827,6 @@ export default class InventoryModuleService
|
||||
reservations,
|
||||
context
|
||||
)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.DELETED,
|
||||
object: "reservation-item",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.RESERVATION_ITEM_DELETED,
|
||||
})({
|
||||
data: reservations,
|
||||
sharedContext: context,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -921,11 +835,19 @@ export default class InventoryModuleService
|
||||
* @param context
|
||||
*/
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async restoreReservationItemsByLineItem(
|
||||
lineItemId: string | string[],
|
||||
@MedusaContext() context: Context = {}
|
||||
): Promise<void> {
|
||||
return await this.restoreReservationItemsByLineItem_(lineItemId, context)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async restoreReservationItemsByLineItem_(
|
||||
lineItemId: string | string[],
|
||||
@MedusaContext() context: Context = {}
|
||||
): Promise<void> {
|
||||
const reservations: InventoryTypes.ReservationItemDTO[] =
|
||||
await this.listReservationItems({ line_item_id: lineItemId }, {}, context)
|
||||
@@ -939,16 +861,6 @@ export default class InventoryModuleService
|
||||
reservations,
|
||||
context
|
||||
)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.CREATED,
|
||||
object: "reservation-item",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.RESERVATION_ITEM_CREATED,
|
||||
})({
|
||||
data: reservations,
|
||||
sharedContext: context,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1008,23 +920,10 @@ export default class InventoryModuleService
|
||||
context
|
||||
)
|
||||
results.push(result)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "inventory-level",
|
||||
source: Modules.INVENTORY,
|
||||
eventName: InventoryEvents.INVENTORY_LEVEL_UPDATED,
|
||||
})({
|
||||
data: { id: result.id },
|
||||
sharedContext: context,
|
||||
})
|
||||
}
|
||||
|
||||
return await this.baseRepository_.serialize<InventoryTypes.InventoryLevelDTO>(
|
||||
Array.isArray(inventoryItemIdOrData) ? results : results[0],
|
||||
{
|
||||
populate: true,
|
||||
}
|
||||
Array.isArray(inventoryItemIdOrData) ? results : results[0]
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+16
-4
@@ -43,6 +43,10 @@ moduleIntegrationTestRunner<INotificationModuleService>({
|
||||
eventBusEmitSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
eventBusEmitSpy.mockClear()
|
||||
})
|
||||
|
||||
it(`should export the appropriate linkable configuration`, () => {
|
||||
const linkable = Module(Modules.NOTIFICATION, {
|
||||
service: NotificationModuleService,
|
||||
@@ -119,16 +123,24 @@ moduleIntegrationTestRunner<INotificationModuleService>({
|
||||
|
||||
const result = await service.createNotifications(notification)
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(2)
|
||||
expect(eventBusEmitSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.arrayContaining([
|
||||
composeMessage(NotificationEvents.NOTIFICATION_CREATED, {
|
||||
data: { id: result.id },
|
||||
object: "notification",
|
||||
source: Modules.NOTIFICATION,
|
||||
action: CommonEvents.CREATED,
|
||||
}),
|
||||
],
|
||||
composeMessage(NotificationEvents.NOTIFICATION_UPDATED, {
|
||||
data: { id: result.id },
|
||||
object: "notification",
|
||||
source: Modules.NOTIFICATION,
|
||||
action: CommonEvents.UPDATED,
|
||||
}),
|
||||
]),
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
promiseAll,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { Notification } from "@models"
|
||||
import { eventBuilders } from "@utils"
|
||||
import NotificationProviderService from "./notification-provider"
|
||||
|
||||
type InjectedDependencies = {
|
||||
@@ -91,11 +90,6 @@ export default class NotificationModuleService
|
||||
NotificationTypes.NotificationDTO[]
|
||||
>(createdNotifications)
|
||||
|
||||
eventBuilders.createdNotification({
|
||||
data: serialized,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return Array.isArray(data) ? serialized : serialized[0]
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import {
|
||||
CommonEvents,
|
||||
moduleEventBuilderFactory,
|
||||
Modules,
|
||||
NotificationEvents,
|
||||
} from "@medusajs/framework/utils"
|
||||
|
||||
export const eventBuilders = {
|
||||
createdNotification: moduleEventBuilderFactory({
|
||||
source: Modules.NOTIFICATION,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "notification",
|
||||
eventName: NotificationEvents.NOTIFICATION_CREATED,
|
||||
}),
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export * from "./events"
|
||||
File diff suppressed because it is too large.
Load diff
@@ -41,6 +41,7 @@ import {
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
BigNumber,
|
||||
EmitEvents,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
isPresent,
|
||||
@@ -182,8 +183,9 @@ export default class PaymentModuleService
|
||||
data: CreatePaymentCollectionDTO[],
|
||||
sharedContext?: Context
|
||||
): Promise<PaymentCollectionDTO[]>
|
||||
@InjectManager()
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createPaymentCollections(
|
||||
data: CreatePaymentCollectionDTO | CreatePaymentCollectionDTO[],
|
||||
@@ -197,10 +199,7 @@ export default class PaymentModuleService
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize<PaymentCollectionDTO[]>(
|
||||
Array.isArray(data) ? collections : collections[0],
|
||||
{
|
||||
populate: true,
|
||||
}
|
||||
Array.isArray(data) ? collections : collections[0]
|
||||
)
|
||||
}
|
||||
|
||||
@@ -226,6 +225,7 @@ export default class PaymentModuleService
|
||||
): Promise<PaymentCollectionDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updatePaymentCollections(
|
||||
idOrSelector: string | FilterablePaymentCollectionProps,
|
||||
@@ -260,10 +260,7 @@ export default class PaymentModuleService
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize<PaymentCollectionDTO[]>(
|
||||
Array.isArray(data) ? result : result[0],
|
||||
{
|
||||
populate: true,
|
||||
}
|
||||
Array.isArray(data) ? result : result[0]
|
||||
)
|
||||
}
|
||||
|
||||
@@ -285,10 +282,23 @@ export default class PaymentModuleService
|
||||
): Promise<PaymentCollectionDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertPaymentCollections(
|
||||
data: UpsertPaymentCollectionDTO | UpsertPaymentCollectionDTO[],
|
||||
@MedusaContext() sharedContext?: Context
|
||||
): Promise<PaymentCollectionDTO | PaymentCollectionDTO[]> {
|
||||
const result = await this.upsertPaymentCollections_(data, sharedContext)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
PaymentCollectionDTO[] | PaymentCollectionDTO
|
||||
>(Array.isArray(data) ? result : result[0])
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertPaymentCollections_(
|
||||
data: UpsertPaymentCollectionDTO | UpsertPaymentCollectionDTO[],
|
||||
@MedusaContext() sharedContext?: Context
|
||||
): Promise<InferEntityType<typeof PaymentCollection>[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter(
|
||||
(collection): collection is UpdatePaymentCollectionDTO => !!collection.id
|
||||
@@ -309,9 +319,7 @@ export default class PaymentModuleService
|
||||
|
||||
const result = (await promiseAll(operations)).flat()
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
PaymentCollectionDTO[] | PaymentCollectionDTO
|
||||
>(Array.isArray(data) ? result : result[0])
|
||||
return result
|
||||
}
|
||||
|
||||
completePaymentCollections(
|
||||
@@ -325,6 +333,7 @@ export default class PaymentModuleService
|
||||
|
||||
// Should we remove this and use `updatePaymentCollections` instead?
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async completePaymentCollections(
|
||||
paymentCollectionId: string | string[],
|
||||
@MedusaContext() sharedContext?: Context
|
||||
@@ -344,12 +353,12 @@ export default class PaymentModuleService
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize(
|
||||
Array.isArray(paymentCollectionId) ? updated : updated[0],
|
||||
{ populate: true }
|
||||
Array.isArray(paymentCollectionId) ? updated : updated[0]
|
||||
)
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async createPaymentSession(
|
||||
paymentCollectionId: string,
|
||||
input: CreatePaymentSessionDTO,
|
||||
@@ -429,6 +438,7 @@ export default class PaymentModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async updatePaymentSession(
|
||||
data: UpdatePaymentSessionDTO,
|
||||
@MedusaContext() sharedContext?: Context
|
||||
@@ -462,10 +472,11 @@ export default class PaymentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize(updated, { populate: true })
|
||||
return await this.baseRepository_.serialize(updated)
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async deletePaymentSession(
|
||||
id: string,
|
||||
@MedusaContext() sharedContext?: Context
|
||||
@@ -484,6 +495,7 @@ export default class PaymentModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async authorizePaymentSession(
|
||||
id: string,
|
||||
context: Record<string, unknown>,
|
||||
@@ -509,9 +521,7 @@ export default class PaymentModuleService
|
||||
|
||||
// this method needs to be idempotent
|
||||
if (session.payment && session.authorized_at) {
|
||||
return await this.baseRepository_.serialize(session.payment, {
|
||||
populate: true,
|
||||
})
|
||||
return await this.baseRepository_.serialize(session.payment)
|
||||
}
|
||||
|
||||
let { data, status } = await this.paymentProviderService_.authorizePayment(
|
||||
@@ -565,13 +575,11 @@ export default class PaymentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize(payment, {
|
||||
populate: true,
|
||||
})
|
||||
return await this.baseRepository_.serialize(payment)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
async authorizePaymentSession_(
|
||||
protected async authorizePaymentSession_(
|
||||
session: InferEntityType<typeof PaymentSession>,
|
||||
data: Record<string, unknown> | undefined,
|
||||
status: PaymentSessionStatus,
|
||||
@@ -620,6 +628,7 @@ export default class PaymentModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async updatePayment(
|
||||
data: UpdatePaymentDTO,
|
||||
@MedusaContext() sharedContext?: Context
|
||||
@@ -632,6 +641,7 @@ export default class PaymentModuleService
|
||||
|
||||
// TODO: This method should return a capture, not a payment
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async capturePayment(
|
||||
data: CreateCaptureDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -680,13 +690,11 @@ export default class PaymentModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize(payment, {
|
||||
populate: true,
|
||||
})
|
||||
return await this.baseRepository_.serialize(payment)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
private async capturePayment_(
|
||||
protected async capturePayment_(
|
||||
data: CreateCaptureDTO,
|
||||
payment: InferEntityType<typeof Payment>,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -750,8 +758,9 @@ export default class PaymentModuleService
|
||||
|
||||
return { isFullyCaptured, capture }
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
private async capturePaymentFromProvider_(
|
||||
protected async capturePaymentFromProvider_(
|
||||
payment: InferEntityType<typeof Payment>,
|
||||
capture: InferEntityType<typeof Capture> | undefined,
|
||||
isFullyCaptured: boolean,
|
||||
@@ -780,6 +789,7 @@ export default class PaymentModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async refundPayment(
|
||||
data: CreateRefundDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -862,7 +872,7 @@ export default class PaymentModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
private async refundPaymentFromProvider_(
|
||||
protected async refundPaymentFromProvider_(
|
||||
payment: InferEntityType<typeof Payment>,
|
||||
refund: InferEntityType<typeof Refund>,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -887,6 +897,7 @@ export default class PaymentModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async cancelPayment(
|
||||
paymentId: string,
|
||||
@MedusaContext() sharedContext?: Context
|
||||
@@ -913,7 +924,7 @@ export default class PaymentModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
private async maybeUpdatePaymentCollection_(
|
||||
protected async maybeUpdatePaymentCollection_(
|
||||
paymentCollectionId: string,
|
||||
sharedContext?: Context
|
||||
) {
|
||||
@@ -1050,6 +1061,7 @@ export default class PaymentModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async createAccountHolder(
|
||||
input: CreateAccountHolderDTO,
|
||||
@MedusaContext() sharedContext?: Context
|
||||
@@ -1089,6 +1101,7 @@ export default class PaymentModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async updateAccountHolder(
|
||||
input: UpdateAccountHolderDTO,
|
||||
@MedusaContext() sharedContext?: Context
|
||||
@@ -1128,6 +1141,7 @@ export default class PaymentModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async deleteAccountHolder(
|
||||
id: string,
|
||||
@MedusaContext() sharedContext?: Context
|
||||
@@ -1187,7 +1201,6 @@ export default class PaymentModuleService
|
||||
return [normalizedResponse, paymentMethods.length]
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
createPaymentMethods(
|
||||
data: CreatePaymentMethodDTO,
|
||||
sharedContext?: Context
|
||||
@@ -1197,7 +1210,9 @@ export default class PaymentModuleService
|
||||
data: CreatePaymentMethodDTO[],
|
||||
sharedContext?: Context
|
||||
): Promise<PaymentMethodDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async createPaymentMethods(
|
||||
data: CreatePaymentMethodDTO | CreatePaymentMethodDTO[],
|
||||
@MedusaContext() sharedContext?: Context
|
||||
|
||||
+66
-49
@@ -461,35 +461,41 @@ moduleIntegrationTestRunner<IPricingModuleService>({
|
||||
)
|
||||
|
||||
const events = eventBusEmitSpy.mock.calls[0][0]
|
||||
expect(events).toHaveLength(3)
|
||||
expect(events[0]).toEqual(
|
||||
composeMessage(PricingEvents.PRICE_LIST_CREATED, {
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price_list",
|
||||
data: { id: priceList.id },
|
||||
})
|
||||
)
|
||||
expect(events[1]).toEqual(
|
||||
composeMessage(PricingEvents.PRICE_LIST_RULE_CREATED, {
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price_list_rule",
|
||||
data: {
|
||||
id: [
|
||||
priceList.price_list_rules?.[0].id,
|
||||
priceList.price_list_rules?.[1].id,
|
||||
],
|
||||
},
|
||||
})
|
||||
)
|
||||
expect(events[2]).toEqual(
|
||||
composeMessage(PricingEvents.PRICE_CREATED, {
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price",
|
||||
data: { id: priceList.prices![0].id },
|
||||
})
|
||||
|
||||
// 4 events: 1 price list created, 2 price list rules created, 1 price created
|
||||
expect(events).toHaveLength(4)
|
||||
|
||||
expect(events).toEqual(
|
||||
expect.arrayContaining([
|
||||
composeMessage(PricingEvents.PRICE_LIST_CREATED, {
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price_list",
|
||||
data: { id: priceList.id },
|
||||
}),
|
||||
composeMessage(PricingEvents.PRICE_LIST_RULE_CREATED, {
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price_list_rule",
|
||||
data: {
|
||||
id: priceList.price_list_rules?.[1].id,
|
||||
},
|
||||
}),
|
||||
composeMessage(PricingEvents.PRICE_LIST_RULE_CREATED, {
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price_list_rule",
|
||||
data: {
|
||||
id: priceList.price_list_rules?.[0].id,
|
||||
},
|
||||
}),
|
||||
composeMessage(PricingEvents.PRICE_CREATED, {
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price",
|
||||
data: { id: priceList.prices![0].id },
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
@@ -789,7 +795,7 @@ moduleIntegrationTestRunner<IPricingModuleService>({
|
||||
it("should update a price to a priceList successfully", async () => {
|
||||
const [priceSet] = await service.createPriceSets([{}])
|
||||
|
||||
await service.addPriceListPrices([
|
||||
const [priceBeforeUpdate] = await service.addPriceListPrices([
|
||||
{
|
||||
price_list_id: "price-list-1",
|
||||
prices: [
|
||||
@@ -806,7 +812,9 @@ moduleIntegrationTestRunner<IPricingModuleService>({
|
||||
},
|
||||
])
|
||||
|
||||
await service.updatePriceListPrices([
|
||||
eventBusEmitSpy.mockClear()
|
||||
|
||||
const [price] = await service.updatePriceListPrices([
|
||||
{
|
||||
price_list_id: "price-list-1",
|
||||
prices: [
|
||||
@@ -822,28 +830,37 @@ moduleIntegrationTestRunner<IPricingModuleService>({
|
||||
},
|
||||
])
|
||||
|
||||
const events = eventBusEmitSpy.mock.calls[2][0]
|
||||
const events = eventBusEmitSpy.mock.calls[0][0]
|
||||
|
||||
// 4 events: 2 price rules created, 1 price updated, 1 price rule updated, 1 price rule deleted
|
||||
expect(events).toHaveLength(4)
|
||||
expect(events).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: "pricing.price-rule.created",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
name: "pricing.price-rule.created",
|
||||
}),
|
||||
expect.objectContaining({
|
||||
name: "pricing.price.updated",
|
||||
metadata: {
|
||||
source: "pricing",
|
||||
expect.objectContaining(
|
||||
composeMessage(PricingEvents.PRICE_UPDATED, {
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "price",
|
||||
action: "updated",
|
||||
},
|
||||
data: {
|
||||
id: "test-price-id",
|
||||
},
|
||||
data: { id: price.id },
|
||||
})
|
||||
),
|
||||
composeMessage(PricingEvents.PRICE_RULE_CREATED, {
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price_rule",
|
||||
data: { id: price.price_rules![0].id },
|
||||
}),
|
||||
expect.objectContaining({
|
||||
name: "pricing.price-rule.deleted",
|
||||
composeMessage(PricingEvents.PRICE_RULE_CREATED, {
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price_rule",
|
||||
data: { id: price.price_rules![1].id },
|
||||
}),
|
||||
composeMessage(PricingEvents.PRICE_RULE_DELETED, {
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "price_rule",
|
||||
data: { id: priceBeforeUpdate.price_rules![0].id },
|
||||
}),
|
||||
])
|
||||
)
|
||||
|
||||
@@ -41,7 +41,6 @@ import {
|
||||
promiseAll,
|
||||
removeNullish,
|
||||
simpleHash,
|
||||
upperCaseFirst,
|
||||
} from "@medusajs/framework/utils"
|
||||
|
||||
import {
|
||||
@@ -55,7 +54,7 @@ import {
|
||||
|
||||
import { Collection } from "@mikro-orm/core"
|
||||
import { ServiceTypes } from "@types"
|
||||
import { eventBuilders, validatePriceListDates } from "@utils"
|
||||
import { validatePriceListDates } from "@utils"
|
||||
import { joinerConfig } from "../joiner-config"
|
||||
|
||||
type InjectedDependencies = {
|
||||
@@ -169,6 +168,8 @@ export default class PricingModuleService
|
||||
return pricingContext
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createPriceRules(
|
||||
...args: Parameters<PricingTypes.IPricingModuleService["createPriceRules"]>
|
||||
@@ -180,6 +181,8 @@ export default class PricingModuleService
|
||||
}
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updatePriceRules(
|
||||
...args: Parameters<PricingTypes.IPricingModuleService["updatePriceRules"]>
|
||||
@@ -191,6 +194,8 @@ export default class PricingModuleService
|
||||
}
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createPriceListRules(
|
||||
...args: any[]
|
||||
@@ -203,6 +208,8 @@ export default class PricingModuleService
|
||||
}
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updatePriceListRules(
|
||||
...args: any[]
|
||||
@@ -269,7 +276,7 @@ export default class PricingModuleService
|
||||
priceSet.calculated_price = calculatedPrice ?? null
|
||||
}
|
||||
|
||||
return priceSets
|
||||
return await this.baseRepository_.serialize<PriceSetDTO[]>(priceSets)
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@@ -291,7 +298,10 @@ export default class PricingModuleService
|
||||
sharedContext
|
||||
)
|
||||
if (!pricingContext || !priceSets.length) {
|
||||
return [priceSets, count]
|
||||
const serializedPriceSets = await this.baseRepository_.serialize<
|
||||
PriceSetDTO[]
|
||||
>(priceSets)
|
||||
return [serializedPriceSets, count]
|
||||
}
|
||||
|
||||
const calculatedPrices = await this.calculatePrices(
|
||||
@@ -310,7 +320,11 @@ export default class PricingModuleService
|
||||
priceSet.calculated_price = calculatedPrice ?? null
|
||||
}
|
||||
|
||||
return [priceSets, count]
|
||||
const serializedPriceSets = await this.baseRepository_.serialize<
|
||||
PriceSetDTO[]
|
||||
>(priceSets)
|
||||
|
||||
return [serializedPriceSets, count]
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@@ -405,73 +419,73 @@ export default class PricingModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const calculatedPrices: PricingTypes.CalculatedPriceSet[] =
|
||||
pricingFilters.id
|
||||
.map((priceSetId: string): PricingTypes.CalculatedPriceSet | null => {
|
||||
const prices = pricesSetPricesMap.get(priceSetId)
|
||||
if (!prices) {
|
||||
return null
|
||||
}
|
||||
const {
|
||||
calculatedPrice,
|
||||
originalPrice,
|
||||
}: {
|
||||
calculatedPrice: PricingTypes.CalculatedPriceSetDTO
|
||||
originalPrice: PricingTypes.CalculatedPriceSetDTO | undefined
|
||||
} = prices
|
||||
const calculatedPrices: PricingTypes.CalculatedPriceSet[] = []
|
||||
|
||||
return {
|
||||
id: priceSetId,
|
||||
is_calculated_price_price_list: !!calculatedPrice?.price_list_id,
|
||||
is_calculated_price_tax_inclusive: isTaxInclusive(
|
||||
priceRulesPriceMap.get(calculatedPrice.id),
|
||||
for (const priceSetId of pricingFilters.id) {
|
||||
const prices = pricesSetPricesMap.get(priceSetId)
|
||||
if (!prices) {
|
||||
continue
|
||||
}
|
||||
|
||||
const {
|
||||
calculatedPrice,
|
||||
originalPrice,
|
||||
}: {
|
||||
calculatedPrice: PricingTypes.CalculatedPriceSetDTO
|
||||
originalPrice: PricingTypes.CalculatedPriceSetDTO | undefined
|
||||
} = prices
|
||||
|
||||
const calculatedPrice_: PricingTypes.CalculatedPriceSet = {
|
||||
id: priceSetId,
|
||||
is_calculated_price_price_list: !!calculatedPrice?.price_list_id,
|
||||
is_calculated_price_tax_inclusive: isTaxInclusive(
|
||||
priceRulesPriceMap.get(calculatedPrice.id),
|
||||
pricingPreferences,
|
||||
calculatedPrice.currency_code!,
|
||||
pricingContext.context?.region_id as string
|
||||
),
|
||||
calculated_amount: isPresent(calculatedPrice?.amount)
|
||||
? parseFloat(calculatedPrice?.amount as string)
|
||||
: null,
|
||||
raw_calculated_amount: calculatedPrice?.raw_amount || null,
|
||||
|
||||
is_original_price_price_list: !!originalPrice?.price_list_id,
|
||||
is_original_price_tax_inclusive: originalPrice?.id
|
||||
? isTaxInclusive(
|
||||
priceRulesPriceMap.get(originalPrice.id),
|
||||
pricingPreferences,
|
||||
calculatedPrice.currency_code!,
|
||||
originalPrice.currency_code || calculatedPrice.currency_code!,
|
||||
pricingContext.context?.region_id as string
|
||||
),
|
||||
calculated_amount: isPresent(calculatedPrice?.amount)
|
||||
? parseFloat(calculatedPrice?.amount as string)
|
||||
: null,
|
||||
raw_calculated_amount: calculatedPrice?.raw_amount || null,
|
||||
)
|
||||
: false,
|
||||
original_amount: isPresent(originalPrice?.amount)
|
||||
? parseFloat(originalPrice?.amount as string)
|
||||
: null,
|
||||
raw_original_amount: originalPrice?.raw_amount || null,
|
||||
|
||||
is_original_price_price_list: !!originalPrice?.price_list_id,
|
||||
is_original_price_tax_inclusive: originalPrice?.id
|
||||
? isTaxInclusive(
|
||||
priceRulesPriceMap.get(originalPrice.id),
|
||||
pricingPreferences,
|
||||
originalPrice.currency_code || calculatedPrice.currency_code!,
|
||||
pricingContext.context?.region_id as string
|
||||
)
|
||||
: false,
|
||||
original_amount: isPresent(originalPrice?.amount)
|
||||
? parseFloat(originalPrice?.amount as string)
|
||||
: null,
|
||||
raw_original_amount: originalPrice?.raw_amount || null,
|
||||
currency_code: calculatedPrice?.currency_code || null,
|
||||
|
||||
currency_code: calculatedPrice?.currency_code || null,
|
||||
calculated_price: {
|
||||
id: calculatedPrice?.id || null,
|
||||
price_list_id: calculatedPrice?.price_list_id || null,
|
||||
price_list_type: calculatedPrice?.price_list_type || null,
|
||||
min_quantity: parseInt(calculatedPrice?.min_quantity || "") || null,
|
||||
max_quantity: parseInt(calculatedPrice?.max_quantity || "") || null,
|
||||
},
|
||||
|
||||
calculated_price: {
|
||||
id: calculatedPrice?.id || null,
|
||||
price_list_id: calculatedPrice?.price_list_id || null,
|
||||
price_list_type: calculatedPrice?.price_list_type || null,
|
||||
min_quantity:
|
||||
parseInt(calculatedPrice?.min_quantity || "") || null,
|
||||
max_quantity:
|
||||
parseInt(calculatedPrice?.max_quantity || "") || null,
|
||||
},
|
||||
original_price: {
|
||||
id: originalPrice?.id || null,
|
||||
price_list_id: originalPrice?.price_list_id || null,
|
||||
price_list_type: originalPrice?.price_list_type || null,
|
||||
min_quantity: parseInt(originalPrice?.min_quantity || "") || null,
|
||||
max_quantity: parseInt(originalPrice?.max_quantity || "") || null,
|
||||
},
|
||||
}
|
||||
|
||||
original_price: {
|
||||
id: originalPrice?.id || null,
|
||||
price_list_id: originalPrice?.price_list_id || null,
|
||||
price_list_type: originalPrice?.price_list_type || null,
|
||||
min_quantity: parseInt(originalPrice?.min_quantity || "") || null,
|
||||
max_quantity: parseInt(originalPrice?.max_quantity || "") || null,
|
||||
},
|
||||
}
|
||||
})
|
||||
.filter(Boolean) as PricingTypes.CalculatedPriceSet[]
|
||||
calculatedPrices.push(calculatedPrice_)
|
||||
}
|
||||
|
||||
return JSON.parse(JSON.stringify(calculatedPrices))
|
||||
return calculatedPrices
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -534,6 +548,22 @@ export default class PricingModuleService
|
||||
data: UpsertPriceSetDTO | UpsertPriceSetDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<PriceSetDTO | PriceSetDTO[]> {
|
||||
const result = await this.upsertPriceSets_(data, sharedContext)
|
||||
|
||||
try {
|
||||
return await this.baseRepository_.serialize<PriceSetDTO[] | PriceSetDTO>(
|
||||
Array.isArray(data) ? result : result[0]
|
||||
)
|
||||
} finally {
|
||||
this.pricingRepository_.clearAvailableAttributes?.()
|
||||
}
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertPriceSets_(
|
||||
data: UpsertPriceSetDTO | UpsertPriceSetDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof PriceSet>[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
|
||||
const forUpdate = input.filter(
|
||||
@@ -554,13 +584,7 @@ export default class PricingModuleService
|
||||
|
||||
const result = (await promiseAll(operations)).flat()
|
||||
|
||||
try {
|
||||
return await this.baseRepository_.serialize<PriceSetDTO[] | PriceSetDTO>(
|
||||
Array.isArray(data) ? result : result[0]
|
||||
)
|
||||
} finally {
|
||||
this.pricingRepository_.clearAvailableAttributes?.()
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -606,12 +630,13 @@ export default class PricingModuleService
|
||||
normalizedInput,
|
||||
sharedContext
|
||||
)
|
||||
const priceSets = await this.baseRepository_.serialize<
|
||||
|
||||
const serializedUpdateResult = await this.baseRepository_.serialize<
|
||||
PriceSetDTO[] | PriceSetDTO
|
||||
>(updateResult)
|
||||
>(isString(idOrSelector) ? updateResult[0] : updateResult)
|
||||
|
||||
try {
|
||||
return isString(idOrSelector) ? priceSets[0] : priceSets
|
||||
return serializedUpdateResult
|
||||
} finally {
|
||||
this.pricingRepository_.clearAvailableAttributes?.()
|
||||
}
|
||||
@@ -707,10 +732,6 @@ export default class PricingModuleService
|
||||
})),
|
||||
sharedContext
|
||||
)
|
||||
eventBuilders.createdPriceRule({
|
||||
data: createdPriceRules.map((r) => ({ id: r.id })),
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
if (priceRulesToUpdate.length > 0) {
|
||||
@@ -718,10 +739,6 @@ export default class PricingModuleService
|
||||
priceRulesToUpdate,
|
||||
sharedContext
|
||||
)
|
||||
eventBuilders.updatedPriceRule({
|
||||
data: updatedPriceRules.map((r) => ({ id: r.id })),
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
if (priceRulesToDelete.length > 0) {
|
||||
@@ -729,10 +746,6 @@ export default class PricingModuleService
|
||||
priceRulesToDelete,
|
||||
sharedContext
|
||||
)
|
||||
eventBuilders.deletedPriceRule({
|
||||
data: priceRulesToDelete.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
const upsertedPriceRules = [
|
||||
@@ -755,10 +768,6 @@ export default class PricingModuleService
|
||||
priceRuleToDelete,
|
||||
sharedContext
|
||||
)
|
||||
eventBuilders.deletedPriceRule({
|
||||
data: priceRuleToDelete.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
;(priceToUpdate as InferEntityType<typeof Price>).rules_count = 0
|
||||
@@ -780,27 +789,6 @@ export default class PricingModuleService
|
||||
await this.priceService_.delete(pricesToDelete, sharedContext)
|
||||
}
|
||||
|
||||
if (createdPrices.length > 0) {
|
||||
eventBuilders.createdPrice({
|
||||
data: createdPrices.map((p) => ({ id: p.id })),
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
if (updatedPrices.length > 0) {
|
||||
eventBuilders.updatedPrice({
|
||||
data: updatedPrices.map((p) => ({ id: p.id })),
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
if (pricesToDelete.length > 0) {
|
||||
eventBuilders.deletedPrice({
|
||||
data: pricesToDelete.map((id) => ({ id })),
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
const priceSets = await this.priceSetService_.list(
|
||||
{ id: normalizedData.map(({ id }) => id) },
|
||||
{
|
||||
@@ -825,11 +813,6 @@ export default class PricingModuleService
|
||||
ps.prices = upsertedPricesMap.get(ps.id) || []
|
||||
})
|
||||
|
||||
eventBuilders.updatedPriceSet({
|
||||
data: priceSets.map((ps) => ({ id: ps.id })),
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return priceSets
|
||||
}
|
||||
|
||||
@@ -952,8 +935,12 @@ export default class PricingModuleService
|
||||
return dbPrices.find((p) => p.id === inputItem.priceSetId)!
|
||||
})
|
||||
|
||||
const serializedOrderedPriceSets = await this.baseRepository_.serialize<
|
||||
PricingTypes.PriceSetDTO[]
|
||||
>(Array.isArray(data) ? orderedPriceSets : orderedPriceSets[0])
|
||||
|
||||
try {
|
||||
return Array.isArray(data) ? orderedPriceSets : orderedPriceSets[0]
|
||||
return serializedOrderedPriceSets
|
||||
} finally {
|
||||
this.pricingRepository_.clearAvailableAttributes?.()
|
||||
}
|
||||
@@ -977,7 +964,7 @@ export default class PricingModuleService
|
||||
}
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-ignore
|
||||
async updatePriceLists(
|
||||
@@ -1117,6 +1104,18 @@ export default class PricingModuleService
|
||||
data: UpsertPricePreferenceDTO | UpsertPricePreferenceDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<PricePreferenceDTO | PricePreferenceDTO[]> {
|
||||
const result = await this.upsertPricePreferences_(data, sharedContext)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
PricePreferenceDTO[] | PricePreferenceDTO
|
||||
>(Array.isArray(data) ? result : result[0])
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertPricePreferences_(
|
||||
data: UpsertPricePreferenceDTO | UpsertPricePreferenceDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof PricePreference>[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter(
|
||||
(
|
||||
@@ -1139,9 +1138,8 @@ export default class PricingModuleService
|
||||
}
|
||||
|
||||
const result = (await promiseAll(operations)).flat()
|
||||
return await this.baseRepository_.serialize<
|
||||
PricePreferenceDTO[] | PricePreferenceDTO
|
||||
>(Array.isArray(data) ? result : result[0])
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -1158,6 +1156,7 @@ export default class PricingModuleService
|
||||
): Promise<PricePreferenceDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updatePricePreferences(
|
||||
idOrSelector: string | PricingTypes.FilterablePricePreferenceProps,
|
||||
@@ -1248,49 +1247,6 @@ export default class PricingModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const eventsData = priceSets.reduce(
|
||||
(eventsData, priceSet) => {
|
||||
eventsData.priceSets.push({
|
||||
id: priceSet.id,
|
||||
})
|
||||
|
||||
priceSet.prices.map((price) => {
|
||||
eventsData.prices.push({
|
||||
id: price.id,
|
||||
})
|
||||
price.price_rules.map((priceRule) => {
|
||||
eventsData.priceRules.push({
|
||||
id: priceRule.id,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return eventsData
|
||||
},
|
||||
{
|
||||
priceSets: [],
|
||||
priceRules: [],
|
||||
prices: [],
|
||||
} as {
|
||||
priceSets: { id: string }[]
|
||||
priceRules: { id: string }[]
|
||||
prices: { id: string }[]
|
||||
}
|
||||
)
|
||||
|
||||
eventBuilders.createdPriceSet({
|
||||
data: eventsData.priceSets,
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.createdPrice({
|
||||
data: eventsData.prices,
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.createdPriceRule({
|
||||
data: eventsData.priceRules,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return priceSets
|
||||
}
|
||||
|
||||
@@ -1336,18 +1292,11 @@ export default class PricingModuleService
|
||||
}
|
||||
})
|
||||
|
||||
const { entities, performedActions } =
|
||||
await this.priceService_.upsertWithReplace(
|
||||
pricesToUpsert,
|
||||
{ relations: ["price_rules"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
composeAllEvents({
|
||||
eventBuilders,
|
||||
performedActions,
|
||||
sharedContext,
|
||||
})
|
||||
const { entities } = await this.priceService_.upsertWithReplace(
|
||||
pricesToUpsert,
|
||||
{ relations: ["price_rules"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return entities
|
||||
}
|
||||
@@ -1401,67 +1350,6 @@ export default class PricingModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
/**
|
||||
* Preparing data for emitting events
|
||||
*/
|
||||
const eventsData = priceLists.reduce(
|
||||
(eventsData, priceList) => {
|
||||
eventsData.priceList.push({
|
||||
id: priceList.id,
|
||||
})
|
||||
|
||||
priceList.price_list_rules.map((listRule) => {
|
||||
eventsData.priceListRules.push({
|
||||
id: listRule.id,
|
||||
})
|
||||
})
|
||||
|
||||
priceList.prices.map((price) => {
|
||||
eventsData.prices.push({
|
||||
id: price.id,
|
||||
})
|
||||
price.price_rules.map((priceRule) => {
|
||||
eventsData.priceRules.push({
|
||||
id: priceRule.id,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
return eventsData
|
||||
},
|
||||
{
|
||||
priceList: [],
|
||||
priceListRules: [],
|
||||
priceRules: [],
|
||||
prices: [],
|
||||
} as {
|
||||
priceList: { id: string }[]
|
||||
priceListRules: { id: string }[]
|
||||
priceRules: { id: string }[]
|
||||
prices: { id: string }[]
|
||||
}
|
||||
)
|
||||
|
||||
/**
|
||||
* Emitting events for all created entities
|
||||
*/
|
||||
eventBuilders.createdPriceList({
|
||||
data: eventsData.priceList,
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.createdPriceListRule({
|
||||
data: eventsData.priceListRules,
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.createdPrice({
|
||||
data: eventsData.prices,
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.createdPriceRule({
|
||||
data: eventsData.priceRules,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return priceLists
|
||||
}
|
||||
|
||||
@@ -1519,16 +1407,12 @@ export default class PricingModuleService
|
||||
}
|
||||
)
|
||||
|
||||
const { entities, performedActions } =
|
||||
await this.priceListService_.upsertWithReplace(normalizedData, {
|
||||
const { entities } = await this.priceListService_.upsertWithReplace(
|
||||
normalizedData,
|
||||
{
|
||||
relations: ["price_list_rules"],
|
||||
})
|
||||
|
||||
composeAllEvents({
|
||||
eventBuilders,
|
||||
performedActions,
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
return entities
|
||||
}
|
||||
@@ -1572,18 +1456,11 @@ export default class PricingModuleService
|
||||
}
|
||||
}
|
||||
|
||||
const { entities, performedActions } =
|
||||
await this.priceService_.upsertWithReplace(
|
||||
pricesToUpsert,
|
||||
{ relations: ["price_rules"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
composeAllEvents({
|
||||
eventBuilders,
|
||||
performedActions,
|
||||
sharedContext,
|
||||
})
|
||||
const { entities } = await this.priceService_.upsertWithReplace(
|
||||
pricesToUpsert,
|
||||
{ relations: ["price_rules"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return entities
|
||||
}
|
||||
@@ -1634,18 +1511,11 @@ export default class PricingModuleService
|
||||
}
|
||||
})
|
||||
|
||||
const { entities, performedActions } =
|
||||
await this.priceService_.upsertWithReplace(
|
||||
pricesToUpsert,
|
||||
{ relations: ["price_rules"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
composeAllEvents({
|
||||
eventBuilders,
|
||||
performedActions,
|
||||
sharedContext,
|
||||
})
|
||||
const { entities } = await this.priceService_.upsertWithReplace(
|
||||
pricesToUpsert,
|
||||
{ relations: ["price_rules"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return entities
|
||||
}
|
||||
@@ -1705,18 +1575,11 @@ export default class PricingModuleService
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
const { entities, performedActions } =
|
||||
await this.priceListService_.upsertWithReplace(
|
||||
priceListsUpsert,
|
||||
{ relations: ["price_list_rules"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
composeAllEvents({
|
||||
eventBuilders,
|
||||
performedActions,
|
||||
sharedContext,
|
||||
})
|
||||
const { entities } = await this.priceListService_.upsertWithReplace(
|
||||
priceListsUpsert,
|
||||
{ relations: ["price_list_rules"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return entities
|
||||
}
|
||||
@@ -1779,18 +1642,11 @@ export default class PricingModuleService
|
||||
})
|
||||
.filter(Boolean)
|
||||
|
||||
const { entities, performedActions } =
|
||||
await this.priceListService_.upsertWithReplace(
|
||||
priceListsUpsert,
|
||||
{ relations: ["price_list_rules"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
composeAllEvents({
|
||||
eventBuilders,
|
||||
performedActions,
|
||||
sharedContext,
|
||||
})
|
||||
const { entities } = await this.priceListService_.upsertWithReplace(
|
||||
priceListsUpsert,
|
||||
{ relations: ["price_list_rules"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return entities
|
||||
}
|
||||
@@ -1829,26 +1685,6 @@ export default class PricingModuleService
|
||||
}
|
||||
}
|
||||
|
||||
const composeAllEvents = ({
|
||||
eventBuilders,
|
||||
performedActions,
|
||||
sharedContext,
|
||||
}) => {
|
||||
for (const action of Object.keys(performedActions)) {
|
||||
for (const entity of Object.keys(performedActions[action])) {
|
||||
const eventName = action + upperCaseFirst(entity)
|
||||
if (!eventBuilders[eventName]) {
|
||||
continue
|
||||
}
|
||||
|
||||
eventBuilders[eventName]({
|
||||
data: performedActions[action][entity] ?? [],
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isTaxInclusive = (
|
||||
priceRules: InferEntityType<typeof PriceRule>[],
|
||||
preferences: InferEntityType<typeof PricePreference>[],
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
import {
|
||||
CommonEvents,
|
||||
moduleEventBuilderFactory,
|
||||
Modules,
|
||||
PricingEvents,
|
||||
} from "@medusajs/framework/utils"
|
||||
|
||||
export const eventBuilders = {
|
||||
createdPriceSet: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price_set",
|
||||
eventName: PricingEvents.PRICE_SET_CREATED,
|
||||
}),
|
||||
createdPrice: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price",
|
||||
eventName: PricingEvents.PRICE_CREATED,
|
||||
}),
|
||||
createdPriceRule: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price_rule",
|
||||
eventName: PricingEvents.PRICE_RULE_CREATED,
|
||||
}),
|
||||
createdPriceList: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price_list",
|
||||
eventName: PricingEvents.PRICE_LIST_CREATED,
|
||||
}),
|
||||
createdPriceListRule: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "price_list_rule",
|
||||
eventName: PricingEvents.PRICE_LIST_RULE_CREATED,
|
||||
}),
|
||||
updatedPriceSet: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "price_set",
|
||||
eventName: PricingEvents.PRICE_SET_UPDATED,
|
||||
}),
|
||||
updatedPrice: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "price",
|
||||
eventName: PricingEvents.PRICE_UPDATED,
|
||||
}),
|
||||
updatedPriceList: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "price_list",
|
||||
eventName: PricingEvents.PRICE_LIST_UPDATED,
|
||||
}),
|
||||
updatedPriceListRule: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "price_list_rule",
|
||||
eventName: PricingEvents.PRICE_LIST_RULE_UPDATED,
|
||||
}),
|
||||
updatedPriceRule: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "price_rule",
|
||||
eventName: PricingEvents.PRICE_RULE_UPDATED,
|
||||
}),
|
||||
deletedPriceSet: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "price_set",
|
||||
eventName: PricingEvents.PRICE_SET_DELETED,
|
||||
}),
|
||||
deletedPrice: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "price",
|
||||
eventName: PricingEvents.PRICE_DELETED,
|
||||
}),
|
||||
deletedPriceList: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "price_list",
|
||||
eventName: PricingEvents.PRICE_LIST_DELETED,
|
||||
}),
|
||||
deletedPriceListRule: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "price_list_rule",
|
||||
eventName: PricingEvents.PRICE_LIST_RULE_DELETED,
|
||||
}),
|
||||
deletedPriceRule: moduleEventBuilderFactory({
|
||||
source: Modules.PRICING,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "price_rule",
|
||||
eventName: PricingEvents.PRICE_RULE_DELETED,
|
||||
}),
|
||||
}
|
||||
@@ -1,2 +1 @@
|
||||
export * from "./validate-price-list-dates"
|
||||
export * from "./events"
|
||||
+4
-1
@@ -79,7 +79,10 @@ export const buildProductAndRelationsData = ({
|
||||
title: faker.commerce.productName(),
|
||||
sku: faker.commerce.productName(),
|
||||
options: options
|
||||
? { [options[0].title]: options[0].values[0] }
|
||||
? options.reduce((acc, option) => {
|
||||
acc[option.title] = option.values[0]
|
||||
return acc
|
||||
}, {} as Record<string, string>)
|
||||
: {
|
||||
[defaultOptionTitle]: defaultOptionValue,
|
||||
},
|
||||
|
||||
File renamed without changes.
+1150
File diff suppressed because it is too large.
Load diff
-77
@@ -1,15 +1,11 @@
|
||||
import { IProductModuleService } from "@medusajs/framework/types"
|
||||
import {
|
||||
CommonEvents,
|
||||
composeMessage,
|
||||
Modules,
|
||||
ProductEvents,
|
||||
ProductStatus,
|
||||
toMikroORMEntity,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { Product, ProductCategory } from "@models"
|
||||
import {
|
||||
MockEventBusService,
|
||||
moduleIntegrationTestRunner,
|
||||
} from "@medusajs/test-utils"
|
||||
import { productCategoriesRankData } from "../../__fixtures__/product-category/data"
|
||||
@@ -18,9 +14,6 @@ jest.setTimeout(30000)
|
||||
|
||||
moduleIntegrationTestRunner<IProductModuleService>({
|
||||
moduleName: Modules.PRODUCT,
|
||||
injectedDependencies: {
|
||||
[Modules.EVENT_BUS]: new MockEventBusService(),
|
||||
},
|
||||
testSuite: ({ MikroOrmWrapper, service }) => {
|
||||
describe("ProductModuleService product categories", () => {
|
||||
let productOne: Product
|
||||
@@ -404,29 +397,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
)
|
||||
})
|
||||
|
||||
it("should emit events through event bus", async () => {
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
|
||||
const category = await service.createProductCategories({
|
||||
name: "New Category",
|
||||
parent_category_id: productCategoryOne.id,
|
||||
})
|
||||
|
||||
expect(eventBusSpy.mock.calls[0][0]).toHaveLength(1)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_CATEGORY_CREATED, {
|
||||
data: { id: category.id },
|
||||
object: "product_category",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it("should append rank from an existing category depending on parent", async () => {
|
||||
await service.createProductCategories({
|
||||
@@ -504,29 +474,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
productCategoryZeroTwo = categories[5]
|
||||
})
|
||||
|
||||
it("should emit events through event bus", async () => {
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
eventBusSpy.mockClear()
|
||||
|
||||
await service.updateProductCategories(productCategoryZero.id, {
|
||||
name: "New Category",
|
||||
})
|
||||
|
||||
expect(eventBusSpy.mock.calls[0][0]).toHaveLength(1)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_CATEGORY_UPDATED, {
|
||||
data: { id: productCategoryZero.id },
|
||||
object: "product_category",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it("should update the name of the category successfully", async () => {
|
||||
await service.updateProductCategories(productCategoryZero.id, {
|
||||
@@ -683,30 +630,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
productCategoryTwo = categories[2]
|
||||
})
|
||||
|
||||
it("should emit events through event bus", async () => {
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
eventBusSpy.mockClear()
|
||||
|
||||
await service.deleteProductCategories([productCategoryOne.id])
|
||||
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
expect.objectContaining({
|
||||
data: { id: productCategoryOne.id },
|
||||
name: "product.product-category.deleted",
|
||||
metadata: {
|
||||
action: CommonEvents.DELETED,
|
||||
object: "product_category",
|
||||
source: Modules.PRODUCT,
|
||||
},
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw an error when an id does not exist", async () => {
|
||||
let error
|
||||
|
||||
-77
@@ -1,14 +1,10 @@
|
||||
import { IProductModuleService } from "@medusajs/framework/types"
|
||||
import {
|
||||
CommonEvents,
|
||||
composeMessage,
|
||||
Modules,
|
||||
ProductEvents,
|
||||
ProductStatus,
|
||||
toMikroORMEntity,
|
||||
} from "@medusajs/framework/utils"
|
||||
import {
|
||||
MockEventBusService,
|
||||
moduleIntegrationTestRunner,
|
||||
} from "@medusajs/test-utils"
|
||||
import { Product, ProductCollection } from "@models"
|
||||
@@ -18,9 +14,6 @@ jest.setTimeout(30000)
|
||||
|
||||
moduleIntegrationTestRunner<IProductModuleService>({
|
||||
moduleName: Modules.PRODUCT,
|
||||
injectedDependencies: {
|
||||
[Modules.EVENT_BUS]: new MockEventBusService(),
|
||||
},
|
||||
testSuite: ({ MikroOrmWrapper, service }) => {
|
||||
describe("ProductModuleService product collections", () => {
|
||||
let productOne: Product
|
||||
@@ -284,59 +277,11 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
expect(collections).toHaveLength(0)
|
||||
})
|
||||
|
||||
it("should emit events through event bus", async () => {
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
await service.deleteProductCollections([collectionId])
|
||||
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
{
|
||||
name: "product.product-collection.deleted",
|
||||
data: { id: collectionId },
|
||||
metadata: {
|
||||
action: CommonEvents.DELETED,
|
||||
object: "product_collection",
|
||||
source: Modules.PRODUCT,
|
||||
},
|
||||
},
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("updateCollections", () => {
|
||||
const collectionId = "test-1"
|
||||
|
||||
it("should emit events through event bus", async () => {
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
|
||||
await service.upsertProductCollections([
|
||||
{
|
||||
id: collectionId,
|
||||
title: "New Collection",
|
||||
product_ids: ["product_id"],
|
||||
},
|
||||
])
|
||||
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_COLLECTION_UPDATED, {
|
||||
data: { id: collectionId },
|
||||
object: "product_collection",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it("should update the value of the collection successfully", async () => {
|
||||
await service.upsertProductCollections([
|
||||
@@ -534,28 +479,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
)
|
||||
})
|
||||
|
||||
it("should emit events through event bus", async () => {
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
|
||||
const collections = await service.createProductCollections([
|
||||
{ title: "New Collection" },
|
||||
])
|
||||
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_COLLECTION_CREATED, {
|
||||
data: { id: collections[0].id },
|
||||
object: "product_collection",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
-61
@@ -1,15 +1,11 @@
|
||||
import { IProductModuleService } from "@medusajs/framework/types"
|
||||
import {
|
||||
CommonEvents,
|
||||
composeMessage,
|
||||
Modules,
|
||||
ProductEvents,
|
||||
ProductStatus,
|
||||
toMikroORMEntity,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { Product, ProductTag } from "@models"
|
||||
import {
|
||||
MockEventBusService,
|
||||
moduleIntegrationTestRunner,
|
||||
} from "@medusajs/test-utils"
|
||||
|
||||
@@ -18,15 +14,6 @@ jest.setTimeout(30000)
|
||||
moduleIntegrationTestRunner<IProductModuleService>({
|
||||
moduleName: Modules.PRODUCT,
|
||||
testSuite: ({ MikroOrmWrapper, service }) => {
|
||||
let eventBusEmitSpy
|
||||
|
||||
beforeEach(() => {
|
||||
eventBusEmitSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
describe("ProductModuleService product tags", () => {
|
||||
let tagOne: ProductTag
|
||||
@@ -303,20 +290,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
|
||||
expect(productTag.value).toEqual("UK")
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_TAG_UPDATED, {
|
||||
data: { id: productTag.id },
|
||||
object: "product_tag",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw an error when an id does not exist", async () => {
|
||||
@@ -350,20 +323,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
|
||||
expect(productTag[0]?.value).toEqual("UK")
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_TAG_CREATED, {
|
||||
data: { id: productTag[0].id },
|
||||
object: "product_tag",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -409,26 +368,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
const newTag = productTags.find((t) => t.value === "new")!
|
||||
const updatedTag = productTags.find((t) => t.value === "updated")!
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(2)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_TAG_CREATED, {
|
||||
data: { id: newTag.id },
|
||||
object: "product_tag",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
}),
|
||||
composeMessage(ProductEvents.PRODUCT_TAG_UPDATED, {
|
||||
data: { id: updatedTag.id },
|
||||
object: "product_tag",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
-41
@@ -7,15 +7,11 @@ import {
|
||||
UpdateProductVariantDTO,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
CommonEvents,
|
||||
composeMessage,
|
||||
Modules,
|
||||
ProductEvents,
|
||||
ProductStatus,
|
||||
} from "@medusajs/framework/utils"
|
||||
|
||||
import {
|
||||
MockEventBusService,
|
||||
moduleIntegrationTestRunner,
|
||||
} from "@medusajs/test-utils"
|
||||
|
||||
@@ -24,15 +20,6 @@ jest.setTimeout(30000)
|
||||
moduleIntegrationTestRunner<IProductModuleService>({
|
||||
moduleName: Modules.PRODUCT,
|
||||
testSuite: ({ service }) => {
|
||||
let eventBusEmitSpy
|
||||
|
||||
beforeEach(() => {
|
||||
eventBusEmitSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks()
|
||||
})
|
||||
|
||||
describe("ProductModuleService product variants", () => {
|
||||
let variantOne: ProductVariantDTO
|
||||
@@ -212,20 +199,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
)
|
||||
expect(productVariant.title).toEqual("new test")
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_VARIANT_UPDATED, {
|
||||
data: { id: variantOne.id },
|
||||
object: "product_variant",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it("should do a partial update on the options of a variant successfully", async () => {
|
||||
@@ -294,20 +267,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
})
|
||||
)
|
||||
|
||||
expect(eventBusEmitSpy.mock.calls[0][0]).toHaveLength(1)
|
||||
expect(eventBusEmitSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_VARIANT_CREATED, {
|
||||
data: { id: variant.id },
|
||||
object: "product_variant",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it("should correctly associate variants with own product options", async () => {
|
||||
|
||||
-130
@@ -4,11 +4,8 @@ import {
|
||||
ProductTagDTO,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
CommonEvents,
|
||||
composeMessage,
|
||||
kebabCase,
|
||||
Modules,
|
||||
ProductEvents,
|
||||
ProductStatus,
|
||||
} from "@medusajs/framework/utils"
|
||||
import {
|
||||
@@ -20,7 +17,6 @@ import {
|
||||
} from "@models"
|
||||
|
||||
import {
|
||||
MockEventBusService,
|
||||
moduleIntegrationTestRunner,
|
||||
} from "@medusajs/test-utils"
|
||||
import { UpdateProductInput } from "@types"
|
||||
@@ -34,9 +30,6 @@ jest.setTimeout(300000)
|
||||
|
||||
moduleIntegrationTestRunner<IProductModuleService>({
|
||||
moduleName: Modules.PRODUCT,
|
||||
injectedDependencies: {
|
||||
[Modules.EVENT_BUS]: new MockEventBusService(),
|
||||
},
|
||||
testSuite: ({ MikroOrmWrapper, service }) => {
|
||||
describe("ProductModuleService products", function () {
|
||||
let productCollectionOne: ProductCollection
|
||||
@@ -573,37 +566,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
)
|
||||
})
|
||||
|
||||
it("should emit events through event bus", async () => {
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
const data = buildProductAndRelationsData({
|
||||
images,
|
||||
thumbnail: images[0].url,
|
||||
})
|
||||
|
||||
const updateData = {
|
||||
...data,
|
||||
options: data.options,
|
||||
id: productOne.id,
|
||||
title: "updated title",
|
||||
}
|
||||
|
||||
await service.upsertProducts([updateData])
|
||||
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_UPDATED, {
|
||||
data: { id: productOne.id },
|
||||
object: "product",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it("should add relationships to a product", async () => {
|
||||
const updateData = {
|
||||
@@ -1086,29 +1048,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
)
|
||||
})
|
||||
|
||||
it("should emit events through eventBus", async () => {
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
const data = buildProductAndRelationsData({
|
||||
images,
|
||||
thumbnail: images[0].url,
|
||||
})
|
||||
|
||||
const products = await service.createProducts([data])
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_CREATED, {
|
||||
data: { id: products[0].id },
|
||||
object: "product",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
it("should throw because variant doesn't have all options set", async () => {
|
||||
const error = await service
|
||||
@@ -1289,75 +1228,6 @@ moduleIntegrationTestRunner<IProductModuleService>({
|
||||
expect(softDeleted).toHaveLength(1)
|
||||
})
|
||||
|
||||
it("should emit events through eventBus", async () => {
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
const data = buildProductAndRelationsData({
|
||||
images,
|
||||
thumbnail: images[0].url,
|
||||
})
|
||||
|
||||
const products = await service.createProducts([data])
|
||||
|
||||
await service.softDeleteProducts([products[0].id])
|
||||
|
||||
expect(eventBusSpy).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_CREATED, {
|
||||
data: { id: products[0].id },
|
||||
object: "product",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
|
||||
expect(eventBusSpy).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
[
|
||||
composeMessage(ProductEvents.PRODUCT_DELETED, {
|
||||
data: { id: [products[0].id] },
|
||||
object: "product",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
}),
|
||||
composeMessage(ProductEvents.PRODUCT_VARIANT_DELETED, {
|
||||
data: { id: [products[0].variants[0].id] },
|
||||
object: "product_variant",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
}),
|
||||
composeMessage(ProductEvents.PRODUCT_OPTION_DELETED, {
|
||||
data: { id: [products[0].options[0].id] },
|
||||
object: "product_option",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
}),
|
||||
composeMessage(ProductEvents.PRODUCT_IMAGE_DELETED, {
|
||||
data: {
|
||||
id: [products[0].images[0].id],
|
||||
},
|
||||
object: "product_image",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
}),
|
||||
composeMessage(ProductEvents.PRODUCT_OPTION_VALUE_DELETED, {
|
||||
data: {
|
||||
id: [products[0].options[0].values[0].id],
|
||||
},
|
||||
object: "product_option_value",
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("restore", function () {
|
||||
|
||||
File renamed without changes.
@@ -29,7 +29,7 @@
|
||||
"resolve:aliases": "tsc --showConfig -p tsconfig.json > tsconfig.resolved.json && tsc-alias -p tsconfig.resolved.json && rimraf tsconfig.resolved.json",
|
||||
"build": "rimraf dist && tsc --build && npm run resolve:aliases",
|
||||
"test": "jest --runInBand --bail --forceExit -- src/**/__tests__/**/*.ts",
|
||||
"test:integration": "jest --bail --forceExit -- integration-tests/__tests__/**/*.ts",
|
||||
"test:integration": "jest --bail --forceExit -- integration-tests/__tests__/**/*.spec.ts",
|
||||
"migration:initial": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create --initial",
|
||||
"migration:create": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:create",
|
||||
"migration:up": "MIKRO_ORM_CLI_CONFIG=./mikro-orm.config.dev.ts medusa-mikro-orm migration:up",
|
||||
|
||||
@@ -452,9 +452,7 @@ export class ProductCategoryRepository extends DALUtils.MikroOrmBaseTreeReposito
|
||||
}
|
||||
let productCategory = await manager.findOne<
|
||||
InferEntityType<typeof ProductCategory>
|
||||
>(ProductCategory.name, {
|
||||
id: categoryData.id,
|
||||
})
|
||||
>(ProductCategory.name, categoryData.id!)
|
||||
|
||||
if (!productCategory) {
|
||||
throw new MedusaError(
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
isPresent,
|
||||
mergeMetadata,
|
||||
isDefined,
|
||||
deepCopy,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { SqlEntityManager, wrap } from "@mikro-orm/postgresql"
|
||||
|
||||
@@ -80,21 +81,22 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory(
|
||||
) => void,
|
||||
context: Context = {}
|
||||
): Promise<InferEntityType<typeof Product>[]> {
|
||||
const productsToUpdate_ = deepCopy(productsToUpdate)
|
||||
const productIdsToUpdate: string[] = []
|
||||
|
||||
productsToUpdate.forEach((productToUpdate) => {
|
||||
productsToUpdate_.forEach((productToUpdate) => {
|
||||
ProductRepository.#correctUpdateDTOTypes(productToUpdate)
|
||||
productIdsToUpdate.push(productToUpdate.id)
|
||||
})
|
||||
|
||||
const relationsToLoad =
|
||||
ProductRepository.#getProductDeepUpdateRelationsToLoad(productsToUpdate)
|
||||
ProductRepository.#getProductDeepUpdateRelationsToLoad(productsToUpdate_)
|
||||
|
||||
const findOptions = buildQuery(
|
||||
{ id: productIdsToUpdate },
|
||||
{
|
||||
relations: relationsToLoad,
|
||||
take: productsToUpdate.length,
|
||||
take: productsToUpdate_.length,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -111,7 +113,7 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory(
|
||||
)
|
||||
}
|
||||
|
||||
for (const productToUpdate of productsToUpdate) {
|
||||
for (const productToUpdate of productsToUpdate_) {
|
||||
const product = productsMap.get(productToUpdate.id)!
|
||||
const wrappedProduct = wrap(product)
|
||||
|
||||
@@ -173,7 +175,7 @@ export class ProductRepository extends DALUtils.mikroOrmBaseRepositoryFactory(
|
||||
// Doing this to ensure updates are returned in the same order they were provided,
|
||||
// since some core flows rely on this.
|
||||
// This is a high level of coupling though.
|
||||
return productsToUpdate.map(
|
||||
return productsToUpdate_.map(
|
||||
(productToUpdate) => productsMap.get(productToUpdate.id)!
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,30 +6,45 @@ import {
|
||||
ProductTypes,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
createMedusaMikroOrmEventSubscriber,
|
||||
FreeTextSearchFilterKeyPrefix,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
isDefined,
|
||||
MedusaContext,
|
||||
MedusaError,
|
||||
MedusaInternalService,
|
||||
MedusaService,
|
||||
ModulesSdkUtils,
|
||||
registerInternalServiceEventSubscriber,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { EntityManager, EventType } from "@mikro-orm/core"
|
||||
import { ProductCategory } from "@models"
|
||||
import { ProductCategoryRepository } from "@repositories"
|
||||
import { UpdateCategoryInput } from "@types"
|
||||
|
||||
type InjectedDependencies = {
|
||||
productCategoryRepository: DAL.TreeRepositoryService
|
||||
productModuleService: ReturnType<typeof MedusaService>
|
||||
}
|
||||
export default class ProductCategoryService {
|
||||
protected readonly productCategoryRepository_: DAL.TreeRepositoryService
|
||||
|
||||
constructor({ productCategoryRepository }: InjectedDependencies) {
|
||||
this.productCategoryRepository_ = productCategoryRepository
|
||||
export default class ProductCategoryService extends MedusaInternalService<
|
||||
InjectedDependencies,
|
||||
typeof ProductCategory
|
||||
>(ProductCategory) {
|
||||
protected readonly productCategoryRepository_: DAL.TreeRepositoryService
|
||||
protected readonly container: InjectedDependencies
|
||||
|
||||
constructor(container: InjectedDependencies) {
|
||||
// @ts-expect-error
|
||||
super(...arguments)
|
||||
this.container = container
|
||||
this.productCategoryRepository_ = container.productCategoryRepository
|
||||
}
|
||||
|
||||
// TODO: Add support for object filter
|
||||
@InjectManager("productCategoryRepository_")
|
||||
// @ts-expect-error
|
||||
async retrieve(
|
||||
productCategoryId: string,
|
||||
config: FindConfig<ProductTypes.ProductCategoryDTO> = {},
|
||||
@@ -150,6 +165,7 @@ export default class ProductCategoryService {
|
||||
}
|
||||
|
||||
@InjectTransactionManager("productCategoryRepository_")
|
||||
// @ts-expect-error
|
||||
async update(
|
||||
data: UpdateCategoryInput[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -160,14 +176,45 @@ export default class ProductCategoryService {
|
||||
}
|
||||
|
||||
@InjectTransactionManager("productCategoryRepository_")
|
||||
// @ts-expect-error
|
||||
async delete(
|
||||
ids: string[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<string[]> {
|
||||
return await this.productCategoryRepository_.delete(ids, sharedContext)
|
||||
const subscriber = createMedusaMikroOrmEventSubscriber(
|
||||
[ProductCategory.name],
|
||||
this.container["productModuleService"]
|
||||
)
|
||||
|
||||
registerInternalServiceEventSubscriber(sharedContext, subscriber)
|
||||
|
||||
const deletedIds = await this.productCategoryRepository_.delete(
|
||||
ids,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
// Delete are handled a bit differently since we are going to the DB directly, therefore
|
||||
// just like upsert with replace, we need to dispatch the events manually.
|
||||
if (deletedIds.length) {
|
||||
const manager = (sharedContext.transactionManager ??
|
||||
sharedContext.manager) as EntityManager
|
||||
const eventManager = manager.getEventManager()
|
||||
|
||||
deletedIds.forEach((id) => {
|
||||
eventManager.dispatchEvent(EventType.afterDelete, {
|
||||
entity: { id },
|
||||
meta: {
|
||||
className: ProductCategory.name,
|
||||
} as Parameters<typeof eventManager.dispatchEvent>[2],
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return deletedIds
|
||||
}
|
||||
|
||||
@InjectTransactionManager("productCategoryRepository_")
|
||||
// @ts-expect-error
|
||||
async softDelete(
|
||||
ids: string[],
|
||||
@MedusaContext() sharedContext?: Context
|
||||
@@ -178,6 +225,7 @@ export default class ProductCategoryService {
|
||||
}
|
||||
|
||||
@InjectTransactionManager("productCategoryRepository_")
|
||||
// @ts-expect-error
|
||||
async restore(
|
||||
ids: string[],
|
||||
@MedusaContext() sharedContext?: Context
|
||||
|
||||
@@ -25,6 +25,7 @@ import { ProductCategoryService } from "@services"
|
||||
|
||||
import {
|
||||
arrayDifference,
|
||||
createMedusaMikroOrmEventSubscriber,
|
||||
EmitEvents,
|
||||
generateEntityId,
|
||||
InjectManager,
|
||||
@@ -37,11 +38,13 @@ import {
|
||||
MedusaContext,
|
||||
MedusaError,
|
||||
MedusaService,
|
||||
MessageAggregator,
|
||||
Modules,
|
||||
ProductStatus,
|
||||
removeUndefined,
|
||||
toHandle,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { EntityManager } from "@mikro-orm/core"
|
||||
import { ProductRepository } from "../repositories"
|
||||
import {
|
||||
UpdateCategoryInput,
|
||||
@@ -52,8 +55,8 @@ import {
|
||||
UpdateTagInput,
|
||||
UpdateTypeInput,
|
||||
} from "../types"
|
||||
import { eventBuilders } from "../utils"
|
||||
import { joinerConfig } from "./../joiner-config"
|
||||
import { eventBuilders } from "../utils/events"
|
||||
|
||||
type InjectedDependencies = {
|
||||
baseRepository: DAL.RepositoryService
|
||||
@@ -331,11 +334,6 @@ export default class ProductModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
eventBuilders.createdProductVariant({
|
||||
data: createdVariants,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return createdVariants
|
||||
}
|
||||
|
||||
@@ -366,11 +364,11 @@ export default class ProductModuleService
|
||||
(variant): variant is ProductTypes.CreateProductVariantDTO => !variant.id
|
||||
)
|
||||
|
||||
let created: InferEntityType<typeof ProductVariant>[] = []
|
||||
let created: ProductTypes.ProductVariantDTO[] = []
|
||||
let updated: InferEntityType<typeof ProductVariant>[] = []
|
||||
|
||||
if (forCreate.length) {
|
||||
created = await this.createVariants_(forCreate, sharedContext)
|
||||
created = await this.createProductVariants(forCreate, sharedContext)
|
||||
}
|
||||
if (forUpdate.length) {
|
||||
updated = await this.updateVariants_(forUpdate, sharedContext)
|
||||
@@ -493,7 +491,7 @@ export default class ProductModuleService
|
||||
)
|
||||
}
|
||||
|
||||
const { entities: productVariants, performedActions } =
|
||||
const { entities: productVariants } =
|
||||
await this.productVariantService_.upsertWithReplace(
|
||||
productVariantsWithOptions,
|
||||
{
|
||||
@@ -502,19 +500,6 @@ export default class ProductModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
eventBuilders.createdProductVariant({
|
||||
data: performedActions.created[ProductVariant.name] ?? [],
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.updatedProductVariant({
|
||||
data: performedActions.updated[ProductVariant.name] ?? [],
|
||||
sharedContext,
|
||||
})
|
||||
eventBuilders.deletedProductVariant({
|
||||
data: performedActions.deleted[ProductVariant.name] ?? [],
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return productVariants
|
||||
}
|
||||
|
||||
@@ -544,11 +529,6 @@ export default class ProductModuleService
|
||||
ProductTypes.ProductTagDTO[]
|
||||
>(tags)
|
||||
|
||||
eventBuilders.createdProductTag({
|
||||
data: createdTags,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return Array.isArray(data) ? createdTags : createdTags[0]
|
||||
}
|
||||
|
||||
@@ -561,12 +541,26 @@ export default class ProductModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductTagDTO>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertProductTags(
|
||||
data: ProductTypes.UpsertProductTagDTO[] | ProductTypes.UpsertProductTagDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ProductTypes.ProductTagDTO[] | ProductTypes.ProductTagDTO> {
|
||||
const tags = await this.upsertProductTags_(data, sharedContext)
|
||||
|
||||
const allTags = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductTagDTO[] | ProductTypes.ProductTagDTO
|
||||
>(Array.isArray(data) ? tags : tags[0])
|
||||
|
||||
return allTags
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertProductTags_(
|
||||
data: ProductTypes.UpsertProductTagDTO[] | ProductTypes.UpsertProductTagDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof ProductTag>[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter((tag): tag is UpdateTagInput => !!tag.id)
|
||||
const forCreate = input.filter(
|
||||
@@ -578,25 +572,12 @@ export default class ProductModuleService
|
||||
|
||||
if (forCreate.length) {
|
||||
created = await this.productTagService_.create(forCreate, sharedContext)
|
||||
eventBuilders.createdProductTag({
|
||||
data: created,
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
if (forUpdate.length) {
|
||||
updated = await this.productTagService_.update(forUpdate, sharedContext)
|
||||
eventBuilders.updatedProductTag({
|
||||
data: updated,
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
const result = [...created, ...updated]
|
||||
const allTags = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductTagDTO[] | ProductTypes.ProductTagDTO
|
||||
>(result)
|
||||
|
||||
return Array.isArray(data) ? allTags : allTags[0]
|
||||
return [...created, ...updated]
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -647,11 +628,6 @@ export default class ProductModuleService
|
||||
ProductTypes.ProductTagDTO[]
|
||||
>(tags)
|
||||
|
||||
eventBuilders.updatedProductTag({
|
||||
data: updatedTags,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return isString(idOrSelector) ? updatedTags[0] : updatedTags
|
||||
}
|
||||
|
||||
@@ -667,6 +643,7 @@ export default class ProductModuleService
|
||||
): Promise<ProductTypes.ProductTypeDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createProductTypes(
|
||||
data:
|
||||
@@ -694,13 +671,30 @@ export default class ProductModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductTypeDTO>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertProductTypes(
|
||||
data:
|
||||
| ProductTypes.UpsertProductTypeDTO[]
|
||||
| ProductTypes.UpsertProductTypeDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<ProductTypes.ProductTypeDTO[] | ProductTypes.ProductTypeDTO> {
|
||||
const types = await this.upsertProductTypes_(data, sharedContext)
|
||||
|
||||
const result = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductTypeDTO[] | ProductTypes.ProductTypeDTO
|
||||
>(types)
|
||||
|
||||
return Array.isArray(data) ? result : result[0]
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertProductTypes_(
|
||||
data:
|
||||
| ProductTypes.UpsertProductTypeDTO
|
||||
| ProductTypes.UpsertProductTypeDTO[],
|
||||
sharedContext?: Context
|
||||
): Promise<InferEntityType<typeof ProductType>[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter((type): type is UpdateTypeInput => !!type.id)
|
||||
const forCreate = input.filter(
|
||||
@@ -717,12 +711,7 @@ export default class ProductModuleService
|
||||
updated = await this.productTypeService_.update(forUpdate, sharedContext)
|
||||
}
|
||||
|
||||
const result = [...created, ...updated]
|
||||
const allTypes = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductTypeDTO[] | ProductTypes.ProductTypeDTO
|
||||
>(result)
|
||||
|
||||
return Array.isArray(data) ? allTypes : allTypes[0]
|
||||
return [...created, ...updated]
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -739,6 +728,7 @@ export default class ProductModuleService
|
||||
): Promise<ProductTypes.ProductTypeDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateProductTypes(
|
||||
idOrSelector: string | ProductTypes.FilterableProductTypeProps,
|
||||
@@ -787,6 +777,7 @@ export default class ProductModuleService
|
||||
): Promise<ProductTypes.ProductOptionDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createProductOptions(
|
||||
data:
|
||||
@@ -842,6 +833,7 @@ export default class ProductModuleService
|
||||
): Promise<ProductTypes.ProductOptionDTO>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@EmitEvents()
|
||||
async upsertProductOptions(
|
||||
data:
|
||||
| ProductTypes.UpsertProductOptionDTO[]
|
||||
@@ -888,6 +880,7 @@ export default class ProductModuleService
|
||||
): Promise<ProductTypes.ProductOptionDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateProductOptions(
|
||||
idOrSelector: string | ProductTypes.FilterableProductOptionProps,
|
||||
@@ -1023,11 +1016,6 @@ export default class ProductModuleService
|
||||
ProductTypes.ProductCollectionDTO[]
|
||||
>(collections)
|
||||
|
||||
eventBuilders.createdProductCollection({
|
||||
data: collections,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return Array.isArray(data) ? createdCollections : createdCollections[0]
|
||||
}
|
||||
|
||||
@@ -1061,7 +1049,7 @@ export default class ProductModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductCollectionDTO>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertProductCollections(
|
||||
data:
|
||||
@@ -1071,6 +1059,24 @@ export default class ProductModuleService
|
||||
): Promise<
|
||||
ProductTypes.ProductCollectionDTO[] | ProductTypes.ProductCollectionDTO
|
||||
> {
|
||||
const collections = await this.upsertCollections_(data, sharedContext)
|
||||
|
||||
const serializedCollections = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductCollectionDTO[]
|
||||
>(collections)
|
||||
|
||||
return Array.isArray(data)
|
||||
? serializedCollections
|
||||
: serializedCollections[0]
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertCollections_(
|
||||
data:
|
||||
| ProductTypes.UpsertProductCollectionDTO[]
|
||||
| ProductTypes.UpsertProductCollectionDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof ProductCollection>[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter(
|
||||
(collection): collection is UpdateCollectionInput => !!collection.id
|
||||
@@ -1091,26 +1097,7 @@ export default class ProductModuleService
|
||||
updated = await this.updateCollections_(forUpdate, sharedContext)
|
||||
}
|
||||
|
||||
const result = [...created, ...updated]
|
||||
const allCollections = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductCollectionDTO[] | ProductTypes.ProductCollectionDTO
|
||||
>(result)
|
||||
|
||||
if (created.length) {
|
||||
eventBuilders.createdProductCollection({
|
||||
data: created,
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
if (updated.length) {
|
||||
eventBuilders.updatedProductCollection({
|
||||
data: updated,
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
return Array.isArray(data) ? allCollections : allCollections[0]
|
||||
return [...created, ...updated]
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -1166,11 +1153,6 @@ export default class ProductModuleService
|
||||
ProductTypes.ProductCollectionDTO[]
|
||||
>(collections)
|
||||
|
||||
eventBuilders.updatedProductCollection({
|
||||
data: updatedCollections,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return isString(idOrSelector) ? updatedCollections[0] : updatedCollections
|
||||
}
|
||||
|
||||
@@ -1283,6 +1265,7 @@ export default class ProductModuleService
|
||||
ProductTypes.ProductCategoryDTO[]
|
||||
>(categories)
|
||||
|
||||
// TODO: Same as the update categories, for some reason I cant get the tree repository update
|
||||
eventBuilders.createdProductCategory({
|
||||
data: createdCategories,
|
||||
sharedContext,
|
||||
@@ -1300,7 +1283,7 @@ export default class ProductModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductCategoryDTO>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertProductCategories(
|
||||
data:
|
||||
@@ -1310,11 +1293,27 @@ export default class ProductModuleService
|
||||
): Promise<
|
||||
ProductTypes.ProductCategoryDTO[] | ProductTypes.ProductCategoryDTO
|
||||
> {
|
||||
const categories = await this.upsertProductCategories_(data, sharedContext)
|
||||
|
||||
const serializedCategories = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductCategoryDTO[]
|
||||
>(categories)
|
||||
|
||||
return Array.isArray(data) ? serializedCategories : serializedCategories[0]
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertProductCategories_(
|
||||
data:
|
||||
| ProductTypes.UpsertProductCategoryDTO[]
|
||||
| ProductTypes.UpsertProductCategoryDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof ProductCategory>[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter(
|
||||
(category): category is UpdateCategoryInput => !!category.id
|
||||
)
|
||||
const forCreate = input.filter(
|
||||
let forCreate = input.filter(
|
||||
(category): category is ProductTypes.CreateProductCategoryDTO =>
|
||||
!category.id
|
||||
)
|
||||
@@ -1323,6 +1322,11 @@ export default class ProductModuleService
|
||||
let updated: InferEntityType<typeof ProductCategory>[] = []
|
||||
|
||||
if (forCreate.length) {
|
||||
forCreate = forCreate.map((productCategory) => {
|
||||
productCategory.handle ??= kebabCase(productCategory.name)
|
||||
return productCategory
|
||||
})
|
||||
|
||||
created = await this.productCategoryService_.create(
|
||||
forCreate,
|
||||
sharedContext
|
||||
@@ -1335,25 +1339,22 @@ export default class ProductModuleService
|
||||
)
|
||||
}
|
||||
|
||||
const createdCategories = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductCategoryDTO[]
|
||||
>(created)
|
||||
const updatedCategories = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductCategoryDTO[]
|
||||
>(updated)
|
||||
// TODO: Same as the update categories, for some reason I cant get the tree repository update
|
||||
// event. I ll need to investigate this
|
||||
if (created.length) {
|
||||
eventBuilders.createdProductCategory({
|
||||
data: created,
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
if (updated.length) {
|
||||
eventBuilders.updatedProductCategory({
|
||||
data: updated,
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
eventBuilders.createdProductCategory({
|
||||
data: createdCategories,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
eventBuilders.updatedProductCategory({
|
||||
data: updatedCategories,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
const result = [...createdCategories, ...updatedCategories]
|
||||
return Array.isArray(data) ? result : result[0]
|
||||
return [...created, ...updated]
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -1377,8 +1378,36 @@ export default class ProductModuleService
|
||||
data: ProductTypes.UpdateProductCategoryDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<
|
||||
ProductTypes.ProductCategoryDTO[] | ProductTypes.ProductCategoryDTO
|
||||
ProductTypes.ProductCategoryDTO | ProductTypes.ProductCategoryDTO[]
|
||||
> {
|
||||
const categories = await this.updateProductCategories_(
|
||||
idOrSelector,
|
||||
data,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const serializedCategories = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductCategoryDTO[]
|
||||
>(categories)
|
||||
|
||||
// TODO: for some reason I cant get the tree repository update
|
||||
// event. I ll need to investigate this
|
||||
eventBuilders.updatedProductCategory({
|
||||
data: serializedCategories,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return isString(idOrSelector)
|
||||
? serializedCategories[0]
|
||||
: serializedCategories
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async updateProductCategories_(
|
||||
idOrSelector: string | ProductTypes.FilterableProductTypeProps,
|
||||
data: ProductTypes.UpdateProductCategoryDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof ProductCategory>[]> {
|
||||
let normalizedInput: UpdateCategoryInput[] = []
|
||||
if (isString(idOrSelector)) {
|
||||
// Check if the type exists in the first place
|
||||
@@ -1406,16 +1435,7 @@ export default class ProductModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const updatedCategories = await this.baseRepository_.serialize<
|
||||
ProductTypes.ProductCategoryDTO[]
|
||||
>(categories)
|
||||
|
||||
eventBuilders.updatedProductCategory({
|
||||
data: updatedCategories,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return isString(idOrSelector) ? updatedCategories[0] : updatedCategories
|
||||
return categories
|
||||
}
|
||||
|
||||
//@ts-expect-error
|
||||
@@ -1443,11 +1463,6 @@ export default class ProductModuleService
|
||||
ProductTypes.ProductDTO[]
|
||||
>(products)
|
||||
|
||||
eventBuilders.createdProduct({
|
||||
data: createdProducts,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return Array.isArray(data) ? createdProducts : createdProducts[0]
|
||||
}
|
||||
|
||||
@@ -1474,11 +1489,11 @@ export default class ProductModuleService
|
||||
(product): product is ProductTypes.CreateProductDTO => !product.id
|
||||
)
|
||||
|
||||
let created: InferEntityType<typeof Product>[] = []
|
||||
let created: ProductTypes.ProductDTO[] = []
|
||||
let updated: InferEntityType<typeof Product>[] = []
|
||||
|
||||
if (forCreate.length) {
|
||||
created = await this.createProducts_(forCreate, sharedContext)
|
||||
created = await this.createProducts(forCreate, sharedContext)
|
||||
}
|
||||
if (forUpdate.length) {
|
||||
updated = await this.updateProducts_(forUpdate, sharedContext)
|
||||
@@ -1489,20 +1504,6 @@ export default class ProductModuleService
|
||||
ProductTypes.ProductDTO[] | ProductTypes.ProductDTO
|
||||
>(result)
|
||||
|
||||
if (created.length) {
|
||||
eventBuilders.createdProduct({
|
||||
data: created,
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
if (updated.length) {
|
||||
eventBuilders.updatedProduct({
|
||||
data: updated,
|
||||
sharedContext,
|
||||
})
|
||||
}
|
||||
|
||||
return Array.isArray(data) ? allProducts : allProducts[0]
|
||||
}
|
||||
|
||||
@@ -1552,11 +1553,6 @@ export default class ProductModuleService
|
||||
ProductTypes.ProductDTO[]
|
||||
>(products)
|
||||
|
||||
eventBuilders.updatedProduct({
|
||||
data: updatedProducts,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return isString(idOrSelector) ? updatedProducts[0] : updatedProducts
|
||||
}
|
||||
|
||||
@@ -1657,20 +1653,47 @@ export default class ProductModuleService
|
||||
data: UpdateProductInput[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof Product>[]> {
|
||||
// We have to do that manually because this method is bypassing the product service and goes
|
||||
// directly to the custom product repository
|
||||
const manager = (sharedContext.transactionManager ??
|
||||
sharedContext.manager) as EntityManager
|
||||
const subscriber = createMedusaMikroOrmEventSubscriber(
|
||||
["updateProducts_"],
|
||||
this as unknown as ReturnType<typeof MedusaService<any>>
|
||||
)
|
||||
|
||||
if (manager && subscriber) {
|
||||
manager
|
||||
.getEventManager()
|
||||
.registerSubscriber(new subscriber(sharedContext))
|
||||
}
|
||||
|
||||
const originalProducts = await this.productService_.list(
|
||||
{
|
||||
id: data.map((d) => d.id),
|
||||
},
|
||||
{
|
||||
relations: ["options", "options.values", "variants", "images", "tags"],
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const normalizedProducts = await this.normalizeUpdateProductInput(
|
||||
data,
|
||||
sharedContext
|
||||
originalProducts
|
||||
)
|
||||
|
||||
for (const product of normalizedProducts) {
|
||||
this.validateProductUpdatePayload(product)
|
||||
}
|
||||
|
||||
return this.productRepository_.deepUpdate(
|
||||
const updatedProducts = await this.productRepository_.deepUpdate(
|
||||
normalizedProducts,
|
||||
ProductModuleService.validateVariantOptions,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return updatedProducts
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -1685,6 +1708,7 @@ export default class ProductModuleService
|
||||
data: ProductTypes.UpdateProductOptionValueDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<ProductTypes.ProductOptionValueDTO[]>
|
||||
|
||||
// @ts-expect-error
|
||||
async updateProductOptionValues(
|
||||
idOrSelector: string | FilterableProductOptionValueProps,
|
||||
@@ -1693,6 +1717,11 @@ export default class ProductModuleService
|
||||
): Promise<
|
||||
ProductTypes.ProductOptionValueDTO | ProductTypes.ProductOptionValueDTO[]
|
||||
> {
|
||||
// TODO: There is a missmatch in the API which lead to function with different number of
|
||||
// arguments. Therefore, applying the MedusaContext() decorator to the function will not work
|
||||
// because the context arg index will differ from method to method.
|
||||
sharedContext.messageAggregator ??= new MessageAggregator()
|
||||
|
||||
let normalizedInput: ({
|
||||
id: string
|
||||
} & ProductTypes.UpdateProductOptionValueDTO)[] = []
|
||||
@@ -1718,7 +1747,7 @@ export default class ProductModuleService
|
||||
}))
|
||||
}
|
||||
|
||||
const productOptionValues = await super.updateProductOptionValues(
|
||||
const productOptionValues = await this.updateProductOptionValues_(
|
||||
normalizedInput,
|
||||
sharedContext
|
||||
)
|
||||
@@ -1727,16 +1756,45 @@ export default class ProductModuleService
|
||||
ProductTypes.ProductOptionValueDTO[]
|
||||
>(productOptionValues)
|
||||
|
||||
eventBuilders.updatedProductOptionValue({
|
||||
data: updatedProductOptionValues,
|
||||
sharedContext: sharedContext,
|
||||
})
|
||||
// TODO: Because of the wrong method override, we have to compensate to prevent breaking
|
||||
// changes right now
|
||||
const groupedEvents = sharedContext.messageAggregator!.getMessages()
|
||||
if (
|
||||
Object.values(groupedEvents).flat().length > 0 &&
|
||||
this.eventBusModuleService_
|
||||
) {
|
||||
const promises: Promise<void>[] = []
|
||||
for (const group of Object.keys(groupedEvents)) {
|
||||
promises.push(
|
||||
this.eventBusModuleService_!.emit(groupedEvents[group], {
|
||||
internal: true,
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
sharedContext.messageAggregator.clearMessages()
|
||||
}
|
||||
|
||||
return isString(idOrSelector)
|
||||
? updatedProductOptionValues[0]
|
||||
: updatedProductOptionValues
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async updateProductOptionValues_(
|
||||
normalizedInput: ({
|
||||
id: string
|
||||
} & ProductTypes.UpdateProductOptionValueDTO)[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof ProductOptionValue>[]> {
|
||||
return await this.productOptionValueService_.update(
|
||||
normalizedInput,
|
||||
sharedContext
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the manually provided handle value of the product
|
||||
* to be URL-safe
|
||||
@@ -1805,8 +1863,7 @@ export default class ProductModuleService
|
||||
const products_ = Array.isArray(products) ? products : [products]
|
||||
|
||||
const normalizedProducts = (await this.normalizeUpdateProductInput(
|
||||
products_ as UpdateProductInput[],
|
||||
sharedContext
|
||||
products_ as UpdateProductInput[]
|
||||
)) as ProductTypes.CreateProductDTO[]
|
||||
|
||||
for (const productData of normalizedProducts) {
|
||||
@@ -1839,6 +1896,12 @@ export default class ProductModuleService
|
||||
) as TOutput
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the input for the update product input
|
||||
* @param products - The products to normalize
|
||||
* @param originalProducts - The original products to use for the normalization (must include options and option values relations)
|
||||
* @returns The normalized products
|
||||
*/
|
||||
protected async normalizeUpdateProductInput<
|
||||
T extends UpdateProductInput | UpdateProductInput[],
|
||||
TOutput = T extends UpdateProductInput[]
|
||||
@@ -1846,7 +1909,7 @@ export default class ProductModuleService
|
||||
: UpdateProductInput
|
||||
>(
|
||||
products: T,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
originalProducts?: InferEntityType<typeof Product>[]
|
||||
): Promise<TOutput> {
|
||||
const products_ = Array.isArray(products) ? products : [products]
|
||||
const productsIds = products_.map((p) => p.id).filter(Boolean)
|
||||
@@ -1854,11 +1917,14 @@ export default class ProductModuleService
|
||||
let dbOptions: InferEntityType<typeof ProductOption>[] = []
|
||||
|
||||
if (productsIds.length) {
|
||||
dbOptions = await this.productOptionService_.list(
|
||||
{ product_id: productsIds },
|
||||
{ relations: ["values"] },
|
||||
sharedContext
|
||||
)
|
||||
// Re map options to handle non serialized data as well
|
||||
dbOptions =
|
||||
originalProducts
|
||||
?.map((originalProduct) =>
|
||||
originalProduct.options.map((option) => option)
|
||||
)
|
||||
.flat()
|
||||
.filter(Boolean) ?? []
|
||||
}
|
||||
|
||||
const normalizedProducts: UpdateProductInput[] = []
|
||||
@@ -1872,7 +1938,9 @@ export default class ProductModuleService
|
||||
if (productData.options?.length) {
|
||||
;(productData as any).options = productData.options?.map((option) => {
|
||||
const dbOption = dbOptions.find(
|
||||
(o) => o.title === option.title && o.product_id === productData.id
|
||||
(o) =>
|
||||
(o.title === option.title || o.id === option.id) &&
|
||||
o.product_id === productData.id
|
||||
)
|
||||
return {
|
||||
title: option.title,
|
||||
|
||||
@@ -6,96 +6,6 @@ import {
|
||||
} from "@medusajs/framework/utils"
|
||||
|
||||
export const eventBuilders = {
|
||||
createdProduct: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "product",
|
||||
eventName: ProductEvents.PRODUCT_CREATED,
|
||||
}),
|
||||
updatedProduct: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "product",
|
||||
eventName: ProductEvents.PRODUCT_UPDATED,
|
||||
}),
|
||||
deletedProduct: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "product",
|
||||
eventName: ProductEvents.PRODUCT_DELETED,
|
||||
}),
|
||||
createdProductVariant: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "product_variant",
|
||||
eventName: ProductEvents.PRODUCT_VARIANT_CREATED,
|
||||
}),
|
||||
updatedProductVariant: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "product_variant",
|
||||
eventName: ProductEvents.PRODUCT_VARIANT_UPDATED,
|
||||
}),
|
||||
deletedProductVariant: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "product_variant",
|
||||
eventName: ProductEvents.PRODUCT_VARIANT_DELETED,
|
||||
}),
|
||||
createdProductOption: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "product_option",
|
||||
eventName: ProductEvents.PRODUCT_OPTION_CREATED,
|
||||
}),
|
||||
updatedProductOption: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "product_option",
|
||||
eventName: ProductEvents.PRODUCT_OPTION_UPDATED,
|
||||
}),
|
||||
deletedProductOption: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "product_option",
|
||||
eventName: ProductEvents.PRODUCT_OPTION_DELETED,
|
||||
}),
|
||||
createdProductType: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "product_type",
|
||||
eventName: ProductEvents.PRODUCT_TYPE_CREATED,
|
||||
}),
|
||||
updatedProductType: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "product_type",
|
||||
eventName: ProductEvents.PRODUCT_TYPE_UPDATED,
|
||||
}),
|
||||
deletedProductType: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "product_type",
|
||||
eventName: ProductEvents.PRODUCT_TYPE_DELETED,
|
||||
}),
|
||||
createdProductTag: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "product_tag",
|
||||
eventName: ProductEvents.PRODUCT_TAG_CREATED,
|
||||
}),
|
||||
updatedProductTag: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "product_tag",
|
||||
eventName: ProductEvents.PRODUCT_TAG_UPDATED,
|
||||
}),
|
||||
deletedProductTag: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "product_tag",
|
||||
eventName: ProductEvents.PRODUCT_TAG_DELETED,
|
||||
}),
|
||||
createdProductCategory: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
@@ -114,40 +24,4 @@ export const eventBuilders = {
|
||||
object: "product_category",
|
||||
eventName: ProductEvents.PRODUCT_CATEGORY_DELETED,
|
||||
}),
|
||||
createdProductCollection: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "product_collection",
|
||||
eventName: ProductEvents.PRODUCT_COLLECTION_CREATED,
|
||||
}),
|
||||
updatedProductCollection: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "product_collection",
|
||||
eventName: ProductEvents.PRODUCT_COLLECTION_UPDATED,
|
||||
}),
|
||||
deletedProductCollection: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "product_collection",
|
||||
eventName: ProductEvents.PRODUCT_COLLECTION_DELETED,
|
||||
}),
|
||||
createdProductOptionValue: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "product_option_value",
|
||||
eventName: ProductEvents.PRODUCT_OPTION_VALUE_CREATED,
|
||||
}),
|
||||
updatedProductOptionValue: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "product_option_value",
|
||||
eventName: ProductEvents.PRODUCT_OPTION_VALUE_UPDATED,
|
||||
}),
|
||||
deletedProductOptionValue: moduleEventBuilderFactory({
|
||||
source: Modules.PRODUCT,
|
||||
action: CommonEvents.DELETED,
|
||||
object: "product_option_value",
|
||||
eventName: ProductEvents.PRODUCT_OPTION_VALUE_DELETED,
|
||||
}),
|
||||
}
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
CampaignBudgetType,
|
||||
ComputedActions,
|
||||
deduplicate,
|
||||
EmitEvents,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
isDefined,
|
||||
@@ -193,6 +194,7 @@ export default class PromotionModuleService
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@EmitEvents()
|
||||
async registerUsage(
|
||||
computedActions: PromotionTypes.UsageComputedActions[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -306,6 +308,7 @@ export default class PromotionModuleService
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@EmitEvents()
|
||||
async revertUsage(
|
||||
computedActions: PromotionTypes.UsageComputedActions[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -625,6 +628,7 @@ export default class PromotionModuleService
|
||||
): Promise<PromotionTypes.PromotionDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createPromotions(
|
||||
data:
|
||||
@@ -1041,6 +1045,7 @@ export default class PromotionModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-ignore
|
||||
async updatePromotionRules(
|
||||
data: PromotionTypes.UpdatePromotionRuleDTO[],
|
||||
@@ -1149,6 +1154,7 @@ export default class PromotionModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async addPromotionTargetRules(
|
||||
promotionId: string,
|
||||
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
||||
@@ -1182,6 +1188,7 @@ export default class PromotionModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async addPromotionBuyRules(
|
||||
promotionId: string,
|
||||
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
||||
@@ -1278,6 +1285,7 @@ export default class PromotionModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async removePromotionRules(
|
||||
promotionId: string,
|
||||
ruleIds: string[],
|
||||
@@ -1305,6 +1313,7 @@ export default class PromotionModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async removePromotionTargetRules(
|
||||
promotionId: string,
|
||||
ruleIds: string[],
|
||||
@@ -1379,6 +1388,7 @@ export default class PromotionModuleService
|
||||
): Promise<PromotionTypes.CampaignDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createCampaigns(
|
||||
data: PromotionTypes.CreateCampaignDTO | PromotionTypes.CreateCampaignDTO[],
|
||||
@@ -1490,6 +1500,7 @@ export default class PromotionModuleService
|
||||
): Promise<PromotionTypes.CampaignDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateCampaigns(
|
||||
data: PromotionTypes.UpdateCampaignDTO | PromotionTypes.UpdateCampaignDTO[],
|
||||
@@ -1583,9 +1594,10 @@ export default class PromotionModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async addPromotionsToCampaign(
|
||||
data: PromotionTypes.AddPromotionsToCampaignDTO,
|
||||
sharedContext?: Context
|
||||
@MedusaContext() sharedContext?: Context
|
||||
): Promise<{ ids: string[] }> {
|
||||
const ids = await this.addPromotionsToCampaign_(data, sharedContext)
|
||||
|
||||
@@ -1650,9 +1662,10 @@ export default class PromotionModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async removePromotionsFromCampaign(
|
||||
data: PromotionTypes.AddPromotionsToCampaignDTO,
|
||||
sharedContext?: Context
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<{ ids: string[] }> {
|
||||
const ids = await this.removePromotionsFromCampaign_(data, sharedContext)
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
arrayDifference,
|
||||
EmitEvents,
|
||||
getDuplicates,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
@@ -78,6 +79,7 @@ export default class RegionModuleService
|
||||
): Promise<RegionDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createRegions(
|
||||
data: CreateRegionDTO | CreateRegionDTO[],
|
||||
@@ -132,6 +134,7 @@ export default class RegionModuleService
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async softDeleteRegions(
|
||||
ids: string | object | string[] | object[],
|
||||
@@ -160,11 +163,24 @@ export default class RegionModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<RegionDTO>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertRegions(
|
||||
data: UpsertRegionDTO | UpsertRegionDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<RegionDTO | RegionDTO[]> {
|
||||
const result = await this.upsertRegions_(data, sharedContext)
|
||||
|
||||
return await this.baseRepository_.serialize<RegionDTO[] | RegionDTO>(
|
||||
Array.isArray(data) ? result : result[0]
|
||||
)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertRegions_(
|
||||
data: UpsertRegionDTO | UpsertRegionDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof Region>[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter(
|
||||
(region): region is UpdateRegionInput => !!region.id
|
||||
@@ -183,9 +199,8 @@ export default class RegionModuleService
|
||||
}
|
||||
|
||||
const result = (await promiseAll(operations)).flat()
|
||||
return await this.baseRepository_.serialize<RegionDTO[] | RegionDTO>(
|
||||
Array.isArray(data) ? result : result[0]
|
||||
)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -202,6 +217,7 @@ export default class RegionModuleService
|
||||
): Promise<RegionDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateRegions(
|
||||
idOrSelector: string | FilterableRegionProps,
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
UpsertSalesChannelDTO,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
EmitEvents,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
isString,
|
||||
@@ -67,6 +68,7 @@ export default class SalesChannelModuleService
|
||||
): Promise<SalesChannelDTO>
|
||||
|
||||
@InjectManager()
|
||||
|
||||
// @ts-expect-error
|
||||
async createSalesChannels(
|
||||
data: CreateSalesChannelDTO | CreateSalesChannelDTO[],
|
||||
@@ -77,10 +79,7 @@ export default class SalesChannelModuleService
|
||||
const result = await this.createSalesChannels_(input, sharedContext)
|
||||
|
||||
return await this.baseRepository_.serialize<SalesChannelDTO[]>(
|
||||
Array.isArray(data) ? result : result[0],
|
||||
{
|
||||
populate: true,
|
||||
}
|
||||
Array.isArray(data) ? result : result[0]
|
||||
)
|
||||
}
|
||||
|
||||
@@ -106,6 +105,7 @@ export default class SalesChannelModuleService
|
||||
): Promise<SalesChannelDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateSalesChannels(
|
||||
idOrSelector: string | FilterableSalesChannelProps,
|
||||
@@ -134,10 +134,7 @@ export default class SalesChannelModuleService
|
||||
)
|
||||
|
||||
return await this.baseRepository_.serialize<SalesChannelDTO[]>(
|
||||
Array.isArray(data) ? result : result[0],
|
||||
{
|
||||
populate: true,
|
||||
}
|
||||
Array.isArray(data) ? result : result[0]
|
||||
)
|
||||
}
|
||||
|
||||
@@ -157,11 +154,25 @@ export default class SalesChannelModuleService
|
||||
data: UpsertSalesChannelDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<SalesChannelDTO>
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
@InjectTransactionManager()
|
||||
async upsertSalesChannels(
|
||||
data: UpsertSalesChannelDTO | UpsertSalesChannelDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<SalesChannelDTO | SalesChannelDTO[]> {
|
||||
const result = await this.upsertSalesChannels_(data, sharedContext)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
SalesChannelDTO[] | SalesChannelDTO
|
||||
>(Array.isArray(data) ? result : result[0])
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertSalesChannels_(
|
||||
data: UpsertSalesChannelDTO | UpsertSalesChannelDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof SalesChannel>[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter(
|
||||
(channel): channel is UpdateSalesChannelDTO => !!channel.id
|
||||
@@ -180,8 +191,7 @@ export default class SalesChannelModuleService
|
||||
}
|
||||
|
||||
const result = (await promiseAll(operations)).flat()
|
||||
return await this.baseRepository_.serialize<
|
||||
SalesChannelDTO[] | SalesChannelDTO
|
||||
>(Array.isArray(data) ? result : result[0])
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
SettingsTypes,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
EmitEvents,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
MedusaContext,
|
||||
@@ -50,7 +51,8 @@ export default class SettingsModuleService
|
||||
this.userPreferenceService_ = userPreferenceService
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createViewConfigurations(
|
||||
data:
|
||||
@@ -97,10 +99,14 @@ export default class SettingsModuleService
|
||||
dataArray,
|
||||
sharedContext
|
||||
)
|
||||
return isArrayInput ? result : result[0]
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
SettingsTypes.ViewConfigurationDTO[] | SettingsTypes.ViewConfigurationDTO
|
||||
>(isArrayInput ? result : result[0])
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateViewConfigurations(
|
||||
idOrSelector: string | SettingsTypes.FilterableViewConfigurationProps,
|
||||
@@ -109,6 +115,25 @@ export default class SettingsModuleService
|
||||
): Promise<
|
||||
SettingsTypes.ViewConfigurationDTO | SettingsTypes.ViewConfigurationDTO[]
|
||||
> {
|
||||
const updated = await this.updateViewConfigurations_(
|
||||
idOrSelector,
|
||||
data,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
SettingsTypes.ViewConfigurationDTO[] | SettingsTypes.ViewConfigurationDTO
|
||||
>(updated)
|
||||
|
||||
return typeof idOrSelector === "string" ? serialized[0] : serialized
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async updateViewConfigurations_(
|
||||
idOrSelector: string | SettingsTypes.FilterableViewConfigurationProps,
|
||||
data: SettingsTypes.UpdateViewConfigurationDTO,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof ViewConfiguration>[]> {
|
||||
let selector: SettingsTypes.FilterableViewConfigurationProps = {}
|
||||
|
||||
if (typeof idOrSelector === "string") {
|
||||
@@ -164,11 +189,7 @@ export default class SettingsModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
SettingsTypes.ViewConfigurationDTO[]
|
||||
>(updatedEntities, { populate: true })
|
||||
|
||||
return typeof idOrSelector === "string" ? serialized[0] : serialized
|
||||
return updatedEntities
|
||||
}
|
||||
|
||||
// For non-configuration updates, use the standard update method
|
||||
@@ -177,11 +198,7 @@ export default class SettingsModuleService
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
SettingsTypes.ViewConfigurationDTO[]
|
||||
>(updated, { populate: true })
|
||||
|
||||
return typeof idOrSelector === "string" ? serialized[0] : serialized
|
||||
return updated as unknown as InferEntityType<typeof ViewConfiguration>[]
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@@ -201,12 +218,12 @@ export default class SettingsModuleService
|
||||
}
|
||||
|
||||
return await this.baseRepository_.serialize<SettingsTypes.UserPreferenceDTO>(
|
||||
prefs[0],
|
||||
{ populate: true }
|
||||
prefs[0]
|
||||
)
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async setUserPreference(
|
||||
userId: string,
|
||||
key: string,
|
||||
@@ -236,8 +253,7 @@ export default class SettingsModuleService
|
||||
}
|
||||
|
||||
return await this.baseRepository_.serialize<SettingsTypes.UserPreferenceDTO>(
|
||||
result,
|
||||
{ populate: true }
|
||||
result
|
||||
)
|
||||
}
|
||||
|
||||
@@ -297,7 +313,8 @@ export default class SettingsModuleService
|
||||
return systemDefaults.length > 0 ? systemDefaults[0] : null
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async setActiveViewConfiguration(
|
||||
entity: string,
|
||||
userId: string,
|
||||
@@ -347,7 +364,8 @@ export default class SettingsModuleService
|
||||
return systemDefaults.length > 0 ? systemDefaults[0] : null
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async clearActiveViewConfiguration(
|
||||
entity: string,
|
||||
userId: string,
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
UpsertStockLocationInput,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
EmitEvents,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
isString,
|
||||
@@ -86,7 +87,9 @@ export default class StockLocationModuleService
|
||||
data: CreateStockLocationInput[],
|
||||
context: Context
|
||||
): Promise<StockLocationTypes.StockLocationDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createStockLocations(
|
||||
data: CreateStockLocationInput | CreateStockLocationInput[],
|
||||
@@ -101,7 +104,7 @@ export default class StockLocationModuleService
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
| StockLocationTypes.StockLocationDTO
|
||||
| StockLocationTypes.StockLocationDTO[]
|
||||
>(created, { populate: true })
|
||||
>(created)
|
||||
|
||||
return Array.isArray(data) ? serialized : serialized[0]
|
||||
}
|
||||
@@ -124,6 +127,7 @@ export default class StockLocationModuleService
|
||||
): Promise<StockLocationTypes.StockLocationDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertStockLocations(
|
||||
data: UpsertStockLocationInput | UpsertStockLocationInput[],
|
||||
@MedusaContext() context: Context = {}
|
||||
@@ -179,6 +183,7 @@ export default class StockLocationModuleService
|
||||
input: UpdateStockLocationInput,
|
||||
context?: Context
|
||||
): Promise<StockLocationTypes.StockLocationDTO[]>
|
||||
|
||||
/**
|
||||
* Updates an existing stock location.
|
||||
* @param stockLocationId - The ID of the stock location to update.
|
||||
@@ -187,6 +192,7 @@ export default class StockLocationModuleService
|
||||
* @returns The updated stock location.
|
||||
*/
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateStockLocations(
|
||||
idOrSelector: string | FilterableStockLocationProps,
|
||||
@@ -208,7 +214,7 @@ export default class StockLocationModuleService
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
| StockLocationTypes.StockLocationDTO
|
||||
| StockLocationTypes.StockLocationDTO[]
|
||||
>(updated, { populate: true })
|
||||
>(updated)
|
||||
|
||||
return Array.isArray(data) ? serialized : serialized[0]
|
||||
}
|
||||
@@ -239,6 +245,7 @@ export default class StockLocationModuleService
|
||||
): Promise<StockLocationTypes.StockLocationAddressDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateStockLocationAddresses(
|
||||
data:
|
||||
@@ -253,7 +260,7 @@ export default class StockLocationModuleService
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
| StockLocationTypes.StockLocationAddressDTO
|
||||
| StockLocationTypes.StockLocationAddressDTO[]
|
||||
>(updated, { populate: true })
|
||||
>(updated)
|
||||
|
||||
return Array.isArray(data) ? serialized : serialized[0]
|
||||
}
|
||||
@@ -276,6 +283,7 @@ export default class StockLocationModuleService
|
||||
): Promise<StockLocationTypes.StockLocationAddressDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertStockLocationAddresses(
|
||||
data: UpsertStockLocationAddressInput | UpsertStockLocationAddressInput[],
|
||||
@MedusaContext() context: Context = {}
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
StoreTypes,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
EmitEvents,
|
||||
getDuplicates,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
@@ -59,7 +60,9 @@ export default class StoreModuleService
|
||||
data: StoreTypes.CreateStoreDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<StoreTypes.StoreDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createStores(
|
||||
data: StoreTypes.CreateStoreDTO | StoreTypes.CreateStoreDTO[],
|
||||
@@ -99,11 +102,25 @@ export default class StoreModuleService
|
||||
data: StoreTypes.UpsertStoreDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<StoreTypes.StoreDTO>
|
||||
@InjectTransactionManager()
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertStores(
|
||||
data: StoreTypes.UpsertStoreDTO | StoreTypes.UpsertStoreDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<StoreTypes.StoreDTO | StoreTypes.StoreDTO[]> {
|
||||
const result = await this.upsertStores_(data, sharedContext)
|
||||
|
||||
return await this.baseRepository_.serialize<
|
||||
StoreTypes.StoreDTO[] | StoreTypes.StoreDTO
|
||||
>(Array.isArray(data) ? result : result[0])
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
protected async upsertStores_(
|
||||
data: StoreTypes.UpsertStoreDTO | StoreTypes.UpsertStoreDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<InferEntityType<typeof Store>[]> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const forUpdate = input.filter(
|
||||
(store): store is UpdateStoreInput => !!store.id
|
||||
@@ -122,9 +139,8 @@ export default class StoreModuleService
|
||||
}
|
||||
|
||||
const result = (await promiseAll(operations)).flat()
|
||||
return await this.baseRepository_.serialize<
|
||||
StoreTypes.StoreDTO[] | StoreTypes.StoreDTO
|
||||
>(Array.isArray(data) ? result : result[0])
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -139,7 +155,9 @@ export default class StoreModuleService
|
||||
data: StoreTypes.UpdateStoreDTO,
|
||||
sharedContext?: Context
|
||||
): Promise<StoreTypes.StoreDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateStores(
|
||||
idOrSelector: string | StoreTypes.FilterableStoreProps,
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
TaxTypes,
|
||||
} from "@medusajs/framework/types"
|
||||
import {
|
||||
EmitEvents,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
isDefined,
|
||||
@@ -17,7 +18,6 @@ import {
|
||||
MedusaContext,
|
||||
MedusaError,
|
||||
ModulesSdkUtils,
|
||||
promiseAll,
|
||||
} from "@medusajs/framework/utils"
|
||||
import { TaxProvider, TaxRate, TaxRateRule, TaxRegion } from "@models"
|
||||
import { TaxProviderService } from "@services"
|
||||
@@ -94,6 +94,7 @@ export default class TaxModuleService
|
||||
): Promise<TaxTypes.TaxRateDTO>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createTaxRates(
|
||||
data: TaxTypes.CreateTaxRateDTO[] | TaxTypes.CreateTaxRateDTO,
|
||||
@@ -101,7 +102,12 @@ export default class TaxModuleService
|
||||
): Promise<TaxTypes.TaxRateDTO[] | TaxTypes.TaxRateDTO> {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const rates = await this.createTaxRates_(input, sharedContext)
|
||||
return Array.isArray(data) ? rates : rates[0]
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
TaxTypes.TaxRateDTO[] | TaxTypes.TaxRateDTO
|
||||
>(rates)
|
||||
|
||||
return Array.isArray(data) ? serialized : serialized[0]
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@@ -145,9 +151,7 @@ export default class TaxModuleService
|
||||
await this.taxRateRuleService_.create(rulesToCreate, sharedContext)
|
||||
}
|
||||
|
||||
return await this.baseRepository_.serialize<TaxTypes.TaxRateDTO[]>(rates, {
|
||||
populate: true,
|
||||
})
|
||||
return rates
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -170,6 +174,7 @@ export default class TaxModuleService
|
||||
): Promise<TaxTypes.TaxRateDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async updateTaxRates(
|
||||
selector: string | string[] | TaxTypes.FilterableTaxRateProps,
|
||||
@@ -177,9 +182,11 @@ export default class TaxModuleService
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TaxTypes.TaxRateDTO | TaxTypes.TaxRateDTO[]> {
|
||||
const rates = await this.updateTaxRates_(selector, data, sharedContext)
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
TaxTypes.TaxRateDTO[]
|
||||
>(rates, { populate: true })
|
||||
>(rates)
|
||||
|
||||
return isString(selector) ? serialized[0] : serialized
|
||||
}
|
||||
|
||||
@@ -282,15 +289,18 @@ export default class TaxModuleService
|
||||
sharedContext?: Context
|
||||
): Promise<TaxTypes.TaxRateDTO>
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
async upsertTaxRates(
|
||||
data: TaxTypes.UpsertTaxRateDTO | TaxTypes.UpsertTaxRateDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TaxTypes.TaxRateDTO | TaxTypes.TaxRateDTO[]> {
|
||||
const result = await this.taxRateService_.upsert(data, sharedContext)
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
TaxTypes.TaxRateDTO[]
|
||||
>(result, { populate: true })
|
||||
>(result)
|
||||
|
||||
return Array.isArray(data) ? serialized : serialized[0]
|
||||
}
|
||||
|
||||
@@ -307,6 +317,7 @@ export default class TaxModuleService
|
||||
): Promise<TaxRegionDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createTaxRegions(
|
||||
data: TaxTypes.CreateTaxRegionDTO | TaxTypes.CreateTaxRegionDTO[],
|
||||
@@ -314,9 +325,15 @@ export default class TaxModuleService
|
||||
) {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const result = await this.createTaxRegions_(input, sharedContext)
|
||||
return Array.isArray(data) ? result : result[0]
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
TaxTypes.TaxRegionDTO[] | TaxTypes.TaxRegionDTO
|
||||
>(result)
|
||||
|
||||
return Array.isArray(data) ? serialized : serialized[0]
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
async createTaxRegions_(
|
||||
data: TaxTypes.CreateTaxRegionDTO[],
|
||||
sharedContext: Context = {}
|
||||
@@ -347,10 +364,7 @@ export default class TaxModuleService
|
||||
await this.createTaxRates(rates, sharedContext)
|
||||
}
|
||||
|
||||
return await this.baseRepository_.serialize<TaxTypes.TaxRegionDTO[]>(
|
||||
regions,
|
||||
{ populate: true }
|
||||
)
|
||||
return regions
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
@@ -365,6 +379,7 @@ export default class TaxModuleService
|
||||
): Promise<TaxTypes.TaxRateRuleDTO[]>
|
||||
|
||||
@InjectManager()
|
||||
@EmitEvents()
|
||||
// @ts-expect-error
|
||||
async createTaxRateRules(
|
||||
data: TaxTypes.CreateTaxRateRuleDTO | TaxTypes.CreateTaxRateRuleDTO[],
|
||||
@@ -372,7 +387,12 @@ export default class TaxModuleService
|
||||
) {
|
||||
const input = Array.isArray(data) ? data : [data]
|
||||
const result = await this.createTaxRateRules_(input, sharedContext)
|
||||
return Array.isArray(data) ? result : result[0]
|
||||
|
||||
const serialized = await this.baseRepository_.serialize<
|
||||
TaxTypes.TaxRateRuleDTO[] | TaxTypes.TaxRateRuleDTO
|
||||
>(result)
|
||||
|
||||
return Array.isArray(data) ? serialized : serialized[0]
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@@ -381,12 +401,7 @@ export default class TaxModuleService
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
const rules = await this.taxRateRuleService_.create(data, sharedContext)
|
||||
return await this.baseRepository_.serialize<TaxTypes.TaxRateRuleDTO[]>(
|
||||
rules,
|
||||
{
|
||||
populate: true,
|
||||
}
|
||||
)
|
||||
return rules
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@@ -419,30 +434,71 @@ export default class TaxModuleService
|
||||
return []
|
||||
}
|
||||
|
||||
const toReturn = await promiseAll(
|
||||
items.map(async (item) => {
|
||||
const regionIds = regions.map((r) => r.id)
|
||||
const rateQuery = this.getTaxRateQueryForItem(item, regionIds)
|
||||
const candidateRates = await this.taxRateService_.list(
|
||||
rateQuery,
|
||||
{
|
||||
relations: ["tax_region", "rules"],
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
const regionIds = regions.map((r) => r.id)
|
||||
|
||||
const applicableRates = await this.getTaxRatesForItem(
|
||||
item,
|
||||
candidateRates
|
||||
)
|
||||
// Collect all unique reference IDs for batch query
|
||||
const productIds = new Set<string>()
|
||||
const productTypeIds = new Set<string>()
|
||||
const shippingOptionIds = new Set<string>()
|
||||
|
||||
return {
|
||||
rates: applicableRates,
|
||||
item,
|
||||
items.forEach((item) => {
|
||||
if ("shipping_option_id" in item) {
|
||||
shippingOptionIds.add(item.shipping_option_id)
|
||||
} else {
|
||||
productIds.add(item.product_id)
|
||||
if (item.product_type_id) {
|
||||
productTypeIds.add(item.product_type_id)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// Build comprehensive query for all items
|
||||
const ruleQueries = [
|
||||
...Array.from(productIds).map((id) => ({
|
||||
reference: "product",
|
||||
reference_id: id,
|
||||
})),
|
||||
...Array.from(productTypeIds).map((id) => ({
|
||||
reference: "product_type",
|
||||
reference_id: id,
|
||||
})),
|
||||
...Array.from(shippingOptionIds).map((id) => ({
|
||||
reference: "shipping_option",
|
||||
reference_id: id,
|
||||
})),
|
||||
]
|
||||
|
||||
const allCandidateRates = await this.taxRateService_.list(
|
||||
{
|
||||
$and: [
|
||||
{ tax_region_id: regionIds },
|
||||
{
|
||||
$or: [
|
||||
{ is_default: true },
|
||||
...(ruleQueries.length ? [{ rules: { $or: ruleQueries } }] : []),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
relations: ["tax_region", "rules"],
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const toReturn = items.map((item) => {
|
||||
const rateQuery = this.getTaxRateQueryForItem(item, regionIds)
|
||||
const candidateRates = allCandidateRates.filter((rate) =>
|
||||
this.rateMatchesQuery(rate, rateQuery)
|
||||
)
|
||||
const applicableRates = this.getTaxRatesForItem(item, candidateRates)
|
||||
|
||||
return {
|
||||
rates: applicableRates,
|
||||
item,
|
||||
}
|
||||
})
|
||||
|
||||
const taxLines = await this.getTaxLinesFromProvider(
|
||||
parentRegion.provider_id as string,
|
||||
toReturn,
|
||||
@@ -574,10 +630,10 @@ export default class TaxModuleService
|
||||
}
|
||||
}
|
||||
|
||||
private async getTaxRatesForItem(
|
||||
private getTaxRatesForItem(
|
||||
item: TaxTypes.TaxableItemDTO | TaxTypes.TaxableShippingDTO,
|
||||
rates: InferEntityType<typeof TaxRate>[]
|
||||
): Promise<InferEntityType<typeof TaxRate>[]> {
|
||||
): InferEntityType<typeof TaxRate>[] {
|
||||
if (!rates.length) {
|
||||
return []
|
||||
}
|
||||
@@ -609,7 +665,17 @@ export default class TaxModuleService
|
||||
private getTaxRateQueryForItem(
|
||||
item: TaxTypes.TaxableItemDTO | TaxTypes.TaxableShippingDTO,
|
||||
regionIds: string[]
|
||||
) {
|
||||
): {
|
||||
$and: {
|
||||
tax_region_id?: string[]
|
||||
$or?: {
|
||||
is_default?: boolean
|
||||
rules?: {
|
||||
$or: { reference: string; reference_id: string | undefined }[]
|
||||
}
|
||||
}[]
|
||||
}[]
|
||||
} {
|
||||
const isShipping = "shipping_option_id" in item
|
||||
let ruleQuery = isShipping
|
||||
? [
|
||||
@@ -637,6 +703,58 @@ export default class TaxModuleService
|
||||
}
|
||||
}
|
||||
|
||||
private rateMatchesQuery(
|
||||
rate: InferEntityType<typeof TaxRate>,
|
||||
query: {
|
||||
$and: {
|
||||
tax_region_id?: string[]
|
||||
$or?: {
|
||||
is_default?: boolean
|
||||
rules?: {
|
||||
$or: { reference: string; reference_id: string | undefined }[]
|
||||
}
|
||||
}[]
|
||||
}[]
|
||||
}
|
||||
): boolean {
|
||||
const { $and } = query
|
||||
const [regionCheck, ruleCheck] = $and
|
||||
|
||||
// Check region match
|
||||
if (!regionCheck.tax_region_id?.includes(rate.tax_region_id)) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Check rule match
|
||||
const { $or } = ruleCheck
|
||||
if (rate.is_default) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Check if any rule matches
|
||||
for (const ruleCondition of $or ?? []) {
|
||||
if (ruleCondition.is_default && rate.is_default) {
|
||||
return true
|
||||
}
|
||||
if (ruleCondition.rules) {
|
||||
const { $or: ruleQueries } = ruleCondition.rules
|
||||
for (const ruleQuery of ruleQueries) {
|
||||
if (
|
||||
[...(rate.rules ?? [])]?.some(
|
||||
(rule: InferEntityType<typeof TaxRateRule>) =>
|
||||
rule.reference === ruleQuery.reference &&
|
||||
rule.reference_id === ruleQuery.reference_id
|
||||
)
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private checkRuleMatches(
|
||||
rate: InferEntityType<typeof TaxRate>,
|
||||
item: TaxTypes.TaxableItemDTO | TaxTypes.TaxableShippingDTO
|
||||
|
||||
@@ -172,17 +172,20 @@ moduleIntegrationTestRunner<IUserModuleService>({
|
||||
},
|
||||
])
|
||||
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
// 2 events: 1 invite updated, 1 invite token generated
|
||||
const events = eventBusSpy.mock.calls[0][0]
|
||||
expect(events).toHaveLength(2)
|
||||
expect(events).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
data: { id: "1" },
|
||||
name: UserEvents.INVITE_UPDATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
expect.objectContaining({
|
||||
data: { id: "1" },
|
||||
name: UserEvents.INVITE_TOKEN_GENERATED,
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -190,21 +193,25 @@ moduleIntegrationTestRunner<IUserModuleService>({
|
||||
describe("resendInvite", () => {
|
||||
it("should emit token generated event for invites", async () => {
|
||||
await service.createInvites(defaultInviteData)
|
||||
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
eventBusSpy.mockClear()
|
||||
|
||||
await service.refreshInviteTokens(["1"])
|
||||
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(2)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
const events = eventBusSpy.mock.calls[0][0]
|
||||
expect(events).toHaveLength(2)
|
||||
expect(events).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
name: UserEvents.INVITE_UPDATED,
|
||||
data: { id: "1" },
|
||||
name: UserEvents.INVITE_TOKEN_GENERATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
expect.objectContaining({
|
||||
name: UserEvents.INVITE_TOKEN_GENERATED,
|
||||
data: { id: "1" },
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -251,21 +258,25 @@ moduleIntegrationTestRunner<IUserModuleService>({
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
await service.createInvites(defaultInviteData)
|
||||
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
// 4 events: 2 invites created, 2 invite token generated
|
||||
const events = eventBusSpy.mock.calls[0][0]
|
||||
expect(events).toHaveLength(3)
|
||||
|
||||
expect(events).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
data: { id: ["1", "2"] },
|
||||
data: { id: "1" },
|
||||
name: UserEvents.INVITE_CREATED,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
data: { id: "2" },
|
||||
name: UserEvents.INVITE_CREATED,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
data: { id: ["1", "2"] },
|
||||
name: UserEvents.INVITE_TOKEN_GENERATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -253,17 +253,22 @@ moduleIntegrationTestRunner<IUserModuleService>({
|
||||
const eventBusSpy = jest.spyOn(MockEventBusService.prototype, "emit")
|
||||
await service.createUsers(defaultUserData)
|
||||
|
||||
expect(eventBusSpy).toHaveBeenCalledTimes(1)
|
||||
expect(eventBusSpy).toHaveBeenCalledWith(
|
||||
[
|
||||
// 2 events: 2 user created
|
||||
expect(eventBusSpy.mock.calls[0][0]).toHaveLength(2)
|
||||
|
||||
const events = eventBusSpy.mock.calls[0][0]
|
||||
expect(events).toHaveLength(2)
|
||||
expect(events).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
data: { id: ["1", "2"] },
|
||||
data: { id: "1" },
|
||||
name: UserEvents.USER_CREATED,
|
||||
}),
|
||||
],
|
||||
{
|
||||
internal: true,
|
||||
}
|
||||
expect.objectContaining({
|
||||
data: { id: "2" },
|
||||
name: UserEvents.USER_CREATED,
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -95,7 +95,7 @@ export default class UserModuleService
|
||||
}
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@InjectManager()
|
||||
async validateInviteToken(
|
||||
token: string,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -129,9 +129,7 @@ export default class UserModuleService
|
||||
)
|
||||
}
|
||||
|
||||
return await this.baseRepository_.serialize<UserTypes.InviteDTO>(invite, {
|
||||
populate: true,
|
||||
})
|
||||
return await this.baseRepository_.serialize<UserTypes.InviteDTO>(invite)
|
||||
}
|
||||
|
||||
@InjectManager()
|
||||
@@ -142,22 +140,21 @@ export default class UserModuleService
|
||||
): Promise<UserTypes.InviteDTO[]> {
|
||||
const invites = await this.refreshInviteTokens_(inviteIds, sharedContext)
|
||||
|
||||
const serializedInvites = await this.baseRepository_.serialize<
|
||||
UserTypes.InviteDTO[]
|
||||
>(invites)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
eventName: UserEvents.INVITE_TOKEN_GENERATED,
|
||||
source: Modules.USER,
|
||||
action: "token_generated",
|
||||
action: CommonEvents.CREATED,
|
||||
object: "invite",
|
||||
})({
|
||||
data: invites,
|
||||
data: serializedInvites,
|
||||
sharedContext,
|
||||
})
|
||||
|
||||
return await this.baseRepository_.serialize<UserTypes.InviteDTO[]>(
|
||||
invites,
|
||||
{
|
||||
populate: true,
|
||||
}
|
||||
)
|
||||
return serializedInvites
|
||||
}
|
||||
|
||||
@InjectTransactionManager()
|
||||
@@ -221,19 +218,7 @@ export default class UserModuleService
|
||||
|
||||
const serializedUsers = await this.baseRepository_.serialize<
|
||||
UserTypes.UserDTO[] | UserTypes.UserDTO
|
||||
>(users, {
|
||||
populate: true,
|
||||
})
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
eventName: UserEvents.USER_CREATED,
|
||||
source: Modules.USER,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "user",
|
||||
})({
|
||||
data: serializedUsers,
|
||||
sharedContext,
|
||||
})
|
||||
>(users)
|
||||
|
||||
return Array.isArray(data) ? serializedUsers : serializedUsers[0]
|
||||
}
|
||||
@@ -262,19 +247,7 @@ export default class UserModuleService
|
||||
|
||||
const serializedUsers = await this.baseRepository_.serialize<
|
||||
UserTypes.UserDTO[]
|
||||
>(updatedUsers, {
|
||||
populate: true,
|
||||
})
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
eventName: UserEvents.USER_UPDATED,
|
||||
source: Modules.USER,
|
||||
action: CommonEvents.UPDATED,
|
||||
object: "user",
|
||||
})({
|
||||
data: serializedUsers,
|
||||
sharedContext,
|
||||
})
|
||||
>(updatedUsers)
|
||||
|
||||
return Array.isArray(data) ? serializedUsers : serializedUsers[0]
|
||||
}
|
||||
@@ -303,19 +276,7 @@ export default class UserModuleService
|
||||
|
||||
const serializedInvites = await this.baseRepository_.serialize<
|
||||
UserTypes.InviteDTO[] | UserTypes.InviteDTO
|
||||
>(invites, {
|
||||
populate: true,
|
||||
})
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
eventName: UserEvents.INVITE_CREATED,
|
||||
source: Modules.USER,
|
||||
action: CommonEvents.CREATED,
|
||||
object: "invite",
|
||||
})({
|
||||
data: serializedInvites,
|
||||
sharedContext,
|
||||
})
|
||||
>(invites)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
eventName: UserEvents.INVITE_TOKEN_GENERATED,
|
||||
@@ -390,14 +351,12 @@ export default class UserModuleService
|
||||
|
||||
const serializedInvites = await this.baseRepository_.serialize<
|
||||
UserTypes.InviteDTO[]
|
||||
>(updatedInvites, {
|
||||
populate: true,
|
||||
})
|
||||
>(updatedInvites)
|
||||
|
||||
moduleEventBuilderFactory({
|
||||
eventName: UserEvents.INVITE_UPDATED,
|
||||
eventName: UserEvents.INVITE_TOKEN_GENERATED,
|
||||
source: Modules.USER,
|
||||
action: CommonEvents.UPDATED,
|
||||
action: "token_generated",
|
||||
object: "invite",
|
||||
})({
|
||||
data: serializedInvites,
|
||||
|
||||
Reference in new issue
Block a user