如何在NetSuite中通过SuiteScript将礼品券应用至销售订单?
NetSuite SuiteScript 销售订单礼品券应用实现方案
核心前提说明
NetSuite内礼品券分两类,实现逻辑有明确区别:
- 储值类礼品券(Gift Certificate):有唯一编码、独立余额、有效期,属于用户储值资产,抵扣后需要扣减对应余额
- 折扣类礼品券(Coupon/Promotion):属于营销折扣,无储值余额,仅用于订单金额减免,不需要做资产类余额扣减
以下方案同时覆盖两类场景,脚本基于SuiteScript 2.x版本编写,适配目前所有在用的NetSuite版本。
通用实现流程
- 有效性校验:拿到礼品券编码后,先查询对应记录的状态、剩余可用额度、有效期、绑定客户范围,直接拦截无效、过期、余额为0的券
- 抵扣额计算:取「礼品券可用余额/折扣额」和「订单剩余应付金额」的较小值作为实际抵扣额,禁止出现超额抵扣
- 订单写入:根据礼品券类型选择写入位置:折扣类券直接调用系统促销接口绑定,储值类券可选择写入物料行(负向金额)或支付行
- 后续联动:订单审核通过后扣减储值券余额、记录抵扣流水;订单作废、退款时按规则回退已抵扣的券余额
可落地脚本实现
方案1:用户事件脚本(服务端)
适用场景:接口传入礼品券、后台自动建单时自动应用礼品券,所有逻辑在服务端执行,安全性最高
/** * @NApiVersion 2.1 * @NScriptType UserEventScript */ define(['N/record', 'N/search', 'N/error'], (record, search, error) => { const GIFT_CERT_ITEM_ID = 123; // 替换为账户内系统预置的礼品券对应非库存物料内部ID const beforeSubmit = (context) => { const { newRecord: salesOrder, type } = context; // 仅处理创建、编辑状态的销售订单 if (![context.UserEventType.CREATE, context.UserEventType.EDIT].includes(type)) return; // 从订单自定义字段获取传入的礼品券编码,可根据实际业务调整取值来源 const inputCertCode = salesOrder.getValue({ fieldId: 'custbody_input_gift_code' }); if (!inputCertCode) return; // 查询匹配的有效礼品券 const certResult = search.create({ type: search.Type.GIFT_CERTIFICATE, filters: [ ['code', 'is', inputCertCode.trim()], ['remaining', 'greaterthan', 0], ['inactive', 'is', false], ['expirationdate', 'onorafter', new Date()] ], columns: ['internalid', 'remaining', 'customer'] }).run().getRange({ start: 0, end: 1 }); if (!certResult.length) { throw error.create({ name: 'INVALID_GIFT_CERT', message: '输入的礼品券无效、已过期或余额为0' }); } const validCert = certResult[0]; const certBalance = parseFloat(validCert.getValue('remaining')); const orderRemain = parseFloat(salesOrder.getValue('remaining')); const applyAmount = Math.min(certBalance, orderRemain); // 写入礼品券抵扣行(负向金额) const lineCount = salesOrder.getLineCount({ sublistId: 'item' }); salesOrder.insertLine({ sublistId: 'item', line: lineCount }); salesOrder.setSublistValue({ sublistId: 'item', line: lineCount, fieldId: 'item', value: GIFT_CERT_ITEM_ID }); salesOrder.setSublistValue({ sublistId: 'item', line: lineCount, fieldId: 'rate', value: -applyAmount }); salesOrder.setSublistValue({ sublistId: 'item', line: lineCount, fieldId: 'custcol_related_gift_cert', value: validCert.id }); salesOrder.setSublistValue({ sublistId: 'item', line: lineCount, fieldId: 'description', value: `礼品券抵扣:${inputCertCode}` }); }; const afterSubmit = (context) => { const { newRecord: salesOrder, type } = context; if (![context.UserEventType.CREATE, context.UserEventType.EDIT].includes(type)) return; // 此处补充余额扣减逻辑:遍历订单礼品券行,扣减对应礼品券记录的剩余余额,同时记录抵扣关联的订单ID、抵扣金额 // 订单作废、退款触发的余额回退逻辑,建议单独写在对应状态变更的用户事件脚本中 }; return { beforeSubmit, afterSubmit }; });
如果要对接NetSuite原生礼品券支付能力,不需要手动写物料行,直接将礼品券ID写入
payment子列表的对应支付方式字段即可,系统会自动完成余额扣减、抵扣计算逻辑,不需要手动处理金额。
方案2:客户端脚本
适用场景:销售订单界面人工录入礼品券时,实时做有效性校验、即时展示抵扣金额
核心实现要点:
- 绑定礼品券编码输入字段的
fieldChanged事件,用户输入完成后调用搜索接口校验券有效性 - 校验通过后弹窗提示用户当前券可抵扣金额,用户确认后再写入订单行
- 所有余额扣减、数据变更逻辑必须放在服务端脚本执行,禁止在客户端直接修改礼品券余额,避免前端篡改数据
上线注意事项
- 权限配置:脚本部署的执行角色必须拥有礼品券记录的查看/编辑权限、销售订单编辑权限,否则会触发权限报错
- 并发控制:高并发场景下给礼品券记录加动态锁,避免同一张券被多个订单同时调用导致超额抵扣
- 税务适配:礼品券抵扣部分的税务计算要符合业务所在地的财税规则,可根据需求在脚本中配置对应税码、计税逻辑
- 对账适配:单独建礼品券抵扣流水自定义记录,存储每笔抵扣关联的订单、券、金额、时间,方便后续财务对账
内容的提问来源于stack exchange,提问作者Yasir Minhaj
相关产品推荐
相关产品推荐

