- 바로빌 카드 거래 API (16 엔드포인트): 조회, 분할, 수동입력, 숨김/복원, 금액수정, 분개 - 바로빌 은행 거래 API (13 엔드포인트): 조회, 분할, 오버라이드, 수동입력, 잔액요약, 분개 - 홈택스 세금계산서 API (13 엔드포인트): 매출/매입 조회, 수동입력, 자체분개, 통합분개 - JournalEntry 소스 타입 상수 추가 (barobill_card, barobill_bank, hometax_invoice)
309 lines
10 KiB
PHP
309 lines
10 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Barobill\BarobillCardTransaction;
|
|
use App\Models\Barobill\BarobillCardTransactionAmountLog;
|
|
use App\Models\Barobill\BarobillCardTransactionHide;
|
|
use App\Models\Barobill\BarobillCardTransactionSplit;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
/**
|
|
* 바로빌 카드 거래 서비스 (React 연동용)
|
|
*
|
|
* MNG에서 동기화된 barobill_card_transactions 데이터를
|
|
* React 프론트엔드에서 조회/분개/숨김 등 처리
|
|
*/
|
|
class BarobillCardTransactionService extends Service
|
|
{
|
|
/**
|
|
* 카드 거래 목록 조회 (기간별, 카드번호별)
|
|
*/
|
|
public function index(array $params): array
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$startDate = $params['start_date'] ?? now()->startOfMonth()->format('Y-m-d');
|
|
$endDate = $params['end_date'] ?? now()->format('Y-m-d');
|
|
$cardNum = $params['card_num'] ?? null;
|
|
$search = $params['search'] ?? null;
|
|
$includeHidden = $params['include_hidden'] ?? false;
|
|
$perPage = $params['per_page'] ?? 50;
|
|
|
|
$query = BarobillCardTransaction::where('tenant_id', $tenantId)
|
|
->whereBetween('use_date', [$startDate, $endDate]);
|
|
|
|
if ($cardNum) {
|
|
$query->where('card_num', $cardNum);
|
|
}
|
|
|
|
if ($search) {
|
|
$query->where(function ($q) use ($search) {
|
|
$q->where('merchant_name', 'like', "%{$search}%")
|
|
->orWhere('memo', 'like', "%{$search}%")
|
|
->orWhere('approval_num', 'like', "%{$search}%");
|
|
});
|
|
}
|
|
|
|
// 숨김 거래 필터링
|
|
if (! $includeHidden) {
|
|
$hiddenKeys = BarobillCardTransactionHide::getHiddenKeys($tenantId, $startDate, $endDate);
|
|
if (! empty($hiddenKeys)) {
|
|
$query->whereNotIn(
|
|
DB::raw("CONCAT(card_num, '|', use_dt, '|', approval_num, '|', approval_amount)"),
|
|
$hiddenKeys
|
|
);
|
|
}
|
|
}
|
|
|
|
$query->orderByDesc('use_date')->orderByDesc('use_dt');
|
|
|
|
$transactions = $query->paginate($perPage);
|
|
|
|
// 분할 거래 정보 로드
|
|
$uniqueKeys = $transactions->getCollection()->map->unique_key->toArray();
|
|
$splits = BarobillCardTransactionSplit::where('tenant_id', $tenantId)
|
|
->whereIn('original_unique_key', $uniqueKeys)
|
|
->orderBy('sort_order')
|
|
->get()
|
|
->groupBy('original_unique_key');
|
|
|
|
$transactions->getCollection()->transform(function ($tx) use ($splits) {
|
|
$tx->splits = $splits->get($tx->unique_key, collect());
|
|
$tx->has_splits = $tx->splits->isNotEmpty();
|
|
|
|
return $tx;
|
|
});
|
|
|
|
return [
|
|
'data' => $transactions,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 단일 카드 거래 상세
|
|
*/
|
|
public function show(int $id): ?BarobillCardTransaction
|
|
{
|
|
return BarobillCardTransaction::where('tenant_id', $this->tenantId())
|
|
->find($id);
|
|
}
|
|
|
|
/**
|
|
* 카드 거래 분할 조회
|
|
*/
|
|
public function getSplits(string $uniqueKey): array
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$splits = BarobillCardTransactionSplit::getByUniqueKey($tenantId, $uniqueKey);
|
|
|
|
return ['items' => $splits];
|
|
}
|
|
|
|
/**
|
|
* 카드 거래 분할 저장
|
|
*/
|
|
public function saveSplits(string $uniqueKey, array $items): array
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
|
|
return DB::transaction(function () use ($tenantId, $uniqueKey, $items) {
|
|
// 기존 분할 삭제
|
|
BarobillCardTransactionSplit::where('tenant_id', $tenantId)
|
|
->where('original_unique_key', $uniqueKey)
|
|
->delete();
|
|
|
|
$created = [];
|
|
foreach ($items as $index => $item) {
|
|
$created[] = BarobillCardTransactionSplit::create([
|
|
'tenant_id' => $tenantId,
|
|
'original_unique_key' => $uniqueKey,
|
|
'split_amount' => $item['split_amount'],
|
|
'split_supply_amount' => $item['split_supply_amount'] ?? 0,
|
|
'split_tax' => $item['split_tax'] ?? 0,
|
|
'account_code' => $item['account_code'] ?? null,
|
|
'account_name' => $item['account_name'] ?? null,
|
|
'deduction_type' => $item['deduction_type'] ?? null,
|
|
'evidence_name' => $item['evidence_name'] ?? null,
|
|
'description' => $item['description'] ?? null,
|
|
'memo' => $item['memo'] ?? null,
|
|
'sort_order' => $index + 1,
|
|
'card_num' => $item['card_num'] ?? null,
|
|
'use_dt' => $item['use_dt'] ?? null,
|
|
'use_date' => $item['use_date'] ?? null,
|
|
'approval_num' => $item['approval_num'] ?? null,
|
|
'original_amount' => $item['original_amount'] ?? 0,
|
|
'merchant_name' => $item['merchant_name'] ?? null,
|
|
]);
|
|
}
|
|
|
|
return ['items' => $created, 'count' => count($created)];
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 카드 거래 분할 삭제
|
|
*/
|
|
public function deleteSplits(string $uniqueKey): array
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$deleted = BarobillCardTransactionSplit::where('tenant_id', $tenantId)
|
|
->where('original_unique_key', $uniqueKey)
|
|
->delete();
|
|
|
|
return ['deleted_count' => $deleted];
|
|
}
|
|
|
|
/**
|
|
* 수동 카드 거래 등록
|
|
*/
|
|
public function storeManual(array $data): BarobillCardTransaction
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
|
|
return BarobillCardTransaction::create([
|
|
'tenant_id' => $tenantId,
|
|
'card_num' => $data['card_num'],
|
|
'card_company' => $data['card_company'] ?? null,
|
|
'card_company_name' => $data['card_company_name'] ?? null,
|
|
'use_dt' => $data['use_dt'],
|
|
'use_date' => $data['use_date'],
|
|
'use_time' => $data['use_time'] ?? null,
|
|
'approval_num' => $data['approval_num'] ?? 'MANUAL-'.now()->format('YmdHis'),
|
|
'approval_type' => $data['approval_type'] ?? '1',
|
|
'approval_amount' => $data['approval_amount'],
|
|
'tax' => $data['tax'] ?? 0,
|
|
'service_charge' => $data['service_charge'] ?? 0,
|
|
'payment_plan' => $data['payment_plan'] ?? null,
|
|
'merchant_name' => $data['merchant_name'],
|
|
'merchant_biz_num' => $data['merchant_biz_num'] ?? null,
|
|
'account_code' => $data['account_code'] ?? null,
|
|
'account_name' => $data['account_name'] ?? null,
|
|
'deduction_type' => $data['deduction_type'] ?? null,
|
|
'evidence_name' => $data['evidence_name'] ?? null,
|
|
'description' => $data['description'] ?? null,
|
|
'memo' => $data['memo'] ?? null,
|
|
'is_manual' => true,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 수동 카드 거래 수정
|
|
*/
|
|
public function updateManual(int $id, array $data): BarobillCardTransaction
|
|
{
|
|
$tx = BarobillCardTransaction::where('tenant_id', $this->tenantId())
|
|
->where('is_manual', true)
|
|
->findOrFail($id);
|
|
|
|
$tx->update($data);
|
|
|
|
return $tx->fresh();
|
|
}
|
|
|
|
/**
|
|
* 수동 카드 거래 삭제
|
|
*/
|
|
public function destroyManual(int $id): bool
|
|
{
|
|
$tx = BarobillCardTransaction::where('tenant_id', $this->tenantId())
|
|
->where('is_manual', true)
|
|
->findOrFail($id);
|
|
|
|
return $tx->delete();
|
|
}
|
|
|
|
/**
|
|
* 카드 거래 숨김
|
|
*/
|
|
public function hide(int $id): BarobillCardTransactionHide
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$userId = $this->apiUserId();
|
|
|
|
$tx = BarobillCardTransaction::where('tenant_id', $tenantId)->findOrFail($id);
|
|
|
|
return BarobillCardTransactionHide::hideTransaction($tenantId, $tx->unique_key, [
|
|
'card_num' => $tx->card_num,
|
|
'use_date' => $tx->use_date,
|
|
'approval_num' => $tx->approval_num,
|
|
'approval_amount' => $tx->approval_amount,
|
|
'merchant_name' => $tx->merchant_name,
|
|
], $userId);
|
|
}
|
|
|
|
/**
|
|
* 카드 거래 숨김 복원
|
|
*/
|
|
public function restore(int $id): bool
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$tx = BarobillCardTransaction::where('tenant_id', $tenantId)->findOrFail($id);
|
|
|
|
return BarobillCardTransactionHide::restoreTransaction($tenantId, $tx->unique_key);
|
|
}
|
|
|
|
/**
|
|
* 숨겨진 거래 목록
|
|
*/
|
|
public function hiddenList(array $params): array
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$startDate = $params['start_date'] ?? now()->startOfMonth()->format('Y-m-d');
|
|
$endDate = $params['end_date'] ?? now()->format('Y-m-d');
|
|
|
|
$hiddenItems = BarobillCardTransactionHide::where('tenant_id', $tenantId)
|
|
->whereBetween('use_date', [$startDate, $endDate])
|
|
->orderByDesc('created_at')
|
|
->get();
|
|
|
|
return ['items' => $hiddenItems];
|
|
}
|
|
|
|
/**
|
|
* 금액 수정 (공급가액/세액 수정)
|
|
*/
|
|
public function updateAmount(int $id, array $data): BarobillCardTransaction
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$userId = $this->apiUserId();
|
|
|
|
$tx = BarobillCardTransaction::where('tenant_id', $tenantId)->findOrFail($id);
|
|
|
|
// 변경 이력 기록
|
|
BarobillCardTransactionAmountLog::create([
|
|
'card_transaction_id' => $tx->id,
|
|
'original_unique_key' => $tx->unique_key,
|
|
'before_supply_amount' => $tx->modified_supply_amount ?? $tx->approval_amount,
|
|
'before_tax' => $tx->modified_tax ?? $tx->tax,
|
|
'after_supply_amount' => $data['supply_amount'],
|
|
'after_tax' => $data['tax'],
|
|
'modified_by' => $userId,
|
|
'modified_by_name' => $data['modified_by_name'] ?? '',
|
|
'ip_address' => request()->ip(),
|
|
]);
|
|
|
|
$tx->update([
|
|
'modified_supply_amount' => $data['supply_amount'],
|
|
'modified_tax' => $data['tax'],
|
|
]);
|
|
|
|
return $tx->fresh();
|
|
}
|
|
|
|
/**
|
|
* 카드 번호 목록 (필터용)
|
|
*/
|
|
public function cardNumbers(): array
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
|
|
$cards = BarobillCardTransaction::where('tenant_id', $tenantId)
|
|
->select('card_num', 'card_company_name')
|
|
->distinct()
|
|
->orderBy('card_num')
|
|
->get();
|
|
|
|
return ['items' => $cards];
|
|
}
|
|
}
|