Files
sam-manage/app/Services/Barobill/BarobillUsageService.php
pro 66b8699fb2 fix:사용량조회 월정액 상품 등록 수 기준으로 변경
- 계좌조회: 거래건수 → 등록 계좌 수 (getBankAccounts API)
- 카드: 사용내역 건수 → 등록 카드 수 (getCards API)
- 세금계산서: 발행 건수 유지 (건별 과금)
- 통계카드, 테이블 헤더, 상세모달 라벨 수정

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 15:37:20 +09:00

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);
}
}