1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package cn.iocoder.yudao.module.crm.service.invoice;
 
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoicePageReqVO;
import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoiceSaveReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.invoice.CrmInvoiceDO;
import jakarta.validation.Valid;
 
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
 
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 
/**
 * CRM 开票 Service 接口
 *
 * @author 超级管理员
 */
public interface CrmInvoiceService {
 
    /**
     * 创建开票
     *
     * @param createReqVO 创建信息
     * @return 编号
     */
    Long createInvoice(@Valid CrmInvoiceSaveReqVO createReqVO);
 
    /**
     * 更新开票
     *
     * @param updateReqVO 更新信息
     */
    void updateInvoice(@Valid CrmInvoiceSaveReqVO updateReqVO);
 
    /**
     * 删除开票
     *
     * @param id 编号
     */
    void deleteInvoice(Long id);
 
    /**
     * 提交开票审批(草稿 / 审核不通过 → 审批中)
     *
     * 审批人由「系统管理 - 审批配置」按业务类型统一配置(业务编码 crm_invoice_approve),
     * 提交时无需指定;未启用审批或未配置有效审批人时抛出业务异常。
     *
     * @param id 开票编号
     */
    void submitInvoice(Long id);
 
    /**
     * 获得开票审批的审批人编号集合
     *
     * 供前端判断当前登录用户是否应展示「审核」按钮;未配置时返回空集合。
     *
     * @return 审批人用户编号集合
     */
    Set<Long> getInvoiceApproverUserIds();
 
    /**
     * 审核开票(审批中 → 审核通过 / 审核不通过)
     *
     * 仅业务编码 crm_invoice_approve 配置的审批人可操作(多人时或签);审核不通过时必须填写不通过原因。
     *
     * @param id           开票编号
     * @param pass         是否通过:true=审核通过 / false=审核不通过
     * @param reviewRemark 审核意见(不通过时即不通过原因,必填)
     */
    void auditInvoice(Long id, Boolean pass, String reviewRemark);
 
    /**
     * 获得开票
     *
     * @param id 编号
     * @return 开票
     */
    CrmInvoiceDO getInvoice(Long id);
 
    /**
     * 获得开票列表
     *
     * @param ids 编号
     * @return 开票列表
     */
    List<CrmInvoiceDO> getInvoiceList(Collection<Long> ids);
 
    /**
     * 获得开票 Map
     *
     * @param ids 编号
     * @return 开票 Map
     */
    default Map<Long, CrmInvoiceDO> getInvoiceMap(Collection<Long> ids) {
        return convertMap(getInvoiceList(ids), CrmInvoiceDO::getId);
    }
 
    /**
     * 获得开票分页
     *
     * 数据权限:基于 {@link CrmInvoiceDO} 读取
     *
     * @param pageReqVO 分页查询
     * @param userId    用户编号
     * @return 开票分页
     */
    PageResult<CrmInvoiceDO> getInvoicePage(CrmInvoicePageReqVO pageReqVO, Long userId);
 
    /**
     * 获得开票分页,基于指定客户
     *
     * @param pageReqVO 分页查询
     * @return 开票分页
     */
    PageResult<CrmInvoiceDO> getInvoicePageByCustomerId(CrmInvoicePageReqVO pageReqVO);
 
    /**
     * 获得待审核开票数量
     *
     * @param userId 用户编号
     * @return 待审批数量
     */
    Long getAuditInvoiceCount(Long userId);
 
    /**
     * 根据合同编号查询开票列表
     *
     * @param contractId   合同编号
     * @param auditStatuses 审批状态集合
     * @return 开票列表
     */
    List<CrmInvoiceDO> getInvoiceListByContractIdAndStatus(Long contractId, Collection<Integer> auditStatuses);
 
    /**
     * 获得合同已开票金额 Map(审批通过 + 审批中,与开票防超校验口径一致)
     *
     * @param contractIds 合同编号
     * @return 开票金额 Map
     */
    Map<Long, BigDecimal> getInvoicePriceMapByContractId(Collection<Long> contractIds);
 
    /**
     * 根据合同编号查询开票数量
     *
     * @param contractId 合同编号
     * @return 开票数量
     */
    Long getInvoiceCountByContractId(Long contractId);
 
}