PaymentController.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: Mead
  5. * Date: 2019/8/26
  6. * Time: 11:19 AM
  7. */
  8. namespace App\Http\Controllers\V1;
  9. use App\Models\CardRidingOrder;
  10. use App\Models\DepositOrder;
  11. use App\Models\Order;
  12. use App\Models\RechargeOrder;
  13. use App\Models\RefundLog;
  14. use App\Models\RentOrder;
  15. use App\Models\User;
  16. use Dingo\Api\Http\Request;
  17. use Illuminate\Support\Facades\Log;
  18. /**
  19. * 支付回调模块
  20. * Class PaymentController
  21. * @package App\Http\Controllers\V1
  22. */
  23. class PaymentController extends BaseController
  24. {
  25. /**
  26. * 支付回调
  27. * @return mixed
  28. * User: Mead
  29. */
  30. public function notify()
  31. {
  32. try {
  33. $payment = app('wechat.payment');
  34. return $payment->handlePaidNotify(function ($message, $fail) {
  35. $type = isset($message['attach']) ? $message['attach'] : $this->getTypeTag($message['out_trade_no']);
  36. $class = $this->byTypeGetModel($type);
  37. $model = new $class;
  38. $order = $model->where('no', $message['out_trade_no'])->first();
  39. if (!$order || (int)$order->pay_status === Order::PAY_STATUS_OK) { // 如果订单不存在 或者 订单已经支付过了
  40. return true; // 告诉微信,我已经处理完了,订单没找到,别再通知我了
  41. }
  42. if ($message['result_code'] === 'FAIL') {
  43. Log::warning('[wechat-pay]:' . json_encode($message, true));
  44. return true;
  45. } else if ($message['return_code'] === 'SUCCESS') {
  46. // TODO: 你的发货逻辑
  47. $order->pay_status = Order::PAY_STATUS_OK;
  48. $order->pay_time = now();
  49. $order->pay_type = Order::PAY_TYPE_WECHAT;
  50. $order->pay_money = bcdiv($message['total_fee'], 100, 2);
  51. $order->save();
  52. $order->pay_order_callback();
  53. return true;
  54. }
  55. });
  56. } catch (\Exception $exception) {
  57. Log::error($exception->getMessage());
  58. }
  59. }
  60. /**
  61. * 退款结果通知回调
  62. * @return mixed
  63. * User: Mead
  64. */
  65. public function refundNotify()
  66. {
  67. try {
  68. $payment = app('wechat.payment');
  69. return $payment->handleRefundedNotify(function ($message, $reqInfo, $fail) {
  70. if ($message['return_code'] === 'FAIL') {
  71. Log::warning('[wechat-pay-refund]:' . json_encode($message, true));
  72. return true;
  73. }
  74. $type = isset($message['attach']) ? $message['attach'] : $this->getTypeTag($reqInfo['out_refund_no']);
  75. $class = $this->byTypeGetModel($type);
  76. if ($reqInfo['refund_request_source'] === 'VENDOR_PLATFORM') {
  77. //商户平台退款
  78. $type = $this->getTypeTag($reqInfo['out_trade_no']);
  79. $class = $this->byTypeGetModel($type);
  80. if (empty($class)) {
  81. return $this->sendOtherRefundOrder($reqInfo['out_trade_no'], 1);
  82. }
  83. $model = new $class;
  84. $d_order = $model->where('no', $reqInfo['out_trade_no'])->first();
  85. if ((int)$d_order->is_refund === DepositOrder::REFUND_OK) {
  86. return true;
  87. }
  88. if ($message['return_code'] == 'SUCCESS') {
  89. if ($reqInfo['refund_status'] == 'SUCCESS') {
  90. $d_order->is_refund = DepositOrder::REFUND_OK;
  91. $d_order->save();
  92. User::where('id', $d_order->user_id)->update([
  93. 'deposit_money' => 0,
  94. 'is_deposit' => User::DEPOSIT_NO
  95. ]);
  96. }
  97. return true;
  98. }
  99. } else {
  100. $no = $reqInfo['out_refund_no'];
  101. Log::error("{$type}==>{$no}");
  102. if (empty($class)) {
  103. //其他项目
  104. return $this->sendOtherRefundOrder($reqInfo['out_refund_no']);
  105. }
  106. $model = new $class;
  107. $refund = $model->where('no', $reqInfo['out_refund_no'])->first();
  108. if (!$refund || (int)$refund->pay_status === RefundLog::PAY_STATUS_OK) {
  109. return true;
  110. }
  111. $refund->result = php2js($reqInfo);
  112. if ($message['return_code'] == 'SUCCESS') {
  113. if ($reqInfo['refund_status'] == 'SUCCESS') {
  114. $refund->pay_status = RefundLog::PAY_STATUS_OK;
  115. $refund->pay_time = date('Y-m-d H:i:s');
  116. $refund->save();
  117. $refund->refund_order_callback();
  118. } else {
  119. $refund->pay_status = RefundLog::PAY_STATUS_ERROR;
  120. $refund->pay_time = date('Y-m-d H:i:s');
  121. $refund->save();
  122. }
  123. }
  124. return true; // 返回 true 告诉微信“我已处理完成”
  125. }
  126. });
  127. } catch (\Exception $exception) {
  128. Log::error($exception->getMessage());
  129. }
  130. }
  131. /**
  132. * 根据订单号实例model
  133. * @param $type
  134. * @return string
  135. * User: Mead
  136. */
  137. protected function byTypeGetModel($type)
  138. {
  139. $class = '';
  140. switch ($type) {
  141. case DepositOrder::NO_TAG:
  142. // 缴纳押金
  143. $class = DepositOrder::class;
  144. break;
  145. case RechargeOrder::NO_TAG:
  146. // 充值
  147. $class = RechargeOrder::class;
  148. break;
  149. case Order::NO_TAG:
  150. // 骑行订单
  151. $class = Order::class;
  152. break;
  153. case RefundLog::NO_TAG:
  154. // 退款
  155. $class = RefundLog::class;
  156. break;
  157. case CardRidingOrder::NO_TAG:
  158. // 骑行卡
  159. $class = CardRidingOrder::class;
  160. break;
  161. }
  162. return $class;
  163. }
  164. /**
  165. * 发送给小斑马
  166. * @param $no
  167. * @param int $is_order_no
  168. * @return bool
  169. * User: Mead
  170. */
  171. public function sendOtherRefundOrder($no, $is_order_no = 0)
  172. {
  173. $re = curl_get("http://api.xbm.weilaibike.com/api/payments/wechat-refund-api?no={$no}&is-order-no={$is_order_no}");
  174. if ($re['status']) {
  175. return true;
  176. }
  177. return false;
  178. }
  179. /**
  180. * 检查订单是否退款成功
  181. * @param Request $request
  182. * @return mixed
  183. * User: Mead
  184. */
  185. public function isOrderRefundPay(Request $request)
  186. {
  187. try {
  188. $no = $request->get('no');
  189. $is_order_no = $request->get('is-order-no', 0);
  190. $type = $this->getTypeTag($no);
  191. $class = $this->byTypeGetModel($type);
  192. if (empty($class)) {
  193. return $this->error();
  194. }
  195. $payment = app('wechat.payment');
  196. if ($is_order_no) {
  197. $re = $payment->refund->queryByOutTradeNumber($no);
  198. } else {
  199. $re = $payment->refund->queryByOutRefundNumber($no);
  200. }
  201. if ($re['return_code'] === 'SUCCESS' && $re['refund_status_0'] === 'SUCCESS') {
  202. $model = new $class;
  203. $refund = $model->where('no', $no)->first();
  204. if ((int)$refund->pay_status === RefundLog::PAY_STATUS_OK) {
  205. return $this->success();
  206. }
  207. if ($re['return_code'] === 'SUCCESS' && $re['refund_status_0'] === 'SUCCESS') {
  208. $model = new $class;
  209. $refund = $model->where('no', $no)->first();
  210. if (in_array($type, [RefundLog::NO_TAG])) {
  211. if ((int)$refund->pay_status === RefundLog::PAY_STATUS_OK) {
  212. return $this->success();
  213. }
  214. //退押金
  215. $refund->pay_status = RefundLog::PAY_STATUS_OK;
  216. $refund->pay_time = date('Y-m-d H:i:s');
  217. $refund->save();
  218. }
  219. $refund->refund_order_callback();
  220. return $this->success();
  221. }
  222. }
  223. return $this->error();
  224. } catch (\Exception $exception) {
  225. return $this->error();
  226. }
  227. }
  228. /**
  229. * 解析订单号tag
  230. * @param $no
  231. * @return mixed
  232. * User: Mead
  233. */
  234. protected function getTypeTag($no)
  235. {
  236. preg_match('/[A-Z]*/', $no, $types);
  237. return $types[0];
  238. }
  239. /**
  240. * 检查订单是否支付成功
  241. * @param Request $request
  242. * @return mixed
  243. * User: Mead
  244. */
  245. public function checkOrderPayStatus(Request $request)
  246. {
  247. try {
  248. $order_no = $request->get('order_no');
  249. $type = substr($order_no, 0, 1);
  250. $class = $this->byTypeGetModel($type);
  251. $model = new $class;
  252. $pay_status = $model->where('no', $order_no)->value('pay_status');
  253. return $this->response->array([
  254. 'is_pay' => !!$pay_status
  255. ]);
  256. } catch (\Exception $exception) {
  257. Log::error($exception->getMessage());
  258. }
  259. }
  260. /**
  261. * 处理租车订单支付结果
  262. * User: Mead
  263. */
  264. public function rentNotify()
  265. {
  266. try {
  267. $payment = app('wechat.payment');
  268. return $payment->handlePaidNotify(function ($message, $fail) {
  269. $type = isset($message['attach']) ? $message['attach'] : $this->getTypeTag($message['out_trade_no']);
  270. $rentOrder = RentOrder::query();
  271. if ($type === RentOrder::NO_TAG) {
  272. $order = $rentOrder->where('no', $message['out_trade_no'])->first();
  273. if (!$order || (int)$order->pay_status === RentOrder::PAY_STATUS_OK) { // 如果订单不存在 或者 订单已经支付过了
  274. return true; // 告诉微信,我已经处理完了,订单没找到,别再通知我了
  275. }
  276. if ($message['result_code'] === 'FAIL') {
  277. Log::warning('[wechat-pay]:' . json_encode($message, true));
  278. return true;
  279. } else if ($message['return_code'] === 'SUCCESS') {
  280. // TODO: 你的发货逻辑
  281. $order->pay_status = RentOrder::PAY_STATUS_OK;
  282. $order->pay_time = now();
  283. $order->pay_type = RentOrder::PAY_TYPE_WECHAT;
  284. $order->pay_money = bcdiv($message['total_fee'], 100, 2);
  285. $order->order_total_money = $order->pay_money;
  286. $order->status = RentOrder::STATUS_COMPLETE_ORDER;
  287. $order->save();
  288. $order->pay_rent_over_order_callback();
  289. return true;
  290. }
  291. }
  292. //
  293. // if ($type === RentOrder::NO_OVER_TAG) {
  294. // $order = $rentOrder->where('over_no', $message['out_trade_no'])->first();
  295. // if (!$order || $order->pay_status === Order::PAY_STATUS_OK) { // 如果订单不存在 或者 订单已经支付过了
  296. // return true; // 告诉微信,我已经处理完了,订单没找到,别再通知我了
  297. // }
  298. //
  299. // if ($message['result_code'] === 'FAIL') {
  300. // Log::warning('[wechat-pay]:' . json_encode($message, true));
  301. // return true;
  302. // } else if ($message['return_code'] === 'SUCCESS') {
  303. // // TODO: 你的发货逻辑
  304. //
  305. // $order->pay_status = RentOrder::PAY_STATUS_OK;
  306. // $order->pay_time = now();
  307. // $order->pay_type = RentOrder::PAY_TYPE_WECHAT;
  308. // $order->pay_money = bcdiv($message['total_fee'], 100, 2);
  309. // $order->order_total_money = $order->pay_money;
  310. // $order->status = RentOrder::STATUS_COMPLETE_ORDER;
  311. //
  312. // $order->save();
  313. //
  314. // $order->pay_rent_over_order_callback();
  315. //
  316. // return true;
  317. // }
  318. // }
  319. });
  320. } catch (\Exception $exception) {
  321. return $this->errorNoValidation($exception->getMessage());
  322. }
  323. }
  324. }