93 lines
3.1 KiB
PHP
93 lines
3.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace app\common\service\pharmacy;
|
|
|
|
use Closure;
|
|
use DomainException;
|
|
use think\facade\Db;
|
|
|
|
final class LockedPharmacySnapshotMutation
|
|
{
|
|
/**
|
|
* @param callable():array<string,mixed> $lockOrder
|
|
* @param callable(array<string,mixed>):?array<string,mixed> $lockClaim
|
|
* @param callable(array<string,mixed>,?array<string,mixed>):mixed $mutation
|
|
*/
|
|
public static function run(
|
|
callable $lockOrder,
|
|
callable $lockClaim,
|
|
callable $mutation,
|
|
bool $assertMutable = true
|
|
): mixed {
|
|
$order = Closure::fromCallable($lockOrder)();
|
|
if ($order === []) {
|
|
throw new DomainException('订单不存在');
|
|
}
|
|
$claim = Closure::fromCallable($lockClaim)($order);
|
|
if ($assertMutable) {
|
|
PharmacyRemoteSnapshotPolicy::assertMutable($order, $claim);
|
|
}
|
|
|
|
$result = Closure::fromCallable($mutation)($order, $claim);
|
|
if ($result === false) {
|
|
throw new DomainException('受保护变更未完成,事务已回滚');
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
/** @param callable(array<string,mixed>,?array<string,mixed>):mixed $mutation */
|
|
public static function execute(
|
|
int $orderId,
|
|
callable $mutation,
|
|
bool $assertMutable = true,
|
|
int $revision = 1
|
|
): mixed {
|
|
return Db::transaction(static fn (): mixed => self::run(
|
|
static fn (): array => (array) (Db::name('tcm_prescription_order')
|
|
->where('id', $orderId)
|
|
->whereNull('delete_time')
|
|
->lock(true)
|
|
->find() ?: []),
|
|
static fn (): ?array => Db::name('pharmacy_submission_claim')
|
|
->where('prescription_order_id', $orderId)
|
|
->where('source_revision', max($revision, 1))
|
|
->lock(true)
|
|
->find() ?: null,
|
|
$mutation,
|
|
$assertMutable
|
|
));
|
|
}
|
|
|
|
/** @param callable(array<int,array<string,mixed>>):mixed $mutation */
|
|
public static function executeForPrescription(int $prescriptionId, callable $mutation): mixed
|
|
{
|
|
return Db::transaction(static function () use ($prescriptionId, $mutation): mixed {
|
|
$orders = Db::name('tcm_prescription_order')
|
|
->where('prescription_id', $prescriptionId)
|
|
->whereNull('delete_time')
|
|
->order('id', 'asc')
|
|
->lock(true)
|
|
->select()
|
|
->toArray();
|
|
foreach ($orders as $order) {
|
|
$claim = Db::name('pharmacy_submission_claim')
|
|
->where('prescription_order_id', (int) $order['id'])
|
|
->where('source_revision', 1)
|
|
->lock(true)
|
|
->find();
|
|
PharmacyRemoteSnapshotPolicy::assertMutable($order, $claim ?: null);
|
|
}
|
|
|
|
$result = Closure::fromCallable($mutation)($orders);
|
|
if ($result === false) {
|
|
throw new DomainException('受保护变更未完成,事务已回滚');
|
|
}
|
|
|
|
return $result;
|
|
});
|
|
}
|
|
}
|