一、配置文件 (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框架编写,其他同行可以自行修改代码以适用自己公司的框架)