- 后台「支付&付费 → 售后策略」:售后功能开关、申请时效、超时效提示(HTML)、 预置原因、申请售后说明、所需材料、申请说明占位文案、可上传图片开关; PHP schema 与 SPA schema 1:1 对齐,group 字段支持拖拽排序 - PaymentRuntime 新增售后设置解析(缺键回退 schema 默认、HTML 走 kses、 中文原因稳定 slug)与 after_sale_expired 时效判定(支付时间起算) - 售后工单支持举证图片(order_aftersale.images 列,最多 3 张, 复用评论图片上传校验)与上传路由;订单视图模型输出 after_sale 按钮状态 - 前台申请 / 超时效提示 / 售后详细三个独立弹窗(modal-mini + 蓝色炫彩头), 订单详情弹窗不再内嵌售后表单并清理相关死代码 - 新增 after-sale-policy 契约测试与运行时 harness,527 项契约测试通过
118 lines
3.9 KiB
PHP
118 lines
3.9 KiB
PHP
<?php
|
|
/**
|
|
* After-sale policy runtime harness.
|
|
*
|
|
* Covers the 「支付&付费 → 售后策略」 runtime resolution: schema defaults when the
|
|
* section was never saved, stored overrides, HTML sanitisation, preset-reason
|
|
* slugs, and the after_sale_expired boundary matrix.
|
|
*/
|
|
|
|
namespace {
|
|
define('ABSPATH', __DIR__);
|
|
define('DAY_IN_SECONDS', 86400);
|
|
|
|
$GLOBALS['aksrt_test_options'] = [];
|
|
$GLOBALS['aksrt_test_now'] = 0;
|
|
|
|
function sanitize_key($value): string {
|
|
return preg_replace('/[^a-z0-9_\-]/', '', strtolower((string) $value)) ?? '';
|
|
}
|
|
|
|
function sanitize_text_field($value): string {
|
|
return trim(preg_replace('/[\r\n\t]+/', ' ', strip_tags((string) $value)) ?? '');
|
|
}
|
|
|
|
function sanitize_textarea_field($value): string {
|
|
return trim(strip_tags((string) $value));
|
|
}
|
|
|
|
function wp_kses_post($value): string {
|
|
$value = preg_replace('#<script\b[^>]*>.*?</script>#is', '', (string) $value);
|
|
return strip_tags($value, '<a><b><strong><em><i><span><div><p><br><ul><ol><li>');
|
|
}
|
|
|
|
function esc_url_raw($value): string {
|
|
return (string) $value;
|
|
}
|
|
|
|
function wp_json_encode($value): string {
|
|
return (string) json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|
}
|
|
|
|
function get_option(string $name, $default = false) {
|
|
return $GLOBALS['aksrt_test_options'][$name] ?? $default;
|
|
}
|
|
|
|
function update_option(string $name, $value): bool {
|
|
$GLOBALS['aksrt_test_options'][$name] = $value;
|
|
return true;
|
|
}
|
|
|
|
function current_time(string $type, $gmt = false) {
|
|
return $GLOBALS['aksrt_test_now'];
|
|
}
|
|
}
|
|
|
|
namespace AKSRT\Settings {
|
|
class Settings {
|
|
public static function get_all(): array {
|
|
$stored = get_option('aksrt_settings', []);
|
|
return is_array($stored) ? $stored : [];
|
|
}
|
|
|
|
public static function read_domain(string $domain, string $section = ''): array {
|
|
return \AKSRT\Admin\SchemaProvider::get_instance()->read_settings($domain, $section);
|
|
}
|
|
|
|
public static function flush_settings_cache(): void {}
|
|
}
|
|
}
|
|
|
|
namespace {
|
|
require_once dirname(__DIR__, 2) . '/src/Admin/Schema/SchemaPayment.php';
|
|
require_once dirname(__DIR__, 2) . '/src/Admin/SchemaProvider.php';
|
|
require_once dirname(__DIR__, 2) . '/src/Settings/PaymentRuntime.php';
|
|
|
|
$GLOBALS['aksrt_test_now'] = strtotime('2026-03-01 12:00:00');
|
|
|
|
// 1) Section never saved: the runtime still resolves schema defaults.
|
|
$defaults = \AKSRT\Settings\PaymentRuntime::get_after_sale_settings();
|
|
|
|
// 2) Stored values override defaults; HTML fields are kses'ed.
|
|
update_option('aksrt_settings', [
|
|
'after_sale_s' => false,
|
|
'after_sale_time_limit' => 30,
|
|
'after_sale_expired_text' => '<div>已超过时效</div><script>alert(1)</script>',
|
|
'after_sale_reasons' => [['t' => '质量问题'], ['t' => '发错货']],
|
|
'after_sale_desc' => '<div>请保持商品完好</div><script>alert(2)</script>',
|
|
'after_sale_materials' => [['t' => '联系邮箱']],
|
|
'after_sale_reason_placeholder' => '请描述问题',
|
|
'after_sale_img_s' => false,
|
|
]);
|
|
$overridden = \AKSRT\Settings\PaymentRuntime::get_after_sale_settings();
|
|
|
|
// 3) Expiry boundary matrix: measured from paid_at, strictly beyond the limit.
|
|
$matrix = [];
|
|
$boundary_cases = [
|
|
'within' => ['2026-02-25 00:00:00', 7, false],
|
|
'exact_boundary' => ['2026-02-22 12:00:00', 7, false],
|
|
'just_expired' => ['2026-02-22 11:59:59', 7, true],
|
|
'long_expired' => ['2026-01-01 00:00:00', 7, true],
|
|
'no_limit' => ['2020-01-01 00:00:00', 0, false],
|
|
'missing_paid' => ['', 7, false],
|
|
];
|
|
$stored = get_option('aksrt_settings', []);
|
|
foreach ($boundary_cases as $name => $case) {
|
|
[$paid_at, $limit, $expected] = $case;
|
|
$stored['after_sale_time_limit'] = $limit;
|
|
update_option('aksrt_settings', $stored);
|
|
$matrix[$name] = \AKSRT\Settings\PaymentRuntime::after_sale_expired($paid_at) === $expected;
|
|
}
|
|
|
|
echo json_encode([
|
|
'defaults' => $defaults,
|
|
'overridden' => $overridden,
|
|
'expired_ok' => $matrix,
|
|
], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
|
}
|