diff --git a/src/application/exceptions/ApplicationExceptions.ts b/src/application/exceptions/ApplicationExceptions.ts index 86bf68b..e024e66 100644 --- a/src/application/exceptions/ApplicationExceptions.ts +++ b/src/application/exceptions/ApplicationExceptions.ts @@ -53,6 +53,14 @@ export class MemberNotFoundFromDiscordAccountIdException extends ApplicationExce } } +export class KarteNotFoundException extends ApplicationException { + constructor(karteId: string) { + const message = `カルテが見つかりません: ${karteId}`; + super(message); + this.name = "KarteNotFoundException"; + } +} + export class DiscordAccountNotConnectedException extends ApplicationException { constructor(userId: string, discordUserId: string) { const message = `ユーザー: ${userId} のDiscordアカウントは紐づいていません: ${discordUserId}`; diff --git a/src/application/index.ts b/src/application/index.ts index 46ce8c6..6a2038e 100644 --- a/src/application/index.ts +++ b/src/application/index.ts @@ -1,4 +1,5 @@ export * from "./usecase/member"; export * from "./usecase/event"; export * from "./usecase/eventParticipation"; +export * from "./usecase/karte"; export * from "./exceptions"; diff --git a/src/application/usecase/karte/CorrectKarte.ts b/src/application/usecase/karte/CorrectKarte.ts new file mode 100644 index 0000000..385696a --- /dev/null +++ b/src/application/usecase/karte/CorrectKarte.ts @@ -0,0 +1,59 @@ +import { KarteNotFoundException } from "#application/exceptions"; +import { IUseCase } from "#application/usecase/base"; +import type { Client } from "#domain/aggregates/karte/Client"; +import type { Consent } from "#domain/aggregates/karte/Consent"; +import type { ConsultationCategory } from "#domain/aggregates/karte/ConsultationCategory"; +import type { FollowUp } from "#domain/aggregates/karte/FollowUp"; +import type { Karte } from "#domain/aggregates/karte/Karte"; +import type { KarteId } from "#domain/aggregates/karte/KarteId"; +import type { KarteRepository } from "#domain/aggregates/karte/KarteRepository"; +import type { WorkDuration } from "#domain/aggregates/karte/WorkDuration"; +import type { MemberId } from "#domain/aggregates/member/MemberId"; +import type { NonEmptyArray } from "#domain/base/NonEmptyArray"; + +/** 訂正時の解決ステータス */ +type CorrectResolution = + | { readonly type: "resolved" } + | { readonly type: "unresolved"; readonly followUp: FollowUp }; + +export type CorrectKarteInput = { + readonly karteId: KarteId; + readonly consultedAt: Date; + readonly client: Client; + readonly consent: Consent; + readonly consultation: { + readonly categories: NonEmptyArray; + readonly targetDevice: string; + readonly troubleDetails: string; + }; + readonly supportRecord: { + readonly assignedMemberIds: NonEmptyArray; + readonly content: string; + readonly resolution: CorrectResolution; + readonly workDuration: WorkDuration; + }; +}; + +export type CorrectKarteOutput = { + readonly karte: Karte; +}; + +export class CorrectKarteUseCase extends IUseCase< + CorrectKarteInput, + CorrectKarteOutput +> { + constructor(private readonly karteRepository: KarteRepository) { + super(); + } + + async execute(input: CorrectKarteInput): Promise { + const existing = await this.karteRepository.findById(input.karteId); + if (!existing) { + throw new KarteNotFoundException(input.karteId); + } + + const corrected = existing.correct(input); + await this.karteRepository.save(corrected); + return { karte: corrected }; + } +} diff --git a/src/application/usecase/karte/CreateKarte.ts b/src/application/usecase/karte/CreateKarte.ts new file mode 100644 index 0000000..dfa20bd --- /dev/null +++ b/src/application/usecase/karte/CreateKarte.ts @@ -0,0 +1,53 @@ +import { IUseCase } from "#application/usecase/base"; +import type { Client } from "#domain/aggregates/karte/Client"; +import type { Consent } from "#domain/aggregates/karte/Consent"; +import type { ConsultationCategory } from "#domain/aggregates/karte/ConsultationCategory"; +import type { FollowUp } from "#domain/aggregates/karte/FollowUp"; +import { Karte } from "#domain/aggregates/karte/Karte"; +import type { KarteId } from "#domain/aggregates/karte/KarteId"; +import type { KarteRepository } from "#domain/aggregates/karte/KarteRepository"; +import type { WorkDuration } from "#domain/aggregates/karte/WorkDuration"; +import type { MemberId } from "#domain/aggregates/member/MemberId"; +import type { NonEmptyArray } from "#domain/base/NonEmptyArray"; + +/** 新規カルテ作成時の解決ステータス */ +type CreateResolution = + | { readonly type: "resolved" } + | { readonly type: "unresolved"; readonly followUp: FollowUp }; + +export type CreateKarteInput = { + readonly id: KarteId; + readonly consultedAt: Date; + readonly client: Client; + readonly consent: Consent; + readonly consultation: { + readonly categories: NonEmptyArray; + readonly targetDevice: string; + readonly troubleDetails: string; + }; + readonly supportRecord: { + readonly assignedMemberIds: NonEmptyArray; + readonly content: string; + readonly resolution: CreateResolution; + readonly workDuration: WorkDuration; + }; +}; + +export type CreateKarteOutput = { + readonly karte: Karte; +}; + +export class CreateKarteUseCase extends IUseCase< + CreateKarteInput, + CreateKarteOutput +> { + constructor(private readonly karteRepository: KarteRepository) { + super(); + } + + async execute(input: CreateKarteInput): Promise { + const karte = Karte.create(input); + await this.karteRepository.save(karte); + return { karte }; + } +} diff --git a/src/application/usecase/karte/GetKarte.ts b/src/application/usecase/karte/GetKarte.ts new file mode 100644 index 0000000..6c6a85c --- /dev/null +++ b/src/application/usecase/karte/GetKarte.ts @@ -0,0 +1,27 @@ +import { KarteNotFoundException } from "#application/exceptions"; +import { IUseCase } from "#application/usecase/base"; +import type { Karte } from "#domain/aggregates/karte/Karte"; +import type { KarteId } from "#domain/aggregates/karte/KarteId"; +import type { KarteRepository } from "#domain/aggregates/karte/KarteRepository"; + +export type GetKarteInput = { + readonly karteId: KarteId; +}; + +export type GetKarteOutput = { + readonly karte: Karte; +}; + +export class GetKarteUseCase extends IUseCase { + constructor(private readonly karteRepository: KarteRepository) { + super(); + } + + async execute(input: GetKarteInput): Promise { + const karte = await this.karteRepository.findById(input.karteId); + if (!karte) { + throw new KarteNotFoundException(input.karteId); + } + return { karte }; + } +} diff --git a/src/application/usecase/karte/index.ts b/src/application/usecase/karte/index.ts new file mode 100644 index 0000000..dc2af18 --- /dev/null +++ b/src/application/usecase/karte/index.ts @@ -0,0 +1,6 @@ +export { CreateKarteUseCase } from "./CreateKarte"; +export type { CreateKarteInput, CreateKarteOutput } from "./CreateKarte"; +export { CorrectKarteUseCase } from "./CorrectKarte"; +export type { CorrectKarteInput, CorrectKarteOutput } from "./CorrectKarte"; +export { GetKarteUseCase } from "./GetKarte"; +export type { GetKarteInput, GetKarteOutput } from "./GetKarte";