PaymentService.php 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. <?php
  2. namespace app\common\service;
  3. use app\common\model\PaymentModel;
  4. use app\common\model\ScoreLogModel;
  5. use app\common\model\ServicesOrderModel;
  6. use app\common\model\ShopGoodsModel;
  7. use app\common\model\ShopOrderGoodsModel as OrderGoods;
  8. use app\common\model\ShopOrderModel;
  9. use app\common\model\ThirdpayBackModel;
  10. use app\common\model\UserModel;
  11. use think\facade\Db;
  12. use utils\RedisCache;
  13. /**
  14. * 支付服务 by wes
  15. * Class PaymentService
  16. * @package app\common\service
  17. */
  18. class PaymentService
  19. {
  20. protected static $instance = null;
  21. protected $cacheTime = 7200;
  22. protected $payWayArr = [
  23. 1=>'wxpay',
  24. 2=>'alipay',
  25. 3=>'balancePay',
  26. 14=>'huifuPay',
  27. 15=>'sqzpay',
  28. 16=>'sqzAliPay',
  29. 17=>'sqzWxPay',
  30. 18=>'sqzYljk',
  31. 19=>'usdtPay',
  32. 20=>'yswkPay',
  33. 22=>'dkpay',
  34. 56=>'ysftyPay',
  35. 66=>'dkysf',
  36. ];
  37. protected $model = null;
  38. public function __construct()
  39. {
  40. $this->model = new PaymentModel();
  41. }
  42. /**
  43. * 静态化入口
  44. * @return static|null
  45. */
  46. public static function make()
  47. {
  48. if(!self::$instance){
  49. self::$instance = new static();
  50. }
  51. return self::$instance;
  52. }
  53. /**
  54. * 获取支付方式标识
  55. * @param $payType 支付类型
  56. * @return string
  57. */
  58. public function getPayCode($payType)
  59. {
  60. return isset($this->payWayArr[$payType])? $this->payWayArr[$payType] : 'defpay';
  61. }
  62. /**
  63. * 按状态获取支付单数量
  64. * @param $uid
  65. * @param $orderType
  66. * @param $state
  67. * @param int $time 时间/小时,默认2小时
  68. * @return array|mixed
  69. * @throws \think\db\exception\DataNotFoundException
  70. * @throws \think\db\exception\DbException
  71. * @throws \think\db\exception\ModelNotFoundException
  72. */
  73. public function getPaymentCountByState($uid, $orderSn='', $orderType, $state, $time = 2)
  74. {
  75. $cacheKey = "caches:paymentCall:u{$uid}_ot{$orderType}_s{$state}_{$time}_{$orderSn}";
  76. $data = RedisCache::get($cacheKey);
  77. if($data){
  78. return $data;
  79. }
  80. $where = [];
  81. if($orderType){
  82. $where['order_type'] = $orderType;
  83. }
  84. if($state){
  85. $where['state'] = $state;
  86. }
  87. $data = $this->model->where($where)->where(function ($query) use($time,$orderSn){
  88. if($time>0){
  89. $query->where('creat_at','>=', time() - $time * 3600);
  90. }
  91. if($orderSn){
  92. $query->where('remarks',$orderSn);
  93. }
  94. })->count('id');
  95. if($data){
  96. RedisCache::set($cacheKey, $data, rand(3,5));
  97. }
  98. return $data;
  99. }
  100. /**
  101. * 验证订单是否已支付
  102. * @param $uid
  103. * @param $orderSn
  104. * @return array|mixed
  105. * @throws \think\db\exception\DataNotFoundException
  106. * @throws \think\db\exception\DbException
  107. * @throws \think\db\exception\ModelNotFoundException
  108. */
  109. public function checkPaymentState($uid, $orderSn)
  110. {
  111. $cacheKey = "caches:paymentState:u{$uid}_sn{$orderSn}";
  112. $data = RedisCache::get($cacheKey);
  113. if($data){
  114. return $data;
  115. }
  116. $data = $this->model->where(['state'=> 6])->where(function ($query) use($orderSn){
  117. if($orderSn){
  118. $query->where('remarks', $orderSn);
  119. }
  120. })->value('id');
  121. if($data){
  122. RedisCache::set($cacheKey, $data, rand(2,3));
  123. }
  124. return $data;
  125. }
  126. /**
  127. * 获取支付信息(有缓存)
  128. * @param $outTradeNo
  129. * @param int $state
  130. * @param string $field
  131. * @param false $cache
  132. * @return array|mixed
  133. */
  134. public function getCacheInfo($outTradeNo, $state=7, $field='', $cache = false)
  135. {
  136. $cacheKey = "caches:payment:info:otn{$outTradeNo}_{$state}".($field? '_'.md5($field):'');
  137. $data = RedisCache::get($cacheKey);
  138. if($data && $cache){
  139. return $data;
  140. }
  141. $where = ['out_trade_no'=> $outTradeNo];
  142. if($state){
  143. $where['state'] = $state;
  144. }
  145. $field = $field? $field : 'id,out_trade_no,uid,total_fee,state,trade_type,out_trade_no1,hy_token_id,syl_sureorderid,hy_bill_no,is_retreat,pay_way,order_type,sid,remarks,trade_no';
  146. $data = $this->model->where($where)
  147. ->field($field)
  148. ->order('creat_at desc')
  149. ->findOrEmpty();
  150. if($data && $cache){
  151. RedisCache::set($cacheKey, $data, rand(5,10));
  152. }
  153. return $data;
  154. }
  155. /**
  156. * 支付回调处理
  157. * @param $outTradeNo
  158. * @param $payMoney
  159. * @param $payType
  160. * @param $content
  161. * @throws \think\Exception
  162. * @throws \think\db\exception\DataNotFoundException
  163. * @throws \think\db\exception\DbException
  164. * @throws \think\db\exception\ModelNotFoundException
  165. */
  166. public function payBack($outTradeNo, $payMoney, $payType, $content)
  167. {
  168. $nowTime = date('Y-m-d H:i:s');
  169. $params = $content? json_decode($content, true):[];
  170. $payCode = PaymentService::make()->getPayCode($payType);
  171. $cacheKey = "caches:payNotify:{$payCode}:otn_{$outTradeNo}:";
  172. RedisCache::set($cacheKey.'catch', ['params'=>$params,'date'=> $nowTime], $this->cacheTime);
  173. // 验证支付请求信息
  174. $payInfo = PaymentService::make()->getCacheInfo($outTradeNo, 0);
  175. $payId = isset($payInfo['id'])? $payInfo['id']:0;
  176. $payUid = isset($payInfo['uid'])? $payInfo['uid']:0;
  177. $payState = isset($payInfo['state'])? intval($payInfo['state']):0;
  178. $totalFee = isset($payInfo['total_fee'])? floatval($payInfo['total_fee']):0;
  179. $orderSn = isset($payInfo['remarks'])? trim($payInfo['remarks']):'';
  180. $orderType = isset($payInfo['order_type'])? intval($payInfo['order_type']) : 0;
  181. if (!$payInfo || $payUid<=0 || empty($orderSn) || $payState!= 7) {
  182. $error = empty($payInfo) || !$payId || empty($orderSn)? "单号{$orderSn}支付信息不存在或参数错误":"单号{$orderSn}已经回调支付";
  183. $logData = ['params'=>$params,'payInfo'=>$payInfo,'msg'=> $error,'date'=> $nowTime];
  184. RedisCache::set($cacheKey.'error', $logData, $this->cacheTime);
  185. sr_throw($error);
  186. }
  187. // 验证支付金额
  188. if($payMoney < $totalFee || $totalFee<=0){
  189. $logData = ['params'=>$params,'payInfo'=>$payInfo,'msg'=> "单号{$orderSn}支付金额错误",'date'=> $nowTime];
  190. RedisCache::set($cacheKey.'error', $logData, $this->cacheTime);
  191. sr_throw("单号{$orderSn}支付金额错误");
  192. }
  193. // 更新支付状态
  194. if(!PaymentModel::where('id', $payId)->update(['state' => 6, 'pay_at' => $nowTime])){
  195. $logData = ['params'=>$params,'payInfo'=>$payInfo,'msg'=> "单号{$orderSn}更新支付状态失败",'date'=> $nowTime];
  196. RedisCache::set($cacheKey.'_error', $logData, $this->cacheTime);
  197. sr_throw("单号{$orderSn}更新支付状态失败");
  198. }
  199. // 第三方回调数据
  200. $data = [
  201. 'out_order_no' => $outTradeNo,
  202. 'content' => $content,
  203. 'create_time' => sr_getcurtime(time()),
  204. 'type' => $payType,
  205. 'uid' => $payUid,
  206. 'money' => $payMoney
  207. ];
  208. if(!ThirdpayBackModel::insertGetid($data)){
  209. $logData = ['params'=>$params,'payInfo'=>$payInfo,'third'=>$data,'msg'=> "单号{$orderSn}处理第三方回调数据错误",'date'=> $nowTime];
  210. RedisCache::set($cacheKey.'_error', $logData, $this->cacheTime);
  211. sr_throw("单号{$orderSn}处理第三方回调数据错误");
  212. }
  213. /* TODO 服务商订单处理 */
  214. if ($orderType == 6) {
  215. // 获取验证订单信息
  216. $orderInfo = ServiceOrderService::make()->getInfoBySn($orderSn, $payUid);
  217. $orderId = isset($orderInfo['order_id'])? $orderInfo['order_id'] : 0;
  218. $orderMoney = isset($orderInfo['payment'])? floatval($orderInfo['payment']) : 0;
  219. $orderStatus = isset($orderInfo['status'])? intval($orderInfo['status']) : 0;
  220. if(empty($orderInfo) || $orderId<=0 || $orderMoney<=0){
  221. $logData = ['params'=>$params,'payInfo'=>$payInfo,'order'=>$orderInfo,'msg'=> "服务商订单{$orderSn}不存在或参数错误",'date'=> $nowTime];
  222. RedisCache::set($cacheKey.'_error', $logData, $this->cacheTime);
  223. sr_throw("服务商订单{$orderSn}不存在或参数错误");
  224. }
  225. // 验证订单状态
  226. if($orderStatus != 1){
  227. $logData = ['params'=>$params,'payInfo'=>$payInfo,'order'=>$orderInfo,'msg'=> "服务商订单{$orderSn}订单已处理",'date'=> $nowTime];
  228. RedisCache::set($cacheKey.'_error', $logData, $this->cacheTime);
  229. sr_throw("服务商订单{$orderSn}订单已处理");
  230. }
  231. // 更新订单状态
  232. if(!ServicesOrderModel::where('order_id', $orderId)->update(['status' => 2, 'pay_type' => $payType, 'updated_time' => $nowTime])){
  233. $logData = ['params'=>$params,'payInfo'=>$payInfo,'order'=>$orderInfo,'msg'=> "服务商订单{$orderSn}更新状态错误",'date'=> $nowTime];
  234. RedisCache::set($cacheKey.'_error', $logData, $this->cacheTime);
  235. sr_throw("服务商订单{$orderSn}更新状态错误");
  236. }
  237. // 更新用户服务商有效期
  238. $date = sr_getcurtime(time(), 'Y-m-d');
  239. $expireDay = date('Y-m-d', strtotime("$date +1 month"));
  240. if(!UserModel::where('id', $payUid)->update(['store_type' => 1,'store_expire_time' => $expireDay,'update_time'=>time()])){
  241. $logData = ['params'=>$params,'payInfo'=>$payInfo,'order'=>$orderInfo,'storeExpire'=>$expireDay,'msg'=> "服务商订单{$orderSn}更新用户服务商有效期错误",'date'=> $nowTime];
  242. RedisCache::set($cacheKey.'_error', $logData, $this->cacheTime);
  243. sr_throw("服务商订单{$orderSn}更新用户服务商有效期错误");
  244. }
  245. $logData = ['params'=>$params,'payInfo'=>$payInfo,'order'=>$orderInfo,'storeExpire'=>$expireDay,'msg'=> "服务商订单{$orderSn}支付回调处理成功",'date'=> $nowTime];
  246. RedisCache::set($cacheKey."success_{$orderSn}", $logData, $this->cacheTime);
  247. }
  248. /** TODO 商城订单处理 **/
  249. elseif ($orderType == 4) {
  250. // 获取验证订单信息
  251. $orderInfo = ShopOrderService::make()->getInfoBySn($orderSn, $payUid);
  252. $orderId = isset($orderInfo['order_id'])? $orderInfo['order_id'] : 0;
  253. $orderMoney = isset($orderInfo['payment'])? floatval($orderInfo['payment']) : 0;
  254. $orderStatus = isset($orderInfo['status'])? intval($orderInfo['status']) : -1;
  255. if(empty($orderInfo) || $orderId<=0 || $orderMoney<=0){
  256. $logData = ['params'=>$params,'payInfo'=>$payInfo,'order'=>$orderInfo,'msg'=> "商城订单{$orderSn}不存在或参数错误",'date'=> $nowTime];
  257. RedisCache::set($cacheKey."error_{$orderSn}", $logData, $this->cacheTime);
  258. sr_throw("商城订单{$orderSn}不存在或参数错误");
  259. }
  260. // 验证订单状态
  261. if($orderStatus != 0){
  262. $logData = ['params'=>$params,'payInfo'=>$payInfo,'order'=>$orderInfo,'msg'=> "商城订单{$orderSn}订单已处理",'date'=> $nowTime];
  263. RedisCache::set($cacheKey."error_{$orderSn}", $logData, $this->cacheTime);
  264. sr_throw("商城订单{$orderSn}订单已处理");
  265. }
  266. // 更新订单状态
  267. if(!ShopOrderModel::where('order_id', $orderId)->update(['status' => 1, 'pay_type' => $payType, 'updated_time' => $nowTime])){
  268. $logData = ['params'=>$params,'payInfo'=>$payInfo,'order'=>$orderInfo,'msg'=> "服务商订单{$orderSn}更新状态错误",'date'=> $nowTime];
  269. RedisCache::set($cacheKey.'_error', $logData, $this->cacheTime);
  270. sr_throw("服务商订单{$orderSn}更新状态错误");
  271. }
  272. // 增加订单商品销量
  273. $updateSale = ShopOrderModel::alias('a')
  274. ->leftJoin('shop_order_goods og', 'og.order_id=a.order_id')
  275. ->leftJoin('shop_goods g', 'g.goods_id=og.goods_id')
  276. ->where(['a.order_id' => $orderId, 'a.user_id' => $payUid])
  277. ->update([
  278. 'g.sales_volume' => Db::raw('g.sales_volume + og.num'),
  279. 'g.real_sales_volume' => Db::raw('g.real_sales_volume + og.num'),
  280. ]);
  281. if (!$updateSale) {
  282. Db::rollback();
  283. $logData = ['params' => $params, 'orderInfo' => $orderInfo, 'payInfo' => $payInfo, 'error' => "商城订单{$orderSn}更新商品销量失败", 'date' => $date];
  284. RedisCache::set($cacheKey . "error_{$orderSn}", $logData, 7200);
  285. sr_throw("商城订单{$orderSn}更新商品销量失败");
  286. }
  287. // 更新用户交易额(消费)
  288. $userInfo = UserService::make()->getCacheInfo($payUid,'id,mobile,score,money,path', false);
  289. $upperPath = isset($userInfo['path'])? $userInfo['path'] : '';
  290. if($userInfo && !UserModel::where('id', $payUid)->inc('total_income', $totalFee)->inc('total_team_income',$totalFee)->update()){
  291. $logData = ['params'=>$params,'payInfo'=>$payInfo,'user'=>$userInfo,'order'=>$orderInfo,'msg'=> "商城订单{$orderSn}更新用户交易数据错误",'date'=> $nowTime];
  292. RedisCache::set($cacheKey."error_{$orderSn}", $logData, $this->cacheTime);
  293. sr_throw("商城订单{$orderSn}更新用户交易数据错误");
  294. }
  295. // 更新团队交易额数据
  296. if($upperPath && !UserModel::whereIn('id', explode(',', $upperPath))->inc('total_team_income',$totalFee)->update()){
  297. $logData = ['params'=>$params,'payInfo'=>$payInfo,'user'=>$userInfo,'order'=>$orderInfo,'msg'=> "商城订单{$orderSn}更新用户上级交易数据错误",'date'=> $nowTime];
  298. RedisCache::set($cacheKey."error_{$orderSn}", $logData, $this->cacheTime);
  299. sr_throw("商城订单{$orderSn}更新用户上级交易数据错误");
  300. }
  301. // 赠送积分处理
  302. $rebateScore = isset($orderInfo['rebate_score']) ? floatval($orderInfo['rebate_score']) : 0;
  303. if ($rebateScore > 0 && $userInfo) {
  304. // 更新用户账户积分
  305. if (!UserModel::where('id', $payUid)->inc('score', $rebateScore)->update()) {
  306. $logData = ['params'=>$params,'payInfo'=>$payInfo,'user'=>$userInfo,'order'=>$orderInfo,'msg'=> "商城订单{$orderSn}赠送积分处理错误",'date'=> $nowTime];
  307. RedisCache::set($cacheKey."error_{$orderSn}", $logData, $this->cacheTime);
  308. sr_throw("商城订单{$orderSn}赠送积分处理错误");
  309. }
  310. // 处理积分流水明细
  311. $userScore = isset($userInfo['score']) ? floatval($userInfo['score']) : 0;
  312. $data = [
  313. 'uid' => $payUid,
  314. 'type' => 3,
  315. 'score' => $rebateScore,
  316. 'create_at' => sr_getcurtime(time()),
  317. 'state' => 12,
  318. 'before_score' => $userScore,
  319. 'after_score' => floatval($userScore + $rebateScore),
  320. 'from_id' => $payId,
  321. 'uid2' => 0
  322. ];
  323. if (!ScoreLogModel::insertGetId($data)) {
  324. $logData = ['params'=>$params,'payInfo'=>$payInfo,'user'=>$userInfo,'order'=>$orderInfo,'msg'=> "商城订单{$orderSn}赠送积分明细处理错误",'date'=> $nowTime];
  325. RedisCache::set($cacheKey."error_{$orderSn}", $logData, $this->cacheTime);
  326. sr_throw("商城订单{$orderSn}赠送积分明细处理错误");
  327. }
  328. }
  329. $logData = ['params'=>$params,'payInfo'=>$payInfo,'user'=>$userInfo,'order'=>$orderInfo,'msg'=> "商城订单{$orderSn}回调处理成功",'date'=> $nowTime];
  330. RedisCache::set($cacheKey."success_{$orderSn}", $logData, $this->cacheTime);
  331. }
  332. return true;
  333. }
  334. }