You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
payment/app/Service/PaymentService.php

188 lines
6.5 KiB
PHP

<?php
declare(strict_types=1);
namespace App\Service;
use App\Exception\BusinessException;
use App\Helper\Log;
use App\Helper\OmiPay\Api;
use App\Helper\OmiPay\Result;
use App\Helper\OmiPay\Signer;
use App\Helper\Platform\Notification;
use App\Helper\Platform\Signer as PlatformSigner;
use App\Helper\Redis;
use App\Helper\RedisKey;
use App\Helper\StringHelper;
use App\Model\App;
use App\Model\Order;
class PaymentService extends AbstractService
{
public function createOrder(App $app, array $params) {
$order = new Order();
$order->merchant_id = $app->merchant_id;
$order->app_id = $app->app_id;
$order->order_no = $this->generateOrderNo();
$order->out_order_no = $params['out_order_no'];
$order->order_name = $params['order_name'];
$order->amount = $params['amount'];
$order->currency = $params['currency'];
$order->redirect_url = $params['redirect_url'];
$order->notify_url = $params['notify_url'];
$order->direct_pay = $params['direct_pay'] ?? 0;
$order->show_pc_pay_url = $params['show_pc_pay_url'] ?? 0;
$order->o_number = $params['o_number'] ?? '';
$order->pos_no = $params['pos_no'] ?? '';
$order->status = Order::STATUS_PREPARE;
$order->save();
return $order;
}
private function generateOrderNo() {
$now = time();
$key = RedisKey::getGenerateOrderNoKey($now);
$incrId = Redis::incr($key);
$incrId = '' . $incrId;
Redis::expire($key, 5*60);
$padLength = 6 - strlen($incrId);
$incrId = str_pad($incrId, $padLength, '0', STR_PAD_LEFT);
return date('YmdHis', $now) . $incrId;
}
public function updateOrderResult(Order $order, array $result)
{
if ($result['is_success']) {
$order->pay_order_no = $result['pay_order_no'];
$order->pay_url = $result['pay_url'];
$order->status = Order::STATUS_WAIT_PAY;
} else {
$order->error_code = $result['error_code'];
$order->error_msg = $result['error_msg'];
$order->status = Order::STATUS_FAILED;
}
$order->save();
}
public function jsapiPay(App $app, array $params) {
$order = Order::where('app_id', $app->app_id)->where('out_order_no', $params['out_order_no'])->first();
if ($order) {
throw new BusinessException('订单重复');
}
$order = $this->createOrder($app, $params);
$result = Api::getExchangeRate('AUD', 'CNY');
if (!$result->isSuccess()) {
throw new BusinessException('获取汇率接口失败');
}
$rate = $result->get('rate');
$result = Api::makeJSAPIOrder(
$order->order_name,
$order->order_no,
'AUD',
intval($order->amount / $rate),
'http://146.70.113.165:9501/payment/notify',
'http://146.70.113.165:9501/payment/page?order_no=' . $order->order_no
);
$this->updateOrderResult($order, $result->toArray());
return $order;
}
public function notify($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['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'] ?: 1;
$order->cny_amount = $params['cny_amount'] ?: $order->amount;
if (!$order->save()) {
return 'NOTIFY FAIL';
}
Log::info('notifyToOut url:' . $order->notify_url, [], 'omipay');
$result = Notification::post($order->notify_url, $this->buildNotifyParams($order, $app));
Log::info('notifyToOut response:' . $result, [], 'omipay');
if ($result != 'SUCCESS') {
return 'NOTIFY FAIL';
}
return 'SUCCESS';
}
protected function buildNotifyParams(Order $order, App $app) {
$params = [
'app_id' => $order->app_id,
'nonce_str' => StringHelper::getRandomString(32),
'timestamp' => time(),
];
$bizData = [
'code' => 'SUCCESS',
'order_no' => $order->order_no,
'out_order_no' => $order->out_order_no,
'currency' => $order->currency,
'total_amount' => $order->amount,
'order_time' => date('YmdHis', $order->created_at->timestamp),
'pay_time' => date('YmdHis', strtotime($order->payed_at)),
'exchange_rate' => $order->exchange_rate,
'cny_amount' => $order->cny_amount,
];
$params['data'] = json_encode($bizData);
$params['sign'] = PlatformSigner::sign($params, $app->app_key);
Log::info('notifyToOut params:', $params, 'omipay');
return $params;
}
public function unifiedPay(App $app, array $params) {
$order = Order::where('app_id', $app->app_id)->where('out_order_no', $params['out_order_no'])->first();
if ($order) {
throw new BusinessException('订单重复');
}
$order = $this->createOrder($app, $params);
$result = \App\Helper\Efps\Api::unifiedPayment(
$order->order_no,
$order->order_name,
$order->amount,
'http://146.70.113.165:9501/payment/notify',
'http://146.70.113.165:9501/payment/page?order_no=' . $order->order_no
);
$this->updateOrderResult($order, $result->toArray());
return $order;
}
}