fix: script org move draf to current save posMasterHistory
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m57s
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m57s
This commit is contained in:
parent
7694a83d5a
commit
3c9e3a1bb6
3 changed files with 173 additions and 8 deletions
|
|
@ -55,9 +55,10 @@ import {
|
||||||
import {
|
import {
|
||||||
CreatePosMasterHistoryEmployee,
|
CreatePosMasterHistoryEmployee,
|
||||||
CreatePosMasterHistoryOfficer,
|
CreatePosMasterHistoryOfficer,
|
||||||
|
SavePosMasterHistoryOfficer,
|
||||||
} from "../services/PositionService";
|
} from "../services/PositionService";
|
||||||
import { orgStructureCache } from "../utils/OrgStructureCache";
|
import { orgStructureCache } from "../utils/OrgStructureCache";
|
||||||
import { OrgIdMapping, AllOrgMappings } from "../interfaces/OrgMapping";
|
import { OrgIdMapping, AllOrgMappings, SavePosMasterHistory } from "../interfaces/OrgMapping";
|
||||||
|
|
||||||
@Route("api/v1/org")
|
@Route("api/v1/org")
|
||||||
@Tags("Organization")
|
@Tags("Organization")
|
||||||
|
|
@ -8110,6 +8111,12 @@ export class OrganizationController extends Controller {
|
||||||
|
|
||||||
// Then delete posMaster records
|
// Then delete posMaster records
|
||||||
await queryRunner.manager.delete(PosMaster, toDeleteIds);
|
await queryRunner.manager.delete(PosMaster, toDeleteIds);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
toDelete.map(async (pos) => {
|
||||||
|
await SavePosMasterHistoryOfficer(queryRunner, pos.ancestorDNA, null, null);
|
||||||
|
}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2.4 Process draft positions (UPDATE or INSERT)
|
// 2.4 Process draft positions (UPDATE or INSERT)
|
||||||
|
|
@ -8176,6 +8183,7 @@ export class OrganizationController extends Controller {
|
||||||
current_holderId: draftPos.next_holderId,
|
current_holderId: draftPos.next_holderId,
|
||||||
statusReport: "DONE",
|
statusReport: "DONE",
|
||||||
});
|
});
|
||||||
|
|
||||||
toInsert.push(newPosMaster);
|
toInsert.push(newPosMaster);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -8231,6 +8239,11 @@ export class OrganizationController extends Controller {
|
||||||
console.error("Error moving draft to current:", error);
|
console.error("Error moving draft to current:", error);
|
||||||
await queryRunner.rollbackTransaction();
|
await queryRunner.rollbackTransaction();
|
||||||
throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดในการย้ายโครงสร้าง");
|
throw new HttpError(HttpStatusCode.INTERNAL_SERVER_ERROR, "เกิดข้อผิดพลาดในการย้ายโครงสร้าง");
|
||||||
|
} finally {
|
||||||
|
if (queryRunner.isTransactionActive) {
|
||||||
|
await queryRunner.rollbackTransaction();
|
||||||
|
}
|
||||||
|
await queryRunner.release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8612,18 +8625,27 @@ export class OrganizationController extends Controller {
|
||||||
): Promise<{ deleted: number; updated: number; inserted: number }> {
|
): Promise<{ deleted: number; updated: number; inserted: number }> {
|
||||||
// Extract draft and current posMaster IDs
|
// Extract draft and current posMaster IDs
|
||||||
const draftPosMasterIds = Array.from(posMasterMapping.keys());
|
const draftPosMasterIds = Array.from(posMasterMapping.keys());
|
||||||
const currentPosMasterIds = Array.from(posMasterMapping.values()).map(([currentId]) => currentId);
|
const currentPosMasterIds = Array.from(posMasterMapping.values()).map(
|
||||||
|
([currentId]) => currentId,
|
||||||
|
);
|
||||||
|
|
||||||
if (draftPosMasterIds.length === 0) {
|
if (draftPosMasterIds.length === 0) {
|
||||||
return { deleted: 0, updated: 0, inserted: 0 };
|
return { deleted: 0, updated: 0, inserted: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fetch draft PosMasters with relations for history tracking
|
||||||
|
const draftPosMasters = await queryRunner.manager.find(PosMaster, {
|
||||||
|
where: { id: In(draftPosMasterIds) },
|
||||||
|
relations: ["orgRoot", "orgChild1", "orgChild2", "orgChild3", "orgChild4", "next_holder"],
|
||||||
|
});
|
||||||
|
|
||||||
// Fetch ALL positions for ALL posMasters in just 2 queries
|
// Fetch ALL positions for ALL posMasters in just 2 queries
|
||||||
const [allDraftPositions, allCurrentPositions] = await Promise.all([
|
const [allDraftPositions, allCurrentPositions] = await Promise.all([
|
||||||
queryRunner.manager.find(Position, {
|
queryRunner.manager.find(Position, {
|
||||||
where: {
|
where: {
|
||||||
posMasterId: In(draftPosMasterIds),
|
posMasterId: In(draftPosMasterIds),
|
||||||
},
|
},
|
||||||
|
relations: ["posType", "posLevel", "posExecutive"],
|
||||||
order: { orderNo: "ASC" },
|
order: { orderNo: "ASC" },
|
||||||
}),
|
}),
|
||||||
queryRunner.manager.find(Position, {
|
queryRunner.manager.find(Position, {
|
||||||
|
|
@ -8656,6 +8678,16 @@ export class OrganizationController extends Controller {
|
||||||
const allToInsert: Array<any> = [];
|
const allToInsert: Array<any> = [];
|
||||||
const profileUpdates: Map<string, any> = new Map();
|
const profileUpdates: Map<string, any> = new Map();
|
||||||
|
|
||||||
|
// Create a map for quick lookup of draft PosMasters with relations
|
||||||
|
const draftPosMasterMap = new Map(draftPosMasters.map((pm: PosMaster) => [pm.id, pm]));
|
||||||
|
|
||||||
|
// Collect PosMasterHistory calls for selected positions
|
||||||
|
const historyCalls: Array<{
|
||||||
|
ancestorDNA: string;
|
||||||
|
profileId: string | null;
|
||||||
|
historyData: SavePosMasterHistory;
|
||||||
|
}> = [];
|
||||||
|
|
||||||
// Process each posMaster mapping
|
// Process each posMaster mapping
|
||||||
for (const [draftPosMasterId, [currentPosMasterId, nextHolderId]] of posMasterMapping) {
|
for (const [draftPosMasterId, [currentPosMasterId, nextHolderId]] of posMasterMapping) {
|
||||||
const draftPositions = draftPositionsByMaster.get(draftPosMasterId) || [];
|
const draftPositions = draftPositionsByMaster.get(draftPosMasterId) || [];
|
||||||
|
|
@ -8710,6 +8742,10 @@ export class OrganizationController extends Controller {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nextHolderId === null) {
|
||||||
|
await SavePosMasterHistoryOfficer(queryRunner, draftPos.ancestorDNA, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
// Collect profile update for the selected position
|
// Collect profile update for the selected position
|
||||||
if (nextHolderId != null && draftPos.positionIsSelected) {
|
if (nextHolderId != null && draftPos.positionIsSelected) {
|
||||||
profileUpdates.set(nextHolderId, {
|
profileUpdates.set(nextHolderId, {
|
||||||
|
|
@ -8718,6 +8754,46 @@ export class OrganizationController extends Controller {
|
||||||
posLevelId: draftPos.posLevelId,
|
posLevelId: draftPos.posLevelId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Collect history data for the selected position
|
||||||
|
if (nextHolderId != null && draftPos.positionIsSelected) {
|
||||||
|
const draftPosMaster = draftPosMasterMap.get(draftPosMasterId) as any;
|
||||||
|
if (draftPosMaster && draftPosMaster.ancestorDNA) {
|
||||||
|
// Find the selected position from draft positions
|
||||||
|
const selectedPos =
|
||||||
|
draftPositions.find((p) => p.positionIsSelected === true) || draftPos;
|
||||||
|
historyCalls.push({
|
||||||
|
ancestorDNA: draftPosMaster.ancestorDNA,
|
||||||
|
profileId: nextHolderId,
|
||||||
|
historyData: {
|
||||||
|
prefix: draftPosMaster.next_holder?.prefix ?? null,
|
||||||
|
firstName: draftPosMaster.next_holder?.firstName ?? null,
|
||||||
|
lastName: draftPosMaster.next_holder?.lastName ?? null,
|
||||||
|
position: selectedPos.positionName ?? null,
|
||||||
|
posType: (selectedPos as any).posType?.posTypeName ?? null,
|
||||||
|
posLevel: (selectedPos as any).posLevel?.posLevelName ?? null,
|
||||||
|
posExecutive: (selectedPos as any).posExecutive?.posExecutiveName ?? null,
|
||||||
|
profileId: nextHolderId,
|
||||||
|
rootDnaId: draftPosMaster.orgRoot?.ancestorDNA ?? null,
|
||||||
|
child1DnaId: draftPosMaster.orgChild1?.ancestorDNA ?? null,
|
||||||
|
child2DnaId: draftPosMaster.orgChild2?.ancestorDNA ?? null,
|
||||||
|
child3DnaId: draftPosMaster.orgChild3?.ancestorDNA ?? null,
|
||||||
|
child4DnaId: draftPosMaster.orgChild4?.ancestorDNA ?? null,
|
||||||
|
shortName:
|
||||||
|
[
|
||||||
|
draftPosMaster.orgChild4?.orgChild4ShortName,
|
||||||
|
draftPosMaster.orgChild3?.orgChild3ShortName,
|
||||||
|
draftPosMaster.orgChild2?.orgChild2ShortName,
|
||||||
|
draftPosMaster.orgChild1?.orgChild1ShortName,
|
||||||
|
draftPosMaster.orgRoot?.orgRootShortName,
|
||||||
|
].find((s) => typeof s === "string" && s.trim().length > 0) ?? null,
|
||||||
|
posMasterNoPrefix: draftPosMaster.posMasterNoPrefix ?? null,
|
||||||
|
posMasterNo: draftPosMaster.posMasterNo ?? null,
|
||||||
|
posMasterNoSuffix: draftPosMaster.posMasterNoSuffix ?? null,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -8738,7 +8814,7 @@ export class OrganizationController extends Controller {
|
||||||
for (let i = 0; i < allToUpdate.length; i += batchSize) {
|
for (let i = 0; i < allToUpdate.length; i += batchSize) {
|
||||||
const batch = allToUpdate.slice(i, i + batchSize);
|
const batch = allToUpdate.slice(i, i + batchSize);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
batch.map(({ id, data }) => queryRunner.manager.update(Position, id, data))
|
batch.map(({ id, data }) => queryRunner.manager.update(Position, id, data)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
updatedCount = allToUpdate.length;
|
updatedCount = allToUpdate.length;
|
||||||
|
|
@ -8759,8 +8835,17 @@ export class OrganizationController extends Controller {
|
||||||
const profileUpdateEntries = Array.from(profileUpdates.entries());
|
const profileUpdateEntries = Array.from(profileUpdates.entries());
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
profileUpdateEntries.map(([profileId, data]) =>
|
profileUpdateEntries.map(([profileId, data]) =>
|
||||||
queryRunner.manager.update(Profile, profileId, data)
|
queryRunner.manager.update(Profile, profileId, data),
|
||||||
)
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save PosMasterHistory for updated positions
|
||||||
|
if (historyCalls.length > 0) {
|
||||||
|
await Promise.all(
|
||||||
|
historyCalls.map(({ ancestorDNA, profileId, historyData }) =>
|
||||||
|
SavePosMasterHistoryOfficer(queryRunner, ancestorDNA, profileId, historyData),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,3 +22,23 @@ export interface AllOrgMappings {
|
||||||
orgChild3: OrgIdMapping;
|
orgChild3: OrgIdMapping;
|
||||||
orgChild4: OrgIdMapping;
|
orgChild4: OrgIdMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SavePosMasterHistory {
|
||||||
|
prefix: string | null;
|
||||||
|
firstName: string | null;
|
||||||
|
lastName: string | null;
|
||||||
|
position: string | null;
|
||||||
|
posType: string | null;
|
||||||
|
posLevel: string | null;
|
||||||
|
posExecutive: string | null;
|
||||||
|
profileId: string | null;
|
||||||
|
rootDnaId: string | null;
|
||||||
|
child1DnaId: string | null;
|
||||||
|
child2DnaId: string | null;
|
||||||
|
child3DnaId: string | null;
|
||||||
|
child4DnaId: string | null;
|
||||||
|
shortName: string | null;
|
||||||
|
posMasterNoPrefix: string | null;
|
||||||
|
posMasterNo: string | null;
|
||||||
|
posMasterNoSuffix: string | null;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { SavePosMasterHistory } from "./../interfaces/OrgMapping";
|
||||||
import { AppDataSource } from "../database/data-source";
|
import { AppDataSource } from "../database/data-source";
|
||||||
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
|
import { EmployeePosMaster } from "../entities/EmployeePosMaster";
|
||||||
import { EmployeeTempPosMaster } from "../entities/EmployeeTempPosMaster";
|
import { EmployeeTempPosMaster } from "../entities/EmployeeTempPosMaster";
|
||||||
|
|
@ -44,9 +45,9 @@ export async function CreatePosMasterHistoryOfficer(
|
||||||
where: {
|
where: {
|
||||||
id: pm.orgRevisionId,
|
id: pm.orgRevisionId,
|
||||||
orgRevisionIsCurrent: true,
|
orgRevisionIsCurrent: true,
|
||||||
orgRevisionIsDraft: false
|
orgRevisionIsDraft: false,
|
||||||
}
|
},
|
||||||
})
|
});
|
||||||
const _null: any = null;
|
const _null: any = null;
|
||||||
const h = new PosMasterHistory();
|
const h = new PosMasterHistory();
|
||||||
const selectedPosition =
|
const selectedPosition =
|
||||||
|
|
@ -260,3 +261,62 @@ export async function getTopDegrees(educations: ProfileEducation[]): Promise<str
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join("\n");
|
.join("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function SavePosMasterHistoryOfficer(
|
||||||
|
queryRunner: any,
|
||||||
|
posMasterDnaId: string,
|
||||||
|
profileId: string | null,
|
||||||
|
pm: SavePosMasterHistory | null,
|
||||||
|
): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
// Type workaround: entity columns are nullable but types don't reflect it
|
||||||
|
const _null: any = null;
|
||||||
|
const repoPosMasterHistory = queryRunner.manager.getRepository(PosMasterHistory);
|
||||||
|
const pmh = await repoPosMasterHistory.findOne({
|
||||||
|
where: {
|
||||||
|
ancestorDNA: posMasterDnaId,
|
||||||
|
},
|
||||||
|
order: { createdAt: "DESC" },
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check if we need to insert a new history record
|
||||||
|
const shouldInsert = !pmh && profileId && pm;
|
||||||
|
const profileChanged = pmh && pmh.profileId !== profileId;
|
||||||
|
|
||||||
|
if (shouldInsert || profileChanged) {
|
||||||
|
// insert new record
|
||||||
|
const newPmh = new PosMasterHistory();
|
||||||
|
newPmh.ancestorDNA = posMasterDnaId;
|
||||||
|
newPmh.prefix = pm?.prefix ?? _null;
|
||||||
|
newPmh.firstName = pm?.firstName ?? _null;
|
||||||
|
newPmh.lastName = pm?.lastName ?? _null;
|
||||||
|
newPmh.position = pm?.position ?? _null;
|
||||||
|
newPmh.posType = pm?.posType ?? _null;
|
||||||
|
newPmh.posLevel = pm?.posLevel ?? _null;
|
||||||
|
newPmh.posExecutive = pm?.posExecutive ?? _null;
|
||||||
|
newPmh.profileId = profileId ?? _null;
|
||||||
|
newPmh.rootDnaId = pm?.rootDnaId ?? _null;
|
||||||
|
newPmh.child1DnaId = pm?.child1DnaId ?? _null;
|
||||||
|
newPmh.child2DnaId = pm?.child2DnaId ?? _null;
|
||||||
|
newPmh.child3DnaId = pm?.child3DnaId ?? _null;
|
||||||
|
newPmh.child4DnaId = pm?.child4DnaId ?? _null;
|
||||||
|
newPmh.shortName = pm?.shortName ?? _null;
|
||||||
|
newPmh.posMasterNoPrefix = pm?.posMasterNoPrefix ?? _null;
|
||||||
|
newPmh.posMasterNo = pm?.posMasterNo ?? _null;
|
||||||
|
newPmh.posMasterNoSuffix = pm?.posMasterNoSuffix ?? _null;
|
||||||
|
// Add audit fields for data integrity
|
||||||
|
newPmh.createdUserId = "system";
|
||||||
|
newPmh.createdFullName = "system";
|
||||||
|
newPmh.lastUpdateUserId = "system";
|
||||||
|
newPmh.lastUpdateFullName = "system";
|
||||||
|
newPmh.createdAt = new Date();
|
||||||
|
newPmh.lastUpdatedAt = new Date();
|
||||||
|
await queryRunner.manager.save(PosMasterHistory, newPmh);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
console.error("SavePosMasterHistoryOfficer error:", err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue