quoteService->index($request->validated()); }, __('message.quote.fetched')); } /** * 견적 단건 조회 */ public function show(int $id) { return ApiResponse::handle(function () use ($id) { return $this->quoteService->show($id); }, __('message.quote.fetched')); } /** * 견적 생성 */ public function store(QuoteStoreRequest $request) { // DEBUG: 요청 데이터 로깅 Log::info('[QuoteController::store] 원본 요청:', [ 'author' => $request->input('author'), 'manager' => $request->input('manager'), 'contact' => $request->input('contact'), 'remarks' => $request->input('remarks'), ]); $validated = $request->validated(); // DEBUG: validated 데이터 로깅 Log::info('[QuoteController::store] validated 데이터:', [ 'author' => $validated['author'] ?? 'NOT_SET', 'manager' => $validated['manager'] ?? 'NOT_SET', 'contact' => $validated['contact'] ?? 'NOT_SET', 'remarks' => $validated['remarks'] ?? 'NOT_SET', ]); return ApiResponse::handle(function () use ($validated) { return $this->quoteService->store($validated); }, __('message.quote.created')); } /** * 견적 수정 */ public function update(QuoteUpdateRequest $request, int $id) { $validated = $request->validated(); // 🔍 디버깅: 요청 데이터 확인 \Log::info('🔍 [QuoteController::update] 요청 수신', [ 'id' => $id, 'raw_options_keys' => $request->input('options') ? array_keys($request->input('options')) : null, 'raw_options_detail_items_count' => $request->input('options.detail_items') ? count($request->input('options.detail_items')) : 0, 'validated_options_keys' => isset($validated['options']) ? array_keys($validated['options']) : null, 'validated_options_detail_items_count' => isset($validated['options']['detail_items']) ? count($validated['options']['detail_items']) : 0, ]); return ApiResponse::handle(function () use ($validated, $id) { return $this->quoteService->update($id, $validated); }, __('message.quote.updated')); } /** * 견적 삭제 */ public function destroy(int $id) { return ApiResponse::handle(function () use ($id) { $this->quoteService->destroy($id); return null; }, __('message.quote.deleted')); } /** * 견적 일괄 삭제 */ public function bulkDestroy(QuoteBulkDeleteRequest $request) { return ApiResponse::handle(function () use ($request) { $count = $this->quoteService->bulkDestroy($request->validated()['ids']); return ['deleted_count' => $count]; }, __('message.quote.bulk_deleted')); } /** * 견적 확정 */ public function finalize(int $id) { return ApiResponse::handle(function () use ($id) { return $this->quoteService->finalize($id); }, __('message.quote.finalized')); } /** * 견적 확정 취소 */ public function cancelFinalize(int $id) { return ApiResponse::handle(function () use ($id) { return $this->quoteService->cancelFinalize($id); }, __('message.quote.finalize_cancelled')); } /** * 수주 전환 */ public function convertToOrder(int $id) { return ApiResponse::handle(function () use ($id) { return $this->quoteService->convertToOrder($id); }, __('message.quote.converted')); } /** * 견적번호 미리보기 */ public function previewNumber(?string $productCategory = null) { return ApiResponse::handle(function () use ($productCategory) { return $this->numberService->preview($productCategory); }, __('message.fetched')); } /** * 자동산출 미리보기 */ public function calculate(QuoteCalculateRequest $request) { return ApiResponse::handle(function () use ($request) { $validated = $request->validated(); return $this->calculationService->calculate( $validated['inputs'] ?? $validated, $validated['product_category'] ?? null ); }, __('message.quote.calculated')); } /** * BOM 기반 자동산출 (10단계 디버깅 포함) * * React 견적등록 화면에서 완제품 코드와 입력 변수를 받아 * BOM 기반으로 품목/단가/금액을 계산합니다. */ public function calculateBom(QuoteBomCalculateRequest $request) { return ApiResponse::handle(function () use ($request) { return $this->calculationService->calculateBom( $request->finished_goods_code, $request->getInputVariables(), $request->boolean('debug', false) ); }, __('message.quote.calculated')); } /** * 다건 BOM 기반 자동산출 * * React 견적등록 화면에서 여러 품목의 완제품 코드와 입력 변수를 받아 * BOM 기반으로 일괄 계산합니다. * React QuoteFormItem 필드명(camelCase)과 API 변수명(약어) 모두 지원합니다. */ public function calculateBomBulk(QuoteBomBulkCalculateRequest $request) { return ApiResponse::handle(function () use ($request) { return $this->calculationService->calculateBomBulk( $request->getInputItems(), $request->boolean('debug', false) ); }, __('message.quote.bulk_calculated')); } /** * 자동산출 입력 스키마 조회 */ public function calculationSchema(?string $productCategory = null) { return ApiResponse::handle(function () use ($productCategory) { return $this->calculationService->getInputSchema($productCategory); }, __('message.fetched')); } /** * 견적서 PDF 생성 */ public function generatePdf(int $id) { return ApiResponse::handle(function () use ($id) { return $this->documentService->generatePdf($id); }, __('message.quote.pdf_generated')); } /** * 견적서 이메일 발송 */ public function sendEmail(QuoteSendEmailRequest $request, int $id) { return ApiResponse::handle(function () use ($request, $id) { return $this->documentService->sendEmail($id, $request->validated()); }, __('message.quote_email_sent')); } /** * 견적서 카카오톡 발송 */ public function sendKakao(QuoteSendKakaoRequest $request, int $id) { return ApiResponse::handle(function () use ($request, $id) { return $this->documentService->sendKakao($id, $request->validated()); }, __('message.quote_kakao_sent')); } /** * 발송 이력 조회 */ public function sendHistory(int $id) { return ApiResponse::handle(function () use ($id) { return $this->documentService->getSendHistory($id); }, __('message.fetched')); } }