feat(malaysia): 이동 이력에 낱개/콤보 분리 표시

- set_movement(콤보 출고 원장)을 이동이력에 병합, 구분 컬럼(낱개/콤보) 추가
- db.list_set_movements (동일 필터: 창고/종류/날짜)
- 콤보 줄은 set_code 를 Item 으로 표시 → 콤보 몇 개 나갔는지 확인 가능

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-22 18:14:45 +09:00
parent b583627bd3
commit 2ab38c7dbd
3 changed files with 63 additions and 8 deletions
+34
View File
@@ -327,6 +327,40 @@ class MalaysiaStockStore:
).fetchall()
return [self._serialize(r) for r in rows]
def list_set_movements(
self,
*,
warehouse_code: str | None = None,
movement_type: str | None = None,
date_from: str | None = None,
date_to: str | None = None,
limit: int = 500,
) -> list[dict[str, Any]]:
"""콤보(세트) 출고 원장(set_movement) 목록. 이동이력 콤보 줄 표시용."""
clauses: list[str] = []
params: list[Any] = []
if warehouse_code:
clauses.append("warehouse_code = %s")
params.append(warehouse_code)
if movement_type in store.MOVEMENT_TYPES:
clauses.append("movement_type = %s")
params.append(movement_type)
if date_from:
clauses.append("movement_date >= %s")
params.append(date_from)
if date_to:
clauses.append("movement_date <= %s")
params.append(date_to)
where = ("WHERE " + " AND ".join(clauses)) if clauses else ""
params.append(int(limit))
with self._pool.connection() as conn:
rows = conn.execute(
f"SELECT * FROM set_movement {where} "
"ORDER BY movement_date DESC, id DESC LIMIT %s",
params,
).fetchall()
return [self._serialize(r) for r in rows]
def daily_movement_totals(
self, *, warehouse_code: str, movement_date: str, movement_type: str
) -> dict[str, int]:
+20 -6
View File
@@ -268,12 +268,26 @@ async def movements_page(request: Request) -> HTMLResponse:
wh = _selected_wh(request, st)
mtype = (request.query_params.get("type") or "").strip().upper()
fdate = (request.query_params.get("date") or "").strip()
movements = st.list_movements(
warehouse_code=wh,
movement_type=mtype if mtype in store.MOVEMENT_TYPES else None,
date_from=fdate or None,
date_to=fdate or None,
limit=300,
mt = mtype if mtype in store.MOVEMENT_TYPES else None
singles = st.list_movements(
warehouse_code=wh, movement_type=mt,
date_from=fdate or None, date_to=fdate or None, limit=300,
)
for m in singles:
m["kind"] = "individual"
# 콤보(세트) 출고 원장도 함께 보여준다(낱개/콤보 분리 표시).
combos = st.list_set_movements(
warehouse_code=wh, movement_type=mt,
date_from=fdate or None, date_to=fdate or None, limit=300,
)
for m in combos:
m["kind"] = "set"
m["item_code"] = m.get("set_code", "")
# 날짜(그다음 id) 내림차순 병합.
movements = sorted(
singles + combos,
key=lambda m: (str(m.get("movement_date") or ""), int(m.get("id") or 0)),
reverse=True,
)
for m in movements:
m["date_label"] = _date_label(m.get("movement_date"))
@@ -144,11 +144,18 @@
</div>
<div class="erp-table-wrap">
<table class="erp-table">
<thead><tr><th>Date</th><th>Type</th><th>Item</th><th style="text-align:right">Qty</th><th>Memo</th><th>By</th></tr></thead>
<thead><tr><th>Date</th><th>구분</th><th>Type</th><th>Item</th><th style="text-align:right">Qty</th><th>Memo</th><th>By</th></tr></thead>
<tbody>
{% for m in movements %}
<tr>
<td>{{ m.date_label }}</td>
<td>
{% if m.kind == 'set' %}
<span class="erp-badge" style="background:#fef3c7;color:#92400e;">콤보</span>
{% else %}
<span class="erp-badge" style="background:#e0e7ff;color:#3730a3;">낱개</span>
{% endif %}
</td>
<td>{{ m.movement_type }}</td>
<td>{{ m.item_code }}</td>
<td style="text-align:right">{{ m.qty }}</td>
@@ -157,7 +164,7 @@
</tr>
{% endfor %}
{% if not movements %}
<tr><td colspan="6" class="erp-muted">이동 이력이 없습니다.</td></tr>
<tr><td colspan="7" class="erp-muted">이동 이력이 없습니다.</td></tr>
{% endif %}
</tbody>
</table>