feat(payment): rebuild order details and asset records
This commit is contained in:
1 parent
476e2f961d
commit
7b55cfb190
57 files changed
+2080
-1294
No files matched your search
@@ -196,6 +196,26 @@ final class LedgerQuery {
|
||||
return 0;
|
||||
}
|
||||
$asset = AssetType::from_value($asset);
|
||||
if (in_array($asset, [AssetType::BALANCE, AssetType::POINTS], true) && class_exists('AKSRT\\Credits\\MetaAssetService')) {
|
||||
$meta_key = $asset === AssetType::POINTS ? 'points_record' : 'balance_record';
|
||||
$records = get_user_meta($user_id, $meta_key, true);
|
||||
$total = 0;
|
||||
foreach (is_array($records) ? $records : [] as $record) {
|
||||
if (!is_array($record) || sanitize_key((string) ($record['type'] ?? '')) !== $reason) continue;
|
||||
$value = $record['value'] ?? 0;
|
||||
if ($asset === AssetType::POINTS) {
|
||||
$delta = is_int($value) ? $value : (preg_match('/^\d+$/', (string) $value) ? (int) $value : 0);
|
||||
} else {
|
||||
$raw = (string) $value;
|
||||
if (str_starts_with($raw, '-')) continue;
|
||||
try { $delta = AssetAmount::balance($raw)->minor(); } catch (\InvalidArgumentException $e) { $delta = 0; }
|
||||
}
|
||||
if ($delta > 0) {
|
||||
$total = $total > PHP_INT_MAX - $delta ? PHP_INT_MAX : $total + $delta;
|
||||
}
|
||||
}
|
||||
return $total;
|
||||
}
|
||||
$entry_table = \AKSRT\Core\DBMigrator::table('asset_entry');
|
||||
$transaction_table = \AKSRT\Core\DBMigrator::table('asset_transaction');
|
||||
return max(0, (int) $wpdb->get_var($wpdb->prepare(
|
||||
|
||||
@@ -37,6 +37,12 @@ final class LedgerService {
|
||||
}
|
||||
|
||||
public function balance(int $user_id, AssetType|string $asset): int {
|
||||
$asset = AssetType::from_value($asset);
|
||||
if (in_array($asset, [AssetType::BALANCE, AssetType::POINTS], true) && class_exists('\AKSRT\Credits\MetaAssetService')) {
|
||||
return $asset === AssetType::POINTS
|
||||
? \AKSRT\Credits\MetaAssetService::get_instance()->balance_points($user_id)
|
||||
: \AKSRT\Credits\MetaAssetService::get_instance()->balance_minor($user_id);
|
||||
}
|
||||
global $wpdb;
|
||||
if ($user_id <= 0) {
|
||||
return 0;
|
||||
@@ -51,6 +57,9 @@ final class LedgerService {
|
||||
}
|
||||
|
||||
public function balance_decimal(int $user_id): string {
|
||||
if (class_exists('\AKSRT\Credits\MetaAssetService')) {
|
||||
return \AKSRT\Credits\MetaAssetService::get_instance()->balance_decimal($user_id);
|
||||
}
|
||||
return AssetAmount::from_minor(AssetType::BALANCE, $this->balance($user_id, AssetType::BALANCE))->decimal();
|
||||
}
|
||||
|
||||
@@ -95,6 +104,24 @@ final class LedgerService {
|
||||
if ($amount_minor <= 0) {
|
||||
return new \WP_Error('aksrt_ledger_amount', __('入账金额必须大于零', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
if (in_array($asset, [AssetType::BALANCE, AssetType::POINTS], true) && class_exists('\AKSRT\Credits\MetaAssetService')) {
|
||||
$command = new LedgerCommand(
|
||||
$operation_key,
|
||||
sanitize_key($reason),
|
||||
[[
|
||||
'user_id' => $user_id,
|
||||
'asset' => $asset->value,
|
||||
'delta_minor' => $amount_minor,
|
||||
'entry_type' => 'credit',
|
||||
'remark' => $remark,
|
||||
]],
|
||||
$this->ref_type($ref),
|
||||
$this->ref_key($ref),
|
||||
$actor_user_id,
|
||||
array_merge($metadata, ['order_number' => $metadata['order_number'] ?? ($ref['key'] ?? '')])
|
||||
);
|
||||
return $this->post_meta_command($command, $guard, $business_mutation);
|
||||
}
|
||||
return $this->post(new LedgerCommand(
|
||||
$operation_key,
|
||||
sanitize_key($reason),
|
||||
@@ -137,6 +164,24 @@ final class LedgerService {
|
||||
if ($amount_minor <= 0) {
|
||||
return new \WP_Error('aksrt_ledger_amount', __('扣减金额必须大于零', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
if (in_array($asset, [AssetType::BALANCE, AssetType::POINTS], true) && class_exists('\AKSRT\Credits\MetaAssetService')) {
|
||||
$command = new LedgerCommand(
|
||||
$operation_key,
|
||||
sanitize_key($reason),
|
||||
[[
|
||||
'user_id' => $user_id,
|
||||
'asset' => $asset->value,
|
||||
'delta_minor' => -$amount_minor,
|
||||
'entry_type' => 'debit',
|
||||
'remark' => $remark,
|
||||
]],
|
||||
$this->ref_type($ref),
|
||||
$this->ref_key($ref),
|
||||
$actor_user_id,
|
||||
array_merge($metadata, ['order_number' => $metadata['order_number'] ?? ($ref['key'] ?? '')])
|
||||
);
|
||||
return $this->post_meta_command($command, $guard, $business_mutation);
|
||||
}
|
||||
return $this->post(new LedgerCommand(
|
||||
$operation_key,
|
||||
sanitize_key($reason),
|
||||
@@ -179,6 +224,11 @@ final class LedgerService {
|
||||
if ($sender_id <= 0 || $recipient_id <= 0 || $sender_id === $recipient_id || $gross_minor <= 0 || $fee_minor < 0 || $fee_minor >= $gross_minor) {
|
||||
return new \WP_Error('aksrt_ledger_transfer', __('转账参数无效', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
if (in_array($asset, [AssetType::BALANCE, AssetType::POINTS], true) && class_exists('\AKSRT\Credits\MetaAssetService')) {
|
||||
return $this->post_meta_command(
|
||||
LedgerCommand::transfer($operation_key, sanitize_key($reason), $sender_id, $recipient_id, $asset, $gross_minor, $fee_minor, $this->ref_type($ref), $this->ref_key($ref), $sender_remark, $recipient_remark, array_merge($metadata, ['order_number' => $ref['key'] ?? '']))
|
||||
);
|
||||
}
|
||||
return $this->post(LedgerCommand::transfer(
|
||||
$operation_key,
|
||||
sanitize_key($reason),
|
||||
@@ -214,12 +264,26 @@ final class LedgerService {
|
||||
if ($user_id <= 0 || $balance_minor <= 0 || $points <= 0) {
|
||||
return new \WP_Error('aksrt_ledger_exchange', __('兑换参数无效', 'aksrt'), ['status' => 400]);
|
||||
}
|
||||
if (class_exists('\AKSRT\Credits\MetaAssetService')) {
|
||||
return $this->post_meta_command(new LedgerCommand(
|
||||
$operation_key,
|
||||
sanitize_key($reason),
|
||||
[
|
||||
['user_id' => $user_id, 'asset' => AssetType::BALANCE->value, 'delta_minor' => -$balance_minor, 'entry_type' => 'debit', 'remark' => $remark],
|
||||
['user_id' => $user_id, 'asset' => AssetType::POINTS->value, 'delta_minor' => $points, 'entry_type' => 'credit', 'remark' => $remark],
|
||||
],
|
||||
$this->ref_type($ref),
|
||||
$this->ref_key($ref),
|
||||
$user_id,
|
||||
array_merge($metadata, ['order_number' => $ref['key'] ?? ''])
|
||||
), $guard, $business_mutation);
|
||||
}
|
||||
return $this->post(new LedgerCommand(
|
||||
$operation_key,
|
||||
sanitize_key($reason),
|
||||
[
|
||||
['user_id' => $user_id, 'asset' => AssetType::BALANCE->value, 'delta_minor' => -$balance_minor, 'entry_type' => 'exchange_out', 'remark' => $remark],
|
||||
['user_id' => $user_id, 'asset' => AssetType::POINTS->value, 'delta_minor' => $points, 'entry_type' => 'exchange_in', 'remark' => $remark],
|
||||
['user_id' => $user_id, 'asset' => AssetType::BALANCE->value, 'delta_minor' => -$balance_minor, 'entry_type' => 'debit', 'remark' => $remark],
|
||||
['user_id' => $user_id, 'asset' => AssetType::POINTS->value, 'delta_minor' => $points, 'entry_type' => 'credit', 'remark' => $remark],
|
||||
],
|
||||
$this->ref_type($ref),
|
||||
$this->ref_key($ref),
|
||||
@@ -234,6 +298,10 @@ final class LedgerService {
|
||||
* @return LedgerResult|\WP_Error
|
||||
*/
|
||||
public function post(LedgerCommand $command, ?callable $guard = null, ?callable $business_mutation = null) {
|
||||
$assets = array_values(array_unique(array_map(static fn(array $entry): string => (string) ($entry['asset'] ?? ''), $command->entries)));
|
||||
if ($assets !== [] && count(array_diff($assets, [AssetType::BALANCE->value, AssetType::POINTS->value])) === 0 && class_exists('\AKSRT\Credits\MetaAssetService')) {
|
||||
return $this->post_meta_command($command, $guard, $business_mutation);
|
||||
}
|
||||
if ($this->transaction_active) {
|
||||
return new \WP_Error('aksrt_ledger_nested', __('账务事务内禁止再次提交账务', 'aksrt'), ['status' => 500]);
|
||||
}
|
||||
@@ -253,6 +321,45 @@ final class LedgerService {
|
||||
return new \WP_Error('aksrt_ledger_db', __('账务处理失败,请稍后重试', 'aksrt'), ['status' => 500]);
|
||||
}
|
||||
|
||||
/** @return LedgerResult|\WP_Error */
|
||||
private function post_meta_command(LedgerCommand $command, ?callable $guard = null, ?callable $business_mutation = null) {
|
||||
if ($this->transaction_active) {
|
||||
return new \WP_Error('aksrt_ledger_nested', __('账务事务内禁止再次提交账务', 'aksrt'), ['status' => 500]);
|
||||
}
|
||||
$this->transaction_active = true;
|
||||
$this->after_commit_callbacks = [];
|
||||
try {
|
||||
$result = \AKSRT\Credits\MetaAssetService::get_instance()->post_command($command, $guard, $business_mutation);
|
||||
$callbacks = is_wp_error($result) ? [] : $this->after_commit_callbacks;
|
||||
$this->after_commit_callbacks = [];
|
||||
if (!is_wp_error($result)) {
|
||||
$this->transaction_active = false;
|
||||
if (!$result->replayed) {
|
||||
try {
|
||||
do_action('aksrt_asset_transaction_committed', $result, $command);
|
||||
} catch (\Throwable $error) {
|
||||
if (defined('WP_DEBUG') && WP_DEBUG) {
|
||||
error_log('[AKSRT Meta Asset Event] ' . $error->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($callbacks as $callback) {
|
||||
try {
|
||||
$callback();
|
||||
} catch (\Throwable $error) {
|
||||
if (defined('WP_DEBUG') && WP_DEBUG) {
|
||||
error_log('[AKSRT Meta Asset After Commit] ' . $error->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
} finally {
|
||||
$this->transaction_active = false;
|
||||
$this->after_commit_callbacks = [];
|
||||
}
|
||||
}
|
||||
|
||||
private function attempt_post(LedgerCommand $command, string $payload_hash, ?callable $guard, ?callable $business_mutation) {
|
||||
global $wpdb;
|
||||
$account_table = $this->table('asset_account');
|
||||
@@ -531,7 +638,7 @@ final class LedgerService {
|
||||
if (isset($wpdb->last_errno)) {
|
||||
return (int) $wpdb->last_errno;
|
||||
}
|
||||
if (preg_match('/\\b(1205|1213)\\b/', (string) ($wpdb->last_error ?? ''), $matches)) {
|
||||
if (preg_match('/\b(1205|1213)\b/', (string) ($wpdb->last_error ?? ''), $matches)) {
|
||||
return (int) $matches[1];
|
||||
}
|
||||
return 0;
|
||||
|
||||
Reference in new issue
Block a user