alias('pp') ->leftJoin('ba_package p', 'p.id = pp.package_id') ->where('pp.id', $packagePriceId) ->field('pp.*, p.name as package_name') ->find(); if (!$package) { throw new \Exception('套餐不存在'); } // 2. 如果是企业套餐,检查用户是否属于企业 if ($package['type'] == 2) { // 企业套餐 $companyInfo = $this->getUserCompany($userId); if (!$companyInfo) { throw new \Exception('只有企业成员才能购买企业套餐'); } // 3. 检查日期卡的最低购买数量 if ($package['is_date_card'] == 1 && $quantity < $package['min_quantity']) { throw new \Exception('企业日期卡至少需要购买' . $package['min_quantity'] . '份'); } return [ 'valid' => true, 'company_id' => $companyInfo['id'], 'company_name' => $companyInfo['name'], 'min_quantity' => $package['min_quantity'] ]; } return ['valid' => true, 'company_id' => null]; } catch (\Throwable $e) { Log::error('验证企业套餐购买资格失败: ' . $e->getMessage()); throw $e; } } /** * 获取用户所在企业 */ public function getUserCompany($userId) { // 检查用户是否是企业创建人 $company = Db::table('ba_company') ->where('creator_id', $userId) ->where('status', 1) ->field('id, name,creator_id') ->find(); if ($company) { return $company; } // 检查是否是成员 $member = Db::table('ba_company_member') ->alias('cm') ->leftJoin('ba_company c', 'c.id = cm.company_id') ->where('cm.user_id', $userId) ->where('cm.status', 1) ->where('c.status', 1) ->field('c.id, c.name') ->find(); return $member; } /** * 处理企业套餐购买(创建席位记录) */ public function processCompanyPackagePurchase($orderId, $companyId, $packagePriceId, $quantity, $cardType, $unitValue, $pointsValue) { Db::startTrans(); try { // 1. 获取或创建企业套餐席位记录 $seatsRecord = Db::table('ba_company_package_seats') ->where('company_id', $companyId) ->where('package_price_id', $packagePriceId) ->find(); if ($seatsRecord) { // 更新现有记录 $updateData = [ 'total_seats' => Db::raw('total_seats + ' . $quantity), 'available_seats' => Db::raw('available_seats + ' . $quantity), 'is_shared' => $cardType < 3 ? 1 : 0, // 次卡/积分卡为共享资源 'update_time' => date('Y-m-d H:i:s') ]; // 如果是次卡,累加次数 if ($cardType == 1) { $updateData['total_times'] = Db::raw('total_times + ' . ($unitValue * $quantity)); $updateData['remaining_times'] = Db::raw('remaining_times + ' . ($unitValue * $quantity)); } // 如果是积分卡,累加积分 if ($cardType == 2) { $updateData['total_points'] = Db::raw('total_points + ' . ($pointsValue * $quantity)); $updateData['remaining_points'] = Db::raw('remaining_points + ' . ($pointsValue * $quantity)); } Db::table('ba_company_package_seats') ->where('id', $seatsRecord['id']) ->update($updateData); $seatsId = $seatsRecord['id']; } else { // 创建新记录 $seatsData = [ 'company_id' => $companyId, 'package_price_id' => $packagePriceId, 'product_id' => $this->getProductIdByPackage($packagePriceId), 'total_seats' => $cardType < 3 ? 1000 : $quantity, 'assigned_seats' => 0, 'available_seats' => $cardType < 3 ? 1000 : $quantity, 'is_shared' => $cardType < 3 ? 1 : 0, // 次卡/积分卡为共享资源 'card_type' => $cardType, 'total_times' => $cardType == 1 ? $unitValue * $quantity : 0, 'remaining_times' => $cardType == 1 ? $unitValue * $quantity : 0, 'total_points' => $cardType == 2 ? $pointsValue * $quantity : 0, 'remaining_points' => $cardType == 2 ? $pointsValue * $quantity : 0, 'status' => 1, 'create_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s') ]; $seatsId = Db::table('ba_company_package_seats')->insertGetId($seatsData); } // 2. 获取购买者ID $buyerId = $this->getOrderBuyerId($orderId); // 3. 查询订单商品 $orderItems = Db::table('ba_order_item') ->where('order_id', $orderId) ->where('package_price_id', $packagePriceId) ->select(); foreach ($orderItems as $item) { if ($cardType >= 3) { // 日期卡:为每个购买的数量创建独立的分配记录 for ($i = 0; $i < $quantity; $i++) { $allocationData = [ 'order_item_id' => $item['id'], 'order_id' => $orderId, 'package_price_id' => $packagePriceId, 'product_id' => $item['product_id'], 'buyer_id' => $buyerId, 'company_id' => $companyId, 'assigned_to_user_id' => null, // 初始不分配 'assigned_by_user_id' => $buyerId, 'record_type' => 2, // 购买记录 'is_general' => 0, 'seat_index' => $i + 1, // 席位索引 'allocation_status' => 0, // 未分配 'allocation_time' => null, 'start_time' => null, 'end_time' => null, 'expire_time' => $this->calculateEndTime($cardType, date('Y-m-d H:i:s')), // 冗余字段 'remaining_times' => 0, // 日期卡没有次数 'remaining_points' => 0, // 日期卡没有积分 'is_used' => 0, 'create_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s') ]; $allocationId = Db::table('ba_company_package_allocation')->insertGetId($allocationData); } } else { // 次卡和积分卡: // 1. 创建通用记录(用于管理总资源) $generalAllocationData = [ 'order_item_id' => $item['id'], 'order_id' => $orderId, 'package_price_id' => $packagePriceId, 'product_id' => $item['product_id'], 'buyer_id' => $buyerId, 'company_id' => $companyId, 'assigned_to_user_id' => null, // 通用记录不分配 'assigned_by_user_id' => $buyerId, 'record_type' => 0, // 通用记录 'is_general' => 1, // 是通用记录 'seat_index' => 0, 'allocation_status' => 0, // 状态:通用记录 'allocation_time' => null, 'start_time' => null, 'end_time' => null, 'expire_time' => null, 'remaining_times' => $cardType == 1 ? $unitValue * $quantity : 0, 'remaining_points' => $cardType == 2 ? $pointsValue * $quantity : 0, 'is_used' => 0, 'create_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s') ]; $generalAllocationId = Db::table('ba_company_package_allocation')->insertGetId($generalAllocationData); // 2. 为购买者创建独立的分配记录 $buyerAllocationData = [ 'order_item_id' => $item['id'], 'order_id' => $orderId, 'package_price_id' => $packagePriceId, 'product_id' => $item['product_id'], 'buyer_id' => $buyerId, 'company_id' => $companyId, 'assigned_to_user_id' => $buyerId, 'assigned_by_user_id' => $buyerId, 'record_type' => 1, // 用户分配记录 'is_general' => 0, 'seat_index' => 0, 'parent_id' => $generalAllocationId, // 关联通用记录 'allocation_status' => 0, // 未分配 'allocation_time' => date('Y-m-d H:i:s'), 'start_time' => date('Y-m-d H:i:s'), 'end_time' => null, 'expire_time' => null, 'remaining_times' => $cardType == 1 ? $unitValue : 0, 'remaining_points' => $cardType == 2 ? $pointsValue : 0, 'is_used' => 0, 'create_time' => date('Y-m-d H:i:s'), 'update_time' => date('Y-m-d H:i:s') ]; $buyerAllocationId = Db::table('ba_company_package_allocation')->insertGetId($buyerAllocationData); // 3. 将购买者添加到授权列表 $seats = Db::table('ba_company_package_seats') ->where('id', $seatsId) ->find(); $authorizedUsers = json_decode($seats['authorized_users'] ?? '[]', true); if (!in_array($buyerId, $authorizedUsers)) { $authorizedUsers[] = $buyerId; Db::table('ba_company_package_seats') ->where('id', $seatsId) ->update([ 'authorized_users' => json_encode($authorizedUsers), 'assigned_member_count' => Db::raw('assigned_member_count + 1') ]); } } // 更新订单商品的分配记录ID(对于日期卡,记录第一个分配记录的ID) if ($cardType >= 3) { // 获取第一个分配记录ID $firstAllocation = Db::table('ba_company_package_allocation') ->where('order_item_id', $item['id']) ->where('record_type', 2) ->order('seat_index', 'asc') ->find(); if ($firstAllocation) { Db::table('ba_order_item') ->where('id', $item['id']) ->update(['allocation_id' => $firstAllocation['id']]); } } else { // 次卡/积分卡使用购买者分配记录ID Db::table('ba_order_item') ->where('id', $item['id']) ->update(['allocation_id' => $buyerAllocationId]); } } Db::commit(); return true; } catch (\Throwable $e) { Db::rollback(); Log::error('处理企业套餐购买失败: ' . $e->getMessage()); throw $e; } } /** * 获取可分配的企业套餐列表(区分类型) */ public function getAvailableCompanyPackages($companyId, $operatorId) { try { // 获取用户角色(创建者或成员) $isCreator = Db::table('ba_company') ->where('id', $companyId) ->where('creator_id', $operatorId) ->count() > 0; // 获取企业所有套餐席位 $seats = Db::table('ba_company_package_seats') ->alias('cs') ->leftJoin('ba_package_price pp', 'pp.id = cs.package_price_id') ->leftJoin('ba_product p', 'p.id = cs.product_id') ->leftJoin('ba_company_package_allocation pcs', 'pcs.package_price_id = pp.id') ->where('cs.company_id', $companyId) ->where('pcs.buyer_id', $operatorId) // ->where('cs.available_seats', '>', 0) ->where('cs.status', 1) ->field('cs.*, pp.spec_name, pp.card_type, pp.type as package_type, p.name as product_name, p.type as product_type, p.link,pp.image') ->group('pcs.package_price_id') ->select(); // 获取企业所有成员(包括创建者) $allMembers = $this->getAllCompanyMembers($companyId); // 处理数据 $result = []; foreach ($seats as $seat) { // 获取该套餐已分配的成员 $allocatedMembers = $this->getAllocatedMembersForPackage($companyId, $seat['package_price_id']); // 获取该套餐已分配的成员ID列表 $allocatedMemberIds = array_column($allocatedMembers, 'user_id'); // 筛选未分配的成员 $unallocatedMembers = []; foreach ($allMembers as $member) { if (!in_array($member['user_id'], $allocatedMemberIds)) { $unallocatedMembers[] = $member; } } // 组织返回数据 $seatItem = [ 'seats_id' => $seat['id'], 'product_id' => $seat['product_id'], 'product_name' => $seat['product_name'], 'product_type' => $seat['product_type'], // 1:网页,2:软件 'product_link' => $seat['link'], 'product_image' => $seat['image'], 'package_price_id' => $seat['package_price_id'], 'spec_name' => $seat['spec_name'], 'card_type' => $seat['card_type'], 'card_type_text' => $this->getCardTypeText($seat['card_type']), 'package_type' => $seat['package_type'], // 1个人,2企业 'total_seats' => $seat['total_seats'], 'assigned_seats' => $seat['assigned_seats'], 'available_seats' => $seat['available_seats'], // 次卡和积分卡相关 'total_times' => $seat['total_times'], 'remaining_times' => $seat['remaining_times'], 'total_points' => $seat['total_points'], 'remaining_points' => $seat['remaining_points'], 'end_time' => $seat['end_time'], // 已分配成员信息 'allocated_members' => $allocatedMembers, // 未分配成员信息 'unallocated_members' => $unallocatedMembers, // 统计信息 'allocated_count' => count($allocatedMembers), 'unallocated_count' => count($unallocatedMembers), 'total_members' => count($allMembers) ]; $result[] = $seatItem; } return [ 'packages' => $result, 'is_creator' => $isCreator, 'total_members' => count($allMembers) ]; } catch (\Throwable $e) { Log::error('获取可分配企业套餐失败: ' . $e->getMessage()); return [ 'packages' => [], 'is_creator' => false, 'total_members' => 0 ]; } } /** * 获取企业所有成员(包括创建者) */ private function getAllCompanyMembers($companyId) { $members = []; // 1. 获取企业创建者 $company = Db::table('ba_company') ->where('id', $companyId) ->field('id, name as company_name, creator_id') ->find(); if ($company && $company['creator_id']) { // 获取创建者用户信息 $creator = Db::table('ba_user') ->where('id', $company['creator_id']) ->field('id as user_id, nickname as member_name, avatar, email, mobile') ->find(); if ($creator) { $creator['is_creator'] = 1; $creator['role'] = 1; // 创建者/管理员 $members[] = $creator; } } // 2. 获取企业成员表中的成员 $companyMembers = Db::table('ba_company_member') ->alias('cm') ->leftJoin('ba_user u', 'u.id = cm.user_id') ->where('cm.company_id', $companyId) ->where('cm.status', 1) ->field(' cm.id as member_id, cm.user_id, COALESCE(cm.name, u.nickname) as member_name, COALESCE(cm.email, u.email) as email, u.avatar, u.mobile, cm.role ') ->select() ->toArray(); // 过滤掉重复的成员(创建者可能也在成员表中) foreach ($companyMembers as $member) { // 检查是否已经是创建者 $isCreator = false; foreach ($members as $existingMember) { if ($existingMember['user_id'] == $member['user_id']) { $isCreator = true; break; } } if (!$isCreator) { $member['is_creator'] = 0; $members[] = $member; } } return $members; } /** * 获取指定套餐已分配的成员 */ private function getAllocatedMembersForPackage($companyId, $packagePriceId) { // 获取套餐信息,判断卡类型 $package = Db::table('ba_package_price') ->where('id', $packagePriceId) ->field('card_type') ->find(); if (!$package) { return []; } $cardType = $package['card_type']; if ($cardType >= 3) { // 日期卡:从分配记录中获取已分配成员 return Db::table('ba_company_package_allocation') ->alias('cpa') ->leftJoin('ba_user u', 'u.id = cpa.assigned_to_user_id') ->leftJoin('ba_company_member cm', 'cm.user_id = cpa.assigned_to_user_id AND cm.company_id = cpa.company_id') ->where('cpa.company_id', $companyId) ->where('cpa.package_price_id', $packagePriceId) ->where('cpa.allocation_status', 1) // 已分配 ->whereNotNull('cpa.assigned_to_user_id') ->field(' cpa.assigned_to_user_id as user_id, COALESCE(cm.name, u.nickname) as member_name, COALESCE(cm.email, u.email) as email, u.avatar, u.mobile, cpa.id as allocation_id, cpa.allocation_time, cpa.start_time, cpa.end_time, cpa.remaining_times, cpa.remaining_points ') ->select() ->toArray(); } else { // 次卡/积分卡:从席位表的授权用户列表中获取 $seats = Db::table('ba_company_package_seats') ->where('company_id', $companyId) ->where('package_price_id', $packagePriceId) ->field('authorized_users') ->find(); if (!$seats || empty($seats['authorized_users'])) { return []; } $authorizedUserIds = json_decode($seats['authorized_users'], true); if (empty($authorizedUserIds)) { return []; } // 获取授权用户的详细信息 $where[]=['cp.record_type','<>',0]; $user=Db::table('ba_user') ->alias('u') // 使用字符串条件替代闭包 ->leftJoin('ba_company_member cm', 'cm.user_id = u.id AND cm.company_id = ' . $companyId) ->leftJoin('ba_company_package_allocation cp', 'u.id = cp.assigned_to_user_id') ->whereIn('u.id', $authorizedUserIds) ->where('cp.allocation_status',1) ->where($where) ->where('cp.package_price_id',$packagePriceId) ->field(' u.id as user_id, COALESCE(cm.name, u.nickname) as member_name, COALESCE(cm.email, u.email) as email, u.avatar, cp.id as allocation_id, u.mobile, cm.role ') ->select() ->toArray(); // dump($user);die; return $user; } } /** * 分配套餐给企业成员 */ public function allocatePackage($seatsId, $assignedToUserId, $operatorId, $remark = '') { Db::startTrans(); try { // 1. 获取席位信息 $seats = Db::table('ba_company_package_seats') ->where('id', $seatsId) ->lock(true) ->find(); if (!$seats || $seats['available_seats'] <= 0) { throw new \Exception('没有可用席位'); } // 2. 检查是否是日期卡 if ($seats['card_type'] < 3) { throw new \Exception('非日期卡类型,请使用assignPackagePermission方法'); } // 3. 检查权限(只有创建者可以分配其他人的,成员只能分配自己的) $isCreator = Db::table('ba_company') ->where('id', $seats['company_id']) ->where('creator_id', $operatorId) ->count() > 0; // 4. 获取一个未分配的购买记录 $availableAllocation = Db::table('ba_company_package_allocation') ->where('company_id', $seats['company_id']) ->where('package_price_id', $seats['package_price_id']) ->where('record_type', 2) // 购买记录 ->whereIn('allocation_status', [0,2]) // 未分配 ->where('assigned_to_user_id', null) // 未指定用户 ->lock(true) ->order('seat_index', 'asc') // 按席位索引排序 ->find(); if (!$availableAllocation) { throw new \Exception('没有可分配的套餐记录'); } // 如果不是创建者,检查是否是购买者 if (!$isCreator && $availableAllocation['buyer_id'] != $operatorId) { throw new \Exception('您只能分配自己购买的套餐'); } // 5. 检查成员是否属于该企业 $isMember = Db::table('ba_company_member') ->where('company_id', $seats['company_id']) ->where('user_id', $assignedToUserId) ->where('status', 1) ->count() > 0; if (!$isMember) { throw new \Exception('该用户不是企业成员'); } // 6. 检查该成员是否已分配此套餐(日期卡只能分配给一个成员) if ($seats['card_type'] >= 3) { // 日期卡 $alreadyAllocated = Db::table('ba_company_package_allocation') ->where('company_id', $seats['company_id']) ->where('package_price_id', $seats['package_price_id']) ->where('assigned_to_user_id', $assignedToUserId) ->where('allocation_status', 1) ->count(); if ($alreadyAllocated > 0) { throw new \Exception('该成员已分配此套餐,如需再次分配请重新购买'); } } // 7. 执行分配 $now = date('Y-m-d H:i:s'); // 计算到期时间 $endTime = $this->calculateEndTime($seats['card_type'], $now); // 更新分配记录 Db::table('ba_company_package_allocation') ->where('id', $availableAllocation['id']) ->update([ 'assigned_to_user_id' => $assignedToUserId, 'assigned_by_user_id' => $operatorId, 'allocation_status' => 1, 'allocation_time' => $now, 'start_time' => $now, 'end_time' => $endTime, 'expire_time' => $endTime, // 更新冗余字段 'update_time' => $now ]); // 8.更新席位表 Db::table('ba_company_package_seats') ->where('id', $seatsId) ->update([ 'assigned_seats' => Db::raw('assigned_seats + 1'), 'available_seats' => Db::raw('available_seats - 1'), 'update_time' => $now ]); // 9. 检查是否所有席位都已分配 $unallocatedCount = Db::table('ba_company_package_allocation') ->where('order_item_id', $availableAllocation['order_item_id']) ->where('allocation_status', 0) ->where('record_type', 2) ->count(); if ($unallocatedCount == 0) { // 所有席位都已分配,更新订单商品 Db::table('ba_order_item') ->where('id', $availableAllocation['order_item_id']) ->update([ 'is_allocated' => 1, 'company_id' => $seats['company_id'] ]); } // 10. 为用户创建产品使用记录 $userProductService = new UserProductService(); $userProductService->createCompanyProductUsage($availableAllocation, $assignedToUserId, $seats['card_type']); // 11. 记录分配日志 Db::table('ba_allocation_log')->insert([ 'allocation_id' => $availableAllocation['id'], 'action' => 1, // 分配 'operator_id' => $operatorId, 'to_user_id' => $assignedToUserId, 'remark' => $remark, 'create_time' => $now ]); Db::commit(); return [ 'success' => true, 'allocation_id' => $availableAllocation['id'], 'message' => '分配成功' ]; } catch (\Throwable $e) { Db::rollback(); Log::error('分配套餐失败: ' . $e->getMessage()); throw $e; } } /** * 取消分配(日期卡独占席位模式) */ public function cancelAllocation($allocationId, $operatorId, $remark = '') { Db::startTrans(); try { // 1. 获取分配记录 $allocation = Db::table('ba_company_package_allocation') ->where('id', $allocationId) ->where('record_type', 2) // 购买记录 ->where('allocation_status', 1) // 已分配 ->lock(true) ->find(); if (!$allocation) { throw new \Exception('分配记录不存在或未分配'); } // 2. 检查权限 $isCreator = Db::table('ba_company') ->where('id', $allocation['company_id']) ->where('creator_id', $operatorId) ->count() > 0; if (!$isCreator && $allocation['assigned_by_user_id'] != $operatorId) { throw new \Exception('您没有取消分配的权限'); } // 3. 获取席位信息 $seats = Db::table('ba_company_package_seats') ->where('company_id', $allocation['company_id']) ->where('package_price_id', $allocation['package_price_id']) ->find(); if (!$seats) { throw new \Exception('企业套餐席位不存在'); } // 4. 执行取消分配 $now = date('Y-m-d H:i:s'); // 更新分配记录状态 Db::table('ba_company_package_allocation') ->where('id', $allocationId) ->update([ 'assigned_to_user_id' => null, 'allocation_status' => 2, 'cancel_allocation_time' => $now, 'update_time' => $now ]); // 5. 更新席位表 Db::table('ba_company_package_seats') ->where('id', $seats['id']) ->update([ 'assigned_seats' => Db::raw('assigned_seats - 1'), 'available_seats' => Db::raw('available_seats + 1'), 'update_time' => $now ]); // 6. 检查是否还有已分配的记录 $allocatedCount = Db::table('ba_company_package_allocation') ->where('order_item_id', $allocation['order_item_id']) ->where('allocation_status', 1) ->count(); if ($allocatedCount == 0) { // 没有已分配的记录,更新订单商品 Db::table('ba_order_item') ->where('id', $allocation['order_item_id']) ->update([ 'is_allocated' => 0, 'allocation_id' => null ]); } // 7. 删除对应的用户产品使用记录 Db::table('ba_user_product_usage') ->where('user_id', $allocation['assigned_to_user_id']) ->where('package_price_id', $allocation['package_price_id']) ->where('company_id', $allocation['company_id']) ->where('package_type', 2) // 企业套餐 ->delete(); // 8. 记录取消分配日志 Db::table('ba_allocation_log')->insert([ 'allocation_id' => $allocationId, 'action' => 2, // 取消分配 'operator_id' => $operatorId, 'from_user_id' => $allocation['assigned_to_user_id'], 'remark' => $remark, 'create_time' => $now ]); Db::commit(); return true; } catch (\Throwable $e) { Db::rollback(); Log::error('取消分配失败: ' . $e->getMessage()); throw $e; } } /** * 分配次卡/积分卡使用权限给成员(授权访问共享资源池) */ public function assignPackagePermission($seatsId, $memberUserId, $allocatorId, $remark = '') { Db::startTrans(); try { // 1. 获取席位信息 $seats = Db::table('ba_company_package_seats') ->where('id', $seatsId) ->lock(true) ->find(); if (!$seats) { throw new \Exception('企业套餐不存在'); } // 2. 检查权限(只有企业创建者或购买者可以分配) $canAssign = $this->checkAssignPermission($allocatorId, $seats['company_id'], $seatsId); if (!$canAssign) { throw new \Exception('没有分配权限'); } // 3. 检查成员是否属于企业 if (!$this->isCompanyMember($memberUserId, $seats['company_id'])) { throw new \Exception('该用户不是企业成员'); } // 4. 检查是否已经是次卡或积分卡 if (!in_array($seats['card_type'], [1, 2])) { throw new \Exception('只有次卡和积分卡支持权限分配'); } // 5. 检查该成员是否已被授权 $authorizedUsers = json_decode($seats['authorized_users'] ?? '[]', true); if (in_array($memberUserId, $authorizedUsers)) { throw new \Exception('该成员已被授权使用此套餐'); } // 6. 查找通用记录 $generalRecord = Db::table('ba_company_package_allocation') ->where('company_id', $seats['company_id']) ->where('package_price_id', $seats['package_price_id']) ->where('record_type', 0) // 通用记录 ->where('is_general', 1) // 是通用记录 ->order('id', 'asc') ->find(); if (!$generalRecord) { throw new \Exception('未找到套餐购买记录'); } // 7. 将成员添加到授权列表 $authorizedUsers[] = $memberUserId; Db::table('ba_company_package_seats') ->where('id', $seatsId) ->update([ 'authorized_users' => json_encode($authorizedUsers), 'assigned_member_count' => Db::raw('assigned_member_count + 1'), 'assigned_seats' => Db::raw('assigned_seats + 1'), 'available_seats' => Db::raw('available_seats - 1'), 'update_time' => date('Y-m-d H:i:s') ]); // 8. 检查是否存在已取消的分配记录 $now = date('Y-m-d H:i:s'); $allocationId = 0; // 查找该用户对于此套餐的已取消分配记录 $canceledAllocation = Db::table('ba_company_package_allocation') ->where('company_id', $seats['company_id']) ->where('package_price_id', $seats['package_price_id']) ->where('assigned_to_user_id', $memberUserId) ->where('record_type', 1) // 用户分配记录 ->where('allocation_status', 2) // 已取消状态 ->order('cancel_allocation_time', 'desc') // 取最新的取消记录 ->find(); if ($canceledAllocation) { // 8.1 更新已取消的记录为已分配状态 Db::table('ba_company_package_allocation') ->where('id', $canceledAllocation['id']) ->update([ 'order_item_id' => $generalRecord['order_item_id'], 'order_id' => $generalRecord['order_id'], 'package_price_id' => $seats['package_price_id'], 'product_id' => $seats['product_id'], 'buyer_id' => $generalRecord['buyer_id'], 'company_id' => $seats['company_id'], 'assigned_to_user_id' => $memberUserId, 'assigned_by_user_id' => $allocatorId, 'record_type' => 1, // 用户分配记录 'is_general' => 0, 'parent_id' => $generalRecord['id'], 'allocation_status' => 1, // 更新为已分配 'allocation_time' => $now, 'cancel_allocation_time' => null, // 清除取消时间 'start_time' => $now, 'end_time' => null, 'expire_time' => null, 'remaining_times' => $seats['remaining_times'], 'remaining_points' => $seats['remaining_points'], 'is_used' => 0, 'usage_count' => $canceledAllocation['usage_count'] ?? 0, // 保留原有使用次数 'update_time' => $now ]); $allocationId = $canceledAllocation['id']; Log::info('复用已取消的分配记录', [ 'allocation_id' => $allocationId, 'member_user_id' => $memberUserId, 'package_price_id' => $seats['package_price_id'], 'company_id' => $seats['company_id'] ]); } else { // 8.2 创建新的分配记录 $newAllocationData = [ 'order_item_id' => $generalRecord['order_item_id'], 'order_id' => $generalRecord['order_id'], 'package_price_id' => $seats['package_price_id'], 'product_id' => $seats['product_id'], 'buyer_id' => $generalRecord['buyer_id'], 'company_id' => $seats['company_id'], 'assigned_to_user_id' => $memberUserId, 'assigned_by_user_id' => $allocatorId, 'record_type' => 1, // 用户分配记录 'is_general' => 0, 'seat_index' => 0, 'parent_id' => $generalRecord['id'], // 关联通用记录 'allocation_status' => 1, // 已分配 'allocation_time' => $now, 'start_time' => $now, 'end_time' => null, 'expire_time' => null, 'remaining_times' => $seats['remaining_times'], 'remaining_points' => $seats['remaining_points'], 'is_used' => 0, 'usage_count' => 0, 'create_time' => $now, 'update_time' => $now ]; $allocationId = Db::table('ba_company_package_allocation')->insertGetId($newAllocationData); Log::info('创建新的分配记录', [ 'allocation_id' => $allocationId, 'member_user_id' => $memberUserId, 'package_price_id' => $seats['package_price_id'], 'company_id' => $seats['company_id'] ]); } // 9. 为用户创建产品使用记录 $userProductService = new UserProductService(); $orderItem = Db::table('ba_order_item')->where('id', $generalRecord['order_item_id'])->find(); if ($orderItem) { $package = Db::table('ba_package_price')->where('id', $seats['package_price_id'])->find(); if ($package) { $userProductService->createCompanyProductUsage($canceledAllocation, $memberUserId, $seats['card_type']); } } // 10. 记录分配日志 Db::table('ba_allocation_log')->insert([ 'allocation_id' => $allocationId, 'action' => 1, // 分配 'operator_id' => $allocatorId, 'to_user_id' => $memberUserId, 'remark' => $remark ?: '分配次卡/积分卡使用权限', 'create_time' => $now ]); Db::commit(); return [ 'success' => true, 'allocation_id' => $allocationId, 'message' => '分配成功' ]; } catch (\Throwable $e) { Db::rollback(); throw $e; } } /** * 检查分配权限 */ private function checkAssignPermission($userId, $companyId, $seatsId = null) { // 1. 检查是否是公司创建者 $isCreator = Db::table('ba_company') ->where('id', $companyId) ->where('creator_id', $userId) ->count() > 0; if ($isCreator) { return true; } // 2. 检查是否是购买者(对于该套餐) if ($seatsId) { $isBuyer = Db::table('ba_company_package_allocation') // ->where('seats_id', $seatsId) ->where('buyer_id', $userId) ->count() > 0; if ($isBuyer) { return true; } } // 3. 检查是否是管理员(根据企业成员表) $isAdmin = Db::table('ba_company_member') ->where('company_id', $companyId) ->where('user_id', $userId) ->where('role', 1) // 1=管理员 ->where('status', 1) ->count() > 0; return $isAdmin; } /** * 检查用户是否是企业成员 */ private function isCompanyMember($userId, $companyId) { // 检查是否是创建者 $isCreator = Db::table('ba_company') ->where('id', $companyId) ->where('creator_id', $userId) ->count() > 0; if ($isCreator) { return true; } // 检查是否是成员 $isMember = Db::table('ba_company_member') ->where('company_id', $companyId) ->where('user_id', $userId) ->where('status', 1) ->count() > 0; return $isMember; } /** * 自动分配席位给购买者 */ public function autoAllocateToBuyer($buyerId, $companyId, $packagePriceId, $orderId) { try { Log::info('开始自动分配席位给购买者', [ 'buyer_id' => $buyerId, 'company_id' => $companyId, 'package_price_id' => $packagePriceId, 'order_id' => $orderId ]); // 1. 检查购买者是否已分配此套餐 $alreadyAllocated = Db::table('ba_company_package_allocation') ->where('company_id', $companyId) ->where('package_price_id', $packagePriceId) ->where('assigned_to_user_id', $buyerId) ->where('allocation_status', 1) // 已分配 ->count(); Log::info('检查购买者是否已分配此套餐结果', [ 'already_allocated' => $alreadyAllocated ]); if ($alreadyAllocated > 0) { Log::info('购买者已分配此套餐,跳过自动分配', [ 'buyer_id' => $buyerId, 'company_id' => $companyId, 'package_price_id' => $packagePriceId ]); return false; // 已分配,跳过 } // 2. 获取可用的席位ID(从席位表中获取) $seats = Db::table('ba_company_package_seats') ->where('company_id', $companyId) ->where('package_price_id', $packagePriceId) ->where('available_seats', '>', 0) ->find(); Log::info('查询可用席位结果', [ 'seats' => $seats ? $seats['id'] : null, 'available_seats' => $seats ? $seats['available_seats'] : 0 ]); if (!$seats) { Log::error('没有可用席位进行自动分配', [ 'company_id' => $companyId, 'package_price_id' => $packagePriceId ]); return false; } // 3. 获取一个未分配的分配记录 $allocation = Db::table('ba_company_package_allocation') ->where('order_id', $orderId) ->where('company_id', $companyId) ->where('package_price_id', $packagePriceId) ->where('allocation_status', 0) // 未分配 ->order('id', 'asc') ->find(); Log::info('查询未分配记录结果', [ 'allocation' => $allocation ? $allocation['id'] : null, 'order_id' => $orderId ]); if (!$allocation) { // 尝试查找任何属于该订单的未分配记录 $allocation = Db::table('ba_company_package_allocation') ->where('order_id', $orderId) ->where('allocation_status', 0) ->order('id', 'asc') ->find(); Log::info('二次查询未分配记录结果', [ 'allocation' => $allocation ? $allocation['id'] : null ]); if (!$allocation) { Log::error('没有找到未分配的分配记录', [ 'order_id' => $orderId, 'company_id' => $companyId, 'package_price_id' => $packagePriceId ]); return false; } } // 4. 获取套餐信息(用于卡类型判断) $package = Db::table('ba_package_price') ->where('id', $packagePriceId) ->find(); if (!$package) { Log::error('套餐信息不存在', ['package_price_id' => $packagePriceId]); return false; } Db::startTrans(); try { // 5. 执行分配 $now = date('Y-m-d H:i:s'); // 更新分配记录 Db::table('ba_company_package_allocation') ->where('id', $allocation['id']) ->update([ 'assigned_to_user_id' => $buyerId, 'assigned_by_user_id' => $buyerId, 'allocation_status' => 1, 'allocation_time' => $now, 'start_time' => $now, 'end_time' => $this->calculateEndTime($package['card_type'], $now), 'update_time' => $now ]); // 更新席位表 Db::table('ba_company_package_seats') ->where('id', $seats['id']) ->update([ 'assigned_seats' => Db::raw('assigned_seats + 1'), 'available_seats' => Db::raw('available_seats - 1'), 'update_time' => $now ]); // 更新订单商品 Db::table('ba_order_item') ->where('id', $allocation['order_item_id']) ->update([ 'is_allocated' => 1, 'company_id' => $companyId ]); // 6. 记录分配日志 Db::table('ba_allocation_log')->insert([ 'allocation_id' => $allocation['id'], 'action' => 1, // 分配 'operator_id' => $buyerId, 'to_user_id' => $buyerId, 'remark' => '购买后自动分配给购买者', 'create_time' => $now ]); // 7. 根据卡类型创建用户产品记录 $userProductService = new UserProductService(); // 所有卡类型都需要创建使用记录 // if ($package['card_type'] >= 3) { // 日期卡 // 日期卡分配时创建使用记录 $userProductService->createCompanyProductUsage($allocation, $buyerId, $package['card_type']); // } else { // 次卡(1)和积分卡(2) // // 获取订单商品信息 // $orderItem = Db::table('ba_order_item') // ->where('id', $allocation['order_item_id']) // ->find(); // // if ($orderItem) { // // 创建用户产品记录(次卡/积分卡) // $userProductService->createUserProductRecord($buyerId, $orderItem, $package); // } // } Db::commit(); Log::info('企业套餐自动分配给购买者成功', [ 'buyer_id' => $buyerId, 'company_id' => $companyId, 'package_price_id' => $packagePriceId, 'allocation_id' => $allocation['id'] ]); return true; } catch (\Throwable $e) { Db::rollback(); Log::error('企业套餐自动分配给购买者失败: ' . $e->getMessage()); throw $e; } } catch (\Throwable $e) { Log::error('自动分配企业套餐给购买者失败: ' . $e->getMessage()); return false; } } /** * 计算到期时间 */ private function calculateEndTime($cardType, $startTime) { $start = strtotime($startTime); switch ($cardType) { case 3: // 日卡 return date('Y-m-d 23:59:59', strtotime('+1 day', $start)); case 4: // 周卡 return date('Y-m-d 23:59:59', strtotime('+7 days', $start)); case 5: // 季卡 return date('Y-m-d 23:59:59', strtotime('+90 days', $start)); case 6: // 月卡 return date('Y-m-d 23:59:59', strtotime('+30 days', $start)); case 7: // 年卡 return date('Y-m-d 23:59:59', strtotime('+365 days', $start)); default: return null; // 次卡和积分卡没有固定到期时间 } } /** * 获取卡类型文本 */ private function getCardTypeText($type) { $map = [ 1 => '次卡', 2 => '积分卡', 3 => '日卡', 4 => '周卡', 5 => '季卡', 6 => '月卡', 7 => '年卡' ]; return $map[$type] ?? '其他'; } private function getProductIdByPackage($packagePriceId) { // 实现获取产品ID的逻辑 $package = Db::table('ba_package_price')->where('id', $packagePriceId)->find(); $product = Db::table('ba_product')->where('package_id', $package['package_id'])->find(); return $product ? $product['id'] : 0; } private function getOrderBuyerId($orderId) { $order = Db::table('ba_order')->where('id', $orderId)->find(); return $order ? $order['user_id'] : 0; } /** * 取消次卡/积分卡权限分配 */ public function cancelPackagePermission($allocationId, $operatorId, $remark = '') { Db::startTrans(); try { // 1. 获取分配记录 $allocation = Db::table('ba_company_package_allocation') ->where('id', $allocationId) ->where('record_type', 1) // 用户分配记录 ->where('allocation_status', 1) // 已分配 ->lock(true) ->find(); if (!$allocation) { throw new \Exception('分配记录不存在或未分配'); } // 2. 检查权限 $canCancel = $this->checkAssignPermission($operatorId, $allocation['company_id']); if (!$canCancel) { throw new \Exception('您没有取消分配的权限'); } // 3. 获取席位信息 $seats = Db::table('ba_company_package_seats') ->where('company_id', $allocation['company_id']) ->where('package_price_id', $allocation['package_price_id']) ->find(); if (!$seats) { throw new \Exception('企业套餐席位不存在'); } // 4. 从授权列表中移除用户 $authorizedUsers = json_decode($seats['authorized_users'] ?? '[]', true); $key = array_search($allocation['assigned_to_user_id'], $authorizedUsers); if ($key !== false) { unset($authorizedUsers[$key]); $authorizedUsers = array_values($authorizedUsers); // 重新索引数组 // 更新席位表 Db::table('ba_company_package_seats') ->where('id', $seats['id']) ->update([ 'authorized_users' => json_encode($authorizedUsers), 'assigned_member_count' => Db::raw('assigned_member_count - 1'), 'assigned_seats' => Db::raw('assigned_seats - 1'), 'available_seats' => Db::raw('available_seats + 1'), 'update_time' => date('Y-m-d H:i:s') ]); } // 5. 更新分配记录状态 $now = date('Y-m-d H:i:s'); Db::table('ba_company_package_allocation') ->where('id', $allocationId) ->update([ 'allocation_status' => 2, // 已取消 'cancel_allocation_time' => $now, 'update_time' => $now ]); // 6. 删除对应的用户产品使用记录 $del=Db::table('ba_user_product_usage') ->where('user_id', $allocation['assigned_to_user_id']) ->where('package_price_id', $allocation['package_price_id']) ->where('company_id', $allocation['company_id']) ->where('package_type', 2) // 企业套餐 ->delete(); // 7. 记录取消分配日志 Db::table('ba_allocation_log')->insert([ 'allocation_id' => $allocationId, 'action' => 2, // 取消分配 'operator_id' => $operatorId, 'from_user_id' => $allocation['assigned_to_user_id'], 'remark' => $remark ?: '取消次卡/积分卡使用权限', 'create_time' => $now ]); Db::commit(); return true; } catch (\Throwable $e) { Db::rollback(); Log::error('取消次卡/积分卡权限失败: ' . $e->getMessage()); throw $e; } } /** * 使用企业次卡/积分卡(从共享资源池扣除) */ public function useSharedCompanyPackage($userId, $packagePriceId, $useQuantity, $productId = null, $remark = '') { Db::startTrans(); try { // 1. 获取用户所在企业 $companyInfo = $this->getUserCompany($userId); if (!$companyInfo) { throw new \Exception('您不属于任何企业'); } // 2. 获取套餐信息 $package = Db::table('ba_package_price') ->where('id', $packagePriceId) ->find(); if (!$package) { throw new \Exception('套餐不存在'); } // 3. 检查卡类型是否为次卡或积分卡 if (!in_array($package['card_type'], [1, 2])) { throw new \Exception('只有次卡和积分卡支持此使用方式'); } // 4. 获取企业套餐席位信息,检查用户是否被授权 $seats = Db::table('ba_company_package_seats') ->where('company_id', $companyInfo['id']) ->where('package_price_id', $packagePriceId) ->lock(true) ->find(); if (!$seats) { throw new \Exception('企业套餐不存在'); } // 检查用户是否在授权列表中 $authorizedUsers = json_decode($seats['authorized_users'] ?? '[]', true); if (!in_array($userId, $authorizedUsers)) { throw new \Exception('您未被授权使用此套餐'); } // 5. 检查共享资源池是否足够 if ($package['card_type'] == 1) { // 次卡 if ($seats['remaining_times'] < $useQuantity) { throw new \Exception('剩余次数不足,剩余:' . $seats['remaining_times'] . '次'); } } elseif ($package['card_type'] == 2) { // 积分卡 if ($seats['remaining_points'] < $useQuantity) { throw new \Exception('剩余积分不足,剩余:' . $seats['remaining_points'] . '积分'); } } // 6. 获取用户的分配记录 $userAllocation = Db::table('ba_company_package_allocation') ->where('company_id', $companyInfo['id']) ->where('package_price_id', $packagePriceId) ->where('assigned_to_user_id', $userId) ->where('allocation_status', 1) ->order('id', 'asc') ->find(); if (!$userAllocation) { throw new \Exception('未找到您的分配记录'); } // 7. 扣减共享池资源 if ($package['card_type'] == 1) { // 次卡 Db::table('ba_company_package_seats') ->where('id', $seats['id']) ->dec('remaining_times', $useQuantity) ->update(); $remainingTimesAfter = $seats['remaining_times'] - $useQuantity; $remainingPointsAfter = $seats['remaining_points']; } else { // 积分卡 Db::table('ba_company_package_seats') ->where('id', $seats['id']) ->dec('remaining_points', $useQuantity) ->update(); $remainingTimesAfter = $seats['remaining_times']; $remainingPointsAfter = $seats['remaining_points'] - $useQuantity; } // 8. 更新分配记录的使用状态 Db::table('ba_company_package_allocation') ->where('id', $userAllocation['id']) ->update([ 'is_used' => 1, 'usage_count' => Db::raw('usage_count + ' . $useQuantity), 'update_time' => date('Y-m-d H:i:s') ]); // 9. 记录使用明细 $usageData = [ 'allocation_id' => $userAllocation['id'], 'company_id' => $companyInfo['id'], 'package_price_id' => $packagePriceId, 'user_id' => $userId, 'card_type' => $package['card_type'], 'used_quantity' => $useQuantity, 'remaining_times_after' => $remainingTimesAfter, 'remaining_points_after' => $remainingPointsAfter, 'product_id' => $productId, 'usage_time' => date('Y-m-d H:i:s'), 'remark' => $remark, 'create_time' => date('Y-m-d H:i:s') ]; $usageId = Db::table('ba_company_package_usage')->insertGetId($usageData); Db::commit(); return [ 'success' => true, 'usage_id' => $usageId, 'remaining_times' => $remainingTimesAfter, 'remaining_points' => $remainingPointsAfter, 'message' => '使用成功' ]; } catch (\Throwable $e) { Db::rollback(); Log::error('使用企业次卡/积分卡失败: ' . $e->getMessage()); throw $e; } } }