diff --git a/.php-cs-fixer.php b/.php-cs-fixer.php index dd164b5..8d207e1 100644 --- a/.php-cs-fixer.php +++ b/.php-cs-fixer.php @@ -1,13 +1,14 @@ setRiskyAllowed(true) @@ -17,19 +18,17 @@ return (new PhpCsFixer\Config()) '@DoctrineAnnotation' => true, '@PhpCsFixer' => true, 'header_comment' => [ - 'comment_type' => 'PHPDoc', - 'header' => $header, 'separate' => 'none', 'location' => 'after_declare_strict', ], 'array_syntax' => [ - 'syntax' => 'short' + 'syntax' => 'short', ], 'list_syntax' => [ - 'syntax' => 'short' + 'syntax' => 'short', ], 'concat_space' => [ - 'spacing' => 'one' + 'spacing' => 'one', ], 'blank_line_before_statement' => [ 'statements' => [ @@ -38,7 +37,7 @@ return (new PhpCsFixer\Config()) ], 'general_phpdoc_annotation_remove' => [ 'annotations' => [ - 'author' + 'author', ], ], 'ordered_imports' => [ diff --git a/app/Command/JinlingCommand.php b/app/Command/JinlingCommand.php index b68c12c..6535cc6 100644 --- a/app/Command/JinlingCommand.php +++ b/app/Command/JinlingCommand.php @@ -9,8 +9,8 @@ use App\Service\AppService; use App\Service\MerchantService; use App\Service\PaymentService; use Hyperf\Command\Command as HyperfCommand; -use Hyperf\Command\Annotation\Command; use Hyperf\Contract\ContainerInterface; +use Hyperf\Command\Annotation\Command; /** * @Command @@ -31,16 +31,16 @@ class JinlingCommand extends HyperfCommand parent::__construct('jinling'); } - public function configure() + public function configure(): void { parent::configure(); $this->setDescription('廖金灵测试'); } - public function handle() + public function handle(): void { /** - * @var PaymentService + * @var PaymentService $paymentService */ $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}'; @@ -51,12 +51,12 @@ class JinlingCommand extends HyperfCommand $this->buildPayPrams(); return; /** - * @var MerchantService + * @var MerchantService $merchantService */ $merchantService = $this->container->make(MerchantService::class); /** - * @var AppService + * @var AppService $appService */ $appService = $this->container->make(AppService::class); $merchant = $merchantService->createMerchant([ @@ -64,12 +64,13 @@ class JinlingCommand extends HyperfCommand 'password' => '123456', 'email' => '360197197@qq.com', 'mobile' => '18760419185', - 'ip' => '127.0.0.1' + 'ip' => '127.0.0.1', ]); $appService->createApp($merchant); } - public function buildPayPrams() { + public function buildPayPrams(): void + { $params = [ 'app_id' => '202304270000004', 'timestamp' => time(), @@ -79,8 +80,8 @@ class JinlingCommand extends HyperfCommand 'order_name' => '测试订单', 'currency' => 'CNY', 'amount' => '10', - 'notify_url' => 'http://www.baidu.com', - 'redirect_url' => 'http://www.google.com', + 'notify_url' => 'https://www.baidu.com', + 'redirect_url' => 'https://www.google.com', 'out_order_no' => '1122', 'direct_pay' => 0, 'show_pc_pay_url' => 0, @@ -90,4 +91,4 @@ class JinlingCommand extends HyperfCommand $params['sign'] = $sign; var_dump(json_encode($params)); } -} \ No newline at end of file +} diff --git a/app/Controller/Payment/NotifyController.php b/app/Controller/Payment/NotifyController.php index 39c2ad9..6655f79 100644 --- a/app/Controller/Payment/NotifyController.php +++ b/app/Controller/Payment/NotifyController.php @@ -4,13 +4,13 @@ declare(strict_types=1); namespace App\Controller\Payment; -use Hyperf\HttpServer\Contract\RequestInterface; use App\Service\PaymentService; +use Hyperf\HttpServer\Contract\RequestInterface; class NotifyController extends AbstractController { private PaymentService $paymentService; - + public function __construct(PaymentService $paymentService) { $this->paymentService = $paymentService; @@ -21,4 +21,9 @@ class NotifyController extends AbstractController $params = $request->all(); return $this->paymentService->notify($params); } + + public function efps(RequestInterface $request) { + $params = $request->all(); + return $this->paymentService->efpsNotify($params); + } } diff --git a/app/Controller/Payment/PageController.php b/app/Controller/Payment/PageController.php index 7f3d704..c850776 100644 --- a/app/Controller/Payment/PageController.php +++ b/app/Controller/Payment/PageController.php @@ -1,14 +1,21 @@ input('order_no', ''); Log::info('redirectToOut orderNo:' . $orderNo, [], 'omipay'); - if (!$orderNo) { + if (! $orderNo) { return '订单号错误'; } $order = Order::where('order_no', $orderNo)->first(); - if (!$order) { + if (! $order) { return '订单号错误'; } Log::info('redirectToOut url:' . $order->redirect_url, [], 'omipay'); diff --git a/app/Controller/Payment/PayController.php b/app/Controller/Payment/PayController.php index 4553927..6eb668f 100644 --- a/app/Controller/Payment/PayController.php +++ b/app/Controller/Payment/PayController.php @@ -26,4 +26,14 @@ class PayController extends AbstractController '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, + ]); + } } diff --git a/app/Helper/Efps/AbstractApi.php b/app/Helper/Efps/AbstractApi.php new file mode 100644 index 0000000..3f83562 --- /dev/null +++ b/app/Helper/Efps/AbstractApi.php @@ -0,0 +1,86 @@ + 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, + ] + } +} \ No newline at end of file diff --git a/app/Helper/Efps/Api.php b/app/Helper/Efps/Api.php new file mode 100644 index 0000000..e2df1e6 --- /dev/null +++ b/app/Helper/Efps/Api.php @@ -0,0 +1,21 @@ +setVersion('3.0'); + $request->setOutTradeNo($outTradeNo); + $request->setOrderInfo($orderInfo); + $request->setPayAmount($payAmount); + $request->setNotifyUrl($notifyUrl); + $request->setRedirectUrl($redirectUrl); + + return self::request($request); + } +} \ No newline at end of file diff --git a/app/Helper/Efps/Config.php b/app/Helper/Efps/Config.php new file mode 100644 index 0000000..1a727fd --- /dev/null +++ b/app/Helper/Efps/Config.php @@ -0,0 +1,16 @@ + '', + 'secret_key' => 'cea6f34bea8640dea91fd8b7a926a9a5', + 'base_url' => 'https://efps.epylinks.cn', + ]; + + public static function get($key) { + return self::$params[$key] ?: null; + } +} \ No newline at end of file diff --git a/app/Helper/Efps/PayNotify.php b/app/Helper/Efps/PayNotify.php new file mode 100644 index 0000000..24420d3 --- /dev/null +++ b/app/Helper/Efps/PayNotify.php @@ -0,0 +1,18 @@ +params = $params; + } + + public function get($key, $default = null) + { + return $this->params[$key] ?: $default; + } +} \ No newline at end of file diff --git a/app/Helper/Efps/Request/AbstractRequest.php b/app/Helper/Efps/Request/AbstractRequest.php new file mode 100644 index 0000000..8469291 --- /dev/null +++ b/app/Helper/Efps/Request/AbstractRequest.php @@ -0,0 +1,32 @@ +uri; + } + + public function getParams() { + return $this->_params; + } + + public function __get($name) + { + return $this->_params[$name]; + } + + public function __set($name, $value) + { + $this->_params[$name] = $value; + } +} \ No newline at end of file diff --git a/app/Helper/Efps/Request/UnifiedPaymentRequest.php b/app/Helper/Efps/Request/UnifiedPaymentRequest.php new file mode 100644 index 0000000..068aee6 --- /dev/null +++ b/app/Helper/Efps/Request/UnifiedPaymentRequest.php @@ -0,0 +1,216 @@ +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; + } +} \ No newline at end of file diff --git a/app/Helper/Efps/Signer.php b/app/Helper/Efps/Signer.php new file mode 100644 index 0000000..296ba75 --- /dev/null +++ b/app/Helper/Efps/Signer.php @@ -0,0 +1,32 @@ +where('status', Order::STATUS_WAIT_PAY)->first(); + $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'], + + ]; + 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) { return 'ORDER FAIL'; } $app = App::where('app_id', $order->app_id)->first(); $order->status = Order::STATUS_PAYED; $order->payed_at = date('Y-m-d H:i:s'); - $order->exchange_rate = $params['exchange_rate'] ?: 0; - $order->cny_amount = $params['cny_amount'] ?: 0; + $order->exchange_rate = $params['exchange_rate'] ?: 1; + $order->cny_amount = $params['cny_amount'] ?: $order->amount; if (!$order->save()) { return 'NOTIFY FAIL'; } @@ -141,4 +167,5 @@ class PaymentService extends AbstractService return $params; } + } diff --git a/composer.json b/composer.json index 20eda0b..19919d4 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "description": "A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.", "license": "Apache-2.0", "require": { - "php": ">=7.3", + "php": ">=7.4", "hyperf/async-queue": "~2.2.0", "hyperf/cache": "~2.2.0", "hyperf/command": "~2.2.0", @@ -33,7 +33,9 @@ "hyperf/rpc-client": "~2.2.0", "hyperf/rpc-server": "~2.2.0", "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": { "friendsofphp/php-cs-fixer": "^3.0", @@ -45,9 +47,7 @@ "swoole/ide-helper": "^4.5" }, "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-redis": "Required to use Redis Client." },