Печать PDF в NetSuite с выбором нескольких записей транзакций

Можно ли напечатать несколько транзакций в одном документе PDF? Я вижу только два варианта, которые, кажется, имеют существенные недостатки:

1) Загрузите отдельные записи в каждый из своих собственных объектов nlobjTemplateRenderer, а затем соедините их все вместе в тегах перед рендерингом в PDF. Имеет лимит менее 50 транзакций в зависимости от других действий, выполняемых при использовании в Suitelet.

2) Выполните поиск по внутренним идентификаторам выбранных записей и передайте результаты поиска в объект nlobjTemplateRenderer. Этот метод, основанный на существующей документации, не дает оснований полагать, что он будет правильно отображать записи со строковыми данными в виде столбцов результатов полностью внутри одного документа.

Похоже, мой лучший вариант - № 1, но разделить нужную транзакцию на группы по 5-10 записей и неоднократно вызывать Suitelet с небольшими группами в надежде достичь 45-секундного лимита времени ожидания nlapiRequestURL, прежде чем соединять их вместе. все результаты и возврат окончательного 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(""));
}

Если это действительно лучший способ, пусть будет так, но я надеюсь, что есть более элегантное решение, которого я просто не вижу.

2 ответа

Решение

Есть несколько частей, которые вы можете соединить вместе, чтобы сделать это.

  1. В пост-обработчике вашего Suitelet используйте библиотеку N/task, чтобы запланировать задачу map/Reduce. Метод task.submit возвращает идентификатор задачи, который вы можете использовать для отслеживания хода выполнения вашей работы. Как только ваш пользовательский интерфейс имеет идентификатор задачи, он может периодически проверять, завершена ли задача. После завершения вы можете показать сгенерированный.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 генерирует и возвращает URL-адрес каждой PDF-файла транзакции. У вас будет только один ключ, чтобы результаты всех этапов карты объединились в одно сокращение.
  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')
 });
}

Почему бы не использовать скрипт Map Reduce для создания PDF? Это должен быть Suitelet?

Другие вопросы по тегам