- 개발/테스트 스크립트를 dev_scripts/ 폴더로 이동 - 스크린샷을 screenshots/ 폴더로 이동 - 백업 파일 보존 (.backup) - 처방 관련 추가 스크립트 포함 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
186 lines
6.9 KiB
Python
186 lines
6.9 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
|
||
"""
|
||
입고 단가와 LOT 단가 차이 분석
|
||
"""
|
||
|
||
import sqlite3
|
||
|
||
def analyze_price_difference():
|
||
conn = sqlite3.connect('database/kdrug.db')
|
||
conn.row_factory = sqlite3.Row
|
||
cursor = conn.cursor()
|
||
|
||
print("=" * 80)
|
||
print("입고 단가와 LOT 단가 차이 상세 분석")
|
||
print("=" * 80)
|
||
print()
|
||
|
||
# 1. 입고 라인과 LOT의 단가 차이 분석
|
||
print("1. 입고 라인 vs LOT 단가 비교")
|
||
print("-" * 60)
|
||
|
||
cursor.execute("""
|
||
SELECT
|
||
h.herb_name,
|
||
prl.line_id,
|
||
prl.quantity_g as purchase_qty,
|
||
prl.unit_price_per_g as purchase_price,
|
||
prl.line_total as purchase_total,
|
||
il.quantity_received as lot_received_qty,
|
||
il.quantity_onhand as lot_current_qty,
|
||
il.unit_price_per_g as lot_price,
|
||
il.quantity_received * il.unit_price_per_g as lot_original_value,
|
||
il.quantity_onhand * il.unit_price_per_g as lot_current_value,
|
||
ABS(prl.unit_price_per_g - il.unit_price_per_g) as price_diff,
|
||
prl.line_total - (il.quantity_received * il.unit_price_per_g) as value_diff
|
||
FROM purchase_receipt_lines prl
|
||
JOIN inventory_lots il ON prl.line_id = il.receipt_line_id
|
||
JOIN herb_items h ON prl.herb_item_id = h.herb_item_id
|
||
WHERE ABS(prl.unit_price_per_g - il.unit_price_per_g) > 0.01
|
||
OR ABS(prl.quantity_g - il.quantity_received) > 0.01
|
||
ORDER BY ABS(value_diff) DESC
|
||
""")
|
||
|
||
diffs = cursor.fetchall()
|
||
|
||
if diffs:
|
||
print(f" ⚠️ 단가 또는 수량이 다른 항목: {len(diffs)}개\n")
|
||
|
||
total_value_diff = 0
|
||
for i, diff in enumerate(diffs[:10], 1):
|
||
print(f" {i}. {diff['herb_name']}")
|
||
print(f" 입고: {diff['purchase_qty']:,.0f}g × ₩{diff['purchase_price']:.2f} = ₩{diff['purchase_total']:,.0f}")
|
||
print(f" LOT: {diff['lot_received_qty']:,.0f}g × ₩{diff['lot_price']:.2f} = ₩{diff['lot_original_value']:,.0f}")
|
||
print(f" 차이: ₩{diff['value_diff']:,.0f}")
|
||
total_value_diff += diff['value_diff']
|
||
print()
|
||
|
||
cursor.execute("""
|
||
SELECT SUM(prl.line_total - (il.quantity_received * il.unit_price_per_g)) as total_diff
|
||
FROM purchase_receipt_lines prl
|
||
JOIN inventory_lots il ON prl.line_id = il.receipt_line_id
|
||
""")
|
||
total_diff = cursor.fetchone()['total_diff'] or 0
|
||
|
||
print(f" 총 차이 금액: ₩{total_diff:,.0f}")
|
||
else:
|
||
print(" ✅ 모든 입고 라인과 LOT의 단가/수량이 일치합니다.")
|
||
|
||
# 2. 입고 총액과 LOT 생성 총액 비교
|
||
print("\n2. 입고 총액 vs LOT 생성 총액")
|
||
print("-" * 60)
|
||
|
||
cursor.execute("""
|
||
SELECT
|
||
SUM(prl.line_total) as purchase_total,
|
||
SUM(il.quantity_received * il.unit_price_per_g) as lot_creation_total
|
||
FROM purchase_receipt_lines prl
|
||
JOIN inventory_lots il ON prl.line_id = il.receipt_line_id
|
||
""")
|
||
|
||
totals = cursor.fetchone()
|
||
|
||
print(f" 입고장 총액: ₩{totals['purchase_total']:,.0f}")
|
||
print(f" LOT 생성 총액: ₩{totals['lot_creation_total']:,.0f}")
|
||
print(f" 차이: ₩{totals['purchase_total'] - totals['lot_creation_total']:,.0f}")
|
||
|
||
# 3. 소비로 인한 차이 분석
|
||
print("\n3. 소비 내역 상세 분석")
|
||
print("-" * 60)
|
||
|
||
# 복합제 소비 상세
|
||
cursor.execute("""
|
||
SELECT
|
||
c.compound_name,
|
||
h.herb_name,
|
||
cc.quantity_used,
|
||
il.unit_price_per_g,
|
||
cc.quantity_used * il.unit_price_per_g as consumption_value,
|
||
cc.consumption_date
|
||
FROM compound_consumptions cc
|
||
JOIN inventory_lots il ON cc.lot_id = il.lot_id
|
||
JOIN compounds c ON cc.compound_id = c.compound_id
|
||
JOIN herb_items h ON il.herb_item_id = h.herb_item_id
|
||
ORDER BY consumption_value DESC
|
||
LIMIT 10
|
||
""")
|
||
|
||
consumptions = cursor.fetchall()
|
||
|
||
print(" 복합제 소비 내역 (상위 10개):")
|
||
total_consumption = 0
|
||
for cons in consumptions:
|
||
print(f" - {cons['compound_name']} - {cons['herb_name']}")
|
||
print(f" {cons['quantity_used']:,.0f}g × ₩{cons['unit_price_per_g']:.2f} = ₩{cons['consumption_value']:,.0f}")
|
||
total_consumption += cons['consumption_value']
|
||
|
||
cursor.execute("""
|
||
SELECT SUM(cc.quantity_used * il.unit_price_per_g) as total
|
||
FROM compound_consumptions cc
|
||
JOIN inventory_lots il ON cc.lot_id = il.lot_id
|
||
""")
|
||
total_consumed = cursor.fetchone()['total'] or 0
|
||
|
||
print(f"\n 총 소비 금액: ₩{total_consumed:,.0f}")
|
||
|
||
# 4. 재고 자산 흐름 요약
|
||
print("\n4. 재고 자산 흐름 요약")
|
||
print("=" * 60)
|
||
|
||
# 입고장 기준
|
||
cursor.execute("SELECT SUM(line_total) as total FROM purchase_receipt_lines")
|
||
receipt_total = cursor.fetchone()['total'] or 0
|
||
|
||
# LOT 생성 기준
|
||
cursor.execute("""
|
||
SELECT SUM(quantity_received * unit_price_per_g) as total
|
||
FROM inventory_lots
|
||
WHERE receipt_line_id IS NOT NULL
|
||
""")
|
||
lot_creation = cursor.fetchone()['total'] or 0
|
||
|
||
# 현재 LOT 재고
|
||
cursor.execute("""
|
||
SELECT SUM(quantity_onhand * unit_price_per_g) as total
|
||
FROM inventory_lots
|
||
WHERE is_depleted = 0 AND quantity_onhand > 0
|
||
""")
|
||
current_inventory = cursor.fetchone()['total'] or 0
|
||
|
||
print(f" 1) 입고장 총액: ₩{receipt_total:,.0f}")
|
||
print(f" 2) LOT 생성 총액: ₩{lot_creation:,.0f}")
|
||
print(f" 차이 (1-2): ₩{receipt_total - lot_creation:,.0f}")
|
||
print()
|
||
print(f" 3) 복합제 소비: ₩{total_consumed:,.0f}")
|
||
print(f" 4) 현재 재고: ₩{current_inventory:,.0f}")
|
||
print()
|
||
print(f" 예상 재고 (2-3): ₩{lot_creation - total_consumed:,.0f}")
|
||
print(f" 실제 재고: ₩{current_inventory:,.0f}")
|
||
print(f" 차이: ₩{current_inventory - (lot_creation - total_consumed):,.0f}")
|
||
|
||
# 5. 차이 원인 설명
|
||
print("\n5. 차이 원인 분석")
|
||
print("-" * 60)
|
||
|
||
price_diff = receipt_total - lot_creation
|
||
if abs(price_diff) > 1000:
|
||
print(f"\n 💡 입고장과 LOT 생성 시 ₩{abs(price_diff):,.0f} 차이가 있습니다.")
|
||
print(" 가능한 원인:")
|
||
print(" - VAT 포함/제외 계산 차이")
|
||
print(" - 단가 반올림 차이")
|
||
print(" - 입고 시점의 환율 적용 차이")
|
||
|
||
consumption_diff = current_inventory - (lot_creation - total_consumed)
|
||
if abs(consumption_diff) > 1000:
|
||
print(f"\n 💡 예상 재고와 실제 재고 간 ₩{abs(consumption_diff):,.0f} 차이가 있습니다.")
|
||
print(" 가능한 원인:")
|
||
print(" - 재고 보정 내역")
|
||
print(" - 소비 시 반올림 오차 누적")
|
||
print(" - 초기 데이터 입력 오류")
|
||
|
||
conn.close()
|
||
|
||
if __name__ == "__main__":
|
||
analyze_price_difference() |