17 KiB
17 KiB
법인카드 대시보드 기술 문서
작성일: 2026-02-20 프로젝트: SAM MNG (관리자 웹) 경로:
/finance/corporate-cards
1. 개요
법인카드 대시보드는 회사의 법인카드를 등록/관리하고, 바로빌(Barobill) SOAP API를 통해 수집된 카드 거래 데이터를 기반으로 사용 현황을 실시간 파악할 수 있는 재무 관리 도구입니다.
핵심 기능
- 카드 등록/수정/비활성화/삭제: 법인카드 CRUD
- 대시보드 요약 카드 6종: 등록카드, 총한도, 매월결제일, 사용금액, 결제, 잔여한도
- 결제일 동적 계산: 현재일이 결제일을 지나면 자동으로 다음 월로 전환
- 휴일/주말 결제일 조정: 공휴일·주말이면 다음 영업일로 자동 이동
- 바로빌 카드거래 연동: 카드번호 기반 사용금액 자동 집계
- 결제(선불결제) 내역 관리: 복수 건의 결제 내역 입력/수정
2. 시스템 아키텍처
┌─────────────────────────────────────────────────────┐
│ Frontend (React 18 + Babel 브라우저 트랜스파일링) │
│ corporate-cards.blade.php │
│ └─ CorporateCardsManagement 컴포넌트 │
│ ├─ 요약 카드 6종 (summary API) │
│ ├─ 카드 목록 테이블 (list API) │
│ ├─ 카드 등록/수정 모달 │
│ └─ 결제 내역 수정 모달 │
└──────────────┬──────────────────────────────────────┘
│ fetch() API 호출
▼
┌─────────────────────────────────────────────────────┐
│ Backend (Laravel 11) │
│ ├─ CorporateCardController (카드 CRUD + 요약) │
│ ├─ CardTransactionController (거래 CRUD) │
│ └─ EcardController (바로빌 SOAP API 연동) │
└──────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ Database (MySQL 8.0) │
│ ├─ corporate_cards (카드 정보) │
│ ├─ corporate_card_prepayments (결제 내역) │
│ ├─ barobill_card_transactions (바로빌 거래) │
│ ├─ barobill_card_transaction_hides (숨긴 거래) │
│ └─ holidays (공휴일 마스터) │
└─────────────────────────────────────────────────────┘
3. API 엔드포인트
모든 엔드포인트는 /finance/corporate-cards 접두사 하위에 정의됩니다.
| Method | URI | Controller Method | 설명 |
|---|---|---|---|
| GET | /finance/corporate-cards |
(클로저) | 페이지 렌더링 (React SPA) |
| GET | /finance/corporate-cards/list |
index() |
카드 목록 JSON |
| GET | /finance/corporate-cards/summary |
summary() |
대시보드 요약 데이터 |
| POST | /finance/corporate-cards/store |
store() |
카드 신규 등록 |
| PUT | /finance/corporate-cards/{id} |
update() |
카드 정보 수정 |
| POST | /finance/corporate-cards/{id}/deactivate |
deactivate() |
카드 비활성화 |
| DELETE | /finance/corporate-cards/{id} |
destroy() |
카드 영구삭제 |
| POST | /finance/corporate-cards/prepayment |
updatePrepayment() |
결제 내역 저장 |
카드거래 내역 API (별도 컨트롤러)
| Method | URI | Controller | 설명 |
|---|---|---|---|
| GET | /finance/card-transactions |
EcardController::index() |
카드사용내역 페이지 |
| GET | /finance/card-transactions/list |
CardTransactionController::index() |
거래내역 JSON |
| POST | /finance/card-transactions/store |
CardTransactionController::store() |
거래 수동 등록 |
| PUT | /finance/card-transactions/{id} |
CardTransactionController::update() |
거래 수정 |
| DELETE | /finance/card-transactions/{id} |
CardTransactionController::destroy() |
거래 삭제 |
4. 데이터베이스 테이블
4.1 corporate_cards (법인카드)
| 컬럼 | 타입 | 설명 |
|---|---|---|
| id | bigint (PK) | |
| tenant_id | int | 테넌트 ID (Multi-tenant 격리) |
| card_name | varchar(100) | 카드 이름 (예: "업무용 법인카드") |
| card_company | varchar(50) | 카드사 (삼성카드, 현대카드 등) |
| card_number | varchar(30) | 카드번호 (하이픈 포함) |
| card_type | enum | credit (신용) / debit (체크) |
| payment_day | int | 결제일 (1~31, 기본값 15) |
| credit_limit | decimal(10,2) | 카드 한도 |
| current_usage | decimal(10,2) | 현재 사용량 (수동 관리) |
| card_holder_name | varchar(100) | 카드 명의자 |
| actual_user | varchar(100) | 실사용자 |
| expiry_date | varchar(10) | 유효기간 (YY/MM) |
| cvc | varchar(10) | CVC 코드 |
| status | enum | active / inactive |
| memo | text | 메모 |
| deleted_at | timestamp | SoftDeletes |
스코프: forTenant($tenantId), active()
4.2 corporate_card_prepayments (결제 내역)
| 컬럼 | 타입 | 설명 |
|---|---|---|
| id | bigint (PK) | |
| tenant_id | int | 테넌트 ID |
| year_month | varchar(7) | 결제 기준 월 (예: "2026-03") |
| amount | int | 총 결제 금액 |
| items | json | 개별 결제 내역 배열 |
| memo | text | 메모 |
items JSON 구조:
[
{
"date": "2026-02-10",
"amount": 500000,
"description": "카드대금 납부"
},
{
"date": "2026-02-15",
"amount": 300000,
"description": "추가 납부"
}
]
주요 메서드: getOrCreate($tenantId, $yearMonth) — 해당 월 레코드가 없으면 amount=0으로 자동 생성
4.3 barobill_card_transactions (바로빌 카드거래)
| 컬럼 | 타입 | 설명 |
|---|---|---|
| id | bigint (PK) | |
| tenant_id | int | 테넌트 ID |
| card_num | varchar | 카드번호 (하이픈 없음, 정규화) |
| card_company | varchar | 카드사 코드 |
| card_company_name | varchar | 카드사명 |
| use_dt | varchar | 사용일시 (YYYYMMDDHHmmss) |
| use_date | varchar(8) | 사용일 (YYYYMMDD) |
| use_time | varchar(6) | 사용시간 (HHmmss) |
| approval_num | varchar | 승인번호 |
| approval_type | char(1) | 1: 승인, 2: 취소 |
| approval_amount | decimal(10,2) | 승인금액 |
| tax | decimal(10,2) | 세금 |
| service_charge | decimal(10,2) | 봉사료 |
| merchant_name | varchar | 가맹점명 |
| merchant_biz_num | varchar | 가맹점 사업자번호 |
| is_manual | boolean | 수동 입력 여부 |
unique_key (가상 속성): card_num|use_dt|approval_num|approval_amount — 거래 식별용
4.4 barobill_card_transaction_hides (숨긴 거래)
| 컬럼 | 타입 | 설명 |
|---|---|---|
| id | bigint (PK) | |
| tenant_id | int | 테넌트 ID |
| original_unique_key | varchar | 원래 거래의 unique_key |
| card_num | varchar | 카드번호 |
| use_date | varchar(8) | 사용일 |
| original_amount | decimal | 원래 금액 |
| merchant_name | varchar | 가맹점명 |
| hidden_by | int | 숨김 처리한 사용자 ID |
4.5 holidays (공휴일)
| 컬럼 | 타입 | 설명 |
|---|---|---|
| id | bigint (PK) | |
| tenant_id | int | 테넌트 ID |
| start_date | date | 시작일 |
| end_date | date | 종료일 |
| name | varchar | 공휴일 이름 |
| type | varchar | 유형 |
| is_recurring | boolean | 매년 반복 여부 |
5. 핵심 비즈니스 로직
5.1 결제일 동적 계산 (★ 핵심 전략)
법인카드의 매월 결제일은 현재 날짜를 기준으로 동적 계산됩니다.
파일: CorporateCardController::summary()
계산 흐름
1. 활성 신용카드의 대표 결제일(payment_day) 조회
└─ 첫 번째 활성 신용카드 기준 (예: 15일)
2. 현재 월의 결제일 생성
└─ createPaymentDate(2026, 2, 15) → 2026-02-15
3. 휴일/주말 조정
└─ getAdjustedPaymentDate() → 토/일/공휴일이면 다음 영업일로 이동
└─ 예: 2/15(일) → 2/16(월)
4. 현재일이 결제일을 지났는지 확인
└─ if (now > adjustedDate) → 다음 월로 이동
└─ 예: 현재 2/20, 결제일 2/16 → 다음: 3/15 (→ 3/16 조정)
5. 결과 반환
├─ paymentDate: 조정된 결제일 (표시용)
├─ paymentDay: 원래 결제일 (설정값)
├─ originalDate: 조정 전 결제일
└─ isAdjusted: 조정 여부 (true이면 "15일→휴일조정" 표시)
월 말일 처리
// 2월 30일 같은 불가능한 날짜 방지
private function createPaymentDate(int $year, int $month, int $day): Carbon
{
$maxDay = Carbon::create($year, $month)->daysInMonth;
return Carbon::create($year, $month, min($day, $maxDay));
}
// 예: payment_day=31, 2월 → 2/28(또는 2/29)
휴일 조정 로직
private function getAdjustedPaymentDate($tenantId, $year, $month, $paymentDay): Carbon
{
$date = createPaymentDate($year, $month, $paymentDay);
// holidays 테이블에서 해당 기간의 휴일 조회
$holidays = Holiday::forTenant($tenantId)
->where('start_date', '<=', $date->addDays(10))
->where('end_date', '>=', $date)
->get();
// 토/일/공휴일이면 다음 영업일로 이동 (앞으로만)
while ($date->isWeekend() || in_array($date, $holidayDates)) {
$date->addDay();
}
return $date;
}
5.2 청구기간 계산
결제일을 기준으로 청구기간을 산출합니다.
청구기간 = 결제일 기준 전월 1일 ~ 결제일 당일
예시 (결제일: 3/15):
- billingStart: 2026-02-01
- billingEnd: 2026-03-15
5.3 사용금액 집계 (바로빌 카드거래)
파일: CorporateCardController::calculateBillingUsage()
1. 활성 카드의 카드번호 수집
└─ 하이픈 제거하여 정규화 (1234-5678-9012-3456 → 1234567890123456)
2. 바로빌 거래 조회
└─ barobill_card_transactions 테이블
└─ card_num IN (정규화된 카드번호들)
└─ use_date BETWEEN 청구시작(YYYYMMDD) AND 청구끝(YYYYMMDD)
3. 숨긴 거래 제외
└─ barobill_card_transaction_hides에서 hidden unique_key 조회
└─ 해당 거래는 집계에서 제외
4. 승인/취소 구분 합산
└─ approval_type = '1' (승인): +금액
└─ approval_type = '2' (취소): -금액
5. 결과: 전체 합계 + 카드별 합계
└─ { total: 1500000, perCard: { "1234...": 800000, "5678...": 700000 } }
5.4 잔여 한도 계산
잔여한도 = 총한도 - 사용금액 + 결제금액
예시:
총한도: 10,000,000원 (모든 활성 신용카드 credit_limit 합계)
사용금액: 3,000,000원 (바로빌 청구기간 거래 합산)
결제금액: 1,000,000원 (corporate_card_prepayments 해당월)
잔여한도: 8,000,000원
6. 대시보드 요약 카드 (6종)
React 컴포넌트 CorporateCardsManagement 내 그리드 레이아웃 (grid-cols-2 lg:grid-cols-6)
| # | 카드명 | 데이터 소스 | 계산 방식 |
|---|---|---|---|
| 1 | 등록 카드 | cards.length |
전체/활성 카드 수 |
| 2 | 총 한도 | totalLimit |
활성 신용카드의 credit_limit 합계 |
| 3 | 매월결제일 | summaryData.paymentDate |
동적 계산 (현재일 > 결제일이면 익월) |
| 4 | 사용금액 | summaryData.billingUsage |
바로빌 거래 합산 (청구기간 기준) |
| 5 | 결제 | summaryData.prepaidAmount |
corporate_card_prepayments 합계 |
| 6 | 잔여 한도 | 계산값 | 총한도 - 사용금액 + 결제금액 |
매월결제일 카드 상세
- 파란색 강조 (border-blue-200, bg-blue-50/30)
- 메인 숫자:
M/D(요일)형식 (예: "3/15(월)") - 보조 텍스트:
- 휴일 미조정: "매월 15일"
- 휴일 조정됨: "15일→휴일조정"
결제 카드 상세
- 주황색 강조 (border-amber-200, bg-amber-50/30)
- 수정 버튼: 결제 내역 모달 열기
- 보조 텍스트: "N건" (입력된 결제 건수) 또는 "미입력"
7. 프론트엔드 구조
기술 스택
- React 18 (Babel 브라우저 트랜스파일링, CDN)
- Lucide Icons (아이콘 라이브러리)
- Tailwind CSS (스타일링)
컴포넌트 구조
CorporateCardsManagement (메인 컴포넌트)
├─ Header (타이틀 + 카드 추가/테스트 버튼)
├─ Summary Cards (6개 요약 카드 그리드)
├─ Search & Filter (검색바 + 상태 필터)
├─ Card Table (카드 목록 테이블)
│ └─ 각 행: 카드정보 + 바로빌 사용금액 + 수정/삭제 버튼
├─ Card Modal (카드 등록/수정 모달)
│ └─ 카드명, 카드사, 카드번호, 유형, 결제일, 한도 등
└─ Prepayment Modal (결제 내역 수정 모달)
└─ 복수 결제 건 (날짜, 금액, 설명) + 합계
데이터 흐름
useEffect (초기 로드)
→ Promise.all([fetchCards(), fetchSummary()])
→ setCards(cardsResult.data)
→ setSummaryData(summaryResult.data)
카드 목록 테이블의 각 카드 행:
→ getBarobillUsage(card.cardNumber)
→ summaryData.cardUsages에서 해당 카드번호의 사용금액 조회
8. Summary API 응답 구조
GET /finance/corporate-cards/summary
{
"success": true,
"data": {
"paymentDate": "2026-03-16",
"paymentDay": 15,
"originalDate": "2026-03-15",
"isAdjusted": true,
"billingPeriod": {
"start": "2026-02-01",
"end": "2026-03-16"
},
"billingUsage": 2850000,
"cardUsages": {
"1234567890123456": 1500000,
"9876543210987654": 1350000
},
"prepaidAmount": 500000,
"prepaidMemo": "",
"prepaidItems": [
{
"date": "2026-02-10",
"amount": 500000,
"description": "카드대금 납부"
}
]
}
}
9. 파일 경로 정리
Backend (Laravel)
| 파일 | 설명 |
|---|---|
app/Http/Controllers/Finance/CorporateCardController.php |
카드 CRUD + 요약 + 결제 |
app/Http/Controllers/Finance/CardTransactionController.php |
카드거래 CRUD |
app/Http/Controllers/Barobill/EcardController.php |
바로빌 SOAP API 연동 |
app/Models/Finance/CorporateCard.php |
법인카드 모델 |
app/Models/Finance/CorporateCardPrepayment.php |
결제 내역 모델 |
app/Models/Barobill/CardTransaction.php |
바로빌 카드거래 모델 |
app/Models/Barobill/CardTransactionHide.php |
숨긴 거래 모델 |
app/Models/System/Holiday.php |
공휴일 모델 |
routes/web.php (909~939행) |
라우트 정의 |
Frontend (React + Blade)
| 파일 | 설명 |
|---|---|
resources/views/finance/corporate-cards.blade.php |
React SPA 전체 (약 1,000행) |
10. 전략적 고려사항
10.1 바로빌 데이터 신뢰성
- 바로빌 SOAP API를 통해 카드거래 데이터를 주기적으로 수집
unique_key(카드번호+사용일시+승인번호+금액)로 중복 방지- 사용자가 특정 거래를 숨길 수 있음 (비용 집계에서 제외)
10.2 Multi-tenant 데이터 격리
- 모든 쿼리에
tenant_id조건 적용 session('selected_tenant_id', 1)로 현재 테넌트 식별
10.3 카드번호 매칭
- DB(corporate_cards)에는 하이픈 포함 카드번호 저장
- 바로빌(barobill_card_transactions)에는 하이픈 없이 저장
- 매칭 시
str_replace('-', '', $num)으로 정규화 후 비교
10.4 결제일 자동 조정
- 토요일, 일요일, 공휴일(holidays 테이블)이면 다음 영업일로 이동
- 현재일이 해당 월 결제일을 이미 지났으면 다음 월 결제일로 자동 전환
- 월 말일 초과 방지 (31일 결제 → 2월은 28일/29일)
10.5 결제(Prepayment) 관리
- 월별로 복수 건의 결제 내역 관리 가능
itemsJSON 필드로 개별 건(날짜, 금액, 설명) 저장amount필드에는items의 합계 자동 계산- 잔여한도 = 총한도 - 사용금액 + 결제금액
11. 변경 이력
| 날짜 | 변경 내용 |
|---|---|
| 2026-02-20 | 매월결제일 동적 계산 로직 추가 (현재일 > 결제일 → 익월 전환) |
| 2026-02-20 | 기술문서 최초 작성 |