Compare commits

...
5 Commits
Author SHA1 Message Date
cheney 75f15aeabb 火车票版本增加try试运行参数 2026-10-21 20:45:08 +08:00
cheney 801920fcde 新增只处理火车票版本 2026-10-21 20:23:11 +08:00
cheney 18941236af 移除随机延时 2026-10-21 20:10:19 +08:00
cheney 3b79054995 更新代理配置与对账单数据 2026-10-21 19:59:48 +08:00
cheney 9cf1aacd74 更新token并增加接口错误处理 2026-10-21 19:59:46 +08:00
6 changed files with 333 additions and 78 deletions
+12 -20
View File
@@ -6,7 +6,7 @@ const EXCEL_FILE = path.join(__dirname, '新建 XLSX 工作表.xlsx');
const SHEET_NAME = '2026'; const SHEET_NAME = '2026';
const BASE_URL = 'https://superstar.geelytravel.com'; const BASE_URL = 'https://superstar.geelytravel.com';
const AUTH_TOKEN = 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKV1QtRC1TRVFfVVNFUl9UTUNfMDAwMDAxODMiLCJ1c2VyX2NvZGUiOiJTRVFfVVNFUl9UTUNfMDAwMDAxODMiLCJyb2xlcyI6WyLnu5PnrpfkuJPlkZgiLCLnu5PnrpfkuJPlkZgiXSwiZXhwIjoxNzg2NTMzNTUxLCJpYXQiOjE3ODM5NDE1NTF9.1Mcmf5IM07Scrry4FzPs6TAcfUu0Nqtjre_2iJlNd5c'; const AUTH_TOKEN = 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKV1QtRC1TRVFfVVNFUl9UTUNfMDAwMDAxODMiLCJ1c2VyX2NvZGUiOiJTRVFfVVNFUl9UTUNfMDAwMDAxODMiLCJyb2xlcyI6WyLnu5PnrpfkuJPlkZgiLCLnu5PnrpfkuJPlkZgiXSwiZXhwIjoxNzk1MDkxMTI3LCJpYXQiOjE3OTI0OTkxMjd9.wPYA-ntdWfT86LsQIYEJdVUHEksbMM9VwE96VqPdGms';
const COMMON_HEADERS = { const COMMON_HEADERS = {
'accept': 'application/json, text/plain, */*', 'accept': 'application/json, text/plain, */*',
@@ -195,10 +195,6 @@ async function processHotelBill(bill, billIndex, totalBills) {
const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId); const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId);
console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp)); console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp));
const waitSeconds = randomDelaySeconds();
console.log(' [延时] 随机等待 ' + waitSeconds + 's 后继续开票...');
await sleep(waitSeconds * 1000);
const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId); const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId);
console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp)); console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp));
@@ -240,10 +236,6 @@ async function processFlightBill(bill, billIndex, totalBills) {
const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId); const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId);
console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp)); console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp));
const waitSeconds = randomDelaySeconds();
console.log(' [延时] 随机等待 ' + waitSeconds + 's 后继续开票...');
await sleep(waitSeconds * 1000);
const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId); const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId);
console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp)); console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp));
@@ -271,10 +263,6 @@ async function processInternationalFlightBill(bill, billIndex, totalBills) {
const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId); const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId);
console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp)); console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp));
const waitSeconds = randomDelaySeconds();
console.log(' [延时] 随机等待 ' + waitSeconds + 's 后继续开票...');
await sleep(waitSeconds * 1000);
const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId); const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId);
console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp)); console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp));
@@ -292,13 +280,15 @@ async function processInternationalFlightBill(bill, billIndex, totalBills) {
console.log(''); console.log('');
} }
// ========== 13. 随机延时 ========== // ========== 接口错误检查 ==========
function sleep(ms) { function ensureOk(resp, what) {
return new Promise(function (resolve) { setTimeout(resolve, ms); }); if (resp && resp.code && resp.code !== 'Z000') {
} if (resp.code === 'E003') {
console.error(' ✗ token 已失效(E003: ' + (resp.msg || '') + '),请更新 AUTH_TOKEN');
function randomDelaySeconds() { process.exit(1);
return Math.floor(15 + Math.random() * 31); }
throw new Error(what + ' 失败: [' + resp.code + '] ' + (resp.msg || resp.message || ''));
}
} }
// ========== 主流程 ========== // ========== 主流程 ==========
@@ -315,6 +305,7 @@ async function main() {
try { try {
const settlementResp = await querySettlementAccountIds(teamId); const settlementResp = await querySettlementAccountIds(teamId);
ensureOk(settlementResp, 'querySettlementAccountIds');
const resultList = settlementResp?.result || []; const resultList = settlementResp?.result || [];
if (resultList.length === 0) { if (resultList.length === 0) {
console.log(' ⚠ ' + teamId + ' 没有 settlement account,跳过\n'); console.log(' ⚠ ' + teamId + ' 没有 settlement account,跳过\n');
@@ -324,6 +315,7 @@ async function main() {
console.log(' -> settlementAccountId: ' + settlementAccountId); console.log(' -> settlementAccountId: ' + settlementAccountId);
const billResp = await queryBillList(settlementAccountId); const billResp = await queryBillList(settlementAccountId);
ensureOk(billResp, 'queryBillList');
const allBills = billResp?.result?.list || []; const allBills = billResp?.result?.list || [];
const total = billResp?.result?.total || 0; const total = billResp?.result?.total || 0;
console.log(' -> 共 ' + total + ' 条对账单'); console.log(' -> 共 ' + total + ' 条对账单');
+275
View File
@@ -0,0 +1,275 @@
const XLSX = require('xlsx');
const path = require('path');
// ========== 配置 ==========
const EXCEL_FILE = path.join(__dirname, '新建 XLSX 工作表.xlsx');
const SHEET_NAME = '2026';
// 试运行模式:运行时传入 try 参数激活(node kaipiao-train-only.js try),
// 只查询和判断状态,不执行任何真实开票动作(init/confirm/submit);不传则执行真实开票
const TRY = process.argv.includes('try');
const BASE_URL = 'https://superstar.geelytravel.com';
const AUTH_TOKEN = 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKV1QtRC1TRVFfVVNFUl9UTUNfMDAwMDAxODMiLCJ1c2VyX2NvZGUiOiJTRVFfVVNFUl9UTUNfMDAwMDAxODMiLCJyb2xlcyI6WyLnu5PnrpfkuJPlkZgiLCLnu5PnrpfkuJPlkZgiXSwiZXhwIjoxNzk1MDkxMTI3LCJpYXQiOjE3OTI0OTkxMjd9.wPYA-ntdWfT86LsQIYEJdVUHEksbMM9VwE96VqPdGms';
const COMMON_HEADERS = {
'accept': 'application/json, text/plain, */*',
'accept-language': 'zh-CN,zh;q=0.9',
'authorization': AUTH_TOKEN,
'cache-control': 'no-cache',
'pragma': 'no-cache',
'requestsource': 'D',
'sec-fetch-dest': 'empty',
'sec-fetch-mode': 'cors',
'sec-fetch-site': 'same-origin',
'usercode': 'SEQ_USER_TMC_00000183',
'cookie': '_c_WBKFRo=CefecIUfnnuqejh60diYtytjDPwI9Qptslcwakc4; acw_tc=731dc87617840296932491914e815aef28b42e276e1a01eb53ed0f548bd5e3',
};
const INVOICE_APPLY_TITLE = '浙江吉利商务服务有限公司';
const INVOICE_TITLE = '吉智(杭州)文化创意有限公司';
const TAXPAYER_ID = '91330109MA2GM71J64';
const ADDRESS = '杭州市萧山区经纪技术开发区启迪路198号A-B102-126B室';
const TELEPHONE = '0571-85321518';
const DEPOSIT_BANK = '中国民生银行股份有限公司杭州分行';
const BANK_ACCOUNT = '631101003';
// ========== 1. 读取 Excel ==========
function readTeamIds() {
const workbook = XLSX.readFile(EXCEL_FILE);
const sheet = workbook.Sheets[SHEET_NAME];
if (!sheet) {
console.error('Sheet "' + SHEET_NAME + '" 不存在');
process.exit(1);
}
const rows = XLSX.utils.sheet_to_json(sheet, { defval: null });
const teamIds = [];
for (const row of rows) {
const val = row['团号'];
if (val && /^TEAM-\d+$/.test(String(val).trim())) {
teamIds.push(String(val).trim());
}
}
console.log('[Excel] 找到 ' + teamIds.length + ' 个 TEAM ID: ' + teamIds.join(', ') + '\n');
return teamIds;
}
// ========== 2. 查询 settlement account ==========
async function querySettlementAccountIds(teamId) {
const url = BASE_URL + '/api/tmc/tmc/customerAccount/settlement/querySettlementAccountIds?customerSettlementAccountName=' + teamId;
const resp = await fetch(url, { headers: COMMON_HEADERS, method: 'GET' });
return resp.json();
}
// ========== 3. 查询 bill list ==========
async function queryBillList(settlementAccountId) {
const url = BASE_URL + '/api/tmc/tmc/settlement/receiveBill/queryBillList?settlementAccountId=' + settlementAccountId + '&pageIndex=1&pageSize=10';
const resp = await fetch(url, { headers: COMMON_HEADERS, method: 'GET' });
return resp.json();
}
// ========== 4. 初始化开票价格信息 ==========
async function initReceiveOrderPrice(settlementSeq, receiveBillId) {
const url = BASE_URL + '/api/tmc/tmc/settlement/receiveInvoice/initReceiveOrderPrice';
const headers = {
...COMMON_HEADERS,
'content-type': 'application/json;charset=UTF-8',
'Referer': BASE_URL + '/new-tmc/finance/settlement/pay/invoice/billing/' + receiveBillId,
};
const body = JSON.stringify({ settlementSeq: settlementSeq });
const resp = await fetch(url, { headers: headers, method: 'POST', body: body });
return resp.json();
}
// ========== 5. 确认开票 ==========
async function confirmInvoiceOrder(settlementSeq, receiveBillId) {
const url = BASE_URL + '/api/tmc/tmc/settlement/receiveInvoice/confirmInvoiceOrder';
const headers = {
...COMMON_HEADERS,
'content-type': 'application/json;charset=UTF-8',
'Referer': BASE_URL + '/new-tmc/finance/settlement/pay/invoice/billing/' + receiveBillId,
};
const body = JSON.stringify({ settlementSeq: settlementSeq, orderMode: '1' });
const resp = await fetch(url, { headers: headers, method: 'POST', body: body });
return resp.json();
}
// ========== 6. 提交开票 ==========
async function submitInvoiceApply(confirmInvoiceKey, invoiceInfoList, receiveBillId) {
const url = BASE_URL + '/api/tmc/tmc/settlement/receiveInvoice/submitInvoiceApply';
const headers = {
...COMMON_HEADERS,
'content-type': 'application/json;charset=UTF-8',
'Referer': BASE_URL + '/new-tmc/finance/settlement/pay/invoice/billing/' + receiveBillId,
};
const body = JSON.stringify({
confirmInvoiceKey: confirmInvoiceKey,
invoiceInfoList: invoiceInfoList,
});
const resp = await fetch(url, { headers: headers, method: 'POST', body: body });
return resp.json();
}
// ========== 7. 填充公司信息 ==========
function fillCompanyInfo(item) {
return {
...item,
invoiceApplyTitle: INVOICE_APPLY_TITLE,
invoiceTitle: INVOICE_TITLE,
taxpayerIdentityNumber: TAXPAYER_ID,
address: ADDRESS,
telephone: TELEPHONE,
depositBank: DEPOSIT_BANK,
bankAccount: BANK_ACCOUNT,
};
}
// ========== 8. 映射火车票开票项 ==========
function mapTrainInvoice(serverItem) {
const invoiceType = serverItem.invoiceType || '';
const item = {
invoiceSerialNum: serverItem.invoiceSerialNum,
invoiceType: invoiceType,
invoicePrice: serverItem.invoicePrice,
taxRate: invoiceType === '13' ? 6 : 0,
invoiceSettlementDetail: serverItem.settlementDetails || '',
invoiceQuantity: serverItem.invoiceQuantity || 0,
ticketList: serverItem.ticketList || null,
};
if (invoiceType === '13') {
item.invoiceContent = '*生产生活服务*代订火车票服务费';
}
return fillCompanyInfo(item);
}
// ========== 9. 处理火车票 ==========
async function processTrainBill(bill, billIndex, totalBills) {
const settlementSeq = bill.settlementSeq;
const receiveBillId = bill.receiveBillId;
console.log(' --- 火车票 [' + billIndex + '/' + totalBills + '] ' + bill.statementName + ' ---');
if (TRY) {
console.log(' [试运行] 跳过真实开票动作(init/confirm/submit)\n');
return;
}
const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId);
console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp));
const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId);
console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp));
const confirmResult = confirmResp?.result;
if (!confirmResult || !confirmResult.invoiceAble) {
console.log(' ⚠ 跳过: ' + (confirmResp?.message || '') + '\n');
return;
}
const confirmInvoiceKey = confirmResult.confirmInvoiceKey;
const submitList = (confirmResult.invoiceInfoList || []).map(mapTrainInvoice);
const submitResp = await submitInvoiceApply(confirmInvoiceKey, submitList, receiveBillId);
console.log(' -> submitInvoiceApply:', JSON.stringify(submitResp));
console.log('');
}
// ========== 接口错误检查 ==========
function ensureOk(resp, what) {
if (resp && resp.code && resp.code !== 'Z000') {
if (resp.code === 'E003') {
console.error(' ✗ token 已失效(E003: ' + (resp.msg || '') + '),请更新 AUTH_TOKEN');
process.exit(1);
}
throw new Error(what + ' 失败: [' + resp.code + '] ' + (resp.msg || resp.message || ''));
}
}
// ========== 主流程 ==========
async function main() {
const teamIds = readTeamIds();
if (teamIds.length === 0) {
console.log('没有找到 TEAM ID,退出');
return;
}
const specialStatusTeamIds = [];
for (let i = 0; i < teamIds.length; i++) {
const teamId = teamIds[i];
console.log('[' + (i + 1) + '/' + teamIds.length + '] 处理 ' + teamId + ' ...');
try {
const settlementResp = await querySettlementAccountIds(teamId);
ensureOk(settlementResp, 'querySettlementAccountIds');
const resultList = settlementResp?.result || [];
if (resultList.length === 0) {
console.log(' ⚠ ' + teamId + ' 没有 settlement account,跳过\n');
continue;
}
const settlementAccountId = resultList[0]?.id;
console.log(' -> settlementAccountId: ' + settlementAccountId);
const billResp = await queryBillList(settlementAccountId);
ensureOk(billResp, 'queryBillList');
const allBills = billResp?.result?.list || [];
const total = billResp?.result?.total || 0;
console.log(' -> 共 ' + total + ' 条对账单');
const skippedBills = allBills.filter(function (b) { return String(b.settlementStatus) === '3'; });
skippedBills.forEach(function (b) {
console.log(' ⚠ 跳过 settlementStatus=3 的对账单: ' + (b.statementName || b.receiveBillId || ''));
});
if (skippedBills.length > 0) {
specialStatusTeamIds.push(teamId);
console.log(' ⚠ TEAM ' + teamId + ' 存在特殊状态(settlementStatus=3)的对账单 ' + skippedBills.length + ' 条\n');
}
const bills = allBills.filter(function (b) { return String(b.settlementStatus) !== '3'; });
console.log(' -> 实际处理 ' + bills.length + ' 条对账单\n');
const trainBills = bills.filter(function (b) { return (b.statementName || '').includes('火车票'); });
const hotelBills = bills.filter(function (b) { return (b.statementName || '').includes('酒店'); });
const flightBills = bills.filter(function (b) { return (b.statementName || '').includes('国内机票'); });
const intlFlightBills = bills.filter(function (b) { return (b.statementName || '').includes('国际机票'); });
const otherBills = bills.filter(function (b) {
const name = b.statementName || '';
return !name.includes('火车票') && !name.includes('酒店') && !name.includes('国内机票') && !name.includes('国际机票');
});
console.log(' -> 火车票: ' + trainBills.length + ' (处理), 酒店: ' + hotelBills.length + ', 国内机票: ' + flightBills.length + ', 国际机票: ' + intlFlightBills.length + ', 其他: ' + otherBills.length + '\n');
for (let j = 0; j < trainBills.length; j++) {
await processTrainBill(trainBills[j], j + 1, trainBills.length);
}
const skippedNonTrainBills = bills.filter(function (b) { return !(b.statementName || '').includes('火车票'); });
if (skippedNonTrainBills.length > 0) {
console.log(' ⚠ 本版本只处理火车票,跳过 ' + skippedNonTrainBills.length + ' 条非火车票对账单:');
skippedNonTrainBills.forEach(function (b) { console.log(' - ' + b.statementName); });
console.log('');
}
if (otherBills.length > 0) {
console.log(' === 以下对账单未处理(未知类型) ===');
otherBills.forEach(function (b) { console.log(' - ' + b.statementName); });
console.log('');
}
} catch (err) {
console.error(' ✗ ' + teamId + ' 出错:', err.message);
}
console.log('');
}
console.log('========== ' + (TRY ? '试运行完成(未执行真实开票)' : '完成') + ' ==========');
if (specialStatusTeamIds.length > 0) {
console.log('存在特殊状态(settlementStatus=3)的 TEAM: ' + specialStatusTeamIds.join(', '));
} else {
console.log('没有 TEAM 存在特殊状态(settlementStatus=3)的对账单');
}
}
main().catch(err => {
console.error('Fatal error:', err);
process.exit(1);
});
+12 -24
View File
@@ -6,7 +6,7 @@ const EXCEL_FILE = path.join(__dirname, '新建 XLSX 工作表.xlsx');
const SHEET_NAME = '2026'; const SHEET_NAME = '2026';
const BASE_URL = 'https://superstar.geelytravel.com'; const BASE_URL = 'https://superstar.geelytravel.com';
const AUTH_TOKEN = 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKV1QtRC1TRVFfVVNFUl9UTUNfMDAwMDAxODMiLCJ1c2VyX2NvZGUiOiJTRVFfVVNFUl9UTUNfMDAwMDAxODMiLCJyb2xlcyI6WyLnu5PnrpfkuJPlkZgiLCLnu5PnrpfkuJPlkZgiXSwiZXhwIjoxNzg2NTMzNTUxLCJpYXQiOjE3ODM5NDE1NTF9.1Mcmf5IM07Scrry4FzPs6TAcfUu0Nqtjre_2iJlNd5c'; const AUTH_TOKEN = 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKV1QtRC1TRVFfVVNFUl9UTUNfMDAwMDAxODMiLCJ1c2VyX2NvZGUiOiJTRVFfVVNFUl9UTUNfMDAwMDAxODMiLCJyb2xlcyI6WyLnu5PnrpfkuJPlkZgiLCLnu5PnrpfkuJPlkZgiXSwiZXhwIjoxNzk1MDkxMTI3LCJpYXQiOjE3OTI0OTkxMjd9.wPYA-ntdWfT86LsQIYEJdVUHEksbMM9VwE96VqPdGms';
const COMMON_HEADERS = { const COMMON_HEADERS = {
'accept': 'application/json, text/plain, */*', 'accept': 'application/json, text/plain, */*',
@@ -206,10 +206,6 @@ async function processTrainBill(bill, billIndex, totalBills) {
const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId); const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId);
console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp)); console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp));
const waitSeconds = randomDelaySeconds();
console.log(' [延时] 随机等待 ' + waitSeconds + 's 后继续开票...');
await sleep(waitSeconds * 1000);
const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId); const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId);
console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp)); console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp));
@@ -244,10 +240,6 @@ async function processHotelBill(bill, billIndex, totalBills) {
const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId); const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId);
console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp)); console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp));
const waitSeconds = randomDelaySeconds();
console.log(' [延时] 随机等待 ' + waitSeconds + 's 后继续开票...');
await sleep(waitSeconds * 1000);
const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId); const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId);
console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp)); console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp));
@@ -289,10 +281,6 @@ async function processFlightBill(bill, billIndex, totalBills) {
const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId); const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId);
console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp)); console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp));
const waitSeconds = randomDelaySeconds();
console.log(' [延时] 随机等待 ' + waitSeconds + 's 后继续开票...');
await sleep(waitSeconds * 1000);
const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId); const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId);
console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp)); console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp));
@@ -320,10 +308,6 @@ async function processInternationalFlightBill(bill, billIndex, totalBills) {
const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId); const initResp = await initReceiveOrderPrice(settlementSeq, receiveBillId);
console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp)); console.log(' -> initReceiveOrderPrice:', JSON.stringify(initResp));
const waitSeconds = randomDelaySeconds();
console.log(' [延时] 随机等待 ' + waitSeconds + 's 后继续开票...');
await sleep(waitSeconds * 1000);
const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId); const confirmResp = await confirmInvoiceOrder(settlementSeq, receiveBillId);
console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp)); console.log(' -> confirmInvoiceOrder:', JSON.stringify(confirmResp));
@@ -341,13 +325,15 @@ async function processInternationalFlightBill(bill, billIndex, totalBills) {
console.log(''); console.log('');
} }
// ========== 15. 随机延时 ========== // ========== 接口错误检查 ==========
function sleep(ms) { function ensureOk(resp, what) {
return new Promise(function (resolve) { setTimeout(resolve, ms); }); if (resp && resp.code && resp.code !== 'Z000') {
} if (resp.code === 'E003') {
console.error(' ✗ token 已失效(E003: ' + (resp.msg || '') + '),请更新 AUTH_TOKEN');
function randomDelaySeconds() { process.exit(1);
return Math.floor(15 + Math.random() * 31); }
throw new Error(what + ' 失败: [' + resp.code + '] ' + (resp.msg || resp.message || ''));
}
} }
// ========== 主流程 ========== // ========== 主流程 ==========
@@ -364,6 +350,7 @@ async function main() {
try { try {
const settlementResp = await querySettlementAccountIds(teamId); const settlementResp = await querySettlementAccountIds(teamId);
ensureOk(settlementResp, 'querySettlementAccountIds');
const resultList = settlementResp?.result || []; const resultList = settlementResp?.result || [];
if (resultList.length === 0) { if (resultList.length === 0) {
console.log(' ⚠ ' + teamId + ' 没有 settlement account,跳过\n'); console.log(' ⚠ ' + teamId + ' 没有 settlement account,跳过\n');
@@ -373,6 +360,7 @@ async function main() {
console.log(' -> settlementAccountId: ' + settlementAccountId); console.log(' -> settlementAccountId: ' + settlementAccountId);
const billResp = await queryBillList(settlementAccountId); const billResp = await queryBillList(settlementAccountId);
ensureOk(billResp, 'queryBillList');
const allBills = billResp?.result?.list || []; const allBills = billResp?.result?.list || [];
const total = billResp?.result?.total || 0; const total = billResp?.result?.total || 0;
console.log(' -> 共 ' + total + ' 条对账单'); console.log(' -> 共 ' + total + ' 条对账单');
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"server": { "server": {
"url": "ws://bh.vps.honor3.com:18888/websocket_path", "url": "ws://baishe.vps.honor3.com:18888/websocket_path",
"password": "helloworld" "password": "helloworld"
}, },
"client_name": "cheney" "client_name": "cheney"
+1 -1
View File
@@ -12,7 +12,7 @@
"name": "superstar", "name": "superstar",
"remote_port": 4443, "remote_port": 4443,
"local_port": 443, "local_port": 443,
"local_ip": "198.19.0.115", "local_ip": "198.19.0.22",
"speed_limit": 0.0, "speed_limit": 0.0,
"protocol": "tcp" "protocol": "tcp"
} }
Binary file not shown.