diff --git a/dictation_client/src/api/api.ts b/dictation_client/src/api/api.ts index 36c518b..602b311 100644 --- a/dictation_client/src/api/api.ts +++ b/dictation_client/src/api/api.ts @@ -68,6 +68,44 @@ export interface ActivateCardLicensesRequest { */ 'cardLicenseKey': string; } +/** + * + * @export + * @interface AllocatableLicenseInfo + */ +export interface AllocatableLicenseInfo { + /** + * + * @type {number} + * @memberof AllocatableLicenseInfo + */ + 'licenseId': number; + /** + * + * @type {string} + * @memberof AllocatableLicenseInfo + */ + 'expiryDate': string; +} +/** + * + * @export + * @interface AllocateLicenseRequest + */ +export interface AllocateLicenseRequest { + /** + * ユーザーID + * @type {number} + * @memberof AllocateLicenseRequest + */ + 'userId': number; + /** + * 割り当てるライセンスのID + * @type {number} + * @memberof AllocateLicenseRequest + */ + 'newLicenseId': number; +} /** * * @export @@ -291,7 +329,7 @@ export interface CreateAccountRequest { * @type {number} * @memberof CreateAccountRequest */ - 'dealerAccountId': number | null; + 'dealerAccountId'?: number; /** * * @type {string} @@ -417,6 +455,19 @@ export interface ErrorResponse { */ 'code': string; } +/** + * + * @export + * @interface GetAllocatableLicensesResponse + */ +export interface GetAllocatableLicensesResponse { + /** + * + * @type {Array} + * @memberof GetAllocatableLicensesResponse + */ + 'allocatableLicenses': Array; +} /** * * @export @@ -2862,6 +2913,46 @@ export const LicensesApiAxiosParamCreator = function (configuration?: Configurat options: localVarRequestOptions, }; }, + /** + * 割り当て可能なライセンスを取得します + * @summary + * @param {object} body + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getAllocatableLicenses: async (body: object, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'body' is not null or undefined + assertParamExists('getAllocatableLicenses', 'body', body) + const localVarPath = `/licenses/allocatable`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(body, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * * @summary @@ -2934,6 +3025,17 @@ export const LicensesApiFp = function(configuration?: Configuration) { const localVarAxiosArgs = await localVarAxiosParamCreator.createOrders(createOrdersRequest, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, + /** + * 割り当て可能なライセンスを取得します + * @summary + * @param {object} body + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async getAllocatableLicenses(body: object, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.getAllocatableLicenses(body, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @summary @@ -2975,6 +3077,16 @@ export const LicensesApiFactory = function (configuration?: Configuration, baseP createOrders(createOrdersRequest: CreateOrdersRequest, options?: any): AxiosPromise { return localVarFp.createOrders(createOrdersRequest, options).then((request) => request(axios, basePath)); }, + /** + * 割り当て可能なライセンスを取得します + * @summary + * @param {object} body + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + getAllocatableLicenses(body: object, options?: any): AxiosPromise { + return localVarFp.getAllocatableLicenses(body, options).then((request) => request(axios, basePath)); + }, /** * * @summary @@ -3019,6 +3131,18 @@ export class LicensesApi extends BaseAPI { return LicensesApiFp(this.configuration).createOrders(createOrdersRequest, options).then((request) => request(this.axios, this.basePath)); } + /** + * 割り当て可能なライセンスを取得します + * @summary + * @param {object} body + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof LicensesApi + */ + public getAllocatableLicenses(body: object, options?: AxiosRequestConfig) { + return LicensesApiFp(this.configuration).getAllocatableLicenses(body, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary @@ -3872,6 +3996,46 @@ export class TasksApi extends BaseAPI { */ export const UsersApiAxiosParamCreator = function (configuration?: Configuration) { return { + /** + * ライセンスを割り当てます + * @summary + * @param {AllocateLicenseRequest} allocateLicenseRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + allocateLicense: async (allocateLicenseRequest: AllocateLicenseRequest, options: AxiosRequestConfig = {}): Promise => { + // verify required parameter 'allocateLicenseRequest' is not null or undefined + assertParamExists('allocateLicense', 'allocateLicenseRequest', allocateLicenseRequest) + const localVarPath = `/users/license/allocate`; + // use dummy base URL string because the URL constructor only accepts absolute URLs. + const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); + let baseOptions; + if (configuration) { + baseOptions = configuration.baseOptions; + } + + const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options}; + const localVarHeaderParameter = {} as any; + const localVarQueryParameter = {} as any; + + // authentication bearer required + // http bearer authentication required + await setBearerAuthToObject(localVarHeaderParameter, configuration) + + + + localVarHeaderParameter['Content-Type'] = 'application/json'; + + setSearchParams(localVarUrlObj, localVarQueryParameter); + let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {}; + localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers}; + localVarRequestOptions.data = serializeDataIfNeeded(allocateLicenseRequest, localVarRequestOptions, configuration) + + return { + url: toPathString(localVarUrlObj), + options: localVarRequestOptions, + }; + }, /** * * @summary @@ -4176,6 +4340,17 @@ export const UsersApiAxiosParamCreator = function (configuration?: Configuration export const UsersApiFp = function(configuration?: Configuration) { const localVarAxiosParamCreator = UsersApiAxiosParamCreator(configuration) return { + /** + * ライセンスを割り当てます + * @summary + * @param {AllocateLicenseRequest} allocateLicenseRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + async allocateLicense(allocateLicenseRequest: AllocateLicenseRequest, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.allocateLicense(allocateLicenseRequest, options); + return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); + }, /** * * @summary @@ -4271,6 +4446,16 @@ export const UsersApiFp = function(configuration?: Configuration) { export const UsersApiFactory = function (configuration?: Configuration, basePath?: string, axios?: AxiosInstance) { const localVarFp = UsersApiFp(configuration) return { + /** + * ライセンスを割り当てます + * @summary + * @param {AllocateLicenseRequest} allocateLicenseRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + */ + allocateLicense(allocateLicenseRequest: AllocateLicenseRequest, options?: any): AxiosPromise { + return localVarFp.allocateLicense(allocateLicenseRequest, options).then((request) => request(axios, basePath)); + }, /** * * @summary @@ -4358,6 +4543,18 @@ export const UsersApiFactory = function (configuration?: Configuration, basePath * @extends {BaseAPI} */ export class UsersApi extends BaseAPI { + /** + * ライセンスを割り当てます + * @summary + * @param {AllocateLicenseRequest} allocateLicenseRequest + * @param {*} [options] Override http request option. + * @throws {RequiredError} + * @memberof UsersApi + */ + public allocateLicense(allocateLicenseRequest: AllocateLicenseRequest, options?: AxiosRequestConfig) { + return UsersApiFp(this.configuration).allocateLicense(allocateLicenseRequest, options).then((request) => request(this.axios, this.basePath)); + } + /** * * @summary diff --git a/dictation_client/src/pages/SignupPage/signupConfirm.tsx b/dictation_client/src/pages/SignupPage/signupConfirm.tsx index 78e45f7..d3cef97 100644 --- a/dictation_client/src/pages/SignupPage/signupConfirm.tsx +++ b/dictation_client/src/pages/SignupPage/signupConfirm.tsx @@ -33,7 +33,7 @@ const SignupConfirm: React.FC = (): JSX.Element => { signupAsync({ companyName, country, - dealerAccountId: dealer?.id ?? 0, + dealerAccountId: dealer?.id ?? undefined, adminName, adminMail, adminPassword, diff --git a/dictation_client/src/pages/SignupPage/signupInput.tsx b/dictation_client/src/pages/SignupPage/signupInput.tsx index 4579800..fd9bef5 100644 --- a/dictation_client/src/pages/SignupPage/signupInput.tsx +++ b/dictation_client/src/pages/SignupPage/signupInput.tsx @@ -26,6 +26,7 @@ import { getTranslationID } from "translation"; import styles from "styles/app.module.scss"; import { getDealersAsync } from "features/signup/operations"; import { LANGUAGE_LIST } from "features/top/constants"; +import { openSnackbar } from "features/ui"; import { COUNTRY_LIST } from "./constants"; const SignupInput: React.FC = (): JSX.Element => { @@ -92,7 +93,7 @@ const SignupInput: React.FC = (): JSX.Element => { // dealer={account_id(第四階層のアカウントID)} でDealerを指定 // language={language(en/de/fr/es)} で言語を指定 const query = new URLSearchParams(search); - const dealerId = parseInt(query.get("dealer") ?? "", 10); + const paramDealer = query.get("dealer"); const language = query.get("language"); // URLで言語が指定されていたら言語を変更 @@ -104,14 +105,30 @@ const SignupInput: React.FC = (): JSX.Element => { document.cookie = `language=${language}; max-age=31536000`; } - // URLでDealerが指定されていたら、そのdealerを選択(国も選択したDealerの国に変更) - if (!Number.isNaN(dealerId)) { - const urlDealer = allDealers.find((x) => x.id === dealerId); - if (urlDealer) { - dispatch(changeCountry({ country: urlDealer.country })); - dispatch(changeDealer({ dealer: urlDealer.id })); - } + // Dealerが取得できていない場合は何もしない + if (allDealers.length === 0) { + return; } + + // URLでDealerが指定されていたら、そのDealerを選択(国も選択したDealerの国に変更) + const urlDealer = allDealers.find( + (x) => x.id === parseInt(paramDealer ?? "", 10) + ); + if (urlDealer) { + dispatch(changeCountry({ country: urlDealer.country })); + dispatch(changeDealer({ dealer: urlDealer.id })); + } else if (paramDealer) { + // URLでDealerが指定されていたが、存在しない場合はメッセージを表示 + dispatch( + openSnackbar({ + level: "error", + message: t( + getTranslationID("signupPage.message.dealerNotFoundError") + ), + }) + ); + } + // eslint-disable-next-line react-hooks/exhaustive-deps }, [i18n, dispatch, search, allDealers]); return ( diff --git a/dictation_client/src/translation/de.json b/dictation_client/src/translation/de.json index 89ebc3d..97556f6 100644 --- a/dictation_client/src/translation/de.json +++ b/dictation_client/src/translation/de.json @@ -41,7 +41,8 @@ "message": { "inputEmptyError": "(de)この項目の入力は必須です。入力してください。", "passwordIncorrectError": "(de)入力されたパスワードがルールを満たしていません。下記のルールを満たすパスワードを入力してください。", - "emailIncorrectError": "(de)メールアドレスの形式が不正です。正しいメールアドレスの形式で入力してください。" + "emailIncorrectError": "(de)メールアドレスの形式が不正です。正しいメールアドレスの形式で入力してください。", + "dealerNotFoundError": "(de)指定されたディーラーが見つかりませんでした。直接ディーラーを指定してください。" }, "text": { "title": "(de)Create your account", @@ -330,4 +331,4 @@ "alreadyIssueLicense": "(de)すでに発行済みの注文です。画面を更新してください。" } } -} +} \ No newline at end of file diff --git a/dictation_client/src/translation/en.json b/dictation_client/src/translation/en.json index 20239ea..2585723 100644 --- a/dictation_client/src/translation/en.json +++ b/dictation_client/src/translation/en.json @@ -41,7 +41,8 @@ "message": { "inputEmptyError": "この項目の入力は必須です。入力してください。", "passwordIncorrectError": "入力されたパスワードがルールを満たしていません。下記のルールを満たすパスワードを入力してください。", - "emailIncorrectError": "メールアドレスの形式が不正です。正しいメールアドレスの形式で入力してください。" + "emailIncorrectError": "メールアドレスの形式が不正です。正しいメールアドレスの形式で入力してください。", + "dealerNotFoundError": "指定されたディーラーが見つかりませんでした。直接ディーラーを指定してください。" }, "text": { "title": "Create your account", @@ -330,4 +331,4 @@ "alreadyIssueLicense": "すでに発行済みの注文です。画面を更新してください。" } } -} +} \ No newline at end of file diff --git a/dictation_client/src/translation/es.json b/dictation_client/src/translation/es.json index 19a21f8..b4d051d 100644 --- a/dictation_client/src/translation/es.json +++ b/dictation_client/src/translation/es.json @@ -41,7 +41,8 @@ "message": { "inputEmptyError": "(es)この項目の入力は必須です。入力してください。", "passwordIncorrectError": "(es)入力されたパスワードがルールを満たしていません。下記のルールを満たすパスワードを入力してください。", - "emailIncorrectError": "(es)メールアドレスの形式が不正です。正しいメールアドレスの形式で入力してください。" + "emailIncorrectError": "(es)メールアドレスの形式が不正です。正しいメールアドレスの形式で入力してください。", + "dealerNotFoundError": "(es)指定されたディーラーが見つかりませんでした。直接ディーラーを指定してください。" }, "text": { "title": "(es)Create your account", @@ -330,4 +331,4 @@ "alreadyIssueLicense": "(es)すでに発行済みの注文です。画面を更新してください。" } } -} +} \ No newline at end of file diff --git a/dictation_client/src/translation/fr.json b/dictation_client/src/translation/fr.json index e1992b2..fadc549 100644 --- a/dictation_client/src/translation/fr.json +++ b/dictation_client/src/translation/fr.json @@ -41,7 +41,8 @@ "message": { "inputEmptyError": "(fr)この項目の入力は必須です。入力してください。", "passwordIncorrectError": "(fr)入力されたパスワードがルールを満たしていません。下記のルールを満たすパスワードを入力してください。", - "emailIncorrectError": "(fr)メールアドレスの形式が不正です。正しいメールアドレスの形式で入力してください。" + "emailIncorrectError": "(fr)メールアドレスの形式が不正です。正しいメールアドレスの形式で入力してください。", + "dealerNotFoundError": "(fr)指定されたディーラーが見つかりませんでした。直接ディーラーを指定してください。" }, "text": { "title": "(fr)Create your account", @@ -330,4 +331,4 @@ "alreadyIssueLicense": "(fr)すでに発行済みの注文です。画面を更新してください。" } } -} +} \ No newline at end of file diff --git a/dictation_server/src/api/odms/openapi.json b/dictation_server/src/api/odms/openapi.json index f980577..7893821 100644 --- a/dictation_server/src/api/odms/openapi.json +++ b/dictation_server/src/api/odms/openapi.json @@ -2027,7 +2027,7 @@ "minLength": 2, "maxLength": 2 }, - "dealerAccountId": { "type": "number", "nullable": true }, + "dealerAccountId": { "type": "number" }, "adminName": { "type": "string" }, "adminMail": { "type": "string" }, "adminPassword": { "type": "string" }, @@ -2040,7 +2040,6 @@ "required": [ "companyName", "country", - "dealerAccountId", "adminName", "adminMail", "adminPassword", diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts index 925471e..ca4a247 100644 --- a/dictation_server/src/features/accounts/accounts.service.ts +++ b/dictation_server/src/features/accounts/accounts.service.ts @@ -125,14 +125,20 @@ export class AccountsService { context: Context, companyName: string, country: string, - dealerAccountId: number | null, + dealerAccountId: number | undefined, email: string, password: string, username: string, role: string, acceptedTermsVersion: string, ): Promise<{ accountId: number; userId: number; externalUserId: string }> { - this.logger.log(`[IN] [${context.trackingId}] ${this.createAccount.name}`); + this.logger.log( + `[IN] [${context.trackingId}] ${this.createAccount.name} | params: { ` + + `country: ${country}, ` + + `dealerAccountId: ${dealerAccountId}, ` + + `role: ${role}, ` + + `acceptedTermsVersion: ${acceptedTermsVersion} };`, + ); try { let externalUser: { sub: string } | ConflictError; try { @@ -178,6 +184,9 @@ export class AccountsService { ); account = newAccount; user = adminUser; + this.logger.log( + `[${context.trackingId}] adminUser.external_id: ${user.external_id}`, + ); } catch (e) { this.logger.error(`error=${e}`); this.logger.error('create account failed'); diff --git a/dictation_server/src/features/accounts/types/types.ts b/dictation_server/src/features/accounts/types/types.ts index a7c2f68..0a0deff 100644 --- a/dictation_server/src/features/accounts/types/types.ts +++ b/dictation_server/src/features/accounts/types/types.ts @@ -11,10 +11,10 @@ export class CreateAccountRequest { maxLength: 2, }) country: string; - @ApiProperty({ nullable: true }) + @ApiProperty({ required: false }) @IsInt() @IsOptional() - dealerAccountId?: number; + dealerAccountId?: number | undefined; @ApiProperty() adminName: string; @ApiProperty() diff --git a/dictation_server/src/repositories/accounts/accounts.repository.service.ts b/dictation_server/src/repositories/accounts/accounts.repository.service.ts index 16b6f47..95c9f57 100644 --- a/dictation_server/src/repositories/accounts/accounts.repository.service.ts +++ b/dictation_server/src/repositories/accounts/accounts.repository.service.ts @@ -92,7 +92,7 @@ export class AccountsRepositoryService { async createAccount( companyName: string, country: string, - dealerAccountId: number | null, + dealerAccountId: number | undefined, tier: number, adminExternalUserId: string, adminUserRole: string,