feat: [sales] 영업 시나리오 상품선택에 프로모션 할인 기능 추가

- 개발비 할인 (비율/금액/전액면제), 구독료 할인, 무료기간, 메모
- 상품 변경 시 프로모션 최대값 자동 조절 (clampPromoValues)
- 프로모션 데이터 management options에 저장/로드
- 합계 영역에 프로모션 적용 금액, 절감액 표시
This commit is contained in:
김보곤
2026-03-14 16:53:13 +09:00
parent ced2161563
commit 23aa38baef
3 changed files with 309 additions and 5 deletions

View File

@@ -30,6 +30,13 @@ public function saveProducts(Request $request): JsonResponse
'products.*.category_id' => 'required|exists:codebridge.sales_product_categories,id',
'products.*.registration_fee' => 'required|numeric|min:0',
'products.*.subscription_fee' => 'required|numeric|min:0',
'promotion' => 'nullable|array',
'promotion.dev_discount_type' => 'nullable|string|in:percent,amount',
'promotion.dev_discount_amount' => 'nullable|numeric|min:0',
'promotion.dev_waive' => 'nullable|boolean',
'promotion.sub_discount_percent' => 'nullable|numeric|min:0|max:50',
'promotion.free_months' => 'nullable|integer|in:0,1,2,3,6',
'promotion.note' => 'nullable|string|max:200',
]);
// tenant_id 또는 prospect_id 중 하나는 필수
@@ -79,6 +86,16 @@ public function saveProducts(Request $request): JsonResponse
$totalRegistrationFee = SalesContractProduct::where('management_id', $management->id)
->sum('registration_fee');
$management->update(['total_registration_fee' => $totalRegistrationFee]);
// 프로모션 저장
if (! empty($validated['promotion'])) {
$opts = $management->options ?? [];
$opts['promotion'] = array_merge($validated['promotion'], [
'applied_at' => now()->toDateTimeString(),
'applied_by_user_id' => auth()->id(),
]);
$management->update(['options' => $opts]);
}
});
return response()->json([