WechatCallbackController.php 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497
  1. <?php
  2. /**
  3. * 重庆赤晓店信息科技有限公司
  4. * https://www.chixiaodian.com
  5. * Copyright (c) 2023 赤店商城 All rights reserved.
  6. */
  7. namespace app\modules\common\controllers;
  8. use app\models\AccountLog;
  9. use app\models\Cash;
  10. use app\models\DeliveryInfo;
  11. use app\models\Option;
  12. use app\models\Order;
  13. use app\models\Store;
  14. use app\models\StoreCash;
  15. use app\models\StoreMini;
  16. use app\models\User;
  17. use app\models\VideoShopOrderExt;
  18. use app\models\WechatConfig;
  19. use app\models\WechatMenuConfig;
  20. use app\modules\admin\models\OrderRevokeForm;
  21. use app\modules\admin\models\VideoShopOrderForm;
  22. use app\modules\admin\models\VideoShopGoodsForm;
  23. use app\utils\Delivery\WechatNewDelivery;
  24. use app\utils\Notice\NoticeSend;
  25. use app\utils\Wechat\Wechat;
  26. use app\utils\Wechat\WechatMini;
  27. use DOMDocument;
  28. use EasyWeChat\Kernel\Messages\News;
  29. use EasyWeChat\Kernel\Messages\NewsItem;
  30. use Symfony\Component\HttpFoundation\HeaderBag;
  31. use Symfony\Component\HttpFoundation\Request as SymfonyRequest;
  32. use yii\web\Controller;
  33. include_once "./utils/Wechat/crypt/wxBizMsgCrypt.php";
  34. class WechatCallbackController extends Controller
  35. {
  36. public function actionIndex() {
  37. // $code = get_params('code');
  38. // Wechat::init(1, Wechat::WECHAT_KIND_OFFICIAL, WechatConfig::TYPE_CONFIG_MP);
  39. // $result = Wechat::$wechat_official->oauth->userFromCode($code);
  40. // \debug_log($result->toArray());
  41. $app = WechatMini::getWechatConfig(get_store_id(), 0, WechatMini::TYPE_OFFICIAL);
  42. if (!$app) {
  43. return '';
  44. }
  45. $app->server->push(function ($message) {
  46. //取消关注事件
  47. if ($message['MsgType'] == 'event') {
  48. if ($message['Event'] == 'subscribe') {
  49. if (\Yii::$app->prod_is_dandianpu()) {
  50. $auto_reply = Option::get('one_store_wechat_official_auto_reply', 0, 'saas', '')['value'];
  51. } else {
  52. $wechat_config = WechatConfig::findOne(['store_id' => get_store_id(), 'type' => WechatConfig::TYPE_CONFIG_MP, 'is_delete' => 0]);
  53. $wechat_config_ext = json_decode($wechat_config->ext, true);
  54. $auto_reply = $wechat_config_ext['auto_reply'];
  55. }
  56. } elseif ($message['Event'] === 'CLICK') {
  57. //点击事件 后台设置自定义菜单按钮点击事件
  58. if (strpos($message['EventKey'], 'news_') !== false) {
  59. $id = str_replace('news_', '', $message['EventKey']);
  60. debug_log($id,'wechat_msg.log');
  61. $menu_config = WechatMenuConfig::findOne($id);
  62. debug_log($menu_config->value,'wechat_msg.log');
  63. if ($menu_config->value) {
  64. $value = json_decode($menu_config->value, true);
  65. $title = $value['title'];
  66. $pic = $value['pic'];
  67. $link = $value['link'];
  68. $desc = $value['desc'];
  69. $items = [
  70. new NewsItem([
  71. 'title' => $title,
  72. 'description' => $desc,
  73. 'url' => $link,
  74. 'image' => $pic,
  75. // ...
  76. ]),
  77. ];
  78. return new News($items);
  79. }
  80. }
  81. }
  82. return $auto_reply ?: '你好!';
  83. }
  84. return '你好!';
  85. });
  86. $response = $app->server->serve();
  87. return $response->send();
  88. }
  89. public function actionVideoShopOrderCallback() {
  90. try {
  91. $request = \Yii::$app->req;
  92. if (\RUN_MODE == 'wokerman') {
  93. $text = $request->rawBody();
  94. } else {
  95. $text = file_get_contents("php://input");
  96. }
  97. $getParam = get_params();
  98. $postParam = post_params();
  99. // $getParam = [
  100. // "mini_id" => "117",
  101. // "signature" => "ecb8e998c045af55dbb914a6c952be857ee96e49",
  102. // "timestamp" => "1700636495",
  103. // "nonce" => "330111248",
  104. // "openid" => "oWGTC5HEQVaRCcgsG-Nqngx5g2xY",
  105. // "encrypt_type" => "aes",
  106. // "msg_signature" => "0d9b2134abb3475603e477de29347c69a9121960",
  107. // ];
  108. // $postParam = [
  109. // "ToUserName" => "gh_da9fa8ea5e45",
  110. // "Encrypt" => "AdJGDYz430yBDIFb+MqdavxuhOAEaCfyEEn5dm4AnLvTbBS6lZpstq4bn/8KJaGAj+QVr7ZoeunMzB8pJMw5hdKMi970G7cuiYKVd+NjxfBCE3iJ+RvfRWQOjVNhuPm59JyDFEQ1XhB4kKZYIhGFqdhP8KGgSpar7rnWBe9VKtYP1rLf3Vi31gfd/Y9x5wQLNA7VXmEDsal+Ie5WU8rw89jKQAhBee+m3PwCPUqFP+XnKdOE9KooXB84bHe4BxYSmI0lWZkmuOgWe3krvGQj1UJBk6qxQw4kZsrKkq6elkFO4suWBxm3SfmycppNr6nayeu6UxcGf/DS9AmXZWxMU9yWZpeNfEqN2YeYfcNt8akruY+U5apZW3qmu1QOTUC/"
  111. // ];
  112. debug_log([
  113. 'get' => $getParam,
  114. 'post' => $postParam,
  115. ], 'wechat-call-back.log');
  116. $mini_id = $getParam['mini_id'];
  117. $store_mini = StoreMini::findOne($mini_id);
  118. $store_id = 0;
  119. if ($store_mini) {
  120. $store_id = $store_mini->store_id;
  121. }
  122. $group = "video_shop_config_" . $mini_id;
  123. $token = Option::get('token', $store_id, $group)['value'];//'Tianxin100';
  124. $encodingAesKey = Option::get('encodingAesKey', $store_id, $group)['value'];//'yu2dLuOA76EjN5nVSqQE4LOQSNT8MBx72SaJry5X4gJ'
  125. $signature = $getParam['signature'];
  126. $tmpArr = array($token, $getParam['timestamp'], $getParam['nonce']);
  127. sort($tmpArr, SORT_STRING);
  128. $tmpStr = implode( $tmpArr );
  129. $tmpStr = sha1( $tmpStr );
  130. if ($tmpStr == $signature) {
  131. if (empty($postParam)) {
  132. return $getParam['echostr'];
  133. }
  134. } else {
  135. return false;
  136. }
  137. $format = "<xml><ToUserName><![CDATA[toUser]]></ToUserName><Encrypt><![CDATA[%s]]></Encrypt></xml>";
  138. $format_xml = sprintf($format, $postParam['Encrypt']);
  139. $wx = new \WXBizMsgCrypt($token, $encodingAesKey, '');
  140. $errCode = $wx->decryptMsg($getParam['msg_signature'], $getParam['timestamp'], $getParam['nonce'], $format_xml, $msg);
  141. if ($errCode === 0) {
  142. $order_msg = json_decode($msg, true);
  143. debug_log($order_msg, __CLASS__);
  144. if (isset($order_msg['Event'])) {
  145. $order_info = $order_msg['order_info'];
  146. $out_order_id = $order_info['order_id'];
  147. $time = $order_msg['CreateTime'];
  148. $order_id_list = VideoShopOrderExt::find()->where(['out_order_id' => $out_order_id, 'is_delete' => 0])
  149. ->select('store_id, mini_id, out_order_id')->asArray()->all();
  150. if(!$order_id_list){
  151. $order_id_list = [[
  152. 'store_id' => $store_id,
  153. 'mini_id' => $mini_id,
  154. 'out_order_id' => (string)$out_order_id,
  155. ]];
  156. }
  157. $params = [];
  158. if (in_array($order_msg['Event'], [
  159. 'channels_ec_order_ext_info_update',//订单其他信息更新
  160. 'channels_ec_order_settle',//订单结算成功
  161. 'channels_ec_order_new',//订单下单
  162. 'channels_ec_order_pay',//订单下单
  163. 'channels_ec_order_cancel',//订单取消
  164. 'channels_ec_order_deliver',//订单发货
  165. 'channels_ec_order_confirm'//订单收货
  166. ])) {
  167. $orderForm = new VideoShopOrderForm();
  168. foreach ($order_id_list as $item) {
  169. $base_ = new WechatMini();
  170. $miniProgram = $base_::getWechatConfig($item['store_id'], $item['mini_id'], 1);
  171. if ($miniProgram) {
  172. $orderForm->miniProgram = $miniProgram;
  173. $orderForm->store_id = $item['store_id'];
  174. $orderForm->mini_id = $item['mini_id'];
  175. $result = $orderForm->syncOrderInfo([$item['out_order_id']]);
  176. debug_log(['小店订单回调' => $result],'syncOrder.log');
  177. }
  178. }
  179. }
  180. // $order_msg = [
  181. // "ToUserName" => "gh_da9fa8ea5e45",
  182. // "FromUserName" => "oWGTC5HEQVaRCcgsG-Nqngx5g2xY",
  183. // "CreateTime" => 1700635660,
  184. // "MsgType" => "event",
  185. // "Event" => "product_spu_audit",
  186. // "ProductSpuAudit" => [
  187. // "product_id" => 10000077907861,
  188. // "status" => 3,
  189. // "reason" => "aaadd123",
  190. // ]
  191. // ];
  192. if (in_array($order_msg['Event'], [
  193. 'product_spu_audit',//商品审核
  194. 'product_spu_listing',//商品上下架
  195. 'product_spu_update'//商品数据更新
  196. ])) {
  197. $key = camelize($order_msg['Event']);
  198. $product_id = $order_msg[$key] ? $order_msg[$key]['product_id'] : 0;
  199. $reason = $order_msg[$key] ? $order_msg[$key]['reason'] : '';
  200. if($product_id){
  201. \app\models\VideoShopGoodsExt::updateAll(['wx_status_reason' => (string)$reason], ['product_id' => (string)$product_id, 'store_id' => $store_id, 'mini_id' => $mini_id]);
  202. }
  203. if ($order_msg['Event'] === "product_spu_update") {
  204. if (isset($order_msg[$key]['status']) && isset($product_id)) {
  205. if (intval($order_msg[$key]['status']) === 2) {
  206. $videoShopGoodsExt = \app\models\VideoShopGoodsExt::findOne(['product_id' => (string)$product_id, 'store_id' => $store_id, 'mini_id' => $mini_id]);
  207. if ($videoShopGoodsExt) {
  208. $goods_id = $videoShopGoodsExt->goods_id;
  209. \app\models\Goods::deleteAll(['id' => $goods_id]);
  210. \app\models\GoodsPic::deleteAll(['goods_id' => $goods_id]);
  211. \app\models\VideoShopGoodsExt::deleteAll(['id' => $videoShopGoodsExt->id]);
  212. }
  213. }
  214. }
  215. }
  216. $form = new VideoShopGoodsForm();
  217. $base_ = new WechatMini();
  218. $miniProgram = $base_::getWechatConfig($store_id, $mini_id, 1);
  219. $form->miniProgram = $miniProgram;
  220. $form->store_id = $store_id;
  221. $form->mini_id = $base_::$mini_id;
  222. $res = $form->syncGoodsInfo($product_id);
  223. debug_log(['小店订单回调' => $res],'syncGoods.log');
  224. }
  225. // if ($order_msg['Event'] === ) {
  226. // $params = [
  227. // 'is_pay' => 1,
  228. // 'pay_time' => $order_info['pay_time'],
  229. // 'trade_status' => Order::ORDER_FLOW_NO_SEND
  230. // ];
  231. // }
  232. //
  233. //
  234. // if ($order_msg['Event'] === ) {
  235. // $params = [
  236. // 'trade_status' => Order::ORDER_FLOW_CANCEL,
  237. // ];
  238. // }
  239. //
  240. //
  241. // if ($order_msg['Event'] === ) {
  242. // $params = [
  243. // 'trade_status' => Order::ORDER_FLOW_SEND,
  244. // 'send_time' => $time
  245. // ];
  246. // }
  247. //
  248. //
  249. // if ($order_msg['Event'] === 'channels_ec_order_confirm') {
  250. // $params = [
  251. // 'trade_status' => Order::ORDER_FLOW_CONFIRM,
  252. // 'confirm_time' => $time
  253. // ];
  254. // }
  255. //
  256. //
  257. //
  258. // Order::updateAll($params, ['id' => $order_id_list]);
  259. }
  260. }
  261. debug_log([
  262. 'errCode' => $errCode,
  263. 'msg' => $msg
  264. ], 'wechat-call-back.log');
  265. } catch (\Exception $e) {
  266. debug_log([
  267. 'code' => 1,
  268. 'get' => get_params(),
  269. 'errCode' => $e->getMessage()
  270. ], 'wechat-call-back.log');
  271. }
  272. }
  273. public function actionDeliveryCallBack() {
  274. try {
  275. $params = post_params();
  276. $order_no = $params['store_order_id'];
  277. $deliveryInfo = DeliveryInfo::findOne(['order_no' => $order_no]);
  278. if ($deliveryInfo) {
  279. $deliveryInfo->wx_order_status = $params['order_status'];
  280. }
  281. if (!$deliveryInfo->save()) {
  282. throw new \Exception(json_encode($deliveryInfo->errors, JSON_UNESCAPED_UNICODE));
  283. }
  284. $order_ = Order::findOne(['order_no' => $order_no, 'is_delete' => 0]);
  285. if (in_array($params['order_status'], [30000, 40000, 50000])) {
  286. $order_->trade_status = Order::ORDER_FLOW_SEND;
  287. }
  288. if (intval($params['order_status']) === 70000) {
  289. $order_->trade_status = Order::ORDER_FLOW_CONFIRM;
  290. }
  291. if (!$order_->save()) {
  292. throw new \Exception(json_encode($order_->errors, JSON_UNESCAPED_UNICODE));
  293. }
  294. //取消订单
  295. if (in_array($params['order_status'], [20000, 20001, 60000])) {
  296. $new_delivery = new WechatNewDelivery();
  297. $result = $new_delivery->handleCancel(['order_no' => $order_no]);
  298. debug_log($result, 'delivery_.log');
  299. }
  300. return $this->asJson([
  301. "return_code" => 0,
  302. "return_msg" => "OK"
  303. ]);
  304. } catch (\Exception $e) {
  305. debug_log([
  306. 'line' => $e->getLine(),
  307. 'file' => $e->getFile(),
  308. 'message' => $e->getMessage()
  309. ], 'delivery_.log');
  310. }
  311. }
  312. //微信转账回调 (先不回)
  313. public function actionWechatTransferBatchesNotify() {
  314. try {
  315. debug_log(['Wechatpay-Serial' => get_header('Wechatpay-Serial'), 'get_header' => get_header(), 'get_params' => get_params(), 'post_params' => post_params()], 'wechatTransferBatchesNotify.log');
  316. $store_id = get_params('store_id');
  317. if ($store_id > 0) {
  318. $store = Store::findOne($store_id);
  319. $wechat_cash = Option::get('wechat_cash', $store_id, 'store')['value'];
  320. if($store->is_platform_transfers == 1){
  321. $wechat_cash = Option::get('store_wechat_cash', $store_id, 'store')['value'];
  322. }
  323. $wechat_cash = json_decode($wechat_cash, true);
  324. $params = post_params();
  325. $res = (new \app\utils\WechatMerchant\WxV3())->decryptToString(
  326. $params['resource']['associated_data'],
  327. $params['resource']['nonce'],
  328. $params['resource']['ciphertext'],
  329. $wechat_cash['mch_api_key']
  330. );
  331. if (!$res) {
  332. return $this->asJson([
  333. 'code' => 'FAIL'
  334. ]);
  335. }
  336. debug_log(['decryptToString' => $res], 'wechatTransferBatchesNotify.log');
  337. $res = json_decode($res, true);
  338. $cash = Cash::findOne(['order_no' => $res['out_bill_no']]);
  339. if ($cash->status == Cash::STATUS_REFUSE) {
  340. return $this->asJson([
  341. 'code' => 'FAIL'
  342. ]);
  343. }
  344. if (intval($cash->wx_cash_type) == Cash::WX_CASH_TYPE_NEW) {
  345. if (!in_array($cash->wx_cash_state, ['SUCCESS', 'FAIL', 'CANCELLED'])) {
  346. $cash->wx_cash_state = $res['state'];
  347. if (in_array($res['state'], ['CANCELLED', 'FAIL'])) {
  348. $cash->wx_cash_error = $res['fail_reason'];
  349. $cash->status = Cash::STATUS_REFUSE;
  350. $user = User::findOne(['id' => $cash->user_id]);
  351. cash::cashRefuse($cash->id);
  352. }
  353. if ($cash->save()) {
  354. debug_log([
  355. 'type' => '提现驳回成功',
  356. 'result' => $res
  357. ], 'wechatTransferBatchesNotify.log');
  358. if (isset($user)) {
  359. NoticeSend::CashFail($cash->user_id, $user->binding, $cash->price, '提现被驳回', '提现被驳回', $store_id);
  360. }
  361. } else {
  362. debug_log([
  363. 'type' => '提现驳回失败',
  364. 'error' => json_encode($cash->errors, JSON_UNESCAPED_UNICODE)
  365. ], 'wechat_cash_status.log');
  366. }
  367. } else {
  368. debug_log([
  369. 'type' => '提现驳回失败 状态已经更改',
  370. 'error' => json_encode($cash->errors, JSON_UNESCAPED_UNICODE)
  371. ], 'wechat_cash_status.log');
  372. }
  373. }
  374. } else {
  375. $platform_mch_api_key = Option::get('platform_mch_api_key', 0, 'saas')['value'];
  376. $params = post_params();
  377. $res = (new \app\utils\WechatMerchant\WxV3())->decryptToString(
  378. $params['resource']['associated_data'],
  379. $params['resource']['nonce'],
  380. $params['resource']['ciphertext'],
  381. $platform_mch_api_key
  382. );
  383. if (!$res) {
  384. return $this->asJson([
  385. 'code' => 'FAIL'
  386. ]);
  387. }
  388. debug_log(['decryptToString' => $res], 'wechatStoreTransferBatchesNotify.log');
  389. $res = json_decode($res, true);
  390. $storeCash = StoreCash::findOne(['order_no' => $res['out_bill_no']]);
  391. if ($storeCash->status == Cash::STATUS_REFUSE) {
  392. return $this->asJson([
  393. 'code' => 'FAIL'
  394. ]);
  395. }
  396. if (intval($storeCash->wx_cash_type) == Cash::WX_CASH_TYPE_NEW) {
  397. if (!in_array($storeCash->wx_cash_state, ['SUCCESS', 'FAIL', 'CANCELLED'])) {
  398. $storeCash->wx_cash_state = $res['state'];
  399. if (in_array($res['state'], ['CANCELLED', 'FAIL'])) {
  400. $storeCash->status = Cash::STATUS_REFUSE;
  401. $store = Store::findOne($storeCash->store_id);
  402. $price = bcadd($storeCash->price, $storeCash->service_charge, 2);
  403. $subMoney = \app\models\Store::addMoney($store, $price, '商城提现打款失败');
  404. debug_log([
  405. 'type' => '商城提现驳回结果',
  406. 'result' => $subMoney
  407. ], 'wechatStoreTransferBatchesNotify.log');
  408. }
  409. if ($storeCash->save()) {
  410. debug_log([
  411. 'type' => '提现驳回成功',
  412. 'result' => $res
  413. ], 'wechatStoreTransferBatchesNotify.log');
  414. } else {
  415. debug_log([
  416. 'type' => '提现驳回失败',
  417. 'error' => json_encode($storeCash->errors, JSON_UNESCAPED_UNICODE)
  418. ], 'wechatStoreTransferBatchesNotify.log');
  419. }
  420. } else {
  421. debug_log([
  422. 'type' => '提现驳回失败 状态已经更改',
  423. 'error' => json_encode($storeCash->errors, JSON_UNESCAPED_UNICODE)
  424. ], 'wechatStoreTransferBatchesNotify.log');
  425. }
  426. }
  427. }
  428. return $this->asJson([
  429. 'code' => 'SUCCESS'
  430. ]);
  431. } catch (\Exception $e) {
  432. debug_log(['message' => $e->getMessage(), 'line' => $e->getLine(), 'file' => $e->getFile()], 'wechatTransferBatchesNotify.log');
  433. return $this->asJson([
  434. 'code' => 'SUCCESS'
  435. ]);
  436. }
  437. }
  438. }