|
|
@@ -3,7 +3,7 @@ namespace common\components\delivery\services\adapter;
|
|
|
|
|
|
use bizGhs\order\classes\OrderItemClass;
|
|
|
use common\components\delivery\helpers\HttpClient;
|
|
|
-use common\components\delivery\helpers\SignHelper;
|
|
|
+use common\components\delivery\platform\fengniao\Fengniao;
|
|
|
use Yii;
|
|
|
|
|
|
/**
|
|
|
@@ -19,42 +19,8 @@ use Yii;
|
|
|
* - 正式环境:https://open-anubis.ele.me/anubis-webapi/v3/invoke/{method}
|
|
|
* - 沙箱环境:https://exam-anubis.ele.me/anubis-webapi/v3/invoke/{method}
|
|
|
*/
|
|
|
-class FengniaoAdapter implements Adapter
|
|
|
+class FengniaoAdapter extends Fengniao implements Adapter
|
|
|
{
|
|
|
- protected $baseUrl;
|
|
|
- protected $appId;
|
|
|
- protected $appSecret;
|
|
|
- protected $merchantId;
|
|
|
- protected $accessToken;
|
|
|
- protected $apiVersion = '1.0';
|
|
|
-
|
|
|
- public function __construct($accessToken = '')
|
|
|
- {
|
|
|
- // 根据环境设置基础URL
|
|
|
- if (getenv('YII_ENV') == 'production') {
|
|
|
- $this->baseUrl = 'https://open-anubis.ele.me/anubis-webapi/v3/invoke';
|
|
|
- } else {
|
|
|
- $this->baseUrl = 'https://exam-anubis.ele.me/anubis-webapi/v3/invoke';
|
|
|
- }
|
|
|
-
|
|
|
- // 配置信息(从Auth类获取)
|
|
|
- $this->appId = '6587209115185920913';
|
|
|
- $this->appSecret = '3f935d5f-bf65-467e-a61c-72cfb1d53960';
|
|
|
- $this->accessToken = $accessToken;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 设置商户ID
|
|
|
- *
|
|
|
- * @param string $merchantId 商户ID
|
|
|
- * @return $this
|
|
|
- */
|
|
|
- public function setMerchantId($merchantId)
|
|
|
- {
|
|
|
- $this->merchantId = $merchantId;
|
|
|
- return $this;
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* 获取已开通城市列表
|
|
|
*
|
|
|
@@ -1480,197 +1446,4 @@ class FengniaoAdapter implements Adapter
|
|
|
'data' => null
|
|
|
];
|
|
|
}
|
|
|
-
|
|
|
- // ------------------------------------- 商户门店接口 ---------------------------------------------
|
|
|
- /**
|
|
|
- * 门店详情查询接口
|
|
|
- */
|
|
|
- public function chainstoreQuery()
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 门店批量查询接口
|
|
|
- *
|
|
|
- * 根据蜂鸟官方文档实现门店批量查询功能。
|
|
|
- * 可按商户ID查询所有门店信息,支持分页。
|
|
|
- *
|
|
|
- * @param array $data 查询参数,结构参考:
|
|
|
- * [
|
|
|
- * // ========== 必填参数 ==========
|
|
|
- * 'merchant_id' => '商户ID(Long类型)',
|
|
|
- *
|
|
|
- * // ========== 可选参数 ==========
|
|
|
- * 'page_no' => '分页页码(默认从1开始)',
|
|
|
- * 'page_size' => '每页条数(默认1000)',
|
|
|
- * ]
|
|
|
- */
|
|
|
- public function chainstoreQueryList($data = [])
|
|
|
- {
|
|
|
- // 验证 merchant_id 必填
|
|
|
- $merchantId = $data['merchant_id'] ?? null;
|
|
|
-
|
|
|
- if (empty($merchantId)) {
|
|
|
- Yii::warning("[FengniaoAdapter] chainstoreQueryList failed: merchant_id is required");
|
|
|
- return [
|
|
|
- 'code' => -1,
|
|
|
- 'msg' => 'merchant_id is required',
|
|
|
- 'data' => null
|
|
|
- ];
|
|
|
- }
|
|
|
- $this->setMerchantId($merchantId);
|
|
|
-
|
|
|
- // 构建业务数据
|
|
|
- $businessData = [];
|
|
|
-
|
|
|
- // 可选参数 - 分页信息
|
|
|
- if (isset($data['page_no']) && $data['page_no'] !== null) {
|
|
|
- $businessData['page_no'] = (int)$data['page_no'];
|
|
|
- }
|
|
|
- if (isset($data['page_size']) && $data['page_size'] !== null) {
|
|
|
- $businessData['page_size'] = (int)$data['page_size'];
|
|
|
- }
|
|
|
-
|
|
|
- // 构建请求参数
|
|
|
- $payload = $this->buildRequestPayload('chainstoreQueryList', $businessData);
|
|
|
-
|
|
|
- // 发送请求
|
|
|
- $url = $this->baseUrl . '/chainstoreQueryList';
|
|
|
- $resp = HttpClient::post($url, $payload, [
|
|
|
- 'Content-Type' => 'application/json',
|
|
|
- ]);
|
|
|
-
|
|
|
- Yii::info("[FengniaoAdapter] chainstoreQueryList Response: " . json_encode($resp));
|
|
|
-
|
|
|
- // 处理响应
|
|
|
- if (isset($resp['code']) && $resp['code'] == '200' && isset($resp['business_data'])) {
|
|
|
- // business_data 是 JSON 字符串,需要解析
|
|
|
- $respData = is_string($resp['business_data']) ? json_decode($resp['business_data'], true) : $resp['business_data'];
|
|
|
-
|
|
|
- if (is_null($respData)) {
|
|
|
- Yii::error("[FengniaoAdapter] Failed to parse business_data: " . $resp['business_data']);
|
|
|
- return [
|
|
|
- 'code' => -1,
|
|
|
- 'msg' => 'Failed to parse response data',
|
|
|
- 'data' => null
|
|
|
- ];
|
|
|
- }
|
|
|
-
|
|
|
- // 解析门店列表
|
|
|
- $chainStoreList = [];
|
|
|
- if (!empty($respData['list']) && is_array($respData['list'])) {
|
|
|
- foreach ($respData['list'] as $store) {
|
|
|
- $chainStoreList[] = [
|
|
|
- 'chain_store_id' => (int)($store['chain_store_id'] ?? 0),
|
|
|
- 'name' => $store['name'] ?? '',
|
|
|
- 'branch_name' => $store['branch_name'] ?? '',
|
|
|
- 'address' => $store['address'] ?? '',
|
|
|
- 'latitude' => (double)($store['latitude'] ?? 0),
|
|
|
- 'longitude' => (double)($store['longitude'] ?? 0),
|
|
|
- 'merchant_id' => (int)($store['merchant_id'] ?? 0),
|
|
|
- 'out_shop_code' => $store['out_shop_code'] ?? '',
|
|
|
- 'chainstore_type' => (int)($store['chainstore_type'] ?? 1),
|
|
|
- 'chainstore_type_desc' => $store['chainstore_type_desc'] ?? '',
|
|
|
- 'position_source' => (int)($store['position_source'] ?? 0),
|
|
|
- 'position_source_desc' => $store['position_source_desc'] ?? '',
|
|
|
- 'status' => (int)($store['status'] ?? 0),
|
|
|
- 'status_desc' => $store['status_desc'] ?? '',
|
|
|
- 'modify_status' => (int)($store['modify_status'] ?? 0),
|
|
|
- 'modify_status_desc' => $store['modify_status_desc'] ?? '',
|
|
|
- ];
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return [
|
|
|
- 'code' => 0,
|
|
|
- 'data' => [
|
|
|
- 'page_no' => (int)($respData['page_no'] ?? 0),
|
|
|
- 'page_size' => (int)($respData['page_size'] ?? 0),
|
|
|
- 'total_page' => (int)($respData['total_page'] ?? 0),
|
|
|
- 'total_count' => (int)($respData['total_count'] ?? 0),
|
|
|
- 'list' => $chainStoreList,
|
|
|
- ]
|
|
|
- ];
|
|
|
- }
|
|
|
-
|
|
|
- return [
|
|
|
- 'code' => (int)($resp['code'] ?? -1),
|
|
|
- 'msg' => $resp['msg'] ?? 'Unknown error',
|
|
|
- 'data' => null
|
|
|
- ];
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 构建API请求参数
|
|
|
- *
|
|
|
- * 根据蜂鸟API规范构建完整的请求参数,包括签名
|
|
|
- *
|
|
|
- * @param string $method API方法名
|
|
|
- * @param array $businessData 业务参数
|
|
|
- * @return array 完整的请求参数
|
|
|
- */
|
|
|
- protected function buildRequestPayload($method, $businessData = [])
|
|
|
- {
|
|
|
- // 生成时间戳(毫秒)
|
|
|
- $timestamp = (string)(time() * 1000);
|
|
|
-
|
|
|
- // 构建参数
|
|
|
- $payload = [
|
|
|
- 'app_id' => $this->appId,
|
|
|
- 'timestamp' => $timestamp,
|
|
|
- 'merchant_id' => $this->merchantId,
|
|
|
- 'access_token' => $this->accessToken,
|
|
|
- 'business_data' => json_encode($businessData, JSON_UNESCAPED_UNICODE),
|
|
|
- 'version' => $this->apiVersion,
|
|
|
- ];
|
|
|
-
|
|
|
- // 计算签名
|
|
|
- $signature = $this->generateSignature($payload);
|
|
|
- $payload['signature'] = $signature;
|
|
|
-
|
|
|
- return $payload;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 生成签名
|
|
|
- *
|
|
|
- * 根据蜂鸟API规范:
|
|
|
- * 签名计算:先按 key 排序,拼接成字符串,前面加上 appSecret,使用 SHA-256 加密
|
|
|
- *
|
|
|
- * @param array $params 待签名参数(不包括signature)
|
|
|
- * @return string 签名值
|
|
|
- */
|
|
|
- public function generateSignature(array $params)
|
|
|
- {
|
|
|
- // Step 1: 过滤空值 -- 不能清除,不然测试环境 code 就被排除了
|
|
|
-// $params = array_filter($params, function ($v) {
|
|
|
-// return $v !== null && $v !== '';
|
|
|
-// });
|
|
|
-
|
|
|
- // Step 2: 按字典序排序
|
|
|
- ksort($params);
|
|
|
-
|
|
|
- // Step 3: 拼接成字符串
|
|
|
- $paramStr = '';
|
|
|
- foreach ($params as $key => $value) {
|
|
|
- $paramStr .= "{$key}={$value}&";
|
|
|
- }
|
|
|
- $paramStr = rtrim($paramStr, '&');
|
|
|
-
|
|
|
- // Step 4: 拼接 appSecret
|
|
|
- $signBefore = $this->appSecret . $paramStr;
|
|
|
- //$signBefore = '1111app_id=222&code=4444&grant_type=authorization_code&merchant_id=333×tamp=1719297100558';
|
|
|
- // Step 5: 使用SHA-256加密
|
|
|
- $signature = hash('sha256', $signBefore);
|
|
|
-
|
|
|
- Yii::info("[FengniaAuth] Sign Before: {$signBefore}, Signature: {$signature}");
|
|
|
- return $signature;
|
|
|
- }
|
|
|
-
|
|
|
- public function second_geneSignature(array $params)
|
|
|
- {
|
|
|
- $signature = strtolower(SignHelper::makeSign($params, $this->appSecret, 'sha256', true, 'fengniao'));
|
|
|
- return $signature;
|
|
|
- }
|
|
|
}
|