From 2bbe36ccf013752ff52d7b89a9a012de0f6a4bf9 Mon Sep 17 00:00:00 2001 From: king Date: Wed, 17 Jun 2026 16:42:05 +0900 Subject: [PATCH] =?UTF-8?q?feat(malaysia):=20=EB=9E=99=20=EC=97=91?= =?UTF-8?q?=EC=85=80=EC=97=90=20=EC=95=84=EC=9D=B4=ED=85=9C=EB=B3=84=20?= =?UTF-8?q?=ED=95=A9=EA=B3=84=20=ED=91=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 상세 표 아래(한 줄 띄움)에 아이템 코드별 수량 합계 표를 추가. 컬럼: 아이템 코드/이름/합계 수량, 코드순 정렬. 자동필터는 상세 표 범위에만 적용(합계 표 제외). 열너비 자동은 그대로. Co-Authored-By: Claude Opus 4.8 --- app/modules/malaysia/router.py | 45 +++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/app/modules/malaysia/router.py b/app/modules/malaysia/router.py index a2b1c93..99979b5 100644 --- a/app/modules/malaysia/router.py +++ b/app/modules/malaysia/router.py @@ -495,26 +495,47 @@ async def rack_export(request: Request) -> StreamingResponse: from openpyxl.styles import Alignment, Font, PatternFill # noqa: WPS433 from openpyxl.utils import get_column_letter # noqa: WPS433 + # 아이템별 합계(코드 기준 수량 합산). 코드→이름 보존, 코드순 정렬. + summary: dict[str, int] = {} + for code, _name, qty, _cell in rows: + summary[code] = summary.get(code, 0) + qty + summary_rows = sorted( + ((code, names.get(code, code), total) for code, total in summary.items()), + key=lambda r: r[0], + ) + + fill = PatternFill(start_color="FF4472C4", end_color="FF4472C4", fill_type="solid") + font = Font(color="FFFFFFFF", bold=True) + center = Alignment(horizontal="center", vertical="center") + + def _style_header(row_idx: int, ncols: int) -> None: + for col in range(1, ncols + 1): + cell = ws.cell(row=row_idx, column=col) + cell.fill = fill + cell.font = font + cell.alignment = center + wb = Workbook() ws = wb.active ws.title = "rack" + + # ── 상세 표 ── header = ["아이템 코드", "이름", "수량", "랙번호"] ws.append(header) for code, name, qty, cell in rows: ws.append([code, name, qty, cell]) + _style_header(1, len(header)) + detail_last = ws.max_row # 자동필터 범위(상세표만) + ws.auto_filter.ref = f"A1:{get_column_letter(len(header))}{detail_last}" - # 제목행: 파랑 배경 + 흰색 굵은글씨 + 가운데 정렬 - fill = PatternFill(start_color="FF4472C4", end_color="FF4472C4", fill_type="solid") - font = Font(color="FFFFFFFF", bold=True) - center = Alignment(horizontal="center", vertical="center") - for col in range(1, len(header) + 1): - cell = ws.cell(row=1, column=col) - cell.fill = fill - cell.font = font - cell.alignment = center - - # 표 전체 자동필터 - ws.auto_filter.ref = ws.dimensions + # ── 아이템별 합계 표 (상세표 아래, 한 줄 띄움) ── + ws.append([]) + sum_header_row = ws.max_row + 1 + sum_header = ["아이템 코드", "이름", "합계 수량"] + ws.append(sum_header) + for code, name, total in summary_rows: + ws.append([code, name, total]) + _style_header(sum_header_row, len(sum_header)) # 열너비 자동(내용 길이 기준, 한글 폭 보정). 최소 8 ~ 최대 50. for col in range(1, len(header) + 1):