From dd8bddc971952c1f205bfe09f196c10ab1806fff Mon Sep 17 00:00:00 2001 From: Kentaro Fukunaga Date: Tue, 27 Feb 2024 02:49:52 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20771:=20=E9=9F=B3=E5=A3=B0?= =?UTF-8?q?=E3=83=95=E3=82=A1=E3=82=A4=E3=83=AB=E3=82=A2=E3=83=83=E3=83=97?= =?UTF-8?q?=E3=83=AD=E3=83=BC=E3=83=89=E5=AE=8C=E4=BA=86API=E5=AE=9F?= =?UTF-8?q?=E8=A3=85=EF=BC=88=E3=82=B9=E3=83=88=E3=83=AC=E3=83=BC=E3=82=B8?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E9=87=8F=E8=B6=85=E9=81=8E=E3=83=81=E3=82=A7?= =?UTF-8?q?=E3=83=83=E3=82=AF=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3687: 音声ファイルアップロード完了API実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3687) - 音声ファイルアップロード完了API実行時に、ストレージの使用量チェックを行い、必要ならメール送信をする実装を追加しました。 ## レビューポイント - 使用量チェックメソッドで他にいい関数名ないか? - なるべく既存実装をいじりたくなかったので自動ルーティング前にチェック機構を配置したが不都合ないか? - テストケースに過不足ないか - 自動テストの実行方法や確認方法として適切か?ほかに代替案ないか? ## 動作確認状況 - ローカルでUT通ることを確認。 - 実際のメール送信はdeveop動作確認でやります。 --- dictation_server/src/constants/index.ts | 6 + .../src/features/files/files.module.ts | 6 + .../src/features/files/files.service.spec.ts | 352 +++++++++++++++++- .../src/features/files/files.service.ts | 147 ++++++++ .../src/features/files/test/utility.ts | 6 +- .../src/gateways/sendgrid/sendgrid.service.ts | 164 ++++++++ .../accounts/accounts.repository.service.ts | 63 +++- .../src/templates/template_U_118.html | 94 +++++ .../src/templates/template_U_118.txt | 44 +++ .../templates/template_U_118_no_parent.html | 83 +++++ .../templates/template_U_118_no_parent.txt | 38 ++ .../src/templates/template_U_119.html | 94 +++++ .../src/templates/template_U_119.txt | 44 +++ .../templates/template_U_119_no_parent.html | 83 +++++ .../templates/template_U_119_no_parent.txt | 38 ++ 15 files changed, 1256 insertions(+), 6 deletions(-) create mode 100644 dictation_server/src/templates/template_U_118.html create mode 100644 dictation_server/src/templates/template_U_118.txt create mode 100644 dictation_server/src/templates/template_U_118_no_parent.html create mode 100644 dictation_server/src/templates/template_U_118_no_parent.txt create mode 100644 dictation_server/src/templates/template_U_119.html create mode 100644 dictation_server/src/templates/template_U_119.txt create mode 100644 dictation_server/src/templates/template_U_119_no_parent.html create mode 100644 dictation_server/src/templates/template_U_119_no_parent.txt diff --git a/dictation_server/src/constants/index.ts b/dictation_server/src/constants/index.ts index cc23b64..6478a26 100644 --- a/dictation_server/src/constants/index.ts +++ b/dictation_server/src/constants/index.ts @@ -333,3 +333,9 @@ export const FILE_RETENTION_DAYS_DEFAULT = 30; * @const {number} */ export const STORAGE_SIZE_PER_LICENSE = 5; + +/** + * ストレージ使用量の警告閾値(%) + * @const {number} + */ +export const STORAGE_WARNING_THRESHOLD_PERCENT = 80; diff --git a/dictation_server/src/features/files/files.module.ts b/dictation_server/src/features/files/files.module.ts index 56ba499..9d087d8 100644 --- a/dictation_server/src/features/files/files.module.ts +++ b/dictation_server/src/features/files/files.module.ts @@ -10,6 +10,9 @@ import { TemplateFilesRepositoryModule } from '../../repositories/template_files import { UserGroupsRepositoryModule } from '../../repositories/user_groups/user_groups.repository.module'; import { NotificationhubModule } from '../../gateways/notificationhub/notificationhub.module'; import { LicensesRepositoryModule } from '../../repositories/licenses/licenses.repository.module'; +import { SendGridModule } from '../../gateways/sendgrid/sendgrid.module'; +import { AdB2cModule } from '../../gateways/adb2c/adb2c.module'; +import { AccountsRepositoryModule } from '../../repositories/accounts/accounts.repository.module'; @Module({ imports: [ @@ -22,6 +25,9 @@ import { LicensesRepositoryModule } from '../../repositories/licenses/licenses.r UserGroupsRepositoryModule, NotificationhubModule, LicensesRepositoryModule, + SendGridModule, + AdB2cModule, + AccountsRepositoryModule, ], providers: [FilesService], controllers: [FilesController], diff --git a/dictation_server/src/features/files/files.service.spec.ts b/dictation_server/src/features/files/files.service.spec.ts index deff777..a849975 100644 --- a/dictation_server/src/features/files/files.service.spec.ts +++ b/dictation_server/src/features/files/files.service.spec.ts @@ -18,7 +18,10 @@ import { makeTestUser, } from '../../common/test/utility'; import { makeTestingModule } from '../../common/test/modules'; -import { overrideBlobstorageService } from '../../common/test/overrides'; +import { + overrideAdB2cService, + overrideBlobstorageService, +} from '../../common/test/overrides'; import { createTemplateFile, getTemplateFiles, @@ -768,6 +771,353 @@ describe('タスク作成から自動ルーティング(DB使用)', () => { // 自動ルーティングが行われていないことを確認 expect(resultCheckoutPermission.length).toEqual(0); }); + it('第五階層アカウントのストレージ使用量が閾値と同値の場合、メール送信が行われない', async () => { + if (!source) fail(); + const module = await makeTestingModule(source); + if (!module) fail(); + + // アカウントを作成する + const { id: accountId } = ( + await makeTestAccount(source, { + tier: 5, + company_name: 'company1', + }) + ).account; + + // 音声ファイルの録音者のユーザー + const { external_id: authorExternalId, author_id: authorAuthorId } = + await makeTestUser(source, { + account_id: accountId, + external_id: 'author-user-external-id', + role: 'author', + author_id: 'AUTHOR_ID', + }); + + // ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。 + // 閾値は、10GB * 0.8 = 8GBとなる。 + const reusableLicense = 2; + for (let i = 0; i < reusableLicense; i++) { + await createLicense( + source, + i + 1, + new Date(2037, 1, 1, 23, 59, 59), + accountId, + LICENSE_TYPE.NORMAL, + LICENSE_ALLOCATED_STATUS.REUSABLE, + null, + null, + null, + null, + ); + } + + const fileSize = 2 * 1000 * 1000 * 1000; // 2GB + // 3つの音声ファイルを事前作成+uploadFinishedで、合計8GBのストレージ使用量状態を作成 + for (let i = 0; i < 3; i++) { + await createTask( + source, + accountId, + 'url', + 'test.zip', + 'InProgress', + undefined, + authorAuthorId ?? '', + undefined, + fileSize, + (i + 1).toString().padStart(8, '0'), + ); + } + + const service = module.get(FilesService); + const spy = jest + .spyOn(service['sendGridService'], 'sendMail') + .mockImplementation(); + const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId'); + await service.uploadFinished( + context, + authorExternalId, // API実行者のユーザーIDを設定 + 'http://blob/url/file.zip', + authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る + 'file.zip', + '11:22:33', + '2023-05-26T11:22:33.444', + '2023-05-26T11:22:33.444', + '2023-05-26T11:22:33.444', + fileSize, + '01', + 'DS2', + 'comment', + 'worktypeId', + optionItemList, + false, + ); + + expect(spy).not.toHaveBeenCalled(); + }); + it('第五階層アカウントのストレージ使用量が閾値+1byteの場合、U-118メール送信が行われる', async () => { + if (!source) fail(); + const module = await makeTestingModule(source); + if (!module) fail(); + + // アカウントを作成する + const { id: accountId } = ( + await makeTestAccount(source, { + tier: 5, + company_name: 'company1', + }) + ).account; + + // 音声ファイルの録音者のユーザー + const { external_id: authorExternalId, author_id: authorAuthorId } = + await makeTestUser(source, { + account_id: accountId, + external_id: 'author-user-external-id', + role: 'author', + author_id: 'AUTHOR_ID', + }); + + // ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。 + // 閾値は、10GB * 0.8 = 8GBとなる。 + const reusableLicense = 2; + for (let i = 0; i < reusableLicense; i++) { + await createLicense( + source, + i + 1, + new Date(2037, 1, 1, 23, 59, 59), + accountId, + LICENSE_TYPE.NORMAL, + LICENSE_ALLOCATED_STATUS.REUSABLE, + null, + null, + null, + null, + ); + } + + const fileSize = 2 * 1000 * 1000 * 1000; // 2GB + // 3つの音声ファイルを事前作成+uploadFinishedで、合計8GB+1byteのストレージ使用量状態を作成 + for (let i = 0; i < 3; i++) { + await createTask( + source, + accountId, + 'url', + 'test.zip', + 'InProgress', + undefined, + authorAuthorId ?? '', + undefined, + fileSize, + (i + 1).toString().padStart(8, '0'), + ); + } + + const service = module.get(FilesService); + // メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。 + const spy = jest + .spyOn(service['sendGridService'], 'sendMailWithU118') + .mockImplementation(); + overrideAdB2cService(service, { + getUsers: async () => [], + }); + const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId'); + await service.uploadFinished( + context, + authorExternalId, // API実行者のユーザーIDを設定 + 'http://blob/url/file.zip', + authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る + 'file.zip', + '11:22:33', + '2023-05-26T11:22:33.444', + '2023-05-26T11:22:33.444', + '2023-05-26T11:22:33.444', + fileSize + 1, + '01', + 'DS2', + 'comment', + 'worktypeId', + optionItemList, + false, + ); + + expect(spy).toHaveBeenCalledTimes(1); + }); + it('第五階層アカウントのストレージ使用量が上限と同値の場合、U-118メール送信が行われる', async () => { + if (!source) fail(); + const module = await makeTestingModule(source); + if (!module) fail(); + + // アカウントを作成する + const { id: accountId } = ( + await makeTestAccount(source, { + tier: 5, + company_name: 'company1', + }) + ).account; + + // 音声ファイルの録音者のユーザー + const { external_id: authorExternalId, author_id: authorAuthorId } = + await makeTestUser(source, { + account_id: accountId, + external_id: 'author-user-external-id', + role: 'author', + author_id: 'AUTHOR_ID', + }); + + // ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。 + const reusableLicense = 2; + for (let i = 0; i < reusableLicense; i++) { + await createLicense( + source, + i + 1, + new Date(2037, 1, 1, 23, 59, 59), + accountId, + LICENSE_TYPE.NORMAL, + LICENSE_ALLOCATED_STATUS.REUSABLE, + null, + null, + null, + null, + ); + } + + const fileSize = 2 * 1000 * 1000 * 1000; // 2GB + // 4つの音声ファイルを事前作成+uploadFinishedで、合計10GBのストレージ使用量状態を作成 + for (let i = 0; i < 4; i++) { + await createTask( + source, + accountId, + 'url', + 'test.zip', + 'InProgress', + undefined, + authorAuthorId ?? '', + undefined, + fileSize, + (i + 1).toString().padStart(8, '0'), + ); + } + + const service = module.get(FilesService); + // メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。 + const spy = jest + .spyOn(service['sendGridService'], 'sendMailWithU118') + .mockImplementation(); + overrideAdB2cService(service, { + getUsers: async () => [], + }); + const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId'); + await service.uploadFinished( + context, + authorExternalId, // API実行者のユーザーIDを設定 + 'http://blob/url/file.zip', + authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る + 'file.zip', + '11:22:33', + '2023-05-26T11:22:33.444', + '2023-05-26T11:22:33.444', + '2023-05-26T11:22:33.444', + fileSize, + '01', + 'DS2', + 'comment', + 'worktypeId', + optionItemList, + false, + ); + + expect(spy).toHaveBeenCalledTimes(1); + }); + it('第五階層アカウントのストレージ使用量が上限+1byteと同値の場合、U-119メール送信が行われる', async () => { + if (!source) fail(); + const module = await makeTestingModule(source); + if (!module) fail(); + + // アカウントを作成する + const { id: accountId } = ( + await makeTestAccount(source, { + tier: 5, + company_name: 'company1', + }) + ).account; + + // 第一階層アカウントを作成する + await makeTestAccount(source, { + tier: 1, + }); + + // 音声ファイルの録音者のユーザー + const { external_id: authorExternalId, author_id: authorAuthorId } = + await makeTestUser(source, { + account_id: accountId, + external_id: 'author-user-external-id', + role: 'author', + author_id: 'AUTHOR_ID', + }); + + // ライセンスを作成する。ライセンスが2つのため、5GB * 2 = 10GBの上限値となる。 + const reusableLicense = 2; + for (let i = 0; i < reusableLicense; i++) { + await createLicense( + source, + i + 1, + new Date(2037, 1, 1, 23, 59, 59), + accountId, + LICENSE_TYPE.NORMAL, + LICENSE_ALLOCATED_STATUS.REUSABLE, + null, + null, + null, + null, + ); + } + + const fileSize = 2 * 1000 * 1000 * 1000; // 2GB + // 4つの音声ファイルを事前作成+uploadFinishedで、合計10GB+1byteのストレージ使用量状態を作成 + for (let i = 0; i < 4; i++) { + await createTask( + source, + accountId, + 'url', + 'test.zip', + 'InProgress', + undefined, + authorAuthorId ?? '', + undefined, + fileSize, + (i + 1).toString().padStart(8, '0'), + ); + } + + const service = module.get(FilesService); + // メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。 + const spy = jest + .spyOn(service['sendGridService'], 'sendMailWithU119') + .mockImplementation(); + overrideAdB2cService(service, { + getUsers: async () => [], + }); + const context = makeContext(`uuidv4`, 'xxx-xxx-xxx-xxx', 'requestId'); + await service.uploadFinished( + context, + authorExternalId, // API実行者のユーザーIDを設定 + 'http://blob/url/file.zip', + authorAuthorId ?? '', // 音声ファイルの情報には、録音者のAuthorIDが入る + 'file.zip', + '11:22:33', + '2023-05-26T11:22:33.444', + '2023-05-26T11:22:33.444', + '2023-05-26T11:22:33.444', + fileSize + 1, + '01', + 'DS2', + 'comment', + 'worktypeId', + optionItemList, + false, + ); + + expect(spy).toHaveBeenCalledTimes(1); + }); it('日付フォーマットが不正な場合、エラーを返却する', async () => { if (!source) fail(); const { id: accountId } = await makeTestSimpleAccount(source); diff --git a/dictation_server/src/features/files/files.service.ts b/dictation_server/src/features/files/files.service.ts index 1f9c042..5736ac2 100644 --- a/dictation_server/src/features/files/files.service.ts +++ b/dictation_server/src/features/files/files.service.ts @@ -6,6 +6,7 @@ import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.servi import { AudioOptionItem, AudioUploadFinishedResponse } from './types/types'; import { OPTION_ITEM_NUM, + STORAGE_WARNING_THRESHOLD_PERCENT, TASK_STATUS, TIERS, USER_LICENSE_STATUS, @@ -37,11 +38,18 @@ import { LicenseNotAllocatedError, } from '../../repositories/licenses/errors/types'; import { LicensesRepositoryService } from '../../repositories/licenses/licenses.repository.service'; +import { DateWithZeroTime } from '../licenses/types/types'; +import { AccountsRepositoryService } from '../../repositories/accounts/accounts.repository.service'; +import { getUserNameAndMailAddress } from '../../gateways/adb2c/utils/utils'; +import { AdB2cService } from '../../gateways/adb2c/adb2c.service'; +import { SendGridService } from '../../gateways/sendgrid/sendgrid.service'; @Injectable() export class FilesService { private readonly logger = new Logger(FilesService.name); constructor( + private readonly accountsRepository: AccountsRepositoryService, + private readonly adB2cService: AdB2cService, private readonly usersRepository: UsersRepositoryService, private readonly tasksRepository: TasksRepositoryService, private readonly tasksRepositoryService: TasksRepositoryService, @@ -50,6 +58,7 @@ export class FilesService { private readonly userGroupsRepositoryService: UserGroupsRepositoryService, private readonly notificationhubService: NotificationhubService, private readonly licensesRepository: LicensesRepositoryService, + private readonly sendGridService: SendGridService, ) {} /** @@ -211,11 +220,20 @@ export class FilesService { ); } catch (e) { this.logger.error(`[${context.getTrackingId()}] error=${e}`); + this.logger.log( + `[OUT] [${context.getTrackingId()}] ${this.uploadFinished.name}`, + ); throw new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ); } + + // 第五階層アカウントはストレージ使用量超過チェックをする。順番は自動ルーティングの前後どちらでも構わない。 + if (user.account?.tier === TIERS.TIER5) { + await this.checkAndAlertStorageUsage(context, user.account_id); + } + try { // ルーティング設定に従い、チェックアウト権限を付与する const { typistGroupIds, typistIds } = @@ -271,6 +289,135 @@ export class FilesService { } } + /** + * ストレージ使用量を確認し、上限または閾値を超えていた場合に通知を行う + * @param context + * @param accountId 確認対象のアカウントID + * @returns + */ + private async checkAndAlertStorageUsage( + context: Context, + accountId: number, + ): Promise { + try { + const currentDate = new DateWithZeroTime(); + const { size, used } = await this.licensesRepository.getStorageInfo( + context, + accountId, + currentDate, + ); + const storageShresholdSize = + (size * STORAGE_WARNING_THRESHOLD_PERCENT) / 100; + + if (used > size) { + this.logger.log( + `[${context.getTrackingId()}] ${ + this.checkAndAlertStorageUsage.name + } | Storage usage is over limit. accountId=${accountId}, size=${size}, used=${used}`, + ); + const tier1AccountId = ( + await this.accountsRepository.findTier1Account(context) + ).id; + const tire1AdminMails = ( + await this.getAccountInformation(context, tier1AccountId) + ).adminEmails; + + const dealer = await this.accountsRepository.findParentAccount( + context, + accountId, + ); + const dealerName: string | null = dealer?.company_name ?? null; + const { companyName, adminEmails } = await this.getAccountInformation( + context, + accountId, + ); + await this.sendGridService.sendMailWithU119( + context, + adminEmails, + companyName, + dealerName, + tire1AdminMails, + ); + return; + } + + if (used > storageShresholdSize) { + this.logger.log( + `[${context.getTrackingId()}] ${ + this.checkAndAlertStorageUsage.name + } | Storage usage is over shresholdSize. accountId=${accountId}, size=${size}, storageShresholdSize=${storageShresholdSize}`, + ); + const dealer = await this.accountsRepository.findParentAccount( + context, + accountId, + ); + const dealerName: string | null = dealer?.company_name ?? null; + const { companyName, adminEmails } = await this.getAccountInformation( + context, + accountId, + ); + await this.sendGridService.sendMailWithU118( + context, + adminEmails, + companyName, + dealerName, + ); + + return; + } + } catch (error) { + // uploadする度にストレージ使用量チェックするため、一連の処理に失敗しても例外は握りつぶす + this.logger.error(`[${context.getTrackingId()}] error=${error}`); + } + } + + /** + * アカウントIDを指定して、アカウント情報と管理者情報を取得する + * @param context + * @param accountId 対象アカウントID + * @returns 企業名/管理者メールアドレス + */ + private async getAccountInformation( + context: Context, + accountId: number, + ): Promise<{ + companyName: string; + adminEmails: string[]; + }> { + // アカウントIDから企業名を取得する + const { company_name } = await this.accountsRepository.findAccountById( + context, + accountId, + ); + + // 管理者一覧を取得 + const admins = await this.usersRepository.findAdminUsers( + context, + accountId, + ); + const adminExternalIDs = admins.map((x) => x.external_id); + + // ADB2Cから管理者IDを元にメールアドレスを取得する + const usersInfo = await this.adB2cService.getUsers( + context, + adminExternalIDs, + ); + + // 生のAzure AD B2Cのユーザー情報からメールアドレスを抽出する + const adminEmails = usersInfo.map((x) => { + const { emailAddress } = getUserNameAndMailAddress(x); + if (emailAddress == null) { + throw new Error('admin email-address is not found'); + } + return emailAddress; + }); + + return { + companyName: company_name, + adminEmails: adminEmails, + }; + } + /** * Publishs upload sas * @param companyName diff --git a/dictation_server/src/features/files/test/utility.ts b/dictation_server/src/features/files/test/utility.ts index 79766a7..c15f981 100644 --- a/dictation_server/src/features/files/test/utility.ts +++ b/dictation_server/src/features/files/test/utility.ts @@ -54,6 +54,8 @@ export const createTask = async ( typist_user_id?: number | undefined, author_id?: string | undefined, owner_user_id?: number | undefined, + fileSize?: number | undefined, + jobNumber?: string | undefined, ): Promise<{ audioFileId: number }> => { const { identifiers: audioFileIdentifiers } = await datasource .getRepository(AudioFile) @@ -68,7 +70,7 @@ export const createTask = async ( duration: '100000', finished_at: new Date(), uploaded_at: new Date(), - file_size: 10000, + file_size: fileSize ?? 10000, priority: '00', audio_format: 'audio_format', is_encrypted: true, @@ -88,7 +90,7 @@ export const createTask = async ( const templateFile = templateFileIdentifiers.pop() as TemplateFile; await datasource.getRepository(Task).insert({ - job_number: '00000001', + job_number: jobNumber ?? '00000001', account_id: account_id, is_job_number_enabled: true, audio_file_id: audioFile.id, diff --git a/dictation_server/src/gateways/sendgrid/sendgrid.service.ts b/dictation_server/src/gateways/sendgrid/sendgrid.service.ts index af901f1..ea80ba7 100644 --- a/dictation_server/src/gateways/sendgrid/sendgrid.service.ts +++ b/dictation_server/src/gateways/sendgrid/sendgrid.service.ts @@ -63,6 +63,14 @@ export class SendGridService { private readonly templateU116Text: string; private readonly templateU117Html: string; private readonly templateU117Text: string; + private readonly templateU118Html: string; + private readonly templateU118Text: string; + private readonly templateU118NoParentHtml: string; + private readonly templateU118NoParentText: string; + private readonly templateU119Html: string; + private readonly templateU119Text: string; + private readonly templateU119NoParentHtml: string; + private readonly templateU119NoParentText: string; constructor(private readonly configService: ConfigService) { this.appDomain = this.configService.getOrThrow('APP_DOMAIN'); @@ -209,6 +217,44 @@ export class SendGridService { path.resolve(__dirname, `../../templates/template_U_117.txt`), 'utf-8', ); + this.templateU118Html = readFileSync( + path.resolve(__dirname, `../../templates/template_U_118.html`), + 'utf-8', + ); + this.templateU118Text = readFileSync( + path.resolve(__dirname, `../../templates/template_U_118.txt`), + 'utf-8', + ); + this.templateU118NoParentHtml = readFileSync( + path.resolve( + __dirname, + `../../templates/template_U_118_no_parent.html`, + ), + 'utf-8', + ); + this.templateU118NoParentText = readFileSync( + path.resolve(__dirname, `../../templates/template_U_118_no_parent.txt`), + 'utf-8', + ); + this.templateU119Html = readFileSync( + path.resolve(__dirname, `../../templates/template_U_119.html`), + 'utf-8', + ); + this.templateU119Text = readFileSync( + path.resolve(__dirname, `../../templates/template_U_119.txt`), + 'utf-8', + ); + this.templateU119NoParentHtml = readFileSync( + path.resolve( + __dirname, + `../../templates/template_U_119_no_parent.html`, + ), + 'utf-8', + ); + this.templateU119NoParentText = readFileSync( + path.resolve(__dirname, `../../templates/template_U_119_no_parent.txt`), + 'utf-8', + ); } } @@ -974,6 +1020,124 @@ export class SendGridService { } } + /** + * U-118のテンプレートを使用したメールを送信する + * @param context + * @param customerAdminMails アカウントの管理者(primary/secondary)のメールアドレス + * @param customerAccountName アカウントの名前 + * @param dealerAccountName 問題発生時に問い合わせする先の上位のディーラー名(会社名) + * @returns mail with u118 + */ + async sendMailWithU118( + context: Context, + customerAdminMails: string[], + customerAccountName: string, + dealerAccountName: string | null, + ): Promise { + this.logger.log( + `[IN] [${context.getTrackingId()}] ${this.sendMailWithU118.name}`, + ); + try { + const subject = 'Storage Usage Worning Notification [U-118]'; + + let html: string; + let text: string; + + if (!dealerAccountName) { + html = this.templateU118NoParentHtml.replaceAll( + CUSTOMER_NAME, + customerAccountName, + ); + text = this.templateU118NoParentText.replaceAll( + CUSTOMER_NAME, + customerAccountName, + ); + } else { + html = this.templateU118Html + .replaceAll(CUSTOMER_NAME, customerAccountName) + .replaceAll(DEALER_NAME, dealerAccountName); + text = this.templateU118Text + .replaceAll(CUSTOMER_NAME, customerAccountName) + .replaceAll(DEALER_NAME, dealerAccountName); + } + + // メールを送信する + await this.sendMail( + context, + customerAdminMails, + [], + this.mailFrom, + subject, + text, + html, + ); + } finally { + this.logger.log( + `[OUT] [${context.getTrackingId()}] ${this.sendMailWithU118.name}`, + ); + } + } + + /** + * U-119のテンプレートを使用したメールを送信する + * @param context + * @param customerAdminMails アカウントの管理者(primary/secondary)のメールアドレス + * @param customerAccountName アカウントの名前 + * @param dealerAccountName 問題発生時に問い合わせする先の上位のディーラー名(会社名) + * @param tire1AdminMails 第一階層の管理者(primary/secondary)のメールアドレス + * @returns mail with u119 + */ + async sendMailWithU119( + context: Context, + customerAdminMails: string[], + customerAccountName: string, + dealerAccountName: string | null, + tire1AdminMails: string[], + ): Promise { + this.logger.log( + `[IN] [${context.getTrackingId()}] ${this.sendMailWithU119.name}`, + ); + try { + const subject = 'Storage Usage Exceeded Notification [U-119]'; + + let html: string; + let text: string; + + if (!dealerAccountName) { + html = this.templateU119NoParentHtml.replaceAll( + CUSTOMER_NAME, + customerAccountName, + ); + text = this.templateU119NoParentText.replaceAll( + CUSTOMER_NAME, + customerAccountName, + ); + } else { + html = this.templateU119Html + .replaceAll(CUSTOMER_NAME, customerAccountName) + .replaceAll(DEALER_NAME, dealerAccountName); + text = this.templateU119Text + .replaceAll(CUSTOMER_NAME, customerAccountName) + .replaceAll(DEALER_NAME, dealerAccountName); + } + + // メールを送信する + await this.sendMail( + context, + customerAdminMails, + tire1AdminMails, + this.mailFrom, + subject, + text, + html, + ); + } finally { + this.logger.log( + `[OUT] [${context.getTrackingId()}] ${this.sendMailWithU119.name}`, + ); + } + } + /** * メールを送信する * @param context diff --git a/dictation_server/src/repositories/accounts/accounts.repository.service.ts b/dictation_server/src/repositories/accounts/accounts.repository.service.ts index 11464b1..a2d4ad5 100644 --- a/dictation_server/src/repositories/accounts/accounts.repository.service.ts +++ b/dictation_server/src/repositories/accounts/accounts.repository.service.ts @@ -279,6 +279,63 @@ export class AccountsRepositoryService { return account; } + /** + * OMDSTokyoのアカウント情報を取得する + * @param id + * @returns account + */ + async findTier1Account(context: Context): Promise { + const account = await this.dataSource.getRepository(Account).findOne({ + where: { + tier: TIERS.TIER1, + }, + comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, + }); + + if (!account) { + throw new AccountNotFoundError(`Account is Not Found.`); + } + return account; + } + + /** + * 指定したアカウントの親アカウント情報を取得します(存在しない場合はnullを返します) + * @param context + * @param accountId + * @returns parent account + */ + async findParentAccount( + context: Context, + accountId: number, + ): Promise { + return await this.dataSource.transaction(async (entityManager) => { + const accountsRepo = entityManager.getRepository(Account); + const myAccount = await accountsRepo.findOne({ + where: { + id: accountId, + }, + comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, + }); + if (!myAccount) { + throw new AccountNotFoundError(`Target Account is Not Found.`); + } + + if (!myAccount.parent_account_id) { + // 親アカウントが存在しない場合は明示的にnullを返す + return null; + } + + const parentAccount = await accountsRepo.findOne({ + where: { + id: myAccount.parent_account_id, + }, + comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, + }); + + return parentAccount; + }); + } + /** * ※サブルーチンとして、別途トランザクション開始された処理から呼び出されることを想定 * 有効期限が現在日付からしきい値以内のライセンス数を取得する @@ -942,11 +999,11 @@ export class AccountsRepositoryService { /** * 一階層上のアカウントを取得する - * @param accountId - * @param tier + * @param accountId 自身の一階層上のアカウントID(子アカウントではない) + * @param tier 自身のアカウントの階層 * @returns account: 一階層上のアカウント */ - async getOneUpperTierAccount( + private async getOneUpperTierAccount( context: Context, accountId: number, tier: number, diff --git a/dictation_server/src/templates/template_U_118.html b/dictation_server/src/templates/template_U_118.html new file mode 100644 index 0000000..acad01a --- /dev/null +++ b/dictation_server/src/templates/template_U_118.html @@ -0,0 +1,94 @@ + + + Storage Usage Worning Notification [U-118] + + + +
+

<English>

+

Dear $CUSTOMER_NAME$,

+

+ The storage usage for your account has reached 80% of its usage limit. + Functions related to the Dictation Workfrow will be restricted until the + storage usage becomes lower than the limit. +

+

+ Please remove Dictations files once the transcription is completed or + add capacity by assigning a license to a new user. 5GB of storage will + be provided to the account for each active user. +

+

+ For detailed information, please sign in to ODMS Cloud and check the + "Subscription" tab. +

+

+ If you need support regarding ODMS Cloud, please contact $DEALER_NAME$. +

+

+ If you have received this e-mail in error, please delete this e-mail + from your system.
+ This is an automatically generated e-mail and this mailbox is not + monitored. Please do not reply. +

+
+
+

<Deutsch>

+

Sehr geehrte(r) $CUSTOMER_NAME$,

+

+ Die Speichernutzung Ihres Kontos hat 80 % des Nutzungslimits erreicht. + Funktionen im Zusammenhang mit dem Dictation Workfrow werden + eingeschränkt, bis die Speichernutzung unter den Grenzwert sinkt. +

+

+ Bitte entfernen Sie Diktatdateien, sobald die Transkription + abgeschlossen ist, oder erhöhen Sie die Kapazität, indem Sie einem neuen + Benutzer eine Lizenz zuweisen. Für jeden aktiven Benutzer werden dem + Konto 5 GB Speicherplatz zur Verfügung gestellt. +

+

+ Für detaillierte Informationen melden Sie sich bitte bei ODMS Cloud an + und überprüfen Sie die Registerkarte „Abonnement“. +

+

+ Wenn Sie Unterstützung bezüglich ODMS Cloud benötigen, wenden Sie sich + bitte an $DEALER_NAME$. +

+

+ Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie + diese E-Mail bitte aus Ihrem System.
+ Dies ist eine automatisch generierte E-Mail und dieses Postfach wird + nicht überwacht. Bitte nicht antworten. +

+
+
+

<Français>

+

Chère/Cher $CUSTOMER_NAME$,

+

+ L'utilisation du stockage pour votre compte a atteint 80 % de sa limite + d'utilisation. Les fonctions liées au Workfrow de dictée seront + restreintes jusqu'à ce que l'utilisation du stockage devienne inférieure + à la limite. +

+

+ Veuillez supprimer les fichiers de dictées une fois la transcription + terminée ou ajouter de la capacité en attribuant une licence à un nouvel + utilisateur. 5 Go de stockage seront fournis au compte pour chaque + utilisateur actif. +

+

+ Pour des informations détaillées, veuillez vous connecter à ODMS Cloud + et consulter l'onglet « Abonnement ». +

+

+ Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez + contacter $DEALER_NAME$. +

+

+ Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail + de votre système.
+ Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres + n'est pas surveillée. Merci de ne pas répondre. +

+
+ + diff --git a/dictation_server/src/templates/template_U_118.txt b/dictation_server/src/templates/template_U_118.txt new file mode 100644 index 0000000..4cc5cf5 --- /dev/null +++ b/dictation_server/src/templates/template_U_118.txt @@ -0,0 +1,44 @@ + + +Dear $CUSTOMER_NAME$, + +The storage usage for your account has reached 80% of its usage limit. Functions related to the Dictation Workfrow will be restricted until the storage usage becomes lower than the limit. + +Please remove Dictations files once the transcription is completed or add capacity by assigning a license to a new user. 5GB of storage will be provided to the account for each active user. + +For detailed information, please sign in to ODMS Cloud and check the "Subscription" tab. + +If you need support regarding ODMS Cloud, please contact $DEALER_NAME$. + +If you have received this e-mail in error, please delete this e-mail from your system. +This is an automatically generated e-mail and this mailbox is not monitored. Please do not reply. + + + +Sehr geehrte(r) $CUSTOMER_NAME$, + +Die Speichernutzung Ihres Kontos hat 80 % des Nutzungslimits erreicht. Funktionen im Zusammenhang mit dem Dictation Workfrow werden eingeschränkt, bis die Speichernutzung unter den Grenzwert sinkt. + +Bitte entfernen Sie Diktatdateien, sobald die Transkription abgeschlossen ist, oder erhöhen Sie die Kapazität, indem Sie einem neuen Benutzer eine Lizenz zuweisen. Für jeden aktiven Benutzer werden dem Konto 5 GB Speicherplatz zur Verfügung gestellt. + +Für detaillierte Informationen melden Sie sich bitte bei ODMS Cloud an und überprüfen Sie die Registerkarte Pour des informations détaillées, veuillez vous connecter à ODMS Cloud et consulter l'onglet « Abonnement ». + +Wenn Sie Unterstützung bezüglich ODMS Cloud benötigen, wenden Sie sich bitte an $DEALER_NAME$. + +Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System. +Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht überwacht. Bitte nicht antworten. + + + +Chère/Cher $CUSTOMER_NAME$, + +L'utilisation du stockage pour votre compte a atteint 80 % de sa limite d'utilisation. Les fonctions liées au Workfrow de dictée seront restreintes jusqu'à ce que l'utilisation du stockage devienne inférieure à la limite. + +Veuillez supprimer les fichiers de dictées une fois la transcription terminée ou ajouter de la capacité en attribuant une licence à un nouvel utilisateur. 5 Go de stockage seront fournis au compte pour chaque utilisateur actif. + +Pour des informations détaillées, veuillez vous connecter à ODMS Cloud et consulter l'onglet « Abonnement ». + +Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez contacter $DEALER_NAME$. + +Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système. +Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres n'est pas surveillée. Merci de ne pas répondre. \ No newline at end of file diff --git a/dictation_server/src/templates/template_U_118_no_parent.html b/dictation_server/src/templates/template_U_118_no_parent.html new file mode 100644 index 0000000..e5ce598 --- /dev/null +++ b/dictation_server/src/templates/template_U_118_no_parent.html @@ -0,0 +1,83 @@ + + + Storage Usage Worning Notification [U-118] + + + +
+

<English>

+

Dear $CUSTOMER_NAME$,

+

+ The storage usage for your account has reached 80% of its usage limit. + Functions related to the Dictation Workfrow will be restricted until the + storage usage becomes lower than the limit. +

+

+ Please remove Dictations files once the transcription is completed or + add capacity by assigning a license to a new user. 5GB of storage will + be provided to the account for each active user. +

+

+ For detailed information, please sign in to ODMS Cloud and check the + "Subscription" tab. +

+

+ If you have received this e-mail in error, please delete this e-mail + from your system.
+ This is an automatically generated e-mail and this mailbox is not + monitored. Please do not reply. +

+
+
+

<Deutsch>

+

Sehr geehrte(r) $CUSTOMER_NAME$,

+

+ Die Speichernutzung Ihres Kontos hat 80 % des Nutzungslimits erreicht. + Funktionen im Zusammenhang mit dem Dictation Workfrow werden + eingeschränkt, bis die Speichernutzung unter den Grenzwert sinkt. +

+

+ Bitte entfernen Sie Diktatdateien, sobald die Transkription + abgeschlossen ist, oder erhöhen Sie die Kapazität, indem Sie einem neuen + Benutzer eine Lizenz zuweisen. Für jeden aktiven Benutzer werden dem + Konto 5 GB Speicherplatz zur Verfügung gestellt. +

+

+ Für detaillierte Informationen melden Sie sich bitte bei ODMS Cloud an + und überprüfen Sie die Registerkarte „Abonnement“. +

+

+ Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie + diese E-Mail bitte aus Ihrem System.
+ Dies ist eine automatisch generierte E-Mail und dieses Postfach wird + nicht überwacht. Bitte nicht antworten. +

+
+
+

<Français>

+

Chère/Cher $CUSTOMER_NAME$,

+

+ L'utilisation du stockage pour votre compte a atteint 80 % de sa limite + d'utilisation. Les fonctions liées au Workfrow de dictée seront + restreintes jusqu'à ce que l'utilisation du stockage devienne inférieure + à la limite. +

+

+ Veuillez supprimer les fichiers de dictées une fois la transcription + terminée ou ajouter de la capacité en attribuant une licence à un nouvel + utilisateur. 5 Go de stockage seront fournis au compte pour chaque + utilisateur actif. +

+

+ Pour des informations détaillées, veuillez vous connecter à ODMS Cloud + et consulter l'onglet « Abonnement ». +

+

+ Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail + de votre système.
+ Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres + n'est pas surveillée. Merci de ne pas répondre. +

+
+ + diff --git a/dictation_server/src/templates/template_U_118_no_parent.txt b/dictation_server/src/templates/template_U_118_no_parent.txt new file mode 100644 index 0000000..f7378f2 --- /dev/null +++ b/dictation_server/src/templates/template_U_118_no_parent.txt @@ -0,0 +1,38 @@ + + +Dear $CUSTOMER_NAME$, + +The storage usage for your account has reached 80% of its usage limit. Functions related to the Dictation Workfrow will be restricted until the storage usage becomes lower than the limit. + +Please remove Dictations files once the transcription is completed or add capacity by assigning a license to a new user. 5GB of storage will be provided to the account for each active user. + +For detailed information, please sign in to ODMS Cloud and check the "Subscription" tab. + +If you have received this e-mail in error, please delete this e-mail from your system. +This is an automatically generated e-mail and this mailbox is not monitored. Please do not reply. + + + +Sehr geehrte(r) $CUSTOMER_NAME$, + +Die Speichernutzung Ihres Kontos hat 80 % des Nutzungslimits erreicht. Funktionen im Zusammenhang mit dem Dictation Workfrow werden eingeschränkt, bis die Speichernutzung unter den Grenzwert sinkt. + +Bitte entfernen Sie Diktatdateien, sobald die Transkription abgeschlossen ist, oder erhöhen Sie die Kapazität, indem Sie einem neuen Benutzer eine Lizenz zuweisen. Für jeden aktiven Benutzer werden dem Konto 5 GB Speicherplatz zur Verfügung gestellt. + +Für detaillierte Informationen melden Sie sich bitte bei ODMS Cloud an und überprüfen Sie die Registerkarte Pour des informations détaillées, veuillez vous connecter à ODMS Cloud et consulter l'onglet « Abonnement ». + +Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System. +Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht überwacht. Bitte nicht antworten. + + + +Chère/Cher $CUSTOMER_NAME$, + +L'utilisation du stockage pour votre compte a atteint 80 % de sa limite d'utilisation. Les fonctions liées au Workfrow de dictée seront restreintes jusqu'à ce que l'utilisation du stockage devienne inférieure à la limite. + +Veuillez supprimer les fichiers de dictées une fois la transcription terminée ou ajouter de la capacité en attribuant une licence à un nouvel utilisateur. 5 Go de stockage seront fournis au compte pour chaque utilisateur actif. + +Pour des informations détaillées, veuillez vous connecter à ODMS Cloud et consulter l'onglet « Abonnement ». + +Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système. +Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres n'est pas surveillée. Merci de ne pas répondre. \ No newline at end of file diff --git a/dictation_server/src/templates/template_U_119.html b/dictation_server/src/templates/template_U_119.html new file mode 100644 index 0000000..0264339 --- /dev/null +++ b/dictation_server/src/templates/template_U_119.html @@ -0,0 +1,94 @@ + + + Storage Usage Exceeded Notification [U-119] + + + +
+

<English>

+

Dear $CUSTOMER_NAME$,

+

+ The storage usage for your account has exceeded the usage limit. + Functions related to the Dictation Workfrow will be restricted until the + storage usage becomes lower than the limit. +

+

+ Please remove Dictations files once the transcription is completed or + add capacity by assigning a license to a new user. 5GB of storage will + be provided to the account for each active user. +

+

+ For detailed information, please sign in to ODMS Cloud and check the + "Subscription" tab. +

+

+ If you need support regarding ODMS Cloud, please contact $DEALER_NAME$. +

+

+ If you have received this e-mail in error, please delete this e-mail + from your system.
+ This is an automatically generated e-mail and this mailbox is not + monitored. Please do not reply. +

+
+
+

<Deutsch>

+

Sehr geehrte(r) $CUSTOMER_NAME$,

+

+ Die Speichernutzung Ihres Kontos hat das Nutzungslimit überschritten. + Funktionen im Zusammenhang mit dem Dictation Workfrow werden + eingeschränkt, bis die Speichernutzung unter den Grenzwert sinkt. +

+

+ Bitte entfernen Sie Diktatdateien, sobald die Transkription + abgeschlossen ist, oder erhöhen Sie die Kapazität, indem Sie einem neuen + Benutzer eine Lizenz zuweisen. Für jeden aktiven Benutzer werden dem + Konto 5 GB Speicherplatz zur Verfügung gestellt. +

+

+ Für detaillierte Informationen melden Sie sich bitte bei ODMS Cloud an + und überprüfen Sie die Registerkarte „Abonnement“. +

+

+ Wenn Sie Unterstützung bezüglich ODMS Cloud benötigen, wenden Sie sich + bitte an $DEALER_NAME$. +

+

+ Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie + diese E-Mail bitte aus Ihrem System.
+ Dies ist eine automatisch generierte E-Mail und dieses Postfach wird + nicht überwacht. Bitte nicht antworten. +

+
+
+

<Français>

+

Chère/Cher $CUSTOMER_NAME$,

+

+ L'utilisation du stockage pour votre compte a dépassé la limite + d'utilisation. Les fonctions liées au Workfrow de dictée seront + restreintes jusqu'à ce que l'utilisation du stockage devienne inférieure + à la limite. +

+

+ Veuillez supprimer les fichiers de dictées une fois la transcription + terminée ou ajouter de la capacité en attribuant une licence à un nouvel + utilisateur. 5 Go de stockage seront fournis au compte pour chaque + utilisateur actif. +

+

+ Pour des informations détaillées, veuillez vous connecter à ODMS Cloud + et consulter l'onglet « Abonnement ». +

+

+ Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez + contacter $DEALER_NAME$. +

+

+ Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail + de votre système.
+ Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres + n'est pas surveillée. Merci de ne pas répondre. +

+
+ + diff --git a/dictation_server/src/templates/template_U_119.txt b/dictation_server/src/templates/template_U_119.txt new file mode 100644 index 0000000..d6c5802 --- /dev/null +++ b/dictation_server/src/templates/template_U_119.txt @@ -0,0 +1,44 @@ + + +Dear $CUSTOMER_NAME$, + +The storage usage for your account has exceeded the usage limit. Functions related to the Dictation Workfrow will be restricted until the storage usage becomes lower than the limit. + +Please remove Dictations files once the transcription is completed or add capacity by assigning a license to a new user. 5GB of storage will be provided to the account for each active user. + +For detailed information, please sign in to ODMS Cloud and check the "Subscription" tab. + +If you need support regarding ODMS Cloud, please contact $DEALER_NAME$. + +If you have received this e-mail in error, please delete this e-mail from your system. +This is an automatically generated e-mail and this mailbox is not monitored. Please do not reply. + + + +Sehr geehrte(r) $CUSTOMER_NAME$, + +Die Speichernutzung Ihres Kontos hat das Nutzungslimit überschritten. Funktionen im Zusammenhang mit dem Dictation Workfrow werden eingeschränkt, bis die Speichernutzung unter den Grenzwert sinkt. + +Bitte entfernen Sie Diktatdateien, sobald die Transkription abgeschlossen ist, oder erhöhen Sie die Kapazität, indem Sie einem neuen Benutzer eine Lizenz zuweisen. Für jeden aktiven Benutzer werden dem Konto 5 GB Speicherplatz zur Verfügung gestellt. + +Für detaillierte Informationen melden Sie sich bitte bei ODMS Cloud an und überprüfen Sie die Registerkarte „Abonnement“. + +Wenn Sie Unterstützung bezüglich ODMS Cloud benötigen, wenden Sie sich bitte an $DEALER_NAME$. + +Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System. +Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht überwacht. Bitte nicht antworten. + + + +Chère/Cher $CUSTOMER_NAME$, + +L'utilisation du stockage pour votre compte a dépassé la limite d'utilisation. Les fonctions liées au Workfrow de dictée seront restreintes jusqu'à ce que l'utilisation du stockage devienne inférieure à la limite. + +Veuillez supprimer les fichiers de dictées une fois la transcription terminée ou ajouter de la capacité en attribuant une licence à un nouvel utilisateur. 5 Go de stockage seront fournis au compte pour chaque utilisateur actif. + +Pour des informations détaillées, veuillez vous connecter à ODMS Cloud et consulter l'onglet « Abonnement ». + +Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez contacter $DEALER_NAME$. + +Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système. +Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres n'est pas surveillée. Merci de ne pas répondre. \ No newline at end of file diff --git a/dictation_server/src/templates/template_U_119_no_parent.html b/dictation_server/src/templates/template_U_119_no_parent.html new file mode 100644 index 0000000..d85a975 --- /dev/null +++ b/dictation_server/src/templates/template_U_119_no_parent.html @@ -0,0 +1,83 @@ + + + Storage Usage Exceeded Notification [U-119] + + + +
+

<English>

+

Dear $CUSTOMER_NAME$,

+

+ The storage usage for your account has exceeded the usage limit. + Functions related to the Dictation Workfrow will be restricted until the + storage usage becomes lower than the limit. +

+

+ Please remove Dictations files once the transcription is completed or + add capacity by assigning a license to a new user. 5GB of storage will + be provided to the account for each active user. +

+

+ For detailed information, please sign in to ODMS Cloud and check the + "Subscription" tab. +

+

+ If you have received this e-mail in error, please delete this e-mail + from your system.
+ This is an automatically generated e-mail and this mailbox is not + monitored. Please do not reply. +

+
+
+

<Deutsch>

+

Sehr geehrte(r) $CUSTOMER_NAME$,

+

+ Die Speichernutzung Ihres Kontos hat das Nutzungslimit überschritten. + Funktionen im Zusammenhang mit dem Dictation Workfrow werden + eingeschränkt, bis die Speichernutzung unter den Grenzwert sinkt. +

+

+ Bitte entfernen Sie Diktatdateien, sobald die Transkription + abgeschlossen ist, oder erhöhen Sie die Kapazität, indem Sie einem neuen + Benutzer eine Lizenz zuweisen. Für jeden aktiven Benutzer werden dem + Konto 5 GB Speicherplatz zur Verfügung gestellt. +

+

+ Für detaillierte Informationen melden Sie sich bitte bei ODMS Cloud an + und überprüfen Sie die Registerkarte „Abonnement“. +

+

+ Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie + diese E-Mail bitte aus Ihrem System.
+ Dies ist eine automatisch generierte E-Mail und dieses Postfach wird + nicht überwacht. Bitte nicht antworten. +

+
+
+

<Français>

+

Chère/Cher $CUSTOMER_NAME$,

+

+ L'utilisation du stockage pour votre compte a dépassé la limite + d'utilisation. Les fonctions liées au Workfrow de dictée seront + restreintes jusqu'à ce que l'utilisation du stockage devienne inférieure + à la limite. +

+

+ Veuillez supprimer les fichiers de dictées une fois la transcription + terminée ou ajouter de la capacité en attribuant une licence à un nouvel + utilisateur. 5 Go de stockage seront fournis au compte pour chaque + utilisateur actif. +

+

+ Pour des informations détaillées, veuillez vous connecter à ODMS Cloud + et consulter l'onglet « Abonnement ». +

+

+ Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail + de votre système.
+ Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres + n'est pas surveillée. Merci de ne pas répondre. +

+
+ + diff --git a/dictation_server/src/templates/template_U_119_no_parent.txt b/dictation_server/src/templates/template_U_119_no_parent.txt new file mode 100644 index 0000000..21a0ff8 --- /dev/null +++ b/dictation_server/src/templates/template_U_119_no_parent.txt @@ -0,0 +1,38 @@ + + +Dear $CUSTOMER_NAME$, + +The storage usage for your account has exceeded the usage limit. Functions related to the Dictation Workfrow will be restricted until the storage usage becomes lower than the limit. + +Please remove Dictations files once the transcription is completed or add capacity by assigning a license to a new user. 5GB of storage will be provided to the account for each active user. + +For detailed information, please sign in to ODMS Cloud and check the "Subscription" tab. + +If you have received this e-mail in error, please delete this e-mail from your system. +This is an automatically generated e-mail and this mailbox is not monitored. Please do not reply. + + + +Sehr geehrte(r) $CUSTOMER_NAME$, + +Die Speichernutzung Ihres Kontos hat das Nutzungslimit überschritten. Funktionen im Zusammenhang mit dem Dictation Workfrow werden eingeschränkt, bis die Speichernutzung unter den Grenzwert sinkt. + +Bitte entfernen Sie Diktatdateien, sobald die Transkription abgeschlossen ist, oder erhöhen Sie die Kapazität, indem Sie einem neuen Benutzer eine Lizenz zuweisen. Für jeden aktiven Benutzer werden dem Konto 5 GB Speicherplatz zur Verfügung gestellt. + +Für detaillierte Informationen melden Sie sich bitte bei ODMS Cloud an und überprüfen Sie die Registerkarte „Abonnement“. + +Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System. +Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht überwacht. Bitte nicht antworten. + + + +Chère/Cher $CUSTOMER_NAME$, + +L'utilisation du stockage pour votre compte a dépassé la limite d'utilisation. Les fonctions liées au Workfrow de dictée seront restreintes jusqu'à ce que l'utilisation du stockage devienne inférieure à la limite. + +Veuillez supprimer les fichiers de dictées une fois la transcription terminée ou ajouter de la capacité en attribuant une licence à un nouvel utilisateur. 5 Go de stockage seront fournis au compte pour chaque utilisateur actif. + +Pour des informations détaillées, veuillez vous connecter à ODMS Cloud et consulter l'onglet « Abonnement ». + +Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système. +Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres n'est pas surveillée. Merci de ne pas répondre. \ No newline at end of file