FinancialService.php 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Bear
  5. * Date: 2018/12/4
  6. * Time: 下午12:43
  7. */
  8. namespace app\main\service;
  9. use app\common\library\Ip;
  10. use app\common\library\Redis;
  11. use app\common\library\Ua;
  12. use app\common\model\Consume;
  13. use app\common\model\Recharge;
  14. use app\common\service\VipCpService;
  15. use app\main\constants\BookConstants;
  16. use app\main\constants\CacheConstants;
  17. use app\main\constants\ClientApiConstants;
  18. use app\main\constants\ErrorCodeConstants;
  19. use app\main\constants\OrderContents;
  20. use app\main\constants\PayConstants;
  21. use app\main\helper\ArrayHelper;
  22. use app\main\model\object\DotBookCollectObject;
  23. use think\Config;
  24. use think\Request;
  25. /**
  26. * 账务管理,money management
  27. * Class FinancialService
  28. * @package app\main\service
  29. */
  30. class FinancialService extends BaseService
  31. {
  32. /**
  33. * @var FinancialService
  34. */
  35. protected static $self = NULL;
  36. /**
  37. * @return FinancialService
  38. */
  39. public static function instance()
  40. {
  41. if (self::$self == NULL) {
  42. self::$self = new self();
  43. }
  44. return self::$self;
  45. }
  46. /**
  47. * @return Recharge
  48. */
  49. public function getRechargeModel()
  50. {
  51. return model('Recharge');
  52. }
  53. /**
  54. * @return Consume
  55. */
  56. public function getConsumeModel()
  57. {
  58. return model('Consume');
  59. }
  60. /**
  61. * 获取免费章节数量
  62. * @param $book_id
  63. * @return int|bool 返回收费章节|-1不收费
  64. */
  65. public function getFreeChapterIdx($book_id)
  66. {
  67. $book_info = BookService::instance()->getBookModel()->BookInfo($book_id);
  68. //容灾处理,如果计费出现问题在后台配置read_free=true则所有书籍都免费
  69. if( Config::get("site.free") ){
  70. return -1;
  71. }
  72. //此书设置了免费时长并且当前时间在免费时长内则免费阅读
  73. if (intval($book_info['free_stime']) < time() && intval($book_info['free_etime']) > time()) {
  74. return -1;
  75. }
  76. //此书为增购限免
  77. $user_id = UserService::instance()->getUserInfo()->id;
  78. $books = BuyMoreService::instance()->getFreeLimitCacheBook($user_id)->data;
  79. if (array_key_exists($book_id, $books)) {
  80. LogService::info('PAYMOREFREELIMIT:' . $book_id . ':' . date('Y-m-d H:i:s', $books[$book_id]));
  81. return -1;
  82. }
  83. $adminConfig = UserService::instance()->getRunTimeObject()->adminConfig;
  84. $default = ArrayHelper::array_get($adminConfig, 'book_chapter_charge_start');
  85. $book = model('BookChargeSetting')->getInfo($adminConfig['admin_id'], $book_id);
  86. if ($book && $book['chapter_charge_start']) {
  87. return $book['chapter_charge_start'] - 1;
  88. } elseif ($default) {
  89. return $default - 1;
  90. }
  91. //如果本书籍设置了免费章节数,以本书籍的免费章节数为准
  92. if( intval($book_info['free_chapter_num']) > 0 ){
  93. return $book_info['free_chapter_num'];
  94. }
  95. //全局免费章节数
  96. if (config('site.book_free_chapter_num') >= 0) {
  97. return intval(config('site.book_free_chapter_num'));
  98. }
  99. return -1;
  100. }
  101. /**
  102. * @param $book_id
  103. * @param $chapter_id
  104. * @return \app\main\model\object\ReturnObject
  105. */
  106. public function getConsumeInfo($book_id, $chapter_id, $chapter_name = '')
  107. {
  108. try {
  109. $user_info = UserService::instance()->getUserInfo();
  110. //vip用户,全部章节免费
  111. if ($user_info->vip_endtime > time()) {
  112. // 针对VIP用户判断是否是CP书籍,免费不用做消费打点,直接返回
  113. if (VipCpService::instance()->isFreeCpBookForVip($book_id, $user_info->id, $user_info->vip_endtime)) {
  114. return $this->setData($user_info->is_black)->getReturn();
  115. }
  116. }
  117. $book_info = BookService::instance()->getBookModel()->BookInfo($book_id);
  118. //获取消费记录
  119. $consume_map = ['user_id' => $user_info->id, 'book_id' => $book_id];
  120. if (intval($book_info['billing_type']) == BookConstants::BOOK_BILLING_MODEL_BOOK && intval($book_info['price']) > 0) {
  121. $consume_map['type'] = BookConstants::BOOK_BILLING_MODEL_BOOK;
  122. } else {
  123. //按章收费
  124. $consume_map['type'] = BookConstants::BOOK_BILLING_MODEL_CHAPTER;
  125. $consume_map['chapter_id'] = $chapter_id;
  126. }
  127. //当前章节已付过费
  128. if ($data = $this->getConsumeModel()->setConnect($user_info->id)->where($consume_map)->find()) {
  129. return $this->setData($data['dd_kandian'] + $data['dd_free_kandian'])->getReturn();
  130. }
  131. //全局每章节书币数
  132. $kandian = $this->getChapterPrice($book_id);
  133. //增购-折扣
  134. $disCache = CacheConstants::getBuyMoreDiscountCache($user_info->id);
  135. $discount = Redis::instance()->zRangeByScore($disCache, time(), '+inf', ['limit' => 1]);
  136. if ($discount) {
  137. $diss = explode(':', $discount[0]);
  138. $kandian = ceil($kandian * $diss[1]);
  139. LogService::info('PAYMOREDISCOUNT:' . $discount[0]);
  140. }
  141. //检查用户看点是否足够,不够时跳转支付页面
  142. UserDdFlushService::instance()->checkUserFlushState($user_info->id);
  143. $totalKandian = FinancialService::instance()->getTotalKandianAndFreeKandian($user_info->id)->data;
  144. if ($totalKandian < $kandian) {
  145. return $this->setCode(ErrorCodeConstants::REDIRECT)->getReturn();
  146. }
  147. //当前章节已进入消费流程
  148. $cacheConsume = CacheConstants::getConsumeCacheChapter($user_info->id, $chapter_id);
  149. if (Redis::instance()->setnx($cacheConsume, 1)){
  150. Redis::instance()->expire($cacheConsume, 2);
  151. } else {
  152. LogService::info('并发请求,消费退出');
  153. return $this->setData(true)->getReturn();
  154. }
  155. //消费书币
  156. $consume_return = $this->payKandian($kandian, $user_info->id);
  157. if ($consume_return->code != ErrorCodeConstants::SUCCESS) {
  158. return $consume_return;
  159. }
  160. // region 用户画像打点到Nginx
  161. $dotdata = [
  162. 'ctime' => time(),
  163. 'uid' => $user_info->id,
  164. 'openid' => $user_info->openid,
  165. 'unionid' => '',
  166. 'ip' => Ip::ip(),
  167. 'country' => Ip::country(Ip::ip()),
  168. 'province' => Ip::province(Ip::ip()),
  169. 'city' => Ip::city(Ip::ip()),
  170. 'pline' => empty(Config::get('site.theme')) ? 'xg' : Config::get('site.theme'),
  171. 'agent_id' => $user_info->agent_id ?? '',
  172. 'chid' => $user_info->channel_id ?? '',
  173. 'ua' => Ua::getUa(),
  174. 'cookie' => '',
  175. 'type' => 'consume',
  176. 'user' => [
  177. 'gender' => $user_info->sex,
  178. 'is_subscribe' => $user_info->is_subscribe,
  179. 'vip_endtime' => $user_info->vip_endtime,
  180. 'subscribe_time' => $user_info->subscribe_time,
  181. 'is_pay' => $user_info->is_pay,
  182. 'referral_id' => $user_info->referral_id,
  183. 'ext' => $user_info->ext?json_decode($user_info->ext, true):'',
  184. ],
  185. 'content' => [
  186. 'order_id' => '',
  187. 'book_id' => $book_id,
  188. 'book_sex' => $book_info['sex'], // 男频? 女频?
  189. 'book_category_id' => $book_info['book_category_id'], //书籍分类ID
  190. 'cz_consume' => $consume_return->data['kandian'], //消费充值看点
  191. 'zs_consume' => $consume_return->data['free_kandian'],//消费赠送看点
  192. ]
  193. ];
  194. curl_user_dot($dotdata);
  195. // endregion
  196. //判断此用户今天有没有在这本书扣过费,放入缓存
  197. $book_today_is_consume = $this->checkIfConsume($book_id, $user_info->id);
  198. //插入消费记录
  199. $consume_data = array_merge($consume_map, $consume_return->data, [
  200. 'user_id' => $user_info->id,
  201. 'book_id' => $book_id,
  202. 'book_name' => $book_info['name'],
  203. 'chapter_id' => $chapter_id,
  204. 'chapter_name' => !empty($chapter_name) ? $chapter_name : $chapter_id,
  205. 'createtime' => time(),
  206. 'updatetime' => time(),
  207. 'extend1' => $book_id,
  208. 'extend2' => $chapter_id,
  209. ]);
  210. $this->getConsumeModel()->setConnect($user_info->id)->insert($consume_data);
  211. $freekandian = $consume_data['free_kandian'] ?? 0;
  212. $per_kandian = $consume_data['kandian'] ?? 0;
  213. $dd_free_kandian = $consume_data['dd_free_kandian'] ?? 0;
  214. $dd_per_kandian = $consume_data['dd_kandian'] ?? 0;
  215. //添加书籍消费统计,管理员
  216. $this->bookConsumeCollect(0, $book_id, $book_today_is_consume, $kandian, $freekandian, $per_kandian);
  217. //添加书籍消费统计,渠道商
  218. $this->bookConsumeCollect(UserService::instance()->getRunTimeObject()->adminId, $book_id, $book_today_is_consume, $kandian, $freekandian, $per_kandian);
  219. //支付成功
  220. return $this->setData($dd_free_kandian + $dd_per_kandian)->getReturn();
  221. } catch (\Exception $e) {
  222. LogService::exception($e);
  223. return $this->setCode(ErrorCodeConstants::EXCEPTION)->setData(false)->getReturn();
  224. }
  225. }
  226. /**
  227. * 获取消费看点
  228. * @param $kandian
  229. * @param $user_id
  230. * @return \app\main\model\object\ReturnObject
  231. */
  232. public function payKandian($kandian, $user_id, $notes='')
  233. {
  234. //检查用户看点是否足够,不够时跳转支付页面
  235. $user_total_free_kandian = $this->getTotalFreeKandian($user_id)->data;
  236. $consume_data = [
  237. 'free_kandian' => 0,
  238. 'dd_free_kandian' => 0,
  239. 'kandian' => 0,
  240. 'dd_kandian' => 0,
  241. ];
  242. $info = [];
  243. $order = [];
  244. //扣除用户看点
  245. if ($user_total_free_kandian >= $kandian) {
  246. $data = $this->reduceFreeKandian($user_id, $kandian, [], $notes);
  247. if ($data->code != ErrorCodeConstants::SUCCESS) {
  248. return $data;
  249. }
  250. $consume_data['dd_free_kandian'] = $data->data[OrderContents::RECHARGE_DD_YES] ?? 0;
  251. $consume_data['free_kandian'] = $data->data[OrderContents::RECHARGE_DD_NO] ?? 0;
  252. while (!empty($data->data['json'])) {
  253. $recharge = array_pop($data->data['json']);
  254. $info[] = [
  255. 'id' => $recharge['recharge_id'],
  256. 'kandian' => 0,
  257. 'free_kandian' => $recharge['free_kandian'],
  258. 'dd_kandian' => 0,
  259. 'dd_free_kandian' => $recharge['dd'] == 1 ? $recharge['free_kandian'] : 0,
  260. ];
  261. if ($recharge['orders_id']) {
  262. $order[] = $recharge['orders_id'];
  263. }
  264. unset($recharge);
  265. }
  266. } else {
  267. if ($user_total_free_kandian) {
  268. $freedata = $this->reduceFreeKandian($user_id, $user_total_free_kandian, [], $notes);
  269. if ($freedata->code != ErrorCodeConstants::SUCCESS) {
  270. return $freedata;
  271. } else {
  272. $consume_data['dd_free_kandian'] = $freedata->data[OrderContents::RECHARGE_DD_YES] ?? 0;
  273. $consume_data['free_kandian'] = $freedata->data[OrderContents::RECHARGE_DD_NO] ?? 0;
  274. while (!empty($freedata->data['json'])) {
  275. $recharge = array_pop($freedata->data['json']);
  276. $info[] = [
  277. 'id' => $recharge['recharge_id'],
  278. 'kandian' => 0,
  279. 'free_kandian' => $recharge['free_kandian'],
  280. 'dd_kandian' => 0,
  281. 'dd_free_kandian' => $recharge['dd'] == 1 ? $recharge['free_kandian'] : 0,
  282. ];
  283. if ($recharge['orders_id']) {
  284. $order[] = $recharge['orders_id'];
  285. }
  286. unset($recharge);
  287. }
  288. }
  289. }
  290. //新的扣永久书币逻辑
  291. UserDdFlushService::instance()->checkUserFlushState($user_id);
  292. $data = $this->reduceKandian($user_id, $kandian - $user_total_free_kandian, [], $notes);
  293. if ($data->code != ErrorCodeConstants::SUCCESS) {
  294. return $data;
  295. }
  296. $consume_data['dd_kandian'] = $data->data[OrderContents::RECHARGE_DD_YES] ?? 0;
  297. $consume_data['kandian'] = $data->data[OrderContents::RECHARGE_DD_NO] ?? 0;
  298. while (!empty($data->data['json'])) {
  299. $recharge = array_pop($data->data['json']);
  300. $info[] = [
  301. 'id' => $recharge['recharge_id'],
  302. 'kandian' => $recharge['kandian'],
  303. 'free_kandian' => 0,
  304. 'dd_kandian' => $recharge['dd'] == 1 ? $recharge['kandian'] : 0,
  305. 'dd_free_kandian' => 0,
  306. ];
  307. if ($recharge['orders_id']) {
  308. $order[] = $recharge['orders_id'];
  309. }
  310. unset($recharge);
  311. }
  312. }
  313. /* $consume_data['consume_info'] = json_encode([
  314. 'recharge' => $info,
  315. 'orders_id' => array_unique($order),
  316. ]);*/
  317. $consume_data['free_kandian'] += $consume_data['dd_free_kandian'];
  318. $consume_data['kandian'] += $consume_data['dd_kandian'];
  319. return $this->setData($consume_data)->getReturn();
  320. }
  321. /**
  322. * 获取章节书币
  323. * @param $book_id
  324. * @return int|mixed
  325. */
  326. public function getChapterPrice($book_id)
  327. {
  328. $book_info = BookService::instance()->getBookModel()->BookInfo($book_id);
  329. //全局每章节书币数
  330. $chapter_price = config('site.book_chapter_price');
  331. if (intval($book_info['billing_type']) == BookConstants::BOOK_BILLING_MODEL_BOOK) {
  332. $chapter_price = intval($book_info['price']);
  333. } elseif ($book_info['billing_type'] == BookConstants::BOOK_BILLING_MODEL_CHAPTER) {
  334. $adminConfig = UserService::instance()->getRunTimeObject()->adminConfig;
  335. $default = ArrayHelper::array_get($adminConfig, 'book_chapter_price');
  336. $book = model('BookChargeSetting')->getInfo($adminConfig['admin_id'], $book_id);
  337. if ($book && $book['chapter_kandian']) {
  338. $chapter_price = $book['chapter_kandian'];
  339. } elseif ($default) {
  340. $chapter_price = $default;
  341. } elseif(intval($book_info['price'])) {
  342. $chapter_price = intval($book_info['price']);
  343. }
  344. }
  345. return $chapter_price;
  346. }
  347. /**
  348. * 检测用户今天有没有在这本书扣过费
  349. * @param $book_id
  350. * @return bool
  351. * @throws \Exception
  352. * @throws \think\db\exception\DataNotFoundException
  353. * @throws \think\db\exception\ModelNotFoundException
  354. * @throws \think\exception\DbException
  355. */
  356. public function checkIfConsume($book_id, $user_id)
  357. {
  358. $book_today_is_consume = false;
  359. $everyDayKey = CacheConstants::getUserIsConsumeBookByDayKey($book_id, $user_id);
  360. if (Redis::instance()->exists($everyDayKey)) {
  361. $book_today_is_consume = true;
  362. } else {
  363. $beginToday = mktime(0, 0, 0, date('m'), date('d'), date('Y'));
  364. $consumeToday = $this->getConsumeModel()->where(['user_id' => $user_id, 'book_id' => $book_id])->order('id', 'desc')->find();
  365. if (isset($consumeToday['updatetime']) && $consumeToday['updatetime'] > $beginToday) {
  366. Redis::instance()->setex($everyDayKey, 86400, '1');
  367. $book_today_is_consume = true;
  368. }
  369. }
  370. return $book_today_is_consume;
  371. }
  372. /**
  373. * 书籍计费统计
  374. * @param $channel_id
  375. * @param $book_id
  376. * @param $isConsumeToday
  377. * @param $count_kandian
  378. * @param $free_kandian
  379. * @param $recharge_kandian
  380. * @throws \Exception
  381. */
  382. private function bookConsumeCollect($channel_id,$book_id,$isConsumeToday,$count_kandian,$free_kandian,$recharge_kandian){
  383. $redis = Redis::instance();
  384. //设置渠道籍列表
  385. $collect_list_key = "BC-CL:".date("Ymd");
  386. $redis->sadd($collect_list_key,$channel_id);
  387. $redis->expire($collect_list_key,86400*2);
  388. //设置渠道商书籍列表
  389. $collect_channel_book_key = "BC-BL:{$channel_id}:".date("Ymd");
  390. $redis->sadd($collect_channel_book_key,$book_id);
  391. $redis->expire($collect_channel_book_key,86400*2);
  392. //设置渠道商对应书籍数据
  393. $collect_key = "BC:{$book_id}:{$channel_id}:".date("Ymd");
  394. if($data = json_decode($redis->get($collect_key),true)){
  395. if(!$isConsumeToday){
  396. $data['spending_users'] = intval($data['spending_users'] ?? 0)+1;
  397. }
  398. $data['spending_num'] = intval($data['spending_num'] ?? 0)+1;
  399. $data['spending_count_kandian'] = intval($data['spending_count_kandian'] ?? 0)+$count_kandian;
  400. $data['spending_free_kandian'] = intval($data['spending_free_kandian'] ?? 0)+$free_kandian;
  401. $data['spending_recharge_kandian'] = intval($data['spending_recharge_kandian'] ?? 0)+$recharge_kandian;
  402. $redis->setex($collect_key,86400*2,json_encode($data));
  403. }else{
  404. $data['spending_users'] = 1;
  405. $data['spending_num'] = 1;
  406. $data['spending_count_kandian'] = $count_kandian;
  407. $data['spending_free_kandian'] = $free_kandian;
  408. $data['spending_recharge_kandian'] = $recharge_kandian;
  409. $redis->setex($collect_key,86400*2,json_encode($data));
  410. }
  411. }
  412. /**
  413. * @param $userInfo
  414. * @param $bookInfo
  415. * @param $chapterInfo
  416. * @return \app\main\model\object\ReturnObject
  417. * @throws \think\db\exception\DataNotFoundException
  418. * @throws \think\db\exception\ModelNotFoundException
  419. * @throws \think\exception\DbException
  420. */
  421. public function feeChapterForClient($userInfo, $bookInfo, $chapterInfo)
  422. {
  423. $bookId = $bookInfo['id'];
  424. $chapterId = $chapterInfo['id'];
  425. //容灾处理,如果计费出现问题在后台配置read_free=true则所有书籍都免费
  426. if (Config::get("site.free")) {
  427. return $this->setData([
  428. 'orderState' => ClientApiConstants::ORDER_CHAPTER_STATE_FREE,
  429. 'state' => ClientApiConstants::CHAPTER_STATE_FINISH
  430. ])->getReturn();
  431. }
  432. //此书设置了免费时长并且当前时间在免费时长内则免费阅读
  433. if (intval($bookInfo['free_stime']) < time() && intval($bookInfo['free_etime']) > time()) {
  434. return $this->setData([
  435. 'orderState' => ClientApiConstants::ORDER_CHAPTER_STATE_LIMIT_FREE,
  436. 'state' => ClientApiConstants::CHAPTER_STATE_FINISH
  437. ])->getReturn();
  438. }
  439. //如果本书籍设置了免费章节数,以本书籍的免费章节数为准
  440. $chapterIdx = intval($bookInfo['free_chapter_num']);
  441. if ($chapterIdx > 0 && $chapterInfo['idx'] <= $chapterIdx) {
  442. return $this->setData([
  443. 'orderState' => ClientApiConstants::ORDER_CHAPTER_STATE_FREE,
  444. 'state' => ClientApiConstants::CHAPTER_STATE_FINISH
  445. ])->getReturn();
  446. }
  447. //全局免费章节数
  448. $siteBookFreeChapterNum = config('site.book_free_chapter_num');
  449. if ($siteBookFreeChapterNum >= 0 && $chapterInfo['idx'] <= $siteBookFreeChapterNum) {
  450. return $this->setData([
  451. 'orderState' => ClientApiConstants::ORDER_CHAPTER_STATE_FREE,
  452. 'state' => ClientApiConstants::CHAPTER_STATE_FINISH
  453. ])->getReturn();
  454. }
  455. if (empty($userInfo)) {
  456. return $this->setData([
  457. 'orderState' => ClientApiConstants::ORDER_CHAPTER_STATE_NORMAL,
  458. 'state' => ClientApiConstants::CHAPTER_STATE_NEED_LOGIN
  459. ])->getReturn();
  460. }
  461. $userId = $userInfo['id'];
  462. //vip用户,全部章节免费
  463. if ($userInfo['vip_endtime'] > time()) {
  464. return $this->setData([
  465. 'orderState' => ClientApiConstants::ORDER_CHAPTER_STATE_FREE,
  466. 'state' => ClientApiConstants::CHAPTER_STATE_FINISH
  467. ])->getReturn();
  468. }
  469. //获取消费记录
  470. $consumeMap = ['user_id' => $userId, 'book_id' => $bookId];
  471. if (intval($bookInfo['billing_type']) == BookConstants::BOOK_BILLING_MODEL_BOOK && intval($bookInfo['price']) > 0) {
  472. $consumeMap['type'] = BookConstants::BOOK_BILLING_MODEL_BOOK;
  473. } else {
  474. //按章收费
  475. $consumeMap['type'] = BookConstants::BOOK_BILLING_MODEL_CHAPTER;
  476. $consumeMap['chapter_id'] = $chapterId;
  477. }
  478. //当前章节已付过费
  479. if ($this->getConsumeModel()->setConnect($userId)->where($consumeMap)->find()) {
  480. return $this->setData([
  481. 'orderState' => ClientApiConstants::ORDER_CHAPTER_STATE_CHARGED,
  482. 'state' => ClientApiConstants::CHAPTER_STATE_FINISH
  483. ])->getReturn();
  484. }
  485. //全局每章节书币数
  486. $chapterPrice = config('site.app_book_chapter_price');
  487. if (intval($bookInfo['billing_type']) == BookConstants::BOOK_BILLING_MODEL_BOOK && intval($bookInfo['app_price']) > 0) {
  488. $chapterPrice = intval($bookInfo['app_price']);
  489. } elseif ($bookInfo['billing_type'] == BookConstants::BOOK_BILLING_MODEL_CHAPTER && intval($bookInfo['app_price']) > 0) {
  490. $chapterPrice = intval($bookInfo['app_price']);
  491. }
  492. //当前章节已进入消费流程
  493. $cacheConsume = CacheConstants::getConsumeCacheChapter($userId, $chapterId);
  494. if (Redis::instance()->exists($cacheConsume)) {
  495. return $this->setData(true)->getReturn();
  496. }
  497. $userTotalKandian = $this->getTotalKandianAndFreeKandian($userId)->data;
  498. if ($userTotalKandian < $chapterPrice) {
  499. return $this->setData([
  500. 'orderState' => ClientApiConstants::ORDER_CHAPTER_STATE_NORMAL,
  501. 'state' => ClientApiConstants::CHAPTER_STATE_BALANCE_NOT_ENOUGH,
  502. 'cost' => $chapterPrice,
  503. ])->getReturn();
  504. }
  505. Redis::instance()->set($cacheConsume, 1, 2);
  506. //扣除用户看点
  507. $consume_return = $this->payKandian($chapterPrice, $userId);
  508. if ($consume_return->code != ErrorCodeConstants::SUCCESS) {
  509. return $consume_return;
  510. }
  511. $userKandianData['kandian'] = $userInfo['kandian'] - $consume_return->data['kandian'];
  512. //减少用户书币
  513. $userKandianUpdate = UserService::instance()->getUserModel()->setConnect($userId)->update($userKandianData,
  514. ['id' => $userId]);
  515. if (!$userKandianUpdate) {
  516. //todo 减用户书币失败
  517. return $this->setCode(ErrorCodeConstants::DB_ERROR_UPDATE)->getReturn();
  518. }
  519. //更新redis
  520. $userKey = CacheConstants::getUserCacheKey($userId);
  521. if (Redis::instance()->exists($userKey)) {
  522. Redis::instance()->hmset($userKey, $userKandianData);
  523. Redis::instance()->expire($userKey, 86400);
  524. }
  525. //插入消费记录
  526. //$consume_return->data['consume_info'] = isset($consume_return->data['consume_info'])?json_encode($consume_return->data['consume_info']):'';
  527. $consumeData = array_merge($consumeMap, $consume_return->data, [
  528. 'user_id' => $userId,
  529. 'book_id' => $bookId,
  530. 'book_name' => $bookInfo['name'],
  531. 'chapter_id' => $chapterId,
  532. 'chapter_name' => $chapterInfo['name'],
  533. 'business_line' => 1,
  534. 'createtime' => time(),
  535. 'updatetime' => time(),
  536. ]);
  537. $this->getConsumeModel()->setConnect($userId)->insert($consumeData);
  538. $freeKandian = $consumeData['free_kandian'] ?? 0;
  539. $kandian = $consumeData['kandian'] ?? 0;
  540. $dotData = new DotBookCollectObject();
  541. $dotData->channelId = $userInfo['channel_id'];
  542. $dotData->eventTime = Request::instance()->server('REQUEST_TIME');
  543. $dotData->bookId = $bookId;
  544. $dotData->countKandian = $chapterPrice;
  545. $dotData->freeKandian = $freeKandian;
  546. $dotData->kandian = $kandian;
  547. $dotData->businessLine = PayConstants::BUSINESS_APP;
  548. $dot = BookDotService::instance()->generateBookData($dotData);
  549. BookDotService::instance()->dotBookInfo($dot);
  550. //支付成功
  551. return $this->setData([
  552. 'orderState' => ClientApiConstants::ORDER_CHAPTER_STATE_NORMAL,
  553. 'state' => ClientApiConstants::CHAPTER_STATE_FINISH,
  554. 'cost' => $chapterPrice,
  555. ])->getReturn();
  556. }
  557. /**
  558. * 扣减免费书币
  559. * @param $uid
  560. * @param $free_kandian
  561. * @param array $data
  562. * @return \app\main\model\object\ReturnObject
  563. */
  564. public function reduceFreeKandian($uid, $free_kandian, $data = [], $notes = '')
  565. {
  566. $redis = Redis::instance();
  567. $redisKey = CacheConstants::getFreeKandianUserRechargeListCacheKey($uid);
  568. $totalFree = $this->getTotalFreeKandian($uid)->data;
  569. if (!$totalFree) {
  570. return $this->setData($data)->getReturn();
  571. }
  572. if ($zresult = $redis->zrangebyscore($redisKey, time(), '+inf', ['limit' => [0, 2]])) {
  573. if ($value = $redis->get($zresult[0])) {
  574. $recharge = json_decode($value, true);
  575. //充值KL字段缺失
  576. if (!array_key_exists('dd', $recharge) || !array_key_exists('orders_id',$recharge)) {
  577. $setResult = $this->getFreeKandian($uid);
  578. if ($setResult->data) {
  579. return $this->reduceFreeKandian($uid, $free_kandian, $data, $notes);
  580. } else {
  581. return $this->setData($data)->getReturn();
  582. }
  583. }
  584. //充值缓存可能会过期
  585. } else {
  586. $setResult = $this->getFreeKandian($uid);
  587. if ($setResult->data) {
  588. return $this->reduceFreeKandian($uid, $free_kandian, $data, $notes);
  589. } else {
  590. return $this->setCode(ErrorCodeConstants::DB_ERROR_UPDATE)->setMsg('免费书币扣减失败1')->getReturn();
  591. }
  592. }
  593. } else {
  594. $setResult = $this->getFreeKandian($uid);
  595. if ($setResult->data) {
  596. return $this->reduceFreeKandian($uid, $free_kandian, $data, $notes);
  597. } else {
  598. return $this->setCode(ErrorCodeConstants::DB_ERROR_UPDATE)->setMsg('免费书币扣减失败2')->getReturn();
  599. }
  600. }
  601. $userKey = CacheConstants::getFreeKandianUserRechargeCacheKey($uid, $recharge['id']);
  602. if ($recharge['remain_free_kandian'] >= $free_kandian) { //如果此条记录够扣
  603. $remain = $recharge['remain_free_kandian'] - $free_kandian;
  604. $updateArr = [
  605. 'remain_free_kandian' => $remain,
  606. ];
  607. /* if (!empty($notes)) {
  608. $notes .= '--扣除免费书币:'.$free_kandian;
  609. $updateArr['notes'] = ['exp', "concat(notes, '$notes')"];
  610. }*/
  611. $res = $this->getRechargeModel()->setConnect($uid)->update($updateArr, ['id' => $recharge['id']]);
  612. if ($res) {
  613. if ($remain > 0) {
  614. $rData = [];
  615. $rData['id'] = $recharge['id'];
  616. $rData['dd'] = $recharge['dd'];
  617. $rData['orders_id'] = $recharge['orders_id'];
  618. $rData['type'] = $recharge['type'];
  619. $rData['remain_free_kandian'] = $remain;
  620. $rData['free_endtime'] = $recharge['free_endtime'];
  621. $redis->del($userKey);
  622. $redis->setex($userKey, $recharge['free_endtime'] - time(), json_encode($rData, JSON_UNESCAPED_UNICODE));
  623. } else {
  624. $redis->del($userKey);
  625. $redis->zrem($redisKey, $userKey);
  626. }
  627. $data = ArrayHelper::array_plus($data, [$recharge['dd'] => $free_kandian]);
  628. //为消费记录 准备数据
  629. $data['json'][] = [
  630. 'orders_id'=>$recharge['orders_id'],
  631. 'recharge_id'=>$recharge['id'],
  632. 'kandian' =>0,
  633. 'free_kandian'=>$free_kandian,
  634. 'dd' => $recharge['dd'],
  635. ];
  636. return $this->setData($data)->getReturn();
  637. } else {
  638. return $this->setCode(ErrorCodeConstants::DB_ERROR_UPDATE)->setMsg('免费书币扣减失败3')->getReturn();
  639. }
  640. } else {
  641. $updateArr = [
  642. 'remain_free_kandian' => 0,
  643. ];
  644. /* if (!empty($notes)) {
  645. $notes .= '--扣除免费书币:'.$recharge['remain_free_kandian'];
  646. $updateArr['notes'] = ['exp', "concat(notes, '$notes')"];
  647. }*/
  648. $res = $this->getRechargeModel()->setConnect($uid)->update($updateArr, ['id' => $recharge['id']]);
  649. if ($res) {
  650. //为消费记录 准备数据
  651. $data['json'][] = [
  652. 'orders_id' =>$recharge['orders_id'],
  653. 'recharge_id'=>$recharge['id'],
  654. 'kandian'=>0,
  655. 'free_kandian'=>$recharge['remain_free_kandian'],
  656. 'dd' => $recharge['dd']
  657. ];
  658. if (count($zresult) == 1) {
  659. $zresult = $redis->zrangebyscore($redisKey, '-inf', '+inf');
  660. if ($zresult) {
  661. foreach ($zresult as $key) {
  662. Redis::instance()->del($key);
  663. }
  664. }
  665. $redis->del($redisKey);
  666. $data = ArrayHelper::array_plus($data, [$recharge['dd'] => $recharge['remain_free_kandian']]);
  667. return $this->setData($data)->getReturn();
  668. } else {
  669. $redis->del($userKey);
  670. $redis->zrem($redisKey, $userKey);
  671. $data = ArrayHelper::array_plus($data, [$recharge['dd'] => $recharge['remain_free_kandian']]);
  672. return $this->reduceFreeKandian($uid, $free_kandian - $recharge['remain_free_kandian'], $data, $notes);
  673. }
  674. } else {
  675. return $this->setCode(ErrorCodeConstants::DB_ERROR_UPDATE)->setMsg('免费书币扣减失败4')->getReturn();
  676. }
  677. }
  678. }
  679. /**
  680. * 设置免费书币
  681. * @param $uid
  682. * @return \app\main\model\object\ReturnObject
  683. */
  684. public function getFreeKandian($uid)
  685. {
  686. $res = $this->getRechargeModel()->setConnect($uid)
  687. ->where('user_id', $uid)
  688. ->where('remain_free_kandian', '>', 0)
  689. ->where('free_endtime', '>', time())
  690. ->order('free_endtime', 'desc')
  691. ->select();
  692. $redisKey = CacheConstants::getFreeKandianUserRechargeListCacheKey($uid);
  693. $zresult = Redis::instance()->zrangebyscore($redisKey, '-inf', '+inf'); //得到未过期免费书币记录
  694. Redis::instance()->del($redisKey);
  695. if ($zresult) {
  696. foreach ($zresult as $val) {
  697. Redis::instance()->del($val);
  698. }
  699. }
  700. $return = [];
  701. if ($res) {
  702. foreach ($res as $key => $val) {
  703. $rData = [];
  704. $rData['id'] = $val->id;
  705. $rData['remain_free_kandian'] = $val->remain_free_kandian;
  706. $rData['free_endtime'] = $val->free_endtime;
  707. $rData['dd'] = $val->dd;
  708. $rData['orders_id'] = $val->orders_id;
  709. $rData['type'] = $val->type;
  710. $rechargeCacheKey = CacheConstants::getFreeKandianUserRechargeCacheKey($uid, $val->id);
  711. Redis::instance()->setex($rechargeCacheKey, $val->free_endtime - time(), json_encode($rData, JSON_UNESCAPED_UNICODE));
  712. Redis::instance()->zadd($redisKey, $val->free_endtime, $rechargeCacheKey);
  713. $return[] = $rData;
  714. LogService::info('AKDINFO:' . $rData['id'] . ':' . $rData['remain_free_kandian']);
  715. }
  716. Redis::instance()->expire($redisKey, 86400 * 5);
  717. return $this->setData($return)->getReturn();
  718. } else {
  719. return $this->setData($return)->getReturn();
  720. }
  721. }
  722. /**
  723. * 消费永久书币
  724. * @param $uid
  725. * @param $kandian
  726. * @param $data
  727. * @return \app\main\model\object\ReturnObject
  728. */
  729. public function reduceKandian($uid, $kandian, $data = [], $notes = '')
  730. {
  731. LogService::info("RDKDINFO:" . $kandian);
  732. $redis = Redis::instance();
  733. $redisKey = CacheConstants::getKandianUserRechargeListCacheKey($uid);
  734. $total = $this->getTotalKandian($uid)->data;
  735. if (!$total) {
  736. return $this->setCode(ErrorCodeConstants::DB_ERROR_UPDATE)->setMsg('永久书币不存在')->getReturn();
  737. }
  738. if ($zresult = $redis->zrangebyscore($redisKey, '-inf', '+inf', ['limit' => [0, 2]])) {
  739. if ($value = $redis->get($zresult[0])) {
  740. $recharge = json_decode($value, true);
  741. } else {
  742. $setResult = $this->getKandian($uid);
  743. if ($setResult->data) {
  744. return $this->reduceKandian($uid, $kandian, $data, $notes);
  745. } else {
  746. return $this->setCode(ErrorCodeConstants::DB_ERROR_UPDATE)->setMsg('永久书币扣减失败1')->getReturn();
  747. }
  748. }
  749. } else {
  750. $setResult = $this->getKandian($uid);
  751. if ($setResult->data) {
  752. return $this->reduceKandian($uid, $kandian, $data, $notes);
  753. } else {
  754. return $this->setCode(ErrorCodeConstants::DB_ERROR_UPDATE)->setMsg('永久书币扣减失败2')->getReturn();
  755. }
  756. }
  757. $userKey = CacheConstants::getKandianUserRechargeCacheKey($uid, $recharge['id']);
  758. if ($recharge['remain_kandian'] >= $kandian) { //如果此条记录够扣
  759. $remain = $recharge['remain_kandian'] - $kandian;
  760. $updateArr = [
  761. 'remain_kandian' => $remain
  762. ];
  763. /* if (!empty($notes)) {
  764. $notes .= '--扣除永久书币:'.$kandian;
  765. $updateArr['notes'] = ['exp', "concat(notes, '$notes')"];
  766. }*/
  767. $res = $this->getRechargeModel()->setConnect($uid)->update($updateArr, ['id' => $recharge['id']]);
  768. if ($remain > 0) {
  769. $rData = [];
  770. $rData['id'] = $recharge['id'];
  771. $rData['orders_id'] = $recharge['orders_id'];
  772. $rData['dd'] = $recharge['dd'];
  773. $rData['type'] = $recharge['type'];
  774. $rData['remain_kandian'] = $remain;
  775. $redis->del($userKey);
  776. $redis->set($userKey, json_encode($rData, JSON_UNESCAPED_UNICODE));
  777. } else {
  778. $redis->del($userKey);
  779. $redis->zrem($redisKey, $userKey);
  780. }
  781. if ($res) {
  782. $data = ArrayHelper::array_plus($data, [$recharge['dd'] => $kandian]);
  783. //为消费记录准备数据
  784. $data['json'][] = [
  785. 'orders_id'=>$recharge['orders_id'],
  786. 'recharge_id'=>$recharge['id'],
  787. 'kandian'=>$kandian,
  788. 'free_kandian'=>0,
  789. 'dd' => $recharge['dd'],
  790. ];
  791. return $this->setData($data)->getReturn();
  792. } else {
  793. return $this->setCode(ErrorCodeConstants::DB_ERROR_UPDATE)->setMsg('永久书币扣减失败3')->getReturn();
  794. }
  795. } else {
  796. $updateArr = [
  797. 'remain_kandian' => 0,
  798. ];
  799. /* if (!empty($notes)) {
  800. $notes .= '--扣除永久书币:'.$recharge['remain_kandian'];
  801. $updateArr['notes'] = ['exp', "concat(notes, '$notes')"];
  802. }*/
  803. $res = $this->getRechargeModel()->setConnect($uid)->update($updateArr, ['id' => $recharge['id']]);
  804. if ($res) {
  805. //为消费记录准备数据
  806. $data['json'][] = [
  807. 'orders_id'=>$recharge['orders_id'],
  808. 'recharge_id'=>$recharge['id'],
  809. 'kandian'=>$recharge['remain_kandian'],
  810. 'free_kandian'=>0,
  811. 'dd' => $recharge['dd']
  812. ];
  813. if (count($zresult) == 1) {
  814. $zresult = $redis->zrangebyscore($redisKey, '-inf', '+inf');
  815. if ($zresult) {
  816. foreach ($zresult as $key) {
  817. Redis::instance()->del($key);
  818. }
  819. }
  820. $redis->del($redisKey);
  821. $data = ArrayHelper::array_plus($data, [$recharge['dd'] => $recharge['remain_kandian']]);
  822. return $this->setData($data)->getReturn();
  823. } else {
  824. $redis->del($userKey);
  825. $redis->zrem($redisKey, $userKey);
  826. $data = ArrayHelper::array_plus($data, [$recharge['dd'] => $recharge['remain_kandian']]);
  827. return $this->reduceKandian($uid, $kandian - $recharge['remain_kandian'], $data, $notes);
  828. }
  829. } else {
  830. return $this->setCode(ErrorCodeConstants::DB_ERROR_UPDATE)->setMsg('永久书币扣减失败4')->getReturn();
  831. }
  832. }
  833. }
  834. /**
  835. * 缓存永久书币
  836. * @param $uid
  837. * @return \app\main\model\object\ReturnObject
  838. */
  839. public function getKandian($uid)
  840. {
  841. $res = $this->getRechargeModel()->setConnect($uid)
  842. ->where('user_id', $uid)
  843. ->where('remain_kandian', '>', 0)
  844. ->select();
  845. $userKey = CacheConstants::getKandianUserRechargeListCacheKey($uid);
  846. $zresult = Redis::instance()->zrangebyscore($userKey, '-inf', '+inf');
  847. Redis::instance()->del($userKey);
  848. if ($zresult) {
  849. foreach ($zresult as $val) {
  850. Redis::instance()->del($val);
  851. }
  852. }
  853. // dump($this->getRechargeModel()->setConnect($uid)->getLastSql());exit;
  854. $return = [];
  855. if ($res) {
  856. foreach ($res as $key => $val) {
  857. $rData = [];
  858. $rData['id'] = $val->id;
  859. $rData['orders_id'] = $val->orders_id;
  860. $rData['remain_kandian'] = $val->remain_kandian;
  861. $rData['dd'] = $val->dd;
  862. $rData['type'] = $val->type;
  863. $rechargeCache = CacheConstants::getKandianUserRechargeCacheKey($uid, $val->id);
  864. Redis::instance()->set($rechargeCache, json_encode($rData, JSON_UNESCAPED_UNICODE));
  865. Redis::instance()->zadd($userKey, $val->id, $rechargeCache);
  866. Redis::instance()->expire($userKey, 86400 * 5);
  867. $return[] = $rData;
  868. }
  869. return $this->setData($return)->getReturn();
  870. } else {
  871. return $this->setData($return)->getReturn();
  872. }
  873. }
  874. /**
  875. * 得到用户总共的免费书币数
  876. * @param $uid
  877. * @param $total
  878. * @return \app\main\model\object\ReturnObject
  879. */
  880. public function getTotalFreeKandian($uid, $total = 1)
  881. {
  882. $totalKandian = 0;
  883. $redis = Redis::instance();
  884. $redisKey = CacheConstants::getFreeKandianUserRechargeListCacheKey($uid);
  885. if ($zresult = $redis->zrangebyscore($redisKey, time(), '+inf')) {
  886. foreach ($zresult as $val) {
  887. if ($value = $redis->get($val)) {
  888. $recharge = json_decode($value, true);
  889. if (!array_key_exists('dd', $recharge)) {
  890. $this->getFreeKandian($uid);
  891. return $this->getTotalFreeKandian($uid);
  892. }
  893. if ($total) {
  894. LogService::info("KDINFO:" . $recharge['id'] . ':' . $recharge['remain_free_kandian']);
  895. $totalKandian += $recharge['remain_free_kandian'];
  896. } else {
  897. if ($recharge['dd'] == OrderContents::ORDER_DEDUCT_NO) {
  898. $totalKandian += $recharge['remain_free_kandian'];
  899. }
  900. }
  901. } else {
  902. $this->getFreeKandian($uid);
  903. return $this->getTotalFreeKandian($uid);
  904. }
  905. }
  906. } else {
  907. $res = $this->getFreeKandian($uid);
  908. if ($res->data) {
  909. return $this->getTotalFreeKandian($uid);
  910. }
  911. }
  912. LogService::info("freekandian:" . $totalKandian);
  913. return $this->setData($totalKandian)->getReturn();
  914. }
  915. /**
  916. * 获取永久看点
  917. * @param $uid
  918. * @param int $total
  919. * @return \app\main\model\object\ReturnObject
  920. */
  921. public function getTotalKandian($uid, $total = 1)
  922. {
  923. $totalKandian = 0;
  924. $redis = Redis::instance();
  925. $redisKey = CacheConstants::getKandianUserRechargeListCacheKey($uid);
  926. if ($zresult = $redis->zrangebyscore($redisKey, '-inf', '+inf')) {
  927. foreach ($zresult as $val) {
  928. if ($value = $redis->get($val)) {
  929. $recharge = json_decode($value, true);
  930. if (!array_key_exists('dd', $recharge) || !array_key_exists('orders_id', $recharge)) {
  931. $this->getKandian($uid);
  932. return $this->getTotalKandian($uid);
  933. }
  934. if ($total) {
  935. LogService::info("KDINFO:" . $recharge['id'] . ':' . $recharge['remain_kandian']);
  936. $totalKandian += $recharge['remain_kandian'];
  937. } else {
  938. if ($recharge['dd'] == OrderContents::ORDER_DEDUCT_NO) {
  939. $totalKandian += $recharge['remain_kandian'];
  940. }
  941. }
  942. } else {
  943. $this->getKandian($uid);
  944. return $this->getTotalKandian($uid);
  945. }
  946. }
  947. } else {
  948. $res = $this->getKandian($uid);
  949. if ($res->data) {
  950. return $this->getTotalKandian($uid);
  951. }
  952. }
  953. LogService::info('kandian:' . $totalKandian);
  954. return $this->setData($totalKandian)->getReturn();
  955. }
  956. /**
  957. * @param $uid
  958. * @param $total int 1=总剩余 0=渠道剩余
  959. * @return \app\main\model\object\ReturnObject
  960. */
  961. public function getTotalRemainKandian($uid, $total = 1)
  962. {
  963. if ($total) {
  964. $rechargeTotal = model('recharge')->setConnect($uid)->where([
  965. 'user_id' => $uid,
  966. ])->sum('kandian');
  967. $consumeTotal = model('consume')->setConnect($uid)->where([
  968. 'user_id' => $uid,
  969. ])->sum('kandian');
  970. } else {
  971. $rechargeTotal = model('recharge')->setConnect($uid)->where([
  972. 'user_id' => $uid,
  973. 'dd' => '0',
  974. ])->sum('kandian');
  975. $consumeTotal = model('consume')->setConnect($uid)->where([
  976. 'user_id' => $uid,
  977. ])->sum('kandian-dd_kandian');
  978. }
  979. $remain = $rechargeTotal - $consumeTotal;
  980. if ($remain < 0) {
  981. $remain = 0;
  982. }
  983. return $this->setData($remain)->getReturn();
  984. }
  985. /**
  986. * @param $uid
  987. * @param $total int 1=总剩余 0=渠道剩余
  988. * @return \app\main\model\object\ReturnObject
  989. */
  990. public function getTotalRemainFreeKandian($uid, $total = 1)
  991. {
  992. if ($total) {
  993. $rechargeTotal = model('recharge')->setConnect($uid)->where('free_endtime', 'gt', time())->where([
  994. 'user_id' => $uid,
  995. ])->sum('free_kandian');
  996. $consumeTotal = model('consume')->setConnect($uid)->where([
  997. 'user_id' => $uid,
  998. ])->sum('free_kandian');
  999. } else {
  1000. $rechargeTotal = model('recharge')->setConnect($uid)->where('free_endtime', 'gt', time())->where([
  1001. 'user_id' => $uid,
  1002. 'dd' => '0',
  1003. ])->sum('free_kandian');
  1004. $consumeTotal = model('consume')->setConnect($uid)->where([
  1005. 'user_id' => $uid,
  1006. ])->sum('free_kandian-dd_free_kandian');
  1007. }
  1008. $remain = $rechargeTotal - $consumeTotal;
  1009. if ($remain < 0) {
  1010. $remain = 0;
  1011. }
  1012. return $this->setData($remain)->getReturn();
  1013. }
  1014. /**
  1015. * @param $uid
  1016. * @param $total int 1=总剩余 0=渠道剩余
  1017. * @return \app\main\model\object\ReturnObject
  1018. */
  1019. public function getTotalRemainOldFreeKandian($uid, $total = 1)
  1020. {
  1021. if ($total) {
  1022. $remain = model('recharge')->setConnect($uid)->where('free_endtime', 'lt', time())->where([
  1023. 'user_id' => $uid,
  1024. ])->sum('remain_free_kandian');
  1025. } else {
  1026. $remain = model('recharge')->setConnect($uid)->where('free_endtime', 'lt', time())->where([
  1027. 'user_id' => $uid,
  1028. 'dd' => '0',
  1029. ])->sum('remain_free_kandian');
  1030. }
  1031. return $this->setData($remain)->getReturn();
  1032. }
  1033. /**
  1034. * 修改用户书币
  1035. * @param $id
  1036. * @param $type
  1037. * @param $edit_type
  1038. * @param int $kandian
  1039. * @param int $free_kandian
  1040. * @param string $notes
  1041. * @return \app\main\model\object\ReturnObject
  1042. */
  1043. public function modifyUserKandian($id, $type, $edit_type, $kandian = 0, $free_kandian = 0, $notes = '',$extend_type=0,$free_day=0)
  1044. {
  1045. $user = UserService::instance()->getUserModel()->getUserInfo($id);
  1046. if ($user) {
  1047. $init = []; //新增充值记录
  1048. $init['user_id'] = $id;
  1049. $init['type'] = 3;
  1050. $init['edit_type'] = $edit_type;
  1051. $init['notes'] = $notes;
  1052. if ($kandian > 0 || $free_kandian > 0) {
  1053. $init['edit_type'] = 1;
  1054. }
  1055. $init['createtime'] = time();
  1056. UserDdFlushService::instance()->checkUserFlushState($id);
  1057. if ($type == 1) { //增加书币
  1058. if ($kandian > 0) {
  1059. $recharge_kandian = $init;
  1060. //系统增加书币时,将永久书币改赠送书币(20天)
  1061. if ($free_day){
  1062. $recharge_kandian['extend_type'] = $extend_type;
  1063. $recharge_kandian['free_kandian'] = $kandian;
  1064. $recharge_kandian['remain_free_kandian'] = $kandian;
  1065. $recharge_kandian['free_endtime'] = $free_day * 86400 + time();
  1066. model('Recharge')->setConnect($id)->insertGetId($recharge_kandian);
  1067. $userKey = CacheConstants::getFreeKandianUserRechargeListCacheKey($id);
  1068. Redis::instance()->del($userKey);
  1069. }else{
  1070. $recharge_kandian['kandian'] = $kandian;
  1071. $recharge_kandian['remain_kandian'] = $kandian;
  1072. $recharge_kandian['extend_type'] = $extend_type;
  1073. model('Recharge')->setConnect($id)->insertGetId($recharge_kandian);
  1074. $userKey = CacheConstants::getKandianUserRechargeListCacheKey($id);
  1075. Redis::instance()->del($userKey);
  1076. }
  1077. }
  1078. if ($free_kandian) {
  1079. $recharge_free = $init;
  1080. $recharge_free['free_kandian'] = $free_kandian;
  1081. $recharge_free['remain_free_kandian'] = $free_kandian;
  1082. $recharge_free['extend_type'] = $extend_type;//增加活動類型字段1,活動報名,2活動贈送书币
  1083. $recharge_free['free_endtime'] = intval(config('site.kandian_free_day')) * 86400 + time();
  1084. model('Recharge')->setConnect($id)->insertGetId($recharge_free);
  1085. $userKey = CacheConstants::getFreeKandianUserRechargeListCacheKey($id);
  1086. Redis::instance()->del($userKey);
  1087. }
  1088. } elseif ($type == 2) { //减少书币
  1089. if ($kandian > 0) { //永久书币
  1090. $res = FinancialService::instance()->reduceKandian($id, $kandian, [], $notes);
  1091. if ($res->code != ErrorCodeConstants::SUCCESS) {
  1092. return $res;
  1093. }
  1094. //添加扣减记录
  1095. $result = $res->data;
  1096. if (isset($result['0'])) {
  1097. //普通书币
  1098. $saveDate = [];
  1099. $saveDate['user_id'] = $id;
  1100. $saveDate['type'] = 3;
  1101. $saveDate['edit_type'] = $edit_type;
  1102. $saveDate['dd'] = 0;
  1103. $saveDate['notes'] = $notes;
  1104. $saveDate['kandian'] = -1*$result['0'];
  1105. $saveDate['remain_kandian'] = 0;
  1106. $saveDate['createtime'] = time();
  1107. model('Recharge')->setConnect($id)->insertGetId($saveDate); //插入充值记录
  1108. }
  1109. if (isset($result['1'])) {
  1110. //扣量书币
  1111. $saveDate = [];
  1112. $saveDate['user_id'] = $id;
  1113. $saveDate['type'] = 3;
  1114. $saveDate['edit_type'] = $edit_type;
  1115. $saveDate['dd'] = 1;
  1116. $saveDate['notes'] = $notes;
  1117. $saveDate['kandian'] = -1*$result['1'];
  1118. $saveDate['remain_kandian'] = 0;
  1119. $saveDate['createtime'] = time();
  1120. model('Recharge')->setConnect($id)->insertGetId($saveDate); //插入充值记录
  1121. }
  1122. }
  1123. if ($free_kandian) { //免费书币
  1124. //减少免费书币
  1125. $res = FinancialService::instance()->reduceFreeKandian($id, $free_kandian, [], $notes);
  1126. if ($res->code != ErrorCodeConstants::SUCCESS) {
  1127. return $res;
  1128. }
  1129. }
  1130. }
  1131. } else { //没有此用户
  1132. return $this->setCode(ErrorCodeConstants::DB_ERROR_SELECT)->setMsg('用户不存在')->getReturn();
  1133. }
  1134. return $this->setData(true)->getReturn();
  1135. }
  1136. public function reduceKandianCampaign( $userId, $match ){
  1137. try{
  1138. //更新老用户 remain_kandian;
  1139. UserDdFlushService::instance()->checkUserFlushState($userId);
  1140. //扣除永久书币
  1141. $res = $this->reduceKandian($userId,$match['kandian'],[],'消耗活动');
  1142. if ( $res->code == 0 ){
  1143. $info = $order = [];
  1144. while (!empty($res->data['json'])) {
  1145. $recharge = array_pop($res->data['json']);
  1146. $info[] = [
  1147. 'id' => $recharge['recharge_id'],
  1148. 'kandian' => $recharge['kandian'],
  1149. 'free_kandian' => 0,
  1150. 'dd_kandian' => $recharge['dd'] == 1 ? $recharge['kandian'] : 0,
  1151. 'dd_free_kandian' => 0,
  1152. ];
  1153. if ($recharge['orders_id']) {
  1154. $order[] = $recharge['orders_id'];
  1155. }
  1156. unset($recharge);
  1157. }
  1158. // 增加消费记录
  1159. $campJson = json_encode([
  1160. 'campaign_id'=>(int)$match['campaign_id'],
  1161. 'campaign_name'=>$match['activeName'],
  1162. 'match_id'=> (int)$match['id'],
  1163. 'match_name'=>$match['match_date'].$match['kandian'],
  1164. ]);
  1165. $consumeData = [
  1166. 'user_id' => (int)$userId,
  1167. 'type' => 3,
  1168. 'chapter_name'=>'',
  1169. 'kandian'=>$match['kandian'],
  1170. 'dd_kandian'=>$res->data[1]??0,
  1171. 'createtime' => time(),
  1172. 'updatetime' => time(),
  1173. 'camp_info'=>$campJson,
  1174. ];
  1175. $this->getConsumeModel()->setConnect($userId)->insert($consumeData);
  1176. // region 用户画像打点到Nginx
  1177. $user_info = UserService::instance()->getUserModel()->getUserInfo($userId, false);
  1178. $ip_redis_key = CacheConstants::USER_IP_PREFIX . $userId;
  1179. $ip_arr = json_decode(Redis::instance()->get($ip_redis_key), true, 1024);
  1180. try{
  1181. $dotdata = [
  1182. 'ctime' => time(),
  1183. 'uid' => $user_info['id'],
  1184. 'openid' => $user_info['openid'],
  1185. 'unionid' => '',
  1186. 'ip' => $ip_arr['ip'] ?? '',
  1187. 'country' => $ip_arr['country'] ?? '',
  1188. 'province' => $ip_arr['province'] ?? '',
  1189. 'city' => $ip_arr['city'] ?? '',
  1190. 'pline' => empty(Config::get('site.theme')) ? 'xg' : Config::get('site.theme'),
  1191. 'agent_id' => $user_info['agent_id'] ?? '',
  1192. 'chid' => $user_info['channel_id'] ?? '',
  1193. 'ua' => $ip_arr['ua'],
  1194. 'cookie' => '',
  1195. 'type' => 'consume',
  1196. 'user' => [
  1197. 'gender' => $user_info['sex'] ?? '',
  1198. 'is_subscribe' => $user_info['is_subscribe'] ?? '',
  1199. 'vip_endtime' => $user_info['vip_endtime'] ?? '',
  1200. 'subscribe_time' => $user_info['subscribe_time'] ?? '',
  1201. 'is_pay' => $user_info['is_pay'] ?? '',
  1202. 'referral_id' => $user_info['referral_id'] ?? '',
  1203. 'ext' => $user_info['ext'] ? json_decode($user_info['ext'], true) : '',
  1204. ],
  1205. 'content' => [
  1206. 'order_id' => '',
  1207. 'book_id' => '',
  1208. 'book_sex' => '', // 男频? 女频?
  1209. 'book_category_id' => '', //书籍分类ID
  1210. 'cz_consume' => $match['kandian'], //消费充值看点
  1211. 'zs_consume' => 0,//消费赠送看点
  1212. ]
  1213. ];
  1214. curl_user_dot($dotdata);
  1215. }catch (\Exception $exception){
  1216. LogService::error($exception->getMessage());
  1217. }
  1218. // endregion
  1219. return $this->setData(['code'=>0,])->getReturn();
  1220. }
  1221. return $res;
  1222. }catch (\Exception $e){
  1223. LogService::exception($e);
  1224. return $this->setCode(ErrorCodeConstants::EXCEPTION)->setData(false)->getReturn();
  1225. }
  1226. }
  1227. /**
  1228. * 获取免费看点+永久看点
  1229. * @param $uid
  1230. * @param int $total
  1231. * @return \app\main\model\object\ReturnObject
  1232. */
  1233. public function getTotalKandianAndFreeKandian($uid, $total = 1)
  1234. {
  1235. $kandian = $this->getTotalKandian($uid, $total)->data;
  1236. $free = $this->getTotalFreeKandian($uid, $total)->data;
  1237. return $this->setData($kandian + $free)->getReturn();
  1238. }
  1239. }