Files
klp-oa/klp-crm/src/main/resources/mapper/CrmSalesReportMapper.xml
Joshi ba12c346e8 feat(sales): 为销售报表添加订单明细查询功能
- 在 CrmOrderItemMapper 中添加根据订单ID列表查询订单明细的方法
- 实现 MyBatis 查询语句支持批量订单ID查询订单明细
- 修改销售报表服务类注入 CrmOrderItemMapper 依赖
- 扩展销售报表查询逻辑以包含订单明细数据
- 在销售报表 VO 中添加订单明细列表字段
- 使用流式处理和分组收集优化订单明细关联逻辑
2025-12-29 16:55:06 +08:00

272 lines
12 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.klp.crm.mapper.CrmSalesReportMapper">
<!-- 通用查询条件 -->
<sql id="selectCondition">
<where>
o.del_flag = 0 AND c.del_flag = 0
<if test="bo.startTime != null">
AND DATE(o.create_time) &gt;= #{bo.startTime}
</if>
<if test="bo.endTime != null">
AND DATE(o.create_time) &lt;= #{bo.endTime}
</if>
<if test="bo.salesmanList != null and bo.salesmanList.size() > 0">
AND o.salesman IN
<foreach collection="bo.salesmanList" item="salesman" open="(" separator="," close=")">
#{salesman}
</foreach>
</if>
<if test="bo.customerIdList != null and bo.customerIdList.size() > 0">
AND o.customer_id IN
<foreach collection="bo.customerIdList" item="customerId" open="(" separator="," close=")">
#{customerId}
</foreach>
</if>
<if test="bo.customerLevelList != null and bo.customerLevelList.size() > 0">
AND c.customer_level IN
<foreach collection="bo.customerLevelList" item="level" open="(" separator="," close=")">
#{level}
</foreach>
</if>
<if test="bo.industryList != null and bo.industryList.size() > 0">
AND c.industry IN
<foreach collection="bo.industryList" item="industry" open="(" separator="," close=")">
#{industry}
</foreach>
</if>
<if test="bo.orderStatusList != null and bo.orderStatusList.size() > 0">
AND o.order_status IN
<foreach collection="bo.orderStatusList" item="status" open="(" separator="," close=")">
#{status}
</foreach>
</if>
<if test="bo.financeStatusList != null and bo.financeStatusList.size() > 0">
AND o.finance_status IN
<foreach collection="bo.financeStatusList" item="status" open="(" separator="," close=")">
#{status}
</foreach>
</if>
<if test="bo.orderTypeList != null and bo.orderTypeList.size() > 0">
AND o.order_type IN
<foreach collection="bo.orderTypeList" item="type" open="(" separator="," close=")">
#{type}
</foreach>
</if>
<if test="bo.minOrderAmount != null">
AND o.order_amount &gt;= #{bo.minOrderAmount}
</if>
<if test="bo.maxOrderAmount != null">
AND o.order_amount &lt;= #{bo.maxOrderAmount}
</if>
<if test="bo.onlyUnpaidOrders != null and bo.onlyUnpaidOrders == true">
AND o.unpaid_amount > 0
</if>
<if test="bo.companyNameKeyword != null and bo.companyNameKeyword != ''">
AND c.company_name LIKE CONCAT('%', #{bo.companyNameKeyword}, '%')
</if>
<if test="bo.orderCodeKeyword != null and bo.orderCodeKeyword != ''">
AND o.order_code LIKE CONCAT('%', #{bo.orderCodeKeyword}, '%')
</if>
<if test="bo.includeObjectionOrders != null and bo.includeObjectionOrders == false">
AND NOT EXISTS (
SELECT 1 FROM crm_sales_objection obj
WHERE obj.order_id = o.order_id AND obj.del_flag = 0
)
</if>
</where>
</sql>
<!-- 查询销售汇总统计数据 -->
<select id="selectSalesSummary" resultType="com.klp.crm.domain.vo.CrmSalesReportVo$SalesSummary">
SELECT
COUNT(o.order_id) as totalOrderCount,
COALESCE(SUM(o.order_amount), 0) as totalSalesAmount,
COUNT(CASE WHEN o.order_status = 3 THEN 1 END) as completedOrderCount,
COALESCE(SUM(CASE WHEN o.order_status = 3 THEN o.order_amount ELSE 0 END), 0) as completedSalesAmount,
COALESCE(SUM(o.unpaid_amount), 0) as totalUnpaidAmount,
COALESCE(AVG(o.order_amount), 0) as avgOrderAmount
FROM crm_order o
LEFT JOIN crm_customer c ON o.customer_id = c.customer_id
<include refid="selectCondition"/>
</select>
<!-- 查询订单明细列表 -->
<select id="selectOrderDetailList" resultType="com.klp.crm.domain.vo.CrmSalesReportVo$OrderDetail">
SELECT
o.order_id,
o.order_code,
c.customer_code,
c.company_name,
c.contact_person,
c.customer_level,
c.industry,
o.order_amount,
o.salesman,
o.delivery_date,
o.order_status,
o.finance_status,
o.unpaid_amount,
o.create_time,
COALESCE(item_stats.item_count, 0) as itemCount,
COALESCE(obj_stats.objection_count, 0) as objectionCount
FROM crm_order o
LEFT JOIN crm_customer c ON o.customer_id = c.customer_id
LEFT JOIN (
SELECT
order_id,
COUNT(*) as item_count
FROM crm_order_item
WHERE del_flag = 0
GROUP BY order_id
) item_stats ON o.order_id = item_stats.order_id
LEFT JOIN (
SELECT
order_id,
COUNT(*) as objection_count
FROM crm_sales_objection
WHERE del_flag = 0
GROUP BY order_id
) obj_stats ON o.order_id = obj_stats.order_id
<include refid="selectCondition"/>
<choose>
<when test="bo.orderBy != null and bo.orderBy != ''">
ORDER BY ${bo.orderBy}
<if test="bo.sortDirection != null and bo.sortDirection != ''">
${bo.sortDirection}
</if>
</when>
<otherwise>
ORDER BY o.create_time DESC
</otherwise>
</choose>
</select>
<!-- 查询销售员统计数据 -->
<select id="selectSalesmanStats" resultType="com.klp.crm.domain.vo.CrmSalesReportVo$SalesmanStat">
SELECT
o.salesman,
COUNT(o.order_id) as orderCount,
COALESCE(SUM(o.order_amount), 0) as salesAmount,
ROUND(
COALESCE(SUM(o.order_amount), 0) * 100.0 /
NULLIF((
SELECT SUM(o2.order_amount)
FROM crm_order o2
LEFT JOIN crm_customer c2 ON o2.customer_id = c2.customer_id
<!-- 子查询使用独立的条件片段避免引用外层o/c -->
<where>
o2.del_flag = 0 AND c2.del_flag = 0
<if test="bo.startTime != null">
AND DATE(o2.create_time) &gt;= #{bo.startTime}
</if>
<if test="bo.endTime != null">
AND DATE(o2.create_time) &lt;= #{bo.endTime}
</if>
<if test="bo.salesmanList != null and bo.salesmanList.size() > 0">
AND o2.salesman IN
<foreach collection="bo.salesmanList" item="salesman" open="(" separator="," close=")">
#{salesman}
</foreach>
</if>
<if test="bo.customerIdList != null and bo.customerIdList.size() > 0">
AND o2.customer_id IN
<foreach collection="bo.customerIdList" item="customerId" open="(" separator="," close=")">
#{customerId}
</foreach>
</if>
<if test="bo.customerLevelList != null and bo.customerLevelList.size() > 0">
AND c2.customer_level IN
<foreach collection="bo.customerLevelList" item="level" open="(" separator="," close=")">
#{level}
</foreach>
</if>
<if test="bo.industryList != null and bo.industryList.size() > 0">
AND c2.industry IN
<foreach collection="bo.industryList" item="industry" open="(" separator="," close=")">
#{industry}
</foreach>
</if>
<if test="bo.orderStatusList != null and bo.orderStatusList.size() > 0">
AND o2.order_status IN
<foreach collection="bo.orderStatusList" item="status" open="(" separator="," close=")">
#{status}
</foreach>
</if>
<if test="bo.financeStatusList != null and bo.financeStatusList.size() > 0">
AND o2.finance_status IN
<foreach collection="bo.financeStatusList" item="status" open="(" separator="," close=")">
#{status}
</foreach>
</if>
<if test="bo.orderTypeList != null and bo.orderTypeList.size() > 0">
AND o2.order_type IN
<foreach collection="bo.orderTypeList" item="type" open="(" separator="," close=")">
#{type}
</foreach>
</if>
<if test="bo.minOrderAmount != null">
AND o2.order_amount &gt;= #{bo.minOrderAmount}
</if>
<if test="bo.maxOrderAmount != null">
AND o2.order_amount &lt;= #{bo.maxOrderAmount}
</if>
<if test="bo.onlyUnpaidOrders != null and bo.onlyUnpaidOrders == true">
AND o2.unpaid_amount > 0
</if>
<if test="bo.companyNameKeyword != null and bo.companyNameKeyword != ''">
AND c2.company_name LIKE CONCAT('%', #{bo.companyNameKeyword}, '%')
</if>
<if test="bo.orderCodeKeyword != null and bo.orderCodeKeyword != ''">
AND o2.order_code LIKE CONCAT('%', #{bo.orderCodeKeyword}, '%')
</if>
<if test="bo.includeObjectionOrders != null and bo.includeObjectionOrders == false">
AND NOT EXISTS (
SELECT 1 FROM crm_sales_objection obj
WHERE obj.order_id = o2.order_id AND obj.del_flag = 0
)
</if>
</where>
), 0),
2
) as percentage
FROM crm_order o
LEFT JOIN crm_customer c ON o.customer_id = c.customer_id
<include refid="selectCondition"/>
GROUP BY o.salesman
ORDER BY salesAmount DESC
</select>
<!-- 查询客户等级统计数据 -->
<select id="selectCustomerLevelStats" resultType="com.klp.crm.domain.vo.CrmSalesReportVo$CustomerLevelStat">
SELECT
c.customer_level,
COUNT(DISTINCT c.customer_id) as customerCount,
COUNT(o.order_id) as orderCount,
COALESCE(SUM(o.order_amount), 0) as salesAmount
FROM crm_order o
LEFT JOIN crm_customer c ON o.customer_id = c.customer_id
<include refid="selectCondition"/>
GROUP BY c.customer_level
ORDER BY salesAmount DESC
</select>
<!-- 查询行业统计数据 -->
<select id="selectIndustryStats" resultType="com.klp.crm.domain.vo.CrmSalesReportVo$IndustryStat">
SELECT
COALESCE(c.industry, '未分类') as industry,
COUNT(DISTINCT c.customer_id) as customerCount,
COUNT(o.order_id) as orderCount,
COALESCE(SUM(o.order_amount), 0) as salesAmount
FROM crm_order o
LEFT JOIN crm_customer c ON o.customer_id = c.customer_id
<include refid="selectCondition"/>
GROUP BY c.industry
ORDER BY salesAmount DESC
</select>
</mapper>