|
|
@@ -1,173 +0,0 @@
|
|
|
-import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
|
|
|
-import { z } from '@hono/zod-openapi';
|
|
|
-import { Customer } from '../customers/customer.entity';
|
|
|
-
|
|
|
-export enum OpportunityStage {
|
|
|
- INITIAL_CONTACT = 'initial_contact',
|
|
|
- NEEDS_ANALYSIS = 'needs_analysis',
|
|
|
- SOLUTION_PROPOSAL = 'solution_proposal',
|
|
|
- NEGOTIATION = 'negotiation',
|
|
|
- CLOSED_WON = 'closed_won',
|
|
|
- CLOSED_LOST = 'closed_lost'
|
|
|
-}
|
|
|
-
|
|
|
-@Entity('opportunity')
|
|
|
-export class Opportunity {
|
|
|
- @PrimaryGeneratedColumn({ unsigned: true, comment: '销售机会ID' })
|
|
|
- id!: number;
|
|
|
-
|
|
|
- @Column({ name: 'customer_id', type: 'int', unsigned: true, comment: '客户ID' })
|
|
|
- customerId!: number;
|
|
|
-
|
|
|
- @ManyToOne(() => Customer)
|
|
|
- @JoinColumn({ name: 'customer_id' })
|
|
|
- customer!: Customer;
|
|
|
-
|
|
|
- @Column({ name: 'title', type: 'varchar', length: 255, comment: '销售机会标题' })
|
|
|
- title!: string;
|
|
|
-
|
|
|
- @Column({ name: 'amount', type: 'decimal', precision: 10, scale: 2, comment: '预计金额' })
|
|
|
- amount!: number;
|
|
|
-
|
|
|
- @Column({
|
|
|
- name: 'stage',
|
|
|
- type: 'enum',
|
|
|
- enum: OpportunityStage,
|
|
|
- default: OpportunityStage.INITIAL_CONTACT,
|
|
|
- comment: '销售阶段(initial_contact:初步接触,needs_analysis:需求确认,solution_proposal:方案制定,negotiation:谈判阶段,closed_won:成交,closed_lost:丢失)'
|
|
|
- })
|
|
|
- stage!: OpportunityStage;
|
|
|
-
|
|
|
- @Column({ name: 'expected_close_date', type: 'date', nullable: true, comment: '预计成交日期' })
|
|
|
- expectedCloseDate!: Date | null;
|
|
|
-
|
|
|
- @Column({ name: 'description', type: 'text', nullable: true, comment: '销售机会描述' })
|
|
|
- description!: string | null;
|
|
|
-
|
|
|
- @Column({ name: 'is_deleted', type: 'tinyint', default: 0, comment: '是否删除(0:未删除,1:已删除)' })
|
|
|
- isDeleted!: number;
|
|
|
-
|
|
|
- @CreateDateColumn({ name: 'created_at', type: 'timestamp', comment: '创建时间' })
|
|
|
- createdAt!: Date;
|
|
|
-
|
|
|
- @UpdateDateColumn({ name: 'updated_at', type: 'timestamp', comment: '更新时间' })
|
|
|
- updatedAt!: Date;
|
|
|
-}
|
|
|
-
|
|
|
-export const OpportunitySchema = z.object({
|
|
|
- id: z.number().int().positive().openapi({
|
|
|
- description: '销售机会ID',
|
|
|
- example: 1
|
|
|
- }),
|
|
|
- customerId: z.number().int().positive().openapi({
|
|
|
- description: '客户ID',
|
|
|
- example: 1
|
|
|
- }),
|
|
|
- title: z.string().max(255).openapi({
|
|
|
- description: '销售机会标题',
|
|
|
- example: '企业软件升级项目'
|
|
|
- }),
|
|
|
- amount: z.coerce.number().multipleOf(0.01).openapi({
|
|
|
- description: '预计金额',
|
|
|
- example: 50000.00
|
|
|
- }),
|
|
|
- stage: z.enum([
|
|
|
- OpportunityStage.INITIAL_CONTACT,
|
|
|
- OpportunityStage.NEEDS_ANALYSIS,
|
|
|
- OpportunityStage.SOLUTION_PROPOSAL,
|
|
|
- OpportunityStage.NEGOTIATION,
|
|
|
- OpportunityStage.CLOSED_WON,
|
|
|
- OpportunityStage.CLOSED_LOST
|
|
|
- ]).openapi({
|
|
|
- description: '销售阶段',
|
|
|
- example: OpportunityStage.INITIAL_CONTACT
|
|
|
- }),
|
|
|
- expectedCloseDate: z.coerce.date().nullable().openapi({
|
|
|
- description: '预计成交日期',
|
|
|
- example: '2023-12-31'
|
|
|
- }),
|
|
|
- description: z.string().nullable().openapi({
|
|
|
- description: '销售机会描述',
|
|
|
- example: '为客户提供企业级软件升级方案'
|
|
|
- }),
|
|
|
- isDeleted: z.number().int().min(0).max(1).openapi({
|
|
|
- description: '是否删除(0:未删除,1:已删除)',
|
|
|
- example: 0
|
|
|
- }),
|
|
|
- createdAt: z.date().openapi({
|
|
|
- description: '创建时间',
|
|
|
- example: '2023-01-01T00:00:00Z'
|
|
|
- }),
|
|
|
- updatedAt: z.date().openapi({
|
|
|
- description: '更新时间',
|
|
|
- example: '2023-01-01T00:00:00Z'
|
|
|
- })
|
|
|
-});
|
|
|
-
|
|
|
-export const CreateOpportunityDto = z.object({
|
|
|
- customerId: z.coerce.number().int().positive().openapi({
|
|
|
- description: '客户ID',
|
|
|
- example: 1
|
|
|
- }),
|
|
|
- title: z.string().max(255).openapi({
|
|
|
- description: '销售机会标题',
|
|
|
- example: '企业软件升级项目'
|
|
|
- }),
|
|
|
- amount: z.coerce.number().multipleOf(0.01).openapi({
|
|
|
- description: '预计金额',
|
|
|
- example: 50000.00
|
|
|
- }),
|
|
|
- stage: z.enum([
|
|
|
- OpportunityStage.INITIAL_CONTACT,
|
|
|
- OpportunityStage.NEEDS_ANALYSIS,
|
|
|
- OpportunityStage.SOLUTION_PROPOSAL,
|
|
|
- OpportunityStage.NEGOTIATION,
|
|
|
- OpportunityStage.CLOSED_WON,
|
|
|
- OpportunityStage.CLOSED_LOST
|
|
|
- ]).optional().default(OpportunityStage.INITIAL_CONTACT).openapi({
|
|
|
- description: '销售阶段',
|
|
|
- example: OpportunityStage.INITIAL_CONTACT
|
|
|
- }),
|
|
|
- expectedCloseDate: z.coerce.date().nullable().optional().openapi({
|
|
|
- description: '预计成交日期',
|
|
|
- example: '2023-12-31'
|
|
|
- }),
|
|
|
- description: z.string().nullable().optional().openapi({
|
|
|
- description: '销售机会描述',
|
|
|
- example: '为客户提供企业级软件升级方案'
|
|
|
- })
|
|
|
-});
|
|
|
-
|
|
|
-export const UpdateOpportunityDto = z.object({
|
|
|
- customerId: z.coerce.number().int().positive().optional().openapi({
|
|
|
- description: '客户ID',
|
|
|
- example: 1
|
|
|
- }),
|
|
|
- title: z.string().max(255).optional().openapi({
|
|
|
- description: '销售机会标题',
|
|
|
- example: '企业软件升级项目'
|
|
|
- }),
|
|
|
- amount: z.coerce.number().multipleOf(0.01).optional().openapi({
|
|
|
- description: '预计金额',
|
|
|
- example: 50000.00
|
|
|
- }),
|
|
|
- stage: z.enum([
|
|
|
- OpportunityStage.INITIAL_CONTACT,
|
|
|
- OpportunityStage.NEEDS_ANALYSIS,
|
|
|
- OpportunityStage.SOLUTION_PROPOSAL,
|
|
|
- OpportunityStage.NEGOTIATION,
|
|
|
- OpportunityStage.CLOSED_WON,
|
|
|
- OpportunityStage.CLOSED_LOST
|
|
|
- ]).optional().openapi({
|
|
|
- description: '销售阶段',
|
|
|
- example: OpportunityStage.INITIAL_CONTACT
|
|
|
- }),
|
|
|
- expectedCloseDate: z.coerce.date().nullable().optional().openapi({
|
|
|
- description: '预计成交日期',
|
|
|
- example: '2023-12-31'
|
|
|
- }),
|
|
|
- description: z.string().nullable().optional().openapi({
|
|
|
- description: '销售机会描述',
|
|
|
- example: '为客户提供企业级软件升级方案'
|
|
|
- })
|
|
|
-});
|