booking flow,summtion, approval, contract, mock payemnt and integration to back office, and also add permissions

This commit is contained in:
marshal
2026-06-05 10:38:31 +03:00
parent 810bbc1168
commit d226d7ef22
94 changed files with 3509 additions and 1042 deletions

View File

@@ -0,0 +1,99 @@
import { ForbiddenException } from '@nestjs/common';
import type { TCurrentUser } from '@tria-plc/api-common/modules/auth/types/current-user.type';
import { FREIGHT_PERMS } from '../seed/freight-permissions.registry';
const SUPER_ADMIN_ROLE = 'super_admin';
type PermissionLike = { key?: string };
type MeLikeUser = {
roles?: { key?: string }[];
permissions?: PermissionLike[];
employee?:
| {
position?: { permissions?: PermissionLike[] };
delegatedPositions?: { permissions?: PermissionLike[] }[];
}
| {
positions?: { permissions?: PermissionLike[] }[];
}[]
| null;
};
export function isSuperAdmin(user: MeLikeUser | null | undefined): boolean {
if (!user?.roles?.length) return false;
return user.roles.some((r) => r.key === SUPER_ADMIN_ROLE);
}
/** Flat permission keys from JWT / session user (roles + position permissions). */
export function collectPermissionKeys(user: MeLikeUser | null | undefined): string[] {
if (!user) return [];
const keys = new Set<string>();
for (const p of user.permissions ?? []) {
if (p.key) keys.add(p.key);
}
const employee = user.employee;
if (!employee) {
return [...keys];
}
if (Array.isArray(employee)) {
for (const emp of employee) {
for (const pos of emp.positions ?? []) {
for (const p of pos.permissions ?? []) {
if (p.key) keys.add(p.key);
}
}
}
return [...keys];
}
for (const p of employee.position?.permissions ?? []) {
if (p.key) keys.add(p.key);
}
for (const delegated of employee.delegatedPositions ?? []) {
for (const p of delegated.permissions ?? []) {
if (p.key) keys.add(p.key);
}
}
return [...keys];
}
export function hasFreightPermission(
user: MeLikeUser | null | undefined,
permissionKey: string,
): boolean {
if (!user) return false;
if (isSuperAdmin(user)) return true;
return collectPermissionKeys(user).includes(permissionKey);
}
export function assertFreightPermission(
user: TCurrentUser | MeLikeUser | null | undefined,
permissionKey: string,
): void {
if (hasFreightPermission(user, permissionKey)) return;
throw new ForbiddenException(`Missing permission: ${permissionKey}`);
}
const APPROVE_ROLE_PERMISSION: Record<string, string> = {
LINE_STAFF: FREIGHT_PERMS.bookings.approveLineStaff,
DIRECTOR: FREIGHT_PERMS.bookings.approveDirector,
CEO: FREIGHT_PERMS.bookings.approveCeo,
};
export function assertCanApproveBookingStep(
user: TCurrentUser | MeLikeUser | null | undefined,
requiredRole: string,
): void {
if (isSuperAdmin(user)) return;
const perm = APPROVE_ROLE_PERMISSION[requiredRole];
if (!perm) {
throw new ForbiddenException(`Unknown approval role: ${requiredRole}`);
}
assertFreightPermission(user, perm);
}