瀏覽代碼

1.顺丰跑腿平台新增查询门店与门店修改接口
2.顺丰跑腿平台在查询门店时,会保存 is_person_direct -- 店铺是否支持专人直送,0不支持 1支持 2只能发独享专送
3.在跑腿询价请求中,顺丰跑腿要根据is_person_direct来判断请求专送还是非专送的询价

shizhongqi 7 月之前
父節點
當前提交
0bc2111f85

+ 32 - 0
app-ghs/controllers/DeliveryShopController.php

@@ -65,4 +65,36 @@ class DeliveryShopController extends BaseController
         }
         util::success('解绑门店成功');
     }
+
+    public function actionStoreDetail()
+    {
+        $post = Yii::$app->request->post();
+        $platform = $post['platform'];
+        $delivery = DeliveryAuthTokenClass::getByCondition(['platform'=>$platform, 'mainId'=>$this->mainId], true);
+        if(!$delivery){
+            util::fail('配送平台不存在');
+        }
+        $ShopService = new ShopService($this->mainId, $platform);
+        $re = $ShopService->storeDetail($this->mainId, $platform, $delivery->shopId);
+        if(!$re){
+            util::fail('获取门店详情失败');
+        }
+        util::success($re, '获取门店详情成功');
+    }
+
+    public function actionUpdateStore()
+    {
+        $post = Yii::$app->request->post();
+        $platform = $post['platform'];
+        $delivery = DeliveryAuthTokenClass::getByCondition(['platform'=>$platform, 'mainId'=>$this->mainId], true);
+        if(!$delivery){
+            util::fail('配送平台不存在');
+        }
+        $ShopService = new ShopService($this->mainId, $platform);
+        $re = $ShopService->updateStore($delivery->shopId, $platform, $post);
+        if(!$re){
+            util::fail('修改门店详情失败');
+        }
+        util::success($re, '修改门店详情成功');
+    }
 }

+ 31 - 16
common/components/delivery/platform/shunfeng/Shop.php

@@ -54,37 +54,52 @@ class Shop extends Shunfeng
     }
 
     /**
-     * 获取店铺信息
-     *
-     * 2025/2/17更新,返回参数更新,支持返回物流产品,详见logistic_type_list
-     * 开发者可通过该接⼝获取到店铺的基础信息(非连锁店铺可以额外获得等级信息和补贴信息)
-     *
-     * @param string $shopId 店铺ID
-     * @param int $shopType 店铺ID类型 1:顺丰店铺ID 2:接⼊⽅店铺ID
-     * @return mixed
+     * 更新店铺信息
+     * @param int $shopId 店铺id(新增店铺接⼝返回)
+     * @param array $post 更新的数据
      */
-    public function getShopInfo($shopId, $shopType = 1)
+    public function updateShop($shopId, $post)
     {
+        // 构建请求参数
         $params = [
+            'dev_id' => $this->devId,
             'shop_id' => $shopId,
-            'shop_type' => $shopType,
-            'push_time' => time()
+            'push_time' => time(),
+        ];
+
+        // 可选参数列表
+        $optionalFields = [
+            'out_shop_id',
+            'shop_name',
+            'shop_address',
+            'longitude',
+            'latitude',
+            'shop_contact_name',
+            'shop_contact_phone'
         ];
-        $response = $this->httpRequest('getshopinfo', $params);
+
+        foreach ($optionalFields as $field) {
+            if (isset($post[$field])) {
+                $params[$field] = $post[$field];
+            }
+        }
+
+        // 调用httpRequest方法发送请求
+        $response = $this->httpRequest('updateshop', $params);
 
         // 检查API响应
         if (isset($response['error_code']) && $response['error_code'] == 0) {
             return [
                 'success' => true,
-                'shop_info' => $response['result']['shop_info'] ?? [],
-                'message' => '获取店铺信息成功',
+                'message' => '店铺信息更新成功',
+                'result' => $response['result'] ?? null,
             ];
         }
 
         return [
             'success' => false,
-            'shop_info' => [],
-            'message' => $response['error_msg'] ?? '获取店铺信息失败',
+            'message' => $response['error_msg'] ?? '店铺信息更新失败',
+            'error_code' => $response['error_code'] ?? -1,
         ];
     }
 }

+ 69 - 5
common/components/delivery/platform/shunfeng/Shunfeng.php

@@ -3,6 +3,7 @@
 
 namespace common\components\delivery\platform\shunfeng;
 
+use bizGhs\express\classes\DeliveryAuthTokenClass;
 use common\components\delivery\helpers\HttpClient;
 
 /**
@@ -15,10 +16,13 @@ class Shunfeng
     protected $devId;
     protected $appSecret;
     protected $shopId;
-    protected $accessToken;
+    protected $deliveryAuthToken; // xhDeliveryAuthToken 表数据
     protected $apiVersion = 19;
 
-    public function __construct($accessToken = '', $shopId = 0)
+    // 自定义设置
+    protected $isPersonDirect = 0; // is_person_direct -- 店铺是否支持专人直送,0不支持 1支持 2只能发独享专送
+
+    public function __construct($deliveryAuthToken, $shopId = 0)
     {
         // 根据环境设置基础URL
         if (getenv('YII_ENV') == 'production') {
@@ -33,14 +37,74 @@ class Shunfeng
             $this->shopId = $shopId;
         }
 
-        // 配置信息(从Auth类获取)
-        $this->accessToken = $accessToken;
+        //保存 xhDeliveryAuthToken 表数据
+        $this->deliveryAuthToken = $deliveryAuthToken;
+
+        //自定义设置取出与设置
+        $customSettingsStr = $deliveryAuthToken['customSettings'];
+        $customSettings = json_decode($customSettingsStr, true);
+
+        if(isset($customSettings['is_person_direct'])){
+            $this->isPersonDirect = $customSettings['is_person_direct'];
+        }
+    }
+
+     /**
+     * 获取店铺信息
+     *
+     * 2025/2/17更新,返回参数更新,支持返回物流产品,详见logistic_type_list
+     * 开发者可通过该接⼝获取到店铺的基础信息(非连锁店铺可以额外获得等级信息和补贴信息)
+     *
+     * @param string $shopId 店铺ID
+     * @param int $shopType 店铺ID类型 1:顺丰店铺ID 2:接⼊⽅店铺ID
+     * @return mixed
+     */
+    public function getShopInfo($shopId=0, $shopType = 1)
+    {
+        if($shopId == 0){
+            $shopId = $this->shopId;
+        }
+        $params = [
+            'shop_id' => $shopId,
+            'shop_type' => $shopType,
+            'push_time' => time()
+        ];
+        $response = $this->httpRequest('getshopinfo', $params);
+
+        // 检查API响应
+        if (isset($response['error_code']) && $response['error_code'] == 0) {
+            // 更新自定义中的json数据
+            $delivery = DeliveryAuthTokenClass::getByCondition(['mainId'=>$this->deliveryAuthToken['mainId'], 'platform'=>'shunfeng'], true);
+            $customSettingsJson = $delivery->customSettings;
+            $customSettings = json_decode($customSettingsJson, true);
+            $customSettings['is_person_direct'] = $response['result']['shop_info']['is_person_direct']; // 店铺是否支持专人直送,0不支持 1支持 2只能发独享专送
+            $customSettingsJson = json_encode($customSettings);
+            $delivery->customSettings = $customSettingsJson;
+            $delivery->save();
+            
+            return [
+                'success' => true,
+                'shop_info' => $response['result']['shop_info'] ?? [],
+                'message' => '获取店铺信息成功',
+            ];
+        }
+
+        return [
+            'success' => false,
+            'shop_info' => [],
+            'message' => $response['error_msg'] ?? '获取店铺信息失败',
+        ];
+    }
+
+    public function getIsPersonDirect()
+    {
+        return $this->isPersonDirect;
     }
 
     /**
      * 构建API请求参数
      *
-     * 根据蜂鸟API规范构建完整的请求参数,包括签名
+     * 根据API规范构建完整的请求参数,包括签名
      *
      * @param string $method API方法名
      * @param array $businessData 业务参数

+ 38 - 14
common/components/delivery/services/DispatchService.php

@@ -48,12 +48,12 @@ class DispatchService
                         $this->adapters['fengniao'] = $adapter;
                         break;
                     case 'shunfeng':
-                        $this->adapters['shunfeng'] = new ShunfengAdapter($pt['accessToken'], $pt['shopId']);
+                        $this->adapters['shunfeng'] = new ShunfengAdapter($pt, $pt['shopId']);
                         break;
                     case 'dada':
-                        $this->adapters['dada'] = new DadaAdapter($pt['accessToken']);
-                        $this->adapters['dada']->setShopNo($pt['shopId']);
-                        $this->adapters['dada']->setSourceId($pt['merchantId']); // 用 merchanId 来保存 sourceId
+                        $this->adapters['dada'] = new DadaAdapter($pt['accessToken'], $pt['shopId']);
+                        //$this->adapters['dada']->setShopNo($pt['shopId']);
+                        //$this->adapters['dada']->setSourceId($pt['merchantId']); // 用 merchanId 来保存 sourceId
                         break;
                     case 'didi':
                         $this->adapters['didi'] = new DidiAdapter($pt['accessToken'], $pt['mainId']);
@@ -85,12 +85,12 @@ class DispatchService
                     $this->adapters['fengniao'] = $adapter;
                     break;
                 case 'shunfeng':
-                    $this->adapters['shunfeng'] = new ShunfengAdapter($authPlatform['accessToken'], $authPlatform['shopId']);
+                    $this->adapters['shunfeng'] = new ShunfengAdapter($authPlatform, $authPlatform['shopId']);
                     break;
                 case 'dada':
-                    $this->adapters['dada'] = new DadaAdapter($authPlatform['accessToken']);
-                    $this->adapters['dada']->setShopNo($authPlatform['shopId']);
-                    $this->adapters['dada']->setSourceId($authPlatform['merchantId']); // 用 merchanId 来保存 sourceId
+                    $this->adapters['dada'] = new DadaAdapter($authPlatform['accessToken'], $authPlatform['shopId']);
+                    //$this->adapters['dada']->setShopNo($authPlatform['shopId']);
+                    //$this->adapters['dada']->setSourceId($authPlatform['merchantId']); // 用 merchanId 来保存 sourceId
                     break;
                 case 'didi':
                     $this->adapters['didi'] = new DidiAdapter($authPlatform['accessToken'], $authPlatform['mainId']);
@@ -305,13 +305,21 @@ class DispatchService
         // 准备顺丰订单数据
         if (isset($this->adapters['shunfeng'])) {
             try {
-                //$customSettings = $this->adapters['shunfeng']->getCustomSettings();
-                $customSettings = [];//自定义用户设置:默认不专人直送
-                $preparedData['shunfeng'] = $this->prepareShunfengData($order, $shop, $customSettings);
+                /** @var ShunfengAdapter $adapter */
+                $adapter = $this->adapters['shunfeng'];
+                // is_person_direct -- 店铺是否支持专人直送,0不支持 1支持 2只能发独享专送
+                $isPersonDirect = $adapter->getIsPersonDirect();
+                if($isPersonDirect != 2){
+                    //$customSettings = $this->adapters['shunfeng']->getCustomSettings();
+                    $customSettings = [];//自定义用户设置:默认不专人直送
+                    $preparedData['shunfeng'] = $this->prepareShunfengData($order, $shop, $customSettings);
+                }
 
                 //添加专人直送的订单数据
-                $customSettings = ['isPersonDirect' => 1];//自定义用户设置:专人直送
-                $preparedData['shunfeng_1v1'] = $this->prepareShunfengData($order, $shop, $customSettings);
+                if(in_array($isPersonDirect, [1, 2])){
+                    $customSettings = ['isPersonDirect' => 1];//自定义用户设置:专人直送
+                    $preparedData['shunfeng_1v1'] = $this->prepareShunfengData($order, $shop, $customSettings);
+                }
             } catch (\Exception $e) {
                 Yii::warning("Shunfeng 数据准备失败: {$e->getMessage()}");
             }
@@ -749,6 +757,10 @@ class DispatchService
                             'vehicle_type' => $data['vehicle_type_list'][$vehicle_type_list_key]
                         ];
                         Yii::info("[DispatchService] {$platform} 报价成功");// . json_encode($quote));
+                    } else {
+                        $errorMsg = $quote['error'] ?? '报价返回数据为空';
+                        $results['failed'][$platform] = $errorMsg;
+                        Yii::warning("[DispatchService] {$platform} 报价返回错误: {$errorMsg}");
                     }
                 } else {
                     // 蜂鸟和闪送的响应处理
@@ -761,6 +773,16 @@ class DispatchService
                         $errorMsg = $quote['error'] ?? '报价返回数据为空';
                         $results['failed'][$platform] = $errorMsg;
                         Yii::warning("[DispatchService] {$platform} 报价返回错误: {$errorMsg}");
+
+                        if(strncmp($platform, 'shunfeng', 8) === 0) {
+                            /** @var ShunfengAdapter $adapter */
+                            if($errorMsg == '暂未开启专人直送服务') {
+                                $adapter->getShopInfo();
+                            }
+                            if($errorMsg == '当前店铺只能发独享专送') {
+                                $adapter->getShopInfo();
+                            }
+                        }
                     }
                 }
             } catch (\Throwable $e) {
@@ -976,13 +998,15 @@ class DispatchService
                         continue;
                     }
 
+                    $serviceType = [0 => '拼送', 1 => '直送'];
+
                     foreach($item['estimateList'] as $arr) {
                         $deliveryList[] = [
                             'name' => '滴滴' . ' (' . $this->adapters['didi']->carType($arr['carType']) . ')',
                             'en_name' => 'didi',
                             'price' => $arr['fee'],
                             'distance' => $arr['distance'],
-                            'type' => $arr['name'], //服务商或车型名称
+                            'type' => $serviceType[$arr['serviceType']], //服务商或车型名称
                             'isAble' => true,
                             // ---------------------------------------------
                             'estimateId' => $arr['estimateId'],

+ 77 - 8
common/components/delivery/services/ShopService.php

@@ -2,13 +2,15 @@
 namespace common\components\delivery\services;
 
 //商户账号绑定管理
+use common\components\delivery\platform\dada\Dada;
 use Yii;
 use bizGhs\express\classes\DeliveryAuthTokenClass;
 use common\components\delivery\platform\fengniao\Shop as FengniaoShop;
 use common\components\delivery\platform\huolala\Shop as HuolalaShop;
 use common\components\delivery\platform\shansong\Shop as ShansongShop;
 use common\components\delivery\platform\shunfeng\Shop as ShunfengShop;
-use common\components\delivery\services\adapter\FengniaoAdapter;
+use common\components\delivery\platform\didi\Didi;
+use common\components\util;
 
 /**
  * 聚合调度逻辑(平台选择/优先级)
@@ -27,7 +29,7 @@ class ShopService
             foreach($authPlatforms as $pt) {
                 switch($pt['platform']) {
                     case 'shansong':
-                        $this->adapters['shansong'] = new ShansongShop($pt['accessToken']);
+                        $this->adapters['shansong'] = new ShansongShop($pt['accessToken'], $pt['shopId']);
                         break;
                     case 'huolala':
                         $this->adapters['huolala'] = new HuolalaShop($pt['accessToken']);
@@ -39,7 +41,13 @@ class ShopService
                         $this->adapters['fengniao'] = $adapter;
                         break;
                     case 'shunfeng':
-                        $this->adapters['shunfeng'] = new ShunfengShop($pt['accessToken'], $pt['shopId']);
+                        $this->adapters['shunfeng'] = new ShunfengShop($pt, $pt['shopId']);
+                        break;
+                    case 'dada':
+                        $this->adapters['dada'] = new Dada($pt['accessToken'], $pt['shopId'], $pt['merchantId']);
+                        break;
+                    case 'didi':
+                        $this->adapters['didi'] = new Didi($pt['accessToken'], $pt['mainId']);
                         break;
                 }
             }
@@ -47,20 +55,25 @@ class ShopService
             $authPlatform = DeliveryAuthTokenClass::getByCondition(['mainId' => $mainId, 'platform' => $platform]);
             switch($platform) {
                 case 'shansong':
-                    $this->adapters['shansong'] = new ShansongShop($authPlatform['accessToken']);
+                    $this->adapters['shansong'] = new ShansongShop($authPlatform['accessToken'], $authPlatform['shopId']);
                     break;
                 case 'huolala':
                     $this->adapters['huolala'] = new HuolalaShop($authPlatform['accessToken']);
                     break;
                 case 'fengniao':
-                    //$this->adapters['fengniao'] = new FengniaoAdapter($authPlatform['accessToken']);
                     $adapter = new FengniaoShop($authPlatform['accessToken']);
                     $adapter->setMerchantId($authPlatform['merchantId']);
                     $adapter->setShopId($authPlatform['shopId']);
                     $this->adapters['fengniao'] = $adapter;
                     break;
                 case 'shunfeng':
-                    $this->adapters['shunfeng'] = new ShunfengShop($authPlatform['accessToken'], $authPlatform['shopId']);
+                    $this->adapters['shunfeng'] = new ShunfengShop($authPlatform, $authPlatform['shopId']);
+                    break;
+                case 'dada':
+                    $this->adapters['dada'] = new Dada($authPlatform['accessToken'], $authPlatform['shopId'], $authPlatform['merchantId']);
+                    break;
+                case 'didi':
+                    $this->adapters['didi'] = new Didi($authPlatform['accessToken'], $authPlatform['mainId']);
                     break;
             }
             $this->platformName = $platform;
@@ -77,22 +90,45 @@ class ShopService
         $ret = [];
         switch($platform) {
             case 'shansong':
+                /** @var ShansongShop $adapter */
                 $adapter = $this->adapters[$platform];
                 $ret = $adapter->getUserAccount();
                 break;
             case 'huolala':
+                /** @var HuolalaShop $adapter */
                 $adapter = $this->adapters[$platform];
                 $ret = $adapter->queryWalletBalance();
                 break;
             case 'fengniao':
+                /** @var FengniaoShop $adapter */
                 $adapter = $this->adapters[$platform];
                 $ret = $adapter->getShopAccountBalance();
                 break;
             case 'shunfeng':
+                /** @var ShunfengShop $adapter */
                 $adapter = $this->adapters[$platform];
                 $ret = $adapter->getShopAccountBalance();  
                 break;
+            case 'dada':
+                /** @var Dada $adapter */
+                $adapter = $this->adapters[$platform];
+                $ret = $adapter->balance();
+                break;
+            case 'didi':
+                /** @var Didi $adapter */
+                $adapter = $this->adapters[$platform];
+                $ret = $adapter->walletBalance();
+                break;
+            default:
+                Yii::error("查询用户余额的平台{$platform}不存在");
+                util::fail("查询用户余额的平台{$platform}不存在");
+        }
+
+        if($ret['success'] === false){
+            Yii::error("查询{$platform}帐户余额:{$ret['message']}");
+            util::fail("查询帐户余额失败: {$ret['message']}");
         }
+
         return $ret['balance'];
     }
 
@@ -146,13 +182,12 @@ class ShopService
             Yii::error('绑定门店失败: ' . $e->getMessage());
             return false;
         }
-        return true;
     }
 
     public function unbindStore($mainId, $platform, $storeId)
     {
         try {
-        switch($platform) {
+            switch($platform) {
             case 'fengniao':
                 /** @var FengniaoShop $shop */
                 $shop = $this->adapters[$platform];
@@ -166,4 +201,38 @@ class ShopService
         }
         return true;
     }
+
+    public function storeDetail($mainId, $platform, $storeId)
+    {
+        try {
+            switch($platform) {
+                case 'shunfeng':
+                    /** @var ShunfengShop $shop */
+                    $shop = $this->adapters[$platform];
+                    $ret = $shop->getShopInfo($storeId, 1);
+                    break;
+            }
+            return $ret;
+        } catch(\Exception $e) {
+            Yii::error('获取门店信息失败: ' . $e->getMessage());
+            return false;
+        }
+    }
+
+    public function updateStore($shopId, $platform, $post)
+    {
+        try {
+            switch($platform) {
+                case 'shunfeng':
+                    /** @var ShunfengShop $shop */
+                    $shop = $this->adapters[$platform];
+                    $ret = $shop->updateshop($shopId, $post);
+                    break;
+            }
+            return $ret;
+        } catch(\Exception $e) {
+            Yii::error('获取门店信息失败: ' . $e->getMessage());
+            return false;
+        }
+    }
 }

+ 14 - 2
common/components/delivery/services/adapter/DidiAdapter.php

@@ -53,12 +53,24 @@ class DidiAdapter extends Didi implements Adapter
                 'serviceLevel' => 0, // 服服务等级
                 'serviceType' => 1,  // 服务类型(快送专用,拉货不需要传) -- 直送
             ],
+            [
+                'bizType' => 12,     // 业务类型 -- 快送
+                'carType' => 1018,   // 车型 -- 两轮车
+                'serviceLevel' => 0, // 服服务等级
+                'serviceType' => 0,  // 服务类型(快送专用,拉货不需要传) -- 拼送
+            ],
             [
                 'bizType' => 12,
                 'carType' => 1017,   // 小轿车
                 'serviceLevel' => 0,
-                'serviceType' => 1,
-            ]
+                'serviceType' => 1,  // 服务类型(快送专用,拉货不需要传) -- 直送
+            ],
+            [
+                'bizType' => 12,
+                'carType' => 1017,   // 小轿车
+                'serviceLevel' => 0,
+                'serviceType' => 0,  // 服务类型(快送专用,拉货不需要传) -- 拼送
+            ],
         ];
         // 如果是预约单,则使用以下 拉货(普通货运)
         $laHuo_serviceCategoryList = [