번식 능력 검사 리스트 및 보고서 수정

This commit is contained in:
2025-12-22 19:52:38 +09:00
parent d3dda3d929
commit 1644fcf241
15 changed files with 916 additions and 407 deletions

View File

@@ -9,6 +9,8 @@ import { CowModel } from '../cow/entities/cow.entity';
import { FarmModel } from '../farm/entities/farm.entity';
import { GenomeRequestModel } from './entities/genome-request.entity';
import { GenomeTraitDetailModel } from './entities/genome-trait-detail.entity';
import { MptModel } from '../mpt/entities/mpt.entity';
import { GeneDetailModel } from '../gene/entities/gene-detail.entity';
/**
* 낮을수록 좋은 형질 목록 (부호 반전 필요)
@@ -139,6 +141,14 @@ export class GenomeService {
// 농장 정보 Repository
@InjectRepository(FarmModel)
private readonly farmRepository: Repository<FarmModel>,
// 번식능력검사 Repository
@InjectRepository(MptModel)
private readonly mptRepository: Repository<MptModel>,
// 유전자검사 상세 Repository
@InjectRepository(GeneDetailModel)
private readonly geneDetailRepository: Repository<GeneDetailModel>,
) { }
// ============================================
@@ -359,7 +369,11 @@ export class GenomeService {
}[];
// 요약
summary: {
totalRequests: number;
totalCows: number; // 검사 받은 전체 개체 수 (합집합, 중복 제외)
genomeCowCount: number; // 유전체 분석 개체 수
geneCowCount: number; // 유전자검사 개체 수
mptCowCount: number; // 번식능력검사 개체 수
totalRequests: number; // 유전체 의뢰 건수 (기존 호환성)
analyzedCount: number;
pendingCount: number;
mismatchCount: number;
@@ -729,21 +743,79 @@ export class GenomeService {
const mismatchCount = requests.filter(r => r.chipSireName && r.chipSireName !== '일치').length;
const pendingCount = totalRequests - analyzedCount - mismatchCount;
// 성별 체크 - 디버깅 강화
// 실제 성별 값 분석
const sexAnalysis = requests.map(r => ({
cowId: r.cow?.cowId,
cowSex: r.cow?.cowSex,
hasCow: !!r.cow,
}));
// Step 5.1: 검사 유형별 개체 수 계산 (합집합, 중복 제외)
// 농장 소유 개체의 cowId 목록 조회
const farmCows = await this.cowRepository.find({
where: { fkFarmNo: farmNo, delDt: IsNull() },
select: ['cowId', 'cowSex'],
});
const farmCowIds = new Set(farmCows.map(c => c.cowId).filter(Boolean));
const farmCowMap = new Map(farmCows.map(c => [c.cowId, c]));
// 성별 체크 (M/수/1 = 수컷, 그 외 모두 암컷으로 처리)
const maleCount = requests.filter(r => {
const sex = r.cow?.cowSex?.toUpperCase();
return sex === 'M' || sex === '수' || sex === '1';
}).length;
// 수컷이 아니면 모두 암컷으로 처리 (null 포함)
const femaleCount = requests.length - maleCount;
// 각 검사별 cowId 조회 (병렬 처리) - genomeRequest도 포함 (리스트 페이지와 일치)
const [genomeRequestCowIds, genomeCowIds, geneCowIds, mptCowIds] = await Promise.all([
// 유전체 분석 의뢰가 있는 개체 (분석불가 포함)
this.genomeRequestRepository
.createQueryBuilder('request')
.innerJoin('request.cow', 'cow')
.select('DISTINCT cow.cowId', 'cowId')
.where('request.delDt IS NULL')
.getRawMany()
.then(rows => rows.map((r: { cowId: string }) => r.cowId).filter(Boolean)),
// 유전체 분석 개체 (형질 데이터 보유)
this.genomeTraitDetailRepository
.createQueryBuilder('trait')
.select('DISTINCT trait.cowId', 'cowId')
.where('trait.delDt IS NULL')
.getRawMany()
.then(rows => rows.map((r: { cowId: string }) => r.cowId).filter(Boolean)),
// 유전자검사 개체
this.geneDetailRepository
.createQueryBuilder('gene')
.select('DISTINCT gene.cowId', 'cowId')
.where('gene.delDt IS NULL')
.getRawMany()
.then(rows => rows.map((r: { cowId: string }) => r.cowId).filter(Boolean)),
// 번식능력검사 개체
this.mptRepository
.createQueryBuilder('mpt')
.select('DISTINCT mpt.cowId', 'cowId')
.where('mpt.delDt IS NULL')
.getRawMany()
.then(rows => rows.map((r: { cowId: string }) => r.cowId).filter(Boolean)),
]);
// 농장 소유 개체만 필터링
const farmGenomeRequestCowIds = genomeRequestCowIds.filter(id => farmCowIds.has(id));
const farmGenomeCowIds = genomeCowIds.filter(id => farmCowIds.has(id));
const farmGeneCowIds = geneCowIds.filter(id => farmCowIds.has(id));
const farmMptCowIds = mptCowIds.filter(id => farmCowIds.has(id));
// 합집합 계산 (중복 제외) - genomeRequest 포함 (리스트 페이지와 일치)
const allTestedCowIds = new Set([
...farmGenomeRequestCowIds,
...farmGenomeCowIds,
...farmGeneCowIds,
...farmMptCowIds,
]);
const totalCows = allTestedCowIds.size;
const genomeCowCount = farmGenomeCowIds.length;
const geneCowCount = farmGeneCowIds.length;
const mptCowCount = farmMptCowIds.length;
// 성별 체크 - 전체 검사 개체 기준 (M/수/1 = 수컷, 그 외 모두 암컷으로 처리)
let maleCount = 0;
let femaleCount = 0;
for (const cowId of allTestedCowIds) {
const cow = farmCowMap.get(cowId);
const sex = cow?.cowSex?.toUpperCase();
if (sex === 'M' || sex === '수' || sex === '1') {
maleCount++;
} else {
femaleCount++;
}
}
// Step 6: 검사 종류별 현황 (SNP, MS)
const testTypeStats = {
@@ -822,7 +894,11 @@ export class GenomeService {
yearlyAvgEbv,
requestHistory,
summary: {
totalRequests,
totalCows, // 검사 받은 전체 개체 수 (합집합)
genomeCowCount, // 유전체 분석 개체 수
geneCowCount, // 유전자검사 개체 수
mptCowCount, // 번식능력검사 개체 수
totalRequests, // 유전체 의뢰 건수 (기존 호환성)
analyzedCount,
pendingCount,
mismatchCount,