CompanyPackageService.php 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481
  1. <?php
  2. namespace app\common\service;
  3. use think\db\Where;
  4. use think\facade\Db;
  5. use think\facade\Log;
  6. class CompanyPackageService
  7. {
  8. /**
  9. * 验证企业套餐购买资格
  10. */
  11. public function validateCompanyPurchase($userId, $packagePriceId, $quantity)
  12. {
  13. try {
  14. // 1. 获取套餐信息
  15. $package = Db::table('ba_package_price')
  16. ->alias('pp')
  17. ->leftJoin('ba_package p', 'p.id = pp.package_id')
  18. ->where('pp.id', $packagePriceId)
  19. ->field('pp.*, p.name as package_name')
  20. ->find();
  21. if (!$package) {
  22. throw new \Exception('套餐不存在');
  23. }
  24. // 2. 如果是企业套餐,检查用户是否属于企业
  25. if ($package['type'] == 2) { // 企业套餐
  26. $companyInfo = $this->getUserCompany($userId);
  27. if (!$companyInfo) {
  28. throw new \Exception('只有企业成员才能购买企业套餐');
  29. }
  30. // 3. 检查日期卡的最低购买数量
  31. if ($package['is_date_card'] == 1 && $quantity < $package['min_quantity']) {
  32. throw new \Exception('企业日期卡至少需要购买' . $package['min_quantity'] . '份');
  33. }
  34. return [
  35. 'valid' => true,
  36. 'company_id' => $companyInfo['id'],
  37. 'company_name' => $companyInfo['name'],
  38. 'min_quantity' => $package['min_quantity']
  39. ];
  40. }
  41. return ['valid' => true, 'company_id' => null];
  42. } catch (\Throwable $e) {
  43. Log::error('验证企业套餐购买资格失败: ' . $e->getMessage());
  44. throw $e;
  45. }
  46. }
  47. /**
  48. * 获取用户所在企业
  49. */
  50. public function getUserCompany($userId)
  51. {
  52. // 检查用户是否是企业创建人
  53. $company = Db::table('ba_company')
  54. ->where('creator_id', $userId)
  55. ->where('status', 1)
  56. ->field('id, name,creator_id')
  57. ->find();
  58. if ($company) {
  59. return $company;
  60. }
  61. // 检查是否是成员
  62. $member = Db::table('ba_company_member')
  63. ->alias('cm')
  64. ->leftJoin('ba_company c', 'c.id = cm.company_id')
  65. ->where('cm.user_id', $userId)
  66. ->where('cm.status', 1)
  67. ->where('c.status', 1)
  68. ->field('c.id, c.name')
  69. ->find();
  70. return $member;
  71. }
  72. /**
  73. * 处理企业套餐购买(创建席位记录)
  74. */
  75. public function processCompanyPackagePurchase($orderId, $companyId, $packagePriceId, $quantity, $cardType, $unitValue, $pointsValue)
  76. {
  77. Db::startTrans();
  78. try {
  79. // 1. 获取或创建企业套餐席位记录
  80. $seatsRecord = Db::table('ba_company_package_seats')
  81. ->where('company_id', $companyId)
  82. ->where('package_price_id', $packagePriceId)
  83. ->find();
  84. if ($seatsRecord) {
  85. // 更新现有记录
  86. $updateData = [
  87. 'total_seats' => Db::raw('total_seats + ' . $quantity),
  88. 'available_seats' => Db::raw('available_seats + ' . $quantity),
  89. 'is_shared' => $cardType < 3 ? 1 : 0, // 次卡/积分卡为共享资源
  90. 'update_time' => date('Y-m-d H:i:s')
  91. ];
  92. // 如果是次卡,累加次数
  93. if ($cardType == 1) {
  94. $updateData['total_times'] = Db::raw('total_times + ' . ($unitValue * $quantity));
  95. $updateData['remaining_times'] = Db::raw('remaining_times + ' . ($unitValue * $quantity));
  96. }
  97. // 如果是积分卡,累加积分
  98. if ($cardType == 2) {
  99. $updateData['total_points'] = Db::raw('total_points + ' . ($pointsValue * $quantity));
  100. $updateData['remaining_points'] = Db::raw('remaining_points + ' . ($pointsValue * $quantity));
  101. }
  102. Db::table('ba_company_package_seats')
  103. ->where('id', $seatsRecord['id'])
  104. ->update($updateData);
  105. $seatsId = $seatsRecord['id'];
  106. } else {
  107. // 创建新记录
  108. $seatsData = [
  109. 'company_id' => $companyId,
  110. 'package_price_id' => $packagePriceId,
  111. 'product_id' => $this->getProductIdByPackage($packagePriceId),
  112. 'total_seats' => $cardType < 3 ? 1000 : $quantity,
  113. 'assigned_seats' => 0,
  114. 'available_seats' => $cardType < 3 ? 1000 : $quantity,
  115. 'is_shared' => $cardType < 3 ? 1 : 0, // 次卡/积分卡为共享资源
  116. 'card_type' => $cardType,
  117. 'total_times' => $cardType == 1 ? $unitValue * $quantity : 0,
  118. 'remaining_times' => $cardType == 1 ? $unitValue * $quantity : 0,
  119. 'total_points' => $cardType == 2 ? $pointsValue * $quantity : 0,
  120. 'remaining_points' => $cardType == 2 ? $pointsValue * $quantity : 0,
  121. 'status' => 1,
  122. 'create_time' => date('Y-m-d H:i:s'),
  123. 'update_time' => date('Y-m-d H:i:s')
  124. ];
  125. $seatsId = Db::table('ba_company_package_seats')->insertGetId($seatsData);
  126. }
  127. // 2. 获取购买者ID
  128. $buyerId = $this->getOrderBuyerId($orderId);
  129. // 3. 查询订单商品
  130. $orderItems = Db::table('ba_order_item')
  131. ->where('order_id', $orderId)
  132. ->where('package_price_id', $packagePriceId)
  133. ->select();
  134. foreach ($orderItems as $item) {
  135. if ($cardType >= 3) {
  136. // 日期卡:为每个购买的数量创建独立的分配记录
  137. for ($i = 0; $i < $quantity; $i++) {
  138. $allocationData = [
  139. 'order_item_id' => $item['id'],
  140. 'order_id' => $orderId,
  141. 'package_price_id' => $packagePriceId,
  142. 'product_id' => $item['product_id'],
  143. 'buyer_id' => $buyerId,
  144. 'company_id' => $companyId,
  145. 'assigned_to_user_id' => null, // 初始不分配
  146. 'assigned_by_user_id' => $buyerId,
  147. 'record_type' => 2, // 购买记录
  148. 'is_general' => 0,
  149. 'seat_index' => $i + 1, // 席位索引
  150. 'allocation_status' => 0, // 未分配
  151. 'allocation_time' => null,
  152. 'start_time' => null,
  153. 'end_time' => null,
  154. 'expire_time' => $this->calculateEndTime($cardType, date('Y-m-d H:i:s')), // 冗余字段
  155. 'remaining_times' => 0, // 日期卡没有次数
  156. 'remaining_points' => 0, // 日期卡没有积分
  157. 'is_used' => 0,
  158. 'create_time' => date('Y-m-d H:i:s'),
  159. 'update_time' => date('Y-m-d H:i:s')
  160. ];
  161. $allocationId = Db::table('ba_company_package_allocation')->insertGetId($allocationData);
  162. }
  163. } else {
  164. // 次卡和积分卡:
  165. // 1. 创建通用记录(用于管理总资源)
  166. $generalAllocationData = [
  167. 'order_item_id' => $item['id'],
  168. 'order_id' => $orderId,
  169. 'package_price_id' => $packagePriceId,
  170. 'product_id' => $item['product_id'],
  171. 'buyer_id' => $buyerId,
  172. 'company_id' => $companyId,
  173. 'assigned_to_user_id' => null, // 通用记录不分配
  174. 'assigned_by_user_id' => $buyerId,
  175. 'record_type' => 0, // 通用记录
  176. 'is_general' => 1, // 是通用记录
  177. 'seat_index' => 0,
  178. 'allocation_status' => 0, // 状态:通用记录
  179. 'allocation_time' => null,
  180. 'start_time' => null,
  181. 'end_time' => null,
  182. 'expire_time' => null,
  183. 'remaining_times' => $cardType == 1 ? $unitValue * $quantity : 0,
  184. 'remaining_points' => $cardType == 2 ? $pointsValue * $quantity : 0,
  185. 'is_used' => 0,
  186. 'create_time' => date('Y-m-d H:i:s'),
  187. 'update_time' => date('Y-m-d H:i:s')
  188. ];
  189. $generalAllocationId = Db::table('ba_company_package_allocation')->insertGetId($generalAllocationData);
  190. // 2. 为购买者创建独立的分配记录
  191. $buyerAllocationData = [
  192. 'order_item_id' => $item['id'],
  193. 'order_id' => $orderId,
  194. 'package_price_id' => $packagePriceId,
  195. 'product_id' => $item['product_id'],
  196. 'buyer_id' => $buyerId,
  197. 'company_id' => $companyId,
  198. 'assigned_to_user_id' => $buyerId,
  199. 'assigned_by_user_id' => $buyerId,
  200. 'record_type' => 1, // 用户分配记录
  201. 'is_general' => 0,
  202. 'seat_index' => 0,
  203. 'parent_id' => $generalAllocationId, // 关联通用记录
  204. 'allocation_status' => 0, // 未分配
  205. 'allocation_time' => date('Y-m-d H:i:s'),
  206. 'start_time' => date('Y-m-d H:i:s'),
  207. 'end_time' => null,
  208. 'expire_time' => null,
  209. 'remaining_times' => $cardType == 1 ? $unitValue : 0,
  210. 'remaining_points' => $cardType == 2 ? $pointsValue : 0,
  211. 'is_used' => 0,
  212. 'create_time' => date('Y-m-d H:i:s'),
  213. 'update_time' => date('Y-m-d H:i:s')
  214. ];
  215. $buyerAllocationId = Db::table('ba_company_package_allocation')->insertGetId($buyerAllocationData);
  216. // 3. 将购买者添加到授权列表
  217. $seats = Db::table('ba_company_package_seats')
  218. ->where('id', $seatsId)
  219. ->find();
  220. $authorizedUsers = json_decode($seats['authorized_users'] ?? '[]', true);
  221. if (!in_array($buyerId, $authorizedUsers)) {
  222. $authorizedUsers[] = $buyerId;
  223. Db::table('ba_company_package_seats')
  224. ->where('id', $seatsId)
  225. ->update([
  226. 'authorized_users' => json_encode($authorizedUsers),
  227. 'assigned_member_count' => Db::raw('assigned_member_count + 1')
  228. ]);
  229. }
  230. }
  231. // 更新订单商品的分配记录ID(对于日期卡,记录第一个分配记录的ID)
  232. if ($cardType >= 3) {
  233. // 获取第一个分配记录ID
  234. $firstAllocation = Db::table('ba_company_package_allocation')
  235. ->where('order_item_id', $item['id'])
  236. ->where('record_type', 2)
  237. ->order('seat_index', 'asc')
  238. ->find();
  239. if ($firstAllocation) {
  240. Db::table('ba_order_item')
  241. ->where('id', $item['id'])
  242. ->update(['allocation_id' => $firstAllocation['id']]);
  243. }
  244. } else {
  245. // 次卡/积分卡使用购买者分配记录ID
  246. Db::table('ba_order_item')
  247. ->where('id', $item['id'])
  248. ->update(['allocation_id' => $buyerAllocationId]);
  249. }
  250. }
  251. Db::commit();
  252. return true;
  253. } catch (\Throwable $e) {
  254. Db::rollback();
  255. Log::error('处理企业套餐购买失败: ' . $e->getMessage());
  256. throw $e;
  257. }
  258. }
  259. /**
  260. * 获取可分配的企业套餐列表(区分类型)
  261. */
  262. public function getAvailableCompanyPackages($companyId, $operatorId)
  263. {
  264. try {
  265. // 获取用户角色(创建者或成员)
  266. $isCreator = Db::table('ba_company')
  267. ->where('id', $companyId)
  268. ->where('creator_id', $operatorId)
  269. ->count() > 0;
  270. // 获取企业所有套餐席位
  271. $seats = Db::table('ba_company_package_seats')
  272. ->alias('cs')
  273. ->leftJoin('ba_package_price pp', 'pp.id = cs.package_price_id')
  274. ->leftJoin('ba_product p', 'p.id = cs.product_id')
  275. ->leftJoin('ba_company_package_allocation pcs', 'pcs.package_price_id = pp.id')
  276. ->where('cs.company_id', $companyId)
  277. ->where('pcs.buyer_id', $operatorId)
  278. // ->where('cs.available_seats', '>', 0)
  279. ->where('cs.status', 1)
  280. ->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')
  281. ->group('pcs.package_price_id')
  282. ->select();
  283. // 获取企业所有成员(包括创建者)
  284. $allMembers = $this->getAllCompanyMembers($companyId);
  285. // 处理数据
  286. $result = [];
  287. foreach ($seats as $seat) {
  288. // 获取该套餐已分配的成员
  289. $allocatedMembers = $this->getAllocatedMembersForPackage($companyId, $seat['package_price_id']);
  290. // 获取该套餐已分配的成员ID列表
  291. $allocatedMemberIds = array_column($allocatedMembers, 'user_id');
  292. // 筛选未分配的成员
  293. $unallocatedMembers = [];
  294. foreach ($allMembers as $member) {
  295. if (!in_array($member['user_id'], $allocatedMemberIds)) {
  296. $unallocatedMembers[] = $member;
  297. }
  298. }
  299. // 组织返回数据
  300. $seatItem = [
  301. 'seats_id' => $seat['id'],
  302. 'product_id' => $seat['product_id'],
  303. 'product_name' => $seat['product_name'],
  304. 'product_type' => $seat['product_type'], // 1:网页,2:软件
  305. 'product_link' => $seat['link'],
  306. 'product_image' => $seat['image'],
  307. 'package_price_id' => $seat['package_price_id'],
  308. 'spec_name' => $seat['spec_name'],
  309. 'card_type' => $seat['card_type'],
  310. 'card_type_text' => $this->getCardTypeText($seat['card_type']),
  311. 'package_type' => $seat['package_type'], // 1个人,2企业
  312. 'total_seats' => $seat['total_seats'],
  313. 'assigned_seats' => $seat['assigned_seats'],
  314. 'available_seats' => $seat['available_seats'],
  315. // 次卡和积分卡相关
  316. 'total_times' => $seat['total_times'],
  317. 'remaining_times' => $seat['remaining_times'],
  318. 'total_points' => $seat['total_points'],
  319. 'remaining_points' => $seat['remaining_points'],
  320. 'end_time' => $seat['end_time'],
  321. // 已分配成员信息
  322. 'allocated_members' => $allocatedMembers,
  323. // 未分配成员信息
  324. 'unallocated_members' => $unallocatedMembers,
  325. // 统计信息
  326. 'allocated_count' => count($allocatedMembers),
  327. 'unallocated_count' => count($unallocatedMembers),
  328. 'total_members' => count($allMembers)
  329. ];
  330. $result[] = $seatItem;
  331. }
  332. return [
  333. 'packages' => $result,
  334. 'is_creator' => $isCreator,
  335. 'total_members' => count($allMembers)
  336. ];
  337. } catch (\Throwable $e) {
  338. Log::error('获取可分配企业套餐失败: ' . $e->getMessage());
  339. return [
  340. 'packages' => [],
  341. 'is_creator' => false,
  342. 'total_members' => 0
  343. ];
  344. }
  345. }
  346. /**
  347. * 获取企业所有成员(包括创建者)
  348. */
  349. private function getAllCompanyMembers($companyId)
  350. {
  351. $members = [];
  352. // 1. 获取企业创建者
  353. $company = Db::table('ba_company')
  354. ->where('id', $companyId)
  355. ->field('id, name as company_name, creator_id')
  356. ->find();
  357. if ($company && $company['creator_id']) {
  358. // 获取创建者用户信息
  359. $creator = Db::table('ba_user')
  360. ->where('id', $company['creator_id'])
  361. ->field('id as user_id, nickname as member_name, avatar, email, mobile')
  362. ->find();
  363. if ($creator) {
  364. $creator['is_creator'] = 1;
  365. $creator['role'] = 1; // 创建者/管理员
  366. $members[] = $creator;
  367. }
  368. }
  369. // 2. 获取企业成员表中的成员
  370. $companyMembers = Db::table('ba_company_member')
  371. ->alias('cm')
  372. ->leftJoin('ba_user u', 'u.id = cm.user_id')
  373. ->where('cm.company_id', $companyId)
  374. ->where('cm.status', 1)
  375. ->field('
  376. cm.id as member_id,
  377. cm.user_id,
  378. COALESCE(cm.name, u.nickname) as member_name,
  379. COALESCE(cm.email, u.email) as email,
  380. u.avatar,
  381. u.mobile,
  382. cm.role
  383. ')
  384. ->select()
  385. ->toArray();
  386. // 过滤掉重复的成员(创建者可能也在成员表中)
  387. foreach ($companyMembers as $member) {
  388. // 检查是否已经是创建者
  389. $isCreator = false;
  390. foreach ($members as $existingMember) {
  391. if ($existingMember['user_id'] == $member['user_id']) {
  392. $isCreator = true;
  393. break;
  394. }
  395. }
  396. if (!$isCreator) {
  397. $member['is_creator'] = 0;
  398. $members[] = $member;
  399. }
  400. }
  401. return $members;
  402. }
  403. /**
  404. * 获取指定套餐已分配的成员
  405. */
  406. private function getAllocatedMembersForPackage($companyId, $packagePriceId)
  407. {
  408. // 获取套餐信息,判断卡类型
  409. $package = Db::table('ba_package_price')
  410. ->where('id', $packagePriceId)
  411. ->field('card_type')
  412. ->find();
  413. if (!$package) {
  414. return [];
  415. }
  416. $cardType = $package['card_type'];
  417. if ($cardType >= 3) {
  418. // 日期卡:从分配记录中获取已分配成员
  419. return Db::table('ba_company_package_allocation')
  420. ->alias('cpa')
  421. ->leftJoin('ba_user u', 'u.id = cpa.assigned_to_user_id')
  422. ->leftJoin('ba_company_member cm', 'cm.user_id = cpa.assigned_to_user_id AND cm.company_id = cpa.company_id')
  423. ->where('cpa.company_id', $companyId)
  424. ->where('cpa.package_price_id', $packagePriceId)
  425. ->where('cpa.allocation_status', 1) // 已分配
  426. ->whereNotNull('cpa.assigned_to_user_id')
  427. ->field('
  428. cpa.assigned_to_user_id as user_id,
  429. COALESCE(cm.name, u.nickname) as member_name,
  430. COALESCE(cm.email, u.email) as email,
  431. u.avatar,
  432. u.mobile,
  433. cpa.id as allocation_id,
  434. cpa.allocation_time,
  435. cpa.start_time,
  436. cpa.end_time,
  437. cpa.remaining_times,
  438. cpa.remaining_points
  439. ')
  440. ->select()
  441. ->toArray();
  442. } else {
  443. // 次卡/积分卡:从席位表的授权用户列表中获取
  444. $seats = Db::table('ba_company_package_seats')
  445. ->where('company_id', $companyId)
  446. ->where('package_price_id', $packagePriceId)
  447. ->field('authorized_users')
  448. ->find();
  449. if (!$seats || empty($seats['authorized_users'])) {
  450. return [];
  451. }
  452. $authorizedUserIds = json_decode($seats['authorized_users'], true);
  453. if (empty($authorizedUserIds)) {
  454. return [];
  455. }
  456. // 获取授权用户的详细信息
  457. $where[]=['cp.record_type','<>',0];
  458. $user=Db::table('ba_user')
  459. ->alias('u')
  460. // 使用字符串条件替代闭包
  461. ->leftJoin('ba_company_member cm', 'cm.user_id = u.id AND cm.company_id = ' . $companyId)
  462. ->leftJoin('ba_company_package_allocation cp', 'u.id = cp.assigned_to_user_id')
  463. ->whereIn('u.id', $authorizedUserIds)
  464. ->where('cp.allocation_status',1)
  465. ->where($where)
  466. ->where('cp.package_price_id',$packagePriceId)
  467. ->field('
  468. u.id as user_id,
  469. COALESCE(cm.name, u.nickname) as member_name,
  470. COALESCE(cm.email, u.email) as email,
  471. u.avatar,
  472. cp.id as allocation_id,
  473. u.mobile,
  474. cm.role
  475. ')
  476. ->select()
  477. ->toArray();
  478. // dump($user);die;
  479. return $user;
  480. }
  481. }
  482. /**
  483. * 分配套餐给企业成员
  484. */
  485. public function allocatePackage($seatsId, $assignedToUserId, $operatorId, $remark = '')
  486. {
  487. Db::startTrans();
  488. try {
  489. // 1. 获取席位信息
  490. $seats = Db::table('ba_company_package_seats')
  491. ->where('id', $seatsId)
  492. ->lock(true)
  493. ->find();
  494. if (!$seats || $seats['available_seats'] <= 0) {
  495. throw new \Exception('没有可用席位');
  496. }
  497. // 2. 检查是否是日期卡
  498. if ($seats['card_type'] < 3) {
  499. throw new \Exception('非日期卡类型,请使用assignPackagePermission方法');
  500. }
  501. // 3. 检查权限(只有创建者可以分配其他人的,成员只能分配自己的)
  502. $isCreator = Db::table('ba_company')
  503. ->where('id', $seats['company_id'])
  504. ->where('creator_id', $operatorId)
  505. ->count() > 0;
  506. // 4. 获取一个未分配的购买记录
  507. $availableAllocation = Db::table('ba_company_package_allocation')
  508. ->where('company_id', $seats['company_id'])
  509. ->where('package_price_id', $seats['package_price_id'])
  510. ->where('record_type', 2) // 购买记录
  511. ->whereIn('allocation_status', [0,2]) // 未分配
  512. ->where('assigned_to_user_id', null) // 未指定用户
  513. ->lock(true)
  514. ->order('seat_index', 'asc') // 按席位索引排序
  515. ->find();
  516. if (!$availableAllocation) {
  517. throw new \Exception('没有可分配的套餐记录');
  518. }
  519. // 如果不是创建者,检查是否是购买者
  520. if (!$isCreator && $availableAllocation['buyer_id'] != $operatorId) {
  521. throw new \Exception('您只能分配自己购买的套餐');
  522. }
  523. // 5. 检查成员是否属于该企业
  524. $isMember = Db::table('ba_company_member')
  525. ->where('company_id', $seats['company_id'])
  526. ->where('user_id', $assignedToUserId)
  527. ->where('status', 1)
  528. ->count() > 0;
  529. if (!$isMember) {
  530. throw new \Exception('该用户不是企业成员');
  531. }
  532. // 6. 检查该成员是否已分配此套餐(日期卡只能分配给一个成员)
  533. if ($seats['card_type'] >= 3) { // 日期卡
  534. $alreadyAllocated = Db::table('ba_company_package_allocation')
  535. ->where('company_id', $seats['company_id'])
  536. ->where('package_price_id', $seats['package_price_id'])
  537. ->where('assigned_to_user_id', $assignedToUserId)
  538. ->where('allocation_status', 1)
  539. ->count();
  540. if ($alreadyAllocated > 0) {
  541. throw new \Exception('该成员已分配此套餐,如需再次分配请重新购买');
  542. }
  543. }
  544. // 7. 执行分配
  545. $now = date('Y-m-d H:i:s');
  546. // 计算到期时间
  547. $endTime = $this->calculateEndTime($seats['card_type'], $now);
  548. // 更新分配记录
  549. Db::table('ba_company_package_allocation')
  550. ->where('id', $availableAllocation['id'])
  551. ->update([
  552. 'assigned_to_user_id' => $assignedToUserId,
  553. 'assigned_by_user_id' => $operatorId,
  554. 'allocation_status' => 1,
  555. 'allocation_time' => $now,
  556. 'start_time' => $now,
  557. 'end_time' => $endTime,
  558. 'expire_time' => $endTime, // 更新冗余字段
  559. 'update_time' => $now
  560. ]);
  561. // 8.更新席位表
  562. Db::table('ba_company_package_seats')
  563. ->where('id', $seatsId)
  564. ->update([
  565. 'assigned_seats' => Db::raw('assigned_seats + 1'),
  566. 'available_seats' => Db::raw('available_seats - 1'),
  567. 'update_time' => $now
  568. ]);
  569. // 9. 检查是否所有席位都已分配
  570. $unallocatedCount = Db::table('ba_company_package_allocation')
  571. ->where('order_item_id', $availableAllocation['order_item_id'])
  572. ->where('allocation_status', 0)
  573. ->where('record_type', 2)
  574. ->count();
  575. if ($unallocatedCount == 0) {
  576. // 所有席位都已分配,更新订单商品
  577. Db::table('ba_order_item')
  578. ->where('id', $availableAllocation['order_item_id'])
  579. ->update([
  580. 'is_allocated' => 1,
  581. 'company_id' => $seats['company_id']
  582. ]);
  583. }
  584. // 10. 为用户创建产品使用记录
  585. $userProductService = new UserProductService();
  586. $userProductService->createCompanyProductUsage($availableAllocation, $assignedToUserId, $seats['card_type']);
  587. // 11. 记录分配日志
  588. Db::table('ba_allocation_log')->insert([
  589. 'allocation_id' => $availableAllocation['id'],
  590. 'action' => 1, // 分配
  591. 'operator_id' => $operatorId,
  592. 'to_user_id' => $assignedToUserId,
  593. 'remark' => $remark,
  594. 'create_time' => $now
  595. ]);
  596. Db::commit();
  597. return [
  598. 'success' => true,
  599. 'allocation_id' => $availableAllocation['id'],
  600. 'message' => '分配成功'
  601. ];
  602. } catch (\Throwable $e) {
  603. Db::rollback();
  604. Log::error('分配套餐失败: ' . $e->getMessage());
  605. throw $e;
  606. }
  607. }
  608. /**
  609. * 取消分配(日期卡独占席位模式)
  610. */
  611. public function cancelAllocation($allocationId, $operatorId, $remark = '')
  612. {
  613. Db::startTrans();
  614. try {
  615. // 1. 获取分配记录
  616. $allocation = Db::table('ba_company_package_allocation')
  617. ->where('id', $allocationId)
  618. ->where('record_type', 2) // 购买记录
  619. ->where('allocation_status', 1) // 已分配
  620. ->lock(true)
  621. ->find();
  622. if (!$allocation) {
  623. throw new \Exception('分配记录不存在或未分配');
  624. }
  625. // 2. 检查权限
  626. $isCreator = Db::table('ba_company')
  627. ->where('id', $allocation['company_id'])
  628. ->where('creator_id', $operatorId)
  629. ->count() > 0;
  630. if (!$isCreator && $allocation['assigned_by_user_id'] != $operatorId) {
  631. throw new \Exception('您没有取消分配的权限');
  632. }
  633. // 3. 获取席位信息
  634. $seats = Db::table('ba_company_package_seats')
  635. ->where('company_id', $allocation['company_id'])
  636. ->where('package_price_id', $allocation['package_price_id'])
  637. ->find();
  638. if (!$seats) {
  639. throw new \Exception('企业套餐席位不存在');
  640. }
  641. // 4. 执行取消分配
  642. $now = date('Y-m-d H:i:s');
  643. // 更新分配记录状态
  644. Db::table('ba_company_package_allocation')
  645. ->where('id', $allocationId)
  646. ->update([
  647. 'assigned_to_user_id' => null,
  648. 'allocation_status' => 2,
  649. 'cancel_allocation_time' => $now,
  650. 'update_time' => $now
  651. ]);
  652. // 5. 更新席位表
  653. Db::table('ba_company_package_seats')
  654. ->where('id', $seats['id'])
  655. ->update([
  656. 'assigned_seats' => Db::raw('assigned_seats - 1'),
  657. 'available_seats' => Db::raw('available_seats + 1'),
  658. 'update_time' => $now
  659. ]);
  660. // 6. 检查是否还有已分配的记录
  661. $allocatedCount = Db::table('ba_company_package_allocation')
  662. ->where('order_item_id', $allocation['order_item_id'])
  663. ->where('allocation_status', 1)
  664. ->count();
  665. if ($allocatedCount == 0) {
  666. // 没有已分配的记录,更新订单商品
  667. Db::table('ba_order_item')
  668. ->where('id', $allocation['order_item_id'])
  669. ->update([
  670. 'is_allocated' => 0,
  671. 'allocation_id' => null
  672. ]);
  673. }
  674. // 7. 删除对应的用户产品使用记录
  675. Db::table('ba_user_product_usage')
  676. ->where('user_id', $allocation['assigned_to_user_id'])
  677. ->where('package_price_id', $allocation['package_price_id'])
  678. ->where('company_id', $allocation['company_id'])
  679. ->where('package_type', 2) // 企业套餐
  680. ->delete();
  681. // 8. 记录取消分配日志
  682. Db::table('ba_allocation_log')->insert([
  683. 'allocation_id' => $allocationId,
  684. 'action' => 2, // 取消分配
  685. 'operator_id' => $operatorId,
  686. 'from_user_id' => $allocation['assigned_to_user_id'],
  687. 'remark' => $remark,
  688. 'create_time' => $now
  689. ]);
  690. Db::commit();
  691. return true;
  692. } catch (\Throwable $e) {
  693. Db::rollback();
  694. Log::error('取消分配失败: ' . $e->getMessage());
  695. throw $e;
  696. }
  697. }
  698. /**
  699. * 分配次卡/积分卡使用权限给成员(授权访问共享资源池)
  700. */
  701. public function assignPackagePermission($seatsId, $memberUserId, $allocatorId, $remark = '')
  702. {
  703. Db::startTrans();
  704. try {
  705. // 1. 获取席位信息
  706. $seats = Db::table('ba_company_package_seats')
  707. ->where('id', $seatsId)
  708. ->lock(true)
  709. ->find();
  710. if (!$seats) {
  711. throw new \Exception('企业套餐不存在');
  712. }
  713. // 2. 检查权限(只有企业创建者或购买者可以分配)
  714. $canAssign = $this->checkAssignPermission($allocatorId, $seats['company_id'], $seatsId);
  715. if (!$canAssign) {
  716. throw new \Exception('没有分配权限');
  717. }
  718. // 3. 检查成员是否属于企业
  719. if (!$this->isCompanyMember($memberUserId, $seats['company_id'])) {
  720. throw new \Exception('该用户不是企业成员');
  721. }
  722. // 4. 检查是否已经是次卡或积分卡
  723. if (!in_array($seats['card_type'], [1, 2])) {
  724. throw new \Exception('只有次卡和积分卡支持权限分配');
  725. }
  726. // 5. 检查该成员是否已被授权
  727. $authorizedUsers = json_decode($seats['authorized_users'] ?? '[]', true);
  728. if (in_array($memberUserId, $authorizedUsers)) {
  729. throw new \Exception('该成员已被授权使用此套餐');
  730. }
  731. // 6. 查找通用记录
  732. $generalRecord = Db::table('ba_company_package_allocation')
  733. ->where('company_id', $seats['company_id'])
  734. ->where('package_price_id', $seats['package_price_id'])
  735. ->where('record_type', 0) // 通用记录
  736. ->where('is_general', 1) // 是通用记录
  737. ->order('id', 'asc')
  738. ->find();
  739. if (!$generalRecord) {
  740. throw new \Exception('未找到套餐购买记录');
  741. }
  742. // 7. 将成员添加到授权列表
  743. $authorizedUsers[] = $memberUserId;
  744. Db::table('ba_company_package_seats')
  745. ->where('id', $seatsId)
  746. ->update([
  747. 'authorized_users' => json_encode($authorizedUsers),
  748. 'assigned_member_count' => Db::raw('assigned_member_count + 1'),
  749. 'assigned_seats' => Db::raw('assigned_seats + 1'),
  750. 'available_seats' => Db::raw('available_seats - 1'),
  751. 'update_time' => date('Y-m-d H:i:s')
  752. ]);
  753. // 8. 检查是否存在已取消的分配记录
  754. $now = date('Y-m-d H:i:s');
  755. $allocationId = 0;
  756. // 查找该用户对于此套餐的已取消分配记录
  757. $canceledAllocation = Db::table('ba_company_package_allocation')
  758. ->where('company_id', $seats['company_id'])
  759. ->where('package_price_id', $seats['package_price_id'])
  760. ->where('assigned_to_user_id', $memberUserId)
  761. ->where('record_type', 1) // 用户分配记录
  762. ->where('allocation_status', 2) // 已取消状态
  763. ->order('cancel_allocation_time', 'desc') // 取最新的取消记录
  764. ->find();
  765. if ($canceledAllocation) {
  766. // 8.1 更新已取消的记录为已分配状态
  767. Db::table('ba_company_package_allocation')
  768. ->where('id', $canceledAllocation['id'])
  769. ->update([
  770. 'order_item_id' => $generalRecord['order_item_id'],
  771. 'order_id' => $generalRecord['order_id'],
  772. 'package_price_id' => $seats['package_price_id'],
  773. 'product_id' => $seats['product_id'],
  774. 'buyer_id' => $generalRecord['buyer_id'],
  775. 'company_id' => $seats['company_id'],
  776. 'assigned_to_user_id' => $memberUserId,
  777. 'assigned_by_user_id' => $allocatorId,
  778. 'record_type' => 1, // 用户分配记录
  779. 'is_general' => 0,
  780. 'parent_id' => $generalRecord['id'],
  781. 'allocation_status' => 1, // 更新为已分配
  782. 'allocation_time' => $now,
  783. 'cancel_allocation_time' => null, // 清除取消时间
  784. 'start_time' => $now,
  785. 'end_time' => null,
  786. 'expire_time' => null,
  787. 'remaining_times' => $seats['remaining_times'],
  788. 'remaining_points' => $seats['remaining_points'],
  789. 'is_used' => 0,
  790. 'usage_count' => $canceledAllocation['usage_count'] ?? 0, // 保留原有使用次数
  791. 'update_time' => $now
  792. ]);
  793. $allocationId = $canceledAllocation['id'];
  794. Log::info('复用已取消的分配记录', [
  795. 'allocation_id' => $allocationId,
  796. 'member_user_id' => $memberUserId,
  797. 'package_price_id' => $seats['package_price_id'],
  798. 'company_id' => $seats['company_id']
  799. ]);
  800. } else {
  801. // 8.2 创建新的分配记录
  802. $newAllocationData = [
  803. 'order_item_id' => $generalRecord['order_item_id'],
  804. 'order_id' => $generalRecord['order_id'],
  805. 'package_price_id' => $seats['package_price_id'],
  806. 'product_id' => $seats['product_id'],
  807. 'buyer_id' => $generalRecord['buyer_id'],
  808. 'company_id' => $seats['company_id'],
  809. 'assigned_to_user_id' => $memberUserId,
  810. 'assigned_by_user_id' => $allocatorId,
  811. 'record_type' => 1, // 用户分配记录
  812. 'is_general' => 0,
  813. 'seat_index' => 0,
  814. 'parent_id' => $generalRecord['id'], // 关联通用记录
  815. 'allocation_status' => 1, // 已分配
  816. 'allocation_time' => $now,
  817. 'start_time' => $now,
  818. 'end_time' => null,
  819. 'expire_time' => null,
  820. 'remaining_times' => $seats['remaining_times'],
  821. 'remaining_points' => $seats['remaining_points'],
  822. 'is_used' => 0,
  823. 'usage_count' => 0,
  824. 'create_time' => $now,
  825. 'update_time' => $now
  826. ];
  827. $allocationId = Db::table('ba_company_package_allocation')->insertGetId($newAllocationData);
  828. Log::info('创建新的分配记录', [
  829. 'allocation_id' => $allocationId,
  830. 'member_user_id' => $memberUserId,
  831. 'package_price_id' => $seats['package_price_id'],
  832. 'company_id' => $seats['company_id']
  833. ]);
  834. }
  835. // 9. 为用户创建产品使用记录
  836. $userProductService = new UserProductService();
  837. $orderItem = Db::table('ba_order_item')->where('id', $generalRecord['order_item_id'])->find();
  838. if ($orderItem) {
  839. $package = Db::table('ba_package_price')->where('id', $seats['package_price_id'])->find();
  840. if ($package) {
  841. $userProductService->createCompanyProductUsage($canceledAllocation, $memberUserId, $seats['card_type']);
  842. }
  843. }
  844. // 10. 记录分配日志
  845. Db::table('ba_allocation_log')->insert([
  846. 'allocation_id' => $allocationId,
  847. 'action' => 1, // 分配
  848. 'operator_id' => $allocatorId,
  849. 'to_user_id' => $memberUserId,
  850. 'remark' => $remark ?: '分配次卡/积分卡使用权限',
  851. 'create_time' => $now
  852. ]);
  853. Db::commit();
  854. return [
  855. 'success' => true,
  856. 'allocation_id' => $allocationId,
  857. 'message' => '分配成功'
  858. ];
  859. } catch (\Throwable $e) {
  860. Db::rollback();
  861. throw $e;
  862. }
  863. }
  864. /**
  865. * 检查分配权限
  866. */
  867. private function checkAssignPermission($userId, $companyId, $seatsId = null)
  868. {
  869. // 1. 检查是否是公司创建者
  870. $isCreator = Db::table('ba_company')
  871. ->where('id', $companyId)
  872. ->where('creator_id', $userId)
  873. ->count() > 0;
  874. if ($isCreator) {
  875. return true;
  876. }
  877. // 2. 检查是否是购买者(对于该套餐)
  878. if ($seatsId) {
  879. $isBuyer = Db::table('ba_company_package_allocation')
  880. // ->where('seats_id', $seatsId)
  881. ->where('buyer_id', $userId)
  882. ->count() > 0;
  883. if ($isBuyer) {
  884. return true;
  885. }
  886. }
  887. // 3. 检查是否是管理员(根据企业成员表)
  888. $isAdmin = Db::table('ba_company_member')
  889. ->where('company_id', $companyId)
  890. ->where('user_id', $userId)
  891. ->where('role', 1) // 1=管理员
  892. ->where('status', 1)
  893. ->count() > 0;
  894. return $isAdmin;
  895. }
  896. /**
  897. * 检查用户是否是企业成员
  898. */
  899. private function isCompanyMember($userId, $companyId)
  900. {
  901. // 检查是否是创建者
  902. $isCreator = Db::table('ba_company')
  903. ->where('id', $companyId)
  904. ->where('creator_id', $userId)
  905. ->count() > 0;
  906. if ($isCreator) {
  907. return true;
  908. }
  909. // 检查是否是成员
  910. $isMember = Db::table('ba_company_member')
  911. ->where('company_id', $companyId)
  912. ->where('user_id', $userId)
  913. ->where('status', 1)
  914. ->count() > 0;
  915. return $isMember;
  916. }
  917. /**
  918. * 自动分配席位给购买者
  919. */
  920. public function autoAllocateToBuyer($buyerId, $companyId, $packagePriceId, $orderId)
  921. {
  922. try {
  923. Log::info('开始自动分配席位给购买者', [
  924. 'buyer_id' => $buyerId,
  925. 'company_id' => $companyId,
  926. 'package_price_id' => $packagePriceId,
  927. 'order_id' => $orderId
  928. ]);
  929. // 1. 检查购买者是否已分配此套餐
  930. $alreadyAllocated = Db::table('ba_company_package_allocation')
  931. ->where('company_id', $companyId)
  932. ->where('package_price_id', $packagePriceId)
  933. ->where('assigned_to_user_id', $buyerId)
  934. ->where('allocation_status', 1) // 已分配
  935. ->count();
  936. Log::info('检查购买者是否已分配此套餐结果', [
  937. 'already_allocated' => $alreadyAllocated
  938. ]);
  939. if ($alreadyAllocated > 0) {
  940. Log::info('购买者已分配此套餐,跳过自动分配', [
  941. 'buyer_id' => $buyerId,
  942. 'company_id' => $companyId,
  943. 'package_price_id' => $packagePriceId
  944. ]);
  945. return false; // 已分配,跳过
  946. }
  947. // 2. 获取可用的席位ID(从席位表中获取)
  948. $seats = Db::table('ba_company_package_seats')
  949. ->where('company_id', $companyId)
  950. ->where('package_price_id', $packagePriceId)
  951. ->where('available_seats', '>', 0)
  952. ->find();
  953. Log::info('查询可用席位结果', [
  954. 'seats' => $seats ? $seats['id'] : null,
  955. 'available_seats' => $seats ? $seats['available_seats'] : 0
  956. ]);
  957. if (!$seats) {
  958. Log::error('没有可用席位进行自动分配', [
  959. 'company_id' => $companyId,
  960. 'package_price_id' => $packagePriceId
  961. ]);
  962. return false;
  963. }
  964. // 3. 获取一个未分配的分配记录
  965. $allocation = Db::table('ba_company_package_allocation')
  966. ->where('order_id', $orderId)
  967. ->where('company_id', $companyId)
  968. ->where('package_price_id', $packagePriceId)
  969. ->where('allocation_status', 0) // 未分配
  970. ->order('id', 'asc')
  971. ->find();
  972. Log::info('查询未分配记录结果', [
  973. 'allocation' => $allocation ? $allocation['id'] : null,
  974. 'order_id' => $orderId
  975. ]);
  976. if (!$allocation) {
  977. // 尝试查找任何属于该订单的未分配记录
  978. $allocation = Db::table('ba_company_package_allocation')
  979. ->where('order_id', $orderId)
  980. ->where('allocation_status', 0)
  981. ->order('id', 'asc')
  982. ->find();
  983. Log::info('二次查询未分配记录结果', [
  984. 'allocation' => $allocation ? $allocation['id'] : null
  985. ]);
  986. if (!$allocation) {
  987. Log::error('没有找到未分配的分配记录', [
  988. 'order_id' => $orderId,
  989. 'company_id' => $companyId,
  990. 'package_price_id' => $packagePriceId
  991. ]);
  992. return false;
  993. }
  994. }
  995. // 4. 获取套餐信息(用于卡类型判断)
  996. $package = Db::table('ba_package_price')
  997. ->where('id', $packagePriceId)
  998. ->find();
  999. if (!$package) {
  1000. Log::error('套餐信息不存在', ['package_price_id' => $packagePriceId]);
  1001. return false;
  1002. }
  1003. Db::startTrans();
  1004. try {
  1005. // 5. 执行分配
  1006. $now = date('Y-m-d H:i:s');
  1007. // 更新分配记录
  1008. Db::table('ba_company_package_allocation')
  1009. ->where('id', $allocation['id'])
  1010. ->update([
  1011. 'assigned_to_user_id' => $buyerId,
  1012. 'assigned_by_user_id' => $buyerId,
  1013. 'allocation_status' => 1,
  1014. 'allocation_time' => $now,
  1015. 'start_time' => $now,
  1016. 'end_time' => $this->calculateEndTime($package['card_type'], $now),
  1017. 'update_time' => $now
  1018. ]);
  1019. // 更新席位表
  1020. Db::table('ba_company_package_seats')
  1021. ->where('id', $seats['id'])
  1022. ->update([
  1023. 'assigned_seats' => Db::raw('assigned_seats + 1'),
  1024. 'available_seats' => Db::raw('available_seats - 1'),
  1025. 'update_time' => $now
  1026. ]);
  1027. // 更新订单商品
  1028. Db::table('ba_order_item')
  1029. ->where('id', $allocation['order_item_id'])
  1030. ->update([
  1031. 'is_allocated' => 1,
  1032. 'company_id' => $companyId
  1033. ]);
  1034. // 6. 记录分配日志
  1035. Db::table('ba_allocation_log')->insert([
  1036. 'allocation_id' => $allocation['id'],
  1037. 'action' => 1, // 分配
  1038. 'operator_id' => $buyerId,
  1039. 'to_user_id' => $buyerId,
  1040. 'remark' => '购买后自动分配给购买者',
  1041. 'create_time' => $now
  1042. ]);
  1043. // 7. 根据卡类型创建用户产品记录
  1044. $userProductService = new UserProductService();
  1045. // 所有卡类型都需要创建使用记录
  1046. // if ($package['card_type'] >= 3) { // 日期卡
  1047. // 日期卡分配时创建使用记录
  1048. $userProductService->createCompanyProductUsage($allocation, $buyerId, $package['card_type']);
  1049. // } else { // 次卡(1)和积分卡(2)
  1050. // // 获取订单商品信息
  1051. // $orderItem = Db::table('ba_order_item')
  1052. // ->where('id', $allocation['order_item_id'])
  1053. // ->find();
  1054. //
  1055. // if ($orderItem) {
  1056. // // 创建用户产品记录(次卡/积分卡)
  1057. // $userProductService->createUserProductRecord($buyerId, $orderItem, $package);
  1058. // }
  1059. // }
  1060. Db::commit();
  1061. Log::info('企业套餐自动分配给购买者成功', [
  1062. 'buyer_id' => $buyerId,
  1063. 'company_id' => $companyId,
  1064. 'package_price_id' => $packagePriceId,
  1065. 'allocation_id' => $allocation['id']
  1066. ]);
  1067. return true;
  1068. } catch (\Throwable $e) {
  1069. Db::rollback();
  1070. Log::error('企业套餐自动分配给购买者失败: ' . $e->getMessage());
  1071. throw $e;
  1072. }
  1073. } catch (\Throwable $e) {
  1074. Log::error('自动分配企业套餐给购买者失败: ' . $e->getMessage());
  1075. return false;
  1076. }
  1077. }
  1078. /**
  1079. * 计算到期时间
  1080. */
  1081. private function calculateEndTime($cardType, $startTime)
  1082. {
  1083. $start = strtotime($startTime);
  1084. switch ($cardType) {
  1085. case 3: // 日卡
  1086. return date('Y-m-d 23:59:59', strtotime('+1 day', $start));
  1087. case 4: // 周卡
  1088. return date('Y-m-d 23:59:59', strtotime('+7 days', $start));
  1089. case 5: // 季卡
  1090. return date('Y-m-d 23:59:59', strtotime('+90 days', $start));
  1091. case 6: // 月卡
  1092. return date('Y-m-d 23:59:59', strtotime('+30 days', $start));
  1093. case 7: // 年卡
  1094. return date('Y-m-d 23:59:59', strtotime('+365 days', $start));
  1095. default:
  1096. return null; // 次卡和积分卡没有固定到期时间
  1097. }
  1098. }
  1099. /**
  1100. * 获取卡类型文本
  1101. */
  1102. private function getCardTypeText($type)
  1103. {
  1104. $map = [
  1105. 1 => '次卡',
  1106. 2 => '积分卡',
  1107. 3 => '日卡',
  1108. 4 => '周卡',
  1109. 5 => '季卡',
  1110. 6 => '月卡',
  1111. 7 => '年卡'
  1112. ];
  1113. return $map[$type] ?? '其他';
  1114. }
  1115. private function getProductIdByPackage($packagePriceId) {
  1116. // 实现获取产品ID的逻辑
  1117. $package = Db::table('ba_package_price')->where('id', $packagePriceId)->find();
  1118. $product = Db::table('ba_product')->where('package_id', $package['package_id'])->find();
  1119. return $product ? $product['id'] : 0;
  1120. }
  1121. private function getOrderBuyerId($orderId) {
  1122. $order = Db::table('ba_order')->where('id', $orderId)->find();
  1123. return $order ? $order['user_id'] : 0;
  1124. }
  1125. /**
  1126. * 取消次卡/积分卡权限分配
  1127. */
  1128. public function cancelPackagePermission($allocationId, $operatorId, $remark = '')
  1129. {
  1130. Db::startTrans();
  1131. try {
  1132. // 1. 获取分配记录
  1133. $allocation = Db::table('ba_company_package_allocation')
  1134. ->where('id', $allocationId)
  1135. ->where('record_type', 1) // 用户分配记录
  1136. ->where('allocation_status', 1) // 已分配
  1137. ->lock(true)
  1138. ->find();
  1139. if (!$allocation) {
  1140. throw new \Exception('分配记录不存在或未分配');
  1141. }
  1142. // 2. 检查权限
  1143. $canCancel = $this->checkAssignPermission($operatorId, $allocation['company_id']);
  1144. if (!$canCancel) {
  1145. throw new \Exception('您没有取消分配的权限');
  1146. }
  1147. // 3. 获取席位信息
  1148. $seats = Db::table('ba_company_package_seats')
  1149. ->where('company_id', $allocation['company_id'])
  1150. ->where('package_price_id', $allocation['package_price_id'])
  1151. ->find();
  1152. if (!$seats) {
  1153. throw new \Exception('企业套餐席位不存在');
  1154. }
  1155. // 4. 从授权列表中移除用户
  1156. $authorizedUsers = json_decode($seats['authorized_users'] ?? '[]', true);
  1157. $key = array_search($allocation['assigned_to_user_id'], $authorizedUsers);
  1158. if ($key !== false) {
  1159. unset($authorizedUsers[$key]);
  1160. $authorizedUsers = array_values($authorizedUsers); // 重新索引数组
  1161. // 更新席位表
  1162. Db::table('ba_company_package_seats')
  1163. ->where('id', $seats['id'])
  1164. ->update([
  1165. 'authorized_users' => json_encode($authorizedUsers),
  1166. 'assigned_member_count' => Db::raw('assigned_member_count - 1'),
  1167. 'assigned_seats' => Db::raw('assigned_seats - 1'),
  1168. 'available_seats' => Db::raw('available_seats + 1'),
  1169. 'update_time' => date('Y-m-d H:i:s')
  1170. ]);
  1171. }
  1172. // 5. 更新分配记录状态
  1173. $now = date('Y-m-d H:i:s');
  1174. Db::table('ba_company_package_allocation')
  1175. ->where('id', $allocationId)
  1176. ->update([
  1177. 'allocation_status' => 2, // 已取消
  1178. 'cancel_allocation_time' => $now,
  1179. 'update_time' => $now
  1180. ]);
  1181. // 6. 删除对应的用户产品使用记录
  1182. $del=Db::table('ba_user_product_usage')
  1183. ->where('user_id', $allocation['assigned_to_user_id'])
  1184. ->where('package_price_id', $allocation['package_price_id'])
  1185. ->where('company_id', $allocation['company_id'])
  1186. ->where('package_type', 2) // 企业套餐
  1187. ->delete();
  1188. // 7. 记录取消分配日志
  1189. Db::table('ba_allocation_log')->insert([
  1190. 'allocation_id' => $allocationId,
  1191. 'action' => 2, // 取消分配
  1192. 'operator_id' => $operatorId,
  1193. 'from_user_id' => $allocation['assigned_to_user_id'],
  1194. 'remark' => $remark ?: '取消次卡/积分卡使用权限',
  1195. 'create_time' => $now
  1196. ]);
  1197. Db::commit();
  1198. return true;
  1199. } catch (\Throwable $e) {
  1200. Db::rollback();
  1201. Log::error('取消次卡/积分卡权限失败: ' . $e->getMessage());
  1202. throw $e;
  1203. }
  1204. }
  1205. /**
  1206. * 使用企业次卡/积分卡(从共享资源池扣除)
  1207. */
  1208. public function useSharedCompanyPackage($userId, $packagePriceId, $useQuantity, $productId = null, $remark = '')
  1209. {
  1210. Db::startTrans();
  1211. try {
  1212. // 1. 获取用户所在企业
  1213. $companyInfo = $this->getUserCompany($userId);
  1214. if (!$companyInfo) {
  1215. throw new \Exception('您不属于任何企业');
  1216. }
  1217. // 2. 获取套餐信息
  1218. $package = Db::table('ba_package_price')
  1219. ->where('id', $packagePriceId)
  1220. ->find();
  1221. if (!$package) {
  1222. throw new \Exception('套餐不存在');
  1223. }
  1224. // 3. 检查卡类型是否为次卡或积分卡
  1225. if (!in_array($package['card_type'], [1, 2])) {
  1226. throw new \Exception('只有次卡和积分卡支持此使用方式');
  1227. }
  1228. // 4. 获取企业套餐席位信息,检查用户是否被授权
  1229. $seats = Db::table('ba_company_package_seats')
  1230. ->where('company_id', $companyInfo['id'])
  1231. ->where('package_price_id', $packagePriceId)
  1232. ->lock(true)
  1233. ->find();
  1234. if (!$seats) {
  1235. throw new \Exception('企业套餐不存在');
  1236. }
  1237. // 检查用户是否在授权列表中
  1238. $authorizedUsers = json_decode($seats['authorized_users'] ?? '[]', true);
  1239. if (!in_array($userId, $authorizedUsers)) {
  1240. throw new \Exception('您未被授权使用此套餐');
  1241. }
  1242. // 5. 检查共享资源池是否足够
  1243. if ($package['card_type'] == 1) { // 次卡
  1244. if ($seats['remaining_times'] < $useQuantity) {
  1245. throw new \Exception('剩余次数不足,剩余:' . $seats['remaining_times'] . '次');
  1246. }
  1247. } elseif ($package['card_type'] == 2) { // 积分卡
  1248. if ($seats['remaining_points'] < $useQuantity) {
  1249. throw new \Exception('剩余积分不足,剩余:' . $seats['remaining_points'] . '积分');
  1250. }
  1251. }
  1252. // 6. 获取用户的分配记录
  1253. $userAllocation = Db::table('ba_company_package_allocation')
  1254. ->where('company_id', $companyInfo['id'])
  1255. ->where('package_price_id', $packagePriceId)
  1256. ->where('assigned_to_user_id', $userId)
  1257. ->where('allocation_status', 1)
  1258. ->order('id', 'asc')
  1259. ->find();
  1260. if (!$userAllocation) {
  1261. throw new \Exception('未找到您的分配记录');
  1262. }
  1263. // 7. 扣减共享池资源
  1264. if ($package['card_type'] == 1) { // 次卡
  1265. Db::table('ba_company_package_seats')
  1266. ->where('id', $seats['id'])
  1267. ->dec('remaining_times', $useQuantity)
  1268. ->update();
  1269. $remainingTimesAfter = $seats['remaining_times'] - $useQuantity;
  1270. $remainingPointsAfter = $seats['remaining_points'];
  1271. } else { // 积分卡
  1272. Db::table('ba_company_package_seats')
  1273. ->where('id', $seats['id'])
  1274. ->dec('remaining_points', $useQuantity)
  1275. ->update();
  1276. $remainingTimesAfter = $seats['remaining_times'];
  1277. $remainingPointsAfter = $seats['remaining_points'] - $useQuantity;
  1278. }
  1279. // 8. 更新分配记录的使用状态
  1280. Db::table('ba_company_package_allocation')
  1281. ->where('id', $userAllocation['id'])
  1282. ->update([
  1283. 'is_used' => 1,
  1284. 'usage_count' => Db::raw('usage_count + ' . $useQuantity),
  1285. 'update_time' => date('Y-m-d H:i:s')
  1286. ]);
  1287. // 9. 记录使用明细
  1288. $usageData = [
  1289. 'allocation_id' => $userAllocation['id'],
  1290. 'company_id' => $companyInfo['id'],
  1291. 'package_price_id' => $packagePriceId,
  1292. 'user_id' => $userId,
  1293. 'card_type' => $package['card_type'],
  1294. 'used_quantity' => $useQuantity,
  1295. 'remaining_times_after' => $remainingTimesAfter,
  1296. 'remaining_points_after' => $remainingPointsAfter,
  1297. 'product_id' => $productId,
  1298. 'usage_time' => date('Y-m-d H:i:s'),
  1299. 'remark' => $remark,
  1300. 'create_time' => date('Y-m-d H:i:s')
  1301. ];
  1302. $usageId = Db::table('ba_company_package_usage')->insertGetId($usageData);
  1303. Db::commit();
  1304. return [
  1305. 'success' => true,
  1306. 'usage_id' => $usageId,
  1307. 'remaining_times' => $remainingTimesAfter,
  1308. 'remaining_points' => $remainingPointsAfter,
  1309. 'message' => '使用成功'
  1310. ];
  1311. } catch (\Throwable $e) {
  1312. Db::rollback();
  1313. Log::error('使用企业次卡/积分卡失败: ' . $e->getMessage());
  1314. throw $e;
  1315. }
  1316. }
  1317. }