Merged PR 893: API修正(upload-finished)
## 概要 [Task4033: API修正(upload-finished)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/4033) - JobNumberテーブルから取得したJOBNUMBERを使用してタスクを作成する。 - テスト追加 ## レビューポイント - テストケースは足りているか - JOBNUMBERの採番ロジックに誤りはないか ## クエリの変更 - Repositoryを変更し、クエリが変更された場合は変更内容を確認する - JobNumberテーブルからの取得と更新クエリを追加した - 既存のクエリを変更はしていない ## 動作確認状況 - ローカルで確認 - 行った修正がデグレを発生させていないことを確認できるか - 具体的にどのような確認をしたか - テストケースを修正し、既存テストがすべて通ることを確認 ## 補足 - 相談、参考資料などがあれば
This commit is contained in:
parent
228e21ba78
commit
35e2d626a0
@ -9,6 +9,8 @@ import {
|
||||
} from '../../constants';
|
||||
import { License } from '../../repositories/licenses/entity/license.entity';
|
||||
import { AccountArchive } from '../../repositories/accounts/entity/account_archive.entity';
|
||||
import { Task } from '../../repositories/tasks/entity/task.entity';
|
||||
import { JobNumber } from '../../repositories/job_number/entity/job_number.entity';
|
||||
|
||||
type InitialTestDBState = {
|
||||
tier1Accounts: { account: Account; users: User[] }[];
|
||||
@ -421,3 +423,26 @@ export const getLicenses = async (
|
||||
});
|
||||
return licenses;
|
||||
};
|
||||
|
||||
export const getTasks = async (
|
||||
datasource: DataSource,
|
||||
account_id: number,
|
||||
): Promise<Task[]> => {
|
||||
const tasks = await datasource.getRepository(Task).find({
|
||||
where: { account_id: account_id },
|
||||
});
|
||||
return tasks;
|
||||
};
|
||||
|
||||
// job_numberを取得する
|
||||
export const getJobNumber = async (
|
||||
datasource: DataSource,
|
||||
account_id: number,
|
||||
): Promise<JobNumber | null> => {
|
||||
const jobNumber = await datasource.getRepository(JobNumber).findOne({
|
||||
where: {
|
||||
account_id: account_id,
|
||||
},
|
||||
});
|
||||
return jobNumber;
|
||||
};
|
||||
|
||||
@ -41,6 +41,7 @@ import {
|
||||
getLicenses,
|
||||
getUserArchive,
|
||||
getAccountArchive,
|
||||
getTasks,
|
||||
} from '../../common/test/utility';
|
||||
import { AccountsService } from './accounts.service';
|
||||
import { Context, makeContext } from '../../common/log';
|
||||
@ -94,7 +95,6 @@ import { truncateAllTable } from '../../common/test/init';
|
||||
import {
|
||||
createTask,
|
||||
getCheckoutPermissions,
|
||||
getTasks,
|
||||
} from '../tasks/test/utility';
|
||||
import { createCheckoutPermissions } from '../tasks/test/utility';
|
||||
import { TestLogger } from '../../common/test/logger';
|
||||
|
||||
@ -3,6 +3,7 @@ import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { makeBlobstorageServiceMockValue } from './test/files.service.mock';
|
||||
import { DataSource } from 'typeorm';
|
||||
import {
|
||||
createJobNumber,
|
||||
createLicense,
|
||||
createTask,
|
||||
createUserGroupAndMember,
|
||||
@ -13,6 +14,8 @@ import {
|
||||
import { FilesService } from './files.service';
|
||||
import { makeContext } from '../../common/log';
|
||||
import {
|
||||
getJobNumber,
|
||||
getTasks,
|
||||
makeHierarchicalAccounts,
|
||||
makeTestAccount,
|
||||
makeTestSimpleAccount,
|
||||
@ -50,6 +53,7 @@ import {
|
||||
} from '../../constants';
|
||||
import { truncateAllTable } from '../../common/test/init';
|
||||
import { TestLogger } from '../../common/test/logger';
|
||||
import { TasksService } from '../tasks/tasks.service';
|
||||
|
||||
describe('publishUploadSas', () => {
|
||||
let source: DataSource | null = null;
|
||||
@ -322,6 +326,10 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
);
|
||||
// ワークフロータイピストを作成
|
||||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||||
|
||||
// 初期値のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000000');
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
|
||||
@ -335,6 +343,7 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
const notificationHubService = module.get<NotificationhubService>(
|
||||
NotificationhubService,
|
||||
);
|
||||
|
||||
const result = await service.uploadFinished(
|
||||
makeContext('trackingId', 'requestId'),
|
||||
authorExternalId,
|
||||
@ -404,7 +413,7 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
accountId,
|
||||
'http://blob/url/file.zip',
|
||||
'file.zip',
|
||||
'01',
|
||||
'Uploaded',
|
||||
typistUserId,
|
||||
authorAuthorId ?? '',
|
||||
);
|
||||
@ -423,6 +432,10 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
);
|
||||
// ワークフロータイピストを作成
|
||||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||||
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000001');
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
|
||||
@ -546,6 +559,9 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
userGroupId, // ルーティング先のユーザーグループIDを設定
|
||||
);
|
||||
|
||||
// 初期値のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000000');
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
|
||||
@ -668,6 +684,9 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
userGroupId, // ルーティング先のユーザーグループIDを設定
|
||||
);
|
||||
|
||||
// 初期値のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000000');
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
|
||||
@ -736,6 +755,10 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
|
||||
// 初期値のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000000');
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
|
||||
@ -835,6 +858,9 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
);
|
||||
}
|
||||
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000003');
|
||||
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
const spy = jest
|
||||
.spyOn(service['sendGridService'], 'sendMail')
|
||||
@ -918,6 +944,9 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
);
|
||||
}
|
||||
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000003');
|
||||
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
// メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。
|
||||
const spy = jest
|
||||
@ -1004,6 +1033,9 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
);
|
||||
}
|
||||
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000004');
|
||||
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
// メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。
|
||||
const spy = jest
|
||||
@ -1095,6 +1127,9 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
);
|
||||
}
|
||||
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000004');
|
||||
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
// メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。
|
||||
const spy = jest
|
||||
@ -1361,7 +1396,7 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
accountId,
|
||||
`http://blob/url/file_${i}.zip`,
|
||||
`file_${i}.zip`,
|
||||
'01',
|
||||
'Uploaded',
|
||||
typistUserId,
|
||||
authorAuthorId ?? '',
|
||||
undefined,
|
||||
@ -1381,6 +1416,9 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
false,
|
||||
);
|
||||
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000010');
|
||||
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
@ -1487,7 +1525,7 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
accountId,
|
||||
`http://blob/url/file_${i}.zip`,
|
||||
`file_${i}.zip`,
|
||||
'01',
|
||||
'Uploaded',
|
||||
typistUserId,
|
||||
authorAuthorId ?? '',
|
||||
undefined,
|
||||
@ -1496,6 +1534,9 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
);
|
||||
}
|
||||
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000010');
|
||||
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
@ -1621,6 +1662,8 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
'Backup',
|
||||
false,
|
||||
);
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000010');
|
||||
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
@ -1747,6 +1790,8 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
'Backup',
|
||||
false,
|
||||
);
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '99999999');
|
||||
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
@ -1844,6 +1889,10 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
);
|
||||
// ワークフロータイピストを作成
|
||||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||||
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '99999999');
|
||||
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
|
||||
@ -1915,6 +1964,457 @@ describe('タスク作成から自動ルーティング(DB使用)', () => {
|
||||
expect(resultCheckoutPermission.length).toEqual(1);
|
||||
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
|
||||
});
|
||||
|
||||
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクが削除されている場合)', async () => {
|
||||
if (!source) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const {
|
||||
external_id: authorExternalId,
|
||||
id: authorUserId,
|
||||
author_id: authorAuthorId,
|
||||
} = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
const { id: typistUserId } = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'typist-user-external-id',
|
||||
role: 'typist',
|
||||
author_id: undefined,
|
||||
});
|
||||
// ワークタイプを作成
|
||||
const { id: worktypeId, custom_worktype_id } = await createWorktype(
|
||||
source,
|
||||
accountId,
|
||||
'worktypeId',
|
||||
);
|
||||
// テンプレートファイルを作成
|
||||
const { id: templateFileId } = await createTemplateFile(
|
||||
source,
|
||||
accountId,
|
||||
'templateFile',
|
||||
'http://blob/url/templateFile.zip',
|
||||
);
|
||||
// ワークフローを作成
|
||||
const { id: workflowId } = await createWorkflow(
|
||||
source,
|
||||
accountId,
|
||||
authorUserId,
|
||||
worktypeId,
|
||||
templateFileId,
|
||||
);
|
||||
// ワークフロータイピストを作成
|
||||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
|
||||
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
await createTask(
|
||||
source,
|
||||
accountId,
|
||||
`http://blob/url/file_${i}.zip`,
|
||||
`file_${i}.zip`,
|
||||
'Uploaded',
|
||||
typistUserId,
|
||||
authorAuthorId ?? '',
|
||||
undefined,
|
||||
undefined,
|
||||
i.toString().padStart(8, '0'),
|
||||
);
|
||||
}
|
||||
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000010');
|
||||
|
||||
{
|
||||
// 初期データ確認
|
||||
const tasks = await getTasks(source, accountId);
|
||||
expect(tasks.length).toEqual(10);
|
||||
const jobNumber = await getJobNumber(source, accountId);
|
||||
expect(jobNumber?.job_number).toEqual('00000010');
|
||||
}
|
||||
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
notificationParam,
|
||||
);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
const taskService = module.get<TasksService>(TasksService);
|
||||
const notificationHubService = module.get<NotificationhubService>(
|
||||
NotificationhubService,
|
||||
);
|
||||
|
||||
// 最新のジョブナンバーのタスクを取得
|
||||
const latestTask = await getTaskFromJobNumber(source, '00000010');
|
||||
await taskService.deleteTask(
|
||||
makeContext('trackingId', 'requestId'),
|
||||
authorExternalId,
|
||||
latestTask?.audio_file_id ?? 0, // 最新タスクのaudioFileId
|
||||
);
|
||||
|
||||
{
|
||||
// タスク削除確認
|
||||
const tasks = await getTasks(source, accountId);
|
||||
expect(tasks.length).toEqual(9);
|
||||
// JobNumberが00000010のタスクが存在しないことを確認
|
||||
expect(
|
||||
tasks.find((task) => task.job_number === '00000010'),
|
||||
).toBeUndefined();
|
||||
}
|
||||
|
||||
const result = await service.uploadFinished(
|
||||
makeContext('trackingId', 'requestId'),
|
||||
authorExternalId,
|
||||
'http://blob/url/file.zip',
|
||||
authorAuthorId ?? '',
|
||||
'file.zip',
|
||||
'11:22:33',
|
||||
'2023-05-26T11:22:33.444',
|
||||
'2023-05-26T11:22:33.444',
|
||||
'2023-05-26T11:22:33.444',
|
||||
256,
|
||||
'01',
|
||||
'DS2',
|
||||
'comment',
|
||||
custom_worktype_id,
|
||||
optionItemList,
|
||||
false,
|
||||
);
|
||||
expect(result.jobNumber).toEqual('00000011');
|
||||
// job_numberテーブルが正しく更新されているか確認
|
||||
const jobNumber = await getJobNumber(source, accountId);
|
||||
expect(jobNumber?.job_number).toEqual('00000011');
|
||||
|
||||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId', 'requestId'),
|
||||
[`user_${typistUserId}`],
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'file',
|
||||
priority: 'High',
|
||||
uploadedAt: '2023-05-26T11:22:33.444',
|
||||
},
|
||||
);
|
||||
// 作成したタスクを取得
|
||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||
// タスクのチェックアウト権限を取得
|
||||
const resultCheckoutPermission = await getCheckoutPermissions(
|
||||
source,
|
||||
resultTask?.id ?? 0,
|
||||
);
|
||||
// タスクのテンプレートファイルIDを確認
|
||||
expect(resultTask?.template_file_id).toEqual(templateFileId);
|
||||
// タスクのチェックアウト権限が想定通り(ワークフローで設定されている)のユーザーIDで作成されているか確認
|
||||
expect(resultCheckoutPermission.length).toEqual(1);
|
||||
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
|
||||
});
|
||||
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(途中のタスクが削除されている場合)', async () => {
|
||||
if (!source) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const {
|
||||
external_id: authorExternalId,
|
||||
id: authorUserId,
|
||||
author_id: authorAuthorId,
|
||||
} = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
const { id: typistUserId } = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'typist-user-external-id',
|
||||
role: 'typist',
|
||||
author_id: undefined,
|
||||
});
|
||||
// ワークタイプを作成
|
||||
const { id: worktypeId, custom_worktype_id } = await createWorktype(
|
||||
source,
|
||||
accountId,
|
||||
'worktypeId',
|
||||
);
|
||||
// テンプレートファイルを作成
|
||||
const { id: templateFileId } = await createTemplateFile(
|
||||
source,
|
||||
accountId,
|
||||
'templateFile',
|
||||
'http://blob/url/templateFile.zip',
|
||||
);
|
||||
// ワークフローを作成
|
||||
const { id: workflowId } = await createWorkflow(
|
||||
source,
|
||||
accountId,
|
||||
authorUserId,
|
||||
worktypeId,
|
||||
templateFileId,
|
||||
);
|
||||
// ワークフロータイピストを作成
|
||||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
|
||||
// タスクを10件作成, ジョブナンバーは00000001から00000010まで
|
||||
for (let i = 1; i <= 10; i++) {
|
||||
await createTask(
|
||||
source,
|
||||
accountId,
|
||||
`http://blob/url/file_${i}.zip`,
|
||||
`file_${i}.zip`,
|
||||
'Uploaded',
|
||||
typistUserId,
|
||||
authorAuthorId ?? '',
|
||||
undefined,
|
||||
undefined,
|
||||
i.toString().padStart(8, '0'),
|
||||
);
|
||||
}
|
||||
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '00000010');
|
||||
|
||||
{
|
||||
// 初期データ確認
|
||||
const tasks = await getTasks(source, accountId);
|
||||
expect(tasks.length).toEqual(10);
|
||||
const jobNumber = await getJobNumber(source, accountId);
|
||||
expect(jobNumber?.job_number).toEqual('00000010');
|
||||
}
|
||||
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
notificationParam,
|
||||
);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
const taskService = module.get<TasksService>(TasksService);
|
||||
const notificationHubService = module.get<NotificationhubService>(
|
||||
NotificationhubService,
|
||||
);
|
||||
|
||||
// 途中のジョブナンバーのタスクを取得
|
||||
const latestTask = await getTaskFromJobNumber(source, '00000005');
|
||||
await taskService.deleteTask(
|
||||
makeContext('trackingId', 'requestId'),
|
||||
authorExternalId,
|
||||
latestTask?.audio_file_id ?? 0, // 最新タスクのaudioFileId
|
||||
);
|
||||
|
||||
{
|
||||
// タスク削除確認
|
||||
const tasks = await getTasks(source, accountId);
|
||||
expect(tasks.length).toEqual(9);
|
||||
// JobNumberが00000005のタスクが存在しないことを確認
|
||||
expect(
|
||||
tasks.find((task) => task.job_number === '00000005'),
|
||||
).toBeUndefined();
|
||||
}
|
||||
|
||||
const result = await service.uploadFinished(
|
||||
makeContext('trackingId', 'requestId'),
|
||||
authorExternalId,
|
||||
'http://blob/url/file.zip',
|
||||
authorAuthorId ?? '',
|
||||
'file.zip',
|
||||
'11:22:33',
|
||||
'2023-05-26T11:22:33.444',
|
||||
'2023-05-26T11:22:33.444',
|
||||
'2023-05-26T11:22:33.444',
|
||||
256,
|
||||
'01',
|
||||
'DS2',
|
||||
'comment',
|
||||
custom_worktype_id,
|
||||
optionItemList,
|
||||
false,
|
||||
);
|
||||
expect(result.jobNumber).toEqual('00000011');
|
||||
// job_numberテーブルが正しく更新されているか確認
|
||||
const jobNumber = await getJobNumber(source, accountId);
|
||||
expect(jobNumber?.job_number).toEqual('00000011');
|
||||
|
||||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId', 'requestId'),
|
||||
[`user_${typistUserId}`],
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'file',
|
||||
priority: 'High',
|
||||
uploadedAt: '2023-05-26T11:22:33.444',
|
||||
},
|
||||
);
|
||||
// 作成したタスクを取得
|
||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||
// タスクのチェックアウト権限を取得
|
||||
const resultCheckoutPermission = await getCheckoutPermissions(
|
||||
source,
|
||||
resultTask?.id ?? 0,
|
||||
);
|
||||
// タスクのテンプレートファイルIDを確認
|
||||
expect(resultTask?.template_file_id).toEqual(templateFileId);
|
||||
// タスクのチェックアウト権限が想定通り(ワークフローで設定されている)のユーザーIDで作成されているか確認
|
||||
expect(resultCheckoutPermission.length).toEqual(1);
|
||||
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
|
||||
});
|
||||
it('タスク作成時に採番されるジョブナンバーが常に最新タスクのジョブナンバー + 1となる(最新タスクのジョブナンバーが99999999で削除されている場合)', async () => {
|
||||
if (!source) fail();
|
||||
const { id: accountId } = await makeTestSimpleAccount(source);
|
||||
const {
|
||||
external_id: authorExternalId,
|
||||
id: authorUserId,
|
||||
author_id: authorAuthorId,
|
||||
} = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'author-user-external-id',
|
||||
role: 'author',
|
||||
author_id: 'AUTHOR_ID',
|
||||
});
|
||||
const { id: typistUserId } = await makeTestUser(source, {
|
||||
account_id: accountId,
|
||||
external_id: 'typist-user-external-id',
|
||||
role: 'typist',
|
||||
author_id: undefined,
|
||||
});
|
||||
// ワークタイプを作成
|
||||
const { id: worktypeId, custom_worktype_id } = await createWorktype(
|
||||
source,
|
||||
accountId,
|
||||
'worktypeId',
|
||||
);
|
||||
// テンプレートファイルを作成
|
||||
const { id: templateFileId } = await createTemplateFile(
|
||||
source,
|
||||
accountId,
|
||||
'templateFile',
|
||||
'http://blob/url/templateFile.zip',
|
||||
);
|
||||
// ワークフローを作成
|
||||
const { id: workflowId } = await createWorkflow(
|
||||
source,
|
||||
accountId,
|
||||
authorUserId,
|
||||
worktypeId,
|
||||
templateFileId,
|
||||
);
|
||||
// ワークフロータイピストを作成
|
||||
await createWorkflowTypist(source, workflowId, typistUserId);
|
||||
const blobParam = makeBlobstorageServiceMockValue();
|
||||
const notificationParam = makeDefaultNotificationhubServiceMockValue();
|
||||
|
||||
// タスクを10件作成, ジョブナンバーは99999989から99999999まで
|
||||
for (let i = 99999989; i <= 99999999; i++) {
|
||||
await createTask(
|
||||
source,
|
||||
accountId,
|
||||
`http://blob/url/file_${i}.zip`,
|
||||
`file_${i}.zip`,
|
||||
'Uploaded',
|
||||
typistUserId,
|
||||
authorAuthorId ?? '',
|
||||
undefined,
|
||||
undefined,
|
||||
i.toString().padStart(8, '0'),
|
||||
);
|
||||
}
|
||||
|
||||
// 最新のジョブナンバーでjob_numberテーブルを作成
|
||||
await createJobNumber(source, accountId, '99999999');
|
||||
|
||||
{
|
||||
// 初期データ確認
|
||||
const tasks = await getTasks(source, accountId);
|
||||
expect(tasks.length).toEqual(11);
|
||||
const jobNumber = await getJobNumber(source, accountId);
|
||||
expect(jobNumber?.job_number).toEqual('99999999');
|
||||
}
|
||||
|
||||
|
||||
|
||||
const module = await makeTestingModuleWithBlobAndNotification(
|
||||
source,
|
||||
blobParam,
|
||||
notificationParam,
|
||||
);
|
||||
if (!module) fail();
|
||||
const service = module.get<FilesService>(FilesService);
|
||||
const taskService = module.get<TasksService>(TasksService);
|
||||
const notificationHubService = module.get<NotificationhubService>(
|
||||
NotificationhubService,
|
||||
);
|
||||
|
||||
// 最新のジョブナンバーのタスクを取得
|
||||
const latestTask = await getTaskFromJobNumber(source, '99999999');
|
||||
await taskService.deleteTask(
|
||||
makeContext('trackingId', 'requestId'),
|
||||
authorExternalId,
|
||||
latestTask?.audio_file_id ?? 0, // 最新タスクのaudioFileId
|
||||
);
|
||||
|
||||
{
|
||||
// タスク削除確認
|
||||
const tasks = await getTasks(source, accountId);
|
||||
expect(tasks.length).toEqual(10);
|
||||
// JobNumberが99999999のタスクが存在しないことを確認
|
||||
expect(
|
||||
tasks.find((task) => task.job_number === '99999999'),
|
||||
).toBeUndefined();
|
||||
}
|
||||
|
||||
const result = await service.uploadFinished(
|
||||
makeContext('trackingId', 'requestId'),
|
||||
authorExternalId,
|
||||
'http://blob/url/file.zip',
|
||||
authorAuthorId ?? '',
|
||||
'file.zip',
|
||||
'11:22:33',
|
||||
'2023-05-26T11:22:33.444',
|
||||
'2023-05-26T11:22:33.444',
|
||||
'2023-05-26T11:22:33.444',
|
||||
256,
|
||||
'01',
|
||||
'DS2',
|
||||
'comment',
|
||||
custom_worktype_id,
|
||||
optionItemList,
|
||||
false,
|
||||
);
|
||||
expect(result.jobNumber).toEqual('00000001');
|
||||
// job_numberテーブルが正しく更新されているか確認
|
||||
// 最新タスクのジョブナンバーが99999999の時、新規作成されたタスクのジョブナンバーは00000001になる
|
||||
const jobNumber = await getJobNumber(source, accountId);
|
||||
expect(jobNumber?.job_number).toEqual('00000001');
|
||||
|
||||
// 通知処理が想定通りの引数で呼ばれているか確認
|
||||
expect(notificationHubService.notify).toHaveBeenCalledWith(
|
||||
makeContext('trackingId', 'requestId'),
|
||||
[`user_${typistUserId}`],
|
||||
{
|
||||
authorId: 'AUTHOR_ID',
|
||||
filename: 'file',
|
||||
priority: 'High',
|
||||
uploadedAt: '2023-05-26T11:22:33.444',
|
||||
},
|
||||
);
|
||||
// 作成したタスクを取得
|
||||
const resultTask = await getTaskFromJobNumber(source, result.jobNumber);
|
||||
// タスクのチェックアウト権限を取得
|
||||
const resultCheckoutPermission = await getCheckoutPermissions(
|
||||
source,
|
||||
resultTask?.id ?? 0,
|
||||
);
|
||||
// タスクのテンプレートファイルIDを確認
|
||||
expect(resultTask?.template_file_id).toEqual(templateFileId);
|
||||
// タスクのチェックアウト権限が想定通り(ワークフローで設定されている)のユーザーIDで作成されているか確認
|
||||
expect(resultCheckoutPermission.length).toEqual(1);
|
||||
expect(resultCheckoutPermission[0].user_id).toEqual(typistUserId);
|
||||
});
|
||||
});
|
||||
|
||||
describe('音声ファイルダウンロードURL取得', () => {
|
||||
|
||||
@ -44,6 +44,7 @@ import {
|
||||
import { UserGroup } from '../../../repositories/user_groups/entity/user_group.entity';
|
||||
import { UserGroupMember } from '../../../repositories/user_groups/entity/user_group_member.entity';
|
||||
import { License } from '../../../repositories/licenses/entity/license.entity';
|
||||
import { JobNumber } from '../../../repositories/job_number/entity/job_number.entity';
|
||||
|
||||
export const createTask = async (
|
||||
datasource: DataSource,
|
||||
@ -109,6 +110,18 @@ export const createTask = async (
|
||||
return { audioFileId: audioFile.id, taskId: task.id };
|
||||
};
|
||||
|
||||
// job_numberテーブルにレコードを作成する
|
||||
export const createJobNumber = async (
|
||||
datasource: DataSource,
|
||||
accountId: number,
|
||||
jobNumber: string,
|
||||
): Promise<void> => {
|
||||
await datasource.getRepository(JobNumber).insert({
|
||||
account_id: accountId,
|
||||
job_number: jobNumber,
|
||||
});
|
||||
};
|
||||
|
||||
export const getTaskFromJobNumber = async (
|
||||
datasource: DataSource,
|
||||
jobNumber: string,
|
||||
|
||||
@ -263,15 +263,6 @@ export const getTask = async (
|
||||
return task;
|
||||
};
|
||||
|
||||
export const getTasks = async (
|
||||
datasource: DataSource,
|
||||
account_id: number,
|
||||
): Promise<Task[]> => {
|
||||
const tasks = await datasource.getRepository(Task).find({
|
||||
where: { account_id: account_id },
|
||||
});
|
||||
return tasks;
|
||||
};
|
||||
|
||||
export const getCheckoutPermissions = async (
|
||||
datasource: DataSource,
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
getTemplateFiles,
|
||||
updateTaskTemplateFile,
|
||||
} from './test/utility';
|
||||
import { makeTestAccount, makeTestUser } from '../../common/test/utility';
|
||||
import { getTasks, makeTestAccount, makeTestUser } from '../../common/test/utility';
|
||||
import { makeContext } from '../../common/log';
|
||||
import { TemplateFilesRepositoryService } from '../../repositories/template_files/template_files.repository.service';
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
@ -14,7 +14,7 @@ import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { truncateAllTable } from '../../common/test/init';
|
||||
import { overrideBlobstorageService } from '../../common/test/overrides';
|
||||
import { TASK_STATUS, USER_ROLES } from '../../constants';
|
||||
import { createTask, getTasks } from '../tasks/test/utility';
|
||||
import { createTask } from '../tasks/test/utility';
|
||||
import {
|
||||
createWorkflow,
|
||||
createWorkflowTypist,
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
import {
|
||||
Entity,
|
||||
Column,
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
} from 'typeorm';
|
||||
import { bigintTransformer } from '../../../common/entity';
|
||||
|
||||
@Entity({ name: 'job_number' })
|
||||
export class JobNumber {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({ type: 'bigint', transformer: bigintTransformer })
|
||||
account_id: number;
|
||||
|
||||
@Column()
|
||||
job_number: string;
|
||||
|
||||
@UpdateDateColumn({
|
||||
default: () => "datetime('now', 'localtime')",
|
||||
type: 'datetime',
|
||||
}) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||
updated_at: Date;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { JobNumber } from './entity/job_number.entity';
|
||||
import { JobNumberRepositoryService } from './job_number.repository.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([JobNumber])],
|
||||
providers: [JobNumberRepositoryService],
|
||||
exports: [JobNumberRepositoryService],
|
||||
})
|
||||
export class JobNumberRepositoryModule {}
|
||||
@ -0,0 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class JobNumberRepositoryService {
|
||||
constructor(private dataSource: DataSource) {}
|
||||
}
|
||||
@ -54,6 +54,7 @@ import {
|
||||
} from '../../common/repository';
|
||||
import { Context } from '../../common/log';
|
||||
import { UserNotFoundError } from '../users/errors/types';
|
||||
import { JobNumber } from '../job_number/entity/job_number.entity';
|
||||
|
||||
@Injectable()
|
||||
export class TasksRepositoryService {
|
||||
@ -905,25 +906,29 @@ export class TasksRepositoryService {
|
||||
|
||||
const taskRepo = entityManager.getRepository(Task);
|
||||
|
||||
// バグ 3954: [4/8リリース]タスクをすべてBackupした後、タスクを作成するとジョブナンバーが1から採番される(暫定対応)
|
||||
// アカウント内で最新タスクのタスクを取得し、そのJOBナンバーをインクリメントして新しいタスクのJOBナンバーを設定する
|
||||
const lastTask = await taskRepo.findOne({
|
||||
// バグ 3954: [4/8リリース]タスクをすべてBackupした後、タスクを作成するとジョブナンバーが1から採番される(恒久対応)
|
||||
// job_numberテーブルから最新のJOBナンバーを取得
|
||||
const jobNumberRepo = entityManager.getRepository(JobNumber);
|
||||
const currentJobNumberData = await jobNumberRepo.findOne({
|
||||
where: { account_id: account_id },
|
||||
order: { created_at: 'DESC', job_number: 'DESC' },
|
||||
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
|
||||
lock: { mode: 'pessimistic_write' },
|
||||
});
|
||||
// JOBナンバーが存在しない場合はエラー
|
||||
// 運用上はあり得ないが、プログラム上発生しうるのでエラーとして処理
|
||||
if (!currentJobNumberData) {
|
||||
throw new Error(`JobNumber not exists. account_id:${account_id}`);
|
||||
}
|
||||
|
||||
let newJobNumber = '00000001';
|
||||
if (!lastTask) {
|
||||
// 初回は00000001
|
||||
newJobNumber = '00000001';
|
||||
} else if (lastTask.job_number === '99999999') {
|
||||
let newJobNumber: string = '';
|
||||
if (currentJobNumberData.job_number === '99999999') {
|
||||
// 末尾なら00000001に戻る
|
||||
newJobNumber = '00000001';
|
||||
} else {
|
||||
// 最新のJOBナンバーをインクリメントして次の番号とする
|
||||
newJobNumber = `${Number(lastTask.job_number) + 1}`.padStart(8, '0');
|
||||
newJobNumber = `${
|
||||
Number(currentJobNumberData.job_number) + 1
|
||||
}`.padStart(8, '0');
|
||||
}
|
||||
task.job_number = newJobNumber;
|
||||
|
||||
@ -935,6 +940,15 @@ export class TasksRepositoryService {
|
||||
context,
|
||||
);
|
||||
|
||||
// JobNumberを更新
|
||||
await updateEntity(
|
||||
jobNumberRepo,
|
||||
{ account_id: account_id },
|
||||
{ job_number: newJobNumber },
|
||||
this.isCommentOut,
|
||||
context,
|
||||
);
|
||||
|
||||
const optionItems = paramOptionItems.map((x) => {
|
||||
return {
|
||||
audio_file_id: persisted.audio_file_id,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user