feat: dashboard overhaul, chargeability reports, dispo import enhancements, UI polish
Dashboard: expanded chargeability widget, resource/project table widgets with sorting and filters, stat cards with formatMoney integration. Chargeability: new report client with filtering, chargeability-bookings use case, updated dashboard overview logic. Dispo import: TBD project handling, parse-dispo-matrix improvements, stage-dispo-projects resource value scores, new tests. Estimates: CommercialTermsEditor component, commercial-terms engine module, expanded estimate schemas and types. UI: AppShell navigation updates, timeline filter/toolbar enhancements, role management improvements, signin page redesign, Tailwind/globals polish, SystemSettings SMTP section, anonymization support. Tests: new router tests (anonymization, chargeability, effort-rule, entitlement, estimate, experience-multiplier, notification, resource, staffing, vacation). Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import type { Prisma } from "@planarchy/db";
|
||||
import type { AssignmentBookingWithFallback } from "./list-assignment-bookings.js";
|
||||
|
||||
type ChargeabilityProjectLike = AssignmentBookingWithFallback["project"];
|
||||
type ChargeabilityBookingLike = Pick<AssignmentBookingWithFallback, "status" | "project">;
|
||||
|
||||
function asObject(value: Prisma.JsonValue | null | undefined): Record<string, unknown> | null {
|
||||
if (value === null || value === undefined || typeof value !== "object" || Array.isArray(value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return value as Record<string, unknown>;
|
||||
}
|
||||
|
||||
export function isImportedTbdDraftProject(project: ChargeabilityProjectLike): boolean {
|
||||
if (project.status !== "DRAFT") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const dynamicFields = asObject(project.dynamicFields);
|
||||
const dispoImport = asObject(dynamicFields?.["dispoImport"] as Prisma.JsonValue | undefined);
|
||||
return dispoImport?.["isTbd"] === true;
|
||||
}
|
||||
|
||||
export function isChargeabilityRelevantProject(
|
||||
project: ChargeabilityProjectLike,
|
||||
includeProposed: boolean,
|
||||
): boolean {
|
||||
if (project.status === "ACTIVE") {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (project.status === "CANCELLED") {
|
||||
return false;
|
||||
}
|
||||
|
||||
return includeProposed && isImportedTbdDraftProject(project);
|
||||
}
|
||||
|
||||
export function isChargeabilityActualBooking(
|
||||
booking: ChargeabilityBookingLike,
|
||||
includeProposed: boolean,
|
||||
): boolean {
|
||||
if (!isChargeabilityRelevantProject(booking.project, includeProposed)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
booking.status === "CONFIRMED" ||
|
||||
booking.status === "ACTIVE" ||
|
||||
(includeProposed && booking.status === "PROPOSED")
|
||||
);
|
||||
}
|
||||
@@ -25,6 +25,7 @@ export interface AssignmentBookingWithFallback {
|
||||
shortCode: string;
|
||||
status: string;
|
||||
orderType: string;
|
||||
dynamicFields: Prisma.JsonValue | null;
|
||||
};
|
||||
resource: {
|
||||
id: string;
|
||||
@@ -67,7 +68,14 @@ export async function listAssignmentBookings(
|
||||
dailyCostCents: true,
|
||||
status: true,
|
||||
project: {
|
||||
select: { id: true, name: true, shortCode: true, status: true, orderType: true },
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
shortCode: true,
|
||||
status: true,
|
||||
orderType: true,
|
||||
dynamicFields: true,
|
||||
},
|
||||
},
|
||||
resource: {
|
||||
select: { id: true, displayName: true, chapter: true },
|
||||
|
||||
Reference in New Issue
Block a user