1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
|
import { pgTable, serial, varchar, integer, date, timestamp, decimal, text, jsonb, boolean } from 'drizzle-orm/pg-core';
import { relations } from 'drizzle-orm';
import { users } from './users'; // users 테이블이 존재한다고 가정
import { vendors } from './vendors'; // vendors 테이블이 존재한다고 가정
import { contracts } from './contract';
import { projects } from './projects'; // projects 테이블 추가
export const generalContractTemplates = pgTable('general_contract_templates', {
id: integer("id").primaryKey().generatedAlwaysAsIdentity(),
contractTemplateType: varchar('contract_template_type', { length: 2 }).notNull(),
contractTemplateName: text('contract_template_name').notNull(),
revision: integer('revision').notNull().default(1),
status: varchar('status', { length: 20 }).notNull().default('ACTIVE'),
fileName: varchar("file_name", { length: 255 }),
filePath: varchar("file_path", { length: 1024 }),
legalReviewRequired: boolean('legal_review_required').notNull().default(false),
createdAt: timestamp('created_at').defaultNow(),
createdBy: integer('created_by').references(() => users.id),
updatedAt: timestamp('updated_at').defaultNow(),
updatedBy: integer('updated_by').references(() => users.id),
disposedAt: timestamp('disposed_at'),
restoredAt: timestamp('restored_at'),
});
export const generalContracts = pgTable('general_contracts', {
// ═══════════════════════════════════════════════════════════════
// 기본 식별 정보
// ═══════════════════════════════════════════════════════════════
id: serial('id').primaryKey(), // 계약 고유 ID
contractNumber: varchar('contract_number', { length: 255 }).notNull().unique(), // 계약번호 (자동 채번)
revision: integer('revision').notNull().default(0), // 계약 개정 번호
//견적에서 넘어온 레코드인지, 입찰에서 넘어온 레코드인지, 자체 생성한 레코드인지 판단하는 타입, default는 자체생성!, notnull
// contractSourceType: 견적(estimate), 입찰(bid), 자체생성(manual) 중 하나를 저장하는 컬럼, default는 'manual', not null
contractSourceType: varchar('contract_source_type', { length: 20 }).notNull().default('manual'),
// ═══════════════════════════════════════════════════════════════
// 계약 분류 및 상태
// ═══════════════════════════════════════════════════════════════
status: varchar('status', { length: 50 }).notNull(), // 계약 상태 (Draft, Complete the Contract, Contract Delete 등)
category: varchar('category', { length: 50 }).notNull(), // 계약구분 (단가계약, 일반계약, 매각계약)
type: varchar('type', { length: 50 }), // 계약종류 (UP, LE, IL, AL 등)
executionMethod: varchar('execution_method', { length: 50 }), // 체결방식 (오프라인, 온라인 등)
name: varchar('name', { length: 255 }), // 계약명
// ═══════════════════════════════════════════════════════════════
// 협력업체 및 계약 기간
// ═══════════════════════════════════════════════════════════════
vendorId: integer('vendor_id').notNull().references(() => vendors.id), // 협력업체 ID
startDate: date('start_date'), // 계약 시작일
endDate: date('end_date'), // 계약 종료일
validityEndDate: date('validity_end_date'), // 계약 유효기간 종료일
// ═══════════════════════════════════════════════════════════════
// 연계 정보
// ═══════════════════════════════════════════════════════════════
linkedRfqOrItb: varchar('linked_rfq_or_itb', { length: 255 }), // 연계 RFQ/ITB 번호
linkedPoNumber: varchar('linked_po_number', { length: 255 }), // 연계 PO 번호
linkedBidNumber: varchar('linked_bid_number', { length: 255 }), // 연계 BID 번호
// ═══════════════════════════════════════════════════════════════
// 계약 범위 및 사양
// ═══════════════════════════════════════════════════════════════
contractScope: varchar('contract_scope', { length: 50 }), // 계약 범위
warrantyPeriod: jsonb('warranty_period').default({}), // 품질/하자 보증기간
specificationType: varchar('specification_type', { length: 50 }), // 사양 유형
specificationManualText: text('specification_manual_text'), // 사양 매뉴얼 텍스트
// ═══════════════════════════════════════════════════════════════
// 금액 정보
// ═══════════════════════════════════════════════════════════════
unitPriceType: varchar('unit_price_type', { length: 50 }), // 단가 유형
contractAmount: decimal('contract_amount', { precision: 15, scale: 2 }), // 계약 금액
currency: varchar('currency', { length: 10 }), // 통화
totalAmount: decimal('total_amount', { precision: 15, scale: 2 }), // 총 금액
availableBudget: decimal('available_budget', { precision: 15, scale: 2 }), // 가용 예산
// ═══════════════════════════════════════════════════════════════
// 지급조건 (Payment Condition)
// ═══════════════════════════════════════════════════════════════
paymentBeforeDelivery: jsonb('payment_before_delivery').default({}), // 납품 전 지급조건
paymentDelivery: varchar('payment_delivery', { length: 50 }), // 납품 지급조건
paymentAfterDelivery: jsonb('payment_after_delivery').default({}), // 납품 외 지급조건
contractCurrency: varchar('contract_currency', { length: 10 }), // 계약통화
paymentTerm: varchar('payment_term', { length: 50 }), // 지불조건 (L003 등)
taxType: varchar('tax_type', { length: 50 }), // 세금 (VV 등)
liquidatedDamages: decimal('liquidated_damages', { precision: 15, scale: 2 }), // 지체상금
liquidatedDamagesPercent: decimal('liquidated_damages_percent', { precision: 5, scale: 2 }), // 지체상금 비율
claimAmount: jsonb('claim_amount').default({}), // 클레임금액
// ═══════════════════════════════════════════════════════════════
// 인도조건 (Delivery Condition)
// ═══════════════════════════════════════════════════════════════
deliveryType: varchar('delivery_type', { length: 50 }), // 납기종류 (단일납기, 분할납기, 구간납기)
deliveryTerm: varchar('delivery_term', { length: 50 }), // 인도조건 (FOB 등)
shippingLocation: varchar('shipping_location', { length: 100 }), // 선적지
dischargeLocation: varchar('discharge_location', { length: 100 }), // 하역지
contractDeliveryDate: date('contract_delivery_date'), // 계약납기일
// ═══════════════════════════════════════════════════════════════
// 추가조건 (Additional Condition)
// ═══════════════════════════════════════════════════════════════
contractEstablishmentConditions: jsonb('contract_establishment_conditions').default({}), // 계약성립조건
interlockingSystem: varchar('interlocking_system', { length: 10 }), // 연동제적용 (Y/N)
mandatoryDocuments: jsonb('mandatory_documents').default({}), // 필수문서동의
contractTerminationConditions: jsonb('contract_termination_conditions').default({}), // 계약해지조건
externalYardEntry: varchar('external_yard_entry', { length: 1 }), // 사외업체 야드투입 (Y/N)
contractAmountReason: text('contract_amount_reason'), // 합의계약 미확정 사유
// ═══════════════════════════════════════════════════════════════
// 기타 계약 조건 및 약관 (JSON 형태)
// ═══════════════════════════════════════════════════════════════
terms: jsonb('terms').default({}), // 계약 조건
complianceChecklist: jsonb('compliance_checklist').default({}), // 하도급법 체크리스트
communicationChannels: jsonb('communication_channels').default({}), // 커뮤니케이션 채널
locations: jsonb('locations').default({}), // 위치 정보
fieldServiceRates: jsonb('field_service_rates').default({}), // 현장 서비스 요금(국가별 현장 서비스 요금)
offsetDetails: jsonb('offset_details').default({}), // 회입/상계내역
// ═══════════════════════════════════════════════════════════════
// 조건검토 의견
// ═══════════════════════════════════════════════════════════════
vendorComment: text('vendor_comment'), // 협력업체 조건검토 의견
shiComment: text('shi_comment'), // 당사 조건검토 의견
// ═══════════════════════════════════════════════════════════════
// 시스템 관리 정보
// ═══════════════════════════════════════════════════════════════
registeredById: integer('registered_by_id').notNull().references(() => users.id), // 등록자 ID
registeredAt: timestamp('registered_at').notNull().defaultNow(), // 등록일시
signedAt: timestamp('signed_at'), // 계약 체결일시
lastUpdatedById: integer('last_updated_by_id').notNull().references(() => users.id), // 최종 수정자 ID
lastUpdatedAt: timestamp('last_updated_at').notNull().defaultNow(), // 최종 수정일시
notes: text('notes'), // 비고
});
export const generalContractItems = pgTable('general_contract_items', {
// ═══════════════════════════════════════════════════════════════
// 기본 식별 정보
// ═══════════════════════════════════════════════════════════════
id: serial('id').primaryKey(), // 품목 고유 ID
contractId: integer('contract_id').notNull().references(() => generalContracts.id), // 계약 ID (외래키)
projectId: integer('project_id').references(() => projects.id), // 프로젝트 ID (nullable)
// ═══════════════════════════════════════════════════════════════
// 품목 기본 정보
// ═══════════════════════════════════════════════════════════════
itemCode: varchar('item_code', { length: 100 }), // 품목코드 (PKG No.)
itemInfo: varchar('item_info', { length: 500 }), // Item 정보 (자재그룹 / 자재코드)
specification: varchar('specification', { length: 500 }), // 규격
// ═══════════════════════════════════════════════════════════════
// 수량 및 단가 정보
// ═══════════════════════════════════════════════════════════════
quantity: decimal('quantity', { precision: 15, scale: 3 }), // 수량
quantityUnit: varchar('quantity_unit', { length: 50 }), // 수량단위
totalWeight: decimal('total_weight', { precision: 15, scale: 3 }), // 총 중량
weightUnit: varchar('weight_unit', { length: 50 }), // 중량단위
contractDeliveryDate: date('contract_delivery_date'), // 계약납기일
contractUnitPrice: decimal('contract_unit_price', { precision: 15, scale: 2 }), // 계약단가
contractAmount: decimal('contract_amount', { precision: 15, scale: 2 }), // 계약금액
contractCurrency: varchar('contract_currency', { length: 10 }), // 계약통화
// ═══════════════════════════════════════════════════════════════
// 시스템 관리 정보
// ═══════════════════════════════════════════════════════════════
createdAt: timestamp('created_at').notNull().defaultNow(), // 생성일시
updatedAt: timestamp('updated_at').notNull().defaultNow(), // 수정일시
});
export const generalContractAttachments = pgTable('general_contract_attachments', {
id: serial('id').primaryKey(),
contractId: integer('contract_id').notNull().references(() => generalContracts.id),
poContractId: integer('po_contract_id').references(() => contracts.id),
documentName: varchar('document_name', { length: 255 }).notNull(), // '사양 및 공급범위', '단가파일', '계약서 서명본' 등
fileName: varchar('file_name', { length: 255 }).notNull(), // 실제 파일명
filePath: varchar('file_path', { length: 512 }).notNull(), // 파일 저장 경로 (S3 URL 등)
shiComment: text('shi_comment'),
vendorComment: text('vendor_comment'),
legalReview: boolean('legal_review').notNull().default(false), // 법무 검토 여부
uploadedAt: timestamp('uploaded_at').notNull().defaultNow(),
uploadedById: integer('uploaded_by_id').notNull().references(() => users.id),
});
export const generalContractAttachmentsRelations = relations(generalContractAttachments, ({ one }) => ({
contract: one(generalContracts, {
fields: [generalContractAttachments.contractId],
references: [generalContracts.id],
}),
}));
export const generalContractItemsRelations = relations(generalContractItems, ({ one }) => ({
contract: one(generalContracts, {
fields: [generalContractItems.contractId],
references: [generalContracts.id],
}),
project: one(projects, {
fields: [generalContractItems.projectId],
references: [projects.id],
}),
}));
export const generalContractsRelations = relations(generalContracts, ({ one, many }) => ({
manager: one(users, {
fields: [generalContracts.registeredById],
references: [users.id],
relationName: 'contract_manager',
}),
lastUpdatedBy: one(users, {
fields: [generalContracts.lastUpdatedById],
references: [users.id],
relationName: 'contract_last_updated_by',
}),
vendor: one(vendors, {
fields: [generalContracts.vendorId],
references: [vendors.id],
}),
items: many(generalContractItems),
attachments: many(generalContractAttachments),
}));
// TypeScript 타입 정의
export type GeneralContractTemplate = typeof generalContractTemplates.$inferSelect;
export type NewGeneralContractTemplate = typeof generalContractTemplates.$inferInsert;
export type GeneralContract = typeof generalContracts.$inferSelect;
export type NewGeneralContract = typeof generalContracts.$inferInsert;
export type GeneralContractItem = typeof generalContractItems.$inferSelect;
export type NewGeneralContractItem = typeof generalContractItems.$inferInsert;
export type GeneralContractAttachment = typeof generalContractAttachments.$inferSelect;
export type NewGeneralContractAttachment = typeof generalContractAttachments.$inferInsert;
|