feat: [finance] 미지급금관리 홈택스/일반전표 데이터 통합 조회
- 홈택스 매입세금계산서 미지급금/미지급비용 대변 데이터 연동 - 일반전표 미지급금/미지급비용 차변 상계 데이터 연동 - 거래처별 잔액 자동 계산 (발생-상계) - 통합잔액/홈택스발생/일반전표상계/수동관리 4탭 구조
This commit is contained in:
@@ -3,9 +3,12 @@
|
||||
namespace App\Http\Controllers\Finance;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Barobill\HometaxInvoiceJournal;
|
||||
use App\Models\Finance\JournalEntryLine;
|
||||
use App\Models\Finance\Payable;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class PayableController extends Controller
|
||||
{
|
||||
@@ -180,4 +183,252 @@ public function destroy(int $id): JsonResponse
|
||||
'message' => '미지급금이 삭제되었습니다.',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 통합 잔액 조회: 홈택스 발생 + 일반전표 상계를 거래처별로 집계
|
||||
*/
|
||||
public function integrated(Request $request): JsonResponse
|
||||
{
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$startDate = $request->input('startDate', date('Y-01-01'));
|
||||
$endDate = $request->input('endDate', date('Y-12-31'));
|
||||
$account = $request->input('account', 'all');
|
||||
$vendor = $request->input('vendor', '');
|
||||
|
||||
$accountCodes = $account === 'all' ? ['204', '205'] : [$account];
|
||||
|
||||
// 1. 홈택스 매입세금계산서 - 대변(미지급금 발생)
|
||||
$hometaxQuery = HometaxInvoiceJournal::where('tenant_id', $tenantId)
|
||||
->whereIn('account_code', $accountCodes)
|
||||
->where('dc_type', 'credit')
|
||||
->where('credit_amount', '>', 0)
|
||||
->whereBetween('write_date', [$startDate, $endDate]);
|
||||
|
||||
if ($vendor) {
|
||||
$hometaxQuery->where('trading_partner_name', 'like', "%{$vendor}%");
|
||||
}
|
||||
|
||||
$hometaxGrouped = (clone $hometaxQuery)
|
||||
->select(
|
||||
'trading_partner_name',
|
||||
'account_code',
|
||||
'account_name',
|
||||
DB::raw('SUM(credit_amount) as total_credit'),
|
||||
DB::raw('COUNT(*) as cnt'),
|
||||
DB::raw('MIN(write_date) as first_date'),
|
||||
DB::raw('MAX(write_date) as last_date')
|
||||
)
|
||||
->groupBy('trading_partner_name', 'account_code', 'account_name')
|
||||
->orderByDesc('total_credit')
|
||||
->get();
|
||||
|
||||
$hometaxDetails = (clone $hometaxQuery)
|
||||
->select('id', 'trading_partner_name', 'account_code', 'account_name', 'credit_amount', 'write_date', 'description', 'nts_confirm_num')
|
||||
->orderByDesc('write_date')
|
||||
->get();
|
||||
|
||||
// 2. 일반전표 - 계정 204/205 차변(상계) + 대변(전표를 통한 발생)
|
||||
$journalQuery = JournalEntryLine::where('journal_entry_lines.tenant_id', $tenantId)
|
||||
->whereIn('journal_entry_lines.account_code', $accountCodes)
|
||||
->join('journal_entries', function ($join) {
|
||||
$join->on('journal_entries.id', '=', 'journal_entry_lines.journal_entry_id')
|
||||
->whereNull('journal_entries.deleted_at');
|
||||
})
|
||||
->whereBetween('journal_entries.entry_date', [$startDate, $endDate]);
|
||||
|
||||
if ($vendor) {
|
||||
$journalQuery->where('journal_entry_lines.trading_partner_name', 'like', "%{$vendor}%");
|
||||
}
|
||||
|
||||
$journalGrouped = (clone $journalQuery)
|
||||
->select(
|
||||
'journal_entry_lines.trading_partner_name',
|
||||
'journal_entry_lines.account_code',
|
||||
'journal_entry_lines.account_name',
|
||||
'journal_entry_lines.dc_type',
|
||||
DB::raw('SUM(journal_entry_lines.debit_amount) as total_debit'),
|
||||
DB::raw('SUM(journal_entry_lines.credit_amount) as total_credit'),
|
||||
DB::raw('COUNT(*) as cnt')
|
||||
)
|
||||
->groupBy('journal_entry_lines.trading_partner_name', 'journal_entry_lines.account_code', 'journal_entry_lines.account_name', 'journal_entry_lines.dc_type')
|
||||
->orderByDesc('total_debit')
|
||||
->get();
|
||||
|
||||
$journalDetails = (clone $journalQuery)
|
||||
->select(
|
||||
'journal_entry_lines.id',
|
||||
'journal_entry_lines.trading_partner_name',
|
||||
'journal_entry_lines.account_code',
|
||||
'journal_entry_lines.account_name',
|
||||
'journal_entry_lines.dc_type',
|
||||
'journal_entry_lines.debit_amount',
|
||||
'journal_entry_lines.credit_amount',
|
||||
'journal_entry_lines.description',
|
||||
'journal_entries.entry_date',
|
||||
'journal_entries.entry_no'
|
||||
)
|
||||
->orderByDesc('journal_entries.entry_date')
|
||||
->get();
|
||||
|
||||
// 3. 거래처별 잔액 계산
|
||||
$vendorMap = [];
|
||||
|
||||
// 홈택스 대변 = 발생
|
||||
foreach ($hometaxGrouped as $row) {
|
||||
$key = $row->trading_partner_name.'|'.$row->account_code;
|
||||
if (! isset($vendorMap[$key])) {
|
||||
$vendorMap[$key] = [
|
||||
'vendorName' => $row->trading_partner_name,
|
||||
'accountCode' => $row->account_code,
|
||||
'accountName' => $row->account_name,
|
||||
'occurred' => 0,
|
||||
'offset' => 0,
|
||||
'hometaxCount' => 0,
|
||||
'journalDebitCount' => 0,
|
||||
'journalCreditCount' => 0,
|
||||
];
|
||||
}
|
||||
$vendorMap[$key]['occurred'] += $row->total_credit;
|
||||
$vendorMap[$key]['hometaxCount'] += $row->cnt;
|
||||
}
|
||||
|
||||
// 일반전표 차변 = 상계, 대변 = 발생
|
||||
foreach ($journalGrouped as $row) {
|
||||
$key = $row->trading_partner_name.'|'.$row->account_code;
|
||||
if (! isset($vendorMap[$key])) {
|
||||
$vendorMap[$key] = [
|
||||
'vendorName' => $row->trading_partner_name,
|
||||
'accountCode' => $row->account_code,
|
||||
'accountName' => $row->account_name,
|
||||
'occurred' => 0,
|
||||
'offset' => 0,
|
||||
'hometaxCount' => 0,
|
||||
'journalDebitCount' => 0,
|
||||
'journalCreditCount' => 0,
|
||||
];
|
||||
}
|
||||
if ($row->dc_type === 'debit') {
|
||||
$vendorMap[$key]['offset'] += $row->total_debit;
|
||||
$vendorMap[$key]['journalDebitCount'] += $row->cnt;
|
||||
} else {
|
||||
$vendorMap[$key]['occurred'] += $row->total_credit;
|
||||
$vendorMap[$key]['journalCreditCount'] += $row->cnt;
|
||||
}
|
||||
}
|
||||
|
||||
// 잔액 계산 및 정렬
|
||||
$byVendor = collect($vendorMap)->map(function ($item) {
|
||||
$item['balance'] = $item['occurred'] - $item['offset'];
|
||||
|
||||
return $item;
|
||||
})->sortByDesc('balance')->values()->all();
|
||||
|
||||
// 4. 요약 통계
|
||||
$totalOccurred = array_sum(array_column($byVendor, 'occurred'));
|
||||
$totalOffset = array_sum(array_column($byVendor, 'offset'));
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'summary' => [
|
||||
'totalOccurred' => $totalOccurred,
|
||||
'totalOffset' => $totalOffset,
|
||||
'totalBalance' => $totalOccurred - $totalOffset,
|
||||
'hometaxCount' => $hometaxDetails->count(),
|
||||
'journalCount' => $journalDetails->count(),
|
||||
'vendorCount' => count($byVendor),
|
||||
],
|
||||
'byVendor' => $byVendor,
|
||||
'hometaxDetails' => $hometaxDetails,
|
||||
'journalDetails' => $journalDetails,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 홈택스 매입세금계산서 미지급금/미지급비용 대변 내역
|
||||
*/
|
||||
public function hometaxPayables(Request $request): JsonResponse
|
||||
{
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$startDate = $request->input('startDate', date('Y-01-01'));
|
||||
$endDate = $request->input('endDate', date('Y-12-31'));
|
||||
$account = $request->input('account', 'all');
|
||||
|
||||
$accountCodes = $account === 'all' ? ['204', '205'] : [$account];
|
||||
|
||||
$items = HometaxInvoiceJournal::where('tenant_id', $tenantId)
|
||||
->whereIn('account_code', $accountCodes)
|
||||
->where('dc_type', 'credit')
|
||||
->where('credit_amount', '>', 0)
|
||||
->whereBetween('write_date', [$startDate, $endDate])
|
||||
->select('id', 'trading_partner_name', 'account_code', 'account_name', 'credit_amount', 'write_date', 'description', 'nts_confirm_num', 'supply_amount', 'tax_amount', 'total_amount')
|
||||
->orderByDesc('write_date')
|
||||
->get();
|
||||
|
||||
$totalCredit = $items->sum('credit_amount');
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $items,
|
||||
'summary' => [
|
||||
'totalCredit' => $totalCredit,
|
||||
'count' => $items->count(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 일반전표 미지급금/미지급비용 내역 (차변=상계, 대변=발생)
|
||||
*/
|
||||
public function journalPayables(Request $request): JsonResponse
|
||||
{
|
||||
$tenantId = session('selected_tenant_id', 1);
|
||||
$startDate = $request->input('startDate', date('Y-01-01'));
|
||||
$endDate = $request->input('endDate', date('Y-12-31'));
|
||||
$account = $request->input('account', 'all');
|
||||
$dcType = $request->input('dcType', 'all');
|
||||
|
||||
$accountCodes = $account === 'all' ? ['204', '205'] : [$account];
|
||||
|
||||
$query = JournalEntryLine::where('journal_entry_lines.tenant_id', $tenantId)
|
||||
->whereIn('journal_entry_lines.account_code', $accountCodes)
|
||||
->join('journal_entries', function ($join) {
|
||||
$join->on('journal_entries.id', '=', 'journal_entry_lines.journal_entry_id')
|
||||
->whereNull('journal_entries.deleted_at');
|
||||
})
|
||||
->whereBetween('journal_entries.entry_date', [$startDate, $endDate]);
|
||||
|
||||
if ($dcType !== 'all') {
|
||||
$query->where('journal_entry_lines.dc_type', $dcType);
|
||||
}
|
||||
|
||||
$items = $query->select(
|
||||
'journal_entry_lines.id',
|
||||
'journal_entry_lines.trading_partner_name',
|
||||
'journal_entry_lines.account_code',
|
||||
'journal_entry_lines.account_name',
|
||||
'journal_entry_lines.dc_type',
|
||||
'journal_entry_lines.debit_amount',
|
||||
'journal_entry_lines.credit_amount',
|
||||
'journal_entry_lines.description',
|
||||
'journal_entries.entry_date',
|
||||
'journal_entries.entry_no'
|
||||
)
|
||||
->orderByDesc('journal_entries.entry_date')
|
||||
->get();
|
||||
|
||||
$totalDebit = $items->sum('debit_amount');
|
||||
$totalCredit = $items->sum('credit_amount');
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $items,
|
||||
'summary' => [
|
||||
'totalDebit' => $totalDebit,
|
||||
'totalCredit' => $totalCredit,
|
||||
'count' => $items->count(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user