首页 > 解决方案 > 在 NetSuite 中打印 PDF 并选择多条交易记录

问题描述

有没有办法将许多交易选择打印到一个 PDF 文档中?我只看到两个似乎有明显缺点的选项:

1) 将单个记录加载到它们自己的每个 nlobjTemplateRenderer 对象中,然后在呈现为 PDF 之前将它们全部在标签内拼接在一起。具有少于 50 个事务的限制,具体取决于在 Suitelet 中使用时采取的其他操作。

2) 根据所选记录的内部 ID 进行搜索,并将搜索结果传递给 nlobjTemplateRenderer 对象。这种基于现有文档的方法不会让我相信它会在单个文档中完全正确地显示带有行数据的记录作为结果列。

似乎我最好的选择是#1,但是将所需的事务分成 5-10 条记录的组,并与小组反复调用 Suitelet,希望在拼接之前满足 nlapiRequestURL 的 45 秒超时限制所有结果并返回最终的 PDF 文档。我几乎看到它的基本形式如下:

// initial called function that will return completed PDF document file
function buildPdfFromRecords() {
    var pdfBuilder = [];
    var selectedIDs = [];
    var chunks = chunkify(selectedIDs, 10);
    for (var c = 0; c < chunks.length; c++) {
        var param = { id_list : JSON.stringify(chunks[s]) };
        var result = nlapiRequestURL(url, param).getBody();
        pdfBuilder.push(result);
    }
    var finalXML = "<pdfset>" + pdfBuilder.join("") + "</pdfset>";
    var pdfDoc = nlapiXMLToPDF(finalXML);
}

// function in suitelet called by url to handle individual groups of record internal IDs
// to mitigate scripting governance limits
function handleRecordIdListRequest(request, reponse) {
    var idList = JSON.parse(request.getParameter("id_list"));
    var templateXML = nlapiLoadRecord("template.txt").getValue();
    var pdfBuilder = [];
    for (var i = 0; i < idList.length; i++) {
        var transRecord = nlapiLoadRecord("recordtype", idList[i]);
        var renderer = nlapiCreateTemplateRenderer();
        renderer.setTemplate(templateXML);
        renderer.addRecord("record", transRecord);
        pdfBuilder.push(renderer.renderToString());
    }
    response.write(pdfBuilder.join(""));
}

如果这真的是最好的方法,那就这样吧,但我希望有一个更优雅的解决方案,我只是没有看到。

标签: javascriptnetsuitesuitescriptbfo

解决方案


您可以将许多部分缝合在一起以完成此操作。

  1. 在 Suitelet 的后处理程序中,使用 N/task 库来安排 map/reduce 任务。task.submit 方法返回一个 taskId,您可以使用它来监控您的工作进度。一旦你的 UI 有了 taskId,它就可以定期检查任务是否已完成。完成后,您可以显示生成的 .pdf。您还可以让用户知道 pdf 可能需要几分钟才能生成,并在完成后通过电子邮件将其发送给他们。这是一个使用参数安排计划脚本的片段:

  const mrTask = task.create({
    taskType:task.TaskType.SCHEDULED_SCRIPT,
    scriptId:'customscript_knsi_batch_products',
    deploymentId: deploymentId,
    params: {
      custscript_knsi_batch_operator:user.id,
      custscript_knsi_batch_sourcing: sourcingId
    }
  });

  try{
    const taskId = mrTask.submit();
    context.response.setHeader({name:'content-type', value:'application/json'});
    context.response.write(JSON.stringify({
      success:true,
      message:'queued as task: '+ taskId
    }));
  }catch(e){
    log.error({
      title:'triggering '+ sourcingId +' for '+ user.email,
      details:(e.message || e.toString()) + (e.getStackTrace ? (' \n \n' + e.getStackTrace().join(' \n')) : '')
    });
    context.response.setHeader({name:'content-type', value:'application/json'});
    context.response.write(JSON.stringify({
      success:false,
      message:'An error occured scheduling this script\n'+e.message
    }));

  1. 使用 Map/Reduce 脚本,您的 map 方法在其中生成并返回每个事务的 pdf 文件 url。您将只有一个键,以便所有 map 阶段的结果合并为一个 reduce。
  2. 在减少步骤中,您可以根据需要生成打开和关闭的 pdf 文件,并将它们的引用放入您的 pdf 映射数组中。
  3. 使用 pdfset 将所有单独的 pdf 绑定到一个 pdf 中:

function renderSet(opts){
	var tpl = ['<?xml version="1.0"?>','<pdfset>'];

	opts.files.forEach(function(id, idx){
		const partFile = file.load({id:id});
		var pdf_fileURL = xml.escape({xmlText:partFile.url});
		tpl.push("<pdf src='" + pdf_fileURL + "'/>");
	});

	tpl.push("</pdfset>");

	log.debug({title:'bound template', details:xml.escape({xmlText:tpl.join('\n')})});

	return render.xmlToPdf({
		xmlString:  tpl.join('\n')
	});
}


推荐阅读