2025-08-13 16:47:01 +07:00
import { Controller , Route , Security , Tags , Path , Request , Response , Get , Query } from "tsoa" ;
2025-08-07 13:05:58 +07:00
import { AppDataSource } from "../database/data-source" ;
import HttpSuccess from "../interfaces/http-success" ;
import HttpStatusCode from "../interfaces/http-status" ;
import HttpError from "../interfaces/http-error" ;
import { ApiName } from "../entities/ApiName" ;
2025-08-08 09:26:48 +07:00
import { isPermissionRequest } from "../middlewares/authWebService" ;
import { RequestWithUserWebService } from "../middlewares/user" ;
2025-08-08 17:14:29 +07:00
import { OrgRevision } from "../entities/OrgRevision" ;
2025-08-13 16:14:44 +07:00
import { ApiHistory } from "../entities/ApiHistory" ;
2025-08-14 11:17:13 +07:00
import { SystemCode } from "./../interfaces/api-type" ;
@Route ( "api/v1/org/api-service" )
2025-08-07 13:05:58 +07:00
@Tags ( "ApiKey" )
2025-08-08 09:26:48 +07:00
@Security ( "webServiceAuth" )
2025-08-07 13:05:58 +07:00
@Response (
HttpStatusCode . INTERNAL_SERVER_ERROR ,
"เกิดข้อผิดพลาด ไม่สามารถแสดงรายการได้ กรุณาลองใหม่ในภายหลัง" ,
)
export class ApiWebServiceController extends Controller {
private apiNameRepository = AppDataSource . getRepository ( ApiName ) ;
2025-08-08 17:14:29 +07:00
private orgRevisionRepository = AppDataSource . getRepository ( OrgRevision ) ;
2025-08-13 16:14:44 +07:00
private apiHistoryRepository = AppDataSource . getRepository ( ApiHistory ) ;
2026-05-21 11:44:28 +07:00
private currentRevisionId : string = "" ;
2025-08-13 16:14:44 +07:00
2026-05-21 11:07:15 +07:00
// การแทนที่ฟิลด์ ID ด้วยฟิลด์ Name สำหรับ Profile entity
private readonly PROFILE_FIELD_REPLACEMENTS : Record <
string ,
{ propertyName : string ; joinRelation : string ; joinField : string }
> = {
posLevelName : {
propertyName : "posLevelId" ,
joinRelation : "posLevel" ,
joinField : "posLevelName" ,
} ,
posTypeName : {
propertyName : "posTypeId" ,
joinRelation : "posType" ,
joinField : "posTypeName" ,
} ,
registrationProvinceName : {
propertyName : "registrationProvinceId" ,
joinRelation : "registrationProvince" ,
joinField : "name" ,
} ,
registrationDistrictName : {
propertyName : "registrationDistrictId" ,
joinRelation : "registrationDistrict" ,
joinField : "name" ,
} ,
registrationSubDistrictName : {
propertyName : "registrationSubDistrictId" ,
joinRelation : "registrationSubDistrict" ,
joinField : "name" ,
} ,
currentProvinceName : {
propertyName : "currentProvinceId" ,
joinRelation : "currentProvince" ,
joinField : "name" ,
} ,
currentDistrictName : {
propertyName : "currentDistrictId" ,
joinRelation : "currentDistrict" ,
joinField : "name" ,
} ,
currentSubDistrictName : {
propertyName : "currentSubDistrictId" ,
joinRelation : "currentSubDistrict" ,
joinField : "name" ,
} ,
} ;
2026-05-21 13:44:03 +07:00
// การแทนที่ฟิลด์ ID ด้วยฟิลด์ Name สำหรับ Position entity
private readonly POSITION_FIELD_REPLACEMENTS : Record <
string ,
{ propertyName : string ; joinRelation : string ; joinField : string }
> = {
posTypeName : {
propertyName : "posTypeId" ,
joinRelation : "posType" ,
joinField : "posTypeName" ,
} ,
posLevelName : {
propertyName : "posLevelId" ,
joinRelation : "posLevel" ,
joinField : "posLevelName" ,
} ,
posExecutiveName : {
propertyName : "posExecutiveId" ,
joinRelation : "posExecutive" ,
joinField : "posExecutiveName" ,
} ,
} ;
2026-05-21 11:44:28 +07:00
/ * *
* build posMaster permission condition
* @summary ส ร ้ า ง เ ง ื ่ อ น ไ ข ก า ร ก ร อ ง ข ้ อ ม ู ล ต า ม ส ิ ท ธ ิ ์ ก า ร เ ข ้ า ถ ึ ง
* /
private buildPosMasterPermissionCondition (
accessType : string | undefined ,
dnaIds : {
dnaRootId? : string | null ;
dnaChild1Id? : string | null ;
dnaChild2Id? : string | null ;
dnaChild3Id? : string | null ;
dnaChild4Id? : string | null ;
} ,
2026-05-21 13:44:03 +07:00
tableAlias : string = "posMaster" ,
2026-05-21 11:44:28 +07:00
) : string {
// ALL - no filtering
if ( accessType === "ALL" ) {
return "1=1" ;
}
// No access type specified but has DNA IDs - default to NORMAL behavior
const conditions : string [ ] = [ ] ;
if ( accessType === "ROOT" && dnaIds . dnaRootId ) {
// All organizations under this root
conditions . push (
2026-05-21 13:44:03 +07:00
` ${ tableAlias } .orgRootId IN (SELECT id FROM orgRoot WHERE orgRevisionId = " ${ this . currentRevisionId } " AND ancestorDNA LIKE " ${ dnaIds . dnaRootId } %") ` ,
2026-05-21 11:44:28 +07:00
) ;
} else if ( accessType === "CHILD" || accessType === "NORMAL" ) {
// Build conditions based on which DNA level is specified
if ( dnaIds . dnaChild4Id ) {
conditions . push (
2026-05-21 13:44:03 +07:00
` ${ tableAlias } .orgChild4Id IN (SELECT id FROM orgChild4 WHERE orgRevisionId = " ${ this . currentRevisionId } " AND ancestorDNA = " ${ dnaIds . dnaChild4Id } ") ` ,
2026-05-21 11:44:28 +07:00
) ;
} else if ( dnaIds . dnaChild3Id ) {
conditions . push (
2026-05-21 13:44:03 +07:00
` ${ tableAlias } .orgChild3Id IN (SELECT id FROM orgChild3 WHERE orgRevisionId = " ${ this . currentRevisionId } " AND ancestorDNA = " ${ dnaIds . dnaChild3Id } ") ` ,
2026-05-21 11:44:28 +07:00
) ;
// For CHILD type, include all descendants
if ( accessType === "CHILD" ) {
conditions . push (
2026-05-21 13:44:03 +07:00
` ( ${ tableAlias } .orgChild3Id IN (SELECT id FROM orgChild3 WHERE orgRevisionId = " ${ this . currentRevisionId } " AND ancestorDNA LIKE " ${ dnaIds . dnaChild3Id } %") OR ${ tableAlias } .orgChild4Id IS NOT NULL) ` ,
2026-05-21 11:44:28 +07:00
) ;
}
} else if ( dnaIds . dnaChild2Id ) {
conditions . push (
2026-05-21 13:44:03 +07:00
` ${ tableAlias } .orgChild2Id IN (SELECT id FROM orgChild2 WHERE orgRevisionId = " ${ this . currentRevisionId } " AND ancestorDNA = " ${ dnaIds . dnaChild2Id } ") ` ,
2026-05-21 11:44:28 +07:00
) ;
if ( accessType === "CHILD" ) {
conditions . push (
2026-05-21 13:44:03 +07:00
` ( ${ tableAlias } .orgChild2Id IN (SELECT id FROM orgChild2 WHERE orgRevisionId = " ${ this . currentRevisionId } " AND ancestorDNA LIKE " ${ dnaIds . dnaChild2Id } %") OR ${ tableAlias } .orgChild3Id IS NOT NULL) ` ,
2026-05-21 11:44:28 +07:00
) ;
}
} else if ( dnaIds . dnaChild1Id ) {
conditions . push (
2026-05-21 13:44:03 +07:00
` ${ tableAlias } .orgChild1Id IN (SELECT id FROM orgChild1 WHERE orgRevisionId = " ${ this . currentRevisionId } " AND ancestorDNA = " ${ dnaIds . dnaChild1Id } ") ` ,
2026-05-21 11:44:28 +07:00
) ;
if ( accessType === "CHILD" ) {
conditions . push (
2026-05-21 13:44:03 +07:00
` ( ${ tableAlias } .orgChild1Id IN (SELECT id FROM orgChild1 WHERE orgRevisionId = " ${ this . currentRevisionId } " AND ancestorDNA LIKE " ${ dnaIds . dnaChild1Id } %") OR ${ tableAlias } .orgChild2Id IS NOT NULL) ` ,
2026-05-21 11:44:28 +07:00
) ;
}
} else if ( dnaIds . dnaRootId ) {
conditions . push (
2026-05-21 13:44:03 +07:00
` ${ tableAlias } .orgRootId IN (SELECT id FROM orgRoot WHERE orgRevisionId = " ${ this . currentRevisionId } " AND ancestorDNA = " ${ dnaIds . dnaRootId } ") ` ,
2026-05-21 11:44:28 +07:00
) ;
if ( accessType === "CHILD" ) {
conditions . push (
2026-05-21 13:44:03 +07:00
` ( ${ tableAlias } .orgRootId IN (SELECT id FROM orgRoot WHERE orgRevisionId = " ${ this . currentRevisionId } " AND ancestorDNA LIKE " ${ dnaIds . dnaRootId } %") OR ${ tableAlias } .orgChild1Id IS NOT NULL) ` ,
2026-05-21 11:44:28 +07:00
) ;
}
}
}
return conditions . length > 0 ? ` ( ${ conditions . join ( " OR " ) } ) ` : "1=1" ;
}
2025-08-07 13:05:58 +07:00
/ * *
* list fields by systems
* @summary ร า ย ก า ร fields ต า ม systems
* /
@Get ( "/:system/:code" )
async listAttribute (
2025-08-08 09:26:48 +07:00
@Request ( ) request : RequestWithUserWebService ,
2025-08-14 11:17:13 +07:00
@Path ( "system" )
system : SystemCode ,
2025-08-07 13:05:58 +07:00
@Path ( "code" ) code : string ,
@Query ( "page" ) page : number = 1 ,
@Query ( "pageSize" ) pageSize : number = 100 ,
) : Promise < HttpSuccess | HttpError > {
2025-08-08 17:14:29 +07:00
const apiName = await this . apiNameRepository . findOne ( {
where : { code } ,
select : [ "id" , "code" , "methodApi" , "system" , "isActive" ] ,
relations : [ "apiAttributes" ] ,
order : {
apiAttributes : {
ordering : "ASC" ,
2025-08-07 13:05:58 +07:00
} ,
2025-08-08 17:14:29 +07:00
} ,
} ) ;
if ( ! apiName || apiName . system != system || ! apiName . isActive || apiName . methodApi != "GET" ) {
throw new HttpError ( HttpStatusCode . NOT_FOUND , "ไม่พบ API ที่ระบุ" ) ;
}
await isPermissionRequest ( request , apiName . id ) ;
const offset = ( page - 1 ) * pageSize ;
2026-05-21 11:07:15 +07:00
let propertyKey = apiName . apiAttributes . map ( ( attr ) = > ` ${ attr . tbName } . ${ attr . propertyKey } ` ) ;
2025-08-07 13:05:58 +07:00
2025-08-14 11:17:13 +07:00
let tbMain : string = "" ;
2025-08-13 16:47:01 +07:00
let condition : string = "1=1" ;
2025-08-08 17:14:29 +07:00
if ( system == "registry" ) {
2025-08-14 11:17:13 +07:00
tbMain = "Profile" ;
2025-08-13 16:47:01 +07:00
} else if ( system == "registry_emp" ) {
2025-08-14 11:17:13 +07:00
tbMain = "ProfileEmployee" ;
2025-08-13 16:47:01 +07:00
condition = ` ProfileEmployee.employeeClass = "PERM" ` ;
} else if ( system == "registry_temp" ) {
2025-08-14 11:17:13 +07:00
tbMain = "ProfileEmployee" ;
2025-08-13 16:47:01 +07:00
condition = ` ProfileEmployee.employeeClass = "TEMP" ` ;
2025-08-14 12:20:59 +07:00
} else if ( system == "organization" ) {
2025-08-14 11:17:13 +07:00
tbMain = "OrgRoot" ;
2025-08-08 17:14:29 +07:00
const revision = await this . orgRevisionRepository . findOne ( {
2025-08-13 16:47:01 +07:00
select : [ "id" ] ,
where : { orgRevisionIsCurrent : true , orgRevisionIsDraft : false } ,
} ) ;
condition = ` OrgRoot.orgRevisionId = " ${ revision ? . id } " ` ;
2025-08-14 12:20:59 +07:00
} else if ( system == "position" ) {
tbMain = "PosMaster" ;
const revision = await this . orgRevisionRepository . findOne ( {
select : [ "id" ] ,
where : { orgRevisionIsCurrent : true , orgRevisionIsDraft : false } ,
} ) ;
condition = ` PosMaster.orgRevisionId = " ${ revision ? . id } " ` ;
2025-08-08 17:14:29 +07:00
}
2025-08-13 11:45:34 +07:00
2026-05-21 11:44:28 +07:00
let posMasterCondition : string = "" ;
2026-05-21 13:44:03 +07:00
let posMasterAlias : string = "" ;
2026-05-21 11:44:28 +07:00
2026-05-21 13:44:03 +07:00
// Special handling for Profile and ProfileEmployee systems with permission filtering
2026-05-21 11:44:28 +07:00
if ( system == "registry" ) {
// Get current revision
const revision = await this . orgRevisionRepository . findOne ( {
select : [ "id" ] ,
where : { orgRevisionIsCurrent : true , orgRevisionIsDraft : false } ,
} ) ;
// Store for use in permission building
this . currentRevisionId = revision ? . id || "" ;
2026-05-21 13:44:03 +07:00
posMasterAlias = "posMaster" ;
2026-05-21 11:44:28 +07:00
// Build permission condition
2026-05-21 13:44:03 +07:00
posMasterCondition = this . buildPosMasterPermissionCondition (
request . user . accessType ,
{
dnaRootId : request.user.dnaRootId ,
dnaChild1Id : request.user.dnaChild1Id ,
dnaChild2Id : request.user.dnaChild2Id ,
dnaChild3Id : request.user.dnaChild3Id ,
dnaChild4Id : request.user.dnaChild4Id ,
} ,
posMasterAlias ,
) ;
} else if ( system == "registry_emp" ) {
// Get current revision
const revision = await this . orgRevisionRepository . findOne ( {
select : [ "id" ] ,
where : { orgRevisionIsCurrent : true , orgRevisionIsDraft : false } ,
} ) ;
// Store for use in permission building
this . currentRevisionId = revision ? . id || "" ;
posMasterAlias = "employeePosMaster" ;
// Build permission condition
posMasterCondition = this . buildPosMasterPermissionCondition (
request . user . accessType ,
{
dnaRootId : request.user.dnaRootId ,
dnaChild1Id : request.user.dnaChild1Id ,
dnaChild2Id : request.user.dnaChild2Id ,
dnaChild3Id : request.user.dnaChild3Id ,
dnaChild4Id : request.user.dnaChild4Id ,
} ,
posMasterAlias ,
) ;
} else if ( system == "registry_temp" ) {
// Get current revision
const revision = await this . orgRevisionRepository . findOne ( {
select : [ "id" ] ,
where : { orgRevisionIsCurrent : true , orgRevisionIsDraft : false } ,
} ) ;
// Store for use in permission building
this . currentRevisionId = revision ? . id || "" ;
posMasterAlias = "employeeTempPosMaster" ;
// Build permission condition
posMasterCondition = this . buildPosMasterPermissionCondition (
request . user . accessType ,
{
dnaRootId : request.user.dnaRootId ,
dnaChild1Id : request.user.dnaChild1Id ,
dnaChild2Id : request.user.dnaChild2Id ,
dnaChild3Id : request.user.dnaChild3Id ,
dnaChild4Id : request.user.dnaChild4Id ,
} ,
posMasterAlias ,
) ;
} else if ( system == "position" ) {
// Get current revision
const revision = await this . orgRevisionRepository . findOne ( {
select : [ "id" ] ,
where : { orgRevisionIsCurrent : true , orgRevisionIsDraft : false } ,
2026-05-21 11:44:28 +07:00
} ) ;
2026-05-21 13:44:03 +07:00
// Store for use in permission building
this . currentRevisionId = revision ? . id || "" ;
posMasterAlias = "PosMaster" ; // Note: Uses PascalCase to match tbMain alias
// Build permission condition
posMasterCondition = this . buildPosMasterPermissionCondition (
request . user . accessType ,
{
dnaRootId : request.user.dnaRootId ,
dnaChild1Id : request.user.dnaChild1Id ,
dnaChild2Id : request.user.dnaChild2Id ,
dnaChild3Id : request.user.dnaChild3Id ,
dnaChild4Id : request.user.dnaChild4Id ,
} ,
posMasterAlias ,
) ;
2026-05-21 11:44:28 +07:00
}
2025-08-14 11:17:13 +07:00
const repo = AppDataSource . getRepository ( tbMain ) ;
2025-08-08 17:14:29 +07:00
const metadata = repo . metadata ;
2025-08-13 16:47:01 +07:00
2025-08-08 17:14:29 +07:00
const relationMap : Record < string , string > = { } ;
metadata . relations . forEach ( ( rel ) = > {
relationMap [ rel . inverseEntityMetadata . name ] = rel . propertyName ;
} ) ;
2025-08-13 16:47:01 +07:00
2025-08-08 17:14:29 +07:00
// ดึงเฉพาะตารางรอง (ถ้าเลือกไว้)
2025-08-13 16:47:01 +07:00
let propertyOtherKey : any [ ] = [ ] ;
2025-08-08 17:14:29 +07:00
propertyOtherKey = [
2025-08-14 11:17:13 +07:00
. . . new Set ( propertyKey . map ( ( x ) = > x . split ( "." ) [ 0 ] ) . filter ( ( tb ) = > tb !== tbMain ) ) ,
2025-08-13 16:47:01 +07:00
] ;
2026-05-21 11:07:15 +07:00
// สำหรับ Profile: ตรวจสอบฟิลด์ที่ต้องการ join และแปลง propertyKey
const profileFieldJoins : Record < string , string > = { } ; // alias -> relationName
if ( tbMain === "Profile" ) {
propertyKey = propertyKey . map ( ( key ) = > {
const [ table , field ] = key . split ( "." ) ;
if ( table === "Profile" ) {
const replacement = this . PROFILE_FIELD_REPLACEMENTS [ field ] ;
if ( replacement ) {
const alias = ` ${ table } _ ${ replacement . joinRelation } ` ;
profileFieldJoins [ alias ] = replacement . joinRelation ;
return ` ${ alias } . ${ replacement . joinField } ` ;
}
}
return key ;
} ) ;
}
2026-05-21 13:44:03 +07:00
// สำหรับ Position: ตรวจสอบฟิลด์ที่ต้องการ join และแปลง propertyKey
const positionFieldJoins : Record < string , string > = { } ; // alias -> relationName
if ( tbMain === "Position" ) {
propertyKey = propertyKey . map ( ( key ) = > {
const [ table , field ] = key . split ( "." ) ;
if ( table === "Position" ) {
const replacement = this . POSITION_FIELD_REPLACEMENTS [ field ] ;
if ( replacement ) {
const alias = ` ${ table } _ ${ replacement . joinRelation } ` ;
positionFieldJoins [ alias ] = replacement . joinRelation ;
return ` ${ alias } . ${ replacement . joinField } ` ;
}
}
return key ;
} ) ;
}
2025-08-14 11:17:13 +07:00
const queryBuilder = repo . createQueryBuilder ( tbMain ) ;
2025-08-07 13:05:58 +07:00
2025-08-08 17:14:29 +07:00
// join กับตารารอง
if ( propertyOtherKey . length > 0 ) {
propertyOtherKey . forEach ( ( tb ) = > {
const relationName = relationMap [ tb ] ;
if ( relationName ) {
2025-08-14 12:20:59 +07:00
queryBuilder . leftJoin (
` ${ tbMain } . ${ relationName === "next_holder" ? "current_holder" : relationName } ` , // เช็คว่าถ้าเป็น next_holder ให้ใช้ current_holder แทน
tb ,
) ;
2025-08-08 17:14:29 +07:00
}
} ) ;
}
2025-08-13 16:47:01 +07:00
2026-05-21 11:07:15 +07:00
// join สำหรับฟิลด์ Profile ที่ต้องการดึงค่าจากตารางอื่น
if ( tbMain === "Profile" && Object . keys ( profileFieldJoins ) . length > 0 ) {
Object . entries ( profileFieldJoins ) . forEach ( ( [ alias , relationName ] ) = > {
queryBuilder . leftJoin ( ` ${ tbMain } . ${ relationName } ` , alias ) ;
} ) ;
}
2026-05-21 13:44:03 +07:00
// join สำหรับฟิลด์ Position ที่ต้องการดึงค่าจากตารางอื่น
if ( tbMain === "Position" && Object . keys ( positionFieldJoins ) . length > 0 ) {
Object . entries ( positionFieldJoins ) . forEach ( ( [ alias , relationName ] ) = > {
queryBuilder . leftJoin ( ` ${ tbMain } . ${ relationName } ` , alias ) ;
} ) ;
}
// join สำหรับ PosMaster เมื่อต้องการดึงค่าจาก Profile (ข้อมูลคนครอง)
const posMasterProfileFields : string [ ] = [ ] ;
if ( tbMain === "PosMaster" ) {
propertyKey . forEach ( ( key ) = > {
if ( key . startsWith ( "Profile." ) ) {
posMasterProfileFields . push ( key ) ;
}
} ) ;
}
// join PosMaster กับ Profile เมื่อมีการขอ Profile fields
if ( tbMain === "PosMaster" && posMasterProfileFields . length > 0 ) {
queryBuilder . leftJoin ( "PosMaster.current_holder" , "Profile" ) ;
}
// join กับ posMaster/employeePosMaster/employeeTempPosMaster เพื่อกรองตามสิทธิ์การเข้าถึง
if ( ( tbMain === "Profile" || tbMain === "ProfileEmployee" ) && posMasterCondition !== "1=1" ) {
if ( tbMain === "Profile" ) {
queryBuilder . leftJoin ( "Profile.current_holders" , "posMaster" ) ;
} else if ( tbMain === "ProfileEmployee" ) {
// Use the correct relation based on posMasterAlias
if ( posMasterAlias === "employeeTempPosMaster" ) {
queryBuilder . leftJoin ( "ProfileEmployee.current_holderTemps" , "employeeTempPosMaster" ) ;
} else {
queryBuilder . leftJoin ( "ProfileEmployee.current_holders" , "employeePosMaster" ) ;
}
}
2026-05-21 11:44:28 +07:00
}
2025-08-13 16:14:44 +07:00
// // เพิ่ม Main.id เพราะจะใช้ pk ในการแมบและนับจำนวน
// if (!propertyKey.includes(`${Main}.id`)) {
// propertyKey.push(`${Main}.id`);
// }
// add FK
2025-08-13 16:47:01 +07:00
let pk : string = "" ;
2025-08-13 16:14:44 +07:00
const primaryColumns = metadata . primaryColumns ;
2025-08-13 16:47:01 +07:00
primaryColumns . forEach ( ( col ) = > {
2025-08-13 16:14:44 +07:00
pk = col . propertyName ;
2025-08-14 11:17:13 +07:00
if ( ! propertyKey . includes ( ` ${ tbMain } . ${ pk } ` ) ) {
propertyKey . push ( ` ${ tbMain } . ${ pk } ` ) ;
2025-08-13 16:14:44 +07:00
}
} ) ;
2025-08-13 11:45:34 +07:00
2025-08-08 17:14:29 +07:00
const [ items , total ] = await queryBuilder
2025-08-13 11:45:34 +07:00
. select ( propertyKey )
2025-08-08 17:14:29 +07:00
. where ( condition )
2026-05-21 11:44:28 +07:00
. andWhere ( posMasterCondition )
2025-08-13 16:14:44 +07:00
. orderBy ( propertyKey [ 0 ] , "ASC" )
2025-08-08 17:14:29 +07:00
. skip ( offset )
. take ( pageSize )
. getManyAndCount ( ) ;
2025-08-13 11:45:34 +07:00
// ลบ Main.id
2025-08-13 16:14:44 +07:00
// const results = items.map(({ id, ...x }) => x);
// const results = items.map(({ pk, ...x }) => x);
// const results = items.map(item => {
// primaryColumns.forEach(col => delete item[col.propertyName]);
// return item;
// });
2025-08-13 16:47:01 +07:00
// split object id ออกก่อน return
const data = items . map ( ( item ) = > {
2026-05-21 11:07:15 +07:00
const { [ pk ] : removedPk , . . . rest } = item ;
// สำหรับ Profile: แปลงฟิลด์ที่มาจาก join กลับเป็นชื่อเดิม
if ( tbMain === "Profile" ) {
const flattened : any = { . . . rest } ;
Object . entries ( this . PROFILE_FIELD_REPLACEMENTS ) . forEach ( ( [ nameField , config ] ) = > {
const alias = ` ${ tbMain } _ ${ config . joinRelation } ` ;
if ( rest [ alias ] && rest [ alias ] [ config . joinField ] !== undefined ) {
flattened [ nameField ] = rest [ alias ] [ config . joinField ] ;
delete flattened [ alias ] ;
}
} ) ;
return flattened ;
}
2026-05-21 13:44:03 +07:00
// สำหรับ Position: แปลงฟิลด์ที่มาจาก join กลับเป็นชื่อเดิม
if ( tbMain === "Position" ) {
const flattened : any = { . . . rest } ;
Object . entries ( this . POSITION_FIELD_REPLACEMENTS ) . forEach ( ( [ nameField , config ] ) = > {
// Remove the original ID field
delete flattened [ config . propertyName ] ;
// Add the name field from joined table
const alias = ` ${ tbMain } _ ${ config . joinRelation } ` ;
if ( rest [ alias ] && rest [ alias ] [ config . joinField ] !== undefined ) {
flattened [ nameField ] = rest [ alias ] [ config . joinField ] ;
}
// Remove the joined table object
delete flattened [ alias ] ;
} ) ;
return flattened ;
}
// สำหรับ PosMaster: แปลงฟิลด์ Profile ที่มาจาก join กลับเป็นฟิลด์ระดับบน
if ( tbMain === "PosMaster" && posMasterProfileFields . length > 0 ) {
const flattened : any = { . . . rest } ;
// Extract Profile fields and add them at top level with "profile_" prefix to avoid conflicts
if ( rest [ "Profile" ] ) {
flattened [ "profile_prefix" ] = rest [ "Profile" ] . prefix ;
flattened [ "profile_rank" ] = rest [ "Profile" ] . rank ;
flattened [ "profile_firstName" ] = rest [ "Profile" ] . firstName ;
flattened [ "profile_lastName" ] = rest [ "Profile" ] . lastName ;
flattened [ "profile_citizenId" ] = rest [ "Profile" ] . citizenId ;
// Remove the nested Profile object
delete flattened [ "Profile" ] ;
}
return flattened ;
}
2026-05-21 11:07:15 +07:00
return rest ;
2025-08-13 16:47:01 +07:00
} ) ;
2025-08-14 12:20:59 +07:00
// console.log("queryBuilder ===> ", queryBuilder.getQuery());
2025-08-13 16:47:01 +07:00
// save api history after query success
2025-08-13 16:14:44 +07:00
const history = {
headerApi : JSON.stringify ( {
host : request.headers.host ,
"x-api-key" : request . headers [ "x-api-key" ] ,
connection : request.headers.connection ,
accept : request.headers.accept ,
} ) ,
tokenApi : Array.isArray ( request . headers [ "x-api-key" ] )
? request . headers [ "x-api-key" ] [ 0 ] || ""
: request . headers [ "x-api-key" ] || "" ,
requestApi : ` ${ request . method } ${ request . protocol } :// ${ request . headers . host } ${ request . originalUrl || request . url } ` ,
responseApi : "OK" ,
ipApi : request.ip ,
codeApi : code ,
apiKeyId : request.user.id ,
apiNameId : apiName.id ,
createdFullName : request.user.name ,
lastUpdateFullName : request.user.name ,
} ;
await this . apiHistoryRepository . save ( history ) ;
2025-08-14 12:20:59 +07:00
2025-08-19 12:07:36 +07:00
// const results = data.map((item) => {
// const flattenedItem: any = {};
// // Extract nested object properties to top level
// Object.keys(item).forEach((key) => {
// const value = item[key];
// if (value && typeof value === "object") {
// // if (Array.isArray(value) && value.length === 1) {
// // // If array has single item, extract it as object
// // Object.assign(flattenedItem, value[0]);
// // } else
// if (!Array.isArray(value)) {
// // Merge nested object properties to top level
// Object.assign(flattenedItem, value);
// } else {
// // Keep arrays with multiple items or empty arrays as is
// flattenedItem[key] = value;
// }
// } else {
// // Keep primitive values as is
// flattenedItem[key] = value;
// }
// });
// return flattenedItem;
// });
return new HttpSuccess ( { data : data , total } ) ;
2025-08-07 13:05:58 +07:00
}
}