edit tender module

This commit is contained in:
Aya
2026-04-26 12:02:45 +03:00
parent 0a9e1bbd4d
commit 11d14c01d2
3 changed files with 81 additions and 22 deletions

View File

@@ -209,11 +209,25 @@ class TendersService {
return cleanedNotes ? `${cleanedNotes}\n${metaBlock}` : metaBlock;
}
private mapTenderExtraFields<T extends { notes?: string | null; bondValue?: any }>(tender: T) {
private getComputedTenderStatus<T extends { status?: string | null; closingDate?: Date | string | null }>(tender: T) {
if (tender.status === 'CONVERTED_TO_DEAL' || tender.status === 'CANCELLED') {
return tender.status;
}
if (tender.closingDate && new Date(tender.closingDate) < new Date()) {
return 'EXPIRED';
}
return tender.status || 'ACTIVE';
}
private mapTenderExtraFields<T extends { notes?: string | null; bondValue?: any; status?: string | null; closingDate?: Date | string | null }>(tender: T) {
const { cleanNotes, meta } = this.extractTenderExtraMeta(tender.notes);
return {
...tender,
status: this.getComputedTenderStatus(tender),
originalStatus: tender.status,
notes: cleanNotes || null,
initialBondValue: meta.initialBondValue ?? Number(tender.bondValue ?? 0),
finalBondValue: meta.finalBondValue ?? null,
@@ -346,7 +360,9 @@ class TendersService {
{ issuingBodyName: { contains: filters.search, mode: 'insensitive' } },
];
}
if (filters.status) where.status = filters.status;
if (filters.status && filters.status !== 'EXPIRED') {
where.status = filters.status;
}
if (filters.source) where.source = filters.source;
if (filters.announcementType) where.announcementType = filters.announcementType;
@@ -362,9 +378,15 @@ class TendersService {
},
orderBy: { createdAt: 'desc' },
});
return {
tenders: tenders.map((t) => this.mapTenderExtraFields(t)),
total,
const mappedTenders = tenders.map((t) => this.mapTenderExtraFields(t));
const filteredTenders =
filters.status === 'EXPIRED'
? mappedTenders.filter((t: any) => t.status === 'EXPIRED')
: mappedTenders;
return {
tenders: filteredTenders,
total: filters.status === 'EXPIRED' ? filteredTenders.length : total,
page,
pageSize,
};
@@ -679,7 +701,17 @@ class TendersService {
return deal;
}
async uploadTenderAttachment(
private decodeUploadedFileName(fileName: string) {
if (!fileName) return 'file';
try {
return Buffer.from(fileName, 'latin1').toString('utf8');
} catch {
return fileName;
}
}
async uploadTenderAttachment(
tenderId: string,
file: { path: string; originalname: string; mimetype: string; size: number },
userId: string,
@@ -687,14 +719,17 @@ class TendersService {
) {
const tender = await prisma.tender.findUnique({ where: { id: tenderId } });
if (!tender) throw new AppError(404, 'Tender not found');
const fileName = path.basename(file.path);
const originalName = this.decodeUploadedFileName(file.originalname);
const attachment = await prisma.attachment.create({
data: {
entityType: 'TENDER',
entityId: tenderId,
tenderId,
fileName,
originalName: file.originalname,
originalName,
mimeType: file.mimetype,
size: file.size,
path: file.path,
@@ -702,6 +737,7 @@ class TendersService {
uploadedBy: userId,
},
});
await AuditLogger.log({
entityType: 'TENDER',
entityId: tenderId,
@@ -709,6 +745,7 @@ class TendersService {
userId,
changes: { attachmentUploaded: attachment.id },
});
return attachment;
}
@@ -722,8 +759,12 @@ class TendersService {
where: { id: directiveId },
select: { id: true, tenderId: true },
});
if (!directive) throw new AppError(404, 'Directive not found');
const fileName = path.basename(file.path);
const originalName = this.decodeUploadedFileName(file.originalname);
const attachment = await prisma.attachment.create({
data: {
entityType: 'TENDER_DIRECTIVE',
@@ -731,7 +772,7 @@ class TendersService {
tenderDirectiveId: directiveId,
tenderId: directive.tenderId,
fileName,
originalName: file.originalname,
originalName,
mimeType: file.mimetype,
size: file.size,
path: file.path,
@@ -739,6 +780,7 @@ class TendersService {
uploadedBy: userId,
},
});
await AuditLogger.log({
entityType: 'TENDER_DIRECTIVE',
entityId: directiveId,
@@ -746,9 +788,9 @@ class TendersService {
userId,
changes: { attachmentUploaded: attachment.id },
});
return attachment;
}
async getAttachmentFile(attachmentId: string): Promise<string> {
const attachment = await prisma.attachment.findUnique({
where: { id: attachmentId },
@@ -766,12 +808,10 @@ class TendersService {
if (!attachment) throw new AppError(404, 'File not found')
// حذف من الديسك
if (attachment.path && fs.existsSync(attachment.path)) {
fs.unlinkSync(attachment.path)
}
// حذف من DB
await prisma.attachment.delete({
where: { id: attachmentId },
})