- 계좌조회: 거래건수 → 등록 계좌 수 (getBankAccounts API) - 카드: 사용내역 건수 → 등록 카드 수 (getCards API) - 세금계산서: 발행 건수 유지 (건별 과금) - 통계카드, 테이블 헤더, 상세모달 라벨 수정 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
324 lines
11 KiB
PHP
324 lines
11 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Barobill;
|
|
|
|
use App\Models\Barobill\BarobillMember;
|
|
use App\Models\Barobill\BarobillPricingPolicy;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Collection;
|
|
|
|
/**
|
|
* 바로빌 사용량 집계 서비스
|
|
*
|
|
* 바로빌 API에는 직접적인 "사용량 집계" API가 없으므로,
|
|
* 각 서비스별 내역 조회 API를 통해 건수를 집계합니다.
|
|
*
|
|
* 과금 정책 (DB 관리):
|
|
* - 전자세금계산서: 기본 100건 무료, 추가 50건 단위 5,000원
|
|
* - 계좌조회: 기본 1계좌 무료, 추가 1계좌당 10,000원
|
|
* - 카드등록: 기본 3장 무료, 추가 1장당 5,000원
|
|
*/
|
|
class BarobillUsageService
|
|
{
|
|
protected BarobillService $barobillService;
|
|
|
|
public function __construct(BarobillService $barobillService)
|
|
{
|
|
$this->barobillService = $barobillService;
|
|
}
|
|
|
|
/**
|
|
* 전체 테넌트 사용량 목록 조회
|
|
*
|
|
* @param string $startDate 시작일 (YYYYMMDD)
|
|
* @param string $endDate 종료일 (YYYYMMDD)
|
|
* @param int|null $tenantId 특정 테넌트만 조회 (null이면 전체)
|
|
* @return array
|
|
*/
|
|
public function getUsageList(string $startDate, string $endDate, ?int $tenantId = null): array
|
|
{
|
|
$query = BarobillMember::query()
|
|
->where('status', 'active')
|
|
->with('tenant:id,company_name');
|
|
|
|
if ($tenantId) {
|
|
$query->where('tenant_id', $tenantId);
|
|
}
|
|
|
|
$members = $query->get();
|
|
$usageList = [];
|
|
|
|
foreach ($members as $member) {
|
|
$usage = $this->getMemberUsage($member, $startDate, $endDate);
|
|
$usageList[] = $usage;
|
|
}
|
|
|
|
return $usageList;
|
|
}
|
|
|
|
/**
|
|
* 단일 회원사 사용량 조회
|
|
*
|
|
* @param BarobillMember $member
|
|
* @param string $startDate 시작일 (YYYYMMDD)
|
|
* @param string $endDate 종료일 (YYYYMMDD)
|
|
* @return array
|
|
*/
|
|
public function getMemberUsage(BarobillMember $member, string $startDate, string $endDate): array
|
|
{
|
|
$taxInvoiceCount = $this->getTaxInvoiceCount($member, $startDate, $endDate);
|
|
$bankAccountCount = $this->getBankAccountCount($member, $startDate, $endDate);
|
|
$cardCount = $this->getCardCount($member, $startDate, $endDate);
|
|
$hometaxCount = $this->getHometaxCount($member, $startDate, $endDate);
|
|
|
|
// 전자세금계산서만 정책 기반 과금액 계산 (다른 서비스는 월정액)
|
|
$taxInvoiceBilling = self::calculateBillingByPolicy('tax_invoice', $taxInvoiceCount);
|
|
$taxInvoiceAmount = $taxInvoiceBilling['billable_amount'];
|
|
|
|
return [
|
|
'member_id' => $member->id,
|
|
'tenant_id' => $member->tenant_id,
|
|
'tenant_name' => $member->tenant?->company_name ?? '-',
|
|
'biz_no' => $member->biz_no,
|
|
'formatted_biz_no' => $member->formatted_biz_no,
|
|
'corp_name' => $member->corp_name,
|
|
'barobill_id' => $member->barobill_id,
|
|
|
|
// 건수
|
|
'tax_invoice_count' => $taxInvoiceCount,
|
|
'bank_account_count' => $bankAccountCount,
|
|
'card_count' => $cardCount,
|
|
'hometax_count' => $hometaxCount,
|
|
|
|
// 금액 (전자세금계산서만 건별 과금, 나머지는 월정액)
|
|
'tax_invoice_amount' => $taxInvoiceAmount,
|
|
'tax_invoice_billing' => $taxInvoiceBilling,
|
|
'total_amount' => $taxInvoiceAmount,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 통계 데이터 집계
|
|
*
|
|
* @param array $usageList 사용량 목록
|
|
* @return array
|
|
*/
|
|
public function aggregateStats(array $usageList): array
|
|
{
|
|
$totalMembers = count($usageList);
|
|
$totalTaxInvoice = 0;
|
|
$totalBankAccount = 0;
|
|
$totalCard = 0;
|
|
$totalHometax = 0;
|
|
$totalAmount = 0;
|
|
|
|
foreach ($usageList as $usage) {
|
|
$totalTaxInvoice += $usage['tax_invoice_count'];
|
|
$totalBankAccount += $usage['bank_account_count'];
|
|
$totalCard += $usage['card_count'];
|
|
$totalHometax += $usage['hometax_count'];
|
|
$totalAmount += $usage['total_amount'];
|
|
}
|
|
|
|
return [
|
|
'total_members' => $totalMembers,
|
|
'total_tax_invoice' => $totalTaxInvoice,
|
|
'total_bank_account' => $totalBankAccount,
|
|
'total_card' => $totalCard,
|
|
'total_hometax' => $totalHometax,
|
|
'total_amount' => $totalAmount,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 전자세금계산서 발행 건수 조회
|
|
*
|
|
* 바로빌 API에 직접적인 세금계산서 건수 조회 API가 없어서
|
|
* 임시로 0을 반환합니다. 실제 구현 시 발행 내역 조회 API 활용 필요.
|
|
*/
|
|
protected function getTaxInvoiceCount(BarobillMember $member, string $startDate, string $endDate): int
|
|
{
|
|
// TODO: 세금계산서 발행 내역 조회 API 연동
|
|
// 현재 바로빌 API에서 제공하는 세금계산서 목록 조회 기능 활용 필요
|
|
// GetTaxInvoiceList 등의 API 활용
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 등록 계좌 수 조회
|
|
*
|
|
* 월정액 과금 기준: 등록된 계좌 개수
|
|
*/
|
|
protected function getBankAccountCount(BarobillMember $member, string $startDate, string $endDate): int
|
|
{
|
|
try {
|
|
$result = $this->barobillService->getBankAccounts($member->biz_no, true);
|
|
|
|
if ($result['success'] && isset($result['data'])) {
|
|
// 배열이면 count
|
|
if (is_array($result['data'])) {
|
|
return count($result['data']);
|
|
}
|
|
// 객체에 계좌 목록이 있으면
|
|
if (is_object($result['data'])) {
|
|
// BankAccountInfoEx 배열이 있는 경우
|
|
if (isset($result['data']->BankAccountInfoEx)) {
|
|
$accounts = $result['data']->BankAccountInfoEx;
|
|
return is_array($accounts) ? count($accounts) : 1;
|
|
}
|
|
}
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::warning('등록 계좌 수 조회 실패', [
|
|
'member_id' => $member->id,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 등록 카드 수 조회
|
|
*
|
|
* 월정액 과금 기준: 등록된 카드 개수
|
|
*/
|
|
protected function getCardCount(BarobillMember $member, string $startDate, string $endDate): int
|
|
{
|
|
try {
|
|
$result = $this->barobillService->getCards($member->biz_no, true);
|
|
|
|
if ($result['success'] && isset($result['data'])) {
|
|
// 배열이면 count
|
|
if (is_array($result['data'])) {
|
|
return count($result['data']);
|
|
}
|
|
// 객체에 카드 목록이 있으면
|
|
if (is_object($result['data'])) {
|
|
// CardInfoEx2 배열이 있는 경우
|
|
if (isset($result['data']->CardInfoEx2)) {
|
|
$cards = $result['data']->CardInfoEx2;
|
|
return is_array($cards) ? count($cards) : 1;
|
|
}
|
|
}
|
|
}
|
|
} catch (\Exception $e) {
|
|
Log::warning('등록 카드 수 조회 실패', [
|
|
'member_id' => $member->id,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 홈텍스 매입/매출 건수 조회
|
|
*
|
|
* 바로빌 API에서 홈텍스 매입/매출 조회 API 활용 필요.
|
|
* 현재는 임시로 0 반환.
|
|
*/
|
|
protected function getHometaxCount(BarobillMember $member, string $startDate, string $endDate): int
|
|
{
|
|
// TODO: 홈텍스 매입/매출 조회 API 연동
|
|
// GetHomeTaxTaxInvoice 등의 API 활용 필요
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 서비스별 과금 정책 정보 반환 (DB에서 조회)
|
|
*/
|
|
public static function getPriceInfo(): array
|
|
{
|
|
$policies = BarobillPricingPolicy::active()->orderBy('sort_order')->get();
|
|
|
|
$priceInfo = [];
|
|
|
|
foreach ($policies as $policy) {
|
|
$priceInfo[$policy->service_type] = [
|
|
'name' => $policy->name,
|
|
'free_quota' => $policy->free_quota,
|
|
'free_quota_unit' => $policy->free_quota_unit,
|
|
'additional_unit' => $policy->additional_unit,
|
|
'additional_unit_label' => $policy->additional_unit_label,
|
|
'additional_price' => $policy->additional_price,
|
|
'description' => $policy->policy_description,
|
|
];
|
|
}
|
|
|
|
// 기본값 설정 (DB에 정책이 없는 경우)
|
|
$defaults = [
|
|
'tax_invoice' => [
|
|
'name' => '계산서 발행',
|
|
'free_quota' => 100,
|
|
'free_quota_unit' => '건',
|
|
'additional_unit' => 50,
|
|
'additional_unit_label' => '건',
|
|
'additional_price' => 5000,
|
|
'description' => '기본 100건 무료, 추가 50건 단위 5,000원',
|
|
],
|
|
'bank_account' => [
|
|
'name' => '계좌조회 수집',
|
|
'free_quota' => 1,
|
|
'free_quota_unit' => '개',
|
|
'additional_unit' => 1,
|
|
'additional_unit_label' => '계좌',
|
|
'additional_price' => 10000,
|
|
'description' => '기본 1계좌 무료, 추가 1계좌당 10,000원',
|
|
],
|
|
'card' => [
|
|
'name' => '법인카드 등록',
|
|
'free_quota' => 3,
|
|
'free_quota_unit' => '장',
|
|
'additional_unit' => 1,
|
|
'additional_unit_label' => '장',
|
|
'additional_price' => 5000,
|
|
'description' => '기본 3장 무료, 추가 1장당 5,000원',
|
|
],
|
|
'hometax' => [
|
|
'name' => '홈텍스 매입/매출',
|
|
'free_quota' => 0,
|
|
'free_quota_unit' => '건',
|
|
'additional_unit' => 1,
|
|
'additional_unit_label' => '건',
|
|
'additional_price' => 0,
|
|
'description' => '월정액 (별도 협의)',
|
|
],
|
|
];
|
|
|
|
// 없는 정책은 기본값으로 채움
|
|
foreach ($defaults as $type => $default) {
|
|
if (!isset($priceInfo[$type])) {
|
|
$priceInfo[$type] = $default;
|
|
}
|
|
}
|
|
|
|
return $priceInfo;
|
|
}
|
|
|
|
/**
|
|
* 사용량에 따른 과금액 계산
|
|
*
|
|
* @param string $serviceType 서비스 유형
|
|
* @param int $usageCount 사용량/등록 수
|
|
* @return array ['free_count' => int, 'billable_count' => int, 'billable_amount' => int]
|
|
*/
|
|
public static function calculateBillingByPolicy(string $serviceType, int $usageCount): array
|
|
{
|
|
$policy = BarobillPricingPolicy::getByServiceType($serviceType);
|
|
|
|
if (!$policy) {
|
|
// 기본 정책이 없으면 과금 없음
|
|
return [
|
|
'free_count' => $usageCount,
|
|
'billable_count' => 0,
|
|
'billable_amount' => 0,
|
|
];
|
|
}
|
|
|
|
return $policy->calculateBilling($usageCount);
|
|
}
|
|
}
|