(function(){
const navAnchor=document.querySelector('[data-s="ai"]');
if(navAnchor){navAnchor.insertAdjacentHTML('beforebegin',`
API配置 ▸
金蝶单据 ▸
金蝶云星空API配置
金蝶销售出库单
金蝶其他出库单
金蝶其他入库单
金蝶调拨单
金蝶费用应收单
积加单据 ▸
`);}
const baseNav=document.querySelector('#group-base');
if(baseNav&&!baseNav.querySelector('[data-s="erp-kingdee-basic"]'))baseNav.insertAdjacentHTML('beforeend','基础资料维护
');
const salesSection=document.getElementById('sales-outbound-standard');
if(salesSection){
const description=salesSection.querySelector('.section-title p');if(description)description.innerText='查看实际参与收入核对的标准数据。Excel导入正式数据仅指以前导入的金蝶销售出库单,不包含其他Excel导入。';
const sourceFilter=document.getElementById('sobSourceFilter');if(sourceFilter){const manual=[...sourceFilter.options].find(option=>option.value==='kingdee');if(manual)manual.text='Excel导入正式数据';if(![...sourceFilter.options].some(option=>option.value==='kingdee_api'))sourceFilter.add(new Option('金蝶API','kingdee_api'),manual?manual.index:-1);}
const kingdeeHead=document.getElementById('sobKt')?.closest('table')?.querySelector('thead tr');if(kingdeeHead)kingdeeHead.innerHTML='数据来源 销售组织 正式状态 期间 平台订单号/关联单据 物料编码 仓库 客户 币别 数量 金额 ';
}
document.querySelector('main').insertAdjacentHTML('beforeend',`
勾选“参与收入核对”的启用组织会在发布时自动合并;任一组织缺少当前期间成功批次时禁止发布。
积加API配置 配置积加开放平台请求地址、应用凭证及两个报表接口。
当前阶段: 接口数据仅保存到原始预览批次,不进入销售出库数据和收入核对。
金蝶云星空API配置 统一维护第三方登录信息,并分别配置各类金蝶单据查询接口。
配置说明: API地址、账套ID、用户名、App ID、App Secret、语言和超时由所有单据共用;每种单据只维护自己的 FormId、组织字段、日期字段和查询字段。
单据接口配置 销售出库、其他入库、其他出库、调拨、应收等单据分别维护,后续可继续新增。
新增单据
顺序 配置编码 单据名称 FormId 组织字段 日期字段 固定过滤条件 状态 操作
${erpApiPullSection('erp-kingdee-sales','金蝶销售出库单','kingdee_sales_outbound',true)}
${erpApiPullSection('erp-kingdee-other-outbound','金蝶其他出库单','kingdee_other_outbound',true)}
${erpApiPullSection('erp-kingdee-other-inbound','金蝶其他入库单','kingdee_other_inbound',true)}
${erpApiPullSection('erp-kingdee-transfer','金蝶调拨单','kingdee_transfer',true)}
${erpApiPullSection('erp-kingdee-accounts-receivable','金蝶费用应收单','kingdee_accounts_receivable',true)}
${erpApiPullSection('erp-jiaplus-delivery','积加配送报告','jiaplus_delivery',false)}
${erpApiPullSection('erp-jiaplus-self-ship','积加自发货订单','jiaplus_self_ship',false)}
`);
function erpApiNavAllowed(resource){return typeof hasResource!=='function'||hasResource(resource);}
window.applyErpApiPermissions=function(){
document.querySelectorAll('#group-erp-api [data-resource]').forEach(el=>{el.style.display=erpApiNavAllowed(el.dataset.resource)?'':'none';});
['kingdee','jiaplus'].forEach(group=>{const wrap=document.getElementById('group-erp-api-'+group),groupTitle=document.getElementById('group-erp-api-'+group+'-title'),visible=wrap&&[...wrap.querySelectorAll('[data-resource]')].some(el=>el.style.display!=='none');if(groupTitle)groupTitle.style.display=visible?'':'none';});
const visible=[...document.querySelectorAll('#group-erp-api [data-resource]')].some(el=>el.style.display!=='none');
const title=document.getElementById('group-erp-api-title');if(title)title.style.display=visible?'':'none';
};
window.applyErpBasicPermissions=function(){const el=document.querySelector('#group-base [data-resource="erp.base.kingdee_basic"]');if(el)el.style.display=erpApiNavAllowed('erp.base.kingdee_basic')?'':'none';};
const oldApply=window.applyPermissions;
if(oldApply)window.applyPermissions=function(){oldApply();window.applyErpApiPermissions();window.applyErpBasicPermissions();};
const meta={
'erp-kingdee-basic':['基础资料维护','维护金蝶销售出库单可选择的销售组织编码、名称和状态。'],
'erp-jiaplus-config':['积加API配置','配置积加开放平台连接与原始报表接口。'],
'erp-kingdee-config':['金蝶云星空API配置','统一维护登录信息,分别配置各类金蝶单据查询接口。'],
'erp-kingdee-sales':['金蝶销售出库单','按销售组织和出库期间拉取原始数据进行核验。'],
'erp-kingdee-other-outbound':['金蝶其他出库单','按年度、期间和组织拉取,发布后用于库存核对。'],
'erp-kingdee-other-inbound':['金蝶其他入库单','按年度、期间和组织拉取,发布后用于库存核对。'],
'erp-kingdee-transfer':['金蝶调拨单','按年度、期间和组织拉取,发布后用于库存核对。'],
'erp-kingdee-accounts-receivable':['金蝶费用应收单','按年度、期间和组织拉取预览;费用核对逻辑暂未启用。'],
'erp-jiaplus-delivery':['积加配送报告','按期间拉取积加配送报告原始数据进行核验。'],
'erp-jiaplus-self-ship':['积加自发货订单','按期间拉取积加自发货订单原始数据进行核验。']
};
document.querySelectorAll('#group-erp-api [data-s]').forEach(el=>el.addEventListener('click',function(ev){
ev.stopPropagation();document.querySelectorAll('.nav').forEach(n=>n.classList.remove('active'));this.classList.add('active');
document.querySelectorAll('.section').forEach(s=>s.classList.remove('active'));const id=this.dataset.s;document.getElementById(id).classList.add('active');
title.innerText=meta[id][0];desc.innerText=meta[id][1];
if(id==='erp-jiaplus-config')loadErpJiaplusConfig();else if(id==='erp-kingdee-config')loadErpKingdeeConfig();else if(id==='erp-kingdee-basic')loadKingdeeSalesOrgs();else loadErpApiPreview(this.dataset.source||erpApiSourceBySection(id));
}));
document.querySelectorAll('#group-base [data-s="erp-kingdee-basic"]').forEach(el=>el.addEventListener('click',function(ev){ev.stopPropagation();document.querySelectorAll('.nav').forEach(n=>n.classList.remove('active'));this.classList.add('active');document.querySelectorAll('.section').forEach(s=>s.classList.remove('active'));document.getElementById('erp-kingdee-basic').classList.add('active');title.innerText=meta['erp-kingdee-basic'][0];desc.innerText=meta['erp-kingdee-basic'][1];loadKingdeeSalesOrgs();}));
})();
window.renderSalesOutboundStandard=async function(){
try{
const filters={doc_type:'sales_outbound',source_type:sobSourceFilter.value,year:sobYearFilter.value,month:sobMonthFilter.value,sku:sobSkuFilter.value,warehouse:sobWhFilter.value,reconcile_filter:sobReconFilter.value,page_size:st.sobPage.size};
const jData=await apiGet('/api/data/standard?side=j&page='+st.sobPage.j+'&'+toQuery(filters));
const kData=await apiGet('/api/data/standard?side=k&page='+st.sobPage.k+'&'+toQuery(filters));
sobJPageInfo.innerText='第 '+jData.page+' / '+Math.max(1,Math.ceil(jData.total/jData.page_size))+' 页,共 '+jData.total+' 条';
sobKPageInfo.innerText='第 '+kData.page+' / '+Math.max(1,Math.ceil(kData.total/kData.page_size))+' 页,共 '+kData.total+' 条';
sobJt.innerHTML=jData.rows.map(r=>{let skipTag=r.skip_reconcile?' 不核对 ':'';return `${r.source_name}${skipTag} ${r.period} ${r.order_no||r.bill_no||''} ${r.sku} ${r.warehouse} ${r.store||''} ${r.currency||''} ${f(r.qty)} ${money(r.amount)} `;}).join('')||'暂无积加数据
';
sobKt.innerHTML=kData.rows.map(r=>{let skipTag=r.customer_skip?' 不核对 ':'';let confirmCell='';if(r.skip_reconcile){confirmCell=` 需手工确认 确认核对 `;}const isApi=r.source_type==='kingdee_api',sourceLabel=isApi?'金蝶API':'Excel导入正式数据',activeTag=r.active_source?'当前正式 ':'备用 ';return `${sourceLabel}${skipTag}${confirmCell} ${r.sales_org||'-'} ${activeTag} ${r.period} ${r.order_no||r.bill_no||''} ${r.sku} ${r.warehouse} ${r.store||''} ${r.currency||''} ${f(r.qty)} ${money(r.amount)} `;}).join('')||'暂无金蝶数据
';
}catch(error){console.error(error);toast('加载销售出库数据失败:'+error.message);}
};
function erpApiPullSection(id,label,source,showOrg){const isSales=source==='kingdee_sales_outbound',isInventory=['kingdee_other_outbound','kingdee_other_inbound','kingdee_transfer'].includes(source),isReceivable=source==='kingdee_accounts_receivable';let actions;if(isSales)actions='校验API/历史数据 导出 Excel 发布到收入核对 ';else if(isInventory)actions=`校验发布数据 导出 Excel 发布到库存核对 `;else if(isReceivable)actions=`导出 Excel `;else actions=`导出 Excel 发布到收入核对 `;const description=isSales?'按年度、期间和销售组织拉取;参与收入核对的组织合并发布。':isInventory?'按年度、期间和组织拉取;发布时替换该期间原有金蝶Excel数据。':isReceivable?'按年度、期间和组织拉取预览;费用核对逻辑暂未启用。':'按所选时间范围拉取完整原始字段,确认无误后发布到销售出库数据与收入核对。';const notice=isSales?'拉取数据先保存在预览区,点击“发布到收入核对”后才成为正式数据。':isInventory?'拉取数据先保存在预览区;发布后按期间覆盖对应类型的金蝶Excel/API正式数据,不与历史数据叠加。':isReceivable?'当前仅支持拉取、查询和导出,不会写入库存核对或收入核对。':'拉取数据先保存在预览区,发布后写入销售出库数据的积加页签;重复业务明细会覆盖。';return `预览隔离: ${notice}
上一页 下一页
每页 100 200 500 1000 条
`;}
const erpApiSources=['kingdee_sales_outbound','kingdee_other_outbound','kingdee_other_inbound','kingdee_transfer','kingdee_accounts_receivable','jiaplus_delivery','jiaplus_self_ship'];
const erpApiPages=Object.fromEntries(erpApiSources.map(source=>[source,1]));
const erpApiPageSizes=Object.fromEntries(erpApiSources.map(source=>[source,100]));
const erpApiTotals=Object.fromEntries(erpApiSources.map(source=>[source,0]));
const erpApiBatchCache=Object.fromEntries(erpApiSources.map(source=>[source,[]]));
const erpApiLastJobStatus=Object.fromEntries(erpApiSources.map(source=>[source,'']));
const erpJiaplusFilterTimers={};
function applyJiaplusPreviewFilter(source){erpApiPages[source]=1;renderErpApiRecords(source);}
function scheduleJiaplusPreviewFilter(source){clearTimeout(erpJiaplusFilterTimers[source]);erpJiaplusFilterTimers[source]=setTimeout(()=>applyJiaplusPreviewFilter(source),300);}
const erpApiSectionSources={'erp-kingdee-sales':'kingdee_sales_outbound','erp-kingdee-other-outbound':'kingdee_other_outbound','erp-kingdee-other-inbound':'kingdee_other_inbound','erp-kingdee-transfer':'kingdee_transfer','erp-kingdee-accounts-receivable':'kingdee_accounts_receivable','erp-jiaplus-delivery':'jiaplus_delivery','erp-jiaplus-self-ship':'jiaplus_self_ship'};
function erpApiSourceBySection(id){return erpApiSectionSources[id]||'jiaplus_self_ship';}
function erpApiPeriodDates(year,month){const f=d=>{const y=d.getFullYear(),m=String(d.getMonth()+1).padStart(2,'0'),day=String(d.getDate()).padStart(2,'0');return `${y}-${m}-${day}`;};return {start:f(new Date(year,month-1,1)),end:f(new Date(year,month,0))};}
function erpApiDefaultDates(source){const now=new Date(),value=window.defaultBusinessPeriod||{year:now.getFullYear(),month:now.getMonth()+1},range=erpApiPeriodDates(value.year,value.month),a=document.getElementById(source+'Start'),b=document.getElementById(source+'End');if(a&&!a.value)a.value=range.start;if(b&&!b.value)b.value=range.end;}
window.applyErpApiBusinessPeriod=function(year,month){
const range=erpApiPeriodDates(year,month);
['jiaplus_delivery','jiaplus_self_ship'].forEach(source=>{const start=document.getElementById(source+'Start'),end=document.getElementById(source+'End');if(start)start.value=range.start;if(end)end.value=range.end;});
const salesYear=document.getElementById('kingdeeSalesYear'),salesPeriod=document.getElementById('kingdeeSalesPeriod');if(salesYear)salesYear.value=String(year);if(salesPeriod)salesPeriod.value=String(month);
kingdeeDocumentSources.forEach(source=>{const yearEl=document.getElementById(source+'Year'),periodEl=document.getElementById(source+'Period');if(yearEl)yearEl.value=String(year);if(periodEl)periodEl.value=String(month);});
kingdeeDefaultPeriodApplied=false;Object.keys(kingdeeDocumentDefaultPeriodApplied).forEach(source=>delete kingdeeDocumentDefaultPeriodApplied[source]);
};
function setupJiaplusSelfShipPullUi(){
const source='jiaplus_self_ship',start=document.getElementById(source+'Start'),end=document.getElementById(source+'End');
if(start?.previousElementSibling)start.previousElementSibling.innerText='发货时间(北京)开始';
if(end?.previousElementSibling)end.previousElementSibling.innerText='发货时间(北京)结束';
const batch=document.getElementById(source+'Batch');if(batch){batch.value='';batch.parentElement.style.display='none';}
const status=document.getElementById(source+'Status');
const card=status?.closest('.card');
if(card&&!document.getElementById('jiaplusSelfShipDateHint'))card.insertAdjacentHTML('afterbegin','日期口径: 按实际发货时间(北京)查询。重新拉取成功后覆盖上一次自发货预览数据,不保留历史查询批次。
');
}
function setupJiaplusDeliveryPullUi(){
const source='jiaplus_delivery',start=document.getElementById(source+'Start'),end=document.getElementById(source+'End');
if(start?.previousElementSibling)start.previousElementSibling.innerText='发货时间(市场时间)开始';
if(end?.previousElementSibling)end.previousElementSibling.innerText='发货时间(市场时间)结束';
const batch=document.getElementById(source+'Batch');if(batch){batch.value='';batch.parentElement.style.display='none';}
const status=document.getElementById(source+'Status'),card=status?.closest('.card');
if(card&&!document.getElementById('jiaplusDeliveryDateHint'))card.insertAdjacentHTML('afterbegin','日期口径: 按发货时间(市场时间)校验,单次范围最多 31 天。接口按更新时间分段检索后,只保留目标发货日期;重新拉取成功后覆盖上一次配送报告预览。
');
}
async function loadErpJiaplusConfig(){try{const c=await apiGet('/api/erp-api/jiaplus/config');erpJAppId.value=c.app_id||'';erpJAppKey.value=c.app_key||'';erpJBase.value=c.base_url||'';erpJHeaders.value=c.headers_json||'{}';erpJMethod.value=c.method||'POST';erpJTimeout.value=c.timeout||60;erpJDeliveryEndpoint.value=c.delivery_endpoint||'/operation/sale/fbaShipment/page';erpJDeliveryPath.value=c.delivery_data_path||'data.rows';erpJDeliveryBody.value=c.delivery_body_template||'{"page":{page},"pagesize":{page_size},"dateType":0,"updateTimeBegin":"{start_date} 00:00:00","updateTimeEnd":"{end_date} 23:59:59"}';erpJSelfEndpoint.value=c.self_ship_endpoint||'/fulfillment/order/foOrder/page';erpJSelfPath.value=c.self_ship_data_path||'data.rows';erpJSelfBody.value=c.self_ship_body_template||'{"page":{page},"pagesize":{page_size},"deliveryTimeAfter":"{start_date}","deliveryTimeBefore":"{end_date}"}';}catch(e){toast('加载积加配置失败:'+e.message);}}
async function saveErpJiaplusConfig(){try{await apiPost('/api/erp-api/jiaplus/config',{app_id:erpJAppId.value.trim(),app_key:erpJAppKey.value.trim(),base_url:erpJBase.value.trim(),headers_json:erpJHeaders.value.trim()||'{}',method:erpJMethod.value,timeout:parseInt(erpJTimeout.value)||60,delivery_endpoint:erpJDeliveryEndpoint.value.trim(),delivery_data_path:erpJDeliveryPath.value.trim(),delivery_body_template:erpJDeliveryBody.value.trim(),self_ship_endpoint:erpJSelfEndpoint.value.trim(),self_ship_data_path:erpJSelfPath.value.trim(),self_ship_body_template:erpJSelfBody.value.trim()});toast('积加API配置已保存');}catch(e){toast(e.message);}}
async function testErpJiaplusConfig(){try{const r=await apiPost('/api/erp-api/jiaplus/test',{});toast(r.message);}catch(e){toast(e.message);}}
let erpKingdeeDocuments=[];
async function loadErpKingdeeConfig(){try{const [c,documents]=await Promise.all([apiGet('/api/erp-api/kingdee/config'),apiGet('/api/erp-api/kingdee/documents')]);erpKBase.value=c.base_url||'';erpKAcct.value=c.acct_id||'';erpKUser.value=c.username||'';erpKAppId.value=c.app_id||'';erpKSecret.value=c.app_secret||'';erpKLcid.value=c.lcid||2052;erpKTimeout.value=c.timeout||60;erpKingdeeDocuments=documents||[];renderErpKingdeeDocuments();if(!erpKDocId.value)resetErpKingdeeDocumentForm();}catch(e){toast('加载金蝶配置失败:'+e.message);}}
function renderErpKingdeeDocuments(){erpKDocTb.innerHTML=erpKingdeeDocuments.map(item=>`${item.sort_order||0} ${esc(item.code)} ${esc(item.name)} ${esc(item.form_id)} ${esc(item.organization_field||'-')} ${esc(item.date_field||'-')} ${esc(item.filter_string||'-')} ${item.enabled?'启用 ':'停用 '} 编辑 测试单据 ${item.code==='sales_outbound'?'':' 删除 '} `).join('')||'暂无单据配置
';}
function resetErpKingdeeDocumentForm(){erpKDocId.value='';erpKDocCode.value='';erpKDocCode.disabled=false;erpKDocName.value='';erpKDocForm.value='';erpKDocOrgField.value='';erpKDocDateField.value='FDate';erpKDocFilter.value='';erpKDocEnabled.value='1';erpKDocSort.value=String((erpKingdeeDocuments.reduce((max,item)=>Math.max(max,Number(item.sort_order)||0),0)||0)+10);erpKDocFields.value='';}
function editErpKingdeeDocument(id){const item=erpKingdeeDocuments.find(row=>row.id===id);if(!item)return;erpKDocId.value=item.id;erpKDocCode.value=item.code||'';erpKDocCode.disabled=true;erpKDocName.value=item.name||'';erpKDocForm.value=item.form_id||'';erpKDocOrgField.value=item.organization_field||'';erpKDocDateField.value=item.date_field||'FDate';erpKDocFilter.value=item.filter_string||'';erpKDocEnabled.value=item.enabled?'1':'0';erpKDocSort.value=item.sort_order||0;erpKDocFields.value=item.field_keys||'';document.getElementById('erp-kingdee-config').scrollIntoView({behavior:'smooth',block:'start'});}
async function saveErpKingdeeDocument(){try{const payload={id:parseInt(erpKDocId.value)||null,code:erpKDocCode.value.trim(),name:erpKDocName.value.trim(),form_id:erpKDocForm.value.trim(),organization_field:erpKDocOrgField.value.trim(),date_field:erpKDocDateField.value.trim()||'FDate',filter_string:erpKDocFilter.value.trim(),field_keys:erpKDocFields.value.trim(),enabled:parseInt(erpKDocEnabled.value),sort_order:parseInt(erpKDocSort.value)||0};await apiPost('/api/erp-api/kingdee/documents',payload);toast('单据接口配置已保存');resetErpKingdeeDocumentForm();await loadErpKingdeeConfig();}catch(e){toast('保存单据配置失败:'+e.message);}}
async function testErpKingdeeDocument(id){try{const result=await apiPost('/api/erp-api/kingdee/documents/'+id+'/test',{});toast(result.message||'测试完成');}catch(e){toast('测试单据失败:'+e.message);}}
async function deleteErpKingdeeDocument(id){const item=erpKingdeeDocuments.find(row=>row.id===id);if(!item||!confirm('确定删除单据配置“'+item.name+'”吗?'))return;try{await apiDelete('/api/erp-api/kingdee/documents/'+id,{});toast('单据配置已删除');resetErpKingdeeDocumentForm();await loadErpKingdeeConfig();}catch(e){toast('删除失败:'+e.message);}}
async function loadKingdeeSalesOrgs(){try{const rows=await apiGet('/api/erp-api/kingdee/sales-orgs');window.kingdeeSalesOrgs=rows||[];document.getElementById('kingdeeOrgTb').innerHTML=window.kingdeeSalesOrgs.map(item=>`${esc(item.code)} ${esc(item.name)} ${item.enabled?'启用 ':'停用 '} ${item.include_in_reconcile?'参与 ':'不参与'} 编辑 删除 `).join('')||'暂无销售组织
';}catch(e){toast('加载销售组织失败:'+e.message);}}
function editKingdeeSalesOrg(id){const item=(window.kingdeeSalesOrgs||[]).find(x=>x.id===id);if(!item)return;document.getElementById('kingdeeOrgCode').value=item.code;document.getElementById('kingdeeOrgName').value=item.name;document.getElementById('kingdeeOrgEnabled').value=item.enabled?'1':'0';document.getElementById('kingdeeOrgReconcile').value=item.include_in_reconcile?'1':'0';document.getElementById('kingdeeOrgCode').dataset.id=id;}
async function saveKingdeeSalesOrg(){try{const code=document.getElementById('kingdeeOrgCode').value.trim(),name=document.getElementById('kingdeeOrgName').value.trim(),enabled=parseInt(document.getElementById('kingdeeOrgEnabled').value),include_in_reconcile=parseInt(document.getElementById('kingdeeOrgReconcile').value),id=parseInt(document.getElementById('kingdeeOrgCode').dataset.id||0)||null;if(!code||!name){toast('请填写销售组织编码和名称');return;}await apiPost('/api/erp-api/kingdee/sales-orgs',{id,code,name,enabled,include_in_reconcile});document.getElementById('kingdeeOrgCode').dataset.id='';toast('销售组织已保存');await loadKingdeeSalesOrgs();}catch(e){toast('保存销售组织失败:'+e.message);}}
async function deleteKingdeeSalesOrg(id){if(!confirm('确定删除这个销售组织吗?'))return;try{await apiDelete('/api/erp-api/kingdee/sales-orgs/'+id);await loadKingdeeSalesOrgs();}catch(e){toast('删除销售组织失败:'+e.message);}}
async function clearKingdeeHistory(){if(!confirm('确定清理全部金蝶销售出库历史拉取数据吗?正式对账数据不会受影响。'))return;try{const r=await apiDelete('/api/erp-api/kingdee/history');toast('已清理 '+(r.deleted_rows||0)+' 条历史明细');await loadKingdeeSalesOrgs();}catch(e){toast('清理历史失败:'+e.message);}}
function kingdeeReconcilePeriod(){return {year:parseInt(document.getElementById('kingdeeSalesYear')?.value||0),period:parseInt(document.getElementById('kingdeeSalesPeriod')?.value||0)};}
async function checkKingdeeReconcile(notify=true){
try{
const selected=kingdeeReconcilePeriod();if(!selected.year||!selected.period)return;
const result=await apiGet('/api/erp-api/kingdee/reconcile-readiness?year='+selected.year+'&period='+selected.period);
window.kingdeeReconcileReadiness=result;
const source=document.getElementById('kingdeeFormalSource');if(source){source.disabled=!result.current_source_available;source.value=result.current_source_available?(result.current_source||'kingdee'):'';source.title=result.current_source_available?'切换收入核对使用的金蝶正式数据':'API数据发布后可切换正式来源';}
const organizations=(result.organizations||[]).map(item=>`${esc(item.code)}:${item.ready?'已拉取 '+item.count+' 条':'缺少成功批次'}`).join(';')||'未配置参与收入核对的组织';
const comparison=result.comparison||{},api=result.api||{},manual=result.manual||{};
const compareText=manual.record_count?`Excel导入正式数据 ${manual.record_count} 条;业务键差异:API缺少 ${comparison.missing_in_api||0},Excel导入缺少 ${comparison.missing_in_manual||0},数量差异 ${comparison.qty_difference_count||0},金额差异 ${comparison.amount_difference_count||0}`:'当前期间没有Excel导入正式数据';
const customerSkipText=result.customer_skip_count?`;客户不核对 ${result.customer_skip_count} 条(保留展示,不参与收入核对)`:'';
const invalidText=Object.entries(result.invalid_fields||{}).map(([label,count])=>{const samples=(result.invalid_field_samples||{})[label]||[];return `${esc(label)}为空 ${count} 条${samples.length?'(单据:'+samples.map(esc).join('、')+')':''}`;}).join(';');
const status=document.getElementById('kingdeeReconcileStatus');
if(status){status.style.background=result.ready?'#f0fdf4':'#fef2f2';status.style.borderColor=result.ready?'#bbf7d0':'#fecaca';status.style.color=result.ready?'#15803d':'#b91c1c';status.innerHTML=`收入核对准备: ${organizations}API合并: ${api.record_count||0} 条,数量 ${erpKingdeeTotalValue('FRealQty',api.qty||0)},金额 ${erpKingdeeTotalValue('FAmount_LC',api.amount||0)}${customerSkipText};${compareText}${invalidText?'未通过原因: '+invalidText+' 查看问题行 ':''}当前正式来源: ${esc(result.current_source_label||'尚未发布')}`;}
if(notify)toast(result.ready?'API数据校验完成,可发布到收入核对':'API数据尚未满足发布条件');
return result;
}catch(error){const status=document.getElementById('kingdeeReconcileStatus');if(status)status.innerHTML='收入核对检查失败: '+esc(error.message);if(notify)toast(error.message);}
}
async function publishKingdeeReconcile(){
const selected=kingdeeReconcilePeriod(),readiness=await checkKingdeeReconcile(false);if(!readiness)return;
if(!readiness.ready){const invalid=Object.entries(readiness.invalid_fields||{}).map(([label,count])=>{const samples=(readiness.invalid_field_samples||{})[label]||[];return `${label}为空 ${count} 条${samples.length?'(单据:'+samples.join('、')+')':''}`;}).join(';');toast(invalid?'API字段不完整:'+invalid:'参与收入核对的组织尚未全部拉取成功,不能发布');return;}
const organizations=(readiness.organizations||[]).map(item=>item.code).join('、');
if(!confirm(`确定将 ${selected.year} 年 ${selected.period} 月组织 ${organizations} 的API数据合并发布到收入核对吗?\nExcel导入正式数据会保留为备用,不会重复参与核对。`))return;
try{showLoading('正在合并并发布金蝶API数据...');const result=await apiPost('/api/erp-api/kingdee/publish',selected);hideLoading();toast(result.message);await checkKingdeeReconcile(false);if(typeof renderSalesOutboundStandard==='function')renderSalesOutboundStandard();}catch(error){hideLoading();toast('发布失败:'+error.message);}
}
async function changeKingdeeFormalSource(){
const selected=kingdeeReconcilePeriod(),source=document.getElementById('kingdeeFormalSource');if(!source||!source.value)return;
try{const result=await apiPost('/api/erp-api/kingdee/reconcile-source',{...selected,source_type:source.value});toast(result.message);await checkKingdeeReconcile(false);if(typeof renderSalesOutboundStandard==='function')renderSalesOutboundStandard();}catch(error){toast('切换失败:'+error.message);await checkKingdeeReconcile(false);}
}
async function saveErpKingdeeConfig(){try{await apiPost('/api/erp-api/kingdee/config',{base_url:erpKBase.value.trim(),acct_id:erpKAcct.value.trim(),username:erpKUser.value.trim(),app_id:erpKAppId.value.trim(),app_secret:erpKSecret.value.trim(),lcid:parseInt(erpKLcid.value)||2052,timeout:parseInt(erpKTimeout.value)||60});toast('金蝶统一登录配置已保存');await loadErpKingdeeConfig();}catch(e){toast(e.message);}}
async function testErpKingdeeConfig(){try{const r=await apiPost('/api/erp-api/kingdee/test',{});toast(r.message);}catch(e){toast(e.message);}}
function setupKingdeePullUi(){const source='kingdee_sales_outbound';if(!document.getElementById('kingdeeSalesYear')){const wrap=document.getElementById(source+'Batch')?.parentElement;if(wrap){wrap.insertAdjacentHTML('beforebegin','年度
期间 '+Array.from({length:12},(_,i)=>''+(i+1)+' 月 ').join('')+'
销售组织 全部销售组织
收入核对使用数据 尚未发布 金蝶API正式数据 Excel导入正式数据
单据编号查询
数据状态 全部 字段不完整 字段完整 客户不核对
');}const currentYear=new Date().getFullYear(),yearEl=document.getElementById('kingdeeSalesYear');yearEl.innerHTML=Array.from({length:7},(_,i)=>currentYear+1-i).map(y=>''+y+' 年 ').join('');yearEl.value=String(currentYear);document.getElementById('kingdeeSalesPeriod').value=String(new Date().getMonth()+1);const start=document.getElementById(source+'Start')?.parentElement,end=document.getElementById(source+'End')?.parentElement,org=document.getElementById(source+'Org')?.parentElement,batch=document.getElementById(source+'Batch')?.parentElement;if(start)start.style.display='none';if(end)end.style.display='none';if(org)org.style.display='none';if(batch)batch.style.display='none';const status=document.getElementById(source+'Status');if(status&&!document.getElementById('kingdeeReconcileStatus'))status.insertAdjacentHTML('afterend','正在检查收入核对数据...
');}}
let kingdeeDefaultPeriodApplied=false;
async function applyKingdeeDefaultPeriod(){if(kingdeeDefaultPeriodApplied)return;try{const value=window.defaultBusinessPeriod||await apiGet('/api/settlement/default-period'),yearEl=document.getElementById('kingdeeSalesYear'),periodEl=document.getElementById('kingdeeSalesPeriod');if(!yearEl||!periodEl)return;const year=String(value.year||''),month=String(value.month||'');if(year&&![...yearEl.options].some(option=>option.value===year))yearEl.add(new Option(year+' 年',year));if(year)yearEl.value=year;if(month)periodEl.value=month;kingdeeDefaultPeriodApplied=true;}catch(error){console.error(error);}}
const kingdeeDocumentSources=new Set(['kingdee_other_outbound','kingdee_other_inbound','kingdee_transfer','kingdee_accounts_receivable']);
const kingdeeInventorySources=new Set(['kingdee_other_outbound','kingdee_other_inbound','kingdee_transfer']);
const kingdeeDocumentDefaultPeriodApplied={};
const kingdeeDocumentFilterTimers={};
function setupKingdeeDocumentPullUi(source){if(!document.getElementById(source+'Year')){const batch=document.getElementById(source+'Batch')?.parentElement;if(batch)batch.insertAdjacentHTML('beforebegin',`年度
期间 ${Array.from({length:12},(_,i)=>''+(i+1)+' 月 ').join('')}
组织 全部组织
单据编号查询
数据状态 全部 字段不完整 字段完整
`);}const currentYear=new Date().getFullYear(),yearEl=document.getElementById(source+'Year'),selectedYear=yearEl?.value;yearEl.innerHTML=Array.from({length:7},(_,i)=>currentYear+1-i).map(year=>`${year} 年 `).join('');yearEl.value=selectedYear&&[...yearEl.options].some(option=>option.value===selectedYear)?selectedYear:String(currentYear);const periodEl=document.getElementById(source+'Period');if(!periodEl.value)periodEl.value=String(new Date().getMonth()+1);[source+'Start',source+'End',source+'Org',source+'Batch'].forEach(id=>{const parent=document.getElementById(id)?.parentElement;if(parent)parent.style.display='none';});const status=document.getElementById(source+'Status');if(status&&!document.getElementById(source+'ReconcileStatus'))status.insertAdjacentHTML('afterend',`${kingdeeInventorySources.has(source)?'正在检查库存核对发布数据...':'费用核对逻辑暂未启用;当前数据仅供预览和导出。'}
`);}
async function applyKingdeeDocumentDefaultPeriod(source){if(kingdeeDocumentDefaultPeriodApplied[source])return;try{const value=window.defaultBusinessPeriod||await apiGet('/api/settlement/default-period'),yearEl=document.getElementById(source+'Year'),periodEl=document.getElementById(source+'Period');if(!yearEl||!periodEl)return;const year=String(value.year||''),month=String(value.month||'');if(year&&![...yearEl.options].some(option=>option.value===year))yearEl.add(new Option(year+' 年',year));if(year)yearEl.value=year;if(month)periodEl.value=month;kingdeeDocumentDefaultPeriodApplied[source]=true;}catch(error){console.error(error);}}
async function loadKingdeeDocumentOrgs(source){try{const rows=await apiGet('/api/erp-api/kingdee/sales-orgs'),el=document.getElementById(source+'OrgSelect');if(!el)return;const enabled=(rows||[]).filter(item=>item.enabled),selected=el.value||'all',firstLoad=el.dataset.loaded!=='1',defaultOrg=enabled.find(item=>String(item.code)==='105'),target=firstLoad&&defaultOrg?String(defaultOrg.id):selected;el.innerHTML='全部组织 '+enabled.map(item=>`${esc(item.code)} · ${esc(item.name)} `).join('');el.value=[...el.options].some(option=>option.value===target)?target:(defaultOrg?String(defaultOrg.id):'all');el.dataset.loaded='1';}catch(error){toast('加载组织失败:'+erpApiFriendlyError(error));}}
function kingdeeDocumentPeriod(source){return {year:parseInt(document.getElementById(source+'Year')?.value||0),period:parseInt(document.getElementById(source+'Period')?.value||0)};}
function onKingdeeDocumentFilterChange(source,check=true){erpApiPages[source]=1;renderErpApiRecords(source);if(check&&kingdeeInventorySources.has(source))checkKingdeeInventory(source,false);}
function scheduleKingdeeDocumentFilter(source){clearTimeout(kingdeeDocumentFilterTimers[source]);kingdeeDocumentFilterTimers[source]=setTimeout(()=>onKingdeeDocumentFilterChange(source,false),300);}
function showInvalidKingdeeDocumentRows(source){const org=document.getElementById(source+'OrgSelect'),bill=document.getElementById(source+'BillSearch'),status=document.getElementById(source+'StatusFilter');if(org)org.value='all';if(bill)bill.value='';if(status)status.value='invalid';erpApiPages[source]=1;renderErpApiRecords(source);}
async function checkKingdeeInventory(source,notify=true){if(!kingdeeInventorySources.has(source))return null;const selected=kingdeeDocumentPeriod(source),status=document.getElementById(source+'ReconcileStatus');try{const result=await apiGet(`/api/erp-api/kingdee/inventory-readiness/${source}?year=${selected.year}&period=${selected.period}`),organizations=(result.organizations||[]).map(item=>`${esc(item.code)}:${item.ready?item.count+' 条':'未拉取'}`).join(';')||'未维护启用的组织105',invalid=Object.entries(result.invalid_fields||{}).map(([label,count])=>`${esc(label)}为空 ${count} 条`).join(';');if(status){status.style.background=result.ready?'#f0fdf4':'#fef2f2';status.style.borderColor=result.ready?'#bbf7d0':'#fecaca';status.style.color=result.ready?'#15803d':'#b91c1c';status.innerHTML=`库存核对准备(组织105): ${organizations}可发布: ${result.record_count||0} 条${invalid?'未通过原因: '+invalid+` 查看问题行 `:''}`;}if(notify)toast(result.ready?'组织105的API数据校验完成,可发布到库存核对':'组织105的API数据尚未满足发布条件');return result;}catch(error){const message=erpApiFriendlyError(error);if(status)status.innerHTML='库存核对检查失败: '+esc(message);if(notify)toast(message);return null;}}
async function publishKingdeeInventory(source){const selected=kingdeeDocumentPeriod(source),readiness=await checkKingdeeInventory(source,false);if(!readiness)return;if(!readiness.ready){toast('启用组织尚未全部拉取成功或数据字段不完整,不能发布');return;}if(!confirm(`确定发布 ${selected.year} 年 ${selected.period} 月的金蝶API数据到库存核对吗?\n该期间对应单据类型的金蝶Excel/API正式数据将被替换。`))return;try{showLoading('正在替换并发布金蝶API数据...');const result=await apiPost('/api/erp-api/kingdee/inventory-publish/'+source,selected);hideLoading();toast(result.message);await checkKingdeeInventory(source,false);}catch(error){hideLoading();toast('发布失败:'+error.message);}}
async function exportKingdeeDocumentPreview(source){const selected=kingdeeDocumentPeriod(source),orgValue=document.getElementById(source+'OrgSelect')?.value||'all',salesOrgId=orgValue==='all'?0:parseInt(orgValue||0);try{const response=await fetch(`/api/erp-api/kingdee/export/${source}?year=${selected.year}&period=${selected.period}&sales_org_id=${salesOrgId}`,{headers:authHeaders()});if(!response.ok){const payload=await response.json().catch(()=>({detail:'导出失败'}));throw new Error(payload.detail||'导出失败');}const blob=await response.blob(),url=URL.createObjectURL(blob),anchor=document.createElement('a');anchor.href=url;anchor.download=`${source}_${selected.year}_${String(selected.period).padStart(2,'0')}.xlsx`;document.body.appendChild(anchor);anchor.click();anchor.remove();URL.revokeObjectURL(url);}catch(error){toast(error.message);}}
async function loadErpApiPreview(source){if(source==='kingdee_sales_outbound'){setupKingdeePullUi();await applyKingdeeDefaultPeriod();await loadKingdeeSalesOrgsForPull();await checkKingdeeReconcile(false);}else if(kingdeeDocumentSources.has(source)){setupKingdeeDocumentPullUi(source);await applyKingdeeDocumentDefaultPeriod(source);await loadKingdeeDocumentOrgs(source);if(kingdeeInventorySources.has(source))await checkKingdeeInventory(source,false);}else{if(source==='jiaplus_self_ship')setupJiaplusSelfShipPullUi();if(source==='jiaplus_delivery')setupJiaplusDeliveryPullUi();erpApiDefaultDates(source);}renderErpApiRecords(source);pollErpApiJob(source);}
async function loadKingdeeSalesOrgsForPull(){try{const rows=await apiGet('/api/erp-api/kingdee/sales-orgs');const el=document.getElementById('kingdeeSalesOrg');if(!el)return;const selected=el.value||'all';el.innerHTML='全部销售组织 '+(rows||[]).filter(item=>item.enabled).map(item=>`${esc(item.code)} · ${esc(item.name)} `).join('');el.value=[...el.options].some(option=>option.value===selected)?selected:'all';}catch(e){toast('加载销售组织失败:'+e.message);}}
function onKingdeePullFilterChange(){erpApiPages.kingdee_sales_outbound=1;renderErpApiRecords('kingdee_sales_outbound');checkKingdeeReconcile(false);}
let kingdeeBillSearchTimer=null;
function onKingdeeBillSearch(){clearTimeout(kingdeeBillSearchTimer);kingdeeBillSearchTimer=setTimeout(()=>{erpApiPages.kingdee_sales_outbound=1;renderErpApiRecords('kingdee_sales_outbound');},300);}
function onKingdeeStatusFilterChange(){erpApiPages.kingdee_sales_outbound=1;renderErpApiRecords('kingdee_sales_outbound');}
function showInvalidKingdeeRows(){const org=document.getElementById('kingdeeSalesOrg'),bill=document.getElementById('kingdeeBillNoSearch'),status=document.getElementById('kingdeeRecordStatus');if(org)org.value='all';if(bill)bill.value='';if(status)status.value='invalid';erpApiPages.kingdee_sales_outbound=1;renderErpApiRecords('kingdee_sales_outbound');}
async function loadErpApiBatches(source){try{const rows=await apiGet('/api/erp-api/batches/'+source);erpApiBatchCache[source]=rows;const el=document.getElementById(source+'Batch');const selected=el.value;el.innerHTML='最新成功批次 '+rows.map(b=>`#${b.id} ${esc(b.start_date)}~${esc(b.end_date)} ${esc(b.status)} (${b.total}) `).join('');if([...el.options].some(o=>o.value===selected))el.value=selected;}catch(e){toast(e.message);}}
function erpApiFriendlyError(error){const message=String(error&&error.message||error||'未知错误');return message.includes('404')?'后台服务尚未加载本次新增接口,请重启本地服务后刷新页面':message;}
function showErpApiStatus(source,status,message){const el=document.getElementById(source+'Status');if(!el)return;const failed=status==='failed',success=status==='success';el.style.background=failed?'#fef2f2':success?'#f0fdf4':'#eff6ff';el.style.borderColor=failed?'#fecaca':success?'#bbf7d0':'#bfdbfe';el.style.color=failed?'#b91c1c':success?'#15803d':'#1d4ed8';el.innerHTML=`${failed?'拉取失败':success?'拉取成功':'后台任务'}: ${esc(message||status||'尚未拉取')}`;}
function onErpApiBatchChange(source){erpApiPages[source]=1;const id=parseInt(document.getElementById(source+'Batch').value||0),batch=erpApiBatchCache[source].find(x=>x.id===id);if(batch)showErpApiStatus(source,batch.status,batch.message);renderErpApiRecords(source);}
async function startErpApiPull(source){try{const btn=document.getElementById(source+'PullBtn');let body;if(source==='kingdee_sales_outbound'){const year=parseInt(document.getElementById('kingdeeSalesYear').value),period=parseInt(document.getElementById('kingdeeSalesPeriod').value),orgValue=document.getElementById('kingdeeSalesOrg').value,salesOrgId=parseInt(orgValue||0);if(orgValue==='all'){toast('“全部销售组织”仅用于查看,拉取时请选择具体组织');return;}if(!year||!period||!salesOrgId){toast('请选择年度、期间和销售组织');return;}body={year,period,sales_org_id:salesOrgId};}else if(kingdeeDocumentSources.has(source)){const {year,period}=kingdeeDocumentPeriod(source),orgValue=document.getElementById(source+'OrgSelect')?.value||'all',salesOrgId=parseInt(orgValue||0);if(orgValue==='all'){toast('“全部组织”仅用于查看,拉取时请选择具体组织');return;}if(!year||!period||!salesOrgId){toast('请选择年度、期间和组织');return;}body={year,period,sales_org_id:salesOrgId};}else{const start=document.getElementById(source+'Start').value,end=document.getElementById(source+'End').value;body={start_date:start,end_date:end,sales_org:''};}btn.disabled=true;btn.innerText='拉取中...';showErpApiStatus(source,'running','正在连接接口并拉取数据');const r=await apiPost('/api/erp-api/pull/'+source,body);erpApiLastJobStatus[source]='running';toast(r.accepted?'后台拉取任务已提交':'该数据源正在拉取');pollErpApiJob(source);}catch(e){const btn=document.getElementById(source+'PullBtn');btn.disabled=false;btn.innerText='后台拉取';showErpApiStatus(source,'failed',e.message);toast('提交失败:'+e.message);}}
async function pollErpApiJob(source){try{const s=await apiGet('/api/erp-api/jobs/'+source),previous=erpApiLastJobStatus[source],btn=document.getElementById(source+'PullBtn');showErpApiStatus(source,s.status,s.message);btn.disabled=!!s.running;btn.innerText=s.running?'拉取中...':'后台拉取';erpApiLastJobStatus[source]=s.status;if(s.running){setTimeout(()=>pollErpApiJob(source),3000);}else if(s.batch_id){if(source==='kingdee_sales_outbound')await checkKingdeeReconcile(false);else if(kingdeeInventorySources.has(source))await checkKingdeeInventory(source,false);renderErpApiRecords(source);if(previous==='running')toast((s.status==='failed'?'拉取失败:':'拉取完成:')+(s.message||''));}}catch(e){showErpApiStatus(source,'failed',erpApiFriendlyError(e));}}
const erpKingdeeColumns=[
['FID','表头内码'],['FEntity_FEntryID','明细内码'],
['FBillNo','单据编号'],['FDate','出库日期','date'],['FSaleOrgId.FNumber','销售组织编码'],
['FSaleOrgId.FName','销售组织名称'],['FCustomerID.FName','客户名称'],
['FMaterialID.FNumber','物料编码'],['FMaterialID.FName','物料名称'],['FRealQty','数量'],['FPrice','单价'],['FAmount','金额'],
['FAmount_LC','金额本位币'],['FTaxAmount','税额'],['FAllAmount','价税合计'],
['FAllAmount_LC','价税合计本位币'],['FSettleCurrID.FName','结算币别'],['FLocalCurrID.FName','本位币'],
['FCreatorId.FName','创建人'],['FPlatform','平台'],['FSourceBillNo','来源单据'],
['FSourceBillType','来源单据类型'],['FPlatformOrderNo','平台订单号'],['FStockID.FName','仓库']
];
const erpKingdeeRequiredPreviewFields=[['FPlatformOrderNo','平台订单号'],['FBillNo','单据编号'],['FMaterialID.FNumber','物料编码'],['FStockID.FName','仓库'],['FCustomerID.FName','客户名称']];
function erpKingdeeMissingFields(data){return erpKingdeeRequiredPreviewFields.filter(([key])=>!String(erpApiCellValue(data,key)||'').trim()).map(([,label])=>label);}
const erpJiaplusSelfShipFieldLabels={
isCustomizationOrder:'是否定制化订单',sourceChannel:'来源渠道',shopName:'店铺/站点',
sellerShipmentEndTime:'卖家发货截止时间',orderTime:'订单订购时间',buyerPayTax:'买家支付税费',
buyerPayShipFee:'买家支付运费',soOrderNo:'销售订单号(内部)',countryCode:'国家/地区',
currency:'币种',id:'订单内部ID',shopId:'店铺ID',shopCountryCode:'店铺国家/地区',
shipmentLevel:'配送等级',actualAmount:'实际支付金额',sellerRemark:'卖家备注',
totalAmount:'订单总金额',buyerInfo:'买家信息',discountCode:'折扣码',
createTime:'系统创建时间',morderType:'配送方式',consigneeInfo:'收货人信息',
sourceOrderNo:'平台单号',orderPerformingParty:'订单履约方',
orderType:'订单类型',discountFee:'折扣金额',
paymentMarketTime:'付款时间(当地)',otherTotalAmount:'其他总金额',erpShopName:'店铺名称',
orderDeliveryStatus:'发货状态',omsPushErrorMessage:'OMS推送信息',receiverMobilePhone:'收件人手机',
orderingTime:'下单时间(北京时间)',buyerAccountId:'买家账号ID',pointsPayment:'积分支付金额',
receiverPhone:'收件人电话',platformWarehouseName:'发货仓',parentOrderNumber:'父订单号',
id:'订单内部ID',refundedTotalAmount:'退款总金额',customerMemo:'客户备注',regionCnName:'区域名称',
platformOrderPaymentStatus:'平台付款状态',estimateLatestDeliveryMarketTime:'预计最晚送达时间(当地)',
orderingMarketTime:'下单时间(当地)',omsPushStatus:'OMS推送状态码',tax:'税费',
receiverAddressPostCode:'收件邮编',platformOriginOrderStatus:'平台原始订单状态',totalAmount:'订单总金额',
orderCancelStatusName:'取消状态',platformOrderDeliveryTime:'实际发货时间',
deliveryTime:'实际发货时间',deliveryTimeMarket:'实际发货时间(当地)',
foOrderNo:'系统订单号',foOrderStatus:'订单状态',bizStatus:'业务状态',
warehouseName:'发货仓库',warehouseId:'仓库ID',
accessMode:'接入方式',orderTotalAmountExcludingTax:'订单售价(不含税)',
discount:'订单折扣',points:'订单积分',shippingAmount:'订单其他费用',
paymentTime:'订单付款时间',paymentTimeMarket:'订单付款时间(当地)',
orderTimeMarket:'订单订购时间(当地)',orderTypeName:'订单类型',
deliveryMethod:'配送方式',taxAmount:'订单税金',warehouseRefCode:'仓库单号',
platformOrderDeliveryMarketTime:'平台发货时间(当地)',platformOrderNumber:'平台订单号',
receiverAddressCountry:'国家/地区',__logisticsCarrier:'物流承运商',
__trackingNumber:'跟踪号(运单号)',__logisticsChannel:'物流渠道',
__detailThirdSku:'三方仓SKU',__detailMsku:'MSKU',__detailSku:'SKU',__detailAsin:'ASIN/ItemID',
__detailCommodityName:'商品名称',__detailUnitPrice:'商品单价',
__detailQuantity:'订购数量',__detailExpectedQuantity:'应发量',__detailValidQuantity:'已发量',
__detailDiscount:'商品折扣',__detailBuyerPayShipFee:'商品买家支付运费',
__detailTaxAmount:'商品税金',__detailShippingAmount:'商品其他费用',__detailTotal:'总额',
__detailSourceLineNo:'来源行号',__detailOutOfStockFlag:'是否缺货',
__detailLineNo:'订单明细行号',__assignedWarehouseName:'平台仓库名称',
__assignedCarrierCode:'平台承运商编码',__assignedWarehouseId:'平台仓库ID'
};
const erpJiaplusSelfShipExtraFields=[
'__logisticsCarrier','__trackingNumber','__logisticsChannel','__detailThirdSku','__detailMsku','__detailSku',
'__detailAsin','__detailCommodityName','__detailUnitPrice',
'__detailQuantity','__detailExpectedQuantity','__detailValidQuantity','__detailDiscount',
'__detailBuyerPayShipFee','__detailTaxAmount','__detailShippingAmount','__detailTotal',
'__detailSourceLineNo','__detailOutOfStockFlag','__detailLineNo','__assignedWarehouseName',
'__assignedCarrierCode','__assignedWarehouseId'
];
const erpJiaplusSelfShipNestedFields=['soOrderDetails','orderItems','platformAssign','buyerInfo','consigneeInfo','foOrderLogisticsInfoVO'];
const erpJiaplusDeliveryFields=[
['__deliveryShop','店铺/站点',['marketName','shopSiteName','shopName','storeName']],
['__deliveryOrderNo','订单编号',['orderId','amazonOrderId','orderNo','sourceOrderNo']],
['__deliveryTitle','商品标题',['listingTitle','productTitle','itemTitle','title','commodityName']],
['__deliveryAsin','ASIN',['asin','asinCode']],
['__deliveryMsku','MSKU',['msku','sellerSku']],
['__deliveryProductName','产品名称',['produceName','productName','skuName']],
['__deliverySku','SKU',['sku','productSku']],
['__deliveryParentProduct','父产品名称',['parentProductName','parentSkuName']],
['__deliverySpu','SPU',['spu','spuCode']],
['__deliveryOperationLevel','商品运营级别',['operationLevel','productOperationLevel']],
['__deliverySellerOrderNo','卖家订单编号',['sellerOrderId','sellerOrderNo']],
['__deliveryOrderType','订单类型',['orderTypeName','orderType']],
['__deliveryReconcileStatus','核对状态',[]],
['__deliveryShipmentId','货件ID',['shipmentId','shipmentNo']],
['__deliveryOrderItemId','订单商品编码',['orderItemId','orderItemCode']],
['__deliveryOrderTimeMarket','订购时间(市场时间)',['purchaseDate','orderTimeMarket','purchaseDateMarket','purchaseDateLocal']],
['__deliveryOrderTimeUtc','订购时间(零时区)',['purchaseDateZero','orderTimeZero','purchaseDateUtc']],
['__deliveryPaymentTimeMarket','付款时间(市场时间)',['paymentsDate','paymentTimeMarket','paymentsDateMarket','paymentsDateLocal']],
['__deliveryPaymentTimeUtc','付款时间(零时区)',['paymentsDateZero','paymentTimeZero','paymentsDateUtc']],
['__deliverySalesChannel','销售渠道',['salesChannel','channelName']],
['__deliveryCurrency','币种',['currency','currencyCode']],
['__deliveryItemPrice','商品售价',['itemPrice','productAmount','salePrice']],
['__deliveryItemTax','税费',['itemTax','itemTaxAmount','taxAmount','tax']],
['__deliveryShippingPrice','运费',['shippingPrice','shippingAmount','freight']],
['__deliveryShippingTax','运费税',['shippingTax','freightTax']],
['__deliveryGiftWrapPrice','礼品包装费',['giftWrapPrice','giftWrapAmount']],
['__deliveryGiftWrapTax','礼品包装税',['giftWrapTax']],
['__deliveryItemPromotion','商品促销折扣',['itemPromotionDiscount','promotionDiscount']],
['__deliveryShippingDiscount','运费折扣',['shipPromotionDiscount','shippingDiscount']],
['__deliveryTotal','总额',[]],
['__deliveryQuantity','发货数量',['quantityShipped','shipmentQuantity','quantity']],
['__deliveryShipmentMarket','发货时间(市场时间)',['shipmentDate','shipmentDateMarket','shipmentTimeMarket','shipmentDateLocal','shipmentTimeLocal','deliveryTimeMarket','shippingTimeMarket','shipDateMarket','shipmentMarketTime']],
['__deliveryShipmentUtc','发货时间(零时区)',['shipmentDateZero','shipmentTimeZero','shipmentDateUtc']],
['__deliveryCarrier','承运人',['carrier','carrierName']],
['__deliveryTracking','追踪号码',['trackingNumber','trackingNo']],
['__deliveryArrivalMarket','预计到达时间(市场时间)',['estimatedArrivalDate','estimatedArrivalDateMarket','estimatedArrivalTimeMarket','estimatedArrivalDateLocal']],
['__deliveryArrivalUtc','预计到达时间(零时区)',['estimatedArrivalDateZero','estimatedArrivalTimeZero','estimatedArrivalDateUtc']],
['__deliveryCenterId','运营中心ID',['fulfillmentCenterId','operationCenterId']],
['__deliveryWarehouse','配送仓库名称',['shipmentWarehouseName','warehouseName','deliveryWarehouseName']],
['__deliveryService','配送服务',['shipServiceLevel','deliveryService']],
['__deliveryBuyerEmail','买家邮箱',['buyerEmail']],
['__deliveryCity','收货城市',['shipCity','shippingCity']],
['__deliveryState','收货地区',['shipState','shippingState']],
['__deliveryCountry','收货国家/地区',['shipCountry','shippingCountry','countryCode']],
['__deliveryUpdateTime','更新时间',['updateDate','updateTime','updatedAt']]
];
const erpJiaplusDeliveryFieldMap=Object.fromEntries(erpJiaplusDeliveryFields.map(([key,label,aliases])=>[key,{label,aliases}]));
const erpJiaplusDeliveryMoneyFields=new Set(['__deliveryItemPrice','__deliveryItemTax','__deliveryShippingPrice','__deliveryShippingTax','__deliveryGiftWrapPrice','__deliveryGiftWrapTax','__deliveryItemPromotion','__deliveryShippingDiscount']);
function erpDeliveryFirstValue(data,aliases){for(const key of aliases){const value=data&&data[key];if(value!==null&&value!==undefined&&value!=='')return value;}return '';}
function erpJiaplusNumber(value){if(value&&typeof value==='object')value=value.currencyAmount??value.amount??value.value??0;const number=Number(String(value??0).replace(/,/g,''));return Number.isFinite(number)?number:0;}
function erpJiaplusAmount(value){return erpJiaplusNumber(value).toLocaleString('zh-CN',{minimumFractionDigits:2,maximumFractionDigits:2});}
function erpDeliveryCellValue(data,key){
const field=erpJiaplusDeliveryFieldMap[key];if(!field)return '';
if(key==='__deliveryReconcileStatus'){
const orderType=String(erpDeliveryFirstValue(data,['orderTypeName','orderType'])||'').toLowerCase();
return ['multichannel','multichannelorder','multi_channel_order','多渠道订单'].includes(orderType)?'不核对(多渠道订单)':'参与核对';
}
if(key==='__deliveryTotal')return erpJiaplusAmount(
erpJiaplusNumber(erpDeliveryFirstValue(data,['itemPrice','productAmount','salePrice']))+
erpJiaplusNumber(erpDeliveryFirstValue(data,['shippingPrice','shippingAmount','freight']))+
erpJiaplusNumber(erpDeliveryFirstValue(data,['giftWrapPrice','giftWrapAmount']))+
erpJiaplusNumber(erpDeliveryFirstValue(data,['itemPromotionDiscount','promotionDiscount']))+
erpJiaplusNumber(erpDeliveryFirstValue(data,['shipPromotionDiscount','shippingDiscount']))
);
if(key==='__deliveryShop'){
const direct=String(erpDeliveryFirstValue(data,['marketName','shopSiteName'])||''),name=String(erpDeliveryFirstValue(data,['shopName','storeName'])||''),country=String(erpDeliveryFirstValue(data,['shopCountry','shopCountryCode','marketCountryCode'])||'');
if(direct)return direct;
return name&&country&&!name.toUpperCase().endsWith(':'+country.toUpperCase())?name+':'+country:name||country;
}
const value=erpDeliveryFirstValue(data,field.aliases);
if(key==='__deliveryOrderType')return ({StandardOrder:'亚马逊销售订单',Multichannel:'多渠道订单',MultiChannelOrder:'多渠道订单',Replacement:'换货订单',ReplacementOrder:'换货订单'})[value]||value;
if(erpJiaplusDeliveryMoneyFields.has(key))return erpJiaplusAmount(value);
if(value&&typeof value==='object')return value.currencyAmount??value.amount??value.value??JSON.stringify(value);
return value;
}
function erpSelfShipTrackingParts(data){
const logistics=data&&data.foOrderLogisticsInfoVO;
if(logistics){return [
logistics.actualCarrier||logistics.logisticsName||'',
logistics.trackingNo||logistics.waybillNo||'',
logistics.logisticsChannelName||logistics.logisticsChannel||''
];}
const result=[[],[],[]];
(data&&Array.isArray(data.items)?data.items:[]).forEach(item=>{
const values=Array.isArray(item.trackingNumberList)&&item.trackingNumberList.length?item.trackingNumberList:[item.trackingNumber];
values.filter(Boolean).forEach(raw=>{
const parts=String(raw).split('&');
const normalized=parts.length>=3?[parts[0],parts[1],parts[2]]:['',parts[0],''];
normalized.forEach((value,index)=>{
if(value&&!result[index].includes(value))result[index].push(value);
});
});
});
return result.map(values=>values.join(';'));
}
function erpSelfShipDetailValues(data,field){
const details=data&&(Array.isArray(data.orderItems)?data.orderItems:Array.isArray(data.soOrderDetails)?data.soOrderDetails:[]);
const fields=Array.isArray(field)?field:[field];
return details
.map(item=>{for(const key of fields){if(item&&item[key]!=null&&item[key]!=='')return item[key];}return '';})
.filter(value=>value!==null&&value!==undefined&&value!=='')
.map(String).join(';');
}
function erpSelfShipDetailTotals(data){
const details=data&&(Array.isArray(data.orderItems)?data.orderItems:Array.isArray(data.soOrderDetails)?data.soOrderDetails:[]);
return details.map(item=>erpJiaplusAmount(
erpJiaplusNumber(item&&item.unitPrice)*erpJiaplusNumber(item&&item.quantity)-
erpJiaplusNumber(item&&item.discount)+erpJiaplusNumber(item&&item.buyerPayShipFee)
)).join(';');
}
function erpApiCellValue(data,key,format){
let value='';
if(key.startsWith('__delivery')){
value=erpDeliveryCellValue(data,key);
}else if(key==='shopName'){
const name=String(data?.shopName||data?.erpShopName||''),country=String(data?.shopCountry||data?.shopCountryCode||(data?.sourceChannel==='SHOPIFY'?'Global':'')||'');
value=name&&country&&!name.toUpperCase().endsWith(':'+country.toUpperCase())?name+':'+country:name||country;
}else if(key==='foOrderStatus'){
value=({ALREADY_DELIVERY:'已发货',AWAIT_DELIVERY:'待发货',CANCELLED:'已取消'})[data?.foOrderStatus]||data?.foOrderStatus||'';
}else if(key==='deliveryMethod'){
value=({SELLER:'卖家自配送',PLATFORM:'平台配送'})[data?.deliveryMethod]||data?.deliveryMethod||'';
}else if(key==='__logisticsCarrier'||key==='__trackingNumber'||key==='__logisticsChannel'){
const index={__logisticsCarrier:0,__trackingNumber:1,__logisticsChannel:2}[key];
value=erpSelfShipTrackingParts(data)[index];
}else if(key==='receiverAddressCountry'){
const country=data&&data.receiverAddressCountry||'',code=data&&data.receiverAddressCountryCode||'';
value=country+(country&&code?'('+code+')':code);
}else if(key==='__detailTotal'){
value=erpSelfShipDetailTotals(data);
}else if(key.startsWith('__detail')){
const field={
__detailThirdSku:'thirdSku',__detailMsku:'msku',__detailSku:'sku',__detailAsin:'asin',
__detailCommodityName:'commodityName',__detailUnitPrice:'unitPrice',
__detailQuantity:'quantity',__detailExpectedQuantity:'expectedQuantity',__detailValidQuantity:'validQuantity',
__detailDiscount:'discount',__detailBuyerPayShipFee:'buyerPayShipFee',
__detailTaxAmount:'taxAmount',__detailShippingAmount:'shippingAmount',
__detailSourceLineNo:'sourceLineNo',__detailOutOfStockFlag:'outOfStockFlag',
__detailLineNo:['foOrderLineNo','packageLineNo','soOrderLineNo']
}[key];
value=erpSelfShipDetailValues(data,field);
if(key==='__detailOutOfStockFlag')value=String(value).split(';').map(item=>item==='Y'?'是':item==='N'?'否':item).join(';');
}else if(key.startsWith('__assigned')){
const field={
__assignedWarehouseName:'platformWarehouseName',
__assignedCarrierCode:'platformCarrierCode',
__assignedWarehouseId:'platformWarehouseId'
}[key];
value=data&&data.platformAssign&&data.platformAssign[field]!=null?data.platformAssign[field]:'';
}else if(key.includes('.')){
value=data&&Object.prototype.hasOwnProperty.call(data,key)?data[key]:key.split('.').reduce((current,part)=>current&¤t[part]!=null?current[part]:'',data);
}else value=data&&data[key]!=null?data[key]:'';
if(format==='date'&&value)value=String(value).slice(0,10);
return typeof value==='object'?JSON.stringify(value):value;
}
const erpKingdeeTotalFields=new Set(['FRealQty','FAmount_LC','FTaxAmount','FAllAmount','FAllAmount_LC']);
function erpKingdeeTotalValue(key,value){
const number=Number(value||0);
return number.toLocaleString('zh-CN',key==='FRealQty'?{maximumFractionDigits:6}:{minimumFractionDigits:2,maximumFractionDigits:2});
}
function renderErpKingdeeTotals(foot,totals,total){
if(!foot)return;
foot.innerHTML='合计(全部 '+total+' 条) '+erpKingdeeColumns.map(column=>{
const key=column[0],value=erpKingdeeTotalFields.has(key)?erpKingdeeTotalValue(key,totals&&totals[key]):'';
return `${esc(value)} `;
}).join('')+' ';
}
async function exportKingdeeSalesOutbound(){
try{
const year=parseInt(document.getElementById('kingdeeSalesYear').value),period=parseInt(document.getElementById('kingdeeSalesPeriod').value),orgValue=document.getElementById('kingdeeSalesOrg').value,salesOrgId=parseInt(orgValue||0);
if(orgValue==='all'){toast('导出时请选择一个具体销售组织');return;}
if(!year||!period||!salesOrgId){toast('请选择年度、期间和销售组织');return;}
showLoading('正在导出金蝶销售出库API数据...');
const url='/api/erp-api/kingdee/export?year='+year+'&period='+period+'&sales_org_id='+salesOrgId;
const response=await fetch(url,{headers:authHeaders()});
if(!response.ok){let message='导出失败:HTTP '+response.status;try{const error=await response.json();if(error.detail)message=error.detail;}catch(_error){}throw new Error(message);}
const blob=await response.blob(),downloadUrl=URL.createObjectURL(blob),anchor=document.createElement('a');
anchor.href=downloadUrl;anchor.download='kingdee_sales_outbound_'+year+'_'+String(period).padStart(2,'0')+'.xlsx';document.body.appendChild(anchor);anchor.click();
setTimeout(()=>{URL.revokeObjectURL(downloadUrl);anchor.remove();},1000);hideLoading();toast('导出成功');
}catch(error){hideLoading();toast(error.message);}
}
async function exportJiaplusPreview(source){
try{
const labels={jiaplus_delivery:'积加配送报告',jiaplus_self_ship:'积加自发货订单'},label=labels[source];
if(!label){toast('不支持的积加导出类型');return;}
showLoading('正在导出'+label+'全量数据...');
const response=await fetch('/api/erp-api/jiaplus/export/'+source,{headers:authHeaders()});
if(!response.ok){let message='导出失败:HTTP '+response.status;try{const error=await response.json();if(error.detail)message=error.detail;}catch(_error){}throw new Error(message);}
const start=document.getElementById(source+'Start')?.value||'',end=document.getElementById(source+'End')?.value||'',disposition=response.headers.get('Content-Disposition')||'',filenameMatch=disposition.match(/filename="?([^";]+)"?/i),blob=await response.blob(),downloadUrl=URL.createObjectURL(blob),anchor=document.createElement('a');
anchor.href=downloadUrl;anchor.download=filenameMatch?filenameMatch[1]:label+'_'+start+'_'+end+'.xlsx';document.body.appendChild(anchor);anchor.click();
setTimeout(()=>{URL.revokeObjectURL(downloadUrl);anchor.remove();},1000);hideLoading();toast('导出成功');
}catch(error){hideLoading();toast(error.message);}
}
async function publishJiaplusPreview(source){
const labels={jiaplus_delivery:'积加配送报告',jiaplus_self_ship:'积加自发货订单'},label=labels[source];
if(!label){toast('不支持的积加发布类型');return;}
if(!confirm('确认将当前'+label+'预览发布到销售出库数据的积加页签?重复业务明细将被覆盖。'))return;
try{
showLoading('正在发布'+label+'...');
const result=await apiPost('/api/erp-api/jiaplus/publish/'+source,{});
hideLoading();toast(result.message||'发布完成');
}catch(error){hideLoading();toast(error.message);}
}
function erpJiaplusStatusHtml(row){
if(row.record_status==='skipped')return '不核对 ';
if(row.record_status==='invalid')return '字段不完整 ';
return '字段完整 ';
}
async function renderErpApiRecords(source){
try{
const batch=document.getElementById(source+'Batch').value;
let url='/api/erp-api/records/'+source+'?page='+erpApiPages[source]+'&page_size='+erpApiPageSizes[source];
if(batch)url+='&batch_id='+batch;
if(source==='kingdee_sales_outbound'){const year=parseInt(document.getElementById('kingdeeSalesYear')?.value||0),period=parseInt(document.getElementById('kingdeeSalesPeriod')?.value||0),orgValue=document.getElementById('kingdeeSalesOrg')?.value||'all',salesOrgId=parseInt(orgValue||0),billNo=document.getElementById('kingdeeBillNoSearch')?.value.trim()||'',recordStatus=document.getElementById('kingdeeRecordStatus')?.value||'all';if(year&&period){url+='&year='+year+'&period='+period;if(orgValue==='all')url+='&all_sales_orgs=true';else if(salesOrgId)url+='&sales_org_id='+salesOrgId;if(billNo)url+='&bill_no='+encodeURIComponent(billNo);if(recordStatus!=='all')url+='&record_status='+recordStatus;}}
else if(kingdeeDocumentSources.has(source)){const {year,period}=kingdeeDocumentPeriod(source),orgValue=document.getElementById(source+'OrgSelect')?.value||'all',salesOrgId=parseInt(orgValue||0),billNo=document.getElementById(source+'BillSearch')?.value.trim()||'',recordStatus=document.getElementById(source+'StatusFilter')?.value||'all';if(year&&period){url+='&year='+year+'&period='+period;if(orgValue==='all')url+='&all_sales_orgs=true';else if(salesOrgId)url+='&sales_org_id='+salesOrgId;if(billNo)url+='&bill_no='+encodeURIComponent(billNo);if(recordStatus!=='all')url+='&record_status='+recordStatus;}}
else if(source==='jiaplus_delivery'||source==='jiaplus_self_ship'){const orderSearch=document.getElementById(source+'OrderSearch')?.value.trim()||'',recordStatus=document.getElementById(source+'RecordStatus')?.value||'all';if(orderSearch)url+='&bill_no='+encodeURIComponent(orderSearch);if(recordStatus!=='all')url+='&record_status='+recordStatus;}
const r=await apiGet(url),rows=r.rows||[],head=document.getElementById(source+'Head'),body=document.getElementById(source+'Body'),foot=document.getElementById(source+'Total');
erpApiTotals[source]=r.total||0;
if(source==='kingdee_sales_outbound'){
head.innerHTML='序号 数据状态 '+erpKingdeeColumns.map(c=>{
const hint=c[0]==='FLocalCurrID.FName'?'取自表头财务页签,显示名称':(['FPrice','FAmount','FAmount_LC','FTaxAmount','FAllAmount','FAllAmount_LC'].includes(c[0])?'取自明细表':'');
return `${c[1]} `;
}).join('')+' ';
body.innerHTML=rows.map((row,index)=>{const missing=erpKingdeeMissingFields(row.data),state=row.customer_skip?'不核对 ':missing.length?`字段不完整 `:'字段完整 ';return `${(r.page-1)*r.page_size+index+1} ${state} ${erpKingdeeColumns.map(c=>`${esc(erpApiCellValue(row.data,c[0],c[2]))} `).join('')} `;}).join('')||`暂无原始数据
`;
renderErpKingdeeTotals(foot,r.totals||{},r.total||0);
}else if(kingdeeDocumentSources.has(source)){
const keys=(r.field_keys||[]).length?r.field_keys:[...new Set(rows.flatMap(row=>Object.keys(row.data||{})))],labels=r.field_labels||{};
head.innerHTML='序号 数据状态 '+keys.map(key=>`${esc(labels[key]||key)} `).join('')+' ';
body.innerHTML=rows.map((row,index)=>{const state=row.record_status==='invalid'?`字段不完整 `:'字段完整 ';return `${(r.page-1)*r.page_size+index+1} ${state} ${keys.map(key=>`${esc(erpApiCellValue(row.data,key,key==='FDate'||key==='FDATE'?'date':''))} `).join('')} `;}).join('')||`暂无原始数据
`;
if(foot)foot.innerHTML='合计(全部 '+(r.total||0)+' 条) '+keys.map(key=>`${Object.prototype.hasOwnProperty.call(r.totals||{},key)?esc(erpKingdeeTotalValue(key,r.totals[key])):''} `).join('')+' ';
}else{
if(foot)foot.innerHTML='';
const keys=source==='jiaplus_self_ship'?
['sourceOrderNo','foOrderNo','shopName','sourceChannel','accessMode','foOrderStatus','orderTypeName','deliveryMethod','warehouseName','warehouseRefCode','deliveryTime','orderTime','paymentTime','sellerShipmentEndTime','createTime','currency','orderTotalAmountExcludingTax','discount','buyerPayShipFee','taxAmount','points','shippingAmount']:
source==='jiaplus_delivery'?erpJiaplusDeliveryFields.map(([key])=>key):[];
if(source==='jiaplus_self_ship')rows.forEach(row=>Object.keys(row.data||{}).forEach(key=>{
if(source==='jiaplus_self_ship'&&erpJiaplusSelfShipNestedFields.includes(key))return;
if(!keys.includes(key)&&keys.length<30)keys.push(key);
}));
if(source==='jiaplus_self_ship')erpJiaplusSelfShipExtraFields.forEach(key=>{if(!keys.includes(key))keys.push(key);});
head.innerHTML='序号 数据状态 外部ID '+keys.map(key=>`${esc(source==='jiaplus_self_ship'?(erpJiaplusSelfShipFieldLabels[key]||key):source==='jiaplus_delivery'?(erpJiaplusDeliveryFieldMap[key]?.label||key):key)} `).join('')+' ';
body.innerHTML=rows.map((row,index)=>`${(r.page-1)*r.page_size+index+1} ${erpJiaplusStatusHtml(row)} ${esc(row.external_id||'')} ${keys.map(key=>`${esc(erpApiCellValue(row.data,key))} `).join('')} `).join('')||'暂无原始数据
';
}
const rangeStart=r.total?(r.page-1)*r.page_size+1:0,rangeEnd=Math.min(r.page*r.page_size,r.total),pages=Math.max(1,Math.ceil(r.total/r.page_size)),batchText=source==='jiaplus_self_ship'||source==='jiaplus_delivery'?'当前预览数据':(r.batch_ids||[]).length?'合并组织数据':'当前组织数据';
document.getElementById(source+'Page').innerText='显示第 '+rangeStart+'-'+rangeEnd+' 条,共 '+r.total+' 条(第 '+r.page+'/'+pages+' 页);'+batchText;
}catch(e){toast('加载原始数据失败:'+erpApiFriendlyError(e));}
}
function changeErpApiPage(source,delta){if(delta>0&&erpApiPages[source]*erpApiPageSizes[source]>=erpApiTotals[source])return;erpApiPages[source]=Math.max(1,erpApiPages[source]+delta);renderErpApiRecords(source);}
function changeErpApiPageSize(source){erpApiPageSizes[source]=parseInt(document.getElementById(source+'PageSize').value)||100;erpApiPages[source]=1;renderErpApiRecords(source);}