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:
parent
cad3a99f70
commit
88ce6a2c9e
@ -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を4つの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
|
||||
);
|
||||
|
||||
@ -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
|
||||
}`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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について、時はゼロパディングした値で比較する(×01~09 ○1~9)
|
||||
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: "内容不一致",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user