From 6477cd8f782286cacc878327970328d2f831a39f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B6=8C=ED=98=81=EC=84=B1?= Date: Thu, 22 Jan 2026 19:17:34 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=88=98=EC=A3=BC=ED=99=95=EC=A0=95=20?= =?UTF-8?q?=EC=8B=9C=20=EB=A7=A4=EC=B6=9C=20=EC=9E=90=EB=8F=99=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - updateStatus 메서드에서 CONFIRMED 전환 시 매출 자동 생성 - sales_recognition = 'on_order_confirm' 설정된 수주만 해당 - createSaleFromOrder() 메서드 추가 (수주→매출 변환) - generateSaleNumber() 메서드 추가 (SAL-YYYYMM-NNNN 형식) - 생성된 매출은 order.sale_id에 자동 연결 Co-Authored-By: Claude Opus 4.5 --- app/Services/OrderService.php | 63 ++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/app/Services/OrderService.php b/app/Services/OrderService.php index 0d4d2dd..7c17250 100644 --- a/app/Services/OrderService.php +++ b/app/Services/OrderService.php @@ -275,11 +275,66 @@ public function updateStatus(int $id, string $status) // 상태 전환 규칙 검증 $this->validateStatusTransition($order->status_code, $status); - $order->status_code = $status; - $order->updated_by = $userId; - $order->save(); + return DB::transaction(function () use ($order, $status, $userId) { + $createdSale = null; - return $order->load(['client:id,name', 'items']); + // 수주확정 시 매출 자동 생성 (sales_recognition = on_order_confirm인 경우) + if ($status === Order::STATUS_CONFIRMED && $order->shouldCreateSaleOnConfirm()) { + $createdSale = $this->createSaleFromOrder($order, $userId); + $order->sale_id = $createdSale->id; + } + + $order->status_code = $status; + $order->updated_by = $userId; + $order->save(); + + $result = $order->load(['client:id,name', 'items']); + + // 매출이 생성된 경우 응답에 포함 + if ($createdSale) { + $result->setAttribute('created_sale', $createdSale); + } + + return $result; + }); + } + + /** + * 수주에서 매출 생성 + */ + private function createSaleFromOrder(Order $order, int $userId): Sale + { + $saleNumber = $this->generateSaleNumber($order->tenant_id); + + $sale = Sale::createFromOrder($order, $saleNumber); + $sale->created_by = $userId; + $sale->save(); + + return $sale; + } + + /** + * 매출번호 자동 생성 + */ + private function generateSaleNumber(int $tenantId): string + { + $prefix = 'SAL'; + $yearMonth = now()->format('Ym'); + + // 해당 월 기준 마지막 번호 조회 + $lastNo = Sale::withoutGlobalScopes() + ->where('tenant_id', $tenantId) + ->where('sale_number', 'like', "{$prefix}-{$yearMonth}-%") + ->orderByDesc('sale_number') + ->value('sale_number'); + + if ($lastNo) { + $seq = (int) substr($lastNo, -4) + 1; + } else { + $seq = 1; + } + + return sprintf('%s-%s-%04d', $prefix, $yearMonth, $seq); } /**