summaryrefslogtreecommitdiff
path: root/db/schema/vendors.ts
diff options
context:
space:
mode:
Diffstat (limited to 'db/schema/vendors.ts')
-rw-r--r--db/schema/vendors.ts181
1 files changed, 174 insertions, 7 deletions
diff --git a/db/schema/vendors.ts b/db/schema/vendors.ts
index acdec3d2..f56a1288 100644
--- a/db/schema/vendors.ts
+++ b/db/schema/vendors.ts
@@ -1,7 +1,20 @@
// db/schema/vendors.ts
-import { pgTable, serial, varchar, text, timestamp, boolean, integer ,pgView} from "drizzle-orm/pg-core";
+import { pgTable, serial, varchar, text, timestamp, boolean, integer ,pgView} from "drizzle-orm/pg-core";
import { items } from "./items";
-import { sql, eq} from "drizzle-orm";
+import { sql, eq, relations} from "drizzle-orm";
+import { users } from "./users";
+
+
+// vendorTypes 테이블 생성
+export const vendorTypes = pgTable("vendor_types", {
+ id: serial("id").primaryKey(),
+ code: varchar("code", { length: 50 }).notNull().unique(),
+ nameKo: varchar("name_ko", { length: 255 }).notNull(),
+ nameEn: varchar("name_en", { length: 255 }).notNull(),
+ createdAt: timestamp("created_at").defaultNow().notNull(),
+ updatedAt: timestamp("updated_at").defaultNow().notNull(),
+});
+
export const vendors = pgTable("vendors", {
id: serial("id").primaryKey(),
@@ -32,7 +45,7 @@ export const vendors = pgTable("vendors", {
})
.notNull()
.default("PENDING_REVIEW"),
-
+ vendorTypeId: integer("vendor_type_id").references(() => vendorTypes.id),
representativeName: varchar("representative_name", { length: 255 }),
representativeBirth: varchar("representative_birth", { length: 20 }),
representativeEmail: varchar("representative_email", { length: 255 }),
@@ -40,6 +53,7 @@ export const vendors = pgTable("vendors", {
corporateRegistrationNumber: varchar("corporate_registration_number", {
length: 100,
}),
+ items: text("items"),
creditAgency: varchar("credit_agency", { length: 50 }),
creditRating: varchar("credit_rating", { length: 50 }),
@@ -255,8 +269,12 @@ export const vendorInvestigationsView = pgView(
export const vendorCandidates = pgTable("vendor_candidates", {
id: serial("id").primaryKey(),
companyName: varchar("company_name", { length: 255 }).notNull(),
- contactEmail: varchar("contact_email", { length: 255 }).notNull(),
+ contactEmail: varchar("contact_email", { length: 255 }),
contactPhone: varchar("contact_phone", { length: 50 }),
+
+ taxId: varchar("tax_id", { length: 100 }).notNull(),
+ address: text("address"),
+
country: varchar("country", { length: 100 }),
// 웹 크롤링 등으로 얻은 상태나 분류
source: varchar("source", { length: 100 }), // 수집 출처
@@ -270,7 +288,10 @@ export const vendorCandidates = pgTable("vendor_candidates", {
})
.notNull()
.default("COLLECTED"),
-
+ remark: text("remark"),
+ items: text("items").notNull(),
+ vendorId: integer("vendor_id")
+ .references(() => vendors.id, { onDelete: "cascade" }),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
@@ -281,7 +302,7 @@ export type VendorCandidates = typeof vendorCandidates.$inferSelect;
export const vendorDetailView = pgView("vendor_detail_view").as((qb) => {
return qb
.select({
- // 벤더 기본 정보
+ // 협력업체 기본 정보
id: vendors.id,
vendorName: vendors.vendorName,
vendorCode: vendors.vendorCode,
@@ -359,4 +380,150 @@ export const vendorDetailView = pgView("vendor_detail_view").as((qb) => {
});
// 타입 정의
-export type VendorDetailView = typeof vendorDetailView.$inferSelect; \ No newline at end of file
+export type VendorDetailView = typeof vendorDetailView.$inferSelect;
+
+
+// 관계 설정 (DrizzleORM을 사용한다고 가정)
+export const vendorRelations = relations(vendors, ({ one }) => ({
+ vendorType: one(vendorTypes, {
+ fields: [vendors.vendorTypeId],
+ references: [vendorTypes.id],
+ }),
+}));
+
+export const vendorTypeRelations = relations(vendorTypes, ({ many }) => ({
+ vendors: many(vendors),
+}));
+
+export type VendorTypes = typeof vendorTypes.$inferSelect;
+
+
+
+
+export const vendorCandidatesWithVendorInfo = pgView("vendor_candidates_with_vendor_info").as((qb) => {
+ return qb
+ .select({
+ // ----------------------------------------
+ // 1) vendorCandidates 기본 필드
+ id: vendorCandidates.id,
+ companyName: vendorCandidates.companyName,
+ contactEmail: vendorCandidates.contactEmail,
+ contactPhone: vendorCandidates.contactPhone,
+ taxId: vendorCandidates.taxId,
+ address: vendorCandidates.address,
+ country: vendorCandidates.country,
+ source: vendorCandidates.source,
+ status: vendorCandidates.status,
+ items: vendorCandidates.items,
+ remark: vendorCandidates.remark,
+ // remark, items, vendorId 등 필요한 필드도 추가
+ createdAt: vendorCandidates.createdAt,
+ updatedAt: vendorCandidates.updatedAt,
+
+ // ----------------------------------------
+ // 2) vendors 조인해서 가져올 필드
+ vendorName: vendors.vendorName,
+ vendorCode: vendors.vendorCode,
+ vendorCreatedAt: sql<Date>`${vendors.createdAt}`.as("vendor_created_at"),
+
+ // ----------------------------------------
+ // 3) 마지막 상태 변경 시각, 변경자 (action = 'status_change')
+ lastStatusChangeAt: sql<Date>`(
+ SELECT l2."created_at"
+ FROM "vendor_candidate_logs" l2
+ WHERE l2."vendor_candidate_id" = "vendor_candidates"."id"
+ AND l2."action" = 'status_change'
+ ORDER BY l2."created_at" DESC
+ LIMIT 1
+ )`.as("last_status_change_at"),
+
+ lastStatusChangeBy: sql<string>`(
+ SELECT u."name"
+ FROM "users" u
+ JOIN "vendor_candidate_logs" l3
+ ON l3."user_id" = u."id"
+ WHERE l3."vendor_candidate_id" = "vendor_candidates"."id"
+ AND l3."action" = 'status_change'
+ ORDER BY l3."created_at" DESC
+ LIMIT 1
+ )`.as("last_status_change_by"),
+
+ // ----------------------------------------
+ // 4) 마지막 초청(Invite) 시각, 초청자 (action = 'invite_sent')
+ lastInvitationAt: sql<Date>`(
+ SELECT l4."created_at"
+ FROM "vendor_candidate_logs" l4
+ WHERE l4."vendor_candidate_id" = "vendor_candidates"."id"
+ AND l4."action" = 'invite_sent'
+ ORDER BY l4."created_at" DESC
+ LIMIT 1
+ )`.as("last_invitation_at"),
+
+ lastInvitationBy: sql<string>`(
+ SELECT u2."name"
+ FROM "users" u2
+ JOIN "vendor_candidate_logs" l5
+ ON l5."user_id" = u2."id"
+ WHERE l5."vendor_candidate_id" = "vendor_candidates"."id"
+ AND l5."action" = 'invite_sent'
+ ORDER BY l5."created_at" DESC
+ LIMIT 1
+ )`.as("last_invitation_by"),
+ })
+ .from(vendorCandidates)
+ .leftJoin(vendors, eq(vendorCandidates.vendorId, vendors.id));
+});
+
+export type VendorCandidatesWithVendorInfo = typeof vendorCandidatesWithVendorInfo.$inferSelect;
+
+
+export const vendorsWithTypesView = pgView("vendors_with_types").as((qb) => {
+ return qb
+ .select({
+ // Vendor fields
+ id: vendors.id,
+ vendorName: vendors.vendorName,
+ vendorCode: vendors.vendorCode,
+ taxId: vendors.taxId,
+ address: vendors.address,
+ country: vendors.country,
+ phone: vendors.phone,
+ email: vendors.email,
+ website: vendors.website,
+ status: vendors.status,
+ vendorTypeId: vendors.vendorTypeId,
+ representativeName: vendors.representativeName,
+ representativeBirth: vendors.representativeBirth,
+ representativeEmail: vendors.representativeEmail,
+ representativePhone: vendors.representativePhone,
+ corporateRegistrationNumber: vendors.corporateRegistrationNumber,
+ items: vendors.items,
+ creditAgency: vendors.creditAgency,
+ creditRating: vendors.creditRating,
+ cashFlowRating: vendors.cashFlowRating,
+ createdAt: vendors.createdAt,
+ updatedAt: vendors.updatedAt,
+
+ // Vendor type fields
+ vendorTypeName: vendorTypes.nameKo,
+ vendorTypeNameEn: vendorTypes.nameEn,
+ vendorTypeCode: vendorTypes.code,
+
+ // Computed vendor category field
+ vendorCategory: sql`
+ CASE
+ WHEN ${vendors.status} = 'ACTIVE' THEN '정규업체'
+ WHEN ${vendors.status} IN ('INACTIVE', 'BLACKLISTED', 'REJECTED') THEN ''
+ ELSE '잠재업체'
+ END
+ `.as("vendor_category")
+ })
+ .from(vendors)
+ .leftJoin(
+ vendorTypes,
+ sql`${vendors.vendorTypeId} = ${vendorTypes.id}`
+ );
+});
+
+// You can also create interfaces for the view
+export type VendorWithType = typeof vendorsWithTypesView.$inferSelect; \ No newline at end of file