51book的机票接口对接,吐血整理(含封装代码)

前言 最近在对接51book的机票接口,遇到了挺多坑,所以整理一份作为记录

机票有两个不同的接口,一个是机票,另一个是保险

一、申请

要接51book的机票,首先是要申请账号,这时候应该是有客户经理跟进,然后具体事宜都会告诉你。

拿到账号之后,客户经理会把你的账号拉入测试组,不然测试购买机票然后改签、退票都是需要钱的,做测试支付机票的时候还要去后台开通2个东西:

  1. 机票支付宝授权,添加营业员
  2. 保险支付宝授权

这两个是分别授权的,有两个网址。

对了,后台还有密码要设置,点击“我的余额”然后就可以设置了。

二、逻辑

购买机票的逻辑

  1. 查询航班
  2. 查看航班座位
  3. 选择座位预订
  4. 填写相关信息,预订订单
  5. 支付
  6. 后续改签、退票

三、开发

51book那边会有接口文档,现在已经更新http新接口

接口主页:http://ws.51book.com/
机票新接口:http://ws.51book.com/ltips/web/CustomerDetailController.in?id=13&flag=getDetail&language=CH

保险接口文档目前还没有在线的,由51book那边单独发送

接口测试需要51book那边把你的ip设为白名单

机票接口:
  1. 公共
  2. 航班查询
  3. 机票预定
  4. 支付
  5. 通知
    1. 出票通知
    2. 取消--取消订单退款通知
    3. 航变通知
    4. 退票通知
    5. 改期通知
  6. 查询订单详情
  7. 支付前校验
    1. 我们av查询时试试运价 这个已经调去一次了时时数据了,那么客人查询一直都不支付,会存在位子是否有效,那么二次验价就会起到效果,他会再次调取一次,如果发生变化他会重新验价,客户支付不了,如果没有就直接可以支付。二次验价主要是给客户更好的体验
    2. 需要开通才能用
  8. 变更查询
  9. 变更申请
  10. 变更需支付
  11. 退票查询
  12. 退票退款申请
  13. 验证舱位价格
  14. 获取客规
    1. 改签退票手续费在这里
注意事项

接口参数和返回都说的很清楚,这里就不在详细描述了,我做对接的时候遇到几个坑,需要注意一下:

  1. 要熟悉下航空公司的规则,例如:儿童是不让单独乘机的,所以买票的时候要做下判断
  2. 儿童不让单独乘机,引发改签和退票也不能单独改和退,所以这里也要做判断
  3. 带儿童的订单,接口返回有两个订单号,都要记录
  4. 因为有2个订单号,所以在接收改签和退票的时候,51book那边发的通知是2次,(但是出票通知就一次)
  5. 改签的时候,原来订单里的票号是不变的,所以后期查询订单接口就查不到变更后的信息,需要自己记录
改签相关
  1. 改签没有次数限制,因为要收手续费,只要航班没起飞就可以改签
  2. 改签不能改出发地和目的地
  3. 变更中是不能改签和退票
  4. 改签只能修改价格比当前高的,同时舱位也要比之前高
  5. 改签手续费是按照原来航班的票价
我设置的状态:

1000:待支付 ,

2000:已支付,待出票 ,

3000:已出票 ,

4000:变更审核中 ,

4100:变更需支付 ,

4200: 处理中,

4300:变更完成,

4400:无法变更,

5000:退票审核中,

5100:审核通过,待退款

5200:退款成功,

5300:无法退/废票,

5400:退款失败,

6000:已取消,

保险接口

  1. 查询保险产品接口
  2. 保险产品查询
  3. 投保
  4. 保险支付
  5. 保单查询
  6. 退保申请

保险接口没有http协议的接口,用的是wsdl格式的,php用soap来对接

首先要说的是保险接口没有异步通知,就是说你下单成功了,他们不是马上可以出保单,需要一会时间,这时候没法立刻获取到保单号,需要调用“保单查询”接口去查,而且不能立即查,需要过一会之后去查才有。查的时候把保单信息放入数据库中。

注意事项

  1. 没有异步通知

  2. 同个人买不同产品需要调用多次购买接口,同个产品的保单明细可以放多个人,就是说一个产品要下一个单

附上机票接口请求封装代码(thinkphp5写的) 注意事项:

  1. segmentList、passengerList这样的参数是二维数组
  2. 有儿童订单的时候返回的是2个数组,两个订单号
<?php
namespace app\common\library\book51;

use think\Env;

/**
 * Class Client
 * @package app\common\library\book51
 * 51book机票接口
 * @author linmt <[<email address>]>
 */
class Client
{
    private $host ;
    private $api ;
    private $code ;
    private $username ;
    public $thirdUsername = '公司名' ;
    function __construct($api='')
    {
        $this->api = $api;
        $this->code= Env::get('51book.code','加密码');
        $this->username= Env::get('51book.username','账号');
        $this->host = "http://api.51book.com/".$this->username."/51";
    }
    public function getUsername(){
        return $this->username;
    }

    public function getApiData($rqData){
        //获取13位带毫秒的时间戳
        list($msec, $sec) = explode(' ', microtime());
        $msectime = (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
        $postFields = [
            'rsIsGzip' => true,
            'rqIdentification' => randomNum(10).time(),//用户自定义唯一(请求表示用于bug,查询记录log ; 小于,等于32长度字符串)
            //13位时间戳
            'timeStamp' => $msectime,
            //第三方名称
            'thirdUsername' => $this->thirdUsername,
            //业务参数
            'rqData' => $rqData
        ];

        $result = $this->curlPost($this->host.$this->api,$postFields);
        //dd($result);
        $result = json_decode($result,true);

        return $result;
    }

    //CURL 请求
    public function curlPost($url,$postFields){
        //将传递过来的参数,数组进行json转换
        $postFields = json_encode($postFields);
        //将参数加密,拼接安全码
        $sign = md5($postFields . $this->code);

        //初始化curl
        $ch = curl_init ();
        $curl_array = array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 100,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => "POST",
            CURLOPT_POSTFIELDS => "{$postFields}",
            CURLOPT_HTTPHEADER => array(
                "cache-control: no-cache",
                "content-type: application/json",
                "sign: {$sign}",
                "username: {$this->username}"
            ),
        );
        
        //组装请求头
        curl_setopt_array($ch, $curl_array);
        //开始请求
        $ret = curl_exec($ch);
        if (false == $ret) {
            $result = curl_error(  $ch);
        } else {
            $rsp = curl_getinfo( $ch, CURLINFO_HTTP_CODE);
            if (200 != $rsp) {
                $result = "请求状态 ". $rsp . " " . curl_error($ch);
            } else {
                $result = $ret;
            }
        }
        curl_close ($ch);
        //返回数组,json格式
        return $result;
    }

}

附上保险接口请求封装代码(需要安装soap扩展)

<?php
namespace app\common\library\book51;
use think\Env;
/**
 * 51book保险api
 * Class Insurance
 * @package app\common\library\book51
 * @author linmt 20191008
 */
class InsuranceClient
{
    private $host = "http://ws.51book.com:8000/ltips/services/insuranceProductService1.0?wsdl";
    private $api ;
    private $code  ;
    private $username;
    private $funcArr  ;
    public $thirdUsername  ;
    function __construct($api='')
    {

        $this->username = Env::get('51book.username','公司名');
        $this->code = Env::get('51book.code','加密码');
        $this->thirdUsername = Env::get('51book.thirdUsername','第三方名');
        $this->api = $api;
        $this->funcArr = [
            'createInsuranceOrder'=>0,
            'getInsuranceOrder'=>1,
            'queryInsProduct'=>2,
            'payInsuranceOrder'=>3,
            'applyForRefund'=>4,
        ];
    }

    /**
     * @param $reqData
     * @param $func
     * @param array $signArr 需要加密sign的字段
     * @return bool
     * @throws \SoapFault
     *  接口列表
     * [0] => createInsuranceOrderResponse createInsuranceOrder(createInsuranceOrder $parameters)
    [1] => getInsuranceOrderResponse getInsuranceOrder(getInsuranceOrder $parameters)
    [2] => queryInsProductResponse queryInsProduct(queryInsProduct $parameters)
    [3] => payInsuranceOrderResponse payInsuranceOrder(payInsuranceOrder $parameters)
    [4] => applyForRefundResponse applyForRefund(applyForRefund $parameters)
     */
    function soapRequest($reqData,$func,$signArr){
        array_unshift($signArr,$this->username);
        array_push($signArr,$this->code);
        $sign = md5(implode('',$signArr));
        $url = $this->host;
        $reqData = array_merge($reqData,['agencyCode'=>$this->username],['sign'=>$sign]);
        $data = array('request' =>$reqData);
        $options = array(
            'trace' 				=> true,
            'encoding' 				=> 'UTF-8',
            'connection_timeout' 	=> 120,
            'soap_version' 			=> 'SOAP_1_1',
            'compression'			=>'SOAP_COMPRESSION_ACCEPT | SOAP_COMPRESSION_GZIP',
            'keep_alive'			=>true
        );
        try {
            $soapclient = new \Soapclient($url, $options);
        }catch (Exception $e ){
            print_r($e);exit;
            return false;
        }
        $funarr	=	$soapclient->__getFunctions();
        //print_r($soapclient->__getTypes ());exit;
        $fun_num = $this->funcArr[$func];
        $fun	=	substr($funarr[$fun_num],strpos($funarr[$fun_num],' ')+1,strpos($funarr[$fun_num],'(')-strpos($funarr[$fun_num],' ')-1);
        try {
            //$back=$soapclient->__call($fun,$data);
            $back=$soapclient->$fun($data);
        }catch (Exception $e ){
            print_r($e);exit;
            return false;
        }
        return $this->objectArray($back);
    }
    
    //对象转数组
    private function objectArray($array) {
        if(is_object($array)) {
            $array = (array)$array;
        }
        if(is_array($array)) {
            foreach($array as $key=>$value) {
                $array[$key] = $this->objectArray($value);
            }
        }
        return $array;
    }
}

流程图奉上 改签流程图 退票流程图

林明潭blog
请先登录后发表评论
  • latest comments
  • 总共0条评论