Pārlūkot izejas kodu

订单搜索脚本,需要对具体的字段做条件,当前相当于示例

jlutt@163.com 2 gadi atpakaļ
vecāks
revīzija
b39f8867dd

+ 16 - 5
conf/script/1000/expressApi/BE_Express_CancelOrder_SFTC.groovy

@@ -53,11 +53,23 @@ class BE_Express_CancelOrder_SFTC implements BusinessExecutor<InvokeCallParams,
     }
 
     @Override
-    OperatorWait getAWait() {
+    OperatorWait getAWait(InvokeCallParams source) {
         return OperatorWait.ASNYC
     }
 
     @Override
+    RetResult<InvokeCallParams> checkExecute(InvokeCallParams source) {
+        //检查订单信息
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+
+        String orderId = invokeOrder["orderId"] as String
+        //todo 获取订单信息
+
+        return RetResult.<InvokeCallParams> successT().result(source)
+    }
+
+    @Override
     RetResult<InvokeCallParams> beforeExecute(InvokeCallParams source) {
         //锁定下订单数据
         def jsonSlurper = new JsonSlurper()
@@ -73,15 +85,14 @@ class BE_Express_CancelOrder_SFTC implements BusinessExecutor<InvokeCallParams,
     }
 
     @Override
-    RetResult<InvokeCallParams> checkExecute(InvokeCallParams source) {
-        //检查订单信息
+    void afterExecute(boolean executeError, InvokeCallParams source, InvokeCallResult dest) {
+        //锁定下订单数据
         def jsonSlurper = new JsonSlurper()
         def invokeOrder = jsonSlurper.parseText(source.params)
 
         String orderId = invokeOrder["orderId"] as String
-        //todo 获取订单信息
 
-        return RetResult.<InvokeCallParams> successT().result(source)
+        lockDataService.hLockDel(orderId, RedisKeys.KEY_ERP_WORKING_ORDER, source.supplierCode)
     }
 
     RetResult<InvokeCallResult> execute(InvokeCallParams source) {

+ 55 - 13
conf/script/1000/expressApi/BE_Express_CreateOrder_SFTC.groovy

@@ -1,9 +1,13 @@
 import com.alibaba.fastjson2.JSON
 import com.dderp.common.api.BusinessExecutor
+import com.dderp.common.api.ERPLockDataService
 import com.dderp.common.datas.ERPModule
-import com.dderp.common.entity.base.ProcessStringItem
+import com.dderp.common.datas.RedisKeys
+import com.dderp.common.entity.base.InvokeCallParams
+import com.dderp.common.entity.base.InvokeCallResult
 import com.dderp.common.entity.express.*
 import com.dderp.common.http.HttpTools
+import com.dySweetFishPlugin.sql.dao.OperatorWait
 import com.sweetfish.convert.json.JsonConvert
 import com.sweetfish.service.RetResult
 import groovy.json.JsonSlurper
@@ -20,7 +24,7 @@ import java.util.concurrent.TimeUnit
 import java.util.concurrent.TimeoutException
 
 @SuppressWarnings("unused")
-class BE_Express_CreateOrder_SFTC implements BusinessExecutor<ProcessStringItem, ProcessStringItem> {
+class BE_Express_CreateOrder_SFTC implements BusinessExecutor<InvokeCallParams, InvokeCallResult> {
 
     private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
 
@@ -36,6 +40,9 @@ class BE_Express_CreateOrder_SFTC implements BusinessExecutor<ProcessStringItem,
     @Resource
     JsonConvert jsonConvert
 
+    @Resource
+    ERPLockDataService lockDataService
+
     @Override
     String scriptName() {
         return "顺丰同城创建订单"
@@ -46,7 +53,50 @@ class BE_Express_CreateOrder_SFTC implements BusinessExecutor<ProcessStringItem,
         return ERPModule.EXPRESS_API
     }
 
-    RetResult<ProcessStringItem> execute(ProcessStringItem source) {
+    @Override
+    OperatorWait getAWait(InvokeCallParams source) {
+        return OperatorWait.ASNYC
+    }
+
+    @Override
+    RetResult<InvokeCallParams> checkExecute(InvokeCallParams source) {
+        //检查订单信息
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+
+        String orderId = invokeOrder["orderId"] as String
+        //todo 获取订单信息
+
+        return RetResult.<InvokeCallParams> successT().result(source)
+    }
+
+    @Override
+    RetResult<InvokeCallParams> beforeExecute(InvokeCallParams source) {
+        //锁定下订单数据
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+
+        String orderId = invokeOrder["orderId"] as String
+
+        //todo 获取订单信息
+        if (lockDataService.hLockAdd(orderId, RedisKeys.KEY_ERP_WORKING_ORDER, source.supplierCode) > 1) {
+            return RetResult.<InvokeCallParams> errorT().retinfo(orderId + "提交工作中,请稍后刷新即可,无需重复操作")
+        }
+        return RetResult.<InvokeCallParams> successT().result(source)
+    }
+
+    @Override
+    void afterExecute(boolean executeError, InvokeCallParams source, InvokeCallResult dest) {
+        //锁定下订单数据
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+
+        String orderId = invokeOrder["orderId"] as String
+
+        lockDataService.hLockDel(orderId, RedisKeys.KEY_ERP_WORKING_ORDER, source.supplierCode)
+    }
+
+    RetResult<InvokeCallResult> execute(InvokeCallParams source) {
         //秒级时间戳,groovy里面不让用system
         long currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8))
         long testTime = LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli()
@@ -116,19 +166,11 @@ class BE_Express_CreateOrder_SFTC implements BusinessExecutor<ProcessStringItem,
             logger.info(orderResult)
             logger.info(jsonConvert.convertTo(createOrderResult))
 
-            return RetResult.<ProcessStringItem> successT().result(
-                    ProcessStringItem.newBuilder()
-                            .itemValue("")
-                            .build()
-            )
+            return RetResult.<InvokeCallResult> successT()
         } catch (InterruptedException | ExecutionException | TimeoutException e) {
             logger.error(e.getMessage(), e)
 
-            return RetResult.<ProcessStringItem> successT().result(
-                    ProcessStringItem.newBuilder()
-                            .itemValue("")
-                            .build()
-            )
+            return RetResult.<InvokeCallResult> errorT().retinfo(e.getMessage())
         }
     }
 }

+ 1 - 1
conf/script/1000/expressApi/BE_Express_GetOrderStatus_SFTC.groovy

@@ -43,7 +43,7 @@ class BE_Express_GetOrderStatus_SFTC implements BusinessExecutor<InvokeCallParam
     }
 
     @Override
-    OperatorWait getAWait() {
+    OperatorWait getAWait(InvokeCallParams source) {
         return OperatorWait.AWAIT
     }
 

+ 1 - 1
conf/script/1000/expressApi/BE_Express_ListOrderFeed_SFTC.groovy

@@ -43,7 +43,7 @@ class BE_Express_ListOrderFeed_SFTC implements BusinessExecutor<InvokeCallParams
     }
 
     @Override
-    OperatorWait getAWait() {
+    OperatorWait getAWait(InvokeCallParams source) {
         return OperatorWait.AWAIT
     }
 

+ 1 - 1
conf/script/1000/expressApi/BE_Express_OrderStatusInvoke_SFTC.groovy

@@ -39,7 +39,7 @@ class BE_Express_OrderStatusInvoke_SFTC implements BusinessExecutor<InvokeCallPa
     }
 
     @Override
-    OperatorWait getAWait() {
+    OperatorWait getAWait(InvokeCallParams source) {
         return OperatorWait.ASNYC
     }
 

+ 1 - 1
conf/script/1000/expressApi/BE_Express_StoreBind_SFTC.groovy

@@ -36,7 +36,7 @@ class BE_Express_StoreBind_SFTC implements BusinessExecutor<InvokeCallParams, In
     }
 
     @Override
-    OperatorWait getAWait() {
+    OperatorWait getAWait(InvokeCallParams source) {
         return OperatorWait.SYNC
     }
 

+ 519 - 0
conf/script/1000/orderSearch/BE_ERP_BusinessOrder_Search.groovy

@@ -0,0 +1,519 @@
+import com.dderp.common.api.BusinessExecutor
+import com.dderp.common.api.SupplierInitService
+import com.dderp.common.datas.ERPModule
+import com.dderp.common.datas.ESKeys
+import com.dderp.common.datas.ReadOrderOption
+import com.dderp.common.entity.base.ProcessSearchOptionsItem
+import com.dderp.common.entity.order.BusinessOrder
+import com.dderp.common.tool.ERPUtils
+import com.dderp.common.datas.ReadOrderOption
+import com.dySweetFishPlugin.elasticsearch.ESClient
+import com.dySweetFishPlugin.tool.lang.DateUtil
+import com.sweetfish.convert.json.JsonConvert
+import com.sweetfish.service.RetResult
+import org.apache.commons.lang3.StringUtils
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.Logger
+import org.elasticsearch.action.search.SearchResponse
+import org.elasticsearch.index.query.BoolQueryBuilder
+import org.elasticsearch.index.query.Operator
+import org.elasticsearch.index.query.QueryBuilder
+import org.elasticsearch.index.query.QueryBuilders
+import org.elasticsearch.join.query.JoinQueryBuilders
+import org.elasticsearch.search.aggregations.AggregationBuilders
+import org.elasticsearch.search.aggregations.metrics.sum.InternalSum
+import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCount
+import org.elasticsearch.search.sort.SortBuilders
+import org.elasticsearch.search.sort.SortOrder
+import org.rex.RMap
+
+import javax.annotation.Resource
+import java.math.RoundingMode
+import java.util.function.ToLongFunction
+
+@SuppressWarnings(["rawtypes"])
+class BE_ERP_BusinessOrder_Search implements BusinessExecutor<ProcessSearchOptionsItem<ReadOrderOption>, BusinessOrder> {
+
+    protected final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
+
+    @Resource
+    SupplierInitService supplierService
+
+    @Resource
+    ESClient esClient
+
+    @Resource
+    JsonConvert jsonConvert
+
+    @Override
+    String scriptName() {
+        return "ERP-外卖订单-查询"
+    }
+
+    @Override
+    ERPModule module() {
+        return ERPModule.ERP_ORDER_SEARCH
+    }
+
+
+    def <T> List<T> searchOrderChildInfoList(Class<T> clazz, String childESType, long[] idOrders, long supplierCode) {
+        return ESList.<T> getESList()
+                .esClient(esClient)
+                .jsonConvert(jsonConvert)
+                .clazz(clazz)
+                .queryBuilder({
+                    //获取完成的数据情况
+                    return QueryBuilders.boolQuery()
+                            .must(QueryBuilders.typeQuery(childESType))
+                            .must(QueryBuilders.termsQuery("idOrder", ERPUtils.longArrayToStrArray(idOrders)))
+                })
+                .index(supplierService.getDateYearESIndex(supplierCode, ESKeys.ES_ERP_PRINT_ORDER_INDEX, 1))
+                .executeNonePage()
+    }
+
+    def <T> Map<Long, List<T>> searchOrderChildInfoMap(Class<T> clazz, String childESType, long[] idOrders, long supplierCode, ToLongFunction<T> convertLong) {
+        return ESMap.<T> getESMap()
+                .srcIds(idOrders)
+                .esClient(esClient)
+                .jsonConvert(jsonConvert)
+                .clazz(clazz)
+                .queryBuilder({
+                    //获取完成的数据情况
+                    return QueryBuilders.boolQuery()
+                            .must(QueryBuilders.typeQuery(childESType))
+                            .must(QueryBuilders.termsQuery("idOrder", ERPUtils.longArrayToStrArray(idOrders)))
+                })
+                .convertLongExecutor(convertLong) //这里直接写{it.idOrder},只要所有的子类有这个值,groovy应该是可以的,只是看着难受,让调用接口传入转换方法
+                .index(supplierService.getDateYearESIndex(supplierCode, ESKeys.ES_ERP_PRINT_ORDER_INDEX, 1))
+                .execute()
+    }
+
+    def <T> List<T> getOrderChildInfo(Class<T> clazz, String childESType, long idOrder, long supplierCode) {
+        return ESList.<T> getESList()
+                .esClient(esClient)
+                .jsonConvert(jsonConvert)
+                .clazz(clazz)
+                .queryBuilder({
+                    //获取完成的数据情况
+                    return QueryBuilders.boolQuery()
+                            .must(QueryBuilders.typeQuery(childESType))
+                            .must(QueryBuilders.termQuery("idOrder", idOrder))
+                })
+                .index(supplierService.getDateYearESIndex(supplierCode, ESKeys.ES_ERP_PRINT_ORDER_INDEX, 1))
+                .executeNonePage()
+    }
+
+    def readOrderOptions(List<BusinessOrder> orderList, String dataSourceId, long supplierCode,
+                         ReadOrderOption... options) {
+        long[] idOrders = orderList*.id.toArray() as long[]
+
+        if ((options != null) && (options.length > 0) && (idOrders.length > 0)) {
+            //防止搞坏事,options传重复数据过来,先去重
+            options.toUnique().each { opt ->
+                switch (opt) {
+
+                }
+            }
+        }
+    }
+
+    def readOrderOptions(BusinessOrder sendOrder, String dataSourceId, long supplierCode,
+                         ReadOrderOption... options) {
+        if ((options != null) && (options.length > 0)) {
+            //防止搞坏事,options传重复数据过来,先去重
+            options.toUnique().each { opt ->
+                switch (opt) {
+
+                }
+            }
+        }
+    }
+
+    def readOrderTotal(RMap searchData, String dataSourceId, long supplierCode, ReadOrderOption... options) {
+
+        if (!(ReadOrderOption.ORDER_TOTAL in options)) {
+            return null
+        }
+
+        //这里的查询需要和主表一致
+        BoolQueryBuilder bqb = search(searchData)
+                .byOrderStates()
+                .byKeyWord()
+                .byBeginTime_Create()
+                .byEndTime_Create()
+                .byClientName()
+                .byIdClient()
+                .byVoidFlag()
+                .build()
+
+
+        //合计金额,所以主表从orderMoney中开始
+
+        SearchResponse searchResponse = esClient.getClient()
+                .prepareSearch(supplierService.getDateYearESIndex(supplierCode, ESKeys.ES_ERP_PRINT_ORDER_INDEX, 1))
+                .setQuery(bqb)
+                .addAggregation(AggregationBuilders.count("sub_count").field("id"))
+                .addAggregation(AggregationBuilders.sum("orderMoneyTotal_Sum").field("orderMoneyTotal"))
+                .addAggregation(AggregationBuilders.sum("chargeMoney_Sum").field("chargeMoney"))
+                .addAggregation(AggregationBuilders.sum("payMoney_Sum").field("payMoney"))
+                .addAggregation(AggregationBuilders.sum("orderQty_Sum").field("orderQty"))
+                .execute().actionGet()
+
+        ValueCount orderCountSum = searchResponse.getAggregations().get("sub_count")
+        InternalSum orderMoneyTotalSum = searchResponse.getAggregations().get("orderMoneyTotal_Sum")
+        InternalSum chargeMoneySum = searchResponse.getAggregations().get("chargeMoney_Sum")
+        InternalSum payMoneySum = searchResponse.getAggregations().get("payMoney_Sum")
+        InternalSum orderQtySum = searchResponse.getAggregations().get("orderQty_Sum")
+
+        RMap<String, Number> collectionData = new RMap<>()
+        collectionData.put("orderCountSum", orderCountSum.getValue())
+        collectionData.put("orderMoneyTotalSum", BigDecimal.valueOf(orderMoneyTotalSum.getValue()).setScale(2, RoundingMode.HALF_UP))
+        collectionData.put("chargeMoneySum", BigDecimal.valueOf(chargeMoneySum.getValue()).setScale(2, RoundingMode.HALF_UP))
+        collectionData.put("payMoneySum", BigDecimal.valueOf(payMoneySum.getValue()).setScale(2, RoundingMode.HALF_UP))
+        collectionData.put("orderQtySum", BigDecimal.valueOf(orderQtySum.getValue()).setScale(0, RoundingMode.HALF_UP))
+
+        return collectionData
+
+    }
+
+    private RetResult<List<BusinessOrder>> queryByConditions(ProcessSearchOptionsItem<ReadOrderOption> source) {
+        String orderByField = "createTimeLong"
+        String orderBySort = "desc"
+
+        if (StringUtils.isNotBlank(source.orderBy)) {
+            orderByField = source.orderBy.split(",")[0].trim()
+            orderBySort = source.orderBy.split(",")[1].trim().toLowerCase()
+        }
+
+        List<BusinessOrder> orderList = ESList.<BusinessOrder> getESList()
+                .esClient(esClient)
+                .jsonConvert(jsonConvert)
+                .clazz(BusinessOrder.class)
+                .queryBuilder({
+                    return search(source.searchData)
+                            .byOrderStates()
+                            .byKeyWord()
+                            .byBeginTime_Create()
+                            .byEndTime_Create()
+                            .byClientName()
+                            .byIdClient()
+                            .byVoidFlag()
+                            .build()
+                })
+                .index(supplierService.getDateYearESIndex(source.supplierCode, ESKeys.ES_ERP_PRINT_ORDER_INDEX, 1))
+                .sortBuilder({
+                    switch (orderBySort) {
+                        case 'asc': return SortBuilders.fieldSort(orderByField).order(SortOrder.ASC)
+                        case 'desc': return SortBuilders.fieldSort(orderByField).order(SortOrder.DESC)
+                    }
+
+                })
+                .dataExecutor(null)
+                .executePage(source.pageFlipper)
+
+        readOrderOptions(orderList, source.dataSourceId, source.supplierCode, source.options)
+
+        RMap<String, Number> collectionData = readOrderTotal(source.searchData, source.dataSourceId, source.supplierCode, source.options)
+        return RetResult.<List<BusinessOrder>> successT().result(orderList).page(source.pageFlipper).attachRMap(collectionData)
+
+
+    }
+
+    private RetResult<List<BusinessOrder>> queryByIds(ProcessSearchOptionsItem<ReadOrderOption> source) {
+        if (!ERPUtils.mapContainKey(source.searchData, ERPUtils.PARAM_SEARCH_IDS)) {
+            return RetResult.<List<BusinessOrder>> errorT().retinfo("无效的ids参数")
+        }
+
+
+        String[] idOrders = source.searchData.get(ERPUtils.PARAM_SEARCH_IDS)
+        //ES规定,addIds或者terms中的数据长度好像是1024个限制,这里为了安全,把list拆分一下
+        //待测试下,collate分隔之后的类型,不行的话还是得List<List<String>>
+        //测试后,结果是List<List<>>,不明白数组为什么转成List
+        List<List<String>> idOrderArrayList = idOrders.collate(500)
+        List<BusinessOrder> orderList = new ArrayList<>()
+
+        idOrderArrayList.each { l ->
+            List<BusinessOrder> subOrderList = ESList.<BusinessOrder> getESList()
+                    .esClient(esClient)
+                    .jsonConvert(jsonConvert)
+                    .clazz(BusinessOrder.class)
+                    .queryBuilder({
+                        return search(source.searchData)
+                                .byIdOrders(l.toArray(String[]::new))
+                                .build()
+                    })
+                    .index(supplierService.getDateYearESIndex(source.supplierCode, ESKeys.ES_ERP_PRINT_ORDER_INDEX, 1))
+                    .executeNonePage()
+            readOrderOptions(subOrderList, source.dataSourceId, source.supplierCode, source.options)
+            if (!subOrderList.isEmpty()) {
+                orderList.addAll(subOrderList)
+            }
+        }
+        return RetResult.<List<BusinessOrder>> successT().result(orderList)
+    }
+
+    private RetResult<BusinessOrder> queryById(ProcessSearchOptionsItem<ReadOrderOption> source) {
+        if (!ERPUtils.mapContainKey(source.searchData, ERPUtils.PARAM_SEARCH_ID)) {
+            return RetResult.<BusinessOrder> errorT().retinfo("无效的id参数")
+        }
+
+        long idOrder = source.searchData.getLong(ERPUtils.PARAM_SEARCH_ID)
+
+        BusinessOrder businessOrder = ESOne.<BusinessOrder> getESOneInfo()
+                .esClient(esClient)
+                .jsonConvert(jsonConvert)
+                .clazz(BusinessOrder.class)
+                .queryBuilder({
+                    //获取完成的数据情况
+                    ESConditionBuilder qb = search(null).byIdOrder(idOrder)
+                    //这里还需要判断数据权限
+                    return qb.build()
+                })
+                .index(supplierService.getDateYearESIndex(source.supplierCode, ESKeys.ES_ERP_PRINT_ORDER_INDEX, 1))
+                .execute()
+
+        if (businessOrder == null) {
+            return RetResult.<BusinessOrder> errorT().retinfo("无效的订单")
+        }
+
+        readOrderOptions(businessOrder, source.dataSourceId, source.supplierCode, source.options)
+
+        return RetResult.<BusinessOrder> successT().result(businessOrder)
+    }
+
+    private RetResult<BusinessOrder> queryByCode(ProcessSearchOptionsItem<ReadOrderOption> source) {
+        if (!ERPUtils.mapContainKey(source.searchData, ERPUtils.PARAM_SEARCH_CODE)) {
+            return RetResult.<BusinessOrder> errorT().retinfo("无效的id参数")
+        }
+
+        String orderCode = source.searchData.getString(ERPUtils.PARAM_SEARCH_CODE)
+
+        BusinessOrder businessOrder = ESOne.<BusinessOrder> getESOneInfo()
+                .esClient(esClient)
+                .jsonConvert(jsonConvert)
+                .clazz(BusinessOrder.class)
+                .queryBuilder({
+                    //获取完成的数据情况
+                    return search(null).byOrderCode(orderCode).build()
+                })
+                .index(supplierService.getDateYearESIndex(source.supplierCode, ESKeys.ES_ERP_PRINT_ORDER_INDEX, 1))
+                .execute()
+
+        if (businessOrder == null) {
+            return RetResult.<BusinessOrder> errorT().retinfo("无效的订单")
+        }
+
+        readOrderOptions(businessOrder, source.dataSourceId, source.supplierCode, source.options)
+
+        return RetResult.<BusinessOrder> successT().result(businessOrder)
+    }
+
+    @Override
+    RetResult<BusinessOrder> execute(ProcessSearchOptionsItem<ReadOrderOption> source) {
+        //可以参考一些都能运的代码,但那个硬编码需要多一些,这里直接判断搜索条件里面都有没有对应的条件
+
+        if (ERPUtils.mapContainKey(source.searchData, ERPUtils.PARAM_SEARCH_ID)) {
+            return queryById(source)
+        } else if (ERPUtils.mapContainKey(source.searchData, ERPUtils.PARAM_SEARCH_CODE)) {
+            return queryByCode(source)
+        }
+
+        return RetResult.<BusinessOrder> errorT().retinfo("无效的查询方式execute,查多数据应该使用executeList")
+    }
+
+    @Override
+    RetResult<List<BusinessOrder>> executeList(ProcessSearchOptionsItem<ReadOrderOption> source) {
+
+        if (ERPUtils.mapContainKey(source.searchData, ERPUtils.PARAM_SEARCH_IDS)) {
+            return queryByIds(source)
+        } else {
+            return queryByConditions(source)
+        }
+    }
+
+    //region 条件构造
+
+    //groovy没法用java中类似SendOrderESConditionBuilder的静态方法构造内部类,强制编译不报错,运行还是报错无适配的构造函数,但用常规的类好使,估计是内部类有什么说法
+
+    ESConditionBuilder search(RMap searchData) {
+        return new ESConditionBuilder(searchData, QueryBuilders.boolQuery().must(QueryBuilders.typeQuery(ESKeys.ES_ERP_PRINT_ORDER_TYPE)))
+    }
+
+    //这里是做一个示例,表示通过查部件子表查询订单
+    ESConditionBuilder searchByOrderRider(RMap searchData) {
+        return new ESConditionBuilder(searchData, QueryBuilders.boolQuery().must(QueryBuilders.typeQuery(ESKeys.ES_ERP_ORDER_PART_TYPE)))
+    }
+
+    //endregion
+
+    class ESConditionBuilder {
+
+        RMap searchData
+
+        BoolQueryBuilder qb
+
+        ESConditionBuilder() {
+        }
+
+        ESConditionBuilder(RMap searchData) {
+            this.searchData = searchData
+        }
+
+        ESConditionBuilder(RMap searchData, BoolQueryBuilder qb) {
+            this.searchData = searchData
+            this.qb = qb
+        }
+
+        //上面没法用java类似的静态方法返回条件,运行期还是报错没有适配的构造函数
+
+        //注意这里如果定义成闭包,不能用this做流式写法,参考https://groovy-lang.org/closures.html#closure-owner
+        //但是用了owner,返回的类型是Object,还得做转换,所以这里直接用java的写法
+
+        ESConditionBuilder byIdOrders(String[] idOrders) {
+            if (idOrders.length > 0) {
+                qb = qb.must(QueryBuilders.idsQuery(ESKeys.ES_ERP_PRINT_ORDER_TYPE).addIds(idOrders))
+            }
+            return this
+        }
+
+        ESConditionBuilder byIdOrders(List<Long> idOrders) {
+            if (!idOrders.isEmpty()) {
+                qb = qb.must(QueryBuilders.idsQuery(ESKeys.ES_ERP_PRINT_ORDER_TYPE).addIds(ERPUtils.longArrayToStrArray(ERPUtils.longListToArray(idOrders))))
+            }
+            return this
+        }
+
+        ESConditionBuilder byIdOrder(long idOrder) {
+            //这里不要判断idOrder是否大于0,防止条件漏了
+            qb = qb.must(QueryBuilders.idsQuery(ESKeys.ES_ERP_PRINT_ORDER_TYPE).addIds(String.valueOf(idOrder)))
+            return this
+        }
+
+        ESConditionBuilder byKeyWord() {
+            if (ERPUtils.mapContainKey(searchData, "keyWord")) {
+                String keyWord = searchData.getString("keyWord")
+                QueryBuilder qbKeyWord = QueryBuilders.boolQuery()
+                        .should(QueryBuilders.termQuery("orderCode", keyWord.toLowerCase()))
+                        .should(QueryBuilders.matchQuery("orderName", keyWord).operator(Operator.AND))
+                        .should(QueryBuilders.matchQuery("clientName", keyWord).operator(Operator.AND))
+                        .should(QueryBuilders.matchQuery("productName", keyWord).operator(Operator.AND))
+                        .should(QueryBuilders.matchQuery("createMan", keyWord).operator(Operator.AND))
+                        .should(QueryBuilders.matchQuery("orderRegion", keyWord).operator(Operator.AND))
+
+                qb = qb.must(qbKeyWord)
+            }
+            return this
+        }
+
+        ESConditionBuilder byOrderStates() {
+            if (ERPUtils.mapContainKey(searchData, "orderStates")) {
+                String orderStates = searchData.getString("orderStates")
+                qb = qb.must(QueryBuilders.termsQuery("orderState", orderStates.split(",")))
+            }
+            return this
+        }
+
+        ESConditionBuilder byOrderStates(String orderStates) {
+            qb = qb.must(QueryBuilders.termsQuery("orderState", orderStates.split(",")))
+            return this
+        }
+
+        ESConditionBuilder byOrderState(int orderState) {
+            qb = qb.must(QueryBuilders.termQuery("orderState", orderState))
+            return this
+        }
+
+        ESConditionBuilder byVoidFlag() {
+            if (ERPUtils.mapContainKey(searchData, "voidFlag")) {
+                int voidFlag = searchData.getInt("voidFlag")
+                if (voidFlag >= 0) {
+                    qb = qb.must(QueryBuilders.termQuery("voidFlag", voidFlag))
+                }
+            }
+            return this
+        }
+
+        ESConditionBuilder byVoidFlag(int voidFlag) {
+            if (voidFlag >= 0) {
+                qb = qb.must(QueryBuilders.termQuery("voidFlag", voidFlag))
+            }
+            return this
+        }
+
+        ESConditionBuilder byOrderCode() {
+            if (ERPUtils.mapContainKey(searchData, "orderCode")) {
+                String orderCode = searchData.getString("orderCode")
+                qb = qb.must(QueryBuilders.termQuery("orderCode", orderCode.toLowerCase()))
+            }
+            return this
+        }
+
+        ESConditionBuilder byOrderCode(String orderCode) {
+            qb = qb.must(QueryBuilders.termQuery("orderCode", orderCode.toLowerCase()))
+            return this
+        }
+
+        ESConditionBuilder byBeginTime_Create() {
+            if (ERPUtils.mapContainKey(searchData, "beginTime")) {
+                String beginTimeStr = searchData.getString("beginTime")
+                long beginTime
+                if (beginTimeStr.contains("-")) {
+                    beginTime = DateUtil.getStartOfDay(DateUtil.asDate(beginTimeStr, "yyyy-MM-dd")).getTime()
+                } else {
+                    beginTime = DateUtil.getStartOfDay(new Date(searchData.getLong("beginTime"))).getTime()
+                }
+                qb = qb.must(QueryBuilders.rangeQuery("createTimeLong").gte(beginTime))
+            }
+            return this
+        }
+
+        ESConditionBuilder byEndTime_Create() {
+            if (ERPUtils.mapContainKey(searchData, "endTime")) {
+                String endTimeStr = searchData.getString("endTime")
+                long endTime
+                if (endTimeStr.contains("-")) {
+                    endTime = DateUtil.getEndOfDay(DateUtil.asDate(endTimeStr, "yyyy-MM-dd")).getTime()
+                } else {
+                    endTime = DateUtil.getEndOfDay(new Date(searchData.getLong("endTime"))).getTime()
+                }
+                qb = qb.must(QueryBuilders.rangeQuery("createTimeLong").lte(endTime))
+            }
+            return this
+        }
+
+        ESConditionBuilder byClientName() {
+            if (ERPUtils.mapContainKey(searchData, "clientName")) {
+                String clientName = searchData.getString("clientName")
+                qb = qb.must(QueryBuilders.boolQuery()
+                        .should(QueryBuilders.matchQuery("clientName", clientName).analyzer("index_ansj").operator(Operator.AND))
+                        .should(QueryBuilders.termQuery("clientName.number", clientName.toLowerCase()))
+                        .should(QueryBuilders.matchQuery("clientName.letter", clientName.toLowerCase()).operator(Operator.AND)))
+            }
+            return this
+        }
+
+        ESConditionBuilder byIdClient() {
+            if (ERPUtils.mapContainKey(searchData, "idClient")) {
+                long idClient = searchData.getLong("idClient")
+                //这里不管是否大于0,都查询
+                qb = qb.must(QueryBuilders.termQuery("idClient", idClient))
+            }
+            return this
+        }
+
+        ESConditionBuilder byIdClient(long idClient) {
+            qb = qb.must(QueryBuilders.termQuery("idClient", idClient))
+            return this
+        }
+
+        ESConditionBuilder byOrderParentQuery(QueryBuilder qbParent) {
+            qb = qb.must(JoinQueryBuilders.hasParentQuery(ESKeys.ES_ERP_PRINT_ORDER_TYPE, qbParent, false))
+            return this
+        }
+
+        BoolQueryBuilder build() {
+            return qb
+        }
+    }
+
+}

+ 178 - 0
ddBusiness/src/main/java/com/dderp/business/service/flycat/OrderSearchServiceImpl.java

@@ -0,0 +1,178 @@
+package com.dderp.business.service.flycat;
+
+import com.dderp.common.api.flycat.OrderSearchService;
+import com.dderp.common.base.BaseService;
+import com.dderp.common.datas.ERPModule;
+import com.dderp.common.datas.ReadOrderOption;
+import com.dderp.common.entity.base.ProcessSearchOptionsItem;
+import com.dderp.common.entity.order.BusinessOrder;
+import com.dderp.common.entity.site.ERPTokenUser;
+import com.dderp.common.tool.ERPUtils;
+import com.sweetfish.service.Local;
+import com.sweetfish.service.RetResult;
+import com.sweetfish.source.PageFlipper;
+import com.sweetfish.util.AnyValue;
+import com.sweetfish.util.AutoLoad;
+import com.sweetfish.util.ObjectPool;
+import com.sweetfish.util.ResourceType;
+import org.rex.RMap;
+
+import java.util.List;
+
+/**
+ * 订单搜索服务
+ * 前端页面上调用搜索可以做到完全脚本化,因为它的查询总是返回json即可,查询功能也基本固定
+ * 但服务之间调用搜索就很麻烦做到这一点了,不能只调用callScript,原因如下
+ * 1、InvokeCallParams功能太单一,服务间调用条件太多,一个对象搞不定
+ * 2、InvokeCallResult在脚本中序列化后,还需要调用方反序列化,多了一步无效的json操作
+ * 3、服务之间调用返回值确实不一样,有的需要订单主表,有的需要订单带部件,有的只要部件,而且带不带子表无法固定,
+ * 所以为了兼顾上面说的几点,有一些硬编码必不可少
+ * 可以把订单所有的对象抽象为两类操作,一种为获取单个对象,一种为获取数组,这样只要结构不动的情况下,可以做到脚本化,而如果结构动,反正是要编译的
+ * 另外要少写一些固定的代码,条件全部用RMap传递,groovy里面初始化一个map对象还是很方便的
+ */
+@AutoLoad(false)
+@Local
+@ResourceType(OrderSearchService.class)
+public class OrderSearchServiceImpl extends BaseService implements OrderSearchService {
+
+    private final ObjectPool<RMap<String, Long>> idsMap = new ObjectPool<>(100,
+            () -> new RMap<>(),
+            null,
+            (t) -> {
+                t.clear();
+                return true;
+            });
+
+    @Override
+    public void init(AnyValue config) {
+        super.init(config);
+    }
+
+    @Override
+    public void destroy(AnyValue config) {
+        super.destroy(config);
+    }
+
+    /**
+     * 查询单个订单信息
+     * <br>在groovy里面使用可以按下面的方法调用
+     * <br>RetResult<PrintOrder> orderResult = orderSearchService.searchBusinessOrder(new RMap<>(ERPUtils.PARAM_SEARCH_ID: 100L), currentUser, dataSourceId, supplierCode)
+     * <br>或者在java里面封装一个
+     * <br> getBusinessOrder(long id)的方法,提供给其它服务调用,写法差不多,简化不了一行代码
+     *
+     * @param searchData   查询条件
+     * @param currentUser  操作人
+     * @param dataSourceId 分库
+     * @param supplierCode 分表
+     * @param options      子表读取规则
+     * @return 订单信息
+     */
+    @SuppressWarnings("rawtypes")
+    public RetResult<BusinessOrder> searchBusinessOrder(RMap searchData,
+                                                        ERPTokenUser currentUser,
+                                                        String dataSourceId,
+                                                        long supplierCode,
+                                                        ReadOrderOption[] options) {
+        return handleScript("ERP_BusinessOrder_Search", ERPModule.ERP_ORDER_SEARCH,
+                dataSourceId, supplierCode,
+                () -> ProcessSearchOptionsItem.<ReadOrderOption>newBuilder()
+                        .searchData(searchData)
+                        .options(options)
+                        .currentUser(currentUser)
+                        .dataSourceId(dataSourceId)
+                        .supplierCode(supplierCode)
+                        .build()
+        );
+    }
+
+    /**
+     * 获取单个订单信息
+     * 对searchBusinessOrder的简单封装
+     *
+     * @param idOrder      订单id
+     * @param currentUser  操作人
+     * @param dataSourceId 分库
+     * @param supplierCode 分表
+     * @param options      子表读取规则
+     * @return 订单信息
+     */
+    public RetResult<BusinessOrder> getBusinessOrder(long idOrder,
+                                                     ERPTokenUser currentUser,
+                                                     String dataSourceId,
+                                                     long supplierCode,
+                                                     ReadOrderOption[] options) {
+        RMap<String, Long> longRMap = idsMap.get();
+        try {
+            longRMap.put(ERPUtils.PARAM_SEARCH_ID, idOrder);
+            return searchBusinessOrder(longRMap, currentUser, dataSourceId, supplierCode, options);
+        } finally {
+            idsMap.accept(longRMap);
+        }
+    }
+
+    /**
+     * 多订单查询,无需分页参数,
+     * <br>在groovy里面使用可以按下面的方法调用,比如通过多id获取订单
+     * <br>RetResult<List<PrintOrder></PrintOrder>> orderResult = orderSearchService.searchPrintOrderList(new RMap<>(ERPUtils.PARAM_SEARCH_IDS: "1,2,3"), currentUser, dataSourceId, supplierCode)
+     * <br>或者在java里面封装一个
+     * <br> getPrintOrder(long id)的方法,提供给其它服务调用,写法差不多,简化不了一行代码
+     *
+     * @param searchData   查询条件
+     * @param currentUser  操作人
+     * @param dataSourceId 分库
+     * @param supplierCode 分表
+     * @param options      子表读取规则
+     * @return 订单列表
+     */
+    @SuppressWarnings("rawtypes")
+    public RetResult<List<BusinessOrder>> searchBusinessOrderList(RMap searchData,
+                                                                  ERPTokenUser currentUser,
+                                                                  String dataSourceId,
+                                                                  long supplierCode,
+                                                                  ReadOrderOption[] options) {
+        return handleScriptList("ERP_BusinessOrder_Search", ERPModule.ERP_ORDER_SEARCH,
+                dataSourceId, supplierCode,
+                () -> ProcessSearchOptionsItem.<ReadOrderOption>newBuilder()
+                        .searchData(searchData)
+                        .options(options)
+                        .currentUser(currentUser)
+                        .dataSourceId(dataSourceId)
+                        .supplierCode(supplierCode)
+                        .build()
+        );
+    }
+
+    /**
+     * 多订单分页查询
+     *
+     * @param searchData   查询条件
+     * @param currentUser  操作人
+     * @param orderBy      排序
+     * @param pageFlipper  分页
+     * @param dataSourceId 分库
+     * @param supplierCode 分表
+     * @param options      子表读取规则
+     * @return 订单列表
+     */
+    @SuppressWarnings("rawtypes")
+    public RetResult<List<BusinessOrder>> searchBusinessOrderList(RMap searchData,
+                                                                  ERPTokenUser currentUser,
+                                                                  String orderBy,
+                                                                  PageFlipper pageFlipper,
+                                                                  String dataSourceId,
+                                                                  long supplierCode,
+                                                                  ReadOrderOption[] options) {
+        return handleScriptList("ERP_BusinessOrder_Search", ERPModule.ERP_ORDER_SEARCH,
+                dataSourceId, supplierCode,
+                () -> ProcessSearchOptionsItem.<ReadOrderOption>newBuilder()
+                        .searchData(searchData)
+                        .pageFlipper(pageFlipper)
+                        .orderBy(orderBy)
+                        .options(options)
+                        .currentUser(currentUser)
+                        .dataSourceId(dataSourceId)
+                        .supplierCode(supplierCode)
+                        .build()
+        );
+    }
+}

+ 7 - 1
ddCommon/src/main/java/com/dderp/common/api/BusinessExecutor.java

@@ -30,7 +30,13 @@ public interface BusinessExecutor<S extends BaseEntity, R extends BaseEntity> {
         return "";
     }
 
-    default OperatorWait getAWait() {
+    /**
+     * 判断脚本执行阻塞方式,有时候同一脚本需要根据参数判断执行方式
+     *
+     * @param source 参数
+     * @return 阻塞方式
+     */
+    default OperatorWait getAWait(S source) {
         return OperatorWait.SYNC;
     }
 

+ 94 - 0
ddCommon/src/main/java/com/dderp/common/api/flycat/OrderSearchService.java

@@ -0,0 +1,94 @@
+package com.dderp.common.api.flycat;
+
+import com.dderp.common.api.ScriptService;
+import com.dderp.common.datas.ReadOrderOption;
+import com.dderp.common.entity.order.BusinessOrder;
+import com.dderp.common.entity.site.ERPTokenUser;
+import com.sweetfish.service.RetResult;
+import com.sweetfish.source.PageFlipper;
+import org.rex.RMap;
+
+import java.util.List;
+
+public interface OrderSearchService extends ScriptService {
+
+    /**
+     * 查询单个订单信息
+     * <br>在groovy里面使用可以按下面的方法调用
+     * <br>RetResult<PrintOrder> orderResult = orderSearchService.searchBusinessOrder(new RMap<>(ERPUtils.PARAM_SEARCH_ID: 100L), currentUser, dataSourceId, supplierCode)
+     * <br>或者在java里面封装一个
+     * <br> getBusinessOrder(long id)的方法,提供给其它服务调用,写法差不多,简化不了一行代码
+     *
+     * @param searchData   查询条件
+     * @param currentUser  操作人
+     * @param dataSourceId 分库
+     * @param supplierCode 分表
+     * @param options      子表读取规则
+     * @return 订单信息
+     */
+    @SuppressWarnings("rawtypes")
+    RetResult<BusinessOrder> searchBusinessOrder(RMap searchData,
+                                                 ERPTokenUser currentUser,
+                                                 String dataSourceId,
+                                                 long supplierCode,
+                                                 ReadOrderOption[] options);
+
+    /**
+     * 获取单个订单信息
+     * 对searchBusinessOrder的简单封装
+     *
+     * @param idOrder      订单id
+     * @param currentUser  操作人
+     * @param dataSourceId 分库
+     * @param supplierCode 分表
+     * @param options      子表读取规则
+     * @return 订单信息
+     */
+    RetResult<BusinessOrder> getBusinessOrder(long idOrder,
+                                              ERPTokenUser currentUser,
+                                              String dataSourceId,
+                                              long supplierCode,
+                                              ReadOrderOption[] options);
+
+    /**
+     * 多订单查询,无需分页参数,
+     * <br>在groovy里面使用可以按下面的方法调用,比如通过多id获取订单
+     * <br>RetResult<List<BusinessOrder></BusinessOrder>> orderResult = orderSearchService.searchBusinessOrderList(new RMap<>(ERPUtils.PARAM_SEARCH_IDS: "1,2,3"), currentUser, dataSourceId, supplierCode)
+     * <br>或者在java里面封装一个
+     * <br> getPrintOrder(long id)的方法,提供给其它服务调用,写法差不多,简化不了一行代码
+     *
+     * @param searchData   查询条件
+     * @param currentUser  操作人
+     * @param dataSourceId 分库
+     * @param supplierCode 分表
+     * @param options      子表读取规则
+     * @return 订单列表
+     */
+    @SuppressWarnings("rawtypes")
+    RetResult<List<BusinessOrder>> searchBusinessOrderList(RMap searchData,
+                                                           ERPTokenUser currentUser,
+                                                           String dataSourceId,
+                                                           long supplierCode,
+                                                           ReadOrderOption[] options);
+
+    /**
+     * 多订单分页查询
+     *
+     * @param searchData   查询条件
+     * @param currentUser  操作人
+     * @param orderBy      排序
+     * @param pageFlipper  分页
+     * @param dataSourceId 分库
+     * @param supplierCode 分表
+     * @param options      子表读取规则
+     * @return 订单列表
+     */
+    @SuppressWarnings("rawtypes")
+    RetResult<List<BusinessOrder>> searchBusinessOrderList(RMap searchData,
+                                                           ERPTokenUser currentUser,
+                                                           String orderBy,
+                                                           PageFlipper pageFlipper,
+                                                           String dataSourceId,
+                                                           long supplierCode,
+                                                           ReadOrderOption[] options);
+}

+ 1 - 1
ddCommon/src/main/java/com/dderp/common/base/BaseService.java

@@ -632,7 +632,7 @@ public abstract class BaseService extends AbstractService {
                     }
 
                     //执行execute方法
-                    OperatorWait aWait = businessExecutor.getAWait();
+                    OperatorWait aWait = businessExecutor.getAWait(source);
                     if (aWait == OperatorWait.SYNC) {
                         try {
                             RetResult<InvokeCallResult> scriptResult = businessExecutor.execute(beforeResult.getResult());

+ 15 - 0
ddCommon/src/main/java/com/dderp/common/datas/ReadOrderOption.java

@@ -0,0 +1,15 @@
+package com.dderp.common.datas;
+
+public enum ReadOrderOption {
+
+    //订单商品明细
+    ORDER_PRODUCT,
+
+    //订单收货信息
+    ORDER_DELIVERY,
+
+    //订单配送信息
+    ORDER_RIDER,
+
+    ORDER_TOTAL
+}

+ 0 - 6
ddCommon/src/main/java/com/dderp/common/datas/ReadPrintOrderOption.java

@@ -1,6 +0,0 @@
-package com.dderp.common.datas;
-
-public enum ReadPrintOrderOption {
-
-    ORDER_TOTAL
-}

+ 155 - 0
ddCommon/src/main/java/com/dderp/common/entity/order/OrderRiderItem.java

@@ -0,0 +1,155 @@
+package com.dderp.common.entity.order;
+
+import com.dderp.common.entity.base.BaseEntity;
+import com.sweetfish.util.Comment;
+import org.rex.db.RColumn;
+
+/**
+ * 订单配送明细
+ */
+public class OrderRiderItem extends BaseEntity {
+
+    @Comment("")
+    @RColumn("id")
+    private long id;
+
+    @Comment("")
+    @RColumn("idorder")
+    private long idOrder;
+
+    @Comment("配送状态")
+    @RColumn("riderstatus")
+    private int riderStatus;
+
+    @Comment("状态说明")
+    @RColumn("statusdesc")
+    private String statusDesc;
+
+    @Comment("配送平台")
+    @RColumn("idplatform")
+    private long idPlatform;
+
+    @Comment("配送平台")
+    @RColumn("platformcode")
+    private String platformCode;
+
+    @Comment("配送平台")
+    @RColumn("platformname")
+    private String platformName;
+
+    @Comment("配送平台订单id")
+    @RColumn("platformorderid")
+    private String platformOrderId;
+
+    @Comment("配送员名称")
+    @RColumn("operatorname")
+    private String operatorName;
+
+    @Comment("配送员电话")
+    @RColumn("operatorphone")
+    private String operatorPhone;
+
+    @Comment("配送员位置经度")
+    @RColumn("riderlng")
+    private String riderLng;
+
+    @Comment("配送员位置纬度")
+    @RColumn("riderlat")
+    private String riderLat;
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public long getIdOrder() {
+        return idOrder;
+    }
+
+    public void setIdOrder(long idOrder) {
+        this.idOrder = idOrder;
+    }
+
+    public int getRiderStatus() {
+        return riderStatus;
+    }
+
+    public void setRiderStatus(int riderStatus) {
+        this.riderStatus = riderStatus;
+    }
+
+    public String getStatusDesc() {
+        return statusDesc;
+    }
+
+    public void setStatusDesc(String statusDesc) {
+        this.statusDesc = statusDesc;
+    }
+
+    public long getIdPlatform() {
+        return idPlatform;
+    }
+
+    public void setIdPlatform(long idPlatform) {
+        this.idPlatform = idPlatform;
+    }
+
+    public String getPlatformCode() {
+        return platformCode;
+    }
+
+    public void setPlatformCode(String platformCode) {
+        this.platformCode = platformCode;
+    }
+
+    public String getPlatformName() {
+        return platformName;
+    }
+
+    public void setPlatformName(String platformName) {
+        this.platformName = platformName;
+    }
+
+    public String getPlatformOrderId() {
+        return platformOrderId;
+    }
+
+    public void setPlatformOrderId(String platformOrderId) {
+        this.platformOrderId = platformOrderId;
+    }
+
+    public String getOperatorName() {
+        return operatorName;
+    }
+
+    public void setOperatorName(String operatorName) {
+        this.operatorName = operatorName;
+    }
+
+    public String getOperatorPhone() {
+        return operatorPhone;
+    }
+
+    public void setOperatorPhone(String operatorPhone) {
+        this.operatorPhone = operatorPhone;
+    }
+
+    public String getRiderLng() {
+        return riderLng;
+    }
+
+    public void setRiderLng(String riderLng) {
+        this.riderLng = riderLng;
+    }
+
+    public String getRiderLat() {
+        return riderLat;
+    }
+
+    public void setRiderLat(String riderLat) {
+        this.riderLat = riderLat;
+    }
+}