From 1e4726f4ccd2f898b393a40ccad9e40c684c10cd Mon Sep 17 00:00:00 2001 From: Mina Choi Date: Wed, 22 Jul 2026 15:19:41 +0900 Subject: [PATCH] =?UTF-8?q?[feat]=20=EC=8A=A4=ED=82=A4=EB=A7=88:=20company?= =?UTF-8?q?.settings=C2=B7items/suppliers/sessions.custom=C2=B7nego=5Fcard?= =?UTF-8?q?s=20=EC=BB=AC=EB=9F=BC=20=EC=B6=94=EA=B0=80(=EB=AA=A8=EB=8D=B8?= =?UTF-8?q?=C2=B7init.sql)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/common/database/model/models.py | 30 +++++++++++++++++++ .../backend/common/database/model/models.py | 7 +++++ postgres-init/init-data/init.sql | 12 ++++++++ 3 files changed, 49 insertions(+) diff --git a/backend/common/database/model/models.py b/backend/common/database/model/models.py index c1e5ea2..6418d31 100644 --- a/backend/common/database/model/models.py +++ b/backend/common/database/model/models.py @@ -58,6 +58,21 @@ class suppliers(MAIN_BASE): deleted = Column(Boolean, nullable=False, server_default=text("false")) # 소프트 삭제 여부 +class companies(MAIN_BASE): + # company.companies (고객사). 공급사 포털 브랜딩(settings.branding) 조회 전용 미러. + @staticmethod + def DBType(): + return DBType.PARTNER.value + + __tablename__ = "companies" + __table_args__ = {"schema": "company"} + + company_id = Column(UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()")) # 회사 식별자(PK) + name = Column(String(100), nullable=False) # 회사명 + settings = Column(JSONB, nullable=True) # 회사별 커스터마이징(branding/labels 등, negodata 소유) + deleted = Column(Boolean, nullable=False, server_default=text("false")) # 소프트 삭제 여부 + + class items(MAIN_BASE): # partner.items (상품). @staticmethod @@ -123,6 +138,7 @@ class sessions(MAIN_BASE): reject_reason = Column(String(255), nullable=True) # 거절 사유 reject_price = Column(BigInteger, nullable=True) # 거절 시 제시가(원) reject_delivery_type = Column(SmallInteger, nullable=True) # 거절 시 배송 유형 (코드) + custom = Column(JSONB, nullable=True) # 협상완료 부가정보 값 {key: value} (정의는 companies.settings.session_fields) created_at = Column(DateTime(timezone=True), nullable=False, server_default=text("(now() AT TIME ZONE 'utc')")) # 생성 시각(UTC) updated_at = Column(DateTime(timezone=True), nullable=False, server_default=text("(now() AT TIME ZONE 'utc')"), onupdate=text("(now() AT TIME ZONE 'utc')")) # 수정 시각(UTC, UPDATE 시 자동 갱신) deleted = Column(Boolean, nullable=False, server_default=text("false")) # 소프트 삭제 여부 @@ -183,6 +199,20 @@ class quotation_settings(MAIN_BASE): deleted = Column(Boolean, nullable=False, server_default=text("false")) # 소프트 삭제 여부 +class nego_cards(MAIN_BASE): + # card.nego_cards (협상카드). backend 는 번호→UUID 변환(chats.card_id 저장)만 위해 최소 컬럼 미러. + @staticmethod + def DBType(): + return DBType.NEGOTIATION.value # 같은 negosium_db — chats 와 동일 세션풀로 조회 + + __tablename__ = "nego_cards" + __table_args__ = {"schema": "card"} + + nego_card_id = Column(UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()")) + number = Column(String(10), nullable=True) # 카드 번호(agent turn.card_id 와 매칭) + deleted = Column(Boolean, nullable=False, server_default=text("false")) + + class chats(MAIN_BASE): # negotiation.chats (협상 채팅 메시지 로그). session 1 : N chats. (session_id, seq) 유니크. @staticmethod diff --git a/negodata/backend/common/database/model/models.py b/negodata/backend/common/database/model/models.py index 583b3d6..b50663d 100644 --- a/negodata/backend/common/database/model/models.py +++ b/negodata/backend/common/database/model/models.py @@ -47,6 +47,8 @@ class companies(MainTableMixin, MAIN_BASE): website_url = Column(String(255), nullable=True) industry = Column(SmallInteger, nullable=True) # 업종 코드 (스키마 SMALLINT) status = Column(SmallInteger, nullable=False, default=CompanyStatus.ACTIVE.value) # CompanyStatus + # 회사별 커스터마이징 설정. branding(CI)/labels(용어)/features(동작)/item_fields·supplier_fields(커스텀필드 정의) + settings = Column(JSONB, nullable=True) class users(MainTableMixin, MAIN_BASE): @@ -109,6 +111,8 @@ class items(MainTableMixin, MAIN_BASE): delivery_type = Column(SmallInteger, nullable=True) # 배송 유형 코드 vat_yn = Column(Boolean, nullable=True) delivery_fee_yn = Column(Boolean, nullable=True) + # 회사 커스텀필드 값. 정의(키/라벨/타입)는 companies.settings.item_fields, 여기는 {key: value}만 + custom = Column(JSONB, nullable=True) class item_internet_lowest_prices(MainTableMixin, MAIN_BASE): @@ -145,6 +149,8 @@ class suppliers(MainTableMixin, MAIN_BASE): manager_email = Column(String(255), nullable=True) manager_contact_number = Column(String(20), nullable=True) # ERD 오타(manger) 교정 total_revenue = Column(BigInteger, nullable=True) # 총매출액 + # 회사 커스텀필드 값. 정의는 companies.settings.supplier_fields, 여기는 {key: value}만 + custom = Column(JSONB, nullable=True) class supplier_users(MainTableMixin, MAIN_BASE): @@ -316,6 +322,7 @@ class sessions(MainTableMixin, MAIN_BASE): reject_price = Column(BigInteger, nullable=True) reject_delivery_type = Column(SmallInteger, nullable=True) # DeliveryType 코드 email_sent_at = Column(DateTime(timezone=True), nullable=True) # 협상 초청 메일 발송 시각(NULL=미발송) + custom = Column(JSONB, nullable=True) # 협상완료 부가정보 값 {key: value} (정의는 companies.settings.session_fields) class chats(MainTableMixin, MAIN_BASE): diff --git a/postgres-init/init-data/init.sql b/postgres-init/init-data/init.sql index e747210..0140522 100644 --- a/postgres-init/init-data/init.sql +++ b/postgres-init/init-data/init.sql @@ -60,6 +60,7 @@ CREATE TABLE IF NOT EXISTS company.companies ( website_url VARCHAR(255) NULL, -- 홈페이지 URL industry SMALLINT NULL, -- 업종 ( 필요한 만큼 숫자에 매핑하여 사용 ) status SMALLINT NOT NULL DEFAULT 1, -- 상태: 1=active(활성), 2=inactive(비활성) + settings JSONB NULL, -- 회사별 커스터마이징: branding(CI)/labels(용어)/features(동작)/item_fields·supplier_fields(커스텀필드 정의) created_at TIMESTAMPTZ NOT NULL DEFAULT now(), -- 생성 시각(UTC) updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), -- 수정 시각(UTC, 앱에서 갱신) deleted BOOLEAN NOT NULL DEFAULT FALSE -- 소프트 삭제 여부 @@ -138,6 +139,7 @@ CREATE TABLE IF NOT EXISTS partner.suppliers ( manager_email VARCHAR(255) NULL, -- 담당자 이메일 manager_contact_number VARCHAR(20) NULL, -- 담당자 연락처 total_revenue BIGINT NULL, -- 총매출액(원). KTC suppliers.total_revenue 미러 + custom JSONB NULL, -- 회사 커스텀필드 값 {key: value} (정의는 companies.settings.supplier_fields) created_at TIMESTAMPTZ NOT NULL DEFAULT now(), -- 생성 시각(UTC) updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), -- 수정 시각(UTC, 앱에서 갱신) deleted BOOLEAN NOT NULL DEFAULT FALSE -- 소프트 삭제 여부 @@ -167,6 +169,7 @@ CREATE TABLE IF NOT EXISTS partner.items ( purchase_price BIGINT NULL, -- 매입가 selling_price BIGINT NULL, -- 판매가 category_type INTEGER NOT NULL DEFAULT 1, -- 자동으로 늘어나는 숫자 ( 카테고리 찾을때 유용한 컬럼) + custom JSONB NULL, -- 회사 커스텀필드 값 {key: value} (정의는 companies.settings.item_fields) created_at TIMESTAMPTZ NOT NULL DEFAULT now(), -- 생성 시각(UTC) updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), -- 수정 시각(UTC, 앱에서 갱신) deleted BOOLEAN NOT NULL DEFAULT FALSE -- 소프트 삭제 여부 @@ -330,6 +333,7 @@ CREATE TABLE IF NOT EXISTS negotiation.sessions ( reject_price BIGINT NULL, -- 거절 시 제시가(원) reject_delivery_type SMALLINT NULL, -- 거절 시 배송 유형(DeliveryType): 1=supplier(협력사배송), 2=courier(지정택배배송), 3=pickup(픽업배송) email_sent_at TIMESTAMPTZ NULL, -- 협상 초청 메일 발송 시각(NULL=미발송). 수동 발송 버튼이 채움 + custom JSONB NULL, -- 협상완료 부가정보 값 {key: value} (정의는 companies.settings.session_fields: 표준납기/MOQ/발주배수/배송유형) created_at TIMESTAMPTZ NOT NULL DEFAULT now(), -- 생성 시각(UTC) updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), -- 수정 시각(UTC, 앱에서 갱신) deleted BOOLEAN NOT NULL DEFAULT FALSE -- 소프트 삭제 여부 @@ -669,6 +673,14 @@ ALTER TABLE company.users ALTER COLUMN last_accessed_at SET DEFAULT now UPDATE supplier.supplier_users SET last_accessed_at = now() WHERE last_accessed_at IS NULL; ALTER TABLE supplier.supplier_users ALTER COLUMN last_accessed_at SET DEFAULT now(); +-- [2026-07-22] 회사별 커스터마이징(브랜딩/용어 라벨/커스텀필드) — IMK 요청 대응 +ALTER TABLE company.companies ADD COLUMN IF NOT EXISTS settings JSONB NULL; +ALTER TABLE partner.items ADD COLUMN IF NOT EXISTS custom JSONB NULL; +ALTER TABLE partner.suppliers ADD COLUMN IF NOT EXISTS custom JSONB NULL; + +-- [2026-07-22] 협상완료 부가정보(표준납기/MOQ/발주배수/배송유형) — 회사 정의(session_fields) 값 저장(#5) +ALTER TABLE negotiation.sessions ADD COLUMN IF NOT EXISTS custom JSONB NULL; + -- ============================================================ -- LPS (인터넷 최저가 검색) — 별도 database lps_db