diff --git a/features/finance/README.md b/features/finance/README.md new file mode 100644 index 0000000..7a63a5a --- /dev/null +++ b/features/finance/README.md @@ -0,0 +1,82 @@ +# 재무/자금관리 기능 + +## 개요 + +SAM 프로젝트의 재무/자금관리 모듈은 회사의 자금 흐름을 종합적으로 관리하는 시스템입니다. +바로빌 API 연동을 통한 실시간 거래 조회, 계좌 관리, 자금 계획, 전표 관리 기능을 제공합니다. + +## 메뉴 구성 + +| 메뉴 | 경로 | 설명 | UI 기술 | +|------|------|------|---------| +| [재무 대시보드](./finance-dashboard.md) | `/finance/dashboard` | 자금 현황 종합 요약 | Blade + JS | +| [일일자금일보](./daily-fund-report.md) | `/finance/daily-fund` | 기간별 계좌 입출금 현황 보고서 | React 18 | +| [자금계획일정](./fund-schedules.md) | `/finance/fund-schedules` | 입금/지급 예정 일정 관리 | Blade | +| [보유계좌관리](./bank-accounts.md) | `/finance/accounts` | 회사 은행계좌 정보 관리 | Blade + HTMX | +| [계좌입출금내역](./account-transactions.md) | `/finance/account-transactions` | 바로빌 연동 거래 조회 및 회계 분류 | React 18 | + +## 아키텍처 + +``` +┌─────────────────────────────────────────────────────────┐ +│ 재무 대시보드 │ +│ (총 잔액, 예정 수입/지출, 최근 거래, 계좌별 잔액) │ +└──────────┬──────────────────┬──────────────────┬────────┘ + │ │ │ + ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ + │ 보유계좌관리 │ │ 자금계획일정 │ │ 계좌입출금내역 │ + │ (계좌 CRUD) │ │ (일정 CRUD) │ │(바로빌 연동) │ + └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ + │ │ │ + ┌──────▼──────────────────▼──────────────────▼──────┐ + │ 데이터베이스 │ + │ bank_accounts, fund_schedules, │ + │ barobill_bank_transactions, journal_entries │ + └──────────────────────────────────────────────────────┘ +``` + +## 주요 기술 스택 + +| 기술 | 용도 | +|------|------| +| Laravel 11 (PHP 8.3) | 백엔드 프레임워크 | +| Blade + Tailwind CSS | 서버 렌더링 UI (대시보드, 계좌관리, 자금일정) | +| React 18 + Babel | 클라이언트 렌더링 UI (자금일보, 입출금내역) | +| HTMX | 부분 페이지 업데이트 (계좌 목록 등) | +| Barobill SOAP API | 은행 거래 실시간 연동 | +| MySQL 8.0 | 데이터 저장 | + +## 데이터 흐름 + +``` +바로빌 SOAP API ──→ barobill_bank_transactions ──→ 계좌입출금내역 + ──→ 일일자금일보 + ──→ 재무 대시보드 + +사용자 입력 ──→ bank_accounts ──→ 보유계좌관리 + ──→ 재무 대시보드 + +사용자 입력 ──→ fund_schedules ──→ 자금계획일정 + ──→ 재무 대시보드 +``` + +## 공통 모델 + +| 모델 | 테이블 | 역할 | +|------|--------|------| +| `Finance\BankAccount` | `bank_accounts` | 보유 계좌 정보 | +| `Finance\FundSchedule` | `fund_schedules` | 자금 일정 | +| `Finance\DailyFundTransaction` | `daily_fund_transactions` | 일일자금 거래 | +| `Finance\DailyFundMemo` | `daily_fund_memos` | 일일자금 메모 | +| `Barobill\BankTransaction` | `barobill_bank_transactions` | 바로빌 거래내역 | +| `Barobill\BankTransactionOverride` | `barobill_bank_transaction_overrides` | 거래 수정 | +| `Barobill\BankTransactionSplit` | `barobill_bank_transaction_splits` | 거래 분개 | +| `Barobill\AccountCode` | `account_codes` | 계정과목 | + +## 서비스 클래스 + +| 서비스 | 파일 | 주요 역할 | +|--------|------|----------| +| `BankAccountService` | `app/Services/BankAccountService.php` | 계좌 CRUD, 통계, 바로빌 연동 | +| `FundScheduleService` | `app/Services/FundScheduleService.php` | 일정 CRUD, 캘린더, 월별 요약 | +| `FcmApiService` | `app/Services/FcmApiService.php` | FCM 푸시 발송 (간접 관련) | diff --git a/features/finance/account-transactions.md b/features/finance/account-transactions.md new file mode 100644 index 0000000..6957ad2 --- /dev/null +++ b/features/finance/account-transactions.md @@ -0,0 +1,339 @@ +# 계좌입출금내역 + +## 개요 + +계좌입출금내역은 바로빌 SOAP API를 통해 은행 거래내역을 실시간으로 조회하고, +회계 분류(계정과목 지정), 분개(1거래→N계정과목), 수동 거래 등록 등을 지원하는 기능입니다. + +- **라우트**: `GET /finance/account-transactions` +- **UI 기술**: React 18 + Babel (브라우저 트랜스파일링) +- **컨트롤러**: `EaccountController` (1,772줄) + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/Barobill/ +│ └── EaccountController.php # 메인 컨트롤러 (1772줄, 16개+ 메서드) +├── app/Models/Barobill/ +│ ├── BankTransaction.php # 바로빌 거래내역 모델 +│ ├── BankTransactionOverride.php # 거래 수정(적요/내용) +│ ├── BankTransactionSplit.php # 거래 분개 +│ ├── AccountCode.php # 계정과목 마스터 +│ ├── BarobillConfig.php # 바로빌 API 설정 +│ └── BarobillMember.php # 테넌트별 바로빌 연동 정보 +└── resources/views/barobill/eaccount/ + └── index.blade.php # React 기반 단일 페이지 +``` + +## 라우트 + +### 웹 라우트 + +```php +// routes/web.php +Route::get('/finance/account-transactions', [EaccountController::class, 'index']); +``` + +### API 라우트 + +```php +// routes/web.php (barobill/eaccount prefix) +GET /accounts → 등록된 계좌 목록 (바로빌) +GET /latest-balances → 계좌별 최신 잔액 (DB) +GET /transactions → 거래내역 조회 (API + DB 병합) +GET /account-codes → 계정과목 목록 (테넌트별) +GET /account-codes/all → 전체 계정과목 +POST /account-codes → 계정과목 등록 +PUT /account-codes/{id} → 계정과목 수정 +DELETE /account-codes/{id} → 계정과목 삭제 +POST /save → 거래 저장 (회계 분류) +GET /export → Excel 내보내기 +POST /save-override → 거래 적요/내용 수정 +POST /manual → 수동 거래 등록 +PUT /manual/{id} → 수동 거래 수정 +DELETE /manual/{id} → 수동 거래 삭제 +GET /splits → 분개 내역 조회 +POST /splits → 분개 저장 +DELETE /splits → 분개 삭제 +``` + +## 컨트롤러 + +### EaccountController + +| 메서드 | HTTP | 설명 | +|--------|------|------| +| `__construct()` | - | SOAP 클라이언트 초기화 (BarobillConfig) | +| `index()` | GET | React 페이지 렌더링 (HX-Redirect 적용) | +| `accounts()` | GET | 바로빌 등록 계좌 목록 | +| `latestBalances()` | GET | DB 기반 최신 잔액 | +| `transactions()` | GET | **거래내역 조회** (API + DB 병합) | +| `accountCodes()` | GET | 계정과목 목록 | +| `accountCodesAll()` | GET | 전체 계정과목 | +| `accountCodeStore()` | POST | 계정과목 등록 | +| `accountCodeUpdate()` | PUT | 계정과목 수정 | +| `accountCodeDestroy()` | DELETE | 계정과목 삭제 | +| `save()` | POST | 거래 저장 (계정과목 지정) | +| `exportExcel()` | GET | Excel 내보내기 | +| `saveOverride()` | POST | 적요/내용 수정 (override) | +| `storeManual()` | POST | 수동 거래 등록 | +| `updateManual()` | PUT | 수동 거래 수정 | +| `destroyManual()` | DELETE | 수동 거래 삭제 | +| `splits()` | GET | 분개 내역 조회 | +| `saveSplits()` | POST | 분개 저장 | +| `deleteSplits()` | DELETE | 분개 삭제 | + +## 바로빌 SOAP API 연동 + +### 설정 구조 + +``` +BarobillConfig (barobill_configs 테이블) +├─ environment: 'test' 또는 'production' +├─ cert_key: 인증서 키 +├─ corp_num: 법인번호 +└─ base_url: SOAP URL + +BarobillMember (barobill_members 테이블) +├─ tenant_id: 테넌트별 분리 +├─ barobill_id: 바로빌 로그인 ID +├─ barobill_pwd: 암호화된 비밀번호 +└─ server_mode: 'test' 또는 'production' (테넌트별) +``` + +### 사용 SOAP 메서드 + +| WSDL | 메서드 | 기능 | +|------|--------|------| +| BANKACCOUNT.asmx | `GetBankAccountEx` | 등록된 계좌 목록 | +| BANKACCOUNT.asmx | `GetPeriodBankAccountTransLog` | 기간별 거래내역 조회 | + +### 에러 코드 + +| 코드 | 의미 | +|------|------| +| `-25005` | 데이터 없음 (정상) | +| `-25001` | 데이터 없음 (정상) | +| 기타 | 에러 메시지 반환 | + +## 핵심 로직 + +### 거래내역 조회 흐름 (transactions) + +``` +React 컴포넌트 (날짜/계좌 선택) + ↓ +GET /barobill/eaccount/transactions + ↓ +1. BarobillMember 조회 (barobill_id) + ↓ +2. 테넌트별 서버 모드 적용 + └─ BarobillConfig 재로드 → SOAP 클라이언트 재초기화 + ↓ +3. [단일 계좌 조회] + ├─ DB 조회: barobill_bank_transactions (저장된 데이터) + ├─ SOAP 호출: GetPeriodBankAccountTransLog + ├─ Override 데이터 병합 (수정된 적요) + ├─ 수동 거래 병합 (중복 제거) + ├─ 분개 데이터 병합 + ├─ 잔액 재계산 (기간 전 잔액 기준) + └─ 정렬 (최신순) + 페이지네이션 + ↓ +4. [전체 계좌 조회] + ├─ GetBankAccountEx로 계좌 목록 조회 + ├─ 각 계좌별로 3번 반복 + └─ 모든 거래 병합 및 정렬 + ↓ +5. JSON 응답 +``` + +### 거래 고유 키 (unique_key) + +```php +// BankTransaction 모델 +return implode('|', [ + $this->bank_account_num, + $this->trans_dt, // 거래일시 + (int) $this->deposit, + (int) $this->withdraw, + (int) $this->balance, +]); +``` + +### 분개 저장 흐름 + +``` +React (분개 모달) + ↓ +POST /barobill/eaccount/splits +{ + originalUniqueKey: "계좌번호|거래일시|입금|출금|잔액", + originalData: { bankAccountNum, transDate, ... }, + splits: [ + { amount: 50000, accountCode: "1000", accountName: "당좌예금" }, + { amount: 50000, accountCode: "2000", accountName: "미수금" } + ] +} + ↓ +기존 분개 삭제 → 새 분개 생성 × N +``` + +### Override 저장 로직 + +``` +POST /barobill/eaccount/save-override +{ + uniqueKey: "거래 고유 키", + modifiedSummary: "수정된 적요", + modifiedCast: "수정된 내용" +} + ↓ +BankTransactionOverride::saveOverride() + → 둘 다 null이면 delete + → 아니면 upsert +``` + +## 모델 + +### BankTransaction (Barobill) + +**테이블**: `barobill_bank_transactions` + +| 필드 | 설명 | +|------|------| +| `tenant_id` | 테넌트 ID | +| `bank_account_num` | 계좌번호 (하이픈 없음) | +| `bank_code` / `bank_name` | 은행 코드/명 | +| `trans_date` | 거래일 (YYYYMMDD) | +| `trans_time` | 거래시간 (HHMMSS) | +| `trans_dt` | 거래일시 (trans_date + trans_time) | +| `deposit` / `withdraw` | 입금액 / 출금액 | +| `balance` | 거래 후 잔액 | +| `summary` / `cast` | 적요 / 내용 | +| `account_code` / `account_name` | 계정과목 코드/명 | +| `is_manual` | 수동 입력 여부 | + +### BankTransactionOverride + +**테이블**: `barobill_bank_transaction_overrides` + +| 필드 | 설명 | +|------|------| +| `unique_key` | 거래 고유 키 | +| `modified_summary` | 수정된 적요 | +| `modified_cast` | 수정된 내용 | + +### BankTransactionSplit + +**테이블**: `barobill_bank_transaction_splits` + +| 필드 | 설명 | +|------|------| +| `original_unique_key` | 원본 거래 고유 키 | +| `split_amount` | 분개 금액 | +| `account_code` / `account_name` | 계정과목 | +| `description` / `memo` | 설명 / 메모 | +| `sort_order` | 정렬 순서 | +| `bank_account_num` / `trans_dt` / `trans_date` | 원본 거래 정보 | +| `original_deposit` / `original_withdraw` | 원본 금액 | + +### AccountCode + +**테이블**: `account_codes` + +| 필드 | 설명 | +|------|------| +| `code` | 계정과목 코드 (예: "1000") | +| `name` | 계정과목명 (예: "당좌예금") | +| `category` | 분류 (자산, 부채, 자본 등) | +| `sort_order` | 정렬 순서 | +| `is_active` | 활성 여부 | + +### BarobillConfig + +**테이블**: `barobill_configs` + +| 필드 | 설명 | +|------|------| +| `name` | 설정명 | +| `environment` | 'test' 또는 'production' | +| `cert_key` | 바로빌 인증서 키 | +| `corp_num` | 법인번호 | +| `is_active` | 활성 여부 | + +### BarobillMember + +**테이블**: `barobill_members` + +| 필드 | 설명 | +|------|------| +| `tenant_id` | 테넌트 ID | +| `biz_no` | 사업자번호 | +| `barobill_id` / `barobill_pwd` | 바로빌 로그인 정보 | +| `server_mode` | 'test' 또는 'production' | +| `status` | active / inactive / pending | + +## 뷰 구성 (React) + +### index.blade.php + +``` +┌─ 테넌트 정보 카드 (Blade) ────────── +│ 회사명, 사업자번호, 바로빌 ID +│ 바로빌 미연동 경고 (조건부) +│ +├─ React 앱 (#eaccount-root) ───────── +│ ├─ 계좌 선택 드롭다운 +│ ├─ 기간 선택 (이번달, 지난달, D-2~5월 버튼) +│ │ +│ ├─ 통계 카드 ────────── +│ │ 총 입금 | 총 출금 | 거래 건수 +│ │ +│ ├─ 거래 테이블 ──────── +│ │ 번호 | 거래일시 | 적요 | 입금 | 출금 | 잔액 | 계정과목 +│ │ ├─ 인라인 편집 (적요, 계정과목) +│ │ ├─ 수동 거래: 보라색 표시 +│ │ ├─ 숨긴 거래: 회색 처리 +│ │ └─ 분개된 거래: 파란색 표시 +│ │ +│ ├─ 수동 거래 등록 모달 ── +│ │ 날짜, 시간, 입금/출금, 금액, 적요, 계정과목 +│ │ +│ ├─ 분개 모달 ────────── +│ │ 원본 거래 정보 → N개 분개 항목 +│ │ +│ └─ 내보내기/저장 버튼 +│ +└─ API 엔드포인트 상수 (Blade에서 정의) +``` + +### React 주요 기능 + +| 기능 | 설명 | +|------|------| +| 계좌별 조회 | 드롭다운에서 계좌 선택 | +| 기간 선택 | 월 단위 버튼 (이번달 ~ D-5월) | +| 인라인 편집 | 적요, 계정과목 직접 수정 | +| 분개 | 1거래 → N계정과목 분할 | +| 수동 입력 | API 미제공 거래 추가 | +| 거래 숨김 | 특정 거래 숨기기/복원 | +| Excel 내보내기 | 조회 데이터 다운로드 | +| 잔액 재계산 | 기간 전 잔액 기준 자동 계산 | + +## 데이터베이스 테이블 요약 + +| 테이블 | 역할 | 마이그레이션 (API) | +|--------|------|-------------------| +| `barobill_bank_transactions` | 거래내역 저장 | `2026_01_23_130000_...` | +| `barobill_bank_transaction_overrides` | 적요/내용 수정 | `2026_02_06_095159_...` | +| `barobill_bank_transaction_splits` | 분개 데이터 | `2026_02_06_200000_...` | +| `account_codes` | 계정과목 마스터 | - | +| `barobill_members` | 테넌트별 연동 정보 | - | +| `barobill_configs` | API 설정 (환경별) | - | + +## HTMX 호환성 + +- React 기반 페이지이므로 **HX-Redirect 필요** +- `@push('scripts')` 블록에 React/Babel 스크립트 포함 +- HTMX 네비게이션 시 전체 페이지 리로드 필수 diff --git a/features/finance/bank-accounts.md b/features/finance/bank-accounts.md new file mode 100644 index 0000000..5dab590 --- /dev/null +++ b/features/finance/bank-accounts.md @@ -0,0 +1,254 @@ +# 보유계좌관리 + +## 개요 + +보유계좌관리는 회사의 은행계좌 정보를 중앙 집중식으로 관리하는 기능입니다. +계좌 등록/수정/삭제, 잔액 조회, 바로빌 연동 최신 잔액 업데이트를 지원합니다. + +- **라우트**: `GET /finance/accounts` +- **라우트 이름**: `finance.accounts.index` +- **UI 기술**: Blade + HTMX + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/ +│ ├── Finance/ +│ │ └── BankAccountController.php # 웹 컨트롤러 +│ └── Api/Admin/ +│ └── BankAccountController.php # API 컨트롤러 +├── app/Services/ +│ └── BankAccountService.php # 비즈니스 로직 +├── app/Models/Finance/ +│ ├── BankAccount.php # 계좌 모델 +│ └── BankTransaction.php # 거래내역 모델 +└── resources/views/finance/accounts/ + ├── index.blade.php # 목록 페이지 + ├── create.blade.php # 등록 폼 + ├── edit.blade.php # 수정 폼 + ├── show.blade.php # 상세 (거래내역 포함) + └── partials/ + └── table.blade.php # 테이블 partial (HTMX) +``` + +## 라우트 + +### 웹 라우트 + +```php +// routes/web.php (finance prefix 그룹 내) +Route::get('/accounts', [BankAccountController::class, 'index'])->name('accounts.index'); +Route::get('/accounts/create', [..., 'create'])->name('accounts.create'); +Route::get('/accounts/{id}', [..., 'show'])->name('accounts.show'); +Route::get('/accounts/{id}/edit', [..., 'edit'])->name('accounts.edit'); +``` + +### API 라우트 + +```php +// routes/api.php (admin/bank-accounts prefix) +GET /all → 전체 계좌 (드롭다운용) +GET /summary → 요약 통계 +GET / → 목록 (페이지네이션) +POST / → 신규 등록 +GET /{id} → 상세 조회 +PUT /{id} → 수정 +DELETE /{id} → 삭제 (Soft Delete) +POST /{id}/restore → 복원 +DELETE /{id}/force → 영구 삭제 (슈퍼관리자만) +POST /{id}/toggle-active → 활성/비활성 토글 +GET /{id}/transactions → 거래내역 조회 +POST /bulk-delete → 일괄 삭제 +POST /bulk-restore → 일괄 복원 +``` + +## 컨트롤러 + +### BankAccountController (웹) + +| 메서드 | 설명 | 특이사항 | +|--------|------|---------| +| `index()` | 계좌 목록 | HTMX 감지 → HX-Redirect (JS 실행 보장) | +| `create()` | 등록 폼 | - | +| `show(id)` | 상세 + 거래내역 | 바로빌 거래 연동 | +| `edit(id)` | 수정 폼 | 404 에러 처리 | + +## 서비스 클래스 + +### BankAccountService + +| 메서드 | 설명 | +|--------|------| +| `getAccounts(filters, perPage)` | 목록 (페이지네이션) + 바로빌 최신 거래일 | +| `getAllAccounts()` | 모든 활성 계좌 (드롭다운용) | +| `getStatsByBank()` | 은행별 통계 | +| `getAccountById(id, withTrashed)` | 단일 조회 | +| `createAccount(data)` | 신규 등록 | +| `updateAccount(account, data)` | 수정 | +| `deleteAccount(account)` | Soft Delete | +| `restoreAccount(account)` | 복원 | +| `forceDeleteAccount(account)` | 영구 삭제 | +| `toggleActive(account)` | 활성/비활성 토글 | +| `getTransactions(accountId, filters, perPage)` | 계좌별 거래내역 | +| `getSummary()` | 전체 요약 (총 계좌 수, 총 잔액) | +| `bulkDelete(ids)` | 일괄 삭제 | +| `bulkRestore(ids)` | 일괄 복원 | + +**바로빌 연동**: `getAccounts()` 실행 시 서브쿼리로 `barobill_bank_transactions` 테이블의 최신 거래 날짜/시간을 조회하여 계좌 데이터에 병합합니다. + +```php +// 계좌번호 매칭: 하이픈 제거 +REPLACE(account_number, '-', '') = barobill_bank_transactions.bank_account_num +``` + +## 모델 + +### BankAccount + +**테이블**: `bank_accounts` + +#### 주요 필드 + +| 필드 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint | 테넌트 ID | +| `bank_code` | string | 은행 코드 (000=한국은행, 020=우리은행 등) | +| `bank_name` | string | 은행명 | +| `account_number` | string | 계좌번호 (하이픈 포함) | +| `account_holder` | string | 예금주명 | +| `account_name` | string | 계좌 별칭 | +| `account_type` | string | 예금종류 (보통예금, 정기예금, 적금) | +| `balance` | decimal(15,2) | 현재 잔액 | +| `currency` | string | 통화 (KRW) | +| `opened_at` | date | 개설일자 | +| `last_transaction_at` | datetime | 최종 거래일시 | +| `branch_name` | string | 지점명 | +| `memo` | text | 메모 | +| `status` | string | active / inactive | +| `is_primary` | boolean | 대표계좌 여부 | +| `sort_order` | int | 정렬 순서 | + +#### Traits + +- `BelongsToTenant` - 테넌트 기반 자동 필터링 +- `SoftDeletes` - Soft Delete 지원 + +#### 주요 Scope + +```php +->active() // status = 'active' +->primary() // is_primary = true +->byBank($name) // 은행별 필터 +->byType($type) // 예금종류별 필터 +->ordered() // sort_order 정렬 +``` + +#### 주요 Accessor + +```php +$account->formatted_balance // "1억 2,345만원" 형식 +$account->masked_account_number // "110-***-5678" +``` + +## 뷰 구성 + +### index.blade.php + +``` +┌─ 페이지 헤더 ────────────────────── +│ 제목: "보유계좌관리" +│ 버튼: "계좌 등록" (파란색) +│ +├─ 요약 카드 (3열) ───────────────── +│ 총 계좌 수 | 총 잔액 | 은행 수 +│ +├─ 테이블 컨테이너 ───────────────── +│ ├─ 헤더: 검색, 상태 필터 +│ └─ HTMX 로드 영역 (#accounts-table) +│ └─ GET /admin/bank-accounts/ +│ +├─ partials/table.blade.php ──────── +│ 컬럼: 은행 | 계좌번호 | 예금종류 | 잔액 | 개설일자 | 최종처리일시 | 작업 +│ ├─ 활성 항목: 수정/삭제 버튼 +│ └─ 삭제된 항목: 복원/영구삭제 (opacity-50 bg-red-50) +│ +└─ JavaScript: refreshAccountBalances() + └─ GET /barobill/eaccount/latest-balances + └─ DOM에서 잔액 실시간 업데이트 +``` + +### 테이블 Partial 특징 + +| 컬럼 | 특이사항 | +|------|---------| +| 은행 | `show/{id}` 링크 | +| 예금종류 | 컬러 배지 (보통예금=파랑, 정기=보라, 적금=초록) | +| 잔액 | `data-account-number` 속성으로 동적 업데이트 | +| 최종처리일시 | 바로빌 거래일 또는 로컬 데이터 | +| 작업 | HTMX 기반 토글/삭제/복원 | + +## 데이터 흐름 + +``` +사용자 (브라우저) + ↓ +BankAccountController::index() + ↓ +BankAccountService::getSummary() + ↓ (bank_accounts: 총 계좌 수, 총 잔액) +View: finance/accounts/index + ├─ 요약 카드 표시 + ├─ HTMX 테이블 로드 + │ ↓ + │ Api\Admin\BankAccountController + │ ↓ + │ BankAccountService::getAccounts() + │ │ ↓ + │ │ bank_accounts + 바로빌 최신 거래일 서브쿼리 + │ └─ JSON/HTML 반환 + │ + └─ refreshAccountBalances() + ↓ + EaccountController::latestBalances() + ↓ + barobill_bank_transactions (최신 잔액) + ↓ + DOM 업데이트 +``` + +## 데이터베이스 스키마 + +### bank_accounts + +**마이그레이션**: `api/database/migrations/2025_12_17_120001_create_bank_accounts_table.php` + +```sql +CREATE TABLE bank_accounts ( + id BIGINT PRIMARY KEY AUTO_INCREMENT, + tenant_id BIGINT NOT NULL, + bank_code VARCHAR(10), + bank_name VARCHAR(50), + account_number VARCHAR(50), + account_holder VARCHAR(100), + account_name VARCHAR(100), + account_type VARCHAR(20), + balance DECIMAL(15,2) DEFAULT 0, + currency VARCHAR(3) DEFAULT 'KRW', + opened_at DATE, + last_transaction_at DATETIME, + branch_name VARCHAR(100), + memo TEXT, + status VARCHAR(20) DEFAULT 'active', + is_primary BOOLEAN DEFAULT FALSE, + sort_order INT DEFAULT 0, + created_by BIGINT, updated_by BIGINT, deleted_by BIGINT, + created_at TIMESTAMP, updated_at TIMESTAMP, deleted_at TIMESTAMP +); +``` + +## HTMX 호환성 + +- Blade + HTMX 기반 (HX-Redirect 사용 - JavaScript 있음) +- 테이블은 HTMX partial로 동적 로드 +- 토글/삭제/복원 액션은 HTMX로 처리 diff --git a/features/finance/daily-fund-report.md b/features/finance/daily-fund-report.md new file mode 100644 index 0000000..7e6fade --- /dev/null +++ b/features/finance/daily-fund-report.md @@ -0,0 +1,201 @@ +# 일일자금일보 + +## 개요 + +일일자금일보는 기간별 계좌 입출금 현황을 조회하고 일별 보고서를 생성하는 기능입니다. +바로빌에서 수집된 은행 거래 데이터를 기반으로 날짜별, 계좌별 입출금 집계를 제공합니다. + +- **라우트**: `GET /finance/daily-fund` +- **UI 기술**: React 18 + Babel (브라우저 트랜스파일링) + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/Finance/ +│ └── DailyFundController.php # 메인 컨트롤러 (6개 메서드) +├── app/Models/Finance/ +│ ├── DailyFundTransaction.php # 수동 거래내역 모델 +│ └── DailyFundMemo.php # 일별 메모 모델 +├── app/Models/Barobill/ +│ ├── BankTransaction.php # 바로빌 거래내역 모델 +│ └── BankTransactionOverride.php # 거래 수정 이력 +└── resources/views/finance/ + └── daily-fund.blade.php # React 기반 UI +``` + +## 라우트 + +```php +// routes/web.php (finance prefix 그룹 내) +Route::get('/daily-fund', [DailyFundController::class, 'index'])->name('daily-fund'); + +// API 엔드포인트 (동일 컨트롤러) +Route::get('/daily-fund/period-report', [DailyFundController::class, 'periodReport']); +Route::post('/daily-fund', [DailyFundController::class, 'store']); +Route::put('/daily-fund/{id}', [DailyFundController::class, 'update']); +Route::delete('/daily-fund/{id}', [DailyFundController::class, 'destroy']); +Route::post('/daily-fund/memo', [DailyFundController::class, 'saveMemo']); +``` + +## 컨트롤러 + +### DailyFundController + +| 메서드 | HTTP | 설명 | +|--------|------|------| +| `index()` | GET | 특정 날짜 거래내역 조회 | +| `store()` | POST | 거래내역 수동 등록 | +| `update()` | PUT | 거래내역 수정 | +| `destroy()` | DELETE | 거래내역 삭제 | +| `saveMemo()` | POST | 일별 메모 저장 | +| `periodReport()` | GET | **기간별 일일자금일보** (핵심) | + +### periodReport() 핵심 로직 + +``` +QueryString: start_date, end_date (YYYYMMDD) + ↓ +BarobillBankTransaction 조회 (trans_date 범위) + ↓ +BankTransactionOverride 병합 (수정된 적요/내용) + ↓ +unique_key 기준 중복 제거 + ↓ +날짜별 그룹핑 + 계좌별 입출금 집계 + ↓ +JSON 응답 +``` + +**응답 구조**: +```json +{ + "dailyReports": [ + { + "date": "20260211", + "dateFormatted": "2026년 2월 11일 수요일", + "accounts": [ + { "bankName": "우리은행", "accountNum": "1002-xxx", "deposit": 5000000, "withdraw": 1000000, "balance": 50000000 } + ], + "deposits": [ + { "time": "0930", "bankName": "우리은행", "summary": "급여입금", "cast": "본사", "amount": 5000000, "balance": 50000000 } + ], + "withdrawals": [ ... ], + "totalDeposit": 5000000, + "totalWithdraw": 1000000 + } + ] +} +``` + +## 뷰 구성 (React) + +### daily-fund.blade.php + +``` +┌─ 기간 선택 컴포넌트 ──────────── +│ 날짜 입력 (start_date ~ end_date) +│ 월별 단축키 (이번달, 지난달 등) +│ +├─ 일별 보고서 반복 렌더링 ──────── +│ ┌─ 날짜 헤더 ────────── +│ │ 2026년 2월 11일 수요일 +│ │ +│ ├─ 계좌별 요약 테이블 ── +│ │ 은행명 | 계좌번호 | 입금 | 출금 | 잔액 +│ │ +│ ├─ 입금 상세 내역 ───── +│ │ 시간 | 은행 | 적요 | 내용 | 금액 | 잔액 +│ │ +│ └─ 출금 상세 내역 ───── +│ 시간 | 은행 | 적요 | 내용 | 금액 | 잔액 +│ +└─ 인쇄 버튼 +``` + +## 데이터 흐름 + +``` +React Component (기간 선택) + ↓ fetch GET /finance/daily-fund/period-report +DailyFundController::periodReport() + ↓ +BarobillBankTransaction 조회 + ↓ (trans_date 범위 필터) +BankTransactionOverride 병합 + ↓ (수정된 적요/내용 덮어쓰기) +unique_key 기준 중복 제거 + ↓ +날짜별 + 계좌별 그룹핑 + ↓ (입금/출금 분류, 계좌별 집계) +JSON 응답 + ↓ +React 렌더링 (테이블, 통계) +``` + +## 데이터베이스 테이블 + +### barobill_bank_transactions (주 데이터) + +| 컬럼 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint | 테넌트 ID | +| `bank_account_num` | string | 계좌번호 | +| `bank_name` | string | 은행명 | +| `trans_date` | string | 거래일 (YYYYMMDD) | +| `trans_time` | string | 거래시간 (HHMM) | +| `deposit` | decimal | 입금액 | +| `withdraw` | decimal | 출금액 | +| `balance` | decimal | 거래 후 잔액 | +| `summary` | string | 적요 | +| `cast` | string | 내용 | + +### daily_fund_transactions (수동 입력) + +| 컬럼 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint | 테넌트 ID | +| `transaction_date` | date | 거래일 | +| `type` | enum | income / expense | +| `amount` | decimal | 금액 | +| `description` | string | 설명 | + +### daily_fund_memos + +| 컬럼 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint | 테넌트 ID | +| `memo_date` | date | 메모 날짜 | +| `memo` | text | 메모 내용 | +| `author` | string | 작성자 | + +## 핵심 로직 + +### 거래 중복 제거 + +```php +->unique(fn($tx) => $tx->unique_key) +// unique_key = bank_account_num|trans_dt|deposit|withdraw|balance +``` + +### 오버라이드 병합 + +```php +BankTransactionOverride::getByUniqueKeys($keys) +// → modified_summary, modified_cast로 원본 적요/내용 덮어쓰기 +// → is_overridden 플래그 설정 +``` + +### 일별 집계 + +``` +거래 목록 → trans_date 기준 그룹핑 + → 각 날짜: 계좌별 분류 + → 입금 합계, 출금 합계 계산 + → 최종 잔액: DESC 정렬 첫 거래의 balance 값 +``` + +## HTMX 호환성 + +- React 기반 페이지이므로 HX-Redirect 필요 +- `@push('scripts')` 블록에 React/Babel 스크립트 포함 diff --git a/features/finance/finance-dashboard.md b/features/finance/finance-dashboard.md new file mode 100644 index 0000000..d0807c8 --- /dev/null +++ b/features/finance/finance-dashboard.md @@ -0,0 +1,190 @@ +# 재무 대시보드 + +## 개요 + +재무 대시보드는 회사의 자금 현황을 한눈에 파악할 수 있는 종합 화면입니다. +총 잔액, 예정 수입/지출, 최근 거래내역, 계좌별 잔액 등을 요약하여 표시합니다. + +- **라우트**: `GET /finance/dashboard` +- **라우트 이름**: `finance.dashboard` +- **UI 기술**: Blade + JavaScript (HTMX 불필요) + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/Finance/ +│ └── FinanceDashboardController.php # 메인 컨트롤러 +├── app/Services/ +│ ├── BankAccountService.php # 계좌 데이터 서비스 +│ └── FundScheduleService.php # 자금일정 데이터 서비스 +├── app/Models/ +│ ├── Finance/ +│ │ ├── BankAccount.php # 계좌 모델 +│ │ └── FundSchedule.php # 자금일정 모델 +│ └── Barobill/ +│ ├── BankTransaction.php # 바로빌 거래내역 +│ ├── BankTransactionOverride.php # 거래 수정 이력 +│ └── CardTransaction.php # 바로빌 카드거래 +└── resources/views/finance/ + └── dashboard.blade.php # 메인 뷰 +``` + +## 라우트 + +```php +// routes/web.php (finance prefix 그룹 내) +Route::get('/dashboard', [FinanceDashboardController::class, 'index'])->name('dashboard'); +``` + +## 컨트롤러 + +### FinanceDashboardController + +| 메서드 | HTTP | 반환 | 설명 | +|--------|------|------|------| +| `index()` | GET | View | 대시보드 메인 페이지 | + +### index() 데이터 수집 + +```php +public function index(): View +{ + // 1. 계좌 요약 (총 잔액, 계좌 수) + $accountSummary = $this->bankAccountService->getSummary(); + + // 2. 자금일정 요약 (7일 내 일정 건수) + $scheduleSummary = $this->fundScheduleService->getSummary(); + + // 3. 이번 달 수입/지출 요약 + $monthlySummary = $this->fundScheduleService->getMonthlySummary($year, $month); + + // 4. 향후 7일 자금 일정 + $upcomingSchedules = $this->fundScheduleService->getUpcomingSchedules(7); + + // 5. 최근 7일 은행 거래내역 (최대 10건) + $recentTransactions = BarobillBankTransaction::where(...) + ->limit(10)->get(); + + // 6. 최근 7일 카드 사용내역 (최대 10건) + $recentCardTransactions = BarobillCardTransaction::where(...) + ->limit(10)->get(); + + // 7. 활성 계좌 잔액 목록 + $accountBalances = BankAccount::active()->ordered()->get(); +} +``` + +## 뷰 구성 + +### dashboard.blade.php + +| 섹션 | 내용 | 데이터 소스 | +|------|------|------------| +| 페이지 헤더 | 제목 + 현재 날짜 + 네비게이션 버튼 | - | +| 요약 카드 (4개) | 총 잔액 / 예정 수입 / 예정 지출 / 7일내 일정 | `accountSummary`, `monthlySummary`, `scheduleSummary` | +| 월별 자금 일정 요약 | 수입/지출/순수익 (완료/예정 분리) | `monthlySummary` | +| 계좌별 잔액 패널 | 활성 계좌 목록 + 잔액 | `accountBalances` | +| 향후 7일 자금 일정 | 예정 일정 (수입/지출 색상 구분) | `upcomingSchedules` | +| 최근 거래내역 | 7일 은행 거래내역 테이블 | `recentTransactions` | +| 최근 카드 사용내역 | 7일 카드 거래 테이블 | `recentCardTransactions` | + +### JavaScript 기능 + +```javascript +// 계좌 잔액 실시간 새로고침 +function refreshAccountBalances() { + // GET /barobill/eaccount/latest-balances + // → 바로빌 DB에서 최신 잔액 조회 + // → DOM 업데이트 (잔액 수치 변경) + // → 로딩/완료 상태 피드백 +} +``` + +## 데이터 흐름 + +``` +FinanceDashboardController::index() +│ +├─ BankAccountService::getSummary() +│ └─ bank_accounts (총 계좌 수, 총 잔액, 은행별 그룹) +│ +├─ FundScheduleService::getSummary() +│ └─ fund_schedules (예정 건수, 예정 수입/지출) +│ +├─ FundScheduleService::getMonthlySummary() +│ └─ fund_schedules (월별 수입/지출, 완료/예정 분리) +│ +├─ FundScheduleService::getUpcomingSchedules(7) +│ └─ fund_schedules (향후 7일 예정 일정) +│ +├─ BarobillBankTransaction 조회 +│ └─ barobill_bank_transactions (최근 7일, 10건) +│ └─ BankTransactionOverride 병합 (수정된 적요) +│ +├─ BarobillCardTransaction 조회 +│ └─ barobill_card_transactions (최근 7일, 10건) +│ +└─ BankAccount::active()->ordered() + └─ bank_accounts (계좌별 잔액) +``` + +## 서비스 반환 구조 + +### BankAccountService::getSummary() + +```php +[ + 'total_accounts' => int, // 활성 계좌 수 + 'total_balance' => float, // 총 잔액 + 'formatted_total_balance' => str, // "1,000,000원" + 'by_bank' => [ // 은행별 상세 + 'bank_name' => ['count' => int, 'total' => float] + ] +] +``` + +### FundScheduleService::getSummary() + +```php +[ + 'pending_count' => int, // 예정 건수 + 'pending_income' => float, // 예정 수입 + 'pending_expense' => float, // 예정 지출 + 'upcoming_7days' => int // 7일 내 일정 건수 +] +``` + +### FundScheduleService::getMonthlySummary() + +```php +[ + 'year' => int, 'month' => int, + 'total_count' => int, + 'income' => [ + 'count' => int, 'total' => float, + 'pending' => float, 'completed' => float + ], + 'expense' => [ + 'count' => int, 'total' => float, + 'pending' => float, 'completed' => float + ], + 'net' => float // 순수익 (수입 - 지출) +] +``` + +## 관련 데이터베이스 테이블 + +| 테이블 | 용도 | +|--------|------| +| `bank_accounts` | 계좌 잔액, 계좌 수 통계 | +| `fund_schedules` | 자금 일정 요약, 예정 수입/지출 | +| `barobill_bank_transactions` | 최근 은행 거래내역 | +| `barobill_card_transactions` | 최근 카드 사용내역 | +| `barobill_bank_transaction_overrides` | 거래 수정 이력 병합 | + +## HTMX 호환성 + +- 순수 Blade 템플릿 (복잡한 JavaScript 없음) +- HX-Redirect 불필요 +- JavaScript는 `refreshAccountBalances()` 함수만 포함 diff --git a/features/finance/fund-schedules.md b/features/finance/fund-schedules.md new file mode 100644 index 0000000..0aa985a --- /dev/null +++ b/features/finance/fund-schedules.md @@ -0,0 +1,235 @@ +# 자금계획일정 + +## 개요 + +자금계획일정은 입금 예정/지급 예정 일정을 등록, 관리하고 월별 캘린더 뷰로 확인하는 기능입니다. +반복 일정, 월별 복사, 상태 관리(예정/완료/취소) 기능을 지원합니다. + +- **라우트**: `GET /finance/fund-schedules` +- **라우트 이름**: `finance.fund-schedules.index` +- **UI 기술**: Blade 템플릿 + +## 파일 구조 + +``` +mng/ +├── app/Http/Controllers/ +│ ├── Finance/ +│ │ └── FundScheduleController.php # 웹 컨트롤러 (5개 메서드) +│ └── Api/Admin/ +│ └── FundScheduleController.php # API 컨트롤러 +├── app/Services/ +│ └── FundScheduleService.php # 비즈니스 로직 (13개+ 공개 메서드) +├── app/Models/Finance/ +│ └── FundSchedule.php # ORM 모델 +└── resources/views/finance/fund-schedules/ + ├── index.blade.php # 캘린더 뷰 + ├── create.blade.php # 등록 폼 + ├── edit.blade.php # 수정 폼 + └── show.blade.php # 상세보기 +``` + +## 라우트 + +### 웹 라우트 + +```php +// routes/web.php (finance prefix 그룹 내) +Route::get('/fund-schedules', [FundScheduleController::class, 'index'])->name('fund-schedules.index'); +Route::get('/fund-schedules/create', [..., 'create'])->name('fund-schedules.create'); +Route::get('/fund-schedules/{id}', [..., 'show'])->name('fund-schedules.show'); +Route::get('/fund-schedules/{id}/edit', [..., 'edit'])->name('fund-schedules.edit'); + +// 호환성 리다이렉트 +Route::get('/fund-schedule', fn() => redirect()->route('finance.fund-schedules.index')); +``` + +### API 라우트 + +```php +// routes/api.php (admin/fund-schedules prefix) +GET / → index() 목록 (페이지네이션) +GET /calendar → calendar() 월별 캘린더 데이터 +GET /summary → summary() 요약 통계 +GET /upcoming → upcoming() 예정 일정 +POST /copy → copy() 월별 일정 복사 +GET /{id} → show() 상세 조회 +POST / → store() 생성 +PUT /{id} → update() 수정 +DELETE /{id} → destroy() 삭제 +``` + +## 컨트롤러 + +### FundScheduleController (웹) + +| 메서드 | 설명 | 데이터 흐름 | +|--------|------|------------| +| `index()` | 캘린더 뷰 | year, month → `getCalendarData()` → `getMonthlySummary()` → View | +| `create()` | 등록 폼 | 계좌 목록, 타입/상태/반복 옵션 → View | +| `edit(id)` | 수정 폼 | ID로 일정 조회 → View | +| `show(id)` | 상세보기 | ID로 일정 조회 → View | + +## 서비스 클래스 + +### FundScheduleService + +| 메서드 | 매개변수 | 설명 | +|--------|---------|------| +| `getSchedules()` | filters, perPage | 필터링 목록 (페이지네이션) | +| `getSchedulesForMonth()` | year, month | 월별 일정 조회 | +| `getSchedulesForDate()` | date | 특정 날짜 일정 | +| `getUpcomingSchedules()` | days=30 | 향후 N일 예정 일정 | +| `getScheduleById()` | id, withTrashed | 단일 조회 | +| `createSchedule()` | data | 생성 (tenant_id, created_by 자동) | +| `updateSchedule()` | schedule, data | 수정 (updated_by 자동) | +| `deleteSchedule()` | schedule | Soft Delete | +| `restoreSchedule()` | schedule | 복원 | +| `forceDeleteSchedule()` | schedule | 영구 삭제 | +| `markAsCompleted()` | schedule, amount, date | 완료 처리 | +| `markAsCancelled()` | schedule | 취소 처리 | +| `copySchedulesToMonth()` | src→tgt year/month | 월별 일정 복사 (말일 처리) | +| `bulkDelete()` | ids | 일괄 삭제 | +| `bulkUpdateStatus()` | ids, status | 일괄 상태 변경 | +| `getMonthlySummary()` | year, month | 월별 요약 | +| `getCalendarData()` | year, month | 캘린더용 날짜별 그룹핑 | +| `getSummary()` | - | 전체 요약 | + +## 모델 + +### FundSchedule + +**테이블**: `fund_schedules` + +#### 상수 정의 + +```php +// 일정 유형 +TYPE_INCOME = 'income' // 입금 예정 +TYPE_EXPENSE = 'expense' // 지급 예정 + +// 상태 +STATUS_PENDING = 'pending' // 예정 +STATUS_COMPLETED = 'completed' // 완료 +STATUS_CANCELLED = 'cancelled' // 취소 + +// 반복 규칙 +RECURRENCE_DAILY = 'daily' +RECURRENCE_WEEKLY = 'weekly' +RECURRENCE_MONTHLY = 'monthly' +RECURRENCE_YEARLY = 'yearly' +``` + +#### 주요 필드 + +| 필드 | 타입 | 설명 | +|------|------|------| +| `tenant_id` | bigint | 테넌트 ID | +| `title` | string | 일정 제목 | +| `description` | text | 설명 | +| `schedule_type` | enum | income / expense | +| `scheduled_date` | date | 예정 날짜 | +| `amount` | decimal(15,2) | 예정 금액 | +| `currency` | string | 통화 (KRW) | +| `related_bank_account_id` | bigint | 관련 계좌 ID | +| `counterparty` | string | 거래처 | +| `category` | string | 카테고리 | +| `status` | enum | pending / completed / cancelled | +| `is_recurring` | boolean | 반복 여부 | +| `recurrence_rule` | string | 반복 규칙 | +| `recurrence_end_date` | date | 반복 종료일 | +| `completed_date` | date | 실제 완료일 | +| `completed_amount` | decimal(15,2) | 실제 금액 | +| `created_by` / `updated_by` / `deleted_by` | bigint | 작업자 | + +#### 주요 Scope + +```php +->income() // TYPE_INCOME만 +->expense() // TYPE_EXPENSE만 +->pending() // STATUS_PENDING만 +->completed() // STATUS_COMPLETED만 +->forMonth(year, month) // 특정 월의 일정 +->dateBetween(s, e) // 날짜 범위 +->ordered() // scheduled_date 정렬 +``` + +#### 주요 Accessor + +```php +$schedule->formatted_amount // "100만원" 형식 +$schedule->type_label // "입금 예정" +$schedule->status_label // "예정" +$schedule->type_color_class // Tailwind 색상 클래스 +$schedule->status_color_class // Tailwind 색상 클래스 +``` + +## 뷰 구성 + +### index.blade.php (캘린더 뷰) + +``` +┌─ 페이지 헤더 ────────────────────── +│ 제목: "자금계획일정" +│ 버튼: "일정 등록" +│ +├─ 월별 요약 카드 (4열) ──────────── +│ 입금 예정 | 지급 예정 | 순 자금 흐름 | 총 일정 +│ +├─ 캘린더 섹션 ───────────────────── +│ ├─ 헤더: 월 네비게이션 (< 2026년 2월 >) +│ ├─ 요일 헤더 (일~토) +│ └─ 날짜 그리드 (일별 일정 표시) +│ ├─ 입금: 초록 배지 +│ ├─ 지출: 빨강 배지 +│ └─ 클릭 시 일정 상세 +│ +└─ 일정 등록/수정 모달 (JavaScript) +``` + +## 핵심 로직 + +### 월별 복사 (copySchedulesToMonth) + +``` +원본 월의 모든 일정 조회 + ↓ +대상 월로 복사 (말일 처리) + 예) 1월 31일 → 2월 28일 (윤년이면 29일) + ↓ +새 일정 생성 (상태: pending으로 초기화) +``` + +### 월별 요약 (getMonthlySummary) + +```php +[ + 'year' => 2026, 'month' => 2, + 'total_count' => 15, + 'income' => [ + 'count' => 5, 'total' => 10000000, + 'pending' => 7000000, 'completed' => 3000000 + ], + 'expense' => [ + 'count' => 10, 'total' => 8000000, + 'pending' => 5000000, 'completed' => 3000000 + ], + 'net' => 2000000 // 수입 - 지출 +] +``` + +### 캘린더 데이터 (getCalendarData) + +```php +// 날짜별 그룹핑 +[ + '2026-02-05' => [ {일정1}, {일정2} ], + '2026-02-06' => [ {일정3} ], + ... +] +``` + +## HTMX 호환성 + +- 순수 Blade 템플릿 (HX-Redirect 불필요) +- JavaScript는 모달 열기/닫기 함수만 포함