Przeglądaj źródła

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	ddCommon/src/main/java/com/dderp/common/api/flycat/OrderSearchService.java
jlutt@163.com 2 lat temu
rodzic
commit
2a9468822e

+ 3 - 0
conf/esTemplate/orderaftersalebill.json

@@ -63,6 +63,9 @@
           }
         }
       },
+      "idRefundRequest": {
+        "type": "long"
+      },
       "applySource": {
         "type": "text",
         "index": "not_analyzed"

+ 38 - 0
conf/esTemplate/orderrefundrequest.json

@@ -54,6 +54,14 @@
       "refundType": {
         "type": "integer"
       },
+      "refuseToRefundReasonCodes": {
+        "type": "text",
+        "index": "not_analyzed"
+      },
+      "refuseToRefundMemo": {
+        "type": "text",
+        "index": "not_analyzed"
+      },
       "deliveryFee": {
         "type": "integer"
       },
@@ -71,6 +79,36 @@
         "type": "text",
         "index": "not_analyzed"
       },
+      "orderName": {
+        "type": "text",
+        "analyzer": "index_ansj",
+        "search_analyzer": "query_ansj",
+        "fields": {
+          "raw": {
+            "type": "keyword"
+          },
+          "number": {
+            "type": "text",
+            "index": "analyzed",
+            "analyzer": "number_analyzer"
+          },
+          "letter": {
+            "type": "text",
+            "index": "analyzed",
+            "analyzer": "letter_analyzer"
+          }
+        }
+      },
+      "orderCode": {
+        "type": "text",
+        "index": "analyzed",
+        "analyzer": "codefull_analyzer",
+        "fields": {
+          "raw": {
+            "type": "keyword"
+          }
+        }
+      },
       "createBy": {
         "type": "long"
       },

+ 1 - 1
conf/script/1000/orderApi/BE_Order_AcceptOrder_DYLK.groovy

@@ -105,7 +105,7 @@ class BE_Order_AcceptOrder_DYLK implements BusinessExecutor<InvokeCallParams, In
         if (storePlatform == null) return RetResult.<InvokeCallResult> errorT().retinfo("订单来源平台未知!")
 
         RMap searchParams = new RMap();
-        searchParams.set("incomePlatformId", platformStoreId)
+        searchParams.set("incomePlatformId", storePlatform.id)
         searchParams.set("incomePlatformOrderCode", incomePlatformOrderCode)
 
         RetResult<List<BusinessOrder>> orderResult = orderSearchService.searchBusinessOrderList(searchParams, currentUser, dataSourceId, supplierCode, null)

+ 163 - 0
conf/script/1000/orderApi/BE_Order_CompleteOrder_DYLK.groovy

@@ -0,0 +1,163 @@
+import com.dderp.business.dao.OrderDao
+import com.dderp.common.api.BusinessExecutor
+import com.dderp.common.api.StoreService
+import com.dderp.common.api.SupplierInitService
+import com.dderp.common.api.flycat.DouyinService
+import com.dderp.common.api.flycat.OrderSearchService
+import com.dderp.common.api.flycat.OrderService
+import com.dderp.common.api.flycat.OrderStepService
+import com.dderp.common.datas.ERPModule
+import com.dderp.common.datas.ESKeys
+import com.dderp.common.datas.flycat.BusinessOrderStatus
+import com.dderp.common.datas.flycat.PlatformType
+import com.dderp.common.entity.base.InvokeCallParams
+import com.dderp.common.entity.base.InvokeCallResult
+import com.dderp.common.entity.order.BusinessOrder
+import com.dderp.common.entity.order.OrderStep
+import com.dderp.common.entity.site.ERPTokenUser
+import com.dderp.common.entity.store.StorePlatform
+import com.dySweetFishPlugin.elasticsearch.ESClient
+import com.dySweetFishPlugin.sql.TableIdService
+import com.dySweetFishPlugin.sql.dao.TunaService
+import com.sweetfish.convert.json.JsonConvert
+import com.sweetfish.service.RetResult
+import groovy.json.JsonSlurper
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.Logger
+import org.elasticsearch.action.bulk.BulkRequestBuilder
+import org.elasticsearch.action.bulk.BulkResponse
+import org.elasticsearch.action.index.IndexRequestBuilder
+import org.elasticsearch.action.support.WriteRequest
+import org.elasticsearch.action.update.UpdateRequestBuilder
+import org.elasticsearch.common.xcontent.XContentType
+import org.rex.RMap
+
+import javax.annotation.Resource
+import java.time.LocalDateTime
+import java.time.ZoneOffset
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder
+
+@SuppressWarnings("unused")
+class BE_Order_CompleteOrder_DYLK implements BusinessExecutor<InvokeCallParams, InvokeCallResult> {
+
+    private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
+
+    @Resource
+    private JsonConvert jsonConvert
+
+    @Resource
+    private TableIdService tableIdService
+
+    @Resource
+    private StoreService storeService
+
+    @Resource
+    private ESClient esClient
+
+    @Resource
+    private SupplierInitService supplierInitService
+
+    @Resource
+    private OrderStepService orderStepService
+
+    @Resource
+    private OrderService orderService
+
+    @Resource
+    private OrderSearchService orderSearchService
+
+    @Resource
+    private DouyinService douyinService
+
+    @Resource
+    private TunaService tunaService
+
+    private OrderDao orderDao
+
+    @Override
+    String scriptName() {
+        return "[抖音来客]订单完成"
+    }
+
+    @Override
+    ERPModule module() {
+        return ERPModule.ORDER_API
+    }
+
+    @Override
+    RetResult<InvokeCallParams> beforeExecute(InvokeCallParams source) {
+        return super.beforeExecute(source)
+    }
+
+    RetResult<InvokeCallResult> execute(InvokeCallParams source) {
+        //秒级时间戳,groovy里面不让用system
+        long currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8))
+        String dataSourceId = source.dataSourceId
+        long supplierCode = source.supplierCode
+        ERPTokenUser currentUser = source.currentUser
+
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+        String incomePlatformOrderCode = invokeOrder["OrderId"] as String
+        String platformStoreId = invokeOrder["PoiId"] as String
+
+        StorePlatform storePlatform = storeService.getStorePlatformByInvokeInfo(platformStoreId, "DYLK", PlatformType.order.value, supplierCode)
+        if (storePlatform == null) return RetResult.<InvokeCallResult> errorT().retinfo("订单来源平台未知!")
+
+        RMap searchParams = new RMap();
+        searchParams.set("incomePlatformId", storePlatform.id)
+        searchParams.set("incomePlatformOrderCode", incomePlatformOrderCode)
+
+        RetResult<List<BusinessOrder>> orderResult = orderSearchService.searchBusinessOrderList(searchParams, currentUser, dataSourceId, supplierCode, null)
+        if (!orderResult.isSuccess()) return RetResult.<InvokeCallResult> errorT().retinfo(orderResult.retinfo)
+
+        BusinessOrder esOrder = orderResult.result.get(0) //这么查只可能有一个
+        esOrder.setOrderStatus(BusinessOrderStatus.orderComplete.value)
+        BusinessOrder.update(esOrder, currentUser.id)
+
+        OrderStep orderStep = orderStepService.parseOrderStep(esOrder.id, "[" + storePlatform.platformName + "]订单已完成", storePlatform.platformCode, currentUser)
+
+
+        //持久化
+        //订单主表
+        BulkRequestBuilder bulkRequest = esClient.getClient().prepareBulk().setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
+
+        UpdateRequestBuilder orderRequest = esClient.getClient().prepareUpdate(
+                supplierInitService.getDateYearESIndex(supplierCode, ESKeys.ES_DELIVER_BUSINESS_ORDER_INDEX, 0),
+                ESKeys.ES_DELIVER_BUSINESS_ORDER_TYPE,
+                String.valueOf(esOrder.getId()))
+                .setDoc(jsonBuilder()
+                        .startObject()
+                        .field("orderStatus", esOrder.orderStatus)
+                        .field("updateBy", esOrder.getUpdateBy())
+                        .field("updateTimeLong", esOrder.getUpdateTimeLong())
+                        .endObject())
+        bulkRequest.add(orderRequest)
+        //订单脚印
+        IndexRequestBuilder orderStepRequest = esClient.getClient()
+                .prepareIndex(supplierInitService.getDateYearESIndex(supplierCode, ESKeys.ES_DELIVER_ORDER_STEP_INDEX, 0),
+                        ESKeys.ES_DELIVER_ORDER_STEP_TYPE)
+                .setId(String.valueOf(orderStep.id))
+                .setSource(jsonConvert.convertTo(orderStep), XContentType.JSON)
+        bulkRequest.add(orderStepRequest)
+
+
+        BulkResponse bulkResponse = bulkRequest.get();
+        orderDao = tunaService.generate(OrderDao.class)
+        if (bulkResponse.hasFailures()) {
+            logger.error("订单完成出错:" + bulkResponse.buildFailureMessage());
+            return RetResult.<InvokeCallResult> errorT().retinfo("订单完成出错:" + esOrder.orderName);
+        } else {
+            logger.info("订单完成成功");
+            //写数据库
+            orderDao.acceptBusinessOrder(esOrder,
+                    [orderStep],
+                    dataSourceId,
+                    String.valueOf(supplierCode))
+
+            return RetResult.<InvokeCallResult> successT().result(InvokeCallResult.success().data(jsonConvert.convertTo(esOrder)))
+        }
+
+    }
+}

+ 6 - 15
conf/script/1000/orderApi/BE_Order_ProcessRefundRequest.groovy

@@ -26,7 +26,7 @@ import java.time.LocalDateTime
 import java.time.ZoneOffset
 
 @SuppressWarnings("unused")
-class BE_Order_ProcessRefundRequest implements BusinessExecutor<InvokeCallParams, InvokeCallResult> {
+class BE_Order_CookingDone_Request implements BusinessExecutor<InvokeCallParams, InvokeCallResult> {
 
     private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
 
@@ -64,7 +64,7 @@ class BE_Order_ProcessRefundRequest implements BusinessExecutor<InvokeCallParams
 
     @Override
     String scriptName() {
-        return "商户同意/拒绝退款请求"
+        return "商家出餐完成"
     }
 
     @Override
@@ -76,16 +76,7 @@ class BE_Order_ProcessRefundRequest implements BusinessExecutor<InvokeCallParams
     RetResult<InvokeCallParams> beforeExecute(InvokeCallParams source) {
         return super.beforeExecute(source)
     }
-
-    /*
-    params : {
-        "idRefundRequest" : 2 ,                         客户退款申请id
-        "approve" : 0 ,                                 拒绝0同意1
-        "rejectReasonCode" : "101,102,103" ,            拒绝原因代码
-        "rejectMemo" : "拒绝原因备注"                     拒绝原因备注
-    }
-    */
-
+    //params:{idOrder:xxx}
     RetResult<InvokeCallResult> execute(InvokeCallParams source) {
         //秒级时间戳,groovy里面不让用system
         long currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8))
@@ -112,14 +103,14 @@ class BE_Order_ProcessRefundRequest implements BusinessExecutor<InvokeCallParams
                         order_id:
                                 esOrder.incomePlatformOrderCode
                 ]
-                String responseStr = douyinService.postInvoker("/goodlife/v1/trade/buy/merchant_confirm_order/", jsonConvert.convertTo(postBody))
+                String responseStr = douyinService.postInvoker("/goodlife/v1/hermes/preparation/complete/confirm/", jsonConvert.convertTo(postBody))
                 def response = jsonSlurper.parseText(responseStr)
                 if (response["data"]["error_code"] as Integer == 0) {
                     return RetResult.<InvokeCallResult> successT()
                 } else {
                     //todo 抖音侧调用失败,怎么处理?
-                    logger.error("[抖音来客]商户接单平台接口调用失败:" + response["data"]["description"] as String)
-                    return RetResult.<InvokeCallResult> errorT().retinfo("[抖音来客]商户接单平台接口调用失败:" + response["data"]["description"] as String)
+                    logger.error("[抖音来客]商户出餐完成平台接口调用失败:" + response["data"]["description"] as String)
+                    return RetResult.<InvokeCallResult> errorT().retinfo("[抖音来客]商户出餐完成平台接口调用失败:" + response["data"]["description"] as String)
                 }
             }
         }

+ 218 - 0
conf/script/1000/orderApi/BE_Order_ProcessRefund_DYLK.groovy

@@ -0,0 +1,218 @@
+import com.dderp.business.dao.OrderDao
+import com.dderp.common.api.BusinessExecutor
+import com.dderp.common.api.StoreService
+import com.dderp.common.api.SupplierInitService
+import com.dderp.common.api.flycat.DouyinService
+import com.dderp.common.api.flycat.OrderSearchService
+import com.dderp.common.api.flycat.OrderService
+import com.dderp.common.api.flycat.OrderStepService
+import com.dderp.common.datas.ERPModule
+import com.dderp.common.datas.ESKeys
+import com.dderp.common.datas.flycat.PlatformType
+import com.dderp.common.datas.flycat.RefundRequestStatus
+import com.dderp.common.entity.base.InvokeCallParams
+import com.dderp.common.entity.base.InvokeCallResult
+import com.dderp.common.entity.order.BusinessOrder
+import com.dderp.common.entity.order.OrderAfterSaleBill
+import com.dderp.common.entity.order.OrderRefundRequest
+import com.dderp.common.entity.order.OrderStep
+import com.dderp.common.entity.site.ERPTokenUser
+import com.dderp.common.entity.store.StorePlatform
+import com.dderp.common.tool.ERPUtils
+import com.dySweetFishPlugin.elasticsearch.ESClient
+import com.dySweetFishPlugin.sql.TableIdService
+import com.dySweetFishPlugin.sql.dao.TunaService
+import com.sweetfish.convert.json.JsonConvert
+import com.sweetfish.service.RetResult
+import groovy.json.JsonSlurper
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.Logger
+import org.elasticsearch.action.bulk.BulkRequestBuilder
+import org.elasticsearch.action.bulk.BulkResponse
+import org.elasticsearch.action.index.IndexRequestBuilder
+import org.elasticsearch.action.support.WriteRequest
+import org.elasticsearch.action.update.UpdateRequestBuilder
+import org.elasticsearch.common.xcontent.XContentType
+import org.rex.RMap
+
+import javax.annotation.Resource
+import java.time.LocalDateTime
+import java.time.ZoneOffset
+
+import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder
+
+@SuppressWarnings("unused")
+class BE_Order_ProcessRefund_DYLK implements BusinessExecutor<InvokeCallParams, InvokeCallResult> {
+
+    private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
+
+    @Resource
+    private JsonConvert jsonConvert
+
+    @Resource
+    private TableIdService tableIdService
+
+    @Resource
+    private StoreService storeService
+
+    @Resource
+    private ESClient esClient
+
+    @Resource
+    private SupplierInitService supplierInitService
+
+    @Resource
+    private OrderStepService orderStepService
+
+    @Resource
+    private OrderService orderService
+
+    @Resource
+    private OrderSearchService orderSearchService
+
+    @Resource
+    private DouyinService douyinService
+
+    @Resource
+    private TunaService tunaService
+
+    private OrderDao orderDao
+
+    @Override
+    String scriptName() {
+        return "商户同意/拒绝退款请求"
+    }
+
+    @Override
+    ERPModule module() {
+        return ERPModule.ORDER_API
+    }
+
+    @Override
+    RetResult<InvokeCallParams> beforeExecute(InvokeCallParams source) {
+        return super.beforeExecute(source)
+    }
+
+    /*
+    params : {
+        "idRefundRequest" : 2 ,                         客户退款申请id
+        "approve" : 0 ,                                 拒绝0同意1
+        "rejectReasonCode" : "[101,102,103]" ,          拒绝原因代码,注意这个括号不能少必须是数组形式
+        "rejectMemo" : "拒绝原因备注"                     拒绝原因备注
+    }
+    */
+
+    RetResult<InvokeCallResult> execute(InvokeCallParams source) {
+        //秒级时间戳,groovy里面不让用system
+        long currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8))
+        String dataSourceId = source.dataSourceId
+        long supplierCode = source.supplierCode
+        ERPTokenUser currentUser = source.currentUser
+
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+        String incomePlatformOrderCode = invokeOrder["order_id"] as String
+        String platformStoreId = invokeOrder["poi_id"] as String
+        String outAfterSaleId = invokeOrder["after_sale_id"] as String
+        boolean pass = invokeOrder["pass"] as boolean
+
+//        StorePlatform storePlatform = storeService.getStorePlatformByInvokeInfo(platformStoreId, "DYLK", PlatformType.order.value, supplierCode)
+//        if (storePlatform == null) return RetResult.<InvokeCallResult> errorT().retinfo("订单来源平台未知!")
+//
+//        RMap searchParams = new RMap();
+//        searchParams.set("incomePlatformId", platformStoreId)
+//        searchParams.set("incomePlatformOrderCode", incomePlatformOrderCode)
+//
+//        RetResult<List<BusinessOrder>> orderResult = orderSearchService.searchBusinessOrderList(searchParams, currentUser, dataSourceId, supplierCode, null)
+//        if (!orderResult.isSuccess()) return RetResult.<InvokeCallResult> errorT().retinfo(orderResult.retinfo)
+//
+//        BusinessOrder esOrder = orderResult.result.get(0) //这么查只可能有一个
+
+        RMap searchParams = new RMap()
+        searchParams.set("outAfterSaleId", outAfterSaleId)
+        RetResult<List<OrderRefundRequest>> requestRetResult = orderSearchService.searchOrderRefundRequestList(searchParams,
+                currentUser, dataSourceId, supplierCode, null)
+        if (!requestRetResult.isSuccess()) return RetResult.<InvokeCallResult> errorT().retinfo(requestRetResult.retinfo)
+
+        OrderRefundRequest refundRequest = requestRetResult.result.get(0) //这么查只可能有一个
+
+        OrderAfterSaleBill afterSaleBill
+        if (!pass) {
+            //拒绝退款
+            def codeList = (invokeOrder["refuse_audit_reasons"] as ArrayList).collect { it["code"] as int }
+            def msgList = (invokeOrder["refuse_audit_reasons"] as ArrayList).collect { it["msg"] as String }
+
+            refundRequest.setRequestStatus(RefundRequestStatus.refuse.value)
+            refundRequest.setRefuseToRefundReasonCodes(jsonConvert.convertTo(codeList))
+            refundRequest.setRefuseToRefundMemo(jsonConvert.convertTo(msgList))
+            OrderRefundRequest.update(refundRequest, currentUser.id)
+        } else {
+            //同意退款
+            refundRequest.setRequestStatus(RefundRequestStatus.agree.value)
+            OrderRefundRequest.update(refundRequest, currentUser.id)
+
+            afterSaleBill = OrderAfterSaleBill.buildFromRefundRequest(refundRequest)
+            afterSaleBill.setId(tableIdService.getTableIdMulti("deOrderAfterSaleBill.id", 1, dataSourceId, String.valueOf(supplierCode)))
+            afterSaleBill.setBillCode(tableIdService.getTableCodeMulti("deOrderAfterSaleBill.code", dataSourceId, String.valueOf(supplierCode)))
+            OrderAfterSaleBill.create(afterSaleBill, currentUser.id)
+        }
+
+        OrderStep orderStep = orderStepService.parseOrderStep(refundRequest.idOrder, "[" + refundRequest.platformName + "]商家已" +
+                pass ? "同意" : "拒绝" + "退款", pass ? "" : refundRequest.refuseToRefundMemo, currentUser)
+
+        //持久化
+        //订单退款申请
+        BulkRequestBuilder bulkRequest = esClient.getClient().prepareBulk().setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE)
+
+        UpdateRequestBuilder refundQueryRequest = esClient.getClient().prepareUpdate(
+                supplierInitService.getDateYearESIndex(supplierCode, ESKeys.ES_DELIVER_ORDER_REFUND_REQUEST_INDEX, 0),
+                ESKeys.ES_DELIVER_ORDER_REFUND_REQUEST_TYPE,
+                String.valueOf(refundRequest.getId()))
+                .setDoc(jsonBuilder()
+                        .startObject()
+                        .field("requestStatus", refundRequest.requestStatus)
+                        .field("updateBy", refundRequest.getUpdateBy())
+                        .field("updateTimeLong", refundRequest.getUpdateTimeLong())
+                        .endObject())
+        bulkRequest.add(refundQueryRequest)
+
+        //订单售后单,只有同意退款才写
+        if (afterSaleBill) {
+            IndexRequestBuilder afterSaleRequest = esClient.getClient()
+                    .prepareIndex(supplierInitService.getDateYearESIndex(supplierCode, ESKeys.ES_DELIVER_BUSINESS_ORDER_INDEX, 0),
+                            ESKeys.ES_DELIVER_ORDER_AFTER_SALE_BILL_TYPE)
+                    .setId(String.valueOf(afterSaleBill.id))
+                    .setParent(String.valueOf(afterSaleBill.idOrder))
+                    .setSource(jsonConvert.convertTo(afterSaleBill), XContentType.JSON)
+            bulkRequest.add(afterSaleRequest)
+        }
+
+        //订单脚印
+        IndexRequestBuilder orderStepRequest = esClient.getClient()
+                .prepareIndex(supplierInitService.getDateYearESIndex(supplierCode, ESKeys.ES_DELIVER_ORDER_STEP_INDEX, 0),
+                        ESKeys.ES_DELIVER_ORDER_STEP_TYPE)
+                .setId(String.valueOf(orderStep.id))
+                .setSource(jsonConvert.convertTo(orderStep), XContentType.JSON)
+        bulkRequest.add(orderStepRequest)
+
+
+        BulkResponse bulkResponse = bulkRequest.get();
+        orderDao = tunaService.generate(OrderDao.class)
+        if (bulkResponse.hasFailures()) {
+            logger.error("商户已同意/拒绝退款出错:" + bulkResponse.buildFailureMessage());
+            return RetResult.<InvokeCallResult> errorT().retinfo("商户已同意/拒绝退款出错:" + refundRequest.orderName);
+        } else {
+            logger.info("商户已同意/拒绝退款成功");
+            //写数据库
+            List<OrderAfterSaleBill> afterSaleBillList = new ArrayList<>()
+            if (afterSaleBill) afterSaleBillList.add(afterSaleBill)
+            orderDao.processRefundOrder(refundRequest,
+                    afterSaleBillList,
+                    [orderStep],
+                    dataSourceId,
+                    String.valueOf(supplierCode))
+
+            return RetResult.<InvokeCallResult> successT()
+        }
+    }
+}

+ 175 - 0
conf/script/1000/orderApi/BE_Order_ProcessRefund_Request.groovy

@@ -0,0 +1,175 @@
+import com.dderp.business.dao.OrderDao
+import com.dderp.common.api.BusinessExecutor
+import com.dderp.common.api.StoreService
+import com.dderp.common.api.SupplierInitService
+import com.dderp.common.api.flycat.DouyinService
+import com.dderp.common.api.flycat.OrderSearchService
+import com.dderp.common.api.flycat.OrderService
+import com.dderp.common.api.flycat.OrderStepService
+import com.dderp.common.datas.ERPModule
+import com.dderp.common.datas.flycat.RefundRequestStatus
+import com.dderp.common.entity.base.InvokeCallParams
+import com.dderp.common.entity.base.InvokeCallResult
+import com.dderp.common.entity.order.BusinessOrder
+import com.dderp.common.entity.order.OrderAfterSaleBill
+import com.dderp.common.entity.order.OrderRefundRequest
+import com.dderp.common.entity.site.ERPTokenUser
+import com.dderp.common.entity.store.StorePlatform
+import com.dderp.common.tool.ERPUtils
+import com.dySweetFishPlugin.elasticsearch.ESClient
+import com.dySweetFishPlugin.sql.TableIdService
+import com.dySweetFishPlugin.sql.dao.TunaService
+import com.sweetfish.convert.json.JsonConvert
+import com.sweetfish.service.RetResult
+import groovy.json.JsonSlurper
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.Logger
+import org.rex.RMap
+
+import javax.annotation.Resource
+import java.time.LocalDateTime
+import java.time.ZoneOffset
+
+@SuppressWarnings("unused")
+class BE_Order_ProcessRefund_Request implements BusinessExecutor<InvokeCallParams, InvokeCallResult> {
+
+    private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
+
+    @Resource
+    private JsonConvert jsonConvert
+
+    @Resource
+    private TableIdService tableIdService
+
+    @Resource
+    private StoreService storeService
+
+    @Resource
+    private ESClient esClient
+
+    @Resource
+    private SupplierInitService supplierInitService
+
+    @Resource
+    private OrderStepService orderStepService
+
+    @Resource
+    private OrderService orderService
+
+    @Resource
+    private OrderSearchService orderSearchService
+
+    @Resource
+    private DouyinService douyinService
+
+    @Resource
+    private TunaService tunaService
+
+    private OrderDao orderDao
+
+    @Override
+    String scriptName() {
+        return "商户同意/拒绝退款请求"
+    }
+
+    @Override
+    ERPModule module() {
+        return ERPModule.ORDER_API
+    }
+
+    @Override
+    RetResult<InvokeCallParams> beforeExecute(InvokeCallParams source) {
+        return super.beforeExecute(source)
+    }
+
+    /*
+    params : {
+        "idRefundRequest" : 2 ,                         客户退款申请id
+        "approve" : 0 ,                                 拒绝0同意1
+        "rejectReasonCode" : "[101,102,103]" ,          拒绝原因代码,注意这个括号不能少必须是数组形式
+        "rejectMemo" : "拒绝原因备注"                     拒绝原因备注
+    }
+    */
+
+    RetResult<InvokeCallResult> execute(InvokeCallParams source) {
+        //秒级时间戳,groovy里面不让用system
+        long currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8))
+        String dataSourceId = source.dataSourceId
+        long supplierCode = source.supplierCode
+        ERPTokenUser currentUser = source.currentUser
+
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+        long idRefundRequest = invokeOrder["idRefundRequest"] as Long
+        int approve = invokeOrder["approve"] as int
+        String rejectReasonCode = invokeOrder["rejectReasonCode"] as String
+        String rejectMemo = invokeOrder["rejectMemo"] as String
+
+        RetResult<OrderRefundRequest> requestRetResult = orderSearchService.searchOrderRefundRequest(new RMap<>(ERPUtils.PARAM_SEARCH_ID: idRefundRequest),
+                currentUser, dataSourceId, supplierCode, null)
+        if (!requestRetResult.isSuccess()) return RetResult.<InvokeCallResult> errorT().retinfo(requestRetResult.retinfo)
+
+        if (!(approve in [0, 1])) return RetResult.<InvokeCallResult> errorT().retinfo("传入状态非法")
+
+        OrderRefundRequest refundRequest = requestRetResult.result
+
+        /* 这部分还是在推送中完成
+        OrderAfterSaleBill afterSaleBill
+        def postBody
+        if (approve == 0) {
+            //拒绝退款
+            refundRequest.setRequestStatus(RefundRequestStatus.refuse.value)
+            refundRequest.setRefuseToRefundReasonCodes(rejectReasonCode)
+            refundRequest.setRefuseToRefundMemo(rejectMemo)
+            OrderRefundRequest.update(refundRequest, currentUser.id)
+
+            postBody = [
+                    after_sale_id: refundRequest.outAfterSaleId,
+                    is_approved  : false,
+                    reject_reason: [
+                            reason_code: rejectReasonCode,
+                            desc       : rejectMemo
+                    ]
+            ]
+        } else if (approve == 1) {
+            //同意退款
+            afterSaleBill = OrderAfterSaleBill.buildFromRefundRequest(refundRequest)
+            afterSaleBill.setId(tableIdService.getTableIdMulti("deOrderAfterSaleBill.id", 1, dataSourceId, String.valueOf(supplierCode)))
+            afterSaleBill.setBillCode(tableIdService.getTableCodeMulti("deOrderAfterSaleBill.code", dataSourceId, String.valueOf(supplierCode)))
+            OrderAfterSaleBill.create(afterSaleBill, currentUser.id)
+        }
+
+         */
+
+        //根据订单来源平台,回调平台的接单接口
+        switch (refundRequest.platformCode) {
+            case "DYLK": {
+                //抖音来客
+                def postBody = [
+                        after_sale_id: refundRequest.outAfterSaleId,
+                        is_approved  : approve == 1,
+                        reject_reason: {
+                            if (approve == 0) {
+                                [
+                                        reason_code: rejectReasonCode,
+                                        desc       : rejectMemo
+                                ]
+                            }
+                        }
+                ]
+
+                String responseStr = douyinService.postInvoker("/goodlife/v1/after_sale/audit/notify/", jsonConvert.convertTo(postBody))
+                def response = jsonSlurper.parseText(responseStr)
+                if (response["extra"]["error_code"] as Integer == 0) {
+                    return RetResult.<InvokeCallResult> successT()
+                } else {
+                    //todo 抖音侧调用失败,怎么处理?
+                    logger.error("[抖音来客]商户接单平台接口调用失败:" + response["extra"]["description"] as String)
+                    return RetResult.<InvokeCallResult> errorT().retinfo("[抖音来客]商户接单平台接口调用失败:" + response["extra"]["description"] as String)
+                }
+            }
+        }
+
+        return RetResult.<InvokeCallResult> errorT().retinfo("订单来源平台未知!")
+    }
+}

+ 477 - 0
conf/script/1000/orderSearch/BE_ERP_OrderRefundRequest_Search.groovy

@@ -0,0 +1,477 @@
+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.OrderRefundRequest
+import com.dderp.common.tool.ERPUtils
+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
+
+@SuppressWarnings(["rawtypes"])
+class BE_ERP_OrderRefundRequest_Search implements BusinessExecutor<ProcessSearchOptionsItem<ReadOrderOption>, OrderRefundRequest> {
+
+    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 readOrderOptions(List<OrderRefundRequest> requestList, String dataSourceId, long supplierCode,
+                         ReadOrderOption... options) {
+        long[] idOrders = requestList*.id.toArray() as long[]
+
+        if ((options != null) && (options.length > 0) && (idOrders.length > 0)) {
+            //防止搞坏事,options传重复数据过来,先去重
+            options.toUnique().each { opt ->
+                switch (opt) {
+
+                }
+            }
+        }
+    }
+
+    def readOrderOptions(OrderRefundRequest refundRequest, 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)
+                .byRequestStatus()
+                .byKeyWord()
+                .byRequestStatus()
+                .byOrderCode()
+                .byBeginTime_Create()
+                .byEndTime_Create()
+                .byIdOrder()
+                .byIdStore()
+                .byIdStorePlatform()
+                .byPlatformCode()
+                .byPlatformType()
+                .byOutAfterSaleId()
+                .build()
+
+
+        //合计金额,所以主表从orderMoney中开始
+
+        SearchResponse searchResponse = esClient.getClient()
+                .prepareSearch(supplierService.getDateYearESIndex(supplierCode, ESKeys.ES_DELIVER_BUSINESS_ORDER_INDEX, 1))
+                .setQuery(bqb)
+                .addAggregation(AggregationBuilders.count("sub_count").field("id"))
+                .addAggregation(AggregationBuilders.sum("deliveryFee_Sum").field("deliveryFee"))
+                .addAggregation(AggregationBuilders.sum("refundFee_Sum").field("refundFee"))
+                .addAggregation(AggregationBuilders.sum("refundProdCount_Sum").field("refundProdCount"))
+                .execute().actionGet()
+
+        ValueCount requestCountSum = searchResponse.getAggregations().get("sub_count")
+        InternalSum deliveryFeeSum = searchResponse.getAggregations().get("deliveryFee_Sum")
+        InternalSum refundFeeSum = searchResponse.getAggregations().get("refundFee_Sum")
+        InternalSum refundProdCountSum = searchResponse.getAggregations().get("refundProdCount_Sum")
+
+        RMap<String, Number> collectionData = new RMap<>()
+        collectionData.put("requestCountSum", requestCountSum.getValue())
+        collectionData.put("deliveryFeeSum", BigDecimal.valueOf(deliveryFeeSum.getValue()).setScale(2, RoundingMode.HALF_UP))
+        collectionData.put("refundFeeSum", BigDecimal.valueOf(refundFeeSum.getValue()).setScale(2, RoundingMode.HALF_UP))
+        collectionData.put("refundProdCountSum", BigDecimal.valueOf(refundProdCountSum.getValue()).setScale(2, RoundingMode.HALF_UP))
+
+        return collectionData
+
+    }
+
+    private RetResult<List<OrderRefundRequest>> 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<OrderRefundRequest> orderList = ESList.<OrderRefundRequest> getESList()
+                .esClient(esClient)
+                .jsonConvert(jsonConvert)
+                .clazz(OrderRefundRequest.class)
+                .queryBuilder({
+                    return search(source.searchData)
+                            .byRequestStatus()
+                            .byKeyWord()
+                            .byRequestStatus()
+                            .byOrderCode()
+                            .byBeginTime_Create()
+                            .byEndTime_Create()
+                            .byIdOrder()
+                            .byIdStore()
+                            .byIdStorePlatform()
+                            .byPlatformCode()
+                            .byPlatformType()
+                            .byOutAfterSaleId()
+                            .build()
+                })
+                .index(supplierService.getDateYearESIndex(source.supplierCode, ESKeys.ES_DELIVER_ORDER_REFUND_REQUEST_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<OrderRefundRequest>> successT().result(orderList).page(source.pageFlipper).attachRMap(collectionData)
+
+
+    }
+
+    private RetResult<List<OrderRefundRequest>> queryByIds(ProcessSearchOptionsItem<ReadOrderOption> source) {
+        if (!ERPUtils.mapContainKey(source.searchData, ERPUtils.PARAM_SEARCH_IDS)) {
+            return RetResult.<List<OrderRefundRequest>> 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<OrderRefundRequest> orderList = new ArrayList<>()
+
+        idOrderArrayList.each { l ->
+            List<OrderRefundRequest> subOrderList = ESList.<OrderRefundRequest> getESList()
+                    .esClient(esClient)
+                    .jsonConvert(jsonConvert)
+                    .clazz(OrderRefundRequest.class)
+                    .queryBuilder({
+                        return search(source.searchData)
+                                .byIds(l.toArray(String[]::new))
+                                .build()
+                    })
+                    .index(supplierService.getDateYearESIndex(source.supplierCode, ESKeys.ES_DELIVER_ORDER_REFUND_REQUEST_INDEX, 1))
+                    .executeNonePage()
+            readOrderOptions(subOrderList, source.dataSourceId, source.supplierCode, source.options)
+            if (!subOrderList.isEmpty()) {
+                orderList.addAll(subOrderList)
+            }
+        }
+        return RetResult.<List<OrderRefundRequest>> successT().result(orderList)
+    }
+
+    private RetResult<OrderRefundRequest> queryById(ProcessSearchOptionsItem<ReadOrderOption> source) {
+        if (!ERPUtils.mapContainKey(source.searchData, ERPUtils.PARAM_SEARCH_ID)) {
+            return RetResult.<OrderRefundRequest> errorT().retinfo("无效的id参数")
+        }
+
+        long idOrder = source.searchData.getLong(ERPUtils.PARAM_SEARCH_ID)
+
+        OrderRefundRequest businessOrder = ESOne.<OrderRefundRequest> getESOneInfo()
+                .esClient(esClient)
+                .jsonConvert(jsonConvert)
+                .clazz(OrderRefundRequest.class)
+                .queryBuilder({
+                    //获取完成的数据情况
+                    ESConditionBuilder qb = search(null).byId(idOrder)
+                    //这里还需要判断数据权限
+                    return qb.build()
+                })
+                .index(supplierService.getDateYearESIndex(source.supplierCode, ESKeys.ES_DELIVER_ORDER_REFUND_REQUEST_INDEX, 1))
+                .execute()
+
+        if (businessOrder == null) {
+            return RetResult.<OrderRefundRequest> errorT().retinfo("无效的订单")
+        }
+
+        readOrderOptions(businessOrder, source.dataSourceId, source.supplierCode, source.options)
+
+        return RetResult.<OrderRefundRequest> successT().result(businessOrder)
+    }
+
+    private RetResult<OrderRefundRequest> queryByCode(ProcessSearchOptionsItem<ReadOrderOption> source) {
+        if (!ERPUtils.mapContainKey(source.searchData, ERPUtils.PARAM_SEARCH_CODE)) {
+            return RetResult.<OrderRefundRequest> errorT().retinfo("无效的id参数")
+        }
+
+        String orderCode = source.searchData.getString(ERPUtils.PARAM_SEARCH_CODE)
+
+        OrderRefundRequest businessOrder = ESOne.<OrderRefundRequest> getESOneInfo()
+                .esClient(esClient)
+                .jsonConvert(jsonConvert)
+                .clazz(OrderRefundRequest.class)
+                .queryBuilder({
+                    //获取完成的数据情况
+                    return search(null).byOrderCode(orderCode).build()
+                })
+                .index(supplierService.getDateYearESIndex(source.supplierCode, ESKeys.ES_DELIVER_ORDER_REFUND_REQUEST_INDEX, 1))
+                .execute()
+
+        if (businessOrder == null) {
+            return RetResult.<OrderRefundRequest> errorT().retinfo("无效的订单")
+        }
+
+        readOrderOptions(businessOrder, source.dataSourceId, source.supplierCode, source.options)
+
+        return RetResult.<OrderRefundRequest> successT().result(businessOrder)
+    }
+
+    @Override
+    RetResult<OrderRefundRequest> 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.<OrderRefundRequest> errorT().retinfo("无效的查询方式execute,查多数据应该使用executeList")
+    }
+
+    @Override
+    RetResult<List<OrderRefundRequest>> 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_DELIVER_ORDER_REFUND_REQUEST_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 byIds(String[] ids) {
+            if (ids.length > 0) {
+                qb = qb.must(QueryBuilders.idsQuery(ESKeys.ES_DELIVER_ORDER_REFUND_REQUEST_TYPE).addIds(ids))
+            }
+            return this
+        }
+
+        ESConditionBuilder byIds(List<Long> ids) {
+            if (!ids.isEmpty()) {
+                qb = qb.must(QueryBuilders.idsQuery(ESKeys.ES_DELIVER_ORDER_REFUND_REQUEST_TYPE).addIds(ERPUtils.longArrayToStrArray(ERPUtils.longListToArray(ids))))
+            }
+            return this
+        }
+
+        ESConditionBuilder byId(long id) {
+            //这里不要判断idOrder是否大于0,防止条件漏了
+            qb = qb.must(QueryBuilders.idsQuery(ESKeys.ES_DELIVER_ORDER_REFUND_REQUEST_TYPE).addIds(String.valueOf(id)))
+            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))
+
+                qb = qb.must(qbKeyWord)
+            }
+            return this
+        }
+
+        ESConditionBuilder byRequestStatus() {
+            if (ERPUtils.mapContainKey(searchData, "requestStatus")) {
+                String orderStates = searchData.getString("requestStatus")
+                qb = qb.must(QueryBuilders.termsQuery("requestStatus", orderStates.split(",")))
+            }
+            return this
+        }
+
+        ESConditionBuilder byRequestStatus(String requestStatus) {
+            qb = qb.must(QueryBuilders.termsQuery("requestStatus", requestStatus.split(",")))
+            return this
+        }
+
+        ESConditionBuilder byRequestStatus(int requestStatus) {
+            qb = qb.must(QueryBuilders.termQuery("requestStatus", requestStatus))
+            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 byIdOrder() {
+            if (ERPUtils.mapContainKey(searchData, "idOrder")) {
+                long idOrder = searchData.getLong("idOrder")
+                //这里不管是否大于0,都查询
+                qb = qb.must(QueryBuilders.termQuery("idOrder", idOrder))
+            }
+            return this
+        }
+
+        ESConditionBuilder byIdStore() {
+            if (ERPUtils.mapContainKey(searchData, "idStore")) {
+                long idStore = searchData.getLong("idStore")
+                //这里不管是否大于0,都查询
+                qb = qb.must(QueryBuilders.termQuery("idStore", idStore))
+            }
+            return this
+        }
+
+        ESConditionBuilder byIdStorePlatform() {
+            if (ERPUtils.mapContainKey(searchData, "idStorePlatform")) {
+                long idStorePlatform = searchData.getLong("idStorePlatform")
+                //这里不管是否大于0,都查询
+                qb = qb.must(QueryBuilders.termQuery("idStorePlatform", idStorePlatform))
+            }
+            return this
+        }
+
+        ESConditionBuilder byPlatformCode() {
+            if (ERPUtils.mapContainKey(searchData, "platformCode")) {
+                String platformCode = searchData.getString("platformCode")
+                qb = qb.must(QueryBuilders.termQuery("platformCode", platformCode.toLowerCase()))
+            }
+            return this
+        }
+
+        ESConditionBuilder byPlatformType() {
+            if (ERPUtils.mapContainKey(searchData, "platformType")) {
+                long platformType = searchData.getLong("platformType")
+                //这里不管是否大于0,都查询
+                qb = qb.must(QueryBuilders.termQuery("platformType", platformType))
+            }
+            return this
+        }
+
+        ESConditionBuilder byOutAfterSaleId() {
+            if (ERPUtils.mapContainKey(searchData, "outAfterSaleId")) {
+                String outAfterSaleId = searchData.getString("outAfterSaleId")
+                qb = qb.must(QueryBuilders.termQuery("outAfterSaleId", outAfterSaleId.toLowerCase()))
+            }
+            return this
+        }
+
+        BoolQueryBuilder build() {
+            return qb
+        }
+    }
+
+}

+ 11 - 0
conf/script/1000/storeApi/BE_Store_BindStorePlatform_Douyin.groovy

@@ -5,6 +5,7 @@ import com.dderp.common.api.PlatformService
 import com.dderp.common.api.StoreService
 import com.dderp.common.datas.ERPModule
 import com.dderp.common.datas.ESKeys
+import com.dderp.common.datas.flycat.PlatformType
 import com.dderp.common.entity.base.ProcessStringItem
 import com.dderp.common.entity.platform.PlatformInfo
 import com.dderp.common.entity.site.ERPTokenUser
@@ -84,6 +85,15 @@ class BE_Store_BindStorePlatform_Douyin implements BusinessExecutor<ProcessStrin
         PlatformInfo platformInfo = platformService.getPlatformInfoByCode("DYLK", true, supplierCode)
         if (platformInfo == null) return RetResult.<StorePlatform> errorT().retinfo("系统档案内未找到[抖音来客]平台")
 
+        //查询之前绑定过这个门店没有
+        StorePlatform esStorePlatform = storeService.getStorePlatformByInvokeInfo(invokeContent["poi_id"] as String,
+                "DYLK", PlatformType.order.value, supplierCode)
+
+        if (esStorePlatform != null) {
+            logger.error("[" + platformInfo.platformName + "]门店已绑定过[" + invokeContent["poi_id"] as String + "]");
+            return RetResult.<StorePlatform> errorT().retinfo("[" + platformInfo.platformName + "]门店已绑定过[" + invokeContent["poi_id"] as String + "]");
+        }
+
         StorePlatform storePlatform = new StorePlatform()
         storePlatform.setId(tableIdService.getTableIdMulti("tbStorePlatform.id", 1, dataSourceId, String.valueOf(supplierCode)))
         storePlatform.setIdStore(idStore)
@@ -109,6 +119,7 @@ class BE_Store_BindStorePlatform_Douyin implements BusinessExecutor<ProcessStrin
             }
         }
 
+
         BulkRequestBuilder bulkRequest = esClient.getClient().prepareBulk().setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
 
         bulkRequest.add(esClient.getClient().prepareIndex(

+ 35 - 10
conf/sqlroot/com/dderp/business/dao/OrderDao.dql

@@ -84,14 +84,39 @@ where id = #{id};
 -- [addOrderAfterSaleBill]
 insert into $table$ (id, idOrder, idStore, outPlatformStoreId,
 idStorePlatform, platformCode, platformType,
-platformName, outAfterSaleId, applySource,
-billCode, userRefundAmount, totalUserRefundAmount,
-prodCountAfterRefund, productsRemainDetail, productsRefundDetail, refundReasonCodes,
-createBy, createTime, createTimeLong,
-updateBy, updateTime, updateTimeLong ) values ( #{id}, #{idorder}, #{idstore}, #{outplatformstoreid},
+platformName, outAfterSaleId, idRefundRequest,
+refundReasonCodes, applySource, billCode,
+userRefundAmount, totalUserRefundAmount, prodCountAfterRefund,
+productsRemainDetail, productsRefundDetail, createBy,
+createTime, createTimeLong, updateBy,
+updateTime, updateTimeLong ) values ( #{id}, #{idorder}, #{idstore}, #{outplatformstoreid},
 #{idstoreplatform}, #{platformcode}, #{platformtype},
-#{platformname}, #{outaftersaleid}, #{applysource},
-#{billcode}, #{userrefundamount}, #{totaluserrefundamount},
-#{prodcountafterrefund}, #{productsremaindetail}, #{productsrefunddetail}, #{refundreasoncodes},
-#{createby}, #{createtime}, #{createtimelong},
-#{updateby}, #{updatetime}, #{updatetimelong} );
+#{platformname}, #{outaftersaleid}, #{idrefundrequest},
+#{refundreasoncodes}, #{applysource}, #{billcode},
+#{userrefundamount}, #{totaluserrefundamount}, #{prodcountafterrefund},
+#{productsremaindetail}, #{productsrefunddetail}, #{createby},
+#{createtime}, #{createtimelong}, #{updateby},
+#{updatetime}, #{updatetimelong} );
+
+-- [addOrderRefundRequest]
+insert into $table$ (id, idOrder, idStore, outPlatformStoreId,
+idStorePlatform, platformCode, platformType,
+platformName, outAfterSaleId, requestStatus,
+refundReasonCodes, userRefundMemo, refundType,
+refuseToRefundReasonCodes, refuseToRefundMemo, deliveryFee,
+refundFee, refundProdCount, refundProductsDetail,
+orderName, orderCode, createBy,
+createTime, createTimeLong, updateBy,
+updateTime, updateTimeLong ) values ( #{id}, #{idorder}, #{idstore}, #{outplatformstoreid},
+#{idstoreplatform}, #{platformcode}, #{platformtype},
+#{platformname}, #{outaftersaleid}, #{requeststatus},
+#{refundreasoncodes}, #{userrefundmemo}, #{refundtype},
+#{refusetorefundreasoncodes}, #{refusetorefundmemo}, #{deliveryfee},
+#{refundfee}, #{refundprodcount}, #{refundproductsdetail},
+#{ordername}, #{ordercode}, #{createby},
+#{createtime}, #{createtimelong}, #{updateby},
+#{updatetime}, #{updatetimelong} );
+
+-- [updateOrderRefundRequest]
+update $table$ set requestStatus = #{requeststatus}, updateBy = #{updateby},updateTime = #{updatetime},updateTimeLong = #{updatetimelong}
+where id = #{id};

+ 9 - 0
conf/初始化业务表.sql

@@ -394,6 +394,15 @@ ALTER TABLE `deorderrefundrequest1000_current`
 ALTER TABLE `deorderaftersalebill1000_current`
     ADD COLUMN `refundReasonCodes` varchar(100) NULL AFTER `billCode`;
 
+ALTER TABLE `deorderrefundrequest1000_current`
+    ADD COLUMN `orderName` varchar(200) NULL AFTER `refundProductsDetail`,
+    ADD COLUMN `orderCode` varchar(100) NULL AFTER `orderName`;
+
+ALTER TABLE `deorderrefundrequest1000_current`
+    ADD COLUMN `refuseToRefundReasonCodes` varchar(200) NULL AFTER `refundType`,
+    ADD COLUMN `refuseToRefundMemo` varchar(500) NULL AFTER `refuseToRefundReasonCodes`;
 
+ALTER TABLE `deorderaftersalebill1000_current`
+    ADD COLUMN `idRefundRequest` bigint(20) NULL AFTER `outAfterSaleId`;
 
 

+ 10 - 0
ddBusiness/src/main/java/com/dderp/business/dao/OrderDao.java

@@ -76,4 +76,14 @@ public interface OrderDao extends DaoRepository {
                            OrderRefundRequest refundRequest,
                            List<OrderStep> stepList,
                            @DatabaseShardingBy String dataSourceId, String tableKey);
+
+    @Sharding(databaseShardingStrategy = SupplierDataBaseShardingStrategy.class, tableShardingStrategy = OrderTableShardingStrategy.class)
+    @DAOMethod(operator = OperatorType.UPDATE, owait = OperatorWait.ASNYC)
+    @SqlId(clazz = OrderDao.class, sql = "updateOrderRefundRequest", table = "deOrderRefundRequest", tableParam = 5, params = {1}, sort = 1)
+    @SqlId(clazz = OrderDao.class, sql = "addOrderAfterSaleBill", table = "deOrderAfterSaleBill", tableParam = 5, params = {2}, sort = 2)
+    @SqlId(clazz = OrderDao.class, sql = "addOrderStep", table = "deOrderStep", tableParam = 5, params = {3}, sort = 3)
+    int processRefundOrder(OrderRefundRequest refundRequest,
+                           List<OrderAfterSaleBill> afterSaleBills, //这个地方用list是为了规避参数不能为null的情况
+                           List<OrderStep> stepList,
+                           @DatabaseShardingBy String dataSourceId, String tableKey);
 }

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

@@ -6,6 +6,7 @@ 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.order.OrderRefundRequest;
 import com.dderp.common.entity.site.ERPTokenUser;
 import com.dderp.common.tool.ERPUtils;
 import com.sweetfish.service.Local;
@@ -176,4 +177,49 @@ public class OrderSearchServiceImpl extends BaseService implements OrderSearchSe
                         .build()
         );
     }
+
+
+    @Override
+    public RetResult<OrderRefundRequest> searchOrderRefundRequest(RMap searchData, ERPTokenUser currentUser, String dataSourceId, long supplierCode, ReadOrderOption[] options) {
+        return handleScript("ERP_OrderRefundRequest_Search", ERPModule.ERP_ORDER_SEARCH,
+                dataSourceId, supplierCode,
+                () -> ProcessSearchOptionsItem.<ReadOrderOption>newBuilder()
+                        .searchData(searchData)
+                        .options(options)
+                        .currentUser(currentUser)
+                        .dataSourceId(dataSourceId)
+                        .supplierCode(supplierCode)
+                        .build()
+        );
+    }
+
+    @Override
+    public RetResult<List<OrderRefundRequest>> searchOrderRefundRequestList(RMap searchData, ERPTokenUser currentUser, String dataSourceId, long supplierCode, ReadOrderOption[] options) {
+        return handleScriptList("ERP_OrderRefundRequest_Search", ERPModule.ERP_ORDER_SEARCH,
+                dataSourceId, supplierCode,
+                () -> ProcessSearchOptionsItem.<ReadOrderOption>newBuilder()
+                        .searchData(searchData)
+                        .options(options)
+                        .currentUser(currentUser)
+                        .dataSourceId(dataSourceId)
+                        .supplierCode(supplierCode)
+                        .build()
+        );
+    }
+
+    @Override
+    public RetResult<List<OrderRefundRequest>> searchOrderRefundRequestList(RMap searchData, ERPTokenUser currentUser, String orderBy, PageFlipper pageFlipper, String dataSourceId, long supplierCode, ReadOrderOption[] options) {
+        return handleScriptList("ERP_OrderRefundRequest_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()
+        );
+    }
 }

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

@@ -3,6 +3,7 @@ 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.order.OrderRefundRequest;
 import com.dderp.common.entity.site.ERPTokenUser;
 import com.sweetfish.service.RetResult;
 import com.sweetfish.source.PageFlipper;
@@ -91,4 +92,68 @@ public interface OrderSearchService extends ScriptService {
                                                            String dataSourceId,
                                                            long supplierCode,
                                                            ReadOrderOption... options);
+
+    /**
+     * 查询单个订单信息
+     * <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<OrderRefundRequest> searchOrderRefundRequest(RMap searchData,
+                                                           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<OrderRefundRequest>> searchOrderRefundRequestList(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<OrderRefundRequest>> searchOrderRefundRequestList(RMap searchData,
+                                                           ERPTokenUser currentUser,
+                                                           String orderBy,
+                                                           PageFlipper pageFlipper,
+                                                           String dataSourceId,
+                                                           long supplierCode,
+                                                           ReadOrderOption[] options);
 }

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

@@ -14,5 +14,6 @@ public enum ReadOrderOption {
     //订单配送信息
     ORDER_RIDER,
 
+    //订单合计信息
     ORDER_TOTAL
 }

+ 4 - 0
ddCommon/src/main/java/com/dderp/common/datas/flycat/BusinessOrderStatus.java

@@ -43,6 +43,10 @@ public enum BusinessOrderStatus {
      */
     riderComplete("配送完成", 14),
 
+    /**
+     * 这个认为是来源平台的订单完成,并不代表本系统订单完成
+     * 后面还有结算流程等
+     */
     orderComplete("订单完成", 20);
 
     private String name;

+ 32 - 0
ddCommon/src/main/java/com/dderp/common/entity/order/OrderAfterSaleBill.java

@@ -47,6 +47,10 @@ public class OrderAfterSaleBill extends BaseEntity {
     @Comment("绑定的该平台系统中的售后单号")
     private String outAfterSaleId;
 
+    @Comment("退款请求id")
+    @RColumn("idrefundrequest")
+    private long idRefundRequest;
+
     @RColumn("refundreasoncodes")
     @Comment("退款原因代码list")
     private String refundReasonCodes;
@@ -226,5 +230,33 @@ public class OrderAfterSaleBill extends BaseEntity {
         this.billCode = billCode;
     }
 
+    public long getIdRefundRequest() {
+        return idRefundRequest;
+    }
 
+    public void setIdRefundRequest(long idRefundRequest) {
+        this.idRefundRequest = idRefundRequest;
+    }
+
+    public static OrderAfterSaleBill buildFromRefundRequest(OrderRefundRequest refundRequest) {
+        OrderAfterSaleBill afterSaleBill = new OrderAfterSaleBill();
+        afterSaleBill.setIdRefundRequest(refundRequest.getId());
+        afterSaleBill.setIdOrder(refundRequest.getIdOrder());
+        afterSaleBill.setIdStore(refundRequest.getIdStore());
+        afterSaleBill.setOutPlatformStoreId(refundRequest.getOutPlatformStoreId());
+        afterSaleBill.setIdStorePlatform(refundRequest.getIdStorePlatform());
+        afterSaleBill.setPlatformCode(refundRequest.getPlatformCode());
+        afterSaleBill.setPlatformType(refundRequest.getPlatformType());
+        afterSaleBill.setPlatformName(refundRequest.getPlatformName());
+        afterSaleBill.setOutAfterSaleId(refundRequest.getOutAfterSaleId());
+        afterSaleBill.setRefundReasonCodes(refundRequest.getRefundReasonCodes());
+        afterSaleBill.setApplySource("USER"); //退款申请目前都是用户发起的,所以写死USER
+        afterSaleBill.setFullRefunded(true); //退款申请目前只支持整单退款,所以金额是整单金额
+        afterSaleBill.setUserRefundAmount(refundRequest.getRefundFee());
+        afterSaleBill.setTotalUserRefundAmount(refundRequest.getRefundFee());
+        afterSaleBill.setProdCountAfterRefund(0);
+        afterSaleBill.setProductsRemainDetail("");
+        afterSaleBill.setProductsRefundDetail(refundRequest.getRefundProductsDetail());
+        return afterSaleBill;
+    }
 }

+ 49 - 0
ddCommon/src/main/java/com/dderp/common/entity/order/OrderRefundRequest.java

@@ -63,6 +63,15 @@ public class OrderRefundRequest extends BaseEntity {
     @RColumn("refundtype")
     private int refundType;
 
+
+    @Comment("如果拒绝退款,填写的拒绝理由codes")
+    @RColumn("refusetorefundreasoncodes")
+    private String refuseToRefundReasonCodes;
+
+    @Comment("如果拒绝退款,填写的拒绝理由备注")
+    @RColumn("refusetorefundmemo")
+    private String refuseToRefundMemo;
+
     @Comment("配送费用")
     @RColumn("deliveryfee")
     private int deliveryFee;
@@ -79,6 +88,14 @@ public class OrderRefundRequest extends BaseEntity {
     @RColumn("refundproductsdetail")
     private String refundProductsDetail;
 
+    @Comment("订单名称")
+    @RColumn("ordername")
+    private String orderName;
+
+    @Comment("订单编号")
+    @RColumn("ordercode")
+    private String orderCode;
+
 
     public long getId() {
         return id;
@@ -215,4 +232,36 @@ public class OrderRefundRequest extends BaseEntity {
     public void setRefundProductsDetail(String refundProductsDetail) {
         this.refundProductsDetail = refundProductsDetail;
     }
+
+    public String getOrderName() {
+        return orderName;
+    }
+
+    public void setOrderName(String orderName) {
+        this.orderName = orderName;
+    }
+
+    public String getOrderCode() {
+        return orderCode;
+    }
+
+    public void setOrderCode(String orderCode) {
+        this.orderCode = orderCode;
+    }
+
+    public String getRefuseToRefundReasonCodes() {
+        return refuseToRefundReasonCodes;
+    }
+
+    public void setRefuseToRefundReasonCodes(String refuseToRefundReasonCodes) {
+        this.refuseToRefundReasonCodes = refuseToRefundReasonCodes;
+    }
+
+    public String getRefuseToRefundMemo() {
+        return refuseToRefundMemo;
+    }
+
+    public void setRefuseToRefundMemo(String refuseToRefundMemo) {
+        this.refuseToRefundMemo = refuseToRefundMemo;
+    }
 }

+ 26 - 0
ddWebCore/src/main/java/com/dderp/webcore/servlet/OrderCallServlet.java

@@ -182,8 +182,34 @@ public class OrderCallServlet extends HttpServlet {
                 });
                 break;
             }
+            case "life_trade_refund_audit": {
+                //订单已同意/拒绝退款消息
+                CompletableFuture.runAsync(() -> {
+                    InvokeCallParams callParams = new InvokeCallParams();
+                    callParams.setBusinessMethod("Order_ProcessRefund_DYLK");
+                    callParams.setParams(callBody.getContent());
+                    RetResult<InvokeCallResult> result = orderService.callOrder(callParams, currentUser, dataSourceId, supplierCode);
+                    if (result.isSuccess())
+                        logger.info("[抖音来客]订单已同意/拒绝退款成功");
+                    else logger.error("[抖音来客]订单已同意/拒绝退款失败:" + result.getRetinfo());
+                });
+                break;
+            }
             case "life_trade_takeout_order_finish": {
                 //订单完成消息
+                CompletableFuture.runAsync(() -> {
+                    InvokeCallParams callParams = new InvokeCallParams();
+                    callParams.setBusinessMethod("Order_CompleteOrder_DYLK");
+                    callParams.setParams(callBody.getContent());
+                    RetResult<InvokeCallResult> result = orderService.callOrder(callParams, currentUser, dataSourceId, supplierCode);
+                    if (result.isSuccess())
+                        logger.info("[抖音来客]订单完成成功");
+                    else logger.error("[抖音来客]订单完成失败:" + result.getRetinfo());
+                });
+                break;
+            }
+            case "life_trade_part_refund_complete": {
+                //订单已部分退款消息
                 break;
             }
             case "life_trade_takeout_order_modify": {