diff --git a/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisWriteoffApplyController.java b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisWriteoffApplyController.java
new file mode 100644
index 000000000..b4b316212
--- /dev/null
+++ b/emis-biz-web/src/main/java/com/xdadan/erp/web/emis/EmisWriteoffApplyController.java
@@ -0,0 +1,374 @@
+/**
+ * @Project: emis
+ * @Title: EmisWriteoffApplyController.java
+ * @author heyu
+ * @date 2025-09-15 23:39:28
+ * @Copyright: ShangHai Duta 2022 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.emis.domain.EmisWriteoffApply;
+import com.xdadan.erp.emis.domain.EmisWriteoffApplyDetail;
+import com.xdadan.erp.emis.domain.exception.EmisBizError;
+import com.xdadan.erp.emis.service.IEmisWriteoffApplyService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.PathVariable;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 销账申请Controller
+ *
+ * @author 何宇
+ * @date 2025-09-16 10:00:00
+ */
+@RestController
+@RequestMapping("/emis/writeoffApply")
+@Slf4j
+public class EmisWriteoffApplyController extends EmisBaseController {
+ @Autowired
+ private IEmisWriteoffApplyService emisWriteoffApplyService;
+
+ /**
+ * 查询销账申请列表
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:list')")
+ @GetMapping("/list")
+ public TableDataInfo list(EmisWriteoffApply emisWriteoffApply) {
+ // 处理params参数,支持运单号、账单号多选查询
+ if (emisWriteoffApply.getParams() != null && emisWriteoffApply.getParams().containsKey("queryParams")) {
+ String queryParams = (String) emisWriteoffApply.getParams().get("queryParams");
+ if (queryParams != null && !queryParams.trim().isEmpty()) {
+ // 清理参数,去除空行和多余空格
+ String[] lines = queryParams.split("\n");
+ StringBuilder cleanParams = new StringBuilder();
+ for (String line : lines) {
+ String trimmed = line.trim();
+ if (!trimmed.isEmpty()) {
+ if (cleanParams.length() > 0) {
+ cleanParams.append("\n");
+ }
+ cleanParams.append(trimmed);
+ }
+ }
+ emisWriteoffApply.getParams().put("queryParams", cleanParams.toString());
+ }
+ }
+
+ startPage();
+ List list = emisWriteoffApplyService.selectEmisWriteoffApplyList(emisWriteoffApply);
+ return getDataTable(list);
+ }
+
+ /**
+ * 导出销账申请列表
+ */
+ @PreAuthorize("@ss.hasPermi('emis:writeoffApply:export')")
+ @Log(title = "销账申请", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(EmisWriteoffApply emisWriteoffApply) {
+ // 处理params参数,支持运单号、账单号多选查询
+ if (emisWriteoffApply.getParams() != null && emisWriteoffApply.getParams().containsKey("queryParams")) {
+ String queryParams = (String) emisWriteoffApply.getParams().get("queryParams");
+ if (queryParams != null && !queryParams.trim().isEmpty()) {
+ // 清理参数,去除空行和多余空格
+ String[] lines = queryParams.split("\n");
+ StringBuilder cleanParams = new StringBuilder();
+ for (String line : lines) {
+ String trimmed = line.trim();
+ if (!trimmed.isEmpty()) {
+ if (cleanParams.length() > 0) {
+ cleanParams.append("\n");
+ }
+ cleanParams.append(trimmed);
+ }
+ }
+ emisWriteoffApply.getParams().put("queryParams", cleanParams.toString());
+ }
+ }
+
+ List list = emisWriteoffApplyService.selectEmisWriteoffApplyList(emisWriteoffApply);
+ // ExcelUtil util = new
+ // ExcelUtil(EmisWriteoffApply.class);
+ // util.exportExcel(response, list, "销账申请数据");
+ log.info("导出销账申请数据,共{}条记录", list.size());
+ }
+
+ /**
+ * 获取销账申请详细信息
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:query')")
+ @GetMapping(value = "/{id}")
+ public AjaxResult getInfo(@PathVariable("id") Long id) {
+ return AjaxResult.success(emisWriteoffApplyService.selectEmisWriteoffApplyById(id));
+ }
+
+ /**
+ * 新增销账申请
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:add')")
+ @Log(title = "销账申请", businessType = BusinessType.INSERT)
+ @PostMapping
+ public AjaxResult add(@RequestBody EmisWriteoffApply emisWriteoffApply) {
+ try {
+ return toAjax(emisWriteoffApplyService.insertEmisWriteoffApply(emisWriteoffApply));
+ } catch (Exception e) {
+ log.error("新增销账申请失败", e);
+ return error("新增销账申请失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 修改销账申请
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:edit')")
+ @Log(title = "销账申请", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public AjaxResult edit(@RequestBody EmisWriteoffApply emisWriteoffApply) throws EmisBizError {
+ return toAjax(emisWriteoffApplyService.updateEmisWriteoffApply(emisWriteoffApply));
+ }
+
+ /**
+ * 删除销账申请
+ * 仅支持删除已撤销的数据,审核中以及审核完成的数据不支持删除
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:remove')")
+ @Log(title = "销账申请", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable Long[] ids) {
+ try {
+ return toAjax(emisWriteoffApplyService.deleteEmisWriteoffApplyByIds(ids));
+ } catch (Exception e) {
+ log.error("删除销账申请失败", e);
+ return error("删除销账申请失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 财务中心审核通过
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:centerPass')")
+ @Log(title = "财务中心审核通过", businessType = BusinessType.UPDATE)
+ @PostMapping("/auditCenterPass/{ids}")
+ public AjaxResult auditCenterPass(@PathVariable Long[] ids) {
+ if (ids != null && ids.length > 0) {
+ for (int i = 0; i < ids.length; i++) {
+ try {
+ long id = ids[i];
+ EmisWriteoffApply emisWriteoffApply = new EmisWriteoffApply();
+ emisWriteoffApply.setId(id);
+
+ emisWriteoffApplyService.auditCenterPass(emisWriteoffApply);
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ // 返回子定义异常
+ if (ex instanceof EmisBizError) {
+ return AjaxResult.error(ex.getMessage(), ((EmisBizError) ex).getErrorCode());
+ }
+
+ return AjaxResult.error("审核异常,联系客服");
+ }
+ }
+ }
+ return AjaxResult.success("操作成功");
+ }
+
+ /**
+ * 财务中心审核驳回
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:centerReject')")
+ @Log(title = "财务中心审核驳回", businessType = BusinessType.UPDATE)
+ @PostMapping("/auditCenterReject/{ids}")
+ public AjaxResult auditCenterReject(@PathVariable Long[] ids, @RequestBody EmisWriteoffApply emisWriteoffApply) {
+ if (ids != null && ids.length > 0) {
+ for (int i = 0; i < ids.length; i++) {
+ try {
+ long id = ids[i];
+ EmisWriteoffApply apply = new EmisWriteoffApply();
+ apply.setId(id);
+ apply.setCenterRejectReason(emisWriteoffApply.getCenterRejectReason());
+
+ emisWriteoffApplyService.auditCenterReject(apply);
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ // 返回子定义异常
+ if (ex instanceof EmisBizError) {
+ return AjaxResult.error(ex.getMessage(), ((EmisBizError) ex).getErrorCode());
+ }
+
+ return AjaxResult.error("审核异常,联系客服");
+ }
+ }
+ }
+ return AjaxResult.success("操作成功");
+ }
+
+ /**
+ * 总部确认
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:headquartersConfirm')")
+ @Log(title = "总部确认", businessType = BusinessType.UPDATE)
+ @PostMapping("/auditHeadquartersConfirm/{ids}")
+ public AjaxResult auditHeadquartersConfirm(@PathVariable Long[] ids) {
+ if (ids != null && ids.length > 0) {
+ for (int i = 0; i < ids.length; i++) {
+ try {
+ long id = ids[i];
+ EmisWriteoffApply emisWriteoffApply = new EmisWriteoffApply();
+ emisWriteoffApply.setId(id);
+
+ emisWriteoffApplyService.auditHeadquartersConfirm(emisWriteoffApply);
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ // 返回子定义异常
+ if (ex instanceof EmisBizError) {
+ return AjaxResult.error(ex.getMessage(), ((EmisBizError) ex).getErrorCode());
+ }
+
+ return AjaxResult.error("确认异常,联系客服");
+ }
+ }
+ }
+ return AjaxResult.success("操作成功");
+ }
+
+ /**
+ * 总部驳回
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:headquartersReject')")
+ @Log(title = "总部驳回", businessType = BusinessType.UPDATE)
+ @PostMapping("/auditHeadquartersReject/{ids}")
+ public AjaxResult auditHeadquartersReject(@PathVariable Long[] ids,
+ @RequestBody EmisWriteoffApply emisWriteoffApply) {
+ if (ids != null && ids.length > 0) {
+ for (int i = 0; i < ids.length; i++) {
+ try {
+ long id = ids[i];
+ EmisWriteoffApply apply = new EmisWriteoffApply();
+ apply.setId(id);
+ apply.setHeadquartersRejectReason(emisWriteoffApply.getHeadquartersRejectReason());
+
+ emisWriteoffApplyService.auditHeadquartersReject(apply);
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ // 返回子定义异常
+ if (ex instanceof EmisBizError) {
+ return AjaxResult.error(ex.getMessage(), ((EmisBizError) ex).getErrorCode());
+ }
+
+ return AjaxResult.error("驳回异常,联系客服");
+ }
+ }
+ }
+ return AjaxResult.success("操作成功");
+ }
+
+ /**
+ * 撤销申请
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:revoke')")
+ @Log(title = "撤销申请", businessType = BusinessType.UPDATE)
+ @PostMapping("/revoke/{ids}")
+ public AjaxResult revoke(@PathVariable Long[] ids) {
+ if (ids != null && ids.length > 0) {
+ for (int i = 0; i < ids.length; i++) {
+ try {
+ long id = ids[i];
+ EmisWriteoffApply emisWriteoffApply = new EmisWriteoffApply();
+ emisWriteoffApply.setId(id);
+
+ emisWriteoffApplyService.revokeApply(emisWriteoffApply);
+
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ // 返回子定义异常
+ if (ex instanceof EmisBizError) {
+ return AjaxResult.error(ex.getMessage(), ((EmisBizError) ex).getErrorCode());
+ }
+
+ return AjaxResult.error("撤销异常,联系客服");
+ }
+ }
+ }
+ return AjaxResult.success("操作成功");
+ }
+
+ /**
+ * 再次申请
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:reapply')")
+ @Log(title = "再次申请", businessType = BusinessType.UPDATE)
+ @PostMapping("/reapply")
+ public AjaxResult reapply(@RequestBody EmisWriteoffApply emisWriteoffApply) {
+ try {
+ return toAjax(emisWriteoffApplyService.reapply(emisWriteoffApply));
+ } catch (Exception e) {
+ log.error("再次申请失败", e);
+ return error("再次申请失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 根据运单号查询运单、结算账单、结算子账单信息(返回EmisWriteoffApplyDetail列表)
+ */
+ // @PreAuthorize("@ss.hasPermi('emis:writeoffApply:queryByBillCodes')")
+ @GetMapping("/queryByBillCodes")
+ public AjaxResult queryByBillCodes(EmisWriteoffApply emisWriteoffApply) {
+ try {
+ // 处理params参数,支持运单号、账单号多选查询
+ if (emisWriteoffApply.getParams() != null && emisWriteoffApply.getParams().containsKey("queryParams")) {
+ String queryParams = (String) emisWriteoffApply.getParams().get("queryParams");
+ if (queryParams != null && !queryParams.trim().isEmpty()) {
+ // 清理参数,去除空行和多余空格
+ String[] lines = queryParams.split("\n");
+ StringBuilder cleanParams = new StringBuilder();
+ for (String line : lines) {
+ String trimmed = line.trim();
+ if (!trimmed.isEmpty()) {
+ if (cleanParams.length() > 0) {
+ cleanParams.append("\n");
+ }
+ cleanParams.append(trimmed);
+ }
+ }
+ emisWriteoffApply.getParams().put("queryParams", cleanParams.toString());
+ }
+ }
+
+ // 检查是否有查询参数
+ if (emisWriteoffApply.getParams() == null ||
+ !emisWriteoffApply.getParams().containsKey("queryParams") ||
+ emisWriteoffApply.getParams().get("queryParams") == null ||
+ emisWriteoffApply.getParams().get("queryParams").toString().trim().isEmpty()) {
+ return error("运单号列表不能为空");
+ }
+
+ // 从queryParams中提取运单号列表
+ String queryParams = (String) emisWriteoffApply.getParams().get("queryParams");
+ String[] billCodes = queryParams.split("\n");
+ List billCodeList = Arrays.asList(billCodes);
+
+ List list = emisWriteoffApplyService
+ .selectEmisWriteoffApplyDetailListByBillCodes(billCodeList);
+ return AjaxResult.success(list);
+ } catch (Exception e) {
+ log.error("根据运单号查询运单、结算账单、结算子账单信息失败", e);
+ return error("查询失败:" + e.getMessage());
+ }
+ }
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisWriteoffApply.java b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisWriteoffApply.java
new file mode 100644
index 000000000..2e824fc65
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisWriteoffApply.java
@@ -0,0 +1,167 @@
+/**
+ * @Project: emis
+ * @Title: EmisWriteoffApply.java
+ * @author heyu
+ * @date 2025-09-15 23:39:28
+ * @Copyright: ShangHai Duta 2022 All rights reserved.
+ * @version v1.0
+ * @Description: 销账申请表 实体类
+ */
+
+package com.xdadan.erp.emis.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.xdadan.erp.common.annotation.Excel;
+import com.xdadan.erp.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * @ClassName EmisWriteoffApply
+ * @Description 销账申请表
+ * @author 何宇
+ * @date 2025-09-16 10:00:00
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class EmisWriteoffApply extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /* id */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /* 申请编号 */
+ @Excel(name = "申请编号")
+ private String applyNo;
+
+ /* 申请人编码 */
+ @Excel(name = "申请人编码")
+ private String applyManCode;
+
+ /* 申请人姓名 */
+ @Excel(name = "申请人")
+ private String applyManName;
+
+ /* 申请站点代码 */
+ @Excel(name = "申请站点代码")
+ private String applySiteCode;
+
+ /* 申请站点名称 */
+ @Excel(name = "申请站点")
+ private String applySiteName;
+
+ /* 申请时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ @Excel(name = "申请时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private Date applyDate;
+
+ /* 销账金额 */
+ @Excel(name = "销账金额")
+ private BigDecimal writeoffAmount;
+
+ /* 收款来源 1-微信支付2支付宝 3-对公 */
+ private String payType;
+
+ /* 交易时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ private Date tradeDate;
+
+ /* 收款人 */
+ private String recipient;
+
+ /* 申请说明 */
+ @Excel(name = "申请说明")
+ private String applyMemo;
+
+ /* 中心审核状态 0-未审核 1-审核通过 2-审核拒绝 3-已撤销*/
+ @Excel(name = "中心审核状态")
+ private String blCenterConfirmed;
+
+ /* 中心审核人编码 */
+ @Excel(name = "中心审核人编码")
+ private String centerConfirmManCode;
+
+ /* 中心审核人姓名 */
+ @Excel(name = "中心审核人")
+ private String centerConfirmManName;
+
+ /* 中心审核时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ @Excel(name = "中心审核时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private Date centerConfirmDate;
+
+ /* 中心审核备注 */
+ @Excel(name = "中心审核备注")
+ private String centerConfirmNote;
+
+ /* 中心驳回原因 */
+ @Excel(name = "中心驳回原因")
+ private String centerRejectReason;
+
+ /* 总部审核状态 0-未审核 1-确认 2-驳回 */
+ @Excel(name = "总部审核状态")
+ private String blHeadquartersConfirmed;
+
+ /* 总部审核人编码 */
+ @Excel(name = "总部审核人编码")
+ private String headquartersConfirmManCode;
+
+ /* 总部审核人姓名 */
+ @Excel(name = "总部审核人")
+ private String headquartersConfirmManName;
+
+ /* 总部审核时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ @Excel(name = "总部审核时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private Date headquartersConfirmDate;
+
+ /* 总部审核备注 */
+ @Excel(name = "总部审核备注")
+ private String headquartersConfirmNote;
+
+ /* 总部驳回原因 */
+ @Excel(name = "总部驳回原因")
+ private String headquartersRejectReason;
+
+ /* 撤销时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ @Excel(name = "撤销时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private Date revokeDate;
+
+ /* 撤销人编码 */
+ @Excel(name = "撤销人编码")
+ private String revokeManCode;
+
+ /* 撤销人姓名 */
+ @Excel(name = "撤销人")
+ private String revokeManName;
+
+ /* 撤销原因 */
+ @Excel(name = "撤销原因")
+ private String revokeReason;
+
+ // 关联明细列表
+ private List detailList;
+
+ // 关联图片列表
+ private List imageList;
+
+ // 查询条件字段(只查询不入库)
+ @TableField(exist = false)
+ private String payee; // 回款联系人
+
+ @TableField(exist = false)
+ private String salesmen; // 销售联系人
+
+ @TableField(exist = false)
+ private String settleBillName; // 账单名称
+
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisWriteoffApplyDetail.java b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisWriteoffApplyDetail.java
new file mode 100644
index 000000000..c8a4cc63e
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisWriteoffApplyDetail.java
@@ -0,0 +1,70 @@
+/**
+ * @Project: emis
+ * @Title: EmisWriteoffApplyDetail.java
+ * @author heyu
+ * @date 2025-09-15 23:39:28
+ * @Copyright: ShangHai Duta 2022 All rights reserved.
+ * @version v1.0
+ * @Description: 销账申请明细表 实体类
+ */
+
+package com.xdadan.erp.emis.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.xdadan.erp.common.annotation.Excel;
+import com.xdadan.erp.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.math.BigDecimal;
+
+/**
+ * @ClassName EmisWriteoffApplyDetail
+ * @Description 销账申请明细表
+ * @author 何宇
+ * @date 2025-19-16 10:00:00
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class EmisWriteoffApplyDetail extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /* id */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /* 申请ID */
+ @Excel(name = "申请ID")
+ private Long applyId;
+
+ /* 申请编号 */
+ @Excel(name = "申请编号")
+ private String applyNo;
+
+ /* 运单号 */
+ @Excel(name = "运单号")
+ private String billCode;
+
+ /* 申请金额 */
+ @Excel(name = "申请金额")
+ private BigDecimal applyMoney;
+
+ /* 账单号 */
+ @Excel(name = "账单号")
+ private String settleBillNo;
+
+ // 关联运单信息(只作查询)
+ @TableField(exist = false)
+ private EmisWaybill emisWaybill = new EmisWaybill();
+
+ // 关联结算账单信息(只作查询)
+ @TableField(exist = false)
+ private EmisSettleBill emisSettleBill = new EmisSettleBill();
+
+ // 关联结算子账单信息(只作查询)
+ @TableField(exist = false)
+ private EmisSettleSubBill emisSettleSubBill = new EmisSettleSubBill();
+
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisWriteoffApplyImage.java b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisWriteoffApplyImage.java
new file mode 100644
index 000000000..26ea83656
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/EmisWriteoffApplyImage.java
@@ -0,0 +1,74 @@
+/**
+ * @Project: emis
+ * @Title: EmisWriteoffApplyImage.java
+ * @author heyu
+ * @date 2025-09-15 23:39:28
+ * @Copyright: ShangHai Duta 2022 All rights reserved.
+ * @version v1.0
+ * @Description: 销账申请图片表 实体类
+ */
+
+package com.xdadan.erp.emis.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.xdadan.erp.common.annotation.Excel;
+import com.xdadan.erp.common.core.domain.BaseEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Date;
+
+/**
+ * @ClassName EmisWriteoffApplyImage
+ * @Description 销账申请图片表
+ * @author heyu
+ * @date 2025-09-16 10:00:00
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+public class EmisWriteoffApplyImage extends BaseEntity {
+ private static final long serialVersionUID = 1L;
+
+ /* id */
+ @TableId(value = "id", type = IdType.AUTO)
+ private Long id;
+
+ /* 申请ID */
+ @Excel(name = "申请ID")
+ private Long applyId;
+
+ /* 申请编号 */
+ @Excel(name = "申请编号")
+ private String applyNo;
+
+ /* 图片名称 */
+ @Excel(name = "图片名称")
+ private String imageName;
+
+ /* 图片路径 */
+ @Excel(name = "图片路径")
+ private String imagePath;
+
+ /* 图片大小 */
+ @Excel(name = "图片大小")
+ private Long imageSize;
+
+ /* 图片类型 */
+ @Excel(name = "图片类型")
+ private String imageType;
+
+ /* 上传时间 */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+ @Excel(name = "上传时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private Date uploadDate;
+
+ /* 上传人编码 */
+ @Excel(name = "上传人编码")
+ private String uploadManCode;
+
+ /* 上传人姓名 */
+ @Excel(name = "上传人")
+ private String uploadManName;
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/enumtype/WriteoffApplyStatus.java b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/enumtype/WriteoffApplyStatus.java
new file mode 100644
index 000000000..6e3142752
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/enumtype/WriteoffApplyStatus.java
@@ -0,0 +1,32 @@
+package com.xdadan.erp.emis.domain.enumtype;
+
+/**
+ * @Project: emis
+ * @Title: WriteoffApplyStatus.java
+ * @author heyu
+ * @date 2025-09-15 23:39:28
+ * @Copyright: ShangHai Duta 2022 All rights reserved.
+ * @version v1.0
+ * @Description:
+ *
+ * 销账申请状态枚举
+ *
+ */
+public enum WriteoffApplyStatus {
+
+ CENTER_PENDING("0", "中心未审核"),
+ CENTER_APPROVED("1", "中心已审核"),
+ CENTER_REJECTED("2", "中心驳回"),
+ REVOKED("3", "已撤销"),
+ HEADQUARTERS_PENDING("0", "总部未审核"),
+ HEADQUARTERS_CONFIRMED("1", "总部确认"),
+ HEADQUARTERS_REJECTED("2", "总部驳回");
+
+ public String statusCode;
+ public String statusName;
+
+ WriteoffApplyStatus(String statusCode, String statusName) {
+ this.statusCode = statusCode;
+ this.statusName = statusName;
+ }
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/enumtype/WriteoffApplyType.java b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/enumtype/WriteoffApplyType.java
new file mode 100644
index 000000000..2dba5382a
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/enumtype/WriteoffApplyType.java
@@ -0,0 +1,20 @@
+package com.xdadan.erp.emis.domain.enumtype;
+
+/**
+ * 销账申请类型枚举
+ */
+public enum WriteoffApplyType {
+
+ WAYBILL("1", "运单号"),
+ BILL("2", "账单号");
+
+ public String typeCode;
+ public String typeName;
+
+ WriteoffApplyType(String typeCode, String typeName) {
+ this.typeCode = typeCode;
+ this.typeName = typeName;
+ }
+}
+
+
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/exception/EmisBizError.java b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/exception/EmisBizError.java
index 2fe422981..52719d780 100644
--- a/emis-biz/src/main/java/com/xdadan/erp/emis/domain/exception/EmisBizError.java
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/domain/exception/EmisBizError.java
@@ -11,6 +11,11 @@ public class EmisBizError extends Exception {
this.errorCode = errorType.getErrorCode();
}
+ public EmisBizError(String errorMessage) {
+ super(errorMessage);
+ this.errorCode = "BIZ_ERROR";
+ }
+
public String getErrorCode() {
return errorCode;
}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyDetailMapper.java b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyDetailMapper.java
new file mode 100644
index 000000000..53f90239d
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyDetailMapper.java
@@ -0,0 +1,107 @@
+/**
+ * @Project: emis
+ * @Title: EmisWriteoffApplyDetailMapper.java
+ * @author heyu
+ * @date 2025-09-15 23:39:28
+ * @Copyright: ShangHai Doitinfo 2022 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.EmisWriteoffApplyDetail;
+
+/**
+ * @ClassName EmisWriteoffApplyDetailMapper
+ * @Description
+ *
+ * 销账申请明细表 Mapper 接口
+ *
+ * @author 何宇
+ * @date 2025-09-16 10:00:00
+ */
+public interface EmisWriteoffApplyDetailMapper extends BaseMapper {
+ /**
+ * 主键查询
+ *
+ * @param id
+ * @return
+ */
+ public EmisWriteoffApplyDetail selectEmisWriteoffApplyDetailById(Long id);
+
+ /**
+ * 查询列表
+ *
+ * @param emisWriteoffApplyDetail
+ * @return 集合
+ */
+ public List selectEmisWriteoffApplyDetailList(
+ EmisWriteoffApplyDetail emisWriteoffApplyDetail);
+
+ /**
+ * 根据申请ID查询明细列表
+ *
+ * @param applyId 申请ID
+ * @return 集合
+ */
+ public List selectEmisWriteoffApplyDetailListByApplyId(Long applyId);
+
+ /**
+ * 根据申请ID查询明细列表(只包含emisWaybill、emisSettleBill、emisSettleSubBill)
+ *
+ * @param applyId 申请ID
+ * @return 集合
+ */
+ public List selectEmisWriteoffApplyDetailListByApplyIdWithDetails(Long applyId);
+
+ /**
+ * 新增
+ *
+ * @param emisWriteoffApplyDetail
+ * @return
+ */
+ public int insertEmisWriteoffApplyDetail(EmisWriteoffApplyDetail emisWriteoffApplyDetail);
+
+ /**
+ * 批量新增
+ *
+ * @param emisWriteoffApplyDetailList
+ * @return
+ */
+ public int insertEmisWriteoffApplyDetailBatch(List emisWriteoffApplyDetailList);
+
+ /**
+ * 修改
+ *
+ * @param emisWriteoffApplyDetail
+ * @return
+ */
+ public int updateEmisWriteoffApplyDetail(EmisWriteoffApplyDetail emisWriteoffApplyDetail);
+
+ /**
+ * 删除
+ *
+ * @param id 主键
+ * @return 结果
+ */
+ public int deleteEmisWriteoffApplyDetailById(Long id);
+
+ /**
+ * 根据申请ID删除明细
+ *
+ * @param applyId 申请ID
+ * @return 结果
+ */
+ public int deleteEmisWriteoffApplyDetailByApplyId(Long applyId);
+
+ /**
+ * 批量删除
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteEmisWriteoffApplyDetailByIds(Long[] ids);
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyImageMapper.java b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyImageMapper.java
new file mode 100644
index 000000000..52ac34c99
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyImageMapper.java
@@ -0,0 +1,98 @@
+/**
+ * @Project: emis
+ * @Title: EmisWriteoffApplyImageMapper.java
+ * @author heyu
+ * @date 2025-09-15 23:39:28
+ * @Copyright: ShangHai Doitinfo 2022 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.EmisWriteoffApplyImage;
+
+/**
+ * @ClassName EmisWriteoffApplyImageMapper
+ * @Description
+ *
+ * 销账申请图片表 Mapper 接口
+ *
+ * @author 何宇
+ * @date 2025-09-16 10:00:00
+ */
+public interface EmisWriteoffApplyImageMapper extends BaseMapper {
+ /**
+ * 主键查询
+ *
+ * @param id
+ * @return
+ */
+ public EmisWriteoffApplyImage selectEmisWriteoffApplyImageById(Long id);
+
+ /**
+ * 查询列表
+ *
+ * @param emisWriteoffApplyImage
+ * @return 集合
+ */
+ public List selectEmisWriteoffApplyImageList(EmisWriteoffApplyImage emisWriteoffApplyImage);
+
+ /**
+ * 根据申请ID查询图片列表
+ *
+ * @param applyId 申请ID
+ * @return 集合
+ */
+ public List selectEmisWriteoffApplyImageListByApplyId(Long applyId);
+
+ /**
+ * 新增
+ *
+ * @param emisWriteoffApplyImage
+ * @return
+ */
+ public int insertEmisWriteoffApplyImage(EmisWriteoffApplyImage emisWriteoffApplyImage);
+
+ /**
+ * 批量新增
+ *
+ * @param emisWriteoffApplyImageList
+ * @return
+ */
+ public int insertEmisWriteoffApplyImageBatch(List emisWriteoffApplyImageList);
+
+ /**
+ * 修改
+ *
+ * @param emisWriteoffApplyImage
+ * @return
+ */
+ public int updateEmisWriteoffApplyImage(EmisWriteoffApplyImage emisWriteoffApplyImage);
+
+ /**
+ * 删除
+ *
+ * @param id 主键
+ * @return 结果
+ */
+ public int deleteEmisWriteoffApplyImageById(Long id);
+
+ /**
+ * 根据申请ID删除图片
+ *
+ * @param applyId 申请ID
+ * @return 结果
+ */
+ public int deleteEmisWriteoffApplyImageByApplyId(Long applyId);
+
+ /**
+ * 批量删除
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteEmisWriteoffApplyImageByIds(Long[] ids);
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyMapper.java b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyMapper.java
new file mode 100644
index 000000000..41501aedd
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/mapper/EmisWriteoffApplyMapper.java
@@ -0,0 +1,131 @@
+/**
+ * @Project: emis
+ * @Title: EmisWriteoffApplyMapper.java
+ * @author heyu
+ * @date 2025-09-15 23:39:28
+ * @Copyright: ShangHai Doitinfo 2022 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.EmisWriteoffApply;
+import com.xdadan.erp.emis.domain.EmisWriteoffApplyDetail;
+
+/**
+ * @ClassName EmisWriteoffApplyMapper
+ * @Description
+ *
+ * 销账申请表 Mapper 接口
+ *
+ * @author 何宇
+ * @date 2025-09-16 10:00:00
+ */
+public interface EmisWriteoffApplyMapper extends BaseMapper {
+ /**
+ * 主键查询
+ *
+ * @param id
+ * @return
+ */
+ public EmisWriteoffApply selectEmisWriteoffApplyById(Long id);
+
+ /**
+ * 查询列表
+ *
+ * @param emisWriteoffApply
+ * @return 集合
+ */
+ public List selectEmisWriteoffApplyList(EmisWriteoffApply emisWriteoffApply);
+
+ /**
+ * 新增
+ *
+ * @param emisWriteoffApply
+ * @return
+ */
+ public int insertEmisWriteoffApply(EmisWriteoffApply emisWriteoffApply);
+
+ /**
+ * 修改
+ *
+ * @param emisWriteoffApply
+ * @return
+ */
+ public int updateEmisWriteoffApply(EmisWriteoffApply emisWriteoffApply);
+
+ /**
+ * 删除
+ *
+ * @param id 主键
+ * @return 结果
+ */
+ public int deleteEmisWriteoffApplyById(Long id);
+
+ /**
+ * 批量删除
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ public int deleteEmisWriteoffApplyByIds(Long[] ids);
+
+ /**
+ * 财务中心审核通过
+ *
+ * @param emisWriteoffApply
+ * @return 结果
+ */
+ public int auditCenterPass(EmisWriteoffApply emisWriteoffApply);
+
+ /**
+ * 根据运单号查询运单、结算账单、结算子账单信息(返回EmisWriteoffApplyDetail列表)
+ *
+ * @param billCodes 运单号列表
+ * @return 销账申请明细集合
+ */
+ public List selectEmisWriteoffApplyDetailListByBillCodes(List billCodes);
+
+ /**
+ * 财务中心审核驳回
+ *
+ * @param emisWriteoffApply
+ * @return 结果
+ */
+ public int auditCenterReject(EmisWriteoffApply emisWriteoffApply);
+
+ /**
+ * 总部确认
+ *
+ * @param emisWriteoffApply
+ * @return 结果
+ */
+ public int auditHeadquartersConfirm(EmisWriteoffApply emisWriteoffApply);
+
+ /**
+ * 总部驳回
+ *
+ * @param emisWriteoffApply
+ * @return 结果
+ */
+ public int auditHeadquartersReject(EmisWriteoffApply emisWriteoffApply);
+
+ /**
+ * 撤销申请
+ *
+ * @param emisWriteoffApply
+ * @return 结果
+ */
+ public int revokeApply(EmisWriteoffApply emisWriteoffApply);
+
+ /**
+ * 再次申请
+ *
+ * @param emisWriteoffApply
+ * @return 结果
+ */
+ public int reapply(EmisWriteoffApply emisWriteoffApply);
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisWriteoffApplyService.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisWriteoffApplyService.java
new file mode 100644
index 000000000..cf9db2796
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/IEmisWriteoffApplyService.java
@@ -0,0 +1,130 @@
+/**
+ * @Project: emis
+ * @Title: IEmisWriteoffApplyService.java
+ * @author heyu
+ * @date 2025-09-15 23:39:28
+ * @Copyright: ShangHai Duta 2022 All rights reserved.
+ * @version v1.0
+ * @Description: 销账申请表 服务类接口
+ */
+package com.xdadan.erp.emis.service;
+
+import java.util.List;
+import com.xdadan.erp.emis.domain.EmisWriteoffApply;
+import com.xdadan.erp.emis.domain.EmisWriteoffApplyDetail;
+import com.xdadan.erp.emis.domain.exception.EmisBizError;
+
+/**
+ * @ClassName IEmisWriteoffApplyService
+ * @Description 销账申请表
+ * @author 何宇
+ * @date 2025-09-16 10:00:00
+ */
+public interface IEmisWriteoffApplyService {
+ /**
+ * 主键查询
+ *
+ * @param id
+ * @return
+ */
+ public EmisWriteoffApply selectEmisWriteoffApplyById(Long id);
+
+ /**
+ * 查询销账申请列表
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 销账申请集合
+ */
+ public List selectEmisWriteoffApplyList(EmisWriteoffApply emisWriteoffApply);
+
+ /**
+ * 新增销账申请
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 结果
+ */
+ public int insertEmisWriteoffApply(EmisWriteoffApply emisWriteoffApply) throws EmisBizError;
+
+ /**
+ * 修改销账申请
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 结果
+ */
+ public int updateEmisWriteoffApply(EmisWriteoffApply emisWriteoffApply) throws EmisBizError;
+
+ /**
+ * 批量删除销账申请
+ * 仅支持删除已撤销的数据,审核中以及审核完成的数据不支持删除
+ *
+ * @param ids 需要删除的销账申请主键集合
+ * @return 结果
+ */
+ public int deleteEmisWriteoffApplyByIds(Long[] ids) throws EmisBizError;
+
+ /**
+ * 删除销账申请信息
+ * 仅支持删除已撤销的数据,审核中以及审核完成的数据不支持删除
+ *
+ * @param id 销账申请主键
+ * @return 结果
+ */
+ public int deleteEmisWriteoffApplyById(Long id) throws EmisBizError;
+
+ /**
+ * 财务中心审核通过(支持单个和批量)
+ *
+ * @param emisWriteoffApply 销账申请(单个操作时传入完整对象,批量操作时传入包含ids的对象)
+ * @return 结果
+ */
+ public int auditCenterPass(EmisWriteoffApply emisWriteoffApply) throws EmisBizError;
+
+ /**
+ * 财务中心审核驳回(支持单个和批量)
+ *
+ * @param emisWriteoffApply 销账申请(单个操作时传入完整对象,批量操作时传入包含ids的对象)
+ * @return 结果
+ */
+ public int auditCenterReject(EmisWriteoffApply emisWriteoffApply) throws EmisBizError;
+
+ /**
+ * 总部确认(支持单个和批量)
+ *
+ * @param emisWriteoffApply 销账申请(单个操作时传入完整对象,批量操作时传入包含ids的对象)
+ * @return 结果
+ */
+ public int auditHeadquartersConfirm(EmisWriteoffApply emisWriteoffApply) throws EmisBizError;
+
+ /**
+ * 总部驳回(支持单个和批量)
+ *
+ * @param emisWriteoffApply 销账申请(单个操作时传入完整对象,批量操作时传入包含ids的对象)
+ * @return 结果
+ */
+ public int auditHeadquartersReject(EmisWriteoffApply emisWriteoffApply) throws EmisBizError;
+
+ /**
+ * 撤销申请(支持单个和批量)
+ *
+ * @param emisWriteoffApply 销账申请(单个操作时传入完整对象,批量操作时传入包含ids的对象)
+ * @return 结果
+ */
+ public int revokeApply(EmisWriteoffApply emisWriteoffApply) throws EmisBizError;
+
+ /**
+ * 再次申请
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 结果
+ */
+ public int reapply(EmisWriteoffApply emisWriteoffApply) throws EmisBizError;
+
+ /**
+ * 根据运单号查询运单、结算账单、结算子账单信息(返回EmisWriteoffApplyDetail列表)
+ *
+ * @param billCodes 运单号列表
+ * @return 销账申请明细集合
+ */
+ public List selectEmisWriteoffApplyDetailListByBillCodes(List billCodes);
+
+}
diff --git a/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisWriteoffApplyServiceImpl.java b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisWriteoffApplyServiceImpl.java
new file mode 100644
index 000000000..e9165894c
--- /dev/null
+++ b/emis-biz/src/main/java/com/xdadan/erp/emis/service/impl/EmisWriteoffApplyServiceImpl.java
@@ -0,0 +1,1110 @@
+/**
+ * @Project: emis
+ * @Title: EmisWriteoffApplyServiceImpl.java
+ * @author heyu
+ * @date 2025-09-15 23:39:28
+ * @Copyright: ShangHai Duta 2022 All rights reserved.
+ * @version v1.0
+ * @Description: 销账申请表 实体类
+ */
+
+package com.xdadan.erp.emis.service.impl;
+
+import java.math.BigDecimal;
+import java.util.*;
+import java.util.HashSet;
+import java.util.Set;
+
+import com.xdadan.erp.common.core.domain.entity.SysUser;
+import com.xdadan.erp.common.utils.SecurityUtils;
+import com.xdadan.erp.emis.domain.*;
+import com.xdadan.erp.emis.domain.enumtype.WriteoffApplyStatus;
+import com.xdadan.erp.emis.domain.exception.EmisBizError;
+import com.xdadan.erp.emis.mapper.*;
+import com.xdadan.erp.emis.service.*;
+import jodd.util.StringUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 销账申请Service业务层处理
+ *
+ * @author 何宇
+ * @date 2025-09-16 10:00:00
+ */
+@Service
+@Slf4j
+public class EmisWriteoffApplyServiceImpl implements IEmisWriteoffApplyService {
+ @Autowired
+ private EmisWriteoffApplyMapper emisWriteoffApplyMapper;
+
+ @Autowired
+ private EmisWriteoffApplyDetailMapper emisWriteoffApplyDetailMapper;
+
+ @Autowired
+ private EmisWriteoffApplyImageMapper emisWriteoffApplyImageMapper;
+
+ @Autowired
+ private EmisWaybillMapper emisWaybillMapper;
+
+ @Autowired
+ private EmisSettleSubBillMapper emisSettleSubBillMapper;
+
+ @Autowired
+ private EmisSettleBillMapper emisSettleBillMapper;
+
+ // 以下Mapper用于关联业务数据处理,暂时注释避免编译警告
+ // @Autowired
+ // private EmisSettlePayRecordMapper emisSettlePayRecordMapper;
+
+ @Autowired
+ private IEmisCreditCustomerService emisCreditCustomerService;
+
+ @Autowired
+ private IEmisCreditSalesmenService emisCreditSalesmenService;
+
+ /**
+ * 查询销账申请
+ *
+ * @param id 销账申请主键
+ * @return 销账申请
+ */
+ @Override
+ public EmisWriteoffApply selectEmisWriteoffApplyById(Long id) {
+ EmisWriteoffApply apply = emisWriteoffApplyMapper.selectEmisWriteoffApplyById(id);
+ if (apply != null) {
+ // 查询明细列表
+ List detailList = emisWriteoffApplyDetailMapper
+ .selectEmisWriteoffApplyDetailListByApplyId(id);
+ apply.setDetailList(detailList);
+
+ // 查询图片列表
+ List imageList = emisWriteoffApplyImageMapper
+ .selectEmisWriteoffApplyImageListByApplyId(id);
+ apply.setImageList(imageList);
+ }
+ return apply;
+ }
+
+ /**
+ * 查询销账申请列表
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 销账申请
+ */
+ @Override
+ public List selectEmisWriteoffApplyList(EmisWriteoffApply emisWriteoffApply) {
+ return emisWriteoffApplyMapper.selectEmisWriteoffApplyList(emisWriteoffApply);
+ }
+
+ /**
+ * 验证销账金额
+ * 销账金额 = 各个运单的applyMoney的和
+ * 验证:申请金额+已收金额 <= 运单应收金额
+ */
+ private void validateWriteoffAmount(EmisWriteoffApply emisWriteoffApply) throws EmisBizError {
+ if (CollectionUtils.isEmpty(emisWriteoffApply.getDetailList())) {
+ throw new EmisBizError("销账申请明细不能为空");
+ }
+
+ BigDecimal totalApplyAmount = BigDecimal.ZERO;
+
+ for (EmisWriteoffApplyDetail detail : emisWriteoffApply.getDetailList()) {
+ if (detail.getApplyMoney() == null) {
+ throw new EmisBizError("运单号 " + detail.getBillCode() + " 的申请金额不能为空");
+ }
+ totalApplyAmount = totalApplyAmount.add(detail.getApplyMoney());
+
+ // 查询运单信息
+ EmisWaybill waybill = emisWaybillMapper.selectEmisWaybillByBillCode(detail.getBillCode());
+ if (waybill == null) {
+ throw new EmisBizError("运单号 " + detail.getBillCode() + " 不存在");
+ }
+
+ // 查询已收金额
+ BigDecimal receivedAmount = detail.getEmisSettleSubBill().getRecedMoney();
+ if (receivedAmount == null) {
+ receivedAmount = BigDecimal.ZERO;
+ }
+
+ // 验证:申请金额 + 已收金额 <= 运单应收金额
+ BigDecimal totalAmount = detail.getApplyMoney().add(receivedAmount);
+ if (totalAmount.compareTo(waybill.getFreight()) > 0) {
+ throw new EmisBizError("运单号 " + detail.getBillCode() + " 的申请金额(" +
+ detail.getApplyMoney() + ") + 已收金额(" + receivedAmount + ") = " +
+ totalAmount + " 超过运单应收金额(" + waybill.getFreight() + ")");
+ }
+ }
+
+ // 验证总销账金额
+ if (emisWriteoffApply.getWriteoffAmount() == null ||
+ emisWriteoffApply.getWriteoffAmount().compareTo(totalApplyAmount) != 0) {
+ throw new EmisBizError("销账金额(" + emisWriteoffApply.getWriteoffAmount() +
+ ") 必须等于各运单申请金额之和(" + totalApplyAmount + ")");
+ }
+ }
+
+ /**
+ * 新增销账申请
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int insertEmisWriteoffApply(EmisWriteoffApply emisWriteoffApply) throws EmisBizError {
+ try {
+ // 先验证销账金额
+ validateWriteoffAmount(emisWriteoffApply);
+
+ // 设置申请编号
+ String applyNo = generateApplyNo();
+ emisWriteoffApply.setApplyNo(applyNo);
+
+ // 设置申请人信息
+ SysUser currentUser = SecurityUtils.getLoginUser().getUser();
+ emisWriteoffApply.setApplyManCode(currentUser.getEmpCode());
+ emisWriteoffApply.setApplyManName(currentUser.getEmpName());
+ emisWriteoffApply.setApplyDate(new Date());
+
+ // 设置初始状态
+ emisWriteoffApply.setBlCenterConfirmed(WriteoffApplyStatus.CENTER_PENDING.statusCode);
+ emisWriteoffApply.setBlHeadquartersConfirmed(WriteoffApplyStatus.CENTER_PENDING.statusCode);
+
+ // 插入主表
+ int result = emisWriteoffApplyMapper.insertEmisWriteoffApply(emisWriteoffApply);
+
+ // 插入明细表
+ if (CollectionUtils.isNotEmpty(emisWriteoffApply.getDetailList())) {
+ for (EmisWriteoffApplyDetail detail : emisWriteoffApply.getDetailList()) {
+ detail.setApplyId(emisWriteoffApply.getId());
+ detail.setApplyNo(applyNo);
+ if (StringUtil.isBlank(detail.getEmisSettleSubBill().getSettleBillNo())) {
+ throw new EmisBizError("账单不存在");
+ }
+ emisWriteoffApplyDetailMapper.insertEmisWriteoffApplyDetail(detail);
+ }
+ }
+
+ // 插入图片表
+ if (CollectionUtils.isNotEmpty(emisWriteoffApply.getImageList())) {
+ for (EmisWriteoffApplyImage image : emisWriteoffApply.getImageList()) {
+ image.setApplyId(emisWriteoffApply.getId());
+ image.setApplyNo(applyNo);
+ image.setUploadManCode(currentUser.getEmpCode());
+ image.setUploadManName(currentUser.getEmpName());
+ image.setUploadDate(new Date());
+ emisWriteoffApplyImageMapper.insertEmisWriteoffApplyImage(image);
+ }
+ }
+
+ return result;
+ } catch (Exception e) {
+ log.error("新增销账申请失败", e);
+ throw new EmisBizError("新增销账申请失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 修改销账申请
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int updateEmisWriteoffApply(EmisWriteoffApply emisWriteoffApply) throws EmisBizError {
+
+ // 先验证销账金额
+ validateWriteoffAmount(emisWriteoffApply);
+
+ // 更新主表
+ int result = emisWriteoffApplyMapper.updateEmisWriteoffApply(emisWriteoffApply);
+
+ // 更新明细表
+ if (CollectionUtils.isNotEmpty(emisWriteoffApply.getDetailList())) {
+ // 先删除原有明细
+ emisWriteoffApplyDetailMapper.deleteEmisWriteoffApplyDetailByApplyId(emisWriteoffApply.getId());
+ // 重新插入明细
+ for (EmisWriteoffApplyDetail detail : emisWriteoffApply.getDetailList()) {
+ detail.setApplyId(emisWriteoffApply.getId());
+ detail.setApplyNo(emisWriteoffApply.getApplyNo());
+ emisWriteoffApplyDetailMapper.insertEmisWriteoffApplyDetail(detail);
+ }
+ }
+
+ // 更新图片表
+ if (CollectionUtils.isNotEmpty(emisWriteoffApply.getImageList())) {
+ // 先删除原有图片
+ emisWriteoffApplyImageMapper.deleteEmisWriteoffApplyImageByApplyId(emisWriteoffApply.getId());
+ // 重新插入图片
+ SysUser currentUser = SecurityUtils.getLoginUser().getUser();
+ for (EmisWriteoffApplyImage image : emisWriteoffApply.getImageList()) {
+ image.setApplyId(emisWriteoffApply.getId());
+ image.setApplyNo(emisWriteoffApply.getApplyNo());
+ image.setUploadManCode(currentUser.getEmpCode());
+ image.setUploadManName(currentUser.getEmpName());
+ image.setUploadDate(new Date());
+ emisWriteoffApplyImageMapper.insertEmisWriteoffApplyImage(image);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * 批量删除销账申请
+ * 仅支持删除已撤销的数据,审核中以及审核完成的数据不支持删除
+ *
+ * @param ids 需要删除的销账申请主键集合
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int deleteEmisWriteoffApplyByIds(Long[] ids) throws EmisBizError {
+ // 检查每个申请的状态,只允许删除已撤销的数据
+ for (Long id : ids) {
+ EmisWriteoffApply apply = emisWriteoffApplyMapper.selectEmisWriteoffApplyById(id);
+ if (apply == null) {
+ throw new EmisBizError("申请不存在,ID: " + id);
+ }
+
+ // 检查中心审核状态,只有已撤销(3)状态才能删除
+ if (!WriteoffApplyStatus.REVOKED.statusCode.equals(apply.getBlCenterConfirmed())) {
+ String statusName = getStatusName(apply.getBlCenterConfirmed());
+ throw new EmisBizError("申请ID " + id + " 状态为" + statusName + ",仅支持删除已撤销的数据");
+ }
+ }
+
+ // 执行删除操作
+ for (Long id : ids) {
+ // 删除明细
+ emisWriteoffApplyDetailMapper.deleteEmisWriteoffApplyDetailByApplyId(id);
+ // 删除图片
+ emisWriteoffApplyImageMapper.deleteEmisWriteoffApplyImageByApplyId(id);
+ }
+ return emisWriteoffApplyMapper.deleteEmisWriteoffApplyByIds(ids);
+ }
+
+ /**
+ * 删除销账申请信息
+ * 仅支持删除已撤销的数据,审核中以及审核完成的数据不支持删除
+ *
+ * @param id 销账申请主键
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int deleteEmisWriteoffApplyById(Long id) throws EmisBizError {
+ // 检查申请状态,只允许删除已撤销的数据
+ EmisWriteoffApply apply = emisWriteoffApplyMapper.selectEmisWriteoffApplyById(id);
+ if (apply == null) {
+ throw new EmisBizError("申请不存在,ID: " + id);
+ }
+
+ // 检查中心审核状态,只有已撤销(3)状态才能删除
+ if (!WriteoffApplyStatus.REVOKED.statusCode.equals(apply.getBlCenterConfirmed())) {
+ String statusName = getStatusName(apply.getBlCenterConfirmed());
+ throw new EmisBizError("申请ID " + id + " 状态为" + statusName + ",仅支持删除已撤销的数据");
+ }
+
+ // 删除明细
+ emisWriteoffApplyDetailMapper.deleteEmisWriteoffApplyDetailByApplyId(id);
+ // 删除图片
+ emisWriteoffApplyImageMapper.deleteEmisWriteoffApplyImageByApplyId(id);
+ return emisWriteoffApplyMapper.deleteEmisWriteoffApplyById(id);
+ }
+
+ /**
+ * 财务中心审核通过
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int auditCenterPass(EmisWriteoffApply emisWriteoffApply) throws EmisBizError {
+ try {
+ // 检查申请状态
+ EmisWriteoffApply existingApply = emisWriteoffApplyMapper
+ .selectEmisWriteoffApplyById(emisWriteoffApply.getId());
+ if (existingApply == null) {
+ throw new EmisBizError("申请不存在");
+ }
+ if (!WriteoffApplyStatus.CENTER_PENDING.statusCode.equals(existingApply.getBlCenterConfirmed())) {
+ throw new EmisBizError("已审核/已撤销");
+ }
+
+ // 设置审核信息
+ SysUser currentUser = SecurityUtils.getLoginUser().getUser();
+ emisWriteoffApply.setBlCenterConfirmed(WriteoffApplyStatus.CENTER_APPROVED.statusCode);
+ emisWriteoffApply.setCenterConfirmManCode(currentUser.getEmpCode());
+ emisWriteoffApply.setCenterConfirmManName(currentUser.getEmpName());
+ emisWriteoffApply.setCenterConfirmDate(new Date());
+
+ // 更新申请状态
+ int result = emisWriteoffApplyMapper.auditCenterPass(emisWriteoffApply);
+
+ // 更新相关业务数据
+ List detailList = updateRelatedBusinessData(existingApply, true);
+
+ // 重算并更新月结客户额度和现金客户额度
+ updateCreditLimits(existingApply, detailList);
+
+ return result;
+ } catch (Exception e) {
+ log.error("财务中心审核通过失败", e);
+ throw new EmisBizError("财务中心审核通过失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 财务中心审核驳回
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int auditCenterReject(EmisWriteoffApply emisWriteoffApply) throws EmisBizError {
+ try {
+ // 检查申请状态
+ EmisWriteoffApply existingApply = emisWriteoffApplyMapper
+ .selectEmisWriteoffApplyById(emisWriteoffApply.getId());
+ if (existingApply == null) {
+ throw new EmisBizError("申请不存在");
+ }
+ if (!WriteoffApplyStatus.CENTER_PENDING.statusCode.equals(existingApply.getBlCenterConfirmed())) {
+ throw new EmisBizError("已审核/已撤销");
+ }
+
+ // 设置审核信息
+ SysUser currentUser = SecurityUtils.getLoginUser().getUser();
+ emisWriteoffApply.setBlCenterConfirmed(WriteoffApplyStatus.CENTER_REJECTED.statusCode);
+ emisWriteoffApply.setCenterConfirmManCode(currentUser.getEmpCode());
+ emisWriteoffApply.setCenterConfirmManName(currentUser.getEmpName());
+ emisWriteoffApply.setCenterConfirmDate(new Date());
+
+ // 更新申请状态
+ int result = emisWriteoffApplyMapper.auditCenterReject(emisWriteoffApply);
+
+ return result;
+ } catch (Exception e) {
+ log.error("财务中心审核驳回失败", e);
+ throw new EmisBizError("财务中心审核驳回失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 总部确认
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int auditHeadquartersConfirm(EmisWriteoffApply emisWriteoffApply) throws EmisBizError {
+ try {
+ // 检查申请状态
+ EmisWriteoffApply existingApply = emisWriteoffApplyMapper
+ .selectEmisWriteoffApplyById(emisWriteoffApply.getId());
+ if (existingApply == null) {
+ throw new EmisBizError("申请不存在");
+ }
+ if (!WriteoffApplyStatus.CENTER_APPROVED.statusCode.equals(existingApply.getBlCenterConfirmed())) {
+ throw new EmisBizError("财务未审核,无法确认");
+ }
+ if (WriteoffApplyStatus.HEADQUARTERS_CONFIRMED.statusCode
+ .equals(existingApply.getBlHeadquartersConfirmed())) {
+ throw new EmisBizError("已确认");
+ }
+ if (WriteoffApplyStatus.HEADQUARTERS_REJECTED.statusCode
+ .equals(existingApply.getBlHeadquartersConfirmed())) {
+ throw new EmisBizError("已驳回,无法确认");
+ }
+
+ // 设置确认信息
+ SysUser currentUser = SecurityUtils.getLoginUser().getUser();
+ emisWriteoffApply.setBlHeadquartersConfirmed(WriteoffApplyStatus.HEADQUARTERS_CONFIRMED.statusCode);
+ emisWriteoffApply.setHeadquartersConfirmManCode(currentUser.getEmpCode());
+ emisWriteoffApply.setHeadquartersConfirmManName(currentUser.getEmpName());
+ emisWriteoffApply.setHeadquartersConfirmDate(new Date());
+
+ // 更新申请状态
+ int result = emisWriteoffApplyMapper.auditHeadquartersConfirm(emisWriteoffApply);
+
+ return result;
+ } catch (Exception e) {
+ log.error("总部确认失败", e);
+ throw new EmisBizError("总部确认失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 总部驳回
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int auditHeadquartersReject(EmisWriteoffApply emisWriteoffApply) throws EmisBizError {
+ try {
+ // 检查申请状态
+ EmisWriteoffApply existingApply = emisWriteoffApplyMapper
+ .selectEmisWriteoffApplyById(emisWriteoffApply.getId());
+ if (existingApply == null) {
+ throw new EmisBizError("申请不存在");
+ }
+ if (!WriteoffApplyStatus.CENTER_APPROVED.statusCode.equals(existingApply.getBlCenterConfirmed())) {
+ throw new EmisBizError("财务未审核,无法确认");
+ }
+ if (WriteoffApplyStatus.HEADQUARTERS_CONFIRMED.statusCode
+ .equals(existingApply.getBlHeadquartersConfirmed())) {
+ throw new EmisBizError("已确认,无法驳回");
+ }
+ if (WriteoffApplyStatus.HEADQUARTERS_REJECTED.statusCode
+ .equals(existingApply.getBlHeadquartersConfirmed())) {
+ throw new EmisBizError("已驳回");
+ }
+
+ // 设置驳回信息
+ SysUser currentUser = SecurityUtils.getLoginUser().getUser();
+ emisWriteoffApply.setBlHeadquartersConfirmed(WriteoffApplyStatus.HEADQUARTERS_REJECTED.statusCode);
+ emisWriteoffApply.setHeadquartersConfirmManCode(currentUser.getEmpCode());
+ emisWriteoffApply.setHeadquartersConfirmManName(currentUser.getEmpName());
+ emisWriteoffApply.setHeadquartersConfirmDate(new Date());
+
+ // 更新申请状态
+ int result = emisWriteoffApplyMapper.auditHeadquartersReject(emisWriteoffApply);
+
+ // 回退相关业务数据
+ List detailList = rollbackRelatedBusinessData(existingApply);
+
+ // 重算并更新月结客户额度和现金客户额度
+ updateCreditLimits(existingApply, detailList);
+
+ return result;
+ } catch (Exception e) {
+ log.error("总部驳回失败", e);
+ throw new EmisBizError("总部驳回失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 撤销申请
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int revokeApply(EmisWriteoffApply emisWriteoffApply) throws EmisBizError {
+ try {
+ // 检查申请状态
+ EmisWriteoffApply existingApply = emisWriteoffApplyMapper
+ .selectEmisWriteoffApplyById(emisWriteoffApply.getId());
+ if (existingApply == null) {
+ throw new EmisBizError("申请不存在");
+ }
+ if (!WriteoffApplyStatus.CENTER_PENDING.statusCode
+ .equals(existingApply.getBlCenterConfirmed())
+ || !WriteoffApplyStatus.HEADQUARTERS_PENDING.statusCode
+ .equals(existingApply.getBlHeadquartersConfirmed())) {
+ throw new EmisBizError("已审核/撤销完成,无法撤销");
+ }
+
+ // 设置撤销信息
+ SysUser currentUser = SecurityUtils.getLoginUser().getUser();
+ emisWriteoffApply.setBlCenterConfirmed(WriteoffApplyStatus.REVOKED.statusCode);
+ emisWriteoffApply.setRevokeManCode(currentUser.getEmpCode());
+ emisWriteoffApply.setRevokeManName(currentUser.getEmpName());
+ emisWriteoffApply.setRevokeDate(new Date());
+
+ // 更新申请状态
+ int result = emisWriteoffApplyMapper.revokeApply(emisWriteoffApply);
+
+ return result;
+ } catch (Exception e) {
+ log.error("撤销申请失败", e);
+ throw new EmisBizError("撤销申请失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 再次申请
+ *
+ * @param emisWriteoffApply 销账申请
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int reapply(EmisWriteoffApply emisWriteoffApply) throws EmisBizError {
+ try {
+ // 检查申请状态
+ EmisWriteoffApply existingApply = emisWriteoffApplyMapper
+ .selectEmisWriteoffApplyById(emisWriteoffApply.getId());
+ if (existingApply == null) {
+ throw new EmisBizError("申请不存在");
+ }
+ if (!WriteoffApplyStatus.REVOKED.statusCode.equals(existingApply.getBlCenterConfirmed()) &&
+ !WriteoffApplyStatus.CENTER_REJECTED.statusCode.equals(existingApply.getBlCenterConfirmed())) {
+ throw new EmisBizError("申请状态不正确,无法再次申请");
+ }
+
+ // 重置状态
+ emisWriteoffApply.setBlCenterConfirmed(WriteoffApplyStatus.CENTER_PENDING.statusCode);
+ emisWriteoffApply.setBlHeadquartersConfirmed(WriteoffApplyStatus.CENTER_PENDING.statusCode);
+ emisWriteoffApply.setCenterConfirmManCode(null);
+ emisWriteoffApply.setCenterConfirmManName(null);
+ emisWriteoffApply.setCenterConfirmDate(null);
+ emisWriteoffApply.setCenterConfirmNote(null);
+ emisWriteoffApply.setCenterRejectReason(null);
+ emisWriteoffApply.setHeadquartersConfirmManCode(null);
+ emisWriteoffApply.setHeadquartersConfirmManName(null);
+ emisWriteoffApply.setHeadquartersConfirmDate(null);
+ emisWriteoffApply.setHeadquartersConfirmNote(null);
+ emisWriteoffApply.setHeadquartersRejectReason(null);
+ emisWriteoffApply.setRevokeManCode(null);
+ emisWriteoffApply.setRevokeManName(null);
+ emisWriteoffApply.setRevokeDate(null);
+ emisWriteoffApply.setRevokeReason(null);
+
+ // 更新申请
+ int result = emisWriteoffApplyMapper.reapply(emisWriteoffApply);
+
+ return result;
+ } catch (Exception e) {
+ log.error("再次申请失败", e);
+ throw new EmisBizError("再次申请失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 生成申请编号
+ */
+ private String generateApplyNo() {
+ return "XZ" + System.currentTimeMillis();
+ }
+
+ /**
+ * 更新相关业务数据
+ *
+ * @return 申请明细列表
+ */
+ private List updateRelatedBusinessData(EmisWriteoffApply apply, boolean isPass)
+ throws EmisBizError {
+ try {
+ log.info("开始更新相关业务数据,申请ID: {}, 是否通过: {}", apply.getId(), isPass);
+
+ // 获取申请明细
+ List detailList = emisWriteoffApplyDetailMapper
+ .selectEmisWriteoffApplyDetailListByApplyId(apply.getId());
+ if (CollectionUtils.isEmpty(detailList)) {
+ log.warn("申请明细为空,申请ID: {}", apply.getId());
+ return detailList;
+ }
+
+ // 按settleBillNo分组处理明细
+ Map> groupedDetails = detailList.stream()
+ .filter(detail -> StringUtil.isNotBlank(detail.getSettleBillNo()))
+ .collect(java.util.stream.Collectors.groupingBy(EmisWriteoffApplyDetail::getSettleBillNo));
+
+ // 处理每个结算账单的销账
+ for (Map.Entry> entry : groupedDetails.entrySet()) {
+ String settleBillNo = entry.getKey();
+ List billDetails = entry.getValue();
+
+ // 计算该结算账单的总申请金额
+ BigDecimal totalApplyMoney = billDetails.stream()
+ .map(EmisWriteoffApplyDetail::getApplyMoney)
+ .filter(Objects::nonNull)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+ // 更新结算账单的收款状态和已收金额
+ updateSettleBillPaymentStatus(settleBillNo, totalApplyMoney, isPass);
+
+ // 处理每个明细(只支持运单号类型)
+ for (EmisWriteoffApplyDetail detail : billDetails) {
+ processWaybillWriteoff(detail, apply, isPass);
+ }
+ }
+
+ log.info("相关业务数据更新完成,申请ID: {}", apply.getId());
+ return detailList;
+ } catch (Exception e) {
+ log.error("更新相关业务数据失败,申请ID: {}", apply.getId(), e);
+ throw new EmisBizError("更新相关业务数据失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 处理运单销账(唯一支持的销账类型)
+ */
+ private void processWaybillWriteoff(EmisWriteoffApplyDetail detail, EmisWriteoffApply apply, boolean isPass)
+ throws EmisBizError {
+ String billCode = detail.getBillCode();
+ if (billCode == null || billCode.trim().isEmpty()) {
+ return;
+ }
+
+ // 获取运单信息
+ EmisWaybill waybill = emisWaybillMapper.selectEmisWaybillByBillCode(billCode);
+ if (waybill == null) {
+ throw new EmisBizError("运单不存在:" + billCode);
+ }
+
+ // 验证申请金额
+ BigDecimal waybillAmount = waybill.getFreight(); // 运单应收金额
+ BigDecimal applyAmount = detail.getApplyMoney(); // 申请销账金额(从明细获取)
+ BigDecimal receivedAmount = detail.getEmisSettleSubBill().getRecedMoney() != null
+ ? detail.getEmisSettleSubBill().getRecedMoney()
+ : BigDecimal.ZERO; // 已收金额
+
+ // 验证:申请金额 + 已收金额 <= 运单金额
+ BigDecimal totalAmount = applyAmount.add(receivedAmount);
+ if (totalAmount.compareTo(waybillAmount) > 0) {
+ throw new EmisBizError("申请金额+已收金额(" + totalAmount + ")超过运单应收金额(" + waybillAmount + ")");
+ }
+
+ // 获取运单对应的子账单
+ List subBillList = emisSettleSubBillMapper.selectSettleSubBillListByBillCode(billCode);
+ if (CollectionUtils.isEmpty(subBillList)) {
+ log.warn("运单{}没有对应的子账单", billCode);
+ return;
+ }
+
+ // 更新子账单
+ for (EmisSettleSubBill subBill : subBillList) {
+ updateSubBillForWriteoff(subBill, detail, isPass);
+ }
+
+ }
+
+ /**
+ * 更新子账单销账信息
+ */
+ private void updateSubBillForWriteoff(EmisSettleSubBill subBill, EmisWriteoffApplyDetail detail, boolean isPass) {
+ EmisSettleSubBill updateSubBill = new EmisSettleSubBill();
+ updateSubBill.setId(subBill.getId());
+ updateSubBill.setBillCode(subBill.getBillCode());
+
+ // 获取申请金额(从明细中获取)
+ BigDecimal applyMoney = detail.getApplyMoney();
+
+ if (isPass) {
+ // 审核通过:增加已收金额
+ BigDecimal currentReceived = subBill.getRecedMoney() != null ? subBill.getRecedMoney() : BigDecimal.ZERO;
+ BigDecimal newReceived = currentReceived.add(applyMoney);
+ updateSubBill.setRecedMoney(newReceived);
+
+ // 更新收款状态
+ if (newReceived.compareTo(subBill.getBillFee()) >= 0) {
+ updateSubBill.setPaymentStatus("1"); // 已收款
+ } else {
+ updateSubBill.setPaymentStatus("2"); // 部分收款
+ }
+ } else {
+ // 审核驳回:减少已收金额
+ BigDecimal currentReceived = subBill.getRecedMoney() != null ? subBill.getRecedMoney() : BigDecimal.ZERO;
+ BigDecimal newReceived = currentReceived.subtract(applyMoney);
+ if (newReceived.compareTo(BigDecimal.ZERO) < 0) {
+ newReceived = BigDecimal.ZERO;
+ }
+ updateSubBill.setRecedMoney(newReceived);
+
+ // 更新收款状态
+ if (newReceived.compareTo(BigDecimal.ZERO) == 0) {
+ updateSubBill.setPaymentStatus("0"); // 未收款
+ } else if (newReceived.compareTo(subBill.getBillFee()) >= 0) {
+ updateSubBill.setPaymentStatus("1"); // 已收款
+ } else {
+ updateSubBill.setPaymentStatus("2"); // 部分收款
+ }
+ }
+
+ emisSettleSubBillMapper.updatePayedStatus(updateSubBill);
+ log.info("更新子账单销账信息,运单号: {}, 已收金额: {}", subBill.getBillCode(), updateSubBill.getRecedMoney());
+ }
+
+ /**
+ * 更新结算账单的收款状态和已收金额
+ */
+ private void updateSettleBillPaymentStatus(String settleBillNo, BigDecimal applyMoney, boolean isPass)
+ throws EmisBizError {
+ try {
+ log.info("更新结算账单收款状态,账单号: {}, 申请金额: {}, 是否通过: {}", settleBillNo, applyMoney, isPass);
+
+ // 获取结算账单信息
+ EmisSettleBill settleBill = emisSettleBillMapper.selectSettleBillBySettleBillNo(settleBillNo);
+ if (settleBill == null) {
+ log.warn("结算账单不存在,账单号: {}", settleBillNo);
+ return;
+ }
+
+ if (isPass) {
+ // 通过销账申请,增加已收金额
+ BigDecimal currentRecedMoney = settleBill.getRecedMoney() != null ? settleBill.getRecedMoney()
+ : BigDecimal.ZERO;
+ BigDecimal newRecedMoney = currentRecedMoney.add(applyMoney);
+
+ // 更新结算账单
+ EmisSettleBill updateBill = new EmisSettleBill();
+ updateBill.setId(settleBill.getId());
+ updateBill.setRecedMoney(newRecedMoney);
+
+ // 根据已收金额和应收金额比较,设置收款状态
+ BigDecimal recMoney = settleBill.getRecMoney() != null ? settleBill.getRecMoney() : BigDecimal.ZERO;
+ if (newRecedMoney.compareTo(BigDecimal.ZERO) == 0) {
+ updateBill.setPaymentStatus("0"); // 未付款
+ } else if (newRecedMoney.compareTo(recMoney) >= 0) {
+ updateBill.setPaymentStatus("1"); // 已付款
+ updateBill.setChargeStatus("1"); // 已核销
+ } else {
+ updateBill.setPaymentStatus("2"); // 部分付款
+ }
+
+ emisSettleBillMapper.updateEmisSettleBill(updateBill);
+ log.info("结算账单收款状态更新成功,账单号: {}, 新已收金额: {}, 收款状态: {}, 核销状态: {}",
+ settleBillNo, newRecedMoney, updateBill.getPaymentStatus(), updateBill.getChargeStatus());
+ } else {
+ // 拒绝销账申请,减少已收金额
+ BigDecimal currentRecedMoney = settleBill.getRecedMoney() != null ? settleBill.getRecedMoney()
+ : BigDecimal.ZERO;
+ BigDecimal newRecedMoney = currentRecedMoney.subtract(applyMoney);
+ if (newRecedMoney.compareTo(BigDecimal.ZERO) < 0) {
+ newRecedMoney = BigDecimal.ZERO;
+ }
+
+ // 更新结算账单
+ EmisSettleBill updateBill = new EmisSettleBill();
+ updateBill.setId(settleBill.getId());
+ updateBill.setRecedMoney(newRecedMoney);
+
+ // 根据已收金额和应收金额比较,设置收款状态
+ BigDecimal recMoney = settleBill.getRecMoney() != null ? settleBill.getRecMoney() : BigDecimal.ZERO;
+ if (newRecedMoney.compareTo(BigDecimal.ZERO) == 0) {
+ updateBill.setPaymentStatus("0"); // 未付款
+ updateBill.setChargeStatus("0"); // 未核销
+ } else if (newRecedMoney.compareTo(recMoney) >= 0) {
+ updateBill.setPaymentStatus("1"); // 已付款
+ updateBill.setChargeStatus("1"); // 已核销
+ } else {
+ updateBill.setPaymentStatus("2"); // 部分付款
+ updateBill.setChargeStatus("0"); // 未核销
+ }
+
+ emisSettleBillMapper.updateEmisSettleBill(updateBill);
+ log.info("结算账单收款状态回退成功,账单号: {}, 新已收金额: {}, 收款状态: {}, 核销状态: {}",
+ settleBillNo, newRecedMoney, updateBill.getPaymentStatus(), updateBill.getChargeStatus());
+ }
+ } catch (Exception e) {
+ log.error("更新结算账单收款状态失败,账单号: {}", settleBillNo, e);
+ throw new EmisBizError("更新结算账单收款状态失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 回退相关业务数据
+ *
+ * @return 申请明细列表
+ */
+ private List rollbackRelatedBusinessData(EmisWriteoffApply apply) throws EmisBizError {
+ try {
+ log.info("开始回退相关业务数据,申请ID: {}", apply.getId());
+
+ // 获取申请明细
+ List detailList = emisWriteoffApplyDetailMapper
+ .selectEmisWriteoffApplyDetailListByApplyId(apply.getId());
+ if (CollectionUtils.isEmpty(detailList)) {
+ log.warn("申请明细为空,申请ID: {}", apply.getId());
+ return detailList;
+ }
+
+ // 按settleBillNo分组处理明细
+ Map> groupedDetails = detailList.stream()
+ .filter(detail -> StringUtil.isNotBlank(detail.getSettleBillNo()))
+ .collect(java.util.stream.Collectors.groupingBy(EmisWriteoffApplyDetail::getSettleBillNo));
+
+ // 处理每个结算账单的销账回退
+ for (Map.Entry> entry : groupedDetails.entrySet()) {
+ String settleBillNo = entry.getKey();
+ List billDetails = entry.getValue();
+
+ // 计算该结算账单的总申请金额
+ BigDecimal totalApplyMoney = billDetails.stream()
+ .map(EmisWriteoffApplyDetail::getApplyMoney)
+ .filter(Objects::nonNull)
+ .reduce(BigDecimal.ZERO, BigDecimal::add);
+
+ // 回退结算账单的收款状态和已收金额
+ rollbackSettleBillPaymentStatus(settleBillNo, totalApplyMoney);
+
+ // 处理每个明细的回退(只支持运单号类型)
+ for (EmisWriteoffApplyDetail detail : billDetails) {
+ rollbackWaybillWriteoff(detail, apply);
+ }
+ }
+
+ log.info("相关业务数据回退完成,申请ID: {}", apply.getId());
+ return detailList;
+ } catch (Exception e) {
+ log.error("回退相关业务数据失败,申请ID: {}", apply.getId(), e);
+ throw new EmisBizError("回退相关业务数据失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 回退结算账单的收款状态和已收金额
+ */
+ private void rollbackSettleBillPaymentStatus(String settleBillNo, BigDecimal applyMoney) throws EmisBizError {
+ try {
+ log.info("回退结算账单收款状态,账单号: {}, 申请金额: {}", settleBillNo, applyMoney);
+
+ // 获取结算账单信息
+ EmisSettleBill settleBill = emisSettleBillMapper.selectSettleBillBySettleBillNo(settleBillNo);
+ if (settleBill == null) {
+ log.warn("结算账单不存在,账单号: {}", settleBillNo);
+ return;
+ }
+
+ // 回退销账申请,减少已收金额
+ BigDecimal currentRecedMoney = settleBill.getRecedMoney() != null ? settleBill.getRecedMoney()
+ : BigDecimal.ZERO;
+ BigDecimal newRecedMoney = currentRecedMoney.subtract(applyMoney);
+ if (newRecedMoney.compareTo(BigDecimal.ZERO) < 0) {
+ newRecedMoney = BigDecimal.ZERO;
+ }
+
+ // 更新结算账单
+ EmisSettleBill updateBill = new EmisSettleBill();
+ updateBill.setId(settleBill.getId());
+ updateBill.setRecedMoney(newRecedMoney);
+
+ // 根据已收金额和应收金额比较,设置收款状态
+ BigDecimal recMoney = settleBill.getRecMoney() != null ? settleBill.getRecMoney() : BigDecimal.ZERO;
+ if (newRecedMoney.compareTo(BigDecimal.ZERO) == 0) {
+ updateBill.setPaymentStatus("0"); // 未付款
+ updateBill.setChargeStatus("0"); // 未核销
+ } else if (newRecedMoney.compareTo(recMoney) >= 0) {
+ updateBill.setPaymentStatus("1"); // 已付款
+ updateBill.setChargeStatus("1"); // 已核销
+ } else {
+ updateBill.setPaymentStatus("2"); // 部分付款
+ updateBill.setChargeStatus("0"); // 未核销
+ }
+
+ emisSettleBillMapper.updateEmisSettleBill(updateBill);
+ log.info("结算账单收款状态回退成功,账单号: {}, 新已收金额: {}, 收款状态: {}, 核销状态: {}",
+ settleBillNo, newRecedMoney, updateBill.getPaymentStatus(), updateBill.getChargeStatus());
+ } catch (Exception e) {
+ log.error("回退结算账单收款状态失败,账单号: {}", settleBillNo, e);
+ throw new EmisBizError("回退结算账单收款状态失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 回退运单销账
+ */
+ private void rollbackWaybillWriteoff(EmisWriteoffApplyDetail detail, EmisWriteoffApply apply) throws EmisBizError {
+ String billCode = detail.getBillCode();
+ if (billCode == null || billCode.trim().isEmpty()) {
+ return;
+ }
+
+ // 获取运单信息
+ EmisWaybill waybill = emisWaybillMapper.selectEmisWaybillByBillCode(billCode);
+ if (waybill == null) {
+ log.warn("运单不存在,运单号: {}", billCode);
+ return;
+ }
+
+ // 获取运单对应的子账单
+ List subBillList = emisSettleSubBillMapper.selectSettleSubBillListByBillCode(billCode);
+ if (CollectionUtils.isEmpty(subBillList)) {
+ log.warn("运单{}没有对应的子账单", billCode);
+ return;
+ }
+
+ // 回退子账单
+ for (EmisSettleSubBill subBill : subBillList) {
+ rollbackSubBillForWriteoff(subBill, detail);
+ }
+ }
+
+ /**
+ * 回退子账单销账信息
+ */
+ private void rollbackSubBillForWriteoff(EmisSettleSubBill subBill, EmisWriteoffApplyDetail detail) {
+ EmisSettleSubBill updateSubBill = new EmisSettleSubBill();
+ updateSubBill.setId(subBill.getId());
+ updateSubBill.setBillCode(subBill.getBillCode());
+
+ // 获取申请金额(从明细中获取)
+ BigDecimal applyMoney = detail.getApplyMoney();
+
+ // 回退销账申请:减少已收金额
+ BigDecimal currentReceived = subBill.getRecedMoney() != null ? subBill.getRecedMoney() : BigDecimal.ZERO;
+ BigDecimal newReceived = currentReceived.subtract(applyMoney);
+ if (newReceived.compareTo(BigDecimal.ZERO) < 0) {
+ newReceived = BigDecimal.ZERO;
+ }
+ updateSubBill.setRecedMoney(newReceived);
+
+ // 更新收款状态
+ if (newReceived.compareTo(BigDecimal.ZERO) == 0) {
+ updateSubBill.setPaymentStatus("0"); // 未收款
+ } else if (newReceived.compareTo(subBill.getBillFee()) >= 0) {
+ updateSubBill.setPaymentStatus("1"); // 已收款
+ } else {
+ updateSubBill.setPaymentStatus("2"); // 部分收款
+ }
+
+ emisSettleSubBillMapper.updatePayedStatus(updateSubBill);
+ log.info("回退子账单销账信息,运单号: {}, 已收金额: {}", subBill.getBillCode(), updateSubBill.getRecedMoney());
+ }
+
+ /**
+ * 根据运单号查询销账申请列表(只返回detailList中的emisWaybill、emisSettleBill、emisSettleSubBill)
+ *
+ * @param billCodes 运单号列表
+ * @return 销账申请集合
+ */
+ @Override
+ public List selectEmisWriteoffApplyDetailListByBillCodes(List billCodes) {
+ if (CollectionUtils.isEmpty(billCodes)) {
+ return new ArrayList<>();
+ }
+ return emisWriteoffApplyMapper.selectEmisWriteoffApplyDetailListByBillCodes(billCodes);
+ }
+
+ /**
+ * 获取状态名称
+ *
+ * @param statusCode 状态代码
+ * @return 状态名称
+ */
+ private String getStatusName(String statusCode) {
+ if (statusCode == null) {
+ return "未知状态";
+ }
+
+ for (WriteoffApplyStatus status : WriteoffApplyStatus.values()) {
+ if (status.statusCode.equals(statusCode)) {
+ return status.statusName;
+ }
+ }
+
+ return "未知状态(" + statusCode + ")";
+ }
+
+ /**
+ * 重算并更新月结客户额度和现金客户额度
+ *
+ * @param apply 销账申请
+ * @param detailList 申请明细列表
+ */
+ private void updateCreditLimits(EmisWriteoffApply apply, List detailList) {
+ try {
+ log.info("开始重算并更新信用额度,申请ID: {}", apply.getId());
+
+ if (CollectionUtils.isEmpty(detailList)) {
+ log.warn("申请明细为空,申请ID: {}", apply.getId());
+ return;
+ }
+
+ // 收集需要更新额度的客户和销售员信息
+ Set customerCodes = new HashSet<>();
+ Set salesmenCodes = new HashSet<>();
+
+ // 遍历明细,获取运单信息
+ for (EmisWriteoffApplyDetail detail : detailList) {
+ if (StringUtil.isNotBlank(detail.getBillCode())) {
+ // 查询运单信息
+ EmisWaybill waybill = emisWaybillMapper.selectEmisWaybillByBillCode(detail.getBillCode());
+ if (waybill != null) {
+ // 收集客户代码
+ if (StringUtil.isNotBlank(waybill.getCustomerCode())) {
+ customerCodes.add(waybill.getCustomerCode());
+ }
+ // 收集销售员代码
+ if (StringUtil.isNotBlank(waybill.getSalesmen())) {
+ salesmenCodes.add(waybill.getSalesmen());
+ }
+ }
+ }
+ }
+
+ // 更新客户信用额度
+ for (String customerCode : customerCodes) {
+ try {
+ updateCustomerCreditLimit(customerCode);
+ } catch (Exception e) {
+ log.error("更新客户信用额度失败,客户代码: {}", customerCode, e);
+ }
+ }
+
+ // 更新销售员信用额度
+ for (String salesmenCode : salesmenCodes) {
+ try {
+ updateSalesmenCreditLimit(salesmenCode);
+ } catch (Exception e) {
+ log.error("更新销售员信用额度失败,销售员代码: {}", salesmenCode, e);
+ }
+ }
+
+ log.info("信用额度重算完成,申请ID: {}", apply.getId());
+ } catch (Exception e) {
+ log.error("重算信用额度失败,申请ID: {}", apply.getId(), e);
+ }
+ }
+
+ /**
+ * 更新客户信用额度
+ *
+ * @param customerCode 客户代码
+ */
+ private void updateCustomerCreditLimit(String customerCode) throws EmisBizError {
+ try {
+ // 查询客户信用额度信息
+ EmisCreditCustomer query = new EmisCreditCustomer();
+ query.setCustomerCode(customerCode);
+ List creditList = emisCreditCustomerService.selectEmisCreditCustomerList(query);
+
+ for (EmisCreditCustomer credit : creditList) {
+ // 调用更新方法,这会触发额度重算
+ emisCreditCustomerService.updateEmisCreditCustomer(credit);
+ log.info("客户信用额度更新成功,客户代码: {}", customerCode);
+ }
+ } catch (Exception e) {
+ log.error("更新客户信用额度失败,客户代码: {}", customerCode, e);
+ throw e;
+ }
+ }
+
+ /**
+ * 更新销售员信用额度
+ *
+ * @param salesmenCode 销售员代码
+ */
+ private void updateSalesmenCreditLimit(String salesmenCode) throws EmisBizError {
+ try {
+ // 查询销售员信用额度信息
+ EmisCreditSalesmen query = new EmisCreditSalesmen();
+ query.setAccCode(salesmenCode);
+ List creditList = emisCreditSalesmenService.selectEmisCreditSalesmenList(query);
+
+ for (EmisCreditSalesmen credit : creditList) {
+ // 调用更新方法,这会触发额度重算
+ emisCreditSalesmenService.updateEmisCreditSalesmen(credit);
+ log.info("销售员信用额度更新成功,销售员代码: {}", salesmenCode);
+ }
+ } catch (Exception e) {
+ log.error("更新销售员信用额度失败,销售员代码: {}", salesmenCode, e);
+ throw e;
+ }
+ }
+}
diff --git a/emis-biz/src/main/resources/mapper/EmisWriteoffApplyDetailMapper.xml b/emis-biz/src/main/resources/mapper/EmisWriteoffApplyDetailMapper.xml
new file mode 100644
index 000000000..562ac31db
--- /dev/null
+++ b/emis-biz/src/main/resources/mapper/EmisWriteoffApplyDetailMapper.xml
@@ -0,0 +1,325 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select wad.id, wad.apply_id, wad.apply_no, wad.bill_code, wad.apply_money, wad.settle_bill_no,
+ w.id as w_id, w.order_sn as w_order_sn, w.cust_order_id as w_cust_order_id, w.bill_code as w_bill_code, w.bill_code_sub as w_bill_code_sub,
+ w.order_status as w_order_status, w.waybill_status as w_waybill_status, w.order_type as w_order_type, w.order_date as w_order_date,
+ w.user_id as w_user_id, w.customer_code as w_customer_code, w.customer_name as w_customer_name, w.open_id as w_open_id,
+ w.receive_name as w_receive_name, w.receive_company as w_receive_company, w.receive_mobile as w_receive_mobile, w.receive_tel as w_receive_tel,
+ w.receive_country as w_receive_country, w.receive_province as w_receive_province, w.receive_city as w_receive_city,
+ w.receive_county as w_receive_county, w.receive_town as w_receive_town, w.receive_address as w_receive_address, w.receive_postcode as w_receive_postcode,
+ w.send_name as w_send_name, w.send_company as w_send_company, w.send_mobile as w_send_mobile, w.send_tel as w_send_tel,
+ w.send_country as w_send_country, w.send_province as w_send_province, w.send_city as w_send_city,
+ w.send_county as w_send_county, w.send_town as w_send_town, w.send_address as w_send_address, w.send_postcode as w_send_postcode,
+ w.freight as w_freight, w.salesmen as w_salesmen, w.payee as w_payee, w.payment_type as w_payment_type, w.product_type as w_product_type,
+ w.parcel_qty as w_parcel_qty, w.bill_weight as w_bill_weight, w.total_volume as w_total_volume, w.send_date as w_send_date,
+ w.dispatch_date as w_dispatch_date, w.sign_man as w_sign_man, w.sign_man_code as w_sign_man_code,
+ w.sign_site_code as w_sign_site_code, w.sign_date as w_sign_date, w.timezone_offset as w_timezone_offset, w.payment_status as w_payment_status,
+ w.payment_date as w_payment_date, w.payment_remark as w_payment_remark, w.order_remark as w_order_remark, w.data_from as w_data_from,
+ w.bl_special_goods as w_bl_special_goods, w.ext_info as w_ext_info, w.lading_bill_code as w_lading_bill_code, w.company_code as w_company_code,
+ w.departure_port as w_departure_port, w.destination_port as w_destination_port, w.box_quantity as w_box_quantity,
+ sb.id as sb_id, sb.settle_bill_no as sb_settle_bill_no, sb.settle_bill_name as sb_settle_bill_name, sb.settle_type as sb_settle_type,
+ sb.settle_start_date as sb_settle_start_date, sb.settle_end_date as sb_settle_end_date, sb.bill_month as sb_bill_month,
+ sb.rec_money as sb_rec_money, sb.reced_money as sb_reced_money, sb.invoiced_money as sb_invoiced_money, sb.cust_no as sb_cust_no,
+ sb.cust_name as sb_cust_name, sb.customer_code as sb_customer_code, sb.customer_name as sb_customer_name, sb.site_code as sb_site_code,
+ sb.site_name as sb_site_name, sb.satisfy_money as sb_satisfy_money, sb.allowance_money as sb_allowance_money, sb.deduction_money as sb_deduction_money,
+ sb.other_money as sb_other_money, sb.satisfy_reason as sb_satisfy_reason, sb.allowance_reason as sb_allowance_reason,
+ sb.deduction_reason as sb_deduction_reason, sb.other_reason as sb_other_reason, sb.open_bill_status as sb_open_bill_status,
+ sb.payment_status as sb_payment_status, sb.charge_status as sb_charge_status, sb.send_piece_sum as sb_send_piece_sum,
+ sb.piece_number as sb_piece_number, sb.fee_weight as sb_fee_weight, sb.uncollected_amount as sb_uncollected_amount,
+ sb.send_money_sum as sb_send_money_sum, sb.refund_amount as sb_refund_amount, sb.refund_money as sb_refund_money,
+ sb.payee as sb_payee, sb.salesmen as sb_salesmen, sb.credit_period as sb_credit_period, sb.credit_period_type as sb_credit_period_type,
+ sb.settle_day as sb_settle_day, sb.payment_due_date as sb_payment_due_date, sb.bl_send_oms as sb_bl_send_oms,
+ sb.bl_confirm_center as sb_bl_confirm_center, sb.confirm_center_date as sb_confirm_center_date, sb.confirm_center_note as sb_confirm_center_note,
+ sb.confirm_center_man_code as sb_confirm_center_man_code, sb.confirm_center_code as sb_confirm_center_code,
+ sb.bl_confirm_site as sb_bl_confirm_site, sb.confirm_site_date as sb_confirm_site_date, sb.confirm_site_man_code as sb_confirm_site_man_code,
+ sb.confirm_site_note as sb_confirm_site_note, sb.confirm_site_code as sb_confirm_site_code,
+ ssb.id as ssb_id, ssb.bill_no as ssb_bill_no, ssb.parent_bill_no as ssb_parent_bill_no, ssb.settle_bill_no as ssb_settle_bill_no,
+ ssb.bill_code as ssb_bill_code, ssb.bill_date as ssb_bill_date, ssb.bill_fee as ssb_bill_fee, ssb.currency as ssb_currency,
+ ssb.settle_type as ssb_settle_type, ssb.bl_split as ssb_bl_split, ssb.bl_merge as ssb_bl_merge, ssb.bill_month as ssb_bill_month,
+ ssb.cust_no as ssb_cust_no, ssb.cust_name as ssb_cust_name, ssb.customer_code as ssb_customer_code, ssb.customer_name as ssb_customer_name,
+ ssb.invoiced_money as ssb_invoiced_money, ssb.reced_money as ssb_reced_money, ssb.satisfy_money as ssb_satisfy_money,
+ ssb.allowance_money as ssb_allowance_money, ssb.deduction_money as ssb_deduction_money, ssb.other_money as ssb_other_money,
+ ssb.satisfy_reason as ssb_satisfy_reason, ssb.allowance_reason as ssb_allowance_reason, ssb.deduction_reason as ssb_deduction_reason,
+ ssb.other_reason as ssb_other_reason, ssb.open_bill_status as ssb_open_bill_status, ssb.payment_status as ssb_payment_status,
+ ssb.charge_status as ssb_charge_status, ssb.payee as ssb_payee, ssb.salesmen as ssb_salesmen, ssb.bl_special_quote as ssb_bl_special_quote,
+ ssb.bl_sensitive as ssb_bl_sensitive, ssb.bl_confirm_center as ssb_bl_confirm_center, ssb.confirm_center_date as ssb_confirm_center_date,
+ ssb.confirm_center_note as ssb_confirm_center_note, ssb.confirm_center_man_code as ssb_confirm_center_man_code,
+ ssb.confirm_center_code as ssb_confirm_center_code, ssb.bl_confirm_site as ssb_bl_confirm_site, ssb.confirm_site_date as ssb_confirm_site_date,
+ ssb.confirm_site_man_code as ssb_confirm_site_man_code, ssb.confirm_site_note as ssb_confirm_site_note, ssb.confirm_site_code as ssb_confirm_site_code
+ from emis_writeoff_apply_detail wad
+ left join emis_waybill w on wad.bill_code = w.bill_code
+ left join emis_settle_bill sb on wad.settle_bill_no = sb.settle_bill_no
+ left join emis_settle_sub_bill ssb on wad.bill_code = ssb.bill_code
+
+
+
+
+
+
+
+
+
+ insert into emis_writeoff_apply_detail
+
+ apply_id,
+ apply_no,
+ bill_code,
+ apply_money,
+ settle_bill_no,
+
+
+ #{applyId},
+ #{applyNo},
+ #{billCode},
+ #{applyMoney},
+ #{settleBillNo},
+
+
+
+
+ insert into emis_writeoff_apply_detail (apply_id, apply_no, bill_code, apply_money, settle_bill_no)
+ values
+
+ (#{item.applyId}, #{item.applyNo}, #{item.billCode}, #{item.applyMoney}, #{item.settleBillNo})
+
+
+
+
+ update emis_writeoff_apply_detail
+
+ apply_id = #{applyId},
+ apply_no = #{applyNo},
+ bill_code = #{billCode},
+ apply_money = #{applyMoney},
+ settle_bill_no = #{settleBillNo},
+
+ where id = #{id}
+
+
+
+ delete from emis_writeoff_apply_detail where id = #{id}
+
+
+
+ delete from emis_writeoff_apply_detail where apply_id = #{applyId}
+
+
+
+ delete from emis_writeoff_apply_detail where id in
+
+ #{id}
+
+
+
+
+
+
+
diff --git a/emis-biz/src/main/resources/mapper/EmisWriteoffApplyImageMapper.xml b/emis-biz/src/main/resources/mapper/EmisWriteoffApplyImageMapper.xml
new file mode 100644
index 000000000..452234f6a
--- /dev/null
+++ b/emis-biz/src/main/resources/mapper/EmisWriteoffApplyImageMapper.xml
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id, apply_id, apply_no, image_name, image_path, image_size, image_type, upload_date, upload_man_code, upload_man_name, create_by, create_time, update_by, update_time, remark from emis_writeoff_apply_image
+
+
+
+
+
+
+
+
+
+ insert into emis_writeoff_apply_image
+
+ apply_id,
+ apply_no,
+ image_name,
+ image_path,
+ image_size,
+ image_type,
+ upload_date,
+ upload_man_code,
+ upload_man_name,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ remark,
+
+
+ #{applyId},
+ #{applyNo},
+ #{imageName},
+ #{imagePath},
+ #{imageSize},
+ #{imageType},
+ #{uploadDate},
+ #{uploadManCode},
+ #{uploadManName},
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+ #{remark},
+
+
+
+
+ insert into emis_writeoff_apply_image (apply_id, apply_no, image_name, image_path, image_size, image_type, upload_date, upload_man_code, upload_man_name, create_by, create_time, update_by, update_time, remark)
+ values
+
+ (#{item.applyId}, #{item.applyNo}, #{item.imageName}, #{item.imagePath}, #{item.imageSize}, #{item.imageType}, #{item.uploadDate}, #{item.uploadManCode}, #{item.uploadManName}, #{item.createBy}, #{item.createTime}, #{item.updateBy}, #{item.updateTime}, #{item.remark})
+
+
+
+
+ update emis_writeoff_apply_image
+
+ apply_id = #{applyId},
+ apply_no = #{applyNo},
+ image_name = #{imageName},
+ image_path = #{imagePath},
+ image_size = #{imageSize},
+ image_type = #{imageType},
+ upload_date = #{uploadDate},
+ upload_man_code = #{uploadManCode},
+ upload_man_name = #{uploadManName},
+ update_by = #{updateBy},
+ update_time = #{updateTime},
+ remark = #{remark},
+
+ where id = #{id}
+
+
+
+ delete from emis_writeoff_apply_image where id = #{id}
+
+
+
+ delete from emis_writeoff_apply_image where apply_id = #{applyId}
+
+
+
+ delete from emis_writeoff_apply_image where id in
+
+ #{id}
+
+
+
+
+
diff --git a/emis-biz/src/main/resources/mapper/EmisWriteoffApplyMapper.xml b/emis-biz/src/main/resources/mapper/EmisWriteoffApplyMapper.xml
new file mode 100644
index 000000000..19de1efbb
--- /dev/null
+++ b/emis-biz/src/main/resources/mapper/EmisWriteoffApplyMapper.xml
@@ -0,0 +1,517 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id, apply_no, apply_man_code, apply_man_name, apply_site_code, apply_site_name, apply_date, writeoff_amount, pay_type, trade_date, recipient, apply_memo, bl_center_confirmed, center_confirm_man_code, center_confirm_man_name, center_confirm_date, center_confirm_note, center_reject_reason, bl_headquarters_confirmed, headquarters_confirm_man_code, headquarters_confirm_man_name, headquarters_confirm_date, headquarters_confirm_note, headquarters_reject_reason, revoke_date, revoke_man_code, revoke_man_name, revoke_reason, create_by, create_time, update_by, update_time, remark from emis_writeoff_apply
+
+
+
+
+
+
+
+ insert into emis_writeoff_apply
+
+ apply_no,
+ apply_man_code,
+ apply_man_name,
+ apply_site_code,
+ apply_site_name,
+ apply_date,
+ writeoff_amount,
+ pay_type,
+ trade_date,
+ recipient,
+ apply_memo,
+ bl_center_confirmed,
+ center_confirm_man_code,
+ center_confirm_man_name,
+ center_confirm_date,
+ center_confirm_note,
+ center_reject_reason,
+ bl_headquarters_confirmed,
+ headquarters_confirm_man_code,
+ headquarters_confirm_man_name,
+ headquarters_confirm_date,
+ headquarters_confirm_note,
+ headquarters_reject_reason,
+ revoke_date,
+ revoke_man_code,
+ revoke_man_name,
+ revoke_reason,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ remark,
+
+
+ #{applyNo},
+ #{applyManCode},
+ #{applyManName},
+ #{applySiteCode},
+ #{applySiteName},
+ #{applyDate},
+ #{writeoffAmount},
+ #{payType},
+ #{tradeDate},
+ #{recipient},
+ #{applyMemo},
+ #{blCenterConfirmed},
+ #{centerConfirmManCode},
+ #{centerConfirmManName},
+ #{centerConfirmDate},
+ #{centerConfirmNote},
+ #{centerRejectReason},
+ #{blHeadquartersConfirmed},
+ #{headquartersConfirmManCode},
+ #{headquartersConfirmManName},
+ #{headquartersConfirmDate},
+ #{headquartersConfirmNote},
+ #{headquartersRejectReason},
+ #{revokeDate},
+ #{revokeManCode},
+ #{revokeManName},
+ #{revokeReason},
+ #{createBy},
+ #{createTime},
+ #{updateBy},
+ #{updateTime},
+ #{remark},
+
+
+
+
+ update emis_writeoff_apply
+
+ apply_no = #{applyNo},
+ apply_man_code = #{applyManCode},
+ apply_man_name = #{applyManName},
+ apply_site_code = #{applySiteCode},
+ apply_site_name = #{applySiteName},
+ apply_date = #{applyDate},
+ writeoff_amount = #{writeoffAmount},
+ apply_memo = #{applyMemo},
+ bl_center_confirmed = #{blCenterConfirmed},
+ center_confirm_man_code = #{centerConfirmManCode},
+ center_confirm_man_name = #{centerConfirmManName},
+ center_confirm_date = #{centerConfirmDate},
+ center_confirm_note = #{centerConfirmNote},
+ center_reject_reason = #{centerRejectReason},
+ bl_headquarters_confirmed = #{blHeadquartersConfirmed},
+ headquarters_confirm_man_code = #{headquartersConfirmManCode},
+ headquarters_confirm_man_name = #{headquartersConfirmManName},
+ headquarters_confirm_date = #{headquartersConfirmDate},
+ headquarters_confirm_note = #{headquartersConfirmNote},
+ headquarters_reject_reason = #{headquartersRejectReason},
+ revoke_date = #{revokeDate},
+ revoke_man_code = #{revokeManCode},
+ revoke_man_name = #{revokeManName},
+ revoke_reason = #{revokeReason},
+ salesmen = #{salesmen},
+ payee = #{payee},
+ update_by = #{updateBy},
+ update_time = #{updateTime},
+ remark = #{remark},
+
+ where id = #{id}
+
+
+
+ delete from emis_writeoff_apply where id = #{id}
+
+
+
+ delete from emis_writeoff_apply where id in
+
+ #{id}
+
+
+
+
+ update emis_writeoff_apply set
+ bl_center_confirmed = #{blCenterConfirmed},
+ center_confirm_man_code = #{centerConfirmManCode},
+ center_confirm_man_name = #{centerConfirmManName},
+ center_confirm_date = #{centerConfirmDate},
+ center_confirm_note = #{centerConfirmNote},
+ update_by = #{updateBy},
+ update_time = #{updateTime}
+ where id = #{id}
+
+
+
+ update emis_writeoff_apply set
+ bl_center_confirmed = #{blCenterConfirmed},
+ center_confirm_man_code = #{centerConfirmManCode},
+ center_confirm_man_name = #{centerConfirmManName},
+ center_confirm_date = #{centerConfirmDate},
+ center_reject_reason = #{centerRejectReason},
+ update_by = #{updateBy},
+ update_time = #{updateTime}
+ where id = #{id}
+
+
+
+ update emis_writeoff_apply set
+ bl_headquarters_confirmed = #{blHeadquartersConfirmed},
+ headquarters_confirm_man_code = #{headquartersConfirmManCode},
+ headquarters_confirm_man_name = #{headquartersConfirmManName},
+ headquarters_confirm_date = #{headquartersConfirmDate},
+ headquarters_confirm_note = #{headquartersConfirmNote},
+ update_by = #{updateBy},
+ update_time = #{updateTime}
+ where id = #{id}
+
+
+
+ update emis_writeoff_apply set
+ bl_headquarters_confirmed = #{blHeadquartersConfirmed},
+ headquarters_confirm_man_code = #{headquartersConfirmManCode},
+ headquarters_confirm_man_name = #{headquartersConfirmManName},
+ headquarters_confirm_date = #{headquartersConfirmDate},
+ headquarters_reject_reason = #{headquartersRejectReason},
+ update_by = #{updateBy},
+ update_time = #{updateTime}
+ where id = #{id}
+
+
+
+ update emis_writeoff_apply set
+ bl_center_confirmed = #{blCenterConfirmed},
+ revoke_man_code = #{revokeManCode},
+ revoke_man_name = #{revokeManName},
+ revoke_date = #{revokeDate},
+ revoke_reason = #{revokeReason},
+ update_by = #{updateBy},
+ update_time = #{updateTime}
+ where id = #{id}
+
+
+
+ update emis_writeoff_apply set
+ bl_center_confirmed = #{blCenterConfirmed},
+ bl_headquarters_confirmed = #{blHeadquartersConfirmed},
+ center_confirm_man_code = null,
+ center_confirm_man_name = null,
+ center_confirm_date = null,
+ center_confirm_note = null,
+ center_reject_reason = null,
+ headquarters_confirm_man_code = null,
+ headquarters_confirm_man_name = null,
+ headquarters_confirm_date = null,
+ headquarters_confirm_note = null,
+ headquarters_reject_reason = null,
+ revoke_man_code = null,
+ revoke_man_name = null,
+ revoke_date = null,
+ revoke_reason = null,
+ update_by = #{updateBy},
+ update_time = #{updateTime}
+ where id = #{id}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+