You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

406 lines
14 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. <?php
  2. namespace App\Service;
  3. use App\Model\OrderMain;
  4. use App\Model\ShopCar;
  5. use Hyperf\Di\Annotation\Inject;
  6. use Hyperf\DbConnection\Db;
  7. use App\Model\CouponUserRecType;
  8. use App\Model\Coupon;
  9. use App\Model\CouponRec;
  10. use App\Model\CouponUserUse;
  11. use Hyperf\Utils\ApplicationContext;
  12. use App\TaskWorker\SSDBTask;
  13. use App\Constants\SsdbKeysPrefix;
  14. use App\Constants\LogLabel;
  15. use App\Commons\Log;
  16. use Exception;
  17. use App\Service\CommonService;
  18. use Hyperf\Redis\Redis;
  19. class CouponService implements CouponServiceInterface
  20. {
  21. /**
  22. * @Inject
  23. * @var Log
  24. */
  25. protected $log;
  26. /**
  27. * @Inject
  28. * @var CommonService
  29. */
  30. protected $commonService;
  31. /**
  32. * 获取用户可领取优惠卷接口
  33. */
  34. public function getSystemCouponUserList($userId,$receiveType)
  35. {
  36. /* 优惠券活动标志 2 */
  37. $ssdb = ApplicationContext::getContainer()->get(SSDBTask::class);
  38. $couponActivity = $ssdb->exec('hgetall', SsdbKeysPrefix::COUPON_REBATE_ACTIVITY);
  39. $activityType = $couponActivity === false ? 0 : $couponActivity['activity'];
  40. $result = [
  41. 'active_type' => 1,
  42. 'not_receive' => [],
  43. 'jump_data' => [
  44. 'src' => "/zh_cjdianc/pages/couponrebate/index?activity_type=".$activityType,
  45. 'src2' => "/zh_cjdianc/pages/couponrebate/index?activity_type=".$activityType,
  46. 'share_bg' => env('OSS_IMG_HOST').'/static/img/coupon_share.png',
  47. 'receive_bg' => env('OSS_IMG_HOST').'/static/img/coupon_bg.png',
  48. 'coupons' => []
  49. ]
  50. ];
  51. $nowTime = time();
  52. $c_ids = [];
  53. $whereC = [
  54. ['end_time','>',$nowTime],
  55. ['start_time','<=',$nowTime],
  56. ['status','=',1]
  57. ];
  58. // 渠道开启,查询该渠道可以领取的优惠券ID
  59. // 渠道未开启,查询所有优惠券
  60. if (env('SUB_CHANNEL') == 1) {
  61. $c_ids = CouponUserRecType::where('receive_type', $receiveType)->where($whereC)->pluck('system_coupon_user_id');
  62. } else {
  63. $c_ids = Coupon::where($whereC)->pluck('id');
  64. }
  65. $couponReceive = CouponRec::where('user_id',$userId);
  66. // 渠道开启,查询该用户在此渠道领过的优惠券ID
  67. if (env('SUB_CHANNEL') == 1) {
  68. $couponReceive->where('receive_type', $receiveType);
  69. }
  70. $cr_ids = $couponReceive->pluck('system_coupon_user_id');
  71. // 可领取的券ID
  72. $c_ids = $c_ids->toArray();
  73. // 已经领取的券ID
  74. $cr_ids = $cr_ids->toArray();
  75. // 当前用户可领的优惠券ID
  76. $couponIds = array_diff($c_ids, $cr_ids);
  77. // 转发型优惠券
  78. $couponReceiveIds = ($couponActivity === false || $this->commonService->empty($couponActivity['forward']) )? [] : explode(',',$couponActivity['forward']);
  79. // 所有优惠券
  80. $couponIds = array_merge($couponIds,$couponReceiveIds);
  81. $whereC = [
  82. ['u.end_time','>',$nowTime],
  83. ['u.start_time','<=',$nowTime],
  84. ['u.status','=',1]
  85. ];
  86. // 查询领取型1 和 转发型2
  87. $whereActiveType = [1,2];
  88. if (env('SUB_CHANNEL') == 1) {
  89. array_push($whereC, ['type.receive_type','=', $receiveType]);
  90. }
  91. $coupons = Db::table('ims_system_coupon_user as u')
  92. ->join('ims_system_coupon_user_receivetype as type', 'u.id', '=', 'type.system_coupon_user_id')
  93. ->whereIn('u.id', $couponIds)
  94. ->whereIn('u.active_type', $whereActiveType)
  95. ->where($whereC)
  96. ->whereRaw('u.inventory_use < u.inventory and u.inventory-u.inventory_use >= type.one_receive_number')
  97. ->select('u.*','type.one_receive_number')
  98. ->orderBy('u.weigh','desc')
  99. ->get();
  100. foreach ($coupons as $k => &$v){
  101. if($v->active_type == 1 && count($result['not_receive']) < 4){
  102. $result['not_receive'][] = $v;
  103. }else if($v->active_type == 2 && in_array($v->id,$couponReceiveIds)){
  104. $result['jump_data']['coupons'][] = $v->id;
  105. }
  106. if($v->discount_type == 2){
  107. $v->discounts = floatval($v->discounts);
  108. }
  109. }
  110. $result['active_type'] = count($result['jump_data']['coupons']) > 0 ? 2 : $result['active_type'] ;
  111. return $result;
  112. }
  113. //统计用户
  114. public function userCouponAccount()
  115. {
  116. }
  117. /**
  118. * 用户领取优惠卷
  119. */
  120. public function userReceiveCoupon()
  121. {
  122. }
  123. /**
  124. * 获取用户已经领取的优惠卷列表
  125. */
  126. public function getUserReceiveCouponList()
  127. {
  128. }
  129. /**
  130. * 获取用户当前订单可用的优惠券列表
  131. * 按分类(1订单 等优惠)分组返回
  132. */
  133. public function getUserAvailableCoupons($orderAmount,$userId,$marketId,$type,$storetypeId,$carIds)
  134. {
  135. $available = [];
  136. $notAvailable = [];
  137. $storetypeIds = explode(',', str_replace(',', ',', $storetypeId));
  138. if (empty($orderAmount) || empty($userId)) {
  139. return [
  140. 'available' => $available,
  141. 'not_available' => array_values($notAvailable)
  142. ];
  143. }
  144. // 获取用户优惠券
  145. $currentTime = time();
  146. $data = Db::table('ims_system_coupon_user_receive as receive')
  147. ->select([
  148. 'receive.id as receive_id',
  149. 'receive.user_id',
  150. 'receive.number_remain',
  151. 'coupon.id',
  152. 'coupon.title',
  153. 'coupon.full_amount',
  154. 'coupon.discounts',
  155. 'coupon.usable_start_time',
  156. 'coupon.usable_end_time',
  157. 'coupon.discount_type'
  158. ])
  159. ->join('ims_system_coupon_user as coupon', 'coupon.id', '=', 'receive.system_coupon_user_id')
  160. ->where(['receive.user_id' => $userId])
  161. ->whereIn('receive.status', [0,1])
  162. ->where('receive.number_remain', '>', 0)
  163. ->whereIn('coupon.type', [1,$type])
  164. ->where('coupon.full_amount', '<=', $orderAmount)
  165. ->where('coupon.usable_start_time', '<=', $currentTime)
  166. ->where('coupon.usable_end_time', '>=', $currentTime)
  167. ->where('coupon.usable_number', '<=', Db::raw('receive.number_remain'))
  168. ->where('coupon.market_id', 'in', [0, $marketId])
  169. ->whereIn('coupon.storetype_id', $storetypeIds)
  170. ->orderByRaw('coupon.discounts DESC, coupon.full_amount DESC')
  171. ->get();
  172. // 分离用户今天用过的优惠券种类
  173. $container = ApplicationContext::getContainer();
  174. $redis = $container->get(Redis::class);
  175. $couponIds = $redis->sMembers('coupon_'.date('Ymd').'_used_'.$userId);
  176. foreach ($data as $key => &$item) {
  177. if (in_array($item->id, $couponIds)) {
  178. $item->msg = '今日已使用';
  179. $notAvailable[$item->id] = $item;
  180. } else {
  181. $available[] = $item;
  182. }
  183. }
  184. //如果存在特价商品 不给用券
  185. $carIdsArr = explode(',',$carIds);
  186. $shopCarExists = ShopCar::whereIn('id',$carIdsArr)
  187. ->where('money',0.01)
  188. ->exists();
  189. if($shopCarExists){
  190. var_dump(1111);
  191. foreach ($available as $k => $v) {
  192. $v->msg = '特价商品不可使用';
  193. $notAvailable[$v->id] = $v;
  194. }
  195. $available = [];
  196. }
  197. return [
  198. 'available' => $available,
  199. 'not_available' => array_values($notAvailable)
  200. ];
  201. }
  202. /**
  203. * @inheritDoc
  204. */
  205. public function getOrderCanUseCoupons($orderAmount, $marketId, $userId, $fields=[], $type = 1, $storeTypeIds = [0])
  206. {
  207. // 用户今日使用过的优惠券
  208. $redis = ApplicationContext::getContainer()->get(Redis::class);
  209. $couponTodayUsedIds = $redis->sMembers('coupon_'.date('Ymd').'_used_'.$userId);
  210. $currentTime = time();
  211. $builder = Db::table('ims_system_coupon_user_receive as receive')
  212. ->join('ims_system_coupon_user as coupon', 'coupon.id', '=', 'receive.system_coupon_user_id', 'inner');
  213. if (is_array($fields)&&!empty($fields)) {
  214. $builder->select($fields);
  215. }
  216. if (is_array($couponTodayUsedIds)&&!empty($couponTodayUsedIds)) {
  217. $builder->whereNotIn('coupon.id', $couponTodayUsedIds);
  218. }
  219. return $builder->where(['receive.user_id' => $userId])
  220. ->whereIn('receive.status', [0,1])
  221. ->where('receive.number_remain', '>', 0)
  222. ->whereIn('coupon.type', [1,$type])
  223. ->where('coupon.full_amount', '<=', $orderAmount)
  224. ->where('coupon.usable_start_time', '<=', $currentTime)
  225. ->where('coupon.usable_end_time', '>=', $currentTime)
  226. ->where('coupon.usable_number', '<=', Db::raw('receive.number_remain'))
  227. ->where('coupon.market_id', 'in', [0, $marketId])
  228. ->whereIn('coupon.storetype_id', $storeTypeIds)
  229. ->orderByRaw('coupon.discounts DESC, coupon.full_amount DESC')
  230. ->get()
  231. ->toArray();
  232. }
  233. /**
  234. * 缓存优惠券今日使用情况
  235. * @param $userId
  236. * @param $couponId
  237. * @param $couponRecId
  238. * @return bool
  239. */
  240. function cacheTodayCouponUsed($userId, $couponId, $couponRecId)
  241. {
  242. $redis = ApplicationContext::getContainer()->get(Redis::class);
  243. $setRes = $redis->sAdd(
  244. 'coupon_'.date('Ymd').'_used_'.$userId,
  245. $couponId
  246. );
  247. $expireRes = $redis->expire(
  248. 'coupon_'.date('Ymd').'_used_'.$userId,
  249. strtotime(date('Y-m-d').' 23:59:59')-time()
  250. );
  251. return $setRes&&$expireRes;
  252. }
  253. /**
  254. * 取消订单返券
  255. * @param $order_id
  256. * @return bool
  257. */
  258. public function refundOrderCoupons($global_order_id){
  259. $order_main = OrderMain::where('global_order_id',$global_order_id)
  260. ->select('id','user_id')
  261. ->first();
  262. $order_id = $order_main->id;
  263. $coupon = CouponUserUse::where([
  264. ['order_main_id','=',$order_id],
  265. ['status','=',CouponUserUse::COUPON_USE_STATE_USED],
  266. ])
  267. ->select('id','user_receive_id','number')
  268. ->first();
  269. if (empty($coupon)) {
  270. return '';
  271. }
  272. // 返回用户优惠券数量并更新状态
  273. $res = Db::update("UPDATE ims_system_coupon_user_receive SET number_remain=number_remain+{$coupon->number}, status=IF(number=number_remain,0,1), update_time=".time().""
  274. ." WHERE id={$coupon->user_receive_id} AND number>=(number_remain+{$coupon->number})");
  275. // 更新使用记录状态为已退回
  276. CouponUserUse::where([
  277. ['id','=',$coupon->id],
  278. ['status','=',CouponUserUse::COUPON_USE_STATE_USED],
  279. ])
  280. ->update([
  281. 'status' => CouponUserUse::COUPON_USE_STATE_CANCEL,
  282. 'return_time' => time(),
  283. 'update_time' => time(),
  284. ]);
  285. //删除当日 redis 使用记录缓存
  286. $redis = ApplicationContext::getContainer()->get(Redis::class);
  287. $remRes = $redis->sRem(
  288. 'coupon_'.date('Ymd').'_used_'.$order_main->user_id,
  289. $coupon->system_coupon_id
  290. );
  291. return $remRes;
  292. }
  293. /* 删除-优惠券今日使用的缓存
  294. * @param $userId
  295. * @param $couponId
  296. * @return bool
  297. */
  298. public function clearTodayCouponUsed($userId, $couponId)
  299. {
  300. $redis = ApplicationContext::getContainer()->get(Redis::class);
  301. $res = $redis->sRem(
  302. 'coupon_'.date('Ymd').'_used_'.$userId,
  303. $couponId
  304. );
  305. return $res;
  306. }
  307. /**
  308. * 退款返还优惠券
  309. * 先查询是否正常使用优惠券
  310. * 修改状态,退还领取记录库存,删除ssdb缓存
  311. */
  312. public function orderRefundCoupons($global_order_id)
  313. {
  314. $order_main = OrderMain::where('global_order_id',$global_order_id)
  315. ->select('id','user_id')
  316. ->first();
  317. $time = time();
  318. Db::beginTransaction();
  319. try {
  320. $couponUses = CouponUserUse::query()
  321. ->select('id','system_coupon_id','user_id','number','user_receive_id')
  322. ->where('order_main_id',$order_main->id)
  323. ->where('status',CouponUserUse::COUPON_USE_STATE_USED)
  324. ->get();
  325. if(!empty($couponUses)){
  326. foreach($couponUses as $use){
  327. $use->status = CouponUserUse::COUPON_USE_STATE_CANCEL;
  328. $use->return_time = $time;
  329. $use->update_time = $time;
  330. $res = $use->save();
  331. $couponReceive = CouponRec::query()
  332. ->where('id',$use->user_receive_id)
  333. ->whereRaw('number >= number_remain+'.$use->number)
  334. ->update([
  335. 'number_remain' => Db::raw('number_remain+'.$use->number),
  336. 'status' => Db::raw('IF(number=number_remain,' . CouponRec::STATE_UNUSED . ',' . CouponRec::STATE_SOME . ')'),
  337. 'update_time' => $time
  338. ]);
  339. $clearUseRedis = $this->clearTodayCouponUsed($use->user_id,$use->system_coupon_id);
  340. }
  341. }
  342. Db::commit();
  343. return true;
  344. } catch (Exception $e) {
  345. $this->log->event(LogLabel::ORDER_LOG, ['msg'=> '订单退款','exception' => $e->getMessage()]);
  346. Db::rollBack();
  347. return false;
  348. }
  349. }
  350. }