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 @@