fix(05-06): add Collection and Remittance CASL subjects, update routes
- Add Collection and Remittance to AppSubjects union type - Grant OFFICE_STAFF manage:Collection and manage:Remittance - Grant COLLECTOR create/read:Collection and create/read:Remittance - Update all 8 collection/remittance route handlers from Subscriber to their dedicated CASL subjects (Collection or Remittance) - Update JSDoc comments in route files to reflect new subject names Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,12 +1,12 @@
|
|||||||
/**
|
/**
|
||||||
* GET /api/collections/[id] — Get a single collection with allocations
|
* GET /api/collections/[id] — Get a single collection with allocations (requires read:Collection)
|
||||||
*/
|
*/
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { withPermission } from "@/lib/middleware/authorize";
|
import { withPermission } from "@/lib/middleware/authorize";
|
||||||
import { withTenantContext } from "@/lib/prisma-tenant";
|
import { withTenantContext } from "@/lib/prisma-tenant";
|
||||||
|
|
||||||
export function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
export function GET(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||||
return withPermission("read", "Subscriber")(
|
return withPermission("read", "Collection")(
|
||||||
async (_req: NextRequest, { user }) => {
|
async (_req: NextRequest, { user }) => {
|
||||||
if (!user.tenantId) {
|
if (!user.tenantId) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* POST /api/collections/[id]/void — Void a collection (reversing JE)
|
* POST /api/collections/[id]/void — Void a collection (requires update:Collection)
|
||||||
*/
|
*/
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { withPermission } from "@/lib/middleware/authorize";
|
import { withPermission } from "@/lib/middleware/authorize";
|
||||||
@@ -7,7 +7,7 @@ import { withTenantContext } from "@/lib/prisma-tenant";
|
|||||||
import { voidCollection } from "@/lib/services/collector-service";
|
import { voidCollection } from "@/lib/services/collector-service";
|
||||||
|
|
||||||
export function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
export function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||||
return withPermission("update", "Subscriber")(
|
return withPermission("update", "Collection")(
|
||||||
async (_req: NextRequest, { user }) => {
|
async (_req: NextRequest, { user }) => {
|
||||||
if (!user.tenantId) {
|
if (!user.tenantId) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
/**
|
/**
|
||||||
* POST /api/collections — Record a new cash collection
|
* POST /api/collections — Record a new cash collection (requires create:Collection)
|
||||||
* GET /api/collections — Get collection history (filtered by subscriberId or collectorId)
|
* GET /api/collections — Get collection history (requires read:Collection)
|
||||||
*/
|
*/
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { withPermission } from "@/lib/middleware/authorize";
|
import { withPermission } from "@/lib/middleware/authorize";
|
||||||
import { withTenantContext } from "@/lib/prisma-tenant";
|
import { withTenantContext } from "@/lib/prisma-tenant";
|
||||||
import { recordCollection, getCollectionHistory } from "@/lib/services/collector-service";
|
import { recordCollection, getCollectionHistory } from "@/lib/services/collector-service";
|
||||||
|
|
||||||
export const POST = withPermission("create", "Subscriber")(
|
export const POST = withPermission("create", "Collection")(
|
||||||
async (req: NextRequest, { user }) => {
|
async (req: NextRequest, { user }) => {
|
||||||
if (!user.tenantId) {
|
if (!user.tenantId) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
@@ -53,7 +53,7 @@ export const POST = withPermission("create", "Subscriber")(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const GET = withPermission("read", "Subscriber")(
|
export const GET = withPermission("read", "Collection")(
|
||||||
async (req: NextRequest, { user }) => {
|
async (req: NextRequest, { user }) => {
|
||||||
if (!user.tenantId) {
|
if (!user.tenantId) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* POST /api/remittances/[id]/verify — Verify a remittance (office staff counts total)
|
* POST /api/remittances/[id]/verify — Verify a remittance (requires update:Remittance)
|
||||||
*/
|
*/
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { withPermission } from "@/lib/middleware/authorize";
|
import { withPermission } from "@/lib/middleware/authorize";
|
||||||
@@ -7,7 +7,7 @@ import { withTenantContext } from "@/lib/prisma-tenant";
|
|||||||
import { verifyRemittance } from "@/lib/services/remittance-service";
|
import { verifyRemittance } from "@/lib/services/remittance-service";
|
||||||
|
|
||||||
export function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
export function POST(req: NextRequest, { params }: { params: Promise<{ id: string }> }) {
|
||||||
return withPermission("update", "Subscriber")(
|
return withPermission("update", "Remittance")(
|
||||||
async (innerReq: NextRequest, { user }) => {
|
async (innerReq: NextRequest, { user }) => {
|
||||||
if (!user.tenantId) {
|
if (!user.tenantId) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* POST /api/remittances — Create a new remittance (collector declares total)
|
* POST /api/remittances — Create a new remittance (requires create:Remittance)
|
||||||
* GET /api/remittances — List remittances with optional filtering
|
* GET /api/remittances — List remittances with optional filtering (requires read:Remittance)
|
||||||
*/
|
*/
|
||||||
import { NextRequest, NextResponse } from "next/server";
|
import { NextRequest, NextResponse } from "next/server";
|
||||||
import { withPermission } from "@/lib/middleware/authorize";
|
import { withPermission } from "@/lib/middleware/authorize";
|
||||||
@@ -8,7 +8,7 @@ import { withTenantContext } from "@/lib/prisma-tenant";
|
|||||||
import { createRemittance, listRemittances } from "@/lib/services/remittance-service";
|
import { createRemittance, listRemittances } from "@/lib/services/remittance-service";
|
||||||
import { RemittanceStatus } from "@prisma/client";
|
import { RemittanceStatus } from "@prisma/client";
|
||||||
|
|
||||||
export const POST = withPermission("create", "Subscriber")(
|
export const POST = withPermission("create", "Remittance")(
|
||||||
async (req: NextRequest, { user }) => {
|
async (req: NextRequest, { user }) => {
|
||||||
if (!user.tenantId) {
|
if (!user.tenantId) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
@@ -50,7 +50,7 @@ export const POST = withPermission("create", "Subscriber")(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export const GET = withPermission("read", "Subscriber")(
|
export const GET = withPermission("read", "Remittance")(
|
||||||
async (req: NextRequest, { user }) => {
|
async (req: NextRequest, { user }) => {
|
||||||
if (!user.tenantId) {
|
if (!user.tenantId) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/**
|
/**
|
||||||
* GET /api/reports/collections — Daily collection summary report
|
* GET /api/reports/collections — Daily collection summary report (requires read:Collection)
|
||||||
*
|
*
|
||||||
* Query params:
|
* Query params:
|
||||||
* date — ISO date string (defaults to today)
|
* date — ISO date string (defaults to today)
|
||||||
@@ -10,7 +10,7 @@ import { withPermission } from "@/lib/middleware/authorize";
|
|||||||
import { withTenantContext } from "@/lib/prisma-tenant";
|
import { withTenantContext } from "@/lib/prisma-tenant";
|
||||||
import { getDailyCollectionSummary, getCollectorCollectionDetail } from "@/lib/services/collection-report-service";
|
import { getDailyCollectionSummary, getCollectorCollectionDetail } from "@/lib/services/collection-report-service";
|
||||||
|
|
||||||
export const GET = withPermission("read", "Subscriber")(
|
export const GET = withPermission("read", "Collection")(
|
||||||
async (req: NextRequest, { user }) => {
|
async (req: NextRequest, { user }) => {
|
||||||
if (!user.tenantId) {
|
if (!user.tenantId) {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|||||||
@@ -66,6 +66,9 @@ export function definePermissionsFor(
|
|||||||
can("manage", "Expense");
|
can("manage", "Expense");
|
||||||
// Vendor management (CRUD)
|
// Vendor management (CRUD)
|
||||||
can("manage", "Vendor");
|
can("manage", "Vendor");
|
||||||
|
// Collection and remittance management
|
||||||
|
can("manage", "Collection");
|
||||||
|
can("manage", "Remittance");
|
||||||
// Job type rates (read-only for office staff — admin configures rates)
|
// Job type rates (read-only for office staff — admin configures rates)
|
||||||
can("read", "JobTypeRate");
|
can("read", "JobTypeRate");
|
||||||
// View financial reports (read-only)
|
// View financial reports (read-only)
|
||||||
@@ -88,6 +91,12 @@ export function definePermissionsFor(
|
|||||||
can("create", "Payment");
|
can("create", "Payment");
|
||||||
// View payment history
|
// View payment history
|
||||||
can("read", "Payment");
|
can("read", "Payment");
|
||||||
|
// Can create and view collections
|
||||||
|
can("create", "Collection");
|
||||||
|
can("read", "Collection");
|
||||||
|
// Can create and view remittances
|
||||||
|
can("create", "Remittance");
|
||||||
|
can("read", "Remittance");
|
||||||
// NOTE: No explicit cannot() needed — Collector simply has no rules for
|
// NOTE: No explicit cannot() needed — Collector simply has no rules for
|
||||||
// Invoice, User management, or Reports. Absence of a rule = no access.
|
// Invoice, User management, or Reports. Absence of a rule = no access.
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ export type AppSubjects =
|
|||||||
| "Subscriber"
|
| "Subscriber"
|
||||||
| "Invoice"
|
| "Invoice"
|
||||||
| "Payment"
|
| "Payment"
|
||||||
|
| "Collection"
|
||||||
|
| "Remittance"
|
||||||
| "Zone"
|
| "Zone"
|
||||||
| "Ticket"
|
| "Ticket"
|
||||||
| "JobOrder"
|
| "JobOrder"
|
||||||
|
|||||||
Reference in New Issue
Block a user