Files
wordpress-theme-aksrt/src/Core/FrontSubmitPay.php
T
kate522 264f2c51b2 fix(admin): replicate reference front-submit settings page 1:1
- Rewrite post_list/submit schema (PHP + JS) with the reference theme's
  field set, order, defaults and dependencies; topics fields excluded
- Map PostDisplay::get_submit_settings() and the FrontSubmit runtime to
  the new keys without legacy fallback
- Guest submission follows the capability matrix; category required on
  submit; pay limits read from the cash/points fieldset
- Drop dead front_submit_* settings, template branches and JS config
- Add submit settings reference contract test
2026-09-24 12:29:19 +08:00

225 lines
10 KiB
PHP

<?php
/**
* @package AKSRT
*/
namespace AKSRT\Core;
defined('ABSPATH') || exit;
/**
* Front-end pay meta save for article submit.
*/
trait FrontSubmitPay {
/**
* @param array<string, mixed> $data
* @param array<string, mixed> $settings
* @return array{success:bool,message?:string}
*/
private function save_pay_meta(int $post_id, array $data, int $user_id, array $settings): array {
if (!$this->user_can_cap('new_post_pay', $user_id)) {
return ['success' => true];
}
// Only touch pay meta when the form sent pay fields.
$has_pay_payload = isset($data['aksrt_pay']) || isset($data['pay_enabled']);
if (!$has_pay_payload) {
return ['success' => true];
}
$raw = is_array($data['aksrt_pay'] ?? null) ? $data['aksrt_pay'] : [];
$enabled = !empty($data['pay_enabled']);
$existing = function_exists('aksrt_get_pay_meta') ? aksrt_get_pay_meta($post_id) : DomainModel::default_pay_meta();
$meta = is_array($existing) ? $existing : DomainModel::default_pay_meta();
if (!$enabled) {
$meta['pay_type'] = DomainModel::PAY_TYPE_NO;
$this->write_pay_meta($post_id, $meta);
return ['success' => true];
}
$pay_modo = sanitize_key((string) ($raw['pay_modo'] ?? '0'));
$pay_modo = $pay_modo === 'points' ? 'points' : '0';
$pay_type = DomainModel::normalize_pay_type((string) ($raw['pay_type'] ?? DomainModel::PAY_TYPE_READING));
if ($pay_type === DomainModel::PAY_TYPE_NO) {
$pay_type = DomainModel::PAY_TYPE_READING;
}
$downloads = DomainModel::sanitize_downloads($raw['downloads'] ?? []);
if ($this->user_can_cap('new_post_pay_download', $user_id)) {
$meta['downloads'] = $downloads;
if ($downloads !== []) {
$pay_type = DomainModel::PAY_TYPE_DOWNLOAD;
} elseif ($pay_type === DomainModel::PAY_TYPE_DOWNLOAD) {
$pay_type = DomainModel::PAY_TYPE_READING;
}
} elseif ($pay_type === DomainModel::PAY_TYPE_DOWNLOAD) {
$pay_type = DomainModel::PAY_TYPE_READING;
$meta['downloads'] = [];
}
$meta['pay_type'] = $pay_type;
$meta['pay_modo'] = $pay_modo;
$allow_free = !empty($settings['pay_free_s']);
$vip_manual = !empty($settings['pay_vip_price_s']);
$vip1_enabled = !array_key_exists('pay_vip_1_enabled', $settings) || !empty($settings['pay_vip_1_enabled']);
$vip2_enabled = !array_key_exists('pay_vip_2_enabled', $settings) || !empty($settings['pay_vip_2_enabled']);
$vip1_disc = (int) ($settings['pay_vip_1_discount'] ?? 100);
$vip2_disc = (int) ($settings['pay_vip_2_discount'] ?? 100);
if ($pay_modo === 'points') {
$points = $this->parse_front_points($raw['points_price'] ?? $data['points_price'] ?? null);
$min = max(0, (int) ($settings['pay_points_min'] ?? 0));
$max = max(0, (int) ($settings['pay_points_max'] ?? 0));
if ($points === null) {
return ['success' => false, 'message' => __('请设置正确的积分价格', 'aksrt')];
}
if (!$allow_free && $points <= 0) {
return ['success' => false, 'message' => __('请设置付费内容的积分价格', 'aksrt')];
}
if ($min > 0 && $points < $min) {
return ['success' => false, 'message' => sprintf(__('积分价格不能低于:%s', 'aksrt'), (string) $min)];
}
if ($max > 0 && $points > $max) {
return ['success' => false, 'message' => sprintf(__('积分价格不能高于:%s', 'aksrt'), (string) $max)];
}
if ($vip_manual) {
$vip1 = $vip1_enabled
? $this->parse_front_points($raw['vip1_points'] ?? null)
: 0;
$vip2 = $vip2_enabled
? $this->parse_front_points($raw['vip2_points'] ?? null)
: 0;
if (($vip1_enabled && $vip1 === null) || ($vip2_enabled && $vip2 === null)) {
return ['success' => false, 'message' => __('请设置正确的会员积分价格', 'aksrt')];
}
if ($vip1_enabled && $vip1 > $points) {
return ['success' => false, 'message' => __('会员积分价格不能高于普通积分价格', 'aksrt')];
}
if ($vip2_enabled && $vip2 > ($vip1_enabled ? $vip1 : $points)) {
return ['success' => false, 'message' => __('更高等级会员积分价格不能高于较低等级会员积分价格', 'aksrt')];
}
} else {
$vip1 = (intdiv($points, 100) * $vip1_disc) + intdiv(($points % 100) * $vip1_disc, 100);
$vip2 = (intdiv($points, 100) * $vip2_disc) + intdiv(($points % 100) * $vip2_disc, 100);
}
$vip1 = max(0, min($points, (int) $vip1));
$vip2 = max(0, min($vip1_enabled ? $vip1 : $points, (int) $vip2));
$meta['points_price'] = $points;
$meta['price'] = '0.00';
$meta['vip1_points'] = $vip1;
$meta['vip2_points'] = $vip2;
$meta['vip1_price'] = '0.00';
$meta['vip2_price'] = '0.00';
} else {
$price_minor = $this->parse_front_cash_minor($raw['price'] ?? null);
$min_yuan = max(0, (int) ($settings['pay_price_min'] ?? 0));
$max_yuan = max(0, (int) ($settings['pay_price_max'] ?? 0));
$min_minor = $min_yuan > 0 ? \AKSRT\Ledger\AssetAmount::balance((string) $min_yuan)->minor() : 0;
$max_minor = $max_yuan > 0 ? \AKSRT\Ledger\AssetAmount::balance((string) $max_yuan)->minor() : 0;
if ($price_minor === null) {
return ['success' => false, 'message' => __('请设置正确的价格', 'aksrt')];
}
if (!$allow_free && $price_minor <= 0) {
return ['success' => false, 'message' => __('请设置付费内容的价格', 'aksrt')];
}
if ($min_minor > 0 && $price_minor < $min_minor) {
return ['success' => false, 'message' => sprintf(__('价格不能低于:%s', 'aksrt'), \AKSRT\Ledger\AssetAmount::decimal_from_minor($min_minor))];
}
if ($max_minor > 0 && $price_minor > $max_minor) {
return ['success' => false, 'message' => sprintf(__('价格不能高于:%s', 'aksrt'), \AKSRT\Ledger\AssetAmount::decimal_from_minor($max_minor))];
}
if ($vip_manual) {
$vip1_minor = $vip1_enabled
? $this->parse_front_cash_minor($raw['vip1_price'] ?? null)
: 0;
$vip2_minor = $vip2_enabled
? $this->parse_front_cash_minor($raw['vip2_price'] ?? null)
: 0;
if (($vip1_enabled && $vip1_minor === null) || ($vip2_enabled && $vip2_minor === null)) {
return ['success' => false, 'message' => __('请设置正确的会员价格', 'aksrt')];
}
if ($vip1_enabled && $vip1_minor > $price_minor) {
return ['success' => false, 'message' => __('会员价不能高于普通价', 'aksrt')];
}
if ($vip2_enabled && $vip2_minor > ($vip1_enabled ? $vip1_minor : $price_minor)) {
return ['success' => false, 'message' => __('更高等级会员价不能高于较低等级会员价', 'aksrt')];
}
} else {
$vip1_minor = \AKSRT\Ledger\AssetAmount::percentage($price_minor, max(0, min(100, $vip1_disc)));
$vip2_minor = \AKSRT\Ledger\AssetAmount::percentage($price_minor, max(0, min(100, $vip2_disc)));
}
$vip1_minor = max(0, min($price_minor, (int) $vip1_minor));
$vip2_minor = max(0, min($vip1_enabled ? $vip1_minor : $price_minor, (int) $vip2_minor));
$meta['price'] = \AKSRT\Ledger\AssetAmount::decimal_from_minor($price_minor);
$meta['points_price'] = 0;
$meta['vip1_price'] = \AKSRT\Ledger\AssetAmount::decimal_from_minor($vip1_minor);
$meta['vip2_price'] = \AKSRT\Ledger\AssetAmount::decimal_from_minor($vip2_minor);
$meta['vip1_points'] = 0;
$meta['vip2_points'] = 0;
}
$pay_limit = (int) ($raw['pay_limit'] ?? 0);
$meta['pay_limit'] = in_array($pay_limit, [0, 1, 2], true) ? $pay_limit : 0;
$this->write_pay_meta($post_id, $meta);
return ['success' => true];
}
private function parse_front_points($value): ?int {
if (is_int($value)) {
return $value >= 0 ? $value : null;
}
if (!is_string($value) || !preg_match('/^(0|[1-9]\d*)$/', trim($value))) {
return null;
}
$value = trim($value);
if (strlen($value) > strlen((string) PHP_INT_MAX)
|| (strlen($value) === strlen((string) PHP_INT_MAX) && strcmp($value, (string) PHP_INT_MAX) > 0)
) {
return null;
}
return (int) $value;
}
private function parse_front_cash_minor($value): ?int {
if (!is_string($value)) {
return null;
}
try {
return \AKSRT\Ledger\AssetAmount::balance_minor($value);
} catch (\InvalidArgumentException $e) {
return null;
}
}
/**
* @param array<string, mixed> $meta
*/
private function write_pay_meta(int $post_id, array $meta): void {
$meta = DomainModel::sanitize_pay_meta($meta);
update_post_meta($post_id, DomainModel::PAY_META_KEY, $meta);
update_post_meta($post_id, DomainModel::PAY_TYPE_KEY, (string) ($meta['pay_type'] ?? DomainModel::PAY_TYPE_NO));
update_post_meta(
$post_id,
DomainModel::PAY_PRICE_KEY,
($meta['pay_modo'] ?? '0') === 'points'
? (int) ($meta['points_price'] ?? 0)
: (string) ($meta['price'] ?? '0.00')
);
update_post_meta(
$post_id,
DomainModel::RESOURCE_MARKER_KEY,
DomainModel::is_resource_pay_type((string) ($meta['pay_type'] ?? 'no')) ? 1 : 0
);
}
}