@@ -83,20 +83,38 @@ function executionCashPolicyConflict(form) {
8383 return allowMarginExplicitlySelected ( form ) && reserveCashOverrideActive ( form ) ;
8484}
8585
86- // --- 修复后的 reconcileExecutionCashPolicy ---
86+ // --- 修复后的 reconcileExecutionCashPolicy (save/restore) ---
8787function reconcileExecutionCashPolicy ( form , changed ) {
8888 if ( ! form ) return ;
8989 if ( changed === "margin" && allowMarginExplicitlySelected ( form ) ) {
90+ // Save current reserve state so it can be restored if margin is later disabled
91+ if ( form . reservePolicyMode !== "none" && ( form . minReservedCashUsd || form . reservedCashRatio ) ) {
92+ form . _prevReserve = {
93+ mode : form . reservePolicyMode ,
94+ floor : form . minReservedCashUsd ,
95+ ratio : form . reservedCashRatio ,
96+ } ;
97+ }
9098 form . reservePolicyMode = "none" ;
9199 form . reservedCashTouched = true ;
92- form . minReservedCashUsd = "" ;
93- form . reservedCashRatio = "" ;
100+ // Keep minReservedCashUsd and reservedCashRatio — will be restored if margin toggled back
94101 } else if ( changed === "reserve" && reserveCashOverrideActive ( form ) ) {
95102 form . cashOnlyExecutionMode = "enabled" ;
96103 form . cashOnlyExecutionTouched = true ;
97104 }
98105}
99106
107+ // --- cash-only change handler restore logic (extracted for testing) ---
108+ function restoreReserveAfterMarginDisabled ( form ) {
109+ if ( ! allowMarginExplicitlySelected ( form ) && form . _prevReserve ) {
110+ form . reservePolicyMode = form . _prevReserve . mode ;
111+ form . minReservedCashUsd = form . _prevReserve . floor ;
112+ form . reservedCashRatio = form . _prevReserve . ratio ;
113+ form . reservedCashTouched = true ;
114+ delete form . _prevReserve ;
115+ }
116+ }
117+
100118// --- 数据辅助函数 ---
101119function cleanOptionalBoolean ( value ) {
102120 if ( value === true || value === "true" || value === "1" || value === 1 ) return true ;
@@ -289,9 +307,12 @@ console.log("\n=== 3. reconcileExecutionCashPolicy (修复后) ===\n");
289307 } ;
290308 reconcileExecutionCashPolicy ( form , "margin" ) ;
291309 assert ( form . reservePolicyMode === "none" , "3a: margin=yes → reservePolicyMode='none'" ) ;
292- assert ( form . minReservedCashUsd === "" , "3a: margin=yes → minReservedCashUsd cleared " ) ;
293- assert ( form . reservedCashRatio === "" , "3a: margin=yes → reservedCashRatio cleared " ) ;
310+ assert ( form . minReservedCashUsd === "10000 " , "3a: margin=yes → minReservedCashUsd PRESERVED " ) ;
311+ assert ( form . reservedCashRatio === "0.05 " , "3a: margin=yes → reservedCashRatio PRESERVED " ) ;
294312 assert ( form . reservedCashTouched === true , "3a: margin=yes → reservedCashTouched=true" ) ;
313+ assert ( form . _prevReserve . mode === "current" , "3a: margin=yes → _prevReserve saved" ) ;
314+ assert ( form . _prevReserve . floor === "10000" , "3a: margin=yes → _prevReserve.floor saved" ) ;
315+ assert ( form . _prevReserve . ratio === "0.05" , "3a: margin=yes → _prevReserve.ratio saved" ) ;
295316}
296317
297318// 3b: 选择"允许融资: 是",当前 reserve=current,无值
@@ -305,7 +326,8 @@ console.log("\n=== 3. reconcileExecutionCashPolicy (修复后) ===\n");
305326 } ;
306327 reconcileExecutionCashPolicy ( form , "margin" ) ;
307328 assert ( form . reservePolicyMode === "none" , "3b: margin=yes (no values) → still 'none'" ) ;
308- assert ( form . minReservedCashUsd === "" , "3b: margin=yes (no values) → floor cleared" ) ;
329+ assert ( form . minReservedCashUsd === "" , "3b: margin=yes (no values) → floor empty" ) ;
330+ assert ( form . _prevReserve === undefined , "3b: no values → _prevReserve NOT saved" ) ;
309331}
310332
311333// 3c: 选择"允许融资: 否" → 不影响预留现金
@@ -669,7 +691,7 @@ console.log("\n=== 8. 回归测试:旧行为不应出现 ===\n");
669691 // 新代码:直接执行
670692 reconcileExecutionCashPolicy ( form , "margin" ) ;
671693 assert ( form . reservePolicyMode === "none" , "8a: new code → reserve cleared regardless" ) ;
672- assert ( form . minReservedCashUsd === "" , "8a: new code → values cleared " ) ;
694+ assert ( form . minReservedCashUsd === "10000 " , "8a: new code → values preserved for restore " ) ;
673695}
674696
675697// 8b: 旧 bug — 初始加载 margin=enabled 时 reserve 仍显示值
@@ -979,5 +1001,119 @@ console.log("\n=== 12. 互斥 UI 不再禁用选项 ===\n");
9791001 assert ( executionCashPolicyConflict ( form ) === false , "12b: no conflict after reconciliation" ) ;
9801002}
9811003
1004+ // ============================================================
1005+ // 13. 融资切换 save/restore 预留现金配置
1006+ // ============================================================
1007+
1008+ console . log ( "\n=== 13. Save/Restore 预留现金配置 ===\n" ) ;
1009+
1010+ // 13a: 用户开融资 → 值保留 → 关融资 → 值恢复
1011+ {
1012+ const form = {
1013+ cashOnlyExecutionMode : "enabled" , // 当前:不允许融资
1014+ reservePolicyMode : "ratio" ,
1015+ minReservedCashUsd : "" ,
1016+ reservedCashRatio : "0.05" ,
1017+ reservedCashTouched : true ,
1018+ cashOnlyExecutionTouched : false ,
1019+ } ;
1020+ // 用户选"允许融资: 是"
1021+ form . cashOnlyExecutionMode = "disabled" ;
1022+ form . cashOnlyExecutionTouched = true ;
1023+ reconcileExecutionCashPolicy ( form , "margin" ) ;
1024+ assert ( form . reservePolicyMode === "none" , "13a-step1: reserve cleared to 'none'" ) ;
1025+ assert ( form . reservedCashRatio === "0.05" , "13a-step1: ratio value preserved" ) ;
1026+ assert ( form . _prevReserve . mode === "ratio" , "13a-step1: prev mode saved" ) ;
1027+ assert ( form . _prevReserve . ratio === "0.05" , "13a-step1: prev ratio saved" ) ;
1028+
1029+ // 用户选"允许融资: 否" → 恢复
1030+ form . cashOnlyExecutionMode = "enabled" ;
1031+ restoreReserveAfterMarginDisabled ( form ) ;
1032+ assert ( form . reservePolicyMode === "ratio" , "13a-step2: reserve restored to 'ratio'" ) ;
1033+ assert ( form . reservedCashRatio === "0.05" , "13a-step2: ratio restored" ) ;
1034+ assert ( form . _prevReserve === undefined , "13a-step2: _prevReserve cleaned up" ) ;
1035+ }
1036+
1037+ // 13b: 用户开融资 → 关融资 → 手动改 reserve → 再开再关不复原旧值
1038+ {
1039+ const form = {
1040+ cashOnlyExecutionMode : "enabled" ,
1041+ reservePolicyMode : "max" ,
1042+ minReservedCashUsd : "10000" ,
1043+ reservedCashRatio : "0.03" ,
1044+ reservedCashTouched : true ,
1045+ cashOnlyExecutionTouched : false ,
1046+ } ;
1047+ // 开融资
1048+ form . cashOnlyExecutionMode = "disabled" ;
1049+ reconcileExecutionCashPolicy ( form , "margin" ) ;
1050+ assert ( form . reservePolicyMode === "none" , "13b-step1: cleared" ) ;
1051+ assert ( form . _prevReserve . mode === "max" , "13b-step1: prev 'max' saved" ) ;
1052+
1053+ // 关融资 → 恢复
1054+ form . cashOnlyExecutionMode = "enabled" ;
1055+ restoreReserveAfterMarginDisabled ( form ) ;
1056+ assert ( form . reservePolicyMode === "max" , "13b-step2: restored to 'max'" ) ;
1057+
1058+ // 用户手动改为 floor
1059+ form . reservePolicyMode = "floor" ;
1060+ form . minReservedCashUsd = "5000" ;
1061+ form . reservedCashRatio = "" ;
1062+ delete form . _prevReserve ;
1063+
1064+ // 再开融资
1065+ form . cashOnlyExecutionMode = "disabled" ;
1066+ reconcileExecutionCashPolicy ( form , "margin" ) ;
1067+ assert ( form . _prevReserve . mode === "floor" , "13b-step3: prev 'floor' saved" ) ;
1068+ assert ( form . _prevReserve . floor === "5000" , "13b-step3: prev floor saved" ) ;
1069+
1070+ // 再关融资 → 恢复 floor
1071+ form . cashOnlyExecutionMode = "enabled" ;
1072+ restoreReserveAfterMarginDisabled ( form ) ;
1073+ assert ( form . reservePolicyMode === "floor" , "13b-step4: restored to 'floor'" ) ;
1074+ assert ( form . minReservedCashUsd === "5000" , "13b-step4: floor restored" ) ;
1075+ }
1076+
1077+ // 13c: reserve=none 时开融资不应保存 _prevReserve
1078+ {
1079+ const form = {
1080+ cashOnlyExecutionMode : "enabled" ,
1081+ reservePolicyMode : "none" ,
1082+ minReservedCashUsd : "" ,
1083+ reservedCashRatio : "" ,
1084+ reservedCashTouched : false ,
1085+ } ;
1086+ form . cashOnlyExecutionMode = "disabled" ;
1087+ reconcileExecutionCashPolicy ( form , "margin" ) ;
1088+ assert ( form . _prevReserve === undefined , "13c: reserve=none → no _prevReserve saved" ) ;
1089+ }
1090+
1091+ // 13d: margin 切到 "enabled" 但无 _prevReserve → 不动
1092+ {
1093+ const form = {
1094+ cashOnlyExecutionMode : "disabled" ,
1095+ reservePolicyMode : "none" ,
1096+ minReservedCashUsd : "" ,
1097+ reservedCashRatio : "" ,
1098+ _prevReserve : undefined ,
1099+ } ;
1100+ form . cashOnlyExecutionMode = "enabled" ;
1101+ restoreReserveAfterMarginDisabled ( form ) ;
1102+ assert ( form . reservePolicyMode === "none" , "13d: no _prevReserve → stays 'none'" ) ;
1103+ }
1104+
1105+ // 13e: account switch 清除 _prevReserve
1106+ {
1107+ const form = {
1108+ cashOnlyExecutionMode : "disabled" ,
1109+ reservePolicyMode : "none" ,
1110+ minReservedCashUsd : "10000" ,
1111+ reservedCashRatio : "0.05" ,
1112+ _prevReserve : { mode : "max" , floor : "10000" , ratio : "0.05" } ,
1113+ } ;
1114+ delete form . _prevReserve ; // simulate account switch
1115+ assert ( form . _prevReserve === undefined , "13e: account switch clears _prevReserve" ) ;
1116+ }
1117+
9821118// ============================================================
9831119summary ( ) ;
0 commit comments