Sales Module (SAAS-018): - Entities: PipelineStage, Lead, Opportunity, Activity - Services: LeadsService, OpportunitiesService, ActivitiesService, PipelineService, SalesDashboardService - Controllers: 25 endpoints for leads, opportunities, activities, pipeline, dashboard - DTOs: Complete CRUD and query DTOs - Integration with DDL functions: convert_lead_to_opportunity, update_opportunity_stage, calculate_lead_score Commissions Module (SAAS-020): - Entities: CommissionScheme, CommissionAssignment, CommissionPeriod, CommissionEntry - Services: SchemesService, AssignmentsService, EntriesService, PeriodsService, CommissionsDashboardService - Controllers: 25 endpoints for schemes, assignments, entries, periods, dashboard - DTOs: Complete CRUD and query DTOs - Integration with DDL functions: calculate_commission, close_period, get_user_earnings Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
274 lines
4.0 KiB
TypeScript
274 lines
4.0 KiB
TypeScript
import {
|
|
IsString,
|
|
IsEmail,
|
|
IsOptional,
|
|
IsEnum,
|
|
IsInt,
|
|
IsUUID,
|
|
IsObject,
|
|
MaxLength,
|
|
Min,
|
|
Max,
|
|
IsNumber,
|
|
} from 'class-validator';
|
|
import { LeadStatus, LeadSource } from '../entities';
|
|
|
|
export class CreateLeadDto {
|
|
@IsString()
|
|
@MaxLength(100)
|
|
firstName: string;
|
|
|
|
@IsString()
|
|
@MaxLength(100)
|
|
lastName: string;
|
|
|
|
@IsEmail()
|
|
@IsOptional()
|
|
email?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(50)
|
|
@IsOptional()
|
|
phone?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(200)
|
|
@IsOptional()
|
|
company?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(150)
|
|
@IsOptional()
|
|
jobTitle?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(255)
|
|
@IsOptional()
|
|
website?: string;
|
|
|
|
@IsEnum(LeadSource)
|
|
@IsOptional()
|
|
source?: LeadSource;
|
|
|
|
@IsEnum(LeadStatus)
|
|
@IsOptional()
|
|
status?: LeadStatus;
|
|
|
|
@IsInt()
|
|
@Min(0)
|
|
@Max(100)
|
|
@IsOptional()
|
|
score?: number;
|
|
|
|
@IsUUID()
|
|
@IsOptional()
|
|
assignedTo?: string;
|
|
|
|
@IsString()
|
|
@IsOptional()
|
|
notes?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(255)
|
|
@IsOptional()
|
|
addressLine1?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(255)
|
|
@IsOptional()
|
|
addressLine2?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(100)
|
|
@IsOptional()
|
|
city?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(100)
|
|
@IsOptional()
|
|
state?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(20)
|
|
@IsOptional()
|
|
postalCode?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(100)
|
|
@IsOptional()
|
|
country?: string;
|
|
|
|
@IsObject()
|
|
@IsOptional()
|
|
customFields?: Record<string, any>;
|
|
}
|
|
|
|
export class UpdateLeadDto {
|
|
@IsString()
|
|
@MaxLength(100)
|
|
@IsOptional()
|
|
firstName?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(100)
|
|
@IsOptional()
|
|
lastName?: string;
|
|
|
|
@IsEmail()
|
|
@IsOptional()
|
|
email?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(50)
|
|
@IsOptional()
|
|
phone?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(200)
|
|
@IsOptional()
|
|
company?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(150)
|
|
@IsOptional()
|
|
jobTitle?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(255)
|
|
@IsOptional()
|
|
website?: string;
|
|
|
|
@IsEnum(LeadSource)
|
|
@IsOptional()
|
|
source?: LeadSource;
|
|
|
|
@IsEnum(LeadStatus)
|
|
@IsOptional()
|
|
status?: LeadStatus;
|
|
|
|
@IsInt()
|
|
@Min(0)
|
|
@Max(100)
|
|
@IsOptional()
|
|
score?: number;
|
|
|
|
@IsUUID()
|
|
@IsOptional()
|
|
assignedTo?: string;
|
|
|
|
@IsString()
|
|
@IsOptional()
|
|
notes?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(255)
|
|
@IsOptional()
|
|
addressLine1?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(255)
|
|
@IsOptional()
|
|
addressLine2?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(100)
|
|
@IsOptional()
|
|
city?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(100)
|
|
@IsOptional()
|
|
state?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(20)
|
|
@IsOptional()
|
|
postalCode?: string;
|
|
|
|
@IsString()
|
|
@MaxLength(100)
|
|
@IsOptional()
|
|
country?: string;
|
|
|
|
@IsObject()
|
|
@IsOptional()
|
|
customFields?: Record<string, any>;
|
|
}
|
|
|
|
export class ConvertLeadDto {
|
|
@IsString()
|
|
@MaxLength(255)
|
|
@IsOptional()
|
|
opportunityName?: string;
|
|
|
|
@IsNumber()
|
|
@Min(0)
|
|
@IsOptional()
|
|
amount?: number;
|
|
|
|
@IsOptional()
|
|
expectedCloseDate?: string;
|
|
}
|
|
|
|
export class LeadResponseDto {
|
|
id: string;
|
|
tenantId: string;
|
|
firstName: string;
|
|
lastName: string;
|
|
fullName: string;
|
|
email: string | null;
|
|
phone: string | null;
|
|
company: string | null;
|
|
jobTitle: string | null;
|
|
website: string | null;
|
|
source: LeadSource;
|
|
status: LeadStatus;
|
|
score: number;
|
|
assignedTo: string | null;
|
|
notes: string | null;
|
|
convertedAt: Date | null;
|
|
convertedToOpportunityId: string | null;
|
|
addressLine1: string | null;
|
|
addressLine2: string | null;
|
|
city: string | null;
|
|
state: string | null;
|
|
postalCode: string | null;
|
|
country: string | null;
|
|
customFields: Record<string, any>;
|
|
createdAt: Date;
|
|
updatedAt: Date;
|
|
createdBy: string | null;
|
|
}
|
|
|
|
export class LeadListQueryDto {
|
|
@IsEnum(LeadStatus)
|
|
@IsOptional()
|
|
status?: LeadStatus;
|
|
|
|
@IsEnum(LeadSource)
|
|
@IsOptional()
|
|
source?: LeadSource;
|
|
|
|
@IsUUID()
|
|
@IsOptional()
|
|
assignedTo?: string;
|
|
|
|
@IsString()
|
|
@IsOptional()
|
|
search?: string;
|
|
|
|
@IsOptional()
|
|
page?: number;
|
|
|
|
@IsOptional()
|
|
limit?: number;
|
|
}
|
|
|
|
export class PaginatedLeadsDto {
|
|
items: LeadResponseDto[];
|
|
total: number;
|
|
page: number;
|
|
limit: number;
|
|
totalPages: number;
|
|
}
|