From f8c2a2dbbe81a9bde5e8560f5589354e553b5b1a Mon Sep 17 00:00:00 2001
From: aike <17730485278@139.com>
Date: Thu, 22 Jan 2026 11:36:48 +0800
Subject: [PATCH] =?UTF-8?q?demand:=20=E5=8F=91=E7=A5=A8=E4=BD=9C=E5=BA=9F?=
=?UTF-8?q?=E7=9B=B8=E5=85=B3=E9=9C=80=E6=B1=82?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../EmisInvoiceCancellationController.java | 257 +++++++++++++++
.../emis/domain/EmisInvoiceCancellation.java | 82 +++++
.../mapper/EmisInvoiceCancellationMapper.java | 108 ++++++
.../IEmisInvoiceCancellationService.java | 106 ++++++
.../EmisInvoiceCancellationServiceImpl.java | 203 ++++++++++++
.../mapper/EmisInvoiceCancellationMapper.xml | 309 ++++++++++++++++++
6 files changed, 1065 insertions(+)
create mode 100644 emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisInvoiceCancellationController.java
create mode 100644 emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisInvoiceCancellation.java
create mode 100644 emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisInvoiceCancellationMapper.java
create mode 100644 emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisInvoiceCancellationService.java
create mode 100644 emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisInvoiceCancellationServiceImpl.java
create mode 100644 emis-biz/src/main/resources/mapper/EmisInvoiceCancellationMapper.xml
diff --git a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisInvoiceCancellationController.java b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisInvoiceCancellationController.java
new file mode 100644
index 000000000..727c42023
--- /dev/null
+++ b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisInvoiceCancellationController.java
@@ -0,0 +1,257 @@
+/**
+ * @Project: emis
+ * @Title: EmisInvoiceCancellationController.java
+ * @author heyu
+ * @date 2026-01-19 14:33:40
+ * @Copyright: ShangHai Duta 2026 All rights reserved.
+ * @version v1.0
+ * @Description:
发票作废表 控制器
+ */
+
+package com.xdadan.erp.web.emis;
+
+import com.xdadan.erp.common.annotation.Log;
+import com.xdadan.erp.common.core.domain.AjaxResult;
+import com.xdadan.erp.common.core.page.TableDataInfo;
+import com.xdadan.erp.common.enums.BusinessType;
+import com.xdadan.erp.common.utils.SecurityUtils;
+import com.xdadan.erp.common.utils.StringUtils;
+import com.xdadan.erp.common.utils.poi.ExcelUtil;
+import com.xdadan.erp.emis.domain.EmisInvoiceCancellation;
+import com.xdadan.erp.emis.domain.EmisSettleInvoiceRecord;
+import com.xdadan.erp.emis.domain.exception.EmisBizError;
+import com.xdadan.erp.emis.service.IEmisInvoiceCancellationService;
+import com.xdadan.erp.emis.service.IEmisSettleInvoiceRecordService;
+import com.xdadan.erp.emis.utils.WaybillHelper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 发票作废表Controller
+ *
+ * @author heyu
+ * @date 2026-01-19 14:33:40
+ */
+@RestController
+@RequestMapping("/emis/emisInvoiceCancellation")
+public class EmisInvoiceCancellationController extends EmisBaseController
+{
+ @Autowired
+ private IEmisInvoiceCancellationService emisInvoiceCancellationService;
+ @Autowired
+ private IEmisSettleInvoiceRecordService emisSettleInvoiceRecordService;
+
+ /**
+ * 查询发票作废表列表
+ */
+ @PreAuthorize("@ss.hasPermi('emis:emisInvoiceCancellation:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(EmisInvoiceCancellation emisInvoiceCancellation)
+ {
+ startPage();
+ setPrivParams(emisInvoiceCancellation);
+ formatQueryParams(emisInvoiceCancellation);
+ List list = emisInvoiceCancellationService.selectEmisInvoiceCancellationList(emisInvoiceCancellation);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出发票作废表列表
+ */
+ @PreAuthorize("@ss.hasPermi('emis:emisInvoiceCancellation:export')")
+ @Log(title = "发票作废表", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(HttpServletResponse response, EmisInvoiceCancellation emisInvoiceCancellation)
+ {
+ setPrivParams(emisInvoiceCancellation);
+ formatQueryParams(emisInvoiceCancellation);
+ List list = emisInvoiceCancellationService.selectEmisInvoiceCancellationList(emisInvoiceCancellation);
+ ExcelUtil util = new ExcelUtil(EmisInvoiceCancellation.class);
+ util.exportExcel(response, list, "发票作废表数据");
+ }
+
+ /**
+ * 获取发票作废表详细信息
+ */
+ @PreAuthorize("@ss.hasPermi('emis:emisInvoiceCancellation:query')")
+ @GetMapping(value = "/{id}")
+ public AjaxResult getInfo(@PathVariable("id") Long id)
+ {
+ return AjaxResult.success(emisInvoiceCancellationService.selectEmisInvoiceCancellationById(id));
+ }
+
+ /**
+ * 新增发票作废表
+ */
+ @PreAuthorize("@ss.hasPermi('emis:emisInvoiceCancellation:add')")
+ @Log(title = "发票作废表", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody EmisInvoiceCancellation emisInvoiceCancellation)
+ {
+ fillApplyInfo(emisInvoiceCancellation);
+ try {
+ return toAjax(emisInvoiceCancellationService.insertEmisInvoiceCancellation(emisInvoiceCancellation));
+ } catch (EmisBizError e) {
+ return AjaxResult.error(e.getMessage(), e.getErrorCode());
+ }
+ }
+
+ /**
+ * 修改发票作废表
+ */
+ @PreAuthorize("@ss.hasPermi('emis:emisInvoiceCancellation:edit')")
+ @Log(title = "发票作废表", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody EmisInvoiceCancellation emisInvoiceCancellation)
+ {
+ try {
+ return toAjax(emisInvoiceCancellationService.updateEmisInvoiceCancellation(emisInvoiceCancellation));
+ } catch (EmisBizError e) {
+ return AjaxResult.error(e.getMessage(), e.getErrorCode());
+ }
+ }
+
+ /**
+ * 删除发票作废表
+ */
+ @PreAuthorize("@ss.hasPermi('emis:emisInvoiceCancellation:remove')")
+ @Log(title = "发票作废表", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable Long[] ids)
+ {
+ try {
+ return toAjax(emisInvoiceCancellationService.deleteEmisInvoiceCancellationByIds(ids));
+ } catch (EmisBizError e) {
+ return AjaxResult.error(e.getMessage(), e.getErrorCode());
+ }
+ }
+
+ /**
+ * 撤销申请
+ */
+ @PreAuthorize("@ss.hasPermi('emis:emisInvoiceCancellation:cancel')")
+ @Log(title = "撤销发票作废申请", businessType = BusinessType.UPDATE)
+ @PostMapping("/cancel/{ids}")
+ public AjaxResult cancel(@PathVariable Long[] ids)
+ {
+ String userCode = SecurityUtils.getLoginUser().getUser().getEmpCode();
+ String siteCode = SecurityUtils.getLoginUser().getUser().getOwnerSiteCode();
+ try {
+ return toAjax(emisInvoiceCancellationService.cancelApply(ids, userCode, siteCode));
+ } catch (EmisBizError e) {
+ return AjaxResult.error(e.getMessage(), e.getErrorCode());
+ }
+ }
+
+ /**
+ * 审核通过
+ */
+ @PreAuthorize("@ss.hasPermi('emis:emisInvoiceCancellation:auditPass')")
+ @Log(title = "发票作废审核通过", businessType = BusinessType.UPDATE)
+ @PostMapping("/audit/pass/{ids}")
+ public AjaxResult auditPass(@PathVariable Long[] ids)
+ {
+ String userCode = SecurityUtils.getLoginUser().getUser().getEmpCode();
+ String siteCode = SecurityUtils.getLoginUser().getUser().getOwnerSiteCode();
+ try {
+ return toAjax(emisInvoiceCancellationService.auditPass(ids, userCode, siteCode));
+ } catch (EmisBizError e) {
+ return AjaxResult.error(e.getMessage(), e.getErrorCode());
+ }
+ }
+
+ /**
+ * 审核驳回
+ */
+ @PreAuthorize("@ss.hasPermi('emis:emisInvoiceCancellation:auditReject')")
+ @Log(title = "发票作废审核驳回", businessType = BusinessType.UPDATE)
+ @PostMapping("/audit/reject/{ids}")
+ public AjaxResult auditReject(@PathVariable Long[] ids, @RequestBody EmisInvoiceCancellation auditBody)
+ {
+ String userCode = SecurityUtils.getLoginUser().getUser().getEmpCode();
+ String siteCode = SecurityUtils.getLoginUser().getUser().getOwnerSiteCode();
+ String rejectReason = auditBody != null ? auditBody.getAuditRejectReason() : "";
+ if (StringUtils.isEmpty(rejectReason)) {
+ return AjaxResult.error("驳回原因不能为空");
+ }
+ try {
+ return toAjax(emisInvoiceCancellationService.auditReject(ids, userCode, siteCode, rejectReason));
+ } catch (EmisBizError e) {
+ return AjaxResult.error(e.getMessage(), e.getErrorCode());
+ }
+ }
+
+ /**
+ * 根据申请序号/发票号查询发票信息并校验是否可新增作废
+ */
+ @GetMapping("/invoiceInfo")
+ public AjaxResult invoiceInfo(EmisSettleInvoiceRecord emisSettleInvoiceRecord) {
+ if (emisSettleInvoiceRecord == null) {
+ return AjaxResult.error("参数不能为空");
+ }
+ String applySeqNo = emisSettleInvoiceRecord.getApplySeqNo();
+ String invoiceNo = emisSettleInvoiceRecord.getInvoiceNo();
+ if (StringUtils.isEmpty(applySeqNo) && StringUtils.isEmpty(invoiceNo)) {
+ return AjaxResult.error("申请序号或发票号必传其一");
+ }
+ if (!StringUtils.isEmpty(applySeqNo)) {
+ applySeqNo = WaybillHelper.formatQueryValue(applySeqNo);
+ }
+ if (!StringUtils.isEmpty(invoiceNo)) {
+ invoiceNo = WaybillHelper.formatQueryValue(invoiceNo);
+ }
+ EmisSettleInvoiceRecord query = new EmisSettleInvoiceRecord();
+ query.setApplySeqNo(applySeqNo);
+ query.setInvoiceNo(invoiceNo);
+ List invoiceList = emisSettleInvoiceRecordService.selectEmisSettleInvoiceRecordList(query);
+ if (invoiceList == null || invoiceList.isEmpty()) {
+ return AjaxResult.error("发票不存在");
+ }
+ EmisSettleInvoiceRecord invoice = invoiceList.get(0);
+ if (emisInvoiceCancellationService.existsActiveApply(invoice.getId())) {
+ return AjaxResult.error("不可重复添加");
+ }
+ return AjaxResult.success(invoice);
+ }
+
+ private void fillApplyInfo(EmisInvoiceCancellation emisInvoiceCancellation) {
+ if (emisInvoiceCancellation == null) {
+ return;
+ }
+ try {
+ if (StringUtils.isEmpty(emisInvoiceCancellation.getApplyManCode())) {
+ emisInvoiceCancellation.setApplyManCode(SecurityUtils.getLoginUser().getUser().getEmpCode());
+ }
+ if (StringUtils.isEmpty(emisInvoiceCancellation.getApplySiteCode())) {
+ emisInvoiceCancellation.setApplySiteCode(SecurityUtils.getLoginUser().getUser().getOwnerSiteCode());
+ }
+ } catch (Exception ignore) {
+ }
+ }
+
+ private void formatQueryParams(EmisInvoiceCancellation emisInvoiceCancellation) {
+ if (emisInvoiceCancellation == null) {
+ return;
+ }
+ if (emisInvoiceCancellation.getParams().get("settleBillNo") != null) {
+ String settleBillNo = WaybillHelper.formatQueryValue(emisInvoiceCancellation.getParams().get("settleBillNo").toString());
+ emisInvoiceCancellation.getParams().put("settleBillNo", settleBillNo);
+ }
+ if (emisInvoiceCancellation.getParams().get("invoiceNo") != null) {
+ String invoiceNo = WaybillHelper.formatQueryValue(emisInvoiceCancellation.getParams().get("invoiceNo").toString());
+ emisInvoiceCancellation.getParams().put("invoiceNo", invoiceNo);
+ }
+ if (emisInvoiceCancellation.getParams().get("applySeqNo") != null) {
+ String applySeqNo = WaybillHelper.formatQueryValue(emisInvoiceCancellation.getParams().get("applySeqNo").toString());
+ emisInvoiceCancellation.getParams().put("applySeqNo", applySeqNo);
+ }
+ if (emisInvoiceCancellation.getParams().get("billCode") != null) {
+ String billCode = WaybillHelper.formatQueryValue(emisInvoiceCancellation.getParams().get("billCode").toString());
+ emisInvoiceCancellation.getParams().put("billCode", billCode);
+ }
+ }
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisInvoiceCancellation.java b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisInvoiceCancellation.java
new file mode 100644
index 000000000..eb1d0945c
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisInvoiceCancellation.java
@@ -0,0 +1,82 @@
+/**
+ * @Project: emis
+ * @Title: EmisInvoiceCancellation.java
+ * @author heyu
+ * @date 2026-01-19 14:33:40
+ * @Copyright: ShangHai Duta 2026 All rights reserved.
+ * @version v1.0
+ * @Description: 发票作废表 实体类
+ */
+
+package com.xdadan.erp.emis.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.xdadan.erp.common.annotation.Excel;
+import com.xdadan.erp.common.annotation.audit.DataAuditField;
+import com.xdadan.erp.common.core.domain.BaseEntity;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * @ClassName EmisInvoiceCancellation
+ * @Description 发票作废表
+ * @author heyu
+ * @date 2026-01-19 14:33:40
+ */
+@Data
+public class EmisInvoiceCancellation extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /* id */
+ private Long id;
+ /* 发票id */
+ private Long invoiceId;
+ /* 申请序号 */
+ private String applySeqNo;
+ /* 申请时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date applyDate;
+ /* 申请原因 */
+ private String applyReason;
+ /* 申请附件url */
+ private String applyTextUrl;
+ /* 申请人 */
+ private String applyManCode;
+ /* 申请站点 */
+ private String applySiteCode;
+ /* 审核状态 0-待审核 1-已通过 2-已驳回 3-已撤销 默认为0 */
+ private String auditStatus;
+ /* 审核日期 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private Date auditDate;
+ /* 审核人 */
+ private String auditManCode;
+ /* 审核站点 */
+ private String auditSiteCode;
+ /* 驳回原因 */
+ private String auditRejectReason;
+
+// 扩展信息-查询返回
+ /* 开票记录表信息 */
+ private EmisSettleInvoiceRecord emisSettleInvoiceRecord;
+ /* 申请人名称 */
+ private String applyManName;
+ /* 申请站点名称 */
+ private String applySiteName;
+ /* 审核人名称 */
+ private String auditManName;
+ /* 审核站点名称 */
+ private String auditSiteName;
+ /* 账单月份 */
+ private String billMonth;
+ /* 月结编号 */
+ private String custNo;
+ /* 客户名称 */
+ private String customerName;
+
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisInvoiceCancellationMapper.java b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisInvoiceCancellationMapper.java
new file mode 100644
index 000000000..7ba1ca8e0
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisInvoiceCancellationMapper.java
@@ -0,0 +1,108 @@
+/**
+ * @Project: emis
+ * @Title: EmisInvoiceCancellationMapper.java
+ * @author heyu
+ * @date 2026-01-19 14:33:40
+ * @Copyright: ShangHai Doitinfo 2026 All rights reserved.
+ * @version v1.0
+ * @Description: 发票作废表 Mapper 接口
+ * Warning : This file is generate by ai tools,don't edit!!!
+ */
+package com.xdadan.erp.emis.mapper;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.xdadan.erp.emis.domain.EmisInvoiceCancellation;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * @ClassName EmisInvoiceCancellationMapper
+ * @Description 发票作废表 Mapper 接口
+ * @author heyu
+ * @date 2026-01-19 14:33:40
+ */
+public interface EmisInvoiceCancellationMapper extends BaseMapper
+{
+
+ /**
+ * 主键查询
+ * @param id
+ * @return
+ */
+ EmisInvoiceCancellation selectEmisInvoiceCancellationById(Long id);
+
+ /**
+ * 查询列表
+ *
+ * @param emisInvoiceCancellation
+ * @return 集合
+ */
+ List selectEmisInvoiceCancellationList(EmisInvoiceCancellation emisInvoiceCancellation);
+
+ /**
+ * 新增
+ *
+ * @param emisInvoiceCancellation
+ * @return
+ */
+ int insertEmisInvoiceCancellation(EmisInvoiceCancellation emisInvoiceCancellation);
+
+ /**
+ * 修改
+ *
+ * @param emisInvoiceCancellation
+ * @return
+ */
+ int updateEmisInvoiceCancellation(EmisInvoiceCancellation emisInvoiceCancellation);
+
+ /**
+ * 删除
+ *
+ * @param id 主键
+ * @return 结果
+ */
+ int deleteEmisInvoiceCancellationById(Long id);
+
+ /**
+ * 批量删除
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ int deleteEmisInvoiceCancellationByIds(Long[] ids);
+
+ /**
+ * 申请撤销(设置审核状态为3-已撤销)
+ */
+ int cancelApply(@Param("ids") Long[] ids, @Param("updateBy") String updateBy,
+ @Param("updateSite") String updateSite);
+
+ /**
+ * 审核通过
+ *
+ * @param ids 申请ID集合
+ * @param auditManCode 审核人
+ * @param auditSiteCode 审核站点
+ * @return 结果
+ */
+ int auditPass(@Param("ids") Long[] ids, @Param("auditManCode") String auditManCode,
+ @Param("auditSiteCode") String auditSiteCode);
+
+ /**
+ * 审核驳回
+ *
+ * @param ids 申请ID集合
+ * @param auditManCode 审核人
+ * @param auditSiteCode 审核站点
+ * @param auditRejectReason 驳回原因
+ * @return 结果
+ */
+ int auditReject(@Param("ids") Long[] ids, @Param("auditManCode") String auditManCode,
+ @Param("auditSiteCode") String auditSiteCode, @Param("auditRejectReason") String auditRejectReason);
+
+ /**
+ * 查询是否存在未完结申请(审核状态0或1)
+ */
+ int countActiveApply(@Param("invoiceId") Long invoiceId);
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisInvoiceCancellationService.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisInvoiceCancellationService.java
new file mode 100644
index 000000000..1c1b56b33
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisInvoiceCancellationService.java
@@ -0,0 +1,106 @@
+/**
+ * @Project: emis
+ * @Title: EmisInvoiceCancellationService.java
+ * @author heyu
+ * @date 2026-01-19 14:33:40
+ * @Copyright: ShangHai Duta 2026 All rights reserved.
+ * @version v1.0
+ * @Description: 发票作废表 服务类接口
+ */
+package com.xdadan.erp.emis.service;
+
+import com.xdadan.erp.emis.domain.EmisInvoiceCancellation;
+
+import java.util.List;
+
+/**
+ * @ClassName EmisInvoiceCancellationService
+ * @Description 发票作废表
+ * @author heyu
+ * @date 2026-01-19 14:33:40
+ */
+public interface IEmisInvoiceCancellationService {
+ /**
+ * 主键查询
+ *
+ * @param id
+ * @return
+ */
+ EmisInvoiceCancellation selectEmisInvoiceCancellationById(Long id);
+
+ /**
+ * 查询发票作废表列表
+ *
+ * @param emisInvoiceCancellation 发票作废表
+ * @return 发票作废表集合
+ */
+ List selectEmisInvoiceCancellationList(EmisInvoiceCancellation emisInvoiceCancellation);
+
+ /**
+ * 新增发票作废表
+ *
+ * @param emisInvoiceCancellation 发票作废表
+ * @return 结果
+ */
+ int insertEmisInvoiceCancellation(EmisInvoiceCancellation emisInvoiceCancellation) throws com.xdadan.erp.emis.domain.exception.EmisBizError;
+
+ /**
+ * 修改发票作废表
+ *
+ * @param emisInvoiceCancellation 发票作废表
+ * @return 结果
+ */
+ int updateEmisInvoiceCancellation(EmisInvoiceCancellation emisInvoiceCancellation) throws com.xdadan.erp.emis.domain.exception.EmisBizError;
+
+ /**
+ * 批量删除发票作废表
+ *
+ * @param ids 需要删除的发票作废表主键集合
+ * @return 结果
+ */
+ int deleteEmisInvoiceCancellationByIds(Long[] ids) throws com.xdadan.erp.emis.domain.exception.EmisBizError;
+
+ /**
+ * 删除发票作废表信息
+ *
+ * @param id 发票作废表主键
+ * @return 结果
+ */
+ int deleteEmisInvoiceCancellationById(Long id) throws com.xdadan.erp.emis.domain.exception.EmisBizError;
+
+ /**
+ * 撤销申请
+ *
+ * @param ids 主键数组
+ * @param updateBy 操作人
+ * @param updateSite 站点
+ * @return 结果
+ */
+ int cancelApply(Long[] ids, String updateBy, String updateSite) throws com.xdadan.erp.emis.domain.exception.EmisBizError;
+
+ /**
+ * 审核通过
+ *
+ * @param ids 申请ID
+ * @param auditManCode 审核人
+ * @param auditSiteCode 审核站点
+ * @return 结果
+ */
+ int auditPass(Long[] ids, String auditManCode, String auditSiteCode) throws com.xdadan.erp.emis.domain.exception.EmisBizError;
+
+ /**
+ * 审核驳回
+ *
+ * @param ids 申请ID
+ * @param auditManCode 审核人
+ * @param auditSiteCode 审核站点
+ * @param auditRejectReason 驳回原因
+ * @return 结果
+ */
+ int auditReject(Long[] ids, String auditManCode, String auditSiteCode, String auditRejectReason) throws com.xdadan.erp.emis.domain.exception.EmisBizError;
+
+ /**
+ * 是否存在审核中/已通过的申请
+ */
+ boolean existsActiveApply(Long invoiceId);
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisInvoiceCancellationServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisInvoiceCancellationServiceImpl.java
new file mode 100644
index 000000000..a4a1577e9
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisInvoiceCancellationServiceImpl.java
@@ -0,0 +1,203 @@
+/**
+ * @Project: emis
+ * @Title: EmisInvoiceCancellationServiceImpl.java
+ * @author heyu
+ * @date 2026-01-19 14:33:40
+ * @Copyright: ShangHai Duta 2026 All rights reserved.
+ * @version v1.0
+ * @Description: 发票作废表 实体类
+ */
+
+package com.xdadan.erp.emis.service.impl;
+
+import java.util.Date;
+import java.util.List;
+
+import com.xdadan.erp.common.utils.DateUtils;
+import com.xdadan.erp.emis.domain.EmisInvoiceCancellation;
+import com.xdadan.erp.emis.domain.enumtype.EmisBizErrorType;
+import com.xdadan.erp.emis.domain.exception.EmisBizError;
+import com.xdadan.erp.emis.mapper.EmisInvoiceCancellationMapper;
+import com.xdadan.erp.emis.service.IEmisInvoiceCancellationService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+/**
+ * 发票作废表Service业务层处理
+ *
+ * @author heyu
+ * @date 2026-01-19 14:33:40
+ */
+@Service
+public class EmisInvoiceCancellationServiceImpl implements IEmisInvoiceCancellationService
+{
+ @Autowired
+ private EmisInvoiceCancellationMapper emisInvoiceCancellationMapper;
+
+ /**
+ * 查询发票作废表
+ *
+ * @param id 发票作废表主键
+ * @return 发票作废表
+ */
+ @Override
+ public EmisInvoiceCancellation selectEmisInvoiceCancellationById(Long id)
+ {
+ return emisInvoiceCancellationMapper.selectEmisInvoiceCancellationById(id);
+ }
+
+ /**
+ * 查询发票作废表列表
+ *
+ * @param emisInvoiceCancellation 发票作废表
+ * @return 发票作废表
+ */
+ @Override
+ public List selectEmisInvoiceCancellationList(EmisInvoiceCancellation emisInvoiceCancellation)
+ {
+ return emisInvoiceCancellationMapper.selectEmisInvoiceCancellationList(emisInvoiceCancellation);
+ }
+
+ /**
+ * 新增发票作废表
+ *
+ * @param emisInvoiceCancellation 发票作废表
+ * @return 结果
+ */
+ @Override
+ public int insertEmisInvoiceCancellation(EmisInvoiceCancellation emisInvoiceCancellation) throws EmisBizError
+ {
+ validateRequired(emisInvoiceCancellation);
+ if (existsActiveApply(emisInvoiceCancellation.getInvoiceId())) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "不可重复添加");
+ }
+ Date now = DateUtils.getNowDate();
+ if (emisInvoiceCancellation.getApplyDate() == null) {
+ emisInvoiceCancellation.setApplyDate(now);
+ }
+ if (!StringUtils.hasText(emisInvoiceCancellation.getApplySeqNo())) {
+ emisInvoiceCancellation.setApplySeqNo(generateApplyNo());
+ }
+ return emisInvoiceCancellationMapper.insertEmisInvoiceCancellation(emisInvoiceCancellation);
+ }
+
+ /**
+ * 生成申请编号
+ */
+ private String generateApplyNo() {
+ return "IC" + System.currentTimeMillis();
+ }
+
+ /**
+ * 修改发票作废表
+ *
+ * @param emisInvoiceCancellation 发票作废表
+ * @return 结果
+ */
+ @Override
+ public int updateEmisInvoiceCancellation(EmisInvoiceCancellation emisInvoiceCancellation) throws EmisBizError
+ {
+ return emisInvoiceCancellationMapper.updateEmisInvoiceCancellation(emisInvoiceCancellation);
+ }
+
+ /**
+ * 批量删除发票作废表
+ *
+ * @param ids 需要删除的发票作废表主键
+ * @return 结果
+ */
+ @Override
+ public int deleteEmisInvoiceCancellationByIds(Long[] ids) throws EmisBizError
+ {
+ validateDeletable(ids);
+ return emisInvoiceCancellationMapper.deleteEmisInvoiceCancellationByIds(ids);
+ }
+
+ /**
+ * 删除发票作废表信息
+ *
+ * @param id 发票作废表主键
+ * @return 结果
+ */
+ @Override
+ public int deleteEmisInvoiceCancellationById(Long id) throws EmisBizError
+ {
+ validateDeletable(new Long[]{id});
+ return emisInvoiceCancellationMapper.deleteEmisInvoiceCancellationById(id);
+ }
+
+ @Override
+ public int cancelApply(Long[] ids, String updateBy, String updateSite) throws EmisBizError {
+ for (Long id : ids) {
+ EmisInvoiceCancellation db = emisInvoiceCancellationMapper.selectEmisInvoiceCancellationById(id);
+ if (db == null || !"0".equals(db.getAuditStatus())) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "仅未审核状态可撤销");
+ }
+ }
+ return emisInvoiceCancellationMapper.cancelApply(ids, updateBy, updateSite);
+ }
+
+ @Override
+ public int auditPass(Long[] ids, String auditManCode, String auditSiteCode) throws EmisBizError {
+ for (Long id : ids) {
+ EmisInvoiceCancellation db = emisInvoiceCancellationMapper.selectEmisInvoiceCancellationById(id);
+ if (db == null) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "申请不存在");
+ }
+ if (!"0".equals(db.getAuditStatus())) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "仅待审核状态可审核");
+ }
+ }
+ return emisInvoiceCancellationMapper.auditPass(ids, auditManCode, auditSiteCode);
+ }
+
+ @Override
+ public int auditReject(Long[] ids, String auditManCode, String auditSiteCode, String auditRejectReason) throws EmisBizError {
+ if (!StringUtils.hasText(auditRejectReason)) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "驳回原因不能为空");
+ }
+ for (Long id : ids) {
+ EmisInvoiceCancellation db = emisInvoiceCancellationMapper.selectEmisInvoiceCancellationById(id);
+ if (db == null) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "申请不存在");
+ }
+ if (!"0".equals(db.getAuditStatus())) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "仅待审核状态可驳回");
+ }
+ }
+ return emisInvoiceCancellationMapper.auditReject(ids, auditManCode, auditSiteCode, auditRejectReason);
+ }
+
+ @Override
+ public boolean existsActiveApply(Long invoiceId) {
+ if (invoiceId == null) {
+ return false;
+ }
+ return emisInvoiceCancellationMapper.countActiveApply(invoiceId) > 0;
+ }
+
+ private void validateRequired(EmisInvoiceCancellation emisInvoiceCancellation) throws EmisBizError {
+ if (emisInvoiceCancellation == null || emisInvoiceCancellation.getInvoiceId() == null) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "invoiceId必传");
+ }
+ if (!StringUtils.hasText(emisInvoiceCancellation.getApplyReason())) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "申请原因必传");
+ }
+ if (!StringUtils.hasText(emisInvoiceCancellation.getApplyTextUrl())) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "申请附件必传");
+ }
+ }
+
+ private void validateDeletable(Long[] ids) throws EmisBizError {
+ for (Long id : ids) {
+ EmisInvoiceCancellation db = emisInvoiceCancellationMapper.selectEmisInvoiceCancellationById(id);
+ if (db == null) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "申请不存在");
+ }
+ if (!"2".equals(db.getAuditStatus()) && !"3".equals(db.getAuditStatus())) {
+ throw new EmisBizError(EmisBizErrorType.FAIL, "仅已驳回或已撤销状态可删除");
+ }
+ }
+ }
+}
diff --git a/emis-biz/src/main/resources/mapper/EmisInvoiceCancellationMapper.xml b/emis-biz/src/main/resources/mapper/EmisInvoiceCancellationMapper.xml
new file mode 100644
index 000000000..a8ffb50f8
--- /dev/null
+++ b/emis-biz/src/main/resources/mapper/EmisInvoiceCancellationMapper.xml
@@ -0,0 +1,309 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select c.id, c.invoice_id, c.apply_seq_no, c.apply_date, c.apply_reason, c.apply_text_url,
+ c.apply_man_code, c.apply_site_code, c.audit_status, c.audit_date, c.audit_man_code, c.audit_site_code,
+ c.audit_reject_reason, c.remark, c.del_flag, c.create_by, c.create_time, c.update_by,
+ c.update_time, c.create_site, c.update_site,
+ i.id as inv_id, i.apply_seq_no as inv_apply_seq_no, i.apply_date as inv_apply_date,
+ i.customer_code as inv_customer_code, i.customer_name as inv_customer_name,
+ i.settle_bill_no as inv_settle_bill_no, i.settle_bill_name as inv_settle_bill_name,
+ i.apply_money as inv_apply_money, i.add_tax_rate as inv_add_tax_rate, i.add_open_money as inv_add_open_money,
+ i.reced_money as inv_reced_money, i.company_name as inv_company_name, i.company_tax_no as inv_company_tax_no,
+ i.invoice_no as inv_invoice_no, i.invoice_status as inv_invoice_status, i.payment_status as inv_payment_status,
+ GROUP_CONCAT(DISTINCT b.bill_month ORDER BY b.bill_month SEPARATOR ',') as bill_month,
+ GROUP_CONCAT(DISTINCT b.cust_no ORDER BY b.cust_no SEPARATOR ',') as cust_no,
+ GROUP_CONCAT(DISTINCT b.customer_name ORDER BY b.customer_name SEPARATOR ',') as customer_name
+ from emis_invoice_cancellation c
+ left join emis_settle_invoice_record i on c.invoice_id = i.id and i.del_flag = '0'
+ left join emis_settle_invoice_bill_rel rel on i.apply_seq_no = rel.apply_seq_no and rel.del_flag = '0'
+ left join emis_settle_bill b on rel.settle_bill_no = b.settle_bill_no and b.del_flag = '0'
+
+
+
+
+
+
+
+ insert into emis_invoice_cancellation
+
+ invoice_id,
+ apply_seq_no,
+ apply_date,
+ apply_reason,
+ apply_text_url,
+ apply_man_code,
+ apply_site_code,
+ audit_status,
+ audit_date,
+ audit_man_code,
+ audit_site_code,
+ audit_reject_reason,
+ remark,
+ del_flag,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ create_site,
+ update_site,
+
+
+ #{invoiceId},
+ #{applySeqNo},
+ #{applyDate},
+ #{applyReason},
+ #{applyTextUrl},
+ #{applyManCode},
+ #{applySiteCode},
+ #{auditStatus},
+ #{auditDate},
+ #{auditManCode},
+ #{auditSiteCode},
+ #{auditRejectReason},
+ #{remark},
+ '0',
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+ #{createSite},
+ #{updateSite},
+
+
+
+
+ update emis_invoice_cancellation
+
+ invoice_id = #{invoiceId},
+ apply_seq_no = #{applySeqNo},
+ apply_date = #{applyDate},
+ apply_reason = #{applyReason},
+ apply_text_url = #{applyTextUrl},
+ apply_man_code = #{applyManCode},
+ apply_site_code = #{applySiteCode},
+ audit_status = #{auditStatus},
+ audit_date = #{auditDate},
+ audit_man_code = #{auditManCode},
+ audit_site_code = #{auditSiteCode},
+ audit_reject_reason = #{auditRejectReason},
+ remark = #{remark},
+ del_flag = #{delFlag},
+ update_by = #{updateBy},
+ update_time = #{updateTime},
+ create_site = #{createSite},
+ update_site = #{updateSite},
+
+ where id = #{id}
+
+
+
+ update emis_invoice_cancellation set del_flag = '2' where id = #{id}
+
+
+
+ update emis_invoice_cancellation set del_flag = '2'
+ where id in
+
+ #{item}
+
+
+
+
+ update emis_invoice_cancellation
+ set audit_status = '3',
+ update_by = #{updateBy},
+ update_site = #{updateSite},
+ update_time = now()
+ where del_flag = '0'
+ and id in
+
+ #{item}
+
+
+
+
+ update emis_invoice_cancellation
+ set audit_status = '1',
+ audit_date = now(),
+ audit_man_code = #{auditManCode},
+ audit_site_code = #{auditSiteCode},
+ update_by = #{auditManCode},
+ update_site = #{auditSiteCode},
+ update_time = now()
+ where del_flag = '0'
+ and id in
+
+ #{item}
+
+
+
+
+ update emis_invoice_cancellation
+ set audit_status = '2',
+ audit_reject_reason = #{auditRejectReason},
+ audit_date = now(),
+ audit_man_code = #{auditManCode},
+ audit_site_code = #{auditSiteCode},
+ update_by = #{auditManCode},
+ update_site = #{auditSiteCode},
+ update_time = now()
+ where del_flag = '0'
+ and id in
+
+ #{item}
+
+
+
+
+
+