config_info = $config_info; // 获取支付宝支付参数(统一支付到平台账户) $this->aop = new AopClient(); $this->aop->alipayrsaPublicKey = $config_info['public_key'] ?? ""; $this->aop->alipayPublicKey = $config_info['alipay_public_key'] ?? ""; $this->aop->isv_app_id = $config_info["isv_app_id"] ?? ""; $this->aop->rsaPrivateKey = $config_info['private_key'] ?? ""; $this->aop->gatewayUrl = 'https://apigw.alipay-eco.com'; $this->aop->alipaySdkVersion = "alipay-sdk-php-20200415"; $this->aop->apiVersion = '1.0'; $this->aop->signType = 'RSA2'; $this->aop->postCharset = 'UTF-8'; $this->aop->format = 'json'; } catch (\Exception $e) { throw new ApiException(-1, '支付宝配置错误'); } } /*** * 支付回调 * @throws \Exception */ public function payNotify() { $service = input('service', '-------'); Log::log('info', '芝麻状态通知:' . $service . ':' . json_encode($_POST)); if ($this->rsaCheckV(request()->post())) { $biz_content = json_decode(input('biz_content'), true); switch ($_POST['service']) { case 'spi.fitness.subscription.syncSubscription': //订购状态通知 $res = $this->syncSubscription($biz_content); break; case 'spi.fitness.order.syncOrder': $res = $this->syncOrder($biz_content); break; case 'spi.fitness.merchant.syncStatus'://商户状态 $res = $this->syncStatus($biz_content); break; case 'spi.fitness.subscription.getActivateInfo'://周期商品回调 $res = $this->getActivateInfo($biz_content); break; default: $fail = [ 'success' => false, 'code' => 10000, "msg" => 'Success', "sub_code" => 'INVALID_PARAMS', "sub_msg" => '未找到服务方式', ]; ksort($fail); $json = [ 'response' => $fail, 'sign' => $this->aop->sign(json_encode($fail), "RSA2") ]; echo json_encode($json); } } else { $fail = [ 'success' => false, 'code' => 10000, "msg" => 'Success', "sub_code" => 'INVALID_PARAMS', "sub_msg" => '验签失败', ]; ksort($fail); $json = [ 'response' => $fail, 'sign' => $this->aop->sign(json_encode($fail), "RSA2") ]; echo json_encode($json); } } /*** * 获取验证数据 * @param $biz_content * @return void */ public function getActivateInfo($biz_content) { if (isset($biz_content['productNo'])) { $outSubscriptionNo = $biz_content['outSubscriptionNo']; $res = cache($outSubscriptionNo); cache($outSubscriptionNo, $res); unset($res['appSubscriptionUrl']); } else { //分享 } $success = [ 'code' => "10000", "msg" => "Success", ]; if ($res) { $success = array_merge($success, $res); } ksort($success); $json = [ 'response' => $success, 'sign' => $this->aop->sign(json_encode($success, JSON_UNESCAPED_UNICODE), "RSA2") ]; echo json_encode($json); } /*** * 商户状态 * @param $data */ public function syncStatus($data) { if (isset($data['merchantPid']) && $data['merchantPid']) { $merchant_smid = $data['merchantPid']; $merchantStatus = $data['merchantStatus']; $recentZhimaReviewStatus = $data['recentZhimaReviewStatus']; // $merchantStatus=[ // 'NORMAL'=>'正常', // 'ABNORMAL'=>'异常商户', // 'PAUSING'=>'暂停中', // 'PAUSED'=>'已暂停', // 'CLOSING'=>'关闭中', // 'CLOSED'=>'已关闭', // 'RECOVERING'=>'恢复中', // ]; // $recentZhimaReviewStatus=[ // 'INCOMPLETE'=>'未补全', // 'UNDER_REVIEW'=>'审核中', // 'PASSED'=>'已通过', // 'FAILED'=>'未通过', // ]; $reviewFailReason = $data['reviewFailReason'] ?? ''; switch ($recentZhimaReviewStatus) { case 'PASSED': case 'NORMAL': $is_zmpay = 1; break; case 'UNDER_REVIEW': $is_zmpay = 0; break; case 'FAILED': $is_zmpay = 2; break; } Db::name('pay_shop')->where('merchant_smid', '=', $merchant_smid)->update([ 'is_zmpay' => $is_zmpay, 'merchantStatus' => $merchantStatus, 'ZhimaReviewStatus' => $recentZhimaReviewStatus, 'zmapply_desc' => $reviewFailReason, ]); } $success = [ 'success' => true, 'code' => 10000, "msg" => 'Success', ]; ksort($success); $json = [ 'response' => $success, 'sign' => $this->aop->sign(json_encode($success), "RSA2") ]; echo json_encode($json); } /*** * 订单回调 * @param $data * @throws \Exception */ public function syncSubscription($data) { $out_trade_no = $data['outSubscriptionNo']; // 支付宝交易号 $trade_no = $data['subscriptionNo']; // 交易状态 $trade_status = $data['subscriptionStatus']; switch ($trade_status) { case 'NORMAL': //正常 $pay_common = new PayCommon(); $retval = $pay_common->onlinePay($out_trade_no, "zmxxpay", $trade_no, "cardservice"); if (empty($retval['data'])) { $fail = [ 'code' => '40000', "msg" => 'Failed', "sub_code" => 'INVALID_PARAMS', "sub_msg" => '参数异常', ]; ksort($fail); $json = [ 'response' => $fail, 'sign' => $this->aop->sign(json_encode($fail, JSON_UNESCAPED_UNICODE), "RSA2") ]; echo json_encode($json); return; } break; case 'PAUSED': //订单暂停 $where = [ 'trade_no' => $trade_no ]; Db::name('member_goods_card')->where($where)->update(['status' => 2, 'jsonValue' => json_encode($data)]); break; case "CANCEL": //超时取消 case "END": //订单结束 case "DEFAULT_CANCEL": //违约取消 $where = [ 'trade_no' => $trade_no ]; Db::name('member_goods_card')->where($where)->update(['status' => 0, 'jsonValue' => json_encode($data)]); break; case "SURRENDER": //解约 $where = [ 'trade_no' => $trade_no ]; Db::name('member_goods_card')->where($where)->update(['status' => 4, 'jsonValue' => json_encode($data)]); break; default: $fail = [ 'success' => false, 'code' => 10000, "msg" => 'Success', "sub_code" => 'INVALID_PARAMS', "sub_msg" => '未找到业务类型', ]; ksort($fail); $json = [ 'response' => $fail, 'sign' => $this->aop->generateSign($fail, "RSA2") ]; echo json_encode($json); return; } $success = [ 'success' => true, 'code' => 10000, "msg" => 'Success', ]; ksort($success); $json = [ 'response' => $success, 'sign' => $this->aop->sign(json_encode($success), "RSA2") ]; echo json_encode($json); } /*** * 订单同步状态 * @param $data */ public function syncOrder($data) { $out_trade_no = $data['outSubscriptionNo']; //平台交易号 // 支付宝交易号 $trade_no = $data['subscriptionNo']; $third_order_no = $data['orderNo']; // 交易状态 $trade_status = $data['orderStatus']; $where = [ 'out_trade_no' => $out_trade_no, 'third_order_no' => $third_order_no ]; $orderInfo = (array)model('order')->getInfo([['out_trade_no', '=', $out_trade_no]], 'site_id,store_id,order_id,member_id,name,mobile,province_id,city_id,district_id,address,full_address,promotion_type,promotion_type_name'); $zmOrder = Db::name('zima_order')->where($where)->find(); if (empty($zmOrder)) { $insdata = [ 'productNo' => $data['productNo'], 'merchantPid' => $data['merchantPid'], 'site_id' => $orderInfo['site_id'], 'store_id' => $orderInfo['store_id'], 'userid' => $data['userId'], 'order_id' => $orderInfo['order_id'] ?? 0, 'uid' => $orderInfo['member_id'] ?? 0, 'trade_no' => $trade_no, 'out_trade_no' => $out_trade_no, 'third_order_no' => $third_order_no, 'verificationCodeStatus' => $data['verificationCodeStatus'] ?? '', 'orderSettleStatus' => $data['orderSettleStatus'], 'create_time' => strtotime($data['orderDate']), 'plan_time' => strtotime($data['planDeductionTime'] ?? ''), 'period' => $data['period'], 'order_status' => $trade_status, 'amount' => $data['deductionAmount'] ]; Db::name('zima_order')->insert($insdata); } else { $updata = [ 'order_status' => $trade_status, 'verificationCodeStatus' => $data['verificationCodeStatus'] ?? '', 'orderSettleStatus' => $data['orderSettleStatus'], 'settleTime' => $data['settleTime'] ?? 0, 'failTimes' => $data['failTimes'] ?? 0, 'failReason' => $data['failReason'] ?? '', ]; if ($trade_status == 'PAID') { //扣款成功 $updata['payChannel'] = $data['payChannel']; $updata['settleDetails'] = json_encode($data['settleDetails']); $updata['pay_time'] = strtotime($data['actualDeductionTime']); event('CloudAliPayOrderPay', array_merge($zmOrder, $updata, $orderInfo));//订单支付成功 } Db::name('zima_order')->where($where)->update($updata); //核销支付中 try { event('CloudAliPaySyncOrder', array_merge($zmOrder, $updata, $orderInfo));//订单同步事件 } catch (\Exception $exception) { trace($exception, 'CloudAliPaySyncOrder同步事件' . json_encode($data)); } } $success = [ 'success' => true, 'code' => 10000, "msg" => 'Success', ]; ksort($success); $json = [ 'response' => $success, 'sign' => $this->aop->sign(json_encode($success), "RSA2") ]; echo json_encode($json); } /*** * 退款 */ public function refund($param) { $pay_info = $param['pay_info']; $bizContent = [ 'merchantPid' => $pay_info['merchantPid'], 'subscriptionNo' => $pay_info['trade_no'], 'orderNo' => $pay_info['order_no'] ]; //其他参数 $params["charset"] = "UTF-8"; $params["isv_app_id"] = $this->aop->isv_app_id; $params["utc_timestamp"] = $this->msectime(); //指定需要调用的service接口 $params["service"] = "api.fitness.orderRefund"; $params["request_id"] = $this->uuid(); $params["biz_content"] = json_encode($bizContent); $params["version"] = "1.0"; $params["sign"] = $this->aop->generateSign($params, "RSA2"); $params["sign_type"] = 'RSA2'; // 调用ECOAPI $result = $this->aop->call($params); return $result; } /*** * 新增或者修改商户 * @param $param * @return false|mixed */ public function upAlipayUser($param, $settleAccountList = '', $site_id = 0) { $bizContent = [ 'merchantPid' => $param['smid'], 'smid' => $param['smid'], 'merchantAppId' => $param['merchantAppId'], 'merchantLoginName' => $param['merchantLoginName'], 'merchantName' => $param['merchantName'], 'separateLedgerRate' => $param['separateLedgerRate'], 'phone' => $param['phone'], 'logoUrl' => $param['logoUrl'] ?? '' ]; if ($settleAccountList) { $bizContent['settleAccountList'] = array_values($settleAccountList); } $proxy_url = config('alipay.cloudAlipay.proxy_url'); if ($proxy_url) { $this->http_post_data($proxy_url, ['userId' => $param['smid'], 'domain' => addon_url('pay/pay/cloudnotify'), 'site_id' => $site_id]); } //其他参数 $params["charset"] = "UTF-8"; $params["isv_app_id"] = $this->aop->isv_app_id; $params["utc_timestamp"] = $this->msectime(); //指定需要调用的service接口 $params["service"] = "api.fitness.newSaveOrUpdate"; $params["request_id"] = $this->uuid(); $params["biz_content"] = json_encode($bizContent); $params["version"] = "1.0"; $params["sign"] = $this->aop->generateSign($params, "RSA2"); $params["sign_type"] = 'RSA2'; // 调用ECOAPI $result = $this->aop->call($params); return $result['response']; } public function merchantApplyInfoQuery($merchantPid,$site_id) { $bizContent = [ 'merchantPid' => $merchantPid ]; //其他参数 $params["charset"] = "UTF-8"; $params["isv_app_id"] = $this->aop->isv_app_id; $params["utc_timestamp"] = $this->msectime(); //指定需要调用的service接口 $params["service"] = "api.fitness.merchantApplyInfoQuery"; $params["request_id"] = $this->uuid(); $params["biz_content"] = json_encode($bizContent); $params["version"] = "1.0"; $params["sign"] = $this->aop->generateSign($params, "RSA2"); $params["sign_type"] = 'RSA2'; // 调用ECOAPI $result = $this->aop->call($params); return $result['response']; } /*** * 上传图片 * @param $base64Img * @return mixed */ public function logoUpload($base64Img) { $bizContent = [ 'picData' => $base64Img ]; //其他参数 $params["charset"] = "UTF-8"; $params["isv_app_id"] = $this->aop->isv_app_id; $params["utc_timestamp"] = $this->msectime(); //指定需要调用的service接口 $params["service"] = "api.fitness.logoUpload"; $params["request_id"] = $this->uuid(); $params["biz_content"] = json_encode($bizContent); $params["version"] = "1.0"; $params["sign"] = $this->aop->generateSign($params, "RSA2"); // 调用ECOAPI $httpClient = new HttpClient(); $res = $httpClient->post($this->aop->gatewayUrl, $params); // 将返回结果转换本地文件编码 $result = json_decode($res, true); return $result['response']; } /*** * 商户解约 * @param $param * @return false|mixed */ public function Surrender($subscriptionNo, $type = 'NORMAL') { $bizContent = [ 'subscriptionNo' => $subscriptionNo, 'subscriptionCancelType' => $type //NORMAL 正常 DEFAULT违约 ]; //其他参数 $params["charset"] = "UTF-8"; $params["isv_app_id"] = $this->aop->isv_app_id; $params["utc_timestamp"] = $this->msectime(); //指定需要调用的service接口 $params["service"] = "api.fitness.subscriptionSurrender"; $params["request_id"] = $this->uuid(); $params["biz_content"] = json_encode($bizContent); $params["version"] = "1.0"; $params["sign"] = $this->aop->generateSign($params, "RSA2"); $params["sign_type"] = 'RSA2'; // 调用ECOAPI $result = $this->aop->call($params); return $result; } /*** * 核销 * @param $verificationCode * @param $orderNo * @return false|mixed */ public function verify($verificationCode, $orderNo = '') { $bizContent = [ 'verificationCode' => $verificationCode // 'orderNo'=>$orderNo, ]; //其他参数 $params["charset"] = "UTF-8"; $params["isv_app_id"] = $this->aop->isv_app_id; $params["utc_timestamp"] = $this->msectime(); //指定需要调用的service接口 $params["service"] = "api.fitness.verification"; $params["request_id"] = $this->uuid(); $params["biz_content"] = json_encode($bizContent); $params["version"] = "1.0"; $params["sign"] = $this->aop->generateSign($params, "RSA2"); $params["sign_type"] = 'RSA2'; // 调用ECOAPI $result = $this->aop->call($params); return $result; } /*** * 订单查询 * @param $subscriptionNo * @param $orderNo * @return false|mixed */ public function orderQuery($subscriptionNo = '', $orderNo = '', $verificationCode = '') { $bizContent = [ 'subscriptionNo' => $subscriptionNo, 'orderNo' => $orderNo, 'verificationCode' => $verificationCode, ]; //其他参数 $params["charset"] = "UTF-8"; $params["isv_app_id"] = $this->aop->isv_app_id; $params["utc_timestamp"] = $this->msectime(); //指定需要调用的service接口 $params["service"] = "api.fitness.orderQuery"; $params["request_id"] = $this->uuid(); $params["biz_content"] = json_encode($bizContent); $params["version"] = "1.0"; $params["sign"] = $this->aop->generateSign($params, "RSA2"); $params["sign_type"] = 'RSA2'; // 调用ECOAPI $result = $this->aop->call($params); return $result; } public function imageUpload($site_id, $image_url, $image_name = '图片', $isCache = false) { $ali = new MinCode($site_id); $result = $ali->imageUpload($image_name, $image_url, $isCache); $result = $result['alipay_offline_material_image_upload_response']; if ($result['code'] == 10000) { return success(0, '', $result); } else { return error(-1, $result['sub_msg']); } } /*** * 验证签名 * @param $data * @return bool|void */ public function rsaCheckV($data) { unset($data['sign_type']); $res = $this->aop->rsaCheckV2($data, $this->aop->alipayrsaPublicKey, 'RSA2'); return $res; } /** * 返回当前的毫秒时间戳 */ public function msectime() { list($s1, $s2) = explode(' ', microtime()); return (float)sprintf('%.0f', (floatval($s1) + floatval($s2)) * 1000); } public function http_post_data($url, $params = array()) { if (is_array($params)) { $params = http_build_query($params, null, '&'); } $ch = curl_init(); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POSTFIELDS, $params); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 30); $response = curl_exec($ch); curl_close($ch); return $response; } /** * 生成UUID */ public function uuid() { $chars = md5(uniqid(mt_rand(), true)); $uuid = substr($chars, 0, 8) . '-' . substr($chars, 8, 4) . '-' . substr($chars, 12, 4) . '-' . substr($chars, 16, 4) . '-' . substr($chars, 20, 12); return $uuid; } }