函数练习

250 阅读7分钟

一.将客户id写入单文本字段

image.png

/**
 * @author 杨宇翔Barry
 * @codeName test
 * @description 客户新建后,将id写入新建的单文本字段
 * @createTime 2023-05-23
 */
void test() {
    String objectAPIName = 'AccountObj'
    String dataId = context.data._id 
    Map updateData = [
      "field_2AUuo__c": context.data.account_no
    ]
    Boolean triggerWorkFlow = true //触发工作流
    def (Boolean error, Map data, String errorMessage) =  Fx.object.update(objectAPIName, dataId, updateData, triggerWorkFlow)
    if (error) {
      log.info("error:" + errorMessage )
    }
    log.info(data)
}

dataId相当于主键

二.将客户负责人的主属部门名称写入单文本字段

image.png

/**
 * @author 杨宇翔Barry
 * @codeName 将客户负责人的主属部门名称写入单文本字段
 * @description 将客户负责人的主属部门名称写入单文本字段
 * @createTime 2023-05-24
 */

UIEvent test() {
    // 校验客户负责人的主属部门是否已经手动填写,如果是,则不需要走if外的流程去获取
    if (null != context.data.field_2zRZ6__c) {
      UIEvent event = UIEvent.build(context) { }
      return event
    }
    
    // 获取负责人数据
    List owners = context.data.owner as List
    String owner_str = owners[0] as String
    def(Boolean error, Map data, String errorMessage) = Fx.org.findUserById(owner_str)

    // 获取负责人主属部门数据
    List depart_id = data.main_department as List
    def (Boolean error1,List data1,String errorMessage1) = Fx.org.findDepartmentByIds(depart_id)
    Map data2 = data1[0] as Map
    String depart_name = data2.name
    log.info(depart_name)

    UIEvent event = UIEvent.build(context) { 
     //主对象修改数据
      editMaster("field_2zRZ6__c": depart_name) 
    }
    return event
}

Groovy必须利用as显式声明类型

三.有客户名称时,设置函数让文本字段为必填,UI更新数据

image.png

UIEvent test() {
    /**
 * @author 杨宇翔Barry
 * @codeName ttt
 * @description dddddd
 * @createTime 2023-05-24
 */

  String accountName = context.data.name
  if( null != accountName ){
      //新建UIEvent事件
      UIEvent event = UIEvent.build(context) {
        //把字段设置为只读、隐藏、必填
        editMasterFields "field_YhHiG__c" required(true)
      }
       return event
  }
}

四.通过查询商机对象获取商机名称

image.png

/**
 * @author 杨宇翔Barry
 * @codeName 通过查询商机对象获取商机名称
 * @description 通过查询商机对象获取商机名称
 * @createTime 2023-05-24
 */
String sql = "select name from NewOpportunityObj;"
def rst = Fx.object.select(sql)
QueryResult queryResult = rst[1] as QueryResult
List dataList = queryResult.dataList as List
dataList.each { item -> 
  Map itemMap = item as Map
  log.info(itemMap.name)
} 

五.新建销售订单手动关联库存单,将库存单明细带入销售订单明细中,产品单价与数量设置只读

image.png

/**
 * @author 杨宇翔Barry
 * @codeName yyx_新建销售订单手动关联库存单2
 * @description yyx_新建销售订单手动关联库存单2
 * @createTime 2023-05-30
 */

  // 库存单id
  String stockList = context.data.field_lSHf9__c as String
  // 查出库存单明细的id、关联的产品
  String sql = "select _id, field_SjE13__c from object_pM0SB__c where field_j4Zjt__c = '$stockList' limit 100 offset 0";
  SelectAttribute att = SelectAttribute.builder()
    .needCount(true)
    .needInvalid(true)
    .fillExtendInfo(true) // 可以顺便把查找关联对象的name字段取出来(减少一次查询操作)
    .build();
  def(Boolean error, Object result, String message) = Fx.object.select(sql, att);
  if (error) {
    log.info("error:" + error)
  }
  QueryResult queryResult = result as QueryResult
  List dataList = queryResult.dataList as List
  
  // //新建UIEvent事件
  UIEvent event = UIEvent.build(context) {
    dataList.each { item -> 
      Map itemMap = item as Map
      String productId = itemMap.field_SjE13__c // 库存单明细关联的产品id
      String productName = itemMap.field_SjE13__c__r // 产品名字
      String stockDetailId = itemMap._id // 库存单明细id
      
      // 查产品单价
      String sql2 = "select price from ProductObj where _id = '$productId'";
      def result2 = Fx.object.select(sql2)
      QueryResult queryResult2 = result2[1] as QueryResult
      List dataList2 = queryResult2.dataList as List
      Map map = dataList2[0] as Map
      def price = map.price
      
      // 查产品数量
      String sql3 = "select field_Bpz84__c from object_pM0SB__c where _id = '$stockDetailId'";
      def result3 = Fx.object.select(sql3)
      QueryResult queryResult3 = result3[1] as QueryResult
      List dataList3 = queryResult3.dataList as List
      Map map2 = dataList3[0] as Map
      def num = map2.field_Bpz84__c
     
      // UI操作
      addDetail "object_OjYMi__c" set("record_type": "default__c", "field_1wsig__c": productId, "field_rn49z__c": productName, "field_Xykq1__c": price, "field_wAJcR__c": num, "field_A7gJR__c": stockDetailId)
      editDetailFields "object_OjYMi__c" fieldApiName("field_Xykq1__c") readOnly(true)
      editDetailFields "object_OjYMi__c" fieldApiName("field_wAJcR__c") readOnly(true)
    } 
  }

  return event

效果:

image.png

六. 新建销售订单时,有多条订单明细,点击提交按钮后,校验各条明细中订单产品的数量,当有数量大于或等于10个时,页面出现弹窗,弹窗中显示数量大于或等于10个的产品名称

image.png

函数挂载:

image.png

image.png

/**
 * @author 杨宇翔Barry
 * @codeName yyx_提交按钮前校验触发弹窗
 * @description 提交按钮前校验触发弹窗
 * @createTime 2023-05-31
 */
 
  boolean flag = false // 是否弹窗
  String content = "数量大于或等于10的产品名称: " // 弹窗内容

  Map detailMap = context.details as Map // 所有从对象(毕竟一个主对象可以有多个重对象)
  List salesOrderProductObjList = detailMap.SalesOrderProductObj as List // 订单产品
  salesOrderProductObjList.each { item ->
      Map map = item as Map
      double quantity = map.quantity as double 
      String product_id = map.product_id as String
    
      // 查询产品名称
      String sql = "select name from ProductObj where _id = '${product_id}'"
      def(Boolean error, Object result, String message) = Fx.object.select(sql);
      QueryResult queryResult = result as QueryResult
      List dataList = queryResult.dataList as List
      
      // 校验
      if(quantity >= 10) {
        // 拼接产品名称
        String name = ""
        dataList.each { item1 ->
          Map itemMap = item1 as Map
          name = itemMap.name
          content += name
          content += " "
        }
        
        flag = true
      }
  }

  if( flag ){
     return ["error": true, "errorMessage": content, "block":true]
  }
  return ["block": false]

效果:

image.png

七. 在函数五的基础上,重新选择关联出库单时会清除之前的明细,并保留手动添加的明细

/**
 * @author 杨宇翔Barry
 * @codeName yyx_新建销售订单手动关联库存单2
 * @description yyx_新建销售订单手动关联库存单2
 * @createTime 2023-05-30
 */

  // 库存单id
  String stockList = context.data.field_lSHf9__c as String
  // 查出库存单明细的id、关联的产品
  String sql = "select _id, field_SjE13__c from object_pM0SB__c where field_j4Zjt__c = '$stockList' limit 100 offset 0";
  SelectAttribute att = SelectAttribute.builder()
    .needCount(true)
    .needInvalid(true)
    .fillExtendInfo(true) // 可以顺便把查找关联对象的name字段取出来(减少一次查询操作)
    .build();
  def(Boolean error, Object result, String message) = Fx.object.select(sql, att);
  if (error) {
    log.info("error:" + error)
  }
  QueryResult queryResult = result as QueryResult
  List dataList = queryResult.dataList as List
  
  // //新建UIEvent事件
  UIEvent event = UIEvent.build(context) {
      // 切换库存单时,清空上一条库存单带过来的明细(条件是: 关联库存单明细编号不为空才删,因为如果为空可能是用户手动填写的)
      // 根据条件删除 从对象, 删除为where中返回为true的从对象
      removeDetail "object_OjYMi__c" where { x -> x.field_A7gJR__c != null } 
      
      dataList.each { item -> 
      Map itemMap = item as Map
      String productId = itemMap.field_SjE13__c // 库存单明细关联的产品id
      String productName = itemMap.field_SjE13__c__r // 产品名字
      String stockDetailId = itemMap._id // 库存单明细id
      
      // 查产品单价
      String sql2 = "select price from ProductObj where _id = '$productId'";
      def result2 = Fx.object.select(sql2)
      QueryResult queryResult2 = result2[1] as QueryResult
      List dataList2 = queryResult2.dataList as List
      Map map = dataList2[0] as Map
      def price = map.price
      
      // 查产品数量
      String sql3 = "select field_Bpz84__c from object_pM0SB__c where _id = '$stockDetailId'";
      def result3 = Fx.object.select(sql3)
      QueryResult queryResult3 = result3[1] as QueryResult
      List dataList3 = queryResult3.dataList as List
      Map map2 = dataList3[0] as Map
      def num = map2.field_Bpz84__c
     
      // UI操作
      addDetail "object_OjYMi__c" set("record_type": "default__c", "field_1wsig__c": productId, "field_rn49z__c": productName, "field_Xykq1__c": price, "field_wAJcR__c": num, "field_A7gJR__c": stockDetailId)
      editDetailFields "object_OjYMi__c" fieldApiName("field_Xykq1__c") readOnly(true)
      editDetailFields "object_OjYMi__c" fieldApiName("field_wAJcR__c") readOnly(true)
      editDetailFields "object_OjYMi__c" fieldApiName("field_A7gJR__c") readOnly(true)
      
    } 
  }

  return event
 
 

八. 在函数六的基础上,引用自产品的折扣字段,当修改产品单价或总金额时,总金额或产品也随之改动

/**
 * @author 杨宇翔Barry
 * @codeName yyx_新建销售订单手动关联库存单2
 * @description yyx_新建销售订单手动关联库存单2
 * @createTime 2023-05-30
 */

  // 库存单id
  String stockList = context.data.field_lSHf9__c as String
  // 查出库存单明细的id、关联的产品
  String sql = "select _id, field_SjE13__c from object_pM0SB__c where field_j4Zjt__c = '$stockList' limit 100 offset 0";
  SelectAttribute att = SelectAttribute.builder()
    .needCount(true)
    .needInvalid(true)
    .fillExtendInfo(true) // 可以顺便把查找关联对象的name字段取出来(减少一次查询操作)
    .build();
  def(Boolean error, Object result, String message) = Fx.object.select(sql, att);
  if (error) {
    log.info("error:" + error)
  }
  QueryResult queryResult = result as QueryResult
  List dataList = queryResult.dataList as List

  Double sumPrice = 0 // 总金额
  
  // //新建UIEvent事件
  UIEvent event = UIEvent.build(context) {
      // 切换库存单时,清空上一条库存单带过来的明细(条件是: 关联库存单明细编号不为空才删,因为如果为空可能是用户手动填写的)
      // 根据条件删除 从对象, 删除为where中返回为true的从对象
      removeDetail "object_OjYMi__c" where { x -> x.field_A7gJR__c != null } 
      
      dataList.each { item -> 
      Map itemMap = item as Map
      String productId = itemMap.field_SjE13__c // 库存单明细关联的产品id
      String productName = itemMap.field_SjE13__c__r // 产品名字
      String stockDetailId = itemMap._id // 库存单明细id
      
      // 查产品单价
      String sql2 = "select price from ProductObj where _id = '$productId'";
      def result2 = Fx.object.select(sql2)
      QueryResult queryResult2 = result2[1] as QueryResult
      List dataList2 = queryResult2.dataList as List
      Map map = dataList2[0] as Map
      Double price = map.price as Double
      
      // 查产品折扣
      String sql4 = "select field_5e6gj__c from ProductObj where _id = '$productId'"
      def result4 = Fx.object.select(sql4)
      QueryResult queryResult4 = result4[1] as QueryResult
      List dataList4 = queryResult4.dataList as List
      Map map3 = dataList4[0] as Map
      def onSaleInput = map3.field_5e6gj__c
      Double onSale = map3.field_5e6gj__c as Double
      if( onSale == null ){
        onSale = 1
      } else {
        onSale /= 100
      }
      
      // 查产品数量
      String sql3 = "select field_Bpz84__c from object_pM0SB__c where _id = '$stockDetailId'";
      def result3 = Fx.object.select(sql3)
      QueryResult queryResult3 = result3[1] as QueryResult
      List dataList3 = queryResult3.dataList as List
      Map map2 = dataList3[0] as Map
      Integer num = map2.field_Bpz84__c as Integer
     
      // 累加总金额
       Double curSumPrice = price * onSale * num
       sumPrice += curSumPrice
      
      // UI操作
      addDetail "object_OjYMi__c" set("record_type": "default__c", "field_1wsig__c": productId, "field_rn49z__c": productName, "field_Xykq1__c": price, "field_wAJcR__c": num, "field_A7gJR__c": stockDetailId, "field_rI6mi__c": onSaleInput, "field_7d31X__c": curSumPrice)
      // editDetailFields "object_OjYMi__c" fieldApiName("field_Xykq1__c") readOnly(true)
      // editDetailFields "object_OjYMi__c" fieldApiName("field_wAJcR__c") readOnly(true)
      // editDetailFields "object_OjYMi__c" fieldApiName("field_A7gJR__c") readOnly(true)
      
    } 
    editMaster("field_14o25__c": sumPrice) 
    
  }
 
  return event
 
 
/**
 * @author 杨宇翔Barry
 * @codeName yyx_产品单价修改
 * @description 产品单价修改
 * @createTime 2023-06-06
 */

  UIEvent event2 = UIEvent.build(context) {
    //获取context信息
  } 
  Map currentData = event2.getCurrentDetail() // 获取当前操作的从对象数据
  String mark = currentData["field_A7gJR__c"] // 明细标识(当前具体是哪一条从对象被更改) // 这里是不能用currentData["_id"]的,因为新建还未提交时从对象此时还未存入数据库,都还没有id
  
  Map detailMap = context.details as Map // 所有从对象(毕竟一个主对象可以有多个重对象)
  List salesOrderProductObjList = detailMap.object_OjYMi__c as List // 获取指定从对象
  
  Map args = context.arg as Map // 上下文参数
  List triggerFieldAPIName =  args.triggerFieldAPIName as List // 监控是哪个字段在进行修改
  
  //新建UIEvent事件
  UIEvent event = UIEvent.build(context) {
      BigDecimal price = currentData["field_Xykq1__c"] as BigDecimal
      BigDecimal onSale = currentData["field_rI6mi__c"] as BigDecimal
      BigDecimal num = currentData["field_wAJcR__c"] as BigDecimal
      BigDecimal zje = currentData["field_7d31X__c"] as BigDecimal
      if( triggerFieldAPIName[0] == "field_Xykq1__c" ){ // 产品单价变动
        if( price != null && onSale != null && num != null){
           zje = price * onSale / 100 * num
           editDetail "object_OjYMi__c" set("field_7d31X__c": zje) where { x -> x["field_A7gJR__c"] == mark }
        }
      } else if( triggerFieldAPIName[0] == "field_7d31X__c" ){ // 总金额变动
        if( zje != null && onSale != null && num != null ){
           price = zje * 100 / num / onSale
           editDetail "object_OjYMi__c" set("field_Xykq1__c": price) where { x -> x["field_A7gJR__c"] == mark }
        }
      }
      
    // 计算所有明细的总金额
    BigDecimal sumPrice = 0
    salesOrderProductObjList.each { item ->
      Map map = item as Map
      if( map != null ){
        BigDecimal tmpPrice = map.field_Xykq1__c as BigDecimal
        BigDecimal tmpSale = map.field_rI6mi__c as BigDecimal
        BigDecimal tmpNum = map.field_wAJcR__c as BigDecimal
        if( tmpPrice != null && tmpSale != null && tmpNum != null){
          tmpSale /= 100
          sumPrice += tmpPrice * tmpSale * tmpNum
        } else {
          sumPrice += 0
        }
      }
    }
    editMaster("field_14o25__c": sumPrice) 
  }

  return event
 
 

更好的代码(不含计算所有明细的总金额):

/**
 * @author 王祎YiWang
 * @codeName 计算订单明细总额(数量)
 * @description 计算订单明细总额(数量)
 * @createTime 2023-06-06
 */
UIEvent event = UIEvent.build(context) { 
    
}


//获取当前操作的行从对象数据
Map currentData = event.getCurrentDetail();
log.info("操作明细数据:"+currentData);
BigDecimal quantity = currentData["quantity"]==null?0:currentData["quantity"] as BigDecimal //数量
BigDecimal product_price = currentData["product_price"]==null?0:currentData["product_price"] as BigDecimal //价格
BigDecimal amount = (quantity*product_price) as BigDecimal;
//修改操作行数据
currentData.put("field_6T8S5__c",amount)//是
return event

更好的代码(包含计算所有明细的总金额):

/**
 * @author 杨宇翔Barry
 * @codeName yyx_产品单价修改
 * @description 产品单价修改
 * @createTime 2023-06-06
 */

UIEvent event = UIEvent.build(context) {
  
}

Map args = context.arg as Map // 上下文参数
List triggerFieldAPIName = args.triggerFieldAPIName as List // 监控是哪个字段在进行修改

Map detailMap = context.details as Map // 所有从对象(毕竟一个主对象可以有多个重对象)
List salesOrderProductObjList = detailMap.object_OjYMi__c as List // 获取指定从对象

// 获取当前操作的从对象行数据
Map currentData = event.getCurrentDetail();
BigDecimal price = (currentData["field_Xykq1__c"] == null) ? 0 : currentData["field_Xykq1__c"] as BigDecimal // 单价
BigDecimal num = (currentData["field_wAJcR__c"] == null) ? 0 : currentData["field_wAJcR__c"] as BigDecimal // 数量
BigDecimal onSale = (currentData["field_rI6mi__c"] == null) ? 0 : currentData["field_rI6mi__c"] as BigDecimal // 折扣
BigDecimal sumPrice = (currentData["field_7d31X__c"] == null) ? 0 : currentData["field_7d31X__c"] as BigDecimal // 总价


if( "field_Xykq1__c" == triggerFieldAPIName[0] ){ // 产品单价发生变动
  sumPrice = price * num * onSale / 100
  currentData.put("field_7d31X__c", sumPrice)
} else if ( "field_7d31X__c" == triggerFieldAPIName[0] ) { // 产品总价发生变动
  price = sumPrice * 100 / num / onSale
  currentData.put("field_Xykq1__c", price)
} 

// 计算所有明细的总金额
BigDecimal sumPriceOfDetail = 0
salesOrderProductObjList.each { item ->
  Map map = item as Map
  if( map != null ){
    BigDecimal tmpPrice = map.field_Xykq1__c as BigDecimal
    BigDecimal tmpSale = map.field_rI6mi__c as BigDecimal
    BigDecimal tmpNum = map.field_wAJcR__c as BigDecimal
    if( tmpPrice != null && tmpSale != null && tmpNum != null){
      tmpSale /= 100
      sumPriceOfDetail += tmpPrice * tmpSale * tmpNum
    } else {
      sumPriceOfDetail += 0
    }
  }
}

UIEvent event2 = UIEvent.build(context) {
  editMaster("field_14o25__c": sumPriceOfDetail) 
}
return event2


总结:

编辑当前操作的从对象的行数据(各字段的值)有两种方法,一种是通过__mark__字段做判断,另一种是通过currentData.put()

通过__mark__字段编辑举例:

__mark__字段是个系统字段, 感觉像是时间戳,独一无二,所以可以作为当前正在操作的从对象的标记

image.png

 String mark = currentData["__mark__"]
 editDetail "object_OjYMi__c" set("field_7d31X__c": sumPrice) where { x -> x["__mark__"] == mark }

通过currentData.put()编辑举例:

currentData.put("field_7d31X__c", sumPrice)

image.png

部分文档(有点老)

//停用,目前需要调整成从接口获取最新价格


/**
1、根据【合同产品明细】内选择的「产品」、「样本个数」检索该产品关联的【产品价格表】,
并将符合标准的【产品价格表】内的「产品单价」和「产品固定价格」带入到合同产品明细中;

2、合同产品明细.样本个数<=产品价格表.数量;
合同产品明细.单价=产品价格表.产品单价;
合同产品明细.固定价格<=产品价格表.产品固定价格;

3、金额小计=样本个数*单价+固定价格;
4、存在人为修改情况 :
(1)如果修改「金额小计」,则   金额小计- (固定价格)/样本个数 = 最新的单价;
(2)如果修改「样本个数」,则  样本个数 * 单价(查询系统内范围单价)+固定价格   = 最新的金额小计  
(3)如果修改「单价」,则   样本个数 * 单价+固定价格   = 最新的金额小计 
5.修改产品则会清空 相关计算字段
zar
**/

//2022年8月12日 产品编辑增加主合同可选产品ID

UIEvent event = UIEvent.build(context) {
//获取context信息
} 

//获取当前操作的从对象数据
Map currentData = event.getCurrentDetail()
log.info(currentData)

//获取所有明细数据
Map details = context.details as Map
log.info("获取所有明细数据:" + details)

// 获取指定的明细的数据
List Mx = details["object_ljRc2__c"] as List

String cpIds = ""
Mx.eachWithIndex{ item2, index2 ->
     Map MXMap=[:] //明细Map
     Map getmap2 = item2 as Map
     String cpId= (getmap2["field_Ecvr1__c"]==null) ? ("") : getmap2["field_Ecvr1__c"] as String
     if(cpId !=""){
         cpIds += cpId + ","
     }
}

SelectAttribute att = SelectAttribute.builder()
.needCount(true)
.build()

String cpId = (currentData["field_Ecvr1__c"]==null) ?(""):currentData["field_Ecvr1__c"] as String  //产品信息 //"797032410702020608"
String sl_String = (currentData["field_D4Pxu__c"]==null) ?("0"):currentData["field_D4Pxu__c"] as String   //获取样本数量
int sl = sl_String as int

String cpmx__c =  (context.data.cpmx__c==null) ? ("") : context.data.cpmx__c as String  // 已选产品明细ID

//------------------------系统字段-----------------------------------
String  mark =currentData["__mark__"]   // 明细标识
log.info("__Mark__   " + mark)

Map args = context.arg as Map

List triggerFieldAPIName =  args.triggerFieldAPIName as List   // 监控是哪个字段在进行修改
log.info("字段监控 " + triggerFieldAPIName[0])
//-----------------------------------------------------------

BigDecimal price = (currentData["field_nVomD__c"]==null) ? (0.00) : currentData["field_nVomD__c"]  as BigDecimal //产品单价
BigDecimal fixed_price = (currentData["field_1Q57c__c"]==null) ? (0.00) : currentData["field_1Q57c__c"] as BigDecimal//固定单价
BigDecimal zje = (currentData["field_a1Po2__c"]==null) ? (0.00) : currentData["field_a1Po2__c"]  as BigDecimal//金额小计

/*************查询产品信息单价*****开始****************/
if( triggerFieldAPIName[0] =="field_D4Pxu__c" ){ // 修改 样本字段
    if(sl > 0) {
        log.info("cp"+cpId)
        String sql = "SELECT _id, " +
        "  name, " +
        "  field_aS62h__c, " +
        "  field_3Dr53__c, " +
        "  field_viVu2__c " +
        "FROM object_5OEA8__c " +
        "WHERE ( field_6K4mM__c ='" + cpId + "' " +
        "AND field_viVu2__c       >= " + sl + " " +
        "AND field_viVu2__c        > 0 " +
        "AND field_QEqdx__c        ='true' ) " +
        "ORDER BY field_viVu2__c  limit 1 offset 0"
        //------------------------------------------------------------

        //如果超出数量则获取最低价 查询 数量为空的配置表
        String sql2 = "SELECT _id, " +
        "  name, " +
        "  field_aS62h__c, " +
        "  field_3Dr53__c, " +
        "  field_viVu2__c " +
        "FROM object_5OEA8__c " +
        "WHERE ( field_6K4mM__c ='" + cpId + "' " +
        "AND field_viVu2__c   is null " +
        "AND field_QEqdx__c        ='true' ) " +
        "ORDER BY field_viVu2__c  limit 1 offset 0"


         // 查询样本数量满足的产品单价
         def (Boolean error, QueryResult queryResult, String message) = Fx.object.select(sql, att)
         if (error) {
             log.info("select error: " + message)
         } else {
             // log.info(queryResult)
         }

         List cpLists = queryResult["dataList"] as List  //查询区间范围价格
         log.info(cpLists)
         if(cpLists.size()>0){
         price = cpLists[0]["field_aS62h__c"] as BigDecimal
         fixed_price = cpLists[0]["field_3Dr53__c"] as BigDecimal
    } else {
         // 如果超出数量则获取最低价 查询 数量为空的配置表
         def (Boolean error2, QueryResult queryResult2, String message2) = Fx.object.select(sql2, att)
         if (error2) {
             log.info("select error2: " + message2)
         } else {
             // log.info(queryResult2)
         }

          List cpLists2 = queryResult2["dataList"]  as  List  //查询区间范围价格
          log.info(cpLists2)
          if(cpLists2.size() > 0){
              price = cpLists2[0]["field_aS62h__c"] as BigDecimal
              fixed_price = cpLists2[0]["field_3Dr53__c"] as BigDecimal 
          }
    }
}


//(2)如果修改「样本个数」,则  样本个数 * 单价(查询系统内范围单价)+固定价格   = 最新的金额小计  
zje = price*sl+fixed_price  //修改样本个数

}

//(1)如果修改「金额小计」,则   金额小计- (固定价格)/样本个数 = 最新的单价;
if( triggerFieldAPIName[0] =="field_a1Po2__c" ){ // 修改 金额

  if(sl ==0){  //如果没有选择sl 则会报错
     price =( zje - fixed_price )
  }else{

    price =( zje - fixed_price )/sl
  }
  
   price = price.setScale(2, BigDecimal.ROUND_UP)   //四舍五入保留两位
}

//(3)如果修改「单价」,则   样本个数 * 单价+固定价格   = 最新的金额小计 
if( triggerFieldAPIName[0] =="field_nVomD__c" ){ // 修改 单价

    zje  = sl*price+fixed_price
  
}



log.info("单价"+price)
log.info("固定单价"+fixed_price)
log.info("总金额"+zje)
/**************查询产品信息单价****结束***************/
 UIEvent event2 = UIEvent.build(context) {
//处理数据


 editMaster("cpmx__c": cpIds) 

if( triggerFieldAPIName[0] =="field_Ecvr1__c" ){ // 修改 产品  置空所有计算字段
 //主对象修改数据

/* 
List cpmxList = [] 

if(cpmx__c !=""){
  
  List  orders = cpmx__c.split(",")  as List
  
  if( orders.contains(cpId) ){
    //是否存在重复
    
  }else{
    
     cpmx__c += cpId+","
  }
  
}else{
  
  cpmx__c = cpId
  
}




  log.info("产品可选ID:  "+cpmx__c)*/
 



  editDetail "object_ljRc2__c" set("__mark__":mark,"field_a1Po2__c": "", "field_nVomD__c": "","field_1Q57c__c":"","field_D4Pxu__c":"") where { x -> (x["__mark__"]) == mark }

}

if( triggerFieldAPIName[0] =="field_a1Po2__c" ){ // 修改 金额字段  重新计算单价
  editDetail "object_ljRc2__c" set("__mark__":mark,"field_nVomD__c": price) where { x -> (x["__mark__"]) == mark }

}

if( triggerFieldAPIName[0] =="field_D4Pxu__c" ){ // 修改 样本个数字段,重新查询配置表计算
  editDetail "object_ljRc2__c" set("__mark__":mark,"field_a1Po2__c": zje, "field_nVomD__c": price,"field_1Q57c__c":fixed_price) where { x -> (x["__mark__"]) == mark }

}


if( triggerFieldAPIName[0] =="field_nVomD__c" ){ // 修改 单价字段  重新总金额
  editDetail "object_ljRc2__c" set("__mark__":mark,"field_a1Po2__c": zje) where { x -> (x["__mark__"]) == mark }

}

} 

return event2

九.新建/编辑客户对象时,要校验客户名称字段是否与客户对象历史数据中的客户曾用名字段有重复。如果重复,则阻止提交。

 // 客户名称
 String name = context.data.name
 // 客户id
 String id = (context.data._id != null) ? context.data._id : ''
 // 查询有无客户对象的“客户曾用名”字段与刚刚填写的客户名称一致
 String sql = "select _id from AccountObj where cym  like '%"+name+"%' and _id !='"+id+"'"
 SelectAttribute att = SelectAttribute.builder()
    .needCount(true)
    .needInvalid(true)
    .build();
  def(Boolean error, Object result, String message) = Fx.object.select(sql, att);
  if (error) {
    log.info("error:" + error)
  }
  log.info("message:" + message)
  QueryResult queryResult = result as QueryResult
  List dataList = (queryResult.dataList == null) ? ([]) : queryResult.dataList as List // 查询结果
  if( dataList.size() > 0 ){
    return ["error": true, "errorMessage":"客户已存在,客户名称【" + name + "】存在", "block":true]
  }
  return ["error": false, "errorMessage":"成功"]

十.自增编号规则

需求1: 销售订单根据业务类型进行编号,不同业务类型,编码前缀不同

Date today = Date.now() as Date;
String date = (today as String).replace("-", "") as String
String record_type = context.data.record_type as String
String counter // 计数器的key
String prefix // 前缀
if( record_type == "default__c" ) {
  counter = "sw";
  prefix = "SO" + "SW" + date
} else if (record_type == "record_2S926__c") {
  counter = "PS"
  prefix = "SO" + "PS" + date
} else if (record_type == "record_4d3dy__c") {
  counter = "DP"
  prefix = "SO" + "DP" + date
}

IncrementNumber rule = IncrementNumber.builder()
  .counter(counter)        // 计数器的key,递增的自增编码需要保证key唯一,同理,更换counter可以重计自增编号
  .condition('YEAR')      // 按年、月、日重计 `YEAR`  `MONTH`  `DAY`  `NONE`
  .postfix('')     // 编码后缀
  .prefix(prefix)       // 编码前缀
  .serialNumber(5)         // 自增编码位数
  .initialValue(1)         // 编号起始值不能小于 0,且默认为 1
  .steppingNumber(1)       // 步进器默认为1,且不能小于1
  .buildRule()
log.info(rule)
return rule

效果:

image.png

需求2: 补充协议需要集成主协议编号进行增加流水,如主协议HT202210210001,补充协议HT202210210001-01

String prefix = "" as String
Integer serialNumber = 0 as Integer // 自增编号位数
String today = Date.now() as String
String today_string = today.replace("-", "") as String
String record_type = context.data.record_type as String // 业务类型
String counter = "" as String // 计数器的key

if( record_type == "record_JqnR0__c" ) { // 补充协议
  String ht = context.data.field_ptiya__c // 关联主合同id
  def(Boolean error, Map data, String errorMessage) = Fx.object.findById("object_20aOd__c", ht)
  String ht_name = data.name as String // 主合同自增编号
  counter = "BC" + ht_name
  prefix = ht_name + "-"
  serialNumber = 2
} else { // 主协议
  counter = "QT"
  prefix = "HT" + today_string
  serialNumber = 4
}

IncrementNumber rule = IncrementNumber.builder()
  .counter(counter)        // 计数器的key,递增的自增编码需要保证key唯一,同理,更换counter可以重计自增编号
  .condition('YEAR')      // 按年、月、日重计 `YEAR`  `MONTH`  `DAY`  `NONE`
  .postfix('')     // 编码后缀
  .prefix(prefix)       // 编码前缀
  .serialNumber(serialNumber)         // 自增编码位数
  .initialValue(1)         // 编号起始值不能小于 0,且默认为 1
  .steppingNumber(1)       // 步进器默认为1,且不能小于1
  .buildRule()
log.info(rule)
return rule

效果:

image.png

注: 一个对象仅支持配置一个编码函数

十一. 计划任务

image.png

image.png

image.png

image.png

需求: 根据上级客户成交状态,定期更新下级客户成交状态


// 符合条件的数据id
List ids = context.objectIds as List
def (boolean error0, List dataList0, String errorMessage0) = Fx.object.findByIds("object_62o05__c", ids)
dataList0.each{ item ->
  Map map = item as Map
  // log.info(context.data.record_type as String) // 错误写法: 当前context中是不存在data属性的,因为这并不是新建编辑页的APL函数(但是测试脚本模拟的是新建编辑页,所以可以打印出数据,而计划任务执行时却没有数据)
  log.info(map.record_type as String)
  if( (map.record_type as String) == "record_6L561__c"  ){ // 下级客户 // 为什么公司不能用continue啊,用了的话就不用写else了
    log.info("——————————当前客户为下级客户,不做处理——————————")
  } else {
    log.info("——————————当前客户为上级客户,更改下级客户——————————")
    String id = map._id // 上级客户id
    String dealStatus = map.field_5Xs1N__c // 上级客户成交状态
    
    // 查询上级客户为此客户的下级客户
    String sql = "select _id from object_62o05__c where field_vvf46__c = '$id'"
    SelectAttribute att = SelectAttribute.builder()
        .needCount(true)
        .needInvalid(true)
        .build();
    def(Boolean error, Object result, String message) = Fx.object.select(sql, att)
    if (error) {
      log.info("error:" + error)
    }
    QueryResult queryResult = result as QueryResult
    List childList = (queryResult.dataList == null) ? ([]) : queryResult.dataList as List // 查询结果
    // 修改下级客户的成交状态与上级客户相同
    childList.each{childAccount ->
      String childAccountId = (childAccount as Map)._id
      def(Boolean errorC, Map dataC, String errorMessageC) = 
        Fx.object.update("object_62o05__c", childAccountId,  ["field_5Xs1N__c": dealStatus],  false,  false)
      if( errorC ) {
        log.info(errorMessageC)
      } else {
        log.info("更新成功")
      }
    }
  }
}

效果:

image.png

image.png

思考: 为什么不在业务类型为下级客户时的布局中,添加引用字段,引用其查找关联的上级客户的成交状态字段,这样实时更新不比定期批量更新更好吗? 还不用写函数

用这种方法也实现了效果,但需求中写的是定期更新

可以支持创建函数任务,用于执行定期计划的函数任务,可满足企业定期批量处理数据的需求。

可以定期批量处理客户,例如将最近跟进时间早于半年的客户进行定期作废。

课后作业:

image.png

十二.范围规则

image.png

方法一: image.png

QueryTemplate作为关联查询的条件的返回结果,更加高效。

除非QueryTemplate的查询方式不能满足需求,否则优先推荐用使用QueryTemplate返回类型函数,用此方法返回的范围数据没有上限,并且执行效率高。

方法二: image.png

不推荐使用List返回类型函数,用此方法返回的数据有上限500条,并且查询和使用id作为返回值的执行效率较低。

方法三: image.png

选择和新建查找关联字段时指定默认业务类型。

image.png

image.png

为什么不用基于字段:

因为查找关联的是自定义客户对象,而这里我们设置条件是需要依据当前表单中的布尔值来设置,所以基于字段是无法实现的

image.png

效果:

image.png

当布尔值选择是时:

image.png

当布尔值选择否时:

image.png

代码:

Boolean flag = context.data.field_0VgL5__c as Boolean // 布尔值
List owner_list = context.data.owner as List
String owner_ = owner_list[0] // 当前数据负责人

QueryTemplate query = null
if( flag ){ // 查找关联可选的数据为负责人为自己
  query = QueryTemplate.AND(
    ["owner":Operator.EQ(owner_)]
  )
  return query
}

// 查找关联可选的数据为负责人为其他人
query = QueryTemplate.AND(
  ["owner":Operator.NE(owner_)]
)
return query

十三.限制动态关联字段可以关联的对象数据范围

代码:

//动态关联字段可以绑定的对象
List objectApiNames = ["object_KkdtL__c","AccountObj","object_qep6N__c"]
def list = []
objectApiNames.each {
  item ->
  RelatedObjectData objRelate = RelatedObjectData.builder()
  .apiName(item)
  .build()
  list.add(objRelate)
}
// log.info(list)
RelatedObject relatedObject = RelatedObject.builder()
  .objectList(list)
  .build()
return relatedObject

十四. 工作流触发函数

image.png


// 获取触发流程的对象的id与apiname
String objectId = context.data["_id"]
String objectApiName = context.data["object_describe_api_name"]

// 查询项目券申领对象的数据(负责人、申领类型、申领项目券金额、申领客户、申领单位)
String sql = "select owner, couponType__c, couponApplicationAmount__c, couponApplicationContact__c, couponApplicationAccount__c from object_Ur0mD__c where _id = '$objectId'";
SelectAttribute att = SelectAttribute.builder()
  .needCount(true)
  .needInvalid(true)
  .build();
def(Boolean error, Object result, String message) = Fx.object.select(sql, att);
if (error) {
  log.info("error:" + error)
  log.info("message:" + message)
}
QueryResult queryResult = result as QueryResult
List dataList = (queryResult.dataList == null) ? ([]) : queryResult.dataList as List // 查询结果

// 对查询结果进行处理
if( dataList.size() == 0 ){
  log.info('查询不到该项目券申领对象')
  return
}
Map ticketMap = [:]
Map dataMap = dataList[0]
List ownerList = (dataMap["owner"] == null) ? ([]) : dataMap["owner"] as List
ticketMap.put("owner", ownerList)
String owner_ = (ownerList.size() == 0) ? ('') : ownerList[0] // 负责人
String couponType = (dataMap["couponType__c"] == null) ? ('') : dataMap["couponType__c"] as String // 申领类型
ticketMap.put("couponType__c", couponType)
BigDecimal couponApplicationAmount = (dataMap["couponApplicationAmount__c"] == null) ? (0) : dataMap["couponApplicationAmount__c"] as BigDecimal // 申领项目券金额
ticketMap.put("couponAmount__c", couponApplicationAmount)
String couponApplicationContact = (dataMap["couponApplicationContact__c"] == null) ? ('') : dataMap["couponApplicationContact__c"] as String // 申领客户
ticketMap.put("couponContactBelongs__c", couponApplicationContact)
String couponApplicationAccount = (dataMap["couponApplicationAccount__c"] == null) ? ('') : dataMap["couponApplicationAccount__c"] as String // 申领单位
ticketMap.put("couponAccountBelongs__c", couponApplicationAccount)
ticketMap.put("couponState__c", "1") // 项目券状态
log.info(ticketMap)

// 创建项目券对象
ActionAttribute attribute = ActionAttribute.build {
  triggerApprovalFlow = false
  triggerWorkflow = false
  skipFunctionAction = true
  specifyCreatedBy = true
  specifyTime = true
  duplicateSearch = false
}
def(Boolean error1,Map data1,String errorMessage1) = Fx.object.create("object_cOCdW__c", ticketMap, null,attribute)
Map map = data1.data as Map
String ticketId = map["_id"] // 刚刚创建的项目券的id

// 项目券申领中回填刚刚创建的项目券的编号
def (Boolean error2, Map data2, String errorMessage2) =  Fx.object.update("object_Ur0mD__c", objectId, ["couponID__c": ticketId], false)
if (error2) {
  log.info("error2:" + errorMessage2 )
}
log.info(data2)


十五. 明细对象根据某个字段判定重复

// 对数据进行赋值
Map details = context.details as Map
List detailList = details["object_A05Hz__c"] as List
List stocks = [] // 存放明细中所有的经销商库存
detailList.each{ item->
  Map itemMap = item as Map
  String stock = itemMap["field_6Ad59__c"]
  stocks.add(stock)
}
if( stocks.size() > 0 && Fx.utils.listUnique(stocks).size() > 0 && stocks.size() != Fx.utils.listUnique(stocks).size()){
  return ["error": true, "errorMessage":"经销商库存字段重复", "block":true]
}

return ["error": false, "errorMessage":"成功"]

十六. 待办列表支持多行文本展示成html

image.png

要申请灰度: 待办列表支持多行文本展示成html

image.png

代码:

String dataId = context.data._id as String;

// 表单
String table = "";

// 表头
String tabHead = "";

// 表体
String tabBody = "";
String tabBodyTr = "";

// 获取订单产品数据
List orderDetails = context.details.object_OjYMi__c as List;
orderDetails.each { item ->

  // 产品名称
	String productName = (item["field_rn49z__c"] == null) ?  ("") : item["field_rn49z__c"] as String;

	// 产品单价
	BigDecimal productSalePrice = (item["field_Xykq1__c"] == null) ? (0.0) : item["field_Xykq1__c"] as BigDecimal;

	// 产品数量
	Integer productQuantity = (item["field_wAJcR__c"] == null) ? (0) : item["field_wAJcR__c"] as Integer;
	
	// 折扣
	Integer productSales = (item["field_rI6mi__c"] == null) ? (0) :  item["field_rI6mi__c"] as Integer;
	productSales /= 10
	
	// 总金额
	BigDecimal productSumPrice = (item["field_7d31X__c"] == null) ? (0.0) : item["field_7d31X__c"] as BigDecimal;

	tabBodyTr += "<tr>" +
              	"<td>"+ productName +"</td>" +
              	"<td>"+ productSalePrice +"</td>" +
              	"<td>"+ productQuantity +"</td>" +
              	"<td>"+ productSales +"</td>" +
              	"<td>"+ productSumPrice +"</td>" +
              "</tr>";
}

tabHead = "<thead>" +
            "<tr style='background-color: #2C334F;'>" +
            "<th width=120px>产品名称</th>" +
            "<th width=200px>产品单价</th>" +
            "<th width=60px>产品数量</th>" +
            "<th width=60px>折扣</th>" +
            "<th width=60px>总金额(元)</th>" +
            "</tr>" +
          "</thead>";

tabBody = "<tbody>" + tabBodyTr + "</tbody>";

table = "__FXHTML__" + "<table style='border: 2px solid;'>" + tabHead + tabBody + "</table>";

def updateResult = Fx.object.update("object_8vqYk__c", dataId, ["field_VM8w5__c": table])
if (updateResult[0]) {
	Fx.message.throwErrorMessage("更新失败:" + updateResult[2]);
} else {
	Fx.log.info("更新成功:" + table);
}