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
@@ -14,7 +14,7 @@ class DBMigrator {
|
||||
use DBMigratorVip;
|
||||
|
||||
/** Current schema version; changing it re-runs dbDelta. */
|
||||
const SCHEMA_VERSION = '2.1.0';
|
||||
const SCHEMA_VERSION = '2.5.0';
|
||||
|
||||
const OPT_KEY = 'aksrt_db_schema_version';
|
||||
|
||||
|
||||
@@ -204,6 +204,29 @@ trait DBMigratorPart2 {
|
||||
) ENGINE=InnoDB {$charset_collate};";
|
||||
dbDelta($sql_order);
|
||||
|
||||
// ---------- order after-sales ----------
|
||||
$sql_order_aftersale = "CREATE TABLE {$prefix}aksrt_order_aftersale (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
order_number VARCHAR(32) NOT NULL,
|
||||
user_id BIGINT UNSIGNED NOT NULL,
|
||||
aftersale_type VARCHAR(24) NOT NULL DEFAULT 'refund',
|
||||
reason TEXT NOT NULL,
|
||||
refund_amount VARCHAR(32) NOT NULL DEFAULT '0',
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'pending',
|
||||
admin_note TEXT DEFAULT NULL,
|
||||
gateway_request_id VARCHAR(128) DEFAULT NULL,
|
||||
gateway_refund_id VARCHAR(128) DEFAULT NULL,
|
||||
gateway_result LONGTEXT DEFAULT NULL,
|
||||
created_at DATETIME NOT NULL,
|
||||
reviewed_at DATETIME DEFAULT NULL,
|
||||
completed_at DATETIME DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
KEY idx_order_status (order_number, status),
|
||||
KEY idx_user_created (user_id, created_at),
|
||||
KEY idx_status_created (status, created_at)
|
||||
) ENGINE=InnoDB {$charset_collate};";
|
||||
dbDelta($sql_order_aftersale);
|
||||
|
||||
// ---------- 9. 作者收益台账 ----------
|
||||
$sql_revenue = "CREATE TABLE {$prefix}aksrt_revenue (
|
||||
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
@@ -246,12 +269,14 @@ trait DBMigratorPart2 {
|
||||
method VARCHAR(32) NOT NULL DEFAULT '',
|
||||
account_info TEXT DEFAULT NULL,
|
||||
status VARCHAR(20) NOT NULL DEFAULT 'pending',
|
||||
operation_key VARCHAR(191) DEFAULT NULL,
|
||||
ledger_transaction_id BIGINT UNSIGNED DEFAULT NULL,
|
||||
created_at DATETIME NOT NULL,
|
||||
processed_at DATETIME DEFAULT NULL,
|
||||
note TEXT DEFAULT NULL,
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uniq_withdrawal_number (withdrawal_number),
|
||||
UNIQUE KEY uniq_withdrawal_operation (operation_key),
|
||||
UNIQUE KEY uniq_ledger_transaction (ledger_transaction_id),
|
||||
KEY idx_user (user_id),
|
||||
KEY idx_user_created (user_id, created_at),
|
||||
|
||||
@@ -25,6 +25,7 @@ trait DBMigratorPart3 {
|
||||
'dl_token' => 'aksrt_dl_token',
|
||||
'notification' => 'aksrt_notification',
|
||||
'order' => 'aksrt_order',
|
||||
'order_aftersale' => 'aksrt_order_aftersale',
|
||||
'order_item' => 'aksrt_order_item',
|
||||
'revenue' => 'aksrt_revenue',
|
||||
'withdrawal' => 'aksrt_withdrawal',
|
||||
|
||||
@@ -40,6 +40,10 @@ class DomainModel {
|
||||
];
|
||||
|
||||
public const ORDER_PRODUCT_RESOURCE = 'resource';
|
||||
public const ORDER_PRODUCT_READING = 'reading';
|
||||
public const ORDER_PRODUCT_DOWNLOAD = 'download';
|
||||
public const ORDER_PRODUCT_IMAGE = 'image';
|
||||
public const ORDER_PRODUCT_VIDEO = 'video';
|
||||
public const ORDER_PRODUCT_VIP = 'vip';
|
||||
public const ORDER_PRODUCT_RECHARGE = 'recharge';
|
||||
public const ORDER_PRODUCT_POINTS = 'points';
|
||||
@@ -51,13 +55,53 @@ class DomainModel {
|
||||
*/
|
||||
public static function order_product_type_labels(): array {
|
||||
return [
|
||||
self::ORDER_PRODUCT_RESOURCE => __('付费内容', 'aksrt'),
|
||||
self::ORDER_PRODUCT_VIP => __('VIP 会员', 'aksrt'),
|
||||
self::ORDER_PRODUCT_READING => __('付费阅读', 'aksrt'),
|
||||
self::ORDER_PRODUCT_DOWNLOAD => __('付费下载', 'aksrt'),
|
||||
self::ORDER_PRODUCT_IMAGE => __('付费图片', 'aksrt'),
|
||||
self::ORDER_PRODUCT_VIDEO => __('付费视频', 'aksrt'),
|
||||
self::ORDER_PRODUCT_VIP => __('购买会员', 'aksrt'),
|
||||
self::ORDER_PRODUCT_RECHARGE => __('余额充值', 'aksrt'),
|
||||
self::ORDER_PRODUCT_POINTS => __('积分购买', 'aksrt'),
|
||||
self::ORDER_PRODUCT_POINTS => __('购买积分', 'aksrt'),
|
||||
];
|
||||
}
|
||||
|
||||
public static function is_resource_product_type(string $type): bool {
|
||||
return in_array(sanitize_key($type), [
|
||||
self::ORDER_PRODUCT_RESOURCE,
|
||||
self::ORDER_PRODUCT_READING,
|
||||
self::ORDER_PRODUCT_DOWNLOAD,
|
||||
self::ORDER_PRODUCT_IMAGE,
|
||||
self::ORDER_PRODUCT_VIDEO,
|
||||
], true);
|
||||
}
|
||||
|
||||
/** Resolve new and historical paid-content order types from stored order meta. */
|
||||
public static function resolve_order_product_type(string $stored_type, array $meta = []): string {
|
||||
$stored_type = sanitize_key($stored_type);
|
||||
if ($stored_type !== self::ORDER_PRODUCT_RESOURCE) {
|
||||
return isset(self::order_product_type_labels()[$stored_type]) ? $stored_type : $stored_type;
|
||||
}
|
||||
$pay_type = sanitize_key((string) ($meta['pay_type'] ?? $meta['content_pay_type'] ?? ''));
|
||||
return match ($pay_type) {
|
||||
self::PAY_TYPE_READING => self::ORDER_PRODUCT_READING,
|
||||
self::PAY_TYPE_DOWNLOAD => self::ORDER_PRODUCT_DOWNLOAD,
|
||||
self::PAY_TYPE_GALLERY => self::ORDER_PRODUCT_IMAGE,
|
||||
self::PAY_TYPE_VIDEO => self::ORDER_PRODUCT_VIDEO,
|
||||
default => self::ORDER_PRODUCT_READING,
|
||||
};
|
||||
}
|
||||
|
||||
/** @return string[] */
|
||||
public static function resource_order_product_types(): array {
|
||||
return [
|
||||
self::ORDER_PRODUCT_RESOURCE,
|
||||
self::ORDER_PRODUCT_READING,
|
||||
self::ORDER_PRODUCT_DOWNLOAD,
|
||||
self::ORDER_PRODUCT_IMAGE,
|
||||
self::ORDER_PRODUCT_VIDEO,
|
||||
];
|
||||
}
|
||||
|
||||
public const PAY_TYPE_NO = 'no';
|
||||
public const PAY_TYPE_READING = 'reading';
|
||||
public const PAY_TYPE_DOWNLOAD = 'download';
|
||||
@@ -67,7 +111,6 @@ class DomainModel {
|
||||
|
||||
public const ORDER_STATUS_PENDING = 'pending';
|
||||
public const ORDER_STATUS_PAID = 'paid';
|
||||
public const ORDER_STATUS_REFUNDING = 'refunding';
|
||||
public const ORDER_STATUS_REFUNDED = 'refunded';
|
||||
public const ORDER_STATUS_CLOSED = 'closed';
|
||||
|
||||
@@ -454,7 +497,6 @@ class DomainModel {
|
||||
return [
|
||||
self::ORDER_STATUS_PENDING => __('待支付', 'aksrt'),
|
||||
self::ORDER_STATUS_PAID => __('已支付', 'aksrt'),
|
||||
self::ORDER_STATUS_REFUNDING => __('退款中', 'aksrt'),
|
||||
self::ORDER_STATUS_REFUNDED => __('已退款', 'aksrt'),
|
||||
self::ORDER_STATUS_CLOSED => __('已关闭', 'aksrt'),
|
||||
];
|
||||
@@ -470,11 +512,7 @@ class DomainModel {
|
||||
self::ORDER_STATUS_CLOSED,
|
||||
],
|
||||
self::ORDER_STATUS_PAID => [
|
||||
self::ORDER_STATUS_REFUNDING,
|
||||
],
|
||||
self::ORDER_STATUS_REFUNDING => [
|
||||
self::ORDER_STATUS_REFUNDED,
|
||||
self::ORDER_STATUS_PAID,
|
||||
],
|
||||
self::ORDER_STATUS_REFUNDED => [],
|
||||
self::ORDER_STATUS_CLOSED => [],
|
||||
@@ -500,6 +538,8 @@ class DomainModel {
|
||||
public static function paid_order_statuses(): array {
|
||||
return [
|
||||
self::ORDER_STATUS_PAID,
|
||||
// Read-only compatibility: normalize_row exposes legacy in-flight refunds as paid.
|
||||
'refunding',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user