318 lines
12 KiB
TypeScript
318 lines
12 KiB
TypeScript
|
|
/**
|
||
|
|
* Test factory helpers.
|
||
|
|
* These return plain data objects — NOT database-inserted records.
|
||
|
|
* Safe to use whether or not a database is available.
|
||
|
|
*/
|
||
|
|
|
||
|
|
// ─── Client ──────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
export interface ClientData {
|
||
|
|
id: string;
|
||
|
|
portId: string;
|
||
|
|
fullName: string;
|
||
|
|
companyName: string | null;
|
||
|
|
nationality: string | null;
|
||
|
|
isProxy: boolean;
|
||
|
|
source: string | null;
|
||
|
|
yachtLengthFt: string | null;
|
||
|
|
yachtLengthM: string | null;
|
||
|
|
archivedAt: Date | null;
|
||
|
|
createdAt: Date;
|
||
|
|
updatedAt: Date;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function makeClient(overrides?: Partial<ClientData>): ClientData {
|
||
|
|
return {
|
||
|
|
id: crypto.randomUUID(),
|
||
|
|
portId: crypto.randomUUID(),
|
||
|
|
fullName: 'Test Client',
|
||
|
|
companyName: null,
|
||
|
|
nationality: null,
|
||
|
|
isProxy: false,
|
||
|
|
source: 'manual',
|
||
|
|
yachtLengthFt: null,
|
||
|
|
yachtLengthM: null,
|
||
|
|
archivedAt: null,
|
||
|
|
createdAt: new Date(),
|
||
|
|
updatedAt: new Date(),
|
||
|
|
...overrides,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// ─── Interest ─────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
export interface InterestData {
|
||
|
|
id: string;
|
||
|
|
portId: string;
|
||
|
|
clientId: string;
|
||
|
|
berthId: string | null;
|
||
|
|
pipelineStage: string;
|
||
|
|
leadCategory: string | null;
|
||
|
|
source: string | null;
|
||
|
|
eoiStatus: string | null;
|
||
|
|
contractStatus: string | null;
|
||
|
|
depositStatus: string | null;
|
||
|
|
notes: string | null;
|
||
|
|
archivedAt: Date | null;
|
||
|
|
createdAt: Date;
|
||
|
|
updatedAt: Date;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function makeInterest(overrides?: Partial<InterestData>): InterestData {
|
||
|
|
return {
|
||
|
|
id: crypto.randomUUID(),
|
||
|
|
portId: crypto.randomUUID(),
|
||
|
|
clientId: crypto.randomUUID(),
|
||
|
|
berthId: null,
|
||
|
|
pipelineStage: 'open',
|
||
|
|
leadCategory: null,
|
||
|
|
source: 'manual',
|
||
|
|
eoiStatus: null,
|
||
|
|
contractStatus: null,
|
||
|
|
depositStatus: null,
|
||
|
|
notes: null,
|
||
|
|
archivedAt: null,
|
||
|
|
createdAt: new Date(),
|
||
|
|
updatedAt: new Date(),
|
||
|
|
...overrides,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// ─── Berth ────────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
export interface BerthData {
|
||
|
|
id: string;
|
||
|
|
portId: string;
|
||
|
|
mooringNumber: string;
|
||
|
|
status: string;
|
||
|
|
area: string | null;
|
||
|
|
lengthM: string | null;
|
||
|
|
price: string | null;
|
||
|
|
tenureType: string | null;
|
||
|
|
archivedAt: Date | null;
|
||
|
|
createdAt: Date;
|
||
|
|
updatedAt: Date;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function makeBerth(overrides?: Partial<BerthData>): BerthData {
|
||
|
|
return {
|
||
|
|
id: crypto.randomUUID(),
|
||
|
|
portId: crypto.randomUUID(),
|
||
|
|
mooringNumber: `B-${Math.floor(Math.random() * 999) + 1}`,
|
||
|
|
status: 'available',
|
||
|
|
area: null,
|
||
|
|
lengthM: '12',
|
||
|
|
price: '50000',
|
||
|
|
tenureType: 'freehold',
|
||
|
|
archivedAt: null,
|
||
|
|
createdAt: new Date(),
|
||
|
|
updatedAt: new Date(),
|
||
|
|
...overrides,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// ─── Webhook ──────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
export interface WebhookData {
|
||
|
|
id: string;
|
||
|
|
portId: string;
|
||
|
|
name: string;
|
||
|
|
url: string;
|
||
|
|
secret: string | null;
|
||
|
|
events: string[];
|
||
|
|
isActive: boolean;
|
||
|
|
createdBy: string;
|
||
|
|
createdAt: Date;
|
||
|
|
updatedAt: Date;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function makeWebhook(overrides?: Partial<WebhookData>): WebhookData {
|
||
|
|
return {
|
||
|
|
id: crypto.randomUUID(),
|
||
|
|
portId: crypto.randomUUID(),
|
||
|
|
name: 'Test Webhook',
|
||
|
|
url: 'https://example.com/webhook',
|
||
|
|
secret: null,
|
||
|
|
events: ['client.created'],
|
||
|
|
isActive: true,
|
||
|
|
createdBy: crypto.randomUUID(),
|
||
|
|
createdAt: new Date(),
|
||
|
|
updatedAt: new Date(),
|
||
|
|
...overrides,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// ─── Audit Log ────────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
export interface AuditMeta {
|
||
|
|
userId: string;
|
||
|
|
portId: string;
|
||
|
|
ipAddress: string;
|
||
|
|
userAgent: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function makeAuditMeta(overrides?: Partial<AuditMeta>): AuditMeta {
|
||
|
|
return {
|
||
|
|
userId: crypto.randomUUID(),
|
||
|
|
portId: crypto.randomUUID(),
|
||
|
|
ipAddress: '127.0.0.1',
|
||
|
|
userAgent: 'vitest/1.0',
|
||
|
|
...overrides,
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// ─── Auth Context ─────────────────────────────────────────────────────────────
|
||
|
|
|
||
|
|
import type { RolePermissions } from '@/lib/db/schema/users';
|
||
|
|
|
||
|
|
/** Full permissions — every action allowed. */
|
||
|
|
export function makeFullPermissions(): RolePermissions {
|
||
|
|
return {
|
||
|
|
clients: { view: true, create: true, edit: true, delete: true, merge: true, export: true },
|
||
|
|
interests: { view: true, create: true, edit: true, delete: true, change_stage: true, generate_eoi: true, export: true },
|
||
|
|
berths: { view: true, edit: true, import: true, manage_waiting_list: true },
|
||
|
|
documents: { view: true, create: true, send_for_signing: true, upload_signed: true, delete: true },
|
||
|
|
expenses: { view: true, create: true, edit: true, delete: true, export: true, scan_receipt: true },
|
||
|
|
invoices: { view: true, create: true, edit: true, delete: true, send: true, record_payment: true, export: true },
|
||
|
|
files: { view: true, upload: true, delete: true, manage_folders: true },
|
||
|
|
email: { view: true, send: true, configure_account: true },
|
||
|
|
reminders: { view_own: true, view_all: true, create: true, edit_own: true, edit_all: true, assign_others: true },
|
||
|
|
calendar: { connect: true, view_events: true },
|
||
|
|
reports: { view_dashboard: true, view_analytics: true, export: true },
|
||
|
|
document_templates: { view: true, generate: true, manage: true },
|
||
|
|
admin: {
|
||
|
|
manage_users: true,
|
||
|
|
view_audit_log: true,
|
||
|
|
manage_settings: true,
|
||
|
|
manage_webhooks: true,
|
||
|
|
manage_reports: true,
|
||
|
|
manage_custom_fields: true,
|
||
|
|
manage_forms: true,
|
||
|
|
manage_tags: true,
|
||
|
|
system_backup: true,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Read-only viewer permissions — no create/update/delete. */
|
||
|
|
export function makeViewerPermissions(): RolePermissions {
|
||
|
|
return {
|
||
|
|
clients: { view: true, create: false, edit: false, delete: false, merge: false, export: false },
|
||
|
|
interests: { view: true, create: false, edit: false, delete: false, change_stage: false, generate_eoi: false, export: false },
|
||
|
|
berths: { view: true, edit: false, import: false, manage_waiting_list: false },
|
||
|
|
documents: { view: true, create: false, send_for_signing: false, upload_signed: false, delete: false },
|
||
|
|
expenses: { view: true, create: false, edit: false, delete: false, export: false, scan_receipt: false },
|
||
|
|
invoices: { view: true, create: false, edit: false, delete: false, send: false, record_payment: false, export: false },
|
||
|
|
files: { view: true, upload: false, delete: false, manage_folders: false },
|
||
|
|
email: { view: true, send: false, configure_account: false },
|
||
|
|
reminders: { view_own: true, view_all: false, create: false, edit_own: false, edit_all: false, assign_others: false },
|
||
|
|
calendar: { connect: false, view_events: true },
|
||
|
|
reports: { view_dashboard: true, view_analytics: false, export: false },
|
||
|
|
document_templates: { view: true, generate: false, manage: false },
|
||
|
|
admin: {
|
||
|
|
manage_users: false,
|
||
|
|
view_audit_log: false,
|
||
|
|
manage_settings: false,
|
||
|
|
manage_webhooks: false,
|
||
|
|
manage_reports: false,
|
||
|
|
manage_custom_fields: false,
|
||
|
|
manage_forms: false,
|
||
|
|
manage_tags: false,
|
||
|
|
system_backup: false,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Sales agent permissions — own clients/interests, no admin. */
|
||
|
|
export function makeSalesAgentPermissions(): RolePermissions {
|
||
|
|
return {
|
||
|
|
clients: { view: true, create: true, edit: true, delete: false, merge: false, export: false },
|
||
|
|
interests: { view: true, create: true, edit: true, delete: false, change_stage: true, generate_eoi: true, export: false },
|
||
|
|
berths: { view: true, edit: false, import: false, manage_waiting_list: false },
|
||
|
|
documents: { view: true, create: true, send_for_signing: true, upload_signed: true, delete: false },
|
||
|
|
expenses: { view: true, create: true, edit: true, delete: false, export: false, scan_receipt: true },
|
||
|
|
invoices: { view: true, create: false, edit: false, delete: false, send: false, record_payment: false, export: false },
|
||
|
|
files: { view: true, upload: true, delete: false, manage_folders: false },
|
||
|
|
email: { view: true, send: true, configure_account: false },
|
||
|
|
reminders: { view_own: true, view_all: false, create: true, edit_own: true, edit_all: false, assign_others: false },
|
||
|
|
calendar: { connect: true, view_events: true },
|
||
|
|
reports: { view_dashboard: true, view_analytics: false, export: false },
|
||
|
|
document_templates: { view: true, generate: true, manage: false },
|
||
|
|
admin: {
|
||
|
|
manage_users: false,
|
||
|
|
view_audit_log: false,
|
||
|
|
manage_settings: false,
|
||
|
|
manage_webhooks: false,
|
||
|
|
manage_reports: false,
|
||
|
|
manage_custom_fields: false,
|
||
|
|
manage_forms: false,
|
||
|
|
manage_tags: false,
|
||
|
|
system_backup: false,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Sales manager — can do most things, limited admin. */
|
||
|
|
export function makeSalesManagerPermissions(): RolePermissions {
|
||
|
|
return {
|
||
|
|
clients: { view: true, create: true, edit: true, delete: true, merge: true, export: true },
|
||
|
|
interests: { view: true, create: true, edit: true, delete: true, change_stage: true, generate_eoi: true, export: true },
|
||
|
|
berths: { view: true, edit: true, import: false, manage_waiting_list: true },
|
||
|
|
documents: { view: true, create: true, send_for_signing: true, upload_signed: true, delete: true },
|
||
|
|
expenses: { view: true, create: true, edit: true, delete: true, export: true, scan_receipt: true },
|
||
|
|
invoices: { view: true, create: true, edit: true, delete: false, send: true, record_payment: true, export: true },
|
||
|
|
files: { view: true, upload: true, delete: true, manage_folders: true },
|
||
|
|
email: { view: true, send: true, configure_account: false },
|
||
|
|
reminders: { view_own: true, view_all: true, create: true, edit_own: true, edit_all: true, assign_others: true },
|
||
|
|
calendar: { connect: true, view_events: true },
|
||
|
|
reports: { view_dashboard: true, view_analytics: true, export: true },
|
||
|
|
document_templates: { view: true, generate: true, manage: false },
|
||
|
|
admin: {
|
||
|
|
manage_users: false,
|
||
|
|
view_audit_log: true,
|
||
|
|
manage_settings: false,
|
||
|
|
manage_webhooks: false,
|
||
|
|
manage_reports: true,
|
||
|
|
manage_custom_fields: false,
|
||
|
|
manage_forms: false,
|
||
|
|
manage_tags: true,
|
||
|
|
system_backup: false,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Director — everything except system backup. */
|
||
|
|
export function makeDirectorPermissions(): RolePermissions {
|
||
|
|
return {
|
||
|
|
...makeFullPermissions(),
|
||
|
|
admin: {
|
||
|
|
...makeFullPermissions().admin,
|
||
|
|
system_backup: false,
|
||
|
|
},
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
// ─── Minimal valid CreateClientInput ─────────────────────────────────────────
|
||
|
|
/** Returns a minimal valid CreateClientInput object for use in service calls. */
|
||
|
|
export function makeCreateClientInput(overrides?: { fullName?: string; portId?: string }) {
|
||
|
|
return {
|
||
|
|
fullName: overrides?.fullName ?? 'Test Client',
|
||
|
|
contacts: [{ channel: 'email' as const, value: 'test@example.com', isPrimary: true }],
|
||
|
|
isProxy: false,
|
||
|
|
tagIds: [] as string[],
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/** Returns a minimal valid CreateInterestInput object. */
|
||
|
|
export function makeCreateInterestInput(overrides?: {
|
||
|
|
clientId?: string;
|
||
|
|
pipelineStage?: 'open' | 'details_sent' | 'in_communication' | 'visited' | 'signed_eoi_nda' | 'deposit_10pct' | 'contract' | 'completed';
|
||
|
|
}) {
|
||
|
|
return {
|
||
|
|
clientId: overrides?.clientId ?? crypto.randomUUID(),
|
||
|
|
pipelineStage: overrides?.pipelineStage ?? ('open' as const),
|
||
|
|
reminderEnabled: false,
|
||
|
|
tagIds: [] as string[],
|
||
|
|
};
|
||
|
|
}
|