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.

462 lines
18 KiB

6 years ago
5 years ago
5 years ago
6 years ago
6 years ago
5 years ago
6 years ago
5 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
5 years ago
6 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
6 years ago
5 years ago
6 years ago
5 years ago
6 years ago
  1. <?php
  2. namespace App\Service\v3\Implementations;
  3. use App\Commons\Log;
  4. use App\Constants\v3\Employee;
  5. use App\Constants\v3\Payment;
  6. use App\Model\v3\Employees;
  7. use App\Model\v3\Order;
  8. use App\Model\v3\OrderGoods;
  9. use App\Model\v3\OrderMain;
  10. use App\Model\v3\Store;
  11. use App\Model\v3\SubscribeMessageTemplate;
  12. use App\Model\v3\User;
  13. use App\Service\v3\Interfaces\MiniprogramServiceInterface;
  14. use EasyWeChat\Factory;
  15. use Hyperf\Guzzle\CoroutineHandler;
  16. use Hyperf\Di\Annotation\Inject;
  17. class MiniprogramService implements MiniprogramServiceInterface
  18. {
  19. /**
  20. * @Inject
  21. * @var Log
  22. */
  23. protected $log;
  24. /**
  25. * @inheritDoc
  26. */
  27. public function sendTemMsgForOnlineOrder($globalOrderId)
  28. {
  29. // 查询订单信息
  30. $order = OrderMain::query()->where(['global_order_id' => $globalOrderId])->first()->toArray();
  31. $payTypes = ['1' => '微信支付', '2' => '余额支付', '3' => '积分支付', '4' => '货到付款'];
  32. $address_store = $order['address'] . ';' .$order['name']. ';'. mb_substr_replace($order['tel'],'****',3,4);
  33. $address = $order['address'] . ';' .$order['name']. ';'. $order['tel'];
  34. // 查询子订单,用于发消息给商户
  35. $order_children = Order::query()
  36. ->with('orderMain')
  37. ->where(['order_main_id' => $globalOrderId])
  38. ->get();
  39. $goods_temp_all = [];
  40. foreach ($order_children as $key => &$item) {
  41. // 订单商品
  42. $order_goods = OrderGoods::query()
  43. ->where(['order_id' => $item->id])
  44. ->get()
  45. ->toArray();
  46. $goods_temp = [];
  47. foreach ($order_goods as $k => &$goods) {
  48. array_push($goods_temp, $goods['name']."*".$goods['number']);
  49. array_push($goods_temp_all, $goods['name']."*".$goods['number']);
  50. }
  51. // 商户/门店的openid
  52. $store = Store::query()->select(['id', 'name', 'user_id'])
  53. ->where(['id' => $item->store_id])
  54. ->first()->toArray();
  55. $store['openid'] = User::query()
  56. ->where(['id' => $store['user_id']])
  57. ->value('openid');
  58. // 模板数据
  59. $data_store = [
  60. 'first' => ['您有新的外卖订单!订单编号:'.$item->order_num, '#ff0000'],
  61. 'keyword' => [
  62. ["您的外卖订单详情:\r\n".implode(";\r\n",$goods_temp), '#ff0000'],
  63. $item->money,
  64. $payTypes[$order['pay_type']],
  65. $item->created_at_text??'',
  66. $address_store,
  67. ],
  68. 'remark' => [$item->note, '#4e6ef2']
  69. ];
  70. $ret_store = $this->sendTempMsg($store['openid'], '-M7DG_ACwJxqdAvyvJuAnPpx4xaLf3VkkN0fckno71c',$data_store);
  71. // 小程序订阅消息发给商户
  72. // 支付金额:{{amount1.DATA}}\n订单编号:{{character_string2.DATA}}\n支付时间:{{date3.DATA}}\n商品详情:{{thing4.DATA}}\n备注:{{thing7.DATA}}\n
  73. $tmplId = 'UfCON4Dj_7aH_Q5k_HvDgzUb3gu67TokPITsJuvCMxc';
  74. $page = 'pages/shopOrders/shopOrders?status=paid&store_id='.$store['id'];
  75. $this->sendSubscribeMessage(
  76. $store['openid'],
  77. $tmplId,
  78. [
  79. 'amount1' => $item->money,
  80. 'character_string2' => $item->order_num,
  81. 'date3' => $item->created_at_text?:date('Y-m-d H:i:s'),
  82. 'thing4' => mb_substr(implode(";", $goods_temp_all),0,18).'..',
  83. 'thing7' => mb_substr(($item->note?:'无备注'), 0, 18).'..',
  84. ],
  85. $page
  86. );
  87. }
  88. // 模板数据发送消息给用户
  89. $data_user = [
  90. 'first' => '您好,下单成功!订单编号:'.$order['global_order_id'],
  91. 'keyword' => [
  92. implode(";\r\n", $goods_temp_all),
  93. $order['money'],
  94. $payTypes[$order['pay_type']],
  95. $order['created_at_text'],
  96. $address,
  97. ],
  98. 'remark' => '感谢您的光临,欢迎下次再来!'
  99. ];
  100. // 获取用户openid,发送给用户
  101. $user_openid = User::query()->where(['id' => $order['user_id']])->value('openid');
  102. $ret_user = $this->sendTempMsg($user_openid,'-M7DG_ACwJxqdAvyvJuAnPpx4xaLf3VkkN0fckno71c', $data_user);
  103. }
  104. /**
  105. * @inheritDoc
  106. */
  107. public function sendTemMsgForOfflineOrder($globalOrderId)
  108. {
  109. // 主订单信息
  110. $orderMain = OrderMain::query()->where(['global_order_id' => $globalOrderId])->first();
  111. // 查询子订单,用于发消息给商户
  112. $order_children = Order::query()
  113. ->where(['order_main_id' => $globalOrderId])
  114. ->get()
  115. ->toArray();
  116. foreach ($order_children as $key => &$item) {
  117. // 商户/门店的openid
  118. $store = Store::query()
  119. ->where(['id' => $item['store_id']])
  120. ->first()->toArray();
  121. $store['openid'] = User::query()
  122. ->where(['id' => $store['user_id']])
  123. ->value('openid');
  124. // 模板数据
  125. $data_store = [
  126. 'first' => '您有新订单收入!订单编号:'.$item['order_num'],
  127. 'keyword' => [
  128. $store['name']?:'',
  129. $item['created_at_text']??'',
  130. '暂无',
  131. $item['money']
  132. ],
  133. 'remark' => '感谢您的使用!'
  134. ];
  135. $ret_store = $this->sendTempMsg($store['openid'], 'lxVbC6PVpKbiO44bYqLmacl-BaME70D47Q0jn2Link0',$data_store);
  136. // 小程序订阅消息发给商户
  137. // 付款金额:{{amount1.DATA}}\n商户名称:{{thing2.DATA}}\n支付方式:{{thing3.DATA}}\n交易单号:{{character_string4.DATA}}\n交易时间:{{time5.DATA}}\n
  138. $tmplId = 'PCRNmKGb7t98xsz_GPux3rhXjsu68TPI3nXR7749dC0';
  139. $page = 'pages/faceOrderList/faceOrderList?store_id='.$store['id'];
  140. $res = $this->sendSubscribeMessage(
  141. $store['openid'],
  142. $tmplId,
  143. [
  144. 'amount1' => $item['money'],
  145. 'thing2' => mb_substr($store['name'], 0, 18).'..',
  146. 'thing3' => mb_substr(Payment::getMessage($orderMain->pay_type), 0, 18).'..',
  147. 'character_string4' => $item['order_num'],
  148. 'time5' => $item['created_at_text']??date('Y-m-d H:i:s'),
  149. ],
  150. $page
  151. );
  152. }
  153. }
  154. /**
  155. * @inheritDoc
  156. */
  157. public function sendTemMsgForAward($money, $note, $openid, $time)
  158. {
  159. // 模板数据发送消息给用户
  160. $data_user = [
  161. 'first' => '恭喜!您有一笔新的奖励收入!',
  162. 'keyword' => [
  163. $money,
  164. $note,
  165. $time
  166. ],
  167. 'remark' => '感谢您的使用!'
  168. ];
  169. // 获取用户openid,发送给用户
  170. $ret_user = $this->sendTempMsg($openid,'ypZ7xdHUjWrRG8P-MD42dhpp6kUlh4Unoh7eTSrLZEg', $data_user);
  171. }
  172. /**
  173. * @inheritDoc
  174. */
  175. public function subscribeMsgForSingleRefund($orderId, $refundStoreAmount, $orderGoodsId = '', $note = '')
  176. {
  177. $order = Order::query()->where(['id' => $orderId])->first();
  178. $store = Store::query()->where(['id' => $order->store_id])->first();
  179. $storeOpenid = User::query()->where(['id' => $store->user_id])->value('openid');
  180. $goodsInfo = [];
  181. if ($orderGoodsId) {
  182. $goodsInfo = OrderGoods::query()->where(['id' => $orderGoodsId])->pluck('name')->toArray();
  183. } else {
  184. $goodsInfo = OrderGoods::query()->where(['order_id' => $orderId])->pluck('name')->toArray();
  185. }
  186. // 小程序订阅消息发给商户
  187. // 订单编号:{{character_string7.DATA}}\n商品名称:{{thing10.DATA}}\n退款金额:{{amount3.DATA}}\n处理时间:{{date4.DATA}}\n退款说明:{{thing5.DATA}}\n
  188. $tmplId = 'OaWeg0q40NVW2WeO5BY1TFdWi4GsgIY1rFBwo2wDa0g';
  189. $page = 'pages/shopOrders/shopOrders?status=refund&store_id='.$store->id;
  190. $this->sendSubscribeMessage(
  191. $storeOpenid,
  192. $tmplId,
  193. [
  194. 'character_string7' => $order->order_num,
  195. 'thing10' => mb_substr(implode(';', $goodsInfo),0,18).'..',
  196. 'amount3' => $refundStoreAmount,
  197. 'date4' => $order->updated_at_text ?? date('Y-m-d H:i:s'),
  198. 'thing5' => mb_substr($note ?: '退款', 0, 18).'..',
  199. ],
  200. $page
  201. );
  202. }
  203. /**
  204. * @inheritDoc
  205. */
  206. public function subscribeMsgForDeliveryStart($globalOrderId)
  207. {
  208. // 主订单信息
  209. $orderMain = OrderMain::query()->where(['global_order_id' => $globalOrderId])->first();
  210. if (!$orderMain) {
  211. return false;
  212. }
  213. // 订单商品
  214. $orderIds = Order::query()->where(['order_main_id' => $globalOrderId])->pluck('id')->toArray();
  215. $goodsInfo = OrderGoods::query()->whereIn('order_id', $orderIds)->pluck('name')->toArray();
  216. // 骑手信息
  217. $horseman = Employees::query()->where(['id' => $orderMain->horseman_id])->whereJsonContains('position', [(string)Employee::TYPE_HORSEMAN])->first();
  218. // 发送给用户的
  219. // 订单编号:{{character_string6.DATA}}\n商品名称:{{thing8.DATA}}\n骑手信息:{{thing7.DATA}}\n送出时间:{{date3.DATA}}\n温馨提示:{{thing4.DATA}}\n
  220. $userTmplId = 'jZMTjlflXrAO7bPk5Lq_rFjol9Yuq5i4czwwrJbteqk';
  221. $userPage = 'pages/orderDetail/orderDetail?global_order_id=' . $globalOrderId;
  222. $userOpenid = User::query()->where(['id' => $orderMain->user_id])->value('openid');
  223. $this->sendSubscribeMessage(
  224. $userOpenid,
  225. $userTmplId,
  226. [
  227. 'character_string6' => $orderMain->global_order_id,
  228. 'thing8' => mb_substr(implode(';', $goodsInfo), 0, 18).'..',
  229. 'thing7' => mb_substr(($horseman->name.'|电话'.$horseman->tel), 0, 18).'..',
  230. 'date3' => $orderMain->updated_at_text ?? '',
  231. 'thing4' => '骑手开始配送,请您耐心等待,感谢使用!',
  232. ],
  233. $userPage
  234. );
  235. // 发送给骑手的
  236. // 订单编号:{{character_string1.DATA}}\n商品信息:{{thing8.DATA}}\n收货地址:{{thing9.DATA}}\n预约时间:{{time17.DATA}}\n温馨提示:{{thing11.DATA}}\n
  237. $horsemanTmplId = '6gxjnBZ4bLnaMC0g8wRaP46jGUZU7YqfYb1FPpJVr50';
  238. $horsemanPage = 'pages/deliverymanOrdersDetail/deliverymanOrdersDetail?global_order_id=' . $globalOrderId . '&employees_id=' . $horseman->id;
  239. $horsemanOpenid = User::query()->where(['id' => $horseman->user_id])->value('openid');
  240. $deliveryNote = $orderMain->delivery_start_time ? date('Y-m-d H:i:s', $orderMain->delivery_start_time+1800) : date('Y-m-d H:i:s', time()+1800);
  241. if (strpos($orderMain->delivery_time_note, ' - ') !== false) {
  242. $arr = explode(' - ', $orderMain->delivery_time_note);
  243. if (is_array($arr) && isset($arr[0]) && $arr[0]) {
  244. $deliveryNote = date('Y-m-d').' '.$orderMain->delivery_time_note.':00';
  245. }
  246. }
  247. $this->sendSubscribeMessage(
  248. $horsemanOpenid,
  249. $horsemanTmplId,
  250. [
  251. 'character_string1' => $orderMain->global_order_id,
  252. 'thing8' => mb_substr(implode(';', $goodsInfo),0,18).'..',
  253. 'thing9' => mb_substr(($orderMain->name.'|'.$orderMain->tel.'|'.$orderMain->address), 0, 18).'..',
  254. 'time17' => $deliveryNote,
  255. 'thing11' => '有新配送订单,请注意及时取货,辛苦了!',
  256. ],
  257. $horsemanPage
  258. );
  259. }
  260. /**
  261. * @inheritDoc
  262. */
  263. public function subscribeMsgForOrderComplete($orderMain)
  264. {
  265. // 主订单信息
  266. if (!($orderMain instanceof OrderMain)) {
  267. $orderMain = OrderMain::query()->where(['global_order_id' => $orderMain])->first();
  268. }
  269. if (!$orderMain) {
  270. return false;
  271. }
  272. // 骑手信息
  273. $horseman = Employees::query()->where(['id' => $orderMain->horseman_id])->whereJsonContains('position', [(string)Employee::TYPE_HORSEMAN])->first();
  274. // 发送小程序订阅消息给用户提示用户订单完成
  275. // 订单编号:{{character_string2.DATA}}\n订单金额:{{amount5.DATA}}\n配送地址:{{thing3.DATA}}\n配送人员:{{thing4.DATA}}\n送达时间:{{time6.DATA}}\n
  276. $userTmplId = 'slYHfLTzKDGWRxnNLyJBr7sb__PEhh9OCrSBpMW_pdE';
  277. $userPage = 'pages/orderDetail/orderDetail?global_order_id=' . $orderMain->global_order_id;
  278. $userOpenid = User::query()->where(['id' => $orderMain->user_id])->value('openid');
  279. $this->sendSubscribeMessage(
  280. $userOpenid,
  281. $userTmplId,
  282. [
  283. 'character_string2' => $orderMain->global_order_id,
  284. 'amount5' => $orderMain->money,
  285. 'thing3' => mb_substr(($orderMain->name.'|'.$orderMain->tel.'|'.$orderMain->address),0,18).'..',
  286. 'thing4' => mb_substr($horseman->name.'|电话'.$horseman->tel, 0, 18).'..',
  287. 'time6' => $orderMain->delivery_time_text?:date('Y-m-d H:i:s'),
  288. ],
  289. $userPage
  290. );
  291. }
  292. /**
  293. * @inheritDoc
  294. */
  295. public function sendTempMsg($openid, $template_id, $data, $redirect_url = '', $applet_config = ['appid' => '', 'pagepath' => ''])
  296. {
  297. if (empty($openid) || empty($template_id) || empty($data)) {
  298. return ;
  299. }
  300. // 先拼个基础的
  301. $template = [
  302. 'touser' => $openid,
  303. 'mp_template_msg' => [
  304. 'appid' => config('wechat.official.app_id'),
  305. 'template_id' => $template_id,
  306. 'url' => $redirect_url,
  307. ]
  308. ];
  309. // 看看有没有小程序跳转的要求
  310. $template['mp_template_msg']['miniprogram'] = $applet_config;
  311. // 重点来了,拼接关键数据data
  312. if (!is_array($data)) { # 数组都不是,请回去
  313. return false;
  314. }
  315. if (is_array($data['first'])) {
  316. $template['mp_template_msg']['data']['first']['value'] = $data['first'][0] ?? '';
  317. $template['mp_template_msg']['data']['first']['color'] = $data['first'][1] ?? '';
  318. } else {
  319. $template['mp_template_msg']['data']['first']['value'] = $data['first'];
  320. }
  321. if (isset($data['keyword'])&&is_array($data['keyword'])) {
  322. foreach ($data['keyword'] as $key => &$keyword) {
  323. $index = $key+1;
  324. if (is_array($keyword)) {
  325. $template['mp_template_msg']['data']['keyword'.$index]['value'] = $keyword[0] ?? '';
  326. $template['mp_template_msg']['data']['keyword'.$index]['color'] = $keyword[1] ?? '';
  327. } else {
  328. $template['mp_template_msg']['data']['keyword'.$index]['value'] = $keyword;
  329. }
  330. }
  331. }
  332. if (is_array($data['remark'])) {
  333. $template['mp_template_msg']['data']['remark']['value'] = $data['remark'][0] ?? '';
  334. $template['mp_template_msg']['data']['remark']['color'] = $data['remark'][1] ?? '';
  335. } else {
  336. $template['mp_template_msg']['data']['remark']['value'] = $data['remark'];
  337. }
  338. $app = Factory::miniProgram(config('wechat.applet'));
  339. $app['guzzle_handler'] = CoroutineHandler::class;
  340. $res = $app->uniform_message->send($template);
  341. if (!isset($res['errcode']) || $res['errcode'] != '0') {
  342. $backtrace = debug_backtrace();
  343. array_shift($backtrace);
  344. $this->log->event('template_message_error', ['from' => json_encode($backtrace), 'res' => json_encode($res), 'msg' => json_encode($template)]);
  345. }
  346. }
  347. public function sendSubscribeMessage($openid, $template_id, $data, $page = '')
  348. {
  349. if (empty($openid) || empty($template_id) || empty($data)) {
  350. return ;
  351. }
  352. $app = Factory::miniProgram(config('wechat.applet'));
  353. $app['guzzle_handler'] = CoroutineHandler::class;
  354. $msgData = [
  355. 'touser' => $openid,
  356. 'template_id' => $template_id,
  357. 'page' => $page,
  358. 'miniprogram_state' => env('APP_ENV')=='prod' ? 'formal' : 'developer',
  359. 'data' => $data
  360. ];
  361. $res = $app->subscribe_message->send($msgData);
  362. if (!isset($res['errcode']) || $res['errcode'] != '0') {
  363. $backtrace = debug_backtrace();
  364. array_shift($backtrace);
  365. $this->log->event('subscribe_message_error', ['from' => json_encode($backtrace), 'res' => json_encode($res), 'msg' => json_encode($msgData)]);
  366. }
  367. return $res;
  368. }
  369. public function getSubscribeMessageTempList($forUserType)
  370. {
  371. if ($forUserType == '') {
  372. $app = Factory::miniProgram(config('wechat.applet'));
  373. $app['guzzle_handler'] = CoroutineHandler::class;
  374. $result = $app->subscribe_message->getTemplates()['data'];
  375. $res = [];
  376. foreach ($result as $key => &$tmpl) {
  377. $res[] = [
  378. 'template_id' => $tmpl['priTmplId'] ?? '',
  379. 'title' => $tmpl['title'] ?? '',
  380. ];
  381. }
  382. return $res;
  383. } else {
  384. $builder = SubscribeMessageTemplate::query()->select('pri_tmpl_id as template_id', 'title');
  385. if ($forUserType != 'all') {
  386. $builder = $builder->where(['for_user_type' => $forUserType]);
  387. }
  388. return $builder->get()->toArray();
  389. }
  390. }
  391. }