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.

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