import { BadRequestException, Injectable } from '@nestjs/common'; import { In } from 'typeorm'; import { UserData } from 'src/module/user/entity/user.entity'; import { ReflectionHelper } from '../../../utils/service/reflection-helper.service'; @Injectable() export class ActionRepository { constructor(private readonly reflectionHelper: ReflectionHelper) {} async getReasonCode(loggedInUser: UserData): Promise { const { organization_id } = loggedInUser; const listMasterRepo = this.reflectionHelper.getRepoService('ListMasterData'); const result = await listMasterRepo.find({ where: { organization_id, source: 'master', }, }); const formatted = result.map((item: any) => ({ label: item.name, value: item.type, })); return formatted; } async defaultReasonCode(list_type: string, loggedInUser: UserData) { const { organization_id } = loggedInUser; if (!list_type) { throw new BadRequestException('list_type is required'); } const listMasterItemsRepo = this.reflectionHelper.getRepoService('ListMasterItems'); const result = await listMasterItemsRepo.find({ where: { listtype: list_type, organization_id, }, }); // Format as array of key-value pairs return result.map((row: any) => ({ label: row.name, value: row.id, })); } async getActions(loggedInUser: UserData, stage_id: number) { const { organization_id } = loggedInUser; const workflowStageActionRepo = this.reflectionHelper.getRepoService('StageActionMapping'); // Step 1: Get all action_ids for the provided stage_id const stageActions = await workflowStageActionRepo.find({ where: { stage_id: stage_id, }, }); if (!stageActions?.length) return []; const actionIds = stageActions.map((sa) => sa.action_id); const mappingIds = stageActions.map((sa) => sa.id); // Step 2: Get template codes with mapping IDs const workflowActionTemplateMappingRepo = this.reflectionHelper.getRepoService('ActionTemplateMapping'); const templateMappings = await workflowActionTemplateMappingRepo.find({ where: { stg_act_mapping_id: In(mappingIds), }, }); const templateCodes = templateMappings.map((tm) => tm.template_code); // Step 3: Fetch template names from frm_wf_comm_template const templateCodeToName: Record = {}; const workflowCommTemplateRepo = this.reflectionHelper.getRepoService('CommTemplate'); if (templateCodes.length > 0) { const templates = await workflowCommTemplateRepo.find({ where: { code: In(templateCodes), organization_id: organization_id, }, }); templates.forEach((tpl) => { templateCodeToName[tpl.code] = tpl.name; }); } // Step 4: Build map of mapping_id → template names const mappingIdToTemplates: Record = {}; for (const tm of templateMappings) { const mappingId = tm.stg_act_mapping_id; const name = templateCodeToName[tm.template_code]; if (name) { if (!mappingIdToTemplates[mappingId]) { mappingIdToTemplates[mappingId] = []; } mappingIdToTemplates[mappingId].push(name); } } // Step 5: Build action_id → template names using mappingIdToTemplates + stageActions const actionIdToTemplates: Record = {}; for (const sa of stageActions) { const mappingId = sa.id; const templates = mappingIdToTemplates[mappingId]; if (templates?.length) { if (!actionIdToTemplates[sa.action_id]) { actionIdToTemplates[sa.action_id] = []; } actionIdToTemplates[sa.action_id].push(...templates); } } // Step 6: Fetch action details const workflowActionRepo = this.reflectionHelper.getRepoService('ActionEntity'); const actionResults = await workflowActionRepo .createQueryBuilder() .select([ 'DISTINCT ON (a.id) a.*', 'ac.name AS action_category', 'ac.modalname AS modalname', 'ar.name AS action_requirement', ]) .from('frm_wf_action', 'a') .leftJoin( 'frm_wf_action_category', 'ac', 'ac.id::text = a.action_category', ) .leftJoin( 'frm_list_master_items', 'ar', `ar.id::text = a.action_requirement AND ar.listtype = 'ACRQ' AND ar.organization_id = :orgId`, { orgId: organization_id }, ) .where('a.organization_id = :orgId', { orgId: organization_id }) .andWhere('a.id::text IN (:...actionIds)', { actionIds }) .getRawMany(); // Step 7: Enrich result with template field const enrichedResult = actionResults.map((row) => { const actionId = Number(row.id); // Ensure numeric ID match const templates = actionIdToTemplates[actionId] || []; const uniqueTemplates = [...new Set(templates)]; // remove duplicates return { ...row, template: uniqueTemplates.join(', '), }; }); return enrichedResult; } async getDependentActions( loggedInUser: UserData, stage_id: number, action_id?: number, ) { // Step 1: Get all action_ids for the provided stage_id let stageActionMappingRepo = this.reflectionHelper.getRepoService('StageActionMapping'); const stageActions = await stageActionMappingRepo.find({ where: { stage_id: stage_id, }, }); if (!stageActions?.length) return []; const actionIds = stageActions.map((sa) => sa.action_id); // Step 2: Fetch action details except the provided action_id incase it is provided const filteredActionIds = action_id ? actionIds.filter((id) => id != action_id) : actionIds; let actionResults; if (filteredActionIds.length === 0) { return []; } const actionRepo = this.reflectionHelper.getRepoService('ActionEntity'); actionResults = await actionRepo .createQueryBuilder('a') .select(['a.id AS action_id', 'a.name AS action_name']) .where('a.id IN(:...actionIds)', { actionIds: filteredActionIds }) .getRawMany(); // Step 3: Format result const enrichedResult = actionResults.map((row) => ({ value: row.action_id, label: row.action_name, })); return enrichedResult; } async getAction( organization_id: number, stage_id: number, mapped_entity_id: number, mapped_entity_type: string, ) { // Step 1: Get all action mappings for the stage const stageActionMappingRepo = this.reflectionHelper.getRepoService('StageActionMapping'); const stageActions = await stageActionMappingRepo.find({ where: { stage_id: stage_id, }, }); if (!stageActions?.length) { return [ { value: '0', label: 'Generic', }, ]; } const actionIds = stageActions.map((sa) => sa.action_id); // Step 2: Fetch all actions with category details const actionRepo = this.reflectionHelper.getRepoService('ActionEntity'); const actions = await actionRepo .createQueryBuilder('a') .select([ 'a.id AS action_id', 'a.name AS action_name', 'a.reason_code AS action_reason_code', 'a.default_reason_code AS default_reason_code', 'a.default_value AS default_value', 'a.mode AS mode', 'a.action_category AS action_category_id', 'ac.reason_code AS category_reason_code', 'ac.modalname AS modalname', 'ac.logo AS logo', 'ac.name AS action_category_name', 'a.dependent_action_id AS dependent_action_id', ]) .leftJoin( 'frm_wf_action_category', 'ac', 'ac.id = a.action_category::bigint', ) .where('a.organization_id = :orgId', { orgId: organization_id }) .andWhere('a.id IN (:...actionIds)', { actionIds }) .orderBy('a.sequence', 'ASC') .getRawMany(); // Step 3: Fetch action_data const actionDataRepo = this.reflectionHelper.getRepoService('ActionDataEntity'); const actionData = await actionDataRepo .createQueryBuilder('ad') .select([ 'ad.action_id AS action_id', 'ad.is_current AS is_current', 'ad.is_mandatory AS is_mandatory', 'ad.is_done AS is_done', ]) .where('ad.stage_id = :stageId', { stageId: stage_id }) .andWhere('ad.action_id IN (:...actionIds)', { actionIds }) .andWhere('ad.mapped_entity_id = :mapped_entity_id', { mapped_entity_id }) .andWhere('ad.mapped_entity_type = :mapped_entity_type', { mapped_entity_type, }) .getRawMany(); const actionIdToData = actionData.reduce((acc, row) => { acc[row.action_id] = { is_current: row.is_current === 'Y', is_mandatory: row.is_mandatory, is_done: row.is_done, }; return acc; }, {}); // Step 5: Enrich actions const enrichedResult = actions.map((row) => { const data = actionIdToData[row.action_id]; const reason_code = row.action_reason_code && row.action_reason_code.trim() ? row.action_reason_code : row.category_reason_code; return { value: row.action_id, dependent_action_id: row.dependent_action_id, label: row.action_name, modalname: row.modalname, logo: row.logo, mode: row.mode, name: row.action_category_name, reason_code, default_reason_code: row.default_reason_code, is_default: row.default_value, is_current: data?.is_current, is_done: data?.is_done, is_mandatory: data?.is_mandatory, }; }); // Step 6: Add fallback option enrichedResult.push({ value: '0', label: 'Generic', } as any); return enrichedResult; } }