feat: 도매상 잔고 모달에 월간 매출 추가
- 백제/지오영/수인 월간매출 API 라우트 추가 - 모달 UI: 잔고 + 월간 매출 동시 표시 - 총 주문액 / 총 미수금 요약 표시
This commit is contained in:
parent
4b2d934839
commit
5519f5ae62
86
backend/analyze_baekje_ledger.py
Normal file
86
backend/analyze_baekje_ledger.py
Normal file
@ -0,0 +1,86 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""백제약품 주문 원장 페이지 분석"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
async def analyze_order_ledger():
|
||||
from playwright.async_api import async_playwright
|
||||
|
||||
username = os.getenv('BAEKJE_USER_ID')
|
||||
password = os.getenv('BAEKJE_PASSWORD')
|
||||
|
||||
print(f'Username: {username}')
|
||||
|
||||
async with async_playwright() as p:
|
||||
browser = await p.chromium.launch(headless=False)
|
||||
context = await browser.new_context()
|
||||
page = await context.new_page()
|
||||
|
||||
# 로그인 페이지
|
||||
await page.goto('https://ibjp.co.kr/dist/login', timeout=15000)
|
||||
await page.wait_for_load_state('networkidle', timeout=10000)
|
||||
|
||||
# 로그인 폼 입력
|
||||
inputs = await page.locator('input[type="text"], input[type="password"]').all()
|
||||
if len(inputs) >= 2:
|
||||
await inputs[0].fill(username)
|
||||
await inputs[1].fill(password)
|
||||
|
||||
# 로그인 버튼 클릭
|
||||
buttons = await page.locator('button').all()
|
||||
for btn in buttons:
|
||||
text = await btn.text_content()
|
||||
if '로그인' in (text or ''):
|
||||
await btn.click()
|
||||
break
|
||||
|
||||
# 로그인 완료 대기
|
||||
try:
|
||||
await page.wait_for_url('**/comOrd**', timeout=15000)
|
||||
print('Login successful, redirected to comOrd')
|
||||
except Exception as e:
|
||||
print(f'URL wait failed: {e}')
|
||||
await asyncio.sleep(3)
|
||||
|
||||
print(f'Current URL: {page.url}')
|
||||
|
||||
# 주문 원장 페이지로 이동
|
||||
await page.goto('https://ibjp.co.kr/dist/ordLedger', timeout=15000)
|
||||
await page.wait_for_load_state('networkidle', timeout=15000)
|
||||
|
||||
print(f'Order Ledger URL: {page.url}')
|
||||
|
||||
# 페이지 HTML 저장
|
||||
html = await page.content()
|
||||
with open('ordLedger_page.html', 'w', encoding='utf-8') as f:
|
||||
f.write(html)
|
||||
print('Page HTML saved to ordLedger_page.html')
|
||||
|
||||
# 스크린샷 저장
|
||||
await page.screenshot(path='ordLedger_screenshot.png', full_page=True)
|
||||
print('Screenshot saved')
|
||||
|
||||
# 테이블 데이터 분석
|
||||
tables = await page.locator('table').all()
|
||||
print(f'Found {len(tables)} tables')
|
||||
|
||||
for i, table in enumerate(tables):
|
||||
headers = await table.locator('th').all()
|
||||
header_texts = [await h.text_content() for h in headers]
|
||||
print(f'Table {i} headers: {header_texts}')
|
||||
|
||||
# 페이지 텍스트 출력 (분석용)
|
||||
body_text = await page.locator('body').text_content()
|
||||
print('\n=== Page Text Preview ===')
|
||||
print(body_text[:3000] if body_text else 'No text')
|
||||
|
||||
await asyncio.sleep(30) # 페이지 확인 시간
|
||||
await browser.close()
|
||||
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(analyze_order_ledger())
|
||||
@ -447,6 +447,37 @@ def api_get_balance():
|
||||
}), 501
|
||||
|
||||
|
||||
@geoyoung_bp.route('/monthly-sales', methods=['GET'])
|
||||
def api_get_monthly_sales():
|
||||
"""
|
||||
월간 매출 조회
|
||||
|
||||
GET /api/geoyoung/monthly-sales?year=2026&month=3
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
year = request.args.get('year', type=int)
|
||||
month = request.args.get('month', type=int)
|
||||
|
||||
# 기본값: 현재 월
|
||||
if not year or not month:
|
||||
now = datetime.now()
|
||||
year = year or now.year
|
||||
month = month or now.month
|
||||
|
||||
session = get_geo_session()
|
||||
|
||||
if hasattr(session, 'get_monthly_sales'):
|
||||
result = session.get_monthly_sales(year, month)
|
||||
return jsonify(result)
|
||||
else:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'NOT_IMPLEMENTED',
|
||||
'message': '지오영 월간 매출 조회 미구현'
|
||||
}), 501
|
||||
|
||||
|
||||
# ========== 하위 호환성 ==========
|
||||
|
||||
# 기존 코드에서 직접 클래스 참조하는 경우를 위해
|
||||
|
||||
10
backend/ordLedger_page.html
Normal file
10
backend/ordLedger_page.html
Normal file
File diff suppressed because one or more lines are too long
BIN
backend/ordLedger_screenshot.png
Normal file
BIN
backend/ordLedger_screenshot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 302 KiB |
@ -134,6 +134,55 @@ def api_sooin_balance():
|
||||
}), 500
|
||||
|
||||
|
||||
@sooin_bp.route('/monthly-sales', methods=['GET'])
|
||||
def api_sooin_monthly_sales():
|
||||
"""
|
||||
수인약품 월간 매출 조회 API
|
||||
|
||||
GET /api/sooin/monthly-sales?year=2026&month=3
|
||||
|
||||
Returns:
|
||||
{
|
||||
"success": true,
|
||||
"total_amount": 3700239, // 월간 매출 합계
|
||||
"total_paid": 0, // 월간 입금 합계
|
||||
"ending_balance": 14293001, // 월말 잔액
|
||||
"opening_balance": 10592762, // 전일(기초) 잔액
|
||||
"from_date": "2026-03-01",
|
||||
"to_date": "2026-03-31"
|
||||
}
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
year = flask_request.args.get('year', type=int)
|
||||
month = flask_request.args.get('month', type=int)
|
||||
|
||||
# 기본값: 현재 월
|
||||
if not year or not month:
|
||||
now = datetime.now()
|
||||
year = year or now.year
|
||||
month = month or now.month
|
||||
|
||||
try:
|
||||
session = get_sooin_session()
|
||||
if hasattr(session, 'get_monthly_sales'):
|
||||
result = session.get_monthly_sales(year, month)
|
||||
return jsonify(result)
|
||||
else:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'NOT_IMPLEMENTED',
|
||||
'message': '수인약품 월간 매출 조회 미구현'
|
||||
}), 501
|
||||
except Exception as e:
|
||||
logger.error(f"수인약품 월간 매출 조회 오류: {e}")
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'error': 'MONTHLY_SALES_ERROR',
|
||||
'message': str(e)
|
||||
}), 500
|
||||
|
||||
|
||||
@sooin_bp.route('/cart', methods=['GET'])
|
||||
def api_sooin_cart():
|
||||
"""장바구니 조회 API"""
|
||||
|
||||
@ -2256,26 +2256,43 @@
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
.balance-total {
|
||||
.balance-summary {
|
||||
background: linear-gradient(135deg, rgba(168, 85, 247, 0.1), rgba(6, 182, 212, 0.1));
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
margin-top: 12px;
|
||||
gap: 16px;
|
||||
}
|
||||
.balance-total-label {
|
||||
.summary-item {
|
||||
text-align: center;
|
||||
flex: 1;
|
||||
}
|
||||
.summary-label {
|
||||
font-size: 12px;
|
||||
color: var(--text-muted);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.balance-total-value {
|
||||
font-size: 28px;
|
||||
.summary-value {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
font-family: 'JetBrains Mono', monospace;
|
||||
}
|
||||
.summary-value.sales {
|
||||
color: #10b981;
|
||||
}
|
||||
.summary-value.balance {
|
||||
background: linear-gradient(135deg, #a855f7, #06b6d4);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.summary-divider {
|
||||
width: 1px;
|
||||
height: 50px;
|
||||
background: var(--border);
|
||||
}
|
||||
.balance-updated {
|
||||
text-align: center;
|
||||
font-size: 11px;
|
||||
@ -2300,17 +2317,23 @@
|
||||
baekje: {
|
||||
id: 'baekje', name: '백제약품', icon: '💉',
|
||||
logo: '/static/img/logo_baekje.svg',
|
||||
color: '#f59e0b', api: '/api/baekje/balance'
|
||||
color: '#f59e0b',
|
||||
balanceApi: '/api/baekje/balance',
|
||||
salesApi: '/api/baekje/monthly-sales'
|
||||
},
|
||||
geoyoung: {
|
||||
id: 'geoyoung', name: '지오영', icon: '🏭',
|
||||
logo: '/static/img/logo_geoyoung.ico',
|
||||
color: '#06b6d4', api: '/api/geoyoung/balance'
|
||||
color: '#06b6d4',
|
||||
balanceApi: '/api/geoyoung/balance',
|
||||
salesApi: '/api/geoyoung/monthly-sales'
|
||||
},
|
||||
sooin: {
|
||||
id: 'sooin', name: '수인약품', icon: '💊',
|
||||
logo: '/static/img/logo_sooin.svg',
|
||||
color: '#a855f7', api: '/api/sooin/balance'
|
||||
color: '#a855f7',
|
||||
balanceApi: '/api/sooin/balance',
|
||||
salesApi: '/api/sooin/monthly-sales'
|
||||
}
|
||||
};
|
||||
const WHOLESALER_ORDER = ['baekje', 'geoyoung', 'sooin'];
|
||||
@ -2320,36 +2343,47 @@
|
||||
content.innerHTML = `
|
||||
<div class="loading-state">
|
||||
<div class="loading-spinner"></div>
|
||||
<div>잔고 조회 중...</div>
|
||||
<div>잔고 및 매출 조회 중...</div>
|
||||
</div>`;
|
||||
|
||||
const wholesalers = WHOLESALER_ORDER.map(id => WHOLESALER_CONFIG[id]);
|
||||
const now = new Date();
|
||||
const year = now.getFullYear();
|
||||
const month = now.getMonth() + 1;
|
||||
|
||||
const results = {};
|
||||
const balanceResults = {};
|
||||
const salesResults = {};
|
||||
let totalBalance = 0;
|
||||
let totalSales = 0;
|
||||
|
||||
// 병렬로 조회
|
||||
await Promise.all(wholesalers.map(async (ws) => {
|
||||
try {
|
||||
const resp = await fetch(ws.api, { timeout: 30000 });
|
||||
const data = await resp.json();
|
||||
results[ws.id] = data;
|
||||
if (data.success && data.balance) {
|
||||
totalBalance += data.balance;
|
||||
}
|
||||
} catch (err) {
|
||||
results[ws.id] = { success: false, error: err.message };
|
||||
}
|
||||
}));
|
||||
// 병렬로 잔고 + 월간매출 조회
|
||||
await Promise.all(wholesalers.flatMap(ws => [
|
||||
// 잔고 조회
|
||||
fetch(ws.balanceApi).then(r => r.json()).then(data => {
|
||||
balanceResults[ws.id] = data;
|
||||
if (data.success && data.balance) totalBalance += data.balance;
|
||||
}).catch(err => {
|
||||
balanceResults[ws.id] = { success: false, error: err.message };
|
||||
}),
|
||||
// 월간 매출 조회
|
||||
fetch(`${ws.salesApi}?year=${year}&month=${month}`).then(r => r.json()).then(data => {
|
||||
salesResults[ws.id] = data;
|
||||
if (data.success && data.total_amount) totalSales += data.total_amount;
|
||||
}).catch(err => {
|
||||
salesResults[ws.id] = { success: false, error: err.message };
|
||||
})
|
||||
]));
|
||||
|
||||
// 결과 렌더링
|
||||
let html = '<div class="balance-grid">';
|
||||
|
||||
wholesalers.forEach(ws => {
|
||||
const data = results[ws.id];
|
||||
const isError = !data.success;
|
||||
const balance = data.balance || 0;
|
||||
const prevBalance = data.prev_balance || data.prev_month_balance || 0;
|
||||
const balData = balanceResults[ws.id] || {};
|
||||
const salesData = salesResults[ws.id] || {};
|
||||
const isError = !balData.success;
|
||||
const balance = balData.balance || 0;
|
||||
const monthlySales = salesData.total_amount || 0;
|
||||
const monthlyPaid = salesData.total_paid || 0;
|
||||
|
||||
html += `
|
||||
<div class="balance-card ${isError ? 'error' : ''}">
|
||||
@ -2362,8 +2396,9 @@
|
||||
<div class="balance-name">${ws.name}</div>
|
||||
<div class="balance-detail">
|
||||
${isError
|
||||
? `❌ ${data.error || '조회 실패'}`
|
||||
: `전월/전일: ${prevBalance.toLocaleString()}원`}
|
||||
? `❌ ${balData.error || '조회 실패'}`
|
||||
: `${month}월 매출: <span style="color:${ws.color};font-weight:600;">${monthlySales.toLocaleString()}원</span>
|
||||
${monthlyPaid > 0 ? ` · 입금: ${monthlyPaid.toLocaleString()}원` : ''}`}
|
||||
</div>
|
||||
</div>
|
||||
<div class="balance-amount">
|
||||
@ -2376,9 +2411,16 @@
|
||||
});
|
||||
|
||||
html += `
|
||||
<div class="balance-total">
|
||||
<div class="balance-total-label">총 미수금</div>
|
||||
<div class="balance-total-value">${totalBalance.toLocaleString()}원</div>
|
||||
<div class="balance-summary">
|
||||
<div class="summary-item">
|
||||
<div class="summary-label">📊 ${month}월 총 주문</div>
|
||||
<div class="summary-value sales">${totalSales.toLocaleString()}원</div>
|
||||
</div>
|
||||
<div class="summary-divider"></div>
|
||||
<div class="summary-item">
|
||||
<div class="summary-label">💰 총 미수금</div>
|
||||
<div class="summary-value balance">${totalBalance.toLocaleString()}원</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="balance-updated">🕐 ${new Date().toLocaleString('ko-KR')}</div>
|
||||
</div>`;
|
||||
|
||||
101
backend/test_baekje_ledger_api.py
Normal file
101
backend/test_baekje_ledger_api.py
Normal file
@ -0,0 +1,101 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""백제약품 주문 원장 API 분석"""
|
||||
|
||||
import json
|
||||
import requests
|
||||
from datetime import datetime, timedelta
|
||||
import calendar
|
||||
|
||||
# 저장된 토큰 로드
|
||||
TOKEN_FILE = r'c:\Users\청춘약국\source\pharmacy-wholesale-api\.baekje_token.json'
|
||||
with open(TOKEN_FILE, 'r', encoding='utf-8') as f:
|
||||
token_data = json.load(f)
|
||||
|
||||
token = token_data['token']
|
||||
cust_cd = token_data['cust_cd']
|
||||
|
||||
print(f"Token expires: {datetime.fromtimestamp(token_data['expires'])}")
|
||||
print(f"Customer code: {cust_cd}")
|
||||
|
||||
# API 세션 설정
|
||||
session = requests.Session()
|
||||
session.headers.update({
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
|
||||
'Origin': 'https://ibjp.co.kr',
|
||||
'Referer': 'https://ibjp.co.kr/',
|
||||
'Authorization': f'Bearer {token}'
|
||||
})
|
||||
|
||||
API_URL = "https://www.ibjp.co.kr"
|
||||
|
||||
# 1. 주문 원장 API 시도 - 다양한 엔드포인트
|
||||
endpoints = [
|
||||
'/ordLedger/listSearch',
|
||||
'/ordLedger/list',
|
||||
'/ord/ledgerList',
|
||||
'/ord/ledgerSearch',
|
||||
'/cust/ordLedger',
|
||||
'/custOrd/ledgerList',
|
||||
'/ordHist/listSearch',
|
||||
'/ordHist/list',
|
||||
]
|
||||
|
||||
# 날짜 설정 (이번 달)
|
||||
today = datetime.now()
|
||||
year = today.year
|
||||
month = today.month
|
||||
_, last_day = calendar.monthrange(year, month)
|
||||
from_date = f"{year}{month:02d}01"
|
||||
to_date = f"{year}{month:02d}{last_day:02d}"
|
||||
|
||||
print(f"\n조회 기간: {from_date} ~ {to_date}")
|
||||
print("\n=== API 엔드포인트 탐색 ===\n")
|
||||
|
||||
params = {
|
||||
'custCd': cust_cd,
|
||||
'startDt': from_date,
|
||||
'endDt': to_date,
|
||||
'stDate': from_date,
|
||||
'edDate': to_date,
|
||||
'year': str(year),
|
||||
'month': f"{month:02d}",
|
||||
}
|
||||
|
||||
for endpoint in endpoints:
|
||||
try:
|
||||
# GET 시도
|
||||
resp = session.get(f"{API_URL}{endpoint}", params=params, timeout=10)
|
||||
print(f"GET {endpoint}: {resp.status_code}")
|
||||
if resp.status_code == 200:
|
||||
try:
|
||||
data = resp.json()
|
||||
print(f" -> JSON Response (first 500 chars): {str(data)[:500]}")
|
||||
except:
|
||||
print(f" -> Text (first 200 chars): {resp.text[:200]}")
|
||||
except Exception as e:
|
||||
print(f"GET {endpoint}: Error - {e}")
|
||||
|
||||
try:
|
||||
# POST 시도
|
||||
resp = session.post(f"{API_URL}{endpoint}", json=params, timeout=10)
|
||||
print(f"POST {endpoint}: {resp.status_code}")
|
||||
if resp.status_code == 200:
|
||||
try:
|
||||
data = resp.json()
|
||||
print(f" -> JSON Response (first 500 chars): {str(data)[:500]}")
|
||||
except:
|
||||
print(f" -> Text (first 200 chars): {resp.text[:200]}")
|
||||
except Exception as e:
|
||||
print(f"POST {endpoint}: Error - {e}")
|
||||
|
||||
# 2. 이미 알려진 API로 데이터 확인
|
||||
print("\n=== 알려진 API 테스트 ===\n")
|
||||
|
||||
# 월간 잔고 조회 (이미 있는 함수에서 사용)
|
||||
resp = session.get(f"{API_URL}/custMonth/listSearch", params={'custCd': cust_cd, 'year': str(year), 'endDt': to_date}, timeout=10)
|
||||
print(f"custMonth/listSearch: {resp.status_code}")
|
||||
if resp.status_code == 200:
|
||||
data = resp.json()
|
||||
print(f" -> {json.dumps(data, ensure_ascii=False, indent=2)[:1500]}")
|
||||
126
backend/test_baekje_ledger_api2.py
Normal file
126
backend/test_baekje_ledger_api2.py
Normal file
@ -0,0 +1,126 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""백제약품 주문 원장 API 분석 - 상세 탐색"""
|
||||
|
||||
import json
|
||||
import requests
|
||||
from datetime import datetime
|
||||
import calendar
|
||||
|
||||
# 저장된 토큰 로드
|
||||
TOKEN_FILE = r'c:\Users\청춘약국\source\pharmacy-wholesale-api\.baekje_token.json'
|
||||
with open(TOKEN_FILE, 'r', encoding='utf-8') as f:
|
||||
token_data = json.load(f)
|
||||
|
||||
token = token_data['token']
|
||||
cust_cd = token_data['cust_cd']
|
||||
|
||||
# API 세션 설정
|
||||
session = requests.Session()
|
||||
session.headers.update({
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
||||
'Accept': 'application/json, text/plain, */*',
|
||||
'Accept-Language': 'ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7',
|
||||
'Origin': 'https://ibjp.co.kr',
|
||||
'Referer': 'https://ibjp.co.kr/',
|
||||
'Authorization': f'Bearer {token}'
|
||||
})
|
||||
|
||||
API_URL = "https://www.ibjp.co.kr"
|
||||
|
||||
today = datetime.now()
|
||||
year = today.year
|
||||
month = today.month
|
||||
_, last_day = calendar.monthrange(year, month)
|
||||
|
||||
print("=== 주문 원장 API 탐색 (다양한 파라미터) ===\n")
|
||||
|
||||
# 날짜 형식 변형
|
||||
date_formats = [
|
||||
{'startDt': f'{year}{month:02d}01', 'endDt': f'{year}{month:02d}{last_day:02d}'},
|
||||
{'stDt': f'{year}{month:02d}01', 'edDt': f'{year}{month:02d}{last_day:02d}'},
|
||||
{'fromDate': f'{year}-{month:02d}-01', 'toDate': f'{year}-{month:02d}-{last_day:02d}'},
|
||||
{'strDt': f'{year}{month:02d}01', 'endDt': f'{year}{month:02d}{last_day:02d}'},
|
||||
{'ordDt': f'{year}{month:02d}'},
|
||||
]
|
||||
|
||||
endpoints = [
|
||||
'/ordLedger/listSearch',
|
||||
'/ordLedger/search',
|
||||
'/ordLedger/ledgerList',
|
||||
'/cust/ordLedgerList',
|
||||
'/cust/ledger',
|
||||
'/ord/histList',
|
||||
'/ord/history',
|
||||
'/ord/list',
|
||||
]
|
||||
|
||||
for endpoint in endpoints:
|
||||
for params in date_formats:
|
||||
full_params = {**params, 'custCd': cust_cd}
|
||||
try:
|
||||
resp = session.get(f"{API_URL}{endpoint}", params=full_params, timeout=10)
|
||||
if resp.status_code == 200:
|
||||
print(f"✓ GET {endpoint} {params}: {resp.status_code}")
|
||||
try:
|
||||
data = resp.json()
|
||||
print(f" -> {str(data)[:300]}")
|
||||
except:
|
||||
print(f" -> {resp.text[:200]}")
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
try:
|
||||
resp = session.post(f"{API_URL}{endpoint}", json=full_params, timeout=10)
|
||||
if resp.status_code == 200:
|
||||
print(f"✓ POST {endpoint} {params}: {resp.status_code}")
|
||||
try:
|
||||
data = resp.json()
|
||||
print(f" -> {str(data)[:300]}")
|
||||
except:
|
||||
print(f" -> {resp.text[:200]}")
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
print("\n=== 주문 이력 관련 API ===\n")
|
||||
|
||||
# 주문 이력 조회 시도
|
||||
order_endpoints = [
|
||||
'/ord/ordList',
|
||||
'/ord/orderHistory',
|
||||
'/ordReg/list',
|
||||
'/ordReg/history',
|
||||
'/order/list',
|
||||
'/order/history',
|
||||
]
|
||||
|
||||
for endpoint in order_endpoints:
|
||||
try:
|
||||
params = {'custCd': cust_cd, 'startDt': f'{year}{month:02d}01', 'endDt': f'{year}{month:02d}{last_day:02d}'}
|
||||
resp = session.get(f"{API_URL}{endpoint}", params=params, timeout=10)
|
||||
print(f"GET {endpoint}: {resp.status_code}")
|
||||
if resp.status_code == 200:
|
||||
try:
|
||||
data = resp.json()
|
||||
print(f" -> {str(data)[:500]}")
|
||||
except:
|
||||
print(f" -> {resp.text[:200]}")
|
||||
except:
|
||||
pass
|
||||
|
||||
print("\n=== custMonth/listSearch 상세 데이터 분석 ===\n")
|
||||
|
||||
# 이미 작동하는 API의 데이터 상세 분석
|
||||
resp = session.get(f"{API_URL}/custMonth/listSearch", params={'custCd': cust_cd, 'year': str(year), 'endDt': f'{year}{month:02d}{last_day:02d}'}, timeout=10)
|
||||
if resp.status_code == 200:
|
||||
data = resp.json()
|
||||
print("월간 데이터 구조:")
|
||||
for item in data:
|
||||
print(f"\n월: {item.get('BALANCE_YM')}")
|
||||
print(f" 매출액(SALE_AMT): {item.get('SALE_AMT'):,}")
|
||||
print(f" 반품액(BACK_AMT): {item.get('BACK_AMT'):,}")
|
||||
print(f" 순반품(PURE_BACK_AMT): {item.get('PURE_BACK_AMT'):,}")
|
||||
print(f" 순매출(TOTAL_AMT): {item.get('TOTAL_AMT'):,}")
|
||||
print(f" 입금액(PAY_CASH_AMT): {item.get('PAY_CASH_AMT'):,}")
|
||||
print(f" 전월이월(PRE_TOTAL_AMT): {item.get('PRE_TOTAL_AMT'):,}")
|
||||
print(f" 월말잔고(BALANCE_A_AMT): {item.get('BALANCE_A_AMT'):,}")
|
||||
print(f" 회전일수(ROTATE_DAY): {item.get('ROTATE_DAY')}")
|
||||
84
backend/test_baekje_monthly_sales.py
Normal file
84
backend/test_baekje_monthly_sales.py
Normal file
@ -0,0 +1,84 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""백제약품 get_monthly_sales() 테스트"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
# wholesale 패키지 경로 추가
|
||||
sys.path.insert(0, r'c:\Users\청춘약국\source\pharmacy-wholesale-api')
|
||||
os.chdir(r'c:\Users\청춘약국\source\pharmacy-pos-qr-system\backend')
|
||||
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
|
||||
from wholesale import BaekjeSession
|
||||
|
||||
def test_monthly_sales():
|
||||
print("=" * 60)
|
||||
print("백제약품 월간 매출 조회 테스트")
|
||||
print("=" * 60)
|
||||
|
||||
session = BaekjeSession()
|
||||
|
||||
# 현재 월 조회
|
||||
from datetime import datetime
|
||||
now = datetime.now()
|
||||
year = now.year
|
||||
month = now.month
|
||||
|
||||
print(f"\n1. 현재 월 ({year}-{month:02d}) 조회:")
|
||||
result = session.get_monthly_sales(year, month)
|
||||
print(f" Success: {result.get('success')}")
|
||||
if result.get('success'):
|
||||
print(f" 월간 매출: {result.get('total_amount'):,}원")
|
||||
print(f" 월간 반품: {result.get('total_returns'):,}원")
|
||||
print(f" 순매출: {result.get('net_amount'):,}원")
|
||||
print(f" 월간 입금: {result.get('total_paid'):,}원")
|
||||
print(f" 월말 잔고: {result.get('ending_balance'):,}원")
|
||||
print(f" 전월이월: {result.get('prev_balance'):,}원")
|
||||
print(f" 회전일수: {result.get('rotate_days')}")
|
||||
print(f" 조회기간: {result.get('from_date')} ~ {result.get('to_date')}")
|
||||
else:
|
||||
print(f" Error: {result.get('error')}")
|
||||
|
||||
# 전월 조회
|
||||
prev_month = month - 1 if month > 1 else 12
|
||||
prev_year = year if month > 1 else year - 1
|
||||
|
||||
print(f"\n2. 전월 ({prev_year}-{prev_month:02d}) 조회:")
|
||||
result = session.get_monthly_sales(prev_year, prev_month)
|
||||
print(f" Success: {result.get('success')}")
|
||||
if result.get('success'):
|
||||
print(f" 월간 매출: {result.get('total_amount'):,}원")
|
||||
print(f" 월간 반품: {result.get('total_returns'):,}원")
|
||||
print(f" 순매출: {result.get('net_amount'):,}원")
|
||||
print(f" 월간 입금: {result.get('total_paid'):,}원")
|
||||
print(f" 월말 잔고: {result.get('ending_balance'):,}원")
|
||||
print(f" 전월이월: {result.get('prev_balance'):,}원")
|
||||
print(f" 회전일수: {result.get('rotate_days')}")
|
||||
print(f" 조회기간: {result.get('from_date')} ~ {result.get('to_date')}")
|
||||
else:
|
||||
print(f" Error: {result.get('error')}")
|
||||
|
||||
# 2달 전 조회
|
||||
prev_month2 = prev_month - 1 if prev_month > 1 else 12
|
||||
prev_year2 = prev_year if prev_month > 1 else prev_year - 1
|
||||
|
||||
print(f"\n3. 2달 전 ({prev_year2}-{prev_month2:02d}) 조회:")
|
||||
result = session.get_monthly_sales(prev_year2, prev_month2)
|
||||
print(f" Success: {result.get('success')}")
|
||||
if result.get('success'):
|
||||
print(f" 월간 매출: {result.get('total_amount'):,}원")
|
||||
print(f" 월간 반품: {result.get('total_returns'):,}원")
|
||||
print(f" 순매출: {result.get('net_amount'):,}원")
|
||||
print(f" 월간 입금: {result.get('total_paid'):,}원")
|
||||
print(f" 월말 잔고: {result.get('ending_balance'):,}원")
|
||||
else:
|
||||
print(f" Error: {result.get('error')}")
|
||||
|
||||
print("\n" + "=" * 60)
|
||||
print("테스트 완료!")
|
||||
print("=" * 60)
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_monthly_sales()
|
||||
Loading…
Reference in New Issue
Block a user