|
|
<?php
|
|
|
|
|
|
class sandpay_plugin
|
|
|
{
|
|
|
static public $info = [
|
|
|
'name' => 'sandpay',
|
|
|
'showname' => '杉德支付',
|
|
|
'author' => '杉德',
|
|
|
'link' => 'https://www.sandpay.com.cn/',
|
|
|
'types' => ['alipay','wxpay','bank'],
|
|
|
'transtypes' => ['bank'],
|
|
|
'inputs' => [
|
|
|
'appid' => [
|
|
|
'name' => '商户编号',
|
|
|
'type' => 'input',
|
|
|
'note' => '',
|
|
|
],
|
|
|
'appkey' => [
|
|
|
'name' => '私钥证书密码',
|
|
|
'type' => 'input',
|
|
|
'note' => '',
|
|
|
],
|
|
|
'appswitch' => [
|
|
|
'name' => '环境选择',
|
|
|
'type' => 'select',
|
|
|
'options' => [0=>'生产环境',1=>'测试环境'],
|
|
|
],
|
|
|
],
|
|
|
'select_bank' => [
|
|
|
'1' => '银联支付',
|
|
|
'2' => '快捷支付',
|
|
|
],
|
|
|
'select' => null,
|
|
|
'note' => '将私钥证书命名为client.pfx(或商户编号.pfx)上传到 /plugins/sandpay/cert/',
|
|
|
'bindwxmp' => true,
|
|
|
'bindwxa' => true,
|
|
|
];
|
|
|
|
|
|
static public function submit(){
|
|
|
global $siteurl, $channel, $order, $sitename;
|
|
|
|
|
|
if($order['typename']=='alipay'){
|
|
|
return ['type'=>'jump','url'=>'/pay/alipay/'.TRADE_NO.'/'];
|
|
|
}elseif($order['typename']=='wxpay'){
|
|
|
if(strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger')!==false && $channel['appwxmp']>0){
|
|
|
return ['type'=>'jump','url'=>'/pay/wxjspay/'.TRADE_NO.'/?d=1'];
|
|
|
}elseif(checkmobile()==true && $channel['appwxa']>0){
|
|
|
return ['type'=>'jump','url'=>'/pay/wxwappay/'.TRADE_NO.'/'];
|
|
|
}else{
|
|
|
return ['type'=>'jump','url'=>'/pay/wxpay/'.TRADE_NO.'/'];
|
|
|
}
|
|
|
}elseif($order['typename']=='bank'){
|
|
|
if(in_array('2',$channel['apptype'])){
|
|
|
return ['type'=>'jump','url'=>'/pay/fastpay/'.TRADE_NO.'/'];
|
|
|
}else{
|
|
|
return ['type'=>'jump','url'=>'/pay/bank/'.TRADE_NO.'/'];
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
static public function mapi(){
|
|
|
global $siteurl, $channel, $order, $conf, $device, $mdevice;
|
|
|
|
|
|
if($order['typename']=='alipay'){
|
|
|
return self::alipay();
|
|
|
}elseif($order['typename']=='wxpay'){
|
|
|
if($mdevice=='wechat' && $channel['appwxmp']>0){
|
|
|
return ['type'=>'jump','url'=>$siteurl.'/pay/wxjspay/'.TRADE_NO.'/?d=1'];
|
|
|
}elseif($device=='mobile' && $channel['appwxa']>0){
|
|
|
return ['type'=>'jump','url'=>$siteurl.'/pay/wxwappay/'.TRADE_NO.'/'];
|
|
|
}else{
|
|
|
return self::wxpay();
|
|
|
}
|
|
|
}elseif($order['typename']=='bank'){
|
|
|
if(in_array('2',$channel['apptype'])){
|
|
|
return self::fastpay();
|
|
|
}else{
|
|
|
return self::bank();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
static private function qrcode($productId, $payTool){
|
|
|
global $channel, $order, $ordername, $conf, $clientip;
|
|
|
|
|
|
require(PAY_ROOT."inc/Build.class.php");
|
|
|
|
|
|
$client = new SandpayCommon($channel['appid'], $channel['appkey'], $channel['appswitch']);
|
|
|
$client->productId = $productId;
|
|
|
$client->body = array(
|
|
|
'payTool' => $payTool,
|
|
|
'orderCode' => TRADE_NO,
|
|
|
'totalAmount' => str_pad(strval($order['realmoney']*100),12,'0',STR_PAD_LEFT),
|
|
|
'subject' => $ordername,
|
|
|
'body' => $ordername,
|
|
|
'notifyUrl' => $conf['localurl'].'pay/notify/'.TRADE_NO.'/',
|
|
|
);
|
|
|
|
|
|
return \lib\Payment::lockPayData(TRADE_NO, function() use($client) {
|
|
|
$ret = $client->request('orderCreate');
|
|
|
return $ret['qrCode'];
|
|
|
});
|
|
|
}
|
|
|
|
|
|
|
|
|
static private function cashier(){
|
|
|
global $siteurl, $channel, $order, $ordername, $conf, $clientip;
|
|
|
|
|
|
require(PAY_ROOT."inc/Build.class.php");
|
|
|
|
|
|
$client = new SandpayCommon($channel['appid'], $channel['appkey'], $channel['appswitch']);
|
|
|
$client->productId = '00002000';
|
|
|
$client->body = array(
|
|
|
'orderCode' => TRADE_NO,
|
|
|
'totalAmount' => str_pad(strval($order['realmoney']*100),12,'0',STR_PAD_LEFT),
|
|
|
'subject' => $ordername,
|
|
|
'body' => $ordername,
|
|
|
'notifyUrl' => $conf['localurl'].'pay/notify/'.TRADE_NO.'/',
|
|
|
'frontUrl' => $siteurl.'pay/return/'.TRADE_NO.'/',
|
|
|
);
|
|
|
$html_text = $client->form('cashierPay');
|
|
|
return ['type'=>'html','data'=>$html_text];
|
|
|
}
|
|
|
|
|
|
|
|
|
static private function newh5($product_code, $pay_extra = []){
|
|
|
global $siteurl, $channel, $order, $ordername, $conf, $clientip;
|
|
|
|
|
|
require(PAY_ROOT."inc/Build.class.php");
|
|
|
$client = new SandpayCommon($channel['appid'], $channel['appkey'], $channel['appswitch']);
|
|
|
|
|
|
$param = [
|
|
|
'version' => '10',
|
|
|
'mer_no' => $channel['appid'],
|
|
|
'mer_order_no' => TRADE_NO,
|
|
|
'create_time' => date('YmdHis'),
|
|
|
'order_amt' => $order['realmoney'],
|
|
|
'notify_url' => $conf['localurl'].'pay/notify/'.TRADE_NO.'/',
|
|
|
'return_url' => $siteurl.'pay/return/'.TRADE_NO.'/',
|
|
|
'create_ip' => str_replace('.','_',$clientip),
|
|
|
'pay_extra' => json_encode($pay_extra),
|
|
|
'accsplit_flag' => 'NO',
|
|
|
'sign_type' => 'RSA',
|
|
|
'store_id' => '000000',
|
|
|
];
|
|
|
$param['sign'] = $client->getSign($param);
|
|
|
$param += [
|
|
|
'expire_time' => date('YmdHis', time()+30*60),
|
|
|
'goods_name' => $ordername,
|
|
|
'product_code' => $product_code,
|
|
|
'clear_cycle' => '1',
|
|
|
'jump_scheme' => 'sandcash://scpay',
|
|
|
'meta_option' => json_encode([["s" => "Android","n" => "wxDemo","id" => "com.pay.paytypetest","sc" => "com.pay.paytypetest"]]),
|
|
|
];
|
|
|
|
|
|
$query = http_build_query($param);
|
|
|
|
|
|
if($product_code == '02010006'){
|
|
|
$attr = 'applet';
|
|
|
}elseif($product_code == '02020005'){
|
|
|
$attr = 'alipaycode';
|
|
|
}elseif($product_code == '02010002'){
|
|
|
$attr = 'wechatpay';
|
|
|
}elseif($product_code == '02020002'){
|
|
|
$attr = 'alipay';
|
|
|
}elseif($product_code == '02000001'){
|
|
|
$attr = 'qrcode';
|
|
|
}elseif($product_code == '05030001'){
|
|
|
$attr = 'fastpayment';
|
|
|
}elseif($product_code == '06030001'){
|
|
|
$attr = 'unionpayh5';
|
|
|
}
|
|
|
|
|
|
if($channel['appswitch'] == 1){
|
|
|
$payurl = "https://sandcash-uat01.sand.com.cn/pay/h5/".$attr."?".$query;
|
|
|
}else{
|
|
|
$payurl = "https://sandcash.mixienet.com.cn/pay/h5/".$attr."?".$query;
|
|
|
}
|
|
|
return $payurl;
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function alipay(){
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try{
|
|
|
$code_url = self::qrcode('00000006','0401');
|
|
|
}catch(Exception $ex){
|
|
|
return ['type'=>'error','msg'=>'支付宝支付下单失败!'.$ex->getMessage()];
|
|
|
}
|
|
|
|
|
|
return ['type'=>'qrcode','page'=>'alipay_qrcode','url'=>$code_url];
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function wxpay(){
|
|
|
try{
|
|
|
$code_url = self::qrcode('00000005','0402');
|
|
|
}catch(Exception $ex){
|
|
|
return ['type'=>'error','msg'=>'微信支付下单失败!'.$ex->getMessage()];
|
|
|
}
|
|
|
|
|
|
if (checkmobile()==true) {
|
|
|
return ['type'=>'qrcode','page'=>'wxpay_wap','url'=>$code_url];
|
|
|
}else{
|
|
|
return ['type'=>'qrcode','page'=>'wxpay_qrcode','url'=>$code_url];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function bank(){
|
|
|
try{
|
|
|
$code_url = self::qrcode('00000012','0403');
|
|
|
}catch(Exception $ex){
|
|
|
return ['type'=>'error','msg'=>'云闪付下单失败!'.$ex->getMessage()];
|
|
|
}
|
|
|
|
|
|
return ['type'=>'qrcode','page'=>'bank_qrcode','url'=>$code_url];
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function fastpay(){
|
|
|
if(checkmobile())
|
|
|
$payurl = self::newh5('06030001');
|
|
|
else
|
|
|
$payurl = self::newh5('05030001');
|
|
|
return ['type'=>'jump','url'=>$payurl];
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function wxjspay(){
|
|
|
global $siteurl, $channel, $order, $ordername, $conf, $clientip;
|
|
|
|
|
|
$wxinfo = \lib\Channel::getWeixin($channel['appwxmp']);
|
|
|
if(!$wxinfo) return ['type'=>'error','msg'=>'支付通道绑定的微信公众号不存在'];
|
|
|
|
|
|
try{
|
|
|
$tools = new \WeChatPay\JsApiTool($wxinfo['appid'], $wxinfo['appsecret']);
|
|
|
$openid = $tools->GetOpenid();
|
|
|
}catch(Exception $e){
|
|
|
return ['type'=>'error','msg'=>$e->getMessage()];
|
|
|
}
|
|
|
$blocks = checkBlockUser($openid, TRADE_NO);
|
|
|
if($blocks) return $blocks;
|
|
|
|
|
|
$payurl = self::newh5('02010002', ["mer_app_id"=>$wxinfo['appid'],"openid"=>$openid]);
|
|
|
|
|
|
return ['type'=>'jump','url'=>$payurl];
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function wxwappay(){
|
|
|
global $siteurl, $channel, $order, $ordername, $conf, $clientip;
|
|
|
|
|
|
$wxinfo = \lib\Channel::getWeixin($channel['appwxa']);
|
|
|
if(!$wxinfo) return ['type'=>'error','msg'=>'支付通道绑定的微信小程序不存在'];
|
|
|
|
|
|
$payurl = self::newh5('02010006', ["resourceAppid"=>$wxinfo['appid'],"resourceEnv"=>""]);
|
|
|
|
|
|
return ['type'=>'jump','url'=>$payurl];
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function notify(){
|
|
|
global $channel, $order;
|
|
|
|
|
|
$sign = $_POST['sign'];
|
|
|
$data = stripslashes($_POST['data']);
|
|
|
|
|
|
|
|
|
|
|
|
require(PAY_ROOT."inc/Build.class.php");
|
|
|
|
|
|
$client = new SandpayCommon($channel['appid'], $channel['appkey'], $channel['appswitch']);
|
|
|
$verifyFlag = $client->verify($data, $sign);
|
|
|
|
|
|
if($verifyFlag){
|
|
|
$array = json_decode($data, true);
|
|
|
if($array['head']['respCode'] == '000000'){
|
|
|
$out_trade_no = $array['body']['orderCode'];
|
|
|
$trade_no = $array['body']['tradeNo'];
|
|
|
$money = $array['body']['totalAmount'];
|
|
|
$buyer = $array['body']['accLogonNo'];
|
|
|
if($out_trade_no == TRADE_NO){
|
|
|
processNotify($order, $trade_no, $buyer);
|
|
|
}
|
|
|
return ['type'=>'html','data'=>'respCode=000000'];
|
|
|
}
|
|
|
}
|
|
|
return ['type'=>'html','data'=>'respCode=020002'];
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function return(){
|
|
|
return ['type'=>'page','page'=>'return'];
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function refund($order){
|
|
|
global $channel, $conf;
|
|
|
if(empty($order))exit();
|
|
|
|
|
|
require(PAY_ROOT."inc/Build.class.php");
|
|
|
|
|
|
$client = new SandpayCommon($channel['appid'], $channel['appkey'], $channel['appswitch']);
|
|
|
$client->body = array(
|
|
|
'orderCode' => $order['api_trade_no'],
|
|
|
'oriOrderCode' => $order['trade_no'],
|
|
|
'refundAmount' => str_pad(strval($order['refundmoney']*100),12,'0',STR_PAD_LEFT),
|
|
|
'notifyUrl' => $conf['localurl'].'pay/refundnotify/'.TRADE_NO.'/',
|
|
|
);
|
|
|
try{
|
|
|
$ret = $client->request('orderRefund');
|
|
|
return ['code'=>0, 'trade_no'=>$ret['orderCode'], 'refund_fee'=>$ret['refundAmount']];
|
|
|
}catch(Exception $ex){
|
|
|
return ['code'=>-1,'msg'=>$ex->getMessage()];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function refundnotify(){
|
|
|
global $channel, $order;
|
|
|
|
|
|
$sign = $_POST['sign'];
|
|
|
$data = stripslashes($_POST['data']);
|
|
|
|
|
|
require(PAY_ROOT."inc/Build.class.php");
|
|
|
|
|
|
$client = new SandpayCommon($channel['appid'], $channel['appkey'], $channel['appswitch']);
|
|
|
$verifyFlag = $client->verify($data, $sign);
|
|
|
|
|
|
if($verifyFlag){
|
|
|
$array = json_decode($data, true);
|
|
|
if($array['head']['respCode'] == '000000'){
|
|
|
$out_trade_no = $array['body']['orderCode'];
|
|
|
$trade_no = $array['body']['tradeNo'];
|
|
|
$money = $array['body']['totalAmount'];
|
|
|
return ['type'=>'html','data'=>'respCode=000000'];
|
|
|
}
|
|
|
}
|
|
|
return ['type'=>'html','data'=>'respCode=020002'];
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function transfer($channel, $bizParam){
|
|
|
if(empty($channel) || empty($bizParam))exit();
|
|
|
|
|
|
require(PAY_ROOT."inc/Transfer.class.php");
|
|
|
|
|
|
$client = new SandpayTransfer($channel['appid'], $channel['appkey']);
|
|
|
try{
|
|
|
$result = $client->agentpay($bizParam['out_biz_no'], $bizParam['payee_account'], $bizParam['payee_real_name'], $bizParam['money'], $bizParam['transfer_desc']);
|
|
|
if (isset($result['respCode']) && $result['respCode']=='0000') {
|
|
|
$status = $result['resultFlag'] == 0 ? 1 : 0;
|
|
|
return ['code'=>0, 'status'=>$status, 'orderid'=>$result['sandSerial'], 'paydate'=>$result['tranDate']];
|
|
|
}else{
|
|
|
return ['code'=>-1, 'errcode'=>$result['respCode'], 'msg'=>'['.$result['respCode'].']'.$result['respDesc']];
|
|
|
}
|
|
|
}catch(Exception $ex){
|
|
|
return ['code'=>-1, 'msg'=>$ex->getMessage()];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function transfer_query($channel, $bizParam){
|
|
|
if(empty($channel) || empty($bizParam))exit();
|
|
|
|
|
|
require(PAY_ROOT."inc/Transfer.class.php");
|
|
|
|
|
|
$client = new SandpayTransfer($channel['appid'], $channel['appkey']);
|
|
|
try{
|
|
|
$result = $client->queryOrder($bizParam['out_biz_no']);
|
|
|
if (isset($result['respCode']) && $result['respCode']=='0000') {
|
|
|
$status = $result['resultFlag'] == 0 ? 1 : 0;
|
|
|
return ['code'=>0, 'status'=>$status];
|
|
|
}else{
|
|
|
return ['code'=>-1, 'msg'=>'['.$result['respCode'].']'.$result['respDesc']];
|
|
|
}
|
|
|
}catch(Exception $ex){
|
|
|
return ['code'=>-1, 'msg'=>$ex->getMessage()];
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
static public function balance_query($channel, $bizParam){
|
|
|
if(empty($channel))exit();
|
|
|
|
|
|
require(PAY_ROOT."inc/Transfer.class.php");
|
|
|
|
|
|
$client = new SandpayTransfer($channel['appid'], $channel['appkey']);
|
|
|
$out_biz_no = date("YmdHis").rand(11111,99999);
|
|
|
try{
|
|
|
$result = $client->queryBalance($out_biz_no);
|
|
|
if (isset($result['respCode']) && $result['respCode']=='0000') {
|
|
|
return ['code'=>0, 'ammount'=>$result['balance'], 'msg'=>'当前账户余额:'.$result['balance'].' 元,可用额度:'.$result['creditAmt']];
|
|
|
}else{
|
|
|
return ['code'=>-1, 'msg'=>'['.$result['respCode'].']'.$result['respDesc']];
|
|
|
}
|
|
|
}catch(Exception $ex){
|
|
|
return ['code'=>-1, 'msg'=>$ex->getMessage()];
|
|
|
}
|
|
|
}
|
|
|
} |