CompanyPackageService.php 59 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479
  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. }