Merged PR 375: API実装(ワークタイプID追加API)
## 概要 [Task2516: API実装(ワークタイプID追加API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2516) - ワークタイプ追加APIとテストを実装しました。 - オプションアイテムも一緒に追加されるように実装しています。 - ワークタイプの制限のためにカスタムバリデータを実装しています。 ## レビューポイント - 追加時のエラー処理は適切か - バリデータは適切か ## UIの変更 - なし ## 動作確認状況 - ローカルで確認
This commit is contained in:
parent
60269306c5
commit
0b7d979fae
@ -41,6 +41,7 @@ import { UserGroupsRepositoryModule } from './repositories/user_groups/user_grou
|
||||
import { SortCriteriaRepositoryModule } from './repositories/sort_criteria/sort_criteria.repository.module';
|
||||
import { TemplateFilesRepositoryModule } from './repositories/template_files/template_files.repository.module';
|
||||
import { WorktypesRepositoryModule } from './repositories/worktypes/worktypes.repository.module';
|
||||
import { OptionItemsRepositoryModule } from './repositories/option_items/option_items.repository.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -96,6 +97,7 @@ import { WorktypesRepositoryModule } from './repositories/worktypes/worktypes.re
|
||||
AuthGuardsModule,
|
||||
SortCriteriaRepositoryModule,
|
||||
WorktypesRepositoryModule,
|
||||
OptionItemsRepositoryModule,
|
||||
],
|
||||
controllers: [
|
||||
HealthController,
|
||||
|
||||
@ -49,4 +49,6 @@ export const ErrorCodes = [
|
||||
'E010807', // ライセンス割り当て解除済みエラー
|
||||
'E010808', // ライセンス注文キャンセル不可エラー
|
||||
'E010908', // タイピストグループ不在エラー
|
||||
'E011001', // ワークタイプ重複エラー
|
||||
'E011002', // ワークタイプ登録上限超過エラー
|
||||
] as const;
|
||||
|
||||
@ -38,4 +38,6 @@ export const errors: Errors = {
|
||||
E010807: 'License is already deallocated Error',
|
||||
E010808: 'Order cancel failed Error',
|
||||
E010908: 'Typist Group not exist Error',
|
||||
E011001: 'Thiw WorkTypeID already used Error',
|
||||
E011002: 'WorkTypeID create limit exceeded Error',
|
||||
};
|
||||
|
||||
@ -30,6 +30,7 @@ import { NotificationhubService } from '../../gateways/notificationhub/notificat
|
||||
import { FilesService } from '../../features/files/files.service';
|
||||
import { LicensesService } from '../../features/licenses/licenses.service';
|
||||
import { TasksService } from '../../features/tasks/tasks.service';
|
||||
import { OptionItemsRepositoryModule } from '../../repositories/option_items/option_items.repository.module';
|
||||
|
||||
export const makeTestingModule = async (
|
||||
datasource: DataSource,
|
||||
@ -65,6 +66,7 @@ export const makeTestingModule = async (
|
||||
AuthGuardsModule,
|
||||
SortCriteriaRepositoryModule,
|
||||
WorktypesRepositoryModule,
|
||||
OptionItemsRepositoryModule,
|
||||
],
|
||||
providers: [
|
||||
AuthService,
|
||||
|
||||
50
dictation_server/src/common/validators/worktype.validator.ts
Normal file
50
dictation_server/src/common/validators/worktype.validator.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import {
|
||||
ValidatorConstraint,
|
||||
ValidatorConstraintInterface,
|
||||
ValidationArguments,
|
||||
ValidationOptions,
|
||||
registerDecorator,
|
||||
} from 'class-validator';
|
||||
|
||||
@ValidatorConstraint()
|
||||
export class IsWorktypeIdCharacters implements ValidatorConstraintInterface {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
validate(value: string) {
|
||||
// 正規表現でWorktypeIDのチェックを行う
|
||||
// 以下の禁則文字を除く半角英数記号
|
||||
// \ (backslash)
|
||||
// / (forward slash)
|
||||
// : (colon)
|
||||
// * (asterisk)
|
||||
// ? (question mark)
|
||||
// " (double quotation mark)
|
||||
// < (less-than symbol)
|
||||
// > (greater-than symbol)
|
||||
// | (vertical bar)
|
||||
// . (period)
|
||||
const regex =
|
||||
/^(?!.*\\)(?!.*\/)(?!.*:)(?!.*\*)(?!.*\?)(?!.*")(?!.*<)(?!.*>)(?!.*\|)(?!.*\.)[ -~]+$/;
|
||||
return regex.test(value);
|
||||
}
|
||||
|
||||
defaultMessage(args: ValidationArguments) {
|
||||
return `WorktypeID rule not satisfied`;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* WorktypeIDで使用できる文字列かをチェックする
|
||||
* @param [validationOptions]
|
||||
* @returns
|
||||
*/
|
||||
export function IsWorktypeId(validationOptions?: ValidationOptions) {
|
||||
return function (object: object, propertyName: string) {
|
||||
registerDecorator({
|
||||
name: 'IsWorktypeId',
|
||||
target: object.constructor,
|
||||
propertyName: propertyName,
|
||||
constraints: [],
|
||||
options: validationOptions,
|
||||
validator: IsWorktypeIdCharacters,
|
||||
});
|
||||
};
|
||||
}
|
||||
@ -223,3 +223,18 @@ export const TRIAL_LICENSE_EXPIRATION_DAYS = 30;
|
||||
* @const {number}
|
||||
*/
|
||||
export const TRIAL_LICENSE_ISSUE_NUM = 100;
|
||||
|
||||
/**
|
||||
* worktypeの最大登録数
|
||||
* @const {number}
|
||||
*/
|
||||
export const WORKTYPE_MAX_COUNT = 20;
|
||||
|
||||
/**
|
||||
* worktypeのDefault値の取りうる値
|
||||
**/
|
||||
export const OPTION_ITEM_VALUE_TYPE = {
|
||||
DEFAULT: 'Default',
|
||||
BLANK: 'Blank',
|
||||
LAST_INPUT: 'LastInput',
|
||||
} as const;
|
||||
|
||||
@ -706,9 +706,12 @@ export class AccountsController {
|
||||
const { userId } = jwt.decode(token, { json: true }) as AccessToken;
|
||||
|
||||
const context = makeContext(userId);
|
||||
console.log(context.trackingId);
|
||||
console.log(worktypeId);
|
||||
console.log(description);
|
||||
await this.accountService.createWorktype(
|
||||
context,
|
||||
userId,
|
||||
worktypeId,
|
||||
description,
|
||||
);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ import {
|
||||
createLicenseOrder,
|
||||
createLicenseSetExpiryDateAndStatus,
|
||||
createWorktype,
|
||||
getOptionItems,
|
||||
getSortCriteria,
|
||||
getTypistGroup,
|
||||
getTypistGroupMember,
|
||||
@ -34,7 +35,12 @@ import {
|
||||
} from '../../common/test/utility';
|
||||
import { AccountsService } from './accounts.service';
|
||||
import { Context, makeContext } from '../../common/log';
|
||||
import { TIERS, USER_ROLES } from '../../constants';
|
||||
import {
|
||||
OPTION_ITEM_VALUE_TYPE,
|
||||
TIERS,
|
||||
USER_ROLES,
|
||||
WORKTYPE_MAX_COUNT,
|
||||
} from '../../constants';
|
||||
import { License } from '../../repositories/licenses/entity/license.entity';
|
||||
import {
|
||||
overrideAccountsRepositoryService,
|
||||
@ -46,6 +52,7 @@ import { AdB2cService } from '../../gateways/adb2c/adb2c.service';
|
||||
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
|
||||
import { UserGroupsRepositoryService } from '../../repositories/user_groups/user_groups.repository.service';
|
||||
import { WorktypesRepositoryService } from '../../repositories/worktypes/worktypes.repository.service';
|
||||
import exp from 'constants';
|
||||
|
||||
describe('createAccount', () => {
|
||||
let source: DataSource = null;
|
||||
@ -3263,3 +3270,147 @@ describe('getWorktypes', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('createWorktype', () => {
|
||||
let source: DataSource = null;
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
database: ':memory:',
|
||||
logging: false,
|
||||
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
|
||||
synchronize: true, // trueにすると自動的にmigrationが行われるため注意
|
||||
});
|
||||
return source.initialize();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
|
||||
it('Worktypeを作成できる', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
// Worktypeが未登録であることを確認
|
||||
{
|
||||
const worktypes = await getWorktypes(source, account.id);
|
||||
const optionItems = await getOptionItems(source);
|
||||
expect(worktypes.length).toBe(0);
|
||||
expect(optionItems.length).toBe(0);
|
||||
}
|
||||
|
||||
await service.createWorktype(
|
||||
context,
|
||||
admin.external_id,
|
||||
'worktype1',
|
||||
'description1',
|
||||
);
|
||||
|
||||
//実行結果を確認
|
||||
{
|
||||
const worktypes = await getWorktypes(source, account.id);
|
||||
const optionItems = await getOptionItems(source, worktypes[0].id);
|
||||
expect(worktypes.length).toBe(1);
|
||||
expect(worktypes[0].custom_worktype_id).toBe('worktype1');
|
||||
expect(worktypes[0].description).toBe('description1');
|
||||
expect(optionItems.length).toBe(10);
|
||||
expect(optionItems[0].item_label).toBe('');
|
||||
expect(optionItems[0].default_value_type).toBe(
|
||||
OPTION_ITEM_VALUE_TYPE.DEFAULT,
|
||||
);
|
||||
expect(optionItems[0].initial_value).toBe('');
|
||||
}
|
||||
});
|
||||
|
||||
it('WorktypeIDが登録済みのWorktypeIDと重複した場合、400エラーとなること', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
const worktypeId = 'worktype1';
|
||||
await createWorktype(source, account.id, worktypeId);
|
||||
|
||||
//作成したデータを確認
|
||||
{
|
||||
const worktypes = await getWorktypes(source, account.id);
|
||||
expect(worktypes.length).toBe(1);
|
||||
expect(worktypes[0].custom_worktype_id).toBe(worktypeId);
|
||||
}
|
||||
|
||||
try {
|
||||
await service.createWorktype(context, admin.external_id, worktypeId);
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E011001'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('WorktypeIDがすでに最大登録数(20件)まで登録されている場合、400エラーとなること', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
// 第五階層のアカウント作成
|
||||
const { account, admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
// あらかじめ最大登録数分のWorktypeを登録する
|
||||
for (let i = 0; i < WORKTYPE_MAX_COUNT; i++) {
|
||||
await createWorktype(source, account.id, `worktype${i + 1}`);
|
||||
}
|
||||
|
||||
//作成したデータを確認
|
||||
{
|
||||
const worktypes = await getWorktypes(source, account.id);
|
||||
expect(worktypes.length).toBe(WORKTYPE_MAX_COUNT);
|
||||
}
|
||||
|
||||
try {
|
||||
await service.createWorktype(context, admin.external_id, 'newWorktypeID');
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E011002'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('DBアクセスに失敗した場合、500エラーを返却する', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
// 第五階層のアカウント作成
|
||||
const { admin } = await makeTestAccount(source, { tier: 5 });
|
||||
|
||||
const service = module.get<AccountsService>(AccountsService);
|
||||
const context = makeContext(admin.external_id);
|
||||
|
||||
//DBアクセスに失敗するようにする
|
||||
const worktypeService = module.get<WorktypesRepositoryService>(
|
||||
WorktypesRepositoryService,
|
||||
);
|
||||
worktypeService.createWorktype = jest.fn().mockRejectedValue('DB failed');
|
||||
|
||||
try {
|
||||
await service.createWorktype(context, admin.external_id, 'worktype1');
|
||||
} catch (e) {
|
||||
if (e instanceof HttpException) {
|
||||
expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR);
|
||||
expect(e.getResponse()).toEqual(makeErrorResponse('E009999'));
|
||||
} else {
|
||||
fail();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -47,6 +47,10 @@ import {
|
||||
TypistIdInvalidError,
|
||||
} from '../../repositories/user_groups/errors/types';
|
||||
import { WorktypesRepositoryService } from '../../repositories/worktypes/worktypes.repository.service';
|
||||
import {
|
||||
WorktypeIdAlreadyExistsError,
|
||||
WorktypeIdMaxCountError,
|
||||
} from '../../repositories/worktypes/errors/types';
|
||||
|
||||
@Injectable()
|
||||
export class AccountsService {
|
||||
@ -1091,4 +1095,63 @@ export class AccountsService {
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* ワークタイプを作成します
|
||||
* @param context
|
||||
* @param externalId
|
||||
* @param worktypeId
|
||||
* @param [description]
|
||||
* @returns worktype
|
||||
*/
|
||||
async createWorktype(
|
||||
context: Context,
|
||||
externalId: string,
|
||||
worktypeId: string,
|
||||
description?: string,
|
||||
): Promise<void> {
|
||||
this.logger.log(`[IN] [${context.trackingId}] ${this.createWorktype.name}`);
|
||||
|
||||
try {
|
||||
// 外部IDをもとにユーザー情報を取得する
|
||||
const { account_id: accountId } =
|
||||
await this.usersRepository.findUserByExternalId(externalId);
|
||||
|
||||
await this.worktypesRepository.createWorktype(
|
||||
accountId,
|
||||
worktypeId,
|
||||
description,
|
||||
);
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
if (e instanceof Error) {
|
||||
switch (e.constructor) {
|
||||
// WorktypeIDが既に存在する場合は400エラーを返す
|
||||
case WorktypeIdAlreadyExistsError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E011001'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
// WorktypeIDが登録上限以上の場合は400エラーを返す
|
||||
case WorktypeIdMaxCountError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E011002'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(
|
||||
`[OUT] [${context.trackingId}] ${this.createWorktype.name}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import { SortCriteria } from '../../../repositories/sort_criteria/entity/sort_cr
|
||||
import { UserGroup } from '../../../repositories/user_groups/entity/user_group.entity';
|
||||
import { UserGroupMember } from '../../../repositories/user_groups/entity/user_group_member.entity';
|
||||
import { Worktype } from '../../../repositories/worktypes/entity/worktype.entity';
|
||||
import { OptionItem } from '../../../repositories/option_items/entity/option_item.entity';
|
||||
|
||||
/**
|
||||
* テスト ユーティリティ: すべてのソート条件を取得する
|
||||
@ -142,3 +143,17 @@ export const getWorktypes = async (
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// オプションアイテムを取得する
|
||||
export const getOptionItems = async (
|
||||
datasource: DataSource,
|
||||
worktypeId?: number,
|
||||
): Promise<OptionItem[]> => {
|
||||
return worktypeId
|
||||
? await datasource.getRepository(OptionItem).find({
|
||||
where: {
|
||||
worktype_id: worktypeId,
|
||||
},
|
||||
})
|
||||
: await datasource.getRepository(OptionItem).find();
|
||||
};
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
import { IsAdminPasswordvalid } from '../../../common/validators/admin.validator';
|
||||
import { IsUnique } from '../../../common/validators/IsUnique.validator';
|
||||
import { Type } from 'class-transformer';
|
||||
import { IsWorktypeId } from '../../../common/validators/worktype.validator';
|
||||
|
||||
export class CreateAccountRequest {
|
||||
@ApiProperty()
|
||||
@ -350,8 +351,12 @@ export class GetWorktypesResponse {
|
||||
export class CreateWorktypesRequest {
|
||||
@ApiProperty({ minLength: 1, description: 'WorktypeID' })
|
||||
@MinLength(1)
|
||||
@MaxLength(255)
|
||||
@IsWorktypeId()
|
||||
worktypeId: string;
|
||||
@ApiProperty({ description: 'Worktypeの説明', required: false })
|
||||
@MaxLength(255)
|
||||
@IsOptional()
|
||||
description?: string;
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
import {
|
||||
Entity,
|
||||
Column,
|
||||
PrimaryGeneratedColumn,
|
||||
UpdateDateColumn,
|
||||
CreateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity({ name: 'option_items' })
|
||||
export class OptionItem {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
@Column()
|
||||
worktype_id: number;
|
||||
@Column()
|
||||
item_label: string;
|
||||
@Column()
|
||||
default_value_type: string;
|
||||
@Column()
|
||||
initial_value: string;
|
||||
@Column({ nullable: true })
|
||||
created_by?: string;
|
||||
@CreateDateColumn({ default: () => "datetime('now', 'localtime')" }) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||
created_at?: Date;
|
||||
@Column({ nullable: true })
|
||||
updated_by?: string;
|
||||
@UpdateDateColumn({ default: () => "datetime('now', 'localtime')" }) // defaultはSQLite用設定値.本番用は別途migrationで設定
|
||||
updated_at?: Date;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { OptionItem } from './entity/option_item.entity';
|
||||
import { OptionItemsRepositoryService } from './option_items.repository.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([OptionItem])],
|
||||
providers: [OptionItemsRepositoryService],
|
||||
exports: [OptionItemsRepositoryService],
|
||||
})
|
||||
export class OptionItemsRepositoryModule {}
|
||||
@ -0,0 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class OptionItemsRepositoryService {
|
||||
constructor(private dataSource: DataSource) {}
|
||||
}
|
||||
@ -1 +1,4 @@
|
||||
|
||||
// WorktypeID重複エラー
|
||||
export class WorktypeIdAlreadyExistsError extends Error {}
|
||||
// WorktypeID登録上限エラー
|
||||
export class WorktypeIdMaxCountError extends Error {}
|
||||
|
||||
@ -1,6 +1,16 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { Worktype } from './entity/worktype.entity';
|
||||
import {
|
||||
OPTION_ITEM_NUM,
|
||||
OPTION_ITEM_VALUE_TYPE,
|
||||
WORKTYPE_MAX_COUNT,
|
||||
} from '../../constants';
|
||||
import {
|
||||
WorktypeIdAlreadyExistsError,
|
||||
WorktypeIdMaxCountError,
|
||||
} from './errors/types';
|
||||
import { OptionItem } from '../option_items/entity/option_item.entity';
|
||||
|
||||
@Injectable()
|
||||
export class WorktypesRepositoryService {
|
||||
@ -19,4 +29,65 @@ export class WorktypesRepositoryService {
|
||||
return worktypes;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* ワークタイプを作成する
|
||||
* @param accountId
|
||||
* @param worktypeId
|
||||
* @param [description]
|
||||
* @returns worktype
|
||||
*/
|
||||
async createWorktype(
|
||||
accountId: number,
|
||||
worktypeId: string,
|
||||
description?: string,
|
||||
): Promise<Worktype> {
|
||||
return await this.dataSource.transaction(async (entityManager) => {
|
||||
const worktypeRepo = entityManager.getRepository(Worktype);
|
||||
const optionItemRepo = entityManager.getRepository(OptionItem);
|
||||
|
||||
const duplicatedWorktype = await worktypeRepo.findOne({
|
||||
where: { account_id: accountId, custom_worktype_id: worktypeId },
|
||||
});
|
||||
|
||||
// ワークタイプIDが重複している場合はエラー
|
||||
if (duplicatedWorktype) {
|
||||
throw new WorktypeIdAlreadyExistsError(
|
||||
`WorktypeID is already exists. WorktypeID: ${worktypeId}`,
|
||||
);
|
||||
}
|
||||
|
||||
const worktypeCount = await worktypeRepo.count({
|
||||
where: { account_id: accountId },
|
||||
});
|
||||
|
||||
// ワークタイプの登録数が上限に達している場合はエラー
|
||||
if (worktypeCount >= WORKTYPE_MAX_COUNT) {
|
||||
throw new WorktypeIdMaxCountError(
|
||||
`Number of worktype is exceeded the limit. MAX_COUNT: ${WORKTYPE_MAX_COUNT}, currentCount: ${worktypeCount}`,
|
||||
);
|
||||
}
|
||||
|
||||
// ワークタイプを作成
|
||||
const worktype = await worktypeRepo.save({
|
||||
account_id: accountId,
|
||||
custom_worktype_id: worktypeId,
|
||||
description: description,
|
||||
});
|
||||
|
||||
// ワークタイプに紐づくオプションアイテムを10件作成
|
||||
const newOptionItems = Array.from({ length: OPTION_ITEM_NUM }, () => {
|
||||
const optionItem = new OptionItem();
|
||||
optionItem.worktype_id = worktype.id;
|
||||
optionItem.item_label = '';
|
||||
optionItem.default_value_type = OPTION_ITEM_VALUE_TYPE.DEFAULT;
|
||||
optionItem.initial_value = '';
|
||||
|
||||
return optionItem;
|
||||
});
|
||||
|
||||
await optionItemRepo.save(newOptionItems);
|
||||
|
||||
return worktype;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user