feat(affiliate): attribution modes, settlement hardening, trusted proxies, QR and poster
- 归因模式可配置(first_touch/last_touch)、停佣开关、懒结算与佣金基数降级复查 - aksrt_get_client_ip 接入 aksrt_trusted_proxies 信任代理名单,防 CDN 头伪造 - 收益页 Canvas 二维码 + 750x1000 推广海报(本地打包 qrcode.min.js,无 CDN) - 契约测试固化归因/海报/信任代理链路
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
const test = require('node:test')
|
||||
const assert = require('node:assert/strict')
|
||||
const fs = require('node:fs')
|
||||
const path = require('node:path')
|
||||
|
||||
const root = path.resolve(__dirname, '..', '..')
|
||||
const read = (...segments) => fs.readFileSync(path.join(root, ...segments), 'utf8')
|
||||
|
||||
test('referral attribution model is a single runtime source with schema surface', () => {
|
||||
const runtime = read('src', 'Settings', 'CreditsRuntime.php')
|
||||
const attribution = read('src', 'Payment', 'ReferralAttribution.php')
|
||||
const phpSchema = read('src', 'Admin', 'Schema', 'SchemaPayment.php')
|
||||
const jsSchema = read('assets', 'admin', 'src', 'schema', 'sections', 'payment', 'affiliate.js')
|
||||
|
||||
// 运行时:唯一枚举与默认值。
|
||||
assert.match(runtime, /referral_attribution_model/)
|
||||
assert.match(runtime, /\['first_touch', 'last_touch'\]/)
|
||||
assert.match(runtime, /'attribution_model' => \$attribution/)
|
||||
|
||||
// 归因行为:capture 末触覆盖、首触保持;注册仲裁按模式取优先方。
|
||||
assert.match(attribution, /\$this->attribution_model\(\) !== 'last_touch'/)
|
||||
assert.match(attribution, /!?\(\$last_touch && \$submitted_valid\)/)
|
||||
assert.match(attribution, /已按最近访问的推广关系绑定/)
|
||||
assert.match(attribution, /已按首次访问的推广关系绑定/)
|
||||
|
||||
// 管理端双 schema 同步暴露该字段。
|
||||
for (const schema of [phpSchema, jsSchema]) {
|
||||
assert.match(schema, /referral_attribution_model/)
|
||||
assert.match(schema, /first_touch/)
|
||||
assert.match(schema, /last_touch/)
|
||||
}
|
||||
})
|
||||
|
||||
test('disabled-code stop-commission switch is wired end to end', () => {
|
||||
const runtime = read('src', 'Settings', 'PaymentRuntime.php')
|
||||
const ledger = read('src', 'Payment', 'CommissionLedger.php')
|
||||
const attribution = read('src', 'Payment', 'ReferralAttribution.php')
|
||||
const phpSchema = read('src', 'Admin', 'Schema', 'SchemaPayment.php')
|
||||
const jsSchema = read('assets', 'admin', 'src', 'schema', 'sections', 'payment', 'affiliate.js')
|
||||
|
||||
assert.match(runtime, /'disabled_code_stops_commission' => !empty\(\$settings\['affiliate_disabled_code_stops_commission'\]\)/)
|
||||
// 记账入口必须在 resolve 推广人之后、写 ledger 之前校验推广码状态。
|
||||
assert.match(ledger, /ReferralAttribution::get_instance\(\)->resolve\(\$buyer\)/)
|
||||
assert.match(ledger, /is_promoter_code_active\(\$promoter\)/)
|
||||
assert.ok(
|
||||
ledger.indexOf('is_promoter_code_active($promoter)') < ledger.indexOf('$wpdb->insert($table'),
|
||||
'disabled-code gate must run before the ledger insert'
|
||||
)
|
||||
assert.match(attribution, /public function is_promoter_code_active\(int \$promoter_id\): bool/)
|
||||
for (const schema of [phpSchema, jsSchema]) {
|
||||
assert.match(schema, /affiliate_disabled_code_stops_commission/)
|
||||
}
|
||||
})
|
||||
|
||||
test('commission base is the discounted payable amount, not the list price', () => {
|
||||
// 下单侧:content 订单金额取优惠链(推广让利 + 优惠券)后的应付净额。
|
||||
const payOrders = read('src', 'Content', 'PayOrders.php')
|
||||
assert.match(payOrders, /\$amount_minor = max\(0, \(int\) \(\$discounted\['payable_minor'\] \?\? 0\)\)/)
|
||||
// 记账侧:佣金基数直接取订单实付金额。
|
||||
const ledger = read('src', 'Payment', 'CommissionLedger.php')
|
||||
assert.match(ledger, /AssetAmount::balance\(is_string\(\$order\['amount'\] \?\? null\) \? \$order\['amount'\] : ''\)/)
|
||||
})
|
||||
|
||||
test('lazy settlement backstop guards the earnings entry points', () => {
|
||||
const ledger = read('src', 'Payment', 'CommissionLedger.php')
|
||||
const attribution = read('src', 'Payment', 'ReferralAttribution.php')
|
||||
|
||||
assert.match(ledger, /private static bool \$lazy_settled = false/)
|
||||
assert.match(ledger, /public function lazy_settle_due\(\): void/)
|
||||
assert.match(ledger, /if \(!\\AKSRT\\Settings\\Settings::affiliate_enabled\(\)\) return;/)
|
||||
assert.ok(
|
||||
ledger.indexOf('lazy_settle_due()') < ledger.indexOf('global \$wpdb; \$table=\$this->table\(\'commission_ledger\'\); \$row=\$wpdb->get_row'),
|
||||
'overview() must trigger the backstop before aggregating balances'
|
||||
)
|
||||
// 收益总览与我的推广两个入口都接入了兜底。
|
||||
assert.match(attribution, /CommissionLedger::get_instance\(\)->lazy_settle_due\(\)/)
|
||||
})
|
||||
Reference in New Issue
Block a user