feat: add notification triggers, comment roles, mention list, and static file serving
- Notify users on ticket assignment and remittance confirm/reject - Add collector role to comment endpoints - Add /users/mention-list endpoint for @mention support - Serve uploaded files via express.static
This commit is contained in:
@@ -42,8 +42,10 @@ export class PaymentController {
|
||||
|
||||
@Get('unremitted')
|
||||
@Roles('technician', 'collector')
|
||||
async getUnremitted(@CurrentUser() user: CurrentUserPayload, @Query('collectorId') collectorId?: string) {
|
||||
return this.paymentService.getUnremittedPayments(user.tenantId, collectorId || user.sub);
|
||||
async getUnremitted(@CurrentUser() user: CurrentUserPayload, @Query('all') all?: string) {
|
||||
const isManager = user.roles?.some((r: string) => ['manager', 'tenant_admin', 'super_admin'].includes(r));
|
||||
// Managers see all unremitted; collectors see only their own
|
||||
return this.paymentService.getUnremittedPayments(user.tenantId, isManager ? null : user.sub);
|
||||
}
|
||||
|
||||
@Get('remittances')
|
||||
|
||||
@@ -158,7 +158,7 @@ export class PaymentService {
|
||||
}));
|
||||
}
|
||||
|
||||
async getUnremittedPayments(tenantId: string, collectorId: string) {
|
||||
async getUnremittedPayments(tenantId: string, collectorId: string | null) {
|
||||
const remittedIds = (await this.prisma.remittancePayment.findMany({
|
||||
where: { remittance: { tenantId } },
|
||||
select: { paymentId: true },
|
||||
@@ -166,10 +166,15 @@ export class PaymentService {
|
||||
.map((r) => r.paymentId);
|
||||
|
||||
return this.prisma.payment.findMany({
|
||||
where: { tenantId, collectedById: collectorId, id: { notIn: remittedIds.length > 0 ? remittedIds : ['none'] } },
|
||||
where: {
|
||||
tenantId,
|
||||
...(collectorId ? { collectedById: collectorId } : {}),
|
||||
id: { notIn: remittedIds.length > 0 ? remittedIds : ['none'] },
|
||||
},
|
||||
include: {
|
||||
client: { select: { firstName: true, lastName: true, accountNumber: true } },
|
||||
invoice: { select: { id: true, number: true } },
|
||||
collectedBy: { select: { id: true, firstName: true, lastName: true } },
|
||||
},
|
||||
orderBy: { createdAt: 'desc' },
|
||||
});
|
||||
@@ -214,6 +219,17 @@ export class PaymentService {
|
||||
include: { collector: { select: { id: true, firstName: true, lastName: true } }, confirmedBy: { select: { id: true, firstName: true, lastName: true } } },
|
||||
});
|
||||
|
||||
// Notify collector that their remittance was approved
|
||||
if (remittance.collectorId) {
|
||||
this.notificationService.create(tenantId, {
|
||||
userId: remittance.collectorId,
|
||||
type: 'in_app',
|
||||
channel: 'remittance_approved',
|
||||
title: 'Remittance Approved',
|
||||
message: `Your remittance of ₱${Number(remittance.totalAmount).toLocaleString()} has been approved`,
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
this.audit.log({
|
||||
tenantId, userId: confirmedById, action: 'remittance.confirmed', entity: 'remittance', entityId: remittanceId,
|
||||
details: { collectorId: remittance.collectorId, amount: Number(remittance.totalAmount) },
|
||||
@@ -263,7 +279,7 @@ export class PaymentService {
|
||||
}
|
||||
}
|
||||
|
||||
return this.prisma.remittance.update({
|
||||
const result = await this.prisma.remittance.update({
|
||||
where: { id: remittanceId },
|
||||
data: {
|
||||
status: 'rejected',
|
||||
@@ -271,5 +287,18 @@ export class PaymentService {
|
||||
confirmedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
// Notify collector that their remittance was rejected
|
||||
if (remittance.collectorId) {
|
||||
this.notificationService.create(tenantId, {
|
||||
userId: remittance.collectorId,
|
||||
type: 'in_app',
|
||||
channel: 'remittance_rejected',
|
||||
title: 'Remittance Rejected',
|
||||
message: `Your remittance of ₱${Number(remittance.totalAmount).toLocaleString()} has been rejected`,
|
||||
}).catch(() => {});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user