Files
miniapi/tests/visa_submission_payment_self_check.php
gaofeng 5be2b76d88 提交
2026-09-11 09:34:15 +08:00

93 lines
8.9 KiB
PHP

<?php
declare(strict_types=1);
namespace {
const MINIAPI_TOKEN_KEY = 'test';
const PAY_MARK = 'evuscn';
function authcode($value, ...$args) { return $value; }
function config($key) { return 'https://example.test/home/users/list'; }
}
namespace think\facade { class Log { static function warning($message) {} } }
namespace api {
class Httpcurl {
public static array $result = [];
public static array $lastPayload = [];
static function request($url, $method, $data) { parse_str($data, self::$lastPayload); return [json_encode(self::$result), null, null, '']; }
}
}
namespace app\miniapi\service\Payment {
class MiniPayService {
public static int $calls = 0;
public static bool $throws = false;
public static array $result = ['code'=>0,'msg'=>'temporary failure'];
function requestForTarget(...$args) { self::$calls++; if (self::$throws) throw new \RuntimeException('offline'); return self::$result; }
}
}
namespace app\miniapi\controller {
class Base {
public array $input = ['openid'=>'test-openid'];
public string $appCode = 'evus_jn_mp';
protected function requireLogin() { return 7; }
protected function postData() { return $this->input; }
protected function currentMiniAppCode() { return $this->appCode; }
protected function currentMiniAppContext($business) { return new \stdClass(); }
protected function ok($data, $msg = '') { return ['code'=>1,'data'=>$data,'msg'=>$msg]; }
protected function fail($msg, $code = 0, $data = []) { return ['code'=>$code,'msg'=>$msg,'data'=>$data]; }
}
}
namespace {
require __DIR__ . '/../app/miniapi/service/VisaApplication/VisaApplicationService.php';
require __DIR__ . '/../app/miniapi/controller/VisaApplication.php';
function checkSubmit($condition, $message) { if (!$condition) throw new RuntimeException($message); }
$controller = new app\miniapi\controller\VisaApplication();
$data = ['order_sn'=>'TEST1','requires_payment'=>true,'total_price'=>7900,'payment_ready'=>true,'payment_business'=>'arrival_card','target_orders'=>[['target_table'=>'singapore','target_order_sn'=>'TEST1','applicant_index'=>0]]];
api\Httpcurl::$result = ['code'=>1,'data'=>$data];
$result = $controller->submit();
checkSubmit($result['code'] === 1 && $result['data']['submission_status'] === 'submitted' && !isset($result['data']['pay']), 'parameter failure must not undo submission');
app\miniapi\service\Payment\MiniPayService::$throws = true;
checkSubmit($controller->submit()['code'] === 1, 'transport exception must not undo submission');
app\miniapi\service\Payment\MiniPayService::$throws = false;
$data['target_orders'][] = ['target_table'=>'singapore','target_order_sn'=>'TEST2','applicant_index'=>1];
api\Httpcurl::$result['data'] = $data;
$before = app\miniapi\service\Payment\MiniPayService::$calls;
checkSubmit($controller->submit()['code'] === 1 && app\miniapi\service\Payment\MiniPayService::$calls === $before, 'batch must not auto-charge first applicant');
api\Httpcurl::$result = ['code'=>0,'msg'=>'validation failed'];
checkSubmit($controller->submit()['code'] === 0, 'actual submission failure remains a failure');
api\Httpcurl::$result = ['code'=>0,'msg'=>'validation failed','data'=>['field_errors'=>[['module_key'=>'traveler','field'=>'passport_number','path'=>'data.applicants.0.traveler.passport_number','message'=>'护照号格式不正确','value'=>'SECRET','money'=>'0.01','mark'=>'forged','target_table'=>'secret']],'target_orders'=>[['target_table'=>'secret']],'pay_url'=>'https://secret.test']];
checkSubmit(($controller->submit()['data'] ?? []) === [], 'legacy submit rejection must not expose direct field metadata');
$controller->appCode = 'evus_jn_app';
$controller->input = ['request_id'=>str_repeat('d',64),'service_code'=>'TEST'];
api\Httpcurl::$result = ['code'=>1,'data'=>['order_sn'=>'TEST1','requires_payment'=>true,'total_price'=>7900,'payment_ready'=>true,'payment_business'=>'arrival_card','target_orders'=>[['target_table'=>'singapore','target_order_sn'=>'TEST1','applicant_index'=>0]],'submission_status'=>'submitted', 'pay_url'=>'https://secret.test']];
$androidStatus = $controller->directStatus();
checkSubmit(($androidStatus['data']['app_payment'] ?? null) === ['order_sn'=>'TEST1','money'=>'79.00','mark'=>'evuscnsingapore','business'=>'arrival_card'] && !isset($androidStatus['data']['target_orders'], $androidStatus['data']['pay_url']), 'android direct status must sanitize internal targets and expose trusted payment business');
$androidForm = $controller->directForm();
checkSubmit(($androidForm['data']['app_payment']['business'] ?? '') === 'arrival_card' && !isset($androidForm['data']['target_orders'], $androidForm['data']['pay_url']), 'android existing direct form result uses the same safe payment shape');
api\Httpcurl::$result = ['code'=>1,'data'=>['order_sn'=>'TEST1','requires_payment'=>true,'total_price'=>7900,'payment_ready'=>false,'directory_synced'=>true,'payment_business'=>'arrival_card','target_orders'=>[['target_table'=>'singapore','target_order_sn'=>'TEST1','applicant_index'=>0]]]];
checkSubmit(!isset($controller->directStatus()['data']['app_payment']), 'android status must not create payment before directory payment readiness');
api\Httpcurl::$result = ['code'=>0,'msg'=>'validation failed','data'=>['field_errors'=>[['module_key'=>'traveler','field'=>'passport_number','path'=>'data.applicants.0.traveler.passport_number','message'=>'护照号格式不正确','value'=>'SECRET','money'=>'0.01','mark'=>'forged','target_table'=>'secret']],'target_orders'=>[['target_table'=>'secret']],'pay_url'=>'https://secret.test']];
$controller->input = ['request_id'=>str_repeat('f',64),'service_code'=>'TEST','nationality_iso2'=>'CN','destination_iso2'=>'SG'];
$safeFailure = $controller->directSubmit();
checkSubmit($safeFailure['code'] === 0 && ($safeFailure['data']['field_errors'] ?? null) === [['module_key'=>'traveler','field_id'=>'passport_number','path'=>'data.applicants.0.traveler.passport_number','message'=>'护照号格式不正确']], 'direct rejection forwards only bounded field location metadata');
checkSubmit(!str_contains(json_encode($safeFailure['data']), 'SECRET') && !str_contains(json_encode($safeFailure['data']), 'forged') && !str_contains(json_encode($safeFailure['data']), 'secret'), 'direct rejection must drop sensitive upstream keys and values');
$controller->appCode = 'evus_jn_mp';
$controller->input = ['openid'=>'test-openid'];
api\Httpcurl::$result = ['code'=>1,'data'=>$data];
$controller->input += ['business'=>'singapore','order_sn'=>'TEST1','total_price'=>1,'target_table'=>'evus'];
api\Httpcurl::$result = ['code'=>1,'data'=>array_merge($data, ['target_orders'=>[$data['target_orders'][0]]])];
app\miniapi\service\Payment\MiniPayService::$result = ['code'=>1,'data'=>['package'=>'prepay_id=test']];
checkSubmit($controller->orderPayment()['code'] === 1, 'per-person payment parameters are forwarded');
checkSubmit(!isset(api\Httpcurl::$lastPayload['total_price'], api\Httpcurl::$lastPayload['target_table']), 'client cannot choose amount or target table');
$controller->input = ['openid'=>'test-openid','request_id'=>str_repeat('a',64),'service_code'=>'TEST','nationality_iso2'=>'CN','destination_iso2'=>'SG'];
checkSubmit($controller->directSubmit()['code'] === 1, 'new direct submit still obtains original native payment parameters');
checkSubmit(api\Httpcurl::$lastPayload['request_id'] === str_repeat('a',64) && !isset(api\Httpcurl::$lastPayload['application_token'],api\Httpcurl::$lastPayload['submission_token']), 'direct submit needs no application credentials');
$claims=json_decode(api\Httpcurl::$lastPayload['user_token'],true);
checkSubmit($claims['order_source']==='jnwxmini' && $claims['user_id']===7, 'new endpoint forwards verified account and source');
$controller->appCode = 'evus_jn_app';
$controller->input = ['request_id'=>str_repeat('b',64),'service_code'=>'TEST','nationality_iso2'=>'CN','destination_iso2'=>'SG','mark'=>'forged','money'=>'0.01','target_table'=>'evus'];
$androidSubmit = $controller->directSubmit();
checkSubmit(($androidSubmit['data']['app_payment'] ?? null) === ['order_sn'=>'TEST1','money'=>'79.00','mark'=>'evuscnsingapore','business'=>'arrival_card'] && !isset($androidSubmit['data']['pay']), 'android direct submit must expose only the server-derived app payment target and business');
$controller->input = ['business'=>'singapore','order_sn'=>'TEST1','mark'=>'forged','money'=>'0.01','target_table'=>'evus'];
$androidRepay = $controller->orderPayment();
checkSubmit(($androidRepay['data']['app_payment'] ?? null) === ['order_sn'=>'TEST1','money'=>'79.00','mark'=>'evuscnsingapore','business'=>'singapore'] && !isset($androidRepay['data']['pay']), 'android repeat payment must only echo the upstream-verified public business');
echo "PASS visa_submission_payment_self_check\n";
}