feat: 2.3 카드/계좌 관리 API 구현
- cards, bank_accounts 테이블 마이그레이션 - Card, BankAccount 모델 (카드번호 암호화) - CardService, BankAccountService - CardController, BankAccountController + FormRequest 4개 - API 엔드포인트 15개 (카드 7개, 계좌 8개) - Swagger 문서 (CardApi.php, BankAccountApi.php)
This commit is contained in:
244
app/Services/BankAccountService.php
Normal file
244
app/Services/BankAccountService.php
Normal file
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\Tenants\BankAccount;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class BankAccountService extends Service
|
||||
{
|
||||
/**
|
||||
* 계좌 목록 조회
|
||||
*/
|
||||
public function index(array $params): LengthAwarePaginator
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
|
||||
$query = BankAccount::query()
|
||||
->where('tenant_id', $tenantId);
|
||||
|
||||
// 검색 필터
|
||||
if (! empty($params['search'])) {
|
||||
$search = $params['search'];
|
||||
$query->where(function ($q) use ($search) {
|
||||
$q->where('account_name', 'like', "%{$search}%")
|
||||
->orWhere('bank_name', 'like', "%{$search}%")
|
||||
->orWhere('account_holder', 'like', "%{$search}%")
|
||||
->orWhere('account_number', 'like', "%{$search}%");
|
||||
});
|
||||
}
|
||||
|
||||
// 상태 필터
|
||||
if (! empty($params['status'])) {
|
||||
$query->where('status', $params['status']);
|
||||
}
|
||||
|
||||
// 담당자 필터
|
||||
if (! empty($params['assigned_user_id'])) {
|
||||
$query->where('assigned_user_id', $params['assigned_user_id']);
|
||||
}
|
||||
|
||||
// 대표계좌만 필터
|
||||
if (isset($params['is_primary']) && $params['is_primary']) {
|
||||
$query->where('is_primary', true);
|
||||
}
|
||||
|
||||
// 정렬: 대표계좌 먼저, 그 다음 생성일순
|
||||
$query->orderByDesc('is_primary')
|
||||
->orderBy($params['sort_by'] ?? 'created_at', $params['sort_dir'] ?? 'desc');
|
||||
|
||||
// 페이지네이션
|
||||
$perPage = $params['per_page'] ?? 20;
|
||||
|
||||
return $query->paginate($perPage);
|
||||
}
|
||||
|
||||
/**
|
||||
* 계좌 상세 조회
|
||||
*/
|
||||
public function show(int $id): BankAccount
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
|
||||
return BankAccount::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->with(['assignedUser:id,name'])
|
||||
->findOrFail($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 계좌 등록
|
||||
*/
|
||||
public function store(array $data): BankAccount
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
$userId = $this->apiUserId();
|
||||
|
||||
return DB::transaction(function () use ($data, $tenantId, $userId) {
|
||||
// 첫 번째 계좌인 경우 자동으로 대표계좌 설정
|
||||
$isFirst = BankAccount::where('tenant_id', $tenantId)->count() === 0;
|
||||
$isPrimary = $data['is_primary'] ?? $isFirst;
|
||||
|
||||
// 대표계좌로 설정 시 기존 대표계좌 해제
|
||||
if ($isPrimary) {
|
||||
BankAccount::where('tenant_id', $tenantId)
|
||||
->where('is_primary', true)
|
||||
->update(['is_primary' => false]);
|
||||
}
|
||||
|
||||
$account = BankAccount::create([
|
||||
'tenant_id' => $tenantId,
|
||||
'bank_code' => $data['bank_code'],
|
||||
'bank_name' => $data['bank_name'],
|
||||
'account_number' => $data['account_number'],
|
||||
'account_holder' => $data['account_holder'],
|
||||
'account_name' => $data['account_name'],
|
||||
'status' => $data['status'] ?? 'active',
|
||||
'assigned_user_id' => $data['assigned_user_id'] ?? null,
|
||||
'is_primary' => $isPrimary,
|
||||
'created_by' => $userId,
|
||||
'updated_by' => $userId,
|
||||
]);
|
||||
|
||||
return $account;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 계좌 수정
|
||||
*/
|
||||
public function update(int $id, array $data): BankAccount
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
$userId = $this->apiUserId();
|
||||
|
||||
return DB::transaction(function () use ($id, $data, $tenantId, $userId) {
|
||||
$account = BankAccount::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->findOrFail($id);
|
||||
|
||||
$account->fill([
|
||||
'bank_code' => $data['bank_code'] ?? $account->bank_code,
|
||||
'bank_name' => $data['bank_name'] ?? $account->bank_name,
|
||||
'account_number' => $data['account_number'] ?? $account->account_number,
|
||||
'account_holder' => $data['account_holder'] ?? $account->account_holder,
|
||||
'account_name' => $data['account_name'] ?? $account->account_name,
|
||||
'status' => $data['status'] ?? $account->status,
|
||||
'assigned_user_id' => $data['assigned_user_id'] ?? $account->assigned_user_id,
|
||||
'updated_by' => $userId,
|
||||
]);
|
||||
|
||||
$account->save();
|
||||
|
||||
return $account->fresh();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 계좌 삭제
|
||||
*/
|
||||
public function destroy(int $id): bool
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
$userId = $this->apiUserId();
|
||||
|
||||
return DB::transaction(function () use ($id, $tenantId, $userId) {
|
||||
$account = BankAccount::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->findOrFail($id);
|
||||
|
||||
// 대표계좌 삭제 시 다른 계좌를 대표로 설정
|
||||
if ($account->is_primary) {
|
||||
$nextPrimary = BankAccount::where('tenant_id', $tenantId)
|
||||
->where('id', '!=', $id)
|
||||
->where('status', 'active')
|
||||
->first();
|
||||
|
||||
if ($nextPrimary) {
|
||||
$nextPrimary->is_primary = true;
|
||||
$nextPrimary->save();
|
||||
}
|
||||
}
|
||||
|
||||
$account->deleted_by = $userId;
|
||||
$account->save();
|
||||
$account->delete();
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 계좌 상태 토글 (사용/정지)
|
||||
*/
|
||||
public function toggleStatus(int $id): BankAccount
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
$userId = $this->apiUserId();
|
||||
|
||||
return DB::transaction(function () use ($id, $tenantId, $userId) {
|
||||
$account = BankAccount::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->findOrFail($id);
|
||||
|
||||
$account->toggleStatus();
|
||||
$account->updated_by = $userId;
|
||||
$account->save();
|
||||
|
||||
return $account;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 대표계좌 설정
|
||||
*/
|
||||
public function setPrimary(int $id): BankAccount
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
$userId = $this->apiUserId();
|
||||
|
||||
return DB::transaction(function () use ($id, $tenantId, $userId) {
|
||||
// 기존 대표계좌 해제
|
||||
BankAccount::where('tenant_id', $tenantId)
|
||||
->where('is_primary', true)
|
||||
->update(['is_primary' => false]);
|
||||
|
||||
// 새 대표계좌 설정
|
||||
$account = BankAccount::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->findOrFail($id);
|
||||
|
||||
$account->is_primary = true;
|
||||
$account->updated_by = $userId;
|
||||
$account->save();
|
||||
|
||||
return $account;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 활성 계좌 목록 조회 (셀렉트박스용)
|
||||
*/
|
||||
public function getActiveAccounts(): array
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
|
||||
return BankAccount::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->where('status', 'active')
|
||||
->orderByDesc('is_primary')
|
||||
->orderBy('account_name')
|
||||
->get(['id', 'account_name', 'bank_name', 'account_number', 'is_primary'])
|
||||
->map(function ($account) {
|
||||
return [
|
||||
'id' => $account->id,
|
||||
'account_name' => $account->account_name,
|
||||
'bank_name' => $account->bank_name,
|
||||
'display_number' => $account->getMaskedAccountNumber(),
|
||||
'is_primary' => $account->is_primary,
|
||||
];
|
||||
})
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user