|
|
@@ -0,0 +1,1414 @@
|
|
|
+<?php
|
|
|
+namespace app\common\service;
|
|
|
+
|
|
|
+use think\facade\Db;
|
|
|
+use think\facade\Log;
|
|
|
+
|
|
|
+class CompanyPackageService
|
|
|
+{
|
|
|
+ /**
|
|
|
+ * 验证企业套餐购买资格
|
|
|
+ */
|
|
|
+ public function validateCompanyPurchase($userId, $packagePriceId, $quantity)
|
|
|
+ {
|
|
|
+ try {
|
|
|
+ // 1. 获取套餐信息
|
|
|
+ $package = Db::table('ba_package_price')
|
|
|
+ ->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' => $quantity,
|
|
|
+ 'assigned_seats' => 0,
|
|
|
+ 'available_seats' => $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' => 1, // 已分配
|
|
|
+ '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')
|
|
|
+ ->where('cs.company_id', $companyId)
|
|
|
+ ->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')
|
|
|
+ ->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.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 [];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取授权用户的详细信息
|
|
|
+
|
|
|
+ $user=Db::table('ba_user')
|
|
|
+ ->alias('u')
|
|
|
+ // 使用字符串条件替代闭包
|
|
|
+ ->leftJoin('ba_company_member cm', 'cm.user_id = u.id AND cm.company_id = ' . $companyId)
|
|
|
+ ->whereIn('u.id', $authorizedUserIds)
|
|
|
+ ->field('
|
|
|
+ u.id as 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();
|
|
|
+ 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) // 购买记录
|
|
|
+ ->where('allocation_status', 0) // 未分配
|
|
|
+ ->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'),
|
|
|
+ 'update_time' => date('Y-m-d H:i:s')
|
|
|
+ ]);
|
|
|
+
|
|
|
+ // 8. 创建新的分配记录
|
|
|
+ $now = date('Y-m-d H:i:s');
|
|
|
+ $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,
|
|
|
+ 'create_time' => $now,
|
|
|
+ 'update_time' => $now
|
|
|
+ ];
|
|
|
+
|
|
|
+ $allocationId = Db::table('ba_company_package_allocation')->insertGetId($newAllocationData);
|
|
|
+
|
|
|
+ // 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->createUserProductRecord($memberUserId, $orderItem, $package);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 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'),
|
|
|
+ '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. 删除对应的用户产品使用记录
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|