SuiteScritp 2.0开发实例 自定义工单+领料单 单据流转 打印
1. 业务流程
2. 系统实现
2.1 自定义工单
借助SuiteBuilder
2.2 自定义领料单
借助SuiteBuilder
2.3 自定义审批工作流
借助SuiteWorkflow
2.4 SuiteScript开发
2.4.1 工单状态变更提醒(需求)
- 功能设计:如果新增已批准工单,邮件、NS站内信通知领料员
- 技术设计:创建已保存搜索,并基于它设置邮件、NS remind提醒相应领料员
2.4.2 从工单创建领料单(需求)
- 功能设计:
a) if 工单状态 = approved , 工单界面添加【生成领料单】按钮
b) 点击此按钮,弹出领料单新增页面
c) 领料单字段(来源工单、领料员、领料车间、仓库等)初始化赋值取自工单 - 技术设计:
a) UserEventScript beforeLoad入口点函数完成页面按钮加载(参见附:WorkOrderToMaterialApplyBs.js)
b) 按钮函数,url 模块API resolveRecord 解析记录类型,生成新url并跳转(参见附:CreateMAOBs.js)
c) UserEventScript beforeLoad完成页面初始化,调用record模块 API 获取工单数据
WorkOrderToMaterialApplyBs.js
2.4.3 工单可以查询到关联领料单号(需求)
- 功能设计:
a) 工单添加一个子标签,下面可以查出领料单列表(头信息)
b) 通过工单行,可以查看该行对应哪些领料单(行信息) - 技术设计:
领料单创建时,需要记录来源单据(工单)的头行信息
工单页面通过UserEventScript beforeLoad加载领料单信息。
2.4.4 领料单批准后通知打印统计员(需求)
- 功能设计:如果新增已批准领料单,邮件、NS站内信通知领料员
- 技术设计:创建已保存搜索,并基于它设置邮件、NS remind提醒相应领料员
2.4.5 已批准的领料单打印PDF
-
功能设计:
a) if 领料单审批状态 = approved, 添加 【打印领料单】 按钮
b) 点击【打印领料单】按钮,出来PDF预览页面 -
技术设计:
a) UserEventScript API beforeLoad 完成页面按钮加载(参见MAOCreateFromWO.js)
// 伪代码
if (type == VIEW && status == 'APPROVED'){
addButton('打印领料单',' print_function')
}
b) 打印按钮方法调用url模块resolveScript(用此API解析Suitelet)生成,并添加参数领料单id。Suitelet将领料单数据转换成xml,再调用render模块API(xmlToPdf)转换成PDF输出。(参见BSPrintMAO.js 和 BsPrintMAOSuitelet.js)
var u = url.resolveScript({
scriptId : 'customscript_yq_bs_printmao_suitelet',
deploymentId : 'customdeploy_yq_bs_printmao_suitelet',
returnExternalUrl : false
});
附
WorkOrderToMaterialApplyBs.js
/**
* @NApiVersion 2.x
* @NScriptType UserEventScript
* @NModuleScope SameAccount
* @author YQ12681
*/
Function Description//
// #1 工单页面加载前
// #1.1 如果是新建模式(type=CREATE), 什么也不做
// #1.2 如果是查看模式(type=VIEW),判断工单状态status
// if status = 'APPROVED', 页面添加'生成领料单'按钮
//
define([], function() {
function beforeLoad(context) {
// context. newRecord,type,form,request
if (context.type === context.UserEventType.CREATE)
;
/*context.newRecord.setValue({
fieldId : 'custrecord_yq_workorder_status_bs',
value : 1
});
* CREATE type下不能用getText,需要先setValue或setText
* 否则会报错: SuiteScript 2.0 Error > SSS_INVALID_API_USAGE error
*
* Cause: In Standard Mode, SSS_INVALID_API_USAGE error appears when a
* user event scripts instantiates records by using the newRecord object
* provided by the script context in the following scenaros: -- When the
* script executes on a record that is being created, and the script
* attempts to use Record.getText(options) without first using
* Record.setText(options) for the same field. -- When the script
* executes on an existing record or on a record being created through
* copying, and the script uses Record.setValue(options) on a field
* before using Record.getText(options) for the same field
*/
else if (context.type === context.UserEventType.VIEW) {
var status = context.newRecord.getText({
fieldId : 'custrecord_yq_workorder_status_bs'
});
// 如果工单状态已审批加载<生成领料单>按钮
try {
if (status === 'APPROVED') {
context.form.clientScriptModulePath = './CreateMAOBs.js';
context.form.addButton({
id : 'custpage_generate_mao',
label : '生成领料单',
functionName : 'create_mao_url'
});
}
log.debug({
title : 'Success',
details : '添加-生成领料单-按钮成功! status = ' + status
});
} catch (ex) {
log.debug({
title : ex.name,
details : ex.message
});
}
}
}
return {
beforeLoad : beforeLoad
};
});
CreateMAOBs.js
/**
* @NApiVersion 2.x
* @author YQ12681
*/
Description//
//
// 定义【生成领料单】按钮的方法
// 此方法生成并打开一个新URL
//
define([ 'N/url', 'N/currentRecord' ], function(url, currentRecord) {
return ({
create_mao_url : function() {
try {
var u = url.resolveRecord({
recordType : 'customrecord_yq_material_apply_bansi',
recordId : '',
isEditMode : true
});
log.debug({
title : 'Success',
details : 'url解析成功'
});
} catch (e1) {
log.debug({
title : e1.name,
details : e1.message
});
}
try {
var record = currentRecord.get();
var woid = record.id;
/*var status = record.getValue({
fieldId : 'custrecord_yq_workorder_status_bs'
});*/
log.debug({
title : 'Success',
details : '获取记录id =' + woid //+ ' status = ' + status
});
} catch (e2) {
log.debug({
title : e2.name,
details : e2.message
});
}
try {
//if (status == 'APPROVED')
window.location.href = u + '&woid=' + woid;
log.debug({
title : 'Success',
details : 'url创建成功'
});
} catch (e3) {
log.debug({
title : e3.name,
details : e3.message
});
}
}
});
});
MAOCreateFromWO.js
/**
* @NApiVersion 2.x
* @NScriptType UserEventScript
* @author YQ12681 Bansi
* MAOCreateFromWO.js
*/
Function Description//
// #1 领料单页面加载前
// #1.1 如果是新建模式(type=CREATE),判断是否从工单自动创建
// if true, 用工单数据初始化赋值领料单
// if false, 手工填写赋值
// #1.2 如果是查看模式(type=VIEW),判断工单状态status
// if status = 'APPROVED', 页面添加'打印领料单'按钮
//
define(
[ 'N/record' ],
function(record) {
function beforeLoad(context) {
var maoRecord = context.newRecord;
var type = context.type;
var form = context.form;
if (type == context.UserEventType.CREATE) {
try {
var woid = context.request.parameters.woid;
if (woid) {
var rec = record.load({
type : 'customrecord_yq_workorder_bs',
id : woid
});
//初始化赋值master
var warehouse = rec.getValue({
fieldId : 'custrecord_yq_workorder_shop_bs'
});
var clerk = rec.getValue({
fieldId : 'custrecord_yq_workorder_lly_bs'
});
var workshop = rec.getValue({
fieldId : 'custrecord_yq_workorder_dept_bs'
});
maoRecord.setValue(
'custrecord_yq_mao_header_sourcewo_bs',
woid);
maoRecord.setValue(
'custrecord_yq_mao_source_workshop_bs',
workshop);
maoRecord.setValue(
'custrecord_yq_material_apply_requestor',
clerk);
maoRecord.setValue('custrecord_yq_warehouse_bansi',
warehouse);
maoRecord.setValue(
'custrecord_yq_material_apply_note_bansi',
'创建自工单:' + rec.getText({
fieldId : 'name'
}));
//初始化赋值明细行
//sublistid为recmach+子记录中作为外键到父记录的字段ID
var sublistIdToSet = 'recmachcustrecord_yq_material_apply_detail_h_bs';
var sublistIdToGet = 'recmachcustrecord_yq_workorder_detail_headid_bs';
var count = rec.getLineCount(sublistIdToGet);
for (var i = 0; i < count; i++) {
maoRecord
.setSublistValue(
sublistIdToSet,
'custrecord1',
i,
rec
.getSublistValue(
sublistIdToGet,
'custrecord_yq_workorder_detail_item_bs',
i));
maoRecord
.setSublistValue(
sublistIdToSet,
'custrecord_yq_material_apply_line_qyt_bs',
i,
rec
.getSublistValue(
sublistIdToGet,
'custrecord_yq_workorder_detail_qty_bs',
i));
}
}
log.debug({
title : 'Success',
details : '赋值成功:woid = ' + woid + ', warehouse = '
+ warehouse + ', clerk = ' + clerk
+ ', workshop = ' + workshop
+ ', sublist = ' + rec.getSublist()
});
} catch (e1) {
log.debug({
title : e1.name,
details : e1.message
});
}
} else if (type == context.UserEventType.VIEW) {
var status = context.newRecord.getText({
fieldId : 'custrecord_yq_ma_status_bansi'
});
try {
if (status == 'APPROVED') {
form.clientScriptModulePath = './BsPrintMAO.js';
form.addButton({
id : 'custpage_print_mao',
label : '打印领料单',
functionName : 'bs_print_mao'
});
log.debug({
title : 'Success',
details : '添加-打印领料单-按钮成功!'
});
}
} catch (ex) {
log.debug({
title : ex.name,
details : ex.message
});
}
}
}
function beforeSubmit(context) {
if (context.type != context.UserEventType.CREATE)
return;
}
return ({
beforeLoad : beforeLoad,
beforeSubmit : beforeSubmit
});
});
BSPrintMAO.js
/**
* @NApiVersion 2.x
* @author YQ12681
* BSPrintMAO.js
*/
Description///
//
// 定义【打印领料单】的方法
// 此方法解析脚本记录id和部署id, 生成一个对suitelet的调用URL
//
/
define([ 'N/url', 'N/currentRecord' ], function(url, currentRecord) {
return ({
bs_print_mao : function() {
try {
var record = currentRecord.get();
var maoId = record.id;
var u = url.resolveScript({
//BsPrintMAO.js
scriptId : 'customscript_yq_bs_printmao_suitelet',
deploymentId : 'customdeploy_yq_bs_printmao_suitelet',
returnExternalUrl : false
// if true 报错:不允许您直接到此页面 https://forms.eu1.netsuite.com/app/site/hosting/scriptlet.nl
//?script=18&deploy=1&compid=5144758_SB1&h=2882965d29273aadff92&maoid=1
// if false 可行
});
u += '&maoid=' + maoId;
log.debug({
title : 'Success',
details : 'url解析成功'
});
} catch (e1) {
log.debug({
title : e1.name,
details : e1.message
});
}
window.open(u);
}
});
});
BsPrintMAOSuitelet.js
/**
* @NApiVersion 2.x
* @NScriptType Suitelet
* @author YQ12681
* BsPrintMAOSuitelet.js
*/
Description
//
//此Suitelet接收请求参数领料单Id(maoId)
//并输出PDF预览响应
//
//
define(
[ 'N/record', 'N/render' ],
function(record, render) {
function onRequest(params) {
//解析url参数 maoid
var maoId = params.request.parameters.maoid;
//加载领料申请记录
var rec = record.load({
type : 'customrecord_yq_material_apply_bansi',
id : maoId
});
var maoNumber = rec.getText('name');
//xml定义打印模板
var xmlStr = '';
xmlStr += '<?xml version="1.0"?><!DOCTYPE pdf PUBLIC "-//big.faceless.org//report" "report-1.1.dtd"><pdf><head>';
xmlStr += '</head>';
xmlStr += '<body padding="0.5in 0.5in 0.5in 0.5in" size="Letter">';
xmlStr += '<table style="width: 100%; font-size: 10pt;"><tr>';
xmlStr += '<td>' + maoNumber + '</td></tr>';
xmlStr += '</table></body>';
xmlStr += '</pdf>'
//xml转成pdf文件
var pdfFile = render.xmlToPdf({
xmlString : xmlStr
});
//输出文件
params.response.writeFile({
file : pdfFile,
isInline : true
});
}
return {
onRequest : onRequest
};
});