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.

393 lines
13 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
  1. <?php
  2. namespace App\Controller\v3;
  3. use App\Constants\v3\LogLabel;
  4. use App\Constants\v3\OrderState;
  5. use App\Constants\v3\OrderType;
  6. use App\Constants\v3\Payment;
  7. use App\Controller\BaseController;
  8. use App\Model\v3\Goods;
  9. use App\Model\v3\GoodsActivity;
  10. use App\Model\v3\Order;
  11. use App\Model\v3\OrderGoods;
  12. use App\Model\v3\OrderMain;
  13. use App\Service\v3\Interfaces\BadgeServiceInterface;
  14. use App\Service\v3\Interfaces\CouponRebateServiceInterface;
  15. use App\Service\v3\Interfaces\CouponServiceInterface;
  16. use App\Service\v3\Interfaces\DeviceServiceInterface;
  17. use App\Service\v3\Interfaces\FeiePrintServiceInterface;
  18. use App\Service\v3\Interfaces\FinancialRecordServiceInterface;
  19. use App\Service\v3\Interfaces\GoodsActivityServiceInterface;
  20. use App\Service\v3\Interfaces\MiniprogramServiceInterface;
  21. use App\Service\v3\Interfaces\MqttServiceInterface;
  22. use App\Service\v3\Interfaces\OrderOfflineServiceInterface;
  23. use App\Service\v3\Interfaces\OrderOnlineServiceInterface;
  24. use App\Service\v3\Interfaces\SeparateAccountsServiceInterface;
  25. use EasyWeChat\Factory;
  26. use Hyperf\DbConnection\Db;
  27. use Hyperf\Guzzle\CoroutineHandler;
  28. use Exception;
  29. use Hyperf\Di\Annotation\Inject;
  30. use Hyperf\HttpMessage\Stream\SwooleStream;
  31. use Symfony\Component\HttpFoundation\Request;
  32. class NotifyController extends BaseController
  33. {
  34. /**
  35. * @Inject
  36. * @var MqttServiceInterface
  37. */
  38. protected $mqttService;
  39. /**
  40. * @Inject
  41. * @var DeviceServiceInterface
  42. */
  43. protected $deviceService;
  44. /**
  45. * @Inject
  46. * @var MiniprogramServiceInterface
  47. */
  48. protected $miniprogramService;
  49. /**
  50. * @Inject
  51. * @var FeiePrintServiceInterface
  52. */
  53. protected $feiePrintService;
  54. /**
  55. * @Inject
  56. * @var CouponRebateServiceInterface
  57. */
  58. protected $couponRebateService;
  59. /**
  60. * @Inject
  61. * @var OrderOnlineServiceInterface
  62. */
  63. protected $orderOnlineService;
  64. /**
  65. * @Inject
  66. * @var OrderOfflineServiceInterface
  67. */
  68. protected $orderOfflineService;
  69. /**
  70. * @Inject
  71. * @var SeparateAccountsServiceInterface
  72. */
  73. protected $separateAccountsService;
  74. /**
  75. * @Inject
  76. * @var CouponServiceInterface
  77. */
  78. protected $couponService;
  79. /**
  80. * @Inject
  81. * @var FinancialRecordServiceInterface
  82. */
  83. protected $financialService;
  84. /**
  85. * @Inject
  86. * @var BadgeServiceInterface
  87. */
  88. protected $badgeService;
  89. /**
  90. * @Inject
  91. * @var GoodsActivityServiceInterface
  92. */
  93. protected $goodsActivityService;
  94. public function wxminiOnline()
  95. {
  96. $config = config('wxpay');
  97. $app = Factory::payment($config);
  98. $app['guzzle_handler'] = CoroutineHandler::class;
  99. $get = $this->request->getQueryParams();
  100. $post = $this->request->getParsedBody();
  101. $cookie = $this->request->getCookieParams();
  102. $files = $this->request->getUploadedFiles();
  103. $server = $this->request->getServerParams();
  104. $xml = $this->request->getBody()->getContents();
  105. $app['request'] = new Request($get,$post,[],$cookie,$files,$server,$xml);
  106. // 通知回调,进行业务处理
  107. $response = $app->handlePaidNotify(function ($message, $fail) use ($app) {
  108. Db::beginTransaction();
  109. try {
  110. // 支付失败或者通知失败
  111. if (
  112. empty($message)
  113. || $message['return_code'] != 'SUCCESS'
  114. || !isset($message['result_code'])
  115. || $message['result_code'] != 'SUCCESS'
  116. ) {
  117. $this->log->event(
  118. LogLabel::ORDER_ONLINE_PAY_NOTIFY_LOG,
  119. $message
  120. );
  121. Db::rollBack();
  122. return $fail('Unknown error but FAIL');
  123. }
  124. // 查询订单
  125. $orderMain = OrderMain::query()
  126. ->where(['global_order_id' => $message['out_trade_no'],'type' => OrderType::ONLINE,'state' => OrderState::UNPAID])
  127. ->first();
  128. // 订单不存在
  129. if (empty($orderMain)) {
  130. $this->log->event(
  131. LogLabel::ORDER_ONLINE_PAY_NOTIFY_LOG,
  132. ['global_order_id_fail' => $message['out_trade_no']]
  133. );
  134. Db::rollBack();
  135. return true;
  136. }
  137. $this->orderOnlineService->doByPaid($orderMain->global_order_id);
  138. $this->separateAccountsService->orderOnlinePaid($orderMain->global_order_id);
  139. Db::commit();
  140. // 优惠券返券
  141. $this->couponRebateService->couponRebateInTask($orderMain->global_order_id);
  142. // 喇叭通知,兼容旧音响,MQTT+IOT
  143. $res = $this->mqttService->speakToStore($orderMain->global_order_id);
  144. $res = $this->deviceService->pubMsgToStoreByOrderMainId($orderMain->global_order_id);
  145. // 打印订单,自动打印
  146. $res = $this->feiePrintService->feiePrint($orderMain->global_order_id);
  147. // 记录badge
  148. $orderChildIds = Order::query()->where(['order_main_id' => $orderMain->global_order_id])->pluck('store_id');
  149. $this->badgeService->doByOrder($orderMain->user_id, $orderChildIds, $orderMain->global_order_id, OrderState::PAID);
  150. // 公众号模板消息
  151. $res = $this->miniprogramService->sendTemMsgForOnlineOrder($orderMain->global_order_id);
  152. return true;
  153. } catch (Exception $e) {
  154. $this->log->event(
  155. LogLabel::ORDER_ONLINE_PAY_NOTIFY_LOG,
  156. ['exception_fail' => $e->getMessage()]
  157. );
  158. Db::rollBack();
  159. return $fail('Exception');
  160. }
  161. });
  162. return $this->response
  163. ->withHeader('Content-Type', 'text/xml')
  164. ->withStatus(200)
  165. ->withBody(new SwooleStream($response->getContent()));
  166. }
  167. public function wxminiOffline()
  168. {
  169. $config = config('wxpay');
  170. $app = Factory::payment($config);
  171. $app['guzzle_handler'] = CoroutineHandler::class;
  172. $get = $this->request->getQueryParams();
  173. $post = $this->request->getParsedBody();
  174. $cookie = $this->request->getCookieParams();
  175. $files = $this->request->getUploadedFiles();
  176. $server = $this->request->getServerParams();
  177. $xml = $this->request->getBody()->getContents();
  178. $app['request'] = new Request($get,$post,[],$cookie,$files,$server,$xml);
  179. // 通知回调,进行业务处理
  180. $response = $app->handlePaidNotify(function ($message, $fail) use ($app) {
  181. Db::beginTransaction();
  182. try {
  183. // 支付失败或者通知失败
  184. if (
  185. empty($message)
  186. || $message['return_code'] != 'SUCCESS'
  187. || !isset($message['result_code'])
  188. || $message['result_code'] != 'SUCCESS'
  189. ) {
  190. $this->log->event(
  191. LogLabel::ORDER_OFFLINE_PAY_NOTIFY_LOG,
  192. $message
  193. );
  194. Db::rollBack();
  195. return $fail('Unknown error but FAIL');
  196. }
  197. // 查询订单
  198. $orderMain = OrderMain::query()
  199. ->where([
  200. 'global_order_id' => $message['out_trade_no'],
  201. 'type' => OrderType::OFFLINE,
  202. 'state' => OrderState::UNPAID
  203. ])
  204. ->first();
  205. // 订单不存在
  206. if (empty($orderMain)) {
  207. $this->log->event(
  208. LogLabel::ORDER_OFFLINE_PAY_NOTIFY_LOG,
  209. ['global_order_id_fail' => $message['out_trade_no']]
  210. );
  211. Db::rollBack();
  212. return true;
  213. }
  214. $orderPaid = $this->orderOfflineService->doByPaid($orderMain->global_order_id);
  215. $separate = $this->separateAccountsService->orderOfflinePaid($orderMain->global_order_id);
  216. Db::commit();
  217. // 喇叭通知,兼容旧音响,MQTT+IOT
  218. $res = $this->mqttService->speakToStore($orderMain->global_order_id);
  219. $res = $this->deviceService->pubMsgToStoreByOrderMainId($orderMain->global_order_id);
  220. // 公众号模板消息
  221. $res = $this->miniprogramService->sendTemMsgForOfflineOrder($orderMain->global_order_id);
  222. return true;
  223. } catch (Exception $e) {
  224. $this->log->event(
  225. LogLabel::ORDER_OFFLINE_PAY_NOTIFY_LOG,
  226. ['exception_fail' => $e->getMessage()]
  227. );
  228. Db::rollBack();
  229. return $fail('Exception');
  230. }
  231. });
  232. return $this->response
  233. ->withHeader('Content-Type', 'text/xml')
  234. ->withStatus(200)
  235. ->withBody(new SwooleStream($response->getContent()));
  236. }
  237. public function wxminiRefund()
  238. {
  239. $config = config('wxpay');
  240. $app = Factory::payment($config);
  241. $app['guzzle_handler'] = CoroutineHandler::class;
  242. $get = $this->request->getQueryParams();
  243. $post = $this->request->getParsedBody();
  244. $cookie = $this->request->getCookieParams();
  245. $files = $this->request->getUploadedFiles();
  246. $server = $this->request->getServerParams();
  247. $xml = $this->request->getBody()->getContents();
  248. $app['request'] = new Request($get,$post,[],$cookie,$files,$server,$xml);
  249. // 通知回调,进行业务处理
  250. $response = $app->handleRefundedNotify(function ($message, $reqInfo, $fail) use ($app) {
  251. Db::beginTransaction();
  252. try {
  253. // 支付失败或者通知失败
  254. if (
  255. empty($message)
  256. || $message['return_code'] != 'SUCCESS'
  257. || !isset($reqInfo['refund_status'])
  258. || $reqInfo['refund_status'] != 'SUCCESS'
  259. ) {
  260. $this->log->event(
  261. LogLabel::ORDER_REFUND_NOTIFY_LOG,
  262. array_merge($message, $reqInfo)
  263. );
  264. Db::rollBack();
  265. return $fail('Unknown error but FAIL');
  266. }
  267. // 查询订单
  268. $orderMain = OrderMain::query()
  269. ->whereNotIn('state', [OrderState::UNPAID])
  270. ->where(['global_order_id' => $reqInfo['out_trade_no'], 'pay_type' => Payment::WECHAT])
  271. ->first();
  272. // 订单不存在
  273. if (empty($orderMain)) {
  274. $this->log->event(
  275. LogLabel::ORDER_REFUND_NOTIFY_LOG,
  276. ['global_order_id_fail' => $reqInfo['out_trade_no']]
  277. );
  278. Db::rollBack();
  279. return true;
  280. }
  281. // 添加退款时间
  282. $orderMain->refund_time = time();
  283. $orderMain->state = OrderState::REFUNDED;
  284. $orderMain->save();
  285. // 退款返还优惠券
  286. $this->couponService->orderRefundCoupons($orderMain->global_order_id);
  287. // 处理特价商品缓存
  288. $orderChildren = Order::query()->where(['order_main_id' => $orderMain->global_order_id])->get()->toArray();
  289. $orderGoods = OrderGoods::query()
  290. // ->where(['activity_type' => 2])
  291. ->whereIn('order_id', array_values(array_column($orderChildren, 'id')))->get()->toArray();
  292. foreach ($orderGoods as $key => &$item) {
  293. if ($item['activity_type'] == 2) { # 活动商品
  294. $this->goodsActivityService->clearCacheRecord($item['goods_id'], $item['number'], $orderMain->user_id);
  295. $goods = GoodsActivity::find($item['goods_id']);
  296. } else {
  297. $goods = Goods::find($item['goods_id']);
  298. }
  299. $goods->inventory = $goods->inventory + $item['number'];
  300. $goods->sales = $goods->sales - $item['number'];
  301. $goods->save();
  302. }
  303. // 添加用户的流水
  304. $this->financialService->userByOLOrderRefund($orderMain->user_id, $orderMain->global_order_id, $orderMain->money);
  305. Db::commit();
  306. // 记录badge
  307. $orderChildIds = array_values(array_column($orderChildren, 'store_id'));
  308. $this->badgeService->doByOrder($orderMain->user_id, $orderChildIds, $orderMain->global_order_id, OrderState::REFUNDED);
  309. return true;
  310. } catch (Exception $e) {
  311. $this->log->event(
  312. LogLabel::ORDER_REFUND_NOTIFY_LOG,
  313. ['exception_fail' => $e->getMessage()]
  314. );
  315. Db::rollBack();
  316. return $fail('Exception');
  317. }
  318. });
  319. return $this->response
  320. ->withHeader('Content-Type', 'text/xml')
  321. ->withStatus(200)
  322. ->withBody(new SwooleStream($response->getContent()));
  323. }
  324. }