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.

385 lines
14 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  1. <?php
  2. namespace App\Controller;
  3. use App\Constants\LogLabel;
  4. use App\Model\Goods;
  5. use App\Model\Order;
  6. use App\Model\OrderGoods;
  7. use App\Model\OrderMain;
  8. use App\Model\OrderSalesStatistic;
  9. use App\Model\SpecCombination;
  10. use App\Model\Store;
  11. use App\Model\StoreAccount;
  12. use App\Model\SystemConfig;
  13. use App\Model\Users;
  14. use App\Service\DeviceServiceInterface;
  15. use App\Service\FeiePrintServiceInterface;
  16. use App\Service\MiniprogramService;
  17. use App\Service\MqttServiceInterface;
  18. use App\Service\UserServiceInterface;
  19. use EasyWeChat\Factory;
  20. use Hyperf\DbConnection\Db;
  21. use Hyperf\Guzzle\CoroutineHandler;
  22. use Exception;
  23. use Hyperf\Di\Annotation\Inject;
  24. use Hyperf\HttpMessage\Stream\SwooleStream;
  25. use Symfony\Component\HttpFoundation\Request;
  26. class NotifyController extends BaseController
  27. {
  28. /**
  29. * @Inject
  30. * @var MqttServiceInterface
  31. */
  32. protected $mqttSpeakerService;
  33. /**
  34. * @Inject
  35. * @var DeviceServiceInterface
  36. */
  37. protected $deviceService;
  38. /**
  39. * @Inject
  40. * @var MiniprogramService
  41. */
  42. protected $miniprogramService;
  43. /**
  44. * @Inject
  45. * @var FeiePrintServiceInterface
  46. */
  47. protected $feiePrintService;
  48. /**
  49. * @Inject
  50. * @var UserServiceInterface
  51. */
  52. protected $userService;
  53. public function wxminiOnline()
  54. {
  55. $config = config('wxpay');
  56. $app = Factory::payment($config);
  57. $app['guzzle_handler'] = CoroutineHandler::class;
  58. $get = $this->request->getQueryParams();
  59. $post = $this->request->getParsedBody();
  60. $cookie = $this->request->getCookieParams();
  61. $files = $this->request->getUploadedFiles();
  62. $server = $this->request->getServerParams();
  63. $xml = $this->request->getBody()->getContents();
  64. $app['request'] = new Request($get,$post,[],$cookie,$files,$server,$xml);
  65. // 通知回调,进行业务处理
  66. $response = $app->handlePaidNotify(function ($message, $fail) use ($app) {
  67. Db::beginTransaction();
  68. try {
  69. // 支付失败或者通知失败
  70. if (
  71. empty($message)
  72. || $message['return_code'] != 'SUCCESS'
  73. || !isset($message['result_code'])
  74. || $message['result_code'] != 'SUCCESS'
  75. ) {
  76. $this->log->event(
  77. LogLabel::PAY_NOTIFY_WXMINI,
  78. $message
  79. );
  80. Db::rollBack();
  81. $fail('Unknown error but FAIL');
  82. }
  83. // 查询订单
  84. $orderMain = OrderMain::query()
  85. ->where([
  86. 'global_order_id' => $message['out_trade_no'],
  87. 'type' => OrderMain::ORDER_TYPE_ONLINE
  88. ])
  89. ->first();
  90. // 订单不存在
  91. if (empty($orderMain)) {
  92. $this->log->event(
  93. LogLabel::PAY_NOTIFY_WXMINI,
  94. ['global_order_id_fail' => $message['out_trade_no']]
  95. );
  96. Db::rollBack();
  97. return true;
  98. }
  99. // 修改订单、子订单状态
  100. $currentTime = time();
  101. $orderMain->state = OrderMain::ORDER_STATE_UNTAKE;
  102. $orderMain->time_pay = $currentTime;
  103. $orderMain->pay_time = date('Y-m-d H:i:s', $currentTime);
  104. $orderMain->save();
  105. $upOrder = Order::query()
  106. ->where(['order_main_id' => $orderMain->id])
  107. ->update(['state' => OrderMain::ORDER_STATE_UNTAKE, 'pay_time' => $orderMain->pay_time]);
  108. // 更新商户销量
  109. $upStoreScore = Store::query()
  110. ->whereIn('id', explode(',', $orderMain->store_ids))
  111. ->update(['score' => Db::raw('score+1')]);
  112. // 更新商品库存和销量
  113. $orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time'])
  114. ->where(['order_main_id' => $orderMain->id])
  115. ->get()
  116. ->toArray();
  117. $orderGoods = OrderGoods::query()->select(['good_id AS id', 'number', 'combination_id'])
  118. ->whereIn('order_id', array_values(array_column($orders, 'id')))
  119. ->get()
  120. ->toArray();
  121. foreach ($orderGoods as $key => &$goodsItem) {
  122. $goods = Goods::find($goodsItem['id']);
  123. // 库存处理,有规格
  124. if ($goodsItem['combination_id']) {
  125. $combination = SpecCombination::find($goodsItem['combination_id']);
  126. $combination->number = $combination->number - $goodsItem['number'];
  127. $combination->save();
  128. } else {
  129. $goods->inventory = $goods->inventory - $goodsItem['number'];
  130. }
  131. $goods->sales = $goods->sales - $goodsItem['number'];
  132. $goods->save();
  133. }
  134. // 月销流水
  135. $statistics = [];
  136. foreach ($orders as $key => &$order) {
  137. $statistics[] = [
  138. 'money' => $order['money'],
  139. 'user_id' => $order['user_id'],
  140. 'store_id' => $order['store_id'],
  141. 'market_id' => $orderMain->market_id,
  142. 'order_id' => $order['id'],
  143. 'createtime' => strtotime($order['pay_time']),
  144. ];
  145. }
  146. if (is_array($statistics) && !empty($statistics)) {
  147. $inSalesStatistics = OrderSalesStatistic::query()->insert($statistics);
  148. }
  149. // 喇叭通知,兼容旧音响,MQTT+IOT
  150. $res = $this->mqttSpeakerService->speakToStore($orderMain->id);
  151. $res = $this->deviceService->pubMsgToStoreByOrderMainId($orderMain->id);
  152. // 公众号模板消息
  153. $res = $this->miniprogramService->sendTemMsgForOnlineOrder($orderMain->id);
  154. // 打印订单,自动打印 TODO 后续优化调用逻辑
  155. $res = $this->feiePrintService->feiePrint($orderMain->global_order_id);
  156. Db::commit();
  157. return true;
  158. } catch (Exception $e) {
  159. $this->log->event(
  160. LogLabel::PAY_NOTIFY_WXMINI,
  161. ['exception_fail' => $e->getMessage()]
  162. );
  163. Db::rollBack();
  164. $fail('Exception');
  165. }
  166. });
  167. return $this->response
  168. ->withHeader('Content-Type', 'text/xml')
  169. ->withStatus(200)
  170. ->withBody(new SwooleStream($response->getContent()));
  171. }
  172. public function wxminiOffline()
  173. {
  174. var_dump('Inside');
  175. $config = config('wxpay');
  176. $app = Factory::payment($config);
  177. $app['guzzle_handler'] = CoroutineHandler::class;
  178. $get = $this->request->getQueryParams();
  179. $post = $this->request->getParsedBody();
  180. $cookie = $this->request->getCookieParams();
  181. $files = $this->request->getUploadedFiles();
  182. $server = $this->request->getServerParams();
  183. $xml = $this->request->getBody()->getContents();
  184. $app['request'] = new Request($get,$post,[],$cookie,$files,$server,$xml);
  185. // 通知回调,进行业务处理
  186. $response = $app->handlePaidNotify(function ($message, $fail) use ($app) {
  187. var_dump('$message', $message);
  188. Db::beginTransaction();
  189. try {
  190. // 支付失败或者通知失败
  191. if (
  192. empty($message)
  193. || $message['return_code'] != 'SUCCESS'
  194. || !isset($message['result_code'])
  195. || $message['result_code'] != 'SUCCESS'
  196. ) {
  197. $this->log->event(
  198. LogLabel::PAY_NOTIFY_WXMINI,
  199. $message
  200. );
  201. Db::rollBack();
  202. $fail('Unknown error but FAIL');
  203. }
  204. // 查询订单
  205. $orderMain = OrderMain::query()
  206. ->where([
  207. 'global_order_id' => $message['out_trade_no'],
  208. 'type' => OrderMain::ORDER_TYPE_OFFLINE
  209. ])
  210. ->first();
  211. // 订单不存在
  212. if (empty($orderMain)) {
  213. $this->log->event(
  214. LogLabel::PAY_NOTIFY_WXMINI,
  215. ['global_order_id_fail' => $message['out_trade_no']]
  216. );
  217. Db::rollBack();
  218. return true;
  219. }
  220. // 修改订单、子订单状态
  221. $currentTime = time();
  222. $orderMain->state = OrderMain::ORDER_STATE_UNTAKE;
  223. $orderMain->dm_state = OrderMain::ORDER_STATE_UNTAKE;
  224. $orderMain->time_pay = $currentTime;
  225. $orderMain->pay_time = date('Y-m-d H:i:s', $currentTime);
  226. $orderMain->save();
  227. var_dump('$orderMain', $orderMain->toArray());
  228. $upOrder = Order::query()
  229. ->where(['order_main_id' => $orderMain->id])
  230. ->update([
  231. 'state' => OrderMain::ORDER_STATE_UNTAKE,
  232. 'dm_state' => OrderMain::ORDER_STATE_UNTAKE,
  233. 'pay_time' => date('Y-m-d H:i:s', $currentTime)
  234. ]);
  235. var_dump('$upOrder', $upOrder);
  236. // 查询子订单,当面付目前实际上只有一个子订单
  237. $orders = Order::query()->select(['id', 'money', 'user_id', 'store_id', 'pay_time'])
  238. ->where(['order_main_id' => $orderMain->id])
  239. ->get()
  240. ->toArray();
  241. var_dump('$orders', $orders);
  242. // 商户钱包、流水资金、奖励、发布模板消息处理
  243. foreach ($orders as $key => $orderItem) {
  244. $recordBase = [
  245. 'user_id' => $orderItem['user_id'],
  246. 'order_id' => $orderItem['id'],
  247. 'store_id' => $orderItem['store_id'],
  248. 'type' => 1,
  249. 'time' => date('Y-m-d H:i:s', $currentTime),
  250. 'add_time' => $currentTime,
  251. ];
  252. // 钱包
  253. $store = Store::find($orderItem['store_id']);
  254. $store->store_wallet = bcadd($store->store_wallet, $orderItem['money'], 2);
  255. $store->save();
  256. // 流水
  257. $record = [
  258. 'money' => $orderItem['money'],
  259. 'note' => '当面付订单收入',
  260. 'category' => 2,
  261. ];
  262. StoreAccount::query()->insert(array_merge($recordBase, $record));
  263. // 平台新用户奖励给商户
  264. $isStageNewUser = $this->userService->isStageNewUser($orderItem['user_id']);
  265. $needAward = false;
  266. $awardAmount = 0;
  267. if ($isStageNewUser) {
  268. $awardAmount = SystemConfig::query()->where(['type' => 1, 'menu_name' => 'award_new_user'])->value('value');
  269. // 流水
  270. $record = [
  271. 'money' => $awardAmount,
  272. 'note' => '新用户下单成功,平台奖励',
  273. 'category' => 3,
  274. ];
  275. $needAward = true;
  276. } else {
  277. $isStoreFirstOrderToday = $this->userService->isStoreFirstOrderToday($orderItem['user_id'],$orderItem['store_id'],$orderItem['id']);
  278. if ($isStoreFirstOrderToday) {
  279. $awardAmount = SystemConfig::query()->where(['type' => 1, 'menu_name' => 'award_each_order'])->value('value');
  280. // 流水
  281. $record = [
  282. 'money' => $awardAmount,
  283. 'note' => '用户下单成功,平台奖励',
  284. 'category' => 4,
  285. ];
  286. $needAward = true;
  287. }
  288. }
  289. if ($needAward && $awardAmount) {
  290. // 奖励钱包
  291. $store->refresh();
  292. $store->award_money = bcadd($store->award_money, $awardAmount, 2);
  293. $store->save();
  294. // 流水
  295. StoreAccount::query()->insert(array_merge($recordBase, $record));
  296. // 发布公众号消息
  297. $openid = Users::query()->where(['id' => $store['user_id']])->value('openid');
  298. $res = $this->miniprogramService->sendTemMsgForAward($record['money'], $record['note'], $openid, $recordBase['time']);
  299. var_dump('$res-award', $res);
  300. }
  301. }
  302. // 喇叭通知,兼容旧音响,MQTT+IOT
  303. $res = $this->mqttSpeakerService->speakToStore($orderMain->id);
  304. var_dump('$res-mqttSpeakerService', $res);
  305. $res = $this->deviceService->pubMsgToStoreByOrderMainId($orderMain->id);
  306. var_dump('$res-deviceService', $res);
  307. // 公众号模板消息
  308. $res = $this->miniprogramService->sendTemMsgForOfflineOrder($orderMain->id);
  309. var_dump('$res-miniprogramService', $res);
  310. Db::commit();
  311. return true;
  312. } catch (Exception $e) {
  313. $this->log->event(
  314. LogLabel::PAY_NOTIFY_WXMINI,
  315. ['exception_fail' => $e->getMessage()]
  316. );
  317. Db::rollBack();
  318. $fail('Exception');
  319. }
  320. });
  321. return $this->response
  322. ->withHeader('Content-Type', 'text/xml')
  323. ->withStatus(200)
  324. ->withBody(new SwooleStream($response->getContent()));
  325. }
  326. }