UserDdFlushService.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. <?php
  2. /**
  3. * Created by: PhpStorm
  4. * User: lytian
  5. * Date: 2019/9/23
  6. * Time: 19:26
  7. */
  8. namespace app\main\service;
  9. use app\common\library\Redis;
  10. use app\main\constants\CacheConstants;
  11. use app\main\constants\OrderContents;
  12. use app\main\constants\UserConstants;
  13. use think\Exception;
  14. use think\Log;
  15. class UserDdFlushService extends BaseService
  16. {
  17. /**
  18. * @var UserDdFlushService
  19. */
  20. protected static $self = null;
  21. /**
  22. * @return BaseService|UserDdFlushService
  23. */
  24. public static function instance()
  25. {
  26. if (self::$self == NULL) {
  27. self::$self = new self();
  28. }
  29. return self::$self;
  30. }
  31. /**
  32. * 刷用户充值记录的剩余永久书币
  33. */
  34. public function flushUserRechargeRemainKandian($user_id, $kandian)
  35. {
  36. //从后向前刷
  37. $rows = model("Recharge")->setConnect($user_id)->where('user_id', 'eq', $user_id)->where('kandian', '>', 0)->order("id desc")->select();
  38. if ($rows) {
  39. $remain = $kandian;
  40. foreach ($rows as $row) {
  41. if ($remain >0) {
  42. if ($row['kandian'] <= $remain) {
  43. $row->save(['remain_kandian' => $row['kandian']]);
  44. $remain = $remain-$row['kandian'];
  45. Log::info("刷新永久书币 用户:{$user_id} 永久剩余书币 充值记录:{$row['id']} 插入:{$row['kandian']},待处理书币:{$remain}");
  46. } else {
  47. $row->save(['remain_kandian' => $remain]);
  48. Log::info("刷新永久书币 用户:{$user_id} 永久剩余书币 充值记录:{$row['id']} 插入:{$remain},待处理书币:0");
  49. $remain = 0;
  50. Log::info("刷新永久书币 用户:{$user_id} 永久剩余书币 已全部处理");
  51. }
  52. } else {
  53. if ($row['remain_kandian'] >0) {
  54. $row->save(['remain_kandian' => 0]);
  55. }
  56. }
  57. }
  58. } else {
  59. Log::info("刷新永久书币 用户:{$user_id} 永久剩余书币 没有充值记录");
  60. }
  61. $cacheKey = CacheConstants::getKandianUserRechargeListCacheKey($user_id);
  62. Redis::instance()->del($cacheKey);
  63. return true;
  64. }
  65. /**
  66. * 刷新用户的消费记录
  67. * @param $user_id
  68. */
  69. public function flushUserConsume($user_id)
  70. {
  71. //拉出所有的充值记录 排好序
  72. $rechargeRows = model("Recharge")->setConnect($user_id)->where('user_id', 'eq', $user_id)->where('vip_starttime', 'exp', 'is null')->order('id asc')->select();
  73. if (empty($rechargeRows)) {
  74. Log::info("刷用户消费记录 用户:{$user_id} 没找到充值记录");
  75. return true;
  76. }
  77. //扣除负数的永久书币
  78. for ($i = 0; $i< count($rechargeRows); $i++) {
  79. if ($rechargeRows[$i]['kandian'] < 0) {
  80. //负的的 往前扣
  81. $j = $i;
  82. $kandian = abs($rechargeRows[$i]['kandian']);
  83. while ($j > 0) {
  84. if ($kandian <= 0) {
  85. break;
  86. }
  87. if ($rechargeRows[$j]['kandian'] > 0) {
  88. if ($kandian >= $rechargeRows[$j]['kandian']) {
  89. //不够扣
  90. $kandian = $kandian - $rechargeRows[$j]['kandian'];
  91. $rechargeRows[$j]['kandian'] = 0;
  92. } else {
  93. //够
  94. $rechargeRows[$j]['kandian'] = $rechargeRows[$j]['kandian'] - $kandian;
  95. $kandian = 0;
  96. }
  97. }
  98. $j--;
  99. }
  100. }
  101. }
  102. //找出所有的消费记录 从前向后
  103. model("Consume")->setConnect($user_id)->where('user_id', 'eq', $user_id)->chunk(100, function ($consumeRows) use (&$rechargeRows, $user_id) {
  104. if (count($consumeRows) > 0) {
  105. $stop = false;
  106. foreach ($consumeRows as $consumeRow) {
  107. $currentConsumeId = $consumeRow['id'];
  108. if (count($rechargeRows) <=0) {
  109. Log::error("刷用户消费记录 用户:{$user_id} 充值记录不够扣");
  110. break;
  111. }
  112. $ddFreeKandian = $ddKandian = 0;
  113. //找出当时所有免费书币和永久书币
  114. if ($consumeRow['free_kandian']) {
  115. Log::info("刷用户消费记录 用户:{$user_id} ID:{$currentConsumeId} 免费书币:{$consumeRow['free_kandian']} 开始进行");
  116. //消耗的是免费看点
  117. $remain = $consumeRow['free_kandian'];
  118. foreach ($rechargeRows as $key =>$rechargeRow) {
  119. if ($rechargeRow['free_kandian'] == 0) {
  120. //说明不是免费书币记录
  121. continue;
  122. }
  123. if ($rechargeRow['free_endtime'] < $consumeRow['createtime']){
  124. continue;
  125. }
  126. if ($remain > $rechargeRow['free_kandian']) {
  127. //不够扣的
  128. if ($rechargeRow['dd'] == 1) {
  129. //扣量赠送书币
  130. $ddFreeKandian += $rechargeRow['free_kandian'];
  131. Log::info("刷用户消费记录 用户:{$user_id} ID:{$currentConsumeId} 免费书币:{$consumeRow['free_kandian']} 刷入扣量免费书币:{$rechargeRow['free_kandian']} 对应充值记录:{$rechargeRow['id']}:当前0");
  132. }else{
  133. Log::info("刷用户消费记录 用户:{$user_id} ID:{$currentConsumeId} 免费书币:{$consumeRow['free_kandian']} 刷入免费书币:{$rechargeRow['free_kandian']} 对应充值记录:{$rechargeRow['id']}:当前0");
  134. }
  135. $remain -= $rechargeRow['free_kandian'];
  136. $rechargeRow['free_kandian'] = 0;
  137. unset($rechargeRows[$key]);
  138. } else {
  139. //够扣
  140. $rechargeRow['free_kandian'] = $rechargeRow['free_kandian'] - $remain;
  141. if ($rechargeRow['dd'] == 1) {
  142. //扣量赠送书币
  143. $ddFreeKandian += $remain;
  144. Log::info("刷用户消费记录 用户:{$user_id} ID:{$currentConsumeId} 免费书币:{$consumeRow['free_kandian']} 刷入扣量免费书币:{$remain} 对应充值记录:{$rechargeRow['id']}:当前{$rechargeRow['free_kandian']}");
  145. }else{
  146. Log::info("刷用户消费记录 用户:{$user_id} ID:{$currentConsumeId} 免费书币:{$consumeRow['free_kandian']} 刷入免费书币:{$remain} 对应充值记录:{$rechargeRow['id']}:当前{$rechargeRow['free_kandian']}");
  147. }
  148. //扣完删除
  149. if ($rechargeRow['free_kandian'] == 0) {
  150. unset($rechargeRows[$key]);
  151. }
  152. break;
  153. }
  154. }
  155. }
  156. if ($consumeRow['kandian']) {
  157. //永久看点
  158. $remain = $consumeRow['kandian'];
  159. Log::info("刷用户消费记录 用户:{$user_id} ID:{$currentConsumeId} 永久书币:{$consumeRow['kandian']} 开始进行");
  160. foreach ($rechargeRows as $key =>$rechargeRow) {
  161. if ($rechargeRow['free_kandian'] > 0) {
  162. //免费的跳过
  163. continue;
  164. }
  165. if ($rechargeRow['kandian'] <=0) {
  166. //负的 删掉
  167. unset($rechargeRows[$key]);
  168. continue;
  169. }
  170. if ($remain > $rechargeRow['kandian']) {
  171. //不够扣的
  172. if ($rechargeRow['dd'] == 1) {
  173. //扣量永久书币
  174. $ddKandian += $rechargeRow['kandian'];
  175. Log::info("刷用户消费记录 用户:{$user_id} ID:{$currentConsumeId} 永久书币:{$consumeRow['kandian']} 刷入扣量永久书币:{$rechargeRow['kandian']} 对应充值记录:{$rechargeRow['id']}");
  176. }
  177. $remain = $remain - $rechargeRow['kandian'];
  178. $rechargeRow['kandian'] = 0;
  179. unset($rechargeRows[$key]);
  180. } else {
  181. //够扣
  182. $rechargeRow['kandian'] = $rechargeRow['kandian'] - $remain;
  183. if ($rechargeRow['dd'] == 1) {
  184. //扣量赠送书币
  185. $ddKandian += $remain;
  186. Log::info("刷用户消费记录 用户:{$user_id} ID:{$currentConsumeId} 永久书币:{$consumeRow['kandian']} 刷入扣量永久书币:{$remain} 对应充值记录:{$rechargeRow['id']}");
  187. }
  188. //扣完删除
  189. if ($rechargeRow['kandian'] == 0) {
  190. unset($rechargeRows[$key]);
  191. }
  192. break;
  193. }
  194. }
  195. }
  196. $consumeRow->save(['dd_kandian' => $ddKandian, 'dd_free_kandian' => $ddFreeKandian]);
  197. Log::info("刷用户消费记录 用户:{$user_id} ID:{$currentConsumeId} 永久书币:{$consumeRow['kandian']} 刷入扣量永久书币:{$ddKandian} 免费书币:{$consumeRow['free_kandian']} 刷入扣量免费书币:{$ddFreeKandian}");
  198. }
  199. unset($consumeRows);
  200. if ($stop) {
  201. return false;
  202. }
  203. } else {
  204. return false;
  205. }
  206. }, 'id', 'asc');
  207. foreach ($rechargeRows as $key => $rechargeRow) {
  208. if ($rechargeRow['free_kandian'] != $rechargeRow['remain_free_kandian']) {
  209. model("Recharge")->setConnect($user_id)
  210. ->update(['remain_free_kandian' => $rechargeRow['free_kandian']], ['id' => $rechargeRow['id']]);
  211. LogService::info('错误回滚:' . $rechargeRow['id'] . ':' . $rechargeRow['free_kandian'] . ':' . $rechargeRow['remain_free_kandian']);
  212. }
  213. }
  214. }
  215. /**
  216. * 重置用户状态
  217. * @param $user_id
  218. * @return bool
  219. */
  220. public function checkUserFlushState($user_id)
  221. {
  222. $userInfo = UserService::instance()->getUserModel()->getUserInfo($user_id);
  223. if ($userInfo) {
  224. try {
  225. $userInfo['flush_state'] = $userInfo['flush_state'] ?? UserConstants::USER_FLUSH_STATE_ORIGIN;
  226. if ($userInfo['flush_state'] == UserConstants::USER_FLUSH_STATE_ORIGIN) {
  227. $this->flushRechargeDd($user_id);
  228. $kandianLeft = FinancialService::instance()->getTotalRemainKandian($user_id)->data;
  229. //时间差用户 全量跑recharge表
  230. if ($kandianLeft > 0) {
  231. $this->flushUserRechargeRemainKandian($user_id, $kandianLeft);
  232. }
  233. UserService::instance()->update(['flush_state' => UserConstants::USER_FLUSH_STATE_READ], ['id' => $user_id]);
  234. // model("User")->setConnect($user_id)->update(['flush_state' => UserConstants::USER_FLUSH_STATE_READ], ['id' => $user_id]);
  235. // Redis::instance()->del('UN:'.$user_id);
  236. } else if ($userInfo['flush_state'] == UserConstants::USER_FLUSH_STATE_COMMAND) {
  237. $this->flushRechargeDd($user_id);
  238. $kandianLeft = FinancialService::instance()->getTotalRemainKandian($user_id)->data;
  239. $kandian = FinancialService::instance()->getTotalKandian($user_id)->data;
  240. if ($kandianLeft != $kandian) {
  241. //需要重刷
  242. $this->flushUserRechargeRemainKandian($user_id, $kandianLeft);
  243. }
  244. UserService::instance()->update(['flush_state' => UserConstants::USER_FLUSH_STATE_READ], ['id' => $user_id]);
  245. // model("User")->setConnect($user_id)->update(['flush_state' => UserConstants::USER_FLUSH_STATE_READ], ['id' => $user_id]);
  246. // Redis::instance()->del('UN:'.$user_id);
  247. }
  248. } catch (Exception $e) {
  249. Log::info("刷用户剩余永久书币异常 用户ID:{$user_id}");
  250. LogService::exception($e);
  251. }
  252. }
  253. return true;
  254. }
  255. /**
  256. * 设置渠道vip时间
  257. * @param $user_id
  258. */
  259. public function flushVip($user_id)
  260. {
  261. $db = FinancialService::instance()->getRechargeModel()
  262. ->setConnect($user_id);
  263. $list = $db
  264. ->where('user_id', $user_id)
  265. ->whereIn('type', [OrderContents::RECHARGE_TYPE_VIP, OrderContents::RECHARGE_TYPE_SYS_VIP])
  266. ->where('dd', OrderContents::ORDER_DEDUCT_NO)
  267. ->order('id', 'asc')
  268. ->select();
  269. if ($list) {
  270. foreach ($list as $index=>$currentRecharge) {
  271. if (!$index) {
  272. $db->update(['channel_vip_starttime' => $currentRecharge['createtime']], ['id' => $currentRecharge['id']]);
  273. } else {
  274. $days = intval($list[$index - 1]['day']);
  275. $hours = intval($list[$index - 1]['hour']);
  276. $preEndTime = $list[$index - 1]['channel_vip_starttime'] + $days * 86400 + $hours * 3600;
  277. if ($currentRecharge['createtime'] > $preEndTime) {
  278. $db->update(['channel_vip_starttime' => $currentRecharge['createtime']], ['id' => $currentRecharge['id']]);
  279. } else {
  280. $db->update(['channel_vip_starttime' => $preEndTime], ['id' => $currentRecharge['id']]);
  281. }
  282. }
  283. }
  284. }
  285. }
  286. /**
  287. * 更新充值的dd字段
  288. * @param $user_id
  289. */
  290. public function flushRechargeDd($user_id)
  291. {
  292. $orders = OrderService::instance()->getOrderModel()
  293. ->where('user_id', $user_id)
  294. ->where('state', OrderContents::ORDER_STATE_PAID)
  295. ->where('deduct', OrderContents::ORDER_DEDUCT_YES)
  296. ->select();
  297. $rechargeIds = [];
  298. if ($orders) {
  299. foreach ($orders as $order) {
  300. $res = FinancialService::instance()->getRechargeModel()
  301. ->setConnect($user_id)
  302. ->field('id, createtime')
  303. ->where('user_id', $user_id)
  304. ->where('type', $order['type'])
  305. ->where('createtime', '>=', $order['finishtime'])
  306. ->order('createtime', 'asc')
  307. ->limit(0, 2)
  308. ->select();
  309. if (count($res) == 1) {
  310. $rechargeIds[] = $res[0]['id'];
  311. } elseif (count($res) == 2) {//用一个用户,2个recharge记录相差2s以内算作一个订单的充值
  312. $sub = abs($res[0]['createtime'] - $res[1]['createtime']);
  313. if ($sub < 3) {
  314. $rechargeIds[] = $res[0]['id'];
  315. $rechargeIds[] = $res[1]['id'];
  316. } else {
  317. $rechargeIds[] = $res[0]['id'];
  318. }
  319. }
  320. }
  321. }
  322. if ($rechargeIds) {
  323. FinancialService::instance()->getRechargeModel()
  324. ->setConnect($user_id)
  325. ->whereIn('id', $rechargeIds)
  326. ->update(['dd' => OrderContents::ORDER_DEDUCT_YES]);
  327. LogService::info('用户充值信息更新:' . json_encode($rechargeIds, JSON_UNESCAPED_UNICODE));
  328. }
  329. }
  330. }