Merged PR 101: API実装(ライセンス注文登録)
## 概要 [Task1685: API実装(ライセンス注文登録)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1685) タスク 1685: API実装(ライセンス注文登録) ライセンス注文APIを追加 ## レビューポイント 登録時のDB処理方法に問題がないか。 処理、エラーハンドリングに過不足がないか。 ## UIの変更 なし ## 動作確認状況 ローカルでユニットテストを実施。 ローカルでAPIを実行し、DBに登録できること・poNumberの重複チェックが想定通りに動作していることを確認。 ## 補足 なし
This commit is contained in:
parent
3191e22ab6
commit
2c935c8b52
@ -19,6 +19,7 @@ import { AccountsRepositoryModule } from './repositories/accounts/accounts.repos
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { SendGridModule } from './gateways/sendgrid/sendgrid.module';
|
||||
import { UsersRepositoryModule } from './repositories/users/users.repository.module';
|
||||
import { LicensesRepositoryModule } from './repositories/licenses/licenses.repository.module';
|
||||
import { AudioFilesRepositoryModule } from './repositories/audio_files/audio_files.repository.module';
|
||||
import { AudioOptionItemsRepositoryModule } from './repositories/audio_option_items/audio_option_items.repository.module';
|
||||
import { TasksRepositoryModule } from './repositories/tasks/tasks.repository.module';
|
||||
@ -55,8 +56,10 @@ import { LicensesController } from './features/licenses/licenses.controller';
|
||||
TasksModule,
|
||||
UsersModule,
|
||||
SendGridModule,
|
||||
LicensesModule,
|
||||
AccountsRepositoryModule,
|
||||
UsersRepositoryModule,
|
||||
LicensesRepositoryModule,
|
||||
AudioFilesRepositoryModule,
|
||||
AudioOptionItemsRepositoryModule,
|
||||
TasksRepositoryModule,
|
||||
@ -77,7 +80,6 @@ import { LicensesController } from './features/licenses/licenses.controller';
|
||||
NotificationModule,
|
||||
NotificationhubModule,
|
||||
BlobstorageModule,
|
||||
LicensesModule,
|
||||
AuthGuardsModule,
|
||||
],
|
||||
controllers: [
|
||||
|
||||
@ -26,6 +26,9 @@ export const ErrorCodes = [
|
||||
'E010201', // 未認証ユーザエラー
|
||||
'E010202', // 認証済ユーザエラー
|
||||
'E010203', // 管理ユーザ権限エラー
|
||||
'E010204', // ユーザ不在エラー
|
||||
'E010301', // メールアドレス登録済みエラー
|
||||
'E010302', // authorId重複エラー
|
||||
'E010401', // PONumber重複エラー
|
||||
'E010501', // アカウント不在エラー
|
||||
] as const;
|
||||
|
||||
@ -15,6 +15,9 @@ export const errors: Errors = {
|
||||
E010201: 'Email not verified user Error.',
|
||||
E010202: 'Email already verified user Error.',
|
||||
E010203: 'Administrator Permissions Error.',
|
||||
E010204: 'User not Found Error.',
|
||||
E010301: 'This email user already created Error',
|
||||
E010302: 'This AuthorId already used Error',
|
||||
E010401: 'This PoNumber already used Error',
|
||||
E010501: 'Account not Found Error.',
|
||||
};
|
||||
|
||||
@ -88,6 +88,18 @@ export const BLOB_STORAGE_REGION_EU = [
|
||||
*/
|
||||
export const ROLE_NONE = 'None';
|
||||
|
||||
/**
|
||||
* ライセンス注文ステータス(発行待ち)
|
||||
* @const {string}
|
||||
*/
|
||||
export const LICENSE_STATUS_ISSUE_REQUESTING = 'Issue Requesting';
|
||||
|
||||
/**
|
||||
* ライセンス注文ステータス(発行済み)
|
||||
* @const {string}
|
||||
*/
|
||||
export const LICENSE_STATUS_ISSUED = 'Issued';
|
||||
|
||||
/**
|
||||
* 音声ファイルに紐づくオプションアイテムの数
|
||||
* @const {string}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { LicensesController } from './licenses.controller';
|
||||
import { LicensesService } from './licenses.service';
|
||||
import { CryptoService } from '../../gateways/crypto/crypto.service';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
describe('LicensesController', () => {
|
||||
@ -16,7 +17,7 @@ describe('LicensesController', () => {
|
||||
}),
|
||||
],
|
||||
controllers: [LicensesController],
|
||||
providers: [LicensesService],
|
||||
providers: [LicensesService, CryptoService],
|
||||
})
|
||||
.overrideProvider(LicensesService)
|
||||
.useValue(mockLicensesService)
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
Post,
|
||||
Req,
|
||||
UseGuards,
|
||||
HttpException,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiResponse,
|
||||
@ -16,12 +17,21 @@ import { ErrorResponse } from '../../common/error/types/types';
|
||||
import { LicensesService } from './licenses.service';
|
||||
import { CreateOrdersResponse, CreateOrdersRequest } from './types/types';
|
||||
import { Request } from 'express';
|
||||
import { CryptoService } from '../../gateways/crypto/crypto.service';
|
||||
import { retrieveAuthorizationToken } from '../../common/http/helper';
|
||||
import { confirmPermission } from '../../common/auth/auth';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { isVerifyError, verify } from '../../common/jwt';
|
||||
import { AccessToken } from '../../common/token';
|
||||
import { AuthGuard } from '../../common/guards/auth/authguards';
|
||||
|
||||
@ApiTags('licenses')
|
||||
@Controller('licenses')
|
||||
export class LicensesController {
|
||||
constructor(private readonly licensesService: LicensesService) {}
|
||||
constructor(
|
||||
private readonly licensesService: LicensesService,
|
||||
private readonly cryptoService: CryptoService,
|
||||
) {}
|
||||
|
||||
@ApiResponse({
|
||||
status: HttpStatus.OK,
|
||||
@ -45,6 +55,8 @@ export class LicensesController {
|
||||
})
|
||||
@ApiOperation({ operationId: 'createOrders' })
|
||||
@ApiBearerAuth()
|
||||
// @UseGuards(AuthGuard)
|
||||
// @UseGuards(RoleGuard.requireds({ roles: ['admin', 'author'] }))
|
||||
@Post('/orders')
|
||||
async createOrders(
|
||||
@Req() req: Request,
|
||||
@ -52,6 +64,41 @@ export class LicensesController {
|
||||
): Promise<CreateOrdersResponse> {
|
||||
console.log(req.header('Authorization'));
|
||||
console.log(body);
|
||||
|
||||
// アクセストークンにより権限を確認する
|
||||
const pubKey = await this.cryptoService.getPublicKey();
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
|
||||
//アクセストークンが存在しない場合のエラー
|
||||
if (accessToken == undefined) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const payload = verify<AccessToken>(accessToken, pubKey);
|
||||
|
||||
//アクセストークン形式エラー
|
||||
if (isVerifyError(payload)) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
//アクセストークンの権限不足エラー
|
||||
if (!confirmPermission(payload.role)) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000108'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
|
||||
// ライセンス注文処理
|
||||
await this.licensesService.licenseOrders(
|
||||
payload,
|
||||
body.poNumber,
|
||||
body.orderCount,
|
||||
);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,8 +1,18 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { LicensesController } from './licenses.controller';
|
||||
import { LicensesService } from './licenses.service';
|
||||
import { CryptoModule } from '../../gateways/crypto/crypto.module';
|
||||
import { UsersRepositoryModule } from '../../repositories/users/users.repository.module';
|
||||
import { AccountsRepositoryModule } from '../../repositories/accounts/accounts.repository.module';
|
||||
import { LicensesRepositoryModule } from '../../repositories/licenses/licenses.repository.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
CryptoModule,
|
||||
UsersRepositoryModule,
|
||||
AccountsRepositoryModule,
|
||||
LicensesRepositoryModule,
|
||||
],
|
||||
controllers: [LicensesController],
|
||||
providers: [LicensesService],
|
||||
})
|
||||
|
||||
@ -1,18 +1,113 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { LicensesService } from './licenses.service';
|
||||
import { AccessToken } from 'src/common/token';
|
||||
import { CreateOrdersRequest } from './types/types';
|
||||
import {
|
||||
makeDefaultAccountsRepositoryMockValue,
|
||||
makeDefaultLicensesRepositoryMockValue,
|
||||
makeDefaultUsersRepositoryMockValue,
|
||||
makeLicensesServiceMock,
|
||||
} from './test/liscense.service.mock';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
|
||||
describe('LicensesService', () => {
|
||||
let service: LicensesService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [LicensesService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<LicensesService>(LicensesService);
|
||||
it('ライセンス注文が完了する', async () => {
|
||||
const lisencesRepositoryMockValue =
|
||||
makeDefaultLicensesRepositoryMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const accountsRepositoryMockValue =
|
||||
makeDefaultAccountsRepositoryMockValue();
|
||||
const service = await makeLicensesServiceMock(
|
||||
lisencesRepositoryMockValue,
|
||||
usersRepositoryMockValue,
|
||||
accountsRepositoryMockValue,
|
||||
);
|
||||
const body = new CreateOrdersRequest();
|
||||
const token: AccessToken = { userId: '0001', role: '' };
|
||||
body.orderCount = 1000;
|
||||
body.poNumber = '1';
|
||||
expect(
|
||||
await service.licenseOrders(token, body.poNumber, body.orderCount),
|
||||
).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(service).toBeDefined();
|
||||
it('ユーザID取得できなかった場合、エラーとなる', async () => {
|
||||
const lisencesRepositoryMockValue =
|
||||
makeDefaultLicensesRepositoryMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
usersRepositoryMockValue.findUserByExternalId = new Error(
|
||||
'User not Found Error.',
|
||||
);
|
||||
const accountsRepositoryMockValue =
|
||||
makeDefaultAccountsRepositoryMockValue();
|
||||
const service = await makeLicensesServiceMock(
|
||||
lisencesRepositoryMockValue,
|
||||
usersRepositoryMockValue,
|
||||
accountsRepositoryMockValue,
|
||||
);
|
||||
const body = new CreateOrdersRequest();
|
||||
const token: AccessToken = { userId: '', role: '' };
|
||||
body.orderCount = 1000;
|
||||
body.poNumber = '1';
|
||||
await expect(
|
||||
service.licenseOrders(token, body.poNumber, body.orderCount),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
it('親ユーザID取得できなかった場合、エラーとなる', async () => {
|
||||
const lisencesRepositoryMockValue =
|
||||
makeDefaultLicensesRepositoryMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
usersRepositoryMockValue.findUserByExternalId = new Error(
|
||||
'Account not Found Error.',
|
||||
);
|
||||
const accountsRepositoryMockValue =
|
||||
makeDefaultAccountsRepositoryMockValue();
|
||||
const service = await makeLicensesServiceMock(
|
||||
lisencesRepositoryMockValue,
|
||||
usersRepositoryMockValue,
|
||||
accountsRepositoryMockValue,
|
||||
);
|
||||
const body = new CreateOrdersRequest();
|
||||
const token: AccessToken = { userId: '0001', role: '' };
|
||||
body.orderCount = 1000;
|
||||
body.poNumber = '1';
|
||||
await expect(
|
||||
service.licenseOrders(token, body.poNumber, body.orderCount),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
it('POナンバー重複時、エラーとなる', async () => {
|
||||
const lisencesRepositoryMockValue =
|
||||
makeDefaultLicensesRepositoryMockValue();
|
||||
lisencesRepositoryMockValue.order = new Error(
|
||||
'Email already verified user Error.',
|
||||
);
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const accountsRepositoryMockValue =
|
||||
makeDefaultAccountsRepositoryMockValue();
|
||||
const service = await makeLicensesServiceMock(
|
||||
lisencesRepositoryMockValue,
|
||||
usersRepositoryMockValue,
|
||||
accountsRepositoryMockValue,
|
||||
);
|
||||
const body = new CreateOrdersRequest();
|
||||
const token: AccessToken = { userId: '0001', role: '' };
|
||||
body.orderCount = 1000;
|
||||
body.poNumber = '1';
|
||||
await expect(
|
||||
service.licenseOrders(token, body.poNumber, body.orderCount),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@ -1,4 +1,108 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
|
||||
import { request } from 'http';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { CryptoService } from '../../gateways/crypto/crypto.service';
|
||||
import { AccessToken } from 'src/common/token';
|
||||
import { User as EntityUser } from '../../repositories/users/entity/user.entity';
|
||||
import {
|
||||
UsersRepositoryService,
|
||||
UserNotFoundError,
|
||||
} from '../../repositories/users/users.repository.service';
|
||||
import {
|
||||
AccountsRepositoryService,
|
||||
AccountNotFoundError,
|
||||
} from '../../repositories/accounts/accounts.repository.service';
|
||||
import {
|
||||
LicensesRepositoryService,
|
||||
PoNumberAlreadyExistError,
|
||||
} from '../../repositories/licenses/licenses.repository.service';
|
||||
import { CreateOrdersRequest } from './types/types';
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
@Injectable()
|
||||
export class LicensesService {}
|
||||
export class LicensesService {
|
||||
constructor(
|
||||
private readonly usersRepository: UsersRepositoryService,
|
||||
private readonly accountsRepository: AccountsRepositoryService,
|
||||
private readonly licensesRepository: LicensesRepositoryService,
|
||||
) {}
|
||||
private readonly logger = new Logger(LicensesService.name);
|
||||
|
||||
/**
|
||||
* license Orders
|
||||
* @param token
|
||||
* @param body
|
||||
*/
|
||||
async licenseOrders(
|
||||
accessToken: AccessToken,
|
||||
poNumber: string,
|
||||
orderCount: number,
|
||||
): Promise<void> {
|
||||
//アクセストークンからユーザーIDを取得する
|
||||
this.logger.log(`[IN] ${this.licenseOrders.name}`);
|
||||
const userId = accessToken.userId;
|
||||
let myAccountId: number;
|
||||
let parentAccountId: number;
|
||||
|
||||
// ユーザIDからアカウントIDを取得する
|
||||
try {
|
||||
myAccountId = (await this.usersRepository.findUserByExternalId(userId))
|
||||
.account_id;
|
||||
} catch (e) {
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010204'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 親アカウントIDを取得
|
||||
try {
|
||||
parentAccountId = (
|
||||
await this.accountsRepository.findAccountById(myAccountId)
|
||||
).parent_account_id;
|
||||
} catch (e) {
|
||||
switch (e.constructor) {
|
||||
case AccountNotFoundError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010501'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
await this.licensesRepository.order(
|
||||
poNumber,
|
||||
myAccountId,
|
||||
parentAccountId,
|
||||
orderCount,
|
||||
);
|
||||
} catch (e) {
|
||||
switch (e.constructor) {
|
||||
case PoNumberAlreadyExistError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010401'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,119 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { LicensesService } from '../licenses.service';
|
||||
import { LicensesRepositoryService } from '../../../repositories/licenses/licenses.repository.service';
|
||||
import { User } from '../../../repositories/users/entity/user.entity';
|
||||
import { Account } from '../../../repositories/accounts/entity/account.entity';
|
||||
import { UsersRepositoryService } from '../../../repositories/users/users.repository.service';
|
||||
import { AccountsRepositoryService } from '../../../repositories/accounts/accounts.repository.service';
|
||||
|
||||
export type LicensesRepositoryMockValue = {
|
||||
order: undefined | Error;
|
||||
};
|
||||
|
||||
export type AccountsRepositoryMockValue = {
|
||||
findAccountById: Account | Error;
|
||||
};
|
||||
|
||||
export type UsersRepositoryMockValue = {
|
||||
findUserByExternalId: User | Error;
|
||||
};
|
||||
|
||||
export const makeLicensesServiceMock = async (
|
||||
licensesRepositoryMockValue: LicensesRepositoryMockValue,
|
||||
usersRepositoryMockValue: UsersRepositoryMockValue,
|
||||
accountsRepositoryMockValue: AccountsRepositoryMockValue,
|
||||
): Promise<LicensesService> => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [LicensesService],
|
||||
})
|
||||
.useMocker((token) => {
|
||||
switch (token) {
|
||||
case LicensesRepositoryService:
|
||||
return makeLicensesRepositoryMock(licensesRepositoryMockValue);
|
||||
case UsersRepositoryService:
|
||||
return makeUsersRepositoryMock(usersRepositoryMockValue);
|
||||
case AccountsRepositoryService:
|
||||
return makeAccountsRepositoryMock(accountsRepositoryMockValue);
|
||||
}
|
||||
})
|
||||
.compile();
|
||||
|
||||
return module.get<LicensesService>(LicensesService);
|
||||
};
|
||||
|
||||
export const makeLicensesRepositoryMock = (
|
||||
value: LicensesRepositoryMockValue,
|
||||
) => {
|
||||
const { order } = value;
|
||||
return {
|
||||
order:
|
||||
order instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(order)
|
||||
: jest.fn<Promise<void>, []>().mockResolvedValue(order),
|
||||
};
|
||||
};
|
||||
|
||||
export const makeUsersRepositoryMock = (value: UsersRepositoryMockValue) => {
|
||||
const { findUserByExternalId } = value;
|
||||
|
||||
return {
|
||||
findUserByExternalId:
|
||||
findUserByExternalId instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(findUserByExternalId)
|
||||
: jest.fn<Promise<User>, []>().mockResolvedValue(findUserByExternalId),
|
||||
};
|
||||
};
|
||||
|
||||
export const makeAccountsRepositoryMock = (
|
||||
value: AccountsRepositoryMockValue,
|
||||
) => {
|
||||
const { findAccountById } = value;
|
||||
|
||||
return {
|
||||
findAccountById:
|
||||
findAccountById instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(findAccountById)
|
||||
: jest.fn<Promise<Account>, []>().mockResolvedValue(findAccountById),
|
||||
};
|
||||
};
|
||||
|
||||
export const makeDefaultLicensesRepositoryMockValue =
|
||||
(): LicensesRepositoryMockValue => {
|
||||
return {
|
||||
order: undefined,
|
||||
};
|
||||
};
|
||||
export const makeDefaultUsersRepositoryMockValue =
|
||||
(): UsersRepositoryMockValue => {
|
||||
const user1 = new User();
|
||||
user1.id = 2;
|
||||
user1.external_id = 'ede66c43-9b9d-4222-93ed-5f11c96e08e2';
|
||||
user1.account_id = 1234567890123456;
|
||||
user1.role = 'none';
|
||||
user1.author_id = '6cce347f-0cf1-a15e-19ab-d00988b643f9';
|
||||
user1.accepted_terms_version = '1.0';
|
||||
user1.email_verified = true;
|
||||
user1.auto_renew = false;
|
||||
user1.license_alert = false;
|
||||
user1.notification = false;
|
||||
user1.deleted_at = undefined;
|
||||
user1.created_by = 'test';
|
||||
user1.created_at = new Date();
|
||||
user1.updated_by = undefined;
|
||||
user1.updated_at = undefined;
|
||||
|
||||
return {
|
||||
findUserByExternalId: user1,
|
||||
};
|
||||
};
|
||||
|
||||
export const makeDefaultAccountsRepositoryMockValue =
|
||||
(): AccountsRepositoryMockValue => {
|
||||
const account1 = new Account();
|
||||
account1.id = 2;
|
||||
account1.parent_account_id = 987654321098765;
|
||||
|
||||
return {
|
||||
findAccountById: account1,
|
||||
};
|
||||
};
|
||||
@ -3,6 +3,8 @@ import { DataSource, UpdateResult } from 'typeorm';
|
||||
import { User } from '../users/entity/user.entity';
|
||||
import { Account } from './entity/account.entity';
|
||||
|
||||
export class AccountNotFoundError extends Error {}
|
||||
|
||||
@Injectable()
|
||||
export class AccountsRepositoryService {
|
||||
constructor(private dataSource: DataSource) {}
|
||||
@ -112,4 +114,22 @@ export class AccountsRepositoryService {
|
||||
return { newAccount: persistedAccount, adminUser: persistedUser };
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* アカウントIDからアカウント情報を取得する
|
||||
* @param id
|
||||
* @returns account
|
||||
*/
|
||||
async findAccountById(id: number): Promise<Account> {
|
||||
const account = await this.dataSource.getRepository(Account).findOne({
|
||||
where: {
|
||||
id: id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!account) {
|
||||
throw new AccountNotFoundError();
|
||||
}
|
||||
return account;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
import {
|
||||
Entity,
|
||||
Column,
|
||||
PrimaryGeneratedColumn,
|
||||
CreateDateColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity({ name: 'license_orders' })
|
||||
export class LicenseOrder {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
po_number: string;
|
||||
|
||||
@Column()
|
||||
from_account_id: number;
|
||||
|
||||
@Column()
|
||||
to_account_id: number;
|
||||
|
||||
@CreateDateColumn()
|
||||
ordered_at: Date;
|
||||
|
||||
@Column('timestamp', { nullable: true })
|
||||
issued_at?: Date;
|
||||
|
||||
@Column()
|
||||
quantity: number;
|
||||
|
||||
@Column()
|
||||
status: string;
|
||||
|
||||
@Column('timestamp', { nullable: true })
|
||||
canceled_at?: Date;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { LicenseOrder } from './entity/license.entity';
|
||||
import { LicensesRepositoryService } from './licenses.repository.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([LicenseOrder])],
|
||||
providers: [LicensesRepositoryService],
|
||||
exports: [LicensesRepositoryService],
|
||||
})
|
||||
export class LicensesRepositoryModule {}
|
||||
@ -0,0 +1,61 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { LicenseOrder } from './entity/license.entity';
|
||||
import {
|
||||
LICENSE_STATUS_ISSUE_REQUESTING,
|
||||
LICENSE_STATUS_ISSUED,
|
||||
} from '../../constants';
|
||||
|
||||
export class PoNumberAlreadyExistError extends Error {}
|
||||
|
||||
@Injectable()
|
||||
export class LicensesRepositoryService {
|
||||
constructor(private dataSource: DataSource) {}
|
||||
|
||||
async order(
|
||||
poNumber: string,
|
||||
fromAccountId: number,
|
||||
toAccountId: number,
|
||||
quantity: number,
|
||||
): Promise<LicenseOrder> {
|
||||
const licenseOrder = new LicenseOrder();
|
||||
licenseOrder.po_number = poNumber;
|
||||
licenseOrder.from_account_id = fromAccountId;
|
||||
licenseOrder.to_account_id = toAccountId;
|
||||
licenseOrder.quantity = quantity;
|
||||
licenseOrder.status = LICENSE_STATUS_ISSUE_REQUESTING;
|
||||
|
||||
// ライセンス注文テーブルに登録する
|
||||
const createdEntity = await this.dataSource.transaction(
|
||||
async (entityManager) => {
|
||||
//poNumberの重複チェックを行う
|
||||
const isPoNumberDuplicated = await entityManager
|
||||
.getRepository(LicenseOrder)
|
||||
.findOne({
|
||||
where: [
|
||||
{
|
||||
po_number: poNumber,
|
||||
from_account_id: fromAccountId,
|
||||
status: LICENSE_STATUS_ISSUED,
|
||||
},
|
||||
{
|
||||
po_number: poNumber,
|
||||
from_account_id: fromAccountId,
|
||||
status: LICENSE_STATUS_ISSUE_REQUESTING,
|
||||
},
|
||||
],
|
||||
});
|
||||
// 重複があった場合はエラーを返却する
|
||||
if (isPoNumberDuplicated) {
|
||||
throw new PoNumberAlreadyExistError();
|
||||
}
|
||||
|
||||
const repo = entityManager.getRepository(LicenseOrder);
|
||||
const newLicenseOrder = repo.create(licenseOrder);
|
||||
const persisted = await repo.save(newLicenseOrder);
|
||||
return persisted;
|
||||
},
|
||||
);
|
||||
return createdEntity;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user