import { Inject, Injectable } from '@nestjs/common'; import { UserData } from '../../user/entity/user.entity'; import * as moment from 'moment'; import { ListMasterService } from 'src/module/listmaster/service/list-master.service'; import { ModuleRef } from '@nestjs/core'; import { AttributeMasterRepository } from '../repository/attribute-master.repository'; import { ReflectionHelper } from 'src/utils/service/reflection-helper.service'; import { EntityMasterRepository } from '../repository/entity-master.repository'; import { EntityManager } from 'typeorm'; @Injectable() export class ResolverService { private mediaDataService: any; constructor( @Inject('ListMasterService') private readonly listMasterService: ListMasterService, private readonly moduleRef: ModuleRef, private readonly attributeMasterRepo: AttributeMasterRepository, private readonly reflectionHelper: ReflectionHelper, private readonly entityMasterRepo: EntityMasterRepository, private readonly entityManger: EntityManager, ) {} private async getMediaDataService() { if (!this.mediaDataService) { const { MediaDataService } = await import('./media-data.service'); this.mediaDataService = this.moduleRef.get(MediaDataService, { strict: false, }); } return this.mediaDataService; } async getResolvedData( loggedInUser: any, entityData: any, entityType: string, ): Promise { const attributeItems = await this.attributeMasterRepo.findAttributesByMappedEntityType( entityType, loggedInUser, ); const resolvedEntityData = { ...entityData }; for (const attr of attributeItems) { const field = attr.attribute_key; const codeValue = entityData[field]; if (!codeValue) continue; // -------- ENTITY or MASTER via getDropdownOptions -------- if ( attr.data_source_type === 'entity' || (attr.data_source_type === 'master' && attr.category != 'Internal') ) { const type = attr.data_source_type === 'entity' ? attr.datasource_list : attr.datasource_list; const params = {}; // you can pass any additional filters here if (Array.isArray(codeValue)) { const resolvedValues: string[] = []; for (const code of codeValue) { const options = await this.listMasterService.getDropdownOptions( type, params, undefined, loggedInUser, ); const item = options.find( (opt) => opt.value == code || opt.code == code, ); resolvedValues.push(item?.label ?? code); } // make resolved values to a comma separated string resolvedEntityData[field] = resolvedValues.join(', '); } else { // if we r resolving a ListMaster then we get the name of the item from ListMasterItems table directly if ( attr.data_source_type === 'master' && Number.isInteger(Number(codeValue)) ) { const listMasterItemsRepo = this.reflectionHelper.getRepoService('ListMasterItems'); const item = await listMasterItemsRepo.findOne({ where: { id: codeValue, }, select: ['name'], }); resolvedEntityData[field] = item?.name ?? codeValue; } else { // ENTITY handling here const options = await this.listMasterService.getDropdownOptions( type, params, undefined, loggedInUser, ); const item = options.find( (opt) => opt.value == codeValue || opt.code == codeValue, ); resolvedEntityData[field] = Array.isArray(item) ? (item?.[attr.data_source_attribute] ?? codeValue) : (item?.label ?? codeValue); // } } } } // -------- DATE / DATETIME -------- else if ( attr.element_type === 'date' || attr.element_type === 'datetime' ) { // Allow both DD-MM-YYYY and standard ISO YYYY-MM-DD const allowedFormats = attr.element_type === 'date' ? ['DD-MM-YYYY', 'YYYY-MM-DD'] : ['DD-MM-YYYY HH:mm:ss', 'YYYY-MM-DD HH:mm:ss', moment.ISO_8601]; // strict parsing enabled const dateValue = moment(codeValue, allowedFormats, true).utcOffset( '+05:30', ); if (dateValue.isValid()) { resolvedEntityData[field] = attr.element_type === 'date' ? dateValue.format('DD-MMM-YYYY') : dateValue.format('DD-MMM-YYYY HH:mm:ss'); } else { // fallback: return original value resolvedEntityData[field] = codeValue; } } // --------UPLOAD / IMAGE -------- else if ( attr.element_type === 'upload' || attr.element_type === 'image' ) { const mediaService = await this.getMediaDataService(); let uploadData: any; if (typeof resolvedEntityData[field] !== 'object') { uploadData = await mediaService.getMediaDownloadUrl( resolvedEntityData[field], loggedInUser, ); } else { uploadData = resolvedEntityData[field]; } resolvedEntityData[field] = uploadData; } } return resolvedEntityData; } async getResolvedValue( loggedInUser: UserData, attrKey: string, rawValue: any, entityType: string, ): Promise { if (rawValue === null || rawValue === undefined || rawValue === '') { return rawValue; } // fetch attribute meta only for the given attributeKey const attr = await this.attributeMasterRepo.findByMappedEntityTypeAndAttributeKeyAndOrganizationId( entityType, attrKey, loggedInUser.enterprise_id, ); if (!attr) return rawValue; // ----------- ENTITY TYPE RESOLUTION ------------------- if (attr.data_source_type === 'entity') { const entityDef = await this.entityMasterRepo.getEntityByMappedEntityType( attr.datasource_list, loggedInUser.enterprise_id, ); if (!entityDef) return rawValue; const tableName = entityDef.db_table_name; // --- If array (multi-select) --- if (Array.isArray(rawValue)) { const resolvedValues: string[] = []; for (const value of rawValue) { const query = tableName === 'sso_organization' ? `SELECT * FROM ${tableName} WHERE code = $1` : `SELECT * FROM ${tableName} WHERE id = $1`; const [item] = await this.entityManger.query(query, [value]); resolvedValues.push(item?.[attr.data_source_attribute] ?? value); } return resolvedValues; } // --- Single value --- const query = `SELECT * FROM ${tableName} WHERE id = $1`; const [item] = await this.entityManger.query(query, [rawValue]); return item?.[attr.data_source_attribute] ?? rawValue; } // ----------- MASTER TYPE RESOLUTION ------------------- if (attr.data_source_type === 'master') { const repo = this.reflectionHelper.getRepoService('ListMasterItems'); let value = rawValue; // 🟦 If rawValue is a JSON string representing array → parse it if (typeof rawValue === 'string') { try { const parsed = JSON.parse(rawValue); if (Array.isArray(parsed)) value = parsed; } catch (e) { // keep as string } } // 🟩 If value is array → resolve each if (Array.isArray(value)) { const resolvedValues: string[] = []; for (const id of value) { const item = await repo.findOne({ where: { id: Number(id) }, }); resolvedValues.push(item?.[attr.data_source_attribute] ?? id); } return resolvedValues; } // 🟨 Single value (must be number) if (!isNaN(rawValue)) { const item = await repo.findOne({ where: { id: Number(rawValue) }, }); return item?.[attr.data_source_attribute] ?? rawValue; } return rawValue; } return rawValue; } async getResolvedId( loggedInUser: UserData, attrKey: string, displayValue: any, entityType: string, ): Promise { if ( displayValue === null || displayValue === undefined || displayValue === '' ) { return displayValue; } // fetch attribute meta const attr = await this.attributeMasterRepo.findByMappedEntityTypeAndAttributeKeyAndOrganizationId( entityType, attrKey, loggedInUser.enterprise_id, ); if (!attr) return displayValue; // -------- ENTITY data_source_type -------- if (attr.data_source_type === 'entity') { const entityDef = await this.entityMasterRepo.getEntityByMappedEntityType( attr.datasource_list, loggedInUser.enterprise_id, ); if (!entityDef) return displayValue; const tableName = entityDef.db_table_name; const query = tableName === 'sso_organization' ? `SELECT id FROM ${tableName} WHERE ${attr.data_source_attribute} = $1` : `SELECT id FROM ${tableName} WHERE ${attr.data_source_attribute} = $1 AND enterprise_id = $2`; const params = tableName === 'sso_organization' ? [displayValue] : [displayValue, loggedInUser.enterprise_id]; const [item] = await this.entityManger.query(query, params); return item?.id ?? displayValue; } // -------- MASTER data_source_type -------- else if (attr.data_source_type === 'master') { const listMasterItemsRepo = this.reflectionHelper.getRepoService('ListMasterItems'); const item = await listMasterItemsRepo.findOne({ where: { [attr.data_source_attribute]: displayValue, enterprise_id: loggedInUser.enterprise_id, listtype: attr.datasource_list, }, }); return item?.id ?? displayValue; } return displayValue; } }