作者 竞泽

add

敏付(第三方清关)
===
### install
```
composer require lackoxygen/min-payment
```
### git
```
http://47.107.73.162:8099/lackoxygen/min-payment.git
```
### 配置仓库
```
{
"type": "git",
"url": "http://47.107.73.162:8099/lackoxygen/min-payment.git"
}
```
### 配置文件
```
发布暂时无法生成,手动copy到config
```
### 示例
```
$min = new MinPayment();
$ret = $min->identifyOrder(function (IdentifyOrder $realNameAuth) {
$realNameAuth->setName('hello');
$realNameAuth->setCid('5234235345x');
$realNameAuth->setOrderNo('2123');
$realNameAuth->setType(1);
});
var_dump($ret->isSuccess());
```
... ...
{
"name": "root/min-payment",
"type": "library",
"description": "敏付",
"license": "MIT",
"authors": [
{
"name": "jz",
"email": "jingzeou@outlook.com"
}
],
"require": {
"php": ">=7.1",
"illuminate/support": "^5.8"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"autoload": {
"psr-4": {
"Lackoxygen\\MinPayment\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"Lackoxygen\\MinPayment\\MinPaymentProvider"
]
}
}
}
... ...
<?php
return [
'merchant_id' => '',
'secret' => '',
'version' => '',
'options' => [
'client' => [
'base_uri' => 'https://openapi.minfupay.cn',
'time' => 30,
],
'retry' => 1
]
];
... ...
<?php
namespace Lackoxygen\MinPayment\Constant;
use Illuminate\Support\Arr;
class Status
{
public const SUCCESS = '00';
public static $constants = [
'00' => '操作成功',
'1007' => '缺少必要信息或参数格式不符合',
'1043' => '异常提交',
'1009' => '签名错误',
'1008' => '商户状态异常或配置错误',
'1004' => '商户不存在',
'1403' => '业务未开通或业务状态非正常',
'1503' => '系统未开启该业务或未被支持',
'1019' => '余额不足',
'1021' => '账户状态非正常',
'1020' => '扣款失败',
'1024' => '账户不存在',
'1010' => '系统异常',
'1018' => '订单支付信息异常(支付人实名认证信息与订单不匹配或实名认证未通过)',
'1011' => '身份验证异常',
'1015' => '订单已存在',
'1014' => '申报订单不存在',
'1001' => '证件号码与姓名一致',
'1002' => '证件号码与姓名不一致',
'1003' => '身份验证异常(网络原因可重新发起)'
];
/**
* @param string $code
* @param string $default
*
* @return array|\ArrayAccess|mixed
*/
public static function translation(string $code, string $default = '')
{
return Arr::get(self::$constants, $code, $default);
}
}
... ...
<?php
namespace Lackoxygen\MinPayment\Contract;
interface ResponseInterface
{
/**
* @return bool
*/
public function isSuccess(): bool;
/**
* @return array
*/
public function toArray(): array;
/**
* @return string
*/
public function toString(): string;
/**
* @return string
*/
public function getContent(): string;
}
... ...
<?php
namespace Lackoxygen\MinPayment\Exception;
class Exception extends \Exception
{
}
... ...
<?php
namespace Lackoxygen\MinPayment;
use Lackoxygen\MinPayment\Contract\ResponseInterface;
use Lackoxygen\MinPayment\Request\CustomsOrder;
use Lackoxygen\MinPayment\Request\CustomsQuery;
use Lackoxygen\MinPayment\Request\IdentifyOrder;
use Lackoxygen\MinPayment\Utils\Client;
use Lackoxygen\MinPayment\Utils\Signature;
class MinPayment
{
/**
* @var Client $client
*/
protected $client;
public function __construct(array $config = [])
{
$this->client = new Client($config + (array)\config('min-payment'));
}
/**
* @param callable $options
*
* @return ResponseInterface
* @throws Exception\Exception
*/
public function identifyOrder(callable $options): ResponseInterface
{
$identifyOrder = new IdentifyOrder;
$options(new IdentifyOrder);
$client = $this->client;
return $client($identifyOrder);
}
/**
* @param callable $options
*
* @return ResponseInterface
* @throws Exception\Exception
*/
public function customsOrder(callable $options): ResponseInterface
{
$customsOrder = new CustomsOrder;
$options($customsOrder);
$client = $this->client;
return $client($customsOrder);
}
/**
* @param callable $options
*
* @return ResponseInterface
* @throws Exception\Exception
*/
public function customsQuery(callable $options): ResponseInterface
{
$customsQuery = new CustomsQuery;
$options($customsQuery);
$client = $this->client;
return $client($customsQuery);
}
/**
* @param array $input
* @param string $signName
*
* @return bool
*/
public function verify(array $input, string $signName = 'sign'): bool
{
$sign = \Arr::get($input, $signName);
unset($input[$signName]);
return Signature::make($input) === $sign;
}
}
... ...
<?php
namespace Lackoxygen\MinPayment;
use Illuminate\Support\ServiceProvider;
class MinPaymentProvider extends ServiceProvider
{
public function boot()
{
$configPath = __DIR__ . '/../config/min-payment.php';
$this->publishes([$configPath => config_path('min-payment.php')], 'lackoxygen');
}
/**
* @return string[]
*/
public function provides()
{
return ['minPayment', MinPayment::class];
}
}
... ...
<?php
namespace Lackoxygen\MinPayment\Request;
class CustomsOrder extends Request
{
/**
* @var string
*/
private $appType;
/**
* @var string
*/
private $customsType;
/**
* @var string
*/
private $payTransactionId;
/**
* @var string
*/
private $orderNo;
/**
* @var string
*/
private $ebpCode;
/**
* @var string
*/
private $ebpName;
/**
* @var string
*/
private $payerIdNumber;
/**
* @var string
*/
private $payerName;
/**
* @var string
*/
private $telephone;
/**
* @var string
*/
private $amountPaid;
/**
* @var string
*/
private $payTime;
/**
* @var string
*/
private $note;
/**
* @var string
*/
private $commodityName;
/**
* @var string
*/
private $commodityDetails;
/**
* @var string
*/
private $isSplit;
/**
* @var string
*/
private $subOrderNo;
/**
* @var string
*/
private $productType;
/**
* @var string
*/
private $logisticsCompany;
/**
* @var string
*/
private $logisticsNumber;
public function __construct()
{
$this->service = 'service.customsOrder';
}
/**
* @param string $appType
*/
public function setAppType(string $appType): void
{
$this->appType = $appType;
}
/**
* @param string $customsType
*/
public function setCustomsType(string $customsType): void
{
$this->customsType = $customsType;
}
/**
* @param string $payTransactionId
*/
public function setPayTransactionId(string $payTransactionId): void
{
$this->payTransactionId = $payTransactionId;
}
/**
* @param string $orderNo
*/
public function setOrderNo(string $orderNo): void
{
$this->orderNo = $orderNo;
}
/**
* @param string $ebpCode
*/
public function setEbpCode(string $ebpCode): void
{
$this->ebpCode = $ebpCode;
}
/**
* @param string $ebpName
*/
public function setEbpName(string $ebpName): void
{
$this->ebpName = $ebpName;
}
/**
* @param string $payerIdNumber
*/
public function setPayerIdNumber(string $payerIdNumber): void
{
$this->payerIdNumber = $payerIdNumber;
}
/**
* @param string $payerName
*/
public function setPayerName(string $payerName): void
{
$this->payerName = $payerName;
}
/**
* @param string $telephone
*/
public function setTelephone(string $telephone): void
{
$this->telephone = $telephone;
}
/**
* @param string $amountPaid
*/
public function setAmountPaid(string $amountPaid): void
{
$this->amountPaid = $amountPaid;
}
/**
* @param string $payTime
*/
public function setPayTime(string $payTime): void
{
$this->payTime = $payTime;
}
/**
* @param string $note
*/
public function setNote(string $note): void
{
$this->note = $note;
}
/**
* @param string $commodityName
*/
public function setCommodityName(string $commodityName): void
{
$this->commodityName = $commodityName;
}
/**
* @param string $commodityDetails
*/
public function setCommodityDetails(string $commodityDetails): void
{
$this->commodityDetails = $commodityDetails;
}
/**
* @param string $isSplit
*/
public function setIsSplit(string $isSplit): void
{
$this->isSplit = $isSplit;
}
/**
* @param string $subOrderNo
*/
public function setSubOrderNo(string $subOrderNo): void
{
$this->subOrderNo = $subOrderNo;
}
/**
* @param string $productType
*/
public function setProductType(string $productType): void
{
$this->productType = $productType;
}
/**
* @param string $logisticsCompany
*/
public function setLogisticsCompany(string $logisticsCompany): void
{
$this->logisticsCompany = $logisticsCompany;
}
/**
* @param string $logisticsNumber
*/
public function setLogisticsNumber(string $logisticsNumber): void
{
$this->logisticsNumber = $logisticsNumber;
}
}
... ...
<?php
namespace Lackoxygen\MinPayment\Request;
class CustomsQuery extends Request
{
/**
* @var string
*/
private $appType;
/**
* @var string
*/
private $customsType;
/**
* @var string
*/
private $payTransactionId;
/**
* @var string
*/
private $orderNo;
/**
* @var string
*/
private $subOrderNo;
/**
* @var string
*/
private $subPayTransactionId;
/**
* @param mixed $appType
*/
public function setAppType($appType): void
{
$this->appType = $appType;
}
/**
* @param mixed $customsType
*/
public function setCustomsType($customsType): void
{
$this->customsType = $customsType;
}
/**
* @param mixed $payTransactionId
*/
public function setPayTransactionId($payTransactionId): void
{
$this->payTransactionId = $payTransactionId;
}
/**
* @param mixed $orderNo
*/
public function setOrderNo($orderNo): void
{
$this->orderNo = $orderNo;
}
/**
* @param mixed $subOrderNo
*/
public function setSubOrderNo($subOrderNo): void
{
$this->subOrderNo = $subOrderNo;
}
/**
* @param mixed $subPayTransactionId
*/
public function setSubPayTransactionId($subPayTransactionId): void
{
$this->subPayTransactionId = $subPayTransactionId;
}
}
... ...
<?php
namespace Lackoxygen\MinPayment\Request;
class IdentifyOrder extends Request
{
/**
* @var string
*/
protected $name;
/**
* @var string
*/
protected $cid;
/**
* @var string
*/
protected $orderNo;
/**
* @var string
*/
protected $type;
public function __construct()
{
$this->service = 'service.identifyOrder';
}
/**
* @param mixed $name
*/
public function setName(string $name): void
{
$this->name = $name;
}
/**
* @param mixed $cid
*/
public function setCid(string $cid): void
{
$suffix = substr($cid, -1, 1);
if (ord($suffix) === 120) {
$cid[strlen($cid) - 1] = chr(88);
}
$this->cid = $cid;
}
/**
* @param mixed $orderNo
*/
public function setOrderNo(string $orderNo): void
{
$this->orderNo = $orderNo;
}
/**
* @param mixed $type
*/
public function setType(string $type): void
{
$this->type = $type;
}
}
... ...
<?php
namespace Lackoxygen\MinPayment\Request;
use GuzzleHttp\RequestOptions;
use Illuminate\Support\Arr;
use Lackoxygen\MinPayment\Utils\Signature;
use ReflectionProperty;
class Request
{
/**
* @var string
*/
protected $mchtId;
/**
* @var string
*/
protected $service;
/**
* @var string
*/
protected $ver;
/**
* @var string
*/
protected $token;
/**
* @return string
*/
public function getMethod(): string
{
return 'POST';
}
/**
* @return string
*/
public function getPath(): string
{
return 'Gateway';
}
/**
* @return string
*/
public function getOption(): string
{
return RequestOptions::JSON;
}
/**
* @param array $config
*
* @return array
*/
public function __invoke(array $config = []): array
{
$this->paddingHead($config);
$body = $this->extract();
$this->signature($body);
return $body;
}
private function signature(&$body)
{
$body['sign'] = Signature::make($body);
}
private function paddingHead(array $config)
{
$this->mchtId = Arr::get($config, 'merchant_id');
$this->token = Signature::encode(microtime(true) . uniqid(''));
$this->ver = Arr::get($config, 'version', 'V3.1');
}
/**
* @return array
*/
private function extract(): array
{
$propertiesArray = [];
$ref = new \ReflectionClass($this);
$properties = $ref->getProperties(ReflectionProperty::IS_PRIVATE | ReflectionProperty::IS_PROTECTED);
foreach ($properties as $property) {
$property->setAccessible(true);
$propertiesArray[$property->getName()] = $property->getValue($this);
}
return $propertiesArray;
}
}
... ...
<?php
namespace Lackoxygen\MinPayment;
use Lackoxygen\MinPayment\Constant\Status;
use Lackoxygen\MinPayment\Contract\ResponseInterface;
use Psr\Http\Message\ResponseInterface as PsrResponseInterface;
class Response implements ResponseInterface
{
/**
* @var PsrResponseInterface $response
*/
protected $response;
/**
* @param PsrResponseInterface $response
*/
public function __construct(PsrResponseInterface $response)
{
$this->response = $response;
}
/**
* @return bool
*/
public function isSuccess(): bool
{
return Status::SUCCESS === (string)\Arr::get($this->toArray(), 'code');
}
/**
* @return array
*/
public function toArray(): array
{
return (array)\json_decode($this->getContent(), true);
}
/**
* @return string
*/
public function toString(): string
{
return $this->getContent();
}
/**
* @return string
*/
public function getContent(): string
{
static $content = null;
if (is_null($content)) {
$this->response->getBody()->rewind();
$content = $this->response->getBody()->getContents();
}
return $content;
}
}
... ...
<?php
namespace Lackoxygen\MinPayment\Utils;
use GuzzleHttp\Exception\ConnectException;
use GuzzleHttp\Exception\GuzzleException;
use Lackoxygen\MinPayment\Exception\Exception;
use Lackoxygen\MinPayment\Request\Request;
use Lackoxygen\MinPayment\Response;
class Client
{
/**
* @var Request $request
*/
protected $request;
/**
* @var array $config
*/
protected $config = [];
/**
* @param array $config
*/
public function __construct(array $config)
{
$this->config = $config;
}
/**
* @param Request $request
*
* @return Response
* @throws Exception
*/
public function __invoke(Request $request)
{
$this->request = $request;
$body = $request($this->config);
return $this->send($body);
}
/**
* @param array $body
*
* @return Response
* @throws Exception
*/
protected function send(array $body)
{
$client = new \GuzzleHttp\Client(\Arr::get($this->config, 'options.client'));
$retries = (int)\Arr::get($this->config, 'retry');
$retry = 0;
do {
try {
$response = $client->request($this->request->getMethod(), $this->request->getPath(), [
$this->request->getOption() => $body
]);
return new Response($response);
} catch (GuzzleException $e) {
throw new Exception($e);
}
} while ($retry++ < $retries);
}
}
... ...
<?php
namespace Lackoxygen\MinPayment\Utils;
class Signature
{
/**
* @var array $item
*/
protected $item = [];
protected function __construct(array $item)
{
$this->item = $item;
}
public static function make(array $items): string
{
$signature = new self($items);
return $signature->toString();
}
protected function sortByASCII()
{
$item = &$this->item;
ksort($item);
}
/**
* @param array $item
* @param callable $filter
*
* @return string
*/
protected function map(array $item, callable $filter): string
{
$array = [];
foreach ($item as $key => $value) {
if ($filter($key, $value) !== false) {
$array[] = $key . '=' . $value;
}
}
return join($array, '&');
}
/**
* @param string $string
*
* @return string
*/
public static function encode(string $string): string
{
return strtoupper(md5($string));
}
/**
* @return string
*/
protected function toString(): string
{
$this->sortByASCII();
$string = $this->map($this->item, function ($k, $v) {
return !($v === '' || $v === null);
});
return self::encode($string);
}
}
... ...