初始化
This commit is contained in:
parent
816ea8219d
commit
b29142fc95
|
@ -0,0 +1,3 @@
|
|||
/vendor/
|
||||
/.idea/
|
||||
/composer.lock
|
|
@ -0,0 +1,16 @@
|
|||
### 顺丰快递开放平台接口 SDK
|
||||
|
||||
# 说明
|
||||
本 SDK 仅个人项目使用不保证能使用所有项目
|
||||
- [顺丰开放平台接口文档](https://open.sf-express.com/Api?category=1&apiClassify=1)
|
||||
|
||||
# 使用
|
||||
请参照 examples 目录内的样例使用
|
||||
|
||||
## 目前已对接
|
||||
- 下订单接口-速运类API
|
||||
- 预下单接口-速运类API
|
||||
- 订单结果查询接口-速运类API
|
||||
- 路由查询接口接口-速运类API
|
||||
- 订单确认/取消接口-速运类API
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "root/sfexpress_sdk",
|
||||
"description": "顺丰SDK",
|
||||
"type": "library",
|
||||
"require": {
|
||||
"php": "7.2.*",
|
||||
"guzzlehttp/guzzle": "^7.8"
|
||||
},
|
||||
"license": "MIT",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Gzlbw\\sfexpress\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "Li Bo Wen",
|
||||
"email": "gzbw79@163.com"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午4:12
|
||||
* Email: gzbw79@163.com
|
||||
* 云打印面单打印2.0接口-面单类API
|
||||
* 文档:https://open.sf-express.com/Api/ApiDetails?level3=317&interName=%E4%BA%91%E6%89%93%E5%8D%B0%E9%9D%A2%E5%8D%952.0%E6%8E%A5%E5%8F%A3-COM_RECE_CLOUD_PRINT_WAYBILLS
|
||||
*/
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
$handle = new \Gzlbw\sfexpress\CloudPrintWaybills("XTYSWNJt2vpS", "2cIBZs3r1QvOhqYCSoAR8ntmhTgYAqdF", true);
|
||||
// 添加要打印的面单快递单号
|
||||
$handle->addWayBills("SF7444471043754");
|
||||
// 获取面单文件
|
||||
$ret = $handle->req([
|
||||
'templateCode' => 'fm_150_standard_XTYSWNJt2vpS', // 模板编码
|
||||
'sync' => true, //
|
||||
]);
|
||||
var_dump($ret);
|
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午3:01
|
||||
* Email: gzbw79@163.com
|
||||
* 下订单接口-速运类API
|
||||
*/
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
$handle = new \Gzlbw\sfexpress\CreateOrder("XTYSWbTkcFef", "lrgdnHl21IOb6wEmPYB6def9C4JG2Se5", true);
|
||||
// 业务订单编号
|
||||
$order_no = date("YmdHi") . rand(1000, 9999);
|
||||
$handle->setOrderId($order_no);
|
||||
// 寄件人信息
|
||||
$handle->addContractInfo("from", "天河区天河南二路丰兴广场", "小李", "", "13800138000", "广东省", "广州市");
|
||||
// 收件人信息
|
||||
$handle->addContractInfo("to", "天河区天河路611号摩登百货", "小张", "", "13800138001", "广东省", "广州市");
|
||||
// 货物信息
|
||||
$handle->addCargoDetail("文件 1份", "1", [
|
||||
'amount' => 10, // 声明价值
|
||||
'currency' => 'CNY' // 价值结算货币
|
||||
]);
|
||||
// 发送请求
|
||||
$ret = $handle->req([
|
||||
'monthlyCard' => '7551234567', // 月结卡号
|
||||
'payMethod' => 1, // 付款方式,支持以下值: 1:寄方付 2:收方付 3:第三方付
|
||||
'expressTypeId' => 2, // 快件产品类别, https://open.sf-express.com/developSupport/734349?activeIndex=324604
|
||||
'remark' => '派件前请电话联系', // 备注
|
||||
'isReturnRoutelabel' => 1, // 是否返回路由标签: 默认1, 1:返回路由标签, 0:不返回;除部分特殊用户外,其余用户都默认返回
|
||||
'isReturnSignBackRoutelabel' => 0, // 是否返回签回单路由标签: 默认0, 1:返回路由标签, 0:不返回
|
||||
'totalWeight' => 1.000 // 订单货物总重量(郑州空港海关必填), 若为子母件必填, 单位千克, 精确到小数点后3位,如果提供此值, 必须>0 (子母件需>6)
|
||||
]);
|
||||
|
||||
var_dump($ret);
|
||||
|
||||
/**
|
||||
* 响应数据样例
|
||||
* array(4) {
|
||||
["apiErrorMsg"]=>
|
||||
string(0) ""
|
||||
["apiResponseID"]=>
|
||||
string(32) "00018A97BCE25C3FE59E04A28E84E33F"
|
||||
["apiResultCode"]=>
|
||||
string(5) "A1000"
|
||||
["apiResultData"]=>
|
||||
string(349) "{"success":true,"errorCode":"S0000","errorMsg":null,"msgData":[{"serviceDate":"2023-09-15","startTime":"2023-09-15 08:00:00","endTime":"2023-09-15 21:30:00"},{"serviceDate":"2023-09-16","startTime":"2023-09-16 08:00:00","endTime":"2023-09-16 21:30:00"},{"serviceDate":"2023-09-17","startTime":"2023-09-17 08:00:00","endTime":"2023-09-17 21:30:00"}]}"
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午3:01
|
||||
* Email: gzbw79@163.com
|
||||
* 预下单接口样例 - 用于校验收件地址是否支持派送和收件
|
||||
*/
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
$handle = new \Gzlbw\sfexpress\PreCreateOrder("XTYSWbTkcFef", "lrgdnHl21IOb6wEmPYB6def9C4JG2Se5", true);
|
||||
// 业务订单编号
|
||||
$order_no = date("YmdHi") . rand(1000, 9999);
|
||||
$handle->setOrderId($order_no);
|
||||
// 寄件人信息
|
||||
$handle->addContractInfo("from", "天河区天河南二路丰兴广场", "小李", "", "13800138000", "广东省", "广州市");
|
||||
// 收件人信息
|
||||
$handle->addContractInfo("to", "天河区天河路611号摩登百货", "小张", "", "13800138001", "广东省", "广州市");
|
||||
// 发送请求
|
||||
$ret = $handle->req([
|
||||
'monthlyCard' => '7551234567', // 月结卡号
|
||||
'payMethod' => 1, // 付款方式,支持以下值: 1:寄方付 2:收方付 3:第三方付
|
||||
'expressTypeId' => 2, // 快件产品类别, https://open.sf-express.com/developSupport/734349?activeIndex=324604
|
||||
'remark' => '派件前请电话联系', // 备注
|
||||
]);
|
||||
|
||||
var_dump($ret);
|
||||
|
||||
/**
|
||||
* 响应数据样例
|
||||
* array(4) {
|
||||
["apiErrorMsg"]=>
|
||||
string(0) ""
|
||||
["apiResponseID"]=>
|
||||
string(32) "00018A97B28A9D3F9F66B7A2B880603F"
|
||||
["apiResultCode"]=>
|
||||
string(5) "A1000"
|
||||
["apiResultData"]=>
|
||||
string(1710) "{"success":true,"errorCode":"S0000","errorMsg":null,"msgData":{"orderId":"2023091515166449","originCode":"020","destCode":"020","filterResult":2,"remark":"","url":null,"paymentLink":null,"isUpstairs":null,"isSpecialWarehouseService":null,"mappingMark":null,"agentMailno":null,"returnExtraInfoList":null,"waybillNoInfoList":[{"waybillType":1,"waybillNo":"SF7444471039325","boxNo":null,"length":null,"width":null,"height":null,"weight":null,"volume":null}],"routeLabelInfo":[{"code":"1000","routeLabelData":{"waybillNo":"SF7444471039325","sourceTransferCode":"020W","sourceCityCode":"020","sourceDeptCode":"020","sourceTeamCode":"","destCityCode":"020","destDeptCode":"020Z069","destDeptCodeMapping":"","destTeamCode":"006","destTeamCodeMapping":"","destTransferCode":"020W","destRouteLabel":"020W-Z069-006","proName":"","cargoTypeCode":"T6","limitTypeCode":"T6","expressTypeCode":"B1","codingMapping":"H7","codingMappingOut":"","xbFlag":"0","printFlag":"000000000","twoDimensionCode":"MMM={'k1':'020W','k2':'020Z069','k3':'006','k4':'T4','k5':'SF7444471039325','k6':'','k7':'dfa46974'}","proCode":"T 标快","printIcon":"00000000","abFlag":"","destPortCode":"","destCountry":"","destPostCode":"","goodsValueTotal":"","currencySymbol":"","cusBatch":"","goodsNumber":"","errMsg":"","checkCode":"dfa46974","proIcon":"","fileIcon":"","fbaIcon":"","icsmIcon":"","destGisDeptCode":"020Z069","newIcon":null,"sendAreaCode":null,"destinationStationCode":null,"sxLabelDestCode":null,"sxDestTransferCode":null,"sxCompany":null,"newAbFlag":null,"destAddrKeyWord":"","rongType":null,"waybillIconList":null},"message":"SF7444471039325:"}],"contactInfoList":null,"sendStartTm":null,"customerRights":null,"expressTypeId":null}}"
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午3:35
|
||||
* Email: gzbw79@163.com
|
||||
* 订单结果查询接口
|
||||
*/
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
$handle = new \Gzlbw\sfexpress\SearchOrder("XTYSWbTkcFef", "lrgdnHl21IOb6wEmPYB6def9C4JG2Se5", true);
|
||||
$ret = $handle->data("2023091515166449");
|
||||
var_dump($ret);
|
||||
|
||||
/**
|
||||
* 响应数据样例
|
||||
* array(4) {
|
||||
["apiErrorMsg"]=>
|
||||
string(0) ""
|
||||
["apiResponseID"]=>
|
||||
string(32) "00018A97C54DF13FE1EDD4F4A9445A3F"
|
||||
["apiResultCode"]=>
|
||||
string(5) "A1000"
|
||||
["apiResultData"]=>
|
||||
string(1333) "{"success":true,"errorCode":"S0000","errorMsg":null,"msgData":{"orderId":"2023091515166449","returnExtraInfoList":null,"waybillNoInfoList":[{"waybillType":1,"waybillNo":"SF7444471039325"}],"origincode":"020","destcode":"020","filterResult":"2","remark":"派件前请电话联系","routeLabelInfo":[{"code":"1000","routeLabelData":{"waybillNo":"SF7444471039325","sourceTransferCode":"020W","sourceCityCode":"020","sourceDeptCode":"020","sourceTeamCode":"","destCityCode":"020","destDeptCode":"020Z069","destDeptCodeMapping":"","destTeamCode":"006","destTeamCodeMapping":"","destTransferCode":"020W","destRouteLabel":"020W-Z069-006","proName":"顺丰标快","cargoTypeCode":"T6","limitTypeCode":"T6","expressTypeCode":"B1","codingMapping":"H7","codingMappingOut":"","xbFlag":"0","printFlag":"000000000","twoDimensionCode":"MMM={'k1':'020W','k2':'020Z069','k3':'006','k4':'T801','k5':'SF7444471039325','k6':'','k7':'b96667f8'}","proCode":"T801","printIcon":"00000000","abFlag":"","destPortCode":"","destCountry":"","destPostCode":"","goodsValueTotal":"","currencySymbol":"","cusBatch":"","goodsNumber":"","errMsg":"","checkCode":"b96667f8","proIcon":"","fileIcon":"","fbaIcon":"","icsmIcon":"","destGisDeptCode":"020Z069","newIcon":null},"message":"SF7444471039325:"}],"contactInfo":null,"clientCode":"XTYSWbTkcFef","serviceList":null}}"
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午3:38
|
||||
* Email: gzbw79@163.com
|
||||
* 路由查询接口
|
||||
*/
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
$handle = new \Gzlbw\sfexpress\SearchRoutes("XTYSWbTkcFef", "lrgdnHl21IOb6wEmPYB6def9C4JG2Se5", true);
|
||||
$ret = $handle->req([
|
||||
'trackingNumber' => ["SF7444471039325"]
|
||||
]);
|
||||
var_dump($ret);
|
||||
|
||||
/**
|
||||
* 响应报文样例
|
||||
* array(4) {
|
||||
["apiErrorMsg"]=>
|
||||
string(0) ""
|
||||
["apiResponseID"]=>
|
||||
string(32) "00018A97CE03FB3FE9D58FC7BD17AB3F"
|
||||
["apiResultCode"]=>
|
||||
string(5) "A1000"
|
||||
["apiResultData"]=>
|
||||
string(238) "{"success":true,"errorCode":"S0000","errorMsg":null,"msgData":{"routeResps":[{"mailNo":"SF7444471039325","routes":[{"acceptAddress":"深圳市","acceptTime":"2023-09-15 15:46:15","remark":"顺丰速运 已收取快件","opCode":"50"}]}]}}"
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午3:53
|
||||
* Email: gzbw79@163.com
|
||||
* 订单确认/取消接口-速运类API
|
||||
*/
|
||||
|
||||
require __DIR__ . "/../vendor/autoload.php";
|
||||
|
||||
$handle = new \Gzlbw\sfexpress\UpdateOrder("XTYSWbTkcFef", "lrgdnHl21IOb6wEmPYB6def9C4JG2Se5", true);
|
||||
// 确认订单
|
||||
$ret = $handle->confirm("2023091515166449");
|
||||
var_dump($ret);
|
||||
/**
|
||||
* 报文响应样例
|
||||
* array(4) {
|
||||
["apiErrorMsg"]=>
|
||||
string(0) ""
|
||||
["apiResponseID"]=>
|
||||
string(32) "00018A97D907F13FDD618D201CAB603F"
|
||||
["apiResultCode"]=>
|
||||
string(5) "A1000"
|
||||
["apiResultData"]=>
|
||||
string(74) "{"success":false,"errorCode":"8037","errorMsg":"已消单","msgData":null}"
|
||||
}
|
||||
*/
|
||||
|
||||
// 撤销订单
|
||||
$ret = $handle->cancel("2023091515166449");
|
||||
var_dump($ret);
|
||||
/**
|
||||
* 报文响应样例
|
||||
* array(4) {
|
||||
["apiErrorMsg"]=>
|
||||
string(0) ""
|
||||
["apiResponseID"]=>
|
||||
string(32) "00018A97D895433FCB8D4B1C739C303F"
|
||||
["apiResultCode"]=>
|
||||
string(5) "A1000"
|
||||
["apiResultData"]=>
|
||||
string(198) "{"success":true,"errorCode":"S0000","errorMsg":null,"msgData":{"orderId":"2023091515166449","waybillNoInfoList":[{"waybillType":1,"waybillNo":"SF7444471039325"}],"resStatus":2,"extraInfoList":null}}"
|
||||
}
|
||||
*/
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午4:01
|
||||
* Email: gzbw79@163.com
|
||||
* 云打印面单打印2.0接口-面单类API
|
||||
*/
|
||||
|
||||
namespace Gzlbw\sfexpress;
|
||||
|
||||
class CloudPrintWaybills extends Handler implements IHandler
|
||||
{
|
||||
protected $serviceCode = 'COM_RECE_CLOUD_PRINT_WAYBILLS';
|
||||
|
||||
/**
|
||||
* 业务数据
|
||||
* @var array
|
||||
*/
|
||||
protected $documents = [];
|
||||
|
||||
public function req(array $msgData, array $options = [])
|
||||
{
|
||||
$this->timestamp = $this->get_time();
|
||||
|
||||
// 获取公共请求参数
|
||||
$params = $this->common_params($this->serviceCode);
|
||||
// 合并请求参数
|
||||
$msgData = array_merge($msgData, [
|
||||
'version' => '2.0',
|
||||
'documents' => $this->documents
|
||||
]);
|
||||
$params = array_merge($params, ['msgData' => $msgData], $options);
|
||||
// 数据签名
|
||||
$params['msgDigest'] = $this->sign($params['msgData'], $this->timestamp);
|
||||
// 多维数组转成一维
|
||||
$this->convert_params($params);
|
||||
return $this->fire('/std/service', ['form_params' => $params]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 除主运单号是必须外其余为条件
|
||||
* 一批不要超过20个运单,字段定义参考 2.3.1 模板固定字段
|
||||
* @param string $master_no 主运单号(必须)
|
||||
* @param array $options 其余参数,参考顺丰文档
|
||||
*/
|
||||
public function addWayBills(string $master_no, array $options = []) {
|
||||
$this->documents[] = array_merge([
|
||||
'masterWaybillNo' => $master_no,
|
||||
], $options);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午1:53
|
||||
* Email: gzbw79@163.com
|
||||
* 下单接口
|
||||
* 顺丰文档:https://open.sf-express.com/Api/ApiDetails?level3=393&interName=%E4%B8%8B%E8%AE%A2%E5%8D%95%E6%8E%A5%E5%8F%A3-EXP_RECE_CREATE_ORDER
|
||||
*/
|
||||
|
||||
namespace Gzlbw\sfexpress;
|
||||
|
||||
class CreateOrder extends OrderCommon implements IHandler
|
||||
{
|
||||
protected $serviceCode = 'EXP_RECE_CREATE_ORDER';
|
||||
|
||||
/**
|
||||
* 联系信息
|
||||
* @var array
|
||||
*/
|
||||
protected $contractInfo = [
|
||||
'contactType' => 1,
|
||||
'company' => '',
|
||||
'contact' => '',
|
||||
'tel' => '',
|
||||
'mobile' => '',
|
||||
'zoneCode' => '',
|
||||
'country' => '',
|
||||
'province' => '',
|
||||
'city' => '',
|
||||
'county' => '',
|
||||
'address' => '',
|
||||
'postCode' => '',
|
||||
'email' => '',
|
||||
'taxNo' => ''
|
||||
];
|
||||
|
||||
/**
|
||||
* 订单号
|
||||
* @var string
|
||||
*/
|
||||
protected $order_id = '';
|
||||
|
||||
/**
|
||||
* 发件人
|
||||
* @var array
|
||||
*/
|
||||
protected $sender = [];
|
||||
|
||||
/**
|
||||
* 收件人
|
||||
* @var array
|
||||
*/
|
||||
protected $receiver = [];
|
||||
|
||||
/**
|
||||
* 订单原始信息
|
||||
* @var
|
||||
*/
|
||||
protected $orderSource;
|
||||
|
||||
/**
|
||||
* 货物详情
|
||||
* @var array
|
||||
*/
|
||||
protected $cargoDetail = [];
|
||||
|
||||
/**
|
||||
* 是否需求分配运单号1:分配 0:不分配(若带单号下单,请传值0)
|
||||
* @var int
|
||||
*/
|
||||
protected $isGenWaybillNo = 1;
|
||||
|
||||
/**
|
||||
* @param array $msgData 业务数据,参照顺丰文档 下订单接口-速运类API 元素<请求> Order
|
||||
* @param array $options 其它请求参数
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function req(array $msgData, array $options = [])
|
||||
{
|
||||
$this->timestamp = $this->get_time();
|
||||
$common = $this->common_params($this->serviceCode);
|
||||
// 业务数据
|
||||
$msgData = array_merge($msgData, [
|
||||
'orderId' => $this->order_id,
|
||||
'cargoDetails' => $this->cargoDetail,
|
||||
'contactInfoList' => [
|
||||
$this->sender,
|
||||
$this->receiver
|
||||
],
|
||||
'orderSource' => $this->orderSource,
|
||||
'isGenWaybillNo' => $this->isGenWaybillNo
|
||||
]);
|
||||
// 合并请求参数
|
||||
$params = array_merge($common, ['msgData' => $msgData], $options);
|
||||
// 数据签名
|
||||
$params['msgDigest'] = $this->sign($params['msgData'], $this->timestamp);
|
||||
// 多维数组转成一维
|
||||
$this->convert_params($params);
|
||||
return $this->fire('/std/service', ['form_params' => $params]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午1:38
|
||||
* Email: gzbw79@163.com
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Gzlbw\sfexpress;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
class Handler
|
||||
{
|
||||
/**
|
||||
* 是否沙盒环境
|
||||
* @var bool
|
||||
*/
|
||||
protected $sandbox = false;
|
||||
|
||||
/**
|
||||
* 顾客编码
|
||||
* @var string
|
||||
*/
|
||||
protected $app_id = '';
|
||||
|
||||
/**
|
||||
* 校验码
|
||||
* @var string
|
||||
*/
|
||||
protected $app_key = '';
|
||||
|
||||
/**
|
||||
* 服务代码
|
||||
* @var string
|
||||
*/
|
||||
protected $serviceCode = '';
|
||||
|
||||
/**
|
||||
* 生产地址
|
||||
* @var string
|
||||
*/
|
||||
protected $product_uri = 'https://bspgw.sf-express.com';
|
||||
|
||||
/**
|
||||
* 沙盒地址
|
||||
* @var string
|
||||
*/
|
||||
protected $sandbox_uri = 'https://sfapi-sbox.sf-express.com';
|
||||
|
||||
/**
|
||||
* 临时目录
|
||||
* @var string
|
||||
*/
|
||||
protected $temp_path = '';
|
||||
|
||||
/**
|
||||
* 请求时间戳
|
||||
* @var int
|
||||
*/
|
||||
protected $timestamp;
|
||||
|
||||
/**
|
||||
* 数据签名
|
||||
* @var string
|
||||
*/
|
||||
protected $sign;
|
||||
|
||||
/**
|
||||
* Handler constructor.
|
||||
* @param string $app_id 客户编号
|
||||
* @param string $app_key 应用验证码(接口签名需要)
|
||||
* @param bool $sandbox 是否沙盒模式
|
||||
* @param string $temp_path 临时目录路径
|
||||
*/
|
||||
public function __construct(string $app_id, string $app_key, bool $sandbox = false, string $temp_path = '')
|
||||
{
|
||||
$this->app_id = $app_id;
|
||||
$this->app_key = $app_key;
|
||||
$this->sandbox = $sandbox;
|
||||
|
||||
$this->temp_path = (empty($temp_path)) ? __DIR__ . "/../temp" : $temp_path;
|
||||
if (!file_exists($this->temp_path)) {
|
||||
@mkdir($this->temp_path, 0755, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据签名
|
||||
* @param array $data 需要参与签名的数据
|
||||
* @param int $timestamp 时间戳
|
||||
* @return string
|
||||
*/
|
||||
protected function sign(array $data, int $timestamp = 0) {
|
||||
$this->timestamp = ($timestamp > 0) ? $timestamp : $this->get_time();
|
||||
$encode = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
$sign = sprintf("%s%s%s", $encode, $this->timestamp, $this->app_key);
|
||||
$sign = urlencode($sign);
|
||||
$sign = md5($sign, true);
|
||||
return base64_encode($sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建UUID
|
||||
* @return string
|
||||
*/
|
||||
protected function create_uuid() {
|
||||
$chars = md5(uniqid(mt_rand(), true));
|
||||
return implode("-", [
|
||||
substr ( $chars, 0, 8 ),
|
||||
substr ( $chars, 8, 4 ),
|
||||
substr ( $chars, 12, 4 ),
|
||||
substr ( $chars, 16, 4 ),
|
||||
substr ( $chars, 20, 12 )
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换参数,将参数中属于数组的要转成 json
|
||||
* @param $params
|
||||
* @return void
|
||||
*/
|
||||
public function convert_params(&$params) {
|
||||
foreach ($params as &$vo) {
|
||||
if (is_array($vo)) {
|
||||
$vo = json_encode($vo, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 access_token
|
||||
* @param bool $update 是否取最新 token
|
||||
* @return string
|
||||
*/
|
||||
public function access_token(bool $update = false) {
|
||||
$cache_file = $this->temp_path . "/" . $this->app_id . "_token.json";
|
||||
if (file_exists($cache_file) && $update === false) {
|
||||
$token = json_decode(file_get_contents($cache_file), true);
|
||||
if ((int)$token['expire_at'] > time()) return $token['accessToken'];
|
||||
}
|
||||
|
||||
$client = new Client($this->client_config());
|
||||
|
||||
$request = $client->post('/oauth2/accessToken', [
|
||||
'query' => [
|
||||
'partnerID' => $this->app_id,
|
||||
'secret' => $this->app_key,
|
||||
'grantType' => 'password'
|
||||
]
|
||||
]);
|
||||
|
||||
/**
|
||||
* 成功报文
|
||||
* {
|
||||
"apiResultCode": "A1000",
|
||||
"apiErrorMsg": "success",
|
||||
"apiResponseID": "000180E0AC18933F963C52701B18C03F",
|
||||
"accessToken": "20D02FC4F63B4A4AA7C9A236EAD5B0A1",
|
||||
"expiresIn": 5150
|
||||
}
|
||||
*/
|
||||
$body = (string)$request->getBody();
|
||||
$response = json_decode($body, true);
|
||||
|
||||
if (empty($response['accessToken'])) {
|
||||
throw new \Exception($body);
|
||||
}
|
||||
|
||||
// 写入缓存
|
||||
$response = array_merge($response, ['expire_at' => time() + $response['expiresIn'] - 20]);
|
||||
file_put_contents($cache_file, json_encode($response, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
return $response['accessToken'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 统一请求方法
|
||||
* @param string $uri_path 请求路径
|
||||
* @param array $options 请求参数
|
||||
* @param string $method 请求方法
|
||||
*/
|
||||
public function fire(string $uri_path, array $options, string $method = 'post') {
|
||||
$client = new Client($this->client_config());
|
||||
$request = $client->request($method, $uri_path, $options);
|
||||
|
||||
$body = (string)$request->getBody();
|
||||
$response = json_decode($body, true);
|
||||
|
||||
if (!$response) throw new \Exception($body);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组合公共参数
|
||||
* @param string $service_code
|
||||
* @param bool $update_token
|
||||
* @return array
|
||||
*/
|
||||
public function common_params(string $service_code, bool $update_token = false) {
|
||||
$token = $this->access_token($update_token);
|
||||
$request_id = $this->create_uuid();
|
||||
|
||||
return [
|
||||
'partnerID' => $this->app_id,
|
||||
'requestID' => $request_id,
|
||||
'serviceCode' => $service_code,
|
||||
'timestamp' => $this->timestamp,
|
||||
'accessToken' => $token,
|
||||
'msgDigest' => '',
|
||||
'msgData' => ''
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 客户端HTTP通用参数
|
||||
* @return array
|
||||
*/
|
||||
private function client_config() {
|
||||
return [
|
||||
'base_uri' => ($this->sandbox) ? $this->sandbox_uri : $this->product_uri,
|
||||
'verify' => false,
|
||||
'headers' => [
|
||||
'Content-type' => 'application/x-www-form-urlencoded;charset=UTF-8'
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回时间戳
|
||||
* @return false|float
|
||||
*/
|
||||
public function get_time() {
|
||||
return ceil(microtime(true) * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤空值参数
|
||||
* @param $data
|
||||
* @return array
|
||||
*/
|
||||
protected function filter_empty($data) {
|
||||
return array_filter($data, function ($v, $k) {
|
||||
return !empty($v);
|
||||
}, ARRAY_FILTER_USE_BOTH);
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求接口
|
||||
* @param array $msgData
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function req(array $msgData, array $options = [])
|
||||
{
|
||||
$this->timestamp = $this->get_time();
|
||||
|
||||
// 获取公共请求参数
|
||||
$params = $this->common_params($this->serviceCode);
|
||||
// 合并请求参数
|
||||
$params = array_merge($params, ['msgData' => $msgData], $options);
|
||||
// 数据签名
|
||||
$params['msgDigest'] = $this->sign($params['msgData'], $this->timestamp);
|
||||
// 多维数组转成一维
|
||||
$this->convert_params($params);
|
||||
return $this->fire('/std/service', ['form_params' => $params]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午1:46
|
||||
* Email: gzbw79@163.com
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Gzlbw\sfexpress;
|
||||
|
||||
|
||||
interface IHandler
|
||||
{
|
||||
/**
|
||||
* 触发请求处理
|
||||
* @param array $msgData
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
*/
|
||||
public function req(array $msgData, array $options = []);
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午3:21
|
||||
* Email: gzbw79@163.com
|
||||
* 订单相关公共类,用于创建或预创建订单使用
|
||||
*/
|
||||
|
||||
namespace Gzlbw\sfexpress;
|
||||
|
||||
abstract class OrderCommon extends Handler
|
||||
{
|
||||
/**
|
||||
* 联系信息
|
||||
* @var array
|
||||
*/
|
||||
protected $contractInfo = [
|
||||
'contactType' => 1,
|
||||
'company' => '',
|
||||
'contact' => '',
|
||||
'tel' => '',
|
||||
'mobile' => '',
|
||||
'zoneCode' => '',
|
||||
'country' => '',
|
||||
'province' => '',
|
||||
'city' => '',
|
||||
'county' => '',
|
||||
'address' => '',
|
||||
'postCode' => '',
|
||||
'email' => '',
|
||||
'taxNo' => ''
|
||||
];
|
||||
|
||||
/**
|
||||
* 订单号
|
||||
* @var string
|
||||
*/
|
||||
protected $order_id = '';
|
||||
|
||||
/**
|
||||
* 发件人
|
||||
* @var array
|
||||
*/
|
||||
protected $sender = [];
|
||||
|
||||
/**
|
||||
* 收件人
|
||||
* @var array
|
||||
*/
|
||||
protected $receiver = [];
|
||||
|
||||
/**
|
||||
* 订单原始信息
|
||||
* @var
|
||||
*/
|
||||
protected $orderSource;
|
||||
|
||||
/**
|
||||
* 货物详情
|
||||
* @var array
|
||||
*/
|
||||
protected $cargoDetail = [];
|
||||
|
||||
/**
|
||||
* 是否需求分配运单号1:分配 0:不分配(若带单号下单,请传值0)
|
||||
* @var int
|
||||
*/
|
||||
protected $isGenWaybillNo = 1;
|
||||
|
||||
/**
|
||||
* 添加收发信息
|
||||
* @param string $type 地址类型: 1,寄件方信息 2,到件方信息
|
||||
* @param string $address 详细地址
|
||||
* @param string $name 姓名
|
||||
* @param string $tel 座机号码(座机和手机只能选一项)
|
||||
* @param string $mobile 手机号码(座机和手机只能选一项)
|
||||
* @param string $province 省名称
|
||||
* @param string $city 城市名称
|
||||
* @param string $country 国家或地区代码 例如:内地件CN 香港852 参照顺丰API附录《城市代码表》
|
||||
* @param array $options 其它可用参数,参照顺丰下订单接口-速运类API ContactInfo元素文档
|
||||
* @return $this
|
||||
*/
|
||||
public function addContractInfo(string $type, string $address, string $name, string $tel, string $mobile, string $province, string $city, string $country = 'CN', array $options = []) {
|
||||
$contractType = ($type == "from") ? 1 : 2;
|
||||
$tmp = array_merge($this->contractInfo, [
|
||||
'contactType' => $contractType,
|
||||
'contact' => $name,
|
||||
'address' => $address,
|
||||
'tel' => $tel,
|
||||
'mobile' => $mobile,
|
||||
'province' => $province,
|
||||
'city' => $city,
|
||||
'county' => $country
|
||||
], $options);
|
||||
|
||||
$tmp = $this->filter_empty($tmp);
|
||||
|
||||
if ($contractType == 1) {
|
||||
$this->sender = $tmp;
|
||||
} else {
|
||||
$this->receiver = $tmp;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加货物明细
|
||||
* @param $name
|
||||
* @param string $count
|
||||
* @param array $options
|
||||
* @return $this
|
||||
*/
|
||||
public function addCargoDetail(string $name, string $count = '',array $options = []) {
|
||||
$tmp = array_merge(compact('name', 'count'), $options);
|
||||
$tmp = $this->filter_empty($tmp);
|
||||
$this->cargoDetail[] = $tmp;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置业务单号
|
||||
* @param string $orderId
|
||||
* @return $this
|
||||
*/
|
||||
public function setOrderId(string $orderId) {
|
||||
$this->order_id = $orderId;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 订单平台类型 (对于平台类客户, 如果需要在订单中 区分订单来源, 则可使用此字段) 天猫:tmall, 拼多多:pinduoduo, 京东 : jd 等平台类型编码
|
||||
* @param string $src
|
||||
* @return $this
|
||||
*/
|
||||
public function orderSource(string $src) {
|
||||
$this->orderSource = $src;
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午3:19
|
||||
* Email: gzbw79@163.com
|
||||
* 预下单接口 - 客户通过传入地址信息等参数,校验是否能下单成功
|
||||
* 顺丰文档:https://open.sf-express.com/Api/ApiDetails?level3=392&interName=%E9%A2%84%E4%B8%8B%E5%8D%95%E6%8E%A5%E5%8F%A3-EXP_RECE_PRE_ORDER
|
||||
*/
|
||||
|
||||
namespace Gzlbw\sfexpress;
|
||||
|
||||
class PreCreateOrder extends OrderCommon implements IHandler
|
||||
{
|
||||
protected $serviceCode = 'EXP_RECE_PRE_ORDER';
|
||||
|
||||
/**
|
||||
* @param array $msgData 业务数据,参照顺丰文档 预下单接口-速运类API 元素<请求> Order
|
||||
* @param array $options 其它请求参数
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function req(array $msgData, array $options = [])
|
||||
{
|
||||
$this->timestamp = $this->get_time();
|
||||
$common = $this->common_params($this->serviceCode);
|
||||
// 业务数据
|
||||
$msgData = array_merge($msgData, [
|
||||
'orderId' => $this->order_id,
|
||||
'cargoDetails' => $this->cargoDetail,
|
||||
'contactInfoList' => [
|
||||
$this->sender,
|
||||
$this->receiver
|
||||
],
|
||||
'orderSource' => $this->orderSource,
|
||||
'isGenWaybillNo' => $this->isGenWaybillNo
|
||||
]);
|
||||
// 合并请求参数
|
||||
$params = array_merge($common, ['msgData' => $msgData], $options);
|
||||
// 数据签名
|
||||
$params['msgDigest'] = $this->sign($params['msgData'], $this->timestamp);
|
||||
// 多维数组转成一维
|
||||
$this->convert_params($params);
|
||||
return $this->fire('/std/service', ['form_params' => $params]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午3:32
|
||||
* Email: gzbw79@163.com
|
||||
* 订单结果查询接口-速运类API
|
||||
* 顺丰文档:https://open.sf-express.com/Api/ApiDetails?level3=396&interName=%E8%AE%A2%E5%8D%95%E7%BB%93%E6%9E%9C%E6%9F%A5%E8%AF%A2%E6%8E%A5%E5%8F%A3-EXP_RECE_SEARCH_ORDER_RESP
|
||||
*/
|
||||
|
||||
namespace Gzlbw\sfexpress;
|
||||
|
||||
class SearchOrder extends Handler implements IHandler
|
||||
{
|
||||
protected $serviceCode = 'EXP_RECE_SEARCH_ORDER_RESP';
|
||||
|
||||
/**
|
||||
* 请求接口
|
||||
* @param array $msgData
|
||||
* @param array $options
|
||||
* @return mixed
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function req(array $msgData, array $options = [])
|
||||
{
|
||||
$this->timestamp = (int)(microtime(true) * 1000);
|
||||
|
||||
$params = $this->common_params($this->serviceCode);
|
||||
// 合并请求参数
|
||||
$params = array_merge($params, ['msgData' => $msgData], $options);
|
||||
// 数据签名
|
||||
$params['msgDigest'] = $this->sign($params['msgData'], $this->timestamp);
|
||||
// 多维数组转成一维
|
||||
$this->convert_params($params);
|
||||
return $this->fire('/std/service', ['form_params' => $params]);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $orderId 业务订单编号
|
||||
* @param int $searchType 查询类型:1正向单 2退货单
|
||||
* @param string $language 响应报文的语言, 缺省值为zh-CN,目前支持以下值zh-CN 表示中文简体, zh-TW或zh-HK或 zh-MO表示中文繁体, en表示英文
|
||||
* @return mixed
|
||||
*/
|
||||
public function data(string $orderId, $searchType = 1, $language = 'zh-CN') {
|
||||
return $this->req([
|
||||
'orderId' => $orderId,
|
||||
'searchType' => $searchType,
|
||||
'language' => $language
|
||||
]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午3:37
|
||||
* Email: gzbw79@163.com
|
||||
* 路由查询接口接口-速运类API
|
||||
* 顺丰文档:https://open.sf-express.com/Api/ApiDetails?level3=397&interName=%E8%B7%AF%E7%94%B1%E6%9F%A5%E8%AF%A2%E6%8E%A5%E5%8F%A3-EXP_RECE_SEARCH_ROUTES
|
||||
*/
|
||||
|
||||
namespace Gzlbw\sfexpress;
|
||||
|
||||
class SearchRoutes extends Handler implements IHandler
|
||||
{
|
||||
protected $serviceCode = 'EXP_RECE_SEARCH_ROUTES';
|
||||
|
||||
public function req(array $msgData, array $options = [])
|
||||
{
|
||||
$this->timestamp = (int)(microtime(true) * 1000);
|
||||
|
||||
$params = $this->common_params($this->serviceCode);
|
||||
$msgData = array_merge($msgData, [
|
||||
'language' => 0, // 0=中文
|
||||
'trackingType' => 1, // 1=根据顺丰运单号查询,2=根据客户订单号查询
|
||||
'methodType' => 1, // 1=标准路由查询,2=定制路由查询
|
||||
]);
|
||||
// 合并请求参数
|
||||
$params = array_merge($params, ['msgData' => $msgData], $options);
|
||||
// 数据签名
|
||||
$params['msgDigest'] = $this->sign($params['msgData'], $this->timestamp);
|
||||
// 多维数组转成一维
|
||||
$this->convert_params($params);
|
||||
return $this->fire('/std/service', ['form_params' => $params]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
/**
|
||||
* Write by BoWen 2023/9/15 下午3:47
|
||||
* Email: gzbw79@163.com
|
||||
* 订单确认/取消接口-速运类API
|
||||
*/
|
||||
|
||||
namespace Gzlbw\sfexpress;
|
||||
|
||||
class UpdateOrder extends Handler implements IHandler
|
||||
{
|
||||
protected $serviceCode = 'EXP_RECE_UPDATE_ORDER';
|
||||
|
||||
protected $waybillNoInfoList = [];
|
||||
|
||||
public function req(array $msgData, array $options = [])
|
||||
{
|
||||
$this->timestamp = $this->get_time();
|
||||
|
||||
// 获取公共请求参数
|
||||
$params = $this->common_params($this->serviceCode);
|
||||
// 合并请求参数
|
||||
$params = array_merge($params, ['msgData' => $msgData], $options);
|
||||
// 数据签名
|
||||
$params['msgDigest'] = $this->sign($params['msgData'], $this->timestamp);
|
||||
// 多维数组转成一维
|
||||
$this->convert_params($params);
|
||||
return $this->fire('/std/service', ['form_params' => $params]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消订单
|
||||
* @param string $order_no 业务单号
|
||||
* @param string $express_no 快递单号
|
||||
* @param int $type 运单号类型 1:母单 2 :子单 3 : 签回单
|
||||
* @param array $msgData 其它业务参数
|
||||
*/
|
||||
public function cancel(string $order_no, string $express_no = '', int $type = 1, array $msgData = []) {
|
||||
if (!empty($express_no)) {
|
||||
$this->waybillNoInfoList[] = ['waybillType' => $type, 'waybillNo' => $express_no];
|
||||
}
|
||||
|
||||
return $this->req(array_merge([
|
||||
'dealType' => 2,
|
||||
'language' => 'zh-CN',
|
||||
'orderId' => $order_no,
|
||||
'waybillNoInfoList' => $this->waybillNoInfoList
|
||||
], $msgData));
|
||||
}
|
||||
|
||||
/**
|
||||
* 确认订单
|
||||
* @param string $order_no 业务单号
|
||||
* @param string $express_no 快递单号
|
||||
* @param int $type 运单号类型 1:母单 2 :子单 3 : 签回单
|
||||
* @param array $msgData 其它业务参数
|
||||
*/
|
||||
public function confirm(string $order_no, string $express_no = '', int $type = 1, array $msgData = []) {
|
||||
if (!empty($express_no)) {
|
||||
$this->waybillNoInfoList[] = ['waybillType' => $type, 'waybillNo' => $express_no];
|
||||
}
|
||||
|
||||
return $this->req(array_merge([
|
||||
'dealType' => 1,
|
||||
'language' => 'zh-CN',
|
||||
'orderId' => $order_no,
|
||||
'waybillNoInfoList' => $this->waybillNoInfoList
|
||||
], $msgData));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
*
|
||||
!.gitignore
|
Loading…
Reference in New Issue