trustbase-seller-backend 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/routes/onboard.html +118 -55
- package/routes/onboard.js +6 -1
- package/test-onboard-applyment.js +29 -15
package/package.json
CHANGED
package/routes/onboard.html
CHANGED
|
@@ -201,13 +201,10 @@ img.auprev{display:none;width:100%;max-height:140px;object-fit:cover;border-radi
|
|
|
201
201
|
<div class="afield"><label for="a_service_phone">客服电话</label><input id="a_service_phone" placeholder="交易记录向买家展示"></div>
|
|
202
202
|
<div class="afield"><label>结算规则 (按主体自动确定, 不用选)</label>
|
|
203
203
|
<div class="arule" id="a_settlement_rule">719 · 个体户通用(0.6% T+1)</div></div>
|
|
204
|
-
<div class="afield"><label for="
|
|
205
|
-
<
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
<option value="__MANUAL__">手动输入编码</option>
|
|
209
|
-
</select>
|
|
210
|
-
<input id="a_settlement_manual" class="amanual" placeholder="4 位 MCC 编码, 如: 5311" style="display:none"></div>
|
|
204
|
+
<div class="afield"><label for="a_industry_cat">所属行业·大类</label>
|
|
205
|
+
<select id="a_industry_cat"></select></div>
|
|
206
|
+
<div class="afield"><label for="a_settlement_id">所属行业·子类 (微信行业名称)</label>
|
|
207
|
+
<select id="a_settlement_id"></select></div>
|
|
211
208
|
</div>
|
|
212
209
|
</div>
|
|
213
210
|
|
|
@@ -218,7 +215,9 @@ img.auprev{display:none;width:100%;max-height:140px;object-fit:cover;border-radi
|
|
|
218
215
|
<div class="afield"><label for="a_legal_id_number">法人身份证号</label><input id="a_legal_id_number" placeholder="17 位数字 + 数字或 X"></div>
|
|
219
216
|
<div class="afield afield-full" id="afield_idaddr" style="display:none"><label for="a_legal_id_address">身份证居住地址 <span class="aopt">企业主体必填, 本机加密</span></label><input id="a_legal_id_address" placeholder="与身份证住址一致, 如: 广东省深圳市南山区xx路xx号"></div>
|
|
220
217
|
<div class="afield afield-full" id="afield_ubo_note" style="display:none">
|
|
221
|
-
<
|
|
218
|
+
<label for="a_beneficiary">最终受益人</label>
|
|
219
|
+
<select id="a_beneficiary"><option value="legal">法定代表人本人 (默认, 微信自动回填受益人信息)</option><option value="other">他人</option></select>
|
|
220
|
+
<div class="ahint" id="a_beneficiary_hint" style="display:none;margin-top:8px">⚠️ 暂不支持受益人为他人的进件, 请选"法定代表人本人"或联系服务商协助</div>
|
|
222
221
|
</div>
|
|
223
222
|
<div class="afield"><label for="a_period_begin">身份证有效期开始</label><input id="a_period_begin" placeholder="YYYY-MM-DD"></div>
|
|
224
223
|
<div class="afield"><label for="a_period_end">有效期结束</label><input id="a_period_end" placeholder="YYYY-MM-DD 或 长期"></div>
|
|
@@ -822,6 +821,8 @@ function restoreApplyDraft(f){
|
|
|
822
821
|
var e=document.getElementById(PREFILL_MAP[k]);
|
|
823
822
|
if(e&&!e.value) e.value=v;
|
|
824
823
|
}
|
|
824
|
+
// 所属行业 (二级联动定位)
|
|
825
|
+
syncIndustrySelection(f.qualification_type);
|
|
825
826
|
// 照片 media_id 复用 → 槽位已传双态
|
|
826
827
|
PREFILL_MEDIA.forEach(function(k){
|
|
827
828
|
if(f[k]&&_aSlots[k]) _aSlots[k].prefill(f[k]);
|
|
@@ -833,6 +834,18 @@ function restoreApplyDraft(f){
|
|
|
833
834
|
// 草稿恢复了编辑态 → 展开表单
|
|
834
835
|
document.getElementById('apply-form').style.display='block';
|
|
835
836
|
}
|
|
837
|
+
// 所属行业二级联动选中 (预填共用): 合法行业名称 → 定位大类 + 选中子类; 非法/旧 MCC → 保持默认重选
|
|
838
|
+
function syncIndustrySelection(ind){
|
|
839
|
+
if(!ind||String(ind).indexOf('***')===0||/^\d+$/.test(String(ind))||ind==='无') return;
|
|
840
|
+
if(typeof industrySubsFor!=='function') return; // 增强脚本未就绪 (理论不到这)
|
|
841
|
+
var type2=(document.getElementById('a_subject_type')||{}).value||'SUBJECT_TYPE_INDIVIDUAL';
|
|
842
|
+
var hit=industrySubsFor(type2).filter(function(s){return s.n===ind;})[0];
|
|
843
|
+
if(!hit) return;
|
|
844
|
+
var ce=document.getElementById('a_industry_cat');
|
|
845
|
+
if(ce){ ce.value=hit.cat; if(typeof renderIndustrySubs==='function') renderIndustrySubs(false); }
|
|
846
|
+
var se=document.getElementById('a_settlement_id');
|
|
847
|
+
if(se) se.value=ind;
|
|
848
|
+
}
|
|
836
849
|
// 任何字段 input/change → 防抖自动保存 (含场景切换时的字段集; file 选择也走 change)
|
|
837
850
|
(function(){
|
|
838
851
|
var form=document.getElementById('apply-form');
|
|
@@ -849,7 +862,6 @@ var PREFILL_MAP={subject_type:'a_subject_type',merchant_shortname:'a_shortname',
|
|
|
849
862
|
legal_id_period_begin:'a_period_begin',legal_id_period_end:'a_period_end',
|
|
850
863
|
account_type:'a_account_type',account_name:'a_account_name',account_number:'a_account_number',
|
|
851
864
|
account_bank:'a_account_bank',bank_name:'a_bank_name',bank_address_code:'a_bank_address_code',
|
|
852
|
-
qualification_type:'a_settlement_id', // 行业类目 MCC (draft 路径用; snapshot 路径走 mcc 兼容段)
|
|
853
865
|
store_name:'a_store_name',store_address_code:'a_store_address_code',store_address:'a_store_address',
|
|
854
866
|
website_url:'a_website_url',appid:'a_appid',appid_type:'a_appid_type'};
|
|
855
867
|
var PREFILL_MEDIA=['license_media_id','legal_id_front_media_id','legal_id_back_media_id',
|
|
@@ -874,16 +886,9 @@ function prefillApplyForm(snap){
|
|
|
874
886
|
var e=document.getElementById(PREFILL_MAP[k]);
|
|
875
887
|
if(e&&!e.value) e.value=v;
|
|
876
888
|
}
|
|
877
|
-
//
|
|
878
|
-
//
|
|
879
|
-
|
|
880
|
-
if((!mcc||mcc==='无'||mcc==='零售') && snap.settlement_id && ['716','719','727'].indexOf(String(snap.settlement_id))<0){
|
|
881
|
-
mcc=snap.settlement_id;
|
|
882
|
-
}
|
|
883
|
-
if(mcc && mcc!=='无' && String(mcc).indexOf('***')!==0){
|
|
884
|
-
var se=document.getElementById('a_settlement_id');
|
|
885
|
-
if(se&&!se.value) se.value=mcc; // 不在码表 (手填值) 时 select 置空, 商户重选/手填
|
|
886
|
-
}
|
|
889
|
+
// 所属行业预填 (二级联动): 合法行业名称 → 定位所属大类并选中子类;
|
|
890
|
+
// 旧快照 MCC 数字/非法值 → 保持默认让商户重选 (静默不报错)
|
|
891
|
+
syncIndustrySelection(snap.qualification_type);
|
|
887
892
|
// 照片复用: media_id 还在微信侧有效 → 槽位走"已上传"双态 (占位图+替换/删除, 无第二个空框)
|
|
888
893
|
var reused=0;
|
|
889
894
|
PREFILL_MEDIA.forEach(function(k){
|
|
@@ -1006,45 +1011,73 @@ async function restoreIdentity(){
|
|
|
1006
1011
|
① 编码字段下拉+联动 ② 状态卡片着色 + 签约二维码占位。
|
|
1007
1012
|
(证件缩略图预览已于二重框修复时并入主脚本 mountApplyUpload 槽位双态) ===== */
|
|
1008
1013
|
(function(){
|
|
1009
|
-
// ⓪
|
|
1010
|
-
//
|
|
1011
|
-
//
|
|
1012
|
-
//
|
|
1013
|
-
var
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1014
|
+
// ⓪ 所属行业二级联动 (2026-10-03 微信官方网页版实证校准):
|
|
1015
|
+
// qualification_type = 二级子类的名称文本 (如 "零售"), 大类只做导航不上送;
|
|
1016
|
+
// 行业结构 大类>子类, 按主体过滤 (企业全套, 个体户/其他组织子集 — 对照 716/719/727 行业子项);
|
|
1017
|
+
// "所属行业不存在"30+ 次失败的真根因是"服务商不能给自己进件"(业务规则), 行业值 "零售" 一直合法。
|
|
1018
|
+
var INDUSTRY_CATS=[
|
|
1019
|
+
{cat:'餐饮/零售', subs:[
|
|
1020
|
+
{n:'餐饮',lic:1},{n:'零售'},{n:'电商平台',ent:1},{n:'食品生鲜',lic:1},{n:'服饰鞋包'},
|
|
1021
|
+
{n:'文物经营/文物复制品销售',lic:1,ent:1}]},
|
|
1022
|
+
{cat:'交通/加油', subs:[
|
|
1023
|
+
{n:'机票/机票代理',lic:1},{n:'旅行社',lic:1,ent:1},{n:'景区酒店',ent:1}]},
|
|
1024
|
+
{cat:'生活/娱乐', subs:[
|
|
1025
|
+
{n:'宠物医院',lic:1},{n:'共享服务',lic:1,ent:1},{n:'休闲娱乐旅游服务',ent:1},
|
|
1026
|
+
{n:'游艺厅/KTV/网吧',lic:1},{n:'院线影城',lic:1,ent:1},{n:'演出赛事',lic:1,ent:1},
|
|
1027
|
+
{n:'居民生活服务',ent:1},{n:'保健美容SPA',lic:1},{n:'美容理发店'}]},
|
|
1028
|
+
{cat:'互联网服务', subs:[
|
|
1029
|
+
{n:'门户论坛/网络广告及推广/软件开发/其他互联网服务'},{n:'电信运营商/宽带收费',lic:1,ent:1}]},
|
|
1030
|
+
{cat:'房产/金融', subs:[
|
|
1031
|
+
{n:'房地产/房产中介',lic:1,ent:1}]},
|
|
1032
|
+
{cat:'医疗/教育', subs:[
|
|
1033
|
+
{n:'私立/民营医院/诊所',lic:1},{n:'保健器械/医疗器械/非处方药品',lic:1},{n:'教育/培训/考试缴费/学费',lic:1}]},
|
|
1034
|
+
{cat:'其他', subs:[
|
|
1035
|
+
{n:'宗教组织'},{n:'拍卖典当',lic:1,ent:1},{n:'咨询/娱乐票务/其他'}]}
|
|
1036
|
+
];
|
|
1037
|
+
// 其他组织 (727) 子集 (对照表口径)
|
|
1038
|
+
var INDUSTRY_OTHERS_ALLOW=['宗教组织','机票/机票代理','私立/民营医院/诊所','咨询/娱乐票务/其他'];
|
|
1039
|
+
var INDUSTRY_DEFAULT_SUB={SUBJECT_TYPE_ENTERPRISE:'零售',SUBJECT_TYPE_INDIVIDUAL:'零售',SUBJECT_TYPE_OTHERS:'咨询/娱乐票务/其他'};
|
|
1025
1040
|
var subj=document.getElementById('a_subject_type');
|
|
1026
|
-
var stl=document.getElementById('a_settlement_id');
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
var
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
stl.value='5311'; // 默认 百货商店 (综合电商最高频)
|
|
1036
|
-
// 搜索过滤 (45 个选项手翻太长)
|
|
1037
|
-
var filt=document.getElementById('a_settlement_filter');
|
|
1038
|
-
if(filt) filt.addEventListener('input',function(){
|
|
1039
|
-
var q=filt.value.trim().toLowerCase();
|
|
1040
|
-
Array.prototype.forEach.call(stl.options,function(o){
|
|
1041
|
-
if(o.value===''||o.value==='__MANUAL__') return;
|
|
1042
|
-
o.hidden = !!(q && o.textContent.toLowerCase().indexOf(q)<0);
|
|
1041
|
+
var stl=document.getElementById('a_settlement_id'); // 子类下拉 (提交 id 稳定: value=子类名称 → qualification_type)
|
|
1042
|
+
var catEl=document.getElementById('a_industry_cat');
|
|
1043
|
+
function industrySubsFor(type){
|
|
1044
|
+
var out=[];
|
|
1045
|
+
INDUSTRY_CATS.forEach(function(c){
|
|
1046
|
+
c.subs.forEach(function(s){
|
|
1047
|
+
if(type==='SUBJECT_TYPE_ENTERPRISE'){ out.push({cat:c.cat,n:s.n,lic:s.lic}); }
|
|
1048
|
+
else if(type==='SUBJECT_TYPE_OTHERS'){ if(INDUSTRY_OTHERS_ALLOW.indexOf(s.n)>=0) out.push({cat:c.cat,n:s.n,lic:s.lic}); }
|
|
1049
|
+
else if(!s.ent){ out.push({cat:c.cat,n:s.n,lic:s.lic}); } // 个体户: 非"仅企业"子项
|
|
1043
1050
|
});
|
|
1044
1051
|
});
|
|
1045
|
-
|
|
1046
|
-
|
|
1052
|
+
return out;
|
|
1053
|
+
}
|
|
1054
|
+
function renderIndustryCats(keepSub){
|
|
1055
|
+
if(!catEl||!stl) return;
|
|
1056
|
+
var type=(subj&&subj.value)||'SUBJECT_TYPE_INDIVIDUAL';
|
|
1057
|
+
var subs=industrySubsFor(type);
|
|
1058
|
+
var cats=[]; subs.forEach(function(s){ if(cats.indexOf(s.cat)<0) cats.push(s.cat); });
|
|
1059
|
+
catEl.innerHTML='';
|
|
1060
|
+
cats.forEach(function(c){ var o=document.createElement('option'); o.value=c; o.textContent=c; catEl.appendChild(o); });
|
|
1061
|
+
catEl.value=cats.indexOf('餐饮/零售')>=0?'餐饮/零售':cats[0];
|
|
1062
|
+
renderIndustrySubs(keepSub);
|
|
1047
1063
|
}
|
|
1064
|
+
function renderIndustrySubs(keepSub){
|
|
1065
|
+
var type=(subj&&subj.value)||'SUBJECT_TYPE_INDIVIDUAL';
|
|
1066
|
+
var cat=catEl.value;
|
|
1067
|
+
var subs=industrySubsFor(type).filter(function(s){ return s.cat===cat; });
|
|
1068
|
+
var cur=keepSub?stl.value:'';
|
|
1069
|
+
stl.innerHTML='';
|
|
1070
|
+
subs.forEach(function(s){
|
|
1071
|
+
var o=document.createElement('option');
|
|
1072
|
+
o.value=s.n; // 提交直接带子类名称文本 (qualification_type)
|
|
1073
|
+
o.textContent=s.n+(s.lic?' ⚠️需许可证':'');
|
|
1074
|
+
stl.appendChild(o);
|
|
1075
|
+
});
|
|
1076
|
+
var def=INDUSTRY_DEFAULT_SUB[type];
|
|
1077
|
+
stl.value=(subs.some(function(s){return s.n===cur;})&&cur)?cur
|
|
1078
|
+
:(subs.some(function(s){return s.n===def;})?def:(subs[0]?subs[0].n:''));
|
|
1079
|
+
}
|
|
1080
|
+
if(catEl){ catEl.addEventListener('change',function(){ renderIndustrySubs(false); }); }
|
|
1048
1081
|
// 结算规则只读展示 (settlement_id 按主体推导: 企业 716 / 个体户 719 / 其他组织 727; 商户不用选)
|
|
1049
1082
|
var SETTLE_RULES={SUBJECT_TYPE_INDIVIDUAL:'719 · 个体户通用(0.6% T+1)',
|
|
1050
1083
|
SUBJECT_TYPE_ENTERPRISE:'716 · 企业通用(0.6% T+1)',SUBJECT_TYPE_OTHERS:'727 · 其他组织通用(0.6% T+1)'};
|
|
@@ -1055,14 +1088,44 @@ async function restoreIdentity(){
|
|
|
1055
1088
|
paintSettleRule();
|
|
1056
1089
|
if(subj&&stl){
|
|
1057
1090
|
subj.addEventListener('change',function(){
|
|
1058
|
-
|
|
1091
|
+
renderIndustryCats(false); // 主体切换 → 大类/子类选项集联动刷新 + 重选默认
|
|
1059
1092
|
paintSettleRule();
|
|
1093
|
+
paintAccountLock(); // 修正2: 企业强制对公
|
|
1060
1094
|
// F4: 企业主体显示身份证居住地址(必填) + UBO 说明; 个体户隐藏
|
|
1061
1095
|
var ent = subj.value==='SUBJECT_TYPE_ENTERPRISE';
|
|
1062
1096
|
var ia=document.getElementById('afield_idaddr'); if(ia) ia.style.display=ent?'':'none';
|
|
1063
1097
|
var un=document.getElementById('afield_ubo_note'); if(un) un.style.display=ent?'':'none';
|
|
1064
1098
|
});
|
|
1065
1099
|
}
|
|
1100
|
+
renderIndustryCats(false); // 初始: 大类 餐饮/零售 > 子类 零售
|
|
1101
|
+
|
|
1102
|
+
// 修正2 (微信网页版实证): 企业主体强制对公账户 — 账户类型锁死对公, 户名=商户全称 (自动带出不可改)
|
|
1103
|
+
function paintAccountLock(){
|
|
1104
|
+
var ent = subj && subj.value==='SUBJECT_TYPE_ENTERPRISE';
|
|
1105
|
+
var at=document.getElementById('a_account_type');
|
|
1106
|
+
var an=document.getElementById('a_account_name');
|
|
1107
|
+
if(at){
|
|
1108
|
+
at.value = ent ? 'BANK_ACCOUNT_TYPE_CORPORATE' : at.value;
|
|
1109
|
+
at.disabled = !!ent;
|
|
1110
|
+
}
|
|
1111
|
+
if(an){
|
|
1112
|
+
if(ent){ an.value=document.getElementById('a_merchant_name').value; an.readOnly=true; }
|
|
1113
|
+
else an.readOnly=false;
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
paintAccountLock();
|
|
1117
|
+
// 修正3 受益人 (网页版同款): 默认"法定代表人本人"(平台自动回填, 页面不重复填); 选"他人"只给提示
|
|
1118
|
+
var bf=document.getElementById('a_beneficiary');
|
|
1119
|
+
if(bf) bf.addEventListener('change',function(){
|
|
1120
|
+
var h=document.getElementById('a_beneficiary_hint');
|
|
1121
|
+
if(h) h.style.display=bf.value==='other'?'':'none';
|
|
1122
|
+
});
|
|
1123
|
+
var mnEl=document.getElementById('a_merchant_name');
|
|
1124
|
+
if(mnEl) mnEl.addEventListener('input',function(){
|
|
1125
|
+
if(subj&&subj.value==='SUBJECT_TYPE_ENTERPRISE'){
|
|
1126
|
+
var an=document.getElementById('a_account_name'); if(an) an.value=mnEl.value;
|
|
1127
|
+
}
|
|
1128
|
+
});
|
|
1066
1129
|
// 省市编码选项 (国标区划码, 两处下拉共用; 微信官方对照表口径)
|
|
1067
1130
|
var CITY_CODES=[['110000','北京市'],['120000','天津市'],['310000','上海市'],['500000','重庆市'],
|
|
1068
1131
|
['130100','石家庄'],['140100','太原'],['150100','呼和浩特'],['210100','沈阳'],['210200','大连'],
|
package/routes/onboard.js
CHANGED
|
@@ -606,7 +606,7 @@ function createOnboardRouter(deps) {
|
|
|
606
606
|
account_name: "开户名称", account_number: "银行账号", account_bank: "开户银行",
|
|
607
607
|
store_name: "门店名称", store_address_code: "门店省市编码", store_address: "门店详细地址",
|
|
608
608
|
website_url: "网站网址", appid: "公众号/小程序 AppID",
|
|
609
|
-
service_phone: "客服电话", qualification_type: "
|
|
609
|
+
service_phone: "客服电话", qualification_type: "所属行业 (微信行业名称)",
|
|
610
610
|
license_media_id: "营业执照照片", legal_id_front_media_id: "身份证人像面", legal_id_back_media_id: "身份证国徽面",
|
|
611
611
|
store_entrance_media_id: "门店门头照片", store_indoor_media_id: "门店内部照片",
|
|
612
612
|
web_home_media_id: "网站首页截图", web_product_media_id: "商品/服务页截图", mp_media_id: "公众号/小程序页面截图",
|
|
@@ -819,6 +819,11 @@ CREATE TABLE IF NOT EXISTS onboard_draft (
|
|
|
819
819
|
// settlement_id = 结算规则 ID, 按主体推导 (商户不用选; 前端不传也兜底)
|
|
820
820
|
payload.settlement_id = payload.subject_type === "SUBJECT_TYPE_ENTERPRISE" ? "716"
|
|
821
821
|
: (payload.subject_type === "SUBJECT_TYPE_OTHERS" ? "727" : "719");
|
|
822
|
+
// 修正2 (微信网页版实证): 企业主体强制对公账户 — account_type 锁死对公, 户名=商户全称
|
|
823
|
+
if (payload.subject_type === "SUBJECT_TYPE_ENTERPRISE") {
|
|
824
|
+
payload.account_type = "BANK_ACCOUNT_TYPE_CORPORATE";
|
|
825
|
+
payload.account_name = payload.merchant_name;
|
|
826
|
+
}
|
|
822
827
|
// M2 断点 c: tb_address 贯通 — SP 台账落列, FINISHED 后 oracle 引导金才知道发给谁
|
|
823
828
|
const identity = await ensureSellerIdentity(basePaths.baseDir());
|
|
824
829
|
payload.tb_address = identity.address;
|
|
@@ -111,7 +111,7 @@ async function fillForm(base) {
|
|
|
111
111
|
account_type: "BANK_ACCOUNT_TYPE_PERSONAL",
|
|
112
112
|
account_name: "张三", account_number: PLAINTEXT.card, account_bank: "招商银行",
|
|
113
113
|
store_name: "张三餐饮店南山店", store_address_code: "440300", store_address: "南山区xx路1号",
|
|
114
|
-
service_phone: "0755-12345678", qualification_type: "
|
|
114
|
+
service_phone: "0755-12345678", qualification_type: "零售", // 所属行业=二级子类名称文本 (settlement_id 结算规则由后端按主体推导)
|
|
115
115
|
...media,
|
|
116
116
|
};
|
|
117
117
|
}
|
|
@@ -287,14 +287,19 @@ test("onboard 页面含进件表单 (btn-apply-submit) 且第③步状态机元
|
|
|
287
287
|
assert.ok(!html.includes("slot.insertBefore(img"), "旧增强脚本预览补丁已删 (二重框根因)");
|
|
288
288
|
assert.ok(html.includes("prefill:function(mediaId)"), "预填走双态 (无第二个空框)");
|
|
289
289
|
// 2026-10-03 MCC 修正: 经营类目下拉是真实 MCC 编码 (716/719/727 是 V2 结算规则 ID, 被微信拒)
|
|
290
|
-
|
|
291
|
-
assert.ok(html.includes("
|
|
292
|
-
assert.ok(
|
|
293
|
-
assert.ok(html.includes("
|
|
294
|
-
assert.ok(html.includes("
|
|
295
|
-
|
|
290
|
+
// 2026-10-03 网页版实证校准: 行业二级联动 (大类导航 + 子类名称文本提交)
|
|
291
|
+
assert.ok(html.includes("a_industry_cat"), "行业大类下拉");
|
|
292
|
+
assert.ok(html.includes("INDUSTRY_CATS") && html.includes("renderIndustrySubs"), "二级联动数据+渲染");
|
|
293
|
+
assert.ok(html.includes("{n:'零售'}"), "默认子类 零售");
|
|
294
|
+
assert.ok(html.includes("餐饮/零售") && html.includes("门户论坛/网络广告及推广/软件开发/其他互联网服务"), "对照表子项");
|
|
295
|
+
assert.ok(html.includes("⚠️需许可证"), "特殊行业许可证标记");
|
|
296
|
+
assert.ok(!html.includes("a_settlement_manual"), "行业手输框不存在 (封闭集合)");
|
|
297
|
+
// 修正2 企业强制对公 + 修正3 受益人
|
|
298
|
+
assert.ok(html.includes("paintAccountLock"), "企业对公锁逻辑");
|
|
299
|
+
assert.ok(html.includes("a_beneficiary"), "受益人选择");
|
|
300
|
+
// 双字段 (结算规则只读展示 + 所属行业下拉)
|
|
296
301
|
assert.ok(html.includes("a_settlement_rule"), "结算规则只读展示框");
|
|
297
|
-
assert.ok(html.includes("结算规则") && html.includes("
|
|
302
|
+
assert.ok(html.includes("结算规则") && html.includes("所属行业"), "双字段标签");
|
|
298
303
|
assert.ok(!html.includes("a_qualification_type"), "旧资质描述字段已移除");
|
|
299
304
|
assert.ok(html.includes("maybeAutoKyc"), "M2: 进件受理后自动 KYC 提交");
|
|
300
305
|
assert.ok(!html.includes("btn-verify"), "手动实名按钮已删 (自动触发)");
|
|
@@ -357,17 +362,18 @@ test("字段语义最终修正: settlement_id=结算规则按主体推导 + qual
|
|
|
357
362
|
let j = await r.json();
|
|
358
363
|
assert.strictEqual(r.status, 400);
|
|
359
364
|
assert.strictEqual(j.field, "qualification_type");
|
|
360
|
-
assert.ok(j.message.includes("
|
|
365
|
+
assert.ok(j.message.includes("所属行业"), j.message);
|
|
361
366
|
// 个体户 → settlement_id=719 (前端没传, 后端推导) + qualification_type=5331 透传
|
|
362
367
|
const before = spCapture.submits.length;
|
|
368
|
+
// 补回行业名称再提交
|
|
369
|
+
form.qualification_type = "零售";
|
|
363
370
|
r = await fetch(base + "/api/onboard/applyment", {
|
|
364
|
-
method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(
|
|
371
|
+
method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(form),
|
|
365
372
|
});
|
|
366
|
-
function form2ok(f){ const c={...f, qualification_type:"5331"}; return c; }
|
|
367
373
|
j = await r.json();
|
|
368
374
|
assert.strictEqual(r.status, 200, JSON.stringify(j));
|
|
369
375
|
assert.strictEqual(spCapture.submits[before].settlement_id, "719", "个体户 → 结算规则 719 (后端推导)");
|
|
370
|
-
assert.strictEqual(spCapture.submits[before].qualification_type, "
|
|
376
|
+
assert.strictEqual(spCapture.submits[before].qualification_type, "零售", "所属行业=二级子类名称文本透传");
|
|
371
377
|
} finally { srv.close(); }
|
|
372
378
|
});
|
|
373
379
|
|
|
@@ -376,7 +382,7 @@ test("字段语义: 企业主体 → settlement_id=716 + qualification_type=MCC
|
|
|
376
382
|
try {
|
|
377
383
|
const form = await fillForm(base);
|
|
378
384
|
form.subject_type = "SUBJECT_TYPE_ENTERPRISE";
|
|
379
|
-
form.qualification_type = "
|
|
385
|
+
form.qualification_type = "零售";
|
|
380
386
|
form.legal_id_address = "广东省深圳市南山区xx路1号101室"; // 企业必填 (F4)
|
|
381
387
|
const before = spCapture.submits.length;
|
|
382
388
|
const r = await fetch(base + "/api/onboard/applyment", {
|
|
@@ -386,11 +392,19 @@ test("字段语义: 企业主体 → settlement_id=716 + qualification_type=MCC
|
|
|
386
392
|
assert.strictEqual(r.status, 200, JSON.stringify(j));
|
|
387
393
|
const fwd = spCapture.submits[before];
|
|
388
394
|
assert.strictEqual(fwd.settlement_id, "716", "企业 → 结算规则 716");
|
|
389
|
-
assert.strictEqual(fwd.qualification_type, "
|
|
395
|
+
assert.strictEqual(fwd.qualification_type, "零售", "所属行业=二级子类名称文本");
|
|
396
|
+
// 修正2 (网页版实证): 企业强制对公 — account_type 锁死 + 户名=公司名 (密文可还原验证)
|
|
397
|
+
assert.strictEqual(fwd.account_type, "BANK_ACCOUNT_TYPE_CORPORATE", "企业强制对公");
|
|
398
|
+
const decName = crypto.privateDecrypt(
|
|
399
|
+
{ key: wxPub.privateKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: "sha1" }, // 加密侧已锁 OAEP-SHA1 (2026-09-26 微信实测)
|
|
400
|
+
Buffer.from(fwd.account_name, "base64")
|
|
401
|
+
).toString("utf8");
|
|
402
|
+
assert.strictEqual(decName, form.merchant_name, "对公户名=商户全称 (自动带出)");
|
|
390
403
|
// SP 侧组装: settlement_info 两字段正确分工
|
|
391
404
|
const wxBody = spApplymentLib.buildApplymentBody({ ...fwd, business_code: "TBTEST" }, (s) => s, { alreadyEncrypted: true });
|
|
392
405
|
assert.strictEqual(wxBody.settlement_info.settlement_id, "716");
|
|
393
|
-
assert.strictEqual(wxBody.settlement_info.qualification_type, "
|
|
406
|
+
assert.strictEqual(wxBody.settlement_info.qualification_type, "零售");
|
|
407
|
+
assert.strictEqual(wxBody.bank_account_info.bank_account_type, "BANK_ACCOUNT_TYPE_CORPORATE");
|
|
394
408
|
} finally { srv.close(); }
|
|
395
409
|
});
|
|
396
410
|
|