contract.entity.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
  2. import { z } from 'zod';
  3. import { Customer } from '@/server/modules/customers/customer.entity';
  4. import { Opportunity } from '@/server/modules/opportunities/opportunity.entity';
  5. import { User } from '@/server/modules/users/user.entity';
  6. @Entity('contracts')
  7. export class Contract {
  8. @PrimaryGeneratedColumn({ unsigned: true })
  9. id!: number;
  10. @Column({
  11. name: 'contract_no',
  12. type: 'varchar',
  13. length: 50,
  14. nullable: false,
  15. unique: true,
  16. comment: '合同编号'
  17. })
  18. contractNo!: string;
  19. @Column({
  20. name: 'title',
  21. type: 'varchar',
  22. length: 100,
  23. nullable: false,
  24. comment: '合同标题'
  25. })
  26. title!: string;
  27. @Column({
  28. name: 'customer_id',
  29. type: 'int',
  30. unsigned: true,
  31. nullable: false,
  32. comment: '客户ID'
  33. })
  34. customerId!: number;
  35. @Column({
  36. name: 'opportunity_id',
  37. type: 'int',
  38. unsigned: true,
  39. nullable: true,
  40. comment: '销售机会ID'
  41. })
  42. opportunityId!: number | null;
  43. @Column({
  44. name: 'amount',
  45. type: 'decimal',
  46. precision: 12,
  47. scale: 2,
  48. nullable: false,
  49. comment: '合同金额'
  50. })
  51. amount!: number;
  52. @Column({
  53. name: 'signed_date',
  54. type: 'date',
  55. nullable: false,
  56. comment: '签约日期'
  57. })
  58. signedDate!: Date;
  59. @Column({
  60. name: 'start_date',
  61. type: 'date',
  62. nullable: false,
  63. comment: '开始日期'
  64. })
  65. startDate!: Date;
  66. @Column({
  67. name: 'end_date',
  68. type: 'date',
  69. nullable: true,
  70. comment: '结束日期'
  71. })
  72. endDate!: Date | null;
  73. @Column({
  74. name: 'status',
  75. type: 'tinyint',
  76. default: 0,
  77. comment: '合同状态(0-草稿, 1-已签约, 2-执行中, 3-已完成, 4-已终止)'
  78. })
  79. status!: number;
  80. @Column({
  81. name: 'payment_terms',
  82. type: 'text',
  83. nullable: true,
  84. comment: '付款条件'
  85. })
  86. paymentTerms!: string | null;
  87. @Column({
  88. name: 'signed_by',
  89. type: 'int',
  90. unsigned: true,
  91. nullable: true,
  92. comment: '签约人ID'
  93. })
  94. signedBy!: number | null;
  95. @Column({
  96. name: 'attachment_url',
  97. type: 'varchar',
  98. length: 255,
  99. nullable: true,
  100. comment: '合同附件URL'
  101. })
  102. attachmentUrl!: string | null;
  103. @Column({
  104. name: 'description',
  105. type: 'text',
  106. nullable: true,
  107. comment: '合同描述'
  108. })
  109. description!: string | null;
  110. @Column({
  111. name: 'is_deleted',
  112. type: 'tinyint',
  113. default: 0,
  114. comment: '删除状态(0-未删除, 1-已删除)'
  115. })
  116. isDeleted!: number;
  117. @Column({
  118. name: 'created_at',
  119. type: 'timestamp',
  120. default: () => 'CURRENT_TIMESTAMP',
  121. comment: '创建时间'
  122. })
  123. createdAt!: Date;
  124. @Column({
  125. name: 'updated_at',
  126. type: 'timestamp',
  127. default: () => 'CURRENT_TIMESTAMP',
  128. onUpdate: 'CURRENT_TIMESTAMP',
  129. comment: '更新时间'
  130. })
  131. updatedAt!: Date;
  132. // 关系定义
  133. @ManyToOne(() => Customer, customer => customer.contracts)
  134. customer!: Customer;
  135. @ManyToOne(() => Opportunity, opportunity => opportunity.id)
  136. opportunity!: Opportunity;
  137. @ManyToOne(() => User, user => user.id)
  138. signedUser!: User;
  139. }
  140. export const ContractSchema = z.object({
  141. id: z.number().int().positive().openapi({
  142. description: '合同ID',
  143. example: 1
  144. }),
  145. contractNo: z.string().min(1).max(50).openapi({
  146. description: '合同编号',
  147. example: 'HT-20230001'
  148. }),
  149. title: z.string().min(1).max(100).openapi({
  150. description: '合同标题',
  151. example: 'ERP系统升级服务合同'
  152. }),
  153. customerId: z.number().int().positive().openapi({
  154. description: '客户ID',
  155. example: 1
  156. }),
  157. opportunityId: z.number().int().positive().nullable().openapi({
  158. description: '销售机会ID',
  159. example: 1
  160. }),
  161. amount: z.number().openapi({
  162. description: '合同金额',
  163. example: 150000.00
  164. }),
  165. signedDate: z.date().openapi({
  166. description: '签约日期',
  167. example: '2023-01-15'
  168. }),
  169. startDate: z.date().openapi({
  170. description: '开始日期',
  171. example: '2023-02-01'
  172. }),
  173. endDate: z.date().nullable().openapi({
  174. description: '结束日期',
  175. example: '2023-12-31'
  176. }),
  177. status: z.number().int().min(0).max(4).openapi({
  178. description: '合同状态(0-草稿, 1-已签约, 2-执行中, 3-已完成, 4-已终止)',
  179. example: 2
  180. }),
  181. paymentTerms: z.string().nullable().openapi({
  182. description: '付款条件',
  183. example: '首付50%,验收后付40%,质保金10%'
  184. }),
  185. signedBy: z.number().int().positive().nullable().openapi({
  186. description: '签约人ID',
  187. example: 1
  188. }),
  189. attachmentUrl: z.string().url().max(255).nullable().openapi({
  190. description: '合同附件URL',
  191. example: 'https://example.com/contracts/HT-20230001.pdf'
  192. }),
  193. description: z.string().nullable().openapi({
  194. description: '合同描述',
  195. example: '为客户提供ERP系统升级服务'
  196. }),
  197. isDeleted: z.number().int().min(0).max(1).openapi({
  198. description: '删除状态(0-未删除, 1-已删除)',
  199. example: 0
  200. }),
  201. createdAt: z.date().openapi({
  202. description: '创建时间',
  203. example: '2023-01-01T00:00:00Z'
  204. }),
  205. updatedAt: z.date().openapi({
  206. description: '更新时间',
  207. example: '2023-01-01T00:00:00Z'
  208. })
  209. });