mirror of
https://gitee.com/technical-laohu/mpay_v2_webman.git
synced 2026-04-26 12:04:28 +08:00
重构初始化
This commit is contained in:
270
app/service/payment/settlement/SettlementLifecycleService.php
Normal file
270
app/service/payment/settlement/SettlementLifecycleService.php
Normal file
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\payment\settlement;
|
||||
|
||||
use app\common\base\BaseService;
|
||||
use app\common\constant\TradeConstant;
|
||||
use app\exception\BusinessStateException;
|
||||
use app\exception\ResourceNotFoundException;
|
||||
use app\exception\ValidationException;
|
||||
use app\model\payment\SettlementOrder;
|
||||
use app\repository\payment\settlement\SettlementItemRepository;
|
||||
use app\repository\payment\settlement\SettlementOrderRepository;
|
||||
use app\repository\payment\trade\PayOrderRepository;
|
||||
use app\service\account\funds\MerchantAccountService;
|
||||
|
||||
/**
|
||||
* 清算生命周期服务。
|
||||
*
|
||||
* 负责清算单创建、明细写入、入账完成和失败终态处理。
|
||||
*/
|
||||
class SettlementLifecycleService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造函数,注入对应依赖。
|
||||
*/
|
||||
public function __construct(
|
||||
protected SettlementOrderRepository $settlementOrderRepository,
|
||||
protected SettlementItemRepository $settlementItemRepository,
|
||||
protected PayOrderRepository $payOrderRepository,
|
||||
protected MerchantAccountService $merchantAccountService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建清算单和明细。
|
||||
*
|
||||
* 适用于平台代收链路的清算批次生成,会同时写入汇总与明细。
|
||||
*
|
||||
* @param array $input 清算单参数
|
||||
* @param array $items 清算明细列表
|
||||
* @return SettlementOrder
|
||||
*/
|
||||
public function createSettlementOrder(array $input, array $items = []): SettlementOrder
|
||||
{
|
||||
$settleNo = trim((string) ($input['settle_no'] ?? ''));
|
||||
if ($settleNo === '') {
|
||||
$settleNo = $this->generateNo('STL');
|
||||
}
|
||||
|
||||
if ($existing = $this->settlementOrderRepository->findBySettleNo($settleNo)) {
|
||||
return $existing;
|
||||
}
|
||||
|
||||
$merchantId = (int) ($input['merchant_id'] ?? 0);
|
||||
$merchantGroupId = (int) ($input['merchant_group_id'] ?? 0);
|
||||
$channelId = (int) ($input['channel_id'] ?? 0);
|
||||
$cycleType = (int) ($input['cycle_type'] ?? TradeConstant::SETTLEMENT_CYCLE_OTHER);
|
||||
$cycleKey = trim((string) ($input['cycle_key'] ?? ''));
|
||||
|
||||
if ($merchantId <= 0 || $merchantGroupId <= 0 || $channelId <= 0 || $cycleKey === '') {
|
||||
throw new ValidationException('清算单入参不完整');
|
||||
}
|
||||
|
||||
return $this->transactionRetry(function () use ($settleNo, $input, $items, $merchantId, $merchantGroupId, $channelId, $cycleType, $cycleKey) {
|
||||
$summary = $this->buildSummary($items, $input);
|
||||
$traceNo = trim((string) ($input['trace_no'] ?? $settleNo));
|
||||
|
||||
$settlementOrder = $this->settlementOrderRepository->create([
|
||||
'settle_no' => $settleNo,
|
||||
'trace_no' => $traceNo,
|
||||
'merchant_id' => $merchantId,
|
||||
'merchant_group_id' => $merchantGroupId,
|
||||
'channel_id' => $channelId,
|
||||
'cycle_type' => $cycleType,
|
||||
'cycle_key' => $cycleKey,
|
||||
'status' => (int) ($input['status'] ?? TradeConstant::SETTLEMENT_STATUS_PENDING),
|
||||
'gross_amount' => $summary['gross_amount'],
|
||||
'fee_amount' => $summary['fee_amount'],
|
||||
'refund_amount' => $summary['refund_amount'],
|
||||
'fee_reverse_amount' => $summary['fee_reverse_amount'],
|
||||
'net_amount' => $summary['net_amount'],
|
||||
'accounted_amount' => $summary['accounted_amount'],
|
||||
'generated_at' => $input['generated_at'] ?? $this->now(),
|
||||
'failed_at' => null,
|
||||
'ext_json' => $input['ext_json'] ?? [],
|
||||
]);
|
||||
|
||||
foreach ($items as $item) {
|
||||
$this->settlementItemRepository->create([
|
||||
'settle_no' => $settleNo,
|
||||
'merchant_id' => $merchantId,
|
||||
'merchant_group_id' => $merchantGroupId,
|
||||
'channel_id' => $channelId,
|
||||
'pay_no' => (string) ($item['pay_no'] ?? ''),
|
||||
'refund_no' => (string) ($item['refund_no'] ?? ''),
|
||||
'pay_amount' => (int) ($item['pay_amount'] ?? 0),
|
||||
'fee_amount' => (int) ($item['fee_amount'] ?? 0),
|
||||
'refund_amount' => (int) ($item['refund_amount'] ?? 0),
|
||||
'fee_reverse_amount' => (int) ($item['fee_reverse_amount'] ?? 0),
|
||||
'net_amount' => (int) ($item['net_amount'] ?? 0),
|
||||
'item_status' => (int) ($item['item_status'] ?? 0),
|
||||
]);
|
||||
}
|
||||
|
||||
return $settlementOrder->refresh();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清算入账成功。
|
||||
*
|
||||
* 会把清算净额计入商户可提现余额,并同步标记清算单与清算明细为已完成。
|
||||
*
|
||||
* @param string $settleNo 清算单号
|
||||
* @return SettlementOrder
|
||||
*/
|
||||
public function completeSettlement(string $settleNo): SettlementOrder
|
||||
{
|
||||
return $this->transactionRetry(function () use ($settleNo) {
|
||||
$settlementOrder = $this->settlementOrderRepository->findForUpdateBySettleNo($settleNo);
|
||||
if (!$settlementOrder) {
|
||||
throw new ResourceNotFoundException('清结算单不存在', ['settle_no' => $settleNo]);
|
||||
}
|
||||
|
||||
$currentStatus = (int) $settlementOrder->status;
|
||||
if ($currentStatus === TradeConstant::SETTLEMENT_STATUS_SETTLED) {
|
||||
return $settlementOrder;
|
||||
}
|
||||
|
||||
if (TradeConstant::isSettlementTerminalStatus($currentStatus)) {
|
||||
return $settlementOrder;
|
||||
}
|
||||
|
||||
if (!in_array($currentStatus, TradeConstant::settlementMutableStatuses(), true)) {
|
||||
throw new BusinessStateException('清结算单状态不允许当前操作', [
|
||||
'settle_no' => $settleNo,
|
||||
'status' => $currentStatus,
|
||||
]);
|
||||
}
|
||||
|
||||
if ((int) $settlementOrder->accounted_amount > 0) {
|
||||
$this->merchantAccountService->creditAvailableAmountInCurrentTransaction(
|
||||
(int) $settlementOrder->merchant_id,
|
||||
(int) $settlementOrder->accounted_amount,
|
||||
$settleNo,
|
||||
'SETTLEMENT_CREDIT:' . $settleNo,
|
||||
[
|
||||
'settle_no' => $settleNo,
|
||||
'remark' => '清算入账',
|
||||
],
|
||||
(string) ($settlementOrder->trace_no ?: $settleNo)
|
||||
);
|
||||
}
|
||||
|
||||
$settlementOrder->status = TradeConstant::SETTLEMENT_STATUS_SETTLED;
|
||||
$settlementOrder->accounted_at = $this->now();
|
||||
$settlementOrder->completed_at = $this->now();
|
||||
$settlementOrder->save();
|
||||
|
||||
$items = $this->settlementItemRepository->listBySettleNo($settleNo);
|
||||
foreach ($items as $item) {
|
||||
$item->item_status = TradeConstant::SETTLEMENT_STATUS_SETTLED;
|
||||
$item->save();
|
||||
|
||||
if (!empty($item->pay_no)) {
|
||||
$payOrder = $this->payOrderRepository->findByPayNo((string) $item->pay_no);
|
||||
if ($payOrder) {
|
||||
$payOrder->settlement_status = TradeConstant::SETTLEMENT_STATUS_SETTLED;
|
||||
$payOrder->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $settlementOrder->refresh();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 清算失败。
|
||||
*
|
||||
* 仅用于清算批次未成功入账时的终态标记。
|
||||
*
|
||||
* @param string $settleNo 清算单号
|
||||
* @param string $reason 失败原因
|
||||
* @return SettlementOrder
|
||||
*/
|
||||
public function failSettlement(string $settleNo, string $reason = ''): SettlementOrder
|
||||
{
|
||||
return $this->transactionRetry(function () use ($settleNo, $reason) {
|
||||
$settlementOrder = $this->settlementOrderRepository->findForUpdateBySettleNo($settleNo);
|
||||
if (!$settlementOrder) {
|
||||
throw new ResourceNotFoundException('清结算单不存在', ['settle_no' => $settleNo]);
|
||||
}
|
||||
|
||||
$currentStatus = (int) $settlementOrder->status;
|
||||
if ($currentStatus === TradeConstant::SETTLEMENT_STATUS_REVERSED) {
|
||||
return $settlementOrder;
|
||||
}
|
||||
|
||||
if (TradeConstant::isSettlementTerminalStatus($currentStatus)) {
|
||||
return $settlementOrder;
|
||||
}
|
||||
|
||||
if (!in_array($currentStatus, TradeConstant::settlementMutableStatuses(), true)) {
|
||||
throw new BusinessStateException('清结算单状态不允许当前操作', [
|
||||
'settle_no' => $settleNo,
|
||||
'status' => $currentStatus,
|
||||
]);
|
||||
}
|
||||
|
||||
$settlementOrder->status = TradeConstant::SETTLEMENT_STATUS_REVERSED;
|
||||
$settlementOrder->fail_reason = $reason;
|
||||
$settlementOrder->failed_at = $this->now();
|
||||
$extJson = (array) $settlementOrder->ext_json;
|
||||
if (trim($reason) !== '') {
|
||||
$extJson['fail_reason'] = $reason;
|
||||
}
|
||||
$settlementOrder->ext_json = $extJson;
|
||||
$settlementOrder->save();
|
||||
|
||||
$items = $this->settlementItemRepository->listBySettleNo($settleNo);
|
||||
foreach ($items as $item) {
|
||||
$item->item_status = TradeConstant::SETTLEMENT_STATUS_REVERSED;
|
||||
$item->save();
|
||||
}
|
||||
|
||||
return $settlementOrder->refresh();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据清算明细构造汇总数据。
|
||||
*/
|
||||
private function buildSummary(array $items, array $input): array
|
||||
{
|
||||
if (!empty($items)) {
|
||||
$grossAmount = 0;
|
||||
$feeAmount = 0;
|
||||
$refundAmount = 0;
|
||||
$feeReverseAmount = 0;
|
||||
$netAmount = 0;
|
||||
|
||||
foreach ($items as $item) {
|
||||
$grossAmount += (int) ($item['pay_amount'] ?? 0);
|
||||
$feeAmount += (int) ($item['fee_amount'] ?? 0);
|
||||
$refundAmount += (int) ($item['refund_amount'] ?? 0);
|
||||
$feeReverseAmount += (int) ($item['fee_reverse_amount'] ?? 0);
|
||||
$netAmount += (int) ($item['net_amount'] ?? 0);
|
||||
}
|
||||
|
||||
return [
|
||||
'gross_amount' => $grossAmount,
|
||||
'fee_amount' => $feeAmount,
|
||||
'refund_amount' => $refundAmount,
|
||||
'fee_reverse_amount' => $feeReverseAmount,
|
||||
'net_amount' => $netAmount,
|
||||
'accounted_amount' => $input['accounted_amount'] ?? $netAmount,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'gross_amount' => (int) ($input['gross_amount'] ?? 0),
|
||||
'fee_amount' => (int) ($input['fee_amount'] ?? 0),
|
||||
'refund_amount' => (int) ($input['refund_amount'] ?? 0),
|
||||
'fee_reverse_amount' => (int) ($input['fee_reverse_amount'] ?? 0),
|
||||
'net_amount' => (int) ($input['net_amount'] ?? 0),
|
||||
'accounted_amount' => (int) ($input['accounted_amount'] ?? 0),
|
||||
];
|
||||
}
|
||||
}
|
||||
226
app/service/payment/settlement/SettlementOrderQueryService.php
Normal file
226
app/service/payment/settlement/SettlementOrderQueryService.php
Normal file
@@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\payment\settlement;
|
||||
|
||||
use app\common\base\BaseService;
|
||||
use app\common\constant\TradeConstant;
|
||||
use app\exception\ResourceNotFoundException;
|
||||
use app\exception\ValidationException;
|
||||
use app\model\payment\SettlementOrder;
|
||||
use app\repository\account\ledger\MerchantAccountLedgerRepository;
|
||||
use app\repository\payment\settlement\SettlementItemRepository;
|
||||
use app\repository\payment\settlement\SettlementOrderRepository;
|
||||
|
||||
/**
|
||||
* 清算订单查询服务。
|
||||
*/
|
||||
class SettlementOrderQueryService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造函数,注入清算订单仓库。
|
||||
*/
|
||||
public function __construct(
|
||||
protected SettlementOrderRepository $settlementOrderRepository,
|
||||
protected SettlementItemRepository $settlementItemRepository,
|
||||
protected MerchantAccountLedgerRepository $merchantAccountLedgerRepository
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询清算订单。
|
||||
*/
|
||||
public function paginate(array $filters = [], int $page = 1, int $pageSize = 10, ?int $merchantId = null)
|
||||
{
|
||||
$query = $this->baseQuery($merchantId);
|
||||
|
||||
$keyword = trim((string) ($filters['keyword'] ?? ''));
|
||||
if ($keyword !== '') {
|
||||
$query->where(function ($builder) use ($keyword) {
|
||||
$builder->where('s.settle_no', 'like', '%' . $keyword . '%')
|
||||
->orWhere('s.trace_no', 'like', '%' . $keyword . '%')
|
||||
->orWhere('m.merchant_no', 'like', '%' . $keyword . '%')
|
||||
->orWhere('m.merchant_name', 'like', '%' . $keyword . '%')
|
||||
->orWhere('g.group_name', 'like', '%' . $keyword . '%')
|
||||
->orWhere('c.name', 'like', '%' . $keyword . '%');
|
||||
});
|
||||
}
|
||||
|
||||
$merchantId = (string) ($filters['merchant_id'] ?? '');
|
||||
if ($merchantId !== '') {
|
||||
$query->where('s.merchant_id', (int) $merchantId);
|
||||
}
|
||||
|
||||
$channelId = (string) ($filters['channel_id'] ?? '');
|
||||
if ($channelId !== '') {
|
||||
$query->where('s.channel_id', (int) $channelId);
|
||||
}
|
||||
|
||||
$status = (string) ($filters['status'] ?? '');
|
||||
if ($status !== '') {
|
||||
$query->where('s.status', (int) $status);
|
||||
}
|
||||
|
||||
$cycleType = (string) ($filters['cycle_type'] ?? '');
|
||||
if ($cycleType !== '') {
|
||||
$query->where('s.cycle_type', (int) $cycleType);
|
||||
}
|
||||
|
||||
$paginator = $query
|
||||
->orderByDesc('s.id')
|
||||
->paginate(max(1, $pageSize), ['*'], 'page', max(1, $page));
|
||||
|
||||
$paginator->getCollection()->transform(function ($row) {
|
||||
return $this->decorateRow($row);
|
||||
});
|
||||
|
||||
return $paginator;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按清算单号查询详情。
|
||||
*/
|
||||
public function findBySettleNo(string $settleNo, ?int $merchantId = null): ?SettlementOrder
|
||||
{
|
||||
$row = $this->baseQuery($merchantId)
|
||||
->where('s.settle_no', $settleNo)
|
||||
->first();
|
||||
|
||||
return $row ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询清算订单详情。
|
||||
*/
|
||||
public function detail(string $settleNo, ?int $merchantId = null): array
|
||||
{
|
||||
$settleNo = trim($settleNo);
|
||||
if ($settleNo === '') {
|
||||
throw new ValidationException('settle_no 不能为空');
|
||||
}
|
||||
|
||||
$settlementOrder = $this->findBySettleNo($settleNo, $merchantId);
|
||||
if (!$settlementOrder) {
|
||||
throw new ResourceNotFoundException('清算单不存在', ['settle_no' => $settleNo]);
|
||||
}
|
||||
|
||||
$traceNo = trim((string) ($settlementOrder->trace_no ?: $settlementOrder->settle_no));
|
||||
$accountLedgers = $traceNo !== ''
|
||||
? $this->merchantAccountLedgerRepository->listByTraceNo($traceNo)
|
||||
: collect();
|
||||
|
||||
if ($accountLedgers->isEmpty()) {
|
||||
$accountLedgers = $this->merchantAccountLedgerRepository->listByBizNo((string) $settlementOrder->settle_no);
|
||||
}
|
||||
|
||||
return [
|
||||
'settlement_order' => $settlementOrder,
|
||||
'items' => $this->settlementItemRepository->listBySettleNo($settleNo),
|
||||
'account_ledgers' => $accountLedgers,
|
||||
'timeline' => $this->buildTimeline($settlementOrder),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建时间线。
|
||||
*/
|
||||
public function buildTimeline(?SettlementOrder $settlementOrder): array
|
||||
{
|
||||
if (!$settlementOrder) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return array_values(array_filter([
|
||||
[
|
||||
'title' => '生成清算单',
|
||||
'status' => 'finish',
|
||||
'at' => $this->formatDateTime($settlementOrder->generated_at ?? null),
|
||||
],
|
||||
$settlementOrder->accounted_at ? [
|
||||
'title' => '入账处理',
|
||||
'status' => 'finish',
|
||||
'at' => $this->formatDateTime($settlementOrder->accounted_at ?? null),
|
||||
] : null,
|
||||
$settlementOrder->completed_at ? [
|
||||
'title' => '清算完成',
|
||||
'status' => 'finish',
|
||||
'at' => $this->formatDateTime($settlementOrder->completed_at ?? null),
|
||||
] : null,
|
||||
$settlementOrder->failed_at ? [
|
||||
'title' => '清算失败',
|
||||
'status' => 'error',
|
||||
'at' => $this->formatDateTime($settlementOrder->failed_at ?? null),
|
||||
'reason' => (string) ($settlementOrder->fail_reason ?? ''),
|
||||
] : null,
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化单条记录。
|
||||
*/
|
||||
private function decorateRow(object $row): object
|
||||
{
|
||||
$row->cycle_type_text = (string) (TradeConstant::settlementCycleMap()[(int) $row->cycle_type] ?? '未知');
|
||||
$row->status_text = (string) (TradeConstant::settlementStatusMap()[(int) $row->status] ?? '未知');
|
||||
$row->gross_amount_text = $this->formatAmount((int) $row->gross_amount);
|
||||
$row->fee_amount_text = $this->formatAmount((int) $row->fee_amount);
|
||||
$row->refund_amount_text = $this->formatAmount((int) $row->refund_amount);
|
||||
$row->fee_reverse_amount_text = $this->formatAmount((int) $row->fee_reverse_amount);
|
||||
$row->net_amount_text = $this->formatAmount((int) $row->net_amount);
|
||||
$row->accounted_amount_text = $this->formatAmount((int) $row->accounted_amount);
|
||||
$row->generated_at_text = $this->formatDateTime($row->generated_at ?? null);
|
||||
$row->accounted_at_text = $this->formatDateTime($row->accounted_at ?? null);
|
||||
$row->completed_at_text = $this->formatDateTime($row->completed_at ?? null);
|
||||
$row->failed_at_text = $this->formatDateTime($row->failed_at ?? null);
|
||||
$row->ext_json_text = $this->formatJson($row->ext_json ?? null);
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一构建查询。
|
||||
*/
|
||||
private function baseQuery(?int $merchantId = null)
|
||||
{
|
||||
$query = $this->settlementOrderRepository->query()
|
||||
->from('ma_settlement_order as s')
|
||||
->leftJoin('ma_merchant as m', 's.merchant_id', '=', 'm.id')
|
||||
->leftJoin('ma_merchant_group as g', 'm.group_id', '=', 'g.id')
|
||||
->leftJoin('ma_payment_channel as c', 's.channel_id', '=', 'c.id')
|
||||
->select([
|
||||
's.id',
|
||||
's.settle_no',
|
||||
's.trace_no',
|
||||
's.merchant_id',
|
||||
's.merchant_group_id',
|
||||
's.channel_id',
|
||||
's.cycle_type',
|
||||
's.cycle_key',
|
||||
's.status',
|
||||
's.gross_amount',
|
||||
's.fee_amount',
|
||||
's.refund_amount',
|
||||
's.fee_reverse_amount',
|
||||
's.net_amount',
|
||||
's.accounted_amount',
|
||||
's.generated_at',
|
||||
's.accounted_at',
|
||||
's.completed_at',
|
||||
's.failed_at',
|
||||
's.fail_reason',
|
||||
's.ext_json',
|
||||
's.created_at',
|
||||
's.updated_at',
|
||||
])
|
||||
->selectRaw("COALESCE(m.merchant_no, '') AS merchant_no")
|
||||
->selectRaw("COALESCE(m.merchant_name, '') AS merchant_name")
|
||||
->selectRaw("COALESCE(g.group_name, '') AS merchant_group_name")
|
||||
->selectRaw("COALESCE(c.name, '') AS channel_name");
|
||||
|
||||
if ($merchantId !== null && $merchantId > 0) {
|
||||
$query->where('s.merchant_id', $merchantId);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
}
|
||||
55
app/service/payment/settlement/SettlementService.php
Normal file
55
app/service/payment/settlement/SettlementService.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace app\service\payment\settlement;
|
||||
|
||||
use app\common\base\BaseService;
|
||||
use app\model\payment\SettlementOrder;
|
||||
|
||||
/**
|
||||
* 清算门面服务。
|
||||
*
|
||||
* 对外保留原有调用契约,内部委托给清算生命周期服务。
|
||||
*/
|
||||
class SettlementService extends BaseService
|
||||
{
|
||||
/**
|
||||
* 构造函数,注入对应依赖。
|
||||
*/
|
||||
public function __construct(
|
||||
protected SettlementOrderQueryService $queryService,
|
||||
protected SettlementLifecycleService $lifecycleService
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建清算单和明细。
|
||||
*/
|
||||
public function createSettlementOrder(array $input, array $items = []): SettlementOrder
|
||||
{
|
||||
return $this->lifecycleService->createSettlementOrder($input, $items);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询清算订单详情。
|
||||
*/
|
||||
public function detail(string $settleNo, ?int $merchantId = null): array
|
||||
{
|
||||
return $this->queryService->detail($settleNo, $merchantId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清算入账成功。
|
||||
*/
|
||||
public function completeSettlement(string $settleNo): SettlementOrder
|
||||
{
|
||||
return $this->lifecycleService->completeSettlement($settleNo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清算失败。
|
||||
*/
|
||||
public function failSettlement(string $settleNo, string $reason = ''): SettlementOrder
|
||||
{
|
||||
return $this->lifecycleService->failSettlement($settleNo, $reason);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user