Pay.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkAdmin
  4. // +----------------------------------------------------------------------
  5. // | 版权所有 2014~2019 广州楚才信息科技有限公司 [ http://www.cuci.cc ]
  6. // +----------------------------------------------------------------------
  7. // | 官方网站: http://demo.thinkadmin.top
  8. // +----------------------------------------------------------------------
  9. // | 开源协议 ( https://mit-license.org )
  10. // +----------------------------------------------------------------------
  11. // | gitee 代码仓库:https://gitee.com/zoujingli/ThinkAdmin
  12. // | github 代码仓库:https://github.com/zoujingli/ThinkAdmin
  13. // +----------------------------------------------------------------------
  14. namespace app\api\controller;
  15. use EasyWeChat\Factory;
  16. use think\Controller;
  17. use think\Db;
  18. use think\Exception;
  19. use app\api\controller\Evaluate;
  20. use AlibabaCloud\Client\AlibabaCloud;
  21. use AlibabaCloud\Client\Exception\ClientException;
  22. use AlibabaCloud\Client\Exception\ServerException;
  23. /**
  24. * 支付管理类
  25. * Class Refund
  26. * @package app\api\controller\Refund
  27. */
  28. class Pay extends Controller
  29. {
  30. //小程序微信支付(type为1时是货主端微信配置,type为2时是接单端微信配置)
  31. public static function wxPay($name='订单支付',$out_trade_no,$total_fee,$notify_url,$trade_type = 'JSAPI',$openid,$type = 1){
  32. try{
  33. if(empty($out_trade_no) || empty($total_fee) || empty($notify_url)) return false;
  34. if($type == 1){
  35. $app = Factory::payment(config('app.wx_pay'));
  36. }else{
  37. $app = Factory::payment(config('app.worker_wx_pay'));
  38. }
  39. $parameter = array(
  40. 'body' => $name,
  41. 'out_trade_no' => $out_trade_no,
  42. 'total_fee' => $total_fee*100,
  43. 'notify_url' => $notify_url, // 支付结果通知网址,如果不设置则会使用配置里的默认地址
  44. 'trade_type' => $trade_type, // 请对应换成你的支付方式对应的值类型
  45. );
  46. if($trade_type != 'APP'){
  47. $parameter['openid'] = $openid;
  48. }
  49. $result = $app->order->unify($parameter);
  50. $jssdk = $app->jssdk;
  51. $config = $jssdk->sdkConfig($result['prepay_id']);
  52. return $config;
  53. }catch (Exception $e){
  54. return false;
  55. }
  56. }
  57. /**
  58. * 抽奖订单回调
  59. */
  60. public function goodsOrderNotify()
  61. {
  62. $app = Factory::payment(config('app.wx_pay'));
  63. $response = $app->handlePaidNotify(function ($message, $fail) {
  64. $this->payResultLog($message,'goods_order');
  65. // 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单
  66. $pay_no = $message['out_trade_no'];
  67. $order_info = Db::name('goods_order')->where('pay_no',$pay_no)->find();
  68. // 如果订单不存在 或者 订单已经支付过了 告诉微信,我已经处理完了,订单没找到,别再通知我了
  69. if ($message['result_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
  70. $goods_info = Db::table('store_goods')->find($order_info['goods_id']);
  71. $spec = json_decode($goods_info['spec'],true);
  72. // 抽奖
  73. $draw_data = draw_lottery($spec,'store_num',$order_info['goods_num']);
  74. $magic_data = [];// 魔玩柜数据
  75. $magic_day = intval(sysconf('magic_days'));// 获取设置天数
  76. foreach ($draw_data as $k=>$n) {
  77. $spec[$k]['store_num'] -= $n;
  78. $magic_data[]=[
  79. 'order_id' => $order_info['id'],
  80. 'goods_id' => $goods_info['id'],
  81. 'user_id' => $order_info['uid'],
  82. 'create_at' => date('Y-m-d H:i:s'),
  83. 'num' => $n,
  84. 'base_num' => $n,
  85. 'crystal' => $spec[$k]['crystal'],
  86. 'case_name' => $spec[$k]['award_name'],
  87. 'case_cover' => $spec[$k]['spec_img'],
  88. 'past_at' => date('Y-m-d H:i:s',strtotime("+$magic_day days")),
  89. 'past_int' => strtotime("+$magic_day days"),
  90. ];
  91. }
  92. $magic_draw = [];// 待抽将数据
  93. foreach ($magic_data as $mv)
  94. {
  95. for ($i=0;$i< $mv['base_num'];$i++ ) {
  96. $magic_draw[]=[
  97. 'order_id' => $order_info['id'],
  98. 'goods_id' => $goods_info['id'],
  99. 'user_id' => $order_info['uid'],
  100. 'create_at' => date('Y-m-d H:i:s'),
  101. 'status' => 0,
  102. 'award_status' => 1,
  103. 'award_name' => $mv['case_name'],
  104. 'award_cover' => $mv['case_cover'],
  105. ];
  106. }
  107. }
  108. Db::startTrans();
  109. // 更新商品库存
  110. Db::table('store_goods')->where('id',$order_info['goods_id'])->update(['spec'=>json_encode($spec)]);
  111. // 魔玩柜
  112. Db::table('magic_case')->insertAll($magic_data);
  113. // 抽奖数据
  114. Db::table('magic_draw')->insertAll($magic_draw);
  115. // 特殊奖励
  116. $special_award = json_decode($goods_info['special_award'],true);
  117. $special_point = $goods_info['special_point'];
  118. $front_court = $special_award[0];// 前场设置
  119. $back_court = $special_award[1]; // 后场设置
  120. $is_draw = 0;
  121. // 前场未抽奖
  122. if($front_court['is_over'] == 0) {
  123. $front_magic = Db::table('magic_draw')
  124. ->field('id,user_id,order_id')
  125. ->where(['goods_id'=>$goods_info['id'],'status'=>0,'is_special'=>0])
  126. ->limit(0,$special_point)
  127. ->order('id asc')
  128. ->select();
  129. // 前场抽奖次数达到前场抽奖节点
  130. if(count($front_magic) == $special_point) {
  131. $is_draw = 1;
  132. $special_award[0]['is_over'] = 1;// 前场抽奖完成标识
  133. $rand_id = array_rand($front_magic,1);// 中奖记录ids
  134. $front_user = $front_magic[$rand_id]['user_id']; // 中奖会员id
  135. $last_id = $front_magic[count($front_magic)-1]['id'];
  136. // 中奖记录插入魔玩柜
  137. $front_case = [
  138. 'order_id' => $front_magic[$rand_id]['order_id'],
  139. 'goods_id' => $goods_info['id'],
  140. 'user_id' => $front_user,
  141. 'create_at' => date('Y-m-d H:i:s'),
  142. 'num' => 1,
  143. 'base_num' => 1,
  144. 'source' => 1,
  145. 'crystal' => $front_court['crystal'],
  146. 'case_name' => $front_court['goods'],
  147. 'case_cover' =>$front_court['cover'],
  148. 'past_at' => date('Y-m-d H:i:s',strtotime("+$magic_day days")),
  149. 'past_int' => strtotime("+$magic_day days"),
  150. ];
  151. Db::table('magic_case')->insert($front_case);
  152. $special_award1 = [
  153. 'order_id' => $order_info['id'],
  154. 'goods_id' => $goods_info['id'],
  155. 'user_id' => $front_user,
  156. 'create_at' => date('Y-m-d H:i:s'),
  157. 'status' => 1,
  158. 'award_status' => 0,
  159. 'award_name' => $front_court['goods'],
  160. 'award_cover' =>$front_court['cover'],
  161. 'is_special' => 1
  162. ];
  163. Db::table('magic_draw')->insert($special_award1);
  164. // 更新抽奖记录
  165. Db::table('magic_draw')
  166. ->where('goods_id','=',$goods_info['id'])->where('id','<=', $last_id)
  167. ->where('id','<>',$front_magic[$rand_id]['id'])
  168. ->where('status','=',0)
  169. ->where('is_special','=',0)
  170. ->update(['status'=>1]);
  171. Db::table('magic_draw')
  172. ->where('id','=', $front_magic[$rand_id]['id'])
  173. ->where('status','=',0)
  174. ->where('is_special','=',0)
  175. ->update(['status'=>1,'award_status'=>2]);
  176. // 生成消息记录
  177. send_user_message($front_user,1,'恭喜您被大奖砸中!获得商品:'.$front_court['goods']);
  178. }
  179. }
  180. // 后场未抽奖 && 商品售罄
  181. if( $special_award[0]['is_over'] ==1 && $back_court['is_over'] == 0 && $goods_info['stock'] == 0){
  182. $back_num = $goods_info['base_stock'] - $special_point;
  183. $back_magic = Db::table('magic_draw')
  184. ->field('id,user_id,order_id')
  185. ->where(['goods_id'=>$goods_info['id'],'status'=>0,'is_special'=>0])
  186. ->limit(0,$back_num)
  187. ->order('id asc')
  188. ->select();
  189. if($back_num == count($back_magic)) {
  190. $is_draw = 1;
  191. $special_award[1]['is_over'] = 1;// 后场抽奖完成标识
  192. $rand_id = array_rand($back_magic,1);// 中奖记录id
  193. $back_user = $back_magic[$rand_id]['user_id']; // 中奖会员id
  194. $back_case = [
  195. 'order_id' => $back_magic[$rand_id]['order_id'],
  196. 'goods_id' => $goods_info['id'],
  197. 'user_id' => $back_user,
  198. 'create_at' => date('Y-m-d H:i:s'),
  199. 'num' => 1,
  200. 'base_num' => 1,
  201. 'source' => 2,
  202. 'crystal' => $back_court['crystal'],
  203. 'case_name' => $back_court['goods'],
  204. 'case_cover' =>$back_court['cover'],
  205. 'past_at' => date('Y-m-d H:i:s',strtotime("+$magic_day days")),
  206. 'past_int' => strtotime("+$magic_day days"),
  207. ];
  208. Db::table('magic_case')->insert($back_case);
  209. $special_award2 = [
  210. 'order_id' => $order_info['id'],
  211. 'goods_id' => $goods_info['id'],
  212. 'user_id' => $back_user,
  213. 'create_at' => date('Y-m-d H:i:s'),
  214. 'status' => 1,
  215. 'award_status' => 0,
  216. 'award_name' => $back_court['goods'],
  217. 'award_cover' =>$back_court['cover'],
  218. 'is_special' => 1
  219. ];
  220. Db::table('magic_draw')->insert($special_award2);
  221. // 更新抽奖记录
  222. Db::table('magic_draw')
  223. ->where('goods_id','=',$goods_info['id'])->where('status','=', 0)
  224. ->where('id','<>',$back_magic[$rand_id]['id'])
  225. ->where('is_special','=',0)
  226. ->update(['status'=>1]);
  227. Db::table('magic_draw')->where('id','=', $back_magic[$rand_id]['id'])
  228. ->where('is_special','=',0)
  229. ->update(['status'=>1,'award_status'=>3]);
  230. // 生成消息记录
  231. send_user_message($back_user,1,'恭喜您被大奖砸中!!获得商品:'.$back_court['goods']);
  232. }
  233. }
  234. // 更新商品抽奖详情
  235. if($is_draw) Db::table('store_goods')->where('id',$goods_info['id'])->update(['special_award'=>json_encode($special_award)]);
  236. // 更新订单状态
  237. $res = Db::table('goods_order')->where('id',$order_info['id'])
  238. ->update(['pay_time'=>date('Y-m-d H:i:s'),'pay_state'=>1,'pay_type'=>1,'status'=>1]);
  239. if(!$res){
  240. Db::rollback();
  241. }else{
  242. Db::commit();
  243. }
  244. return true; // 返回处理完成
  245. } else if ($message['return_code'] != 'SUCCESS'){
  246. return $fail('通信失败,请稍后再通知我');
  247. }
  248. });
  249. $response->send();
  250. }
  251. /**
  252. * 魔玩柜订单回调
  253. */
  254. public function magicOrderNotify()
  255. {
  256. $app = Factory::payment(config('app.wx_pay'));
  257. $response = $app->handlePaidNotify(function ($message, $fail) {
  258. $this->payResultLog($message,'magic_order');
  259. // 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单
  260. $pay_no = $message['out_trade_no'];
  261. $order_info = Db::name('magic_order')->where('pay_no',$pay_no)->find();
  262. // 如果订单不存在 或者 订单已经支付过了 告诉微信,我已经处理完了,订单没找到,别再通知我了
  263. if ($message['result_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
  264. Db::startTrans();
  265. // 更新订单状态
  266. $res = Db::table('magic_order')->where('id',$order_info['id'])
  267. ->update(['pay_time'=>date('Y-m-d H:i:s'),'pay_state'=>1,'pay_type'=>1,'status'=>1]);
  268. if(!$res){
  269. Db::rollback();
  270. }else{
  271. Db::commit();
  272. }
  273. return true; // 返回处理完成
  274. } else if ($message['return_code'] != 'SUCCESS'){
  275. return $fail('通信失败,请稍后再通知我');
  276. }
  277. });
  278. $response->send();
  279. }
  280. /**
  281. *明信片充值
  282. */
  283. public function crystalRecharge()
  284. {
  285. $app = Factory::payment(config('app.wx_pay'));
  286. $response = $app->handlePaidNotify(function ($message, $fail) {
  287. $this->payResultLog($message,'crystal_order');
  288. // 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单
  289. $pay_no = $message['out_trade_no'];
  290. $order_info = Db::name('crystal_order')->where('pay_no',$pay_no)->find();
  291. // 如果订单不存在 或者 订单已经支付过了 告诉微信,我已经处理完了,订单没找到,别再通知我了
  292. if ($message['result_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
  293. Db::startTrans();
  294. $user_info = Db::table('store_member')->find($order_info['uid']);
  295. // 更新会员余额
  296. Db::table('store_member')->where('id',$order_info['uid'])->update(['crystal_cash'=>bcadd($user_info['crystal_cash'],$order_info['crystal'],2)]);
  297. // 明信片明细
  298. balance_log($order_info['uid'],$order_info['crystal'],'余额充值',2,$order_info['id']);
  299. // 更新订单状态
  300. $res = Db::table('crystal_order')->where('id',$order_info['id'])
  301. ->update(['pay_at'=>date('Y-m-d H:i:s'),'pay_state'=>1,'pay_type'=>1,'status'=>1]);
  302. if(!$res){
  303. Db::rollback();
  304. }else{
  305. Db::commit();
  306. }
  307. return true; // 返回处理完成
  308. } else if ($message['return_code'] != 'SUCCESS'){
  309. return $fail('通信失败,请稍后再通知我');
  310. }
  311. });
  312. $response->send();
  313. }
  314. /**
  315. * 兑换订单回调
  316. */
  317. public function exchangeOrderNotify(){
  318. $app = Factory::payment(config('app.wx_pay'));
  319. $response = $app->handlePaidNotify(function ($message, $fail) {
  320. $this->payResultLog($message,'exchange_order');
  321. // 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单
  322. $pay_no = $message['out_trade_no'];
  323. $order_info = Db::name('exchange_order')->where('pay_no',$pay_no)->find();
  324. // 如果订单不存在 或者 订单已经支付过了 告诉微信,我已经处理完了,订单没找到,别再通知我了
  325. if ($message['result_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
  326. Db::startTrans();
  327. // 更新订单状态
  328. $res = Db::table('exchange_order')->where('id',$order_info['id'])
  329. ->update(['pay_time'=>date('Y-m-d H:i:s'),'pay_state'=>1,'status'=>1]);
  330. if(!$res){
  331. Db::rollback();
  332. }else{
  333. Db::commit();
  334. }
  335. return true; // 返回处理完成
  336. } else if ($message['return_code'] != 'SUCCESS'){
  337. return $fail('通信失败,请稍后再通知我');
  338. }
  339. });
  340. $response->send();
  341. }
  342. /**
  343. * 集市订单回调
  344. */
  345. public function marketOrderNotify(){
  346. $app = Factory::payment(config('app.wx_pay'));
  347. $response = $app->handlePaidNotify(function ($message, $fail) {
  348. $this->payResultLog($message,'market_order');
  349. // 使用通知里的 "微信支付订单号" 或者 "商户订单号" 去自己的数据库找到订单
  350. $pay_no = $message['out_trade_no'];
  351. $order_info = Db::name('market_order')->where('pay_no',$pay_no)->find();
  352. // 如果订单不存在 或者 订单已经支付过了 告诉微信,我已经处理完了,订单没找到,别再通知我了
  353. if ($message['result_code'] == 'SUCCESS') { // return_code 表示通信状态,不代表支付状态
  354. Db::startTrans();
  355. // 更新订单状态
  356. $res = Db::table('market_order')->where('id',$order_info['id'])
  357. ->update(['pay_time'=>date('Y-m-d H:i:s'),'pay_state'=>1,'status'=>1]);
  358. //$freight = get_freight($order_info['goods_num']);
  359. $freight = bcadd(sysconf('market_freight'),0,2);
  360. $vendor_info = Db::table('store_member')->find($order_info['vendor_id']);
  361. $sell_money = Db::table('market_goods')->where('id',$order_info['goods_id'])->value('sell_price');
  362. //$sell_money = bcsub($order_info['price_total'],$freight,2);
  363. if($sell_money > 0) {
  364. Db::table('store_member')->where('id',$vendor_info['id'])->update(['crystal_cash'=>bcadd($vendor_info['crystal_cash'],$sell_money,2)]);
  365. balance_log($order_info['vendor_id'],$sell_money,'集市商品售卖',14,$order_info['id']);
  366. }
  367. if(!$res){
  368. Db::rollback();
  369. }else{
  370. Db::commit();
  371. }
  372. return true; // 返回处理完成
  373. } else if ($message['return_code'] != 'SUCCESS'){
  374. return $fail('通信失败,请稍后再通知我');
  375. }
  376. });
  377. $response->send();
  378. }
  379. /**
  380. * 记录支付日志
  381. * @param $message
  382. * @param $table_name
  383. */
  384. public function payResultLog($message,$table_name)
  385. {
  386. // 回调记录
  387. $ret_arr = [];
  388. $ret_arr['transaction_id'] = isset($message['transaction_id']) ?$message['transaction_id']: '';
  389. $ret_arr['trade_no'] = isset($message['out_trade_no']) ?$message['out_trade_no']: '';
  390. $ret_arr['return_code'] = isset($message['return_code']) ?$message['return_code']: '';
  391. $ret_arr['result_code'] = isset($message['result_code']) ?$message['result_code']: '';
  392. $ret_arr['create_at'] = date('Y-m-d H:i:s');
  393. $ret_arr['order_table'] = $table_name;
  394. $ret_arr['result'] = json_encode($message);
  395. Db::table('order_pay_result')->insert($ret_arr);
  396. }
  397. }