Merge branch 'develop' into release-ccb

This commit is contained in:
SAITO-PC-3\saito.k 2024-06-11 11:20:34 +09:00
commit c73340ec51
29 changed files with 576 additions and 63 deletions

View File

@ -13,7 +13,7 @@ describe("parse", () => {
email: "sample@example.com",
role: 1,
author_id: "HOGE",
auto_renew: 1,
auto_assign: 1,
notification: 1,
encryption: 1,
encryption_password: "abcd",
@ -58,7 +58,7 @@ describe("parse", () => {
email: "sample@example.com",
role: 1,
author_id: null,
auto_renew: 1,
auto_assign: 1,
notification: 1,
encryption: 1,
encryption_password: "abcd",
@ -76,7 +76,7 @@ describe("parse", () => {
email: "sample@example.com",
role: null,
author_id: "HOGE",
auto_renew: 1,
auto_assign: 1,
notification: 1,
encryption: 1,
encryption_password: "abcd",
@ -94,7 +94,7 @@ describe("parse", () => {
email: "sample@example.com",
role: 1,
author_id: "HOGE",
auto_renew: 1,
auto_assign: 1,
notification: 1,
encryption: 1,
encryption_password: "abcd",
@ -105,7 +105,7 @@ describe("parse", () => {
email: "sample2@example.com",
role: 1,
author_id: "HOGE2",
auto_renew: 1,
auto_assign: 1,
notification: 1,
encryption: 1,
encryption_password: "abcd2",
@ -119,7 +119,7 @@ describe("parse", () => {
const actualValue = actualData[i];
const expectValue = expectData[i];
expect(actualValue.author_id).toEqual(expectValue.author_id);
expect(actualValue.auto_renew).toEqual(expectValue.auto_renew);
expect(actualValue.auto_assign).toEqual(expectValue.auto_assign);
expect(actualValue.email).toEqual(expectValue.email);
expect(actualValue.encryption).toEqual(expectValue.encryption);
expect(actualValue.encryption_password).toEqual(
@ -141,7 +141,7 @@ describe("parse", () => {
email: "sample@example.com",
role: 1,
author_id: "1111",
auto_renew: 1,
auto_assign: 1,
notification: 1,
encryption: 1,
encryption_password: "222222",

View File

@ -6,7 +6,7 @@ export type CSVType = {
email: string | null;
role: number | null;
author_id: string | null;
auto_renew: number | null;
auto_assign: number | null;
notification: number;
encryption: number | null;
encryption_password: string | null;
@ -19,7 +19,7 @@ const CSVTypeFields: (keyof CSVType)[] = [
"email",
"role",
"author_id",
"auto_renew",
"auto_assign",
"notification",
"encryption",
"encryption_password",
@ -45,7 +45,7 @@ export const parseCSV = async (csvString: string): Promise<CSVType[]> =>
dynamicTyping: {
// author_id, encryption_passwordは数値のみの場合、numberに変換されたくないためdynamicTypingをtrueにしない
role: true,
auto_renew: true,
auto_assign: true,
notification: true,
encryption: true,
prompt: true,

View File

@ -1,2 +1,2 @@
name,email,role,author_id,auto_renew,notification,encryption,encryption_password,prompt
name,email,role,author_id,auto_assign,notification,encryption,encryption_password,prompt
hoge,sample@example.com,1,"HOGE",1,1,1,abcd,0
1 name email role author_id auto_renew auto_assign notification encryption encryption_password prompt
2 hoge sample@example.com 1 HOGE 1 1 1 1 abcd 0

View File

@ -1,2 +1,2 @@
name,email,role,auto_renew,notification,encryption,encryption_password,prompt
name,email,role,auto_assign,notification,encryption,encryption_password,prompt
hoge,sample@example.com,1,"HOGE",1,1,1,abcd,0
Can't render this file because it has a wrong number of fields in line 2.

View File

@ -1,2 +1,2 @@
name,role,author_id,auto_renew,notification,encryption,encryption_password,prompt
name,role,author_id,auto_assign,notification,encryption,encryption_password,prompt
hoge,sample@example.com,1,"HOGE",1,1,1,abcd,0
Can't render this file because it has a wrong number of fields in line 2.

View File

@ -1,2 +1,2 @@
name,emeil,role,author_id,auto_renew,notification,encryption,encryption_password,prompt
name,emeil,role,author_id,auto_assign,notification,encryption,encryption_password,prompt
hoge,sample@example.com,1,"HOGE",1,1,1,abcd,0
1 name emeil role author_id auto_renew auto_assign notification encryption encryption_password prompt
2 hoge sample@example.com 1 HOGE 1 1 1 1 abcd 0

View File

@ -1,2 +1,2 @@
name,email,role,author_id,auto_renew,notification,encryption,encryption_password,prompt
name,email,role,author_id,auto_assign,notification,encryption,encryption_password,prompt
hoge,sample@example.com,1,,1,1,1,abcd,0
1 name email role author_id auto_renew auto_assign notification encryption encryption_password prompt
2 hoge sample@example.com 1 1 1 1 1 abcd 0

View File

@ -1,2 +1,2 @@
name,email,role,author_id,auto_renew,notification,encryption,encryption_password,prompt
name,email,role,author_id,auto_assign,notification,encryption,encryption_password,prompt
hoge,sample@example.com,,"HOGE",1,1,1,abcd,0
1 name email role author_id auto_renew auto_assign notification encryption encryption_password prompt
2 hoge sample@example.com HOGE 1 1 1 1 abcd 0

View File

@ -1,3 +1,3 @@
name,email,role,author_id,auto_renew,notification,encryption,encryption_password,prompt
name,email,role,author_id,auto_assign,notification,encryption,encryption_password,prompt
hoge,sample@example.com,1,"HOGE",1,1,1,abcd,0,x
hoge2,sample2@example.com,1,"HOGE2",1,1,1,abcd2,0,1,32,4,aa
Can't render this file because it has a wrong number of fields in line 2.

View File

@ -1,2 +1,2 @@
name,email,role,author_id,auto_renew,notification,encryption,encryption_password,prompt
name,email,role,author_id,auto_assign,notification,encryption,encryption_password,prompt
hoge,sample@example.com,1,1111,1,1,1,222222,0
1 name email role author_id auto_renew auto_assign notification encryption encryption_password prompt
2 hoge sample@example.com 1 1111 1 1 1 1 222222 0

View File

@ -534,7 +534,7 @@ export const importUsersAsync = createAsyncThunk<
email: user.email ?? "",
role: user.role ?? 0,
authorId: user.author_id ?? undefined,
autoRenew: user.auto_renew ?? 0,
autoRenew: user.auto_assign ?? 0,
notification: user.notification ?? 0,
encryption: user.encryption ?? undefined,
encryptionPassword: user.encryption_password ?? undefined,

View File

@ -493,8 +493,8 @@ export const selectImportValidationErrors = (state: RootState) => {
}
}
// auto_renew
if (csvUser.auto_renew === null || ![0, 1].includes(csvUser.auto_renew)) {
// auto_assign
if (csvUser.auto_assign === null || ![0, 1].includes(csvUser.auto_assign)) {
invalidInput.push(rowNumber);
// eslint-disable-next-line no-continue
continue;

View File

@ -104,6 +104,15 @@ export const FilePropertyPopup: React.FC<FilePropertyPopupProps> = (props) => {
name="submit"
value={t(getTranslationID("dictationPage.label.fileNameSave"))}
className={`${styles.formSubmit} ${styles.isActive}`}
style={{
position: "relative",
marginTop: "0.2rem",
right: "auto",
maxWidth: "18rem",
whiteSpace: "normal",
overflowWrap: "break-word",
fontSize: "small",
}}
onClick={saveFileName}
/>
{isPushSaveButton && fileName.length === 0 && (

View File

@ -52,7 +52,7 @@ export const ImportPopup: React.FC<UserAddPopupProps> = (props) => {
"email",
"role",
"author_id",
"auto_renew",
"auto_assign",
"notification",
"encryption",
"encryption_password",

View File

@ -15,7 +15,7 @@
"copyRight": "© OM Digital Solutions Corporation",
"edit": "Editar",
"save": "Ahorrar",
"delete": "Delete",
"delete": "Borrar",
"return": "Devolver",
"operationInsteadOf": "Operar la nube ODMS en nombre de:",
"headerAccount": "Cuenta",

View File

@ -15,7 +15,7 @@
"copyRight": "© OM Digital Solutions Corporation",
"edit": "Éditer",
"save": "Sauvegarder",
"delete": "Delete",
"delete": "Supprimer",
"return": "Retour",
"operationInsteadOf": "Exploiter le Cloud ODMS pour le compte de :",
"headerAccount": "Compte",

View File

@ -9,6 +9,8 @@ import {
GetPartnerUsersRequest,
UpdatePartnerInfoRequest,
CreateWorktypesRequest,
UpdateWorktypesRequest,
UpdateWorktypeRequestParam,
} from './types/types';
import { plainToClass } from 'class-transformer';
import { validate } from 'class-validator';
@ -124,6 +126,101 @@ describe('AccountsController', () => {
});
});
describe('valdation UpdateWorktypesRequest', () => {
it('最低限の有効なリクエストが成功する', async () => {
const request = new UpdateWorktypesRequest();
request.worktypeId = 'TEST';
const valdationObject = plainToClass(UpdateWorktypesRequest, request);
const errors = await validate(valdationObject);
expect(errors.length).toBe(0);
});
it('worktypeIdが指定されていない場合、リクエストが失敗する', async () => {
const request = new UpdateWorktypesRequest();
const valdationObject = plainToClass(UpdateWorktypesRequest, request);
const errors = await validate(valdationObject);
expect(errors.length).toBe(1);
});
it('worktypeIdが空文字の場合、リクエストが失敗する', async () => {
const request = new UpdateWorktypesRequest();
request.worktypeId = '';
const valdationObject = plainToClass(UpdateWorktypesRequest, request);
const errors = await validate(valdationObject);
expect(errors.length).toBe(1);
});
it('worktypeIdが16文字を超える場合、リクエストが失敗する', async () => {
const request = new UpdateWorktypesRequest();
request.worktypeId = '123456789A1234567';
const valdationObject = plainToClass(UpdateWorktypesRequest, request);
const errors = await validate(valdationObject);
expect(errors.length).toBe(1);
});
it('worktypeIdが16文字の場合、リクエストが成功する', async () => {
const request = new UpdateWorktypesRequest();
request.worktypeId = '123456789A123456';
const valdationObject = plainToClass(UpdateWorktypesRequest, request);
const errors = await validate(valdationObject);
expect(errors.length).toBe(0);
});
it('worktypeIdに使用不可文字が含まれる場合、リクエストが失敗する', async () => {
const request = new UpdateWorktypesRequest();
request.worktypeId = 'test.test';
const valdationObject = plainToClass(UpdateWorktypesRequest, request);
const errors = await validate(valdationObject);
expect(errors.length).toBe(1);
});
it('descriptionが255文字を超える場合、リクエストが失敗する', async () => {
const request = new UpdateWorktypesRequest();
request.worktypeId = 'TEST';
request.description =
'1234567A0A1234567A1A1234567A2A1234567A3A1234567A4A1234567A5A1234567A6A1234567A7A1234567A8A1234567A9A' +
'1234567B0B1234567B1B1234567B2B1234567B3B1234567B4B1234567B5B1234567B6B1234567B7B1234567B8B1234567B9B' +
'1234567A0A1234567A1A1234567A2A1234567A3A1234567A4A123456';
const valdationObject = plainToClass(UpdateWorktypesRequest, request);
const errors = await validate(valdationObject);
expect(errors.length).toBe(1);
});
it('descriptionが255文字の場合、リクエストが成功する', async () => {
const request = new UpdateWorktypesRequest();
request.worktypeId = 'TEST';
request.description =
'1234567A0A1234567A1A1234567A2A1234567A3A1234567A4A1234567A5A1234567A6A1234567A7A1234567A8A1234567A9A' +
'1234567B0B1234567B1B1234567B2B1234567B3B1234567B4B1234567B5B1234567B6B1234567B7B1234567B8B1234567B9B' +
'1234567A0A1234567A1A1234567A2A1234567A3A1234567A4A12345';
const valdationObject = plainToClass(UpdateWorktypesRequest, request);
const errors = await validate(valdationObject);
expect(errors.length).toBe(0);
});
});
describe('valdation UpdateWorktypeRequestParam', () => {
it('最低限の有効なリクエストが成功する', async () => {
const request = new UpdateWorktypeRequestParam();
request.id = 1;
const valdationObject = plainToClass(UpdateWorktypeRequestParam, request);
const errors = await validate(valdationObject);
expect(errors.length).toBe(0);
});
it('idが1より小さい場合、リクエストが失敗する', async () => {
const request = new UpdateWorktypeRequestParam();
request.id = 0;
const valdationObject = plainToClass(UpdateWorktypeRequestParam, request);
const errors = await validate(valdationObject);
expect(errors.length).toBe(1);
});
it('idが数値でない場合、リクエストが失敗する', async () => {
const request = { id: '0' };
const valdationObject = plainToClass(UpdateWorktypeRequestParam, request);
const errors = await validate(valdationObject);
expect(errors.length).toBe(1);
});
});
describe('valdation switchParentRequest', () => {
it('最低限の有効なリクエストが成功する', async () => {
const request = new SwitchParentRequest();

View File

@ -25,6 +25,7 @@ import {
} from '../../constants';
import {
makeHierarchicalAccounts,
makeTestAccount,
makeTestSimpleAccount,
makeTestUser,
} from '../../common/test/utility';
@ -387,8 +388,12 @@ describe('カードライセンスを取り込む', () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
// 明日の日付を取得
// ミリ秒以下は切り捨てる
const tommorow = new Date();
tommorow.setDate(tommorow.getDate() + 1);
tommorow.setMilliseconds(0);
const now = new Date();
const { id: accountId } = await makeTestSimpleAccount(source);
const { external_id: externalId } = await makeTestUser(source, {
account_id: accountId,
@ -402,7 +407,7 @@ describe('カードライセンスを取り込む', () => {
await createLicense(
source,
1,
new Date(now.getTime() + 60 * 60 * 1000),
new Date(tommorow.getTime() + 60 * 60 * 1000),
accountId,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
@ -428,7 +433,7 @@ describe('カードライセンスを取り込む', () => {
await createLicense(
source,
3,
new Date(now.getTime() + 60 * 60 * 1000),
new Date(tommorow.getTime() + 60 * 60 * 1000),
accountId,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
@ -441,7 +446,7 @@ describe('カードライセンスを取り込む', () => {
await createLicense(
source,
4,
new Date(now.getTime() + 60 * 60 * 1000 * 2),
new Date(tommorow.getTime() + 60 * 60 * 1000 * 2),
accountId,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
@ -467,7 +472,7 @@ describe('カードライセンスを取り込む', () => {
await createLicense(
source,
6,
new Date(now.getTime() + 60 * 60 * 1000 * 2),
new Date(tommorow.getTime() + 60 * 60 * 1000 * 2),
accountId,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.ALLOCATED,
@ -480,7 +485,7 @@ describe('カードライセンスを取り込む', () => {
await createLicense(
source,
7,
new Date(now.getTime() + 60 * 60 * 1000 * 2),
new Date(tommorow.getTime() + 60 * 60 * 1000 * 2),
accountId,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.DELETED,
@ -493,7 +498,7 @@ describe('カードライセンスを取り込む', () => {
await createLicense(
source,
8,
new Date(now.getTime() + 60 * 60 * 1000),
new Date(tommorow.getTime() + 60 * 60 * 1000),
accountId + 1,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
@ -506,7 +511,7 @@ describe('カードライセンスを取り込む', () => {
await createLicense(
source,
9,
new Date(now.getTime() - 60 * 60 * 1000 * 24),
new Date(tommorow.getTime() - 60 * 60 * 1000 * 24),
accountId,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
@ -1610,3 +1615,397 @@ describe('ライセンス注文キャンセル', () => {
);
});
});
describe('割り当て可能なライセンス取得', () => {
let source: DataSource | null = null;
beforeAll(async () => {
if (source == null) {
source = await (async () => {
const s = new DataSource({
type: 'mysql',
host: 'test_mysql_db',
port: 3306,
username: 'user',
password: 'password',
database: 'odms',
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
synchronize: false, // trueにすると自動的にmigrationが行われるため注意
logger: new TestLogger('none'),
logging: true,
});
return await s.initialize();
})();
}
});
beforeEach(async () => {
if (source) {
await truncateAllTable(source);
}
});
afterAll(async () => {
await source?.destroy();
source = null;
});
it('割り当て可能なライセンスを取得できる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const { account, admin } = await makeTestAccount(source, {
company_name: 'AAA',
tier: 5,
});
// ライセンスを作成
// 有効期限が当日のライセンスをつ、有効期限が翌日のライセンスを1つ、有効期限が翌々日のライセンスを1つ作成
// ミリ秒以下は切り捨てる DBで扱っていないため
const today = new Date();
today.setMilliseconds(0);
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setMilliseconds(0);
const dayAfterTomorrow = new Date();
dayAfterTomorrow.setDate(dayAfterTomorrow.getDate() + 2);
dayAfterTomorrow.setMilliseconds(0);
await createLicense(
source,
1,
today,
account.id,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
null,
null,
null,
null,
);
await createLicense(
source,
2,
tomorrow,
account.id,
LICENSE_TYPE.CARD,
LICENSE_ALLOCATED_STATUS.REUSABLE,
null,
null,
null,
null,
);
await createLicense(
source,
3,
dayAfterTomorrow,
account.id,
LICENSE_TYPE.TRIAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
null,
null,
null,
null,
);
// ライセンス作成したデータを確認
{
const license1 = await selectLicense(source, 1);
expect(license1.license?.id).toBe(1);
expect(license1.license?.expiry_date).toEqual(today);
expect(license1.license?.allocated_user_id).toBe(null);
expect(license1.license?.status).toBe(
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
);
expect(license1.license?.account_id).toBe(account.id);
expect(license1.license?.type).toBe(LICENSE_TYPE.NORMAL);
const license2 = await selectLicense(source, 2);
expect(license2.license?.id).toBe(2);
expect(license2.license?.expiry_date).toEqual(tomorrow);
expect(license2.license?.allocated_user_id).toBe(null);
expect(license2.license?.status).toBe(LICENSE_ALLOCATED_STATUS.REUSABLE);
expect(license2.license?.account_id).toBe(account.id);
expect(license2.license?.type).toBe(LICENSE_TYPE.CARD);
const license3 = await selectLicense(source, 3);
expect(license3.license?.id).toBe(3);
expect(license3.license?.expiry_date).toEqual(dayAfterTomorrow);
expect(license3.license?.allocated_user_id).toBe(null);
expect(license3.license?.status).toBe(
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
);
expect(license3.license?.account_id).toBe(account.id);
expect(license3.license?.type).toBe(LICENSE_TYPE.TRIAL);
}
const service = module.get<LicensesService>(LicensesService);
const context = makeContext('trackingId', 'requestId');
const response = await service.getAllocatableLicenses(
context,
admin.external_id,
);
// 有効期限が当日のライセンスは取得されない
// 有効期限が長い順に取得される
expect(response.allocatableLicenses.length).toBe(2);
expect(response.allocatableLicenses[0].licenseId).toBe(3);
expect(response.allocatableLicenses[0].expiryDate).toEqual(
dayAfterTomorrow,
);
expect(response.allocatableLicenses[1].licenseId).toBe(2);
expect(response.allocatableLicenses[1].expiryDate).toEqual(tomorrow);
});
it('割り当て可能なライセンスが存在しない場合、空の配列を返却する', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const { account, admin } = await makeTestAccount(source, {
company_name: 'AAA',
tier: 5,
});
// ライセンスを作成
// 有効期限が当日のライセンスを3つ、有効期限が昨日のライセンスを1つ作成
// ミリ秒以下は切り捨てる DBで扱っていないため
const today = new Date();
today.setMilliseconds(0);
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
yesterday.setMilliseconds(0);
for (let i = 1; i <= 3; i++) {
await createLicense(
source,
i,
today,
account.id,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
null,
null,
null,
null,
);
}
await createLicense(
source,
4,
yesterday,
account.id,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
null,
null,
null,
null,
);
// ライセンス作成したデータを確認
{
const license1 = await selectLicense(source, 1);
expect(license1.license?.id).toBe(1);
expect(license1.license?.expiry_date).toEqual(today);
expect(license1.license?.allocated_user_id).toBe(null);
expect(license1.license?.status).toBe(
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
);
expect(license1.license?.account_id).toBe(account.id);
expect(license1.license?.type).toBe(LICENSE_TYPE.NORMAL);
const license2 = await selectLicense(source, 2);
expect(license2.license?.id).toBe(2);
expect(license2.license?.expiry_date).toEqual(today);
expect(license2.license?.allocated_user_id).toBe(null);
expect(license2.license?.status).toBe(
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
);
expect(license2.license?.account_id).toBe(account.id);
expect(license2.license?.type).toBe(LICENSE_TYPE.NORMAL);
const license3 = await selectLicense(source, 3);
expect(license3.license?.id).toBe(3);
expect(license3.license?.expiry_date).toEqual(today);
expect(license3.license?.allocated_user_id).toBe(null);
expect(license3.license?.status).toBe(
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
);
expect(license3.license?.account_id).toBe(account.id);
expect(license3.license?.type).toBe(LICENSE_TYPE.NORMAL);
const license4 = await selectLicense(source, 4);
expect(license4.license?.id).toBe(4);
expect(license4.license?.expiry_date).toEqual(yesterday);
expect(license4.license?.allocated_user_id).toBe(null);
expect(license4.license?.status).toBe(
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
);
expect(license4.license?.account_id).toBe(account.id);
expect(license4.license?.type).toBe(LICENSE_TYPE.NORMAL);
}
const service = module.get<LicensesService>(LicensesService);
const context = makeContext('trackingId', 'requestId');
const response = await service.getAllocatableLicenses(
context,
admin.external_id,
);
// 有効期限が当日のライセンスは取得されない
// 有効期限が切れているライセンスは取得されない
expect(response.allocatableLicenses.length).toBe(0);
expect(response.allocatableLicenses).toEqual([]);
});
it('割り当て可能なライセンスを100件取得できる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const { account, admin } = await makeTestAccount(source, {
company_name: 'AAA',
tier: 5,
});
// ライセンスを作成
// 有効期限が30日後のライセンスを100件作成
// ミリ秒以下は切り捨てる DBで扱っていないため
const date = new Date();
date.setDate(date.getDate() + 30);
date.setMilliseconds(0);
for (let i = 1; i <= 100; i++) {
await createLicense(
source,
i,
date,
account.id,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
null,
null,
null,
null,
);
}
// ライセンス作成したデータを確認
for (let i = 1; i <= 100; i++) {
const license = await selectLicense(source, i);
expect(license.license?.id).toBe(i);
expect(license.license?.expiry_date).toEqual(date);
expect(license.license?.allocated_user_id).toBe(null);
expect(license.license?.status).toBe(
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
);
expect(license.license?.account_id).toBe(account.id);
expect(license.license?.type).toBe(LICENSE_TYPE.NORMAL);
}
const service = module.get<LicensesService>(LicensesService);
const context = makeContext('trackingId', 'requestId');
const response = await service.getAllocatableLicenses(
context,
admin.external_id,
);
// 100件取得できる
expect(response.allocatableLicenses.length).toBe(100);
});
it('既に割り当てられているライセンスは取得されない', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
if (!module) fail();
const { account, admin } = await makeTestAccount(source, {
company_name: 'AAA',
tier: 5,
});
// ライセンスを作成
// ライセンスを5件作成(10日後から1日ずつ有効期限を設定)
// 有効期限が設定されていないライセンス(新規ライセンス)を1件作成
// 既に割り当てられているライセンスを1件作成
// ミリ秒以下は切り捨てる DBで扱っていないため
const date = new Date();
date.setMinutes(0);
date.setSeconds(0);
date.setDate(date.getDate() + 10);
date.setMilliseconds(0);
for (let i = 1; i <= 5; i++) {
await createLicense(
source,
i,
date,
account.id,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
admin.id,
null,
null,
null,
);
date.setDate(date.getDate() + 1);
}
// 新規ライセンス
await createLicense(
source,
6,
null,
account.id,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
null,
null,
null,
null,
);
// 既に割り当てられているライセンス
await createLicense(
source,
7,
date,
account.id,
LICENSE_TYPE.NORMAL,
LICENSE_ALLOCATED_STATUS.ALLOCATED,
admin.id,
null,
null,
null,
);
// ライセンス作成したデータを確認
{
const date = new Date();
date.setMinutes(0);
date.setSeconds(0);
date.setDate(date.getDate() + 10);
date.setMilliseconds(0);
for (let i = 1; i <= 5; i++) {
const license = await selectLicense(source, i);
expect(license.license?.id).toBe(i);
expect(license.license?.expiry_date).toEqual(date);
expect(license.license?.allocated_user_id).toBe(admin.id);
expect(license.license?.status).toBe(
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
);
expect(license.license?.account_id).toBe(account.id);
expect(license.license?.type).toBe(LICENSE_TYPE.NORMAL);
date.setDate(date.getDate() + 1);
}
const newLicense = await selectLicense(source, 6);
expect(newLicense.license?.id).toBe(6);
expect(newLicense.license?.expiry_date).toBe(null);
expect(newLicense.license?.allocated_user_id).toBe(null);
expect(newLicense.license?.status).toBe(
LICENSE_ALLOCATED_STATUS.UNALLOCATED,
);
const allocatedLicense = await selectLicense(source, 7);
expect(allocatedLicense.license?.id).toBe(7);
expect(allocatedLicense.license?.expiry_date).toEqual(date);
expect(allocatedLicense.license?.allocated_user_id).toBe(admin.id);
expect(allocatedLicense.license?.status).toBe(
LICENSE_ALLOCATED_STATUS.ALLOCATED,
);
expect(allocatedLicense.license?.account_id).toBe(account.id);
expect(allocatedLicense.license?.type).toBe(LICENSE_TYPE.NORMAL);
}
const service = module.get<LicensesService>(LicensesService);
const context = makeContext('trackingId', 'requestId');
const response = await service.getAllocatableLicenses(
context,
admin.external_id,
);
// 既に割り当てられているライセンスは取得されない
// 新規ライセンスは取得される
// 有効期限が長い順に取得される
expect(response.allocatableLicenses.length).toBe(6);
expect(response.allocatableLicenses[0].licenseId).toBe(6);
expect(response.allocatableLicenses[0].expiryDate).toBe(undefined);
expect(response.allocatableLicenses[1].licenseId).toBe(5); // 有効期限が最も長い
expect(response.allocatableLicenses[2].licenseId).toBe(4);
expect(response.allocatableLicenses[3].licenseId).toBe(3);
expect(response.allocatableLicenses[4].licenseId).toBe(2);
expect(response.allocatableLicenses[5].licenseId).toBe(1);
});
});

View File

@ -525,9 +525,14 @@ export class LicensesRepositoryService {
context: Context,
myAccountId: number,
): Promise<AllocatableLicenseInfo[]> {
const nowDate = new DateWithZeroTime();
const licenseRepo = this.dataSource.getRepository(License);
// EntityManagerではorderBy句で、expiry_dateに対して複数条件でソートを使用するため出来ない為、createQueryBuilderを使用する。
// プロダクト バックログ項目 4218: [FB対応]有効期限当日のライセンスは一覧に表示しない の対応
// 有効期限が当日のライセンスは取得しない
// 明日の00:00:00を取得
const tomorrowDate = new DateWithZeroTime(
new Date().setDate(new Date().getDate() + 1),
);
const queryBuilder = licenseRepo
.createQueryBuilder('license')
.where('license.account_id = :accountId', { accountId: myAccountId })
@ -538,8 +543,8 @@ export class LicensesRepositoryService {
],
})
.andWhere(
'(license.expiry_date >= :nowDate OR license.expiry_date IS NULL)',
{ nowDate },
'(license.expiry_date >= :tomorrowDate OR license.expiry_date IS NULL)',
{ tomorrowDate },
)
.comment(`${context.getTrackingId()}_${new Date().toUTCString()}`)
.orderBy('license.expiry_date IS NULL', 'DESC')
@ -597,6 +602,9 @@ export class LicensesRepositoryService {
}
// 期限切れの場合はエラー
// 有効期限が当日のライセンスは割り当て不可
// XXX 記述は「有効期限が過去のライセンスは割り当て不可」のような意図だと思われるが、実際の処理は「有効期限が当日のライセンスは割り当て不可」になっている
// より正確な記述に修正したほうが良いが、リリース後のため、修正は保留2024年6月7日
if (targetLicense.expiry_date) {
const currentDay = new Date();
currentDay.setHours(23, 59, 59, 999);

View File

@ -13,7 +13,7 @@
<p>
We have received your bulk user registration request. <br />
- Date and time: $REQUEST_TIME$<br />
- SCV file name: $FILE_NAME$
- CSV file name: $FILE_NAME$
</p>
<p>
・Please wait until the registration is complete. This may take a few minutes to process.<br />
@ -36,7 +36,7 @@
<p>
Wir haben Ihre Anfrage zur Massenbenutzerregistrierung erhalten.<br />
- Datum und Uhrzeit: $REQUEST_TIME$<br />
- SCV-Dateiname: $FILE_NAME$
- CSV-Dateiname: $FILE_NAME$
</p>
<p>
・Bitte warten Sie, bis die Registrierung abgeschlossen ist. Die Bearbeitung kann einige Minuten dauern.<br />
@ -59,7 +59,7 @@
<p>
Nous avons reçu votre demande d'enregistrement groupé d'utilisateur.<br />
- Date et heure : $REQUEST_TIME$<br />
- Nom du fichier SCV : $FILE_NAME$
- Nom du fichier CSV : $FILE_NAME$
</p>
<p>
・Veuillez attendre que l'inscription soit terminée. Le traitement peut prendre quelques minutes.<br />

View File

@ -4,7 +4,7 @@ Dear $CUSTOMER_NAME$,
We have received your bulk user registration request.
- Date and time: $REQUEST_TIME$
- SCV file name: $FILE_NAME$
- CSV file name: $FILE_NAME$
・Please wait until the registration is complete. This may take a few minutes to process.
・Notification will be sent separately upon completion.
@ -21,7 +21,7 @@ Sehr geehrte(r) $CUSTOMER_NAME$,
Wir haben Ihre Anfrage zur Massenbenutzerregistrierung erhalten.
- Datum und Uhrzeit: $REQUEST_TIME$
- SCV-Dateiname: $FILE_NAME$
- CSV-Dateiname: $FILE_NAME$
・Bitte warten Sie, bis die Registrierung abgeschlossen ist. Die Bearbeitung kann einige Minuten dauern.
・Eine Benachrichtigung wird nach Abschluss separat verschickt.
@ -38,7 +38,7 @@ Chère/Cher $CUSTOMER_NAME$,
Nous avons reçu votre demande d'enregistrement groupé d'utilisateur.
- Date et heure : $REQUEST_TIME$
- Nom du fichier SCV : $FILE_NAME$
- Nom du fichier CSV : $FILE_NAME$
・Veuillez attendre que l'inscription soit terminée. Le traitement peut prendre quelques minutes.
・Une notification sera envoyée séparément une fois terminée.

View File

@ -13,7 +13,7 @@
<p>
We have received your bulk user registration request. <br />
- Date and time: $REQUEST_TIME$<br />
- SCV file name: $FILE_NAME$
- CSV file name: $FILE_NAME$
</p>
<p>
・Please wait until the registration is complete. This may take a few minutes to process.<br />
@ -33,7 +33,7 @@
<p>
Wir haben Ihre Anfrage zur Massenbenutzerregistrierung erhalten.<br />
- Datum und Uhrzeit: $REQUEST_TIME$<br />
- SCV-Dateiname: $FILE_NAME$
- CSV-Dateiname: $FILE_NAME$
</p>
<p>
・Bitte warten Sie, bis die Registrierung abgeschlossen ist. Die Bearbeitung kann einige Minuten dauern.<br />
@ -53,7 +53,7 @@
<p>
Nous avons reçu votre demande d'enregistrement groupé d'utilisateur.<br />
- Date et heure : $REQUEST_TIME$<br />
- Nom du fichier SCV : $FILE_NAME$
- Nom du fichier CSV : $FILE_NAME$
</p>
<p>
・Veuillez attendre que l'inscription soit terminée. Le traitement peut prendre quelques minutes.<br />

View File

@ -4,7 +4,7 @@ Dear $CUSTOMER_NAME$,
We have received your bulk user registration request.
- Date and time: $REQUEST_TIME$
- SCV file name: $FILE_NAME$
- CSV file name: $FILE_NAME$
・Please wait until the registration is complete. This may take a few minutes to process.
・Notification will be sent separately upon completion.
@ -19,7 +19,7 @@ Sehr geehrte(r) $CUSTOMER_NAME$,
Wir haben Ihre Anfrage zur Massenbenutzerregistrierung erhalten.
- Datum und Uhrzeit: $REQUEST_TIME$
- SCV-Dateiname: $FILE_NAME$
- CSV-Dateiname: $FILE_NAME$
・Bitte warten Sie, bis die Registrierung abgeschlossen ist. Die Bearbeitung kann einige Minuten dauern.
・Eine Benachrichtigung wird nach Abschluss separat verschickt.
@ -34,7 +34,7 @@ Chère/Cher $CUSTOMER_NAME$,
Nous avons reçu votre demande d'enregistrement groupé d'utilisateur.
- Date et heure : $REQUEST_TIME$
- Nom du fichier SCV : $FILE_NAME$
- Nom du fichier CSV : $FILE_NAME$
・Veuillez attendre que l'inscription soit terminée. Le traitement peut prendre quelques minutes.
・Une notification sera envoyée séparément une fois terminée.

View File

@ -10,7 +10,7 @@
<p>
Bulk user registration using the CSV file has been completed.<br />
- Date and time: $REQUEST_TIME$<br />
- SCV file name: $FILE_NAME$
- CSV file name: $FILE_NAME$
</p>
<p>
・User Registration Notification [U-114] will be sent to the registered users.<br />
@ -33,7 +33,7 @@
<p>
Die Massenbenutzerregistrierung mithilfe der CSV-Datei wurde abgeschlossen.<br />
- Datum und Uhrzeit: $REQUEST_TIME$<br />
- SCV-Dateiname: $FILE_NAME$
- CSV-Dateiname: $FILE_NAME$
</p>
<p>
・Die Benutzerregistrierungsbenachrichtigung [U-114] wird an die registrierten Benutzer gesendet.<br />
@ -57,7 +57,7 @@
<p>
L'enregistrement groupé des utilisateurs à l'aide du fichier CSV est terminé.<br />
- Date et heure : $REQUEST_TIME$<br />
- Nom du fichier SCV : $FILE_NAME$
- Nom du fichier CSV : $FILE_NAME$
</p>
<p>
・La notification d'enregistrement de l'utilisateur [U-114] sera envoyée aux utilisateurs enregistrés.<br />

View File

@ -4,7 +4,7 @@ Dear $CUSTOMER_NAME$,
Bulk user registration using the CSV file has been completed.
- Date and time: $REQUEST_TIME$
- SCV file name: $FILE_NAME$
- CSV file name: $FILE_NAME$
・User Registration Notification [U-114] will be sent to the registered users.
・Registration will not be completed unless the user verifies their email address.
@ -21,7 +21,7 @@ Sehr geehrte(r) $CUSTOMER_NAME$,
Die Massenbenutzerregistrierung mithilfe der CSV-Datei wurde abgeschlossen.
- Datum und Uhrzeit: $REQUEST_TIME$
- SCV-Dateiname: $FILE_NAME$
- CSV-Dateiname: $FILE_NAME$
・Die Benutzerregistrierungsbenachrichtigung [U-114] wird an die registrierten Benutzer gesendet.
・Die Registrierung wird erst abgeschlossen, wenn der Benutzer seine E-Mail-Adresse bestätigt.
@ -38,7 +38,7 @@ Chère/Cher $CUSTOMER_NAME$,
L'enregistrement groupé des utilisateurs à l'aide du fichier CSV est terminé.
- Date et heure : $REQUEST_TIME$
- Nom du fichier SCV : $FILE_NAME$
- Nom du fichier CSV : $FILE_NAME$
・La notification d'enregistrement de l'utilisateur [U-114] sera envoyée aux utilisateurs enregistrés.
・L'inscription ne sera complétée que si l'utilisateur vérifie son adresse e-mail.

View File

@ -10,7 +10,7 @@
<p>
Bulk user registration using the CSV file has been completed.<br />
- Date and time: $REQUEST_TIME$<br />
- SCV file name: $FILE_NAME$
- CSV file name: $FILE_NAME$
</p>
<p>
・User Registration Notification [U-114] will be sent to the registered users.<br />
@ -30,7 +30,7 @@
<p>
Die Massenbenutzerregistrierung mithilfe der CSV-Datei wurde abgeschlossen.<br />
- Datum und Uhrzeit: $REQUEST_TIME$<br />
- SCV-Dateiname: $FILE_NAME$
- CSV-Dateiname: $FILE_NAME$
</p>
<p>
・Die Benutzerregistrierungsbenachrichtigung [U-114] wird an die registrierten Benutzer gesendet.<br />
@ -51,7 +51,7 @@
<p>
L'enregistrement groupé des utilisateurs à l'aide du fichier CSV est terminé.<br />
- Date et heure : $REQUEST_TIME$<br />
- Nom du fichier SCV : $FILE_NAME$
- Nom du fichier CSV : $FILE_NAME$
</p>
<p>
・La notification d'enregistrement de l'utilisateur [U-114] sera envoyée aux utilisateurs enregistrés.<br />

View File

@ -4,7 +4,7 @@ Dear $CUSTOMER_NAME$,
Bulk user registration using the CSV file has been completed.
- Date and time: $REQUEST_TIME$
- SCV file name: $FILE_NAME$
- CSV file name: $FILE_NAME$
・User Registration Notification [U-114] will be sent to the registered users.
・Registration will not be completed unless the user verifies their email address.
@ -19,7 +19,7 @@ Sehr geehrte(r) $CUSTOMER_NAME$,
Die Massenbenutzerregistrierung mithilfe der CSV-Datei wurde abgeschlossen.
- Datum und Uhrzeit: $REQUEST_TIME$
- SCV-Dateiname: $FILE_NAME$
- CSV-Dateiname: $FILE_NAME$
・Die Benutzerregistrierungsbenachrichtigung [U-114] wird an die registrierten Benutzer gesendet.
・Die Registrierung wird erst abgeschlossen, wenn der Benutzer seine E-Mail-Adresse bestätigt.
@ -34,7 +34,7 @@ Chère/Cher $CUSTOMER_NAME$,
L'enregistrement groupé des utilisateurs à l'aide du fichier CSV est terminé.
- Date et heure : $REQUEST_TIME$
- Nom du fichier SCV : $FILE_NAME$
- Nom du fichier CSV : $FILE_NAME$
・La notification d'enregistrement de l'utilisateur [U-114] sera envoyée aux utilisateurs enregistrés.
・L'inscription ne sera complétée que si l'utilisateur vérifie son adresse e-mail.