- AccountCode 모델/서비스 확장 (업데이트, 기본 계정과목 시딩) - JournalSyncService 추가 (전표 자동 연동) - SyncsExpenseAccounts 트레이트 추가 - CardTransactionController, TaxInvoiceController 기능 확장 - expense_accounts 테이블에 전표 연결 컬럼 마이그레이션 - account_codes 테이블 확장 마이그레이션 - 전체 테넌트 기본 계정과목 시딩 마이그레이션 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
228 lines
6.3 KiB
PHP
228 lines
6.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\V1;
|
|
|
|
use App\Helpers\ApiResponse;
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Requests\TaxInvoice\CancelTaxInvoiceRequest;
|
|
use App\Http\Requests\TaxInvoice\CreateTaxInvoiceRequest;
|
|
use App\Http\Requests\TaxInvoice\TaxInvoiceListRequest;
|
|
use App\Http\Requests\TaxInvoice\TaxInvoiceSummaryRequest;
|
|
use App\Http\Requests\TaxInvoice\UpdateTaxInvoiceRequest;
|
|
use App\Http\Requests\V1\TaxInvoice\BulkIssueRequest;
|
|
use App\Models\Tenants\JournalEntry;
|
|
use App\Services\JournalSyncService;
|
|
use App\Services\TaxInvoiceService;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
|
|
class TaxInvoiceController extends Controller
|
|
{
|
|
public function __construct(
|
|
private TaxInvoiceService $taxInvoiceService,
|
|
private JournalSyncService $journalSyncService,
|
|
) {}
|
|
|
|
/**
|
|
* 세금계산서 목록 조회
|
|
*/
|
|
public function index(TaxInvoiceListRequest $request)
|
|
{
|
|
$taxInvoices = $this->taxInvoiceService->list($request->validated());
|
|
|
|
return ApiResponse::handle(
|
|
data: $taxInvoices,
|
|
message: __('message.fetched')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 상세 조회
|
|
*/
|
|
public function show(int $id)
|
|
{
|
|
$taxInvoice = $this->taxInvoiceService->show($id);
|
|
|
|
return ApiResponse::handle(
|
|
data: $taxInvoice,
|
|
message: __('message.fetched')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 생성
|
|
*/
|
|
public function store(CreateTaxInvoiceRequest $request)
|
|
{
|
|
$taxInvoice = $this->taxInvoiceService->create($request->validated());
|
|
|
|
return ApiResponse::handle(
|
|
data: $taxInvoice,
|
|
message: __('message.created'),
|
|
status: 201
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 수정
|
|
*/
|
|
public function update(UpdateTaxInvoiceRequest $request, int $id)
|
|
{
|
|
$taxInvoice = $this->taxInvoiceService->update($id, $request->validated());
|
|
|
|
return ApiResponse::handle(
|
|
data: $taxInvoice,
|
|
message: __('message.updated')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 삭제
|
|
*/
|
|
public function destroy(int $id)
|
|
{
|
|
$this->taxInvoiceService->delete($id);
|
|
|
|
return ApiResponse::handle(
|
|
data: null,
|
|
message: __('message.deleted')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 발행
|
|
*/
|
|
public function issue(int $id)
|
|
{
|
|
$taxInvoice = $this->taxInvoiceService->issue($id);
|
|
|
|
return ApiResponse::handle(
|
|
data: $taxInvoice,
|
|
message: __('message.tax_invoice.issued')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 일괄 발행
|
|
*/
|
|
public function bulkIssue(BulkIssueRequest $request)
|
|
{
|
|
$result = $this->taxInvoiceService->bulkIssue($request->getIds());
|
|
|
|
return ApiResponse::handle(
|
|
data: $result,
|
|
message: __('message.tax_invoice.bulk_issued')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 취소
|
|
*/
|
|
public function cancel(CancelTaxInvoiceRequest $request, int $id)
|
|
{
|
|
$taxInvoice = $this->taxInvoiceService->cancel($id, $request->validated()['reason']);
|
|
|
|
return ApiResponse::handle(
|
|
data: $taxInvoice,
|
|
message: __('message.tax_invoice.cancelled')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 국세청 전송 상태 조회
|
|
*/
|
|
public function checkStatus(int $id)
|
|
{
|
|
$taxInvoice = $this->taxInvoiceService->checkStatus($id);
|
|
|
|
return ApiResponse::handle(
|
|
data: $taxInvoice,
|
|
message: __('message.fetched')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 요약 통계
|
|
*/
|
|
public function summary(TaxInvoiceSummaryRequest $request)
|
|
{
|
|
$summary = $this->taxInvoiceService->summary($request->validated());
|
|
|
|
return ApiResponse::handle(
|
|
data: $summary,
|
|
message: __('message.fetched')
|
|
);
|
|
}
|
|
|
|
// =========================================================================
|
|
// 분개 (Journal Entries)
|
|
// =========================================================================
|
|
|
|
/**
|
|
* 세금계산서 분개 조회
|
|
*/
|
|
public function getJournalEntries(int $id): JsonResponse
|
|
{
|
|
return ApiResponse::handle(function () use ($id) {
|
|
$sourceKey = "tax_invoice_{$id}";
|
|
$data = $this->journalSyncService->getForSource(
|
|
JournalEntry::SOURCE_TAX_INVOICE,
|
|
$sourceKey
|
|
);
|
|
|
|
return $data ?? ['rows' => []];
|
|
}, __('message.fetched'));
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 분개 저장/수정
|
|
*/
|
|
public function storeJournalEntries(Request $request, int $id): JsonResponse
|
|
{
|
|
return ApiResponse::handle(function () use ($request, $id) {
|
|
$validated = $request->validate([
|
|
'rows' => 'required|array|min:1',
|
|
'rows.*.side' => 'required|in:debit,credit',
|
|
'rows.*.account_subject' => 'required|string|max:20',
|
|
'rows.*.debit_amount' => 'required|integer|min:0',
|
|
'rows.*.credit_amount' => 'required|integer|min:0',
|
|
]);
|
|
|
|
// 세금계산서 정보 조회 (entry_date용)
|
|
$taxInvoice = $this->taxInvoiceService->show($id);
|
|
|
|
$rows = array_map(fn ($row) => [
|
|
'side' => $row['side'],
|
|
'account_code' => $row['account_subject'],
|
|
'debit_amount' => $row['debit_amount'],
|
|
'credit_amount' => $row['credit_amount'],
|
|
], $validated['rows']);
|
|
|
|
$sourceKey = "tax_invoice_{$id}";
|
|
|
|
return $this->journalSyncService->saveForSource(
|
|
JournalEntry::SOURCE_TAX_INVOICE,
|
|
$sourceKey,
|
|
$taxInvoice->issue_date?->format('Y-m-d') ?? now()->format('Y-m-d'),
|
|
"세금계산서 분개 (#{$id})",
|
|
$rows,
|
|
);
|
|
}, __('message.created'));
|
|
}
|
|
|
|
/**
|
|
* 세금계산서 분개 삭제
|
|
*/
|
|
public function deleteJournalEntries(int $id): JsonResponse
|
|
{
|
|
return ApiResponse::handle(function () use ($id) {
|
|
$sourceKey = "tax_invoice_{$id}";
|
|
|
|
return $this->journalSyncService->deleteForSource(
|
|
JournalEntry::SOURCE_TAX_INVOICE,
|
|
$sourceKey
|
|
);
|
|
}, __('message.deleted'));
|
|
}
|
|
}
|