| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- <?php
- namespace Longyi\RewardPoints\Http\Controllers\Admin;
- use Exception;
- use Illuminate\Http\JsonResponse;
- use Illuminate\Http\RedirectResponse;
- use Illuminate\Http\Request;
- use Illuminate\Validation\Rule;
- use Illuminate\View\View;
- use Longyi\RewardPoints\Models\RewardActiveRule;
- use Longyi\RewardPoints\Repositories\RewardPointRepository;
- use Webkul\Admin\Http\Controllers\Controller;
- use Webkul\Core\Models\Channel;
- use Webkul\Customer\Models\CustomerGroup;
- class RuleController extends Controller
- {
- /**
- * Transaction type mapping with complete configuration
- */
- private const TRANSACTION_TYPES = [
- 3 => ['name' => 'Order', 'icon' => 'icon-shopping-cart', 'color' => 'blue'],
- 2 => ['name' => 'Registration', 'icon' => 'icon-user', 'color' => 'green'],
- 4 => ['name' => 'Product Review', 'icon' => 'icon-star', 'color' => 'yellow'],
- 9 => ['name' => 'Login', 'icon' => 'icon-calendar', 'color' => 'purple'],
- 5 => ['name' => 'Referral', 'icon' => 'icon-share', 'color' => 'indigo'],
- 6 => ['name' => 'Birthday', 'icon' => 'icon-gift', 'color' => 'pink'],
- 7 => ['name' => 'Share', 'icon' => 'icon-share-alt', 'color' => 'orange'],
- 8 => ['name' => 'Subscribe', 'icon' => 'icon-envelope', 'color' => 'orange'],
- ];
- /**
- * Valid transaction type IDs
- */
- private const VALID_TRANSACTION_TYPES = [1, 2, 3, 4, 5, 6, 7, 8];
- /**
- * Color classes mapping for transaction types
- */
- private const COLOR_CLASSES = [
- 'blue' => 'bg-blue-100 dark:bg-blue-900 text-blue-700 dark:text-blue-300',
- 'green' => 'bg-green-100 dark:bg-green-900 text-green-700 dark:text-green-300',
- 'yellow' => 'bg-yellow-100 dark:bg-yellow-900 text-yellow-700 dark:text-yellow-300',
- 'purple' => 'bg-purple-100 dark:bg-purple-900 text-purple-700 dark:text-purple-300',
- 'indigo' => 'bg-indigo-100 dark:bg-indigo-900 text-indigo-700 dark:text-indigo-300',
- 'pink' => 'bg-pink-100 dark:bg-pink-900 text-pink-700 dark:text-pink-300',
- 'orange' => 'bg-orange-100 dark:bg-orange-900 text-orange-700 dark:text-orange-300',
- 'gray' => 'bg-gray-100 dark:bg-gray-800 text-gray-500 dark:text-gray-400',
- ];
- protected RewardPointRepository $rewardPointRepository;
- protected array $_config;
- public function __construct(RewardPointRepository $rewardPointRepository)
- {
- $this->rewardPointRepository = $rewardPointRepository;
- $this->_config = request('_config', []);
- }
- /**
- * Display a listing of reward rules
- */
- public function index(): View
- {
- $rules = RewardActiveRule::query()
- ->orderBy('rule_id', 'desc')
- ->paginate(15);
- $customerGroupsList = $this->getCustomerGroups();
- $transactionTypes = self::TRANSACTION_TYPES;
- $colorClasses = self::COLOR_CLASSES;
- $view = $this->_config['view'] ?? 'rewardpoints::admin.rules.index';
- return view($view, compact('rules', 'customerGroupsList', 'transactionTypes', 'colorClasses'));
- }
- /**
- * Show the form for creating a new reward rule
- */
- public function create(): View
- {
- $view = $this->_config['view'] ?? 'rewardpoints::admin.rules.create';
- return view($view, [
- 'transactionTypes' => self::TRANSACTION_TYPES,
- 'storeViews' => $this->getStoreViews(),
- 'customerGroups' => $this->getCustomerGroups(),
- 'colorClasses' => self::COLOR_CLASSES,
- ]);
- }
- /**
- * Show the form for editing the specified reward rule
- */
- public function edit(int $id): View
- {
- $rule = RewardActiveRule::findOrFail($id);
- // 处理 Store Views 数据
- $selectedStoreViews = $this->parseStoreViews($rule);
- // 如果规则适用于所有店铺(store_view = '0'),则转换为 'all' 选项
- $selectedStoreViewsForSelect = [];
- if ($rule->store_view === '0' || empty($selectedStoreViews)) {
- $selectedStoreViewsForSelect = ['all'];
- } else {
- $selectedStoreViewsForSelect = $selectedStoreViews;
- }
- // 处理客户群组数据
- $selectedCustomerGroupsArray = $this->parseCustomerGroups($rule);
- $selectedCustomerGroupsPoints = $rule->enable_different_points_by_group
- ? (json_decode($rule->customer_group_ids, true) ?: [])
- : [];
- $view = $this->_config['view'] ?? 'rewardpoints::admin.rules.edit';
- return view($view, [
- 'rule' => $rule,
- 'transactionTypes' => self::TRANSACTION_TYPES,
- 'storeViews' => $this->getStoreViews(),
- 'customerGroups' => $this->getCustomerGroups(),
- 'selectedStoreViewsForSelect' => $selectedStoreViewsForSelect,
- 'selectedCustomerGroupsArray' => $selectedCustomerGroupsArray,
- 'selectedCustomerGroupsPoints' => $selectedCustomerGroupsPoints,
- 'colorClasses' => self::COLOR_CLASSES,
- ]);
- }
- /**
- * Store a newly created reward rule
- */
- public function store(Request $request): RedirectResponse
- {
- $validated = $this->validateStoreRequest($request);
- try {
- $data = $this->prepareDataForSave($request, $validated);
- RewardActiveRule::create($data);
- session()->flash('success', 'Reward rule created successfully.');
- return $this->redirectToIndex();
- } catch (Exception $e) {
- session()->flash('error', 'Error creating reward rule: ' . $e->getMessage());
- return redirect()->back()->withInput();
- }
- }
- /**
- * Update the specified reward rule
- */
- public function update(Request $request, int $id): RedirectResponse
- {
- $validated = $this->validateUpdateRequest($request);
- $rule = RewardActiveRule::findOrFail($id);
- try {
- $data = $this->prepareDataForSave($request, $validated);
- // 确保 enable_different_points_by_group 字段被正确设置
- $data['enable_different_points_by_group'] = $request->boolean('enable_different_points_by_group');
- $rule->update($data);
- session()->flash('success', 'Reward rule updated successfully.');
- return $this->redirectToIndex();
- } catch (Exception $e) {
- session()->flash('error', 'Error updating reward rule: ' . $e->getMessage());
- return redirect()->back()->withInput();
- }
- }
- /**
- * Remove the specified reward rule
- */
- public function destroy(int $id): JsonResponse|RedirectResponse
- {
- try {
- $rule = RewardActiveRule::findOrFail($id);
- $rule->delete();
- $message = 'Reward rule deleted successfully.';
- session()->flash('success', $message);
- if (request()->ajax()) {
- return response()->json(['status' => true, 'message' => $message]);
- }
- return $this->redirectToIndex();
- } catch (Exception $e) {
- $message = 'Error deleting reward rule: ' . $e->getMessage();
- session()->flash('error', $message);
- if (request()->ajax()) {
- return response()->json(['status' => false, 'message' => 'Error deleting reward rule.'], 500);
- }
- return $this->redirectToIndex()->with('error', $message);
- }
- }
- /**
- * Update rule status
- */
- public function updateStatus(int $id, Request $request): JsonResponse
- {
- try {
- $rule = RewardActiveRule::findOrFail($id);
- $rule->status = $request->input('status', 0);
- $rule->save();
- return response()->json([
- 'status' => true,
- 'message' => 'Rule status updated successfully.',
- ]);
- } catch (Exception $e) {
- return response()->json([
- 'status' => false,
- 'message' => 'Error updating rule status.',
- ], 500);
- }
- }
- /**
- * Validate store request
- */
- private function validateStoreRequest(Request $request): array
- {
- $rules = [
- 'rule_name' => 'required|string|max:255',
- 'type_of_transaction' => ['required', 'integer', Rule::in(self::VALID_TRANSACTION_TYPES)],
- 'status' => 'required|boolean',
- 'enable_different_points_by_group' => 'nullable|boolean',
- 'expired_day' => 'nullable|integer|min:0',
- 'comment' => 'nullable|string|max:500',
- 'store_view' => 'nullable|array',
- 'store_view.*' => 'nullable|string',
- ];
- return $request->validate($rules);
- }
- /**
- * Validate update request
- */
- private function validateUpdateRequest(Request $request): array
- {
- $rules = [
- 'rule_name' => 'required|string|max:255',
- 'type_of_transaction' => ['required', 'integer', Rule::in(self::VALID_TRANSACTION_TYPES)],
- 'status' => 'required|boolean',
- 'enable_different_points_by_group' => 'nullable|boolean',
- 'default_expired' => 'nullable|boolean',
- 'expired_day' => 'nullable|integer|min:0',
- 'coupon_code' => 'nullable|string|max:255',
- 'comment' => 'nullable|string|max:500',
- 'store_view' => 'nullable|array',
- 'store_view.*' => 'nullable|string',
- ];
- return $request->validate($rules);
- }
- /**
- * Prepare data for saving
- */
- private function prepareDataForSave(Request $request, array $validated): array
- {
- $data = array_intersect_key($validated, array_flip([
- 'rule_name',
- 'type_of_transaction',
- 'default_expired',
- 'expired_day',
- 'date_event',
- 'comment',
- 'coupon_code',
- 'status',
- 'enable_different_points_by_group',
- ]));
- // Handle store views - 修复:确保正确处理 store_view
- $storeViews = $request->get('store_view', []);
- $data['store_view'] = $this->formatStoreViews($storeViews);
- // Handle points configuration
- $this->handlePointsConfiguration($request, $data);
- return $data;
- }
- /**
- * Format store views for database storage
- */
- private function formatStoreViews($storeViews): string
- {
- // 如果 storeViews 为空或为 '0',返回 '0' 表示所有店铺
- if (empty($storeViews) || $storeViews === '0') {
- return '0';
- }
- // 如果是单个值,直接返回
- if (is_scalar($storeViews) && !empty($storeViews)) {
- return (string)$storeViews;
- }
- return '0';
- }
- /**
- * Handle points configuration based on group settings
- */
- private function handlePointsConfiguration(Request $request, array &$data): void
- {
- if ($request->boolean('enable_different_points_by_group')) {
- $groupPoints = $request->get('group_points', []);
- // 确保 $groupPoints 是数组
- if (!is_array($groupPoints)) {
- $groupPoints = [];
- }
- // 过滤并处理群组积分数据,确保键是字符串或整数
- $filteredPoints = [];
- foreach ($groupPoints as $groupId => $points) {
- // 确保键是标量类型且不为空
- if (is_scalar($groupId) && !empty($groupId)) {
- // 确保积分值是数字
- $pointsValue = is_numeric($points) ? (int)$points : 0;
- if ($pointsValue >= 0) {
- $filteredPoints[(string)$groupId] = $pointsValue;
- }
- }
- }
- $data['customer_group_ids'] = !empty($filteredPoints) ? json_encode($filteredPoints) : '{}';
- $data['reward_point'] = 0;
- } else {
- $request->validate([
- 'reward_point' => 'required|integer|min:0',
- ]);
- $data['reward_point'] = (int)$request->get('reward_point');
- $data['customer_group_ids'] = $this->formatCustomerGroups($request->get('customer_group_ids', []));
- }
- }
- /**
- * Format customer groups for database storage
- */
- private function formatCustomerGroups($customerGroups): string
- {
- if (is_array($customerGroups) && !empty($customerGroups)) {
- // 过滤掉空值并确保所有值都是标量
- $filtered = [];
- foreach ($customerGroups as $groupId) {
- if (is_scalar($groupId) && !empty($groupId)) {
- $filtered[] = (string)$groupId;
- }
- }
- return !empty($filtered) ? implode(',', array_unique($filtered)) : '';
- }
- return '';
- }
- /**
- * Parse store views from rule
- */
- private function parseStoreViews(RewardActiveRule $rule): array
- {
- if ($rule->store_view && $rule->store_view !== '0') {
- $views = explode(',', $rule->store_view);
- // 过滤空值
- return array_filter($views, function($view) {
- return !empty($view);
- });
- }
- return [];
- }
- /**
- * Parse customer groups from rule
- */
- private function parseCustomerGroups(RewardActiveRule $rule): array
- {
- if ($rule->enable_different_points_by_group) {
- $decoded = json_decode($rule->customer_group_ids, true);
- if (is_array($decoded)) {
- // 确保解码后的数据格式正确
- $result = [];
- foreach ($decoded as $groupId => $points) {
- if (is_scalar($groupId) && !empty($groupId)) {
- $result[(string)$groupId] = is_numeric($points) ? (int)$points : 0;
- }
- }
- return $result;
- }
- return [];
- }
- if ($rule->customer_group_ids && $rule->customer_group_ids !== '') {
- $groups = explode(',', $rule->customer_group_ids);
- // 过滤空值
- return array_filter($groups, function($group) {
- return !empty($group);
- });
- }
- return [];
- }
- /**
- * Get all store views
- */
- protected function getStoreViews(): array
- {
- try {
- $channels = Channel::all();
- $storeViews = [];
- foreach ($channels as $channel) {
- $storeViews[$channel->code] = $channel->name;
- }
- return $storeViews;
- } catch (Exception $e) {
- return ['0' => 'All Stores'];
- }
- }
- /**
- * Get all customer groups
- */
- protected function getCustomerGroups(): array
- {
- try {
- $groups = CustomerGroup::orderBy('id')->get();
- $customerGroups = [];
- foreach ($groups as $group) {
- $customerGroups[$group->id] = $group->name;
- }
- return $customerGroups;
- } catch (Exception $e) {
- return ['0' => 'All Groups'];
- }
- }
- /**
- * Get transaction type configuration
- */
- public function getTransactionTypeConfig(): array
- {
- return self::TRANSACTION_TYPES;
- }
- /**
- * Get transaction type name
- */
- protected function getTransactionTypeName(int $typeId): string
- {
- return self::TRANSACTION_TYPES[$typeId]['name'] ?? 'Unknown';
- }
- /**
- * Get transaction type color classes
- */
- protected function getTransactionTypeColorClass(int $typeId): string
- {
- $color = self::TRANSACTION_TYPES[$typeId]['color'] ?? 'gray';
- return self::COLOR_CLASSES[$color] ?? self::COLOR_CLASSES['gray'];
- }
- /**
- * Redirect to index route
- */
- private function redirectToIndex(): RedirectResponse
- {
- $route = $this->_config['redirect'] ?? 'admin.reward-points.rules.index';
- return redirect()->route($route);
- }
- }
|