parent
5c15b77747
commit
ca55df873a
@ -0,0 +1,5 @@ |
||||
composer.lock |
||||
.idea/ |
||||
vendor/ |
||||
tests/ |
||||
.phpunit.result.cache |
||||
@ -1,3 +1,110 @@ |
||||
# hfpay-lib |
||||
# 说明 |
||||
|
||||
汇付SDK |
||||
|
||||
使用PHP-DI容器 |
||||
|
||||
## 要求 |
||||
|
||||
php >= 7.4 |
||||
|
||||
## 配置 |
||||
|
||||
```php |
||||
$config=[ |
||||
//环境 |
||||
'debug' => true, |
||||
//本地签名服务器 |
||||
'sign_server' => '', |
||||
//版本号,默认为10 |
||||
'version' => '10', |
||||
//商户ID |
||||
'mid' => '6666000100064457', |
||||
//签名服务器上的文件路径(非本地签名文件) |
||||
'sign_file' => '', |
||||
//签名密码 |
||||
'sign_pwd' => '123456', |
||||
//签名服务器上的证书路径(非本地签名文件) |
||||
'cert_file' => '' |
||||
]; |
||||
``` |
||||
|
||||
## 初始化 |
||||
|
||||
```php |
||||
$client = HFPayClient::getInstance()->init($config); |
||||
``` |
||||
|
||||
## 使用 |
||||
|
||||
### 一. 市场接口 |
||||
|
||||
#### 1. 开户 |
||||
|
||||
```php |
||||
$client->market()->create() |
||||
``` |
||||
|
||||
#### 2. 钱包管理 |
||||
|
||||
```php |
||||
$client->market()->walletManage() |
||||
``` |
||||
|
||||
### 二. 查询接口 |
||||
|
||||
### 三.管理接口 |
||||
|
||||
### 四.交易接口 |
||||
|
||||
## 示例 |
||||
|
||||
```php |
||||
<?php |
||||
$config = [ |
||||
//使用环境 |
||||
'debug' => true, |
||||
//本地签名服务器 |
||||
'sign_server' => 'https://sign.location.server/', |
||||
'version' => '10', |
||||
//商户ID |
||||
'mid' => '666000001', |
||||
'sign_file' => '/CFCA/HF123.pfx', |
||||
'sign_pwd' => '123456', |
||||
'cert_file' => '/CFCA/cert/CFCA_1234.cer' |
||||
]; |
||||
|
||||
$client = HFPayClient::getInstance()->init($params); |
||||
|
||||
// 使用 |
||||
try{ |
||||
$response=$client->query()->wallet('用户ID'); |
||||
if($response->isSuccess()){ |
||||
//获取原始HTML数据 |
||||
$response->getSource(); |
||||
//获取 array 结果 |
||||
$response->getBody(); |
||||
//获取解密后的结果 |
||||
$response->getDecodeBody(); |
||||
} |
||||
}catch (\Tansilu\HfPayLib\exception\SignException $e){ |
||||
|
||||
}catch (\Tansilu\HfPayLib\exception\BizException $e){ |
||||
// |
||||
} |
||||
?> |
||||
``` |
||||
|
||||
## 回调通知处理 |
||||
|
||||
```php |
||||
$checkValue=$_POST['check_value'] |
||||
|
||||
$sign=new \Tansilu\HfPayLib\library\impl\SignerHttpClient( |
||||
$config |
||||
); |
||||
|
||||
$result=$sign->decode($checkValue); |
||||
|
||||
print_r($result) |
||||
``` |
||||
@ -0,0 +1,18 @@ |
||||
{ |
||||
"name": "tansilu/hfpay-lib", |
||||
"version": "0.0.1", |
||||
"type": "library", |
||||
"require": { |
||||
"guzzlehttp/guzzle": "^7.10", |
||||
"php-di/php-di": "^6.4", |
||||
"ext-json": "*" |
||||
}, |
||||
"require-dev": { |
||||
"phpunit/phpunit": "^9.6" |
||||
}, |
||||
"autoload": { |
||||
"psr-4": { |
||||
"Tansilu\\HfPayLib\\": "src/" |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,19 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<phpunit bootstrap="vendor/autoload.php" |
||||
colors="true"> |
||||
<testsuites> |
||||
<testsuite name="Application Test Suite"> |
||||
<directory suffix="Test.php">tests</directory> |
||||
</testsuite> |
||||
</testsuites> |
||||
<!-- <filter>--> |
||||
<!-- <whitelist processUncoveredFilesFromWhitelist="true">--> |
||||
<!-- <directory suffix=".php">./app</directory>--> |
||||
<!-- </whitelist>--> |
||||
<!-- </filter>--> |
||||
<coverage processUncoveredFiles="true"> |
||||
<include> |
||||
<directory suffix=".php">./app</directory> |
||||
</include> |
||||
</coverage> |
||||
</phpunit> |
||||
@ -0,0 +1,92 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib; |
||||
|
||||
class Constant |
||||
{ |
||||
/** |
||||
* 证件类型:身份证 |
||||
*/ |
||||
const ID_TYPE_CARD = '10'; |
||||
|
||||
/** |
||||
* 用于购买的钱包,仅用于购买 |
||||
*/ |
||||
const USE_TO_BUY = 'buyers_wallet'; |
||||
/** |
||||
* 用于购买交易的钱包,可用于收款和转账 |
||||
*/ |
||||
const USE_TO_TRANS = 'wallet'; |
||||
|
||||
/** |
||||
* 交易类型 |
||||
* 1 企业开户 2 个体户开户 5快捷绑卡 6取现绑卡 7个人开户 8钱包户 |
||||
*/ |
||||
const TRANS_TYPE_COMPANY = 1; |
||||
const TRANS_TYPE_USER = 2; |
||||
const TRANS_TYPE_QUICK_CARD = 5; |
||||
const TRANS_TYPE_CASH_CARD = 6; |
||||
const TRANS_TYPE_PERSON = 7; |
||||
const TRANS_TYPE_WALLET = 8; |
||||
|
||||
const CARD_TYPE_USER = '0'; |
||||
const CARD_TYPE_COMPANY = '1'; |
||||
/** |
||||
* 取现卡 标识符 0非取现卡 1取现卡 |
||||
*/ |
||||
const CARD_CASH_FLAG_NONE = 0; |
||||
const CARD_CASH_FLAG_ACTIVE = 1; |
||||
|
||||
/** |
||||
* 文件类型 |
||||
*/ |
||||
const FILE_TYPE_CHARGE = '1'; |
||||
const FILE_TYPE_CASH = '2'; |
||||
const FILE_TYPE_PAY = '3'; |
||||
const FILE_TYPE_TRANSFER = '4'; |
||||
const FILE_TYPE_ORDER = '5'; |
||||
const FILE_TYPE_REFUND = '6'; |
||||
|
||||
/** |
||||
* 担保阶段 |
||||
* A:担保入账; |
||||
* B:担保出账; |
||||
* C:担保完成 |
||||
*/ |
||||
const GUARANTEE_STAGE_IN = 'A'; |
||||
const GUARANTEE_STAGE_OUT = 'B'; |
||||
const GUARANTEE_STAGE_COMPLETE = 'C'; |
||||
|
||||
/** |
||||
* 分账类型 0实时分账 1延时分账 |
||||
*/ |
||||
const DIV_TYPE_REAL = 0; |
||||
const DIV_TYPE_LAZY = 1; |
||||
|
||||
/** |
||||
* 终端类型 |
||||
*/ |
||||
const TERMINAL_WX_APPLET = 1; |
||||
const TERMINAL_ALI_APPLET = 2; |
||||
const TERMINAL_APP = 3; |
||||
const TERMINAL_H5 = 4; |
||||
|
||||
/** |
||||
* 藏品市场类型 1一级市场 2二级市场 |
||||
*/ |
||||
const MARKET_MASTER = 1; |
||||
const MARKET_SUB = 2; |
||||
|
||||
/** |
||||
* 设备类型 |
||||
*/ |
||||
const DEVICE_TYPE_PC = 1; |
||||
const DEVICE_TYPE_MOBILE = 2; |
||||
|
||||
/** |
||||
* 分账用途 1:主交易金额:2:商户服务费:3:其他费用 |
||||
* */ |
||||
const RISK_DIV_TYPE_MASTER = 1; |
||||
const RISK_DIV_TYPE_FEE = 2; |
||||
const RISK_DIV_TYPE_OTHER = 3; |
||||
} |
||||
@ -0,0 +1,105 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib; |
||||
|
||||
use DI\Container; |
||||
use DI\ContainerBuilder; |
||||
use DI\DependencyException; |
||||
use DI\NotFoundException; |
||||
use Tansilu\HfPayLib\exception\InitException; |
||||
use Tansilu\HfPayLib\factory\impl\ManageFactory; |
||||
use Tansilu\HfPayLib\factory\impl\MarketFactory; |
||||
use Tansilu\HfPayLib\factory\impl\QueryFactory; |
||||
use Tansilu\HfPayLib\factory\impl\TradeFactory; |
||||
use Tansilu\HfPayLib\http\IHttpClient; |
||||
use Tansilu\HfPayLib\http\impl\HFPayHttpClient; |
||||
|
||||
class HFPayClient |
||||
{ |
||||
public static ?HFPayClient $instance = null; |
||||
|
||||
public static function getInstance(): HFPayClient |
||||
{ |
||||
if(self::$instance == null) { |
||||
self::$instance = new HFPayClient(); |
||||
} |
||||
return self::$instance; |
||||
} |
||||
|
||||
private Container $container; |
||||
|
||||
|
||||
/** |
||||
* @param array $config |
||||
* |
||||
* @return HFPayClient |
||||
* @throws InitException |
||||
* @throws \Exception |
||||
*/ |
||||
public function init(array $config): HFPayClient |
||||
{ |
||||
$builder = new ContainerBuilder(); |
||||
//添加配置 |
||||
|
||||
$this->container = $builder->build(); |
||||
|
||||
//添加HTTP接口 |
||||
$client = new HFPayHttpClient($config); |
||||
$this->container->set(IHttpClient::class, $client); |
||||
return $this; |
||||
} |
||||
|
||||
/** |
||||
* @throws \Exception |
||||
*/ |
||||
private function __construct() |
||||
{ |
||||
|
||||
} |
||||
|
||||
|
||||
/** |
||||
* 查询接口 |
||||
* |
||||
* @throws DependencyException |
||||
* @throws NotFoundException |
||||
*/ |
||||
public function query(): QueryFactory |
||||
{ |
||||
return $this->container->make(QueryFactory::class); |
||||
} |
||||
|
||||
/** |
||||
* 市场接入接口 |
||||
* |
||||
* @throws DependencyException |
||||
* @throws NotFoundException |
||||
*/ |
||||
public function market(): MarketFactory |
||||
{ |
||||
return $this->container->make(MarketFactory::class); |
||||
} |
||||
|
||||
/** |
||||
* 管理接口 |
||||
* |
||||
* @throws DependencyException |
||||
* @throws NotFoundException |
||||
*/ |
||||
public function manage(): ManageFactory |
||||
{ |
||||
return $this->container->make(ManageFactory::class); |
||||
} |
||||
|
||||
/** |
||||
* 交易接口 |
||||
* |
||||
* @return TradeFactory |
||||
* @throws DependencyException |
||||
* @throws NotFoundException |
||||
*/ |
||||
public function trade(): TradeFactory |
||||
{ |
||||
return $this->container->make(TradeFactory::class); |
||||
} |
||||
} |
||||
@ -0,0 +1,28 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\exception; |
||||
|
||||
use Exception; |
||||
use Throwable; |
||||
|
||||
class ApiException extends Exception |
||||
{ |
||||
protected string $errCode; |
||||
|
||||
public function getErrCode(): string |
||||
{ |
||||
return $this->errCode; |
||||
} |
||||
|
||||
public function setErrCode(string $errCode): void |
||||
{ |
||||
$this->errCode = $errCode; |
||||
} |
||||
|
||||
public function __construct($message = "", $errCode = '', Throwable $previous = null) |
||||
{ |
||||
$this->errCode = $errCode; |
||||
parent::__construct($message, 1, $previous); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,30 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\exception; |
||||
|
||||
use Exception; |
||||
use Throwable; |
||||
|
||||
class BizException extends Exception |
||||
{ |
||||
protected string $errCode; |
||||
|
||||
public function getErrCode(): string |
||||
{ |
||||
return $this->errCode; |
||||
} |
||||
|
||||
public function setErrCode(string $errCode): void |
||||
{ |
||||
$this->errCode = $errCode; |
||||
} |
||||
|
||||
public function __construct($message = "", $errCode = '', Throwable $previous = null) |
||||
{ |
||||
$this->errCode = $errCode; |
||||
parent::__construct($message, 1, $previous); |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
@ -0,0 +1,14 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\exception; |
||||
|
||||
use Exception; |
||||
use Throwable; |
||||
|
||||
class InitException extends Exception |
||||
{ |
||||
public function __construct($message = "", $code = 0, Throwable $previous = null) |
||||
{ |
||||
parent::__construct($message, $code, $previous); |
||||
} |
||||
} |
||||
@ -0,0 +1,30 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\exception; |
||||
|
||||
use Exception; |
||||
use Throwable; |
||||
|
||||
class ParamsException extends Exception |
||||
{ |
||||
protected string $errCode; |
||||
|
||||
public function getErrCode(): string |
||||
{ |
||||
return $this->errCode; |
||||
} |
||||
|
||||
public function setErrCode(string $errCode): void |
||||
{ |
||||
$this->errCode = $errCode; |
||||
} |
||||
|
||||
public function __construct($message = "", $errCode = '', Throwable $previous = null) |
||||
{ |
||||
$this->errCode = $errCode; |
||||
parent::__construct($message, 1, $previous); |
||||
} |
||||
|
||||
|
||||
|
||||
} |
||||
@ -0,0 +1,14 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\exception; |
||||
|
||||
use Exception; |
||||
use Throwable; |
||||
|
||||
class SignException extends Exception |
||||
{ |
||||
public function __construct($message = "", $code = 0, Throwable $previous = null) |
||||
{ |
||||
parent::__construct($message, $code, $previous); |
||||
} |
||||
} |
||||
@ -0,0 +1,58 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory; |
||||
|
||||
use Tansilu\HfPayLib\exception\ApiException; |
||||
use Tansilu\HfPayLib\exception\BizException; |
||||
use Tansilu\HfPayLib\http\Factory; |
||||
use Tansilu\HfPayLib\http\Response; |
||||
|
||||
class BaseFactory extends Factory |
||||
{ |
||||
|
||||
/** |
||||
* JSON 请求 |
||||
* |
||||
* @param string $uri |
||||
* @param array $data |
||||
* |
||||
* @return array |
||||
* @throws ApiException |
||||
* @throws BizException |
||||
*/ |
||||
public function processJson(string $uri, array $data): array |
||||
{ |
||||
$response = $this->postJson($uri, $data); |
||||
return $this->parseResponse($response); |
||||
} |
||||
|
||||
/** |
||||
* GET 请求 |
||||
* |
||||
* @throws BizException |
||||
* @throws ApiException |
||||
*/ |
||||
public function processGet(string $uri, array $data): array |
||||
{ |
||||
$response = $this->get($uri, $data); |
||||
return $this->parseResponse($response); |
||||
} |
||||
|
||||
/** |
||||
* @throws BizException |
||||
* @throws ApiException |
||||
*/ |
||||
private function parseResponse(Response $response) |
||||
{ |
||||
if(!$response->isSuccess()) { |
||||
throw new ApiException('API请求过程中遇到错误' . $response->getCode()); |
||||
} |
||||
$b = $response->getBody(); |
||||
|
||||
if(!$b['success']) { |
||||
throw new BizException($b['message'], $b['errorCode']); |
||||
} |
||||
return $b['data'] ?? []; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,221 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\impl; |
||||
|
||||
use Tansilu\HfPayLib\Constant; |
||||
use Tansilu\HfPayLib\exception\ParamsException; |
||||
use Tansilu\HfPayLib\factory\object\manage\BindCashCard; |
||||
use Tansilu\HfPayLib\factory\object\manage\CertificateInfo; |
||||
use Tansilu\HfPayLib\factory\object\manage\DownloadFiles; |
||||
use Tansilu\HfPayLib\factory\object\manage\UnBindCard; |
||||
use Tansilu\HfPayLib\http\Factory; |
||||
|
||||
class ManageFactory extends Factory |
||||
{ |
||||
/** |
||||
* 绑定取现卡 |
||||
* |
||||
* @param string $customId |
||||
* @param string $orderId |
||||
* @param string $orderDate |
||||
* @param string $cardNo |
||||
* @param string $cardType |
||||
* @param string $bankId |
||||
* @param string $branchName |
||||
* @param string $cardProv |
||||
* @param string $cardArea |
||||
* @param string $cashFlag |
||||
* @param string $bgRetUrl |
||||
* @param string $attach |
||||
* @param string $extension |
||||
* |
||||
* @return BindCashCard|null |
||||
* @throws ParamsException |
||||
* |
||||
* @ses https://hfpay.cloudpnr.com/customers/nft/#/manage/bindCashCard |
||||
*/ |
||||
function bindCashCard( |
||||
string $customId, |
||||
string $orderId, |
||||
string $orderDate, |
||||
string $cardNo, |
||||
string $cardType = Constant::CARD_TYPE_USER, |
||||
string $bankId = '', |
||||
string $branchName = '', |
||||
string $cardProv = '', |
||||
string $cardArea = '', |
||||
string $cashFlag = Constant::CARD_CASH_FLAG_NONE, |
||||
string $bgRetUrl = '', |
||||
string $attach = '', |
||||
string $extension = '' |
||||
): ?BindCashCard |
||||
{ |
||||
$params = [ |
||||
'user_cust_id' => $customId, |
||||
'order_id' => $orderId, |
||||
'order_date' => $orderDate, |
||||
'bank_id' => $bankId, |
||||
'card_num' => $cardNo, |
||||
'card_type' => $cardType, |
||||
'default_cash_flag' => $cashFlag |
||||
]; |
||||
if($cardType == Constant::CARD_TYPE_COMPANY) { |
||||
if(empty($bankId)) { |
||||
throw new ParamsException('对公账户需要填写银行代码'); |
||||
} |
||||
} |
||||
if(!empty($branchName)) { |
||||
$params['branch_name'] = $branchName; |
||||
} |
||||
if(!empty($cardProv)) { |
||||
$params['card_prov'] = $cardProv; |
||||
} |
||||
if(!empty($cardArea)) { |
||||
$params['card_area'] = $cardArea; |
||||
} |
||||
if(!empty($attach)) { |
||||
$params['mer_priv'] = $attach; |
||||
} |
||||
if(!empty($extension)) { |
||||
$params['extension'] = $extension; |
||||
} |
||||
if(!empty($bgRetUrl)) { |
||||
$params['bg_ret_url'] = $bgRetUrl; |
||||
} |
||||
$result = $this->post('/api/acou/bind08', $params); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return BindCashCard::make($result->getBody()); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 银行卡解绑 |
||||
* |
||||
* @param string $customId |
||||
* @param string $orderId |
||||
* @param string $orderDate |
||||
* @param string $bindCardId |
||||
* @param string $cardType |
||||
* @param string $bgRetUrl |
||||
* @param string $attach |
||||
* @param string $extension |
||||
* @param string $devInfoJson |
||||
* |
||||
* @return UnBindCard|null |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/manage/unbindCard |
||||
*/ |
||||
public function unBindCard(string $customId, string $orderId, string $orderDate, string $bindCardId, string $cardType, |
||||
string $bgRetUrl, |
||||
string $attach = '', string $extension = '', string $devInfoJson = '' |
||||
): ?UnBindCard |
||||
{ |
||||
$params = [ |
||||
'user_cust_id' => $customId, |
||||
'order_id' => $orderId, |
||||
'order_date' => $orderDate, |
||||
'bank_card_id' => $bindCardId, |
||||
'card_buss_type' => $cardType, |
||||
'bg_ret_url' => $bgRetUrl, |
||||
]; |
||||
if(!empty($attach)) { |
||||
$params['mer_priv'] = $attach; |
||||
} |
||||
if(!empty($extension)) { |
||||
$params['extension'] = $extension; |
||||
} |
||||
if(!empty($devInfoJson)) { |
||||
$params['dev_info_json'] = $devInfoJson; |
||||
} |
||||
$result = $this->post('/api/acou/unbd01', $params); |
||||
|
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return UnBindCard::make($result->getBody()); |
||||
} |
||||
|
||||
/** |
||||
* 文件下载 |
||||
* |
||||
* @param string $fileDate |
||||
* @param string $fileType |
||||
* |
||||
* @return DownloadFiles |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/manage/fileDownload |
||||
*/ |
||||
function fileDownload(string $fileDate, string $fileType = Constant::FILE_TYPE_CHARGE): ?DownloadFiles |
||||
{ |
||||
$params = [ |
||||
'file_date' => $fileDate, |
||||
'file_type' => $fileType |
||||
]; |
||||
$result = $this->post('/api/alse/file02', $params); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
|
||||
return DownloadFiles::make($result->getBody()); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 电子凭证下载 |
||||
* |
||||
* 后台返回(异步) |
||||
* |
||||
* @param string $customId |
||||
* @param string $orderId |
||||
* @param string $orderDate |
||||
* @param string $originalOrderDate |
||||
* @param string $bgRetUrl |
||||
* @param array $originalOrderId |
||||
* @param string $stage |
||||
* @param string $attach |
||||
* @param string $extension |
||||
* |
||||
* @return ?CertificateInfo |
||||
* |
||||
* https://hfpay.cloudpnr.com/customers/nft/#/manage/electronicCertificate |
||||
*/ |
||||
function eCertificate( |
||||
string $customId, |
||||
string $orderId, |
||||
string $orderDate, |
||||
string $originalOrderDate, |
||||
string $bgRetUrl, |
||||
array $originalOrderId = [], |
||||
string $stage = Constant::GUARANTEE_STAGE_IN, |
||||
string $attach = '', |
||||
string $extension = '' |
||||
): ?CertificateInfo |
||||
{ |
||||
$params = [ |
||||
'user_cust_id' => $customId, |
||||
'order_id' => $orderId, |
||||
'order_date' => $orderDate, |
||||
'bg_ret_url' => $bgRetUrl, |
||||
'org_order_date' => $originalOrderDate, |
||||
'guarantee_stage' => $stage, |
||||
]; |
||||
if(!empty($attach)) { |
||||
$params['mer_priv'] = $attach; |
||||
} |
||||
if(!empty($extension)) { |
||||
$params['extension'] = $extension; |
||||
} |
||||
if(!empty($originalOrderId)) { |
||||
$params['org_order_id'] = join(',', $originalOrderId); |
||||
} |
||||
$result = $this->post('/api/alse/file05', $params); |
||||
|
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
|
||||
return CertificateInfo::make($result->getBody()); |
||||
} |
||||
} |
||||
@ -0,0 +1,86 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\impl; |
||||
|
||||
use Tansilu\HfPayLib\Constant; |
||||
use Tansilu\HfPayLib\exception\BizException; |
||||
use Tansilu\HfPayLib\exception\ParamsException; |
||||
use Tansilu\HfPayLib\factory\BaseFactory; |
||||
use Tansilu\HfPayLib\factory\object\market\OpenAccountRequest; |
||||
use Tansilu\HfPayLib\factory\object\market\OpenAccountResponse; |
||||
use Tansilu\HfPayLib\factory\object\market\WalletManageInfoResponse; |
||||
use Tansilu\HfPayLib\factory\object\query\WalletStatus; |
||||
|
||||
/** |
||||
* 综合市场管理 |
||||
*/ |
||||
class MarketFactory extends BaseFactory |
||||
{ |
||||
/** |
||||
* 开户 |
||||
* |
||||
* @throws BizException |
||||
* @throws ParamsException |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/compositeMarket/walletOpenAccount |
||||
*/ |
||||
public function create( |
||||
OpenAccountRequest $params |
||||
): OpenAccountResponse |
||||
{ |
||||
$request = $params->toParams(); |
||||
|
||||
$data = $this->post('/api/hfpwallet/w00003', $request); |
||||
|
||||
if(!$data->isSuccess()) { |
||||
throw new BizException('账户创建失败', $data->getCode()); |
||||
} |
||||
return OpenAccountResponse::make($data->getBody()); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 钱包管理 |
||||
* |
||||
* @param string $customId |
||||
* @param string $orderId |
||||
* @param string $orderDate |
||||
* @param string $accountId |
||||
* @param string $retUrl |
||||
* @param string $attach |
||||
* @param string $faceLicenseKey |
||||
* |
||||
* @return WalletManageInfoResponse|null |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/compositeMarket/walletManage |
||||
*/ |
||||
function walletManage(string $customId, string $orderId, string $orderDate, string $accountId = '', string $retUrl = '', |
||||
|
||||
string $attach = '', |
||||
string $faceLicenseKey = ''): ?WalletManageInfoResponse |
||||
{ |
||||
$params = [ |
||||
'user_cust_id' => $customId, |
||||
'order_date' => $orderDate, |
||||
'order_id' => $orderId, |
||||
]; |
||||
if(empty($accountId)) { |
||||
$params['acct_id'] = $accountId; |
||||
} |
||||
if(!empty($retUrl)) { |
||||
$params['ret_url'] = $retUrl; |
||||
} |
||||
if(!empty($attach)) { |
||||
$params['mer_priv'] = $attach; |
||||
} |
||||
if(!empty($faceLicenseKey)) { |
||||
$params['face_license_key'] = $faceLicenseKey; |
||||
} |
||||
|
||||
$result = $this->post('/api/hfpwallet/w00004', $params); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return WalletManageInfoResponse::make($result->getBody()); |
||||
} |
||||
} |
||||
@ -0,0 +1,214 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\impl; |
||||
|
||||
use Tansilu\HfPayLib\exception\ParamsException; |
||||
use Tansilu\HfPayLib\factory\BaseFactory; |
||||
use Tansilu\HfPayLib\factory\object\query\BalanceInfo; |
||||
use Tansilu\HfPayLib\factory\object\query\BindCardStatus; |
||||
use Tansilu\HfPayLib\factory\object\query\ChainBalance; |
||||
use Tansilu\HfPayLib\factory\object\query\OpenStatus; |
||||
use Tansilu\HfPayLib\factory\object\query\RecordLog; |
||||
use Tansilu\HfPayLib\factory\object\query\TransStatus; |
||||
use Tansilu\HfPayLib\factory\object\query\WalletStatus; |
||||
|
||||
class QueryFactory extends BaseFactory |
||||
{ |
||||
/** |
||||
* 开户状态查询 |
||||
* |
||||
* @param string $orderId |
||||
* @param string $orderDate |
||||
* @param string $transType |
||||
* |
||||
* @return ?OpenStatus |
||||
* |
||||
* @ses https://hfpay.cloudpnr.com/customers/nft/#/query/openAccountQuery |
||||
*/ |
||||
function openStatus(string $orderId, string $orderDate, string $transType): ?OpenStatus |
||||
{ |
||||
$result = $this->post('/api/alse/qry009', [ |
||||
'order_id' => $orderId, |
||||
'order_date' => $orderDate, |
||||
'trans_type' => $transType |
||||
]); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return OpenStatus::make($result->getBody()); |
||||
} |
||||
|
||||
/** |
||||
* 钱包状态 |
||||
* |
||||
* @param string $customId 用户客户号 |
||||
* |
||||
* @return WalletStatus|null |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/walletStateQuery |
||||
*/ |
||||
function wallet(string $customId): ?WalletStatus |
||||
{ |
||||
$result = $this->post('/api/alse/qry016', [ |
||||
'user_cust_id' => $customId |
||||
]); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return WalletStatus::make($result->getBody()); |
||||
} |
||||
|
||||
/** |
||||
* 查询交易状态 |
||||
* |
||||
* @param string $orderID |
||||
* @param string $orderDate |
||||
* @param string $transType |
||||
* @param string $attach |
||||
* @param string $extension |
||||
* |
||||
* @return TransStatus|null |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/transactionStateQuery |
||||
*/ |
||||
function trans(string $orderID, string $orderDate, string $transType, string $attach = '', string $extension = ''): ?TransStatus |
||||
{ |
||||
$params = [ |
||||
'order_id' => $orderID, |
||||
'order_date' => $orderDate, |
||||
'trans_type' => $transType |
||||
]; |
||||
if(!empty($attach)) { |
||||
$params['mer_priv'] = $attach; |
||||
} |
||||
if(!empty($extension)) { |
||||
$params['extension'] = $extension; |
||||
} |
||||
$result = $this->post('/api/alse/qry008', $params); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return TransStatus::make($result->getBody()); |
||||
} |
||||
|
||||
/** |
||||
* 查询用户绑卡信息 |
||||
* |
||||
* @param string $userId |
||||
* @param string $cardId |
||||
* |
||||
* @return BindCardStatus|null |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/bindCardInfoQuery |
||||
*/ |
||||
function bindCard(string $userId, string $cardId = ''): ?BindCardStatus |
||||
{ |
||||
$params = [ |
||||
'user_cust_id' => $userId |
||||
]; |
||||
if(!empty($cardId)) { |
||||
$params['bind_card_id'] = $cardId; |
||||
} |
||||
$result = $this->post('/api/alse/qry004', $params); |
||||
|
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return BindCardStatus::make($result->getBody()); |
||||
} |
||||
|
||||
/** |
||||
* 余额查询 |
||||
* |
||||
* @param string $customId |
||||
* @param string $accountId |
||||
* @param string $isGuarantee |
||||
* |
||||
* @return BalanceInfo|null |
||||
* @throws ParamsException |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/balanceQuery |
||||
*/ |
||||
function balance(string $customId, string $accountId = '', string $isGuarantee = ''): ?BalanceInfo |
||||
{ |
||||
$params = [ |
||||
'user_cust_id' => $customId |
||||
]; |
||||
if($isGuarantee != '1') { |
||||
if(empty($accountId)) { |
||||
throw new ParamsException('账户号不能为空', 'PARAMS_ACCOUNT_ID_IS_EMPTY'); |
||||
} |
||||
$params['acct_id'] = $accountId; |
||||
} |
||||
if(!empty($isGuarantee)) { |
||||
$params['is_query_guarantee'] = $isGuarantee; |
||||
} |
||||
$result = $this->post('/api/alse/qry001', $params); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return BalanceInfo::make($result->getBody()); |
||||
} |
||||
|
||||
/** |
||||
* 流水记录查询 |
||||
* |
||||
* @param string $customId |
||||
* @param string $accountId |
||||
* @param string $startDate |
||||
* @param string $endDate |
||||
* @param int $pageSize |
||||
* @param int $pageNum |
||||
* @param string $productId |
||||
* @param string $productSeqId |
||||
* |
||||
* @return RecordLog|null |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/accountRecordQuery |
||||
*/ |
||||
function record(string $customId, string $accountId, string $startDate, string $endDate, int $pageSize, int $pageNum, string $productId = '', string $productSeqId = ''): ?RecordLog |
||||
{ |
||||
$params = [ |
||||
'user_cust_id' => $customId, |
||||
'acct_id' => $accountId, |
||||
'trans_start_date' => $startDate, |
||||
'trans_end_date' => $endDate, |
||||
'page_size' => $pageSize, |
||||
'page_num' => $pageNum, |
||||
]; |
||||
if(!empty($productId)) { |
||||
$params['product_id'] = $productId; |
||||
} |
||||
if(!empty($productSeqId)) { |
||||
$params['product_req_seq_id'] = $productSeqId; |
||||
} |
||||
|
||||
$result = $this->post('/api/alse/qry005', $params); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return RecordLog::make($result->getBody()); |
||||
} |
||||
|
||||
/** |
||||
* 链上余额查询 |
||||
* |
||||
* @param string $customId |
||||
* |
||||
* @return ChainBalance|null |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/chainBalanceQuery |
||||
*/ |
||||
function chainBalance(string $customId): ?ChainBalance |
||||
{ |
||||
$params = [ |
||||
'user_cust_id' => $customId, |
||||
]; |
||||
|
||||
$result = $this->post('/api/alse/qry022', $params); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return ChainBalance::make($result->getBody()); |
||||
} |
||||
} |
||||
@ -0,0 +1,132 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\impl; |
||||
|
||||
use Tansilu\HfPayLib\exception\ParamsException; |
||||
use Tansilu\HfPayLib\factory\object\trade\CloseOrder; |
||||
use Tansilu\HfPayLib\factory\object\trade\DelayDivide; |
||||
use Tansilu\HfPayLib\factory\object\trade\DelayDivideRequest; |
||||
use Tansilu\HfPayLib\factory\object\trade\RefundGoodsRequest; |
||||
use Tansilu\HfPayLib\factory\object\trade\RefundGoodsResponse; |
||||
use Tansilu\HfPayLib\factory\object\trade\RefundInfo; |
||||
use Tansilu\HfPayLib\factory\object\trade\RefundRequest; |
||||
use Tansilu\HfPayLib\factory\object\trade\UnifiedOrder; |
||||
use Tansilu\HfPayLib\factory\object\trade\UnifiedOrderRequest; |
||||
use Tansilu\HfPayLib\http\Factory; |
||||
|
||||
/** |
||||
* 交易接口 |
||||
*/ |
||||
class TradeFactory extends Factory |
||||
{ |
||||
/** |
||||
* 统一下单 |
||||
* |
||||
* @param UnifiedOrderRequest $request |
||||
* |
||||
* @return UnifiedOrder|null |
||||
* @throws ParamsException |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/transaction/unifiedOrder |
||||
*/ |
||||
function unifiedOrder( |
||||
UnifiedOrderRequest $request |
||||
): ?UnifiedOrder |
||||
{ |
||||
$params = $request->toParams(); |
||||
|
||||
$result = $this->post('/api/hfpwallet/pay033', $params); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return UnifiedOrder::make($result->getBody()); |
||||
} |
||||
|
||||
/** |
||||
* 延时分账确认 |
||||
* |
||||
* @param DelayDivideRequest $request |
||||
* |
||||
* @return DelayDivide|null |
||||
* @throws ParamsException |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/transaction/delayDivideConfirm |
||||
*/ |
||||
function delayDivideConfirm(DelayDivideRequest $request): ?DelayDivide |
||||
{ |
||||
$params = $request->toParams(); |
||||
$result = $this->post('/api/hfpwallet/pay033', $params); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return DelayDivide::make($result->getBody()); |
||||
} |
||||
|
||||
/** |
||||
* 关闭订单 |
||||
* |
||||
* @param string $orderId |
||||
* @param string $orderDate |
||||
* @param string $merPriv |
||||
* |
||||
* @return CloseOrder|null |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/transaction/closeOrder |
||||
*/ |
||||
function closeOrder(string $orderId, string $orderDate, string $merPriv = ''): ?CloseOrder |
||||
{ |
||||
$params = [ |
||||
'order_id' => $orderId, |
||||
'order_date' => $orderDate, |
||||
]; |
||||
if(!empty($merPriv)) { |
||||
$params['mer_priv'] = $merPriv; |
||||
} |
||||
$result = $this->post('/api/hfpwallet/pay034', $params); |
||||
|
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return CloseOrder::make($result->getBody()); |
||||
} |
||||
|
||||
/** |
||||
* 退款 |
||||
* |
||||
* @param RefundRequest $request |
||||
* |
||||
* @return RefundInfo|null |
||||
* @throws ParamsException |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/transaction/refund |
||||
*/ |
||||
function refund(RefundRequest $request): ?RefundInfo |
||||
{ |
||||
$params = $request->toParams(); |
||||
$result = $this->post('/api/hfpay/reb001', $params); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return RefundInfo::make($result->getBody()); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* 退货 |
||||
* |
||||
* @param RefundGoodsRequest $request |
||||
* |
||||
* @return RefundGoodsResponse|null |
||||
* @throws ParamsException |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/transaction/refundGoods |
||||
*/ |
||||
function refundGoods(RefundGoodsRequest $request): ?RefundGoodsResponse |
||||
{ |
||||
$params = $request->toParams(); |
||||
$result = $this->post('/api/hfpay/reb002', $params); |
||||
if(!$result->isSuccess()) { |
||||
return null; |
||||
} |
||||
return RefundGoodsResponse::make($result->getBody()); |
||||
} |
||||
} |
||||
@ -0,0 +1,22 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object; |
||||
|
||||
trait RequestObj |
||||
{ |
||||
private array $data; |
||||
|
||||
public function __set($name, $value) |
||||
{ |
||||
$this->data[$name] = $value; |
||||
} |
||||
|
||||
public function __get($name) |
||||
{ |
||||
if(isset($this->data[$name])) { |
||||
return $this->data[$name]; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,23 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object; |
||||
|
||||
trait ResponseObj |
||||
{ |
||||
public static function make(array $data): self |
||||
{ |
||||
$self = new self(); |
||||
$self->data = $data; |
||||
return $self; |
||||
} |
||||
|
||||
private array $data; |
||||
|
||||
public function __get($name) |
||||
{ |
||||
if(array_key_exists($name, $this->data)) { |
||||
return $this->data[$name]; |
||||
} |
||||
return null; |
||||
} |
||||
} |
||||
@ -0,0 +1,30 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\manage; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 取现卡绑定信息 |
||||
* |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答返回描述 |
||||
* @property-read $mer_cust_id 商户唯一标识号 |
||||
* @property-read $user_cust_id 用户唯一标识号 |
||||
* @property-read $acct_id 用户账户号 |
||||
* @property-read $order_date 订单日期 |
||||
* @property-read $order_id 订单号 |
||||
* @property-read $platform_seq_id 本平台交易唯一标识号 |
||||
* @property-read $bank_id 银行代号 |
||||
* @property-read $card_num 银行卡号 |
||||
* @property-read $bind_card_id 绑定ID |
||||
* @property-read $card_prov 银行卡开户省份 |
||||
* @property-read $card_area 银行卡开户地区 |
||||
* @property-read $mer_priv 商户私有域 |
||||
* @property-read $extension 扩展域 |
||||
* |
||||
*/ |
||||
class BindCashCard |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,24 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\manage; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答返回描述 |
||||
* @property-read $mer_cust_id 商户客户号 |
||||
* @property-read $order_id 交易订单号 |
||||
* @property-read $order_date 交易订单日期 |
||||
* @property-read $org_order_id 原交易订单号 |
||||
* @property-read $org_order_date 原交易订单日期 |
||||
* @property-read $guarantee_stage 交易阶段 |
||||
* @property-read $error_order_id 无效订单号 |
||||
* @property-read $bg_ret_url 异步通知地址 |
||||
* @property-read $mer_priv 商户私有域 |
||||
* @property-read $extension 扩展域 |
||||
*/ |
||||
class CertificateInfo |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,18 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\manage; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 文件下载信息 |
||||
* |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答返回描述 |
||||
* @property-read $mer_cust_id 商户客户号 |
||||
* @property-read $file_infos 文件信息列表 |
||||
*/ |
||||
class DownloadFiles |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,25 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\manage; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 解绑银行卡 |
||||
* |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答返回描述 |
||||
* @property-read $mer_cust_id 商户唯一标识号 |
||||
* @property-read $user_cust_id 用户唯一标识号 |
||||
* @property-read $order_date 订单日期 |
||||
* @property-read $order_id 订单号 |
||||
* @property-read $bind_card_id 银行卡绑定ID |
||||
* @property-read $card_buss_type 银行卡类型 |
||||
* @property-read $bg_ret_url 后台返回地址 |
||||
* @property-read $mer_priv 商户私有域 |
||||
* @property-read $extension 扩展域 |
||||
*/ |
||||
class UnBindCard |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,78 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\market; |
||||
|
||||
use Tansilu\HfPayLib\Constant; |
||||
use Tansilu\HfPayLib\exception\ParamsException; |
||||
use Tansilu\HfPayLib\factory\object\RequestObj; |
||||
use Tansilu\HfPayLib\utils\StrFilterHelper; |
||||
|
||||
/** |
||||
* @property string $order_date 订单日期 |
||||
* @property string $order_id 订单号 |
||||
* @property string $user_name 用户姓名 |
||||
* @property string $market_type 应用市场 |
||||
* @property string $acct_usage_type 账户用途 |
||||
* @property string $id_card 证件号 |
||||
* @property string $id_card_type 证件类型 |
||||
* @property string $user_id 用户ID |
||||
* @property string $user_mobile 手机号 |
||||
* @property string $ret_url 页面回调地址 |
||||
* @property string $mer_priv 商户私有域 |
||||
* @property string $extension 扩展域 |
||||
* @property string $bg_ret_url 商户后台应答地址 |
||||
* @property string $face_license_key 人脸licenseKey |
||||
*/ |
||||
class OpenAccountRequest |
||||
{ |
||||
use RequestObj; |
||||
|
||||
|
||||
/** |
||||
* @throws ParamsException |
||||
*/ |
||||
public function toParams(): array |
||||
{ |
||||
if(empty($this->data['order_date'])) { |
||||
throw new ParamsException('订单日期不能为空', 'order_date'); |
||||
} |
||||
if(empty($this->data['order_id'])) { |
||||
throw new ParamsException('订单号不能为空', 'order_id'); |
||||
} |
||||
if(empty($this->data['user_name'])) { |
||||
throw new ParamsException('用户姓名不能为空', 'user_name'); |
||||
} |
||||
if(empty($this->data['market_type'])) { |
||||
throw new ParamsException('应用市场类型不能为空', 'market_type'); |
||||
} |
||||
if(!in_array($this->data['market_type'], [Constant::MARKET_MASTER, Constant::MARKET_SUB])) { |
||||
throw new ParamsException('应用市场类型不正确', 'market_type'); |
||||
} |
||||
if(empty($this->data['acct_usage_type'])) { |
||||
throw new ParamsException('账户用途不能为空', 'acct_usage_type'); |
||||
} |
||||
if(!in_array($this->data['acct_usage_type'], [Constant::USE_TO_BUY, Constant::USE_TO_TRANS])) { |
||||
throw new ParamsException('账户用途类型不正确', 'acct_usage_type'); |
||||
} |
||||
if(empty($this->data['id_card'])) { |
||||
throw new ParamsException('证件号不能为空', 'id_card'); |
||||
} |
||||
if(empty($this->data['id_card_type'])) { |
||||
throw new ParamsException('证件类型不能为空', 'id_card_type'); |
||||
} |
||||
if(!in_array($this->data['id_card_type'], [Constant::ID_TYPE_CARD])) { |
||||
throw new ParamsException('证件类型不支持', 'id_card_type'); |
||||
} |
||||
if(empty($this->data['user_id'])) { |
||||
throw new ParamsException('用户ID不能为空', 'user_id'); |
||||
} |
||||
if(!empty($this->data['ret_url'])) { |
||||
StrFilterHelper::fileUrl($this->data['ret_url']); |
||||
} |
||||
if(!empty($this->data['bg_ret_url'])) { |
||||
StrFilterHelper::fileUrl($this->data['bg_ret_url']); |
||||
} |
||||
|
||||
return $this->data; |
||||
} |
||||
} |
||||
@ -0,0 +1,15 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\market; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 开户 |
||||
* |
||||
* @property-read $redirect_url 跳转地址 |
||||
*/ |
||||
class OpenAccountResponse |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,15 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\market; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 账户管理 |
||||
* |
||||
* @property-read $redirect_url 管理跳转地址 |
||||
*/ |
||||
class WalletManageInfoResponse |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,17 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\query; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 余额查询 |
||||
* |
||||
* |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/balanceQuery |
||||
*/ |
||||
class BalanceInfo |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\query; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 绑卡信息 |
||||
* |
||||
* @property-read $resp_code 应答返回码 定长6位String 必选 C00000–调用成功 |
||||
* @property-read $resp_desc 应答返回描述 变长String 必选 返回码的对应中文描述 |
||||
* @property-read $mer_cust_id 商户客户号 定长16位String 必选 由汇付生成,商户的唯一性标识 |
||||
* @property-read $user_cust_id 用户客户号 定长16位String 必选 由汇付生成,用户的唯一性标识 |
||||
* @property-read $card_list 卡列表 String(Json) 必选 绑定的银行卡列表 |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/bindCardInfoQuery |
||||
*/ |
||||
class BindCardStatus |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\query; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 链上账户余额 |
||||
* |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答描述 |
||||
* @property-read $mer_cust_id 商户客户号 |
||||
* @property-read $user_cust_id 用户客户号 |
||||
* @property-read $user_id 用户ID |
||||
* @property-read $chain_addr 链账户地址 |
||||
* @property-read $chain_balance 链账户余额 |
||||
*/ |
||||
class ChainBalance |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,33 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\query; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 开户状态 |
||||
* |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答描述 |
||||
* @property-read $mer_cust_id 商户客户号 |
||||
* @property-read $user_cust_id 用户客户号 |
||||
* @property-read $order_date 订单日期 |
||||
* @property-read $order_id 订单号 |
||||
* @property-read $trans_type 交易类型 |
||||
* @property-read $trans_stat 交易状态 |
||||
* @property-read $trans_resp_code 交易返回码 |
||||
* @property-read $trans_resp_desc 交易返回描述 |
||||
* @property-read $platform_seq_id 原交易流水号 |
||||
* @property-read $acct_id 账户信息 |
||||
* @property-read $fee_cust_id 手续费客户号 |
||||
* @property-read $fee_amt 手续费金额 |
||||
* @property-read $fee_acct_id 手续费子账号 |
||||
* @property-read $mer_priv 商户私有域 |
||||
* @property-read $extension 扩展域 |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/openAccountQuery |
||||
*/ |
||||
class OpenStatus |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,23 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\query; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 流水记录 |
||||
* |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答返回描述 |
||||
* @property-read $mer_cust_id 商户客户号 |
||||
* @property-read $user_cust_id 用户客户号 |
||||
* @property-read $acct_id 账户号 |
||||
* @property-read $total_count 总条数 |
||||
* @property-read $acct_logs 账务流水 |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/accountRecordQuery |
||||
*/ |
||||
class RecordLog |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,43 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\query; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 交易状态 |
||||
* |
||||
* @property-read $resp_code 应答返回码 定长6位String 必选 返回码,该字段只对本次查询接口调用负责,不是交易的返回码 |
||||
* @property-read $resp_desc 应答返回描述 变长String 必选 返回码的对应中文描述 |
||||
* @property-read $mer_cust_id 商户客户号 定长16位String 必选 由汇付生成,商户的唯一性标识 |
||||
* @property-read $user_cust_id 用户客户号 定长16位String 可选 由汇付生成,用户唯一性标识 |
||||
* @property-read $order_id 订单号 变长50位String 必选 |
||||
* @property-read $order_date 订单日期 定长8位String 必选 格式:yyyyMMdd,例如20180101 |
||||
* @property-read $trans_type 交易类型 定长2位String 必选 |
||||
* 1、当请求参数的trans_type=36时,并且这笔交易成功,则返回字段的trans_type=3表示用户实际使用快捷支付,返回字段的trans_type=13表示用户实际使用余额支付,返回字段的trans_type=6表示用户实际使用支付宝正扫支付,返回字段的trans_type=10表示用户实际使用支付宝统一下单支付,返回字段的trans_type=11表示用户实际使用微信公众号支付,返回字段的trans_type=12表示用户实际使用微信小程序支付。 |
||||
* 2、平台只有知道该笔订单实际使用哪种支付方式时,才能指定后续延时分账确认、退款时的交易类型 |
||||
* @property-read $trans_stat 交易状态 定长1位String 必选 I:初始 P:处理中 S:成功 F:失败 C:订单关闭 |
||||
* 表示这笔订单的交易状态,通过该字段来判断这笔交易是交易成功、交易失败、交易处理中 |
||||
* @property-read $trans_resp_code 交易返回码 定长6位String 可选 数据库中的返回码,没有就不返。 |
||||
* 示这笔订单的返回码,通过该字段来判断这笔交易是交易成功、交易失败、交易处理中 |
||||
* @property-read $trans_resp_desc 交易返回描述 变长String 可选 数据库中的返回描述 |
||||
* @property-read $fee_amt 手续费金额 变长14位String 可选 |
||||
* @property-read $fee_acct_id 手续费账户号 变长9位String 可选 |
||||
* @property-read $fee_cust_id 手续费客户号 定长16位String 可选 |
||||
* @property-read $bg_bank_message 银行返回描述 变长200位String 可选 |
||||
* @property-read $trans_amt 交易金额 变长14位String 可选 泛指交易金额,金额格式必须保留两位小数,例如2.00 |
||||
* @property-read $platform_seq_id 原交易流水号 变长20位String 必选 原交易返回的“本平台交易唯一标识号” |
||||
* @property-read $out_trans_id 外部订单流水号 变长64位String 可选 指支付宝、微信、银联流水号 |
||||
* @property-read $div_detail 分账账户串 变长String 可选 库表中的分账串,参见下文中的分账账户串 |
||||
* @property-read $payer_bank_no 付款方银行编号 变长String 可选 |
||||
* @property-read $payer_acct_id 付款方银行账号 变长String 可选 |
||||
* @property-read $payer_acct_nm 付款方银行账户名 变长String 可选 |
||||
* @property-read $mer_priv 商户私有域 变长120位String 可选 |
||||
* @property-read $extension 扩展域 变长512位String 可选 |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/transactionStateQuery |
||||
*/ |
||||
class TransStatus |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\query; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* 钱包状态 |
||||
* |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答描述 |
||||
* @property-read $user_cust_id 用户客户号 |
||||
* @property-read $user_name 用户姓名 |
||||
* @property-read $acct_info_list 账户列表 |
||||
* |
||||
* @see https://hfpay.cloudpnr.com/customers/nft/#/query/walletStateQuery |
||||
*/ |
||||
class WalletStatus |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,17 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答返回描述 |
||||
* @property-read $mer_cust_id 商户客户号 |
||||
* @property-read $order_id 订单号 |
||||
* @property-read $order_date 订单日期 |
||||
*/ |
||||
class CloseOrder |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,28 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答返回描述 |
||||
* @property-read $mer_cust_id 商户客户号 |
||||
* @property-read $order_id 订单号 |
||||
* @property-read $order_date 订单日期 |
||||
* @property-read $platform_seq_id 本平台交易唯一标识号 |
||||
* @property-read $org_order_id 原订单号 |
||||
* @property-read $org_order_date 原订单日期 |
||||
* @property-read $org_trans_type 原交易类型 |
||||
* @property-read $trans_amt 订单确认金额 |
||||
* @property-read $in_cust_id 入账客户号 |
||||
* @property-read $in_acct_id 入账账户号 |
||||
* @property-read $div_details 入账明细 |
||||
* @property-read $mer_priv 商户私有域 |
||||
* @property-read $share_fee_mode 手续费分摊模式 |
||||
* @property-read $extension 扩展域 |
||||
*/ |
||||
class DelayDivide |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,71 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
use Tansilu\HfPayLib\exception\ParamsException; |
||||
use Tansilu\HfPayLib\factory\object\RequestObj; |
||||
|
||||
/** |
||||
* @property string $order_id 订单号 |
||||
* @property string $order_date 订单日期 |
||||
* @property string $org_order_id 原订单号 |
||||
* @property string $org_order_date 原订单日期 |
||||
* @property string $org_trans_type 原交易类型 |
||||
* @property string $trans_amt 订单确认金额 |
||||
* @property array $div_details 分账账户串 |
||||
* @property DeviceInfo $dev_info_json 设备信息 |
||||
* @property string $mer_priv 商户私有域 |
||||
* @property string $extension 扩展域 |
||||
* @property string $share_fee_mode 手续费分摊模式标志 |
||||
*/ |
||||
class DelayDivideRequest |
||||
{ |
||||
|
||||
use RequestObj; |
||||
|
||||
|
||||
public function toParams(): array |
||||
{ |
||||
$params = []; |
||||
if(empty($this->data['order_id'])) { |
||||
throw new ParamsException('订单ID不能为空', 'order_id'); |
||||
} |
||||
$params["order_id"] = $this->data['order_id']; |
||||
if(empty($this->data['order_date'])) { |
||||
throw new ParamsException('订单日期不能为空', 'order_date'); |
||||
} |
||||
$params["order_date"] = $this->data['order_date']; |
||||
if(empty($this->data['org_order_id'])) { |
||||
throw new ParamsException('原支付的订单号不能为空', 'org_order_id'); |
||||
} |
||||
$params["org_order_id"] = $this->data['org_order_id']; |
||||
if(empty($this->data['org_order_date'])) { |
||||
throw new ParamsException('原支付订单日期不能为空', 'org_order_date'); |
||||
} |
||||
$params["org_order_date"] = $this->data['org_order_date']; |
||||
if(empty($this->data['org_trans_type'])) { |
||||
throw new ParamsException('原交易类型不能为空', 'org_trans_type'); |
||||
} |
||||
$params["org_trans_type"] = $this->data['org_trans_type']; |
||||
if(empty($this->data['trans_amt'])) { |
||||
throw new ParamsException('订单确认金额不能为空', 'trans_amt'); |
||||
} |
||||
if($this->data['div_details'] != null) { |
||||
$params["div_details"] = json_encode($this->data['div_details'], JSON_UNESCAPED_UNICODE); |
||||
} |
||||
if($this->data['dev_info_json'] != null) { |
||||
$params['dev_info_json'] = $this->data['dev_info_json']->toJson(); |
||||
} |
||||
if(!empty($this->data['mer_priv'])) { |
||||
$params['mer_priv'] = $this->data['mer_priv']; |
||||
} |
||||
if(!empty($this->data['extension'])) { |
||||
$params['extension'] = $this->data['extension']; |
||||
} |
||||
if(!empty($this->data['share_fee_mode'])) { |
||||
$params['share_fee_mode'] = $this->data['share_fee_mode']; |
||||
} |
||||
|
||||
return $params; |
||||
} |
||||
} |
||||
@ -0,0 +1,79 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
use Tansilu\HfPayLib\exception\ParamsException; |
||||
|
||||
/** |
||||
* @property $devType 设备类型 |
||||
* @property $ipAddr IP地址 |
||||
* @property $devSysType 设备系统类型 |
||||
* @property $UUID UUID |
||||
* @property $MAC MAC |
||||
* @property $IMEI IMEI码 |
||||
* @property $IMSI IMSI码 |
||||
* @property $ICCID ICCID码 |
||||
* @property $MEID MEID码 |
||||
* @property $SEID SEID |
||||
* @property $ipProvName IP省 |
||||
* @property $ipCityName IP市 |
||||
* @property $ipAreaName IP地区 |
||||
* @property $ipType IP地址类型 |
||||
* @property $cenX 定位地址(经度) |
||||
* @property $cenY 定位地址(纬度) |
||||
* @property $ipProvCode 定位地址(省编码) |
||||
* @property $ipCityCode 定位地址(市编码) |
||||
* @property $ipAreaCode 定位地址(区编码) |
||||
* @property $provName 定位地址(省) |
||||
* @property $cityName 定位地址(市) |
||||
* @property $areaName 定位地址(区) |
||||
* @property $unDevCode 用户交易设备(唯一识别码) |
||||
* @property $serviceProviderIp 商户服务IP地址 |
||||
* @property $merUrl 商户网址 |
||||
*/ |
||||
class DeviceInfo |
||||
{ |
||||
public static function make( |
||||
string $devType, |
||||
string $ipAddr, |
||||
string $mac |
||||
): self |
||||
{ |
||||
$self = new self(); |
||||
$self->devType = $devType; |
||||
$self->ipAddr = $ipAddr; |
||||
$self->MAC = $mac; |
||||
|
||||
return $self; |
||||
} |
||||
|
||||
private array $data; |
||||
|
||||
public function __get($name) |
||||
{ |
||||
if(array_key_exists($name, $this->data)) { |
||||
return $this->data[$name]; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public function __set($name, $value) |
||||
{ |
||||
$this->data[$name] = $value; |
||||
} |
||||
|
||||
|
||||
public function toJSON(): string |
||||
{ |
||||
if(empty($this->data['devType'])) { |
||||
throw new ParamsException('设备类型不能为空', 'devInfoJson.devType'); |
||||
} |
||||
if(empty($this->data['ipAddr'])) { |
||||
throw new ParamsException('设备IP地址不能为空', 'devInfoJson.ipAddr'); |
||||
} |
||||
if(empty($this->data['MAC']) && empty($this->data['IMEI'])) { |
||||
throw new ParamsException('设备MAC或IMEI不能为空', 'devInfoJson.MAC|devInfoJson.IMEI'); |
||||
} |
||||
return json_encode($this->data, JSON_UNESCAPED_UNICODE); |
||||
} |
||||
} |
||||
@ -0,0 +1,43 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
/** |
||||
* @property $divCustId 分账客户号 |
||||
* @property $divAcctId 分账账户号 |
||||
* @property $divAmt 分账金额 |
||||
* @property $riskDivType 风控分账用途 |
||||
*/ |
||||
class DivDetail |
||||
{ |
||||
public static function make(string $divCustId, string $divAcctId, string $amount, string $riskDivType): self |
||||
{ |
||||
$self = new self(); |
||||
$self->divCustId = $divCustId; |
||||
$self->divAcctId = $divAcctId; |
||||
$self->divAmt = $amount; |
||||
$self->riskDivType = $riskDivType; |
||||
return $self; |
||||
} |
||||
|
||||
private array $data; |
||||
|
||||
public function __get($name) |
||||
{ |
||||
if(array_key_exists($name, $this->data)) { |
||||
return $this->data[$name]; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public function __set($name, $value) |
||||
{ |
||||
$this->data[$name] = $value; |
||||
} |
||||
|
||||
|
||||
public function toJSON(): string |
||||
{ |
||||
return json_encode($this->data, JSON_UNESCAPED_UNICODE); |
||||
} |
||||
} |
||||
@ -0,0 +1,54 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
/** |
||||
* 藏品信息 |
||||
* |
||||
* @property string $objectType 藏品系列 |
||||
* @property string $objectName 藏品名称 |
||||
* @property string $objectTime 上架时间 |
||||
* @property int $marketType 藏品交易市场类型 |
||||
* @property string $objectAddr 藏品合约地址 |
||||
* @property string $chainBelong 藏品认证网络 |
||||
* @property string $chainId 藏品tokenId |
||||
* @property string $objectStandard 藏品区块链合约标准 |
||||
* @property string $objectTransactions 藏品交易记录 |
||||
* @property string $objectIssuerName 发行方名称 |
||||
* @property string $regMobileNo 买家注册手机号 |
||||
* @property string $regDate 买家注册时间 |
||||
* @property string $regIpAddr 买家注册ip地址 |
||||
* @property string $regCertId 买家注册证件号 |
||||
* @property string $regCustId 买家注册用户ID |
||||
* |
||||
*/ |
||||
class ObjectInfo |
||||
{ |
||||
public static function make(int $marketType): self |
||||
{ |
||||
$self = new self(); |
||||
$self->marketType = $marketType; |
||||
return $self; |
||||
} |
||||
|
||||
private array $data; |
||||
|
||||
public function __get($name) |
||||
{ |
||||
if(array_key_exists($name, $this->data)) { |
||||
return $this->data[$name]; |
||||
} |
||||
return null; |
||||
} |
||||
|
||||
public function __set($name, $value) |
||||
{ |
||||
$this->data[$name] = $value; |
||||
} |
||||
|
||||
|
||||
public function toJSON(): string |
||||
{ |
||||
return json_encode($this->data, JSON_UNESCAPED_UNICODE); |
||||
} |
||||
} |
||||
@ -0,0 +1,73 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
use Tansilu\HfPayLib\exception\ParamsException; |
||||
use Tansilu\HfPayLib\factory\object\RequestObj; |
||||
use Tansilu\HfPayLib\utils\StrFilterHelper; |
||||
|
||||
/** |
||||
* @property string $order_date 订单日期 |
||||
* @property string $order_id 订单号 |
||||
* @property string $org_order_date 原确认订单日期 |
||||
* @property string $org_order_id 原确认订单号 |
||||
* @property string $trans_amt 退货金额 |
||||
* @property array $div_details 退货明细 |
||||
* @property string $remark 备注 |
||||
* @property string $bg_ret_url 后台返回地址 |
||||
* @property string $mer_priv 商户私有域 |
||||
* @property string $extension 扩展域 |
||||
* @property DeviceInfo $dev_info_json 设备静态信息 |
||||
*/ |
||||
class RefundGoodsRequest |
||||
{ |
||||
|
||||
use RequestObj; |
||||
|
||||
|
||||
/** |
||||
* @return array |
||||
* @throws ParamsException |
||||
*/ |
||||
public function toParams(): array |
||||
{ |
||||
$params = []; |
||||
if(empty($this->data['order_date'])) { |
||||
throw new ParamsException('订单日期不能为空', 'order_date'); |
||||
} |
||||
if(empty($this->data['order_id'])) { |
||||
throw new ParamsException('订单号不能为空', 'order_id'); |
||||
} |
||||
if(empty($this->data['org_order_date'])) { |
||||
throw new ParamsException('原交易订单日期不能为空', 'org_order_date'); |
||||
} |
||||
$params['org_order_date'] = $this->data['org_order_date']; |
||||
if(empty($this->data['org_order_id'])) { |
||||
throw new ParamsException('原交易订单号不能为空', 'org_order_id'); |
||||
} |
||||
|
||||
if(empty($this->data['trans_amt'])) { |
||||
throw new ParamsException('退款金额不能为空', 'trans_amt'); |
||||
} |
||||
if(!empty($params['div_details'])) { |
||||
$params['div_details'] = json_encode($this->data['div_details'], JSON_UNESCAPED_UNICODE); |
||||
} |
||||
|
||||
if(!empty($this->data['remark'])) { |
||||
$params['remark'] = $this->data['remark']; |
||||
} |
||||
if(!empty($this->data['bg_ret_url'])) { |
||||
$params['bg_ret_url'] = StrFilterHelper::fileUrl($this->data['bg_ret_url']); |
||||
} |
||||
if(!empty($this->data['mer_priv'])) { |
||||
$params['mer_priv'] = $this->data['mer_priv']; |
||||
} |
||||
if(!empty($this->data['extension'])) { |
||||
$params['extension'] = $this->data['extension']; |
||||
} |
||||
if(!empty($this->data['dev_info_json'])) { |
||||
$params['dev_info_json'] = $this->data['dev_info_json']->toJSON(); |
||||
} |
||||
return $params; |
||||
} |
||||
} |
||||
@ -0,0 +1,24 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* @property $resp_code 应答返回码 |
||||
* @property $resp_desc 应答返回描述 |
||||
* @property $mer_cust_id 商户唯一标识号 |
||||
* @property $order_date 订单日期 |
||||
* @property $order_id 订单号 |
||||
* @property $trans_amt 退货金额 |
||||
* @property $fee_amt 退款手续费 |
||||
* @property $div_details 退货明细 |
||||
* @property $platform_seq_id 本平台交易唯一标识号 |
||||
* @property $bg_ret_url 后台返回地址 |
||||
* @property $mer_priv 商户私有域 |
||||
* @property $extension 扩展域 |
||||
*/ |
||||
class RefundGoodsResponse |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,24 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答返回描述 |
||||
* @property-read $mer_cust_id 商户唯一标识号 |
||||
* @property-read $order_date 订单日期 |
||||
* @property-read $order_id 订单号 |
||||
* @property-read $trans_amt 退款金额 |
||||
* @property-read $fee_amt 退款手续费 |
||||
* @property-read $div_details 退款明细 |
||||
* @property-read $platform_seq_id 本平台交易唯一标识号 |
||||
* @property-read $bg_ret_url 后台返回地址 |
||||
* @property-read $mer_priv 商户私有域 |
||||
* @property-read $extension 扩展域 |
||||
*/ |
||||
class RefundInfo |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,74 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
use Tansilu\HfPayLib\exception\ParamsException; |
||||
use Tansilu\HfPayLib\factory\object\RequestObj; |
||||
use Tansilu\HfPayLib\utils\StrFilterHelper; |
||||
|
||||
/** |
||||
* @property $order_date 订单日期 |
||||
* @property $order_id 订单号 |
||||
* @property $org_order_date 原交易订单日期 |
||||
* @property $org_order_id 原交易订单号 |
||||
* @property $trans_type 原交易类型 |
||||
* @property $trans_amt 退款金额 |
||||
* @property array $div_details 退款明细 |
||||
* @property $remark 备注 |
||||
* @property $bg_ret_url 后台返回地址 |
||||
* @property $mer_priv 商户私有域 |
||||
* @property $extension 扩展域 |
||||
* @property DeviceInfo $dev_info_json 设备静态信息 |
||||
*/ |
||||
class RefundRequest |
||||
{ |
||||
|
||||
use RequestObj; |
||||
|
||||
public function toParams(): array |
||||
{ |
||||
$params = []; |
||||
if(empty($this->data['order_date'])) { |
||||
throw new ParamsException('订单日期不能为空', 'order_date'); |
||||
} |
||||
$params['order_date'] = $this->data['order_date']; |
||||
|
||||
if(empty($this->data['order_id'])) { |
||||
throw new ParamsException('订单号不能为空', 'order_id'); |
||||
} |
||||
$params['order_id'] = $this->data['order_id']; |
||||
if(empty($this->data['org_order_date'])) { |
||||
throw new ParamsException('原交易订单日期不能为空', 'org_order_date'); |
||||
} |
||||
$params['org_order_date'] = $this->data['org_order_date']; |
||||
if(empty($this->data['org_order_id'])) { |
||||
throw new ParamsException('原交易订单号不能为空', 'org_order_id'); |
||||
} |
||||
if(!empty($params['trans_type'])) { |
||||
$params['trans_type'] = $this->data['trans_type']; |
||||
} |
||||
if(empty($this->data['trans_amt'])) { |
||||
throw new ParamsException('退款金额不能为空', 'trans_amt'); |
||||
} |
||||
if(!empty($params['div_details'])) { |
||||
$params['div_details'] = json_encode($this->data['div_details'], JSON_UNESCAPED_UNICODE); |
||||
} |
||||
if(!empty($this->data['remark'])) { |
||||
$params['remark'] = $this->data['remark']; |
||||
} |
||||
if(!empty($this->data['bg_ret_url'])) { |
||||
$params['bg_ret_url'] = StrFilterHelper::fileUrl($this->data['bg_ret_url']); |
||||
} |
||||
if(!empty($this->data['mer_priv'])) { |
||||
$params['mer_priv'] = $this->data['mer_priv']; |
||||
} |
||||
if(!empty($this->data['extension'])) { |
||||
$params['extension'] = $this->data['extension']; |
||||
} |
||||
if(!empty($this->data['dev_info_json'])) { |
||||
$params['dev_info_json'] = $this->data['dev_info_json']->toJSON(); |
||||
} |
||||
return $params; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
use Tansilu\HfPayLib\factory\object\ResponseObj; |
||||
|
||||
/** |
||||
* @property-read $resp_code 应答返回码 |
||||
* @property-read $resp_desc 应答返回描述 |
||||
* @property-read $mer_cust_id 商户客户号 |
||||
* @property-read $order_id 订单号 |
||||
* @property-read $order_date 订单日期 |
||||
* @property-read $trans_amt 订单金额 |
||||
* @property-read $mer_priv 商户私有域 |
||||
* @property-read $uuid 会话ID |
||||
* @property-read $pay_url 跳转收银台地址 |
||||
*/ |
||||
class UnifiedOrder |
||||
{ |
||||
use ResponseObj; |
||||
} |
||||
@ -0,0 +1,172 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\factory\object\trade; |
||||
|
||||
use Tansilu\HfPayLib\Constant; |
||||
use Tansilu\HfPayLib\exception\ParamsException; |
||||
use Tansilu\HfPayLib\factory\object\RequestObj; |
||||
use Tansilu\HfPayLib\utils\StrFilterHelper; |
||||
|
||||
/** |
||||
* 统一下单请求参数配置 |
||||
* |
||||
* @property string $order_date 订单日期 |
||||
* @property string $order_id 订单号 |
||||
* @property string $user_cust_id 用户客户号 |
||||
* @property string $user_name 用户姓名 |
||||
* @property string $id_card_type 用户证件类型 |
||||
* @property string $id_card 用户证件号 |
||||
* @property string $div_type 分账区分 |
||||
* @property array $div_details 分账账户串 |
||||
* @property string $trans_amt 交易金额 |
||||
* @property string $order_expire_time 订单超时时间 |
||||
* @property string $ret_url 前台返回地址 |
||||
* @property string $bg_ret_url 后台返回地址 |
||||
* @property string $mer_priv 商户私有域 |
||||
* @property string $extension 扩展域 |
||||
* @property string $goods_tag 商品标记 |
||||
* @property string $attach_info 附加信息 |
||||
* @property string $goods_desc 商品描述 |
||||
* @property string $goods_type 商品类型 |
||||
* @property DeviceInfo $dev_info_json 设备信息 |
||||
* @property ObjectInfo $object_info 藏品信息 |
||||
* @property string $wx_app_id 微信公众号appId |
||||
* @property string $wx_applet_app_id 微信小程序appId |
||||
* @property string $ali_app_id 支付宝appId |
||||
* @property string $term_type 终端类型 |
||||
* @property string $limit_pay 禁用贷记卡 |
||||
* @property string $face_license_key 人脸licenseKey |
||||
*/ |
||||
class UnifiedOrderRequest |
||||
{ |
||||
use RequestObj; |
||||
|
||||
|
||||
/** |
||||
* @return array |
||||
* @throws ParamsException |
||||
*/ |
||||
public function toParams(): array |
||||
{ |
||||
$params = []; |
||||
if(empty($this->data['order_date'])) { |
||||
throw new ParamsException('订单日期不能为空', 'order_date'); |
||||
} |
||||
$params['order_date'] = $this->data['order_date']; |
||||
|
||||
if(empty($this->data['order_id'])) { |
||||
throw new ParamsException('订单号不能为空', 'order_id'); |
||||
} |
||||
$params['order_id'] = $this->data['order_id']; |
||||
if(empty($this->data['object_info'])) { |
||||
throw new ParamsException('藏品信息不能为空', 'object_info'); |
||||
} |
||||
$objectInfo = $this->data['object_info']; |
||||
if($objectInfo->marketType == null) { |
||||
throw new ParamsException('藏品交易市场类型不正确', 'object_info.marketType'); |
||||
} |
||||
if($objectInfo->marketType == Constant::MARKET_MASTER) { |
||||
if($this->data['user_name'] == null && $this->data['user_cust_id'] == null) { |
||||
throw new ParamsException('付款人信息不能为空', 'user_name|user_cust_id'); |
||||
} |
||||
//证件信息 |
||||
if($this->data['user_cust_id'] == null) { |
||||
if($this->data['id_card_type'] == null) { |
||||
throw new ParamsException('用户证件信息不能为空', 'id_card_type'); |
||||
} |
||||
if($this->data['id_card'] == null) { |
||||
throw new ParamsException('用户证件号不能为空', 'id_card'); |
||||
} |
||||
} |
||||
} else if($objectInfo->marketType == Constant::MARKET_SUB) { |
||||
if($this->data['user_cust_id'] == null) { |
||||
throw new ParamsException('用户客户号不能为空', 'user_cust_id'); |
||||
} |
||||
} |
||||
if($this->data['user_name']) { |
||||
$params['user_name'] = $this->data['user_name']; |
||||
} |
||||
if($this->data['user_cust_id'] != null) { |
||||
$params['user_cust_id'] = $this->data['user_cust_id']; |
||||
} |
||||
if($this->data['id_card_type'] == null) { |
||||
$params['id_card_type'] = $this->data['id_card_type']; |
||||
} |
||||
if($this->data['id_card'] != null) { |
||||
$params['id_card'] = $this->data['id_card']; |
||||
} |
||||
if(!empty($this->data['div_type'])) { |
||||
$params['div_type'] = $this->data['div_type']; |
||||
} |
||||
|
||||
if($this->data['div_details'] != null && empty($this->data['div_details'])) { |
||||
//分账 |
||||
$params['div_details'] = json_encode($this->data['div_details']); |
||||
} |
||||
if($this->data['trans_amt'] == null) { |
||||
throw new ParamsException('交易金额不能为空', 'trans_amt'); |
||||
} |
||||
if($this->data['order_expire_time'] != null) { |
||||
$params['order_expire_time'] = $this->data['order_expire_time']; |
||||
} |
||||
if($this->data['ret_url'] != null) { |
||||
$params['ret_url'] = $this->data['ret_url']; |
||||
} |
||||
if(!empty($this->data['bg_ret_url'])) { |
||||
$params['bg_ret_url'] = StrFilterHelper::fileUrl($this->data['bg_ret_url']); |
||||
} |
||||
if(!empty($this->data['mer_priv'])) { |
||||
$params['mer_priv'] = $this->data['mer_priv']; |
||||
} |
||||
if(!empty($this->data['extension'])) { |
||||
$params['extension'] = $this->data['extension']; |
||||
} |
||||
if(!empty($this->data['goods_tag'])) { |
||||
$params['goods_tag'] = $this->data['goods_tag']; |
||||
} |
||||
if(!empty($this->data['attach_info'])) { |
||||
$params['attach_info'] = $this->data['attach_info']; |
||||
} |
||||
if(!empty($this->data['goods_desc'])) { |
||||
$params['goods_desc'] = $this->data['goods_desc']; |
||||
} |
||||
if(!empty($this->data['goods_tag'])) { |
||||
$params['goods_tag'] = $this->data['goods_tag']; |
||||
} |
||||
if(!empty($this->data['goods_type'])) { |
||||
$params['goods_type'] = $this->data['goods_type']; |
||||
} |
||||
if(empty($this->data['dev_info_json'])) { |
||||
throw new ParamsException('设备信息不能为了', 'dev_info_json'); |
||||
} |
||||
$devInfoJson = $this->data['dev_info_json']; |
||||
$devInfoStr = $devInfoJson->toJSON(); |
||||
$params['dev_info_json'] = $devInfoStr; |
||||
|
||||
//藏品 |
||||
if(empty($this->data['object_info'])) { |
||||
throw new ParamsException('藏品信息不能为空', 'object_info'); |
||||
} |
||||
$params['object_info'] = $this->data['object_info']->toJSON(); |
||||
if(!empty($this->data['wx_app_id'])) { |
||||
$params['wx_app_id'] = $this->data['wx_app_id']; |
||||
} |
||||
if(!empty($this->data['wx_applet_app_id'])) { |
||||
$params['wx_applet_app_id'] = $this->data['wx_applet_app_id']; |
||||
} |
||||
if(!empty($this->data['ali_app_id'])) { |
||||
$params['ali_app_id'] = $this->data['ali_app_id']; |
||||
} |
||||
if(!empty($this->data['term_type'])) { |
||||
$params['term_type'] = $this->data['term_type']; |
||||
} |
||||
if(!empty($this->data['limit_pay'])) { |
||||
$params['limit_pay'] = $this->data['limit_pay']; |
||||
} |
||||
if(!empty($this->data['face_license_key'])) { |
||||
$params['face_license_key'] = $this->data['face_license_key']; |
||||
} |
||||
|
||||
return $params; |
||||
} |
||||
} |
||||
@ -0,0 +1,83 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\http; |
||||
|
||||
use Tansilu\HfPayLib\exception\BizException; |
||||
|
||||
class ErrCodeHelper |
||||
{ |
||||
/** |
||||
* @throws BizException |
||||
*/ |
||||
public static function parseError(string $code, $desc): void |
||||
{ |
||||
// $err = [ |
||||
// //'C00000' => '请求成功', |
||||
// 'C00001' => '请求处理中', |
||||
// 'C00002' => '请求已受理', |
||||
// 'C00003' => '请求失败', |
||||
// 'C00005' => '查询失败', |
||||
// 'C00006' => '交易关闭', |
||||
// 'C00007' => '记录不存在', |
||||
// 'C00008' => '用户不存在', |
||||
// 'C00098' => '系统超时', |
||||
// 'C00099' => '系统异常', |
||||
// 'C00097' => '并发异常', |
||||
// 'C00096' => '系统繁忙', |
||||
// 'C00100' => '请求参数非法', |
||||
// 'C00101' => '商户无此接口权限', |
||||
// 'C00102' => '验证签名失败', |
||||
// 'C00103' => '商户状态异常', |
||||
// 'C00104' => '用户状态异常', |
||||
// 'C00105' => '账户状态异常', |
||||
// 'C00106' => '商户签名未配置', |
||||
// 'C00107' => '消息类型与签名内容不一致', |
||||
// 'C00108' => '商户客户号与签名内容不一致', |
||||
// 'C00109' => '版本号与签名内容不一致', |
||||
// 'C00110' => '商户号不存在', |
||||
// 'C00111' => '用户客户号不存在', |
||||
// 'C00112' => '账号不存在', |
||||
// 'C00113' => '页面数据被篡改', |
||||
// 'C00114' => '订单号重复', |
||||
// 'C00115' => '账户可用余额不足', |
||||
// 'C00116' => '商户配置异常', |
||||
// 'C00117' => '账户余额查询失败', |
||||
// 'C00118' => '未查询到内容', |
||||
// 'C00119' => '暂时不支持贷记卡', |
||||
// 'C00120' => '银行卡号不正确', |
||||
// 'C00121' => '银行卡相关信息不完整或格式不正确', |
||||
// 'C00122' => '手续费计算异常', |
||||
// 'C00123' => '手续费余额不足', |
||||
// 'C00124' => '短信验证码发送手机号与验证手机号不一致', |
||||
// 'C00126' => '短信验证码已失效请重新获取', |
||||
// 'C00127' => '短信验证码发送接口与接口不一致', |
||||
// 'C00128' => '短信验证码发送过于频繁或单日发送次数超限', |
||||
// 'C00129' => '请获取短信验证码', |
||||
// 'C00130' => '短信验证码不正确', |
||||
// 'C00131' => '短信订单号重复', |
||||
// 'C00132' => '用户未设置交易密码', |
||||
// 'C00133' => '绑卡信息不存在', |
||||
// 'C00134' => '手续费金额不得大于等于交易金额', |
||||
// 'C00800' => '风控信息验证失败', |
||||
// 'C00801' => '单笔交易限制或其他', |
||||
// 'C00802' => '商户超限额或限次', |
||||
// 'C00803' => '商户未开通该功能权限', |
||||
// 'C00804' => '商户交易限制', |
||||
// 'C00805' => '人脸识别系统异常', |
||||
// 'C00806' => '等待人脸识别校验', |
||||
// 'C00807' => '风控待二次校验', |
||||
// 'C00808' => '风控二次校验失败', |
||||
// 'S00017' => '未知交易类型', |
||||
// 'S00018' => '未查询到订单信息', |
||||
// 'S00050' => '当前钱包账户未上链', |
||||
// 'A40150' => '钱包信息查询失败', |
||||
// 'A40155' => '当前用户不是钱包户', |
||||
// ]; |
||||
// if(isset($err[$code])) { |
||||
// throw new BizException($err[$code] . ' ' . $code . ' ' . $desc, $code); |
||||
// } |
||||
if($code != 'C00000') { |
||||
throw new BizException($desc . ' ' . $code, $code); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,47 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\http; |
||||
|
||||
class Factory |
||||
{ |
||||
|
||||
protected IHttpClient $client; |
||||
|
||||
protected string $base = ''; |
||||
|
||||
public function __construct(IHttpClient $client) |
||||
{ |
||||
$this->client = $client; |
||||
} |
||||
|
||||
public function request(string $method, string $url, array $query = [], array $data = []): Response |
||||
{ |
||||
return $this->client->request($method, $url, $query, $data); |
||||
} |
||||
|
||||
public function get(string $url, array $query = []): Response |
||||
{ |
||||
return $this->client->get($url, $query); |
||||
|
||||
} |
||||
|
||||
public function post(string $url, array $data = []): Response |
||||
{ |
||||
return $this->client->post($url, $data); |
||||
} |
||||
|
||||
public function put(string $url, array $data = []): Response |
||||
{ |
||||
return $this->client->put($url, $data); |
||||
} |
||||
|
||||
public function delete(string $url, array $data = []): Response |
||||
{ |
||||
return $this->client->delete($url, $data); |
||||
} |
||||
|
||||
public function postJson(string $url, array $data = []): Response |
||||
{ |
||||
return $this->client->postJson($url, $data); |
||||
} |
||||
} |
||||
@ -0,0 +1,21 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\http; |
||||
|
||||
interface IHttpClient |
||||
{ |
||||
function request(string $method, string $uri, ?array $query = [], ?array $body = [], string $format = 'json'): Response; |
||||
|
||||
function get(string $uri, ?array $data = []): Response; |
||||
|
||||
function post(string $uri, ?array $data = []): Response; |
||||
|
||||
function patch(string $uri, ?array $data = []): Response; |
||||
|
||||
function put(string $uri, ?array $data = []): Response; |
||||
|
||||
function delete(string $uri, ?array $data = []): Response; |
||||
|
||||
function postJson(string $uri, ?array $data = []): Response; |
||||
|
||||
} |
||||
@ -0,0 +1,78 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\http; |
||||
|
||||
use Psr\Http\Message\ResponseInterface; |
||||
use Tansilu\HfPayLib\exception\ApiException; |
||||
|
||||
class Response |
||||
{ |
||||
/** |
||||
* @var int 状态码 |
||||
*/ |
||||
private int $statusCode = 200; |
||||
private array $body = []; |
||||
|
||||
private string $source; |
||||
|
||||
/** |
||||
* @throws ApiException |
||||
*/ |
||||
public static function make(ResponseInterface $response): Response |
||||
{ |
||||
$self = new self(); |
||||
$self->statusCode = $response->getStatusCode(); |
||||
|
||||
$self->source = $response->getBody()->getContents(); |
||||
|
||||
if(!empty($self->source)) { |
||||
$contentType = $response->getHeader('Content-Type'); |
||||
if(empty($contentType)) { |
||||
throw new ApiException('反馈的消息未指明内容格式Content-Type'); |
||||
} |
||||
$bodyFormat = explode(';', $contentType[0]); |
||||
switch ($bodyFormat[0]) { |
||||
case 'text/html': |
||||
case 'application/json': |
||||
$self->body = json_decode($self->source, true); |
||||
break; |
||||
case 'application/xml': |
||||
case 'text/plain': |
||||
default: |
||||
throw new ApiException('反馈的数据格式不支持处理' . $bodyFormat[0]); |
||||
} |
||||
} |
||||
return $self; |
||||
} |
||||
|
||||
public static function tempInit(int $code, array $body) |
||||
{ |
||||
$self = new self(); |
||||
$self->statusCode = $code; |
||||
$self->body = $body; |
||||
return $self; |
||||
} |
||||
|
||||
/** |
||||
* @return bool 是否成功 |
||||
*/ |
||||
public function isSuccess(): bool |
||||
{ |
||||
return $this->statusCode >= 200 && $this->statusCode < 300; |
||||
} |
||||
|
||||
public function getCode(): int |
||||
{ |
||||
return $this->statusCode; |
||||
} |
||||
|
||||
public function getBody(): array |
||||
{ |
||||
return $this->body; |
||||
} |
||||
|
||||
public function getSource(): string |
||||
{ |
||||
return $this->source; |
||||
} |
||||
} |
||||
@ -0,0 +1,276 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\http\impl; |
||||
|
||||
|
||||
use GuzzleHttp\Client; |
||||
use GuzzleHttp\Exception\GuzzleException; |
||||
use Tansilu\HfPayLib\exception\ApiException; |
||||
use Tansilu\HfPayLib\exception\BizException; |
||||
use Tansilu\HfPayLib\exception\InitException; |
||||
use Tansilu\HfPayLib\exception\SignException; |
||||
use Tansilu\HfPayLib\http\ErrCodeHelper; |
||||
use Tansilu\HfPayLib\http\IHttpClient; |
||||
use Tansilu\HfPayLib\http\Response; |
||||
use Tansilu\HfPayLib\library\impl\SignerHttpClient; |
||||
use Tansilu\HfPayLib\library\ISigner; |
||||
|
||||
class HFPayHttpClient implements IHttpClient |
||||
{ |
||||
|
||||
|
||||
/** |
||||
* 接口地址 |
||||
*/ |
||||
private const API_ENDPOINT = 'https://hfpay.cloudpnr.com'; |
||||
private const TEST_ENDPOINT = 'https://hfpay.testpnr.com'; |
||||
private const API_VERSION = '10'; |
||||
/** |
||||
* @var Client HTTP客户端 |
||||
*/ |
||||
private Client $client; |
||||
|
||||
private array $config; |
||||
|
||||
/** |
||||
* |
||||
* @throws InitException |
||||
*/ |
||||
public function __construct(array $config = []) |
||||
{ |
||||
if(empty($config['sign_server'])) { |
||||
throw new InitException('签名服务器地址不正确'); |
||||
} |
||||
$this->config = $config; |
||||
|
||||
//先获取Token |
||||
$options = $this->getHttpClientOption($config['debug'] ? |
||||
self::TEST_ENDPOINT : self::API_ENDPOINT); |
||||
$this->client = new Client($options); |
||||
|
||||
//签名客户端 |
||||
$this->signClient = new SignerHttpClient( |
||||
$config['sign_server'], |
||||
$this->config['sign_file'], |
||||
$this->config['sign_pwd'], |
||||
$this->config['cert_file']); |
||||
} |
||||
|
||||
/** |
||||
* 客户端参数 |
||||
* |
||||
* @param string $baseUri |
||||
* |
||||
* @return array |
||||
*/ |
||||
private function getHttpClientOption(string $baseUri): array |
||||
{ |
||||
return [ |
||||
'base_uri' => $baseUri, |
||||
'connect_timeout' => 10, |
||||
'timeout' => 30, |
||||
'headers' => [ |
||||
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', |
||||
'Accept' => 'application/json', |
||||
//'referer' => $baseUrl, |
||||
'Cache-Control' => 'no-cache', |
||||
'accept-encoding' => 'gzip, deflate, br, zstd', |
||||
'accept-language' => 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7' |
||||
], |
||||
'allow_redirects' => [ |
||||
'max' => 3, |
||||
'track_redirects' => false, |
||||
'strict' => false, |
||||
], |
||||
//'debug' => true, |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* 获取请求参数 |
||||
* |
||||
* @return array |
||||
*/ |
||||
private function getRequestOptions(): array |
||||
{ |
||||
return [ |
||||
'debug' => false, |
||||
//不抛出异常 |
||||
'http_errors' => false, |
||||
'headers' => [ |
||||
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', |
||||
//目前只能接受JSON的数据格式 |
||||
'Accept' => 'application/json', |
||||
//'referer' => $baseUrl, |
||||
'Cache-Control' => 'no-cache', |
||||
'accept-encoding' => 'gzip, deflate', |
||||
'accept-language' => 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7' |
||||
] |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* @var SignerHttpClient 签名客户端 |
||||
*/ |
||||
private ISigner $signClient; |
||||
|
||||
|
||||
/** |
||||
* @param string $method |
||||
* @param string $uri |
||||
* @param array|null $query |
||||
* @param array|null $body |
||||
* @param string $format |
||||
* |
||||
* @return Response |
||||
* @throws ApiException |
||||
* @throws BizException |
||||
* @throws SignException |
||||
*/ |
||||
function request(string $method, string $uri, ?array $query = [], ?array $body = [], string $format = 'form'): Response |
||||
{ |
||||
$options = $this->getRequestOptions(); |
||||
|
||||
if(!empty($query)) { |
||||
$options['query'] = array_filter($query, fn($v) => $v !== null); |
||||
} |
||||
//添加固定的参数 |
||||
//版本号 |
||||
if(empty($body['version'])) { |
||||
$body['version'] = $this->config['version'] ?? ''; |
||||
} |
||||
if(empty($body['mer_cust_id'])) { |
||||
$body['mer_cust_id'] = $this->config['mid'] ?? ''; |
||||
} |
||||
if(empty($body['bg_ret_url']) && !empty($this->config['callback'])) { |
||||
$body['bg_ret_url'] = $this->config['callback']; |
||||
} |
||||
|
||||
//将内容生成签名 |
||||
$sign = $this->signClient->sign($body); |
||||
$body['check_value'] = $sign; |
||||
|
||||
// echo '请求参数 #####'; |
||||
// print_r($body); |
||||
// echo '请求参数 end'; |
||||
if(empty($format)) { |
||||
$format = 'form'; |
||||
} |
||||
switch ($format) { |
||||
case 'json': |
||||
$options['json'] = array_filter($body, fn($v) => $v !== null); |
||||
break; |
||||
case 'form': |
||||
$options['form_params'] = array_filter($body, fn($v) => $v !== null); |
||||
break; |
||||
case 'body': |
||||
$options['body'] = array_filter($body, fn($v) => $v !== null); |
||||
break; |
||||
} |
||||
|
||||
try { |
||||
$resp = $this->client->request($method, $uri, $options); |
||||
} catch (GuzzleException $e) { |
||||
throw new ApiException($e->getMessage()); |
||||
} |
||||
$response = Response::make($resp); |
||||
|
||||
if(!$response->isSuccess()) { |
||||
throw new ApiException('汇付反馈状态不正确', $resp->getStatusCode()); |
||||
} |
||||
//验证数据 |
||||
$body = $response->getBody(); |
||||
if(!$this->signClient->verify($body)) { |
||||
throw new ApiException('签名验证未通过'); |
||||
} |
||||
//解码 |
||||
$decodeBody = $this->signClient->decode($body['check_value']); |
||||
ErrCodeHelper::parseError($decodeBody['resp_code'], $decodeBody['resp_desc']); |
||||
return Response::tempInit(200, $decodeBody); |
||||
} |
||||
|
||||
/** |
||||
* @param string $uri |
||||
* @param array|null $data |
||||
* |
||||
* @return Response |
||||
* @throws ApiException |
||||
* @throws BizException |
||||
* @throws SignException |
||||
*/ |
||||
function get(string $uri, ?array $data = []): Response |
||||
{ |
||||
return $this->request('GET', $uri, $data); |
||||
} |
||||
|
||||
/** |
||||
* @param string $uri |
||||
* @param array|null $data |
||||
* |
||||
* @return Response |
||||
* @throws ApiException |
||||
* @throws BizException |
||||
* @throws SignException |
||||
*/ |
||||
function post(string $uri, ?array $data = []): Response |
||||
{ |
||||
return $this->request('POST', $uri, [], $data, 'form'); |
||||
} |
||||
|
||||
/** |
||||
* @param string $uri |
||||
* @param array|null $data |
||||
* |
||||
* @return Response |
||||
* @throws ApiException |
||||
* @throws BizException |
||||
* @throws SignException |
||||
*/ |
||||
function patch(string $uri, ?array $data = []): Response |
||||
{ |
||||
return $this->request('PATCH', $uri, [], $data, 'body'); |
||||
} |
||||
|
||||
/** |
||||
* @param string $uri |
||||
* @param array|null $data |
||||
* |
||||
* @return Response |
||||
* @throws ApiException |
||||
* @throws BizException |
||||
* @throws SignException |
||||
*/ |
||||
function put(string $uri, ?array $data = []): Response |
||||
{ |
||||
return $this->request('PUT', $uri, [], $data, 'body'); |
||||
} |
||||
|
||||
/** |
||||
* @param string $uri |
||||
* @param array|null $data |
||||
* |
||||
* @return Response |
||||
* @throws ApiException |
||||
* @throws BizException |
||||
* @throws SignException |
||||
*/ |
||||
function delete(string $uri, ?array $data = []): Response |
||||
{ |
||||
return $this->request('DELETE', $uri, [], $data, 'body'); |
||||
} |
||||
|
||||
/** |
||||
* @param string $uri |
||||
* @param array|null $data |
||||
* @param bool $needToken |
||||
* |
||||
* @return Response |
||||
* @throws ApiException |
||||
* @throws BizException |
||||
* @throws SignException |
||||
*/ |
||||
function postJson(string $uri, ?array $data = [], bool $needToken = true): Response |
||||
{ |
||||
return $this->request('POST', $uri, [], $data, 'json', $needToken); |
||||
} |
||||
} |
||||
@ -0,0 +1,12 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\library; |
||||
|
||||
interface ISigner |
||||
{ |
||||
function sign(array $data): string; |
||||
|
||||
function verify(array $data): bool; |
||||
|
||||
function decode(string $data): array; |
||||
} |
||||
@ -0,0 +1,162 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\library\impl; |
||||
|
||||
use GuzzleHttp\Client; |
||||
use GuzzleHttp\Exception\GuzzleException; |
||||
use Tansilu\HfPayLib\exception\ApiException; |
||||
use Tansilu\HfPayLib\exception\BizException; |
||||
use Tansilu\HfPayLib\exception\SignException; |
||||
use Tansilu\HfPayLib\http\ErrCodeHelper; |
||||
use Tansilu\HfPayLib\http\Response; |
||||
use Tansilu\HfPayLib\library\ISigner; |
||||
|
||||
class SignerHttpClient implements ISigner |
||||
{ |
||||
|
||||
private Client $client; |
||||
|
||||
private string $pfxFileName; |
||||
private string $pfxFilePwd; |
||||
private string $certFile; |
||||
|
||||
public function __construct( |
||||
string $server, |
||||
string $pfxFileName, |
||||
string $pfxFilePwd, |
||||
string $certFile |
||||
) |
||||
{ |
||||
$this->pfxFileName = $pfxFileName; |
||||
$this->pfxFilePwd = $pfxFilePwd; |
||||
$this->certFile = $certFile; |
||||
$option = [ |
||||
'base_uri' => $server, |
||||
'connect_timeout' => 10, |
||||
'timeout' => 30, |
||||
'headers' => [ |
||||
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', |
||||
'Accept' => 'application/json', |
||||
//'referer' => $baseUrl, |
||||
'Cache-Control' => 'no-cache', |
||||
'accept-encoding' => 'gzip, deflate, br, zstd', |
||||
'accept-language' => 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7' |
||||
], |
||||
'allow_redirects' => [ |
||||
'max' => 3, |
||||
'track_redirects' => false, |
||||
'strict' => false, |
||||
], |
||||
]; |
||||
$this->client = new Client($option); |
||||
} |
||||
|
||||
private function getRequestOptions(): array |
||||
{ |
||||
return [ |
||||
'debug' => false, |
||||
//不抛出异常 |
||||
'http_errors' => false, |
||||
'headers' => [ |
||||
'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36', |
||||
//目前只能接受JSON的数据格式 |
||||
'Accept' => 'application/json', |
||||
//'referer' => $baseUrl, |
||||
'Cache-Control' => 'no-cache', |
||||
'accept-encoding' => 'gzip, deflate', |
||||
'accept-language' => 'zh-CN,zh;q=0.9,en;q=0.8,zh-TW;q=0.7' |
||||
] |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* 生成签名数据 |
||||
* |
||||
* @param array $data |
||||
* |
||||
* @return string |
||||
* @throws ApiException |
||||
* @throws BizException |
||||
* @throws SignException |
||||
*/ |
||||
function sign(array $data): string |
||||
{ |
||||
if(empty($data)) { |
||||
throw new SignException('待签名的数据不能为空'); |
||||
} |
||||
|
||||
$requestData = [ |
||||
'data' => json_encode([ |
||||
'pfx_file_name' => $this->pfxFileName, |
||||
'pfx_file_pwd' => $this->pfxFilePwd, |
||||
], JSON_UNESCAPED_UNICODE), |
||||
'params' => json_encode( |
||||
$data, |
||||
JSON_UNESCAPED_UNICODE |
||||
), |
||||
]; |
||||
$options = $this->getRequestOptions(); |
||||
$options['form_params'] = $requestData; |
||||
|
||||
try { |
||||
$result = $this->client->post('/hfpcfca/cfca/makeSign', $options); |
||||
$response = Response::make($result); |
||||
if(!$response->isSuccess()) { |
||||
throw new SignException('签名请求失败,请检查签名服务器 ' . $response->getCode()); |
||||
} |
||||
$body = $response->getBody(); |
||||
//处理错误码 |
||||
ErrCodeHelper::parseError($body['resp_code'], $body['resp_desc']); |
||||
if(empty($body['check_value'])) { |
||||
throw new SignException('签名服务器未反馈任何签名数据'); |
||||
} |
||||
return $body['check_value']; |
||||
} catch (GuzzleException $e) { |
||||
throw new SignException('签名服务不可用' . $e->getMessage()); |
||||
} |
||||
} |
||||
|
||||
function verify(array $data): bool |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* 解码 |
||||
* |
||||
* @param string $data |
||||
* |
||||
* @return array |
||||
* @throws BizException |
||||
* @throws SignException |
||||
* @throws ApiException |
||||
*/ |
||||
function decode(string $data): array |
||||
{ |
||||
$requestData = [ |
||||
'params' => json_encode([ |
||||
'check_value' => $data, |
||||
'cert_file' => $this->certFile |
||||
], JSON_UNESCAPED_UNICODE), |
||||
]; |
||||
|
||||
$options = $this->getRequestOptions(); |
||||
$options['form_params'] = $requestData; |
||||
|
||||
try { |
||||
$resp = $this->client->post('/hfpcfca/cfca/verifySign', $options); |
||||
} catch (GuzzleException $e) { |
||||
throw new ApiException('签名服务器请求失败 ' . $e->getMessage()); |
||||
} |
||||
$response = Response::make($resp); |
||||
if(!$response->isSuccess()) { |
||||
throw new SignException('签名检查请求失败,请检查签名服务器'); |
||||
} |
||||
$body = $response->getBody(); |
||||
ErrCodeHelper::parseError($body['resp_code'], $body['resp_desc']); |
||||
if(empty($body['params'])) { |
||||
return []; |
||||
} |
||||
return json_decode($body['params'], true); |
||||
} |
||||
} |
||||
@ -0,0 +1,34 @@ |
||||
<?php |
||||
|
||||
namespace Tansilu\HfPayLib\utils; |
||||
|
||||
use Tansilu\HfPayLib\exception\ParamsException; |
||||
|
||||
class StrFilterHelper |
||||
{ |
||||
public static function fileUrl(string $url): string |
||||
{ |
||||
$disableWord = [ |
||||
'recv', |
||||
'rbsmag', |
||||
'cashmag', |
||||
'cash', |
||||
'ubs', |
||||
'acctmag', |
||||
'buser', |
||||
'busermag', |
||||
'mtp', |
||||
'mtpmag', |
||||
'muser', |
||||
'musermag', |
||||
'ubsmag', |
||||
'mag' |
||||
]; |
||||
foreach ($disableWord as $word) { |
||||
if(strpos($url, $word) !== false) { |
||||
throw new ParamsException('URL中存在禁用的字符' . $word, 'DISABLED_STRING'); |
||||
} |
||||
} |
||||
return $url; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue