- BarobillService HTTP→SOAP 전환 (MNG EtaxController 포팅) - TI SOAP 클라이언트, callSoap(), buildTaxInvoiceData MNG 형식 적용 - issueTaxInvoice/cancelTaxInvoice/checkNtsSendStatus SOAP 방식 - 공급자 설정 조회/저장 API (GET/PUT /supplier-settings) - 생성+즉시발행 통합 API (POST /issue-direct) - SaveSupplierSettingsRequest FormRequest 추가
634 lines
22 KiB
PHP
634 lines
22 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Tenants\BarobillSetting;
|
|
use App\Models\Tenants\TaxInvoice;
|
|
use Illuminate\Support\Facades\Log;
|
|
use SoapClient;
|
|
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
|
|
|
/**
|
|
* 바로빌 API 연동 서비스 (SOAP)
|
|
*
|
|
* 바로빌 개발자센터: https://dev.barobill.co.kr/
|
|
* 바로빌은 SOAP API만 제공하므로 SoapClient를 사용합니다.
|
|
*/
|
|
class BarobillService extends Service
|
|
{
|
|
/**
|
|
* 바로빌 SOAP 기본 URL
|
|
*/
|
|
private const SOAP_BASE_URL = 'https://ws.baroservice.com';
|
|
|
|
/**
|
|
* 바로빌 SOAP 테스트 URL
|
|
*/
|
|
private const SOAP_TEST_URL = 'https://testws.baroservice.com';
|
|
|
|
/**
|
|
* 테스트 모드 여부
|
|
*/
|
|
private bool $testMode;
|
|
|
|
/**
|
|
* TI(Tax Invoice) SOAP 클라이언트
|
|
*/
|
|
private ?SoapClient $tiSoapClient = null;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->testMode = config('services.barobill.test_mode', true);
|
|
}
|
|
|
|
// =========================================================================
|
|
// SOAP 클라이언트
|
|
// =========================================================================
|
|
|
|
/**
|
|
* TI SOAP 클라이언트 초기화/반환
|
|
*/
|
|
private function getTiSoapClient(): SoapClient
|
|
{
|
|
if ($this->tiSoapClient === null) {
|
|
$baseUrl = $this->testMode ? self::SOAP_TEST_URL : self::SOAP_BASE_URL;
|
|
|
|
$context = stream_context_create([
|
|
'ssl' => [
|
|
'verify_peer' => ! $this->testMode,
|
|
'verify_peer_name' => ! $this->testMode,
|
|
'allow_self_signed' => $this->testMode,
|
|
],
|
|
]);
|
|
|
|
$this->tiSoapClient = new SoapClient($baseUrl.'/TI.asmx?WSDL', [
|
|
'trace' => true,
|
|
'encoding' => 'UTF-8',
|
|
'exceptions' => true,
|
|
'connection_timeout' => 30,
|
|
'stream_context' => $context,
|
|
'cache_wsdl' => WSDL_CACHE_NONE,
|
|
]);
|
|
}
|
|
|
|
return $this->tiSoapClient;
|
|
}
|
|
|
|
/**
|
|
* SOAP API 호출
|
|
*
|
|
* MNG EtaxController::callBarobillSOAP() 포팅
|
|
* 음수 반환값 = 에러 코드 (바로빌 규격)
|
|
*/
|
|
private function callSoap(string $method, array $params): array
|
|
{
|
|
$client = $this->getTiSoapClient();
|
|
|
|
if (! isset($params['CERTKEY'])) {
|
|
$setting = $this->getSetting();
|
|
if (! $setting) {
|
|
return [
|
|
'success' => false,
|
|
'error' => '바로빌 설정이 없습니다.',
|
|
];
|
|
}
|
|
$params['CERTKEY'] = $setting->cert_key;
|
|
}
|
|
|
|
try {
|
|
$result = $client->$method($params);
|
|
$resultProperty = $method.'Result';
|
|
|
|
if (isset($result->$resultProperty)) {
|
|
$resultData = $result->$resultProperty;
|
|
|
|
// 바로빌 규격: 음수 반환값은 에러 코드
|
|
if (is_numeric($resultData) && $resultData < 0) {
|
|
return [
|
|
'success' => false,
|
|
'error' => '바로빌 API 오류 코드: '.$resultData,
|
|
'error_code' => (int) $resultData,
|
|
];
|
|
}
|
|
|
|
return ['success' => true, 'data' => $resultData];
|
|
}
|
|
|
|
return ['success' => true, 'data' => $result];
|
|
} catch (\SoapFault $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'SOAP 오류: '.$e->getMessage(),
|
|
];
|
|
} catch (\Throwable $e) {
|
|
return [
|
|
'success' => false,
|
|
'error' => 'API 호출 오류: '.$e->getMessage(),
|
|
];
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// 설정 관리
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 바로빌 설정 조회
|
|
*/
|
|
public function getSetting(): ?BarobillSetting
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
|
|
return BarobillSetting::query()
|
|
->where('tenant_id', $tenantId)
|
|
->first();
|
|
}
|
|
|
|
/**
|
|
* 바로빌 설정 저장
|
|
*/
|
|
public function saveSetting(array $data): BarobillSetting
|
|
{
|
|
$tenantId = $this->tenantId();
|
|
$userId = $this->apiUserId();
|
|
|
|
$setting = BarobillSetting::query()
|
|
->where('tenant_id', $tenantId)
|
|
->first();
|
|
|
|
if ($setting) {
|
|
$setting->fill(array_merge($data, ['updated_by' => $userId]));
|
|
$setting->save();
|
|
} else {
|
|
$setting = BarobillSetting::create(array_merge($data, [
|
|
'tenant_id' => $tenantId,
|
|
'created_by' => $userId,
|
|
'updated_by' => $userId,
|
|
]));
|
|
}
|
|
|
|
return $setting->fresh();
|
|
}
|
|
|
|
/**
|
|
* 연동 테스트 (SOAP)
|
|
*/
|
|
public function testConnection(): array
|
|
{
|
|
$setting = $this->getSetting();
|
|
|
|
if (! $setting || ! $setting->canConnect()) {
|
|
throw new BadRequestHttpException(__('error.barobill.setting_not_configured'));
|
|
}
|
|
|
|
try {
|
|
$response = $this->callSoap('GetAccessToken', [
|
|
'CERTKEY' => $setting->cert_key,
|
|
'CorpNum' => $setting->corp_num,
|
|
'ID' => $setting->barobill_id,
|
|
]);
|
|
|
|
if ($response['success']) {
|
|
$resultData = $response['data'];
|
|
|
|
// 양수 또는 문자열 토큰 = 성공
|
|
if (is_string($resultData) || (is_numeric($resultData) && $resultData > 0)) {
|
|
$setting->verified_at = now();
|
|
$setting->save();
|
|
|
|
return [
|
|
'success' => true,
|
|
'message' => __('message.barobill.connection_success'),
|
|
'verified_at' => $setting->verified_at->toDateTimeString(),
|
|
];
|
|
}
|
|
}
|
|
|
|
throw new \Exception($response['error'] ?? __('error.barobill.connection_failed'));
|
|
} catch (BadRequestHttpException $e) {
|
|
throw $e;
|
|
} catch (\Exception $e) {
|
|
Log::error('바로빌 연동 테스트 실패', [
|
|
'tenant_id' => $this->tenantId(),
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
throw new BadRequestHttpException(__('error.barobill.connection_failed').': '.$e->getMessage());
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// 사업자등록번호 검증
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 사업자등록번호 유효성 검사 (휴폐업 조회)
|
|
*
|
|
* 바로빌 API를 통해 사업자등록번호의 유효성을 검증합니다.
|
|
* 바로빌 설정이 없는 경우 기본 형식 검증만 수행합니다.
|
|
*
|
|
* @param string $businessNumber 사업자등록번호 (10자리, 하이픈 제거)
|
|
* @return array{valid: bool, status: string, status_label: string, corp_name: ?string, ceo_name: ?string, message: string}
|
|
*/
|
|
public function checkBusinessNumber(string $businessNumber): array
|
|
{
|
|
// 하이픈 제거 및 숫자만 추출
|
|
$businessNumber = preg_replace('/[^0-9]/', '', $businessNumber);
|
|
|
|
// 기본 형식 검증 (10자리)
|
|
if (strlen($businessNumber) !== 10) {
|
|
return [
|
|
'valid' => false,
|
|
'status' => 'invalid_format',
|
|
'status_label' => '형식 오류',
|
|
'corp_name' => null,
|
|
'ceo_name' => null,
|
|
'message' => __('error.company.invalid_business_number_format'),
|
|
];
|
|
}
|
|
|
|
// 체크섬 검증 (사업자등록번호 자체 유효성)
|
|
if (! $this->validateBusinessNumberChecksum($businessNumber)) {
|
|
return [
|
|
'valid' => false,
|
|
'status' => 'invalid_checksum',
|
|
'status_label' => '유효하지 않음',
|
|
'corp_name' => null,
|
|
'ceo_name' => null,
|
|
'message' => __('error.company.invalid_business_number'),
|
|
];
|
|
}
|
|
|
|
// 바로빌 SOAP API 조회 시도
|
|
try {
|
|
$response = $this->callSoap('CheckCorpNum', [
|
|
'CorpNum' => $businessNumber,
|
|
]);
|
|
|
|
if ($response['success']) {
|
|
$resultData = $response['data'];
|
|
|
|
// 양수 결과 = 유효한 사업자
|
|
if (is_numeric($resultData) && $resultData >= 0) {
|
|
return [
|
|
'valid' => true,
|
|
'status' => 'active',
|
|
'status_label' => '유효함',
|
|
'corp_name' => null,
|
|
'ceo_name' => null,
|
|
'message' => __('message.company.business_number_valid'),
|
|
];
|
|
}
|
|
}
|
|
|
|
// API 실패 시 형식 검증 결과만 반환
|
|
return [
|
|
'valid' => true,
|
|
'status' => 'format_valid',
|
|
'status_label' => '형식 유효',
|
|
'corp_name' => null,
|
|
'ceo_name' => null,
|
|
'message' => __('message.company.business_number_format_valid'),
|
|
];
|
|
} catch (\Exception $e) {
|
|
// API 호출 실패 시 형식 검증 결과만 반환
|
|
Log::warning('바로빌 사업자번호 조회 실패', [
|
|
'business_number' => $businessNumber,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
return [
|
|
'valid' => true,
|
|
'status' => 'format_valid',
|
|
'status_label' => '형식 유효 (API 조회 불가)',
|
|
'corp_name' => null,
|
|
'ceo_name' => null,
|
|
'message' => __('message.company.business_number_format_valid'),
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 사업자등록번호 체크섬 검증
|
|
*
|
|
* @param string $businessNumber 10자리 사업자등록번호
|
|
*/
|
|
private function validateBusinessNumberChecksum(string $businessNumber): bool
|
|
{
|
|
if (strlen($businessNumber) !== 10) {
|
|
return false;
|
|
}
|
|
|
|
$digits = str_split($businessNumber);
|
|
$multipliers = [1, 3, 7, 1, 3, 7, 1, 3, 5];
|
|
$sum = 0;
|
|
|
|
for ($i = 0; $i < 9; $i++) {
|
|
$sum += intval($digits[$i]) * $multipliers[$i];
|
|
}
|
|
|
|
// 8번째 자리 (인덱스 8)에 대한 추가 처리
|
|
$sum += intval(floor(intval($digits[8]) * 5 / 10));
|
|
|
|
$remainder = $sum % 10;
|
|
$checkDigit = (10 - $remainder) % 10;
|
|
|
|
return $checkDigit === intval($digits[9]);
|
|
}
|
|
|
|
// =========================================================================
|
|
// 세금계산서 발행
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 세금계산서 발행 (SOAP RegistAndIssueTaxInvoice)
|
|
*
|
|
* MNG EtaxController::issueTaxInvoice() 포팅
|
|
*/
|
|
public function issueTaxInvoice(TaxInvoice $taxInvoice): TaxInvoice
|
|
{
|
|
$setting = $this->getSetting();
|
|
|
|
if (! $setting || ! $setting->canConnect()) {
|
|
throw new BadRequestHttpException(__('error.barobill.setting_not_configured'));
|
|
}
|
|
|
|
try {
|
|
$apiData = $this->buildTaxInvoiceData($taxInvoice, $setting);
|
|
$response = $this->callSoap('RegistAndIssueTaxInvoice', $apiData);
|
|
|
|
if ($response['success']) {
|
|
$resultData = $response['data'];
|
|
// 바로빌 규격: 양수 반환값이 Invoice ID
|
|
$taxInvoice->barobill_invoice_id = is_numeric($resultData) ? (string) $resultData : null;
|
|
$taxInvoice->status = TaxInvoice::STATUS_ISSUED;
|
|
$taxInvoice->issued_at = now();
|
|
$taxInvoice->error_message = null;
|
|
$taxInvoice->save();
|
|
|
|
Log::info('세금계산서 발행 성공', [
|
|
'tenant_id' => $this->tenantId(),
|
|
'tax_invoice_id' => $taxInvoice->id,
|
|
'barobill_invoice_id' => $taxInvoice->barobill_invoice_id,
|
|
]);
|
|
|
|
return $taxInvoice->fresh();
|
|
}
|
|
|
|
throw new \Exception($response['error'] ?? '발행 실패');
|
|
} catch (BadRequestHttpException $e) {
|
|
throw $e;
|
|
} catch (\Exception $e) {
|
|
// 발행 실패
|
|
$taxInvoice->status = TaxInvoice::STATUS_FAILED;
|
|
$taxInvoice->error_message = $e->getMessage();
|
|
$taxInvoice->save();
|
|
|
|
Log::error('세금계산서 발행 실패', [
|
|
'tenant_id' => $this->tenantId(),
|
|
'tax_invoice_id' => $taxInvoice->id,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
throw new BadRequestHttpException(__('error.barobill.issue_failed').': '.$e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 취소 (SOAP CancelTaxInvoice)
|
|
*/
|
|
public function cancelTaxInvoice(TaxInvoice $taxInvoice, string $reason): TaxInvoice
|
|
{
|
|
$setting = $this->getSetting();
|
|
|
|
if (! $setting || ! $setting->canConnect()) {
|
|
throw new BadRequestHttpException(__('error.barobill.setting_not_configured'));
|
|
}
|
|
|
|
if (! $taxInvoice->canCancel()) {
|
|
throw new BadRequestHttpException(__('error.barobill.cannot_cancel'));
|
|
}
|
|
|
|
try {
|
|
$response = $this->callSoap('ProcTaxInvoice', [
|
|
'CERTKEY' => $setting->cert_key,
|
|
'CorpNum' => $setting->corp_num,
|
|
'MgtNum' => $taxInvoice->barobill_invoice_id,
|
|
'ProcType' => 4, // 4: 발행취소
|
|
'Memo' => $reason,
|
|
]);
|
|
|
|
if ($response['success']) {
|
|
$taxInvoice->status = TaxInvoice::STATUS_CANCELLED;
|
|
$taxInvoice->cancelled_at = now();
|
|
$taxInvoice->description = ($taxInvoice->description ? $taxInvoice->description."\n" : '').'취소 사유: '.$reason;
|
|
$taxInvoice->save();
|
|
|
|
Log::info('세금계산서 취소 성공', [
|
|
'tenant_id' => $this->tenantId(),
|
|
'tax_invoice_id' => $taxInvoice->id,
|
|
'reason' => $reason,
|
|
]);
|
|
|
|
return $taxInvoice->fresh();
|
|
}
|
|
|
|
throw new \Exception($response['error'] ?? '취소 실패');
|
|
} catch (BadRequestHttpException $e) {
|
|
throw $e;
|
|
} catch (\Exception $e) {
|
|
Log::error('세금계산서 취소 실패', [
|
|
'tenant_id' => $this->tenantId(),
|
|
'tax_invoice_id' => $taxInvoice->id,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
throw new BadRequestHttpException(__('error.barobill.cancel_failed').': '.$e->getMessage());
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 국세청 전송 상태 조회 (SOAP GetTaxInvoiceState)
|
|
*/
|
|
public function checkNtsSendStatus(TaxInvoice $taxInvoice): TaxInvoice
|
|
{
|
|
$setting = $this->getSetting();
|
|
|
|
if (! $setting || ! $setting->canConnect()) {
|
|
throw new BadRequestHttpException(__('error.barobill.setting_not_configured'));
|
|
}
|
|
|
|
if (empty($taxInvoice->barobill_invoice_id)) {
|
|
throw new BadRequestHttpException(__('error.barobill.not_issued'));
|
|
}
|
|
|
|
try {
|
|
$response = $this->callSoap('GetTaxInvoiceState', [
|
|
'CERTKEY' => $setting->cert_key,
|
|
'CorpNum' => $setting->corp_num,
|
|
'MgtNum' => $taxInvoice->barobill_invoice_id,
|
|
]);
|
|
|
|
if ($response['success'] && $response['data']) {
|
|
$stateData = $response['data'];
|
|
|
|
// SOAP 결과 객체에서 상태 추출
|
|
$state = is_object($stateData) ? ($stateData->NTSSendState ?? null) : null;
|
|
|
|
if ($state !== null) {
|
|
$taxInvoice->nts_send_status = (string) $state;
|
|
|
|
// 국세청 전송 완료 시 상태 업데이트
|
|
if (in_array($state, [3, '3', '전송완료']) && ! $taxInvoice->sent_at) {
|
|
$taxInvoice->status = TaxInvoice::STATUS_SENT;
|
|
$taxInvoice->sent_at = now();
|
|
|
|
if (is_object($stateData) && ! empty($stateData->NTSConfirmNum)) {
|
|
$taxInvoice->nts_confirm_num = $stateData->NTSConfirmNum;
|
|
}
|
|
}
|
|
|
|
$taxInvoice->save();
|
|
}
|
|
}
|
|
|
|
return $taxInvoice->fresh();
|
|
} catch (BadRequestHttpException $e) {
|
|
throw $e;
|
|
} catch (\Exception $e) {
|
|
Log::error('국세청 전송 상태 조회 실패', [
|
|
'tenant_id' => $this->tenantId(),
|
|
'tax_invoice_id' => $taxInvoice->id,
|
|
'error' => $e->getMessage(),
|
|
]);
|
|
|
|
throw new BadRequestHttpException(__('error.barobill.status_check_failed').': '.$e->getMessage());
|
|
}
|
|
}
|
|
|
|
// =========================================================================
|
|
// Private 메서드
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 세금계산서 발행용 데이터 구성 (MNG SOAP 형식)
|
|
*
|
|
* MNG EtaxController::issueTaxInvoice() 의 Invoice 구조를 포팅
|
|
* InvoicerParty/InvoiceeParty/TaxInvoiceTradeLineItems 중첩 구조
|
|
*/
|
|
private function buildTaxInvoiceData(TaxInvoice $taxInvoice, BarobillSetting $setting): array
|
|
{
|
|
$supplyAmt = (int) $taxInvoice->supply_amount;
|
|
$taxAmt = (int) $taxInvoice->tax_amount;
|
|
$total = (int) $taxInvoice->total_amount;
|
|
$taxType = $taxAmt == 0 ? 2 : 1; // 1:과세, 2:영세, 3:면세
|
|
|
|
// 관리번호 (유니크)
|
|
$mgtNum = 'SAM'.date('YmdHis').$taxInvoice->id;
|
|
|
|
// 품목 구성
|
|
$tradeLineItems = [];
|
|
foreach ($taxInvoice->items ?? [] as $item) {
|
|
$tradeLineItems[] = [
|
|
'PurchaseExpiry' => $taxInvoice->issue_date->format('Ymd'),
|
|
'Name' => $item['name'] ?? '',
|
|
'Information' => $item['spec'] ?? '',
|
|
'ChargeableUnit' => (string) ($item['qty'] ?? 1),
|
|
'UnitPrice' => (string) ($item['unit_price'] ?? 0),
|
|
'Amount' => (string) ($item['supply_amt'] ?? 0),
|
|
'Tax' => (string) ($item['tax_amt'] ?? 0),
|
|
'Description' => $item['remark'] ?? '',
|
|
];
|
|
}
|
|
|
|
// 품목이 없는 경우 기본 품목 추가
|
|
if (empty($tradeLineItems)) {
|
|
$tradeLineItems[] = [
|
|
'PurchaseExpiry' => $taxInvoice->issue_date->format('Ymd'),
|
|
'Name' => $taxInvoice->description ?? '품목',
|
|
'Information' => '',
|
|
'ChargeableUnit' => '1',
|
|
'UnitPrice' => (string) $supplyAmt,
|
|
'Amount' => (string) $supplyAmt,
|
|
'Tax' => (string) $taxAmt,
|
|
'Description' => '',
|
|
];
|
|
}
|
|
|
|
return [
|
|
'CorpNum' => $setting->corp_num,
|
|
'Invoice' => [
|
|
'IssueDirection' => 1, // 1: 정발행
|
|
'TaxInvoiceType' => $this->mapInvoiceTypeToCode($taxInvoice->invoice_type),
|
|
'ModifyCode' => '',
|
|
'TaxType' => $taxType,
|
|
'TaxCalcType' => 1, // 1: 소계합계
|
|
'PurposeType' => 2, // 2: 청구
|
|
'WriteDate' => $taxInvoice->issue_date->format('Ymd'),
|
|
'AmountTotal' => (string) $supplyAmt,
|
|
'TaxTotal' => (string) $taxAmt,
|
|
'TotalAmount' => (string) $total,
|
|
'Cash' => '0',
|
|
'ChkBill' => '0',
|
|
'Note' => '0',
|
|
'Credit' => (string) $total,
|
|
'Remark1' => $taxInvoice->description ?? '',
|
|
'Remark2' => '',
|
|
'Remark3' => '',
|
|
'InvoicerParty' => [
|
|
'MgtNum' => $mgtNum,
|
|
'CorpNum' => $taxInvoice->supplier_corp_num,
|
|
'TaxRegID' => '',
|
|
'CorpName' => $taxInvoice->supplier_corp_name,
|
|
'CEOName' => $taxInvoice->supplier_ceo_name ?? '',
|
|
'Addr' => $taxInvoice->supplier_addr ?? '',
|
|
'BizType' => $taxInvoice->supplier_biz_type ?? '',
|
|
'BizClass' => $taxInvoice->supplier_biz_class ?? '',
|
|
'ContactID' => $setting->barobill_id,
|
|
'ContactName' => $setting->contact_name ?? '',
|
|
'TEL' => $setting->contact_tel ?? '',
|
|
'HP' => '',
|
|
'Email' => $setting->contact_id ?? '',
|
|
],
|
|
'InvoiceeParty' => [
|
|
'MgtNum' => '',
|
|
'CorpNum' => str_replace('-', '', $taxInvoice->buyer_corp_num ?? ''),
|
|
'TaxRegID' => '',
|
|
'CorpName' => $taxInvoice->buyer_corp_name ?? '',
|
|
'CEOName' => $taxInvoice->buyer_ceo_name ?? '',
|
|
'Addr' => $taxInvoice->buyer_addr ?? '',
|
|
'BizType' => $taxInvoice->buyer_biz_type ?? '',
|
|
'BizClass' => $taxInvoice->buyer_biz_class ?? '',
|
|
'ContactID' => '',
|
|
'ContactName' => '',
|
|
'TEL' => '',
|
|
'HP' => '',
|
|
'Email' => $taxInvoice->buyer_contact_id ?? '',
|
|
],
|
|
'BrokerParty' => [],
|
|
'TaxInvoiceTradeLineItems' => [
|
|
'TaxInvoiceTradeLineItem' => $tradeLineItems,
|
|
],
|
|
],
|
|
'SendSMS' => false,
|
|
'ForceIssue' => false,
|
|
'MailTitle' => '',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 유형을 바로빌 코드로 매핑
|
|
*
|
|
* @return int 1: 세금계산서, 2: 계산서, 4: 수정세금계산서
|
|
*/
|
|
private function mapInvoiceTypeToCode(string $type): int
|
|
{
|
|
return match ($type) {
|
|
TaxInvoice::TYPE_TAX_INVOICE => 1,
|
|
TaxInvoice::TYPE_INVOICE => 2,
|
|
TaxInvoice::TYPE_MODIFIED_TAX_INVOICE => 4,
|
|
default => 1,
|
|
};
|
|
}
|
|
}
|