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
package cn.iocoder.yudao.module.crm.dal.mysql.invoice;
 
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX;
import cn.iocoder.yudao.module.crm.controller.admin.invoice.vo.invoice.CrmInvoicePageReqVO;
import cn.iocoder.yudao.module.crm.dal.dataobject.invoice.CrmInvoiceDO;
import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum;
import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum;
import cn.iocoder.yudao.module.crm.util.CrmPermissionUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.ibatis.annotations.Mapper;
 
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
 
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
 
/**
 * 开票 Mapper
 *
 * @author 超级管理员
 */
@Mapper
public interface CrmInvoiceMapper extends BaseMapperX<CrmInvoiceDO> {
 
    default CrmInvoiceDO selectByNo(String no) {
        return selectOne(CrmInvoiceDO::getNo, no);
    }
 
    /**
     * 提交审批:置为审批中,并清空上一轮审核结果
     *
     * 之所以用 UpdateWrapper 而非 updateById:MyBatis-Plus 默认的字段更新策略会忽略 null,
     * 直接 updateById 无法把审核不通过后残留的审核人、审核时间、审核意见真正清空。
     *
     * @param id     开票编号
     * @param status 目标状态(审批中)
     * @return 影响行数
     */
    default int submitAndResetAuditInfo(Long id, Integer status) {
        return update(null, new LambdaUpdateWrapper<CrmInvoiceDO>()
                .eq(CrmInvoiceDO::getId, id)
                .set(CrmInvoiceDO::getAuditStatus, status)
                .set(CrmInvoiceDO::getReviewerId, null)
                .set(CrmInvoiceDO::getReviewerName, null)
                .set(CrmInvoiceDO::getReviewTime, null)
                .set(CrmInvoiceDO::getReviewRemark, null));
    }
 
    /**
     * 审核:写入审核结果、审核人与审核意见
     *
     * reviewRemark 允许为 null(审核通过时意见可选),故同样使用 UpdateWrapper 直写。
     *
     * @param id           开票编号
     * @param status       目标状态(审核通过 / 审核不通过)
     * @param reviewerId   审核人编号
     * @param reviewerName 审核人姓名
     * @param reviewRemark 审核意见
     * @return 影响行数
     */
    default int auditInvoice(Long id, Integer status, Long reviewerId,
                             String reviewerName, String reviewRemark) {
        return update(null, new LambdaUpdateWrapper<CrmInvoiceDO>()
                .eq(CrmInvoiceDO::getId, id)
                .set(CrmInvoiceDO::getAuditStatus, status)
                .set(CrmInvoiceDO::getReviewerId, reviewerId)
                .set(CrmInvoiceDO::getReviewerName, reviewerName)
                .set(CrmInvoiceDO::getReviewTime, LocalDateTime.now())
                .set(CrmInvoiceDO::getReviewRemark, reviewRemark));
    }
 
    default PageResult<CrmInvoiceDO> selectPageByCustomerId(CrmInvoicePageReqVO reqVO) {
        return selectPage(reqVO, new LambdaQueryWrapperX<CrmInvoiceDO>()
                .eq(CrmInvoiceDO::getCustomerId, reqVO.getCustomerId()) // 必须传递
                .eqIfPresent(CrmInvoiceDO::getNo, reqVO.getNo())
                .eqIfPresent(CrmInvoiceDO::getContractId, reqVO.getContractId())
                .orderByDesc(CrmInvoiceDO::getId));
    }
 
    default PageResult<CrmInvoiceDO> selectPage(CrmInvoicePageReqVO pageReqVO, Long userId) {
        MPJLambdaWrapperX<CrmInvoiceDO> query = new MPJLambdaWrapperX<>();
        // 拼接数据权限的查询条件
        CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_INVOICE.getType(),
                CrmInvoiceDO::getId, userId, pageReqVO.getSceneType());
        // 拼接自身的查询条件
        query.selectAll(CrmInvoiceDO.class)
                .eqIfPresent(CrmInvoiceDO::getNo, pageReqVO.getNo())
                .eqIfPresent(CrmInvoiceDO::getContractId, pageReqVO.getContractId())
                .eqIfPresent(CrmInvoiceDO::getAuditStatus, pageReqVO.getAuditStatus())
                .orderByDesc(CrmInvoiceDO::getId);
        return selectJoinPage(pageReqVO, CrmInvoiceDO.class, query);
    }
 
    default Long selectCountByAudit(Long userId) {
        MPJLambdaWrapperX<CrmInvoiceDO> query = new MPJLambdaWrapperX<>();
        // 我负责的 + 非公海
        CrmPermissionUtils.appendPermissionCondition(query, CrmBizTypeEnum.CRM_INVOICE.getType(),
                CrmInvoiceDO::getId, userId, CrmSceneTypeEnum.OWNER.getType());
        // 未审核
        query.eq(CrmInvoiceDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus());
        return selectCount(query);
    }
 
    default List<CrmInvoiceDO> selectListByContractIdAndStatus(Long contractId, Collection<Integer> auditStatuses) {
        return selectList(new LambdaQueryWrapperX<CrmInvoiceDO>()
                .eq(CrmInvoiceDO::getContractId, contractId)
                .in(CrmInvoiceDO::getAuditStatus, auditStatuses));
    }
 
    default Map<Long, BigDecimal> selectInvoicePriceMapByContractId(Collection<Long> contractIds) {
        if (CollUtil.isEmpty(contractIds)) {
            return Collections.emptyMap();
        }
        // SQL sum 查询(审批通过 + 审批中,与开票防超校验口径一致)
        List<Map<String, Object>> result = selectMaps(new QueryWrapper<CrmInvoiceDO>()
                .select("contract_id, SUM(price) AS total_price")
                .in("audit_status", CrmAuditStatusEnum.APPROVE.getStatus(),
                        CrmAuditStatusEnum.PROCESS.getStatus())
                .groupBy("contract_id")
                .in("contract_id", contractIds));
        // 获得金额
        return convertMap(result, obj -> (Long) obj.get("contract_id"), obj -> (BigDecimal) obj.get("total_price"));
    }
 
    default Long selectCountByContractId(Long contractId) {
        return selectCount(CrmInvoiceDO::getContractId, contractId);
    }
 
}