Files
dyolink/backend/src/modules/treatments/treatments.controller.ts

380 lines
13 KiB
TypeScript
Raw Normal View History

import {
Body,
Controller,
Delete,
Get,
Param,
ParseIntPipe,
Patch,
Post,
Put,
Query,
Req,
Res,
UploadedFiles,
UseGuards,
UseInterceptors,
} from '@nestjs/common';
import { FilesInterceptor } from '@nestjs/platform-express';
import { ApiBearerAuth, ApiBody, ApiConsumes, ApiOperation, ApiTags } from '@nestjs/swagger';
import { memoryStorage } from 'multer';
import type { Response } from 'express';
import { ClinicOrgGuard } from '../../common/guards/clinic-org.guard';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import {
SaveTreatmentDraftDto,
SaveTreatmentLabCasesDto,
UpdateLabCaseDueDateDto,
CreateStandaloneTreatmentDto,
ListDayTreatmentsDto,
} from './dto/treatment.dto';
import { CreateLabCaseCommentDto } from '../lab-case-comments/dto/lab-case-comment.dto';
import { LabCaseCommentsService } from '../lab-case-comments/lab-case-comments.service';
import { TreatmentsService } from './treatments.service';
@ApiTags('treatments')
@ApiBearerAuth('JWT-auth')
@UseGuards(JwtAuthGuard, ClinicOrgGuard)
@Controller('treatments')
export class TreatmentsController {
constructor(
private readonly treatmentsService: TreatmentsService,
private readonly commentsService: LabCaseCommentsService,
) {}
@Get('linked-organizations')
@ApiOperation({ summary: 'List active linked counterpart organizations (TAB_TREATMENT_READ)' })
listLinkedOrganizations(@Req() req: { user: { id: string; organizationId?: string } }) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.listLinkedOrganizations(req.user.id, organizationId);
}
@Get('lab-cases/unread')
@ApiOperation({ summary: 'Sent lab cases with unread lab activity for the organization (TAB_TREATMENT_READ)' })
listUnreadLabCases(@Req() req: { user: { id: string; organizationId?: string } }) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.listUnreadLabCases(organizationId, req.user.id);
}
@Get('patients/:patientId/lab-cases')
@ApiOperation({ summary: 'Sent lab cases for a patient with tracker summaries (TAB_TREATMENT_READ)' })
listPatientLabCases(
@Param('patientId') patientId: string,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.listPatientLabCases(
patientId,
organizationId,
req.user.id,
);
}
@Get('patients/:patientId/history')
@ApiOperation({ summary: 'List treatments for a patient (draft and completed, TAB_TREATMENT_READ)' })
listPatientHistory(
@Param('patientId') patientId: string,
@Query('limit', new ParseIntPipe({ optional: true })) limit = 20,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.listPatientHistory(
patientId,
organizationId,
req.user.id,
limit,
);
}
@Get('day')
@ApiOperation({ summary: 'Standalone (no appointment) treatments for a local day range' })
listDayStandalone(
@Query() query: ListDayTreatmentsDto,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.listDayStandalone(
query.from,
query.to,
organizationId,
req.user.id,
);
}
@Post()
@ApiOperation({ summary: 'Create a treatment without an appointment (TAB_TREATMENT_EDIT)' })
createStandalone(
@Body() dto: CreateStandaloneTreatmentDto,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.createStandalone(dto, organizationId, req.user.id);
}
@Get('appointments/:appointmentId/draft')
@ApiOperation({ summary: 'Get draft treatment for an appointment (TAB_TREATMENT_READ)' })
getDraft(
@Param('appointmentId') appointmentId: string,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.getDraftForAppointment(
appointmentId,
organizationId,
req.user.id,
);
}
@Put('appointments/:appointmentId/draft')
@ApiOperation({ summary: 'Save draft treatment details for an appointment (TAB_TREATMENT_EDIT)' })
saveDraft(
@Param('appointmentId') appointmentId: string,
@Body() dto: SaveTreatmentDraftDto,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.saveDraftForAppointment(
appointmentId,
dto,
organizationId,
req.user.id,
);
}
@Put('appointments/:appointmentId/lab-cases')
@ApiOperation({ summary: 'Save lab case groupings for a draft treatment (TAB_TREATMENT_EDIT)' })
saveLabCases(
@Param('appointmentId') appointmentId: string,
@Body() dto: SaveTreatmentLabCasesDto,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.saveLabCasesForAppointment(
appointmentId,
dto,
organizationId,
req.user.id,
);
}
@Post('appointments/:appointmentId/details/:detailClientKey/attachments')
@ApiOperation({ summary: 'Upload attachments for a draft treatment detail (TAB_TREATMENT_EDIT)' })
@ApiConsumes('multipart/form-data')
@ApiBody({
schema: {
type: 'object',
properties: {
files: {
type: 'array',
items: { type: 'string', format: 'binary' },
},
},
},
})
@UseInterceptors(
FilesInterceptor('files', 20, {
storage: memoryStorage(),
}),
)
uploadDetailAttachments(
@Param('appointmentId') appointmentId: string,
@Param('detailClientKey') detailClientKey: string,
@UploadedFiles() files: Express.Multer.File[],
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.uploadDetailAttachments(
appointmentId,
detailClientKey,
files,
organizationId,
req.user.id,
);
}
/** @deprecated Use details/:detailClientKey/attachments */
@Post('appointments/:appointmentId/cases/:caseClientKey/attachments')
@ApiOperation({ summary: 'Legacy alias for detail attachment upload' })
@ApiConsumes('multipart/form-data')
@UseInterceptors(
FilesInterceptor('files', 20, {
storage: memoryStorage(),
}),
)
uploadDetailAttachmentsLegacy(
@Param('appointmentId') appointmentId: string,
@Param('caseClientKey') caseClientKey: string,
@UploadedFiles() files: Express.Multer.File[],
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.uploadDetailAttachments(
appointmentId,
caseClientKey,
files,
organizationId,
req.user.id,
);
}
@Get('attachments/:attachmentId/file')
@ApiOperation({ summary: 'Download a treatment attachment (TAB_TREATMENT_READ)' })
async downloadAttachment(
@Param('attachmentId') attachmentId: string,
@Req() req: { user: { id: string; organizationId?: string } },
@Res() res: Response,
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
const file = await this.treatmentsService.streamAttachmentFile(
attachmentId,
organizationId,
req.user.id,
);
res.setHeader('Content-Type', file.mimeType);
res.setHeader('Content-Disposition', `inline; filename="${file.fileName}"`);
file.stream.pipe(res);
}
@Post('lab-cases/:labCaseId/send')
@ApiOperation({ summary: 'Send a lab case to its destination organization (TAB_TREATMENT_EDIT)' })
sendLabCase(
@Param('labCaseId') labCaseId: string,
@Req() req: { user: { id: string; organizationId?: string; language?: string | null } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.sendLabCase(
labCaseId,
organizationId,
req.user.id,
req.user.language,
);
}
@Patch('lab-cases/:labCaseId/due-date')
@ApiOperation({ summary: 'Update expected due date for a sent lab case' })
updateLabCaseDueDate(
@Param('labCaseId') labCaseId: string,
@Body() dto: UpdateLabCaseDueDateDto,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.updateLabCaseDueDate(
labCaseId,
dto,
organizationId,
req.user.id,
);
}
@Get('lab-cases/:labCaseId/comments')
@ApiOperation({ summary: 'List comments for a lab case during treatment dispatch' })
listLabCaseComments(
@Param('labCaseId') labCaseId: string,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.commentsService.listForClinicTreatmentCase(
labCaseId,
organizationId,
req.user.id,
);
}
@Post('lab-cases/:labCaseId/comments')
@ApiOperation({ summary: 'Add a comment to a lab case during treatment dispatch' })
addLabCaseComment(
@Param('labCaseId') labCaseId: string,
@Body() dto: CreateLabCaseCommentDto,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.commentsService.addForClinicTreatmentCase(
labCaseId,
organizationId,
req.user.id,
dto,
);
}
@Get(':treatmentId/draft')
@ApiOperation({ summary: 'Get a treatment draft by treatment id (TAB_TREATMENT_READ)' })
getDraftByTreatment(
@Param('treatmentId') treatmentId: string,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.getDraftForTreatment(
treatmentId,
organizationId,
req.user.id,
);
}
@Put(':treatmentId/draft')
@ApiOperation({ summary: 'Save draft treatment details by treatment id (TAB_TREATMENT_EDIT)' })
saveDraftByTreatment(
@Param('treatmentId') treatmentId: string,
@Body() dto: SaveTreatmentDraftDto,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.saveDraftForTreatment(
treatmentId,
dto,
organizationId,
req.user.id,
);
}
@Put(':treatmentId/lab-cases')
@ApiOperation({ summary: 'Save lab case groupings by treatment id (TAB_TREATMENT_EDIT)' })
saveLabCasesByTreatment(
@Param('treatmentId') treatmentId: string,
@Body() dto: SaveTreatmentLabCasesDto,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.saveLabCasesForTreatment(
treatmentId,
dto,
organizationId,
req.user.id,
);
}
@Post(':treatmentId/details/:detailClientKey/attachments')
@ApiOperation({ summary: 'Upload attachments for a standalone treatment detail' })
@ApiConsumes('multipart/form-data')
@UseInterceptors(
FilesInterceptor('files', 20, {
storage: memoryStorage(),
}),
)
uploadDetailAttachmentsByTreatment(
@Param('treatmentId') treatmentId: string,
@Param('detailClientKey') detailClientKey: string,
@UploadedFiles() files: Express.Multer.File[],
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.uploadDetailAttachmentsForTreatment(
treatmentId,
detailClientKey,
files,
organizationId,
req.user.id,
);
}
@Delete(':treatmentId')
@ApiOperation({ summary: 'Delete an empty standalone treatment (no details)' })
deleteStandalone(
@Param('treatmentId') treatmentId: string,
@Req() req: { user: { id: string; organizationId?: string } },
) {
const organizationId = this.treatmentsService.getOrganizationIdFromUser(req.user);
return this.treatmentsService.deleteStandalone(treatmentId, organizationId, req.user.id);
}
}