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.
yanzong/app/store/model/PaymentTemplate.php

221 lines
7.8 KiB

<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务,帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件,不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);
namespace app\store\model;
use think\facade\Filesystem;
use cores\exception\BaseException;
use app\common\library\helper;
use app\store\model\Payment as PaymentModel;
use app\common\enum\payment\Method as PaymentMethodEnum;
use app\common\model\PaymentTemplate as PaymentTemplateModel;
use app\common\library\wechat\payment\PlatformCertDown;
/**
* 模型类:支付方式记录
* Class PaymentTemplate
* @package app\store\model
*/
class PaymentTemplate extends PaymentTemplateModel
{
/**
* 获取列表
* @return \think\Paginator
* @throws \think\db\exception\DbException
*/
public function getList($merchantId = 0): \think\Paginator
{
$where = [
['is_delete', '=', 0],
];
// if (isset($merchantId) && $merchantId) {
// $where[] = ['merchant_id', '=', $merchantId];
// }
$where[] = ['merchant_id', '=', $merchantId];
return $this->where($where)->where('is_delete', '=', 0)
->order(['sort' => 'asc', $this->getPk()])
->paginate(15);
}
/**
* 新增记录
* @param array $data
* @return bool|false
* @throws BaseException
*/
public function add(array $data): bool
{
// 整理保存的数据
$config = helper::jsonDecode(htmlspecialchars_decode($data['config']));
$methodConfig = $config[$data['method']];
$data['store_id'] = self::$storeId;
// 写入证书文件
$data['config'] = [$data['method'] => $this->certFileName($data['method'], $methodConfig)];
// 写入到数据库
return $this->save($data);
}
/**
* 更新记录
* @param array $data
* @return bool
* @throws BaseException
*/
public function edit(array $data): bool
{
// 整理保存的数据
$config = helper::jsonDecode(htmlspecialchars_decode($data['config']));
$methodConfig = $config[$data['method']];
$data['store_id'] = self::$storeId;
// 记录证书文件名
$data['config'] = [
$data['method'] => array_merge($methodConfig, $this->certFileName($data['method'], $methodConfig))
];
// 记录微信支付v3平台证书序号
if ($data['method'] === 'wechat' && $data['config']['wechat']['version'] === 'v3') {
$data['wechatpay_serial'] = $data['config']['wechat'][$data['config']['wechat']['mchType']]['platformCertSerial'];
}
// 更新到数据库
return $this->save($data) !== false;
}
/**
* 记录证书文件名
* @param string $method 支付方式类型
* @param array $config 支付配置
* @return array
* @throws BaseException
*/
private function certFileName(string $method, array $config): array
{
if ($method === PaymentMethodEnum::WECHAT) {
$config['normal'] = $this->saveCertFileNames($config['normal'], $method, [
'apiclientCert',
'apiclientKey'
], 'pem');
$config['provider'] = $this->saveCertFileNames($config['provider'], $method, [
'spApiclientCert',
'spApiclientKey'
], 'pem');
// 微信支付v3下载 [微信平台证书]
$config['version'] === 'v3' && $this->downloadPlatformCert($config);
}
if ($method === PaymentMethodEnum::ALIPAY && $config['signMode'] == 10) {
$config = $this->saveCertFileNames($config, $method, [
'appCertPublicKey',
'alipayCertPublicKey',
'alipayRootCert'
], 'crt');
}
return $config;
}
/**
* 微信支付v3下载 [微信平台证书]
* @param array $config
* @return void
* @throws BaseException
*/
private function downloadPlatformCert(array &$config): void
{
// 配置项的字段(用于区分普通商户和子商户)
$field = $config['mchType'] === 'normal' ? ['normal', 'apiclientCert', 'apiclientKey', 'apiKey', 'mchId']
: ['provider', 'spApiclientCert', 'spApiclientKey', 'spApiKey', 'spMchId'];
// 微信商户API证书 [公钥]
$publicKey = parent::realPathCertFile(PaymentMethodEnum::WECHAT, $config[$field[0]][$field[1]], self::$storeId);
// 微信商户API证书 [私钥]
$privatekey = parent::realPathCertFile(PaymentMethodEnum::WECHAT, $config[$field[0]][$field[2]], self::$storeId);
// 生成平台证书文件名
$platformCertName = $this->buildCertFileName('platformCert', 'pem');
// 证书保存的目录
$certFolder = parent::certFolder(PaymentMethodEnum::WECHAT, self::$storeId);
// 下载平台证书
$downloader = new PlatformCertDown([
'key' => $config[$field[0]][$field[3]],
'mchid' => $config[$field[0]][$field[4]],
'privatekey' => $privatekey,
'publicKey' => $publicKey,
'output' => $certFolder,
'fileName' => $platformCertName
]);
$downloader->run();
// 记录平台证书
$config[$field[0]]['platformCert'] = $platformCertName;
$config[$field[0]]['platformCertSerial'] = $downloader->getPlatformCertSerial();
}
/**
* 批量设置证书文件名
* @param array $config 配置项
* @param string $method 支付方式类型
* @param array $certNames
* @param string $ext 文件后缀
* @return array
*/
private function saveCertFileNames(array $config, string $method, array $certNames, string $ext): array
{
foreach ($certNames as $name) {
$config[$name] = $this->writeFile($method, $name, $ext) ?: $config[$name];
}
return $config;
}
/**
* 写入证书文件
* @param string $method 支付方式类型
* @param string $name 证书名称
* @param string $ext 文件后缀
* @return string|false
*/
private function writeFile(string $method, string $name, string $ext)
{
// 接收上传的文件
$file = request()->file($name);
if (empty($file)) {
return false;
}
// 证书文件夹路径
$dirPath = "payment/{$method}/" . self::$storeId;
// 证书文件名
$fileName = $this->buildCertFileName($name, $ext);
// 写入到本地服务器
Filesystem::disk('data')->putFileAs($dirPath, $file, $fileName);
return $fileName;
}
/**
* 生成证书文件名
* @param string $name
* @param string $ext
* @return string
*/
private function buildCertFileName(string $name, string $ext): string
{
$hash = str_substr(md5(get_guid_v4()), 8);
return "{$name}-{$hash}.{$ext}";
}
/**
* 删除记录
* @return bool
*/
public function setDelete(): bool
{
// 验证模板是否被引用
if (PaymentModel::existsTemplateId($this['template_id'])) {
$this->error = '当前支付模板已被引用,需解除后才可删除';
return false;
}
// 标记为已删除
return $this->save(['is_delete' => 1]);
}
}