feat: 세금계산서/거래명세서 일괄 발행 API 추가
- POST /api/v1/tax-invoices/bulk-issue: 세금계산서 일괄 발행 - POST /api/v1/sales/bulk-issue-statement: 거래명세서 일괄 발행 - FormRequest 검증 (최대 100건) - Service 일괄 처리 로직 (개별 오류 처리) - Swagger 문서 추가 - i18n 메시지 키 추가 (ko/en)
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
use App\Helpers\ApiResponse;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\V1\Common\BulkUpdateAccountCodeRequest;
|
||||
use App\Http\Requests\V1\Sale\BulkIssueStatementRequest;
|
||||
use App\Http\Requests\V1\Sale\SendStatementRequest;
|
||||
use App\Http\Requests\V1\Sale\StoreSaleRequest;
|
||||
use App\Http\Requests\V1\Sale\UpdateSaleRequest;
|
||||
@@ -151,4 +152,14 @@ public function sendStatement(int $id, SendStatementRequest $request)
|
||||
|
||||
return ApiResponse::success($result, __('message.sale.statement_sent'));
|
||||
}
|
||||
|
||||
/**
|
||||
* 거래명세서 일괄 발행
|
||||
*/
|
||||
public function bulkIssueStatement(BulkIssueStatementRequest $request)
|
||||
{
|
||||
$result = $this->service->bulkIssueStatement($request->getIds());
|
||||
|
||||
return ApiResponse::success($result, __('message.sale.bulk_statement_issued'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
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\Services\TaxInvoiceService;
|
||||
|
||||
class TaxInvoiceController extends Controller
|
||||
@@ -96,6 +97,19 @@ public function issue(int $id)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 세금계산서 일괄 발행
|
||||
*/
|
||||
public function bulkIssue(BulkIssueRequest $request)
|
||||
{
|
||||
$result = $this->taxInvoiceService->bulkIssue($request->getIds());
|
||||
|
||||
return ApiResponse::handle(
|
||||
data: $result,
|
||||
message: __('message.tax_invoice.bulk_issued')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 세금계산서 취소
|
||||
*/
|
||||
|
||||
62
app/Http/Requests/V1/Sale/BulkIssueStatementRequest.php
Normal file
62
app/Http/Requests/V1/Sale/BulkIssueStatementRequest.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\V1\Sale;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* 거래명세서 일괄 발행 요청 검증
|
||||
*/
|
||||
class BulkIssueStatementRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* 권한 확인
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 유효성 검사 규칙
|
||||
*
|
||||
* @return array<string, array<int, mixed>>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'ids' => ['required', 'array', 'min:1', 'max:100'],
|
||||
'ids.*' => ['required', 'integer', 'min:1'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 유효성 검사 메시지
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'ids.required' => __('validation.required', ['attribute' => 'ID 목록']),
|
||||
'ids.array' => __('validation.array', ['attribute' => 'ID 목록']),
|
||||
'ids.min' => __('validation.min.array', ['attribute' => 'ID 목록', 'min' => 1]),
|
||||
'ids.max' => __('validation.max.array', ['attribute' => 'ID 목록', 'max' => 100]),
|
||||
'ids.*.required' => __('validation.required', ['attribute' => 'ID']),
|
||||
'ids.*.integer' => __('validation.integer', ['attribute' => 'ID']),
|
||||
'ids.*.min' => __('validation.min.numeric', ['attribute' => 'ID', 'min' => 1]),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 검증된 ID 배열 반환
|
||||
*
|
||||
* @return array<int, int>
|
||||
*/
|
||||
public function getIds(): array
|
||||
{
|
||||
return $this->validated('ids');
|
||||
}
|
||||
}
|
||||
62
app/Http/Requests/V1/TaxInvoice/BulkIssueRequest.php
Normal file
62
app/Http/Requests/V1/TaxInvoice/BulkIssueRequest.php
Normal file
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Requests\V1\TaxInvoice;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
/**
|
||||
* 세금계산서 일괄 발행 요청 검증
|
||||
*/
|
||||
class BulkIssueRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* 권한 확인
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 유효성 검사 규칙
|
||||
*
|
||||
* @return array<string, array<int, mixed>>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'ids' => ['required', 'array', 'min:1', 'max:100'],
|
||||
'ids.*' => ['required', 'integer', 'min:1'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 유효성 검사 메시지
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'ids.required' => __('validation.required', ['attribute' => 'ID 목록']),
|
||||
'ids.array' => __('validation.array', ['attribute' => 'ID 목록']),
|
||||
'ids.min' => __('validation.min.array', ['attribute' => 'ID 목록', 'min' => 1]),
|
||||
'ids.max' => __('validation.max.array', ['attribute' => 'ID 목록', 'max' => 100]),
|
||||
'ids.*.required' => __('validation.required', ['attribute' => 'ID']),
|
||||
'ids.*.integer' => __('validation.integer', ['attribute' => 'ID']),
|
||||
'ids.*.min' => __('validation.min.numeric', ['attribute' => 'ID', 'min' => 1]),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 검증된 ID 배열 반환
|
||||
*
|
||||
* @return array<int, int>
|
||||
*/
|
||||
public function getIds(): array
|
||||
{
|
||||
return $this->validated('ids');
|
||||
}
|
||||
}
|
||||
@@ -365,6 +365,68 @@ public function issueStatement(int $id): array
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 거래명세서 일괄 발행
|
||||
*
|
||||
* @param array<int> $ids 발행할 매출 ID 배열
|
||||
* @return array{issued: int, failed: int, errors: array<int, string>}
|
||||
*/
|
||||
public function bulkIssueStatement(array $ids): array
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
$userId = $this->apiUserId();
|
||||
$results = [
|
||||
'issued' => 0,
|
||||
'failed' => 0,
|
||||
'errors' => [],
|
||||
];
|
||||
|
||||
$sales = Sale::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->whereIn('id', $ids)
|
||||
->get();
|
||||
|
||||
foreach ($sales as $sale) {
|
||||
try {
|
||||
// 확정된 매출만 거래명세서 발행 가능
|
||||
if ($sale->status !== 'confirmed') {
|
||||
$results['errors'][$sale->id] = __('error.sale.statement_requires_confirmed');
|
||||
$results['failed']++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// 이미 발행된 경우
|
||||
if ($sale->statement_issued_at !== null) {
|
||||
$results['errors'][$sale->id] = __('error.sale.statement_already_issued');
|
||||
$results['failed']++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// 발행 시간 기록
|
||||
$sale->statement_issued_at = now();
|
||||
$sale->statement_issued_by = $userId;
|
||||
$sale->save();
|
||||
|
||||
$results['issued']++;
|
||||
} catch (\Throwable $e) {
|
||||
$results['errors'][$sale->id] = $e->getMessage();
|
||||
$results['failed']++;
|
||||
}
|
||||
}
|
||||
|
||||
// 요청된 ID 중 찾지 못한 것들도 실패 처리
|
||||
$foundIds = $sales->pluck('id')->toArray();
|
||||
$notFoundIds = array_diff($ids, $foundIds);
|
||||
foreach ($notFoundIds as $notFoundId) {
|
||||
$results['errors'][$notFoundId] = __('error.sale.not_found');
|
||||
$results['failed']++;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 거래명세서 이메일 발송
|
||||
*/
|
||||
|
||||
@@ -195,6 +195,54 @@ public function issue(int $id): TaxInvoice
|
||||
return $this->barobillService->issueTaxInvoice($taxInvoice);
|
||||
}
|
||||
|
||||
/**
|
||||
* 세금계산서 일괄 발행
|
||||
*
|
||||
* @param array<int> $ids 발행할 세금계산서 ID 배열
|
||||
* @return array{issued: int, failed: int, errors: array<int, string>}
|
||||
*/
|
||||
public function bulkIssue(array $ids): array
|
||||
{
|
||||
$tenantId = $this->tenantId();
|
||||
$results = [
|
||||
'issued' => 0,
|
||||
'failed' => 0,
|
||||
'errors' => [],
|
||||
];
|
||||
|
||||
$taxInvoices = TaxInvoice::query()
|
||||
->where('tenant_id', $tenantId)
|
||||
->whereIn('id', $ids)
|
||||
->get();
|
||||
|
||||
foreach ($taxInvoices as $taxInvoice) {
|
||||
try {
|
||||
if (! $taxInvoice->canEdit()) {
|
||||
$results['errors'][$taxInvoice->id] = __('error.tax_invoice.already_issued');
|
||||
$results['failed']++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->barobillService->issueTaxInvoice($taxInvoice);
|
||||
$results['issued']++;
|
||||
} catch (\Throwable $e) {
|
||||
$results['errors'][$taxInvoice->id] = $e->getMessage();
|
||||
$results['failed']++;
|
||||
}
|
||||
}
|
||||
|
||||
// 요청된 ID 중 찾지 못한 것들도 실패 처리
|
||||
$foundIds = $taxInvoices->pluck('id')->toArray();
|
||||
$notFoundIds = array_diff($ids, $foundIds);
|
||||
foreach ($notFoundIds as $notFoundId) {
|
||||
$results['errors'][$notFoundId] = __('error.tax_invoice.not_found');
|
||||
$results['failed']++;
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* 세금계산서 취소
|
||||
*/
|
||||
|
||||
@@ -154,6 +154,29 @@
|
||||
* @OA\Property(property="sent_at", type="string", format="date-time", example="2025-01-15T10:30:00+09:00", description="발송일시"),
|
||||
* @OA\Property(property="statement_number", type="string", example="STSL202501150001", description="거래명세서 번호")
|
||||
* )
|
||||
*
|
||||
* @OA\Schema(
|
||||
* schema="SaleBulkIssueStatementRequest",
|
||||
* type="object",
|
||||
* required={"ids"},
|
||||
* description="거래명세서 일괄 발행 요청",
|
||||
*
|
||||
* @OA\Property(property="ids", type="array", minItems=1, maxItems=100, description="발행할 매출 ID 목록 (최대 100개)",
|
||||
* @OA\Items(type="integer", example=1)
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @OA\Schema(
|
||||
* schema="SaleBulkIssueStatementResponse",
|
||||
* type="object",
|
||||
* description="거래명세서 일괄 발행 응답",
|
||||
*
|
||||
* @OA\Property(property="issued", type="integer", example=8, description="발행 성공 건수"),
|
||||
* @OA\Property(property="failed", type="integer", example=2, description="발행 실패 건수"),
|
||||
* @OA\Property(property="errors", type="object", description="실패 상세 (ID: 에러메시지)",
|
||||
* @OA\AdditionalProperties(type="string", example="확정 상태가 아닌 매출입니다.")
|
||||
* )
|
||||
* )
|
||||
*/
|
||||
class SaleApi
|
||||
{
|
||||
@@ -514,4 +537,41 @@ public function issueStatement() {}
|
||||
* )
|
||||
*/
|
||||
public function sendStatement() {}
|
||||
|
||||
/**
|
||||
* @OA\Post(
|
||||
* path="/api/v1/sales/bulk-issue-statement",
|
||||
* tags={"Sales"},
|
||||
* summary="거래명세서 일괄 발행",
|
||||
* description="여러 매출에 대한 거래명세서를 일괄 발행합니다. 확정(confirmed) 상태이면서 아직 발행되지 않은 건만 발행됩니다. 각 건별로 성공/실패가 처리됩니다.",
|
||||
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
|
||||
*
|
||||
* @OA\RequestBody(
|
||||
* required=true,
|
||||
*
|
||||
* @OA\JsonContent(ref="#/components/schemas/SaleBulkIssueStatementRequest")
|
||||
* ),
|
||||
*
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="일괄 발행 처리 완료",
|
||||
*
|
||||
* @OA\JsonContent(
|
||||
* allOf={
|
||||
*
|
||||
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
|
||||
* @OA\Schema(
|
||||
*
|
||||
* @OA\Property(property="data", ref="#/components/schemas/SaleBulkIssueStatementResponse")
|
||||
* )
|
||||
* }
|
||||
* )
|
||||
* ),
|
||||
*
|
||||
* @OA\Response(response=400, description="잘못된 요청", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||
* @OA\Response(response=500, description="서버 에러", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||||
* )
|
||||
*/
|
||||
public function bulkIssueStatement() {}
|
||||
}
|
||||
|
||||
@@ -171,6 +171,29 @@
|
||||
* )
|
||||
*
|
||||
* @OA\Schema(
|
||||
* schema="TaxInvoiceBulkIssueRequest",
|
||||
* type="object",
|
||||
* required={"ids"},
|
||||
* description="세금계산서 일괄 발행 요청",
|
||||
*
|
||||
* @OA\Property(property="ids", type="array", minItems=1, maxItems=100, description="발행할 세금계산서 ID 목록 (최대 100개)",
|
||||
* @OA\Items(type="integer", example=1)
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @OA\Schema(
|
||||
* schema="TaxInvoiceBulkIssueResponse",
|
||||
* type="object",
|
||||
* description="세금계산서 일괄 발행 응답",
|
||||
*
|
||||
* @OA\Property(property="issued", type="integer", example=8, description="발행 성공 건수"),
|
||||
* @OA\Property(property="failed", type="integer", example=2, description="발행 실패 건수"),
|
||||
* @OA\Property(property="errors", type="object", description="실패 상세 (ID: 에러메시지)",
|
||||
* @OA\AdditionalProperties(type="string", example="이미 발행된 세금계산서입니다.")
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @OA\Schema(
|
||||
* schema="TaxInvoiceSummary",
|
||||
* type="object",
|
||||
* description="세금계산서 요약 통계",
|
||||
@@ -525,4 +548,41 @@ public function cancel() {}
|
||||
* )
|
||||
*/
|
||||
public function checkStatus() {}
|
||||
|
||||
/**
|
||||
* @OA\Post(
|
||||
* path="/api/v1/tax-invoices/bulk-issue",
|
||||
* tags={"TaxInvoices"},
|
||||
* summary="세금계산서 일괄 발행",
|
||||
* description="여러 세금계산서를 일괄 발행합니다. 바로빌 API를 통해 전자세금계산서가 발행됩니다. 임시저장(draft) 상태인 건만 발행되며, 각 건별로 성공/실패가 처리됩니다.",
|
||||
* security={{"ApiKeyAuth":{}},{"BearerAuth":{}}},
|
||||
*
|
||||
* @OA\RequestBody(
|
||||
* required=true,
|
||||
*
|
||||
* @OA\JsonContent(ref="#/components/schemas/TaxInvoiceBulkIssueRequest")
|
||||
* ),
|
||||
*
|
||||
* @OA\Response(
|
||||
* response=200,
|
||||
* description="일괄 발행 처리 완료",
|
||||
*
|
||||
* @OA\JsonContent(
|
||||
* allOf={
|
||||
*
|
||||
* @OA\Schema(ref="#/components/schemas/ApiResponse"),
|
||||
* @OA\Schema(
|
||||
*
|
||||
* @OA\Property(property="data", ref="#/components/schemas/TaxInvoiceBulkIssueResponse")
|
||||
* )
|
||||
* }
|
||||
* )
|
||||
* ),
|
||||
*
|
||||
* @OA\Response(response=400, description="잘못된 요청", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||
* @OA\Response(response=401, description="인증 실패", @OA\JsonContent(ref="#/components/schemas/ErrorResponse")),
|
||||
* @OA\Response(response=500, description="서버 에러", @OA\JsonContent(ref="#/components/schemas/ErrorResponse"))
|
||||
* )
|
||||
*/
|
||||
public function bulkIssue() {}
|
||||
}
|
||||
|
||||
@@ -102,4 +102,19 @@
|
||||
'deleted' => 'Order has been deleted.',
|
||||
'status_updated' => 'Order status has been updated.',
|
||||
],
|
||||
|
||||
// Sale Management
|
||||
'sale' => [
|
||||
'confirmed' => 'Sale has been confirmed.',
|
||||
'statement_issued' => 'Statement has been issued.',
|
||||
'statement_sent' => 'Statement has been sent.',
|
||||
'bulk_statement_issued' => 'Statements have been issued in bulk.',
|
||||
],
|
||||
|
||||
// Tax Invoice Management
|
||||
'tax_invoice' => [
|
||||
'issued' => 'Tax invoice has been issued.',
|
||||
'cancelled' => 'Tax invoice has been cancelled.',
|
||||
'bulk_issued' => 'Tax invoices have been issued in bulk.',
|
||||
],
|
||||
];
|
||||
|
||||
@@ -254,6 +254,25 @@
|
||||
'no_base_salary' => '기본급이 설정되지 않았습니다.',
|
||||
],
|
||||
|
||||
// 세금계산서 관련
|
||||
'tax_invoice' => [
|
||||
'not_found' => '세금계산서 정보를 찾을 수 없습니다.',
|
||||
'cannot_edit' => '발행된 세금계산서는 수정할 수 없습니다.',
|
||||
'cannot_delete' => '발행된 세금계산서는 삭제할 수 없습니다.',
|
||||
'already_issued' => '이미 발행된 세금계산서입니다.',
|
||||
],
|
||||
|
||||
// 매출 관련
|
||||
'sale' => [
|
||||
'not_found' => '매출 정보를 찾을 수 없습니다.',
|
||||
'cannot_edit' => '확정된 매출은 수정할 수 없습니다.',
|
||||
'cannot_delete' => '확정된 매출은 삭제할 수 없습니다.',
|
||||
'cannot_confirm' => '이미 확정된 매출입니다.',
|
||||
'statement_requires_confirmed' => '확정된 매출만 거래명세서를 발행할 수 있습니다.',
|
||||
'statement_already_issued' => '이미 발행된 거래명세서입니다.',
|
||||
'recipient_email_required' => '수신자 이메일이 필요합니다.',
|
||||
],
|
||||
|
||||
// 대시보드 관련
|
||||
'dashboard' => [
|
||||
'invalid_period' => '기간은 week, month, quarter 중 하나여야 합니다.',
|
||||
@@ -399,4 +418,13 @@
|
||||
'cannot_delete' => '해당 입찰은 삭제할 수 없습니다.',
|
||||
'invalid_status' => '유효하지 않은 입찰 상태입니다.',
|
||||
],
|
||||
|
||||
// 계약 관련
|
||||
'contract' => [
|
||||
'not_found' => '계약을 찾을 수 없습니다.',
|
||||
'already_registered' => '이미 계약이 등록된 입찰입니다. (계약번호: :code)',
|
||||
'bidding_not_awarded' => '낙찰 상태인 입찰만 계약으로 전환할 수 있습니다.',
|
||||
'cannot_delete' => '해당 계약은 삭제할 수 없습니다.',
|
||||
'invalid_status' => '유효하지 않은 계약 상태입니다.',
|
||||
],
|
||||
];
|
||||
|
||||
@@ -298,6 +298,14 @@
|
||||
'confirmed' => '매출이 확정되었습니다.',
|
||||
'statement_issued' => '거래명세서가 발행되었습니다.',
|
||||
'statement_sent' => '거래명세서가 발송되었습니다.',
|
||||
'bulk_statement_issued' => '거래명세서가 일괄 발행되었습니다.',
|
||||
],
|
||||
|
||||
// 세금계산서 관리
|
||||
'tax_invoice' => [
|
||||
'issued' => '세금계산서가 발행되었습니다.',
|
||||
'cancelled' => '세금계산서가 취소되었습니다.',
|
||||
'bulk_issued' => '세금계산서가 일괄 발행되었습니다.',
|
||||
],
|
||||
|
||||
// 급여 관리
|
||||
@@ -459,4 +467,15 @@
|
||||
'production_order_reverted' => '생산지시가 되돌려졌습니다.',
|
||||
'order_confirmation_reverted' => '수주확정이 취소되었습니다.',
|
||||
],
|
||||
|
||||
// 입찰관리
|
||||
'bidding' => [
|
||||
'fetched' => '입찰을 조회했습니다.',
|
||||
'created' => '입찰이 등록되었습니다.',
|
||||
'updated' => '입찰이 수정되었습니다.',
|
||||
'deleted' => '입찰이 삭제되었습니다.',
|
||||
'bulk_deleted' => '입찰이 일괄 삭제되었습니다.',
|
||||
'status_updated' => '입찰 상태가 변경되었습니다.',
|
||||
'converted' => '견적이 입찰로 변환되었습니다.',
|
||||
],
|
||||
];
|
||||
|
||||
@@ -450,6 +450,7 @@
|
||||
Route::get('/stats', [ContractController::class, 'stats'])->name('v1.construction.contracts.stats');
|
||||
Route::get('/stage-counts', [ContractController::class, 'stageCounts'])->name('v1.construction.contracts.stage-counts');
|
||||
Route::delete('/bulk', [ContractController::class, 'bulkDestroy'])->name('v1.construction.contracts.bulk-destroy');
|
||||
Route::post('/from-bidding/{biddingId}', [ContractController::class, 'storeFromBidding'])->whereNumber('biddingId')->name('v1.construction.contracts.store-from-bidding');
|
||||
Route::get('/{id}', [ContractController::class, 'show'])->whereNumber('id')->name('v1.construction.contracts.show');
|
||||
Route::put('/{id}', [ContractController::class, 'update'])->whereNumber('id')->name('v1.construction.contracts.update');
|
||||
Route::delete('/{id}', [ContractController::class, 'destroy'])->whereNumber('id')->name('v1.construction.contracts.destroy');
|
||||
@@ -679,6 +680,7 @@
|
||||
Route::get('/{id}/statement', [SaleController::class, 'getStatement'])->whereNumber('id')->name('v1.sales.statement.show');
|
||||
Route::post('/{id}/statement/issue', [SaleController::class, 'issueStatement'])->whereNumber('id')->name('v1.sales.statement.issue');
|
||||
Route::post('/{id}/statement/send', [SaleController::class, 'sendStatement'])->whereNumber('id')->name('v1.sales.statement.send');
|
||||
Route::post('/bulk-issue-statement', [SaleController::class, 'bulkIssueStatement'])->name('v1.sales.bulk-issue-statement');
|
||||
});
|
||||
|
||||
// Purchase API (매입 관리)
|
||||
@@ -746,6 +748,7 @@
|
||||
Route::post('/{id}/issue', [TaxInvoiceController::class, 'issue'])->whereNumber('id')->name('v1.tax-invoices.issue');
|
||||
Route::post('/{id}/cancel', [TaxInvoiceController::class, 'cancel'])->whereNumber('id')->name('v1.tax-invoices.cancel');
|
||||
Route::get('/{id}/check-status', [TaxInvoiceController::class, 'checkStatus'])->whereNumber('id')->name('v1.tax-invoices.check-status');
|
||||
Route::post('/bulk-issue', [TaxInvoiceController::class, 'bulkIssue'])->name('v1.tax-invoices.bulk-issue');
|
||||
});
|
||||
|
||||
// Bad Debt API (악성채권 추심관리)
|
||||
|
||||
Reference in New Issue
Block a user