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.

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