Files
sam-docs/CORPORATE_CARD_DASHBOARD.md
2026-02-20 20:06:32 +09:00

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) 관리

  • 월별로 복수 건의 결제 내역 관리 가능
  • items JSON 필드로 개별 건(날짜, 금액, 설명) 저장
  • amount 필드에는 items의 합계 자동 계산
  • 잔여한도 = 총한도 - 사용금액 + 결제금액

11. 변경 이력

날짜 변경 내용
2026-02-20 매월결제일 동적 계산 로직 추가 (현재일 > 결제일 → 익월 전환)
2026-02-20 기술문서 최초 작성