diff --git a/dictation_server/src/features/accounts/accounts.controller.ts b/dictation_server/src/features/accounts/accounts.controller.ts index 03fcc6c..609f84f 100644 --- a/dictation_server/src/features/accounts/accounts.controller.ts +++ b/dictation_server/src/features/accounts/accounts.controller.ts @@ -38,7 +38,6 @@ import { RoleGuard } from '../../common/guards/role/roleguards'; import { retrieveAuthorizationToken } from '../../common/http/helper'; import { AccessToken } from '../../common/token'; import jwt from 'jsonwebtoken'; -import { LicenseHistory } from '../../repositories/licenses/entity/license.entity'; @ApiTags('accounts') @Controller('accounts') @@ -360,26 +359,9 @@ export class AccountsController { ): Promise { const { limit, offset, accountId } = body; - // XXX Task2261で本実装する - const orderHistories: LicenseOrder[] = []; - const orderHistory: LicenseOrder = { - orderDate: '2023/01/01', - issueDate: '2023/01/01', - numberOfOrder: 50, - poNumber: 'PO001', - status: 'Issue Requesting', - }; - orderHistories.push(orderHistory); - const getOrderHistoriesResponce = new GetOrderHistoriesResponce(); - getOrderHistoriesResponce.total = 1; - getOrderHistoriesResponce.orderHistories = orderHistories; - /* = - await this.accountService.getOrderHistoriesResponce( - limit, - offset, - accountId, - ); - */ + const getOrderHistoriesResponce = + await this.accountService.getOrderHistories(limit, offset, accountId); + return getOrderHistoriesResponce; } } diff --git a/dictation_server/src/features/accounts/accounts.module.ts b/dictation_server/src/features/accounts/accounts.module.ts index 046e462..a706b56 100644 --- a/dictation_server/src/features/accounts/accounts.module.ts +++ b/dictation_server/src/features/accounts/accounts.module.ts @@ -1,5 +1,6 @@ import { Module } from '@nestjs/common'; import { UsersRepositoryModule } from '../../repositories/users/users.repository.module'; +import { LicensesRepositoryModule } from '../../repositories/licenses/licenses.repository.module'; import { SendGridModule } from '../../gateways/sendgrid/sendgrid.module'; import { AccountsRepositoryModule } from '../../repositories/accounts/accounts.repository.module'; import { AccountsController } from './accounts.controller'; @@ -11,6 +12,7 @@ import { UserGroupsRepositoryModule } from '../../repositories/user_groups/user_ imports: [ AccountsRepositoryModule, UsersRepositoryModule, + LicensesRepositoryModule, UserGroupsRepositoryModule, SendGridModule, AdB2cModule, diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts index c334f6a..db6ed7d 100644 --- a/dictation_server/src/features/accounts/accounts.service.spec.ts +++ b/dictation_server/src/features/accounts/accounts.service.spec.ts @@ -4,6 +4,7 @@ import { makeAccountsServiceMock, makeDefaultAccountsRepositoryMockValue, makeDefaultAdB2cMockValue, + makeDefaultLicensesRepositoryMockValue, makeDefaultSendGridlValue, makeDefaultUserGroupsRepositoryMockValue, makeDefaultUsersRepositoryMockValue, @@ -29,6 +30,8 @@ describe('AccountsService', () => { makeDefaultAccountsRepositoryMockValue(); const configMockValue = makeDefaultConfigValue(); const sendGridMockValue = makeDefaultSendGridlValue(); + const licensesRepositoryMockValue = + makeDefaultLicensesRepositoryMockValue(); const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, @@ -36,6 +39,7 @@ describe('AccountsService', () => { adb2cParam, configMockValue, sendGridMockValue, + licensesRepositoryMockValue, ); expect(await service.getLicenseSummary(accountId)).toEqual( expectedAccountLisenceCounts, @@ -53,6 +57,8 @@ describe('AccountsService', () => { accountsRepositoryMockValue.getLicenseSummaryInfo = null; const configMockValue = makeDefaultConfigValue(); const sendGridMockValue = makeDefaultSendGridlValue(); + const licensesRepositoryMockValue = + makeDefaultLicensesRepositoryMockValue(); const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, @@ -60,6 +66,7 @@ describe('AccountsService', () => { adb2cParam, configMockValue, sendGridMockValue, + licensesRepositoryMockValue, ); await expect(service.getLicenseSummary(accountId)).rejects.toEqual( new HttpException( @@ -79,6 +86,8 @@ describe('AccountsService', () => { makeDefaultAccountsRepositoryMockValue(); const configMockValue = makeDefaultConfigValue(); const sendGridMockValue = makeDefaultSendGridlValue(); + const licensesRepositoryMockValue = + makeDefaultLicensesRepositoryMockValue(); const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, @@ -86,6 +95,7 @@ describe('AccountsService', () => { adb2cParam, configMockValue, sendGridMockValue, + licensesRepositoryMockValue, ); expect(await service.getTypists(externalId)).toEqual([ { id: 1, name: 'Typist1' }, @@ -104,6 +114,8 @@ describe('AccountsService', () => { makeDefaultAccountsRepositoryMockValue(); const configMockValue = makeDefaultConfigValue(); const sendGridMockValue = makeDefaultSendGridlValue(); + const licensesRepositoryMockValue = + makeDefaultLicensesRepositoryMockValue(); const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, @@ -111,6 +123,7 @@ describe('AccountsService', () => { adb2cParam, configMockValue, sendGridMockValue, + licensesRepositoryMockValue, ); await expect(service.getTypists(externalId)).rejects.toEqual( new HttpException( @@ -130,6 +143,8 @@ describe('AccountsService', () => { makeDefaultAccountsRepositoryMockValue(); const configMockValue = makeDefaultConfigValue(); const sendGridMockValue = makeDefaultSendGridlValue(); + const licensesRepositoryMockValue = + makeDefaultLicensesRepositoryMockValue(); const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, @@ -137,6 +152,7 @@ describe('AccountsService', () => { adb2cParam, configMockValue, sendGridMockValue, + licensesRepositoryMockValue, ); await expect(service.getTypists(externalId)).rejects.toEqual( new HttpException( @@ -156,6 +172,8 @@ describe('AccountsService', () => { makeDefaultUserGroupsRepositoryMockValue(); const configMockValue = makeDefaultConfigValue(); const sendGridMockValue = makeDefaultSendGridlValue(); + const licensesRepositoryMockValue = + makeDefaultLicensesRepositoryMockValue(); const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, @@ -163,6 +181,7 @@ describe('AccountsService', () => { adb2cParam, configMockValue, sendGridMockValue, + licensesRepositoryMockValue, ); expect(await service.getTypistGroups(externalId)).toEqual([ @@ -181,6 +200,8 @@ describe('AccountsService', () => { makeDefaultUserGroupsRepositoryMockValue(); const configMockValue = makeDefaultConfigValue(); const sendGridMockValue = makeDefaultSendGridlValue(); + const licensesRepositoryMockValue = + makeDefaultLicensesRepositoryMockValue(); const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, @@ -188,6 +209,7 @@ describe('AccountsService', () => { adb2cParam, configMockValue, sendGridMockValue, + licensesRepositoryMockValue, ); await expect(service.getTypistGroups(externalId)).rejects.toEqual( @@ -208,6 +230,8 @@ describe('AccountsService', () => { userGroupsRepositoryMockValue.getUserGroups = new Error('DB failed'); const configMockValue = makeDefaultConfigValue(); const sendGridMockValue = makeDefaultSendGridlValue(); + const licensesRepositoryMockValue = + makeDefaultLicensesRepositoryMockValue(); const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, @@ -215,6 +239,7 @@ describe('AccountsService', () => { adb2cParam, configMockValue, sendGridMockValue, + licensesRepositoryMockValue, ); await expect(service.getTypistGroups(externalId)).rejects.toEqual( @@ -239,7 +264,8 @@ describe('AccountsService', () => { makeDefaultAccountsRepositoryMockValue(); const configMockValue = makeDefaultConfigValue(); const sendGridMockValue = makeDefaultSendGridlValue(); - + const licensesRepositoryMockValue = + makeDefaultLicensesRepositoryMockValue(); const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, @@ -247,6 +273,7 @@ describe('AccountsService', () => { adb2cParam, configMockValue, sendGridMockValue, + licensesRepositoryMockValue, ); expect( await service.createPartnerAccount( @@ -275,7 +302,8 @@ describe('AccountsService', () => { accountsRepositoryMockValue.createAccount = new Error('DB failed'); const configMockValue = makeDefaultConfigValue(); const sendGridMockValue = makeDefaultSendGridlValue(); - + const licensesRepositoryMockValue = + makeDefaultLicensesRepositoryMockValue(); const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, @@ -283,6 +311,7 @@ describe('AccountsService', () => { adb2cParam, configMockValue, sendGridMockValue, + licensesRepositoryMockValue, ); await expect( service.createPartnerAccount( @@ -368,7 +397,13 @@ describe('createPartnerAccount', () => { await createLicense(source, childAccountId2); // ライセンス注文を追加(子1→親:10ライセンス、子2→親:5ライセンス) - await createLicenseOrder(source, childAccountId1, parentAccountId, 10); + await createLicenseOrder( + source, + childAccountId1, + parentAccountId, + 10, + 'TEST222', + ); await createLicenseOrder(source, childAccountId2, parentAccountId, 5); const service = module.get(AccountsService); @@ -397,3 +432,120 @@ describe('createPartnerAccount', () => { expect(responce.childrenPartnerLicenses[1].issueRequesting).toBe(5); }); }); + +describe('getOrderHistories', () => { + 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('指定したアカウントIDの注文履歴情報を取得できる', async () => { + const module = await makeTestingModule(source); + + const targetAccountId = 10; + const targetParentAccountId = 14; + const now = new Date(); // 現在の時刻を取得 + + // 注文履歴情報の作成 + await createLicenseOrder( + source, + targetAccountId, + targetParentAccountId, + 10, + 'TEST001', + new Date(now.getTime() + 60 * 60 * 1000), + ); + await createLicenseOrder( + source, + targetAccountId, + targetParentAccountId, + 10, + 'TEST002', + new Date(now.getTime() + 60 * 60 * 1000 * 2), + ); + await createLicenseOrder( + source, + targetAccountId, + targetParentAccountId, + 10, + 'TEST003', + new Date(now.getTime() + 60 * 60 * 1000 * 3), + ); + await createLicenseOrder( + source, + targetAccountId, + targetParentAccountId, + 10, + 'TEST004', + new Date(now.getTime() + 60 * 60 * 1000 * 4), + ); + await createLicenseOrder( + source, + targetAccountId, + targetParentAccountId, + 10, + 'TEST005', + new Date(now.getTime() + 60 * 60 * 1000 * 5), + ); + + const service = module.get(AccountsService); + const accountId = targetAccountId; + const offset = 1; + const limit = 2; + + const responce = await service.getOrderHistories(limit, offset, accountId); + + expect(responce.total).toBe(5); + + expect(responce.orderHistories[0].poNumber).toBe('TEST004'); + expect(responce.orderHistories[1].poNumber).toBe('TEST003'); + }); + it('注文履歴情報の取得に失敗した場合、エラーとなる', async () => { + const limit = 0; + const offset = 0; + const accountId = 0; + const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); + usersRepositoryMockValue.findTypistUsers = new Error(); + const userGroupsRepositoryMockValue = + makeDefaultUserGroupsRepositoryMockValue(); + const adb2cParam = makeDefaultAdB2cMockValue(); + const accountsRepositoryMockValue = + makeDefaultAccountsRepositoryMockValue(); + const configMockValue = makeDefaultConfigValue(); + const sendGridMockValue = makeDefaultSendGridlValue(); + const licensesRepositoryMockValue = + makeDefaultLicensesRepositoryMockValue(); + licensesRepositoryMockValue.getLicenseOrderHistoryInfo = new Error( + 'DB failed', + ); + const service = await makeAccountsServiceMock( + accountsRepositoryMockValue, + usersRepositoryMockValue, + userGroupsRepositoryMockValue, + adb2cParam, + configMockValue, + sendGridMockValue, + licensesRepositoryMockValue, + ); + await expect( + service.getOrderHistories(limit, offset, accountId), + ).rejects.toEqual( + new HttpException( + makeErrorResponse('E009999'), + HttpStatus.INTERNAL_SERVER_ERROR, + ), + ); + }); +}); diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts index bc134ad..bb2d857 100644 --- a/dictation_server/src/features/accounts/accounts.service.ts +++ b/dictation_server/src/features/accounts/accounts.service.ts @@ -20,6 +20,8 @@ import { TypistGroup, GetPartnerLicensesResponse, PartnerLicenseInfo, + GetOrderHistoriesResponce, + LicenseOrder, } from './types/types'; import { DateWithZeroTime } from '../licenses/types/types'; import { GetLicenseSummaryResponse, Typist } from './types/types'; @@ -27,11 +29,12 @@ import { AccessToken } from '../../common/token'; import { UserNotFoundError } from '../../repositories/users/errors/types'; import { UserGroupsRepositoryService } from '../../repositories/user_groups/user_groups.repository.service'; import { makePassword } from '../../common/password'; - +import { LicensesRepositoryService } from '../../repositories/licenses/licenses.repository.service'; @Injectable() export class AccountsService { constructor( private readonly accountRepository: AccountsRepositoryService, + private readonly licensesRepository: LicensesRepositoryService, private readonly usersRepository: UsersRepositoryService, private readonly userGroupsRepository: UserGroupsRepositoryService, private readonly adB2cService: AdB2cService, @@ -492,4 +495,59 @@ export class AccountsService { this.logger.log(`[OUT] ${this.getPartnerLicenses.name}`); } } + /** + * 注文履歴情報を取得する + * @param limit + * @param offset + * @param accountId + * @returns getOrderHistoriesResponce + */ + async getOrderHistories( + limit: number, + offset: number, + accountId: number, + ): Promise { + this.logger.log(`[IN] ${this.getOrderHistories.name}`); + + try { + const licenseHistoryInfo = + await this.licensesRepository.getLicenseOrderHistoryInfo( + accountId, + offset, + limit, + ); + + // 戻り値用に配列の詰めなおしを行う + const orderHistories: LicenseOrder[] = []; + for (const licenseOrder of licenseHistoryInfo.licenseOrders) { + const returnLicenseOrder: LicenseOrder = { + issueDate: new Date(licenseOrder.issued_at) + .toISOString() + .substr(0, 10) + .replace(/-/g, '/'), + numberOfOrder: licenseOrder.quantity, + orderDate: new Date(licenseOrder.ordered_at) + .toISOString() + .substr(0, 10) + .replace(/-/g, '/'), + poNumber: licenseOrder.po_number, + status: licenseOrder.status, + }; + orderHistories.push(returnLicenseOrder); + } + const getOrderHistoriesResponse: GetOrderHistoriesResponce = { + total: licenseHistoryInfo.total, + orderHistories: orderHistories, + }; + return getOrderHistoriesResponse; + } catch (e) { + this.logger.error(e); + throw new HttpException( + makeErrorResponse('E009999'), + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } finally { + this.logger.log(`[OUT] ${this.getOrderHistories.name}`); + } + } } diff --git a/dictation_server/src/features/accounts/test/accounts.service.mock.ts b/dictation_server/src/features/accounts/test/accounts.service.mock.ts index 83b072e..490cb05 100644 --- a/dictation_server/src/features/accounts/test/accounts.service.mock.ts +++ b/dictation_server/src/features/accounts/test/accounts.service.mock.ts @@ -9,10 +9,18 @@ import { ConflictError, } from '../../../gateways/adb2c/adb2c.service'; import { SendGridService } from '../../../gateways/sendgrid/sendgrid.service'; -import { Account, LicenseSummaryInfo } from '../types/types'; +import { Account, LicenseOrder, LicenseSummaryInfo } from '../types/types'; import { UserGroup } from '../../../repositories/user_groups/entity/user_group.entity'; import { UserGroupsRepositoryService } from '../../../repositories/user_groups/user_groups.repository.service'; import { AdB2cUser } from '../../../gateways/adb2c/types/types'; +import { LicensesRepositoryService } from '../../../repositories/licenses/licenses.repository.service'; + +export type LicensesRepositoryMockValue = { + getLicenseOrderHistoryInfo: { + total: number; + orderHistories: LicenseOrder[]; + } | Error; +}; export type UsersRepositoryMockValue = { findUserById: User | Error; findUserByExternalId: User | Error; @@ -55,6 +63,7 @@ export const makeAccountsServiceMock = async ( adB2cMockValue: AdB2cMockValue, configMockValue: ConfigMockValue, sendGridMockValue: SendGridMockValue, + licensesRepositoryMockValue: LicensesRepositoryMockValue ): Promise => { const module: TestingModule = await Test.createTestingModule({ providers: [AccountsService], @@ -79,6 +88,8 @@ export const makeAccountsServiceMock = async ( return makeConfigMock(configMockValue); case SendGridService: return makeSendGridServiceMock(sendGridMockValue); + case LicensesRepositoryService: + return makeLicensesRepositoryMock(licensesRepositoryMockValue); } }) .compile(); @@ -111,6 +122,24 @@ export const makeAccountsRepositoryMock = ( .mockResolvedValue(createAccount), }; }; +export const makeLicensesRepositoryMock = (value: LicensesRepositoryMockValue) => { + const { getLicenseOrderHistoryInfo } = + value; + + return { + findUserById: + getLicenseOrderHistoryInfo instanceof Error + ? jest + .fn, []>() + .mockRejectedValue(getLicenseOrderHistoryInfo) + : jest + .fn< + Promise<{ total: number; orderHistories: LicenseOrder[] }>, + [] + >() + .mockResolvedValue(getLicenseOrderHistoryInfo), + }; +}; export const makeUsersRepositoryMock = (value: UsersRepositoryMockValue) => { const { findUserById, findUserByExternalId, findTypistUsers } = value; @@ -355,3 +384,19 @@ export const makeDefaultSendGridlValue = (): SendGridMockValue => { }, }; }; +export const makeDefaultLicensesRepositoryMockValue = (): LicensesRepositoryMockValue => { + return { + getLicenseOrderHistoryInfo: { + total: 100, + orderHistories: [ + { + orderDate: '2023/04/01', + issueDate: '2023/04/01', + numberOfOrder: 10, + poNumber: 'PO001', + status:'Issued' + }, + ], + }, + }; +}; \ No newline at end of file diff --git a/dictation_server/src/features/accounts/test/utility.ts b/dictation_server/src/features/accounts/test/utility.ts index 707e856..a098ee7 100644 --- a/dictation_server/src/features/accounts/test/utility.ts +++ b/dictation_server/src/features/accounts/test/utility.ts @@ -55,12 +55,14 @@ export const createLicenseOrder = async ( fromAccountId: number, toAccountId: number, quantity: number, + po_number = 'TEST123', + ordered_at = new Date(), ): Promise => { const { identifiers } = await datasource.getRepository(LicenseOrder).insert({ - po_number: 'TEST123', + po_number: po_number, from_account_id: fromAccountId, to_account_id: toAccountId, - ordered_at: new Date(), + ordered_at: ordered_at, issued_at: null, quantity: quantity, status: 'Issue Requesting', diff --git a/dictation_server/src/repositories/licenses/licenses.repository.service.ts b/dictation_server/src/repositories/licenses/licenses.repository.service.ts index 04fc010..1d085be 100644 --- a/dictation_server/src/repositories/licenses/licenses.repository.service.ts +++ b/dictation_server/src/repositories/licenses/licenses.repository.service.ts @@ -255,4 +255,45 @@ export class LicensesRepositoryService { }); return; } + + /** + * アカウントIDに紐づく注文履歴情報を取得する + * @param accountId + * @param offset + * @param limit + * @returns total + * @returns licenseOrders + */ + async getLicenseOrderHistoryInfo( + accountId: number, + offset: number, + limit: number, + ): Promise<{ + total: number; + licenseOrders: LicenseOrder[]; + }> { + return await this.dataSource.transaction(async (entityManager) => { + const licenseOrder = entityManager.getRepository(LicenseOrder); + // limit/offsetによらない総件数を取得する + const total = await licenseOrder.count({ + where: { + from_account_id: accountId, + }, + }); + const licenseOrders = await licenseOrder.find({ + where: { + from_account_id: accountId, + }, + order: { + ordered_at: 'DESC', + }, + take: limit, + skip: offset, + }); + return { + total: total, + licenseOrders: licenseOrders, + }; + }); + } }