first commit
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace app\common\service\pharmacy;
|
||||
|
||||
use Closure;
|
||||
use DomainException;
|
||||
use InvalidArgumentException;
|
||||
use Throwable;
|
||||
|
||||
final class PharmacySubmissionClaimWorkflow
|
||||
{
|
||||
private Closure $acquireClaim;
|
||||
private Closure $invokeRemote;
|
||||
private Closure $markSuccess;
|
||||
private Closure $markFailure;
|
||||
private Closure $markReconcile;
|
||||
|
||||
public function __construct(
|
||||
callable $acquireClaim,
|
||||
callable $invokeRemote,
|
||||
callable $markSuccess,
|
||||
callable $markFailure,
|
||||
callable $markReconcile
|
||||
) {
|
||||
$this->acquireClaim = Closure::fromCallable($acquireClaim);
|
||||
$this->invokeRemote = Closure::fromCallable($invokeRemote);
|
||||
$this->markSuccess = Closure::fromCallable($markSuccess);
|
||||
$this->markFailure = Closure::fromCallable($markFailure);
|
||||
$this->markReconcile = Closure::fromCallable($markReconcile);
|
||||
}
|
||||
|
||||
/** @return array<string,mixed> */
|
||||
public function execute(string $target): array
|
||||
{
|
||||
if (!in_array($target, ['gancao', 'direct'], true)) {
|
||||
throw new InvalidArgumentException('Unsupported pharmacy target');
|
||||
}
|
||||
|
||||
$claim = ($this->acquireClaim)($target);
|
||||
if (!empty($claim['idempotent'])) {
|
||||
$result = is_array($claim['result'] ?? null) ? $claim['result'] : [];
|
||||
return $result + ['target' => $target, 'idempotent' => true];
|
||||
}
|
||||
|
||||
$token = trim((string) ($claim['token'] ?? $claim['claim_token'] ?? ''));
|
||||
if ($token === '') {
|
||||
throw new DomainException('药房提交凭证缺失');
|
||||
}
|
||||
$claimStatus = strtoupper(trim((string) ($claim['status'] ?? '')));
|
||||
if ($target === 'gancao' && (
|
||||
!empty($claim['reconcile'])
|
||||
|| in_array($claimStatus, ['UNKNOWN', 'PENDING_RECONCILE'], true)
|
||||
)) {
|
||||
throw new PharmacyReconciliationRequiredException(
|
||||
'甘草药房远端结果待核对,当前禁止重提;请等待人工或后续对账'
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
$result = ($this->invokeRemote)($target, $token, $claim);
|
||||
if (!is_array($result)) {
|
||||
throw new DomainException('药房返回数据格式错误');
|
||||
}
|
||||
} catch (Throwable $exception) {
|
||||
if (PharmacyRemoteOutcomeClassifier::isConfirmedNoCreate($exception)) {
|
||||
($this->markFailure)($target, $token, $exception->getMessage(), $claim);
|
||||
} else {
|
||||
($this->markReconcile)($target, $token, $exception->getMessage(), $claim);
|
||||
}
|
||||
throw $exception;
|
||||
}
|
||||
|
||||
try {
|
||||
$finalized = (bool) ($this->markSuccess)($target, $token, $result, $claim);
|
||||
} catch (Throwable $exception) {
|
||||
($this->markReconcile)($target, $token, '远端成功但本地回写异常:' . $exception->getMessage(), $claim);
|
||||
throw new PharmacyReconciliationRequiredException(
|
||||
'远端可能已创建订单,本地回写失败,必须对账后再操作',
|
||||
0,
|
||||
$exception
|
||||
);
|
||||
}
|
||||
if (!$finalized) {
|
||||
($this->markReconcile)($target, $token, '远端成功但本地提交凭证无法完成', $claim);
|
||||
throw new PharmacyReconciliationRequiredException('远端已返回成功,本地回写未完成,必须对账后再操作');
|
||||
}
|
||||
|
||||
return $result + ['target' => $target, 'idempotent' => false];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user