上海航信电子发票对接
一、配置文件 (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框架编写,其他同行可以自行修改代码以适用自己公司的框架)