efps-version
elf 2 years ago
parent ed77841a57
commit 6275f594cb

@ -1,13 +1,14 @@
<?php <?php
$header = <<<'EOF' declare(strict_types=1);
This file is part of Hyperf. /**
* This file is part of Hyperf.
@link https://www.hyperf.io *
@document https://hyperf.wiki * @link https://www.hyperf.io
@contact group@hyperf.io * @document https://hyperf.wiki
@license https://github.com/hyperf/hyperf/blob/master/LICENSE * @contact group@hyperf.io
EOF; * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return (new PhpCsFixer\Config()) return (new PhpCsFixer\Config())
->setRiskyAllowed(true) ->setRiskyAllowed(true)
@ -17,19 +18,17 @@ return (new PhpCsFixer\Config())
'@DoctrineAnnotation' => true, '@DoctrineAnnotation' => true,
'@PhpCsFixer' => true, '@PhpCsFixer' => true,
'header_comment' => [ 'header_comment' => [
'comment_type' => 'PHPDoc',
'header' => $header,
'separate' => 'none', 'separate' => 'none',
'location' => 'after_declare_strict', 'location' => 'after_declare_strict',
], ],
'array_syntax' => [ 'array_syntax' => [
'syntax' => 'short' 'syntax' => 'short',
], ],
'list_syntax' => [ 'list_syntax' => [
'syntax' => 'short' 'syntax' => 'short',
], ],
'concat_space' => [ 'concat_space' => [
'spacing' => 'one' 'spacing' => 'one',
], ],
'blank_line_before_statement' => [ 'blank_line_before_statement' => [
'statements' => [ 'statements' => [
@ -38,7 +37,7 @@ return (new PhpCsFixer\Config())
], ],
'general_phpdoc_annotation_remove' => [ 'general_phpdoc_annotation_remove' => [
'annotations' => [ 'annotations' => [
'author' 'author',
], ],
], ],
'ordered_imports' => [ 'ordered_imports' => [

@ -9,8 +9,8 @@ use App\Service\AppService;
use App\Service\MerchantService; use App\Service\MerchantService;
use App\Service\PaymentService; use App\Service\PaymentService;
use Hyperf\Command\Command as HyperfCommand; use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
use Hyperf\Contract\ContainerInterface; use Hyperf\Contract\ContainerInterface;
use Hyperf\Command\Annotation\Command;
/** /**
* @Command * @Command
@ -31,16 +31,16 @@ class JinlingCommand extends HyperfCommand
parent::__construct('jinling'); parent::__construct('jinling');
} }
public function configure() public function configure(): void
{ {
parent::configure(); parent::configure();
$this->setDescription('廖金灵测试'); $this->setDescription('廖金灵测试');
} }
public function handle() public function handle(): void
{ {
/** /**
* @var PaymentService * @var PaymentService $paymentService
*/ */
$paymentService = $this->container->make(PaymentService::class); $paymentService = $this->container->make(PaymentService::class);
$paramsJson = '{"return_code":"SUCCESS","nonce_str":"4a40481401bb47cc81411ab3a8181bad","timestamp":1682659313039,"sign":"5AD859576B783CB44D1FAA0E7DD4C463","order_no":"TR23042830042195760003775","out_order_no":"2023042813194700001","total_amount":2,"currency":"AUD","order_time":"20230428151948","pay_time":"20230428152021","exchange_rate":459899100,"cny_amount":9}'; $paramsJson = '{"return_code":"SUCCESS","nonce_str":"4a40481401bb47cc81411ab3a8181bad","timestamp":1682659313039,"sign":"5AD859576B783CB44D1FAA0E7DD4C463","order_no":"TR23042830042195760003775","out_order_no":"2023042813194700001","total_amount":2,"currency":"AUD","order_time":"20230428151948","pay_time":"20230428152021","exchange_rate":459899100,"cny_amount":9}';
@ -51,12 +51,12 @@ class JinlingCommand extends HyperfCommand
$this->buildPayPrams(); $this->buildPayPrams();
return; return;
/** /**
* @var MerchantService * @var MerchantService $merchantService
*/ */
$merchantService = $this->container->make(MerchantService::class); $merchantService = $this->container->make(MerchantService::class);
/** /**
* @var AppService * @var AppService $appService
*/ */
$appService = $this->container->make(AppService::class); $appService = $this->container->make(AppService::class);
$merchant = $merchantService->createMerchant([ $merchant = $merchantService->createMerchant([
@ -64,12 +64,13 @@ class JinlingCommand extends HyperfCommand
'password' => '123456', 'password' => '123456',
'email' => '360197197@qq.com', 'email' => '360197197@qq.com',
'mobile' => '18760419185', 'mobile' => '18760419185',
'ip' => '127.0.0.1' 'ip' => '127.0.0.1',
]); ]);
$appService->createApp($merchant); $appService->createApp($merchant);
} }
public function buildPayPrams() { public function buildPayPrams(): void
{
$params = [ $params = [
'app_id' => '202304270000004', 'app_id' => '202304270000004',
'timestamp' => time(), 'timestamp' => time(),
@ -79,8 +80,8 @@ class JinlingCommand extends HyperfCommand
'order_name' => '测试订单', 'order_name' => '测试订单',
'currency' => 'CNY', 'currency' => 'CNY',
'amount' => '10', 'amount' => '10',
'notify_url' => 'http://www.baidu.com', 'notify_url' => 'https://www.baidu.com',
'redirect_url' => 'http://www.google.com', 'redirect_url' => 'https://www.google.com',
'out_order_no' => '1122', 'out_order_no' => '1122',
'direct_pay' => 0, 'direct_pay' => 0,
'show_pc_pay_url' => 0, 'show_pc_pay_url' => 0,

@ -4,8 +4,8 @@ declare(strict_types=1);
namespace App\Controller\Payment; namespace App\Controller\Payment;
use Hyperf\HttpServer\Contract\RequestInterface;
use App\Service\PaymentService; use App\Service\PaymentService;
use Hyperf\HttpServer\Contract\RequestInterface;
class NotifyController extends AbstractController class NotifyController extends AbstractController
{ {
@ -21,4 +21,9 @@ class NotifyController extends AbstractController
$params = $request->all(); $params = $request->all();
return $this->paymentService->notify($params); return $this->paymentService->notify($params);
} }
public function efps(RequestInterface $request) {
$params = $request->all();
return $this->paymentService->efpsNotify($params);
}
} }

@ -1,14 +1,21 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace App\Controller\Payment; namespace App\Controller\Payment;
use App\Helper\Log; use App\Helper\Log;
use App\Model\Order; use App\Model\Order;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface; use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Http\Message\ResponseInterface as Psr7ResponseInterface; use Psr\Http\Message\ResponseInterface as Psr7ResponseInterface;
use Hyperf\HttpServer\Contract\RequestInterface;
class PageController extends AbstractController class PageController extends AbstractController
{ {
@ -16,11 +23,11 @@ class PageController extends AbstractController
{ {
$orderNo = $request->input('order_no', ''); $orderNo = $request->input('order_no', '');
Log::info('redirectToOut orderNo:' . $orderNo, [], 'omipay'); Log::info('redirectToOut orderNo:' . $orderNo, [], 'omipay');
if (!$orderNo) { if (! $orderNo) {
return '订单号错误'; return '订单号错误';
} }
$order = Order::where('order_no', $orderNo)->first(); $order = Order::where('order_no', $orderNo)->first();
if (!$order) { if (! $order) {
return '订单号错误'; return '订单号错误';
} }
Log::info('redirectToOut url:' . $order->redirect_url, [], 'omipay'); Log::info('redirectToOut url:' . $order->redirect_url, [], 'omipay');

@ -26,4 +26,14 @@ class PayController extends AbstractController
'order_no' => $order->order_no, 'order_no' => $order->order_no,
]); ]);
} }
public function unified()
{
$payRequest = new JsapiPayRequest($request->all());
$order = $this->paymentService->jsapiPay($payRequest->getApp(), $payRequest->getData());
return $this->success([
'pay_url' => $order->pay_url,
'order_no' => $order->order_no,
]);
}
} }

@ -0,0 +1,86 @@
<?php
namespace App\Helper\Efps;
use App\Helper\Log;
use App\Helper\StringHelper;
use App\Helper\TimeHelper;
use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use Hyperf\Guzzle\CoroutineHandler;
abstract class AbstractApi
{
protected static $client;
protected static function getCommonParams() {
$params = [
'm_number' => Config::get('app_id'),
'timestamp' => TimeHelper::getMillisecond(),
'nonce_str' => StringHelper::getRandomString(32),
];
$params['sign'] = Signer::sign($params);
return $params;
}
public static function request(AbstractRequest $request) {
$params = self::getCommonParams();
$params = array_merge($params, $request->getParams());
try {
Log::info('url:' . $request->getUrl(), [], 'omipay');
$response = self::getClient()->post($request->getUrl(), [
'query' => $params
]);
Log::info('request:', $params, 'omipay');
$body = (string)$response->getBody();
Log::info('response:' . $body, [], 'omipay');
$result = json_decode($body, true);
if (empty($result)) {
$result = [
'return_code' => 'FAIL',
'error_code' => 'RESPONSE_ERROR',
'error_msg' => '返回数据异常',
];
}
return new Result($result);
} catch (Exception $e) {
Log::error('error:' . $e->getMessage(), [], 'omipay');
return new Result([
'return_code' => 'FAIL',
'error_code' => 'NETWORK_ERROR',
'error_msg' => '网络错误',
]);
}
}
protected static function getClient(): Client {
if (!self::$client) {
self::$client = new Client([
'base_uri' => Config::get('base_url'),
'handler' => HandlerStack::create(new CoroutineHandler()),
'headers' => [
'Content-Type' => 'application/json',
],
'timeout' => 5,
'swoole' => [
'timeout' => 10,
'socket_buffer_size' => 1024 * 1024 * 2,
],
]);
}
return self::$client;
}
protected static function getHeaders($sign, $encKey, $timestamp)
{
return [
'x-efps-sign-no' => '',
'x-efps-sign-type' => 'RSAwithSHA256',
'x-efps-sign' => $sign,
'x-efps-timestamp' => $timestamp,
'x-efps-version' => '2.0',
'x-efps-enc-key' => $encKey,
]
}
}

@ -0,0 +1,21 @@
<?php
namespace App\Helper\Efps;
use App\Helper\Efps\Request\UnifiedPaymentRequest;
class Api
{
public static function unifiedPayment($outTradeNo, $orderInfo, $payAmount, $notifyUrl, $redirectUrl)
{
$request = new UnifiedPaymentRequest();
$request->setVersion('3.0');
$request->setOutTradeNo($outTradeNo);
$request->setOrderInfo($orderInfo);
$request->setPayAmount($payAmount);
$request->setNotifyUrl($notifyUrl);
$request->setRedirectUrl($redirectUrl);
return self::request($request);
}
}

@ -0,0 +1,16 @@
<?php
namespace App\Helper\Efps;
class Config
{
private static $params = [
'app_id' => '',
'secret_key' => 'cea6f34bea8640dea91fd8b7a926a9a5',
'base_url' => 'https://efps.epylinks.cn',
];
public static function get($key) {
return self::$params[$key] ?: null;
}
}

@ -0,0 +1,18 @@
<?php
namespace App\Helper\Efps;
class PayNotify
{
private $params;
public function __construct($params)
{
$this->params = $params;
}
public function get($key, $default = null)
{
return $this->params[$key] ?: $default;
}
}

@ -0,0 +1,32 @@
<?php
namespace App\Helper\Efps\Request;
use App\Helper\Efps\Config;
class AbstractRequest
{
protected $uri;
protected $method;
protected $_params = [];
public function getUrl() {
return Config::get('base_url') . $this->uri;
}
public function getParams() {
return $this->_params;
}
public function __get($name)
{
return $this->_params[$name];
}
public function __set($name, $value)
{
$this->_params[$name] = $value;
}
}

@ -0,0 +1,216 @@
<?php
namespace App\Helper\Efps\Request;
class UnifiedPaymentRequest extends AbstractRequest
{
protected $uri = '/api/txs/pay/UnifiedPayment';
/**
* @param mixed $version
*/
public function setVersion($version): void
{
$this->version = $version;
}
/**
* @param mixed $outTradeNo
*/
public function setOutTradeNo($outTradeNo): void
{
$this->outTradeNo = $outTradeNo;
}
/**
* @param mixed $customerCode
*/
public function setCustomerCode($customerCode): void
{
$this->customerCode = $customerCode;
}
/**
* @param mixed $clientIp
*/
public function setClientIp($clientIp): void
{
$this->clientIp = $clientIp;
}
/**
* @param mixed $orderInfo
*/
public function setOrderInfo($orderInfo): void
{
$this->orderInfo = $orderInfo;
}
/**
* @param mixed $payAmount
*/
public function setPayAmount($payAmount): void
{
$this->payAmount = $payAmount;
}
/**
* @param mixed $payCurrency
*/
public function setPayCurrency($payCurrency): void
{
$this->payCurrency = $payCurrency;
}
/**
* @param mixed $noCreditCards
*/
public function setNoCreditCards($noCreditCards): void
{
$this->noCreditCards = $noCreditCards;
}
/**
* @param mixed $notifyUrl
*/
public function setNotifyUrl($notifyUrl): void
{
$this->notifyUrl = $notifyUrl;
}
/**
* @param mixed $redirectUrl
*/
public function setRedirectUrl($redirectUrl): void
{
$this->redirectUrl = $redirectUrl;
}
/**
* @param mixed $attachData
*/
public function setAttachData($attachData): void
{
$this->attachData = $attachData;
}
/**
* @param mixed $transactionStartTime
*/
public function setTransactionStartTime($transactionStartTime): void
{
$this->transactionStartTime = $transactionStartTime;
}
/**
* @param mixed $transactionEndTime
*/
public function setTransactionEndTime($transactionEndTime): void
{
$this->transactionEndTime = $transactionEndTime;
}
/**
* @param mixed $payMethod
*/
public function setPayMethod($payMethod): void
{
$this->payMethod = $payMethod;
}
/**
* @param mixed $subAppId
*/
public function setSubAppId($subAppId): void
{
$this->subAppId = $subAppId;
}
/**
* @param mixed $channelMchtNo
*/
public function setChannelMchtNo($channelMchtNo): void
{
$this->channelMchtNo = $channelMchtNo;
}
/**
* @param mixed $enablePayChannels
*/
public function setEnablePayChannels($enablePayChannels): void
{
$this->enablePayChannels = $enablePayChannels;
}
/**
* @param mixed $instalmentsNum
*/
public function setInstalmentsNum($instalmentsNum): void
{
$this->instalmentsNum = $instalmentsNum;
}
/**
* @param mixed $storeId
*/
public function setStoreId($storeId): void
{
$this->storeId = $storeId;
}
/**
* @param mixed $alipayStoreId
*/
public function setAlipayStoreId($alipayStoreId): void
{
$this->alipayStoreId = $alipayStoreId;
}
/**
* @param mixed $extUserInfo
*/
public function setExtUserInfo($extUserInfo): void
{
$this->extUserInfo = $extUserInfo;
}
/**
* @param mixed $terminalInfo
*/
public function setTerminalInfo($terminalInfo): void
{
$this->terminalInfo = $terminalInfo;
}
/**
* @param mixed $areaInfo
*/
public function setAreaInfo($areaInfo): void
{
$this->areaInfo = $areaInfo;
}
/**
* @param mixed $extendParams
*/
public function setExtendParams($extendParams): void
{
$this->extendParams = $extendParams;
}
/**
* @param mixed $coupons
*/
public function setCoupons($coupons): void
{
$this->coupons = $coupons;
}
/**
* @param mixed $nonceStr
*/
public function setNonceStr($nonceStr): void
{
$this->nonceStr = $nonceStr;
}
}

@ -0,0 +1,32 @@
<?php
namespace App\Helper\Efps;
class Signer
{
public static function sign($content, $privateKey)
{
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap($privateKey, 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----";
$key = openssl_get_privatekey($privateKey);
// openssl_private_encrypt($content, $signature, $privateKey, OPENSSL_PKCS1_PADDING);
openssl_sign($content, $signature, $key, OPENSSL_ALGO_SHA256);
openssl_free_key($key);
return base64_encode($signature);
}
public function verify($content, $sign, $publicKey){
$publicKey = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap($publicKey, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
$key = openssl_get_publickey($publicKey);
$ok = openssl_verify($content, base64_decode($sign), $key, 'SHA256');
openssl_free_key($key);
return $ok;
}
}

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace App\Service; namespace App\Service;
use App\Exception\BusinessException; use App\Exception\BusinessException;
use App\Helper\Efps\PayNotify;
use App\Helper\Log; use App\Helper\Log;
use App\Helper\OmiPay\Api; use App\Helper\OmiPay\Api;
use App\Helper\OmiPay\Result; use App\Helper\OmiPay\Result;
@ -94,16 +95,41 @@ class PaymentService extends AbstractService
if ($params['return_code'] != 'SUCCESS') { if ($params['return_code'] != 'SUCCESS') {
return 'STATUS FAIL'; return 'STATUS FAIL';
} }
$params = [
'order_no' => $params['out_order_no'],
'cny_amount' => $params['cny_amount'],
'exchange_rage' => $params['exchange_rage'],
];
return $this->handleNotify($params);
}
public function efpsNotify($params) {
Log::info('notify:', $params, 'omipay');
if (!Signer::verify($params)) {
return 'SIGN FAIL';
}
if ($params['return_code'] != 'SUCCESS') {
return 'STATUS FAIL';
}
$params = [
'order_no' => $params['outTradeNo'],
$order = Order::where('order_no', $params['out_order_no'])->where('status', Order::STATUS_WAIT_PAY)->first(); ];
return $this->handleNotify($params);
}
private function handleNotify($params) {
$order = Order::where('order_no', $params['order_no'] ?: '')
->where('status', Order::STATUS_WAIT_PAY)
->first();
if (!$order) { if (!$order) {
return 'ORDER FAIL'; return 'ORDER FAIL';
} }
$app = App::where('app_id', $order->app_id)->first(); $app = App::where('app_id', $order->app_id)->first();
$order->status = Order::STATUS_PAYED; $order->status = Order::STATUS_PAYED;
$order->payed_at = date('Y-m-d H:i:s'); $order->payed_at = date('Y-m-d H:i:s');
$order->exchange_rate = $params['exchange_rate'] ?: 0; $order->exchange_rate = $params['exchange_rate'] ?: 1;
$order->cny_amount = $params['cny_amount'] ?: 0; $order->cny_amount = $params['cny_amount'] ?: $order->amount;
if (!$order->save()) { if (!$order->save()) {
return 'NOTIFY FAIL'; return 'NOTIFY FAIL';
} }
@ -141,4 +167,5 @@ class PaymentService extends AbstractService
return $params; return $params;
} }
} }

@ -12,7 +12,7 @@
"description": "A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.", "description": "A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.",
"license": "Apache-2.0", "license": "Apache-2.0",
"require": { "require": {
"php": ">=7.3", "php": ">=7.4",
"hyperf/async-queue": "~2.2.0", "hyperf/async-queue": "~2.2.0",
"hyperf/cache": "~2.2.0", "hyperf/cache": "~2.2.0",
"hyperf/command": "~2.2.0", "hyperf/command": "~2.2.0",
@ -33,7 +33,9 @@
"hyperf/rpc-client": "~2.2.0", "hyperf/rpc-client": "~2.2.0",
"hyperf/rpc-server": "~2.2.0", "hyperf/rpc-server": "~2.2.0",
"hyperf/validation": "^2.2", "hyperf/validation": "^2.2",
"phpoffice/phpspreadsheet": "^1.24" "phpoffice/phpspreadsheet": "^1.24",
"ext-json": "Required to use JSON.",
"ext-openssl": "Required to use HTTPS."
}, },
"require-dev": { "require-dev": {
"friendsofphp/php-cs-fixer": "^3.0", "friendsofphp/php-cs-fixer": "^3.0",
@ -45,8 +47,6 @@
"swoole/ide-helper": "^4.5" "swoole/ide-helper": "^4.5"
}, },
"suggest": { "suggest": {
"ext-openssl": "Required to use HTTPS.",
"ext-json": "Required to use JSON.",
"ext-pdo": "Required to use MySQL Client.", "ext-pdo": "Required to use MySQL Client.",
"ext-pdo_mysql": "Required to use MySQL Client.", "ext-pdo_mysql": "Required to use MySQL Client.",
"ext-redis": "Required to use Redis Client." "ext-redis": "Required to use Redis Client."

Loading…
Cancel
Save