发票管理apiadmin
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

481 lines
17 KiB

<?php
namespace app\service\invoice;
use app\model\InvoiceHead;
use app\model\InvoiceIssuance;
use app\model\InvoiceIssuanceData;
use app\service\webService\ChinaTaxes;
use app\service\webService\FeeService;
use Endroid\QrCode\Builder\Builder;
use Endroid\QrCode\Encoding\Encoding;
use Endroid\QrCode\ErrorCorrectionLevel\ErrorCorrectionLevelHigh;
use Endroid\QrCode\Label\Alignment\LabelAlignmentCenter;
use Endroid\QrCode\Label\Font\NotoSans;
use Endroid\QrCode\Writer\PngWriter;
use fast\FuncException;
use think\App;
use think\facade\Log;
use think\facade\Request;
class InvoiceIssuanceService
{
/**
* 获取发票列表
* @param $param
* @param $wechat_user_id
* @return array
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
public static function getListPage($param, $wechat_user_id): array
{
$limit = $params['limit'] ?? 10;
$where = [
['wechat_user_id', '=', $wechat_user_id],
['delete_time', '=', 0]
];
if (isset($param['start_date']) && !empty($param['start_date'])) {
$where[] = [
'create_time', '>=', strtotime($param['start_date'] . ' 00:00:00')
];
}
if (isset($param['end_date']) && !empty($param['end_date'])) {
$where[] = [
'create_time', '<=', strtotime($param['end_date'] . ' 23:59:59')
];
}
$model = (new InvoiceIssuance());
$data = $model->where($where)
->field('id,project_id,invoice_head_id,amount,create_time,status')
->order('create_time desc')
->paginate($limit, false)
->each(function ($item, $key) {
$InvoiceHead = (new InvoiceHead)->find($item->invoice_head_id);
$item->serial_number = date("YmdHis") . rand(0000, 9999);
$item->head_type = '';
$item->head_title = '';
if ($InvoiceHead) {
$item->head_type = InvoiceHead::$typeArr[$InvoiceHead['type']];
$item->head_title = $InvoiceHead['title'];
}
$item->project_id = InvoiceIssuance::$projectArr[$item->project_id] ?? '';
$item->status = InvoiceIssuance::$statusArr[$item->status];
});
return $data->toArray();
}
/**
* 验证缴费
* @param $pucode
* @param $expire_time
* @param $project_id
* @return string[]
* @throws FuncException
*/
public static function validateFeePay($pucode, $expire_time, $project_id): array
{
$expire_date = date('Ym', strtotime($expire_time));
$errorMsg = '该账单还未缴费,请先完成缴费。';
switch ($project_id) {
case 1:
$ComputeDetail = self::getFeeComputeDetail($pucode, $expire_date);
if ($ComputeDetail['MsgID'] != 1) {
throw new FuncException($errorMsg);
}
return ['amount' => $ComputeDetail['WaterAmount']];
case 2:
throw new FuncException('尚未开发,请耐心等待!');
default:
throw new FuncException('尚未开发,请耐心等待!');
}
}
/**
*
* @param $pucode
* @param $expire_date
* @return mixed
* @throws FuncException
*/
public static function getFeeComputeDetail($pucode, $expire_date)
{
$FeeService = new FeeService($pucode);
$param = [
'startCostYearMonth' => $expire_date,
'endCostYearMonth' => $expire_date,
'PaymentStatus' => 2,
];
return $FeeService->getComputeDetail($param);
}
/**
* 获取二维码
* @param $id
* @return string
*/
public static function getQrCode($id): string
{
$url = Request::domain();
$codeUrl = $url . '/api/InvoiceIssuance/downFile?id='.$id;
$result = Builder::create()
->writer(new PngWriter())
->writerOptions([])
->data($codeUrl)
->encoding(new Encoding('UTF-8'))
->errorCorrectionLevel(new ErrorCorrectionLevelHigh())
->size(300)
->margin(10)
->labelText('发票已开具,请扫描二维码获取发票!')
->labelFont(new NotoSans(20))
->labelAlignment(new LabelAlignmentCenter())
->validateResult(false)
->build();
return $result->getDataUri();
}
/**
* 处理申请日期
* @param $expire_time
* @return array
*/
private function getInvoiceDate($expire_time): array
{
$expire_time = strtotime(date("Y-m",$expire_time));
return [
'nsqxDm' => date("m", $expire_time), // 申请月份
'skssqq' => date("Y-m-d", $expire_time), // 申请开始日期
'skssqz' => date("Y-m-d", strtotime('+1 month -1 day', $expire_time)),// 申请结束日期
];
}
/**
* 获取水务用户信息
* @param $pucode
* @return array|mixed
* @throws FuncException
*/
private function getFeeUserData($pucode)
{
$FeeService = new FeeService($pucode);
$feeUsers = $FeeService->getUsers();
if (!$feeUsers) {
throw new FuncException('未获取到用户信息');
}
return $feeUsers;
}
/**
* 开具完税证明
* @param $invoiceIssuance // 开票信息
* @return bool|string
*/
public function IssueAnInvoice($invoiceIssuance)
{
try {
// 用户编码
$pucode = $invoiceIssuance['pucode'];
if (empty($invoiceIssuance['expire_time'])) {
throw new FuncException('申请日期不能为空');
}
$invoiceDate = $this->getInvoiceDate($invoiceIssuance['expire_time']);
$feeUsers = $this->getFeeUserData($pucode);
$bdznsrsbh = '91440300772709730N'; // 被代征纳税人识别号
$feeUsers['bdznsrsbh'] = $bdznsrsbh;
// 获取用户应收费信息
$FeeComputeDetail = self::getFeeComputeDetail($pucode, date("Ym", $invoiceIssuance['expire_time']));
if ($FeeComputeDetail['MsgID'] != 1) {
throw new FuncException($FeeComputeDetail);
}
$feeUsers['jsyj'] = $FeeComputeDetail['WaterAmount'];
$feeUsers['zsfsmc'] = $FeeComputeDetail['chargetype'];
$feeUsers['jfrq'] = $FeeComputeDetail['WaterPayDate'];
// 保存
$ChinaTaxes = new ChinaTaxes($feeUsers, $invoiceDate);
$savingDetailedData = $ChinaTaxes->savingDetailedData();
// 批次号
$sbpch = $savingDetailedData['sbpch'];
(new InvoiceIssuanceData())->saveField($invoiceIssuance['id'], 'sbpch', $sbpch);
// 委托 - 加工数据
$realTimeProcessing = $ChinaTaxes->realTimeProcessing($sbpch);
if ($realTimeProcessing['code'] == 200) {
// 处理加工成功返回数据
if (!isset($realTimeProcessing['data']['mxGrid'])) {
throw new FuncException('加工数据有误');
}
$mxGrid = $realTimeProcessing['data']['mxGrid'];
$jsyj = 0; // 总金额
if (isset($mxGrid['sbMxsjVOList'])) {
foreach ($mxGrid['sbMxsjVOList'] as $sbMxsjVOValue) {
if (isset($sbMxsjVOValue['jsyj'])) $jsyj += $sbMxsjVOValue['jsyj'];
}
}
// 加工成功 电子缴款申请
$issueElectronic = $ChinaTaxes->issueElectronic($sbpch, $bdznsrsbh);
if (!isset($issueElectronic['pzsqkjYcxxList']['pzsqkjYcxxVO']['assetID'])) {
throw new FuncException('文件唯一标识不存在');
}
$assetID = $issueElectronic['pzsqkjYcxxList']['pzsqkjYcxxVO']['assetID']; // 文件唯一标识
// 查询电子缴款凭证上链信息
$queryPaymentVoucher = $ChinaTaxes->queryPaymentVoucher($assetID);
//$mmq = $queryPaymentVoucher['mmq'];
$meta = $queryPaymentVoucher['meta'];
$data = $queryPaymentVoucher['data'];
// 拼接pdf
// 盖章
$requestData = ['data' => $data, 'meta' => $meta];
$deCompress = $this->deCompress($requestData);
if ($deCompress['status'] != 200) {
throw new FuncException('pdf数据解密失败');
}
if (!isset($deCompress['data']['pdfdata'])) {
throw new FuncException('pdf文件合并失败');
}
$pdfFilepath = $this->savePdfFile($deCompress['data']['pdfdata']);
(new InvoiceIssuanceData())->saveData($invoiceIssuance['id'], $bdznsrsbh, $jsyj, $assetID, $pdfFilepath);
(new InvoiceIssuance())->where('id', $invoiceIssuance['id'])->save(['status' => 3]);
} else if ($realTimeProcessing['code'] == 302) {
// 加工失败
// 查询上传异常数据接口
$queryUploadErrorData = $ChinaTaxes->queryUploadErrorData($sbpch);
if (!isset($queryUploadErrorData['mxGrid']['sbMxsjVOList']['ycms'])) {
throw new FuncException('异常信息返回有误');
}
// 查询待开具电子缴款
$queryIssuedPaymentVoucher = $ChinaTaxes->queryIssuedPaymentVoucher($bdznsrsbh);
// 保存用户异常状态
$ycms = $queryUploadErrorData['mxGrid']['sbMxsjVOList']['ycms']; // 数据异常描述
(new InvoiceIssuanceData())->saveField($invoiceIssuance['id'], 'ycms', $ycms);
// 开票失败
(new InvoiceIssuance())->where('id', $invoiceIssuance['id'])->save(['status' => 2]);
//throw new FuncException('加工失败流程待定!');
}
return true;
} catch (\Exception $e) {
(new InvoiceIssuanceData())->saveField($invoiceIssuance['id'], 'ycms', $e->getMessage());
$this->writeLog($e);
return $e->getMessage();
}
}
/**
* 用户更正数据后作废再发起
*/
public function cancelInitiateAgain($invoiceIssuance)
{
try {
$feeUsers = $this->getFeeUserData($invoiceIssuance['pucode']);
$InvoiceIssuanceWhere = ['invoice_issuance_id' => $invoiceIssuance['id'], 'status' => 1];
$InvoiceIssuanceData = (new InvoiceIssuanceData())->where($InvoiceIssuanceWhere)->find();
if (!$InvoiceIssuanceData) {
throw new FuncException('上次发起数据不存在');
}
$bdznsrsbh = '91440300772709730N'; // 被代征纳税人识别号
$sbpch = $InvoiceIssuanceData['sbpch'];
$ChinaTaxes = new ChinaTaxes($feeUsers, []);
$identityCheck = $ChinaTaxes->identityCheck($bdznsrsbh);
if (isset($identityCheck['zt']) && $identityCheck['zt'] == 'N') {
throw new FuncException($identityCheck['Yy']);// 返回校验不通过原因
}
// 代征明细数据虚拟户更正接口
$ChinaTaxes->collectionDetails($bdznsrsbh, $sbpch);
// 作废 3.2
$ChinaTaxes->invalidEntrustCollection($sbpch);
// 修改作废
(new InvoiceIssuanceData())->saveField($invoiceIssuance['id'], 'status', 0, 2);
$result = $this->IssueAnInvoice($invoiceIssuance);
if ($result !== true) {
throw new \Exception($result);
}
return true;
} catch (\Exception $e) {
(new InvoiceIssuanceData())->saveField($invoiceIssuance['id'], 'ycms', $e->getMessage());
$this->writeLog($e);
return $e->getMessage();
}
}
/**
* 保存 PDF
* @param $pdfBaseData
* @return string
*/
public function savePdfFile($pdfBaseData): string
{
$pdfStr = str_replace('data:application/pdf;base64,', '', $pdfBaseData);
$pdfDecode = base64_decode($pdfStr);
$d = '/';
$fileName = time() . rand(000000, 999999) . '.pdf';
$now_date = date("{$d}Y{$d}m{$d}d");
$downPath = 'pdffile' . $now_date;
$fileDirPath = (new App())->getRootPath() . 'public' . $d . $downPath;
$filenamePath = $fileDirPath . $d . $fileName;
$savePath = $downPath . $d . $fileName;
if (!file_exists($fileDirPath)) {
mkdir($fileDirPath, 0777, true);
}
file_put_contents($filenamePath, $pdfDecode);
return $savePath;
}
/**
* 汇总结报 (汇总、结报)
* @param $invoiceIssuance
* @throws FuncException
*/
public function SummaryReport($invoiceIssuance)
{
if (empty($invoiceIssuance['expire_time'])) {
throw new FuncException('申请日期不能为空');
}
$invoiceDate = $this->getInvoiceDate($invoiceIssuance['expire_time']);
$bdznsrsbh = ''; // 被征纳税人
$ChinaTaxes = new ChinaTaxes([], $invoiceDate);
$daiZhengSummaryQuery = $ChinaTaxes->daiZhengSummaryQuery($bdznsrsbh);
$sbpch = $daiZhengSummaryQuery['cxwjbList']['cxwjbVO']['sbpch']; // 申报批次号
$ydzse = $daiZhengSummaryQuery['cxwjbList']['cxwjbVO']['ydzse']; // 应代征税额
$ChinaTaxes->daiZhengSummaryReport($ydzse);
}
public function writeLog($e)
{
Log::record('Exception message: ' . $e->getMessage());
Log::record('Exception file: ' . $e->getFile());
Log::record('Exception line: ' . $e->getLine());
Log::record('Exception trace: ' . $e->getTraceAsString());
}
/**
* 调用java sm4 解密
* @param array $data
* @return mixed
* @throws FuncException
*/
public function deCompress(array $data)
{
$java_decode_url = 'https://intp.xingtongworld.com/v1/tax/xt';
// 初始化cURL会话
$ch = curl_init();
// 设置cURL选项
curl_setopt($ch, CURLOPT_URL, $java_decode_url); // 目标URL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回结果而不是输出
curl_setopt($ch, CURLOPT_POST, true); // 发送POST请求
// 设置POST字段
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: multipart/form-data')); // 设置HTTP头
// 跳过证书验证(不推荐在生产环境使用)
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// 跳过主机名验证
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
// 执行cURL会话
$response = curl_exec($ch);
// 检查是否有错误发生
if (curl_errno($ch)) {
throw new FuncException('请求失败');
}
// 关闭cURL会话
curl_close($ch);
return json_decode($response, true);
}
/**
* get请求
* @param $url
* @return mixed
* @throws FuncException
*/
public function curlGet($url)
{
// 初始化cURL会话
$ch = curl_init();
// 设置cURL选项
curl_setopt($ch, CURLOPT_URL, $url); // 目标URL
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回结果而不是输出
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET"); // 发送GET请求
// 跳过证书验证(不推荐在生产环境使用)
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// 跳过主机名验证
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
// 执行cURL会话
$response = curl_exec($ch);
// 检查是否有错误发生
if (curl_errno($ch)) {
throw new FuncException('请求失败');
}
// 关闭cURL会话
curl_close($ch);
return json_decode($response, true);
}
}