order->unify($attributes); if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') { //小程序,公众号 if (in_array($order_source, [Client_::mnp, Client_::oa])) { $data = $app->jssdk->bridgeConfig($result['prepay_id'], false); } //app客户端 if (in_array($order_source, [Client_::ios, Client_::android])) { $data = $app->jssdk->appConfig($result['prepay_id'], false); } //pc端 if ($order_source == Client_::pc) { $data = self::getNativeCode($result, $order); } //h5(非微信环境) if ($order_source == Client_::h5) { $redirect_url = request()->domain().'/mobile/pages/user_order/user_order'; $redirect_url = urlencode($redirect_url); $data = $result['mweb_url'].'&redirect_url='.$redirect_url; } return $data; } else { if (isset($result['return_code']) && $result['return_code'] == 'FAIL') { throw new Exception($result['return_msg']); } if (isset($result['err_code_des'])) { throw new Exception($result['err_code_des']); } throw new Exception('未知原因'); } } catch (Exception $e) { self::$error = '支付失败:' . $e->getMessage(); return false; } } /** * Notes: NATIVE 支付二维码 * @param $result * @param $order * @author kiki * @return string * @throws \Endroid\QrCode\Exception\InvalidWriterException */ public static function getNativeCode($result, $order) { $save_dir = 'uploads/pay_code/'; $qr_src = md5($order['order_sn'].mt_rand(10000, 99999)) . '.png'; $code_url = ROOT_PATH.'/'.$save_dir . $qr_src; $qrCode = new QrCode(); $qrCode->setText($result['code_url']); $qrCode->setSize(200); $qrCode->setWriterByName('png'); !file_exists($save_dir) && mkdir($save_dir, 777, true); $qrCode->writeFile($code_url); //生成base64临时图片 if ($fp = fopen($code_url, "rb", 0)) { $gambar = fread($fp, filesize($code_url)); fclose($fp); $base64 = chunk_split(base64_encode($gambar)); $base64 = 'data:image/png;base64,' . $base64; } //删除文件 if (strstr($code_url, $save_dir)) { unlink($code_url); } return $base64; } /** * Notes: 支付参数 * @param $from * @param $order * @param $order_source * @param $auth * @param $notify_url * @author kiki * @return array */ public static function getAttributes($from, $order, $order_source, $auth, $notify_url) { switch ($from) { case 'order': $attributes = [ 'trade_type' => 'JSAPI', 'body' => '商品', // 'out_trade_no' => $order['order_sn'], 'total_fee' => $order['order_amount'] * 100, // 单位:分 'notify_url' => $notify_url, 'openid' => $auth['openid'], 'attach' => 'order' ]; break; case 'recharge': $attributes = [ 'trade_type' => 'JSAPI', 'body' => '充值', // 'out_trade_no' => $order['order_sn'], 'total_fee' => $order['order_amount'] * 100, // 单位:分 'notify_url' => $notify_url, 'openid' => $auth['openid'], 'attach' => 'recharge' ]; break; } //app支付类型 if ($order_source == Client_::android || $order_source == Client_::ios) { $attributes['trade_type'] = 'APP'; } //NATIVE模式设置 if ($order_source == Client_::pc) { $attributes['trade_type'] = 'NATIVE'; $attributes['product_id'] = $order['order_sn']; } //h5支付类型 if ($order_source == Client_::h5) { $attributes['trade_type'] = 'MWEB'; } //在白名单内,一分钱 if (PaymentLogic::isPayWhiteList($order['user_id'])) { $attributes['total_fee'] = 1; } //修改微信统一下单,订单编号 -> 支付回调时截取前面的单号 18个 //修改原因:回调时使用了不同的回调地址,导致跨客户端支付时(例如小程序,公众号)可能出现201,商户订单号重复错误 $attributes['out_trade_no'] = $order['order_sn'].$attributes['trade_type'].$order_source; return $attributes; } /** * Notes: 获取微信配置 * @param $order * @param $order_source * @return array * @throws \think\db\exception\DataNotFoundException * @throws \think\db\exception\ModelNotFoundException * @throws \think\exception\DbException * @author kiki */ public static function getWeChatConfig($order, $order_source) { $pay_config = WeChatServer::getPayConfigBySource($order_source); $where[] = ['user_id', '=', $order['user_id']]; $where[] = ['client', '=', $order_source]; $auth = Db::name('user_auth')->where($where)->find(); $data = [ 'auth' => $auth, 'config' => $pay_config['config'], 'notify_url' => $pay_config['notify_url'], 'order_source' => $order_source, ]; return $data; } /** * Notes: 支付回调 * @param $config * @author kiki * @throws \EasyWeChat\Kernel\Exceptions\Exception */ public static function notify($config) { $app = new Application($config); $response = $app->handlePaidNotify(function ($message, $fail) { if ($message['return_code'] !== 'SUCCESS') { return $fail('通信失败'); } // 用户是否支付成功 if ($message['result_code'] === 'SUCCESS') { $extra['transaction_id'] = $message['transaction_id']; $attach = $message['attach']; $message['out_trade_no'] = mb_substr($message['out_trade_no'], 0, 18); switch ($attach) { case 'order': $order = Db::name('order')->where(['order_sn' => $message['out_trade_no']])->find(); if (!$order || $order['pay_status'] >= Pay::ISPAID) { return true; } PayNotifyLogic::handle('order', $message['out_trade_no'], $extra); break; case 'recharge': $order = Db::name('recharge_order')->where(['order_sn' => $message['out_trade_no']])->find(); if (!$order || $order['pay_status'] >= Pay::ISPAID) { return true; } PayNotifyLogic::handle('recharge', $message['out_trade_no'], $extra); break; } } elseif ($message['result_code'] === 'FAIL') { // 用户支付失败 } return true; // 返回处理完成 }); $response->send(); } /** * Notes: 退款 * @param $config * @param $data //微信订单号、商户退款单号、订单金额、退款金额、其他参数 * @return array|bool|\EasyWeChat\Kernel\Support\Collection|object|\Psr\Http\Message\ResponseInterface|string * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException * @author kiki */ public static function refund($config, $data) { if (!empty($data["transaction_id"])) { $app = Factory::payment($config); $result = $app->refund->byTransactionId( $data['transaction_id'], $data['refund_sn'], $data['total_fee'], $data['refund_fee'] ); return $result; } else { return false; } } }