Veronique %!s(int64=2) %!d(string=hai) anos
pai
achega
718068e7b7
Modificáronse 26 ficheiros con 726 adicións e 215 borrados
  1. 7 24
      conf/esTemplate/businessorder.json
  2. 2 1
      conf/esTemplate/platforminfo.json
  3. 2 1
      conf/esTemplate/platformrequire.json
  4. 2 0
      conf/platform.properties
  5. 3 0
      conf/rediskeys.properties
  6. 7 0
      conf/script/1000/orderApi/BE_Order_CreateOrder_Douyin.groovy
  7. 139 0
      conf/script/1000/storeApi/BE_Store_BindStorePlatform_Douyin.groovy
  8. 84 0
      conf/script/1000/storeApi/BE_Store_GenerateStoreAuthUrl_Douyin.groovy
  9. 2 2
      conf/sqlroot/com/dderp/business/dao/OrderDao.dql
  10. 4 1
      conf/初始化业务表.sql
  11. 18 0
      ddBusiness/src/main/java/com/dderp/business/service/PlatformServiceImpl.java
  12. 31 3
      ddBusiness/src/main/java/com/dderp/business/service/StoreServiceImpl.java
  13. 2 0
      ddBusiness/src/main/java/com/dderp/business/service/flycat/DouyinServiceImpl.java
  14. 2 0
      ddCommon/src/main/java/com/dderp/common/api/PlatformService.java
  15. 16 1
      ddCommon/src/main/java/com/dderp/common/api/StoreService.java
  16. 3 1
      ddCommon/src/main/java/com/dderp/common/api/flycat/DouyinService.java
  17. 6 1
      ddCommon/src/main/java/com/dderp/common/datas/BusinessOrderStatus.java
  18. 2 1
      ddCommon/src/main/java/com/dderp/common/datas/ERPModule.java
  19. 5 0
      ddCommon/src/main/java/com/dderp/common/datas/RedisKeys.java
  20. 46 0
      ddCommon/src/main/java/com/dderp/common/entity/invoke/douyin/DouyinCallBody.java
  21. 6 0
      ddCommon/src/main/java/com/dderp/common/entity/platform/PlatformInfo.java
  22. 1 0
      ddCommon/src/main/java/com/dderp/common/entity/store/ViewStoreInfo.java
  23. 36 0
      ddCommon/src/main/java/com/dderp/common/tool/DouyinTools.java
  24. 209 176
      ddCommon/src/main/java/com/dderp/common/tool/InvokeSignature.java
  25. 19 0
      ddWebCore/src/main/java/com/dderp/webcore/rest/StoreRest.java
  26. 72 3
      ddWebCore/src/main/java/com/dderp/webcore/servlet/OrderCallServlet.java

+ 7 - 24
conf/esTemplate/businessorder.json

@@ -26,21 +26,11 @@
       },
       "orderCode": {
         "type": "text",
-        "analyzer": "index_ansj",
-        "search_analyzer": "query_ansj",
+        "index": "analyzed",
+        "analyzer": "codefull_analyzer",
         "fields": {
           "raw": {
             "type": "keyword"
-          },
-          "number": {
-            "type": "text",
-            "index": "analyzed",
-            "analyzer": "number_analyzer"
-          },
-          "letter": {
-            "type": "text",
-            "index": "analyzed",
-            "analyzer": "letter_analyzer"
           }
         }
       },
@@ -56,21 +46,11 @@
       },
       "incomePlatformOrderCode": {
         "type": "text",
-        "analyzer": "index_ansj",
-        "search_analyzer": "query_ansj",
+        "index": "analyzed",
+        "analyzer": "codefull_analyzer",
         "fields": {
           "raw": {
             "type": "keyword"
-          },
-          "number": {
-            "type": "text",
-            "index": "analyzed",
-            "analyzer": "number_analyzer"
-          },
-          "letter": {
-            "type": "text",
-            "index": "analyzed",
-            "analyzer": "letter_analyzer"
           }
         }
       },
@@ -83,6 +63,9 @@
       "idStore": {
         "type": "long"
       },
+      "orderSequence": {
+        "type": "long"
+      },
       "storeName": {
         "type": "text",
         "analyzer": "index_ansj",

+ 2 - 1
conf/esTemplate/platforminfo.json

@@ -6,7 +6,8 @@
       },
       "platformCode": {
         "type": "text",
-        "analyzer": "index_ansj",
+        "index": "analyzed",
+        "analyzer": "codefull_analyzer",
         "fields": {
           "raw": {
             "type": "keyword"

+ 2 - 1
conf/esTemplate/platformrequire.json

@@ -26,7 +26,8 @@
       },
       "requireCode": {
         "type": "text",
-        "index": "not_analyzed",
+        "index": "analyzed",
+        "analyzer": "codefull_analyzer",
         "fields": {
           "raw": {
             "type": "keyword"

+ 2 - 0
conf/platform.properties

@@ -1,6 +1,8 @@
 #抖音来客
 #请求地址
 douyin.reqUrl=https://open.douyin.com
+#商户授权url地址
+douyin.storeBindUrl=https://auth.dylk.com/auth-isv
 #appId
 douyin.appId=awd61ulpox5tdzhe
 #appSecret

+ 3 - 0
conf/rediskeys.properties

@@ -125,6 +125,9 @@ redis.erp.working.order = dydeliver:erp:working:order
 redis.erp.working.express.sf.order = dydeliver:erp:working:express:sf:order
 redis.erp.working.express.sf.store = dydeliver:erp:working:express:sf:store
 
+#抖音推送消息msg_id
+redis.deliver.douyin.call.msgid = dydeliver:douyin:callmsgid
+
 
 
 

+ 7 - 0
conf/script/1000/orderApi/BE_Order_CreateOrder_Douyin.groovy

@@ -2,6 +2,7 @@ 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.OrderService
 import com.dderp.common.api.flycat.OrderStepService
 import com.dderp.common.datas.BusinessOrderStatus
 import com.dderp.common.datas.ERPModule
@@ -60,6 +61,9 @@ class BE_Order_CreateOrder_Douyin implements BusinessExecutor<ProcessStringItem,
     private OrderStepService orderStepService
 
     @Resource
+    private OrderService orderService
+
+    @Resource
     private TunaService tunaService
 
     private OrderDao orderDao
@@ -114,6 +118,9 @@ class BE_Order_CreateOrder_Douyin implements BusinessExecutor<ProcessStringItem,
                 invokeOrder["receiver_info"]["location_name"] + "-" +
                 invokeOrder["receiver_info"]["receiver_name"]
         businessOrder.setDeliverAddressAll(address)
+        //写入订单序号
+        long sequence = orderService.getOrderSequence(viewStoreInfo.storeInfo.id, storePlatform.idPlatformInfo, supplierCode)
+        businessOrder.setOrderSequence(sequence)
 
         //订单金额类信息
         OrderFinances orderFinances = new OrderFinances()

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

@@ -0,0 +1,139 @@
+import com.dderp.business.dao.StoreDao
+import com.dderp.common.api.BusinessExecutor
+import com.dderp.common.api.NoSqlKeysService
+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.entity.base.ProcessStringItem
+import com.dderp.common.entity.platform.PlatformInfo
+import com.dderp.common.entity.site.ERPTokenUser
+import com.dderp.common.entity.store.StorePlatform
+import com.dderp.common.entity.store.StorePlatformRequire
+import com.dderp.common.entity.store.ViewStoreInfo
+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.support.WriteRequest
+import org.elasticsearch.common.xcontent.XContentType
+
+import javax.annotation.Resource
+import java.time.LocalDateTime
+import java.time.ZoneOffset
+
+@SuppressWarnings("unused")
+class BE_Store_BindStorePlatform_Douyin implements BusinessExecutor<ProcessStringItem, StorePlatform> {
+
+    private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
+
+    @Resource
+    private JsonConvert jsonConvert
+
+    @Resource
+    private TableIdService tableIdService
+
+    @Resource
+    private StoreService storeService
+
+    @Resource
+    private PlatformService platformService
+
+    @Resource
+    private ESClient esClient
+
+    @Resource
+    private NoSqlKeysService keysService
+
+    @Resource
+    private TunaService tunaService
+
+    private StoreDao storeDao
+
+    @Override
+    String scriptName() {
+        return "抖音来客授权并绑定门店"
+    }
+
+    @Override
+    ERPModule module() {
+        return ERPModule.STORE_API
+    }
+
+
+    RetResult<StorePlatform> execute(ProcessStringItem 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 invokeContent = jsonSlurper.parseText(source.itemValue)
+
+        long idStore = invokeContent["out_shop_id"] as Long
+        ViewStoreInfo viewStoreInfo = storeService.getViewStoreInfo(idStore, supplierCode, false, false, false)
+        if (viewStoreInfo == null) return RetResult.<StorePlatform> errorT().retinfo("门店信息不存在")
+
+        PlatformInfo platformInfo = platformService.getPlatformInfoByCode("DYLK", supplierCode)
+        if (platformInfo == null) return RetResult.<StorePlatform> errorT().retinfo("系统档案内未找到[抖音来客]平台")
+
+        StorePlatform storePlatform = new StorePlatform()
+        storePlatform.setId(tableIdService.getTableIdMulti("tbStorePlatform.id", 1, dataSourceId, String.valueOf(supplierCode)))
+        storePlatform.setIdStore(idStore)
+        storePlatform.setIdPlatformInfo(platformInfo.id)
+        storePlatform.setPlatformName(platformInfo.platformName)
+        storePlatform.setPlatformCode(platformInfo.platformCode)
+        storePlatform.setPlatformType(platformInfo.platformType)
+        storePlatform.setEnableStatue(1)
+        StorePlatform.create(storePlatform, currentUser.id)
+
+        if (platformInfo.requireList.size() > 0) {
+            long requireId = tableIdService.getTableIdMulti("tbStorePlatformRequire.id", platformInfo.requireList.size(), dataSourceId, String.valueOf(supplierCode))
+            platformInfo.requireList.each { require ->
+                StorePlatformRequire storePlatformRequire = new StorePlatformRequire()
+                storePlatformRequire.setId(requireId)
+                storePlatformRequire.setIdStore(viewStoreInfo.storeInfo.id)
+                storePlatformRequire.setIdPlatformRequire(require.id)
+                storePlatformRequire.setIdStorePlatform(storePlatform.id)
+                storePlatformRequire.setPlatformRequireCode(require.requireCode)
+                storePlatformRequire.setPlatformRequireName(require.requireName)
+                StorePlatformRequire.create(storePlatformRequire, currentUser.id)
+            }
+        }
+
+        BulkRequestBuilder bulkRequest = esClient.getClient().prepareBulk().setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
+
+        bulkRequest.add(esClient.getClient().prepareIndex(
+                keysService.getESKey(ESKeys.ES_DELIVER_STORE_PLATFORM_INDEX, supplierCode), ESKeys.ES_DELIVER_STORE_PLATFORM_TYPE)
+                .setId(String.valueOf(storePlatform.getId()))
+                .setSource(jsonConvert.convertTo(storePlatform), XContentType.JSON));
+
+        storePlatform.getRequireList().forEach(x -> {
+            bulkRequest.add(esClient.getClient().prepareIndex(
+                    keysService.getESKey(ESKeys.ES_DELIVER_STORE_PLATFORM_INDEX, supplierCode), ESKeys.ES_DELIVER_STORE_PLATFORM_REQUIRE_TYPE)
+                    .setId(String.valueOf(x.getId()))
+                    .setParent(String.valueOf(storePlatform.getId()))
+                    .setSource(jsonConvert.convertTo(x), XContentType.JSON));
+        });
+
+        BulkResponse bulkResponse = bulkRequest.get();
+
+        if (bulkResponse.hasFailures()) {
+            logger.error("门店开通平台出错:" + bulkResponse.buildFailureMessage());
+            return RetResult.<StorePlatform> errorT().retinfo("门店开通平台出错:" + storePlatform.getPlatformName());
+        } else {
+            logger.info("门店开通平台成功");
+            //写数据库
+            storeDao = tunaService.generate(StoreDao.class)
+            storeDao.addStorePlatform(storePlatform, storePlatform.getRequireList(), dataSourceId, supplierCode);
+            return RetResult.successT();
+        }
+    }
+}

+ 84 - 0
conf/script/1000/storeApi/BE_Store_GenerateStoreAuthUrl_Douyin.groovy

@@ -0,0 +1,84 @@
+import com.dderp.common.api.BusinessExecutor
+import com.dderp.common.api.StoreService
+import com.dderp.common.datas.ERPModule
+import com.dderp.common.entity.base.ProcessIdItem
+import com.dderp.common.entity.base.ScriptStringResult
+import com.dderp.common.entity.store.ViewStoreInfo
+import com.dderp.common.tool.DouyinTools
+import com.dySweetFishPlugin.sql.dao.OperatorWait
+import com.sweetfish.service.RetResult
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.Logger
+
+import javax.annotation.Resource
+import java.time.LocalDateTime
+import java.time.ZoneOffset
+import java.util.stream.Collectors
+
+class BE_Store_GenerateStoreAuthUrl_Douyin implements BusinessExecutor<ProcessIdItem, ScriptStringResult> {
+
+    private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
+
+    @Resource(name = "property.douyin.appId")
+    String dyAppId
+
+    @Resource(name = "property.douyin.appSecret")
+    String dyAppSecret
+
+    @Resource(name = "property.douyin.storeBindUrl")
+    String dyStoreBindUrl
+
+    @Resource
+    private StoreService storeService
+
+    @Override
+    String scriptName() {
+        return "抖音来客店铺绑定地址"
+    }
+
+    @Override
+    ERPModule module() {
+        return ERPModule.STORE_API
+    }
+
+    @Override
+    OperatorWait getAWait(ProcessIdItem source) {
+        return OperatorWait.SYNC
+    }
+
+    @Override
+    RetResult<ProcessIdItem> checkExecute(ProcessIdItem source) {
+        //检查门店信息
+        ViewStoreInfo viewStoreInfo = storeService.getViewStoreInfo(source.id, source.supplierCode, false, false, false)
+        if (viewStoreInfo == null) return RetResult.<ProcessIdItem> errorT().retinfo("门店不存在")
+
+        if (viewStoreInfo.storeInfo.voidFlag == 1) return RetResult.<ProcessIdItem> errorT().retinfo("门店已被禁用,不支持该操作")
+
+        return RetResult.<ProcessIdItem> successT().result(source)
+    }
+
+    RetResult<ScriptStringResult> execute(ProcessIdItem source) {
+        long currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)) //秒数
+
+        Map<String, String> query = new HashMap<>();
+        query.put("client_key", dyAppId)
+        query.put("timestamp", String.valueOf(currentTime))
+        query.put("charset", "UTF-8")
+        query.put("solution_key", "5")
+        query.put("out_shop_id", String.valueOf(source.id))
+        query.put("permission_keys", String.join("1,2,4,5,6,7,8,10,11,15,16"));
+//        query.put("extra", dto.getExtra());
+
+        String signResult = DouyinTools.SignV2(dyAppSecret, "", query);
+        query.put("sign", signResult);
+
+        String queryStr = query.entrySet().stream()
+                .map(entry -> new StringBuilder().append(entry.getKey()).append("=").append(entry.getValue()))
+                .collect(Collectors.joining("&"));
+        StringBuilder resultSb = new StringBuilder(dyStoreBindUrl).append("?").append(queryStr);
+        ScriptStringResult result = new ScriptStringResult()
+        result.setResultStr(resultSb.toString())
+
+        return RetResult.<ScriptStringResult> successT().result(result)
+    }
+}

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

@@ -18,14 +18,14 @@ select * from $table$;
 insert into $table$ (id, orderName, orderCode, orderStatus,
 incomePlatformId, incomePlatformName, incomePlatformOrderCode,
 incomePlatformOrderTime, incomePlatformOrderTimeLong, suggestDeliverTime,
-suggestDeliverTimeLong, idStore, storeName,
+suggestDeliverTimeLong, orderSequence, idStore, storeName,
 deliverFee, deliverDistance, deliverAddressAll,
 outGoingPlatformId, outGoingPlatformName, voidFlag,
 createBy, createTime, createTimeLong,
 updateBy, updateTime, updateTimeLong ) values ( #{id}, #{ordername}, #{ordercode}, #{orderstatus},
 #{incomeplatformid}, #{incomeplatformname}, #{incomeplatformordercode},
 #{incomeplatformordertime}, #{incomeplatformordertimelong}, #{suggestdelivertime},
-#{suggestdelivertimelong}, #{idstore}, #{storename},
+#{suggestdelivertimelong}, #{ordersequence}, #{idstore}, #{storename},
 #{deliverfee}, #{deliverdistance}, #{deliveraddressall},
 #{outgoingplatformid}, #{outgoingplatformname}, #{voidflag},
 #{createby}, #{createtime}, #{createtimelong},

+ 4 - 1
conf/初始化业务表.sql

@@ -412,4 +412,7 @@ ALTER TABLE `tbstoreplatform1000`
     ADD COLUMN `platformStoreId` varchar(255) NULL AFTER `idStore`;
 
 ALTER TABLE `deorderdeliveryinfo1000_currnet`
-    ADD COLUMN `bookingDeliverTimeLong` bigint(20) NULL AFTER `bookingDeliverTime`;
+    ADD COLUMN `bookingDeliverTimeLong` bigint(20) NULL AFTER `bookingDeliverTime`;
+
+ALTER TABLE `debusinessorder1000_current`
+    ADD COLUMN `orderSequence` bigint(20) NULL AFTER `suggestDeliverTimeLong`;

+ 18 - 0
ddBusiness/src/main/java/com/dderp/business/service/PlatformServiceImpl.java

@@ -111,10 +111,25 @@ public class PlatformServiceImpl extends BaseService implements PlatformService
     }
 
     @Override
+    public PlatformInfo getPlatformInfoByCode(String platformCode, long supplierCode) {
+        return this.getESOneInfo(esClient, jsonConvert,
+                PlatformInfo.class,
+                (a) -> {
+                    return QueryBuilders.boolQuery().must(QueryBuilders.typeQuery(ESKeys.ES_DELIVER_PLATFORM_INFO_TYPE))
+                            .must(QueryBuilders.termQuery("platformCode.raw", platformCode));
+                },
+                keysService.getESKey(ESKeys.ES_DELIVER_PLATFORM_INFO_INDEX, supplierCode),
+                null);
+    }
+
+    @Override
     public RetResult<PlatformInfo> addPlatformInfo(PlatformInfo platformInfo, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
         if (StringUtils.isBlank(platformInfo.getPlatformName()))
             return RetResult.<PlatformInfo>errorT().retinfo("平台名称不可为空");
 
+        if (StringUtils.isBlank(platformInfo.getPlatformCode()))
+            return RetResult.<PlatformInfo>errorT().retinfo("平台编号不可为空");
+
         if (PlatformType.getName(platformInfo.getPlatformType()) == null)
             return RetResult.<PlatformInfo>errorT().retinfo("平台类型非法");
 
@@ -133,6 +148,9 @@ public class PlatformServiceImpl extends BaseService implements PlatformService
 
         if (esInfo != null) return RetResult.<PlatformInfo>errorT().retinfo("已存在同名的平台");
 
+        esInfo = this.getPlatformInfoByCode(platformInfo.getPlatformCode(), supplierCode);
+        if (esInfo != null) return RetResult.<PlatformInfo>errorT().retinfo("已存在同编号的平台");
+
         platformInfo.setId(tableIdService.getTableIdMulti("tbPlatformInfo.id", 1, dataSourceId, String.valueOf(supplierCode)));
         //前端传进来的是平台需求的list,由于获取平台信息的时候几乎必带需求信息而且一般不会很多,所以不做子表直接序列化进主表
         platformInfo.setRequireListSerial(jsonConvert.convertTo(platformInfo.getRequireList()));

+ 31 - 3
ddBusiness/src/main/java/com/dderp/business/service/StoreServiceImpl.java

@@ -5,7 +5,11 @@ import com.dderp.common.api.NoSqlKeysService;
 import com.dderp.common.api.SortBuilderExecutor;
 import com.dderp.common.api.StoreService;
 import com.dderp.common.base.BaseService;
+import com.dderp.common.datas.ERPModule;
 import com.dderp.common.datas.ESKeys;
+import com.dderp.common.entity.base.ProcessIdItem;
+import com.dderp.common.entity.base.ProcessStringItem;
+import com.dderp.common.entity.base.ScriptStringResult;
 import com.dderp.common.entity.site.ERPTokenUser;
 import com.dderp.common.entity.store.*;
 import com.dderp.common.tool.ERPUtils;
@@ -147,7 +151,7 @@ public class StoreServiceImpl extends BaseService implements StoreService {
     }
 
     @Override
-    public RetResult<StoreBrand> uploadBrandLogo(long idStoreBrand,String fileLink, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
+    public RetResult<StoreBrand> uploadBrandLogo(long idStoreBrand, String fileLink, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
         StoreBrand esInfo = this.getStoreBrand(idStoreBrand, supplierCode);
         if (esInfo == null)
             return RetResult.<StoreBrand>errorT().retinfo("未找到此门店品牌");
@@ -413,6 +417,30 @@ public class StoreServiceImpl extends BaseService implements StoreService {
     }
 
     @Override
+    public RetResult<ScriptStringResult> generateStoreAuthUrl_Douyin(long idStore, String dataSourceId, long supplierCode) {
+        return this.handleScript("Store_GenerateStoreAuthUrl_Douyin", ERPModule.STORE_API, dataSourceId, supplierCode,
+                () -> {
+                    return ProcessIdItem.newBuilder()
+                            .id(idStore)
+                            .dataSourceId(dataSourceId)
+                            .supplierCode(supplierCode)
+                            .build();
+                });
+    }
+
+    @Override
+    public RetResult<StorePlatform> bindStorePlatformDouyin(String requestContent, String dataSourceId, long supplierCode) {
+        return handleScript("Store_BindStorePlatformDouyin", ERPModule.STORE_API,
+                dataSourceId, supplierCode,
+                () -> ProcessStringItem.newBuilder()
+                        .itemValue(requestContent)
+                        .dataSourceId(dataSourceId)
+                        .supplierCode(supplierCode)
+                        .build()
+        );
+    }
+
+    @Override
     public StoreInvoiceInfo getStoreInvoiceInfo(long idStore, long supplierCode) {
         return this.getESOneInfo(esClient, jsonConvert,
                 StoreInvoiceInfo.class,
@@ -634,11 +662,11 @@ public class StoreServiceImpl extends BaseService implements StoreService {
         StorePlatform esInfo = this.getESOneInfo(esClient, jsonConvert,
                 StorePlatform.class,
                 (a) -> {
-                    BoolQueryBuilder qb = QueryBuilders.boolQuery().must(QueryBuilders.typeQuery(ESKeys.ES_DELIVER_STORE_PLATFORM_TYPE));
+                    BoolQueryBuilder qb = QueryBuilders.boolQuery().must(QueryBuilders.typeQuery(ESKeys.ES_DELIVER_PLATFORM_INFO_TYPE));
                     qb.must(QueryBuilders.termQuery("idPlatformInfo", storePlatform.getIdPlatformInfo()));
                     return qb;
                 },
-                keysService.getESKey(ESKeys.ES_DELIVER_STORE_PLATFORM_INDEX, supplierCode),
+                keysService.getESKey(ESKeys.ES_DELIVER_PLATFORM_INFO_INDEX, supplierCode),
                 null);
         if (esInfo != null)
             return RetResult.<StorePlatform>errorT().retinfo("此平台已开通:" + storePlatform.getPlatformName());

+ 2 - 0
ddBusiness/src/main/java/com/dderp/business/service/flycat/DouyinServiceImpl.java

@@ -8,6 +8,7 @@ import com.dderp.common.entity.base.ProcessStringItem;
 import com.dderp.common.entity.invoke.douyin.DouyinTokenRequest;
 import com.dderp.common.entity.invoke.douyin.DouyinTokenResponse;
 import com.dderp.common.entity.order.BusinessOrder;
+import com.dderp.common.entity.store.StorePlatform;
 import com.dderp.common.http.HttpTools;
 import com.dySweetFishPlugin.redis.RedisService;
 import com.dySweetFishPlugin.tool.lang.ThreadFactoryWithNamePrefix;
@@ -173,4 +174,5 @@ public class DouyinServiceImpl extends BaseService implements DouyinService {
                         .build()
         );
     }
+
 }

+ 2 - 0
ddCommon/src/main/java/com/dderp/common/api/PlatformService.java

@@ -17,6 +17,8 @@ public interface PlatformService extends ScriptService {
 
     PlatformInfo getPlatformInfo(long idPlatformInfo, long supplierCode);
 
+    PlatformInfo getPlatformInfoByCode(String platformCode, long supplierCode);
+
     RetResult<PlatformInfo> addPlatformInfo(PlatformInfo platformInfo, ERPTokenUser currentUser, String dataSourceId, long supplierCode);
 
     RetResult<PlatformInfo> updatePlatformInfo(PlatformInfo platformInfo, ERPTokenUser currentUser, String dataSourceId, long supplierCode);

+ 16 - 1
ddCommon/src/main/java/com/dderp/common/api/StoreService.java

@@ -1,5 +1,7 @@
 package com.dderp.common.api;
 
+import com.dderp.common.entity.base.ProcessStringItem;
+import com.dderp.common.entity.base.ScriptStringResult;
 import com.dderp.common.entity.site.ERPTokenUser;
 import com.dderp.common.entity.store.*;
 import com.sweetfish.service.RetResult;
@@ -18,7 +20,7 @@ public interface StoreService extends ScriptService {
 
     RetResult<StoreBrand> addStoreBrand(StoreBrand storeBrand, ERPTokenUser currentUser, String dataSourceId, long supplierCode);
 
-    RetResult<StoreBrand> uploadBrandLogo(long idStoreBrand,String fileLink, ERPTokenUser currentUser, String dataSourceId, long supplierCode);
+    RetResult<StoreBrand> uploadBrandLogo(long idStoreBrand, String fileLink, ERPTokenUser currentUser, String dataSourceId, long supplierCode);
 
     RetResult<StoreBrand> updateStoreBrand(StoreBrand storeBrand, ERPTokenUser currentUser, String dataSourceId, long supplierCode);
 
@@ -33,6 +35,19 @@ public interface StoreService extends ScriptService {
     RetResult<StoreInfo> addStoreInfo(StoreInfo storeInfo, ERPTokenUser currentUser, String dataSourceId, long supplierCode);
 
     /**
+     * 生成门店授权url_抖音来客
+     *
+     * @param idStore
+     * @param dataSourceId
+     * @param supplierCode
+     * @return
+     */
+    RetResult<ScriptStringResult> generateStoreAuthUrl_Douyin(long idStore, String dataSourceId, long supplierCode);
+
+
+    RetResult<StorePlatform> bindStorePlatformDouyin(String requestContent, String dataSourceId, long supplierCode);
+
+    /**
      * 获取门店开票信息
      */
     StoreInvoiceInfo getStoreInvoiceInfo(long idStore, long supplierCode);

+ 3 - 1
ddCommon/src/main/java/com/dderp/common/api/flycat/DouyinService.java

@@ -1,11 +1,13 @@
 package com.dderp.common.api.flycat;
 
 import com.dderp.common.entity.order.BusinessOrder;
+import com.dderp.common.entity.store.StorePlatform;
 import com.sweetfish.service.RetResult;
 import com.sweetfish.service.Service;
 
 public interface DouyinService extends Service {
-    RetResult<BusinessOrder> importOrderFromDouyin(String douyinRequestBody, String dataSourceId, long supplierCode);
+    RetResult<BusinessOrder> importOrderFromDouyin(String requestContent, String dataSourceId, long supplierCode);
+
 
 
 }

+ 6 - 1
ddCommon/src/main/java/com/dderp/common/datas/BusinessOrderStatus.java

@@ -9,11 +9,16 @@ package com.dderp.common.datas;
 public enum BusinessOrderStatus {
 
     /**
-     * 从平台生成订单,待配送
+     * 从平台生成订单,用户已付款
      */
     init("初始化", 0),
 
     /**
+     * 平台商户已接单
+     */
+    receive("商户接单",1),
+
+    /**
      * 选择了配送平台,下单,等待配送平台回调
      */
     delivery("配送平台下达", 10),

+ 2 - 1
ddCommon/src/main/java/com/dderp/common/datas/ERPModule.java

@@ -42,7 +42,8 @@ public enum ERPModule {
 
     EXPRESS_API(200, "expressApi", "配送平台接口", "", "expressApi"),
 
-    ORDER_API(300, "orderApi", "订单平台接口", "", "orderApi");
+    ORDER_API(300, "orderApi", "订单平台接口", "", "orderApi"),
+    STORE_API(400, "storeAPi", "平台门店接口", "", "storeApi");
 
 
     private int value;

+ 5 - 0
ddCommon/src/main/java/com/dderp/common/datas/RedisKeys.java

@@ -330,6 +330,11 @@ public class RedisKeys {
      */
     public static final String KEY_ORDER_SHOP_SEQUENCE = "redis.erp.order.shop.sequence";
 
+    /**
+     * 抖音推送消息msg_id,用于记录避免重复处理
+     */
+    public static final String KEY_DOUYIN_CALL_MSG_ID = "redis.deliver.douyin.call.msgid";
+
     private RedisKeys() {
     }
 }

+ 46 - 0
ddCommon/src/main/java/com/dderp/common/entity/invoke/douyin/DouyinCallBody.java

@@ -0,0 +1,46 @@
+package com.dderp.common.entity.invoke.douyin;
+
+/**
+ * 抖音推送消息体
+ */
+public class DouyinCallBody {
+    private String event;
+
+    private String client_key;
+
+    private String content;
+
+    private String log_id;
+
+    public String getEvent() {
+        return event;
+    }
+
+    public void setEvent(String event) {
+        this.event = event;
+    }
+
+    public String getClient_key() {
+        return client_key;
+    }
+
+    public void setClient_key(String client_key) {
+        this.client_key = client_key;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getLog_id() {
+        return log_id;
+    }
+
+    public void setLog_id(String log_id) {
+        this.log_id = log_id;
+    }
+}

+ 6 - 0
ddCommon/src/main/java/com/dderp/common/entity/platform/PlatformInfo.java

@@ -1,8 +1,10 @@
 package com.dderp.common.entity.platform;
 
+import com.alibaba.fastjson.JSON;
 import com.dderp.common.entity.base.BaseEntity;
 import com.dderp.common.tdoc.ApiPlace;
 import com.sweetfish.util.Comment;
+import org.apache.commons.lang3.StringUtils;
 import org.rex.db.RColumn;
 
 import java.util.ArrayList;
@@ -103,5 +105,9 @@ public class PlatformInfo extends BaseEntity {
 
     public void setRequireListSerial(String requireListSerial) {
         this.requireListSerial = requireListSerial;
+
+        if (StringUtils.isNotBlank(this.requireListSerial)) {
+            this.requireList = JSON.parseArray(this.requireListSerial, PlatformRequire.class);
+        }
     }
 }

+ 1 - 0
ddCommon/src/main/java/com/dderp/common/entity/store/ViewStoreInfo.java

@@ -23,6 +23,7 @@ public class ViewStoreInfo extends BaseEntity {
     }
 
     public ViewStoreInfo(StoreInfo storeInfo) {
+        if (storeInfo == null) return;
         this.storeInfo = storeInfo;
         if (storeInfo != null) {
             storeInfo.getPlatformList().forEach(storePlatform -> {

+ 36 - 0
ddCommon/src/main/java/com/dderp/common/tool/DouyinTools.java

@@ -0,0 +1,36 @@
+package com.dderp.common.tool;
+
+import java.util.Map;
+
+public class DouyinTools {
+    /**
+     * SignV2 用于生活服务应用计算header中的签名(sha256) 新申请应用请使用该方法计算
+     *
+     * @param clientSecret 应用secret
+     * @param body         post请求/spi请求中的body参数json字符串
+     * @param query        url参数
+     * @return 签名
+     */
+    public static String SignV2(String clientSecret, String body, Map<String, String> query) {
+        StringBuilder str = new StringBuilder(clientSecret);
+
+        query.keySet().stream()
+                .filter(a -> !"sign".equals(a))
+                .sorted()
+                .forEach(k -> {
+                    String val = query.get(k);
+                    str.append("&");
+                    str.append(k).append("=").append(val);
+                });
+
+        if (body != null && !"".equals(body)) {
+            str.append("&");
+            str.append("body").append("=").append(body);
+        }
+
+        String result = InvokeSignature.SHA256(str.toString());
+        System.out.printf("[Sign] v2 str:%s, result:%s\n", str.toString(), result);
+
+        return result;
+    }
+}

+ 209 - 176
ddCommon/src/main/java/com/dderp/common/tool/InvokeSignature.java

@@ -7,9 +7,8 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.StringWriter;
 import java.lang.reflect.Field;
-import java.security.KeyFactory;
-import java.security.PrivateKey;
-import java.security.PublicKey;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
 import java.security.spec.PKCS8EncodedKeySpec;
 import java.security.spec.X509EncodedKeySpec;
 import java.util.*;
@@ -21,212 +20,246 @@ import java.util.*;
  */
 public class InvokeSignature {
 
-  /**
-   * 获取所有Fields,包含父类field
-   *
-   * @param clazz clazz
-   * @return list
-   */
-  private static List<Field> getAllFields(Class<?> clazz) {
-    if (!clazz.equals(Object.class)) {
-      List<Field> fields = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()));
-      List<Field> fields2 = getAllFields(clazz.getSuperclass());
-      if (fields2 != null) {
-        fields.addAll(fields2);
-      }
-      return fields;
-    } else {
-      return null;
+    /**
+     * 获取所有Fields,包含父类field
+     *
+     * @param clazz clazz
+     * @return list
+     */
+    private static List<Field> getAllFields(Class<?> clazz) {
+        if (!clazz.equals(Object.class)) {
+            List<Field> fields = new ArrayList<>(Arrays.asList(clazz.getDeclaredFields()));
+            List<Field> fields2 = getAllFields(clazz.getSuperclass());
+            if (fields2 != null) {
+                fields.addAll(fields2);
+            }
+            return fields;
+        } else {
+            return null;
+        }
     }
-  }
-
-  private static PublicKey getPublicKeyFromX509(String algorithm,
-                                               InputStream ins) throws Exception {
-    KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
 
-    StringWriter writer = new StringWriter();
-    StreamUtil.io(new InputStreamReader(ins), writer);
+    private static PublicKey getPublicKeyFromX509(String algorithm,
+                                                  InputStream ins) throws Exception {
+        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
 
-    byte[] encodedKey = writer.toString().getBytes();
+        StringWriter writer = new StringWriter();
+        StreamUtil.io(new InputStreamReader(ins), writer);
 
-    encodedKey = Base64.decodeBase64(encodedKey);
+        byte[] encodedKey = writer.toString().getBytes();
 
-    return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
-  }
+        encodedKey = Base64.decodeBase64(encodedKey);
 
-  private static PrivateKey getPrivateKeyFromPKCS8(String algorithm,
-                                                  InputStream ins) throws Exception {
-    if (ins == null || StringUtils.isEmpty(algorithm)) {
-      return null;
+        return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
     }
 
-    KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
+    private static PrivateKey getPrivateKeyFromPKCS8(String algorithm,
+                                                     InputStream ins) throws Exception {
+        if (ins == null || StringUtils.isEmpty(algorithm)) {
+            return null;
+        }
 
-    byte[] encodedKey = StreamUtil.readText(ins).getBytes();
+        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
 
-    encodedKey = Base64.decodeBase64(encodedKey);
+        byte[] encodedKey = StreamUtil.readText(ins).getBytes();
 
-    return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
-  }
+        encodedKey = Base64.decodeBase64(encodedKey);
 
-  public static String getSignCheckContent(Map<String, String> params) {
-    if (params == null) {
-      return null;
+        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
     }
 
-    params.remove("sign");
-    params.remove("sign_type");
+    public static String getSignCheckContent(Map<String, String> params) {
+        if (params == null) {
+            return null;
+        }
+
+        params.remove("sign");
+        params.remove("sign_type");
 
-    StringBuffer content = new StringBuffer();
-    List<String> keys = new ArrayList<>(params.keySet());
-    Collections.sort(keys);
+        StringBuffer content = new StringBuffer();
+        List<String> keys = new ArrayList<>(params.keySet());
+        Collections.sort(keys);
+
+        for (int i = 0; i < keys.size(); i++) {
+            String key = keys.get(i);
+            String value = params.get(key);
+            if (StringUtils.isNoneEmpty(key, value)) {
+                content.append((i == 0 ? "" : "&") + key + "=" + value);
+            }
+        }
 
-    for (int i = 0; i < keys.size(); i++) {
-      String key = keys.get(i);
-      String value = params.get(key);
-      if (StringUtils.isNoneEmpty(key, value)) {
-        content.append((i == 0 ? "" : "&") + key + "=" + value);
-      }
+        return content.toString();
     }
 
-    return content.toString();
-  }
 
+    /**
+     * 验证签名
+     *
+     * @param params
+     * @param publicKey
+     * @param charset
+     * @return
+     */
+    public static boolean rsaCheck(Map<String, String> params,
+                                   String publicKey,
+                                   String charset) {
+        String sign = params.get("sign");
+        String content = getSignCheckContent(params);
+
+        return rsa256CheckContent(content, sign, publicKey, charset);
+    }
 
-  /**
-   * 验证签名
-   *
-   * @param params
-   * @param publicKey
-   * @param charset
-   * @return
-   */
-  public static boolean rsaCheck(Map<String, String> params,
-                                 String publicKey,
+    public static String getSignContent(Map<String, String> sortedParams) {
+        StringBuffer content = new StringBuffer();
+        List<String> keys = new ArrayList<>(sortedParams.keySet());
+        Collections.sort(keys);
+        int index = 0;
+        for (String key : keys) {
+            String value = sortedParams.get(key);
+            if (StringUtils.isNoneEmpty(key, value)) {
+                content.append((index == 0 ? "" : "&") + key + "=" + value);
+                index++;
+            }
+        }
+        return content.toString();
+    }
+
+    /**
+     * rsa内容签名
+     *
+     * @param content
+     * @param privateKey
+     * @param charset
+     * @return
+     */
+    public static String rsaSign(String content,
+                                 String privateKey,
                                  String charset) {
-    String sign = params.get("sign");
-    String content = getSignCheckContent(params);
-
-    return rsa256CheckContent(content, sign, publicKey, charset);
-  }
-
-  public static String getSignContent(Map<String, String> sortedParams) {
-    StringBuffer content = new StringBuffer();
-    List<String> keys = new ArrayList<>(sortedParams.keySet());
-    Collections.sort(keys);
-    int index = 0;
-    for (String key : keys) {
-      String value = sortedParams.get(key);
-      if (StringUtils.isNoneEmpty(key, value)) {
-        content.append((index == 0 ? "" : "&") + key + "=" + value);
-        index++;
-      }
+        return rsa256Sign(content, privateKey, charset);
     }
-    return content.toString();
-  }
-
-  /**
-   * rsa内容签名
-   *
-   * @param content
-   * @param privateKey
-   * @param charset
-   * @return
-   */
-  public static String rsaSign(String content,
-                               String privateKey,
-                               String charset) {
-    return rsa256Sign(content, privateKey, charset);
-  }
-
-  /**
-   * 转换对象为map
-   *
-   * @param object object
-   * @param ignore ignore
-   * @return map
-   */
-  public static Map<String, String> objectToMap(Object object, String... ignore) {
-    Map<String, String> tempMap = new LinkedHashMap<>();
-    for (Field f : getAllFields(object.getClass())) {
-      if (!f.isAccessible()) {
-        f.setAccessible(true);
-      }
-      boolean ig = false;
-      if (ignore != null && ignore.length > 0) {
-        for (String i : ignore) {
-          if (i.equals(f.getName())) {
-            ig = true;
-            break;
-          }
+
+    /**
+     * 转换对象为map
+     *
+     * @param object object
+     * @param ignore ignore
+     * @return map
+     */
+    public static Map<String, String> objectToMap(Object object, String... ignore) {
+        Map<String, String> tempMap = new LinkedHashMap<>();
+        for (Field f : getAllFields(object.getClass())) {
+            if (!f.isAccessible()) {
+                f.setAccessible(true);
+            }
+            boolean ig = false;
+            if (ignore != null && ignore.length > 0) {
+                for (String i : ignore) {
+                    if (i.equals(f.getName())) {
+                        ig = true;
+                        break;
+                    }
+                }
+            }
+            if (ig) {
+                continue;
+            } else {
+                Object o = null;
+                try {
+                    o = f.get(object);
+                } catch (IllegalArgumentException | IllegalAccessException e) {
+                    e.printStackTrace();
+                }
+                tempMap.put(f.getName(), o == null ? "" : o.toString());
+            }
         }
-      }
-      if (ig) {
-        continue;
-      } else {
-        Object o = null;
+        return tempMap;
+    }
+
+    private static boolean rsa256CheckContent(String content,
+                                              String sign,
+                                              String publicKey,
+                                              String charset) {
         try {
-          o = f.get(object);
-        } catch (IllegalArgumentException | IllegalAccessException e) {
-          e.printStackTrace();
+            PublicKey pubKey = getPublicKeyFromX509("RSA",
+                    new ByteArrayInputStream(publicKey.getBytes()));
+
+            java.security.Signature signature = java.security.Signature
+                    .getInstance("SHA256WithRSA");
+
+            signature.initVerify(pubKey);
+
+            if (StringUtils.isEmpty(charset)) {
+                signature.update(content.getBytes());
+            } else {
+                signature.update(content.getBytes(charset));
+            }
+
+            return signature.verify(Base64.decodeBase64(sign.getBytes()));
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
         }
-        tempMap.put(f.getName(), o == null ? "" : o.toString());
-      }
-    }
-    return tempMap;
-  }
-
-  private static boolean rsa256CheckContent(String content,
-                                            String sign,
-                                            String publicKey,
-                                            String charset) {
-    try {
-      PublicKey pubKey = getPublicKeyFromX509("RSA",
-          new ByteArrayInputStream(publicKey.getBytes()));
-
-      java.security.Signature signature = java.security.Signature
-          .getInstance("SHA256WithRSA");
-
-      signature.initVerify(pubKey);
-
-      if (StringUtils.isEmpty(charset)) {
-        signature.update(content.getBytes());
-      } else {
-        signature.update(content.getBytes(charset));
-      }
-
-      return signature.verify(Base64.decodeBase64(sign.getBytes()));
-    } catch (Exception e) {
-      throw new RuntimeException(
-          "RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
     }
-  }
 
-  private static String rsa256Sign(String content,
-                                   String privateKey,
-                                   String charset) {
+    private static String rsa256Sign(String content,
+                                     String privateKey,
+                                     String charset) {
+
+        try {
+            PrivateKey priKey = getPrivateKeyFromPKCS8("RSA",
+                    new ByteArrayInputStream(privateKey.getBytes()));
 
-    try {
-      PrivateKey priKey = getPrivateKeyFromPKCS8("RSA",
-          new ByteArrayInputStream(privateKey.getBytes()));
+            java.security.Signature signature = java.security.Signature
+                    .getInstance("SHA256WithRSA");
 
-      java.security.Signature signature = java.security.Signature
-          .getInstance("SHA256WithRSA");
+            signature.initSign(priKey);
 
-      signature.initSign(priKey);
+            if (StringUtils.isEmpty(charset)) {
+                signature.update(content.getBytes());
+            } else {
+                signature.update(content.getBytes(charset));
+            }
 
-      if (StringUtils.isEmpty(charset)) {
-        signature.update(content.getBytes());
-      } else {
-        signature.update(content.getBytes(charset));
-      }
+            byte[] signed = signature.sign();
 
-      byte[] signed = signature.sign();
+            return new String(Base64.encodeBase64(signed));
+        } catch (Exception e) {
+            throw new RuntimeException("RSAcontent = " + content + "; charset = " + charset, e);
+        }
 
-      return new String(Base64.encodeBase64(signed));
-    } catch (Exception e) {
-      throw new RuntimeException("RSAcontent = " + content + "; charset = " + charset, e);
     }
 
-  }
+    /**
+     * SHA-256加密
+     *
+     * @param input 明文
+     * @return 密文
+     */
+    public static String SHA256(String input) {
+        String result = "";
+        try {
+            MessageDigest md = MessageDigest.getInstance("SHA-256");
+            md.update(input.getBytes(StandardCharsets.UTF_8));
+            byte[] digest = md.digest();
+            result = bytes2Hex(digest);
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace();
+        }
+        return result;
+
+    }
+
+    /**
+     * 将字节数组转换为十六进制字符串
+     */
+    public static String bytes2Hex(byte[] bts) {
+        StringBuilder hexSb = new StringBuilder();
+        for (byte b : bts) {
+            String hex = Integer.toHexString(0xff & b);
+            if (hex.length() == 1) hexSb.append('0');
+            hexSb.append(hex);
+        }
+        return hexSb.toString();
+    }
+
 }

+ 19 - 0
ddWebCore/src/main/java/com/dderp/webcore/rest/StoreRest.java

@@ -6,6 +6,7 @@ import com.dderp.common.base.BaseService;
 import com.dderp.common.datas.ERPHeader;
 import com.dderp.common.datas.ERPModule;
 import com.dderp.common.datas.HttpCode;
+import com.dderp.common.entity.base.ScriptStringResult;
 import com.dderp.common.entity.platform.PlatformInfo;
 import com.dderp.common.entity.platform.PlatformRequire;
 import com.dderp.common.entity.site.ERPTokenUser;
@@ -163,6 +164,24 @@ public class StoreRest extends BaseService {
         );
     }
 
+
+    @RestMapping(name = "generateStoreAuthUrl_Douyin", auth = true, sort = 14, comment = "生成门店平台授权地址_抖音来客", methods = {"POST"})
+    @WebApiBean(result = true, type = StoreInfo.class)
+    public CompletableFuture<RMap> generateStoreAuthUrl_Douyin(
+            @RestParam(name = "idStore", comment = "门店id") long idStore,
+            @RestParam(name = "&", comment = "当前用户,不需要传入") ERPTokenUser currentUser,
+            @RestHeader(name = ERPHeader.HTTPHEADER_DATASOURCE) String dataSourceId,
+            @RestHeader(name = ERPHeader.HTTPHEADER_SUPPLIER) String supplierCode) {
+        return CompletableFuture.supplyAsync(
+                () -> {
+                    RetResult<ScriptStringResult> resultRet = storeService.generateStoreAuthUrl_Douyin(idStore,  dataSourceId, Long.parseLong(supplierCode));
+                    if (!resultRet.isSuccess())
+                        return RMapUtils.error(HttpCode.BAD_REQUEST.value(), resultRet.getRetinfo());
+                    return RMapUtils.successV2(resultRet.getResult(), null, null);
+                }, getExecutor()
+        );
+    }
+
     @RestMapping(name = "configStoreInvoiceInfo", auth = true, sort = 14, comment = "开启与关闭门店开票", methods = {"POST"})
     @WebApiBean(result = true, type = StoreInvoiceInfo.class)
     public CompletableFuture<RMap> configStoreInvoiceInfo(

+ 72 - 3
ddWebCore/src/main/java/com/dderp/webcore/servlet/OrderCallServlet.java

@@ -1,6 +1,13 @@
 package com.dderp.webcore.servlet;
 
+import com.dderp.common.api.NoSqlKeysService;
+import com.dderp.common.api.StoreService;
+import com.dderp.common.api.flycat.DouyinService;
+import com.dderp.common.datas.ERPHeader;
+import com.dderp.common.datas.RedisKeys;
+import com.dderp.common.entity.invoke.douyin.DouyinCallBody;
 import com.dderp.common.entity.site.ERPTokenUser;
+import com.dySweetFishPlugin.redis.RedisService;
 import com.sweetfish.convert.json.JsonConvert;
 import com.sweetfish.net.WorkThread;
 import com.sweetfish.net.http.*;
@@ -24,6 +31,18 @@ public class OrderCallServlet extends HttpServlet {
     @Resource
     private JsonConvert jsonConvert;
 
+    @Resource
+    private RedisService redisService;
+
+    @Resource
+    private NoSqlKeysService keysService;
+
+    @Resource
+    private DouyinService douyinService;
+
+    @Resource
+    private StoreService storeService;
+
     @Resource(name = "property.douyin.appSecret")
     private String douyinAppSecret;
 
@@ -58,17 +77,67 @@ public class OrderCallServlet extends HttpServlet {
 
         response.finish(bodyMap.get("content"));
 
-        /*  以上为接口接入验证代码,以下为正式带验签代码
+        /*  以上为接口接入验证代码,以下为正式带验签代码  */
         String douyinSign = request.getHeader("X-Douyin-Signature");
         String douyinMsgId = request.getHeader("Msg-Id");
+        String dataSourceId = request.getHeader(ERPHeader.HTTPHEADER_DATASOURCE);
+        long supplierCode = Long.parseLong(request.getHeader(ERPHeader.HTTPHEADER_SUPPLIER));
+
+        if (redisService.exists(keysService.getRedisKey(RedisKeys.KEY_DOUYIN_CALL_MSG_ID, supplierCode))) {
+            //重复消息,不处理
+            response.finish();
+            return;
+        }
+        //1小时过期,应该够了吧
+        redisService.expire(keysService.getRedisKey(RedisKeys.KEY_DOUYIN_CALL_MSG_ID, supplierCode), 3600);
+
 
         String signData = douyinAppSecret + body;
         String sign = DigestUtils.sha1Hex(signData);
         if (!sign.equals(douyinSign)) {
-            logger.error("验签失败");
+            logger.error("[抖音来客]Webhooks推送消息验签失败");
             response.finish();
+            return;
+        }
+
+        DouyinCallBody callBody = jsonConvert.convertFrom(DouyinCallBody.class, body);
+        logger.info("[抖音来客]Webhooks推送消息:[" + callBody.getEvent() + "]");
+        logger.info(callBody.getContent());
+
+        switch (callBody.getEvent()) {
+            case "life_saas_cooperate_auth_with_bind": {
+                //能力授权&门店绑定消息
+                storeService.bindStorePlatformDouyin(callBody.getContent(), dataSourceId, supplierCode);
+                break;
+            }
+            case "life_takeout_order_pay_success": {
+                //用户下单消息
+                douyinService.importOrderFromDouyin(callBody.getContent(), dataSourceId, supplierCode);
+                break;
+            }
+            case "life_takeout_order_merchant_receive":{
+                //商户接单消息
+                break;
+            }
+            case "life_takeout_order_merchant_refuse":{
+                //商户拒单消息
+                break;
+            }
+            case "life_trade_refund_complete":{
+                //订单已取消消息
+                break;
+            }
+            case "life_trade_takeout_order_finish":{
+                //订单完成消息
+                break;
+            }
+            case "life_trade_takeout_order_modify":{
+                //订单修改消息,主要是修改配送信息
+                break;
+            }
         }
 
-         */
+        //无论如何,最终还得返回个200
+        response.finish();
     }
 }