Merge branch 'develop' into ccb

This commit is contained in:
makabe 2024-02-05 16:36:09 +09:00
commit 8e159a1c2a
10 changed files with 165 additions and 64 deletions

View File

@ -191,6 +191,7 @@ const AccountPage: React.FC = (): JSX.Element => {
)} )}
</dt> </dt>
{isTier5 && ( {isTier5 && (
<>
<dd> <dd>
{/* eslint-disable-next-line jsx-a11y/label-has-associated-control */} {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
<label> <label>
@ -208,6 +209,14 @@ const AccountPage: React.FC = (): JSX.Element => {
/> />
</label> </label>
</dd> </dd>
<dd className={`${styles.full} ${styles.formComment}`}>
{t(
getTranslationID(
"accountPage.text.dealerManagementAnnotation"
)
)}
</dd>
</>
)} )}
{!isTier5 && <dd>-</dd>} {!isTier5 && <dd>-</dd>}
</dl> </dl>
@ -374,6 +383,15 @@ const AccountPage: React.FC = (): JSX.Element => {
className={styles.icLoading} className={styles.icLoading}
alt="Loading" alt="Loading"
/> />
{isTier5 && (
<p className={styles.formComment}>
{t(
getTranslationID(
"accountPage.text.dealerManagementAnnotation"
)
)}
</p>
)}
</div> </div>
</div> </div>
{isTier5 && ( {isTier5 && (

View File

@ -1632,8 +1632,31 @@ _:-ms-lang(x)::-ms-backdrop,
.account .listVertical dd .formInput { .account .listVertical dd .formInput {
max-width: 100%; max-width: 100%;
} }
.account .listVertical dd.full {
width: 100%;
padding-top: 0;
background: none;
}
.account .listVertical dd.full.odd {
background: #f5f5f5;
}
.account .listVertical dd.formComment {
text-align: left;
font-size: 0.9rem;
word-break: break-word;
}
.account .box100 .formComment {
display: block;
width: 600px;
text-align: left;
}
.account .box100.alignRight { .account .box100.alignRight {
width: calc(1200px + 3rem); width: calc(1200px + 3rem);
text-align: right;
}
.account .box100.alignRight .formComment {
margin-left: 648px;
text-align: right;
} }
.menuAction { .menuAction {
@ -2306,7 +2329,8 @@ tr.isSelected .menuInTable li a.isDisable {
} }
.formChange ul.chooseMember li input + label:hover, .formChange ul.chooseMember li input + label:hover,
.formChange ul.holdMember li input + label:hover { .formChange ul.holdMember li input + label:hover {
background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left center; background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left
center;
background-size: 1.3rem; background-size: 1.3rem;
} }
.formChange ul.chooseMember li input:checked + label, .formChange ul.chooseMember li input:checked + label,
@ -2317,8 +2341,8 @@ tr.isSelected .menuInTable li a.isDisable {
} }
.formChange ul.chooseMember li input:checked + label:hover, .formChange ul.chooseMember li input:checked + label:hover,
.formChange ul.holdMember li input:checked + label:hover { .formChange ul.holdMember li input:checked + label:hover {
background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat right background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat
center; right center;
background-size: 1.3rem; background-size: 1.3rem;
} }
.formChange > p { .formChange > p {
@ -2471,7 +2495,8 @@ tr.isSelected .menuInTable li a.isDisable {
} }
.formChange ul.chooseMember li input + label:hover, .formChange ul.chooseMember li input + label:hover,
.formChange ul.holdMember li input + label:hover { .formChange ul.holdMember li input + label:hover {
background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left center; background: #e6e6e6 url(../assets/images/arrow_circle_left.svg) no-repeat left
center;
background-size: 1.3rem; background-size: 1.3rem;
} }
.formChange ul.chooseMember li input:checked + label, .formChange ul.chooseMember li input:checked + label,
@ -2482,8 +2507,8 @@ tr.isSelected .menuInTable li a.isDisable {
} }
.formChange ul.chooseMember li input:checked + label:hover, .formChange ul.chooseMember li input:checked + label:hover,
.formChange ul.holdMember li input:checked + label:hover { .formChange ul.holdMember li input:checked + label:hover {
background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat right background: #e6e6e6 url(../assets/images/arrow_circle_right.svg) no-repeat
center; right center;
background-size: 1.3rem; background-size: 1.3rem;
} }
.formChange > p { .formChange > p {

View File

@ -107,6 +107,7 @@ declare const classNames: {
readonly clm0: "clm0"; readonly clm0: "clm0";
readonly menuInTable: "menuInTable"; readonly menuInTable: "menuInTable";
readonly isSelected: "isSelected"; readonly isSelected: "isSelected";
readonly odd: "odd";
readonly alignRight: "alignRight"; readonly alignRight: "alignRight";
readonly menuAction: "menuAction"; readonly menuAction: "menuAction";
readonly inTable: "inTable"; readonly inTable: "inTable";

View File

@ -0,0 +1,27 @@
-- +migrate Up
ALTER TABLE `tasks` ADD INDEX `idx_tasks_audio_file_id` (audio_file_id);
ALTER TABLE `tasks` ADD INDEX `idx_tasks_status` (status);
ALTER TABLE `tasks` ADD INDEX `idx_tasks_typist_user_id` (typist_user_id);
ALTER TABLE `tasks` ADD INDEX `idx_tasks_is_job_number_enabled` (is_job_number_enabled);
ALTER TABLE `checkout_permission` ADD INDEX `idx_checkout_permission_task_id` (task_id);
ALTER TABLE `checkout_permission` ADD INDEX `idx_checkout_permission_user_group_id` (user_group_id);
ALTER TABLE `checkout_permission` ADD INDEX `idx_checkout_permission_user_id` (user_id);
ALTER TABLE `users` ADD INDEX `idx_users_role` (role);
ALTER TABLE `users` ADD INDEX `idx_users_author_id` (author_id);
ALTER TABLE `users` ADD INDEX `idx_users_deleted_at` (deleted_at);
ALTER TABLE `worktypes` ADD INDEX `idx_worktypes_custom_worktype_id` (custom_worktype_id);
ALTER TABLE `workflows` ADD INDEX `idx_workflows_account_id` (account_id);
-- +migrate Down
ALTER TABLE `tasks` DROP INDEX `idx_tasks_audio_file_id`;
ALTER TABLE `tasks` DROP INDEX `idx_tasks_status`;
ALTER TABLE `tasks` DROP INDEX `idx_tasks_typist_user_id`;
ALTER TABLE `tasks` DROP INDEX `idx_tasks_is_job_number_enabled`;
ALTER TABLE `checkout_permission` DROP INDEX `idx_checkout_permission_task_id`;
ALTER TABLE `checkout_permission` DROP INDEX `idx_checkout_permission_user_group_id`;
ALTER TABLE `checkout_permission` DROP INDEX `idx_checkout_permission_user_id`;
ALTER TABLE `users` DROP INDEX `idx_users_role`;
ALTER TABLE `users` DROP INDEX `idx_users_author_id`;
ALTER TABLE `users` DROP INDEX `idx_users_deleted_at`;
ALTER TABLE `worktypes` DROP INDEX `idx_worktypes_custom_worktype_id`;
ALTER TABLE `workflows` DROP INDEX `idx_workflows_account_id`;

View File

@ -194,6 +194,7 @@ export class TasksRepositoryService {
audio_file_id: audio_file_id, audio_file_id: audio_file_id,
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
if (!task) { if (!task) {
throw new TasksNotFoundError( throw new TasksNotFoundError(
@ -209,6 +210,7 @@ export class TasksRepositoryService {
typist_user_id: user_id, typist_user_id: user_id,
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
if (tasks.length > 0) { if (tasks.length > 0) {
@ -247,6 +249,7 @@ export class TasksRepositoryService {
}, },
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
// ユーザーの所属するすべてのグループIDを列挙 // ユーザーの所属するすべてのグループIDを列挙
const groupIds = groups.map((member) => member.user_group_id); const groupIds = groups.map((member) => member.user_group_id);
@ -269,6 +272,7 @@ export class TasksRepositoryService {
}, },
], ],
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
//チェックアウト権限がなければエラー //チェックアウト権限がなければエラー
@ -339,6 +343,7 @@ export class TasksRepositoryService {
audio_file_id: audio_file_id, audio_file_id: audio_file_id,
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
if (!task) { if (!task) {
throw new TasksNotFoundError( throw new TasksNotFoundError(
@ -392,6 +397,7 @@ export class TasksRepositoryService {
audio_file_id: audio_file_id, audio_file_id: audio_file_id,
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
if (!task) { if (!task) {
throw new TasksNotFoundError( throw new TasksNotFoundError(
@ -467,6 +473,7 @@ export class TasksRepositoryService {
audio_file_id: audio_file_id, audio_file_id: audio_file_id,
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
if (!task) { if (!task) {
throw new TasksNotFoundError( throw new TasksNotFoundError(
@ -518,6 +525,7 @@ export class TasksRepositoryService {
audio_file_id: audio_file_id, audio_file_id: audio_file_id,
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
if (!task) { if (!task) {
throw new TasksNotFoundError( throw new TasksNotFoundError(
@ -901,6 +909,7 @@ export class TasksRepositoryService {
where: { account_id: account_id, is_job_number_enabled: true }, where: { account_id: account_id, is_job_number_enabled: true },
order: { created_at: 'DESC', job_number: 'DESC' }, order: { created_at: 'DESC', job_number: 'DESC' },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
let newJobNumber = '00000001'; let newJobNumber = '00000001';
@ -963,30 +972,6 @@ export class TasksRepositoryService {
assignees: Assignee[], assignees: Assignee[],
): Promise<void> { ): Promise<void> {
await this.dataSource.transaction(async (entityManager) => { await this.dataSource.transaction(async (entityManager) => {
// UserGroupの取得/存在確認
const userGroupIds = assignees
.filter((x) => x.typistGroupId !== undefined)
.map((y) => {
return y.typistGroupId;
});
const groupRepo = entityManager.getRepository(UserGroup);
const groupRecords = await groupRepo.find({
where: {
id: In(userGroupIds),
account_id: account_id,
deleted_at: IsNull(),
},
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
});
// idはユニークであるため取得件数の一致でグループの存在を確認
if (userGroupIds.length !== groupRecords.length) {
throw new TypistUserGroupNotFoundError(
`Group not exists Error. reqUserGroupId:${userGroupIds}; resUserGroupId:${groupRecords.map(
(x) => x.id,
)}`,
);
}
// Userの取得/存在確認 // Userの取得/存在確認
const typistUserIds = assignees const typistUserIds = assignees
.filter((x) => x.typistUserId !== undefined) .filter((x) => x.typistUserId !== undefined)
@ -1014,6 +999,31 @@ export class TasksRepositoryService {
); );
} }
// UserGroupの取得/存在確認
const userGroupIds = assignees
.filter((x) => x.typistGroupId !== undefined)
.map((y) => {
return y.typistGroupId;
});
const groupRepo = entityManager.getRepository(UserGroup);
const groupRecords = await groupRepo.find({
where: {
id: In(userGroupIds),
account_id: account_id,
deleted_at: IsNull(),
},
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
});
// idはユニークであるため取得件数の一致でグループの存在を確認
if (userGroupIds.length !== groupRecords.length) {
throw new TypistUserGroupNotFoundError(
`Group not exists Error. reqUserGroupId:${userGroupIds}; resUserGroupId:${groupRecords.map(
(x) => x.id,
)}`,
);
}
// 引数audioFileIdを使ってTaskレコードを特定し、そのステータスを取得/存在確認 // 引数audioFileIdを使ってTaskレコードを特定し、そのステータスを取得/存在確認
const taskRepo = entityManager.getRepository(Task); const taskRepo = entityManager.getRepository(Task);
@ -1029,6 +1039,7 @@ export class TasksRepositoryService {
}, },
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
//タスクが存在しない or ステータスがUploadedでなければエラー //タスクが存在しない or ステータスがUploadedでなければエラー
if (!taskRecord) { if (!taskRecord) {
@ -1192,39 +1203,51 @@ export class TasksRepositoryService {
return await this.dataSource.transaction(async (entityManager) => { return await this.dataSource.transaction(async (entityManager) => {
// 音声ファイルを取得 // 音声ファイルを取得
const audioFileRepo = entityManager.getRepository(AudioFile); const audioFileRepo = entityManager.getRepository(AudioFile);
const audioFile = await audioFileRepo.findOne({ const audio = await audioFileRepo.findOne({
relations: {
task: true,
},
where: { where: {
id: audioFileId, id: audioFileId,
account_id: accountId, account_id: accountId,
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
}); });
if (!audioFile) { if (!audio) {
throw new Error( throw new Error(
`audio file not found. audio_file_id:${audioFileId}, accountId:${accountId}`, `audio file not found. audio_file_id:${audioFileId}, accountId:${accountId}`,
); );
} }
const { task } = audioFile;
if (!task) {
throw new Error(
`task not found. audio_file_id:${audioFileId}, accountId:${accountId}`,
);
}
// authorIdをもとにユーザーを取得 // authorIdをもとにユーザーを取得
const userRepo = entityManager.getRepository(User); const userRepo = entityManager.getRepository(User);
const authorUser = await userRepo.findOne({ const authorUser = await userRepo.findOne({
where: { where: {
author_id: audioFile.author_id, author_id: audio.author_id,
account_id: accountId, account_id: accountId,
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
// TaskとFileを取得
const taskRepo = entityManager.getRepository(Task);
const task = await taskRepo.findOne({
relations: {
file: true,
},
where: {
account_id: accountId,
audio_file_id: audioFileId,
},
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
});
const audioFile = task?.file;
if (!audioFile) {
throw new Error(
`audio file not found. audio_file_id:${audioFileId}, accountId:${accountId}`,
);
}
// 音声ファイル上のworktypeIdをもとにworktypeを取得 // 音声ファイル上のworktypeIdをもとにworktypeを取得
const worktypeRepo = entityManager.getRepository(Worktype); const worktypeRepo = entityManager.getRepository(Worktype);
const worktypeRecord = await worktypeRepo.findOne({ const worktypeRecord = await worktypeRepo.findOne({
@ -1233,6 +1256,7 @@ export class TasksRepositoryService {
account_id: accountId, account_id: accountId,
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
// 音声ファイル上のworktypeIdが設定されているが、一致するworktypeが存在しない場合はエラーを出して終了 // 音声ファイル上のworktypeIdが設定されているが、一致するworktypeが存在しない場合はエラーを出して終了
@ -1254,6 +1278,7 @@ export class TasksRepositoryService {
worktype_id: worktypeRecord?.id ?? IsNull(), worktype_id: worktypeRecord?.id ?? IsNull(),
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
// Workflowルーティングルールがあればタスクのチェックアウト権限を設定する // Workflowルーティングルールがあればタスクのチェックアウト権限を設定する
@ -1281,6 +1306,7 @@ export class TasksRepositoryService {
account_id: accountId, account_id: accountId,
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
if (!myAuthorUser) { if (!myAuthorUser) {
throw new Error( throw new Error(
@ -1297,6 +1323,7 @@ export class TasksRepositoryService {
worktype_id: worktypeRecord?.id ?? IsNull(), worktype_id: worktypeRecord?.id ?? IsNull(),
}, },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
// API実行者のAuthorIdと音声ファイルのWorktypeをもとにルーティングルールを取得できない場合はエラーを出して終了 // API実行者のAuthorIdと音声ファイルのWorktypeをもとにルーティングルールを取得できない場合はエラーを出して終了
@ -1478,6 +1505,7 @@ export class TasksRepositoryService {
const typistUsers = await userRepo.find({ const typistUsers = await userRepo.find({
where: { account_id: accountId, id: In(typistIds) }, where: { account_id: accountId, id: In(typistIds) },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
if (typistUsers.length !== typistIds.length) { if (typistUsers.length !== typistIds.length) {
throw new Error(`typist not found. ids: ${typistIds}`); throw new Error(`typist not found. ids: ${typistIds}`);
@ -1491,6 +1519,7 @@ export class TasksRepositoryService {
const typistGroups = await userGroupRepo.find({ const typistGroups = await userGroupRepo.find({
where: { account_id: accountId, id: In(groupIds) }, where: { account_id: accountId, id: In(groupIds) },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
if (typistGroups.length !== groupIds.length) { if (typistGroups.length !== groupIds.length) {
throw new Error(`typist group not found. ids: ${groupIds}`); throw new Error(`typist group not found. ids: ${groupIds}`);

View File

@ -220,6 +220,7 @@ export class WorktypesRepositoryService {
const worktype = await worktypeRepo.findOne({ const worktype = await worktypeRepo.findOne({
where: { account_id: accountId, id: id }, where: { account_id: accountId, id: id },
comment: `${context.getTrackingId()}_${new Date().toUTCString()}`, comment: `${context.getTrackingId()}_${new Date().toUTCString()}`,
lock: { mode: 'pessimistic_write' },
}); });
// ワークタイプが存在しない場合はエラー // ワークタイプが存在しない場合はエラー
if (!worktype) { if (!worktype) {