Files
DentalManagementMH06/apps/Backend/src/routes/commissions.ts
Gitead 7360b1930b feat: add provider column, commission tracking, and report provider filter
- Claims & Payments: save npiProviderId when submitting MH claim; sync between claim and payment on update
- Claims table: add Provider column showing rendering provider name
- Payments table: add Provider column + purple Commissioned badge on status
- Claim edit modal: add Rendering Provider dropdown (defaults to Mary Scannell)
- Payment edit modal: add Rendering Provider dropdown + Commissioned metadata display
- Reports page: add Provider filter dropdown (dynamic from NPI providers settings)
- Reports page: remove Collections by Doctor report type and Select Doctor dropdown
- Commission section: new section in reports page with date range + provider filter, shows eligible paid claims/payments per provider, multi-select checkboxes, Pay Commission modal with print + save, marks payments as commissioned so they are excluded from future cycles
- DB: add CommissionBatch and CommissionBatchItem tables; backfill Payment.npiProviderId from linked claims
- Backend: PATCH /api/payments/:id/provider syncs to linked claim; PUT /api/claims/:id syncs to linked payment; new /api/commissions routes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 23:51:39 -04:00

82 lines
3.0 KiB
TypeScript

import { Router } from "express";
import type { Request, Response } from "express";
import { storage } from "../storage";
const router = Router();
/** GET /api/commissions/eligible
* Query: npiProviderId (required), from?, to?
*/
router.get("/eligible", async (req: Request, res: Response): Promise<any> => {
try {
const npiProviderId = Number(req.query.npiProviderId);
if (!npiProviderId || !Number.isFinite(npiProviderId)) {
return res.status(400).json({ message: "npiProviderId is required" });
}
const from = req.query.from ? new Date(String(req.query.from)) : null;
const to = req.query.to ? new Date(String(req.query.to)) : null;
if (req.query.from && isNaN(from!.getTime()))
return res.status(400).json({ message: "Invalid 'from' date" });
if (req.query.to && isNaN(to!.getTime()))
return res.status(400).json({ message: "Invalid 'to' date" });
const payments = await storage.getEligiblePayments(npiProviderId, from, to);
return res.json(payments);
} catch (err: any) {
console.error("GET /api/commissions/eligible error:", err);
return res.status(500).json({ message: err?.message ?? "Failed to fetch eligible payments" });
}
});
/** GET /api/commissions/batches
* Query: npiProviderId? (optional filter)
*/
router.get("/batches", async (req: Request, res: Response): Promise<any> => {
try {
const npiProviderId = req.query.npiProviderId
? Number(req.query.npiProviderId)
: undefined;
const batches = await storage.getCommissionBatches(npiProviderId);
return res.json(batches);
} catch (err: any) {
console.error("GET /api/commissions/batches error:", err);
return res.status(500).json({ message: err?.message ?? "Failed to fetch commission batches" });
}
});
/** POST /api/commissions
* Body: { npiProviderId, paymentIds[], totalCollection, commissionAmount, notes? }
*/
router.post("/", async (req: Request, res: Response): Promise<any> => {
try {
const userId = req.user?.id;
if (!userId) return res.status(401).json({ message: "Unauthorized" });
const { npiProviderId, paymentIds, totalCollection, commissionAmount, notes } = req.body;
if (!npiProviderId || !Array.isArray(paymentIds) || paymentIds.length === 0) {
return res.status(400).json({ message: "npiProviderId and at least one paymentId are required" });
}
if (typeof totalCollection !== "number" || typeof commissionAmount !== "number") {
return res.status(400).json({ message: "totalCollection and commissionAmount must be numbers" });
}
const batch = await storage.createCommissionBatch({
npiProviderId: Number(npiProviderId),
paymentIds: paymentIds.map(Number),
totalCollection,
commissionAmount,
notes: notes ?? undefined,
});
return res.status(201).json(batch);
} catch (err: any) {
console.error("POST /api/commissions error:", err);
return res.status(500).json({ message: err?.message ?? "Failed to create commission batch" });
}
});
export default router;