Merged PR 796: [3回目実行][フルデータ]develop環境での移行実施後の修正作業

## 概要
[Task3802: [3回目実行][フルデータ]develop環境での移行実施後の修正作業](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3802)

- 元PBI or タスクへのリンク(内容・目的などはそちらにあるはず)
- 何をどう変更したか、追加したライブラリなど
- このPull Requestでの対象/対象外
- 影響範囲(他の機能にも影響があるか)

## レビューポイント
- 特にレビューしてほしい箇所
- 軽微なものや自明なものは記載不要
- 修正範囲が大きい場合などに記載
- 全体的にや仕様を満たしているか等は本当に必要な時のみ記載

## UIの変更
- Before/Afterのスクショなど
- スクショ置き場

## 動作確認状況
- ローカルで確認、develop環境で確認など

## 補足
- 相談、参考資料などがあれば
This commit is contained in:
masaaki 2024-03-01 12:00:42 +00:00 committed by maruyama.t
parent cad3a99f70
commit 88ce6a2c9e
3 changed files with 221 additions and 97 deletions

View File

@ -73,7 +73,8 @@ export class TransferController {
const matchList = line.match(regExp);
if (matchList) {
matchList.forEach((match) => {
const replaced = match.replace(/,/g, " ");
// カンマを\に変換
const replaced = match.replace(/,/g, "\\");
line = line.replace(match, replaced);
});
}
@ -95,49 +96,50 @@ export class TransferController {
HttpStatus.BAD_REQUEST
);
}
csvInputFile.push({
type: data[0],
account_id: data[1],
parent_id: data[2],
email: data[3],
company_name: data[4],
first_name: data[5],
last_name: data[6],
country: data[7],
state: data[8],
start_date: data[9],
expired_date: data[10],
user_email: data[11],
author_id: data[12],
recording_mode: data[13],
wt1: data[14],
wt2: data[15],
wt3: data[16],
wt4: data[17],
wt5: data[18],
wt6: data[19],
wt7: data[20],
wt8: data[21],
wt9: data[22],
wt10: data[23],
wt11: data[24],
wt12: data[25],
wt13: data[26],
wt14: data[27],
wt15: data[28],
wt16: data[29],
wt17: data[30],
wt18: data[31],
wt19: data[32],
wt20: data[33],
});
// data[1]がundefinedの場合、配列には格納しない
if (data[1] !== undefined) {
// バックスラッシュをカンマに戻す
data.forEach((value, index) => {
data[index] = value.replace(/\\/g, ",");
});
csvInputFile.push({
type: data[0],
account_id: data[1],
parent_id: data[2],
email: data[3],
company_name: data[4],
first_name: data[5],
last_name: data[6],
country: data[7],
state: data[8],
start_date: data[9],
expired_date: data[10],
user_email: data[11],
author_id: data[12],
recording_mode: data[13],
wt1: data[14],
wt2: data[15],
wt3: data[16],
wt4: data[17],
wt5: data[18],
wt6: data[19],
wt7: data[20],
wt8: data[21],
wt9: data[22],
wt10: data[23],
wt11: data[24],
wt12: data[25],
wt13: data[26],
wt14: data[27],
wt15: data[28],
wt16: data[29],
wt17: data[30],
wt18: data[31],
wt19: data[32],
wt20: data[33],
});
}
});
// 最後の行がundefinedの場合はその行を削除
if (csvInputFile[csvInputFile.length - 1].account_id === undefined) {
csvInputFile.pop();
}
// 各データのバリデーションチェック
await this.transferService.validateInputData(context, csvInputFile);
@ -153,12 +155,12 @@ export class TransferController {
// アカウントID numberとstring対応表の出力
const accountsMappingFiles: AccountsMappingFile[] = [];
accountIdMap.forEach((value, key) => {
const accountsMappingFile = new AccountsMappingFile();
const accountsMappingFile = new AccountsMappingFile();
accountsMappingFile.accountIdNumber = value;
accountsMappingFile.accountIdText = key
accountsMappingFiles.push(accountsMappingFile)
accountsMappingFile.accountIdText = key;
accountsMappingFiles.push(accountsMappingFile);
});
fs.writeFileSync(
`${inputFilePath}account_map.json`,
JSON.stringify(accountsMappingFiles)
@ -188,6 +190,13 @@ export class TransferController {
LicensesFile
);
// AuthorIDが重複している場合通番を付与する
const transferDuplicateAuthorResultUsers =
await this.transferService.transferDuplicateAuthor(
context,
resultDuplicateEmail.usersFileLines
);
// transferResponseCsvをつのJSONファイルの出力する(出力先はinputと同じにする)
const outputFilePath = body.inputFilePath;
const WorktypesFile = transferResponseCsv.worktypesFileLines;
@ -195,7 +204,7 @@ export class TransferController {
context,
outputFilePath,
resultDuplicateEmail.accountsFileLines,
resultDuplicateEmail.usersFileLines,
transferDuplicateAuthorResultUsers,
resultDuplicateEmail.licensesFileLines,
WorktypesFile
);

View File

@ -54,6 +54,12 @@ export class TransferService {
let userIdIndex = 0;
// authorIdとuserIdの対応関係を保持するMapを定義
const authorIdToUserIdMap: Map<string, number> = new Map();
// countryのリストを生成
const countryAccounts = csvInputFile.filter(
(item) => item.type === "Country"
);
// csvInputFileを一行読み込みする
csvInputFile.forEach((line) => {
// typeが"USER"以外の場合、アカウントデータの作成を行う
@ -105,8 +111,13 @@ export class TransferService {
authorId: null,
});
} else {
// typeが"USER"の場合
if (line.type == MIGRATION_TYPE.USER) {
// typeが"USER"の場合、かつcountryのアカウントIDに所属していない場合
if (
line.type == MIGRATION_TYPE.USER &&
!countryAccounts.some(
(countryAccount) => countryAccount.account_id === line.account_id
)
) {
// line.author_idが存在する場合のみユーザーデータを作成する
if (line.author_id) {
// userIdIndexをインクリメントする
@ -229,46 +240,38 @@ export class TransferService {
const relocatedAccounts: AccountsFile[] = [];
const dealerRecords: Map<number, number> = new Map();
// accountsFileTypeをループ
accountsFileType.forEach((account) => {
// Distributorの場合はdealerを検索し、COUNTRYかチェックする
if (account.type === MIGRATION_TYPE.DISTRIBUTOR) {
const distributorParent = accountsFileType.find(
(a) => a.accountId === account.dealerAccountId
);
if (distributorParent.type === MIGRATION_TYPE.COUNTRY) {
dealerRecords.set(
account.accountId,
distributorParent.dealerAccountId // Countryの親、BCのIDを設定
);
const countryAccounts = accountsFileType.filter(
(item) => item.type === MIGRATION_TYPE.COUNTRY
);
const notCountryAccounts = accountsFileType.filter(
(item) => item.type !== MIGRATION_TYPE.COUNTRY
);
notCountryAccounts.forEach((notCountryAccount) => {
let assignDealerAccountId = notCountryAccount.dealerAccountId;
// 親アカウントIDがcountryの場合、countryの親アカウントIDを設定する
for (const countryAccount of countryAccounts) {
if (countryAccount.accountId === notCountryAccount.dealerAccountId) {
assignDealerAccountId = countryAccount.dealerAccountId;
}
} else {
dealerRecords.set(account.accountId, account.dealerAccountId);
}
});
// AccountsFileTypeのループを行い、階層情報の置換と新たな配列へのpushを行う
accountsFileType.forEach((account) => {
// Countryのレコードは除外する
if (account.type !== MIGRATION_TYPE.COUNTRY) {
const dealerAccountId =
dealerRecords.get(account.accountId) ?? account.dealerAccountId;
const type = this.getAccountType(account.type);
const newAccount: AccountsFile = {
accountId: account.accountId,
type: type,
companyName: account.companyName,
country: account.country,
dealerAccountId: dealerAccountId,
adminName: account.adminName,
adminMail: account.adminMail,
userId: account.userId,
role: account.role,
authorId: account.authorId,
};
const assignType = this.getAccountType(notCountryAccount.type);
relocatedAccounts.push(newAccount);
}
const newAccount: AccountsFile = {
accountId: notCountryAccount.accountId,
type: assignType,
companyName: notCountryAccount.companyName,
country: notCountryAccount.country,
dealerAccountId: assignDealerAccountId,
adminName: notCountryAccount.adminName,
adminMail: notCountryAccount.adminMail,
userId: notCountryAccount.userId,
role: notCountryAccount.role,
authorId: notCountryAccount.authorId,
};
relocatedAccounts.push(newAccount);
});
return relocatedAccounts;
@ -364,6 +367,8 @@ export class TransferService {
);
try {
// エラー配列を定義
let errorArray: string[] = [];
// アカウントに対するworktypeのMap配列を作成する
const accountWorktypeMap = new Map<string, string[]>();
// csvInputFileのバリデーションチェックを行う
@ -383,6 +388,13 @@ export class TransferService {
HttpStatus.BAD_REQUEST
);
}
// typeがUSER以外の場合で、countryがnullの場合エラー配列に格納する
if (line.type !== MIGRATION_TYPE.USER) {
if (!line.country) {
// countryがnullの場合エラー配列に格納する
errorArray.push(`country is null. index=${index}`);
}
}
// countryのバリデーションチェック
if (line.country) {
if (!COUNTRY_LIST.find((country) => country.label === line.country)) {
@ -451,6 +463,15 @@ export class TransferService {
}
}
});
// エラー配列に値が存在する場合はエラーファイルを出力する
if (errorArray.length > 0) {
const errorFileJson = JSON.stringify(errorArray);
fs.writeFileSync(`error.json`, errorFileJson);
throw new HttpException(
`errorArray is invalid. errorArray=${errorArray}`,
HttpStatus.BAD_REQUEST
);
}
} catch (e) {
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
throw new HttpException(
@ -603,4 +624,67 @@ export class TransferService {
);
}
}
/**
* transferDuplicateAuthor
* @param usersFileLines: UsersFile[]
* @returns UsersFile[]
*/
async transferDuplicateAuthor(
context: Context,
usersFileLines: UsersFile[]
): Promise<UsersFile[]> {
// パラメータ内容が長大なのでログには出さない
this.logger.log(
`[IN] [${context.getTrackingId()}] ${this.transferDuplicateAuthor.name}`
);
try {
const newUsersFileLines: UsersFile[] = [];
let processingAccountId: number = 0; //処理中のアカウントID
let duplicateSequence: number = 2;
let authorIdList: String[] = [];
for (const user of usersFileLines) {
if (user.accountId !== processingAccountId) {
//アカウントIDが別になった場合、通番を初期化する
duplicateSequence = 2;
processingAccountId = user.accountId;
authorIdList = [];
}
let assignAuthorId = user.authorId;
if (authorIdList.includes(user.authorId)) {
// 同じauthorIdがいる場合、自分のauthorIdに連番を付与する
assignAuthorId = assignAuthorId + duplicateSequence;
duplicateSequence = duplicateSequence + 1;
}
authorIdList.push(user.authorId);
// 新しいAuthorIdのユーザに詰め替え
const newUser: UsersFile = {
accountId: user.accountId,
userId: user.userId,
name: user.name,
role: user.role,
authorId: assignAuthorId,
email: user.email,
};
newUsersFileLines.push(newUser);
}
return newUsersFileLines;
} catch (e) {
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
throw new HttpException(
makeErrorResponse("E009999"),
HttpStatus.INTERNAL_SERVER_ERROR
);
} finally {
this.logger.log(
`[OUT] [${context.getTrackingId()}] ${
this.transferDuplicateAuthor.name
}`
);
}
}
}

View File

@ -53,9 +53,11 @@ export class VerificationService {
// 件数情報の取得
this.logger.log(`入力ファイルから件数情報を取得する`);
const accountCountFromFile = csvInputFiles.filter(
const accountFromFile = csvInputFiles.filter(
(item) => item.type !== "USER" && item.type !== "Country"
).length;
);
const accountCountFromFile = accountFromFile.length;
const cardLicensesCountFromFile = cardlicensesInputFiles.length;
const licensesCountFromFile =
@ -66,18 +68,35 @@ export class VerificationService {
// 管理ユーザ数のカウント
const administratorCountFromFile = accountCountFromFile;
// 一般ユーザ数のカウント
const normaluserCountFromFile = csvInputFiles.filter(
(item) => item.type === "USER" && item.user_email.length !== 0
).length;
// countryのアカウントに所属するユーザをカウント対象外とする
const countryAccountFromFile = csvInputFiles.filter(
(item) => item.type === "Country"
);
// USER、かつuser_emailが設定なし、かつcountryのアカウントID以外をユーザとする
const normaluserFromFile = csvInputFiles.filter(
(item) =>
item.type === "USER" &&
item.user_email.length !== 0 &&
!countryAccountFromFile.some(
(countryItem) => countryItem.account_id === item.account_id
)
);
const normaluserCountFromFile = normaluserFromFile.length;
// ユーザ重複数のカウント
let mailAdresses: string[] = [];
csvInputFiles.forEach((item) => {
// メールアドレスの要素を配列に追加(入力データとして管理者とユーザの両方に入ることはない)
accountFromFile.forEach((item) => {
// メールアドレスの要素を配列に追加
if (item.email.length !== 0) {
mailAdresses.push(item.email);
}
});
normaluserFromFile.forEach((item) => {
// メールアドレスの要素を配列に追加
if (item.user_email.length !== 0) {
mailAdresses.push(item.user_email);
}
@ -232,7 +251,11 @@ export class VerificationService {
}
// dateを任意のフォーマットに変換する
const getFormattedDate = (date: Date | null, format: string) => {
const getFormattedDate = (
date: Date | null,
format: string,
padHours: boolean = false // trueの場合、hhについてゼロパディングする00→0、01→1、23→23
) => {
if (!date) {
return null;
}
@ -244,9 +267,13 @@ const getFormattedDate = (date: Date | null, format: string) => {
s: date.getSeconds(),
};
// hhの値をゼロパディングするかどうかのフラグを確認
const hourSymbol = padHours ? "hh" : "h";
const formatted = format.replace(/(M+|d+|h+|m+|s+)/g, (v) =>
(
(v.length > 1 ? "0" : "") + symbol[v.slice(-1) as keyof typeof symbol]
(v.length > 1 && v !== hourSymbol ? "0" : "") +
symbol[v.slice(-1) as keyof typeof symbol]
).slice(-2)
);
@ -542,12 +569,15 @@ function compareLicenses(
VerificationResultDetails.push(VerificationResultDetailsOne);
isNoError = false;
}
// expiry_dateについて、時はゼロパディングした値で比較する×0109 ○19
if (
!licensesFromDatabase[i] ||
licensesFromFile[i].expired_date !==
getFormattedDate(
licensesFromDatabase[i].expiry_date,
`yyyy/MM/dd hh:mm:ss`
`yyyy/MM/dd hh:mm:ss`,
true
)
) {
const VerificationResultDetailsOne: VerificationResultDetails = {
@ -559,7 +589,8 @@ function compareLicenses(
databaseData: licensesFromDatabase[i]
? getFormattedDate(
licensesFromDatabase[i].expiry_date,
`yyyy/MM/dd hh:mm:ss`
`yyyy/MM/dd hh:mm:ss`,
true
)
: "undifined",
reason: "内容不一致",