- 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>
82 lines
3.0 KiB
TypeScript
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;
|