190 lines
7.7 KiB
Python
190 lines
7.7 KiB
Python
from abc import ABC, abstractmethod
|
|
from typing import Tuple
|
|
|
|
from sqlalchemy import select, func, update
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from common.database.db_session_manager import DB_SESSION_MNG
|
|
from common.database.model.models import supplier_items, items, suppliers
|
|
from common.enums import ErrorType
|
|
from common.logger import LOG
|
|
from common.utils.gtime import GTime
|
|
|
|
|
|
# 협력사-상품 매핑 CRUD. 스코프는 상위(협력사/상품)가 company_id 로 이미 걸린다.
|
|
class ISupplierItemCRUD(ABC):
|
|
@abstractmethod
|
|
async def list_by_supplier(self, cdb: AsyncSession, supplier_id) -> Tuple[ErrorType, list]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def list_by_item(self, cdb: AsyncSession, item_id) -> Tuple[ErrorType, list]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def get_by_id(self, cdb: AsyncSession, supplier_item_id) -> Tuple[ErrorType, supplier_items]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def existing_item_ids(self, cdb: AsyncSession, supplier_id, item_ids: list) -> Tuple[ErrorType, list]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def find_items_by_names(self, cdb: AsyncSession, company_id, names: list) -> Tuple[ErrorType, list]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def add_many(self, cdb: AsyncSession, mappings: list) -> ErrorType:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def update_type(self, cdb: AsyncSession, supplier_item_id, supply_type: int) -> ErrorType:
|
|
pass
|
|
|
|
@abstractmethod
|
|
async def soft_delete(self, cdb: AsyncSession, supplier_item_id) -> ErrorType:
|
|
pass
|
|
|
|
|
|
class SupplierItemCRUD(ISupplierItemCRUD):
|
|
async def list_by_supplier(self, cdb: AsyncSession, supplier_id) -> Tuple[ErrorType, list]:
|
|
# 협력사 상세용: 매핑 + 상품명/코드/카테고리/제조사 조인.
|
|
# Row(supplier_item_id, item_id, name, code, supply_type, category, manufacturer)
|
|
try:
|
|
query = (
|
|
select(
|
|
supplier_items.supplier_item_id,
|
|
supplier_items.item_id,
|
|
items.name,
|
|
items.code,
|
|
supplier_items.supply_type,
|
|
items.category,
|
|
items.manufacturer,
|
|
)
|
|
.join(items, items.item_id == supplier_items.item_id)
|
|
.where(
|
|
supplier_items.supplier_id == supplier_id,
|
|
supplier_items.deleted == False, # noqa: E712
|
|
items.deleted == False, # noqa: E712
|
|
)
|
|
.order_by(supplier_items.created_at.desc())
|
|
)
|
|
err_type, rows = await DB_SESSION_MNG.execute(cdb, query)
|
|
if err_type != ErrorType.SUCCESS:
|
|
return err_type, []
|
|
return ErrorType.SUCCESS, list(rows)
|
|
except Exception as ex:
|
|
LOG.e_no_callstack(ex)
|
|
return ErrorType.DB_RUN_FAILED, []
|
|
|
|
async def list_by_item(self, cdb: AsyncSession, item_id) -> Tuple[ErrorType, list]:
|
|
# 견적생성 모달·상품 상세 공용: 이 상품을 취급하는 협력사별 공급유형.
|
|
# Row(supplier_id, supply_type, name, supplier_item_id)
|
|
try:
|
|
query = (
|
|
select(
|
|
supplier_items.supplier_id,
|
|
supplier_items.supply_type,
|
|
suppliers.name,
|
|
supplier_items.supplier_item_id,
|
|
)
|
|
.join(suppliers, suppliers.supplier_id == supplier_items.supplier_id)
|
|
.where(
|
|
supplier_items.item_id == item_id,
|
|
supplier_items.deleted == False, # noqa: E712
|
|
suppliers.deleted == False, # noqa: E712
|
|
)
|
|
)
|
|
err_type, rows = await DB_SESSION_MNG.execute(cdb, query)
|
|
if err_type != ErrorType.SUCCESS:
|
|
return err_type, []
|
|
return ErrorType.SUCCESS, list(rows)
|
|
except Exception as ex:
|
|
LOG.e_no_callstack(ex)
|
|
return ErrorType.DB_RUN_FAILED, []
|
|
|
|
async def get_by_id(self, cdb: AsyncSession, supplier_item_id) -> Tuple[ErrorType, supplier_items]:
|
|
try:
|
|
query = select(supplier_items).where(
|
|
supplier_items.supplier_item_id == supplier_item_id,
|
|
supplier_items.deleted == False, # noqa: E712
|
|
).limit(1)
|
|
err_type, row_list = await DB_SESSION_MNG.execute(cdb, query)
|
|
if err_type != ErrorType.SUCCESS:
|
|
return err_type, None
|
|
if len(row_list) != 1:
|
|
return ErrorType.DB_INVALID_KEY, None
|
|
return ErrorType.SUCCESS, row_list[0]
|
|
except Exception as ex:
|
|
LOG.e_no_callstack(ex)
|
|
return ErrorType.DB_RUN_FAILED, None
|
|
|
|
async def existing_item_ids(self, cdb: AsyncSession, supplier_id, item_ids: list) -> Tuple[ErrorType, list]:
|
|
# 이 협력사에 이미 매핑된 item_id 들(중복 등록 스킵용).
|
|
try:
|
|
if not item_ids:
|
|
return ErrorType.SUCCESS, []
|
|
query = select(supplier_items.item_id).where(
|
|
supplier_items.supplier_id == supplier_id,
|
|
supplier_items.item_id.in_(item_ids),
|
|
supplier_items.deleted == False, # noqa: E712
|
|
)
|
|
err_type, rows = await DB_SESSION_MNG.execute(cdb, query)
|
|
if err_type != ErrorType.SUCCESS:
|
|
return err_type, []
|
|
return ErrorType.SUCCESS, [r for r in rows if r is not None]
|
|
except Exception as ex:
|
|
LOG.e_no_callstack(ex)
|
|
return ErrorType.DB_RUN_FAILED, []
|
|
|
|
async def find_items_by_names(self, cdb: AsyncSession, company_id, names: list) -> Tuple[ErrorType, list]:
|
|
# 상품명(정확 일치) → 상품. Row(item_id, name). 이름 중복 상품이 있으면 여럿 반환될 수 있다(서비스에서 첫 매칭 사용).
|
|
try:
|
|
if not names:
|
|
return ErrorType.SUCCESS, []
|
|
query = select(items.item_id, items.name).where(
|
|
items.company_id == company_id,
|
|
items.name.in_(names),
|
|
items.deleted == False, # noqa: E712
|
|
)
|
|
err_type, rows = await DB_SESSION_MNG.execute(cdb, query)
|
|
if err_type != ErrorType.SUCCESS:
|
|
return err_type, []
|
|
return ErrorType.SUCCESS, list(rows)
|
|
except Exception as ex:
|
|
LOG.e_no_callstack(ex)
|
|
return ErrorType.DB_RUN_FAILED, []
|
|
|
|
async def add_many(self, cdb: AsyncSession, mappings: list) -> ErrorType:
|
|
try:
|
|
if not mappings:
|
|
return ErrorType.SUCCESS
|
|
return await DB_SESSION_MNG.insert(cdb, mappings)
|
|
except Exception as ex:
|
|
LOG.e_no_callstack(ex)
|
|
return ErrorType.DB_RUN_FAILED
|
|
|
|
async def update_type(self, cdb: AsyncSession, supplier_item_id, supply_type: int) -> ErrorType:
|
|
try:
|
|
query = (
|
|
update(supplier_items)
|
|
.where(supplier_items.supplier_item_id == supplier_item_id)
|
|
.values(supply_type=supply_type, updated_at=GTime.UTC())
|
|
)
|
|
return await DB_SESSION_MNG.add(cdb, query)
|
|
except Exception as ex:
|
|
LOG.e_no_callstack(ex)
|
|
return ErrorType.DB_RUN_FAILED
|
|
|
|
async def soft_delete(self, cdb: AsyncSession, supplier_item_id) -> ErrorType:
|
|
try:
|
|
query = (
|
|
update(supplier_items)
|
|
.where(supplier_items.supplier_item_id == supplier_item_id)
|
|
.values(deleted=True, updated_at=GTime.UTC())
|
|
)
|
|
return await DB_SESSION_MNG.add(cdb, query)
|
|
except Exception as ex:
|
|
LOG.e_no_callstack(ex)
|
|
return ErrorType.DB_RUN_FAILED
|