一、配置文件 (config/invoice.php;发票配置数据由开票平台提供,以下配置数据随机修改过不可用于测试)

 


<?php/**
* Created by PhpStorm. * User: Jason * Date: 2019/7/1 * Time: 10:16 */ return [ \'DSPTBM\' => \'sdf11dfd1MsfdFWegesdfIK\', //\'电商平台编码\' \'NSRSBH\' => \'9670101000000090\', //\'纳税人识别码\' \'NSRMC\' => \'XXX官方旗舰店\', //\'纳税人名称\', \'XHFMC\' => \'XXX官方旗舰店\', //\'销货方名称\' \'XHF_DZ\' => \'上海市杨浦区控江路XXX号\', //\'销货方地址\', \'XHF_DH\' => \'17621251***\', //\'销货方电话\', \'XHF_YHZH\' => \'\', //\'销货方银行账号\', \'KPY\' => \'财务一\', //\'开票员\', \'SKY\' => \'\', //\'收款员(可选)\', \'HSBZ\' => \'1\', \'TERMINALCODE\' => \'0\', \'APPID\' => \'ZZS_PT_DZFP\', \'TAXPAYWERID\' => \'9670101000000090\', //\'税号\', \'AUTHORIZATIONCODE\' => \'56301000000090\', //\'授权码\', \'ENCRYPTCODE\' =>\'2\', //0:不加密 1: 3DES 加密 2:CA \'INTERFACE_FPKJ\' => \'ECXML.FPKJ.BC.E_INV\', \'INTERFACE_FPXZ\' => \'ECXML.FPXZ.CX.E_INV\', \'INTERFACE_FPYX\' => \'ECXML.EMAILPHONEFPTS.TS.E.INV\', \'REQUESTCODE\' => \'sdf11dfd1MsfdFWegesdfIK\', //\'请求码\', \'RESPONSECODE\' => \'211\', //\'响应码\', \'PASSWORD\' => \'\', //\'密码\', ///\'DATAEXCHANGEID\' => \'交互码\', \'KJFP\' => \'ECXML.FPKJ.BC.E_INV\', \'DOWNLOAD\' => \'ECXML.FPXZ.CX.E_INV\', \'EMAIL\' => \'ECXML.EMAILPHONEFPTS.TS.E.INV\', \'REGISTERCODE\' => \'922588450019\', //\'注册码\', ];

  二、拼装请求数据 (packageinfo.php)

<?php
/**
 * Created by PhpStorm.
 * User: Jason
 * Date: 2019/7/2
 * Time: 10:35
 */

class ome_invoice_packageinfo
{
    private static $_instance = null;

    private $config = [];

    public function __construct()
    {
        $this->config = include ROOT_DIR.\'/config/invoice.php\';
    }

    /***
     * @param $interface
     * @return string
     */
    public function getXml($interface, $content)
    {
        $rand = rand(1000000000,9999999999);
        $pwd = $rand.base64_encode(md5($rand.$this->config[\'REGISTERCODE\']));
        $terminalcode = $this->config[\'TERMINALCODE\'];
        $appid = $this->config[\'APPID\'];
        $dsptbm = $this->config[\'DSPTBM\'];
        $password = $pwd;
        $date = date(\'Y-m-d\');
        $taxpayerid = $this->config[\'TAXPAYWERID\'];
        $authorizationcode = $this->config[\'AUTHORIZATIONCODE\'];
        $response = $this->config[\'RESPONSECODE\'];
        $dataexchangeid = $this->config[\'REQUESTCODE\'].date(\'Ymd\').substr($rand,0,9);
        $str = <<<XML
<?xml version="1.0" encoding="utf-8" ?>
<interface xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.chinatax.gov.cn/tirip/dataspec/interfaces.xsd"
	version="DZFP1.0">
<globalInfo>
		 <terminalCode>{$terminalcode}</terminalCode>
		 <appId>{$appid}</appId>
		 <version>2.0</version>
		 <interfaceCode>{$interface}</interfaceCode>
		 <requestCode>{$dsptbm}</requestCode>
		 <requestTime>{$date}</requestTime>
		 <responseCode>{$response}</responseCode>
		 <dataExchangeId>{$dataexchangeid}</dataExchangeId>
		 <userName>{$dsptbm}</userName>
		 <passWord>{$password}</passWord>
		 <taxpayerId>{$taxpayerid}</taxpayerId>
		 <authorizationCode>{$authorizationcode}</authorizationCode>
</globalInfo>
<returnStateInfo>
<returnCode/>
<returnMessage/>
</returnStateInfo>
<Data>
	<dataDescription>
		  <zipCode>0</zipCode>
		  <encryptCode>0</encryptCode>
		  <codeType>0</codeType>
	</dataDescription>
	<content>
		{$content}	
	</content>
</Data>
</interface>
XML;


        return $str;

    }

    /***
     * @param array $config
     * @param array $arr
     * @return string
     */
    public function getContent(array $arr)
    {
      
        $fpkj = \'\';
        foreach ($this->content_0($config) as $key => $item){
            if($item[\'text\']!==\'\'){
                $fpkj .= \'<\'.strtoupper($item[\'key\']).\'>\'.$item[\'text\'].\'</\'.$item[\'key\'].\'>\';
            }else{
                $fpkj .= \'<\'.strtoupper($item[\'key\']).\'>\'.$arr[$item[\'key\']].\'</\'.$item[\'key\'].\'>\';
            }
        }
        $xm_size = count($arr[\'items\']);
        $fpkj_xm = \'\';
        foreach ($arr[\'items\'] as $num => $value){
            $fpkj_xm .= \'<FPKJXX_XMXX>\';
            foreach ($this->content_1($config) as $key=>$item){
                if($item[\'text\']!==\'\'){
                    $fpkj_xm .= \'<\'.strtoupper($item[\'key\']).\'>\'.$item[\'text\'].\'</\'.$item[\'key\'].\'>\';
                }else{
                    $fpkj_xm .= \'<\'.strtoupper($item[\'key\']).\'>\'.$value[$item[\'key\']].\'</\'.$item[\'key\'].\'>\';
                }
            }
            $fpkj_xm .= \'</FPKJXX_XMXX>\';
            //津贴被折扣行
            if(isset($value[\'discount\'])){
                //size对应
                $xm_size++;
                $fpkj_xm .= \'<FPKJXX_XMXX>\';
                foreach ($this->content_1($config) as $key=>$item){
                    if($item[\'text\']!==\'\'){
                        $fpkj_xm .= \'<\'.strtoupper($item[\'key\']).\'>\'.$item[\'text\'].\'</\'.$item[\'key\'].\'>\';
                    }else{
                        $fpkj_xm .= \'<\'.strtoupper($item[\'key\']).\'>\'.$value[\'discount\'][$item[\'key\']].\'</\'.$item[\'key\'].\'>\';
                    }
                }
                $fpkj_xm .= \'</FPKJXX_XMXX>\';
            }
        }
        $fpkj_dd = \'\';
        foreach ($this->content_2() as $key=>$item){
            if($item[\'text\']!==\'\'){
                $fpkj_dd .= \'<\'.strtoupper($item[\'key\']).\'>\'.$item[\'text\'].\'</\'.$item[\'key\'].\'>\';
            }else{
                if($item[\'text\']===null){
                    $fpkj_dd .= \'<\'.strtoupper($item[\'key\']).\'/>\';
                    continue;
                }
                $fpkj_dd .= \'<\'.strtoupper($item[\'key\']).\'>\'.$arr[$item[\'key\']].\'</\'.$item[\'key\'].\'>\';
            }
        }
        $root = <<<ROOT
<REQUEST_FPKJXX class="REQUEST_FPKJXX">
    <FPKJXX_FPTXX class="FPKJXX_FPTXX">
       {$fpkj}
    </FPKJXX_FPTXX>
    <FPKJXX_XMXXS class="FPKJXX_XMXX;" size="{$xm_size}">
    {$fpkj_xm}
    </FPKJXX_XMXXS>
    <FPKJXX_DDXX class="FPKJXX_DDXX">
    {$fpkj_dd}
    </FPKJXX_DDXX>
</REQUEST_FPKJXX>
ROOT;

        return base64_encode($root);
    }

    /***
     * @param string $xml
     * @return mixed|\SimpleXMLElement
     */
    public function XML2array(string $xml)
    {
        $arr = simplexml_load_string($xml);
        $arr = json_decode(json_encode($arr),TRUE);
        return $arr;
    }

    public function getDownload($arr)
    {
        $content = \'\';

        foreach ($this->download($this->config) as $key => $item){
            if($item[\'text\']!==\'\'){
                $content .= \'<\'.strtoupper($item[\'key\']).\'>\'.$item[\'text\'].\'</\'.$item[\'key\'].\'>\';
            }else{
                if($item[\'text\']===null){
                    $content .= \'<\'.strtoupper($item[\'key\']).\'/>\';
                    continue;
                }
                $content .= \'<\'.strtoupper($item[\'key\']).\'>\'.$arr[$item[\'key\']].\'</\'.$item[\'key\'].\'>\';
            }
        }

        $root = <<<ROOT
<REQUEST_FPXXXZ_NEW class="REQUEST_FPXXXZ_NEW">
    {$content}
</REQUEST_FPXXXZ_NEW>
ROOT;

        return base64_encode($root);
    }

    /***
     * @param array $arr
     * @return string
     */
    public function getEmail(array $arr)
    {
        $nsrsbh = $this->config[\'NSRSBH\'];

        $root = <<<ROOT
<REQUEST_EMAILPHONEFPTS class="REQUEST_EMAILPHONEFPTS">
    <TSFSXX class="TSFSXX">
        <COMMON_NODES class="COMMON_NODE;" size="4">
            <COMMON_NODE> 
                <NAME>TSFS</NAME> 
                <VALUE>0</VALUE>
            </COMMON_NODE>
            <COMMON_NODE>
                <NAME>SJ</NAME>
                <VALUE></VALUE> 
            </COMMON_NODE>
            <COMMON_NODE>
                <NAME>EMAIL</NAME>
                <VALUE>{$arr[\'email\']}</VALUE> 
            </COMMON_NODE>
            <COMMON_NODE>
                <NAME>扩展字段名称</NAME>
                <VALUE>扩展字段值</VALUE> 
            </COMMON_NODE>
        </COMMON_NODES> 
    </TSFSXX>
    <FPXXS class="FPXX;" size="1">
        <FPXX>
             <COMMON_NODES class="COMMON_NODE;" size="5"> 
                <COMMON_NODE>
                    <NAME>FPQQLSH</NAME>
                    <VALUE>{$arr[\'FPQQLSH\']}</VALUE> 
                </COMMON_NODE>
                <COMMON_NODE>
                    <NAME>NSRSBH</NAME>
                    <VALUE>{$nsrsbh}</VALUE> 
                </COMMON_NODE> 
                <COMMON_NODE>
                    <NAME>FP_DM</NAME>
                    <VALUE>{$arr[\'fp_dm\']}</VALUE> 
                </COMMON_NODE> 
                <COMMON_NODE>
                    <NAME>FP_HM</NAME>
                    <VALUE>{$arr[\'fp_hm\']}</VALUE> 
                </COMMON_NODE> 
                <COMMON_NODE>
                    <NAME>扩展字段名称</NAME>
                    <VALUE>扩展字段值</VALUE>
                </COMMON_NODE>
            </COMMON_NODES> 
        </FPXX>
    </FPXXS>
</REQUEST_EMAILPHONEFPTS>
ROOT;

        return base64_encode($root);
    }

    /***
     * @param $config
     * @return array
     */
    private function content_0($config)
    {
        return  [
            \'FPQQLSH\'=>[
                \'key\'=>\'FPQQLSH\',
                \'text\'=>\'\',
                \'comment\'=>\'请求流水号\'
            ],
            \'DSPTBM\'=>[
                \'key\'=>\'DSPTBM\',
                \'text\'=>$config[\'DSPTBM\'],
                \'comment\'=>\'平台编码\'
            ],
            \'NSRSBH\'=>[
                \'key\'=>\'NSRSBH\',
                \'text\'=>$config[\'NSRSBH\'],
                \'comment\'=>\'开票方识别号\'
            ],
            \'NSRMC\'=>[
                \'key\'=>\'NSRMC\',
                \'text\'=>$config[\'NSRMC\'],
                \'comment\'=>\'开票方名称\'
            ],
            \'DKBZ\'=>[
                \'key\'=>\'DKBZ\',
                \'text\'=>\'0\'
            ],
            \'KPXM\'=>[
                \'key\'=>\'KPXM\',
                \'text\'=>\'\',
                \'comment\'=>\'商品信息中第一条\'
            ],
            \'BMB_BBH\'=>[
                \'key\'=>\'BMB_BBH\',
                \'text\'=>\'1.0\'
            ],
            \'XHF_NSRSBH\'=>[
                \'key\'=>\'XHF_NSRSBH\',
                \'text\'=>$config[\'NSRSBH\'],
                \'comment\'=>\'销方识别码\'
            ],
            \'XHFMC\'=>[
                \'key\'=>\'XHFMC\',
                \'text\'=>$config[\'NSRMC\'],
                \'comment\'=>\'销方名称\'
            ],
            \'XHF_DZ\'=>[
                \'key\'=>\'XHF_DZ\',
                \'text\'=>$config[\'XHF_DZ\'],
                \'comment\'=>\'销方地址\'
            ],
            \'XHF_DH\'=>[
                \'key\'=>\'XHF_DH\',
                \'text\'=>$config[\'XHF_DH\'],
                \'comment\'=>\'销方电话\'
            ],
            \'XHF_YHZH\'=>[
                \'key\'=>\'XHF_YHZH\',
                \'text\'=>$config[\'XHF_YHZH\'],
                \'comment\'=>\'销方银行账号\'
            ],
            \'GHFMC\'=>[
                \'key\'=>\'GHFMC\',
                \'text\'=>\'\',
                \'comment\'=>\'购货方名称\'
            ],
            \'GHF_SJ\'=>[
                \'key\'=>\'GHF_SJ\',
                \'text\'=>\'\',
                \'comment\'=>\'购货方手机\'
            ],
            //01-企业 02-机关事业单位 03-个人  04-其他
            \'GHFQYLX\'=>[
                \'key\'=>\'GHFQYLX\',
                \'text\'=>\'\',
                \'comment\'=>\'购货方名称\'
            ],
            \'SKY\'=>[
                \'key\'=>\'SKY\',
                \'text\'=>$config[\'SKY\'],
            ],
            \'KPY\'=>[
                \'key\'=>\'KPY\',
                \'text\'=>$config[\'KPY\'],
            ],
            //1 正票  2 红票
            \'KPLX\'=>[
                \'key\'=>\'KPLX\',
                \'text\'=>\'\',
                \'comment\'=>\'开票类型\'
            ],
            //10 正票正常开具 11 正票错票重开 20 退货折让红票 21 错票重开红票 22 换票冲红(全冲红电子发票,开具纸质发票)
            \'CZDM\'=>[
                \'key\'=>\'CZDM\',
                \'text\'=>\'\',
                \'comment\'=>\'操作代码\'
            ],
            \'QD_BZ\'=>[
                \'key\'=>\'QD_BZ\',
                \'text\'=>\'0\'
            ],
            //小数点后2位 以元为单位精确到分  double
            \'KPHJJE\'=>[
                \'key\'=>\'KPHJJE\',
                \'text\'=>\'\',
                \'comment\'=>\'价税合计金额\'
            ],
            //double
            \'HJBHSJE\'=>[
                \'key\'=>\'HJBHSJE\',
                \'text\'=>\'\',
                \'comment\'=>\'合计不含税金额\'
            ],
            \'HJSE\'=>[
                \'key\'=>\'HJSE\',
                \'text\'=>\'\',
                \'comment\'=>\'合计税额\'
            ]
        ];
    }


    /***
     * @param array $config
     * @return array
     */
    private function content_1(array $config)
    {
        return [
            \'XMMC\'=>[
                \'key\'=>\'XMMC\',
                \'text\'=>\'\',
                \'comment\'=>\'项目名称\'
            ],
            \'XMSL\'=>[
                \'key\'=>\'XMSL\',
                \'text\'=>\'\',
                \'comment\'=>\'项目数量\'
            ],
            \'HSBZ\'=>[
                \'key\'=>\'HSBZ\',
                \'text\'=>$config[\'HSBZ\']
            ],
            \'FPHXZ\'=>[
                \'key\'=>\'FPHXZ\',
                \'text\'=>\'\',
            ],
            //小数点后8位小数
            \'XMDJ\'=>[
                \'key\'=>\'XMDJ\',
                \'text\'=>\'\'
            ],
            \'SPBM\'=>[
                \'key\'=>\'SPBM\',
                \'text\'=>\'\'
            ],
            \'ZXBM\'=>[
                \'key\'=>\'ZXBM\',
                \'text\'=>\'\'
            ],
            \'YHZCBS\'=>[
                \'key\'=>\'YHZCBS\',
                \'text\'=>\'0\',
                \'comment\'=>\'优惠政策标识\'
            ],
            //小数点后2位
            \'XMJE\'=>[
                \'key\'=>\'XMJE\',
                \'text\'=>\'\',
                \'comment\'=>\'项目金额\'
            ],
            //税率
            \'SL\'=>[
                \'key\'=>\'SL\',
                \'text\'=>\'0.03\'
            ],
        ];
    }

    /***
     * @return array
     */
    private function content_2()
    {
        return [
            \'DDH\'=>[
                \'key\'=>\'DDH\',
                \'text\'=>\'\'
            ],
            \'DDDATE\'=>[
                \'key\'=>\'DDDATE\',
                \'text\'=>null,
            ]
        ];
    }

    /***
     * @param array $config
     * @return array
     */
    private function download(array $config)
    {
        return [
            \'DDH\'=>[
                \'key\'=>\'DDH\',
                \'text\'=>\'\',
            ],
            \'FPQQLSH\'=>[
                \'key\'=>\'FPQQLSH\',
                \'text\'=>\'\'
            ],
            \'DSPTBM\'=>[
                \'key\'=>\'DSPTBM\',
                \'text\'=>$config[\'DSPTBM\'],
            ],
            \'NSRSBH\'=>[
                \'key\'=>\'NSRSBH\',
                \'text\'=>$config[\'NSRSBH\'],
            ],
            \'PDF_XZFS\'=>[
                \'key\'=>\'PDF_XZFS\',
                \'text\'=>\'\'  //0-发票状态查询 1-pdf文件
            ]
        ];
    }

    /***
     * @param array $config
     * @return array
     */
    public function email(array $config)
    {
        return [
            \'TSFS\'=>\'\',
            \'EMAIL\'=>\'\',
            \'FPQQLSH\'=>\'\',
            \'NSRSBH\'=>$config[\'NSRSBH\'],
            \'FP_DM\'=>\'\',
            \'FP_HM\'=>\'\'
        ];
    }

    private function udate($utimestamp = null) {
        if (is_null($utimestamp))
            $utimestamp = microtime(true);

        $timestamp = floor($utimestamp);
        $milliseconds = round(($utimestamp - $timestamp) * 100);
        return $milliseconds;
    }
}

  三、封装SDK(invoicesdk.php)

<?php
/**
 * Created by PhpStorm.
 * User: Jason
 * Date: 2019/7/3
 * Time: 10:20
 */
date_default_timezone_set("Asia/Shanghai");

class ome_invoice_invoicesdk
{
    const KJFP = \'ECXML.FPKJ.BC.E_INV\';
    const DOWNLOAD = \'ECXML.FPXZ.CX.E_INV\';
    const EMAIL = \'ECXML.EMAILPHONEFPTS.TS.E.INV\';

    const HOST = \'http://fw1test.shdzfp.com:9000/sajt-shdzfp-sl-http/SvrServlet\';    //test

    public function __construct()
    {
        $this->packageInfoObj = kernel::single("ome_invoice_packageinfo");
    }

    /***
     * @param array $arr
     * @return \SimpleXMLElement
     * 开具发票
     */
    public function create(array $arr)
    {
        $data = [];
        if ($arr[\'invoice_type\'] == 2) {
            $data[\'ghfmc\'] = $arr[\'invoice_title\'];
            $data[\'ghfqylx\'] = \'01\';
        } else {
            $data[\'ghfmc\'] = \'个人\';
            $data[\'ghfqylx\'] = \'03\';
        }
        $items = [];
        //查询子项目
        foreach ($arr[\'items\'] as $key => $item) {
            $show_name = $item[\'name\'];
            $items[$key][\'XMMC\'] = $show_name;
            $items[$key][\'XMSL\'] = sprintf(\'%.8f\', $item[\'quantity\']);
            $items[$key][\'XMDJ\'] = sprintf(\'%.8f\', $item[\'price\']);
            $items[$key][\'SPBM\'] = $item[\'spbm\'];
            $items[$key][\'ZXBM\'] = $item[\'zxbm\'];
            $items[$key][\'XMJE\'] = sprintf(\'%.2f\', $item[\'price\'] * $item[\'quantity\']);


            if ($arr[\'discount\'] && $arr[\'discount\'] != 0.00 && $key == 0) {
                $items[$key][\'FPHXZ\'] = 2;
                $items[$key][\'discount\'] = [
                    \'XMMC\' => $show_name,
                    \'XMSL\' => \'-\' . sprintf(\'%.8f\', 1),
                    \'FPHXZ\' => \'1\',
                    \'XMDJ\' => sprintf(\'%.8f\', $arr[\'discount\']),
                    \'SPBM\' => $item[\'spbm\'],
                    \'ZXBM\' => $item[\'id\'],
                    \'XMJE\' => \'-\' . sprintf(\'%.2f\', $arr[\'discount\'])
                ];
            } else {
                $items[$key][\'FPHXZ\'] = 0;
            }
            if ($key == 0) {
                $data[\'KPXM\'] = $show_name; //kpxm
            }
        }
        $data[\'items\'] = $items;
        $data[\'mobile\'] = isset($arr[\'mobile\']) ? $arr[\'mobile\'] : \'\';
        
        $data[\'KPHJJE\'] = sprintf(\'%.2f\', $arr[\'sum\']);
        $data[\'HJBHSJE\'] = sprintf(\'%.2f\', $arr[\'sum\']);
        $data[\'HJSE\'] = sprintf(\'%.2f\', $arr[\'HJSE\']);
        $data[\'DDH\'] = $arr[\'order_bn\'];

        $data[\'FPQQLSH\'] = $arr[\'FPQQLSH\'];
        ///$data[\'KPXM\'] = $arr[\'KPXM\'];
        $data[\'GHFMC\'] = $arr[\'GHFMC\'];
        $data[\'GHF_SJ\'] = $arr[\'GHF_SJ\'];
        $data[\'GHFQYLX\'] = $arr[\'GHFQYLX\'];
        $data[\'KPLX\'] = $arr[\'KPLX\'];
        $data[\'CZDM\'] = $arr[\'CZDM\'];
        
        $content = $this->packageInfoObj->getContent($data);

        $xml = $this->packageInfoObj->getXml(self::KJFP, $content);
        file_put_contents(\'./request_xml_\' . date(\'YmdHis\', time()) . \'.xml\', $xml);
        
        
        $request_time = microtime(true);
        $response = $this->postCurl(self::HOST, $xml);
        $this->runtime = microtime(true) - $request_time;
        
        //file_put_contents(\'./invoice_response_\' . date(\'YmdHis\', time()) . \'.xml\', $response);
        
        $content = simplexml_load_string($response);

        //请求日志数据组装
        $log_data = array(
            \'api_handler\' => \'request\',
            \'api_name\' => \'ECXML.FPKJ.BC.E_INV\',
            \'api_status\' => $content->returnStateInfo->returnCode == \'0000\' ? \'success\' : \'fail\',
            \'api_request_time\' => $request_time,
            \'api_check_time\' => time(),
            \'api_runtime\' => $this->get_runtime(),
            \'api_method\' => \'POST\',
            \'api_response_status\' => empty($content->returnStateInfo->returnCode) ? \'-\' : (string) $content->returnStateInfo->returnCode,
            \'api_url\' => self::HOST,
            \'api_request_data\' => $xml,
            \'api_response_data\' => $response,
            \'sys_error_data\' => $content->returnStateInfo->returnCode == \'0000\' ? \'NULL\' : (string) base64_decode($content->returnStateInfo->returnMessage),
        );

        $this->writeLog($log_data);

        if ($content->returnStateInfo->returnCode == \'0000\') {
            $kaipiaoModel = app::get("ome")->model("invoice_kaipiao");

            $kaipiao_data = [
                \'order_bn\' => $data[\'DDH\'],
                \'fpqqlsh\' => $data[\'FPQQLSH\'],
                \'user_name\' => (string) $content->globalInfo->userName,
                \'password\' => (string) $content->globalInfo->passWord,
                \'add_time\' => time()
            ];
            
            $kaipiaoModel->save($kaipiao_data);
        }


        
        return $content;
    }

    /***
     * @param array $arr
     * @return mixed
     */
    public function download(array $arr)
    {
       
        $data[\'FPQQLSH\'] = \'SW_1562151541_1019422043\';    //此处FPQQLSH必须是开票成功时请求数据里的FPQQLSH

        $len = strlen($arr[\'order_bn\']);
        $data[\'lsh\'] = str_repeat(\'0\', 20 - $len) . $arr[\'order_bn\'];
        $data[\'PDF_XZFS\'] = 2;
        $data[\'DDH\'] = $arr[\'order_bn\'];
        $content = $this->packageInfoObj->getDownload($data);
        $xml = $this->packageInfoObj->getXml(self::DOWNLOAD, $content);

        //file_put_contents(\'./download_request_xml_\' . date(\'YmdHis\', time()) . \'.xml\', $xml);

        $request_time = microtime(true);
        $response = $this->postCurl(self::HOST, $xml);
        $this->runtime = microtime(true) - $request_time;

        file_put_contents(\'./download_invoice_response_\' . date(\'YmdHis\', time()) . \'.xml\', $response);

        $content = simplexml_load_string($response);

        //请求日志数据组装
        $log_data = array(
            \'api_handler\' => \'request\',
            \'api_name\' => \'ECXML.FPXZ.CX.E_INV\',
            \'api_status\' => $content->returnStateInfo->returnCode == \'0000\' ? \'success\' : \'fail\',
            \'api_request_time\' => $request_time,
            \'api_check_time\' => time(),
            \'api_runtime\' => $this->get_runtime(),
            \'api_method\' => \'POST\',
            \'api_response_status\' => empty($content->returnStateInfo->returnCode) ? \'-\' : (string) $content->returnStateInfo->returnCode,
            \'api_url\' => self::HOST,
            \'api_request_data\' => $xml,
            \'api_response_data\' => $response,
            \'sys_error_data\' => $content->returnStateInfo->returnCode == \'0000\' ? \'NULL\' : (string) base64_decode($content->returnStateInfo->returnMessage),
        );

        $this->writeLog($log_data);

        if ($content->returnStateInfo->returnCode == \'0000\') {
            //PDF_XZFS 1 content内容要先解密再解压
            if ($content->Data->dataDescription->zipCode == 1) {
                $content = gzdecode(base64_decode($return->Data->content));
                $pdf = simplexml_load_string($content);
                return $pdf;
            }
        } elseif ($return->Data->dataDescription->zipCode[0] == 2){
                //PDF_XZFS 2 content内容只要解密不要解压
               $content = base64_decode($return->Data->content);
                $pdf = simplexml_load_string($content);
                return $pdf;
        }
    }

    public function email(array $arr)
    {
        $len = strlen($arr[\'order_bn\']);
        $data[\'lsh\'] = str_repeat(\'0\', 20 - $len) . $arr[\'order_bn\'];
        $data[\'eamil\'] = $arr[\'email\'];
        $data[\'fp_dm\'] = $arr[\'fp_dm\'];
        $data[\'fp_hm\'] = $arr[\'fp_hm\'];
        $content = $this->packageInfoObj->getEmail($data);
        $xml = $this->packageInfoObj->getXml(self::EMAIL, $content);

        $request_time = microtime(true);
        $response = $this->postCurl(self::HOST, $xml);
        $this->runtime = microtime(true) - $request_time;

        $return = simplexml_load_string($response);
        if ($return->returnStateInfo->returnCode == \'0000\') {
            //修改状态
            return $return;
        }
        //请求日志数据组装
        $log_data = array(
            \'api_handler\' => \'request\',
            \'api_name\' => \'ECXML.FPXZ.CX.E_INV\',
            \'api_status\' => $return->returnStateInfo->returnCode == \'0000\' ? \'success\' : \'fail\',
            \'api_request_time\' => $request_time,
            \'api_check_time\' => time(),
            \'api_runtime\' => $this->get_runtime(),
            \'api_method\' => \'POST\',
            \'api_response_status\' => empty($return->returnStateInfo->returnCode) ? \'-\' : (string) $return->returnStateInfo->returnCode,
            \'api_url\' => self::HOST,
            \'api_request_data\' => $xml,
            \'api_response_data\' => $response,
            \'sys_error_data\' => $return->returnStateInfo->returnCode == \'0000\' ? \'NULL\' : (string) base64_decode($return->returnStateInfo->returnMessage),
        );

        $this->writeLog($log_data);
    }

    public function postCurl($url, $params, $headerArr = \'\')
    {
        if (!$url) {
            return \'请求缺少URL!\';
        }

        $headers = array(
            //\'content-type:application/json;charset=utf-8\',
            \'content-type:application/x-www-form-urlencoded;charset=utf-8\',

        );

        if (is_array($headerArr) && !empty($headerArr)) {
            $queryHeaders = array();
            foreach ($headerArr as $k => $v) {
                $queryHeaders[] = $k . \':\' . $v;
            }
            //print_r($queryHeaders);
            $headers = array_merge($headers, $queryHeaders);
        }

        //$body = json_encode($params);
        $body = $params;

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_POST, 1);

        //curl_setopt($ch, CURLOPT_HTTPHEADER,array("Content-Type: application/json;charset=utf-8"));

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);

        //绕过SSL验证
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        if (!empty($headers)) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }

        $return_content = curl_exec($ch);//运行curl
        curl_close($ch);

        return $return_content;

    }

    public function writeLog($log_data)
    {
        app::get(\'ome\')->model(\'invoice_request_log\')->save($log_data);
    }

    /**
     * 获取接口调用执行时间
     * @return string
     */
    protected function get_runtime()
    {
        return sprintf(\'%.6f\', $this->runtime);
    }
}

   四、测试脚本

<?php
/**
 * Created by PhpStorm.
 * User: Jason
 * Date: 2019/7/3
 * Time: 18:59
 */
class ome_ctl_test extends desktop_controller
{
   

    public function invoice()
    {
        $arr = [
            \'invoice_type\' => \'01\',
            \'invoice_title\' => \'测试发票单\',
            \'items\' => [
                [
                    \'name\' => \'手表\',	//项目名称
                    \'quantity\' => \'1\',
                    \'price\' => \'100.00\',	//项目单价
                    \'spbm\' => \'1040204020000000000\',	//商品编码 填商品名称对应的商品税收分类编码,19位不足补0
                    \'zxbm\' => \'1001\',	//自行编码
                    \'id\' => \'1001\',		//有折扣时自行编码取值

                ],
            ],
            \'discount\' => \'\',
            \'mobile\' => \'17621256***\',
            \'sum\' => \'100.00\',	//价税合计金额
            \'order_bn\' => \'order_1000001\',	//订单号
            \'FPQQLSH\' => \'SW_\'.time().\'_\'.rand(1000000000, 9999999999),	//请求流水号
            \'KPXM\' => \'sfd\',	//商品信息中第一条
            \'GHFMC\' => \'张三\',	//购货方名称
            \'GHF_SJ\' => \'17621256***\',	//购货方手机
            \'GHFQYLX\' => \'01\',	//购货方企业类型
            \'KPLX\' => \'1\',	//开票类型	1 正票 2 红票
            \'CZDM\' => \'10\',	//操作代码
            \'HJBHSJE\' => \'90.00\',	//合计不含税金额
            \'HJSE\' => \'100\',	//合计税额

            \'KPHJJE\' => \'100\',	//价税合计金额

        ];

        $invoiceSdkObj = kernel::single("ome_invoice_invoicesdk");

        //$res = $invoiceSdkObj->create($arr);
        $res = $invoiceSdkObj->download($arr);



    }

}

 

五、response返回示例:

  1.开票

  

<?xml version="1.0" encoding="UTF-8"?>
<interface xmlns:schemaLocation="http://www.chinatax.gov.cn/tirip/dataspec/interfaces.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="WLFP1.0">
 <globalInfo>
  <terminalCode>0</terminalCode>
  <appId>ZZS_PT_DZFP</appId>
  <version>2.0</version>
  <interfaceCode>ECXML.FPKJ.BC.E_INV</interfaceCode>
  <requestCode>111MFWIK</requestCode>
  <requestTime>2019-07-03</requestTime>
  <responseCode>121</responseCode>
  <dataExchangeId>111MFWIK20190703127514978</dataExchangeId>
  <userName>111MFWIK</userName>
  <passWord>1275149784YTZjMDUxMTcwZGIzYTE4NjU5ODM1NGUxOTA0MzcyMDg=</passWord>
  <taxpayerId>310101000000090</taxpayerId>
  <authorizationCode>3100000090</authorizationCode>
 </globalInfo>
 <returnStateInfo>
  <returnCode>0000</returnCode>
  <returnMessage>5o6l5pS25byA56Wo5pWw5o2u5oiQ5Yqf77yB</returnMessage>
 </returnStateInfo>
 <Data>
  <dataDescription>
   <zipCode>0</zipCode>
   <encryptCode>0</encryptCode>
   <codeType>0</codeType>
  </dataDescription>
  <content />
 </Data>
</interface>

  2.发票下载(含发票 PDF URL)

  

<?xml version="1.0" encoding="utf-8" ?>
<interface xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.chinatax.gov.cn/tirip/dataspec/interfaces.xsd"
    version="DZFP1.0">
<globalInfo>
         <terminalCode>0</terminalCode>
         <appId>ZZS_PT_DZFP</appId>
         <version>2.0</version>
         <interfaceCode>ECXML.FPXZ.CX.E_INV</interfaceCode>
         <requestCode>111MFWIK</requestCode>
         <requestTime>2019-07-04</requestTime>
         <responseCode>121</responseCode>
         <dataExchangeId>111MFWIK20190704138486180</dataExchangeId>
         <userName>111MFWIK</userName>
         <passWord>1384861802N2UzZmFhMzg1MTY0M2ZmOGRiNjE3YjJhNjhkMzdjNGI=</passWord>
         <taxpayerId>310101000000090</taxpayerId>
         <authorizationCode>3100000090</authorizationCode>
</globalInfo>
<returnStateInfo>
<returnCode/>
<returnMessage/>
</returnStateInfo>
<Data>
    <dataDescription>
          <zipCode>0</zipCode>
          <encryptCode>0</encryptCode>
          <codeType>0</codeType>
    </dataDescription>
    <content>
        PFJFUVVFU1RfRlBYWFhaX05FVyBjbGFzcz0iUkVRVUVTVF9GUFhYWFpfTkVXIj4KICAgIDxEREg+b3JkZXJfMTAwMDAwMTwvRERIPjxGUFFRTFNIPlNXXzE1NjIxNTE1NDFfMTAxOTQyMjA0MzwvRlBRUUxTSD48RFNQVEJNPjExMU1GV0lLPC9EU1BUQk0+PE5TUlNCSD4zMTAxMDEwMDAwMDAwOTA8L05TUlNCSD48UERGX1haRlM+MjwvUERGX1haRlM+CjwvUkVRVUVTVF9GUFhYWFpfTkVXPg==    
    </content>
</Data>
</interface>

 

  3.发票下载(含发票 PDF FILE)

  

<?xml version="1.0" encoding="utf-8" ?>
<interface xmlns="" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.chinatax.gov.cn/tirip/dataspec/interfaces.xsd"
    version="DZFP1.0">
<globalInfo>
         <terminalCode>0</terminalCode>
         <appId>ZZS_PT_DZFP</appId>
         <version>2.0</version>
         <interfaceCode>ECXML.FPXZ.CX.E_INV</interfaceCode>
         <requestCode>111MFWIK</requestCode>
         <requestTime>2019-07-03</requestTime>
         <responseCode>121</responseCode>
         <dataExchangeId>111MFWIK20190703112641847</dataExchangeId>
         <userName>111MFWIK</userName>
         <passWord>1126418479NmNkOTIyN2YzNDQ4MDNjMGU1MWUyNDkzZTc1ZmVkZGI=</passWord>
         <taxpayerId>310101000000090</taxpayerId>
         <authorizationCode>3100000090</authorizationCode>
</globalInfo>
<returnStateInfo>
<returnCode/>
<returnMessage/>
</returnStateInfo>
<Data>
    <dataDescription>
          <zipCode>0</zipCode>
          <encryptCode>0</encryptCode>
          <codeType>0</codeType>
    </dataDescription>
    <content>
        PFJFUVVFU1RfRlBYWFhaX05FVyBjbGFzcz0iUkVRVUVTVF9GUFhYWFpfTkVXIj4KICAgIDxEREg+b3JkZXJfMTAwMDAwMTwvRERIPjxGUFFRTFNIPlNXXzE1NjIxNTE1NDFfMTAxOTQyMjA0MzwvRlBRUUxTSD48RFNQVEJNPjExMU1GV0lLPC9EU1BUQk0+PE5TUlNCSD4zMTAxMDEwMDAwMDAwOTA8L05TUlNCSD48UERGX1haRlM+MTwvUERGX1haRlM+CjwvUkVRVUVTVF9GUFhYWFpfTkVXPg==    
    </content>
</Data>
</interface>

 

六、发票样式效果

  

 

  

(注:代码基于商派OMS框架编写,其他同行可以自行修改代码以适用自己公司的框架)

版权声明:本文为IT-Crowd原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/IT-Crowd/p/11131355.html