diff --git a/pom.xml b/pom.xml
index e8b2cc7..b22cf81 100644
--- a/pom.xml
+++ b/pom.xml
@@ -247,7 +247,50 @@
org.xerial
sqlite-jdbc
-
+
+
+ com.oracle.database.jdbc
+ ojdbc8
+ 19.8.0.0
+
+
+
+ com.oracle.database.nls
+ orai18n
+ 19.8.0.0
+
+
+
+
+ jakarta.xml.bind
+ jakarta.xml.bind-api
+ 2.3.3
+
+
+
+ com.sun.xml.bind
+ jaxb-core
+ 2.3.0
+
+
+ com.sun.xml.bind
+ jaxb-impl
+ 2.3.0
+
+
+
+ jakarta.activation
+ jakarta.activation-api
+ 1.2.2
+
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
diff --git a/sql/sqlite3.db b/sql/sqlite3.db
index eaa5696..c491636 100644
Binary files a/sql/sqlite3.db and b/sql/sqlite3.db differ
diff --git a/src/main/java/top/lidee/common/constant/InvoiceConstants.java b/src/main/java/top/lidee/common/constant/InvoiceConstants.java
new file mode 100644
index 0000000..2800d88
--- /dev/null
+++ b/src/main/java/top/lidee/common/constant/InvoiceConstants.java
@@ -0,0 +1,13 @@
+package top.lidee.common.constant;
+
+public class InvoiceConstants {
+
+ /** 未处理 */
+ public static final String UNTREATED = "0";
+
+ /** 已处理 但未成功 Processed but not successful*/
+ public static final String PROCESSED_NOT_SUCCESSFUL = "1";
+
+ /** 已成功 */
+ public static final String SUCCESSFUL = "2";
+}
diff --git a/src/main/java/top/lidee/project/monitor/job/task/SuYuanScheduledTask.java b/src/main/java/top/lidee/project/monitor/job/task/SuYuanScheduledTask.java
new file mode 100644
index 0000000..3214d66
--- /dev/null
+++ b/src/main/java/top/lidee/project/monitor/job/task/SuYuanScheduledTask.java
@@ -0,0 +1,203 @@
+package top.lidee.project.monitor.job.task;
+
+/*
+ * 发票引入定时任务
+ * */
+
+import org.apache.shiro.util.CollectionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import top.lidee.common.constant.InvoiceConstants;
+import top.lidee.project.monitor.job.util.HttpXml;
+import top.lidee.project.monitor.job.util.InvoiceXmlSy;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+import top.lidee.project.system.record.mapper.GrInvoiceRecordMapper;
+
+import javax.annotation.Resource;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.sql.*;
+import java.text.SimpleDateFormat;
+import java.util.*;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 发票定时任务(更新发票状态)
+ *
+ */
+
+@Component("suYuanScheduledTask")
+public class SuYuanScheduledTask {
+ private static final Logger log = LoggerFactory.getLogger(SuYuanScheduledTask.class);
+ // 数据库连接信息
+
+ @Value("${invoice.url}")
+ private String URL;
+
+ @Value("${invoice.eiInvWebService}")
+ private String eiInvWebServiceUrl;
+ /**
+ * 数据库用户名
+ */
+ @Value("${invoice.username}")
+ private String USERNAME;
+ /**
+ * 数据库密码
+ */
+ @Value("${invoice.password}")
+ private String PASSWORD;
+ @Value("${invoice.taxId}")
+ private String taxId;
+ @Value("${invoice.authCode}")
+ private String authCode;
+ @Value("${invoice.updateCode}")
+ private String interfaceCode;
+ private static final String fPath = "C:\\log\\fplog.log";
+
+ @Resource
+ private GrInvoiceRecordMapper grInvoiceRecordMapper;
+
+ public void updateInvoice() {
+ GrInvoiceRecord grInvoiceRecord = new GrInvoiceRecord();
+ grInvoiceRecord.setStatus(InvoiceConstants.UNTREATED);
+ List grInvoiceRecords = grInvoiceRecordMapper.selectGrInvoiceRecordList(grInvoiceRecord);
+ if (CollectionUtils.isEmpty(grInvoiceRecords)) {
+ System.out.println("没有待请求数据");
+ return;
+ }
+ try {
+
+ for (GrInvoiceRecord invoiceRecord : grInvoiceRecords) {
+ String key = invoiceRecord.getDjh();
+ String txtCon = "";
+ List billNos = new ArrayList<>();
+ billNos.add(key);
+
+ System.out.println("溯源 Id:" + billNos);
+ txtCon += "溯源 Id:" + billNos + "\n";
+ //封装 请求报文
+ String xmldata = InvoiceXmlSy.generateDwzsXml(billNos);
+
+ // 组装接口需要的请求报文
+ String payload = HttpXml.bulidSoapXML(interfaceCode, taxId, authCode, xmldata, "eiInterface");
+ System.out.println(payload);
+ boolean hasError = false;
+ try {
+ // 调用接口
+ Map res = HttpXml.webServiceExecute(eiInvWebServiceUrl, payload);
+ System.out.println("接口请求状态:" + res.get("httpStatus"));
+ System.out.println("接口返回的原始报文:" + res.get("data"));
+ txtCon += "接口请求状态:" + res.get("httpStatus") + "\n";
+ txtCon += "接口返回的原始报文:" + res.get("data") + "\n";
+ if (200 == (int) res.get("httpStatus")) {
+ try {
+ // 解析接口返回的报文
+ HashMap serviceData = HttpXml.parseResponseXML((String) res.get("data"));
+ System.out.println("业务处理返回代码:" + serviceData.get("returnCode"));
+ System.out.println("业务处理返回提示:" + serviceData.get("returnMessage"));
+ System.out.println("业务处理返回数据:" + serviceData.get("data"));
+
+ txtCon += "业务处理返回代码:" + serviceData.get("returnCode") + "\n";
+ txtCon += "业务处理返回提示:" + serviceData.get("returnMessage") + "\n";
+ txtCon += "业务处理返回数据:" + serviceData.get("data") + "\n";
+// appendToFile(fPath, txtCon);
+ String invNumber = "1";
+ String xml = serviceData.get("data");
+ Pattern pattern = Pattern.compile("(.*?)");
+ Matcher matcher = pattern.matcher(xml);
+ if (matcher.find()) {
+ invNumber = matcher.group(1);
+ }
+
+ // 如果没有被开发票(invNumber 为 1)
+ if (invNumber.equals("1")) {
+ log.error("单据号 " + key + " 还未开票");
+ continue;
+ }
+
+ if (serviceData.get("returnCode").equals("0000")) {
+ //更新数据库
+ Connection conn = null;
+ Statement stmt = null;
+ ResultSet rs = null;
+ try {
+ System.out.println("更新视图开始");
+ // 1. 加载 Oracle JDBC 驱动
+ Class.forName("oracle.jdbc.driver.OracleDriver");
+ // 2. 建立数据库连接
+ conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
+ // 3. 创建 Statement 对象
+ stmt = conn.createStatement();
+ // 4. 执行查询语句
+ String sql = "update gr_dp_saset_sdhm_v a set a.zxcolumn1 = '" + invNumber + "' where a.sasettleid =" + key;
+ PreparedStatement pstmt = conn.prepareStatement(sql);
+ int rowsA = pstmt.executeUpdate();
+ System.out.println("完成更新视图:" + rowsA);
+ invoiceRecord.setStatus(InvoiceConstants.SUCCESSFUL);
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ invoiceRecord.setKpsj(sdf.format(new Date()));
+ invoiceRecord.setInvNumber(invNumber);
+ grInvoiceRecordMapper.updateGrInvoiceRecord(invoiceRecord);
+ } catch (Exception e) {
+ e.printStackTrace();
+ // 发生错误,标记为已尝试但不需要重试
+ hasError = true;
+ // 6. 关闭资源
+ try {
+ if (rs != null) rs.close();
+ if (stmt != null) stmt.close();
+ if (conn != null) conn.close();
+ } catch (SQLException e11) {
+ e11.printStackTrace();
+ }
+ }
+ } else {
+ // 业务处理失败,标记为已尝试但不需要重试
+ hasError = true;
+ log.error("业务处理失败:" + serviceData.get("returnMessage"));
+ }
+ } catch (Exception e) {
+ log.error("解析报文出错的,保持业务为处理中状态,需要检查原因");
+ e.printStackTrace();
+ hasError = true;
+ }
+ } else {
+ // HTTP 请求状态不是 200,标记为已尝试但不需要重试
+ hasError = true;
+ log.error("HTTP 请求失败,状态码:" + res.get("httpStatus"));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ hasError = true;
+ }
+
+ // 如果发生错误,更新状态为 1(已尝试但不需要重试)
+ if (hasError) {
+ invoiceRecord.setStatus(InvoiceConstants.PROCESSED_NOT_SUCCESSFUL);
+ grInvoiceRecordMapper.updateGrInvoiceRecord(invoiceRecord);
+ log.error("单据号 " + key + " 处理失败,标记为已尝试状态");
+ }
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ // 追加写入模式
+ public static void appendToFile(String filePath, String content) throws IOException {
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, true))) {
+ writer.newLine(); // 换行后再追加
+ writer.write(content);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/java/top/lidee/project/monitor/job/task/YinEuScheduledTask.java b/src/main/java/top/lidee/project/monitor/job/task/YinEuScheduledTask.java
new file mode 100644
index 0000000..0097707
--- /dev/null
+++ b/src/main/java/top/lidee/project/monitor/job/task/YinEuScheduledTask.java
@@ -0,0 +1,228 @@
+package top.lidee.project.monitor.job.task;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.stereotype.Component;
+import top.lidee.common.constant.InvoiceConstants;
+import top.lidee.project.monitor.job.util.HttpXml;
+import top.lidee.project.monitor.job.util.InvoiceXmlGenerator;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+import top.lidee.project.system.record.mapper.GrInvoiceRecordMapper;
+
+import javax.annotation.Resource;
+import javax.xml.bind.JAXBException;
+import java.sql.*;
+import java.util.*;
+import java.util.Date;
+
+
+/**
+ * 发票定时任务
+ *
+ */
+@Component("yinEuScheduledTask")
+public class YinEuScheduledTask {
+
+ @Value("${invoice.url}")
+ private String URL;
+ /**
+ * 数据库用户名
+ */
+ @Value("${invoice.username}")
+ private String USERNAME;
+ /**
+ * 数据库密码
+ */
+ @Value("${invoice.password}")
+ private String PASSWORD;
+ @Value("${invoice.taxId}")
+ private String taxId;
+ @Value("${invoice.authCode}")
+ private String authCode;
+ @Value("${invoice.interfaceCode}")
+ private String interfaceCode;
+ @Value("${invoice.iBillInterfaceWebService}")
+ private String iBillInterfaceWebServiceUrl;
+
+
+ @Resource
+ private GrInvoiceRecordMapper grInvoiceRecordMapper;
+
+ // 每隔5秒执行一次
+ public void insertInvoice() {
+
+ System.out.println("单据引入开始执行");
+ //查询是否有待处理数据
+ Connection conn = null;
+ Statement stmt = null;
+ ResultSet rs = null;
+
+ try {
+ // 1. 加载Oracle JDBC驱动
+ Class.forName("oracle.jdbc.driver.OracleDriver");
+ // 2. 建立数据库连接
+ conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
+ // 3. 创建Statement对象
+ stmt = conn.createStatement();
+ // 4. 执行查询语句
+ String sql = "SELECT g.*,COUNT(*) OVER (PARTITION BY g.SASETTLEID) AS MXS FROM GR_DP_SASET_V g";
+ sql = "SELECT DJH,DJRQ,FPZL,KPLX,GMF_MC,HSBZ,XMMC,GGXH,DW,XMSL,XMDJ,XMJE,SL,ZKJE,CREATE_PERSON_NAME,BZ,SASETTLEID,SASETTLEDTLID,MXS FROM (SELECT t.*,COUNT(*) OVER (PARTITION BY DJH) AS MXS,\n" +
+ "ROW_NUMBER() OVER (PARTITION BY DJH ORDER BY SASETTLEID) AS rn FROM GR_DP_SASET_V t) WHERE rn = 1";
+ rs = stmt.executeQuery(sql);
+ if (!rs.isBeforeFirst()) {
+ System.out.println("警告:查询结果为空,没有待处理的单据数据!");
+ } else {
+ System.out.println("查询成功,开始处理单据数据...");
+ }
+ // 5. 处理查询结果
+ while (rs.next()) {
+ String SASETTLEID = rs.getString("SASETTLEID");
+ // 1. 构造根对象
+ InvoiceXmlGenerator.RequestCommonDjlr request = new InvoiceXmlGenerator.RequestCommonDjlr();
+
+ // 2. 构造发票集合
+ InvoiceXmlGenerator.CommonDjlrFpts fpts = new InvoiceXmlGenerator.CommonDjlrFpts();
+ List fptList = new ArrayList<>();
+
+ // 3. 构造一张发票头
+ InvoiceXmlGenerator.CommonDjlrFpt fpt = new InvoiceXmlGenerator.CommonDjlrFpt();
+ String djh = rs.getString("DJH");
+ String djrq = rs.getString("DJRQ");
+ String fpzl = rs.getString("FPZL");
+ String gmfMc = rs.getString("GMF_MC");
+ GrInvoiceRecord grInvoiceRecord = new GrInvoiceRecord();
+ grInvoiceRecord.setDjh(djh);
+ grInvoiceRecord.setDjrq(djrq);
+ grInvoiceRecord.setFpzl(fpzl);
+ grInvoiceRecord.setGmfMc(gmfMc);
+ grInvoiceRecord.setCreateTime(new Date());
+ fpt.setDjh(djh);
+ fpt.setDjrq(djrq);
+ fpt.setFpzl(fpzl);
+ fpt.setKplx(rs.getString("KPLX"));
+ fpt.setGmfMc(gmfMc);
+ fpt.setHsbz(rs.getString("HSBZ"));
+ fpt.setKpr("方国旭");
+ fpt.setSkr("方国旭");
+ fpt.setFhr("方国旭");
+ fpt.setBz(rs.getString("BZ"));
+ fpt.setZzbm("ORG001");
+// fpt.setCreatePersonName(rs.getString("CREATE_PERSON_NAME"));
+ fpt.setCreatePersonName("陈志");
+
+ // 4. 构造明细集合
+ InvoiceXmlGenerator.CommonDjlrXmxxs xmxxs = new InvoiceXmlGenerator.CommonDjlrXmxxs();
+ List xmxxList = new ArrayList<>();
+ if (rs.getString("MXS").toString().equals("1")) {
+ System.out.println("查询明细数据:1条");
+ InvoiceXmlGenerator.CommonDjlrXmxx xm1 = new InvoiceXmlGenerator.CommonDjlrXmxx();
+ xm1.setXh("1");
+ xm1.setXmmc(rs.getString("XMMC"));
+ xm1.setGgxh(rs.getString("GGXH"));
+ xm1.setDw(rs.getString("DW"));
+ xm1.setXmsl(rs.getString("XMSL"));
+ xm1.setXmje(rs.getString("XMJE"));
+ xm1.setSl(rs.getString("SL"));
+ xm1.setZkje(rs.getString("ZKJE"));
+ xmxxList.add(xm1);
+
+ } else {
+ //多条明细
+ ResultSet rsmx = null;
+ String sqlmx = "SELECT * FROM GR_DP_SASET_V where SASETTLEID=" + rs.getString("SASETTLEID");
+ rsmx = stmt.executeQuery(sqlmx);
+ System.out.println("查询明细数据:" + rsmx.getFetchSize() + "条");
+ int i = 1;
+ while (rsmx.next()) {
+ InvoiceXmlGenerator.CommonDjlrXmxx xm1 = new InvoiceXmlGenerator.CommonDjlrXmxx();
+ xm1.setXh(i + "");
+ xm1.setXmmc(rsmx.getString("XMMC"));
+ xm1.setGgxh(rsmx.getString("GGXH"));
+ xm1.setDw(rsmx.getString("DW"));
+ xm1.setXmsl(rsmx.getString("XMSL"));
+ xm1.setXmje(rsmx.getString("XMJE"));
+ xm1.setSl(rsmx.getString("SL"));
+ xm1.setZkje(rsmx.getString("ZKJE"));
+ xmxxList.add(xm1);
+ i++;
+ }
+ }
+
+ xmxxs.setCommonDjlrXmxxList(xmxxList);
+ fpt.setCommonDjlrXmxxs(xmxxs);
+
+ fptList.add(fpt);
+ fpts.setCommonDjlrFptList(fptList);
+ request.setCommonDjlrFpts(fpts);
+
+ // 5. 生成 XML 字符串
+ String xmldata = InvoiceXmlGenerator.generateXml(request).replace("", "");
+ //封装 请求报文
+ // 组装接口需要的请求报文
+ String payload = HttpXml.bulidSoapXML(interfaceCode, taxId, authCode, xmldata, "impSoHeaderInterface");
+
+ try {
+ // 调用接口
+ Map res = HttpXml.webServiceExecute(iBillInterfaceWebServiceUrl, payload);
+ System.out.println("接口请求状态:" + res.get("httpStatus"));
+ System.out.println("接口返回的原始报文:" + res.get("data"));
+ if (200 == (int) res.get("httpStatus")) {
+ try {
+ // 解析接口返回的报文
+// HashMap serviceData= parseResponseXML((String) res.get("data"));
+// System.out.println("业务处理返回代码:"+serviceData.get("returnCode"));
+// System.out.println("业务处理返回提示:"+serviceData.get("returnMessage"));
+// System.out.println("业务处理返回数据:"+serviceData.get("data"));
+ if (res.get("data").toString().contains("returnCode>0000</returnCode>")) {
+ //更新视图
+ System.out.println("更新视图");
+ String sqlupdate = "update GR_DP_SASET_V a set a.zxcolumn2 = '1' where a.sasettleid =" + SASETTLEID;
+ PreparedStatement pstmt = conn.prepareStatement(sqlupdate);
+ pstmt.execute();
+ System.out.println("完成更新视图");
+ grInvoiceRecord.setStatus(InvoiceConstants.UNTREATED);
+ grInvoiceRecord.setCreateTime(new Date());
+ grInvoiceRecordMapper.insertGrInvoiceRecord(grInvoiceRecord);
+ }
+
+ } catch (Exception e) {
+ System.out.println("解析报文出错的,保持业务为处理中状态,需要检查原因");
+ e.printStackTrace();
+ }
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.out.println("数据库操作失败");
+ }
+ System.out.println(xmldata);
+ }
+
+ } catch (ClassNotFoundException e) {
+ System.out.println("Oracle JDBC驱动未找到!");
+ e.printStackTrace();
+ } catch (SQLException | JAXBException e) {
+ System.out.println("数据库访问异常!");
+ e.printStackTrace();
+ } finally {
+ // 6. 关闭资源
+ try {
+ if (rs != null) rs.close();
+ if (stmt != null) stmt.close();
+ if (conn != null) conn.close();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ }
+
+// // 1. XML构造根对象
+// InvoiceXmlGenerator.RequestCommonDjlr request = new InvoiceXmlGenerator.RequestCommonDjlr();
+//
+// // 2. 构造发票集合
+// InvoiceXmlGenerator.CommonDjlrFpts fpts = new InvoiceXmlGenerator.CommonDjlrFpts();
+// List fptList = new ArrayList<>();
+
+
+ System.out.println("定时任务完成");
+ }
+
+}
diff --git a/src/main/java/top/lidee/project/monitor/job/util/HttpXml.java b/src/main/java/top/lidee/project/monitor/job/util/HttpXml.java
new file mode 100644
index 0000000..eb7ba5e
--- /dev/null
+++ b/src/main/java/top/lidee/project/monitor/job/util/HttpXml.java
@@ -0,0 +1,140 @@
+package top.lidee.project.monitor.job.util;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+
+
+public class HttpXml {
+
+ /*
+ * 数据请求
+ * @param requesturl 请求地址
+ * @param soapXML 请求报文
+ * */
+ public static Map webServiceExecute(String requesturl, String soapXML) throws Exception {
+ HttpURLConnection conn = null;
+ OutputStream os = null;
+ Map reslut = new HashMap<>();
+ try {
+ //1创建连接
+ URL url = new URL(requesturl);
+ conn = (HttpURLConnection) url.openConnection();
+ //2设置连接的配置
+ conn.setRequestMethod("POST");
+ conn.setRequestProperty("content-type", "text/xml;charset=utf-8");
+ conn.setDoInput(true);
+ conn.setDoOutput(true);
+ //3打开连接发送数据
+ os = conn.getOutputStream();
+ os.write(soapXML.getBytes());
+
+ String temp = null;
+ //4接收服务端的响应
+ //4.1http的响应码
+ int responseCode = conn.getResponseCode();
+ //4.2获取返回报文
+ BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
+ StringBuilder response = new StringBuilder();
+ String responseLine;
+ while ((responseLine = br.readLine()) != null) {
+ response.append(responseLine.trim());
+ }
+ //简单模拟封装返回结果
+ reslut.put("httpStatus", responseCode);
+ reslut.put("data", response.toString());
+
+ } catch (Exception e) {
+ throw new RuntimeException("调用"+requesturl+"webservice出错!", e);
+ } finally {
+ if (conn != null) {
+ conn.disconnect();
+ }
+ }
+ return reslut;
+ }
+
+ /**
+ * 构建Soap请求报文
+ * @param interfaceCode 接口编码
+ * @param taxId 税号
+ * @param authCode 授权码
+ * @param content 内层业务报文的明文
+ */
+ public static String bulidSoapXML(String interfaceCode, String taxId, String authCode, String content, String ffmc) {
+ //数据报文通过base64编码
+ String payload = Base64.getEncoder().encodeToString(content.getBytes(StandardCharsets.UTF_8));
+ return "\n" +
+ "\n" +
+ "\n" +
+ "\n" +
+ "\t \t\n" +
+ "\t \t\t\n" +
+ "\t\t1.0 \t\t\n" +
+ "\t\t" + taxId + " \t\t\n" +
+ "\t\t" + interfaceCode + " \t\t\n" +
+ "\t\t" + authCode + " \t\n" +
+ "\t \t\n" +
+ "\t\t \t\t\n" +
+ "\t\t0000 \t\t\n" +
+ "\t\t \t\n" +
+ "\t \t\n" +
+ "\t \t\t\n" +
+ "\t\t \t\t\t\n" +
+ "\t\t\t0 \t\t\t\n" +
+ "\t\t\t0 \t\t\t\n" +
+ "\t\t\t0 \t\t\n" +
+ "\t\t \t\t\n" +
+ "\t\t" + payload + "\t\n" +
+ "\t\n" +
+ "\t]]>\n" +
+ "\t\n" +
+
+ "\n" +
+ "\n" +
+ "";
+ }
+
+ public static HashMap parseResponseXML(String resData){
+ try {
+ // 获取DocumentBuilderFactory实例
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ // 配置安全选项防止XXE攻击
+ factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ // 创建DocumentBuilder
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ // 解析XML文件
+ Document document = builder.parse(new ByteArrayInputStream(resData.getBytes(StandardCharsets.UTF_8)));
+ // 获取根元素
+ Element root = document.getDocumentElement();
+ // 获取out节点
+ Node out = root.getFirstChild().getFirstChild().getFirstChild();
+ Document outXML = builder.parse(new ByteArrayInputStream(out.getTextContent().getBytes(StandardCharsets.UTF_8)));
+ // 解析返回的业务处理结果
+ String returnCode = outXML.getElementsByTagName("returnCode").item(0).getTextContent();
+ String returnMessage = outXML.getElementsByTagName("returnMessage").item(0).getTextContent();
+ String data = outXML.getElementsByTagName("content").item(0).getTextContent();
+ HashMap resMap = new HashMap<>();
+ resMap.put("returnCode", returnCode);
+ resMap.put("returnMessage", new String(Base64.getDecoder().decode(returnMessage)));
+ resMap.put("data", new String(Base64.getDecoder().decode(data)));
+ return resMap;
+ }catch (Exception e){
+ throw new RuntimeException("解析返回报文报错",e);
+ }
+
+ }
+}
diff --git a/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlGenerator.java b/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlGenerator.java
new file mode 100644
index 0000000..60035d4
--- /dev/null
+++ b/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlGenerator.java
@@ -0,0 +1,86 @@
+package top.lidee.project.monitor.job.util;
+
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import java.io.StringWriter;
+import java.util.List;
+
+public class InvoiceXmlGenerator {
+
+ // ========== XML 映射类 ==========
+ @XmlRootElement(name = "REQUEST_COMMON_DJLR")
+ @XmlType(propOrder = {"commonDjlrFpts"})
+ public static class RequestCommonDjlr {
+ private CommonDjlrFpts commonDjlrFpts;
+ @XmlElement(name = "COMMON_DJLR_FPTS")
+ public CommonDjlrFpts getCommonDjlrFpts() { return commonDjlrFpts; }
+ public void setCommonDjlrFpts(CommonDjlrFpts commonDjlrFpts) { this.commonDjlrFpts = commonDjlrFpts; }
+ }
+
+ @XmlType(propOrder = {"commonDjlrFptList"})
+ public static class CommonDjlrFpts {
+ private List commonDjlrFptList;
+ @XmlElement(name = "COMMON_DJLR_FPT")
+ public List getCommonDjlrFptList() { return commonDjlrFptList; }
+ public void setCommonDjlrFptList(List commonDjlrFptList) { this.commonDjlrFptList = commonDjlrFptList; }
+ }
+
+ @XmlType(propOrder = {"djh", "djrq", "fpzl", "kplx", "gmfMc", "hsbz", "kpr", "skr", "fhr", "bz", "zzbm", "createPersonName", "commonDjlrXmxxs"})
+ public static class CommonDjlrFpt {
+ private String djh, djrq, fpzl, kplx, gmfMc, hsbz, kpr, skr, fhr, bz, zzbm, createPersonName;
+ private CommonDjlrXmxxs commonDjlrXmxxs;
+ // getter/setter (均使用 @XmlElement 指定标签名)
+ @XmlElement(name = "DJH") public String getDjh() { return djh; } public void setDjh(String djh) { this.djh = djh; }
+ @XmlElement(name = "DJRQ") public String getDjrq() { return djrq; } public void setDjrq(String djrq) { this.djrq = djrq; }
+ @XmlElement(name = "FPZL") public String getFpzl() { return fpzl; } public void setFpzl(String fpzl) { this.fpzl = fpzl; }
+ @XmlElement(name = "KPLX") public String getKplx() { return kplx; } public void setKplx(String kplx) { this.kplx = kplx; }
+ @XmlElement(name = "GMF_MC") public String getGmfMc() { return gmfMc; } public void setGmfMc(String gmfMc) { this.gmfMc = gmfMc; }
+ @XmlElement(name = "HSBZ") public String getHsbz() { return hsbz; } public void setHsbz(String hsbz) { this.hsbz = hsbz; }
+ @XmlElement(name = "KPR") public String getKpr() { return kpr; } public void setKpr(String kpr) { this.kpr = kpr; }
+ @XmlElement(name = "SKR") public String getSkr() { return skr; } public void setSkr(String skr) { this.skr = skr; }
+ @XmlElement(name = "FHR") public String getFhr() { return fhr; } public void setFhr(String fhr) { this.fhr = fhr; }
+ @XmlElement(name = "BZ") public String getBz() { return bz; } public void setBz(String bz) { this.bz = bz; }
+ @XmlElement(name = "ZZBM") public String getZzbm() { return zzbm; } public void setZzbm(String zzbm) { this.zzbm = zzbm; }
+ @XmlElement(name = "CREATE_PERSON_NAME") public String getCreatePersonName() { return createPersonName; } public void setCreatePersonName(String createPersonName) { this.createPersonName = createPersonName; }
+ @XmlElement(name = "COMMON_DJLR_XMXXS") public CommonDjlrXmxxs getCommonDjlrXmxxs() { return commonDjlrXmxxs; } public void setCommonDjlrXmxxs(CommonDjlrXmxxs commonDjlrXmxxs) { this.commonDjlrXmxxs = commonDjlrXmxxs; }
+ }
+
+ @XmlType(propOrder = {"commonDjlrXmxxList"})
+ public static class CommonDjlrXmxxs {
+ private List commonDjlrXmxxList;
+ @XmlElement(name = "COMMON_DJLR_XMXX")
+ public List getCommonDjlrXmxxList() { return commonDjlrXmxxList; }
+ public void setCommonDjlrXmxxList(List commonDjlrXmxxList) { this.commonDjlrXmxxList = commonDjlrXmxxList; }
+ }
+
+ @XmlType(propOrder = {"xh", "xmmc", "ggxh", "dw", "xmsl", "xmje", "sl", "zkje"})
+ public static class CommonDjlrXmxx {
+ private String xh, xmmc, ggxh, dw, xmsl, xmje, sl, zkje;
+ @XmlElement(name = "XH") public String getXh() { return xh; } public void setXh(String xh) { this.xh = xh; }
+ @XmlElement(name = "XMMC") public String getXmmc() { return xmmc; } public void setXmmc(String xmmc) { this.xmmc = xmmc; }
+ @XmlElement(name = "GGXH") public String getGgxh() { return ggxh; } public void setGgxh(String ggxh) { this.ggxh = ggxh; }
+ @XmlElement(name = "DW") public String getDw() { return dw; } public void setDw(String dw) { this.dw = dw; }
+ @XmlElement(name = "XMSL") public String getXmsl() { return xmsl; } public void setXmsl(String xmsl) { this.xmsl = xmsl; }
+ @XmlElement(name = "XMJE") public String getXmje() { return xmje; } public void setXmje(String xmje) { this.xmje = xmje; }
+ @XmlElement(name = "SL") public String getSl() { return sl; } public void setSl(String sl) { this.sl = sl; }
+ @XmlElement(name = "ZKJE") public String getZkje() { return zkje; } public void setZkje(String zkje) { this.zkje = zkje; }
+ }
+
+ // ========== 生成 XML 字符串的方法 ==========
+ public static String generateXml(RequestCommonDjlr request) throws JAXBException {
+ JAXBContext context = JAXBContext.newInstance(RequestCommonDjlr.class);
+ Marshaller marshaller = context.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
+ marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
+
+ StringWriter sw = new StringWriter();
+ marshaller.marshal(request, sw);
+ return sw.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlSy.java b/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlSy.java
new file mode 100644
index 0000000..3f5ed5b
--- /dev/null
+++ b/src/main/java/top/lidee/project/monitor/job/util/InvoiceXmlSy.java
@@ -0,0 +1,68 @@
+package top.lidee.project.monitor.job.util;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import java.io.StringWriter;
+import java.util.List;
+
+public class InvoiceXmlSy {
+
+ /**
+ * 生成 XML 字符串
+ * @param billNoList 单据号列表,每个元素将生成一个 节点
+ * @return 格式化的 XML 字符串(不含 XML 声明)
+ * @throws ParserConfigurationException XML 解析器配置异常
+ * @throws TransformerException XML 转换异常
+ */
+ public static String generateDwzsXml(List billNoList) throws ParserConfigurationException, TransformerException {
+ // 1. 创建 Document 对象
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document doc = builder.newDocument();
+
+ // 2. 创建根元素 REQUEST_COMMON_DWZS,并设置 class 属性
+ Element root = doc.createElement("REQUEST_COMMON_DWZS");
+ root.setAttribute("class", "REQUEST_COMMON_DWZS");
+ doc.appendChild(root);
+
+ // 3. 创建 COMMON_DWZS_HEADERS 元素
+ Element headers = doc.createElement("COMMON_DWZS_HEADERS");
+ root.appendChild(headers);
+
+ // 4. 遍历单据号列表,为每个单据号创建一个 COMMON_DWZS_HEADER
+ for (String billNo : billNoList) {
+ Element header = doc.createElement("COMMON_DWZS_HEADER");
+ header.setAttribute("class", "COMMON_DWZS_HEADER");
+ headers.appendChild(header);
+
+ Element billNoElem = doc.createElement("BILLNO");
+ // 如果单据号为 null,则设为空字符串,避免 null 值导致异常
+ billNoElem.setTextContent(billNo != null ? billNo : "");
+ header.appendChild(billNoElem);
+ }
+
+ // 5. 将 Document 对象转换为格式化的 XML 字符串
+ TransformerFactory tf = TransformerFactory.newInstance();
+ Transformer transformer = tf.newTransformer();
+
+ // 设置输出属性:省略 XML 声明,启用缩进(4空格)
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes");
+ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+
+ StringWriter writer = new StringWriter();
+ transformer.transform(new DOMSource(doc), new StreamResult(writer));
+ return writer.toString();
+ }
+
+}
diff --git a/src/main/java/top/lidee/project/system/record/controller/GrInvoiceRecordController.java b/src/main/java/top/lidee/project/system/record/controller/GrInvoiceRecordController.java
new file mode 100644
index 0000000..a849c97
--- /dev/null
+++ b/src/main/java/top/lidee/project/system/record/controller/GrInvoiceRecordController.java
@@ -0,0 +1,136 @@
+package top.lidee.project.system.record.controller;
+
+import java.util.List;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+import top.lidee.framework.aspectj.lang.annotation.Log;
+import top.lidee.framework.aspectj.lang.enums.BusinessType;
+import top.lidee.framework.web.controller.BaseController;
+import top.lidee.framework.web.domain.AjaxResult;
+import top.lidee.common.utils.poi.ExcelUtil;
+import top.lidee.framework.web.page.TableDataInfo;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+import top.lidee.project.system.record.service.IGrInvoiceRecordService;
+
+/**
+ * 发票Controller
+ *
+ * @author yuheng
+ * @date 2026-04-02
+ */
+@Controller
+@RequestMapping("/system/record")
+public class GrInvoiceRecordController extends BaseController
+{
+ private String prefix = "system/record";
+
+ @Autowired
+ private IGrInvoiceRecordService grInvoiceRecordService;
+
+ @RequiresPermissions("system:record:view")
+ @GetMapping()
+ public String record()
+ {
+ return prefix + "/record";
+ }
+
+ /**
+ * 查询发票列表
+ */
+ @RequiresPermissions("system:record:list")
+ @PostMapping("/list")
+ @ResponseBody
+ public TableDataInfo list(GrInvoiceRecord grInvoiceRecord)
+ {
+ startPage();
+ List list = grInvoiceRecordService.selectGrInvoiceRecordList(grInvoiceRecord);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出发票列表
+ */
+ @RequiresPermissions("system:record:export")
+ @Log(title = "发票", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ @ResponseBody
+ public AjaxResult export(GrInvoiceRecord grInvoiceRecord)
+ {
+ List list = grInvoiceRecordService.selectGrInvoiceRecordList(grInvoiceRecord);
+ ExcelUtil util = new ExcelUtil(GrInvoiceRecord.class);
+ return util.exportExcel(list, "发票数据");
+ }
+
+ /**
+ * 新增发票
+ */
+ @GetMapping("/add")
+ public String add()
+ {
+ return prefix + "/add";
+ }
+
+ /**
+ * 新增保存发票
+ */
+ @RequiresPermissions("system:record:add")
+ @Log(title = "发票", businessType = BusinessType.INSERT)
+ @PostMapping("/add")
+ @ResponseBody
+ public AjaxResult addSave(GrInvoiceRecord grInvoiceRecord)
+ {
+ return toAjax(grInvoiceRecordService.insertGrInvoiceRecord(grInvoiceRecord));
+ }
+
+ /**
+ * 修改发票
+ */
+ @RequiresPermissions("system:record:edit")
+ @GetMapping("/edit/{id}")
+ public String edit(@PathVariable("id") String id, ModelMap mmap)
+ {
+ GrInvoiceRecord grInvoiceRecord = grInvoiceRecordService.selectGrInvoiceRecordById(id);
+ mmap.put("grInvoiceRecord", grInvoiceRecord);
+ return prefix + "/edit";
+ }
+
+ /**
+ * 修改保存发票
+ */
+ @RequiresPermissions("system:record:edit")
+ @Log(title = "发票", businessType = BusinessType.UPDATE)
+ @PostMapping("/edit")
+ @ResponseBody
+ public AjaxResult editSave(GrInvoiceRecord grInvoiceRecord)
+ {
+ return toAjax(grInvoiceRecordService.updateGrInvoiceRecord(grInvoiceRecord));
+ }
+
+ /**
+ * 删除发票
+ */
+ @RequiresPermissions("system:record:remove")
+ @Log(title = "发票", businessType = BusinessType.DELETE)
+ @PostMapping( "/remove")
+ @ResponseBody
+ public AjaxResult remove(String ids)
+ {
+ return toAjax(grInvoiceRecordService.deleteGrInvoiceRecordByIds(ids));
+ }
+
+ /**
+ * 批量处理发票
+ */
+ @RequiresPermissions("system:record:list")
+ @Log(title = "发票", businessType = BusinessType.UPDATE)
+ @PostMapping("/batchProcess")
+ @ResponseBody
+ public AjaxResult batchProcess(@RequestParam List idList)
+ {
+ return toAjax(grInvoiceRecordService.batchProcess(idList));
+ }
+
+}
diff --git a/src/main/java/top/lidee/project/system/record/domain/GrInvoiceRecord.java b/src/main/java/top/lidee/project/system/record/domain/GrInvoiceRecord.java
new file mode 100644
index 0000000..3c1e6a9
--- /dev/null
+++ b/src/main/java/top/lidee/project/system/record/domain/GrInvoiceRecord.java
@@ -0,0 +1,51 @@
+package top.lidee.project.system.record.domain;
+
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import top.lidee.framework.aspectj.lang.annotation.Excel;
+import top.lidee.framework.web.domain.BaseEntity;
+
+import java.util.List;
+
+/**
+ * 发票对象 gr_invoice_record
+ *
+ * @author yuheng
+ * @date 2026-04-02
+ */
+@Data
+public class GrInvoiceRecord extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /** */
+ private Long id;
+
+ /**单据号*/
+ @Excel(name = "")
+ private String djh;
+
+ /**单据日期*/
+ @Excel(name = "")
+ private String djrq;
+
+ /**发票种类*/
+ @Excel(name = "")
+ private String fpzl;
+
+ /**开票时间*/
+ @Excel(name = "")
+ private String kpsj;
+
+ /**开票状态*/
+ @Excel(name = "")
+ private String status;
+
+ private List statusList;
+ /**客户名称*/
+ private String gmfMc;
+
+ private String invNumber;
+
+
+}
diff --git a/src/main/java/top/lidee/project/system/record/mapper/GrInvoiceRecordMapper.java b/src/main/java/top/lidee/project/system/record/mapper/GrInvoiceRecordMapper.java
new file mode 100644
index 0000000..e4c7991
--- /dev/null
+++ b/src/main/java/top/lidee/project/system/record/mapper/GrInvoiceRecordMapper.java
@@ -0,0 +1,65 @@
+package top.lidee.project.system.record.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+
+/**
+ * 发票Mapper接口
+ *
+ * @author yuheng
+ * @date 2026-04-02
+ */
+public interface GrInvoiceRecordMapper
+{
+ /**
+ * 查询发票
+ *
+ * @param id 发票主键
+ * @return 发票
+ */
+ public GrInvoiceRecord selectGrInvoiceRecordById(String id);
+
+ /**
+ * 查询发票列表
+ *
+ * @param grInvoiceRecord 发票
+ * @return 发票集合
+ */
+ public List selectGrInvoiceRecordList(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 新增发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ public int insertGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 修改发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ public int updateGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 删除发票
+ *
+ * @param id 发票主键
+ * @return 结果
+ */
+ public int deleteGrInvoiceRecordById(String id);
+
+ /**
+ * 批量删除发票
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteGrInvoiceRecordByIds(String[] ids);
+
+ List selectGrInvoiceRecordListByIdList(@Param("list") List idList);
+}
diff --git a/src/main/java/top/lidee/project/system/record/service/IGrInvoiceRecordService.java b/src/main/java/top/lidee/project/system/record/service/IGrInvoiceRecordService.java
new file mode 100644
index 0000000..135f08b
--- /dev/null
+++ b/src/main/java/top/lidee/project/system/record/service/IGrInvoiceRecordService.java
@@ -0,0 +1,63 @@
+package top.lidee.project.system.record.service;
+
+import java.util.List;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+
+/**
+ * 发票Service接口
+ *
+ * @author yuheng
+ * @date 2026-04-02
+ */
+public interface IGrInvoiceRecordService
+{
+ /**
+ * 查询发票
+ *
+ * @param id 发票主键
+ * @return 发票
+ */
+ public GrInvoiceRecord selectGrInvoiceRecordById(String id);
+
+ /**
+ * 查询发票列表
+ *
+ * @param grInvoiceRecord 发票
+ * @return 发票集合
+ */
+ public List selectGrInvoiceRecordList(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 新增发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ public int insertGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 修改发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ public int updateGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord);
+
+ /**
+ * 批量删除发票
+ *
+ * @param ids 需要删除的发票主键集合
+ * @return 结果
+ */
+ public int deleteGrInvoiceRecordByIds(String ids);
+
+ /**
+ * 删除发票信息
+ *
+ * @param id 发票主键
+ * @return 结果
+ */
+ public int deleteGrInvoiceRecordById(String id);
+
+ int batchProcess(List idList);
+}
diff --git a/src/main/java/top/lidee/project/system/record/service/impl/GrInvoiceRecordServiceImpl.java b/src/main/java/top/lidee/project/system/record/service/impl/GrInvoiceRecordServiceImpl.java
new file mode 100644
index 0000000..1959483
--- /dev/null
+++ b/src/main/java/top/lidee/project/system/record/service/impl/GrInvoiceRecordServiceImpl.java
@@ -0,0 +1,280 @@
+package top.lidee.project.system.record.service.impl;
+
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.sql.*;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Value;
+import top.lidee.common.constant.InvoiceConstants;
+import top.lidee.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import top.lidee.common.utils.StringUtils;
+import top.lidee.project.monitor.job.util.HttpXml;
+import top.lidee.project.monitor.job.util.InvoiceXmlSy;
+import top.lidee.project.system.record.mapper.GrInvoiceRecordMapper;
+import top.lidee.project.system.record.domain.GrInvoiceRecord;
+import top.lidee.project.system.record.service.IGrInvoiceRecordService;
+import top.lidee.common.utils.text.Convert;
+
+import javax.annotation.Resource;
+
+/**
+ * 发票Service业务层处理
+ *
+ * @author yuheng
+ * @date 2026-04-02
+ */
+@Service
+public class GrInvoiceRecordServiceImpl implements IGrInvoiceRecordService {
+ @Autowired
+ private GrInvoiceRecordMapper grInvoiceRecordMapper;
+
+ @Value("${invoice.url}")
+ private String URL;
+
+ @Value("${invoice.eiInvWebService}")
+ private String eiInvWebServiceUrl;
+ /**
+ * 数据库用户名
+ */
+ @Value("${invoice.username}")
+ private String USERNAME;
+ /**
+ * 数据库密码
+ */
+ @Value("${invoice.password}")
+ private String PASSWORD;
+ @Value("${invoice.taxId}")
+ private String taxId;
+ @Value("${invoice.authCode}")
+ private String authCode;
+ @Value("${invoice.updateCode}")
+ private String interfaceCode;
+ private static final String fPath = "C:\\log\\fplog.log";
+
+
+ /**
+ * 查询发票
+ *
+ * @param id 发票主键
+ * @return 发票
+ */
+ @Override
+ public GrInvoiceRecord selectGrInvoiceRecordById(String id) {
+ return grInvoiceRecordMapper.selectGrInvoiceRecordById(id);
+ }
+
+ /**
+ * 查询发票列表
+ *
+ * @param grInvoiceRecord 发票
+ * @return 发票
+ */
+ @Override
+ public List selectGrInvoiceRecordList(GrInvoiceRecord grInvoiceRecord) {
+ if (StringUtils.isNotBlank(grInvoiceRecord.getStatus()) && InvoiceConstants.UNTREATED.equals(grInvoiceRecord.getStatus())) {
+ List statusList = new ArrayList<>();
+ statusList.add(InvoiceConstants.UNTREATED);
+ statusList.add(InvoiceConstants.PROCESSED_NOT_SUCCESSFUL);
+ grInvoiceRecord.setStatus(null);
+ grInvoiceRecord.setStatusList(statusList);
+ }
+ return grInvoiceRecordMapper.selectGrInvoiceRecordList(grInvoiceRecord);
+ }
+
+ /**
+ * 新增发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ @Override
+ public int insertGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord) {
+ grInvoiceRecord.setCreateTime(DateUtils.getNowDate());
+ return grInvoiceRecordMapper.insertGrInvoiceRecord(grInvoiceRecord);
+ }
+
+ /**
+ * 修改发票
+ *
+ * @param grInvoiceRecord 发票
+ * @return 结果
+ */
+ @Override
+ public int updateGrInvoiceRecord(GrInvoiceRecord grInvoiceRecord) {
+ grInvoiceRecord.setUpdateTime(DateUtils.getNowDate());
+ return grInvoiceRecordMapper.updateGrInvoiceRecord(grInvoiceRecord);
+ }
+
+ /**
+ * 批量删除发票
+ *
+ * @param ids 需要删除的发票主键
+ * @return 结果
+ */
+ @Override
+ public int deleteGrInvoiceRecordByIds(String ids) {
+ return grInvoiceRecordMapper.deleteGrInvoiceRecordByIds(Convert.toStrArray(ids));
+ }
+
+ /**
+ * 删除发票信息
+ *
+ * @param id 发票主键
+ * @return 结果
+ */
+ @Override
+ public int deleteGrInvoiceRecordById(String id) {
+ return grInvoiceRecordMapper.deleteGrInvoiceRecordById(id);
+ }
+
+ @Override
+ public int batchProcess(List idList) {
+ if (CollectionUtils.isEmpty(idList)) {
+ return 1;
+ }
+ List grInvoiceRecords = grInvoiceRecordMapper.selectGrInvoiceRecordListByIdList(idList);
+ if (CollectionUtils.isEmpty(grInvoiceRecords)) {
+ System.out.println("没有待请求数据");
+ return 1;
+ }
+ try {
+ for (GrInvoiceRecord invoiceRecord : grInvoiceRecords) {
+ String key = invoiceRecord.getDjh();
+ String txtCon = "";
+ List billNos = new ArrayList<>();
+ billNos.add(key);
+
+ System.out.println("溯源 Id:" + billNos);
+ txtCon += "溯源 Id:" + billNos + "\n";
+ //封装 请求报文
+ String xmldata = InvoiceXmlSy.generateDwzsXml(billNos);
+
+ // 组装接口需要的请求报文
+ String payload = HttpXml.bulidSoapXML(interfaceCode, taxId, authCode, xmldata, "eiInterface");
+ System.out.println(payload);
+ boolean hasError = false;
+ try {
+ // 调用接口
+ Map res = HttpXml.webServiceExecute(eiInvWebServiceUrl, payload);
+ System.out.println("接口请求状态:" + res.get("httpStatus"));
+ System.out.println("接口返回的原始报文:" + res.get("data"));
+ txtCon += "接口请求状态:" + res.get("httpStatus") + "\n";
+ txtCon += "接口返回的原始报文:" + res.get("data") + "\n";
+ if (200 == (int) res.get("httpStatus")) {
+ try {
+ // 解析接口返回的报文
+ HashMap serviceData = HttpXml.parseResponseXML((String) res.get("data"));
+ System.out.println("业务处理返回代码:" + serviceData.get("returnCode"));
+ System.out.println("业务处理返回提示:" + serviceData.get("returnMessage"));
+ System.out.println("业务处理返回数据:" + serviceData.get("data"));
+
+ txtCon += "业务处理返回代码:" + serviceData.get("returnCode") + "\n";
+ txtCon += "业务处理返回提示:" + serviceData.get("returnMessage") + "\n";
+ txtCon += "业务处理返回数据:" + serviceData.get("data") + "\n";
+// appendToFile(fPath, txtCon);
+ String invNumber = "1";
+ String xml = serviceData.get("data");
+ Pattern pattern = Pattern.compile("(.*?)");
+ Matcher matcher = pattern.matcher(xml);
+ if (matcher.find()) {
+ invNumber = matcher.group(1);
+ }
+
+ // 如果没有被开发票(invNumber 为 1)
+ if (invNumber.equals("1")) {
+ System.out.println("单据号 " + key + " 还未开票");
+ continue;
+ }
+
+ if (serviceData.get("returnCode").equals("0000")) {
+ //更新数据库
+ Connection conn = null;
+ Statement stmt = null;
+ ResultSet rs = null;
+ try {
+ System.out.println("更新视图开始");
+ // 1. 加载 Oracle JDBC 驱动
+ Class.forName("oracle.jdbc.driver.OracleDriver");
+ // 2. 建立数据库连接
+ conn = DriverManager.getConnection(URL, USERNAME, PASSWORD);
+ // 3. 创建 Statement 对象
+ stmt = conn.createStatement();
+ // 4. 执行查询语句
+ String sql = "update gr_dp_saset_sdhm_v a set a.zxcolumn1 = '" + invNumber + "' where a.sasettleid =" + key;
+ PreparedStatement pstmt = conn.prepareStatement(sql);
+ int rowsA = pstmt.executeUpdate();
+ System.out.println("完成更新视图:" + rowsA);
+ invoiceRecord.setStatus(InvoiceConstants.SUCCESSFUL);
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
+ invoiceRecord.setKpsj(sdf.format(new Date()));
+ invoiceRecord.setInvNumber(invNumber);
+ grInvoiceRecordMapper.updateGrInvoiceRecord(invoiceRecord);
+ } catch (Exception e) {
+ e.printStackTrace();
+ // 发生错误,标记为已尝试但不需要重试
+ hasError = true;
+ // 6. 关闭资源
+ try {
+ if (rs != null) rs.close();
+ if (stmt != null) stmt.close();
+ if (conn != null) conn.close();
+ } catch (SQLException e11) {
+ e11.printStackTrace();
+ }
+ }
+ } else {
+ // 业务处理失败,标记为已尝试但不需要重试
+ hasError = true;
+ System.out.println("业务处理失败:" + serviceData.get("returnMessage"));
+ }
+ } catch (Exception e) {
+ System.out.println("解析报文出错的,保持业务为处理中状态,需要检查原因");
+ e.printStackTrace();
+ hasError = true;
+ }
+ } else {
+ // HTTP 请求状态不是 200,标记为已尝试但不需要重试
+ hasError = true;
+ System.out.println("HTTP 请求失败,状态码:" + res.get("httpStatus"));
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ hasError = true;
+ }
+ // 如果发生错误,更新状态为 1(已尝试但不需要重试)
+ if (hasError) {
+ invoiceRecord.setStatus(InvoiceConstants.PROCESSED_NOT_SUCCESSFUL);
+ grInvoiceRecordMapper.updateGrInvoiceRecord(invoiceRecord);
+ System.out.println("单据号 " + key + " 处理失败,标记为已尝试状态");
+ }
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return 1;
+ }
+
+
+ // 追加写入模式
+ public static void appendToFile(String filePath, String content) throws IOException {
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(filePath, true))) {
+ writer.newLine(); // 换行后再追加
+ writer.write(content);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/main/resources/application-druid.yml b/src/main/resources/application-druid.yml
index 3cfe970..6035786 100644
--- a/src/main/resources/application-druid.yml
+++ b/src/main/resources/application-druid.yml
@@ -7,7 +7,8 @@ spring:
druid:
# 主库数据源 root
master:
- url: jdbc:sqlite:D:/uploadPath/SQLite/sqlite3.db?date_string_format=yyyy-MM-dd HH:mm:ss
+# url: jdbc:sqlite:D:/work/gr_fapiao/sql/sqlite3.db?date_string_format=yyyy-MM-dd HH:mm:ss
+ url: jdbc:sqlite:c:/SQLite/sql/sqlite3.db?date_string_format=yyyy-MM-dd HH:mm:ss
username:
password:
# 从库数据源
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 9470c32..570f94f 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -150,4 +150,23 @@ gen:
# 自动去除表前缀,默认是true
autoRemovePre: true
# 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
- tablePrefix: sys_
\ No newline at end of file
+ tablePrefix: sys_
+invoice:
+ # 开票系统地址
+ url: jdbc:oracle:thin:@192.168.1.247:1521:gryy
+ # 开票系统用户名
+ username: GRYYINV
+ # 开票系统密码
+ password: xxb147258368
+
+ taxId: 9134040072334670XN
+
+ authCode: 7G5X2YSSMA
+
+ interfaceCode: DJLR
+
+ updateCode: DWZS
+
+ eiInvWebService: https://csxtqd.nuocity.com/open/services/eiInvWebService?wsdl
+
+ iBillInterfaceWebService: https://csxtqd.nuocity.com/open/services/iBillInterfaceWebService?wsdl
diff --git a/src/main/resources/mybatis/system/GrInvoiceRecordMapper.xml b/src/main/resources/mybatis/system/GrInvoiceRecordMapper.xml
new file mode 100644
index 0000000..68c7e45
--- /dev/null
+++ b/src/main/resources/mybatis/system/GrInvoiceRecordMapper.xml
@@ -0,0 +1,131 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id,
+ djh,
+ djrq,
+ fpzl,
+ kpsj,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ status,
+ gmf_mc,
+ inv_number
+ from gr_invoice_record
+
+
+
+
+
+
+
+ insert into gr_invoice_record
+
+ id,
+ djh,
+ djrq,
+ fpzl,
+ kpsj,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ status,
+ gmf_mc,
+ inv_number,
+
+
+ #{id},
+ #{djh},
+ #{djrq},
+ #{fpzl},
+ #{kpsj},
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+ #{status},
+ #{gmfMc},
+ #{invNumber},
+
+
+
+
+ update gr_invoice_record
+
+ djh = #{djh},
+ djrq = #{djrq},
+ fpzl = #{fpzl},
+ kpsj = #{kpsj},
+ create_by = #{createBy},
+ create_time = #{createTime},
+ update_by = #{updateBy},
+ update_time = #{updateTime},
+ status = #{status},
+ gmf_mc = #{gmfMc},
+ inv_number = #{invNumber},
+
+ where id = #{id}
+
+
+
+ delete
+ from gr_invoice_record
+ where id = #{id}
+
+
+
+ delete from gr_invoice_record where id in
+
+ #{id}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html
index 91f74e6..0067c5a 100644
--- a/src/main/resources/templates/index.html
+++ b/src/main/resources/templates/index.html
@@ -26,7 +26,7 @@
- lidee
+ 电票系统