Commit 6a8135bf by wangyu

feat: 新增富友支付(公众号、小程序、主扫、被扫支付,交易、退款订单查询,订单关闭,订单撤销),调整其它已发现的问题

1 parent fe1a50cd
Showing with 1975 additions and 100 deletions
...@@ -8,14 +8,16 @@ ...@@ -8,14 +8,16 @@
"authors": [ "authors": [
{ {
"name": "ldy", "name": "ldy",
"email": "932497180@qq.com", "email": "bingge@ledouya.com"
"homepage": ""
} }
], ],
"require": { "require": {
"php": ">=5.6", "php": ">=7.0",
"ext-bcmath": "*", "ext-bcmath": "*",
"ext-mbstring": "*" "ext-mbstring": "*",
"ext-json": "*",
"ext-openssl": "*",
"ext-iconv": "*"
}, },
"require-dev": { "require-dev": {
"endroid/qrcode": "~1.9" "endroid/qrcode": "~1.9"
......
<?php
date_default_timezone_set('Asia/Shanghai');
require_once __DIR__ . '/../../autoload.php';
require_once __DIR__ . '/common.php';
use Payment\Common\PayException;
use Payment\Client\Charge;
use Payment\Config;
$payData = [
'order_type' => 'WECHAT', //ALIPAY、UNIONPAY、BESTPAY
'order_no' => trade_no(null, true),
'amount' => 1,
'auth_code' => '',
'subject' => '支付测试',
'attach' => '10054c238f670a2e9649a8b100f20562'
];
var_dump($payData);
//2019062017085196425851101985
try {
$ret = Charge::run(Config::FU_CHANNEL_BAR, $config, $payData);
} catch (PayException $e) {
exit($e->errorMessage());
}
echo json_encode($ret, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
\ No newline at end of file
<?php
date_default_timezone_set('Asia/Shanghai');
require_once __DIR__ . '/../../autoload.php';
require_once __DIR__ . '/common.php';
use Payment\Client\Cancel;
use Payment\Common\PayException;
use Payment\Config;
$payData = [
'order_type' => 'WECHAT', //ALIPAY
'order_no' => trade_no(null, true),
'refund_no' => trade_no(null, true)
];
try {
$ret = Cancel::run(Config::FU_CHARGE, $config, $payData);
} catch (PayException $e) {
echo $e->errorMessage();
exit;
}
echo json_encode($ret, JSON_UNESCAPED_UNICODE);
\ No newline at end of file
<?php
date_default_timezone_set('Asia/Shanghai');
require_once __DIR__ . '/../../autoload.php';
require_once __DIR__ . '/common.php';
use Payment\Client\Query;
use Payment\Common\PayException;
use Payment\Config;
$payData = [
'order_type' => 'WECHAT', //ALIPAY、UNIONPAY、BESTPAY
'order_no' => trade_no(null, true), //商户订单号
];
try {
$ret = Query::run(Config::FU_CHARGE, $config, $payData);
} catch (PayException $e) {
exit($e->errorMessage());
}
echo json_encode($ret, JSON_UNESCAPED_UNICODE);
\ No newline at end of file
<?php
date_default_timezone_set('Asia/Shanghai');
require_once __DIR__ . '/../../autoload.php';
require_once __DIR__ . '/common.php';
use Payment\Client\Close;
use Payment\Common\PayException;
use Payment\Config;
$payData = [
'order_type' => 'WECHAT', //WXAPP、WXH5、ALIPAY
'order_no' => trade_no(null, true)
];
try {
$ret = Close::run(Config::FU_CHARGE, $config, $payData);
} catch (PayException $e) {
echo $e->errorMessage();
exit;
}
echo json_encode($ret, JSON_UNESCAPED_UNICODE);
\ No newline at end of file
<?php
$config = [
'ins_cd' => '08A9999999', //机构号
'mchnt_cd' => '0002900F0370542', //商户号
'term_id' => '88888888', //终端号
'sub_appid' => 'wx24863377e74518f8', //子商户appid
'private_key' => '-----BEGIN RSA PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJgAzD8fEvBHQTyxUEeK963mjziM
WG7nxpi+pDMdtWiakc6xVhhbaipLaHo4wVI92A2wr3ptGQ1/YsASEHm3m2wGOpT2vrb2Ln/S7lz1
ShjTKaT8U6rKgCdpQNHUuLhBQlpJer2mcYEzG/nGzcyalOCgXC/6CySiJCWJmPyR45bJAgMBAAEC
gYBHFfBvAKBBwIEQ2jeaDbKBIFcQcgoVa81jt5xgz178WXUg/awu3emLeBKXPh2i0YtN87hM/+J8
fnt3KbuMwMItCsTD72XFXLM4FgzJ4555CUCXBf5/tcKpS2xT8qV8QDr8oLKA18sQxWp8BMPrNp0e
pmwun/gwgxoyQrJUB5YgZQJBAOiVXHiTnc3KwvIkdOEPmlfePFnkD4zzcv2UwTlHWgCyM/L8SCAF
clXmSiJfKSZZS7o0kIeJJ6xe3Mf4/HSlhdMCQQCnTow+TnlEhDTPtWa+TUgzOys83Q/VLikqKmDz
kWJ7I12+WX6AbxxEHLD+THn0JGrlvzTEIZyCe0sjQy4LzQNzAkEAr2SjfVJkuGJlrNENSwPHMugm
vusbRwH3/38ET7udBdVdE6poga1Z0al+0njMwVypnNwy+eLWhkhrWmpLh3OjfQJAI3BV8JS6xzKh
5SVtn/3Kv19XJ0tEIUnn2lCjvLQdAixZnQpj61ydxie1rggRBQ/5vLSlvq3H8zOelNeUF1fT1QJA
DNo+tkHVXLY9H2kdWFoYTvuLexHAgrsnHxONOlSA5hcVLd1B3p9utOt3QeDf6x2i1lqhTH2w8gzj
vsnx13tWqg==
-----END RSA PRIVATE KEY-----', //RSA私钥
'notify_url' => 'http://www.ledian.com/payments/notify', //通知地址
'use_sandbox' => false,
'return_raw' => false
];
/**
* 获取用户IP及端口号
* @param bool $port 是否获取端口号
* @param bool $portJoin 端口号是否追加至IP后
* @return string
* @author KingRainy <kingrainy@163.com>
*/
function getIp($port = false, $portJoin = false)
{
$realip = '';
$unknown = '127.0.0.1';
if (isset($_SERVER)) {
if (isset($_SERVER['HTTP_X_FORWARDED_FOR']) && !empty($_SERVER['HTTP_X_FORWARDED_FOR']) && strcasecmp($_SERVER['HTTP_X_FORWARDED_FOR'], $unknown)) {
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
foreach ($arr as $ip) {
$ip = trim($ip);
if ($ip != 'unknown') {
$realip = $ip;
break;
}
}
} else if (isset($_SERVER['HTTP_CLIENT_IP']) && !empty($_SERVER['HTTP_CLIENT_IP']) && strcasecmp($_SERVER['HTTP_CLIENT_IP'], $unknown)) {
$realip = $_SERVER['HTTP_CLIENT_IP'];
} else if (isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR']) && strcasecmp($_SERVER['REMOTE_ADDR'], $unknown)) {
$realip = $_SERVER['REMOTE_ADDR'];
} else {
$realip = $unknown;
}
} else {
if (getenv('HTTP_X_FORWARDED_FOR') && strcasecmp(getenv('HTTP_X_FORWARDED_FOR'), $unknown)) {
$realip = getenv("HTTP_X_FORWARDED_FOR");
} else if (getenv('HTTP_CLIENT_IP') && strcasecmp(getenv('HTTP_CLIENT_IP'), $unknown)) {
$realip = getenv("HTTP_CLIENT_IP");
} else if (getenv('REMOTE_ADDR') && strcasecmp(getenv('REMOTE_ADDR'), $unknown)) {
$realip = getenv("REMOTE_ADDR");
} else {
$realip = $unknown;
}
}
$matches = array();
$ipMatches = preg_match("/[\d\.]{7,15}/", $realip, $matches);
if ($ipMatches) {
$realip = $matches[0];
} else {
$realip = $unknown;
}
if ($port) {
$ipport = intval($_SERVER['REMOTE_PORT'] ?? 0);
if ($portJoin) {
$realip = $realip . ':' . $ipport;
} else {
return $ipport;
}
}
return $realip;
}
/**
* 随机生成字符串
* @param mixed $length 长度
* @param bool $numeric 仅为数字
* @return string
* @author wangyu <wangyu@ledouya.com>
* @createTime 2018/3/21 18:40
*/
function random($length, $numeric = false)
{
$seed = base_convert(md5(microtime() . ($_SERVER['DOCUMENT_ROOT']) ?? getIp(true, true)), 16, $numeric ? 10 : 35);
$seed = $numeric ? (str_replace('0', '', $seed) . '012340567890') : ($seed . 'zZ' . strtoupper($seed));
if ($numeric) {
$hash = '';
} else {
$hash = chr(rand(1, 26) + rand(0, 1) * 32 + 64);
$length--;
}
$max = strlen($seed) - 1;
for ($i = 0; $i < $length; $i++) {
$hash .= $seed{mt_rand(0, $max)};
}
return $hash;
}
/**
* 生成32位随机字符串
* @return string
* @author wangyu <wangyu@ledouya.com>
* @createTime 2018/5/12 15:19
*/
function uuid32()
{
$uuid = md5(uniqid(md5(microtime(true)), true));
return $uuid;
}
/**
* 全局唯一标识符(uuid实现)
* @param string $namespace 自定义命名空间
* @return string
* @author wangyu <wangyu@ledouya.com>
* @createTime 2018/7/19 11:33
*/
function guid($namespace = '')
{
$data = ($_SERVER['REQUEST_TIME_FLOAT'] ?? ($_SERVER['REQUEST_TIME'] ?? time())) . ($_SERVER['REMOTE_ADDR'] ?? getIp(true, true));
$hash = strtoupper(hash('ripemd128', uuid32() . md5($namespace . $data)));
return substr($hash, 0, 8) . '-' . substr($hash, 8, 4) . '-' . substr($hash, 12, 4) . '-' . substr($hash, 16, 4) . '-' . substr($hash, 20, 12);
}
/**
* 订单号生成(32位字符串)
* @param null $custom 自定义字符,需为大于0小于100的数字,可用来做业务方自定义数据使用
* @param bool $simple 是否采用简单模式
* @return string
* @author wangyu <wangyu@ledouya.com>
* @createTime 2018/4/25 15:50
*/
function trade_no($custom = null, $simple = false)
{
list($usec, $sec) = explode(' ', microtime());
$usec = substr(str_replace('0.', '', $usec), 0, 6);
if (false === $simple) {
if (!empty($custom) && $custom > 0 && $custom < 99) {
$custom = str_pad($custom, 2, '0', STR_PAD_LEFT);
} else {
$custom = rand(10, 99);
}
$str = substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 10);
return date('YmdHis') . $usec . $str . $custom;
}
$str = substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
return date('YmdHis') . $usec . $str;
}
\ No newline at end of file
<?php
date_default_timezone_set('Asia/Shanghai');
require_once __DIR__ . '/../../autoload.php';
require_once __DIR__ . '/common.php';
use Payment\Common\PayException;
use Payment\Client\Charge;
use Payment\Config;
$payData = [
'trade_type' => 'LETPAY',
'order_no' => time(),
'amount' => 1,
'subject' => '支付测试',
'openid' => 'oUlAM0Wp1K1rJEGJ0t__Ls5-qFKE',
'attach' => '10054c238f670a2e9649a8b100f20562'
];
try {
$ret = Charge::run(Config::FU_CHANNEL_LITE, $config, $payData);
} catch (PayException $e) {
echo $e->errorMessage();
exit;
}
echo json_encode($ret, JSON_UNESCAPED_UNICODE);
\ No newline at end of file
<?php
date_default_timezone_set('Asia/Shanghai');
require_once __DIR__ . '/../../autoload.php';
require_once __DIR__ . '/common.php';
require_once __DIR__ . '/../testNotify.php';
use Payment\Client\Notify;
use Payment\Common\PayException;
$channel = 'fu_charge';
$callback = new TestNotify();
$_POST['req'] = '%3C%3Fxml+version%3D%221.0%22+encoding%3D%22GBK%22+standalone%3D%22yes%22%3F%3E%3Cxml%3E%3Ccurr_type%3ECNY%3C%2Fcurr_type%3E%3Cins_cd%3E08A9999999%3C%2Fins_cd%3E%3Cmchnt_cd%3E0002900F0370542%3C%2Fmchnt_cd%3E%3Cmchnt_order_no%3E2019062017530653068450564957%3C%2Fmchnt_order_no%3E%3Corder_amt%3E1%3C%2Forder_amt%3E%3Corder_type%3EWECHAT%3C%2Forder_type%3E%3Crandom_str%3ELBY9GBWNNFV2RSTJX9PK549HGZK9J5U7%3C%2Frandom_str%3E%3Creserved_addn_inf%3E10054c238f670a2e9649a8b100f20562%3C%2Freserved_addn_inf%3E%3Creserved_bank_type%3ECFT%3C%2Freserved_bank_type%3E%3Creserved_buyer_logon_id%3E%3C%2Freserved_buyer_logon_id%3E%3Creserved_channel_order_id%3E2019062017530653068450564957%3C%2Freserved_channel_order_id%3E%3Creserved_coupon_fee%3E0%3C%2Freserved_coupon_fee%3E%3Creserved_fund_bill_list%3E%3C%2Freserved_fund_bill_list%3E%3Creserved_fy_settle_dt%3E20190620%3C%2Freserved_fy_settle_dt%3E%3Creserved_fy_trace_no%3E060001686318%3C%2Freserved_fy_trace_no%3E%3Creserved_is_credit%3E0%3C%2Freserved_is_credit%3E%3Creserved_settlement_amt%3E1%3C%2Freserved_settlement_amt%3E%3Cresult_code%3E000000%3C%2Fresult_code%3E%3Cresult_msg%3ESUCCESS%3C%2Fresult_msg%3E%3Csettle_order_amt%3E1%3C%2Fsettle_order_amt%3E%3Csign%3E2lvzV829wI5miCS%2FYPkdhcPMmwwd5Z3en%2BNeXfwgEqvqXNXbUeMipHM9JeNZX1l3zuCnSgEyyQWcijeyzPSOC5UiOoxSGOwx1tsQPF9rDUFu25ApVz%2B7hT6rn5R3bc9zK0phgYjdkkKF64%2BCrWsI4gEnJHIyo568FgDqyVziXhA%3D%3C%2Fsign%3E%3Cterm_id%3E%3C%2Fterm_id%3E%3Ctransaction_id%3E4200000334201906209673443163%3C%2Ftransaction_id%3E%3Ctxn_fin_ts%3E20190620175355%3C%2Ftxn_fin_ts%3E%3Cuser_id%3EoUpF8uBpoepFxyJcDAonTatbs8Zc%3C%2Fuser_id%3E%3C%2Fxml%3E';
try {
$ret = Notify::run($channel, $config, $callback);
var_dump($ret);
} catch (PayException $e) {
echo $e->errorMessage();
exit;
}
\ No newline at end of file
<?php
date_default_timezone_set('Asia/Shanghai');
require_once __DIR__ . '/../../autoload.php';
require_once __DIR__ . '/common.php';
use Payment\Client\Refund;
use Payment\Common\PayException;
use Payment\Config;
$payData = [
'order_type' => 'WECHAT', //ALIPAY、UNIONPAY、BESTPAY
'order_no' => trade_no(null, true),
'refund_no' => trade_no(null, true),
'total_fee' => 1, //订单总金额
'refund_fee' => 1, //退款金额
'trade_date' => '', //原交易日期(Ymd,如:20190620)
];
//var_dump($payData);
try {
$ret = Refund::run(Config::FU_REFUND, $config, $payData);
} catch (PayException $e) {
echo $e->errorMessage();
exit;
}
echo json_encode($ret, JSON_UNESCAPED_UNICODE);
\ No newline at end of file
<?php
date_default_timezone_set('Asia/Shanghai');
require_once __DIR__ . '/../../autoload.php';
require_once __DIR__ . '/common.php';
use Payment\Client\Query;
use Payment\Common\PayException;
use Payment\Config;
$payData = [
'order_no' => trade_no(null, true), //商户订单号
'refund_no' => trade_no(null, true), //商户退款单号
];
try {
$ret = Query::run(Config::FU_REFUND, $config, $payData);
} catch (PayException $e) {
exit($e->errorMessage());
}
echo json_encode($ret, JSON_UNESCAPED_UNICODE);
\ No newline at end of file
<?php
date_default_timezone_set('Asia/Shanghai');
require_once __DIR__ . '/../../autoload.php';
require_once __DIR__ . '/common.php';
use Payment\Common\PayException;
use Payment\Client\Charge;
use Payment\Config;
$payData = [
'order_type' => 'WECHAT', //ALIPAY
'order_no' => trade_no(null, true),
'amount' => 1,
'subject' => '支付测试',
'attach' => '10054c238f670a2e9649a8b100f20562'
];
$config['notify_url'] = 'http://api.hotel.ledianyun.com/api/index/test';
try {
$ret = Charge::run(Config::FU_CHANNEL_SCAN, $config, $payData);
} catch (PayException $e) {
echo $e->errorMessage();
exit;
}
echo json_encode($ret, JSON_UNESCAPED_UNICODE);
\ No newline at end of file
...@@ -2,11 +2,6 @@ ...@@ -2,11 +2,6 @@
use Payment\Notify\PayNotifyInterface; use Payment\Notify\PayNotifyInterface;
use Payment\Config; use Payment\Config;
/**
*
* @createTime: 2016-07-20 18:31
* @description:
*/
/** /**
* 客户端需要继承该接口,并实现这个方法,在其中实现对应的业务逻辑 * 客户端需要继承该接口,并实现这个方法,在其中实现对应的业务逻辑
...@@ -15,9 +10,10 @@ use Payment\Config; ...@@ -15,9 +10,10 @@ use Payment\Config;
*/ */
class TestNotify implements PayNotifyInterface class TestNotify implements PayNotifyInterface
{ {
public function notifyProcess(array $data) public function notifyProcess(array $data)
{ {
$channel = $data['channel']; $channel = $data['channel'] ?? '';
if ($channel === Config::ALI_CHARGE) {// 支付宝支付 if ($channel === Config::ALI_CHARGE) {// 支付宝支付
} elseif ($channel === Config::WX_CHARGE) {// 微信支付 } elseif ($channel === Config::WX_CHARGE) {// 微信支付
...@@ -27,10 +23,11 @@ class TestNotify implements PayNotifyInterface ...@@ -27,10 +23,11 @@ class TestNotify implements PayNotifyInterface
} elseif ($channel === Config::CMB_BIND) {// 招商签约 } elseif ($channel === Config::CMB_BIND) {// 招商签约
} }
echo '----'; echo PHP_EOL . '--------------------------------------------------------' . PHP_EOL;
var_dump($data); var_dump($channel, $data);
// 执行业务逻辑,成功后返回true // 执行业务逻辑,成功后返回true
return true; return true;
} }
} }
<?php
namespace Payment\Cancel;
use Payment\Common\Fu\Data\Cancel\CancelData;
use Payment\Common\Fu\FuBaseStrategy;
use Payment\Common\FuConfig;
/**
* 撤单,仅支持条码支付
* Class FuCancel
* @package Payment\Charge\Fu
*/
class FuCancel extends FuBaseStrategy
{
public function getBuildDataClass()
{
return CancelData::class;
}
protected function getReqUrl($url = null)
{
return parent::getReqUrl($url ?? FuConfig::CANCEL_URL);
}
/**
* retData
* @param array $data
* @return array|mixed
*/
protected function retData(array $data)
{
$backData = [
'order_type' => $data['order_type'] ?? '', //订单类型
'order_no' => $data['mchnt_order_no'] ?? '', //原交易商户订单号
'refund_no' => $data['cancel_order_no'] ?? '', //商户撤销单号
'out_trade_no' => $data['transaction_id'] ?? '', //渠道交易流水号
'out_cancel_no' => $data['cancel_id'] ?? '', //渠道撤销流水号
];
return $backData;
}
}
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
namespace Payment; namespace Payment;
use Payment\Cancel\FuCancel;
use Payment\Charge\MiPay\MiCancel; use Payment\Charge\MiPay\MiCancel;
use Payment\Charge\Sw\SwCancel; use Payment\Charge\Sw\SwCancel;
use Payment\Charge\TLpay\TLCancel; use Payment\Charge\TLpay\TLCancel;
...@@ -40,7 +41,6 @@ class CancelContext ...@@ -40,7 +41,6 @@ class CancelContext
{ {
try { try {
switch ($channel) { switch ($channel) {
case Config::TL_CHANNEL_LITE: case Config::TL_CHANNEL_LITE:
$this->cancelHandler = new TLCancel($config); $this->cancelHandler = new TLCancel($config);
break; break;
...@@ -50,6 +50,9 @@ class CancelContext ...@@ -50,6 +50,9 @@ class CancelContext
case Config::SW_CHARGE: case Config::SW_CHARGE:
$this->cancelHandler = new SwCancel($config); $this->cancelHandler = new SwCancel($config);
break; break;
case Config::FU_CHARGE:
$this->cancelHandler = new FuCancel($config);
break;
default: default:
throw new PayException('当前仅支持:通联支付平台'); throw new PayException('当前仅支持:通联支付平台');
} }
...@@ -69,7 +72,7 @@ class CancelContext ...@@ -69,7 +72,7 @@ class CancelContext
*/ */
public function cancel(array $data) public function cancel(array $data)
{ {
if (! $this->cancelHandler instanceof BaseStrategy) { if (!$this->cancelHandler instanceof BaseStrategy) {
throw new PayException('请检查初始化是否正确'); throw new PayException('请检查初始化是否正确');
} }
......
<?php
namespace Payment\Charge\Fu;
use Payment\Common\Fu\Data\BackBarChargeData;
use Payment\Common\Fu\Data\Charge\BarChargeData;
use Payment\Common\Fu\FuBaseStrategy;
use Payment\Common\FuConfig;
/**
* Class FuScanCharge
* @package Payment\Charge\Fu
*/
class FuBarCharge extends FuBaseStrategy
{
public function getBuildDataClass()
{
return BarChargeData::class;
}
protected function getReqUrl($url = null)
{
return parent::getReqUrl($url ?? FuConfig::MICROPAY_URL);
}
/**
* 处理扫码支付的返回值
* @param array $ret
* @return array|mixed
* @throws \Payment\Common\PayException
*/
protected function retData(array $ret)
{
$back = new BackBarChargeData($this->config, $ret);
$backData = $back->getData();
return $backData;
}
}
<?php
namespace Payment\Charge\Fu;
use Payment\Common\Fu\Data\Cancel\CloseData;
use Payment\Common\Fu\FuBaseStrategy;
use Payment\Common\FuConfig;
/**
* Class FuClose
* @package Payment\Charge\Fu
*/
class FuClose extends FuBaseStrategy
{
public function getBuildDataClass()
{
return CloseData::class;
}
protected function getReqUrl($url = null)
{
return parent::getReqUrl($url ?? FuConfig::CLOSE_URL);
}
/**
* retData
* @param array $data
* @return array|mixed
*/
protected function retData(array $data)
{
$backData = [
'order_type' => $data['order_type'] ?? '', //订单类型
'order_no' => $data['mchnt_order_no'] ?? '', //商户订单号, 商户系统内部的订单号
];
return $backData;
}
}
<?php
namespace Payment\Charge\Fu;
use Payment\Common\Fu\Data\BackPubChargeData;
use Payment\Common\Fu\Data\Charge\PubChargeData;
use Payment\Common\Fu\FuBaseStrategy;
use Payment\Common\FuConfig;
/**
* Class FuPubCharge
* @package Payment\Charge\Fu
*/
class FuPubCharge extends FuBaseStrategy
{
public function getBuildDataClass()
{
return PubChargeData::class;
}
protected function getReqUrl($url = null)
{
return parent::getReqUrl($url ?: FuConfig::UNIFIED_URL);
}
/**
* 处理支付的返回值。直接返回与微信文档对应的字段
* @param array $ret
*
* @return array $data 包含以下键
*
* ```php
* $data = [
* 'appId' => '', // 公众号id
* 'package' => '', // 订单详情扩展字符串 统一下单接口返回的prepay_id参数值,提交格式如:prepay_id=***
* 'nonceStr' => '', // 随机字符串
* 'timeStamp' => '', // 时间戳
* 'signType' => '', // 签名算法,暂支持MD5
* 'paySign' => '', // 签名
* ];
* ```
*
* @throws \Payment\Common\PayException
*/
protected function retData(array $ret)
{
$back = new BackPubChargeData($this->config, $ret);
// $back->setSign();
$backData = $back->getData();
// $backData['paySign'] = $backData['sign'];
// 移除sign
unset($backData['sign']);
// 公众号支付返回数组结构
return $backData;
}
}
<?php
namespace Payment\Charge\Fu;
use Payment\Common\Fu\Data\BackScanChargeData;
use Payment\Common\Fu\Data\Charge\ScanChargeData;
use Payment\Common\Fu\FuBaseStrategy;
use Payment\Common\FuConfig;
/**
* Class FuScanCharge
* @package Payment\Charge\Fu
*/
class FuScanCharge extends FuBaseStrategy
{
public function getBuildDataClass()
{
return ScanChargeData::class;
}
protected function getReqUrl($url = null)
{
return parent::getReqUrl($url ?? FuConfig::SCANPAY_URL);
}
/**
* 处理扫码支付的返回值
* @param array $ret
* @return array|mixed
* @throws \Payment\Common\PayException
*/
protected function retData(array $ret)
{
$back = new BackScanChargeData($this->config, $ret);
$backData = $back->getData();
return $backData;
}
}
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
namespace Payment\Charge\Sw; namespace Payment\Charge\Sw;
use Payment\Common\Sw\Data\BackCancelData; use Payment\Common\Sw\Data\BackCancelData;
use Payment\Common\Sw\Data\Charge\CancelData; use Payment\Common\Sw\Data\Cancel\CancelData;
use Payment\Common\Sw\SwBaseStrategy; use Payment\Common\Sw\SwBaseStrategy;
use Payment\Common\SwConfig; use Payment\Common\SwConfig;
......
...@@ -15,7 +15,9 @@ use Payment\Charge\Ali\AliWapCharge; ...@@ -15,7 +15,9 @@ use Payment\Charge\Ali\AliWapCharge;
use Payment\Charge\Ali\AliWebCharge; use Payment\Charge\Ali\AliWebCharge;
use Payment\Charge\Ali\AliQrCharge; use Payment\Charge\Ali\AliQrCharge;
use Payment\Charge\Cmb\CmbCharge; use Payment\Charge\Cmb\CmbCharge;
use Payment\Charge\Fu\FuBarCharge;
use Payment\Charge\Fu\FuPubCharge;
use Payment\Charge\Fu\FuScanCharge;
use Payment\Charge\MiPay\MiLiteCharge; use Payment\Charge\MiPay\MiLiteCharge;
use Payment\Charge\Sw\SwBarCharge; use Payment\Charge\Sw\SwBarCharge;
use Payment\Charge\Sw\SwFaceCharge; use Payment\Charge\Sw\SwFaceCharge;
...@@ -61,6 +63,7 @@ class ChargeContext ...@@ -61,6 +63,7 @@ class ChargeContext
// 初始化时,可能抛出异常,再次统一再抛出给客户端进行处理 // 初始化时,可能抛出异常,再次统一再抛出给客户端进行处理
try { try {
switch ($channel) { switch ($channel) {
//支付宝
case Config::ALI_CHANNEL_WAP: case Config::ALI_CHANNEL_WAP:
$this->channel = new AliWapCharge($config); $this->channel = new AliWapCharge($config);
break; break;
...@@ -77,6 +80,7 @@ class ChargeContext ...@@ -77,6 +80,7 @@ class ChargeContext
$this->channel = new AliBarCharge($config); $this->channel = new AliBarCharge($config);
break; break;
//微信
case Config::WX_CHANNEL_APP: case Config::WX_CHANNEL_APP:
$this->channel = new WxAppCharge($config); $this->channel = new WxAppCharge($config);
break; break;
...@@ -98,10 +102,12 @@ class ChargeContext ...@@ -98,10 +102,12 @@ class ChargeContext
$this->channel = new CmbCharge($config); $this->channel = new CmbCharge($config);
break; break;
//通联
case Config::TL_CHANNEL_LITE: //通联支付 case Config::TL_CHANNEL_LITE: //通联支付
$this->channel = new TLLiteCharge($config); $this->channel = new TLLiteCharge($config);
break; break;
//米付
case Config::MI_CHANNEL_LITE: //米付小程序通道 case Config::MI_CHANNEL_LITE: //米付小程序通道
$this->channel = new MiLiteCharge($config); $this->channel = new MiLiteCharge($config);
break; break;
...@@ -126,8 +132,20 @@ class ChargeContext ...@@ -126,8 +132,20 @@ class ChargeContext
$this->channel = new SwFaceInfo($config); $this->channel = new SwFaceInfo($config);
break; break;
//富友
case Config::FU_CHANNEL_PUB:
case Config::FU_CHANNEL_LITE:
$this->channel = new FuPubCharge($config);
break;
case Config::FU_CHANNEL_SCAN:
$this->channel = new FuScanCharge($config);
break;
case Config::FU_CHANNEL_BAR:
$this->channel = new FuBarCharge($config);
break;
default: default:
throw new PayException('当前支持:支付宝 微信 招商一网通 通联支付 米付'); throw new PayException('当前支持:支付宝、微信、招商一网通、通联支付、米付支付、扫呗支付、富友支付。');
} }
} catch (PayException $e) { } catch (PayException $e) {
throw $e; throw $e;
...@@ -155,7 +173,7 @@ class ChargeContext ...@@ -155,7 +173,7 @@ class ChargeContext
*/ */
public function charge(array $data) public function charge(array $data)
{ {
if (! $this->channel instanceof BaseStrategy) { if (!$this->channel instanceof BaseStrategy) {
throw new PayException('请检查初始化是否正确'); throw new PayException('请检查初始化是否正确');
} }
......
...@@ -31,13 +31,16 @@ class Cancel ...@@ -31,13 +31,16 @@ class Cancel
Config::WX_CHANNEL_LITE,// 微信小程序支付 Config::WX_CHANNEL_LITE,// 微信小程序支付
Config::CMB_CHANNEL_APP,// 招行一网通 Config::CMB_CHANNEL_APP,// 招行一网通
'applepay_upacp',// Apple Pay
Config::APPLE_PAY,// Apple Pay
Config::TL_CHANNEL_LITE,//通联支付 Config::TL_CHANNEL_LITE,//通联支付
Config::MI_CHANNEL_LITE, //米付 Config::MI_CHANNEL_LITE, //米付
Config::SW_CHARGE,//扫呗支付退款 Config::SW_CHARGE, //扫呗支付退款
Config::FU_CHARGE, //富友
]; ];
/** /**
...@@ -71,7 +74,7 @@ class Cancel ...@@ -71,7 +74,7 @@ class Cancel
*/ */
public static function run($channel, $config, $metadata) public static function run($channel, $config, $metadata)
{ {
if (! in_array($channel, self::$supportChannel)) { if (!in_array($channel, self::$supportChannel)) {
throw new PayException('sdk当前不支持该支付渠道,当前仅支持:' . implode(',', self::$supportChannel)); throw new PayException('sdk当前不支持该支付渠道,当前仅支持:' . implode(',', self::$supportChannel));
} }
......
...@@ -30,7 +30,6 @@ class Charge ...@@ -30,7 +30,6 @@ class Charge
Config::TL_CHANNEL_LITE, // 通联支付 Config::TL_CHANNEL_LITE, // 通联支付
Config::MI_CHANNEL_LITE,//米付小程序通道 Config::MI_CHANNEL_LITE,//米付小程序通道
//立楚扫呗:公众号、小程序、扫码、自助收款 //立楚扫呗:公众号、小程序、扫码、自助收款
Config::SW_CHANNEL_PUB, Config::SW_CHANNEL_PUB,
Config::SW_CHANNEL_LITE, Config::SW_CHANNEL_LITE,
...@@ -38,6 +37,10 @@ class Charge ...@@ -38,6 +37,10 @@ class Charge
Config::SW_CHANNEL_FACEPAY, Config::SW_CHANNEL_FACEPAY,
Config::SW_CHANNEL_BAR, Config::SW_CHANNEL_BAR,
Config::FU_CHANNEL_PUB,
Config::FU_CHANNEL_LITE,
Config::FU_CHANNEL_SCAN,
Config::FU_CHANNEL_BAR,
]; ];
......
<?php <?php
/**
* Created by IntelliJ IDEA.
* User: yeran
* Date: 2018/4/23
* Time: 下午6:07
*/
namespace Payment\Client; namespace Payment\Client;
use Payment\CloseContext; use Payment\CloseContext;
use Payment\Common\PayException; use Payment\Common\PayException;
use Payment\Config; use Payment\Config;
...@@ -22,8 +15,8 @@ use Payment\Config; ...@@ -22,8 +15,8 @@ use Payment\Config;
class Close { class Close {
private static $supportChannel = [ private static $supportChannel = [
Config::SW_CHARGE, //扫呗支付关闭订单
Config::SW_CHARGE,//扫呗支付关闭订单 Config::FU_CHARGE, //富友支付关闭订单
]; ];
/** /**
......
...@@ -17,13 +17,16 @@ class Notify ...@@ -17,13 +17,16 @@ class Notify
Config::WX_CHARGE,// 微信 Config::WX_CHARGE,// 微信
Config::CMB_CHARGE,// 招行一网通 Config::CMB_CHARGE,// 招行一网通
'applepay_upacp',// Apple Pay
Config::APPLE_PAY, //apple pay
Config::TL_CHARGE,//通联支付 Config::TL_CHARGE,//通联支付
Config::MI_CHARGE,//米付 Config::MI_CHARGE,//米付
Config::SW_CHARGE,//扫呗 Config::SW_CHARGE,//扫呗
Config::FU_CHARGE, //富友
]; ];
/** /**
......
...@@ -38,6 +38,9 @@ class Query ...@@ -38,6 +38,9 @@ class Query
Config::MI_QUERY,//米付 Config::MI_QUERY,//米付
Config::SW_QUERY,//扫呗 Config::SW_QUERY,//扫呗
Config::FU_CHARGE,
Config::FU_REFUND,
]; ];
/** /**
...@@ -70,8 +73,8 @@ class Query ...@@ -70,8 +73,8 @@ class Query
*/ */
public static function run($queryType, $config, $metadata) public static function run($queryType, $config, $metadata)
{ {
if (! in_array($queryType, self::$supportType)) { if (!in_array($queryType, self::$supportType)) {
throw new PayException('sdk当前不支持该类型查询,当前仅支持:' . implode(',', self::$supportType) . __LINE__); throw new PayException('sdk当前不支持该类型查询,当前仅支持:' . implode(',', self::$supportType));
} }
try { try {
......
...@@ -27,12 +27,14 @@ class Refund ...@@ -27,12 +27,14 @@ class Refund
Config::CMB_REFUND,// 招行一网通 Config::CMB_REFUND,// 招行一网通
'applepay_upacp',// Apple Pay Config::APPLE_PAY,// Apple Pay
Config::TL_REFUND,//通联支付 Config::TL_REFUND,//通联支付
Config::MI_REFUND,//米付 Config::MI_REFUND,//米付
Config::SW_REFUND,//扫呗 Config::SW_REFUND,//扫呗
Config::FU_REFUND, //富友
]; ];
/** /**
...@@ -58,7 +60,7 @@ class Refund ...@@ -58,7 +60,7 @@ class Refund
public static function run($channel, $config, $refundData) public static function run($channel, $config, $refundData)
{ {
if (! in_array($channel, self::$supportChannel)) { if (!in_array($channel, self::$supportChannel)) {
throw new PayException('sdk当前不支持该退款渠道,当前仅支持:' . implode(',', self::$supportChannel)); throw new PayException('sdk当前不支持该退款渠道,当前仅支持:' . implode(',', self::$supportChannel));
} }
......
...@@ -22,7 +22,8 @@ class Transfer ...@@ -22,7 +22,8 @@ class Transfer
Config::WX_TRANSFER,// 微信 Config::WX_TRANSFER,// 微信
'cmb_wallet',// 招行一网通 'cmb_wallet',// 招行一网通
'applepay_upacp',// Apple Pay
Config::APPLE_PAY,// Apple Pay
]; ];
/** /**
......
<?php <?php
/**
* @author: yeran
* @createTime: 2019-03-25 00:15
* @description: 交易关闭接口
*/
namespace Payment; namespace Payment;
use Payment\Charge\Fu\FuClose;
use Payment\Charge\Sw\SwClose; use Payment\Charge\Sw\SwClose;
use Payment\Common\BaseStrategy; use Payment\Common\BaseStrategy;
use Payment\Common\PayException; use Payment\Common\PayException;
/** /**
* Class CloseContext * Class CloseContext
* @package Payment * @package Payment
...@@ -20,15 +14,14 @@ use Payment\Common\PayException; ...@@ -20,15 +14,14 @@ use Payment\Common\PayException;
class CloseContext class CloseContext
{ {
/** /**
* 退款的渠道 * 关闭订单的渠道
* @var BaseStrategy * @var BaseStrategy
*/ */
protected $closeHandler; protected $closeHandler;
/** /**
* 设置对应的退款渠道 * 设置对应的关闭订单渠道
* @param string $channel 退款渠道 * @param string $channel 关闭订单渠道
* - @see Config * - @see Config
* *
* @param array $config 配置文件 * @param array $config 配置文件
...@@ -39,12 +32,14 @@ class CloseContext ...@@ -39,12 +32,14 @@ class CloseContext
{ {
try { try {
switch ($channel) { switch ($channel) {
case Config::SW_CHARGE: case Config::SW_CHARGE:
$this->closeHandler = new SwClose($config); $this->closeHandler = new SwClose($config);
break; break;
case Config::FU_CHARGE:
$this->closeHandler = new FuClose($config);
break;
default: default:
throw new PayException('当前仅支持:通联支付平台'); throw new PayException('当前仅支持:SW_CHARGE、FU_CHARGE');
} }
} catch (PayException $e) { } catch (PayException $e) {
throw $e; throw $e;
...@@ -62,7 +57,7 @@ class CloseContext ...@@ -62,7 +57,7 @@ class CloseContext
*/ */
public function close(array $data) public function close(array $data)
{ {
if (! $this->closeHandler instanceof BaseStrategy) { if (!$this->closeHandler instanceof BaseStrategy) {
throw new PayException('请检查初始化是否正确'); throw new PayException('请检查初始化是否正确');
} }
......
...@@ -51,16 +51,17 @@ abstract class BaseData ...@@ -51,16 +51,17 @@ abstract class BaseData
$this->channel = Config::ALI_PAY; $this->channel = Config::ALI_PAY;
} elseif ($config instanceof CmbConfig) { } elseif ($config instanceof CmbConfig) {
$this->channel = Config::CMB_PAY; $this->channel = Config::CMB_PAY;
}elseif ($config instanceof TLConfig) { } elseif ($config instanceof TLConfig) {
$this->channel = Config::TL_PAY; $this->channel = Config::TL_PAY;
} elseif ($config instanceof MiConfig) { } elseif ($config instanceof MiConfig) {
$this->channel = Config::MI_PAY; $this->channel = Config::MI_PAY;
}elseif ($config instanceof SwConfig) { } elseif ($config instanceof SwConfig) {
$this->channel = Config::SW_PAY; $this->channel = Config::SW_PAY;
} elseif ($config instanceof FuConfig) {
$this->channel = Config::FU_PAY;
} }
$this->data = array_merge($config->toArray(), $reqData);//配置信息合并 $this->data = array_merge($config->toArray(), $reqData);//配置信息合并
try { try {
$this->checkDataParam(); $this->checkDataParam();
} catch (PayException $e) { } catch (PayException $e) {
...@@ -96,58 +97,55 @@ abstract class BaseData ...@@ -96,58 +97,55 @@ abstract class BaseData
public function __isset($name) public function __isset($name)
{ {
// TODO: Implement __isset() method. if (isset($this->data[$name])) return (false === empty($this->data[$name]));
if (isset($this->data[$name])) {
return (false === empty($this->data[$name]));
}
return null; return null;
} }
/** /**
* 设置签名 * 设置签名
* *
* @throws \Exception
*/ */
public function setSign() public function setSign()
{ {
$this->buildData(); $this->buildData();
if ($this->channel === Config::CMB_PAY) { if ($this->channel === Config::CMB_PAY) {
$data = $this->retData['reqData']; $data = $this->retData['reqData'];
} else { } else {
if ($this->orgid) {
if($this->orgid){
$this->retData['orgid'] = $this->orgid; $this->retData['orgid'] = $this->orgid;
$this->retData = ArrayUtil::paraFilter($this->retData); $this->retData = ArrayUtil::paraFilter($this->retData);
} }
$data = $this->retData; $data = $this->retData;
} }
switch ($this->channel) {
if($this->channel === Config::TL_PAY){ case Config::TL_PAY:
$this->retData['sign'] = ArrayUtil::SignArray($data, $this->md5Key); //签名
$this->retData['sign'] = ArrayUtil::SignArray($data,$this->md5Key);//签名 break;
case Config::MI_PAY:
}else if ($this->channel === Config::MI_PAY){ $basePath = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'CacertFile' . DIRECTORY_SEPARATOR;
$this->cacertPath = "{$basePath}mipay" . DIRECTORY_SEPARATOR . "ldy_private_key.pem";
$basePath = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'CacertFile' . DIRECTORY_SEPARATOR; $this->retData['sign'] = ArrayUtil::SignRSA($data, $this->cacertPath);//签名
$this->cacertPath = "{$basePath}mipay".DIRECTORY_SEPARATOR."ldy_private_key.pem"; break;
$this->retData['sign'] = ArrayUtil::SignRSA($data,$this->cacertPath);//签名 case Config::SW_PAY:
//添加令牌,参数由makesign函数自由控制
} else if($this->channel === Config::SW_PAY){ $signData = $this->certainSignData ?? $data;
$values = ArrayUtil::removeKeys($signData, ['key_sign']);
//添加令牌,参数由makesign函数自由控制 if ($this->sign_sort) $values = ArrayUtil::arraySort($values);
$signData = $this->certainSignData??$data; $signStr = ArrayUtil::createLinkstring($values);
$values = ArrayUtil::removeKeys($signData, ['key_sign']); $this->makeSign($signStr);
if($this->sign_sort) $values = ArrayUtil::arraySort($values); break;
$signStr = ArrayUtil::createLinkstring($values); case Config::FU_PAY:
$this->makeSign($signStr); $signData = ArrayUtil::arraySort(ArrayUtil::removeKeys(empty($this->certainSignData) ? $data : $this->certainSignData, ['sign']));
foreach ($signData as $key => $value) if (false !== strpos($key, 'reserved_')) unset($signData[$key]);
}else{ $this->retData['sign'] = $this->makeSign(mb_convert_encoding(ArrayUtil::createLinkstring($signData), 'gbk', 'utf-8'));
$values = ArrayUtil::removeKeys($data, ['sign']); unset($signData);
$values = ArrayUtil::arraySort($values); break;
$signStr = ArrayUtil::createLinkstring($values); default:
$this->retData['sign'] = $this->makeSign($signStr); $values = ArrayUtil::removeKeys($data, ['sign']);
$values = ArrayUtil::arraySort($values);
$signStr = ArrayUtil::createLinkstring($values);
$this->retData['sign'] = $this->makeSign($signStr);
} }
} }
......
<?php
namespace Payment\Common\Fu\Data;
/**
* Class BackBarChargeData
* @package Payment\Common\Fu\Data
*/
class BackBarChargeData extends FuBaseData
{
public function getData()
{
$this->retData = [
'order_no' => $this->reserved_mchnt_order_no, //商户订单号
'out_order_no' => $this->reserved_fy_order_no, //富友订单号
'order_type' => $this->order_type, //订单类型
'amount' => $this->total_amount, //订单金额
'buyer_id' => $this->reserved_buyer_logon_id ?? '', //买家在渠道登录账号
'business_buyer_id' => $this->buyer_id ?? '', //用户在商户的id
'transaction_id' => $this->transaction_id,
'channel_order_id' => $this->reserved_channel_order_id, //条码流水号,用户账单二维码对应的流水
'time_end' => empty($this->reserved_txn_fin_ts) ? '' : date('Y-m-d H:i:s', strtotime($this->reserved_txn_fin_ts)), //用户支付时间
'bank_type' => $this->reserved_bank_type ?? '', //付款方式
'return_param' => $this->addn_inf ?? '', //附加数据
];
return parent::getData(); // TODO: Change the autogenerated stub
}
protected function buildData()
{
}
protected function checkDataParam()
{
// 对于返回数据不做检查检查
}
}
<?php
namespace Payment\Common\Fu\Data;
/**
* Class BackPubChargeData
* @package Payment\Common\Fu\Data
*/
class BackPubChargeData extends FuBaseData
{
public function getData()
{
$data = [];
switch ($this->trade_type) {
case 'JSAPI': //微信公众号
case 'LETPAY': //小程序
$data = [
'appId' => $this->subAppid ?? $this->sdk_appid,
'timeStamp' => $this->sdk_timestamp ?? time(),
'nonceStr' => $this->sdk_noncestr,
'package' => $this->sdk_package,
'signType' => $this->sdk_signtype,
];
break;
case 'FWC':
$data = [
'transaction_id' => $this->reserved_transaction_id
];
break;
default:
}
$this->retData['package'] = $data;
$this->retData['other'] = [
'out_trade_no' => $this->reserved_fy_order_no ?: '',
'attach' => $this->reserved_addn_inf ?: ''
];
return parent::getData(); // TODO: Change the autogenerated stub
}
protected function buildData()
{
}
protected function checkDataParam()
{
// 不进行检查
}
}
<?php
namespace Payment\Common\Fu\Data;
/**
* Class BackScanChargeData
* @package Payment\Common\Fu\Data
*/
class BackScanChargeData extends FuBaseData
{
public function getData()
{
$data = [
'qrcode' => $this->qr_code ?? '',
'session_id' => $this->session_id
];
$this->retData['package'] = $data;
$this->retData['other'] = [
'out_trade_no' => $this->reserved_fy_order_no ?: '',
'channel_trade_no' => $this->reserved_channel_order_id ?: '',
'attach' => $this->reserved_addn_inf ?: ''
];
return parent::getData(); // TODO: Change the autogenerated stub
}
protected function buildData()
{
}
protected function checkDataParam()
{
// 对于返回数据不做检查检查
}
}
<?php
namespace Payment\Common\Fu\Data\Cancel;
use Payment\Common\Fu\Data\FuBaseData;
use Payment\Common\PayException;
/**
* Class CancelData
* @package Payment\Common\Fu\Data\Cancel
*/
class CancelData extends FuBaseData
{
protected function checkDataParam()
{
if (empty($this->order_no) || mb_strlen($this->order_no) > 30) throw new PayException('商户系统订单号不能为空且长度不能超过30位');
if (empty($this->refund_no) || mb_strlen($this->refund_no) > 30) throw new PayException('商户系统撤销单号不能为空且长度不能超过30位');
$tradeType = $this->order_type = $this->trade_type ?? ($this->order_type ?? '');
if (empty($tradeType)) throw new PayException('订单类型有误(支持WECHAT、ALIPAY,条码支付)');
}
protected function buildData()
{
$signData = [
'version' => $this->version,
'ins_cd' => $this->institutionId, //机构号,接入机构在富友的唯一代码
'mchnt_cd' => $this->merchantId, //商户号, 富友分配给二级商户的商户号
'term_id' => $this->terminalId ?? '88888888', //终端号(没有真实终端号统一填88888888)
'random_str' => $this->randomStr, //随机字符串
'mchnt_order_no' => $this->order_no, //商户订单号, 商户系统内部的订单号(5到30个字符、只能包含字母数字,区分大小写)
'order_type' => $this->order_type, //订单类型:ALIPAY、WECHAT
'cancel_order_no' => $this->refund_no, //商户撤销单号
'operator_id' => $this->operator_id ?? '', //操作员
];
if (!empty($this->reserved_fy_term_id)) $signData['reserved_fy_term_id'] = $this->reserved_fy_term_id; //富友终端号(非富友终端请勿填写)
// foreach ($signData as $key => $value) if (false !== strpos($key, 'reserved_') && empty($value)) unset($signData[$key]);
$this->retData = $signData;
}
}
<?php
namespace Payment\Common\Fu\Data\Cancel;
use Payment\Common\Fu\Data\FuBaseData;
use Payment\Common\PayException;
/**
* Class CloseData
* @package Payment\Common\Fu\Data\Cancel
*/
class CloseData extends FuBaseData
{
protected function checkDataParam()
{
if (empty($this->order_no) || mb_strlen($this->order_no) > 30) throw new PayException('商户系统订单号不能为空且长度不能超过30位');
$tradeType = $this->order_type = $this->trade_type ?? ($this->order_type ?? '');
if (empty($tradeType)) throw new PayException('订单类型有误(支持WECHAT、WXAPP、WXH5、ALIPAY)');
}
protected function buildData()
{
$signData = [
'version' => $this->version,
'ins_cd' => $this->institutionId, //机构号,接入机构在富友的唯一代码
'mchnt_cd' => $this->merchantId, //商户号, 富友分配给二级商户的商户号
'term_id' => $this->terminalId ?? '88888888', //终端号(没有真实终端号统一填88888888)
'random_str' => $this->randomStr, //随机字符串
'mchnt_order_no' => $this->order_no, //商户订单号, 商户系统内部的订单号
'order_type' => $this->order_type, //订单类型:WECHAT(统一下单、公众号、小程序),WXAPP(微信 app),WXH5(微信 h5),ALIPAY(统一下单,服务窗)
'sub_appid' => $this->sub_appid ?? '', //子商户公众号id, 子商户配置多个公众号时必填
];
$this->retData = $signData;
}
}
<?php
namespace Payment\Common\Fu\Data\Charge;
use Payment\Common\PayException;
/**
* 条码支付
*
* Class BarChargeData
*
* @property string $order_no 商户订单号
* @property int $amount 订单总金额
* @property string $auth_code 扫码支付授权码,设备读取用户的条码或者二维码信息
* @property string $order_type 订单类型:WECHAT、ALIPAY、UNIONPAY、BESTPAY
*
* @package Payment\Common\Fu\Data\Charge
*/
class BarChargeData extends ChargeBaseData
{
/**
* checkDataParam
* @return mixed|void
* @throws PayException
*/
protected function checkDataParam()
{
parent::checkDataParam();
$tradeType = $this->order_type = $this->trade_type ?? ($this->order_type ?? '');
if (empty($tradeType)) throw new PayException('订单类型有误(支持WECHAT、ALIPAY、UNIONPAY、BESTPAY)');
$clientIp = $this->client_ip;
if (empty($clientIp)) $this->client_ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
}
/**
* 构建用于支付的签名相关数据
* @return array|void
*/
protected function buildData()
{
$signData = [
'version' => $this->version,
'ins_cd' => $this->institutionId, //机构号,接入机构在富友的唯一代码
'mchnt_cd' => $this->merchantId, //商户号, 富友分配给二级商户的商户号
'term_id' => $this->terminalId ?? '88888888', //终端号(没有真实终端号统一填88888888)
'random_str' => $this->randomStr, //随机字符串
'order_type' => $this->order_type, //订单类型:ALIPAY、WECHAT、UNIONPAY(银联二维码)
'goods_des' => $this->subject, //商品描述, 商品或支付单简要描述
'goods_detail' => $this->body ?? '', //单品优惠功能字段(填错影响交易)
'goods_tag' => $this->goods_tag ?? '', //商品标记
'addn_inf' => $this->attach ?? '', //附加数据
'mchnt_order_no' => $this->order_no, //商户订单号, 商户系统内部的订单号(5到30个字符、只能包含字母数字,区分大小写)
'curr_type' => $this->curr_type ?? 'CNY', //货币类型,默认人民币:CNY
'order_amt' => intval($this->amount), //总金额, 订单总金额,单位为分
'term_ip' => $this->client_ip ?? '127.0.0.1', //终端IP
'txn_begin_ts' => date('YmdHis', $this->startTime ?? time()), //交易起始时间, 订单生成时间,格式为yyyyMMddHHmmss
'auth_code' => $this->auth_code, //扫码支付授权码,设备读取用户的条码或者二维码信息
'sence' => $this->sence ?? 1, //支付场景,默认1(1:条码支付,2:声波支付)
'reserved_sub_appid' => '', //$this->subAppid ?? ($this->sub_appid ?? ''), //子商户公众号id,微信交易为商户的appid(小程序,公众号必填)
'reserved_expire_minute' => intval($this->reserved_expire_minute ?? 0), //交易关闭时间,如不设置默认为0,单位:分钟,最大值为1440
'reserved_limit_pay' => $this->limitPay ?? '', //限制支付,no_credit:不能使用信用卡
'reserved_fy_term_type' => $this->reserved_fy_term_type ?? 0, //富友终端类型
'reserved_fy_term_id' => $this->reserved_fy_term_id ?? '', //富友终端号
'reserved_fy_term_sn' => $this->reserved_fy_term_sn ?? '', //富友序列号
'reserved_txn_bonus' => intval($this->reserved_txn_bonus ?? 0), //积分抵扣金额,单位为分
'reserved_hb_fq_num' => intval($this->reserved_hb_fq_num ?? 0), //花呗分期期数:仅支持3、6、12
'reserved_hb_fq_seller_percent' => intval($this->reserved_hb_fq_seller_percent ?? 0), //花呗分期商家手续费比例,目前仅支持用户出资,如需使用,请填写0
'reserved_device_info' => $this->reserved_device_info ?? '' //设备信息,托传给微信。用于单品券核销
];
foreach ($signData as $key => $value) if (false !== strpos($key, 'reserved_') && empty($value)) unset($signData[$key]);
$this->retData = $signData;
}
}
<?php
namespace Payment\Common\Fu\Data\Charge;
use Payment\Common\Fu\Data\FuBaseData;
use Payment\Common\PayException;
use Payment\Config;
/**
* Class ChargeBaseData
* @package Payment\Common\Fu\Data\Charge
*/
abstract class ChargeBaseData extends FuBaseData
{
/**
* 检查传入的支付信息是否正确
*/
protected function checkDataParam()
{
// 检查订单号是否合法
if (empty($this->order_no) || mb_strlen($this->order_no) > 30) throw new PayException('商户系统订单号不能为空且长度不能超过30位');
// 检查金额不能低于0.01
if ($this->amount < bcmul(Config::PAY_MIN_FEE, 100)) throw new PayException('支付金额不能低于 ' . Config::PAY_MIN_FEE . ' 元');
// 检查商品名称
if (empty($this->subject)) throw new PayException('必须提供商品名称');
}
}
<?php
namespace Payment\Common\Fu\Data\Charge;
use Payment\Common\PayException;
/**
* Class PubChargeData
* @package Payment\Common\Fu\Data\Charge
*/
class PubChargeData extends ChargeBaseData
{
/**
* checkDataParam
* @return mixed|void
* @throws PayException
*/
protected function checkDataParam()
{
parent::checkDataParam();
$tradeType = $this->trade_type = $this->trade_type ?? ($this->order_type ?? '');
if (empty($tradeType)) throw new PayException('订单类型有误(支持JSAPI、FWC、LETPAY、BESTPAY)');
$openid = $this->openid;
if (empty($openid)) throw new PayException('用户标识有误');
$clientIp = $this->client_ip;
if (empty($clientIp)) {
$this->client_ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
}
}
/**
* 构建用于支付的签名相关数据
* @return array|void
*/
protected function buildData()
{
$signData = [
'version' => $this->version,
'ins_cd' => $this->institutionId, //机构号,接入机构在富友的唯一代码
'mchnt_cd' => $this->merchantId, //商户号, 富友分配给二级商户的商户号
'term_id' => $this->terminalId ?? '88888888', //终端号(没有真实终端号统一填88888888)
'random_str' => $this->randomStr, //随机字符串
'goods_des' => $this->subject, //商品描述, 商品或支付单简要描述
'goods_detail' => $this->body ?? '', //单品优惠功能字段(填错影响交易)
'goods_tag' => $this->goods_tag ?? '', //商品标记
'product_id' => $this->product_id ?? '', //商品标识
'addn_inf' => $this->attach ?? '', //附加数据
'mchnt_order_no' => $this->order_no, //商户订单号, 商户系统内部的订单号(5到30个字符、只能包含字母数字,区分大小写)
'curr_type' => $this->curr_type ?? 'CNY', //货币类型,默认人民币:CNY
'order_amt' => intval($this->amount), //总金额, 订单总金额,单位为分
'term_ip' => $this->client_ip ?? '127.0.0.1', //终端IP
'txn_begin_ts' => date('YmdHis', $this->startTime ?? time()), //交易起始时间, 订单生成时间,格式为yyyyMMddHHmmss
'notify_url' => $this->notifyUrl ?? $this->notify_url, //通知地址, 接收富友异步通知回调地址,通知url必须为直接可访问的url,不能携带参数
'limit_pay' => $this->limitPay ?? '', //限制支付,no_credit:不能使用信用卡
'trade_type' => $this->trade_type, //订单类型:JSAPI-公众号支付、FWC-支付宝服务窗、LETPAY-小程序、BESTPAY-翼支付js
'openid' => '', //用户标识(暂已废弃)
'sub_openid' => $this->openid ?? $this->sub_openid, //子商户用户标识,支付宝服务窗为用户buyer_id(此场景必填)微信公众号为用户的openid(小程序,公众号,服务窗必填)
'sub_appid' => $this->subAppid ?? ($this->sub_appid ?? ''), //子商户公众号id,微信交易为商户的appid(小程序,公众号必填)
'reserved_expire_minute' => intval($this->reserved_expire_minute ?? 0), //交易关闭时间,如不设置默认为0,单位:分钟,最大值为1440
'reserved_fy_term_type' => $this->reserved_fy_term_type ?? 0, //富友终端类型
'reserved_fy_term_id' => $this->reserved_fy_term_id ?? '', //富友终端号
'reserved_fy_term_sn' => $this->reserved_fy_term_sn ?? '', //富友序列号
'reserved_txn_bonus' => intval($this->reserved_txn_bonus ?? 0), //积分抵扣金额,单位为分
'reserved_hb_fq_num' => intval($this->reserved_hb_fq_num ?? 0), //花呗分期期数:仅支持3、6、12
'reserved_hb_fq_seller_percent' => intval($this->reserved_hb_fq_seller_percent ?? 0), //花呗分期商家手续费比例,目前仅支持用户出资,如需使用,请填写0
'reserved_device_info' => $this->reserved_device_info ?? '' //设备信息,托传给微信。用于单品券核销
];
foreach ($signData as $key => $value) if (false !== strpos($key, 'reserved_') && empty($value)) unset($signData[$key]);
$this->retData = $signData;
}
}
<?php
namespace Payment\Common\Fu\Data\Charge;
use Payment\Common\PayException;
/**
* Class ScanChargeData
* @package Payment\Common\Fu\Data\Charge
*/
class ScanChargeData extends ChargeBaseData
{
/**
* checkDataParam
* @return mixed|void
* @throws PayException
*/
protected function checkDataParam()
{
parent::checkDataParam();
$tradeType = $this->order_type = $this->trade_type ?? ($this->order_type ?? '');
if (empty($tradeType)) throw new PayException('订单类型有误(支持WECHAT、ALIPAY、UNIONPAY)');
// $openid = $this->openid;
// if (empty($openid)) throw new PayException('用户标识有误');
$clientIp = $this->client_ip;
if (empty($clientIp)) $this->client_ip = isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1';
}
/**
* 构建用于支付的签名相关数据
* @return array|void
*/
protected function buildData()
{
$signData = [
'version' => $this->version,
'ins_cd' => $this->institutionId, //机构号,接入机构在富友的唯一代码
'mchnt_cd' => $this->merchantId, //商户号, 富友分配给二级商户的商户号
'term_id' => $this->terminalId ?? '88888888', //终端号(没有真实终端号统一填88888888)
'random_str' => $this->randomStr, //随机字符串
'order_type' => $this->order_type, //订单类型:ALIPAY、WECHAT、UNIONPAY(银联二维码)
'goods_des' => $this->subject, //商品描述, 商品或支付单简要描述
'goods_detail' => $this->body ?? '', //单品优惠功能字段(填错影响交易)
'goods_tag' => $this->goods_tag ?? '', //商品标记
'addn_inf' => $this->attach ?? '', //附加数据
'mchnt_order_no' => $this->order_no, //商户订单号, 商户系统内部的订单号(5到30个字符、只能包含字母数字,区分大小写)
'curr_type' => $this->curr_type ?? 'CNY', //货币类型,默认人民币:CNY
'order_amt' => intval($this->amount), //总金额, 订单总金额,单位为分
'term_ip' => $this->client_ip ?? '127.0.0.1', //终端IP
'txn_begin_ts' => date('YmdHis', $this->startTime ?? time()), //交易起始时间, 订单生成时间,格式为yyyyMMddHHmmss
'notify_url' => $this->notifyUrl ?? $this->notify_url, //通知地址, 接收富友异步通知回调地址,通知url必须为直接可访问的url,不能携带参数
// 'limit_pay' => $this->limitPay ?? '', //限制支付,no_credit:不能使用信用卡
// 'openid' => '', //用户标识
// 'sub_openid' => $this->openid ?? $this->sub_openid, //子商户用户标识,支付宝服务窗为用户buyer_id(此场景必填)微信公众号为用户的openid(小程序,公众号,服务窗必填)
// 'sub_appid' => $this->subAppid ?? ($this->sub_appid ?? ''), //子商户公众号id,微信交易为商户的appid(小程序,公众号必填)
'reserved_sub_appid' => '', //$this->subAppid ?? ($this->sub_appid ?? ''), //子商户公众号id,微信交易为商户的appid(小程序,公众号必填)
'reserved_expire_minute' => intval($this->reserved_expire_minute ?? 0), //交易关闭时间,如不设置默认为0,单位:分钟,最大值为1440
'reserved_limit_pay' => $this->limitPay ?? '', //限制支付,no_credit:不能使用信用卡
'reserved_fy_term_type' => $this->reserved_fy_term_type ?? 0, //富友终端类型
'reserved_fy_term_id' => $this->reserved_fy_term_id ?? '', //富友终端号
'reserved_fy_term_sn' => $this->reserved_fy_term_sn ?? '', //富友序列号
'reserved_txn_bonus' => intval($this->reserved_txn_bonus ?? 0), //积分抵扣金额,单位为分
'reserved_hb_fq_num' => intval($this->reserved_hb_fq_num ?? 0), //花呗分期期数:仅支持3、6、12
'reserved_hb_fq_seller_percent' => intval($this->reserved_hb_fq_seller_percent ?? 0), //花呗分期商家手续费比例,目前仅支持用户出资,如需使用,请填写0
'reserved_device_info' => $this->reserved_device_info ?? '' //设备信息,托传给微信。用于单品券核销
];
foreach ($signData as $key => $value) if (false !== strpos($key, 'reserved_') && empty($value)) unset($signData[$key]);
$this->retData = $signData;
}
}
<?php
namespace Payment\Common\Fu\Data;
use Payment\Common\BaseData;
use Payment\Common\PayException;
/**
* Class FuBaseData
* @package Payment\Common\Fu\Data
*/
abstract class FuBaseData extends BaseData
{
/**
* 签名算法实现
* @param string $signStr
* @return string
* @throws PayException
*/
protected function makeSign($signStr)
{
return $this->sign($signStr);
}
/**
* 签名
* @param $signStr
* @return string
* @throws PayException
*/
private function sign($signStr)
{
if (empty($this->privateKey)) throw new PayException('Private key does not exist');
$privateKey = is_file($this->privateKey) ? file_get_contents($this->privateKey) : $this->privateKey;
if (empty($privateKey)) throw new PayException('Private key error');
$pkeyid = openssl_get_privatekey($privateKey);
if (empty($pkeyid)) throw new PayException('Private key resource identifier false');
$verify = openssl_sign($signStr, $signature, $pkeyid, OPENSSL_ALGO_MD5);
openssl_free_key($pkeyid);
return base64_encode($signature);
}
}
<?php
namespace Payment\Common\Fu\Data\Query;
use Payment\Common\PayException;
use Payment\Common\Fu\Data\FuBaseData;
/**
* 交易查询(支持3日内所有交易查询)
*
* Class ChargeQueryData
*
* @property string $order_no 商户系统订单号
* @property string $order_type 订单类型:ALIPAY(统一下单、条码支付、服务窗支付),WECHAT(统一下单、条码支付、公众号支付),UNIONPAY,BESTPAY(翼支付)
*
* @package Payment\Common\Fu\Data\Query
*/
class ChargeQueryData extends FuBaseData
{
protected function checkDataParam()
{
if (empty($this->order_no) || mb_strlen($this->order_no) > 30) throw new PayException('商户系统订单号不能为空且长度不能超过30位');
$tradeType = $this->order_type = $this->trade_type ?? ($this->order_type ?? '');
if (empty($tradeType)) throw new PayException('订单类型有误(支持WECHAT、ALIPAY、UNIONPAY、BESTPAY)');
}
protected function buildData()
{
$signData = [
'version' => $this->version,
'ins_cd' => $this->institutionId, //机构号,接入机构在富友的唯一代码
'mchnt_cd' => $this->merchantId, //商户号, 富友分配给二级商户的商户号
'term_id' => $this->terminalId ?? '88888888', //终端号(没有真实终端号统一填88888888)
'random_str' => $this->randomStr, //随机字符串
'mchnt_order_no' => $this->order_no, //商户订单号, 商户系统内部的订单号(5到30个字符、只能包含字母数字,区分大小写)
'order_type' => $this->order_type, //订单类型:ALIPAY(统一下单、条码支付、服务窗支付),WECHAT(统一下单、条码支付、公众号支付),UNIONPAY,BESTPAY(翼支付)
];
$this->retData = $signData;
}
}
\ No newline at end of file
<?php
namespace Payment\Common\Fu\Data\Query;
use Payment\Common\PayException;
use Payment\Common\Fu\Data\FuBaseData;
/**
* 退款查询(支持3日内所有退款交易查询)
*
* Class ChargeQueryData
*
* @property string $order_no 商户系统订单号
* @property string $refund_no 商户系统退款单号
* @property string $order_type 订单类型:ALIPAY(统一下单、条码支付、服务窗支付),WECHAT(统一下单、条码支付、公众号支付),UNIONPAY,BESTPAY(翼支付)
*
* @package Payment\Common\Fu\Data\Query
*/
class RefundQueryData extends FuBaseData
{
protected function checkDataParam()
{
if (empty($this->order_no) || mb_strlen($this->order_no) > 30) throw new PayException('商户系统订单号不能为空且长度不能超过30位');
if (empty($this->refund_no) || mb_strlen($this->refund_no) > 30) throw new PayException('商户系统退款单号不能为空且长度不能超过30位');
// $tradeType = $this->order_type = $this->trade_type ?? ($this->order_type ?? '');
// if (empty($tradeType)) throw new PayException('订单类型有误(支持WECHAT、ALIPAY、UNIONPAY、BESTPAY)');
}
protected function buildData()
{
$signData = [
'version' => $this->version,
'ins_cd' => $this->institutionId, //机构号,接入机构在富友的唯一代码
'mchnt_cd' => $this->merchantId, //商户号, 富友分配给二级商户的商户号
'term_id' => $this->terminalId ?? '88888888', //终端号(没有真实终端号统一填88888888)
'random_str' => $this->randomStr, //随机字符串
'refund_order_no' => $this->refund_no, //商户退款单号, 商户系统内部的退款单号(5到30个字符、只能包含字母数字,区分大小写)
// 'order_type' => $this->order_type, //订单类型:ALIPAY(统一下单、条码支付、服务窗支付),WECHAT(统一下单、条码支付、公众号支付),UNIONPAY,BESTPAY(翼支付)
];
$this->retData = $signData;
}
}
\ No newline at end of file
<?php
namespace Payment\Common\Fu\Data;
use Payment\Common\PayException;
/**
* 退款
*
* Class RefundData
*
* @property string $order_no 商户系统订单号
* @property string $refund_no 商户系统退款单号
* @property int $total_fee 订单总金额,单位为分,只能为整数
* @property int $refund_fee 退款总金额,不能大于订单总金额,单位为分,只能为整数
* @property string $order_type 订单类型:ALIPAY(统一下单、条码支付、服务窗支付),WECHAT(统一下单、条码支付、公众号支付),UNIONPAY,BESTPAY(翼支付)
* @property string $trade_date 原交易日期(Ymd,如:20190620)
*
* @package Payment\Common\Fu\Data
*/
class RefundData extends FuBaseData
{
protected function checkDataParam()
{
if (empty($this->order_no) || mb_strlen($this->order_no) > 30) throw new PayException('商户系统订单号不能为空且长度不能超过30位');
if (empty($this->refund_no) || mb_strlen($this->refund_no) > 30) throw new PayException('商户系统退款单号不能为空且长度不能超过30位');
$totalFee = intval($this->total_fee ?? 0); //订单总金额
$refundFee = intval($this->refund_fee ?? 0); //退款总金额
if (empty($totalFee) || empty($refundFee)) throw new PayException('订单总金额或退款金额有误');
if (bccomp($refundFee, $totalFee) === 1) throw new PayException('退款金额不能大于订单总金额');
$tradeType = $this->order_type = $this->trade_type ?? ($this->order_type ?? '');
if (empty($tradeType)) throw new PayException('订单类型有误(支持WECHAT、ALIPAY、UNIONPAY、BESTPAY)');
}
protected function buildData()
{
$signData = [
'version' => $this->version,
'ins_cd' => $this->institutionId, //机构号,接入机构在富友的唯一代码
'mchnt_cd' => $this->merchantId, //商户号, 富友分配给二级商户的商户号
'term_id' => $this->terminalId ?? '88888888', //终端号(没有真实终端号统一填88888888)
'random_str' => $this->randomStr, //随机字符串
'mchnt_order_no' => $this->order_no, //商户订单号, 商户系统内部的订单号(5到30个字符、只能包含字母数字,区分大小写)
'order_type' => $this->order_type, //订单类型:ALIPAY(统一下单、条码支付、服务窗支付),WECHAT(统一下单、条码支付、公众号支付),UNIONPAY,BESTPAY(翼支付)
'refund_order_no' => $this->refund_no, //商户撤销单号
'total_amt' => $this->total_fee, //订单总金额
'refund_amt' => $this->refund_fee, //退款总金额
'operator_id' => $this->operator_id ?? '', //操作员
];
if (!empty($this->reserved_fy_term_id)) $signData['reserved_fy_term_id'] = $this->reserved_fy_term_id; //富友终端号
if (!empty($this->reserved_origi_dt)) $signData['reserved_origi_dt'] = $this->trade_date; //原交易日期( yyyyMMdd )!该值必定等于reserved_fy_settle_dt(富友接收交易时间。理论和合作方下单时间一致。微量夸日交易会不一致)。不填该值支持30天内的交易进行退款。填写该值,支持90天
$this->retData = $signData;
}
}
\ No newline at end of file
<?php
namespace Payment\Common\Fu;
use Payment\Common\BaseData;
use Payment\Common\BaseStrategy;
use Payment\Common\PayException;
use Payment\Common\FuConfig;
use Payment\Utils\Curl;
use Payment\Utils\DataParser;
abstract class FuBaseStrategy implements BaseStrategy
{
protected $config;
/**
* 支付数据
* @var BaseData $reqData
*/
protected $reqData;
/**
* FuBaseStrategy constructor.
* @param array $config
* @throws PayException
*/
public function __construct(array $config)
{
/* 设置内部字符编码为 UTF-8 */
// mb_internal_encoding("UTF-8");
try {
$this->config = new FuConfig($config);
} catch (PayException $e) {
throw $e;
}
}
/**
* 发送请求
* @param array $body
* @return mixed
* @throws PayException
*/
protected function sendReq($body)
{
$url = $this->getReqUrl();
if (is_null($url)) {
throw new PayException('目前不支持该接口。请联系开发者添加');
}
$body = DataParser::toXml($body);
if (empty($body)) throw new PayException('支付数据异常');
$response = $this->curlPost('req=' . urlencode(urlencode(mb_convert_encoding('<?xml version="1.0" encoding="GBK" standalone="yes"?>' . $body, 'gbk', 'utf-8'))), $url); //请求的数据的编码需从utf-8转为gbk,否则客户端显示会乱码
if ($response['error']) throw new PayException('网络发生错误,请稍后再试curl返回码:' . $response['message']);
// $retData = DataParser::toArray(mb_convert_encoding(urldecode($response['body']), 'utf-8', 'gbk')); //将返回数据的编码从gbk转为utf-8后包含中文就解析失败,没有深究
$retData = DataParser::toArray(urldecode($response['body']));
if (empty($retData['result_code'])) throw new PayException('支付平台返回错误提示5:系统繁忙 hint: [code does not exist]');
if ($retData['result_code'] != '000000') throw new PayException('支付平台返回错误提示5:' . $retData['result_msg'] ?? $retData['result_code']);
//TODO: 解析出来的数据如果为空会变成数组,在此处将空数组转为空字符串(可能是由于xml空节点在转为对象时已经变成了空对象,在转成数组也就成为了空数组)
foreach ($retData as $key => &$value) $value = is_array($value) && empty($value) ? '' : $value;
unset($value);
return $retData;
}
/**
* 请求
* @param $body
* @param $url
* @return array
*/
protected function curlPost($body, $url)
{
$curl = new Curl();
$header = [
'content-type: application/x-www-form-urlencoded'
];
return $curl->set([
'CURLOPT_HEADER' => 0,
'CURLOPT_HTTPHEADER' => $header
])->post($body)->submit($url, false);
}
/**
* 获取请求地址
* @param null $url
* @return string
*/
protected function getReqUrl($url = null)
{
return $this->config->base_url . ($url ?? FuConfig::UNIFIED_URL);
}
/**
* @param array $data
*
* @throws PayException
* @throws \Exception
* @return array|string
*/
public function handle(array $data)
{
$buildClass = $this->getBuildDataClass();
$this->reqData = new $buildClass($this->config, $data);
$this->reqData->setSign();
$body = $this->reqData->getData();
$ret = $this->sendReq($body);
$flag = true;// $this->verifySign($ret);
if (!$flag) {
throw new PayException('返回数据被篡改。请检查网络是否安全!');
}
return $this->retData($ret);
}
/**
* 处理返回值并返回给客户端
* @param array $ret
* @return mixed
*
*/
protected function retData(array $ret)
{
return $ret;
}
/**
* 签名验证
* @param array $retData
* @return bool
* @throws PayException
*/
protected function verifySign(array $retData)
{
$retSign = $retData['sign'];
if (empty($this->publicKey)) return false;
$publicKey = is_file($this->publicKey) ? file_get_contents($this->publicKey) : $this->publicKey;
if (empty($publicKey)) throw new PayException('Public key error');
$pubkey = openssl_pkey_get_public($publicKey);
if (empty($pubkey)) throw new PayException('Public key resource identifier false');
$data = '';
$result = openssl_verify($data, base64_decode($retSign), $pubkey, OPENSSL_ALGO_MD5);
return 1 === $result;
}
}
<?php
namespace Payment\Common;
use Payment\Utils\ArrayUtil;
use Payment\Utils\StrUtil;
final class FuConfig extends ConfigInterface
{
public const UNIFIED_URL = '/wxPreCreate'; //公众号/服务窗统一下单
public const SCANPAY_URL = '/preCreate'; //主扫统一下单,扫码支付(预支付)
public const MICROPAY_URL = '/micropay'; //条码支付,商户扫用户二维码收款
public const QUERY_URL = '/commonQuery'; //订单查询
public const REFUND_URL = '/commonRefund'; //退款申请
public const CLOSE_URL = '/closeorder'; //关闭订单(只有未支付的订单才能发起关闭。订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟)
public const CANCEL_URL = '/cancelorder'; //撤销交易
public const CHARGE_QUERY_URL = '/commonQuery'; //订单查询
public const REFUND_QUERY_URL = '/refundQuery'; //退款查询
public $base_url = 'https://fundwx.fuiou.com';
public $version = '1.0';
public $signType = 'RSA';
public $institutionId; //机构号
public $merchantId; //商户号
public $terminalId = '88888888'; //终端号
public $subAppid; //子商户公众号id,微信交易为商户的appid(小程序,公众号必填)
public $randomStr; //随机字符串
public $attach; //附加数据
public $startTime; //交易开始时间(秒级时间戳)
public $certainSignData = []; //专门用于签名的数据
public $privateKey; //私钥
/**
* FuConfig constructor.
* @param array $config
* @throws PayException
*/
public function __construct(array $config)
{
try {
$this->initConfig($config);
} catch (PayException $e) {
throw $e;
}
}
/**
* 初始化配置文件参数
* @param array $config
* @throws PayException
*/
/**
* 初始化配置文件参数
* @param array $config
* @throws PayException
*/
private function initConfig(array $config)
{
$config = ArrayUtil::paraFilter($config);
if (key_exists('ins_cd', $config) && !empty($config['ins_cd'])) $this->institutionId = $config['ins_cd']; else throw new PayException('必须提供机构号');
if (key_exists('mchnt_cd', $config) && !empty($config['mchnt_cd'])) $this->merchantId = $config['mchnt_cd']; else throw new PayException('必须提供商户号');
if (key_exists('term_id', $config) && !empty($config['term_id'])) $this->terminalId = $config['term_id']; //else throw new PayException('必须提供商户号');
if (key_exists('sub_appid', $config) && !empty($config['sub_appid'])) $this->subAppid = $config['sub_appid'];
if (key_exists('notify_url', $config) && !empty($config['notify_url'])) $this->notifyUrl = $config['notify_url']; else throw new PayException('必须提供通知地址');
if (key_exists('private_key', $config) && !empty($config['private_key'])) $this->privateKey = $config['private_key']; else throw new PayException('必须提供私钥');
if (key_exists('limit_pay', $config) && !empty($config['limit_pay']) && $config['limit_pay'][0] === 'no_credit') $this->limitPay = $config['limit_pay'][0]; //设置禁止使用的支付方式
if (key_exists('return_raw', $config)) $this->returnRaw = filter_var($config['return_raw'], FILTER_VALIDATE_BOOLEAN);
$this->randomStr = StrUtil::getNonceStr(); //生成随机字符串
$this->attach = $config['attach'] ?? ($config['addn_inf'] ?? '');
if (key_exists('base_url', $config) && !empty($config['base_url'])) $this->base_url = rtrim($config['base_url'], '/');
$this->startTime = time();
}
}
...@@ -23,7 +23,7 @@ abstract class ChargeBaseData extends SwBaseData ...@@ -23,7 +23,7 @@ abstract class ChargeBaseData extends SwBaseData
{ {
// 检查订单号是否合法 // 检查订单号是否合法
if (empty($this->terminal_trace) || mb_strlen($this->terminal_trace) > 32) { if (empty($this->terminal_trace) || mb_strlen($this->terminal_trace) > 32) {
throw new PayException('商户系统的订单号不能为空,并且长度不能超过32位'); throw new PayException('商户系统的订单号不能为空且长度不能超过32位');
} }
// 检查金额不能低于0.01 // 检查金额不能低于0.01
......
...@@ -61,11 +61,11 @@ abstract class SwBaseStrategy implements BaseStrategy ...@@ -61,11 +61,11 @@ abstract class SwBaseStrategy implements BaseStrategy
$retData = (json_decode($responseTxt['body'],true)); $retData = (json_decode($responseTxt['body'],true));
if ($retData['return_code'] != '01') { if ($retData['return_code'] != '01') {
throw new PayException('SW平台返回错误提示:' . $retData['return_msg']); throw new PayException('支付平台返回错误提示4:' . $retData['return_msg']);
} }
if ($retData['result_code'] == '02') { if ($retData['result_code'] == '02') {
$msg = $retData['result_code'] .' : '. $retData['return_msg']; $msg = $retData['result_code'] .' : '. $retData['return_msg'];
throw new PayException('SW返回错误提示:' . $msg); throw new PayException('支付平台返回错误提示4:' . $msg);
} }
return $retData; return $retData;
......
...@@ -8,22 +8,23 @@ ...@@ -8,22 +8,23 @@
* *
* @version 2.6.1 * @version 2.6.1
* @version 3.0.0 by yeran 2018-10-30 * @version 3.0.0 by yeran 2018-10-30
* @version 3.2.0 by wangyu 2019-06-18 新增富友支付
*/ */
namespace Payment; namespace Payment;
final class Config final class Config
{ {
const VERSION = '3.0.0'; const VERSION = '3.2.0';
//======================= 账户类型 ======================// //======================= 账户类型 ======================//
const WECHAT_PAY = 'wechat'; const WECHAT_PAY = 'wechat';
const ALI_PAY = 'ali'; const ALI_PAY = 'ali';
const CMB_PAY = 'cmb'; const CMB_PAY = 'cmb';
const TL_PAY ='tl'; // 通联支付 const TL_PAY ='tl'; //通联支付
const MI_PAY = 'mipay'; // 米付 const MI_PAY = 'mipay'; //米付
const SW_PAY ='swpay';//扫呗支付 const SW_PAY ='swpay';//扫呗支付
const FU_PAY ='fupay'; //富友支付
//========================= 金额问题设置 =======================// //========================= 金额问题设置 =======================//
...@@ -124,7 +125,6 @@ final class Config ...@@ -124,7 +125,6 @@ final class Config
//========================= 米付相关接口 =======================// //========================= 米付相关接口 =======================//
// 支付常量 // 支付常量
const MI_CHANNEL_APP = 'mi_pub';// 米付微信公众号h5支付 const MI_CHANNEL_APP = 'mi_pub';// 米付微信公众号h5支付
...@@ -175,6 +175,20 @@ final class Config ...@@ -175,6 +175,20 @@ final class Config
//========================= 富友相关接口 =======================//
// 支付常量
const FU_CHANNEL_PUB = 'fu_pub';// 微信公众号h5支付
const FU_CHANNEL_LITE = 'fu_lite';// 小程序支付
const FU_CHANNEL_SCAN = 'fu_scan';// 扫码支付
const FU_CHANNEL_BAR = 'fu_bar';// 刷卡(条码)支付 用户被扫模式
const FU_CHARGE = 'fu_charge';// 统一下单
const FU_REFUND = 'fu_refund';// 退款
const FU_CANCEL = 'fu_cancel';// 交易撤销,只能撤销当天的交易,全额退款,实时返回退款结果
} }
<?php
namespace Payment\Notify;
use Payment\Common\PayException;
use Payment\Common\FuConfig;
use Payment\Config;
use Payment\Utils\ArrayUtil;
use Payment\Utils\DataParser;
/**
* Class FuNotify
* @package Payment\Notify
*/
class FuNotify extends NotifyStrategy
{
/**
* SwNotify constructor.
* @param array $config
* @throws PayException
*/
public function __construct(array $config)
{
parent::__construct($config);
try {
$this->config = new FuConfig($config);
} catch (PayException $e) {
throw $e;
}
}
/**
* 获取通知数据
* @return array|bool
*/
public function getNotifyData()
{
$params = [];
$data = $_POST['req'] ?? file_get_contents('php://input');
if (empty($data)) return false;
$params = DataParser::toArray(urldecode($data));
if (empty($params) || count($params) < 1) return false;
foreach ($params as $key => &$value) $value = is_array($value) && empty($value) ? '' : $value;
unset($value);
return $params;
}
/**
* 检查通知数据
* @param array $data
* @return bool
* @throws \Exception
*/
public function checkNotifyData(array $data)
{
if ($data['result_code'] != '000000') return false;
return $this->verifySign($data);
}
/**
* 检查数据是否被篡改过
* @param array $retData
* @return bool
*/
protected function verifySign(array $retData)
{
$retSign = $retData['sign'] ?? '';
return true;
}
/**
* 封装回调函数需要的数据格式
* @param array $data
* @return array|false
*/
protected function getRetData(array $data)
{
if ($this->config->returnRaw) return array_merge($data, ['channel' => Config::FU_CHARGE]);
$retData = [
'ins_cd' => $data['ins_cd'], //机构号
'mchnt_cd' => $data['mchnt_cd'], //商户号
'term_id' => $data['term_id'] ?? '', //终端号
'user_id' => $data['user_id'] ?? '', //用户在商户的id
'buyer_id' => $data['reserved_buyer_logon_id'] ?? '', //买家在渠道登录账号
'pay_time' => date('Y-m-d H:i:s', strtotime($data['txn_fin_ts'])),//支付完成时间
'amount' => $data['order_amt'], //订单金额
'amount_settle' => $data['settle_order_amt'], //应结订单金额
'transaction_id' => $data['transaction_id'] ?? '', //渠道交易流水号
'order_no' => $data['mchnt_order_no'] ?? '', //商户订单号, 商户系统内部的订单号
'return_param' => $data['reserved_addn_inf'] ?? '', //附加数据
'channel' => Config::WX_CHARGE, //通道
];
return $retData;
}
/**
* replyNotify
* @param bool $flag
* @param string $msg
* @return int
*/
protected function replyNotify($flag, $msg = 'OK')
{
return ($flag ? 1 : 0);
}
}
...@@ -9,6 +9,7 @@ namespace Payment; ...@@ -9,6 +9,7 @@ namespace Payment;
use Payment\Notify\AliNotify; use Payment\Notify\AliNotify;
use Payment\Notify\CmbNotify; use Payment\Notify\CmbNotify;
use Payment\Notify\FuNotify;
use Payment\Notify\MiNotify; use Payment\Notify\MiNotify;
use Payment\Notify\NotifyStrategy; use Payment\Notify\NotifyStrategy;
use Payment\Notify\PayNotifyInterface; use Payment\Notify\PayNotifyInterface;
...@@ -57,8 +58,11 @@ class NotifyContext ...@@ -57,8 +58,11 @@ class NotifyContext
case Config::SW_CHARGE: case Config::SW_CHARGE:
$this->notify = new SwNotify($config); $this->notify = new SwNotify($config);
break; break;
case Config::FU_CHARGE:
$this->notify = new FuNotify($config);
break;
default: default:
throw new PayException('当前仅支持:ALI_CHARGE WX_CHARGE CMB_CHARGE TLNotify MiNotify SwNotify'); throw new PayException('当前仅支持:ALI_CHARGE WX_CHARGE CMB_CHARGE TL_CHARGE MI_CHARGE SW_CHARGE FU_CHARGE');
} }
} catch (PayException $e) { } catch (PayException $e) {
throw $e; throw $e;
......
<?php
namespace Payment\Query\Fu;
use Payment\Common\Fu\Data\Query\ChargeQueryData;
use Payment\Common\Fu\FuBaseStrategy;
use Payment\Common\FuConfig;
use Payment\Config;
class FuChargeQuery extends FuBaseStrategy
{
/**
* 返回查询订单的数据
* @return \Payment\Common\BaseData|string
*/
public function getBuildDataClass()
{
return ChargeQueryData::class;
}
/**
* 返回查询url
* @param null $url
* @return string
*/
protected function getReqUrl($url = null)
{
return parent::getReqUrl($url ?? FuConfig::CHARGE_QUERY_URL);
}
/**
* retData
* @param array $data
* @return array|mixed
*/
protected function retData(array $data)
{
$backData = [
'amount' => $data['order_amt'],
'channel' => Config::FU_CHARGE,
'order_type' => $data['order_type'] ?? '',
'order_no' => $data['mchnt_order_no'], //商户订单号, 商户系统内部的订单号
'buyer_id' => $data['reserved_buyer_logon_id'] ?? '', //买家在渠道登录账号
'business_buyer_id' => $data['buyer_id'] ?? '', //用户在商户的id
'trade_state' => $data['trans_stat'], //查询状态
'transaction_id' => $data['transaction_id'], //渠道订单号
'time_end' => empty($data['reserved_txn_fin_ts']) ? '' : date('Y-m-d H:i:s', strtotime($data['reserved_txn_fin_ts'])), //用户支付时间
'return_param' => $data['addn_inf'] ?? '', //附加数据
'bank_type' => $data['reserved_bank_type'] ?? '' //付款方式
];
return $backData;
}
}
<?php
namespace Payment\Query\Fu;
use Payment\Common\Fu\Data\Query\RefundQueryData;
use Payment\Common\Fu\FuBaseStrategy;
use Payment\Common\FuConfig;
class FuRefundQuery extends FuBaseStrategy
{
/**
* 返回查询订单的数据
* @return \Payment\Common\BaseData|string
*/
public function getBuildDataClass()
{
return RefundQueryData::class;
}
/**
* 返回查询url
* @param null $url
* @return string
*/
protected function getReqUrl($url = null)
{
return parent::getReqUrl($url ?? FuConfig::REFUND_QUERY_URL);
}
/**
* retData
* @param array $data
* @return array|mixed
*/
protected function retData(array $data)
{
$backData = [
'order_type' => $data['order_type'] ?? '', //订单类型
'order_no' => $data['mchnt_order_no'] ?? '', //原交易商户订单号
'refund_no' => $data['cancel_order_no'] ?? '', //商户撤销单号
'out_trade_no' => $data['transaction_id'] ?? '', //渠道交易流水号
'out_refund_no' => $data['refund_id'] ?? '', //渠道撤销流水号
'refund_fee' => $data['reserved_refund_amt'] ?? 0, //退款金额
];
return $backData;
}
}
<?php <?php
/** /**
* @author: yeran * @author: yeran
* @createTime: 2018-10-30 11:30 * @createTime: 2018-10-30 11:30
...@@ -14,6 +15,8 @@ use Payment\Query\Ali\AliRefundQuery; ...@@ -14,6 +15,8 @@ use Payment\Query\Ali\AliRefundQuery;
use Payment\Query\Ali\AliTransferQuery; use Payment\Query\Ali\AliTransferQuery;
use Payment\Query\Cmb\CmbChargeQuery; use Payment\Query\Cmb\CmbChargeQuery;
use Payment\Query\Cmb\CmbRefundQuery; use Payment\Query\Cmb\CmbRefundQuery;
use Payment\Query\Fu\FuChargeQuery;
use Payment\Query\Fu\FuRefundQuery;
use Payment\Query\MiPay\MiQuery; use Payment\Query\MiPay\MiQuery;
use Payment\Query\Sw\SwChargeQuery; use Payment\Query\Sw\SwChargeQuery;
use Payment\Query\TLpay\TLQuery; use Payment\Query\TLpay\TLQuery;
...@@ -79,8 +82,16 @@ class QueryContext ...@@ -79,8 +82,16 @@ class QueryContext
case Config::SW_QUERY:// 扫呗查询 case Config::SW_QUERY:// 扫呗查询
$this->query = new SwChargeQuery($config); $this->query = new SwChargeQuery($config);
break; break;
case Config::FU_CHARGE:
$this->query = new FuChargeQuery($config);
break;
case Config::FU_REFUND:
$this->query = new FuRefundQuery($config);
break;
default: default:
throw new PayException('当前仅支持:ALI_CHARGE ALI_REFUND WX_CHARGE WX_REFUND WX_TRANSFER CMB_CHARGE CMB_REFUND TLPAY MI_QUERY SW_QUERY'); throw new PayException('当前仅支持:ALI_CHARGE ALI_REFUND WX_CHARGE WX_REFUND WX_TRANSFER CMB_CHARGE CMB_REFUND TLPAY MI_QUERY SW_QUERY FU_CHARGE FU_REFUND');
} }
} catch (PayException $e) { } catch (PayException $e) {
throw $e; throw $e;
......
<?php
namespace Payment\Refund;
use Payment\Common\Fu\Data\RefundData;
use Payment\Common\Fu\FuBaseStrategy;
use Payment\Common\FuConfig;
/**
* 交易退款
*
* 总退款金额不能超过订单总金额
* 目前支持对90天以内的交易进行退款,支持全额或者是多次部分退款
* 如需要30天外交易退款,需传入 reserved_origi_dt 字段,如该字段不传入,则仅支持30内交易进行退款
*
* Class FuRefund
* @package Payment\Refund
*/
class FuRefund extends FuBaseStrategy
{
/**
* 返回查询订单的数据
*
*/
public function getBuildDataClass()
{
return RefundData::class;
}
/**
* 返回微信查询的url
* @param null $url
* @return string
*/
protected function getReqUrl($url = null)
{
return parent::getReqUrl($url ?? FuConfig::REFUND_URL);
}
/**
* retData
* @param array $data
* @return array|mixed
*/
protected function retData(array $data)
{
$backData = [
'order_type' => $data['order_type'] ?? '', //订单类型
'order_no' => $data['mchnt_order_no'] ?? '', //原交易商户订单号
'refund_no' => $data['cancel_order_no'] ?? '', //商户撤销单号
'out_trade_no' => $data['transaction_id'] ?? '', //渠道交易流水号
'out_refund_no' => $data['refund_id'] ?? '', //渠道撤销流水号
'refund_fee' => $data['reserved_refund_amt'] ?? 0, //退款金额
];
return $backData;
}
}
<?php <?php
/** /**
* @author: yeran * @author: yeran
* @createTime: 2018-10-30 11:35 * @createTime: 2018-10-30 11:35
...@@ -11,6 +12,7 @@ use Payment\Common\BaseStrategy; ...@@ -11,6 +12,7 @@ use Payment\Common\BaseStrategy;
use Payment\Common\PayException; use Payment\Common\PayException;
use Payment\Refund\AliRefund; use Payment\Refund\AliRefund;
use Payment\Refund\CmbRefund; use Payment\Refund\CmbRefund;
use Payment\Refund\FuRefund;
use Payment\Refund\MiRefund; use Payment\Refund\MiRefund;
use Payment\Refund\SwRefund; use Payment\Refund\SwRefund;
use Payment\Refund\TLRefund; use Payment\Refund\TLRefund;
...@@ -56,8 +58,11 @@ class RefundContext ...@@ -56,8 +58,11 @@ class RefundContext
case Config::SW_REFUND: case Config::SW_REFUND:
$this->refund = new SwRefund($config); $this->refund = new SwRefund($config);
break; break;
case Config::FU_REFUND:
$this->refund = new FuRefund($config);
break;
default: default:
throw new PayException('当前仅支持:ALI WEIXIN CMB TLRefund MiRefund SwRefund'); throw new PayException('当前仅支持:ALI WEIXIN CMB TL MI SW FU');
} }
} catch (PayException $e) { } catch (PayException $e) {
throw $e; throw $e;
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!