如何从对象数组设置发票行项目数据并避免重复加载发票
解决重复加载发票并批量处理行数据的问题
问题背景
使用定时脚本处理多张发票行级数据时,由于JEIDArray中存在重复的发票ID(invId),导致同一张发票被重复加载、处理和保存,既浪费资源又降低效率。需要优化逻辑,实现同一发票仅加载一次,同时正确为对应行设置数据。
原始数据与代码
原始数据数组
var JEIDArray = [ { item: "663", amount: "3000.00", JE: 13026407, invId: "13020561" }, { item: "663", amount: "100.00", JE: 13026408, invId: "13020561" }, { item: "663", amount: "111.00", JE: 13026409, invId: "13026406" }, { item: "663", amount: "222.00", JE: 13026410, invId: "13026406" }, { item: "373", amount: "444.00", JE: 13026411, invId: "13026406" } ];
原始处理函数
function updateInvoice(JEIDArray) { try { for (var r=0;r<JEIDArray.length;r++) { var getRecId=JEIDArray[r].invId; log.debug("getRecId",getRecId); var invoice = record.load({ type: record.Type.INVOICE, id: getRecId, isDynamic: false }) // 获取发票行数 var lineCount = invoice.getLineCount({ sublistId: 'item' }); log.debug("lineCount", lineCount); // 遍历发票行 for (var i = 0; i < lineCount; i++) { var currentItemId = invoice.getSublistValue({ sublistId: 'item', fieldId: 'item', line: i }); var currentItemAmount = invoice.getSublistValue({ sublistId: 'item', fieldId: 'custcol_ay_cts_allocation_amount', line: i }); // 遍历JEIDArray找匹配项 var flag = false; for (var j = 0; j < JEIDArray.length; j++) { var jeItem = JEIDArray[j]; if (currentItemId == jeItem.item && currentItemAmount == jeItem.amount) { flag = true; invoice.setSublistValue({ sublistId: 'item', fieldId: 'custcol_ay_cts_assoc_ic', // 自定义字段 line: i, value: jeItem.JE }); break; } } } // 保存发票 var invoiceId=invoice.save(); log.debug('Invoice Updated', `Invoice ID: ${invoiceId}`); } } catch(e) { log.error('Error updating invoice', e); } }
优化方案
核心思路是先按发票ID分组数据,将同一发票的所有行级数据聚合到一起,之后每个发票仅加载一次,一次性处理完所有对应行再保存。
优化步骤
- 分组数据:将
JEIDArray转换为以invId为键的对象,每个键对应该发票的所有行数据数组。 - 单发票单加载:遍历分组后的每个发票ID,仅加载一次发票记录。
- 精准匹配行数据:处理发票行时,直接从当前发票的分组数据中查找匹配的
item和amount,避免全局遍历整个数组。 - 单发票单保存:处理完当前发票的所有目标行后,仅保存一次。
优化后的代码
function updateInvoice(JEIDArray) { try { // 按invId分组数据,减少重复遍历 const groupedByInvId = {}; JEIDArray.forEach(item => { const invId = item.invId; if (!groupedByInvId[invId]) { groupedByInvId[invId] = []; } groupedByInvId[invId].push(item); }); // 遍历每个分组的发票,仅加载一次 Object.keys(groupedByInvId).forEach(invId => { log.debug("Processing Invoice", invId); // 加载发票(单发票仅一次) const invoice = record.load({ type: record.Type.INVOICE, id: invId, isDynamic: false }); const lineCount = invoice.getLineCount({ sublistId: 'item' }); log.debug("Invoice Line Count", lineCount); // 获取当前发票对应的所有行数据 const invoiceItems = groupedByInvId[invId]; // 处理发票行,匹配分组后的数据 for (let i = 0; i < lineCount; i++) { const currentItemId = invoice.getSublistValue({ sublistId: 'item', fieldId: 'item', line: i }); const currentItemAmount = invoice.getSublistValue({ sublistId: 'item', fieldId: 'custcol_ay_cts_allocation_amount', line: i }); // 从当前发票的分组数据中找匹配项,无需遍历整个JEIDArray const matchedItem = invoiceItems.find(jeItem => jeItem.item === currentItemId && jeItem.amount === currentItemAmount ); if (matchedItem) { invoice.setSublistValue({ sublistId: 'item', fieldId: 'custcol_ay_cts_assoc_ic', line: i, value: matchedItem.JE }); log.debug(`Set JE ${matchedItem.JE} for line ${i} of invoice ${invId}`); } } // 单发票仅保存一次 const savedInvoiceId = invoice.save(); log.debug('Invoice Updated', `Invoice ID: ${savedInvoiceId}`); }); } catch(e) { log.error('Error updating invoices', e); } }
优化效果
- 避免重复加载同一发票,减少API调用次数(原逻辑中invId为13020561的发票会被加载2次,优化后仅1次)。
- 减少嵌套遍历次数,提升处理效率(原逻辑复杂度为O(n*m),优化后为O(n + m),n为总数据行数,m为发票总行数)。
- 每个发票仅保存一次,降低数据冲突风险。
内容的提问来源于stack exchange,提问作者Maira S
相关产品推荐
相关产品推荐

