From 8a02b7fd11f20e578979b909c3ba81159934606a Mon Sep 17 00:00:00 2001 From: gaofeng <1212121@qq.com> Date: Wed, 9 Sep 2026 10:42:06 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/miniapi/controller/VisaApplication.php | 53 +++++++++++++------ app/miniapi/route/app.php | 5 ++ .../VisaApplicationService.php | 11 ++-- tests/visa_application_facade_self_check.php | 1 + 4 files changed, 51 insertions(+), 19 deletions(-) diff --git a/app/miniapi/controller/VisaApplication.php b/app/miniapi/controller/VisaApplication.php index ce39c68..26b47f0 100644 --- a/app/miniapi/controller/VisaApplication.php +++ b/app/miniapi/controller/VisaApplication.php @@ -8,35 +8,56 @@ use app\miniapi\service\VisaApplication\VisaApplicationService; final class VisaApplication extends Base { + public function directForm() { return $this->call(fn($service,$userId) => $service->directForm($userId,$this->postData(),$this->orderSource())); } + public function directStatus() { return $this->call(fn($service,$userId) => $service->directStatus($userId,$this->postData(),$this->orderSource())); } + public function directSubmit() { return $this->submitOrder(true); } public function options() { return $this->call(fn($service, $userId) => $service->options($userId, $this->orderSource())); } public function start() { return $this->call(fn($service, $userId) => $service->start($userId, $this->postData(), $this->orderSource())); } - public function application() { return $this->call(fn($service, $userId) => $service->application($userId, trim((string)$this->request->param('public_id', '')))); } + public function application() { return $this->call(fn($service, $userId) => $service->application($userId, trim((string)$this->request->param('public_id', '')), trim((string)$this->request->param('submission_token', '')))); } public function draft() { return $this->call(fn($service, $userId) => $service->saveDraft($userId, $this->postData()), '草稿已保存'); } - public function submit() + public function submit() { return $this->submitOrder(false); } + private function submitOrder(bool $direct) { $userId = $this->requireLogin(); if (!is_int($userId)) return $userId; $input = $this->postData(); - $result = (new VisaApplicationService())->submit($userId, $input); + $service = new VisaApplicationService(); + $result = $direct ? $service->directSubmit($userId,$input,$this->orderSource()) : $service->submit($userId,$input); if ((int)($result['code'] ?? 0) !== 1) return $this->fail((string)($result['msg'] ?? '服务异常,请稍后重试')); $data = (array)($result['data'] ?? []); + $data['submission_status'] = 'submitted'; if (!empty($data['requires_payment'])) { - $target = VisaApplicationService::nativePaymentForCheck($data); - $openid = trim((string)($input['openid'] ?? '')); - if (!$target || $openid === '') return $this->fail($openid === '' ? '微信用户信息缺失,请重新登录后支付' : '支付订单信息异常'); - $pay = (new MiniPayService())->requestForTarget( - $this->currentMiniAppContext('visa'), - $target['order_sn'], - $target['money'], - $openid, - $target['target_table'], - 'miniapi visa mini pay' - ); - if ((int)($pay['code'] ?? 0) !== 1) return $this->fail((string)($pay['msg'] ?? '支付参数获取失败')); - $data['pay'] = $pay['data']; + if (($data['directory_synced'] ?? true) === false) $data['payment_message'] = '申请已提交,订单目录同步未完成,请联系客服核对'; + elseif (count((array)($data['target_orders'] ?? [])) > 1) $data['payment_message'] = '申请已提交,请在我的申请中按申请人分别支付'; + elseif (array_key_exists('payment_ready', $data) && !$data['payment_ready']) $data['payment_message'] = $data['payment_message'] ?? '申请已提交,请到我的申请查看支付状态'; + else { + $pay = $this->paymentParameters($data, $input); + if ((int)($pay['code'] ?? 0) === 1) $data['pay'] = $pay['data']; + else $data['payment_message'] = (string)($pay['msg'] ?? '支付参数暂不可用'); + } + $data['payment_status'] = isset($data['pay']) ? 'ready' : 'pending'; } unset($data['target_orders'], $data['pay_url']); return $this->ok($data, '提交成功'); } + public function orderDetail() { return $this->call(fn($service, $userId) => $service->orderDetail($userId, ['business' => (string)$this->request->param('business', ''), 'order_sn' => (string)$this->request->param('order_sn', '')])); } + public function orderPayment() + { + $userId = $this->requireLogin(); if (!is_int($userId)) return $userId; + $input = $this->postData(); + $result = (new VisaApplicationService())->orderPayment($userId, ['business' => (string)($input['business'] ?? ''), 'order_sn' => (string)($input['order_sn'] ?? '')]); + if ((int)($result['code'] ?? 0) !== 1) return $this->fail((string)($result['msg'] ?? '支付状态需核对')); + $pay = $this->paymentParameters((array)$result['data'], $input); + return (int)($pay['code'] ?? 0) === 1 ? $this->ok(['pay' => $pay['data']]) : $this->fail((string)($pay['msg'] ?? '支付参数暂不可用')); + } + private function paymentParameters(array $data, array $input): array + { + $target = VisaApplicationService::nativePaymentForCheck($data); + $openid = trim((string)($input['openid'] ?? '')); + if (!$target || $openid === '') return ['code' => 0, 'msg' => $openid === '' ? '请重新登录后到我的申请支付' : '支付订单信息需核对']; + try { + return (new MiniPayService())->requestForTarget($this->currentMiniAppContext('visa'), $target['order_sn'], $target['money'], $openid, $target['target_table'], 'miniapi visa mini pay'); + } catch (\Throwable $e) { return ['code' => 0, 'msg' => '支付参数暂不可用,请到我的申请继续支付']; } + } public function agree() { $result = (new VisaApplicationService())->agree(trim((string)$this->request->param('doc_code', ''))); diff --git a/app/miniapi/route/app.php b/app/miniapi/route/app.php index 7f257d9..962a764 100644 --- a/app/miniapi/route/app.php +++ b/app/miniapi/route/app.php @@ -61,10 +61,15 @@ Route::group(function () { Route::post('evus/apply', 'Evus/apply'); Route::post('esta/apply', 'Esta/apply'); Route::get('visa/options', 'VisaApplication/options'); + Route::post('visa/direct-form', 'VisaApplication/directForm'); + Route::post('visa/direct-submit', 'VisaApplication/directSubmit'); + Route::post('visa/direct-status', 'VisaApplication/directStatus'); Route::post('visa/start', 'VisaApplication/start'); Route::get('visa/application', 'VisaApplication/application'); Route::post('visa/draft', 'VisaApplication/draft'); Route::post('visa/submit', 'VisaApplication/submit'); + Route::get('visa/order-detail', 'VisaApplication/orderDetail'); + Route::post('visa/order-pay', 'VisaApplication/orderPayment'); Route::get('visa/data-source', 'VisaApplication/dataSource'); Route::get('visa/agree', 'VisaApplication/agree'); })->namespace('app\\miniapi\\controller'); diff --git a/app/miniapi/service/VisaApplication/VisaApplicationService.php b/app/miniapi/service/VisaApplication/VisaApplicationService.php index 8689f9b..5e33949 100644 --- a/app/miniapi/service/VisaApplication/VisaApplicationService.php +++ b/app/miniapi/service/VisaApplication/VisaApplicationService.php @@ -8,14 +8,19 @@ use think\facade\Log; final class VisaApplicationService { - private const ACTIONS = ['options', 'start', 'application', 'saveDraft', 'submit', 'dataSource', 'agree']; + private const ACTIONS = ['directForm', 'directSubmit', 'directStatus', 'options', 'start', 'application', 'saveDraft', 'submit', 'dataSource', 'agree', 'orderDetail', 'orderPayment']; private const DATA_SOURCE_PARAMS = ['model', 'source_code', 'page', 'size', 'state_id', 'hotel_state', 'provinceCode', 'country', 'entry_mode', 'province', 'accommodation_province', 'accommodation_municipality', 'city', 'id', 'air_transport_type', 'state', 'japan_province', 'travel_country', 'hotel_city', 'districtCode', 'nationality_iso2', 'next_destination']; + public function directForm(int $userId, array $data, string $source): array { return $this->request('directForm',$userId,array_merge($data,['order_source'=>$source])); } + public function directSubmit(int $userId, array $data, string $source): array { return $this->request('directSubmit',$userId,array_merge($data,['order_source'=>$source])); } + public function directStatus(int $userId, array $data, string $source): array { return $this->request('directStatus',$userId,array_merge($data,['order_source'=>$source])); } public function options(int $userId, string $orderSource): array { return $this->request('options', $userId, ['order_source' => $orderSource]); } public function start(int $userId, array $data, string $orderSource): array { return $this->request('start', $userId, array_merge($data, ['order_source' => $orderSource])); } - public function application(int $userId, string $publicId): array { return $this->request('application', $userId, ['public_id' => $publicId]); } + public function application(int $userId, string $publicId, string $submissionToken = ''): array { return $this->request('application', $userId, ['public_id' => $publicId] + ($submissionToken !== '' ? ['submission_token' => $submissionToken] : [])); } public function saveDraft(int $userId, array $data): array { return $this->request('saveDraft', $userId, $data); } public function submit(int $userId, array $data): array { return self::decorateSubmitForCheck($this->request('submit', $userId, $data)); } + public function orderDetail(int $userId, array $data): array { return $this->request('orderDetail', $userId, $data); } + public function orderPayment(int $userId, array $data): array { return $this->request('orderPayment', $userId, $data); } public function agree(string $docCode): array { if (!preg_match('/^[A-Za-z0-9._-]{1,64}$/', $docCode)) return ['code' => 0, 'msg' => '协议参数错误', 'data' => []]; @@ -25,7 +30,7 @@ final class VisaApplicationService public static function nativePaymentForCheck(array $data): array { $cents = (int)($data['total_price'] ?? 0); - if (empty($data['requires_payment']) || $cents <= 0 || !is_array($data['target_orders'] ?? null)) return []; + if (empty($data['requires_payment']) || $cents <= 0 || !is_array($data['target_orders'] ?? null) || count($data['target_orders']) !== 1) return []; $target = null; foreach ($data['target_orders'] as $item) { if (is_array($item) && (int)($item['applicant_index'] ?? -1) === 0) { $target = $item; break; } diff --git a/tests/visa_application_facade_self_check.php b/tests/visa_application_facade_self_check.php index d64253b..cd9ccf4 100644 --- a/tests/visa_application_facade_self_check.php +++ b/tests/visa_application_facade_self_check.php @@ -28,6 +28,7 @@ $native = VisaApplicationService::nativePaymentForCheck([ ], ]); if ($native !== ['target_table' => 'singapore', 'order_sn' => '2026090412000012', 'money' => '79.00']) throw new RuntimeException('native payment target failed'); +if (VisaApplicationService::nativePaymentForCheck(['requires_payment'=>true,'total_price'=>15800,'target_orders'=>[['target_table'=>'singapore','target_order_sn'=>'1','applicant_index'=>0],['target_table'=>'singapore','target_order_sn'=>'2','applicant_index'=>1]]]) !== []) throw new RuntimeException('must not charge the batch against its first applicant'); if (VisaApplicationService::nativePaymentForCheck(['requires_payment' => true, 'total_price' => 7900, 'target_orders' => [['target_table' => 'bad-table', 'target_order_sn' => '1']]]) !== []) throw new RuntimeException('unsafe payment target accepted'); if (VisaApplicationService::dataSourceQueryForCheck('inac.city', ['model' => 'region', 'source_code' => 'jnwxmini', 'state_id' => '11', 'hotel_state' => '12', 'provinceCode' => '13', 'country' => 'CN', 'application_token' => 'secret', 'user_token' => 'secret']) !== ['type' => 'inac.city', 'model' => 'region', 'source_code' => 'jnwxmini', 'state_id' => '11', 'hotel_state' => '12', 'provinceCode' => '13', 'country' => 'CN']) throw new RuntimeException('miniapi data source filtering failed'); $controllerSource = (string)file_get_contents(dirname(__DIR__) . '/app/miniapi/controller/VisaApplication.php');