fix(pre-planting): 签署合同前检查实名认证 + 修正合同金额
- getMergeContractPdf: KYC 为 null 时返回 400,不允许查看合同 - getMergeContractPdf: 从源订单汇总实际绿积分金额,CNY = 绿积分 × 1.1 - Flutter: KYC 错误时显示专用提示 + "去完成实名认证" 按钮 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
b1e5e6b29f
commit
cd73b2dec4
|
|
@ -406,10 +406,19 @@ export class PrePlantingApplicationService {
|
||||||
return m;
|
return m;
|
||||||
});
|
});
|
||||||
|
|
||||||
// 获取用户 KYC 信息
|
// 获取用户 KYC 信息 - 未完成实名认证则不允许查看合同
|
||||||
const kycInfo = await this.identityServiceClient.getUserKycInfo(
|
const kycInfo = await this.identityServiceClient.getUserKycInfo(merge.accountSequence);
|
||||||
merge.accountSequence,
|
if (!kycInfo || !kycInfo.realName) {
|
||||||
);
|
throw new BadRequestException('请先完成实名认证方可查看和签署合同');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从源订单汇总实际支付的绿积分金额
|
||||||
|
const sourceOrders = await this.prisma.prePlantingOrder.findMany({
|
||||||
|
where: { orderNo: { in: merge.sourceOrderNos } },
|
||||||
|
select: { totalAmount: true },
|
||||||
|
});
|
||||||
|
const greenPointsAmount = sourceOrders.reduce((sum, o) => sum + o.totalAmount, 0);
|
||||||
|
const totalAmount = Math.round(greenPointsAmount * 1.1 * 100) / 100; // 含税 CNY
|
||||||
|
|
||||||
// 生成北京时间日期
|
// 生成北京时间日期
|
||||||
const now = new Date(Date.now() + 8 * 60 * 60 * 1000);
|
const now = new Date(Date.now() + 8 * 60 * 60 * 1000);
|
||||||
|
|
@ -417,10 +426,12 @@ export class PrePlantingApplicationService {
|
||||||
|
|
||||||
return this.pdfGeneratorService.generateContractPdf({
|
return this.pdfGeneratorService.generateContractPdf({
|
||||||
contractNo: mergeNo,
|
contractNo: mergeNo,
|
||||||
userRealName: kycInfo?.realName || '未认证',
|
userRealName: kycInfo.realName,
|
||||||
userIdCard: kycInfo?.idCardNumber || '',
|
userIdCard: kycInfo.idCardNumber || '',
|
||||||
userPhone: kycInfo?.phoneNumber || '',
|
userPhone: kycInfo.phoneNumber || '',
|
||||||
treeCount: merge.treeCount,
|
treeCount: merge.treeCount,
|
||||||
|
totalAmount,
|
||||||
|
greenPointsAmount,
|
||||||
signingDate,
|
signingDate,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'package:go_router/go_router.dart';
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import '../../../../core/di/injection_container.dart';
|
import '../../../../core/di/injection_container.dart';
|
||||||
import '../../../../core/services/pre_planting_service.dart';
|
import '../../../../core/services/pre_planting_service.dart';
|
||||||
|
import '../../../../routes/route_paths.dart';
|
||||||
import '../../../contract_signing/presentation/widgets/signature_pad.dart';
|
import '../../../contract_signing/presentation/widgets/signature_pad.dart';
|
||||||
|
|
||||||
/// 预种合并合同签署页面
|
/// 预种合并合同签署页面
|
||||||
|
|
@ -38,6 +39,7 @@ class _PrePlantingMergeSigningPageState
|
||||||
bool _isSubmitting = false;
|
bool _isSubmitting = false;
|
||||||
bool _showSignaturePad = false;
|
bool _showSignaturePad = false;
|
||||||
String? _errorMessage;
|
String? _errorMessage;
|
||||||
|
bool _isKycRequired = false;
|
||||||
int _downloadProgress = 0;
|
int _downloadProgress = 0;
|
||||||
int _downloadRetryCount = 0;
|
int _downloadRetryCount = 0;
|
||||||
|
|
||||||
|
|
@ -90,10 +92,13 @@ class _PrePlantingMergeSigningPageState
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('[MergeSigningPage] PDF加载失败: $e');
|
debugPrint('[MergeSigningPage] PDF加载失败: $e');
|
||||||
if (mounted) {
|
if (mounted) {
|
||||||
|
final msg = e.toString();
|
||||||
|
final isKyc = msg.contains('实名认证') || msg.contains('400');
|
||||||
setState(() {
|
setState(() {
|
||||||
_isPdfLoading = false;
|
_isPdfLoading = false;
|
||||||
_downloadRetryCount++;
|
_isKycRequired = isKyc;
|
||||||
_errorMessage = '加载合同失败,请点击重试';
|
_errorMessage = isKyc ? '请先完成实名认证方可查看和签署合同' : '加载合同失败,请点击重试';
|
||||||
|
if (!isKyc) _downloadRetryCount++;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -306,8 +311,11 @@ class _PrePlantingMergeSigningPageState
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.cloud_download_outlined,
|
Icon(
|
||||||
color: Color(0xFFD4AF37), size: 56),
|
_isKycRequired ? Icons.person_off_outlined : Icons.cloud_download_outlined,
|
||||||
|
color: _isKycRequired ? Colors.red : const Color(0xFFD4AF37),
|
||||||
|
size: 56,
|
||||||
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(
|
Text(
|
||||||
_errorMessage!,
|
_errorMessage!,
|
||||||
|
|
@ -315,17 +323,29 @@ class _PrePlantingMergeSigningPageState
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
ElevatedButton.icon(
|
if (_isKycRequired)
|
||||||
onPressed: _loadPdf,
|
ElevatedButton.icon(
|
||||||
style: ElevatedButton.styleFrom(
|
onPressed: () => context.push(RoutePaths.kycEntry),
|
||||||
backgroundColor: const Color(0xFFD4AF37),
|
style: ElevatedButton.styleFrom(
|
||||||
padding: const EdgeInsets.symmetric(
|
backgroundColor: Colors.red,
|
||||||
horizontal: 32, vertical: 12)),
|
padding: const EdgeInsets.symmetric(
|
||||||
icon: const Icon(Icons.refresh, color: Colors.white),
|
horizontal: 32, vertical: 12)),
|
||||||
label: const Text('重试',
|
icon: const Icon(Icons.verified_user, color: Colors.white),
|
||||||
style: TextStyle(color: Colors.white, fontSize: 16)),
|
label: const Text('去完成实名认证',
|
||||||
),
|
style: TextStyle(color: Colors.white, fontSize: 16)),
|
||||||
if (_downloadRetryCount > 0)
|
)
|
||||||
|
else
|
||||||
|
ElevatedButton.icon(
|
||||||
|
onPressed: _loadPdf,
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: const Color(0xFFD4AF37),
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 32, vertical: 12)),
|
||||||
|
icon: const Icon(Icons.refresh, color: Colors.white),
|
||||||
|
label: const Text('重试',
|
||||||
|
style: TextStyle(color: Colors.white, fontSize: 16)),
|
||||||
|
),
|
||||||
|
if (!_isKycRequired && _downloadRetryCount > 0)
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 12),
|
padding: const EdgeInsets.only(top: 12),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue