You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
5.7 KiB
221 lines
5.7 KiB
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Libs\AppException;
|
|
use App\Models\MchApp;
|
|
|
|
class OutService
|
|
{
|
|
|
|
/**
|
|
* 生成签名
|
|
* @param array $params
|
|
* @param string $secretKey
|
|
* @return string
|
|
*/
|
|
private function makeSign(array $params, string $secretKey): string
|
|
{
|
|
ksort($params);
|
|
|
|
$signStr = '';
|
|
|
|
foreach ($params as $key => $value) {
|
|
if ($value === null || $value === '' || $key === 'sign') {
|
|
continue;
|
|
}
|
|
if ($signStr) {
|
|
$signStr .= '&';
|
|
}
|
|
$signStr .= $key.'='.$value;
|
|
}
|
|
|
|
$signStr .= '&key='.$secretKey;
|
|
$sign = md5($signStr);
|
|
|
|
return strtoupper($sign);
|
|
}
|
|
|
|
/**
|
|
* 时间戳偏差校验
|
|
* @throws AppException
|
|
*/
|
|
private function checkRequestTime(int $requestTime): void
|
|
{
|
|
if (abs(time() - $requestTime / 1000) > 300) {
|
|
throw new AppException('时间戳相差大于300秒');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 渠道编码校验
|
|
* @throws AppException
|
|
*/
|
|
private function checkIfCode(string $ifCode): void
|
|
{
|
|
if ($ifCode !== 'alipay') {
|
|
throw new AppException('渠道编码固定为:alipay');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 接口版本号校验
|
|
* @throws AppException
|
|
*/
|
|
private function checkVersion(string $version): void
|
|
{
|
|
if ($version !== '1.0') {
|
|
throw new AppException('接口版本号固定为:1.0');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 签名类型校验
|
|
* @throws AppException
|
|
*/
|
|
private function checkSignType(string $signType): void
|
|
{
|
|
if ($signType !== 'MD5') {
|
|
throw new AppException('签名类型固定为:MD5');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 校验签名
|
|
* @throws AppException
|
|
*/
|
|
private function checkSign(array $params, string $secretKey): void
|
|
{
|
|
if (empty($params['sign'])) {
|
|
throw new AppException('签名缺失');
|
|
}
|
|
|
|
$checkSign = $this->makeSign($params, $secretKey);
|
|
|
|
if ($checkSign !== $params['sign']) {
|
|
throw new AppException('签名不匹配');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 根据商户号和应用ID获取应用
|
|
* @throws AppException
|
|
*/
|
|
private function getMchApp(string $mchNo, string $appId): MchApp
|
|
{
|
|
$app = MchApp::query()
|
|
->where('mch_no', $mchNo)
|
|
->where('app_id', $appId)
|
|
->first();
|
|
|
|
if (empty($app)) {
|
|
throw new AppException('应用不存在');
|
|
}
|
|
|
|
if (empty($app->account_book_id)) {
|
|
throw new AppException('还未开通记账本');
|
|
}
|
|
|
|
return $app;
|
|
}
|
|
|
|
/**
|
|
* 查询记账本余额
|
|
* @param array $params
|
|
* @return array
|
|
* @throws AppException
|
|
*/
|
|
public function queryBalance(array $params): array
|
|
{
|
|
$this->checkRequestTime($params['reqTime']);
|
|
$this->checkIfCode($params['ifCode']);
|
|
$this->checkVersion($params['version']);
|
|
$this->checkSignType($params['signType']);
|
|
|
|
$mchApp = $this->getMchApp($params['mchNo'], $params['appId']);
|
|
|
|
$this->checkSign($params, $mchApp->secret_key);
|
|
|
|
// TODO mock
|
|
$data = [
|
|
'availableAmount' => 700,
|
|
];
|
|
|
|
$sign = $this->makeSign($data, $mchApp->secret_key);
|
|
|
|
return [$data, $sign];
|
|
}
|
|
|
|
/**
|
|
* 单笔转账
|
|
* @param array $params
|
|
* @return array
|
|
* @throws AppException
|
|
*/
|
|
public function transferOrder(array $params): array
|
|
{
|
|
$this->checkRequestTime($params['reqTime']);
|
|
$this->checkIfCode($params['ifCode']);
|
|
$this->checkVersion($params['version']);
|
|
$this->checkSignType($params['signType']);
|
|
|
|
$mchApp = $this->getMchApp($params['mchNo'], $params['appId']);
|
|
|
|
$this->checkSign($params, $mchApp->secret_key);
|
|
|
|
// TODO mock
|
|
$data = [
|
|
'accountName' => '广西拉米信息科技有限公司',
|
|
'accountNo' => '3858074971@qq.com',
|
|
'amount' => 300,
|
|
'channelOrderNo' => '20250825020070011530820074021763',
|
|
'mchOrderNo' => 'P00000000000000000010',
|
|
'state' => 1,
|
|
'transferId' => 'T1708316875559008'
|
|
];
|
|
|
|
$sign = $this->makeSign($data, $mchApp->secret_key);
|
|
|
|
return [$data, $sign];
|
|
}
|
|
|
|
/**
|
|
* 转账查询
|
|
* @param array $params
|
|
* @return array
|
|
* @throws AppException
|
|
*/
|
|
public function transferQuery(array $params): array
|
|
{
|
|
$this->checkRequestTime($params['reqTime']);
|
|
$this->checkVersion($params['version']);
|
|
$this->checkSignType($params['signType']);
|
|
|
|
$mchApp = $this->getMchApp($params['mchNo'], $params['appId']);
|
|
|
|
$this->checkSign($params, $mchApp->secret_key);
|
|
|
|
// TODO mock
|
|
$data = [
|
|
'accountName' => '广西拉米信息科技有限公司',
|
|
'accountNo' => '3858074971@qq.com',
|
|
'amount' => 300,
|
|
'appId' => '664714f9e4b078d6ee5d0007',
|
|
'channelOrderNo' => '20250825020070011530820074021763',
|
|
'createdAt' => 1756092887724,
|
|
'currency' => 'cny',
|
|
'entryType' => 'ALIPAY_CASH',
|
|
'ifCode' => 'alipay',
|
|
'mchNo' => 'M1715934457',
|
|
'mchOrderNo' => 'P00000000000000000010',
|
|
'state' => 2,
|
|
'successTime' => 1756092888000,
|
|
'transferDesc' => '提现到账3.00元',
|
|
'transferId' => 'T1708316875559008'
|
|
];
|
|
|
|
$sign = $this->makeSign($data, $mchApp->secret_key);
|
|
|
|
return [$data, $sign];
|
|
}
|
|
}
|