Browse Source

顺丰同城配送出口

jlutt@163.com 2 years ago
parent
commit
dbed245490
22 changed files with 1722 additions and 137 deletions
  1. 8 33
      conf/application-ddWebOne.xml
  2. 26 26
      conf/eskeys.properties
  3. 61 57
      conf/rediskeys.properties
  4. 133 0
      conf/script/1000/expressApi/BE_Express_CreateOrder_SFTC.groovy
  5. 111 0
      conf/script/1000/expressApi/BE_Express_OrderStatusInvoke_SFTC.groovy
  6. 28 0
      conf/script/1000/expressApi/ExpressApiSign.groovy
  7. 4 0
      conf/sftc.properties
  8. 61 0
      ddBusiness/src/main/java/com/dderp/business/service/flycat/ExpressOutServiceImpl.java
  9. 18 0
      ddCommon/src/main/java/com/dderp/common/api/flycat/ExpressOutService.java
  10. 1 1
      ddCommon/src/main/java/com/dderp/common/base/BaseService.java
  11. 1 19
      ddCommon/src/main/java/com/dderp/common/datas/ERPModule.java
  12. 1 1
      ddCommon/src/main/java/com/dderp/common/datas/ESKeys.java
  13. 10 0
      ddCommon/src/main/java/com/dderp/common/datas/RedisKeys.java
  14. 27 0
      ddCommon/src/main/java/com/dderp/common/entity/express/SFCreateOrderResult.java
  15. 613 0
      ddCommon/src/main/java/com/dderp/common/entity/express/SFOrder.java
  16. 211 0
      ddCommon/src/main/java/com/dderp/common/entity/express/SFOrderDetail.java
  17. 73 0
      ddCommon/src/main/java/com/dderp/common/entity/express/SFOrderPickupInfo.java
  18. 84 0
      ddCommon/src/main/java/com/dderp/common/entity/express/SFOrderProductDetail.java
  19. 73 0
      ddCommon/src/main/java/com/dderp/common/entity/express/SFOrderReceive.java
  20. 62 0
      ddCommon/src/main/java/com/dderp/common/entity/express/SFOrderShop.java
  21. 42 0
      ddWebCore/src/main/java/com/dderp/webcore/rest/flycat/ExpressOutRest.java
  22. 74 0
      ddWebCore/src/main/java/com/dderp/webcore/servlet/ExpressCallServlet.java

+ 8 - 33
conf/application-ddWebOne.xml

@@ -7,7 +7,7 @@
             <node addr="127.0.0.1" port="52101"/>
         </group>
 
-        <properties load="redis.properties;workProcess.properties;callCenter.properties">
+        <properties load="redis.properties;workProcess.properties;sftc.properties">
             <property name="orderFileRoot" value="${APP_HOME}/orderFiles"/>
             <!--注入sql脚本的目录-->
             <property name="sqlroot" value="${APP_HOME}/conf/sqlroot/"/>
@@ -17,8 +17,8 @@
             <!--注入初始化code配置文件-->
             <property name="tableCodeFile" value="${APP_HOME}/conf/KeyCode.xml"/>
 
-            <property name="tableIdPrefix" value="aeerp:tableid:"/>
-            <property name="tableCodePrefix" value="aeerp:tablecode:"/>
+            <property name="tableIdPrefix" value="dderp:tableid:"/>
+            <property name="tableCodePrefix" value="dderp:tablecode:"/>
 
             <!--session过期时间-->
             <property name="sessionExpireSeconds" value="3600"/>
@@ -73,6 +73,8 @@
                 <isUseScriptService value="true"/>
             </service>
             <service value="com.dderp.webcore.rest.ProductRest"/>
+
+            <service value="com.dderp.webcore.rest.flycat.ExpressOutRest"/>
         </services>
 
         <resource-servlet webroot="root" index="index.html">
@@ -97,6 +99,8 @@
             </service>
             <service value="com.dderp.webcore.rest.ProductRest"/>
 
+            <service value="com.dderp.webcore.rest.flycat.ExpressOutRest"/>
+
             <websocket value="com.dderp.webcore.websocket.ERPWebSocket" name="aws" groups="ERP_SERVICE_REMOTE"/>
         </rest>
 
@@ -235,45 +239,16 @@
                 <isUseScriptService value="false"/>
             </service>
 
-            <service value="com.dderp.business.service.erp.ProductServiceImpl" groups="ERP_SERVICE_REMOTE">
-                <master value="true"/>
-                <isUseScriptService value="true"/>
-            </service>
-
-            <service value="com.dderp.business.service.erp.OrderServiceImpl" groups="ERP_SERVICE_REMOTE">
+            <service value="com.dderp.business.service.flycat.ExpressOutServiceImpl" groups="ERP_SERVICE_REMOTE">
                 <master value="true"/>
                 <isUseScriptService value="true"/>
             </service>
 
-            <service value="com.dderp.business.service.erp.OrderSearchServiceImpl" groups="ERP_SERVICE_REMOTE">
-                <master value="true"/>
-                <isUseScriptService value="true"/>
-            </service>
 
-            <service value="com.dderp.business.service.erp.ClientServiceImpl" groups="ERP_SERVICE_REMOTE">
-                <master value="true"/>
-                <isUseScriptService value="true"/>
-            </service>
 
-            <service value="com.dderp.business.service.erp.OutAssistServiceImpl" groups="ERP_SERVICE_REMOTE">
-                <master value="true"/>
-                <isUseScriptService value="true"/>
-            </service>
 
-            <service value="com.dderp.business.service.erp.SupplierServiceImpl" groups="ERP_SERVICE_REMOTE">
-                <master value="true"/>
-                <isUseScriptService value="true"/>
-            </service>
 
-            <service value="com.dderp.business.service.erp.MaterialServiceImpl" groups="ERP_SERVICE_REMOTE">
-                <master value="true"/>
-                <isUseScriptService value="true"/>
-            </service>
 
-            <service value="com.dderp.business.service.erp.PaperServiceImpl" groups="ERP_SERVICE_REMOTE">
-                <master value="true"/>
-                <isUseScriptService value="true"/>
-            </service>
         </services>
     </server>
 </application>

+ 26 - 26
conf/eskeys.properties

@@ -3,62 +3,62 @@
 #注意ES的index只能为小写
 
 #系统群发消息索引库,理论上此库只需一个即可,群发消息不会太多
-es.sysmsg.index=aeerp_sysmsg_
+es.sysmsg.index=dderp_sysmsg_
 
 #系统群发消息内容索引库
-es.sysmsgtext.index = aeerp_sysmsgtext_
+es.sysmsgtext.index = dderp_sysmsgtext_
 
 #用户对用户或者消息通知,发送给指定人的消息,暂时可以只用一个进行存储,
 #未来数据量大的情况下,可以按年份之类的条件增加索引
-es.p2pmsg.index = aeerp_p2pmsg_
+es.p2pmsg.index = dderp_p2pmsg_
 
 #点对点消息内容索引库
-es.p2pmsgtext.index = aeerp_p2pmsgtext_
+es.p2pmsgtext.index = dderp_p2pmsgtext_
 
 #用户对应消息状态,用户在登录时在群发和对点发消息库中查找未读的消息写入此库中
 #方便分页和最后的展示,理论上此库需要进行分表,可以针对用户id进行路由
-es.usermsg.index = aeerp_usermsg_
+es.usermsg.index = dderp_usermsg_
 
 
 #通用文件信息存储
-es.erpfile.index = aeerp_erpfile_
+es.erpfile.index = dderp_erpfile_
 
 #数据权限
-es.erpdatapurview.index = aeerp_erpdatepurview_
+es.erpdatapurview.index = dderp_erpdatepurview_
 
 #查询统计
-es.inquireinfo.index = aeerp_inquireinfo_
+es.inquireinfo.index = dderp_inquireinfo_
 
-es.productinfo.index = aeerp_product_info_
-es.product.image.index = aeerp_product_image_
+es.productinfo.index = dderp_product_info_
+es.product.image.index = dderp_product_image_
 
-es.workprocess.index = aeerp_workprocess_info_
+es.workprocess.index = dderp_workprocess_info_
 #订单索引
-es.printorder.index = aeerp_printorder_
-es.orderstep.index = aeerp_orderstep_
+es.printorder.index = dderp_printorder_
+es.orderstep.index = dderp_orderstep_
 
 #施工单
-es.printbill.index = aeerp_printbill_
-es.billstep.index = aeerp_billstep_
-es.breedprocess.index = aeerp_breedprocess_
+es.printbill.index = dderp_printbill_
+es.billstep.index = dderp_billstep_
+es.breedprocess.index = dderp_breedprocess_
 
 #客户
-es.clientinfo.index = aeerp_clientinfo_
-es.clientreceiveaddress.index = aeerp_clientreceiveaddress_
+es.clientinfo.index = dderp_clientinfo_
+es.clientreceiveaddress.index = dderp_clientreceiveaddress_
 
 #纸张&辅料
-es.paperbaseinfo.index = aeerp_paperbaseinfo_
-es.paperinfotype.index = aeerp_paperinfotype_
-es.paperinfo.index = aeerp_paperinfo_
-es.paperquoteinfo.index = aeerp_paperquoteinfo_
+es.paperbaseinfo.index = dderp_paperbaseinfo_
+es.paperinfotype.index = dderp_paperinfotype_
+es.paperinfo.index = dderp_paperinfo_
+es.paperquoteinfo.index = dderp_paperquoteinfo_
 
-es.materialinfotype.index = aeerp_materialinfotype_
-es.materialinfo.index = aeerp_materialinfo_
+es.materialinfotype.index = dderp_materialinfotype_
+es.materialinfo.index = dderp_materialinfo_
 
 #外协
-es.outassistinfo.index = aeerp_outassistinfo_
+es.outassistinfo.index = dderp_outassistinfo_
 #供应商
-es.supplierInfo.index = aeerp_supplierinfo_
+es.supplierInfo.index = dderp_supplierinfo_
 #平台档案
 es.platforminfo.index = dydeliver_platforminfo_
 #平台需求信息档案

+ 61 - 57
conf/rediskeys.properties

@@ -1,112 +1,116 @@
 # suppress inspection "UnusedProperty" for whole file
 
-redis.reqlimit=aeerp:reqlimit
-redis.authcode=aeerp:authcode
-redis.sessions=aeerp:sessions
-redis.platformsupplier=aeerp:platform:supplier
-redis.platformsuppliercode=aeerp:platform:suppliercode
+redis.reqlimit=dderp:reqlimit
+redis.authcode=dderp:authcode
+redis.sessions=dderp:sessions
+redis.platformsupplier=dderp:platform:supplier
+redis.platformsuppliercode=dderp:platform:suppliercode
 #单个redis节点的分布式锁
-redis.lock=aeerp:lock
-redis.dept=aeerp:sysdept
-redis.account=aeerp:account
+redis.lock=dderp:lock
+redis.dept=dderp:sysdept
+redis.account=dderp:account
 #存储所有的系统功能,以hash结构存储,如果内存占用高,可把key写成纯数字
-redis.sysactions=aeerp:sysactions
+redis.sysactions=dderp:sysactions
 #存储所有的系统菜单,以hash结构存储,如果内存占用高,可把key写成纯数字
-redis.sysmenus=aeerp:sysmenus
+redis.sysmenus=dderp:sysmenus
 #存储所有的系统角色,以hash结构存储,如果内存占用高,可把key写成纯数字
-redis.sysroles=aeerp:sysroles
-redis.sysrolemenus=aeerp:sysrolemenus
+redis.sysroles=dderp:sysroles
+redis.sysrolemenus=dderp:sysrolemenus
 #存储角色的菜单和功能
-redis.sysroleactions=aeerp:sysroleactions
+redis.sysroleactions=dderp:sysroleactions
 #存储用户角色,每个用户一个键值
 #当前服务端未保存用户和session的对应关系,导致无法快速获取用户的角色关系
 #这里在首次从数据库中获取时进行存储,在修改员工档案的时候删除键值并修改
-redis.sysuserrole=aeerp:sysuserrole
-redis.erp.dicttype=aeerp:erp:dicttype
+redis.sysuserrole=dderp:sysuserrole
+redis.erp.dicttype=dderp:erp:dicttype
 
 
 #系统配置
-redis.configvalue=aeerp:configvalue
+redis.configvalue=dderp:configvalue
 #字典数据
-redis.dicttype=aeerp:dicttype
-redis.dictdata=aeerp:dictdata
+redis.dicttype=dderp:dicttype
+redis.dictdata=dderp:dictdata
 
 #业务脚本
-redis.businessscript=aeerp:businessscript
-redis.scriptcompile=aeerp:scriptcompile
+redis.businessscript=dderp:businessscript
+redis.scriptcompile=dderp:scriptcompile
 
 #分厂信息
-redis.companyinfo = aeerp:companyinfo
+redis.companyinfo = dderp:companyinfo
 
 #消息类型
-redis.erp.noticemessage = aeerp:noticemessage
-redis.erp.usernoticemessage = aeerp:usernoticemessage
+redis.erp.noticemessage = dderp:noticemessage
+redis.erp.usernoticemessage = dderp:usernoticemessage
 
-redis.erp.pay.tradeno = aeerp:erp:pay:tradeno
+redis.erp.pay.tradeno = dderp:erp:pay:tradeno
 
 #消息组前缀
-redis.erp.noticemsggroup = aeerp:noticemsggroup
+redis.erp.noticemsggroup = dderp:noticemsggroup
 
 #登录用户,一直记录,用户登录则记录下信息
-redis.erp.loginuser = aeerp:loginuser
-redis.erp.onlineuser = aeerp:onlineuser
+redis.erp.loginuser = dderp:loginuser
+redis.erp.onlineuser = dderp:onlineuser
 
-redis.erp.personconfig = aeerp:personconfig
+redis.erp.personconfig = dderp:personconfig
 
-redis.formtoken = aeerp:formtoken
-redis.formtokenex = aeerp:formtokenex
+redis.formtoken = dderp:formtoken
+redis.formtokenex = dderp:formtokenex
 
 #仪表盘
-redis.cardpanel = aeerp:cardpanel
+redis.cardpanel = dderp:cardpanel
 
 #业务锁定数据
-redis.erplock.data = aeerp:erplock:data
-redis.erplock.userdata = aeerp:erplock:userdata
-redis.erplock.exclusivelockpart = aeerp:erplock:exclusivelockpart
+redis.erplock.data = dderp:erplock:data
+redis.erplock.userdata = dderp:erplock:userdata
+redis.erplock.exclusivelockpart = dderp:erplock:exclusivelockpart
 
 #版的版心尺寸
-redis.erp.breedplatesize = aeerp:erp:breedplatesize
+redis.erp.breedplatesize = dderp:erp:breedplatesize
 
 #查询统计
-redis.erp.inquireinfo = aeerp:erp:inquireinfo
+redis.erp.inquireinfo = dderp:erp:inquireinfo
 
 #分厂
-redis.company.info = aeerp:erp:company:info
+redis.company.info = dderp:erp:company:info
 
-redis.erp.product.parameter = aeerp:erp:product:parameter
-redis.erp.product.info = aeerp:erp:product:info
-redis.erp.product.detail = aeerp:erp:product:detail
-redis.erp.product.type = aeerp:erp:product:type
-redis.erp.product.pagePrice = aeerp:erp:product:pagePrice
-redis.erp.product.example.image = aeerp:erp:product:exampleImage
-redis.erp.product.room = aeerp:erp:product:room
+redis.erp.product.parameter = dderp:erp:product:parameter
+redis.erp.product.info = dderp:erp:product:info
+redis.erp.product.detail = dderp:erp:product:detail
+redis.erp.product.type = dderp:erp:product:type
+redis.erp.product.pagePrice = dderp:erp:product:pagePrice
+redis.erp.product.example.image = dderp:erp:product:exampleImage
+redis.erp.product.room = dderp:erp:product:room
 
 #单据打印次数
-redis.erp.itemprintcount = aeerp:print:printcount
+redis.erp.itemprintcount = dderp:print:printcount
 
-redis.erp.order.cycle.item = aeerp:erp:cycle:item:order
+redis.erp.order.cycle.item = dderp:erp:cycle:item:order
 
-redis.erp.print.bill.cycle.item = aeerp:erp:cycle:item:printBill
+redis.erp.print.bill.cycle.item = dderp:erp:cycle:item:printBill
 
 
-redis.erp.develop.client = aeerp:erp:developclient
-redis.erp.develop.client.code = aeerp:erp:developclientcode
+redis.erp.develop.client = dderp:erp:developclient
+redis.erp.develop.client.code = dderp:erp:developclientcode
 
 #机型机台
-redis.erp.machine.type = aeerp:erp:machine:type
-redis.erp.machine.info = aeerp:erp:machine:info
+redis.erp.machine.type = dderp:erp:machine:type
+redis.erp.machine.info = dderp:erp:machine:info
 
 #数据锁定
 
-redis.erp.client.industry.info = aeerp:erp:client:industry:info
-redis.erp.client.moneybalance = aeerp:erp:client:balance:clientmoney
-redis.erp.client.clientlevel = aeerp:erp:client:clientlevel
+redis.erp.client.industry.info = dderp:erp:client:industry:info
+redis.erp.client.moneybalance = dderp:erp:client:balance:clientmoney
+redis.erp.client.clientlevel = dderp:erp:client:clientlevel
 
 #纸张品牌
-redis.erp.paper.brand = aeerp:erp:paper:brand
+redis.erp.paper.brand = dderp:erp:paper:brand
 #纸张开数档案
-redis.erp.paper.cut.info = aeerp:erp:paper:cut:info
-redis.erp.paper.cut.size.info= aeerp:erp:paper:cut:size:info
+redis.erp.paper.cut.info = dderp:erp:paper:cut:info
+redis.erp.paper.cut.size.info= dderp:erp:paper:cut:size:info
+
+
+redis.erp.working.express.sf.order = dderp:erp:working:express:sf:order
+redis.erp.working.express.sf.store = dderp:erp:working:express:sf:store
 
 
 

+ 133 - 0
conf/script/1000/expressApi/BE_Express_CreateOrder_SFTC.groovy

@@ -0,0 +1,133 @@
+import com.alibaba.fastjson2.JSON
+import com.alibaba.fastjson2.JSONWriter
+import com.dderp.common.api.BusinessExecutor
+import com.dderp.common.datas.ERPModule
+import com.dderp.common.entity.base.ProcessStringItem
+import com.dderp.common.entity.express.SFCreateOrderResult
+import com.dderp.common.entity.express.SFOrder
+import com.dderp.common.entity.express.SFOrderDetail
+import com.dderp.common.entity.express.SFOrderProductDetail
+import com.dderp.common.entity.express.SFOrderReceive
+import com.dderp.common.http.HttpTools
+import com.sweetfish.convert.json.JsonConvert
+import com.sweetfish.service.RetResult
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.Logger
+
+import javax.annotation.Resource
+import java.nio.charset.StandardCharsets
+import java.time.LocalDateTime
+import java.time.ZoneOffset
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.ExecutionException
+import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeoutException
+
+@SuppressWarnings("unused")
+class BE_Express_CreateOrder_SFTC implements BusinessExecutor<ProcessStringItem, ProcessStringItem> {
+
+    private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
+
+    @Resource(name = "property.sftc.appId")
+    long sfAppId
+
+    @Resource(name = "property.sftc.appKey")
+    String sfAppKey
+
+    @Resource(name = "property.sftc.createOrderUrl")
+    String sfCreateOrderUrl
+
+    @Resource
+    JsonConvert jsonConvert
+
+    @Override
+    String scriptName() {
+        return "顺丰同城创建订单"
+    }
+
+    @Override
+    ERPModule module() {
+        return ERPModule.EXPRESS_API
+    }
+
+    RetResult<ProcessStringItem> execute(ProcessStringItem source) {
+        //秒级时间戳,groovy里面不让用system
+        long currentTime = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8))
+        long testTime = LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli()
+        SFOrder sfOrder = new SFOrder(
+                dev_id: sfAppId,
+                shop_id: "3243279847393",
+                shop_type: 1,
+                shop_order_id: "JY" + testTime + "L",
+                order_sequence: "测试",
+                lbs_type: 2,
+                order_time: currentTime,
+                push_time: currentTime,
+                vehicle: 0,
+                four_wheeler_type: 10,
+                rider_pick_method: 1,
+                version: 19,
+
+                order_detail: new SFOrderDetail(
+                        total_price: 30100L,
+                        product_type: 6,
+                        weight_gram: 3000L,
+                        product_num: 15,
+                        product_type_num: 5,
+                        product_detail: [
+                                new SFOrderProductDetail(
+                                        product_name: "测试商品1",
+                                        product_num: 1
+                                ),
+                                new SFOrderProductDetail(
+                                        product_name: "测试商品2",
+                                        product_num: 3
+                                ),
+                        ]
+
+                ),
+
+                receive: new SFOrderReceive(
+                        user_name: "顺丰同城",
+                        user_phone: "18237171439",
+                        user_lng: "116.339392",
+                        user_lat: "40.002349",
+                        user_address: "北京市海淀区学清嘉创大厦A座15层"
+                )
+        )
+
+
+        String postData = JSON.toJSONString(sfOrder)
+        logger.info("请求数据: " + postData)
+        String sign = ExpressApiSign.sfGenerateOpenSign(postData, sfAppId, sfAppKey)
+
+        String url = sfCreateOrderUrl + "sign=" + sign
+
+        CompletableFuture<String> apiResult = HttpTools.postHttpContentAsync(url,
+                5000,
+                StandardCharsets.UTF_8,
+                postData,
+                ["Content-Type": "application/json;charset=utf-8"])
+        try {
+            String orderResult = apiResult.get(6000, TimeUnit.SECONDS)
+
+            SFCreateOrderResult createOrderResult = jsonConvert.convertFromO(SFCreateOrderResult.class, orderResult)
+            logger.info(orderResult)
+            logger.info(jsonConvert.convertTo(createOrderResult))
+
+            return RetResult.<ProcessStringItem> successT().result(
+                    ProcessStringItem.newBuilder()
+                            .itemValue("")
+                            .build()
+            )
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            logger.error(e.getMessage(), e)
+
+            return RetResult.<ProcessStringItem> successT().result(
+                    ProcessStringItem.newBuilder()
+                            .itemValue("")
+                            .build()
+            )
+        }
+    }
+}

+ 111 - 0
conf/script/1000/expressApi/BE_Express_OrderStatusInvoke_SFTC.groovy

@@ -0,0 +1,111 @@
+import com.dderp.common.api.BusinessExecutor
+import com.dderp.common.api.ERPLockDataService
+import com.dderp.common.api.NoSqlKeysService
+import com.dderp.common.datas.ERPModule
+import com.dderp.common.datas.RedisKeys
+import com.dderp.common.entity.base.InvokeCallParams
+import com.dderp.common.entity.base.InvokeCallResult
+import com.dySweetFishPlugin.sql.dao.OperatorWait
+import com.sweetfish.convert.json.JsonConvert
+import com.sweetfish.service.RetResult
+import groovy.json.JsonSlurper
+import org.apache.commons.lang3.StringUtils
+import org.apache.logging.log4j.LogManager
+import org.apache.logging.log4j.Logger
+
+import javax.annotation.Resource
+
+class BE_Express_OrderStatusInvoke_SFTC implements BusinessExecutor<InvokeCallParams, InvokeCallResult> {
+
+    private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName())
+
+    @Resource
+    JsonConvert jsonConvert
+
+    @Resource
+    ERPLockDataService lockDataService
+
+    @Resource
+    NoSqlKeysService keysService
+
+    @Override
+    String scriptName() {
+        return "顺丰同城数据回调"
+    }
+
+    @Override
+    ERPModule module() {
+        return ERPModule.EXPRESS_API
+    }
+
+    @Override
+    OperatorWait getAWait() {
+        return OperatorWait.ASNYC
+    }
+
+    @Override
+    RetResult<InvokeCallParams> beforeExecute(InvokeCallParams source) {
+        //此回调post的数据看着没有子表,直接用groovy自带的json即可,如果有子表,还是应该建立一个类进行转换
+
+        //锁定下数据,防止重复提交
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+
+        String urlIndex = invokeOrder["url_index"] as String
+
+        //这里除了店铺授权和店铺取消授权,其它都是订单,if-else先写着
+        if (StringUtils.equalsIgnoreCase("bindnotify", urlIndex)) {
+            //店铺授权回调
+            String shopId = invokeOrder["shop_id"] as String
+            if (lockDataService.hLockAdd(shopId, RedisKeys.KEY_ERP_WORKING_SF_STORE, source.supplierCode) > 1) {
+                return RetResult.<InvokeCallParams> errorT().retinfo(shopId + "提交工作中,请稍后刷新即可,无需重复操作")
+            }
+        } else if (StringUtils.equalsIgnoreCase("cancelbindnotify", urlIndex)) {
+            //店铺取消授权回调
+            String shopId = invokeOrder["shop_id"] as String
+            if (lockDataService.hLockAdd(shopId, RedisKeys.KEY_ERP_WORKING_SF_STORE, source.supplierCode) > 1) {
+                return RetResult.<InvokeCallParams> errorT().retinfo(shopId + "提交工作中,请稍后刷新即可,无需重复操作")
+            }
+        } else {
+            String invokeOrderId = invokeOrder["sf_order_id"] as String
+            if (lockDataService.hLockAdd(invokeOrderId, RedisKeys.KEY_ERP_WORKING_SF_ORDER, source.supplierCode) > 1) {
+                return RetResult.<InvokeCallParams> errorT().retinfo(invokeOrderId + "提交工作中,请稍后刷新即可,无需重复操作")
+            }
+        }
+
+        return RetResult.<InvokeCallParams> successT().result(source)
+    }
+
+    @Override
+    void afterExecute(boolean executeError, InvokeCallParams source, InvokeCallResult dest) {
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+
+        String urlIndex = invokeOrder["url_index"] as String
+        if (StringUtils.equalsIgnoreCase("bindnotify", urlIndex)) {
+            //店铺授权回调
+            String shopId = invokeOrder["shop_id"] as String
+            lockDataService.hLockDel(shopId, RedisKeys.KEY_ERP_WORKING_SF_STORE, source.supplierCode)
+        } else if (StringUtils.equalsIgnoreCase("cancelbindnotify", urlIndex)) {
+            //店铺取消授权回调
+            String shopId = invokeOrder["shop_id"] as String
+            lockDataService.hLockDel(shopId, RedisKeys.KEY_ERP_WORKING_SF_STORE, source.supplierCode)
+        } else {
+            String invokeOrderId = invokeOrder["sf_order_id"] as String
+            lockDataService.hLockDel(invokeOrderId,RedisKeys.KEY_ERP_WORKING_SF_ORDER, source.supplierCode)
+        }
+    }
+
+    RetResult<InvokeCallResult> execute(InvokeCallParams source) {
+        def jsonSlurper = new JsonSlurper()
+        def invokeOrder = jsonSlurper.parseText(source.params)
+
+        logger.info(invokeOrder["url_index"])
+        logger.info(invokeOrder["sf_order_id"])
+        logger.info(invokeOrder["operator_name"])
+
+        return RetResult.<InvokeCallResult> successT().result(
+                InvokeCallResult.success()
+        )
+    }
+}

+ 28 - 0
conf/script/1000/expressApi/ExpressApiSign.groovy

@@ -0,0 +1,28 @@
+import org.apache.commons.codec.binary.Base64
+
+import java.security.MessageDigest
+
+class ExpressApiSign {
+
+    static String sfGenerateOpenSign(String postData, Long appId, String appKey) {
+        StringBuilder sb =  new StringBuilder()
+        sb.append(postData)
+        sb.append("&" + appId + "&" + appKey)
+        MessageDigest md = MessageDigest.getInstance("MD5")
+        byte[] md5 = md.digest(sb.toString().getBytes("utf-8"))
+        int i
+        StringBuffer buf = new StringBuffer("")
+        for (int offset = 0; offset < md5.length; offset++) {
+            i = md5[offset]
+            if (i < 0) {
+                i += 256
+            }
+            if (i < 16) {
+                buf.append("0")
+            }
+            buf.append(Integer.toHexString(i))
+        }
+        String ret = Base64.encodeBase64String(buf.toString().getBytes("utf-8"))
+        return  ret
+    }
+}

+ 4 - 0
conf/sftc.properties

@@ -0,0 +1,4 @@
+sftc.appId = 1688762808
+sftc.appKey = 48bbf2d69b43a38cac9df1a7e753a784
+
+sftc.createOrderUrl = https://openic.sf-express.com/open/api/external/createorder?

+ 61 - 0
ddBusiness/src/main/java/com/dderp/business/service/flycat/ExpressOutServiceImpl.java

@@ -0,0 +1,61 @@
+package com.dderp.business.service.flycat;
+
+import com.dderp.common.api.flycat.ExpressOutService;
+import com.dderp.common.base.BaseService;
+import com.dderp.common.datas.ERPModule;
+import com.dderp.common.entity.base.InvokeCallParams;
+import com.dderp.common.entity.base.InvokeCallResult;
+import com.dderp.common.entity.base.ProcessStringItem;
+import com.dderp.common.entity.site.ERPTokenUser;
+import com.sweetfish.service.Local;
+import com.sweetfish.service.RetResult;
+import com.sweetfish.util.AnyValue;
+import com.sweetfish.util.AutoLoad;
+import com.sweetfish.util.ResourceType;
+import org.apache.commons.lang3.StringUtils;
+
+@AutoLoad(false)
+@Local
+@ResourceType(ExpressOutService.class)
+public class ExpressOutServiceImpl extends BaseService implements ExpressOutService {
+
+    @Override
+    public void init(AnyValue config) {
+        super.init(config);
+    }
+
+    @Override
+    public void destroy(AnyValue config) {
+        super.destroy(config);
+    }
+
+    @Override
+    public void start(AnyValue config) {
+        super.start(config);
+    }
+
+    public RetResult<ProcessStringItem> test(String dataSourceId, long supplierCode) {
+        return handleScript("Express_CreateOrder_SFTC", ERPModule.EXPRESS_API,
+                dataSourceId, supplierCode,
+                () -> ProcessStringItem.newBuilder()
+                        .itemValue("test")
+                        .build()
+        );
+    }
+
+    public RetResult<InvokeCallResult> callExpress(InvokeCallParams source, ERPTokenUser currentUser, String dataSourceId, long supplierCode) {
+        if (source == null) {
+            return RetResult.<InvokeCallResult>errorT().retinfo("无效的参数信息");
+        }
+
+        if (StringUtils.isEmpty(source.getBusinessMethod())) {
+            return RetResult.<InvokeCallResult>errorT().retinfo("无效的参数方法[businessMethod]信息");
+        }
+
+        source.setCurrentUser(currentUser);
+        source.setDataSourceId(dataSourceId);
+        source.setSupplierCode(supplierCode);
+
+        return callScript(source.getBusinessMethod(), source, currentUser, dataSourceId, supplierCode);
+    }
+}

+ 18 - 0
ddCommon/src/main/java/com/dderp/common/api/flycat/ExpressOutService.java

@@ -0,0 +1,18 @@
+package com.dderp.common.api.flycat;
+
+import com.dderp.common.api.ScriptService;
+import com.dderp.common.entity.base.InvokeCallParams;
+import com.dderp.common.entity.base.InvokeCallResult;
+import com.dderp.common.entity.base.ProcessStringItem;
+import com.dderp.common.entity.site.ERPTokenUser;
+import com.sweetfish.service.RetResult;
+
+/**
+ * 快递配送服务
+ */
+public interface ExpressOutService extends ScriptService {
+
+    RetResult<ProcessStringItem> test(String dataSourceId, long supplierCode);
+
+    RetResult<InvokeCallResult> callExpress(InvokeCallParams source, ERPTokenUser currentUser, String dataSourceId, long supplierCode);
+}

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

@@ -628,7 +628,7 @@ public abstract class BaseService extends AbstractService {
                     //开始执行前的函数,可用于 锁定数据 之类的处理
                     RetResult<InvokeCallParams> beforeResult = businessExecutor.beforeExecute(checkResult.getResult());
                     if (!beforeResult.isSuccess()) {
-                        return RetResult.<InvokeCallResult>errorT().retinfo(checkResult.getRetinfo());
+                        return RetResult.<InvokeCallResult>errorT().retinfo(beforeResult.getRetinfo());
                     }
 
                     //执行execute方法

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

@@ -40,25 +40,7 @@ public enum ERPModule {
 
     ADDRESSPARSER(153, "addressparser", "地址解析", "", "addressparser"),
 
-    BOXCALC(154, "boxcalc", "包数计算", "", "boxcalc"),
-
-    DNY(200, "dny", "都能运", "", "dny"),
-
-    DNY_ORDER(201, "dnyOrder", "都能运订单", "", "dny"),
-
-    DNY_BILL(202, "dnyBill", "都能运发货单", "", "dny"),
-
-    DNY_BILL_SEARCH(203, "dnyBillSearch", "都能运发货单查询", "", "dny"),
-
-    DNY_ORDER_SEARCH(204, "dnyOrderSearch", "都能运订单查询", "", "dny"),
-
-    DNY_FINANCE(205, "dnyFinance", "都能运财务", "", "dny"),
-
-    DNY_PRODUCT(206, "dnyProduct", "都能运产品档案", "", "dny"),
-
-    DNY_ORDER_PAY(207, "dnyOrderPay", "都能运订单在线收款", "", "dny"),
-
-    DNY_DATA_SYNC(208, "dnyDataSync", "都能运数据库同步ES", "", "dny");
+    EXPRESS_API(200, "expressApi", "配送平台接口", "", "expressApi");
 
 
     private int value;

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

@@ -42,7 +42,7 @@ public class ESKeys {
     /**
      * 操作记录
      */
-    public static final String ESOPLOG_INDEX = "aeerp_oplog";
+    public static final String ESOPLOG_INDEX = "dderp_oplog";
 
 
     /**

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

@@ -287,6 +287,16 @@ public class RedisKeys {
 
     //endregion
 
+    //region 锁定数据
+
+    //顺丰同城订单
+    public static final String KEY_ERP_WORKING_SF_ORDER = "redis.erp.working.express.sf.order";
+
+    //顺丰同城店铺
+    public static final String KEY_ERP_WORKING_SF_STORE = "redis.erp.working.express.sf.store";
+
+    //endregion
+
     private RedisKeys() {
     }
 }

+ 27 - 0
ddCommon/src/main/java/com/dderp/common/entity/express/SFCreateOrderResult.java

@@ -0,0 +1,27 @@
+package com.dderp.common.entity.express;
+
+import com.dderp.common.entity.base.BaseEntity;
+
+public class SFCreateOrderResult extends BaseEntity {
+
+    private int error_code;
+
+    private String error_msg;
+
+
+    public int getError_code() {
+        return error_code;
+    }
+
+    public void setError_code(int error_code) {
+        this.error_code = error_code;
+    }
+
+    public String getError_msg() {
+        return error_msg;
+    }
+
+    public void setError_msg(String error_msg) {
+        this.error_msg = error_msg;
+    }
+}

+ 613 - 0
ddCommon/src/main/java/com/dderp/common/entity/express/SFOrder.java

@@ -0,0 +1,613 @@
+package com.dderp.common.entity.express;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+import com.dderp.common.entity.base.BaseEntity;
+import com.sweetfish.util.Comment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 顺丰同城订单信息
+ */
+public class SFOrder extends BaseEntity {
+
+    @Comment("同城开发者ID")
+    private long dev_id;
+
+    @Comment("店铺ID")
+    private String shop_id;
+
+    @Comment("店铺ID类型 1:顺丰店铺ID ;2:接入方店铺ID")
+    private int shop_type;
+
+    @Comment("商家订单号")
+    private String shop_order_id;
+
+    @Comment("商家预计备餐时长")
+    private long shop_preparation_time;
+
+    @Comment("商家订单号")
+    private String order_source;
+
+    @Comment("商家订单号")
+    private String order_sequence;
+
+    @Comment("商家订单号")
+    private int lbs_type;
+
+    @Comment("商家订单号")
+    private long order_time;
+
+    @Comment("商家订单号")
+    private int is_appoint;
+
+    @Comment("商家订单号")
+    private int appoint_type;
+
+    @Comment("商家订单号")
+    private long expect_time;
+
+    @Comment("商家订单号")
+    private long expect_pickup_time;
+
+    @Comment("商家订单号")
+    private String shop_expect_time;
+
+    @Comment("商家订单号")
+    private int is_insured;
+
+    @Comment("商家订单号")
+    private int is_person_direct;
+
+    @Comment("商家订单号")
+    @JSONField(serialize = false)
+    private int vehicle;
+
+    @Comment("车型")
+    @JSONField(serialize = false)
+    private int four_wheeler_type;
+
+    @Comment("保价金额")
+    private long declared_value;
+
+    @Comment("订单小费,不传或者传0为不加小费")
+    private long gratuity_fee;
+
+    @Comment("订单备注")
+    private String remark;
+
+    @Comment("物流流向")
+    private long rider_pick_method;
+
+    @Comment("返回字段控制标志位(二进制)")
+    private int return_flag;
+
+    @Comment("是否发送取件码、收件码")
+    private int verify_code_type;
+
+    @Comment("推单时间")
+    private long push_time;
+
+    @Comment("订单版本号")
+    private long order_ver;
+
+    @Comment("版本号")
+    private long version;
+
+    @Comment("收货人信息")
+    private SFOrderReceive receive;
+
+    @Comment("发货店铺信息")
+    private SFOrderShop shop;
+
+    @Comment("订单详情")
+    private SFOrderDetail order_detail;
+
+    @Comment("多点取货信息")
+    private List<SFOrderPickupInfo> multi_pickup_info = new ArrayList<>();
+
+    @Comment("骑手token")
+    private String rider_token;
+
+    public SFOrder() {
+    }
+
+    private SFOrder(Builder builder) {
+        setDev_id(builder.dev_id);
+        setShop_id(builder.shop_id);
+        setShop_type(builder.shop_type);
+        setShop_order_id(builder.shop_order_id);
+        setShop_preparation_time(builder.shop_preparation_time);
+        setOrder_source(builder.order_source);
+        setOrder_sequence(builder.order_sequence);
+        setLbs_type(builder.lbs_type);
+        setOrder_time(builder.order_time);
+        setIs_appoint(builder.is_appoint);
+        setAppoint_type(builder.appoint_type);
+        setExpect_time(builder.expect_time);
+        setExpect_pickup_time(builder.expect_pickup_time);
+        setShop_expect_time(builder.shop_expect_time);
+        setIs_insured(builder.is_insured);
+        setIs_person_direct(builder.is_person_direct);
+        setVehicle(builder.vehicle);
+        setFour_wheeler_type(builder.four_wheeler_type);
+        setDeclared_value(builder.declared_value);
+        setGratuity_fee(builder.gratuity_fee);
+        setRemark(builder.remark);
+        setRider_pick_method(builder.rider_pick_method);
+        setReturn_flag(builder.return_flag);
+        setVerify_code_type(builder.verify_code_type);
+        setPush_time(builder.push_time);
+        setOrder_ver(builder.order_ver);
+        setVersion(builder.version);
+        setReceive(builder.receive);
+        setShop(builder.shop);
+        setOrder_detail(builder.order_detail);
+        setMulti_pickup_info(builder.multi_pickup_info);
+        setRider_token(builder.rider_token);
+    }
+
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+
+    public long getDev_id() {
+        return dev_id;
+    }
+
+    public void setDev_id(long dev_id) {
+        this.dev_id = dev_id;
+    }
+
+    public String getShop_id() {
+        return shop_id;
+    }
+
+    public void setShop_id(String shop_id) {
+        this.shop_id = shop_id;
+    }
+
+    public int getShop_type() {
+        return shop_type;
+    }
+
+    public void setShop_type(int shop_type) {
+        this.shop_type = shop_type;
+    }
+
+    public String getShop_order_id() {
+        return shop_order_id;
+    }
+
+    public void setShop_order_id(String shop_order_id) {
+        this.shop_order_id = shop_order_id;
+    }
+
+    public long getShop_preparation_time() {
+        return shop_preparation_time;
+    }
+
+    public void setShop_preparation_time(long shop_preparation_time) {
+        this.shop_preparation_time = shop_preparation_time;
+    }
+
+    public String getOrder_source() {
+        return order_source;
+    }
+
+    public void setOrder_source(String order_source) {
+        this.order_source = order_source;
+    }
+
+    public String getOrder_sequence() {
+        return order_sequence;
+    }
+
+    public void setOrder_sequence(String order_sequence) {
+        this.order_sequence = order_sequence;
+    }
+
+    public int getLbs_type() {
+        return lbs_type;
+    }
+
+    public void setLbs_type(int lbs_type) {
+        this.lbs_type = lbs_type;
+    }
+
+    public long getOrder_time() {
+        return order_time;
+    }
+
+    public void setOrder_time(long order_time) {
+        this.order_time = order_time;
+    }
+
+    public int getIs_appoint() {
+        return is_appoint;
+    }
+
+    public void setIs_appoint(int is_appoint) {
+        this.is_appoint = is_appoint;
+    }
+
+    public int getAppoint_type() {
+        return appoint_type;
+    }
+
+    public void setAppoint_type(int appoint_type) {
+        this.appoint_type = appoint_type;
+    }
+
+    public long getExpect_time() {
+        return expect_time;
+    }
+
+    public void setExpect_time(long expect_time) {
+        this.expect_time = expect_time;
+    }
+
+    public long getExpect_pickup_time() {
+        return expect_pickup_time;
+    }
+
+    public void setExpect_pickup_time(long expect_pickup_time) {
+        this.expect_pickup_time = expect_pickup_time;
+    }
+
+    public String getShop_expect_time() {
+        return shop_expect_time;
+    }
+
+    public void setShop_expect_time(String shop_expect_time) {
+        this.shop_expect_time = shop_expect_time;
+    }
+
+    public int getIs_insured() {
+        return is_insured;
+    }
+
+    public void setIs_insured(int is_insured) {
+        this.is_insured = is_insured;
+    }
+
+    public int getIs_person_direct() {
+        return is_person_direct;
+    }
+
+    public void setIs_person_direct(int is_person_direct) {
+        this.is_person_direct = is_person_direct;
+    }
+
+    public int getVehicle() {
+        return vehicle;
+    }
+
+    public void setVehicle(int vehicle) {
+        this.vehicle = vehicle;
+    }
+
+    public int getFour_wheeler_type() {
+        return four_wheeler_type;
+    }
+
+    public void setFour_wheeler_type(int four_wheeler_type) {
+        this.four_wheeler_type = four_wheeler_type;
+    }
+
+    public long getDeclared_value() {
+        return declared_value;
+    }
+
+    public void setDeclared_value(long declared_value) {
+        this.declared_value = declared_value;
+    }
+
+    public long getGratuity_fee() {
+        return gratuity_fee;
+    }
+
+    public void setGratuity_fee(long gratuity_fee) {
+        this.gratuity_fee = gratuity_fee;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public long getRider_pick_method() {
+        return rider_pick_method;
+    }
+
+    public void setRider_pick_method(long rider_pick_method) {
+        this.rider_pick_method = rider_pick_method;
+    }
+
+    public int getReturn_flag() {
+        return return_flag;
+    }
+
+    public void setReturn_flag(int return_flag) {
+        this.return_flag = return_flag;
+    }
+
+    public int getVerify_code_type() {
+        return verify_code_type;
+    }
+
+    public void setVerify_code_type(int verify_code_type) {
+        this.verify_code_type = verify_code_type;
+    }
+
+    public long getPush_time() {
+        return push_time;
+    }
+
+    public void setPush_time(long push_time) {
+        this.push_time = push_time;
+    }
+
+    public long getOrder_ver() {
+        return order_ver;
+    }
+
+    public void setOrder_ver(long order_ver) {
+        this.order_ver = order_ver;
+    }
+
+    public long getVersion() {
+        return version;
+    }
+
+    public void setVersion(long version) {
+        this.version = version;
+    }
+
+    public SFOrderReceive getReceive() {
+        return receive;
+    }
+
+    public void setReceive(SFOrderReceive receive) {
+        this.receive = receive;
+    }
+
+    public SFOrderShop getShop() {
+        return shop;
+    }
+
+    public void setShop(SFOrderShop shop) {
+        this.shop = shop;
+    }
+
+    public SFOrderDetail getOrder_detail() {
+        return order_detail;
+    }
+
+    public void setOrder_detail(SFOrderDetail order_detail) {
+        this.order_detail = order_detail;
+    }
+
+    public List<SFOrderPickupInfo> getMulti_pickup_info() {
+        return multi_pickup_info;
+    }
+
+    public void setMulti_pickup_info(List<SFOrderPickupInfo> multi_pickup_info) {
+        this.multi_pickup_info = multi_pickup_info;
+    }
+
+    public String getRider_token() {
+        return rider_token;
+    }
+
+    public void setRider_token(String rider_token) {
+        this.rider_token = rider_token;
+    }
+
+    public static final class Builder {
+        private long dev_id;
+        private String shop_id;
+        private int shop_type;
+        private String shop_order_id;
+        private long shop_preparation_time;
+        private String order_source;
+        private String order_sequence;
+        private int lbs_type;
+        private long order_time;
+        private int is_appoint;
+        private int appoint_type;
+        private long expect_time;
+        private long expect_pickup_time;
+        private String shop_expect_time;
+        private int is_insured;
+        private int is_person_direct;
+        private int vehicle;
+        private int four_wheeler_type;
+        private long declared_value;
+        private long gratuity_fee;
+        private String remark;
+        private long rider_pick_method;
+        private int return_flag;
+        private int verify_code_type;
+        private long push_time;
+        private long order_ver;
+        private long version;
+        private SFOrderReceive receive;
+        private SFOrderShop shop;
+        private SFOrderDetail order_detail;
+        private List<SFOrderPickupInfo> multi_pickup_info;
+        private String rider_token;
+
+        private Builder() {
+        }
+
+        public Builder dev_id(long val) {
+            dev_id = val;
+            return this;
+        }
+
+        public Builder shop_id(String val) {
+            shop_id = val;
+            return this;
+        }
+
+        public Builder shop_type(int val) {
+            shop_type = val;
+            return this;
+        }
+
+        public Builder shop_order_id(String val) {
+            shop_order_id = val;
+            return this;
+        }
+
+        public Builder shop_preparation_time(long val) {
+            shop_preparation_time = val;
+            return this;
+        }
+
+        public Builder order_source(String val) {
+            order_source = val;
+            return this;
+        }
+
+        public Builder order_sequence(String val) {
+            order_sequence = val;
+            return this;
+        }
+
+        public Builder lbs_type(int val) {
+            lbs_type = val;
+            return this;
+        }
+
+        public Builder order_time(long val) {
+            order_time = val;
+            return this;
+        }
+
+        public Builder is_appoint(int val) {
+            is_appoint = val;
+            return this;
+        }
+
+        public Builder appoint_type(int val) {
+            appoint_type = val;
+            return this;
+        }
+
+        public Builder expect_time(long val) {
+            expect_time = val;
+            return this;
+        }
+
+        public Builder expect_pickup_time(long val) {
+            expect_pickup_time = val;
+            return this;
+        }
+
+        public Builder shop_expect_time(String val) {
+            shop_expect_time = val;
+            return this;
+        }
+
+        public Builder is_insured(int val) {
+            is_insured = val;
+            return this;
+        }
+
+        public Builder is_person_direct(int val) {
+            is_person_direct = val;
+            return this;
+        }
+
+        public Builder vehicle(int val) {
+            vehicle = val;
+            return this;
+        }
+
+        public Builder four_wheeler_type(int val) {
+            four_wheeler_type = val;
+            return this;
+        }
+
+        public Builder declared_value(long val) {
+            declared_value = val;
+            return this;
+        }
+
+        public Builder gratuity_fee(long val) {
+            gratuity_fee = val;
+            return this;
+        }
+
+        public Builder remark(String val) {
+            remark = val;
+            return this;
+        }
+
+        public Builder rider_pick_method(long val) {
+            rider_pick_method = val;
+            return this;
+        }
+
+        public Builder return_flag(int val) {
+            return_flag = val;
+            return this;
+        }
+
+        public Builder verify_code_type(int val) {
+            verify_code_type = val;
+            return this;
+        }
+
+        public Builder push_time(long val) {
+            push_time = val;
+            return this;
+        }
+
+        public Builder order_ver(long val) {
+            order_ver = val;
+            return this;
+        }
+
+        public Builder version(long val) {
+            version = val;
+            return this;
+        }
+
+        public Builder receive(SFOrderReceive val) {
+            receive = val;
+            return this;
+        }
+
+        public Builder shop(SFOrderShop val) {
+            shop = val;
+            return this;
+        }
+
+        public Builder order_detail(SFOrderDetail val) {
+            order_detail = val;
+            return this;
+        }
+
+        public Builder multi_pickup_info(List<SFOrderPickupInfo> val) {
+            multi_pickup_info = val;
+            return this;
+        }
+
+        public Builder rider_token(String val) {
+            rider_token = val;
+            return this;
+        }
+
+        public SFOrder build() {
+            return new SFOrder(this);
+        }
+    }
+}

+ 211 - 0
ddCommon/src/main/java/com/dderp/common/entity/express/SFOrderDetail.java

@@ -0,0 +1,211 @@
+package com.dderp.common.entity.express;
+
+import com.dderp.common.entity.base.BaseEntity;
+import com.sweetfish.util.Comment;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SFOrderDetail extends BaseEntity {
+
+    @Comment("用户订单商品总金额(单位:分)")
+    private long total_price;
+
+    @Comment("物品类型")
+    private long product_type;
+
+    @Comment("用户实付商家金额(单位:分)")
+    private long user_money;
+
+    @Comment("商家实收用户金额(单位:分)")
+    private long shop_money;
+
+    @Comment("物品重量(单位:克)")
+    private long weight_gram;
+
+    @Comment("物品体积(单位:升)")
+    private long volume_litre;
+
+    @Comment("商家收取用户的配送费(单位:分)")
+    private long delivery_money;
+
+    @Comment("物品个数")
+    private long product_num;
+
+    @Comment("物品种类个数")
+    private long product_type_num;
+
+    @Comment("物品详情")
+    private List<SFOrderProductDetail> product_detail = new ArrayList<>();
+
+    public SFOrderDetail() {
+    }
+
+    private SFOrderDetail(Builder builder) {
+        setTotal_price(builder.total_price);
+        setProduct_type(builder.product_type);
+        setUser_money(builder.user_money);
+        setShop_money(builder.shop_money);
+        setWeight_gram(builder.weight_gram);
+        setVolume_litre(builder.volume_litre);
+        setDelivery_money(builder.delivery_money);
+        setProduct_num(builder.product_num);
+        setProduct_type_num(builder.product_type_num);
+        setProduct_detail(builder.product_detail);
+    }
+
+    public static Builder newBuilder() {
+        return new Builder();
+    }
+
+
+    public long getTotal_price() {
+        return total_price;
+    }
+
+    public void setTotal_price(long total_price) {
+        this.total_price = total_price;
+    }
+
+    public long getProduct_type() {
+        return product_type;
+    }
+
+    public void setProduct_type(long product_type) {
+        this.product_type = product_type;
+    }
+
+    public long getUser_money() {
+        return user_money;
+    }
+
+    public void setUser_money(long user_money) {
+        this.user_money = user_money;
+    }
+
+    public long getShop_money() {
+        return shop_money;
+    }
+
+    public void setShop_money(long shop_money) {
+        this.shop_money = shop_money;
+    }
+
+    public long getWeight_gram() {
+        return weight_gram;
+    }
+
+    public void setWeight_gram(long weight_gram) {
+        this.weight_gram = weight_gram;
+    }
+
+    public long getVolume_litre() {
+        return volume_litre;
+    }
+
+    public void setVolume_litre(long volume_litre) {
+        this.volume_litre = volume_litre;
+    }
+
+    public long getDelivery_money() {
+        return delivery_money;
+    }
+
+    public void setDelivery_money(long delivery_money) {
+        this.delivery_money = delivery_money;
+    }
+
+    public long getProduct_num() {
+        return product_num;
+    }
+
+    public void setProduct_num(long product_num) {
+        this.product_num = product_num;
+    }
+
+    public long getProduct_type_num() {
+        return product_type_num;
+    }
+
+    public void setProduct_type_num(long product_type_num) {
+        this.product_type_num = product_type_num;
+    }
+
+    public List<SFOrderProductDetail> getProduct_detail() {
+        return product_detail;
+    }
+
+    public void setProduct_detail(List<SFOrderProductDetail> product_detail) {
+        this.product_detail = product_detail;
+    }
+
+    public static final class Builder {
+        private long total_price;
+        private long product_type;
+        private long user_money;
+        private long shop_money;
+        private long weight_gram;
+        private long volume_litre;
+        private long delivery_money;
+        private long product_num;
+        private long product_type_num;
+        private List<SFOrderProductDetail> product_detail;
+
+        private Builder() {
+        }
+
+        public Builder total_price(long val) {
+            total_price = val;
+            return this;
+        }
+
+        public Builder product_type(long val) {
+            product_type = val;
+            return this;
+        }
+
+        public Builder user_money(long val) {
+            user_money = val;
+            return this;
+        }
+
+        public Builder shop_money(long val) {
+            shop_money = val;
+            return this;
+        }
+
+        public Builder weight_gram(long val) {
+            weight_gram = val;
+            return this;
+        }
+
+        public Builder volume_litre(long val) {
+            volume_litre = val;
+            return this;
+        }
+
+        public Builder delivery_money(long val) {
+            delivery_money = val;
+            return this;
+        }
+
+        public Builder product_num(long val) {
+            product_num = val;
+            return this;
+        }
+
+        public Builder product_type_num(long val) {
+            product_type_num = val;
+            return this;
+        }
+
+        public Builder product_detail(List<SFOrderProductDetail> val) {
+            product_detail = val;
+            return this;
+        }
+
+        public SFOrderDetail build() {
+            return new SFOrderDetail(this);
+        }
+    }
+}

+ 73 - 0
ddCommon/src/main/java/com/dderp/common/entity/express/SFOrderPickupInfo.java

@@ -0,0 +1,73 @@
+package com.dderp.common.entity.express;
+
+import com.dderp.common.entity.base.BaseEntity;
+import com.sweetfish.util.Comment;
+
+public class SFOrderPickupInfo extends BaseEntity {
+
+    @Comment("取货点地址")
+    private String pickup_shop_address;
+
+    @Comment("取货点店铺手机号")
+    private String pickup_shop_phone;
+
+    @Comment("取货点店铺名称")
+    private String pickup_shop_name;
+
+    @Comment("取货点经度")
+    private String pickup_lng;
+
+    @Comment("取货点纬度")
+    private String pickup_lat;
+
+    @Comment("取货点店铺物品信息")
+    private String pickup_products;
+
+    public String getPickup_shop_address() {
+        return pickup_shop_address;
+    }
+
+    public void setPickup_shop_address(String pickup_shop_address) {
+        this.pickup_shop_address = pickup_shop_address;
+    }
+
+    public String getPickup_shop_phone() {
+        return pickup_shop_phone;
+    }
+
+    public void setPickup_shop_phone(String pickup_shop_phone) {
+        this.pickup_shop_phone = pickup_shop_phone;
+    }
+
+    public String getPickup_shop_name() {
+        return pickup_shop_name;
+    }
+
+    public void setPickup_shop_name(String pickup_shop_name) {
+        this.pickup_shop_name = pickup_shop_name;
+    }
+
+    public String getPickup_lng() {
+        return pickup_lng;
+    }
+
+    public void setPickup_lng(String pickup_lng) {
+        this.pickup_lng = pickup_lng;
+    }
+
+    public String getPickup_lat() {
+        return pickup_lat;
+    }
+
+    public void setPickup_lat(String pickup_lat) {
+        this.pickup_lat = pickup_lat;
+    }
+
+    public String getPickup_products() {
+        return pickup_products;
+    }
+
+    public void setPickup_products(String pickup_products) {
+        this.pickup_products = pickup_products;
+    }
+}

+ 84 - 0
ddCommon/src/main/java/com/dderp/common/entity/express/SFOrderProductDetail.java

@@ -0,0 +1,84 @@
+package com.dderp.common.entity.express;
+
+import com.dderp.common.entity.base.BaseEntity;
+import com.sweetfish.util.Comment;
+
+public class SFOrderProductDetail extends BaseEntity {
+
+    @Comment("物品名称")
+    private String product_name;
+
+    @Comment("物品ID")
+    private long product_id;
+
+    @Comment("物品数量")
+    private long product_num;
+
+    @Comment("物品价格")
+    private long product_price;
+
+    @Comment("物品单位")
+    private String product_unit;
+
+    @Comment("备注")
+    private String product_remark;
+
+    @Comment("详情")
+    private String item_detail;
+
+    public String getProduct_name() {
+        return product_name;
+    }
+
+    public void setProduct_name(String product_name) {
+        this.product_name = product_name;
+    }
+
+    public long getProduct_id() {
+        return product_id;
+    }
+
+    public void setProduct_id(long product_id) {
+        this.product_id = product_id;
+    }
+
+    public long getProduct_num() {
+        return product_num;
+    }
+
+    public void setProduct_num(long product_num) {
+        this.product_num = product_num;
+    }
+
+    public long getProduct_price() {
+        return product_price;
+    }
+
+    public void setProduct_price(long product_price) {
+        this.product_price = product_price;
+    }
+
+    public String getProduct_unit() {
+        return product_unit;
+    }
+
+    public void setProduct_unit(String product_unit) {
+        this.product_unit = product_unit;
+    }
+
+    public String getProduct_remark() {
+        return product_remark;
+    }
+
+    public void setProduct_remark(String product_remark) {
+        this.product_remark = product_remark;
+    }
+
+    public String getItem_detail() {
+        return item_detail;
+    }
+
+    public void setItem_detail(String item_detail) {
+        this.item_detail = item_detail;
+    }
+}

+ 73 - 0
ddCommon/src/main/java/com/dderp/common/entity/express/SFOrderReceive.java

@@ -0,0 +1,73 @@
+package com.dderp.common.entity.express;
+
+import com.dderp.common.entity.base.BaseEntity;
+import com.sweetfish.util.Comment;
+
+public class SFOrderReceive extends BaseEntity {
+
+    @Comment("用户姓名")
+    private String user_name;
+
+    @Comment("用户电话")
+    private String user_phone;
+
+    @Comment("用户地址")
+    private String user_address;
+
+    @Comment("用户经度")
+    private String user_lng;
+
+    @Comment("用户纬度")
+    private String user_lat;
+
+    @Comment("发单城市")
+    private String city_name;
+
+    public String getUser_name() {
+        return user_name;
+    }
+
+    public void setUser_name(String user_name) {
+        this.user_name = user_name;
+    }
+
+    public String getUser_phone() {
+        return user_phone;
+    }
+
+    public void setUser_phone(String user_phone) {
+        this.user_phone = user_phone;
+    }
+
+    public String getUser_address() {
+        return user_address;
+    }
+
+    public void setUser_address(String user_address) {
+        this.user_address = user_address;
+    }
+
+    public String getUser_lng() {
+        return user_lng;
+    }
+
+    public void setUser_lng(String user_lng) {
+        this.user_lng = user_lng;
+    }
+
+    public String getUser_lat() {
+        return user_lat;
+    }
+
+    public void setUser_lat(String user_lat) {
+        this.user_lat = user_lat;
+    }
+
+    public String getCity_name() {
+        return city_name;
+    }
+
+    public void setCity_name(String city_name) {
+        this.city_name = city_name;
+    }
+}

+ 62 - 0
ddCommon/src/main/java/com/dderp/common/entity/express/SFOrderShop.java

@@ -0,0 +1,62 @@
+package com.dderp.common.entity.express;
+
+import com.dderp.common.entity.base.BaseEntity;
+import com.sweetfish.util.Comment;
+
+public class SFOrderShop extends BaseEntity {
+
+    @Comment("店铺名称")
+    private String shop_name;
+
+    @Comment("店铺电话")
+    private String shop_phone;
+
+    @Comment("店铺地址")
+    private String shop_address;
+
+    @Comment("店铺经度")
+    private String shop_lng;
+
+    @Comment("店铺纬度")
+    private String shop_lat;
+
+    public String getShop_name() {
+        return shop_name;
+    }
+
+    public void setShop_name(String shop_name) {
+        this.shop_name = shop_name;
+    }
+
+    public String getShop_phone() {
+        return shop_phone;
+    }
+
+    public void setShop_phone(String shop_phone) {
+        this.shop_phone = shop_phone;
+    }
+
+    public String getShop_address() {
+        return shop_address;
+    }
+
+    public void setShop_address(String shop_address) {
+        this.shop_address = shop_address;
+    }
+
+    public String getShop_lng() {
+        return shop_lng;
+    }
+
+    public void setShop_lng(String shop_lng) {
+        this.shop_lng = shop_lng;
+    }
+
+    public String getShop_lat() {
+        return shop_lat;
+    }
+
+    public void setShop_lat(String shop_lat) {
+        this.shop_lat = shop_lat;
+    }
+}

+ 42 - 0
ddWebCore/src/main/java/com/dderp/webcore/rest/flycat/ExpressOutRest.java

@@ -0,0 +1,42 @@
+package com.dderp.webcore.rest.flycat;
+
+import com.dderp.common.api.flycat.ExpressOutService;
+import com.dderp.common.base.BaseService;
+import com.dderp.common.datas.ERPHeader;
+import com.dderp.common.entity.base.ProcessStringItem;
+import com.dderp.common.entity.site.ERPTokenUser;
+import com.dySweetFishPlugin.sql.RMapUtils;
+import com.sweetfish.net.http.RestHeader;
+import com.sweetfish.net.http.RestMapping;
+import com.sweetfish.net.http.RestParam;
+import com.sweetfish.net.http.RestService;
+import com.sweetfish.service.Local;
+import com.sweetfish.service.RetResult;
+import com.sweetfish.util.AutoLoad;
+import org.rex.RMap;
+
+import javax.annotation.Resource;
+import java.util.concurrent.CompletableFuture;
+
+@AutoLoad(false)
+@Local
+@RestService(name = "eout", moduleid = 200, comment = "快递配送服务")
+@SuppressWarnings({"rawtypes", "unused"})
+public class ExpressOutRest extends BaseService {
+
+    @Resource
+    ExpressOutService expressOutService;
+
+    @RestMapping(name = "testExpress", sort = 1, comment = "测试", methods = {"GET", "POST"})
+    public CompletableFuture<RMap> testExpress(
+            @RestParam(name = "&", comment = "登录用户,无需传入") ERPTokenUser currentUser,
+            @RestHeader(name = ERPHeader.HTTPHEADER_DATASOURCE) String dataSourceId,
+            @RestHeader(name = ERPHeader.HTTPHEADER_SUPPLIER) String supplierCode) {
+        return CompletableFuture.supplyAsync(
+                () -> {
+                    RetResult<ProcessStringItem> infoResult = expressOutService.test(dataSourceId, Long.parseLong(supplierCode));
+                    return RMapUtils.successV2(infoResult, null, null);
+                }, getExecutor()
+        );
+    }
+}

+ 74 - 0
ddWebCore/src/main/java/com/dderp/webcore/servlet/ExpressCallServlet.java

@@ -1,14 +1,25 @@
 package com.dderp.webcore.servlet;
 
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.dderp.common.api.flycat.ExpressOutService;
+import com.dderp.common.datas.ERPHeader;
+import com.dderp.common.entity.base.InvokeCallParams;
 import com.dderp.common.entity.express.ExpressCallResult;
 import com.dderp.common.entity.site.ERPTokenUser;
+import com.dderp.common.tool.ERPUtils;
 import com.sweetfish.net.WorkThread;
 import com.sweetfish.net.http.*;
 import com.sweetfish.util.AnyValue;
 import com.sweetfish.util.AutoLoad;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.StringUtils;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
+import javax.annotation.Resource;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.ForkJoinPool;
 
@@ -17,6 +28,15 @@ import java.util.concurrent.ForkJoinPool;
 @HttpUserType(ERPTokenUser.class)
 public class ExpressCallServlet extends HttpServlet {
 
+    @Resource(name = "property.sftc.appId")
+    private long sfAppId;
+
+    @Resource(name = "property.sftc.appKey")
+    private String sfAppKey;
+
+    @Resource
+    ExpressOutService expressOutService;
+
     private final Logger logger = LogManager.getLogger(this.getClass().getSimpleName());
 
     private ExecutorService getExecutor() {
@@ -37,12 +57,66 @@ public class ExpressCallServlet extends HttpServlet {
         super.destroy(context, config);
     }
 
+    private String sfGenerateOpenSign(String postData, Long appId, String appKey) {
+        try {
+            String sb = postData +
+                    "&" + appId + "&" + appKey;
+            MessageDigest md = MessageDigest.getInstance("MD5");
+            byte[] md5 = md.digest(sb.getBytes(StandardCharsets.UTF_8));
+            int i;
+            StringBuilder buf = new StringBuilder();
+            for (int offset = 0; offset < md5.length; offset++) {
+                i = md5[offset];
+                if (i < 0) {
+                    i += 256;
+                }
+                if (i < 16) {
+                    buf.append("0");
+                }
+                buf.append(Integer.toHexString(i));
+            }
+            return Base64.encodeBase64String(buf.toString().getBytes(StandardCharsets.UTF_8));
+        } catch (Exception e) {
+            return "";
+        }
+    }
+
     //当前查看顺丰的回调,没有字段体现出顺丰的接口,大概每个快递平台需要不同的地址提供回调,顺丰的回调可以通过url_index来判断回调的业务
 
     @HttpMapping(url = "/express/sfCall", methods = {"POST", "GET"}, comment = "回调入口")
     public void sfCall(HttpRequest request, HttpResponse response) {
         //简单的入口,估计也没多少接口提供出去,这里多加一层方法包一下,是担心后续会修改
         logger.info(request);
+
+        //验证签名,防止乱post
+        String body = request.getBodyUTF8();
+        String currentSign = sfGenerateOpenSign(body, sfAppId, sfAppKey);
+        String orginSign = request.getParameter("sign", "");
+        if (!StringUtils.equals(currentSign, orginSign)) {
+            logger.error("签名错误");
+            response.finish(ExpressCallResult.success());
+            return;
+        }
+
+        String dataSourceId = request.getHeader(ERPHeader.HTTPHEADER_DATASOURCE, "");
+        long supplierCode = request.getLongHeader(ERPHeader.HTTPHEADER_SUPPLIER, 0L);
+
+        if ((StringUtils.isBlank(dataSourceId)) || (supplierCode <= 0L)) {
+            response.finish(ExpressCallResult.success());
+            return;
+        }
+
+        //其它平台看了两个,好像都只有一个回调,就顺丰有一堆回调,这里统一,让脚本里面分开处理,脚本大点就大点吧
+
+        InvokeCallParams callParams = InvokeCallParams.newBuilder()
+                .businessMethod("Express_OrderStatusInvoke_SFTC")
+                .params(body)
+                .currentUser(ERPUtils.getSysTokenUser())
+                .dataSourceId(dataSourceId)
+                .supplierCode(supplierCode)
+                .build();
+        expressOutService.callExpress(callParams, ERPUtils.getSysTokenUser(), dataSourceId, supplierCode);
+
         response.finish(ExpressCallResult.success());
     }
 }