mirror of
https://gitee.com/technical-laohu/mpay_v2_webman.git
synced 2026-04-27 20:44:30 +08:00
更新统一使用 PHPDoc + PSR-19 标准注释
This commit is contained in:
@@ -13,9 +13,25 @@ use app\repository\payment\config\PaymentTypeRepository;
|
||||
|
||||
/**
|
||||
* 支付通道命令服务。
|
||||
*
|
||||
* 负责支付通道的新增、修改、删除以及写入前的商户、插件和支付方式约束校验。
|
||||
*
|
||||
* @property MerchantRepository $merchantRepository 商户仓库
|
||||
* @property PaymentChannelRepository $paymentChannelRepository 支付渠道仓库
|
||||
* @property PaymentPluginRepository $paymentPluginRepository 支付插件仓库
|
||||
* @property PaymentTypeRepository $paymentTypeRepository 支付类型仓库
|
||||
*/
|
||||
class PaymentChannelCommandService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造方法。
|
||||
*
|
||||
* @param MerchantRepository $merchantRepository 商户仓库
|
||||
* @param PaymentChannelRepository $paymentChannelRepository 支付渠道仓库
|
||||
* @param PaymentPluginRepository $paymentPluginRepository 支付插件仓库
|
||||
* @param PaymentTypeRepository $paymentTypeRepository 支付类型仓库
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected MerchantRepository $merchantRepository,
|
||||
protected PaymentChannelRepository $paymentChannelRepository,
|
||||
@@ -24,13 +40,27 @@ class PaymentChannelCommandService extends BaseService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 ID 查询支付通道。
|
||||
*
|
||||
* @param int $id 支付通道ID
|
||||
* @return PaymentChannel|null 支付通道模型
|
||||
*/
|
||||
public function findById(int $id): ?PaymentChannel
|
||||
{
|
||||
return $this->paymentChannelRepository->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增支付通道。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentChannel 新增后的支付通道模型
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function create(array $data): PaymentChannel
|
||||
{
|
||||
// 新增通道前先校验名称、商户归属和插件支付方式兼容性。
|
||||
$this->assertChannelNameUnique((string) ($data['name'] ?? ''));
|
||||
$this->assertMerchantExists($data);
|
||||
$this->assertPluginSupportsPayType($data);
|
||||
@@ -38,8 +68,17 @@ class PaymentChannelCommandService extends BaseService
|
||||
return $this->paymentChannelRepository->create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新支付通道。
|
||||
*
|
||||
* @param int $id 支付通道ID
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentChannel|null 更新后的支付通道模型
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function update(int $id, array $data): ?PaymentChannel
|
||||
{
|
||||
// 更新通道时同样要先拦住冲突配置,避免保存后才发现路由不可用。
|
||||
$this->assertChannelNameUnique((string) ($data['name'] ?? ''), $id);
|
||||
$this->assertMerchantExists($data);
|
||||
$this->assertPluginSupportsPayType($data);
|
||||
@@ -51,11 +90,24 @@ class PaymentChannelCommandService extends BaseService
|
||||
return $this->paymentChannelRepository->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除支付通道。
|
||||
*
|
||||
* @param int $id 支付通道ID
|
||||
* @return bool 是否删除成功
|
||||
*/
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
return $this->paymentChannelRepository->deleteById($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验通道所属商户是否存在。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return void
|
||||
* @throws PaymentException
|
||||
*/
|
||||
private function assertMerchantExists(array $data): void
|
||||
{
|
||||
if (!array_key_exists('merchant_id', $data)) {
|
||||
@@ -63,6 +115,7 @@ class PaymentChannelCommandService extends BaseService
|
||||
}
|
||||
|
||||
$merchantId = (int) $data['merchant_id'];
|
||||
// merchant_id 为空或为 0 时通常表示通道草稿,这里不强制拦截。
|
||||
if ($merchantId === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -74,11 +127,19 @@ class PaymentChannelCommandService extends BaseService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验支付插件是否支持当前支付方式。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return void
|
||||
* @throws PaymentException
|
||||
*/
|
||||
private function assertPluginSupportsPayType(array $data): void
|
||||
{
|
||||
$pluginCode = trim((string) ($data['plugin_code'] ?? ''));
|
||||
$payTypeId = (int) ($data['pay_type_id'] ?? 0);
|
||||
|
||||
// 草稿态允许只填一半字段,只有插件和支付方式都明确时才做交叉校验。
|
||||
if ($pluginCode === '' || $payTypeId <= 0) {
|
||||
return;
|
||||
}
|
||||
@@ -90,6 +151,7 @@ class PaymentChannelCommandService extends BaseService
|
||||
return;
|
||||
}
|
||||
|
||||
// 插件支持的支付方式可能来自 JSON 配置,先统一压成编码列表再比对。
|
||||
$payTypes = is_array($plugin->pay_types) ? $plugin->pay_types : [];
|
||||
$payTypeCodes = array_values(array_filter(array_map(static fn ($item) => trim((string) $item), $payTypes)));
|
||||
$payTypeCode = trim((string) $paymentType->code);
|
||||
@@ -102,6 +164,14 @@ class PaymentChannelCommandService extends BaseService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验通道名称唯一。
|
||||
*
|
||||
* @param string $name 通道名称
|
||||
* @param int $ignoreId 排除的通道ID
|
||||
* @return void
|
||||
* @throws PaymentException
|
||||
*/
|
||||
private function assertChannelNameUnique(string $name, int $ignoreId = 0): void
|
||||
{
|
||||
$name = trim($name);
|
||||
@@ -117,3 +187,5 @@ class PaymentChannelCommandService extends BaseService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -8,15 +8,30 @@ use app\model\payment\PaymentChannel;
|
||||
use app\repository\payment\config\PaymentChannelRepository;
|
||||
|
||||
/**
|
||||
* 支付通道查询服务。
|
||||
* 支付通道查询与选项拼装服务。
|
||||
*
|
||||
* 负责支付通道列表、详情、下拉选项和路由候选数据的查询拼装。
|
||||
*
|
||||
* @property PaymentChannelRepository $paymentChannelRepository 支付渠道仓库
|
||||
*/
|
||||
class PaymentChannelQueryService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造方法。
|
||||
*
|
||||
* @param PaymentChannelRepository $paymentChannelRepository 支付渠道仓库
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PaymentChannelRepository $paymentChannelRepository
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用支付通道选项。
|
||||
*
|
||||
* @return array<int, array{label: string, value: int}> 启用通道选项
|
||||
*/
|
||||
public function enabledOptions(): array
|
||||
{
|
||||
return $this->paymentChannelRepository->query()
|
||||
@@ -38,6 +53,14 @@ class PaymentChannelQueryService extends BaseService
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索支付通道选项。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return array{list: array<int, array{label: string, value: int, merchant_id: int, merchant_no: string, merchant_name: string, channel_mode: int, pay_type_id: int, pay_type_name: string, plugin_code: string}>, total: int, page: int, size: int} 通道搜索结果
|
||||
*/
|
||||
public function searchOptions(array $filters = [], int $page = 1, int $pageSize = 20): array
|
||||
{
|
||||
$query = $this->paymentChannelRepository->query()
|
||||
@@ -59,12 +82,15 @@ class PaymentChannelQueryService extends BaseService
|
||||
|
||||
$ids = $this->normalizeIds($filters['ids'] ?? []);
|
||||
if (!empty($ids)) {
|
||||
// 显式传 ID 时,直接按 ID 集合返回,避免再叠加其他筛选条件影响回显。
|
||||
$query->whereIn('c.id', $ids);
|
||||
} else {
|
||||
// 选择器默认只给启用通道,避免把已停用的历史数据混进后台下拉框。
|
||||
$query->where('c.status', CommonConstant::STATUS_ENABLED);
|
||||
|
||||
$keyword = trim((string) ($filters['keyword'] ?? ''));
|
||||
if ($keyword !== '') {
|
||||
// 关键词同时支持通道、插件和商户维度搜索,方便后台快速定位路由节点。
|
||||
$query->where(function ($builder) use ($keyword) {
|
||||
$builder->where('c.name', 'like', '%' . $keyword . '%')
|
||||
->orWhere('c.plugin_code', 'like', '%' . $keyword . '%')
|
||||
@@ -87,6 +113,7 @@ class PaymentChannelQueryService extends BaseService
|
||||
|
||||
$excludeIds = $this->normalizeIds($filters['exclude_ids'] ?? []);
|
||||
if (!empty($excludeIds)) {
|
||||
// 编排时经常要排除当前已选项,这里提供反选列表避免重复挂载同一通道。
|
||||
$query->whereNotIn('c.id', $excludeIds);
|
||||
}
|
||||
}
|
||||
@@ -119,6 +146,12 @@ class PaymentChannelQueryService extends BaseService
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支付通道路由候选选项。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @return array<int, array{label: string, value: int, merchant_id: int, channel_mode: int, pay_type_id: int, plugin_code: string, pay_type_name: string}> 路由候选选项
|
||||
*/
|
||||
public function routeOptions(array $filters = []): array
|
||||
{
|
||||
$query = $this->paymentChannelRepository->query()
|
||||
@@ -140,6 +173,7 @@ class PaymentChannelQueryService extends BaseService
|
||||
}
|
||||
|
||||
if (array_key_exists('merchant_id', $filters) && $filters['merchant_id'] !== '') {
|
||||
// 路由预览/编排时会按商户分组筛选通道,这里直接用商户 ID 限定范围。
|
||||
$query->where('c.merchant_id', (int) $filters['merchant_id']);
|
||||
}
|
||||
|
||||
@@ -162,6 +196,14 @@ class PaymentChannelQueryService extends BaseService
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询支付通道。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 分页结果
|
||||
*/
|
||||
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10)
|
||||
{
|
||||
$query = $this->paymentChannelRepository->query()
|
||||
@@ -175,6 +217,7 @@ class PaymentChannelQueryService extends BaseService
|
||||
|
||||
$keyword = trim((string) ($filters['keyword'] ?? ''));
|
||||
if ($keyword !== '') {
|
||||
// 列表页的搜索同时覆盖通道名、插件编码和商户信息,便于运营一次性查到整条链路。
|
||||
$query->where(function ($builder) use ($keyword) {
|
||||
$builder->where('c.name', 'like', '%' . $keyword . '%')
|
||||
->orWhere('c.plugin_code', 'like', '%' . $keyword . '%')
|
||||
@@ -210,11 +253,23 @@ class PaymentChannelQueryService extends BaseService
|
||||
->paginate(max(1, $pageSize), ['*'], 'page', max(1, $page));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 ID 查询支付通道。
|
||||
*
|
||||
* @param int $id 支付通道ID
|
||||
* @return PaymentChannel|null 支付通道模型
|
||||
*/
|
||||
public function findById(int $id): ?PaymentChannel
|
||||
{
|
||||
return $this->paymentChannelRepository->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 归一化 ID 列表。
|
||||
*
|
||||
* @param array|string|int $ids 通道ID或ID列表
|
||||
* @return array<int, int> ID 列表
|
||||
*/
|
||||
private function normalizeIds(array|string|int $ids): array
|
||||
{
|
||||
if (is_string($ids)) {
|
||||
@@ -223,6 +278,9 @@ class PaymentChannelQueryService extends BaseService
|
||||
$ids = [$ids];
|
||||
}
|
||||
|
||||
// 下拉/搜索参数有时是字符串、有时是数组,统一压成正整数列表后再查询。
|
||||
return array_values(array_filter(array_map(static fn ($id) => (int) $id, $ids), static fn ($id) => $id > 0));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,53 +6,116 @@ use app\common\base\BaseService;
|
||||
use app\model\payment\PaymentChannel;
|
||||
|
||||
/**
|
||||
* 支付通道门面服务。
|
||||
* 支付通道服务。
|
||||
*
|
||||
* @property PaymentChannelQueryService $queryService 查询服务
|
||||
* @property PaymentChannelCommandService $commandService 命令服务
|
||||
*/
|
||||
class PaymentChannelService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造方法。
|
||||
*
|
||||
* @param PaymentChannelQueryService $queryService 查询服务
|
||||
* @param PaymentChannelCommandService $commandService 命令服务
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PaymentChannelQueryService $queryService,
|
||||
protected PaymentChannelCommandService $commandService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用支付通道选项。
|
||||
*
|
||||
* @return array<int, array{label: string, value: int}> 启用通道选项
|
||||
*/
|
||||
public function enabledOptions(): array
|
||||
{
|
||||
return $this->queryService->enabledOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索支付通道选项。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return array{list: array<int, array<string, mixed>>, total: int, page: int, size: int} 通道搜索结果
|
||||
*/
|
||||
public function searchOptions(array $filters = [], int $page = 1, int $pageSize = 20): array
|
||||
{
|
||||
return $this->queryService->searchOptions($filters, $page, $pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取支付渠道路由选项。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @return array<int, array<string, mixed>> 路由候选选项
|
||||
*/
|
||||
public function routeOptions(array $filters = []): array
|
||||
{
|
||||
return $this->queryService->routeOptions($filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询支付通道。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 分页结果
|
||||
*/
|
||||
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10)
|
||||
{
|
||||
return $this->queryService->paginate($filters, $page, $pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 ID 查询支付通道。
|
||||
*
|
||||
* @param int $id 支付通道ID
|
||||
* @return PaymentChannel|null 支付通道模型
|
||||
*/
|
||||
public function findById(int $id): ?PaymentChannel
|
||||
{
|
||||
return $this->queryService->findById($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增支付通道。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentChannel 新增后的支付通道模型
|
||||
*/
|
||||
public function create(array $data): PaymentChannel
|
||||
{
|
||||
return $this->commandService->create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新支付通道。
|
||||
*
|
||||
* @param int $id 支付通道ID
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentChannel|null 更新后的支付通道模型
|
||||
*/
|
||||
public function update(int $id, array $data): ?PaymentChannel
|
||||
{
|
||||
return $this->commandService->update($id, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除支付通道。
|
||||
*
|
||||
* @param int $id 支付通道ID
|
||||
* @return bool 是否删除成功
|
||||
*/
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
return $this->commandService->delete($id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,10 +11,20 @@ use app\repository\payment\config\PaymentPluginRepository;
|
||||
/**
|
||||
* 支付插件配置服务。
|
||||
*
|
||||
* 负责插件公共配置的增删改查和下拉选项输出。
|
||||
* 负责支付插件公共配置的增删改查、下拉选项输出以及插件存在性校验。
|
||||
*
|
||||
* @property PaymentPluginConfRepository $paymentPluginConfRepository 支付插件配置仓库
|
||||
* @property PaymentPluginRepository $paymentPluginRepository 支付插件仓库
|
||||
*/
|
||||
class PaymentPluginConfService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造方法。
|
||||
*
|
||||
* @param PaymentPluginConfRepository $paymentPluginConfRepository 支付插件配置仓库
|
||||
* @param PaymentPluginRepository $paymentPluginRepository 支付插件仓库
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PaymentPluginConfRepository $paymentPluginConfRepository,
|
||||
protected PaymentPluginRepository $paymentPluginRepository
|
||||
@@ -23,6 +33,11 @@ class PaymentPluginConfService extends BaseService
|
||||
|
||||
/**
|
||||
* 分页查询插件配置。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 分页结果
|
||||
*/
|
||||
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10)
|
||||
{
|
||||
@@ -43,6 +58,7 @@ class PaymentPluginConfService extends BaseService
|
||||
|
||||
$keyword = trim((string) ($filters['keyword'] ?? ''));
|
||||
if ($keyword !== '') {
|
||||
// 列表页关键词同时覆盖插件编码、备注和插件名称,方便后台快速定位配置记录。
|
||||
$query->where(function ($builder) use ($keyword) {
|
||||
$builder->where('c.plugin_code', 'like', '%' . $keyword . '%')
|
||||
->orWhere('c.remark', 'like', '%' . $keyword . '%')
|
||||
@@ -62,6 +78,9 @@ class PaymentPluginConfService extends BaseService
|
||||
|
||||
/**
|
||||
* 按 ID 查询插件配置。
|
||||
*
|
||||
* @param int $id 支付插件配置ID
|
||||
* @return PaymentPluginConf|null 插件配置模型
|
||||
*/
|
||||
public function findById(int $id): ?PaymentPluginConf
|
||||
{
|
||||
@@ -70,6 +89,10 @@ class PaymentPluginConfService extends BaseService
|
||||
|
||||
/**
|
||||
* 新增插件配置。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentPluginConf 新增后的插件配置模型
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function create(array $data): PaymentPluginConf
|
||||
{
|
||||
@@ -81,6 +104,11 @@ class PaymentPluginConfService extends BaseService
|
||||
|
||||
/**
|
||||
* 修改插件配置。
|
||||
*
|
||||
* @param int $id 支付插件配置ID
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentPluginConf|null 更新后的插件配置模型
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function update(int $id, array $data): ?PaymentPluginConf
|
||||
{
|
||||
@@ -96,6 +124,9 @@ class PaymentPluginConfService extends BaseService
|
||||
|
||||
/**
|
||||
* 删除插件配置。
|
||||
*
|
||||
* @param int $id 支付插件配置ID
|
||||
* @return bool 是否删除成功
|
||||
*/
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
@@ -104,6 +135,9 @@ class PaymentPluginConfService extends BaseService
|
||||
|
||||
/**
|
||||
* 查询插件配置下拉选项。
|
||||
*
|
||||
* @param string|null $pluginCode 插件编码
|
||||
* @return array<int, array{label: string, value: int, plugin_code: string, plugin_name: string}> 配置选项
|
||||
*/
|
||||
public function options(?string $pluginCode = null): array
|
||||
{
|
||||
@@ -120,6 +154,7 @@ class PaymentPluginConfService extends BaseService
|
||||
->orderByDesc('c.id');
|
||||
|
||||
if ($pluginCode !== '') {
|
||||
// 如果前端已经明确指定插件编码,就只回这个插件下的配置选项。
|
||||
$query->where('c.plugin_code', $pluginCode);
|
||||
}
|
||||
|
||||
@@ -138,7 +173,12 @@ class PaymentPluginConfService extends BaseService
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程查询插件配置选择项。
|
||||
* 搜索插件配置选择项。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return array{list: array<int, array{label: string, value: int, plugin_code: string, plugin_name: string}>, total: int, page: int, size: int} 配置搜索结果
|
||||
*/
|
||||
public function searchOptions(array $filters = [], int $page = 1, int $pageSize = 20): array
|
||||
{
|
||||
@@ -154,15 +194,18 @@ class PaymentPluginConfService extends BaseService
|
||||
|
||||
$ids = $filters['ids'] ?? [];
|
||||
if (is_array($ids) && $ids !== []) {
|
||||
// 显式传 ID 时优先按配置主键回显,避免关键词过滤把已选项漏掉。
|
||||
$query->whereIn('c.id', array_map('intval', $ids));
|
||||
} else {
|
||||
$pluginCode = trim((string) ($filters['plugin_code'] ?? ''));
|
||||
if ($pluginCode !== '') {
|
||||
// 插件编码是配置项的一级过滤条件,先收窄到单个插件。
|
||||
$query->where('c.plugin_code', $pluginCode);
|
||||
}
|
||||
|
||||
$keyword = trim((string) ($filters['keyword'] ?? ''));
|
||||
if ($keyword !== '') {
|
||||
// 数字关键词既可以按配置 ID 查,也可以按编码或备注查。
|
||||
$query->where(function ($builder) use ($keyword) {
|
||||
$builder->where('c.plugin_code', 'like', '%' . $keyword . '%')
|
||||
->orWhere('p.name', 'like', '%' . $keyword . '%')
|
||||
@@ -197,13 +240,18 @@ class PaymentPluginConfService extends BaseService
|
||||
}
|
||||
|
||||
/**
|
||||
* 标准化写入数据。
|
||||
* 标准化插件配置写入数据。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return array<string, mixed> 标准化后的数据
|
||||
*/
|
||||
private function normalizePayload(array $data): array
|
||||
{
|
||||
return [
|
||||
'plugin_code' => trim((string) ($data['plugin_code'] ?? '')),
|
||||
// 配置内容统一按数组保存,外部传入非数组时直接回退为空数组。
|
||||
'config' => is_array($data['config'] ?? null) ? $data['config'] : [],
|
||||
// 默认结算周期按日配置,截止时间默认按当天 23:59:59 收口。
|
||||
'settlement_cycle_type' => (int) ($data['settlement_cycle_type'] ?? 1),
|
||||
'settlement_cutoff_time' => trim((string) ($data['settlement_cutoff_time'] ?? '23:59:59')) ?: '23:59:59',
|
||||
'remark' => trim((string) ($data['remark'] ?? '')),
|
||||
@@ -212,6 +260,10 @@ class PaymentPluginConfService extends BaseService
|
||||
|
||||
/**
|
||||
* 校验插件是否存在。
|
||||
*
|
||||
* @param string $pluginCode 插件编码
|
||||
* @return void
|
||||
* @throws PaymentException
|
||||
*/
|
||||
private function assertPluginExists(string $pluginCode): void
|
||||
{
|
||||
@@ -219,6 +271,7 @@ class PaymentPluginConfService extends BaseService
|
||||
throw new PaymentException('插件编码不能为空', 40230);
|
||||
}
|
||||
|
||||
// 插件配置必须挂到已存在的插件定义上,避免配置和实际实现脱节。
|
||||
if (!$this->paymentPluginRepository->findByCode($pluginCode)) {
|
||||
throw new PaymentException('支付插件不存在', 40231, [
|
||||
'plugin_code' => $pluginCode,
|
||||
|
||||
@@ -11,11 +11,18 @@ use app\repository\payment\config\PaymentPluginRepository;
|
||||
* 支付插件管理服务。
|
||||
*
|
||||
* 负责插件目录同步、插件列表查询,以及 JSON 字段写入前的归一化。
|
||||
*
|
||||
* @property PaymentPluginRepository $paymentPluginRepository 支付插件仓库
|
||||
* @property PaymentPluginSyncService $paymentPluginSyncService 支付插件同步服务
|
||||
*/
|
||||
class PaymentPluginService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造函数,注入支付插件仓库。
|
||||
* 构造方法。
|
||||
*
|
||||
* @param PaymentPluginRepository $paymentPluginRepository 支付插件仓库
|
||||
* @param PaymentPluginSyncService $paymentPluginSyncService 支付插件同步服务
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PaymentPluginRepository $paymentPluginRepository,
|
||||
@@ -25,6 +32,11 @@ class PaymentPluginService extends BaseService
|
||||
|
||||
/**
|
||||
* 分页查询支付插件。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 分页结果
|
||||
*/
|
||||
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10)
|
||||
{
|
||||
@@ -60,6 +72,8 @@ class PaymentPluginService extends BaseService
|
||||
|
||||
/**
|
||||
* 查询启用中的支付插件选项。
|
||||
*
|
||||
* @return array<int, array{label: string, value: string, code: string, name: string}> 启用插件选项
|
||||
*/
|
||||
public function enabledOptions(): array
|
||||
{
|
||||
@@ -77,7 +91,12 @@ class PaymentPluginService extends BaseService
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程查询支付插件选择项。
|
||||
* 搜索支付插件选择项。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return array{list: array<int, array{label: string, value: string, code: string, name: string, pay_types: array<int, string>}>, total: int, page: int, size: int} 插件搜索结果
|
||||
*/
|
||||
public function searchOptions(array $filters = [], int $page = 1, int $pageSize = 20): array
|
||||
{
|
||||
@@ -88,6 +107,7 @@ class PaymentPluginService extends BaseService
|
||||
|
||||
$ids = $filters['ids'] ?? [];
|
||||
if (is_array($ids) && $ids !== []) {
|
||||
// 显式传 ID 时优先按编码集合回显,避免关键词过滤把手工选择项漏掉。
|
||||
$query->whereIn('code', array_values(array_filter(array_map('strval', $ids))));
|
||||
} else {
|
||||
$keyword = trim((string) ($filters['keyword'] ?? ''));
|
||||
@@ -100,6 +120,7 @@ class PaymentPluginService extends BaseService
|
||||
|
||||
$payTypeCode = trim((string) ($filters['pay_type_code'] ?? ''));
|
||||
if ($payTypeCode !== '') {
|
||||
// 如果前端按支付方式筛选,就只保留 pay_types 中包含该编码的插件。
|
||||
$query->whereJsonContains('pay_types', $payTypeCode);
|
||||
}
|
||||
}
|
||||
@@ -124,9 +145,12 @@ class PaymentPluginService extends BaseService
|
||||
|
||||
/**
|
||||
* 查询通道配置场景使用的支付插件选项。
|
||||
*
|
||||
* @return array<int, array{label: string, value: string, code: string, name: string, pay_types: array<int, string>}> 通道配置选项
|
||||
*/
|
||||
public function channelOptions(): array
|
||||
{
|
||||
// 通道配置场景只需要启用中的插件,并且要带上支付方式集合供前端联动展示。
|
||||
return $this->paymentPluginRepository->enabledList([
|
||||
'code',
|
||||
'name',
|
||||
@@ -147,6 +171,9 @@ class PaymentPluginService extends BaseService
|
||||
|
||||
/**
|
||||
* 按插件编码查询插件。
|
||||
*
|
||||
* @param string $code 插件编码
|
||||
* @return PaymentPlugin|null 插件模型
|
||||
*/
|
||||
public function findByCode(string $code): ?PaymentPlugin
|
||||
{
|
||||
@@ -156,7 +183,9 @@ class PaymentPluginService extends BaseService
|
||||
/**
|
||||
* 查询插件配置结构。
|
||||
*
|
||||
* @return array<string, mixed>
|
||||
* @param string $code 插件编码
|
||||
* @return array{config_schema: array<int, mixed>} 配置结构
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function getSchema(string $code): array
|
||||
{
|
||||
@@ -174,10 +203,15 @@ class PaymentPluginService extends BaseService
|
||||
|
||||
/**
|
||||
* 更新支付插件。
|
||||
*
|
||||
* @param string $code 插件编码
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentPlugin|null 更新后的插件模型
|
||||
*/
|
||||
public function update(string $code, array $data): ?PaymentPlugin
|
||||
{
|
||||
$payload = [];
|
||||
// 插件元信息由文件同步维护,后台这里只允许调整状态和备注,避免人工改动覆盖同步结果。
|
||||
if (array_key_exists('status', $data)) {
|
||||
$payload['status'] = (int) $data['status'];
|
||||
}
|
||||
@@ -199,6 +233,8 @@ class PaymentPluginService extends BaseService
|
||||
|
||||
/**
|
||||
* 从插件目录刷新并同步支付插件定义。
|
||||
*
|
||||
* @return array{count: int, plugins: array<int, PaymentPlugin>} 同步结果
|
||||
*/
|
||||
public function refreshFromClasses(): array
|
||||
{
|
||||
|
||||
@@ -12,26 +12,40 @@ use app\repository\payment\config\PaymentPluginRepository;
|
||||
/**
|
||||
* 支付插件同步服务。
|
||||
*
|
||||
* 负责扫描插件目录、实例化插件类并同步数据库定义。
|
||||
* 负责扫描插件目录、实例化插件类并同步数据库中的插件定义。
|
||||
*
|
||||
* @property PaymentPluginRepository $paymentPluginRepository 支付插件仓库
|
||||
*/
|
||||
class PaymentPluginSyncService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造方法。
|
||||
*
|
||||
* @param PaymentPluginRepository $paymentPluginRepository 支付插件仓库
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PaymentPluginRepository $paymentPluginRepository
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 从插件目录刷新并同步支付插件定义。
|
||||
*
|
||||
* @return array{count: int, plugins: array<int, PaymentPlugin>} 同步结果
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function refreshFromClasses(): array
|
||||
{
|
||||
$directory = base_path() . DIRECTORY_SEPARATOR . 'app' . DIRECTORY_SEPARATOR . 'common' . DIRECTORY_SEPARATOR . 'payment';
|
||||
// 扫描固定目录下的插件类文件,每个文件都可能对应一个可同步的插件定义。
|
||||
$files = glob($directory . DIRECTORY_SEPARATOR . '*.php') ?: [];
|
||||
|
||||
// 以插件 code 为键去重,避免同一个插件被多个类重复注册。
|
||||
$rows = [];
|
||||
foreach ($files as $file) {
|
||||
$shortClassName = pathinfo($file, PATHINFO_FILENAME);
|
||||
$className = 'app\\common\\payment\\' . $shortClassName;
|
||||
// 先实例化插件,再从实例上读取元信息作为同步源。
|
||||
$plugin = $this->instantiatePlugin($className);
|
||||
if (!$plugin) {
|
||||
continue;
|
||||
@@ -62,6 +76,7 @@ class PaymentPluginSyncService extends BaseService
|
||||
];
|
||||
}
|
||||
|
||||
// 先固定排序,再和数据库现有记录逐条对比,保证同步过程稳定可复现。
|
||||
ksort($rows);
|
||||
|
||||
$existing = $this->paymentPluginRepository->query()
|
||||
@@ -79,6 +94,7 @@ class PaymentPluginSyncService extends BaseService
|
||||
]);
|
||||
|
||||
if ($current) {
|
||||
// 已存在的插件只覆盖元信息,不改动人工维护的状态和备注。
|
||||
$current->fill($payload);
|
||||
$current->save();
|
||||
unset($existing[$code]);
|
||||
@@ -88,6 +104,7 @@ class PaymentPluginSyncService extends BaseService
|
||||
$this->paymentPluginRepository->create($payload);
|
||||
}
|
||||
|
||||
// 数据库里还残留、但文件中已不存在的插件,直接删除避免配置漂移。
|
||||
foreach ($existing as $plugin) {
|
||||
$plugin->delete();
|
||||
}
|
||||
@@ -105,6 +122,9 @@ class PaymentPluginSyncService extends BaseService
|
||||
|
||||
/**
|
||||
* 实例化插件类并过滤非支付插件类。
|
||||
*
|
||||
* @param string $className 插件类名
|
||||
* @return null|(PaymentInterface&PayPluginInterface) 支付插件实例
|
||||
*/
|
||||
private function instantiatePlugin(string $className): null|(PaymentInterface & PayPluginInterface)
|
||||
{
|
||||
@@ -120,3 +140,5 @@ class PaymentPluginSyncService extends BaseService
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,9 +11,23 @@ use app\repository\payment\config\PaymentPollGroupRepository;
|
||||
|
||||
/**
|
||||
* 商户分组路由绑定服务。
|
||||
*
|
||||
* 负责把商户分组和支付方式绑定到指定轮询组,并校验轮询组与支付方式的匹配关系。
|
||||
*
|
||||
* @property PaymentPollGroupBindRepository $paymentPollGroupBindRepository 支付轮询分组绑定仓库
|
||||
* @property MerchantGroupRepository $merchantGroupRepository 商户分组仓库
|
||||
* @property PaymentPollGroupRepository $paymentPollGroupRepository 支付轮询分组仓库
|
||||
*/
|
||||
class PaymentPollGroupBindService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造方法。
|
||||
*
|
||||
* @param PaymentPollGroupBindRepository $paymentPollGroupBindRepository 支付轮询分组绑定仓库
|
||||
* @param MerchantGroupRepository $merchantGroupRepository 商户分组仓库
|
||||
* @param PaymentPollGroupRepository $paymentPollGroupRepository 支付轮询分组仓库
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PaymentPollGroupBindRepository $paymentPollGroupBindRepository,
|
||||
protected MerchantGroupRepository $merchantGroupRepository,
|
||||
@@ -23,6 +37,11 @@ class PaymentPollGroupBindService extends BaseService
|
||||
|
||||
/**
|
||||
* 分页查询商户分组路由绑定。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 分页结果
|
||||
*/
|
||||
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10)
|
||||
{
|
||||
@@ -76,11 +95,24 @@ class PaymentPollGroupBindService extends BaseService
|
||||
->paginate(max(1, $pageSize), ['*'], 'page', max(1, $page));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 ID 查询路由绑定。
|
||||
*
|
||||
* @param int $id 绑定ID
|
||||
* @return PaymentPollGroupBind|null 绑定模型
|
||||
*/
|
||||
public function findById(int $id): ?PaymentPollGroupBind
|
||||
{
|
||||
return $this->paymentPollGroupBindRepository->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建路由绑定。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentPollGroupBind 新增后的绑定模型
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function create(array $data): PaymentPollGroupBind
|
||||
{
|
||||
$this->assertBindingUnique((int) $data['merchant_group_id'], (int) $data['pay_type_id']);
|
||||
@@ -89,6 +121,14 @@ class PaymentPollGroupBindService extends BaseService
|
||||
return $this->paymentPollGroupBindRepository->create($this->normalizePayload($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新路由绑定。
|
||||
*
|
||||
* @param int $id 绑定ID
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentPollGroupBind|null 更新后的绑定模型
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function update(int $id, array $data): ?PaymentPollGroupBind
|
||||
{
|
||||
$current = $this->paymentPollGroupBindRepository->find($id);
|
||||
@@ -96,6 +136,7 @@ class PaymentPollGroupBindService extends BaseService
|
||||
return null;
|
||||
}
|
||||
|
||||
// 更新时要以现有记录为底,把未传的分组和支付方式补齐后再做唯一性校验。
|
||||
$merchantGroupId = (int) ($data['merchant_group_id'] ?? $current->merchant_group_id);
|
||||
$payTypeId = (int) ($data['pay_type_id'] ?? $current->pay_type_id);
|
||||
$this->assertBindingUnique($merchantGroupId, $payTypeId, $id);
|
||||
@@ -108,11 +149,23 @@ class PaymentPollGroupBindService extends BaseService
|
||||
return $this->paymentPollGroupBindRepository->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除路由绑定。
|
||||
*
|
||||
* @param int $id 绑定ID
|
||||
* @return bool 是否删除成功
|
||||
*/
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
return $this->paymentPollGroupBindRepository->deleteById($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标准化路由绑定写入数据。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return array<string, mixed> 标准化后的数据
|
||||
*/
|
||||
private function normalizePayload(array $data): array
|
||||
{
|
||||
return [
|
||||
@@ -124,6 +177,15 @@ class PaymentPollGroupBindService extends BaseService
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验商户分组与支付方式的绑定唯一性。
|
||||
*
|
||||
* @param int $merchantGroupId 商户分组ID
|
||||
* @param int $payTypeId 支付方式ID
|
||||
* @param int $ignoreId 排除的绑定ID
|
||||
* @return void
|
||||
* @throws PaymentException
|
||||
*/
|
||||
private function assertBindingUnique(int $merchantGroupId, int $payTypeId, int $ignoreId = 0): void
|
||||
{
|
||||
$query = $this->paymentPollGroupBindRepository->query()
|
||||
@@ -142,11 +204,19 @@ class PaymentPollGroupBindService extends BaseService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验轮询组与支付方式是否一致。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return void
|
||||
* @throws PaymentException
|
||||
*/
|
||||
private function assertPollGroupMatchesPayType(array $data): void
|
||||
{
|
||||
$pollGroupId = (int) ($data['poll_group_id'] ?? 0);
|
||||
$payTypeId = (int) ($data['pay_type_id'] ?? 0);
|
||||
|
||||
// 轮询组和支付方式必须保持一致;轮询组缺失时交给上层必填校验处理。
|
||||
$pollGroup = $this->paymentPollGroupRepository->find($pollGroupId);
|
||||
if (!$pollGroup) {
|
||||
return;
|
||||
@@ -160,3 +230,5 @@ class PaymentPollGroupBindService extends BaseService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,9 +11,23 @@ use app\repository\payment\config\PaymentPollGroupRepository;
|
||||
|
||||
/**
|
||||
* 轮询组通道编排服务。
|
||||
*
|
||||
* 负责维护轮询组内通道的顺序、权重、默认通道以及支付方式一致性。
|
||||
*
|
||||
* @property PaymentPollGroupChannelRepository $paymentPollGroupChannelRepository 支付轮询分组渠道仓库
|
||||
* @property PaymentPollGroupRepository $paymentPollGroupRepository 支付轮询分组仓库
|
||||
* @property PaymentChannelRepository $paymentChannelRepository 支付渠道仓库
|
||||
*/
|
||||
class PaymentPollGroupChannelService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造方法。
|
||||
*
|
||||
* @param PaymentPollGroupChannelRepository $paymentPollGroupChannelRepository 支付轮询分组渠道仓库
|
||||
* @param PaymentPollGroupRepository $paymentPollGroupRepository 支付轮询分组仓库
|
||||
* @param PaymentChannelRepository $paymentChannelRepository 支付渠道仓库
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PaymentPollGroupChannelRepository $paymentPollGroupChannelRepository,
|
||||
protected PaymentPollGroupRepository $paymentPollGroupRepository,
|
||||
@@ -23,6 +37,11 @@ class PaymentPollGroupChannelService extends BaseService
|
||||
|
||||
/**
|
||||
* 分页查询轮询组通道编排。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 分页结果
|
||||
*/
|
||||
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10)
|
||||
{
|
||||
@@ -79,11 +98,24 @@ class PaymentPollGroupChannelService extends BaseService
|
||||
->paginate(max(1, $pageSize), ['*'], 'page', max(1, $page));
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 ID 查询轮询组通道编排。
|
||||
*
|
||||
* @param int $id 编排ID
|
||||
* @return PaymentPollGroupChannel|null 编排模型
|
||||
*/
|
||||
public function findById(int $id): ?PaymentPollGroupChannel
|
||||
{
|
||||
return $this->paymentPollGroupChannelRepository->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建轮询组通道编排。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentPollGroupChannel 新增后的编排模型
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function create(array $data): PaymentPollGroupChannel
|
||||
{
|
||||
$this->assertPairUnique((int) $data['poll_group_id'], (int) $data['channel_id']);
|
||||
@@ -91,6 +123,7 @@ class PaymentPollGroupChannelService extends BaseService
|
||||
$payload = $this->normalizePayload($data);
|
||||
|
||||
return $this->transaction(function () use ($payload) {
|
||||
// 一个轮询组只能有一个默认通道,新增默认项前先清理掉其他默认标记。
|
||||
if ((int) ($payload['is_default'] ?? 0) === 1) {
|
||||
$this->paymentPollGroupChannelRepository->clearDefaultExcept((int) $payload['poll_group_id']);
|
||||
}
|
||||
@@ -99,6 +132,14 @@ class PaymentPollGroupChannelService extends BaseService
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新轮询组通道编排。
|
||||
*
|
||||
* @param int $id 编排ID
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentPollGroupChannel|null 更新后的编排模型
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function update(int $id, array $data): ?PaymentPollGroupChannel
|
||||
{
|
||||
$current = $this->paymentPollGroupChannelRepository->find($id);
|
||||
@@ -114,6 +155,7 @@ class PaymentPollGroupChannelService extends BaseService
|
||||
$payload = $this->normalizePayload($data);
|
||||
|
||||
return $this->transaction(function () use ($id, $payload) {
|
||||
// 更新成默认通道时,同样先把本轮询组的其他默认项清空。
|
||||
if ((int) ($payload['is_default'] ?? 0) === 1) {
|
||||
$this->paymentPollGroupChannelRepository->clearDefaultExcept((int) $payload['poll_group_id'], $id);
|
||||
}
|
||||
@@ -126,17 +168,30 @@ class PaymentPollGroupChannelService extends BaseService
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除轮询组通道编排。
|
||||
*
|
||||
* @param int $id 编排ID
|
||||
* @return bool 是否删除成功
|
||||
*/
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
return $this->paymentPollGroupChannelRepository->deleteById($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 标准化编排写入数据。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return array<string, mixed> 标准化后的数据
|
||||
*/
|
||||
private function normalizePayload(array $data): array
|
||||
{
|
||||
return [
|
||||
'poll_group_id' => (int) $data['poll_group_id'],
|
||||
'channel_id' => (int) $data['channel_id'],
|
||||
'sort_no' => (int) ($data['sort_no'] ?? 0),
|
||||
// 权重至少为 1,避免轮询时出现 0 权重通道导致随机分配失真。
|
||||
'weight' => max(1, (int) ($data['weight'] ?? 100)),
|
||||
'is_default' => (int) ($data['is_default'] ?? 0),
|
||||
'status' => (int) ($data['status'] ?? 1),
|
||||
@@ -144,6 +199,15 @@ class PaymentPollGroupChannelService extends BaseService
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验轮询组与通道的组合唯一性。
|
||||
*
|
||||
* @param int $pollGroupId 轮询组ID
|
||||
* @param int $channelId 通道ID
|
||||
* @param int $ignoreId 排除的编排ID
|
||||
* @return void
|
||||
* @throws PaymentException
|
||||
*/
|
||||
private function assertPairUnique(int $pollGroupId, int $channelId, int $ignoreId = 0): void
|
||||
{
|
||||
$query = $this->paymentPollGroupChannelRepository->query()
|
||||
@@ -162,6 +226,13 @@ class PaymentPollGroupChannelService extends BaseService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验通道支付方式与轮询组支付方式一致。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return void
|
||||
* @throws PaymentException
|
||||
*/
|
||||
private function assertChannelMatchesPollGroup(array $data): void
|
||||
{
|
||||
$pollGroupId = (int) ($data['poll_group_id'] ?? 0);
|
||||
@@ -174,6 +245,7 @@ class PaymentPollGroupChannelService extends BaseService
|
||||
return;
|
||||
}
|
||||
|
||||
// 轮询组和通道必须属于同一支付方式,否则排序再正确也会在运行时被路由规则拦下。
|
||||
if ((int) $pollGroup->pay_type_id !== (int) $channel->pay_type_id) {
|
||||
throw new PaymentException('轮询组与支付通道的支付方式不一致', 40231, [
|
||||
'poll_group_id' => $pollGroupId,
|
||||
@@ -182,3 +254,6 @@ class PaymentPollGroupChannelService extends BaseService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -9,22 +9,47 @@ use app\repository\payment\config\PaymentPollGroupRepository;
|
||||
|
||||
/**
|
||||
* 支付轮询组命令服务。
|
||||
*
|
||||
* @property PaymentPollGroupRepository $paymentPollGroupRepository 支付轮询分组仓库
|
||||
*/
|
||||
class PaymentPollGroupCommandService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造方法。
|
||||
*
|
||||
* @param PaymentPollGroupRepository $paymentPollGroupRepository 支付轮询分组仓库
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PaymentPollGroupRepository $paymentPollGroupRepository
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建支付轮询组。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentPollGroup 新增后的轮询组模型
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function create(array $data): PaymentPollGroup
|
||||
{
|
||||
// 新增前先确保轮询组名称不冲突,避免后台同时出现两个同名配置。
|
||||
$this->assertGroupNameUnique((string) ($data['group_name'] ?? ''));
|
||||
return $this->paymentPollGroupRepository->create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新支付轮询组。
|
||||
*
|
||||
* @param int $id 轮询组ID
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentPollGroup|null 更新后的轮询组模型
|
||||
* @throws PaymentException
|
||||
*/
|
||||
public function update(int $id, array $data): ?PaymentPollGroup
|
||||
{
|
||||
// 更新时同样要排除自身后再做唯一性判断,防止修改回原名时误报冲突。
|
||||
$this->assertGroupNameUnique((string) ($data['group_name'] ?? ''), $id);
|
||||
if (!$this->paymentPollGroupRepository->updateById($id, $data)) {
|
||||
return null;
|
||||
@@ -33,11 +58,25 @@ class PaymentPollGroupCommandService extends BaseService
|
||||
return $this->paymentPollGroupRepository->find($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除支付轮询组。
|
||||
*
|
||||
* @param int $id 轮询组ID
|
||||
* @return bool 是否删除成功
|
||||
*/
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
return $this->paymentPollGroupRepository->deleteById($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验轮询组名称唯一。
|
||||
*
|
||||
* @param string $groupName 轮询组名称
|
||||
* @param int $ignoreId 排除的轮询组ID
|
||||
* @return void
|
||||
* @throws PaymentException
|
||||
*/
|
||||
private function assertGroupNameUnique(string $groupName, int $ignoreId = 0): void
|
||||
{
|
||||
$groupName = trim($groupName);
|
||||
@@ -53,3 +92,6 @@ class PaymentPollGroupCommandService extends BaseService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,21 +7,40 @@ use app\model\payment\PaymentPollGroup;
|
||||
use app\repository\payment\config\PaymentPollGroupRepository;
|
||||
|
||||
/**
|
||||
* 支付轮询组查询服务。
|
||||
* 支付轮询组查询与选项拼装服务。
|
||||
*
|
||||
* 负责轮询组列表、详情和启用选项输出。
|
||||
*
|
||||
* @property PaymentPollGroupRepository $paymentPollGroupRepository 支付轮询分组仓库
|
||||
*/
|
||||
class PaymentPollGroupQueryService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造方法。
|
||||
*
|
||||
* @param PaymentPollGroupRepository $paymentPollGroupRepository 支付轮询分组仓库
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PaymentPollGroupRepository $paymentPollGroupRepository
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询支付轮询组。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 分页结果
|
||||
*/
|
||||
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10)
|
||||
{
|
||||
$query = $this->paymentPollGroupRepository->query();
|
||||
|
||||
$keyword = trim((string) ($filters['keyword'] ?? ''));
|
||||
if ($keyword !== '') {
|
||||
// 轮询组列表只按组名搜索,避免把支付方式或路由模式混进模糊搜索结果里。
|
||||
$query->where('group_name', 'like', '%' . $keyword . '%');
|
||||
}
|
||||
|
||||
@@ -47,12 +66,19 @@ class PaymentPollGroupQueryService extends BaseService
|
||||
->paginate(max(1, $pageSize), ['*'], 'page', max(1, $page));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用支付轮询组选项。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @return array<int, array{label: string, value: int, pay_type_id: int, route_mode: int}> 启用轮询组选项
|
||||
*/
|
||||
public function enabledOptions(array $filters = []): array
|
||||
{
|
||||
$query = $this->paymentPollGroupRepository->query()
|
||||
->where('status', 1);
|
||||
|
||||
if (($payTypeId = (int) ($filters['pay_type_id'] ?? 0)) > 0) {
|
||||
// 轮询组选项通常要跟支付方式联动,因此启用项会先按支付方式收窄。
|
||||
$query->where('pay_type_id', $payTypeId);
|
||||
}
|
||||
|
||||
@@ -72,8 +98,17 @@ class PaymentPollGroupQueryService extends BaseService
|
||||
->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 ID 查询轮询组。
|
||||
*
|
||||
* @param int $id 轮询组ID
|
||||
* @return PaymentPollGroup|null 轮询组模型
|
||||
*/
|
||||
public function findById(int $id): ?PaymentPollGroup
|
||||
{
|
||||
return $this->paymentPollGroupRepository->find($id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,43 +6,94 @@ use app\common\base\BaseService;
|
||||
use app\model\payment\PaymentPollGroup;
|
||||
|
||||
/**
|
||||
* 支付轮询组门面服务。
|
||||
* 支付轮询组服务。
|
||||
*
|
||||
* @property PaymentPollGroupQueryService $queryService 查询服务
|
||||
* @property PaymentPollGroupCommandService $commandService 命令服务
|
||||
*/
|
||||
class PaymentPollGroupService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造方法。
|
||||
*
|
||||
* @param PaymentPollGroupQueryService $queryService 查询服务
|
||||
* @param PaymentPollGroupCommandService $commandService 命令服务
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PaymentPollGroupQueryService $queryService,
|
||||
protected PaymentPollGroupCommandService $commandService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询支付轮询组。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 分页结果
|
||||
*/
|
||||
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10)
|
||||
{
|
||||
return $this->queryService->paginate($filters, $page, $pageSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取启用支付轮询组选项。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @return array<int, array<string, mixed>> 启用轮询组选项
|
||||
*/
|
||||
public function enabledOptions(array $filters = []): array
|
||||
{
|
||||
return $this->queryService->enabledOptions($filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按 ID 查询支付轮询组。
|
||||
*
|
||||
* @param int $id 轮询组ID
|
||||
* @return PaymentPollGroup|null 轮询组模型
|
||||
*/
|
||||
public function findById(int $id): ?PaymentPollGroup
|
||||
{
|
||||
return $this->queryService->findById($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增支付轮询组。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentPollGroup 新增后的轮询组模型
|
||||
*/
|
||||
public function create(array $data): PaymentPollGroup
|
||||
{
|
||||
return $this->commandService->create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新支付轮询组。
|
||||
*
|
||||
* @param int $id 轮询组ID
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentPollGroup|null 更新后的轮询组模型
|
||||
*/
|
||||
public function update(int $id, array $data): ?PaymentPollGroup
|
||||
{
|
||||
return $this->commandService->update($id, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除支付轮询组。
|
||||
*
|
||||
* @param int $id 轮询组ID
|
||||
* @return bool 是否删除成功
|
||||
*/
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
return $this->commandService->delete($id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,11 +11,16 @@ use app\repository\payment\config\PaymentTypeRepository;
|
||||
* 支付方式字典服务。
|
||||
*
|
||||
* 负责支付方式的基础列表查询、新增、修改、删除和下拉选项输出。
|
||||
*
|
||||
* @property PaymentTypeRepository $paymentTypeRepository 支付类型仓库
|
||||
*/
|
||||
class PaymentTypeService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造函数,注入支付方式仓库。
|
||||
* 构造方法。
|
||||
*
|
||||
* @param PaymentTypeRepository $paymentTypeRepository 支付类型仓库
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PaymentTypeRepository $paymentTypeRepository
|
||||
@@ -24,6 +29,11 @@ class PaymentTypeService extends BaseService
|
||||
|
||||
/**
|
||||
* 分页查询支付方式。
|
||||
*
|
||||
* @param array $filters 筛选条件
|
||||
* @param int $page 页码
|
||||
* @param int $pageSize 每页条数
|
||||
* @return \Illuminate\Contracts\Pagination\LengthAwarePaginator 分页结果
|
||||
*/
|
||||
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10)
|
||||
{
|
||||
@@ -59,6 +69,8 @@ class PaymentTypeService extends BaseService
|
||||
|
||||
/**
|
||||
* 查询启用中的支付方式选项。
|
||||
*
|
||||
* @return array<int, array{label: string, value: int, code: string}> 启用支付方式选项
|
||||
*/
|
||||
public function enabledOptions(): array
|
||||
{
|
||||
@@ -76,6 +88,10 @@ class PaymentTypeService extends BaseService
|
||||
|
||||
/**
|
||||
* 解析启用中的支付方式,优先按编码匹配,未命中则取首个启用项。
|
||||
*
|
||||
* @param string $code 支付方式编码
|
||||
* @return PaymentType 支付方式模型
|
||||
* @throws ValidationException
|
||||
*/
|
||||
public function resolveEnabledType(string $code = ''): PaymentType
|
||||
{
|
||||
@@ -87,6 +103,7 @@ class PaymentTypeService extends BaseService
|
||||
}
|
||||
}
|
||||
|
||||
// 没有传编码或编码不可用时,直接回退到系统当前首个启用支付方式。
|
||||
$paymentType = $this->paymentTypeRepository->enabledList()->first();
|
||||
if (!$paymentType) {
|
||||
throw new ValidationException('未配置可用支付方式');
|
||||
@@ -97,6 +114,9 @@ class PaymentTypeService extends BaseService
|
||||
|
||||
/**
|
||||
* 根据支付方式编码查询字典。
|
||||
*
|
||||
* @param string $code 支付方式编码
|
||||
* @return PaymentType|null 支付方式模型
|
||||
*/
|
||||
public function findByCode(string $code): ?PaymentType
|
||||
{
|
||||
@@ -105,6 +125,9 @@ class PaymentTypeService extends BaseService
|
||||
|
||||
/**
|
||||
* 根据支付方式 ID 解析支付方式编码。
|
||||
*
|
||||
* @param int $id 支付方式ID
|
||||
* @return string 支付方式编码
|
||||
*/
|
||||
public function resolveCodeById(int $id): string
|
||||
{
|
||||
@@ -114,6 +137,9 @@ class PaymentTypeService extends BaseService
|
||||
|
||||
/**
|
||||
* 按 ID 查询支付方式。
|
||||
*
|
||||
* @param int $id 支付方式ID
|
||||
* @return PaymentType|null 支付方式模型
|
||||
*/
|
||||
public function findById(int $id): ?PaymentType
|
||||
{
|
||||
@@ -122,6 +148,9 @@ class PaymentTypeService extends BaseService
|
||||
|
||||
/**
|
||||
* 新增支付方式。
|
||||
*
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentType 新增后的支付方式模型
|
||||
*/
|
||||
public function create(array $data): PaymentType
|
||||
{
|
||||
@@ -130,6 +159,10 @@ class PaymentTypeService extends BaseService
|
||||
|
||||
/**
|
||||
* 更新支付方式。
|
||||
*
|
||||
* @param int $id 支付方式ID
|
||||
* @param array $data 写入数据
|
||||
* @return PaymentType|null 更新后的支付方式模型
|
||||
*/
|
||||
public function update(int $id, array $data): ?PaymentType
|
||||
{
|
||||
@@ -142,9 +175,14 @@ class PaymentTypeService extends BaseService
|
||||
|
||||
/**
|
||||
* 删除支付方式。
|
||||
*
|
||||
* @param int $id 支付方式ID
|
||||
* @return bool 是否删除成功
|
||||
*/
|
||||
public function delete(int $id): bool
|
||||
{
|
||||
return $this->paymentTypeRepository->deleteById($id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user