✨ 按客户区域计算毛利并完善汇总展示
This commit is contained in:
@@ -26,6 +26,8 @@ public class PrcProfitReportQuery extends BaseEntity
|
||||
private List<String> customerCodes;
|
||||
/** 按客户当前区域筛选。 */
|
||||
private String customerArea;
|
||||
/** 服务端根据客户区域确定的计算规则。 */
|
||||
private String profitRule;
|
||||
private String customerName;
|
||||
/** 客户名称拆分后的多值查询条件。 */
|
||||
private List<String> customerNames;
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.bms.price.enums;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/** 客户区域字典值对应的毛利计算规则。 */
|
||||
public enum ProfitAreaRule
|
||||
{
|
||||
SHENZHEN("C"),
|
||||
GUANGZHOU("GZ");
|
||||
|
||||
private final String customerArea;
|
||||
|
||||
ProfitAreaRule(String customerArea)
|
||||
{
|
||||
this.customerArea = customerArea;
|
||||
}
|
||||
|
||||
public static ProfitAreaRule fromCustomerArea(String customerArea)
|
||||
{
|
||||
if (customerArea != null)
|
||||
{
|
||||
for (ProfitAreaRule rule : values())
|
||||
{
|
||||
if (rule.customerArea.equals(customerArea.trim()))
|
||||
{
|
||||
return rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Map<String, String> areaRules()
|
||||
{
|
||||
Map<String, String> result = new LinkedHashMap<>();
|
||||
for (ProfitAreaRule rule : values())
|
||||
{
|
||||
result.put(rule.customerArea, rule.name());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.bms.price.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import com.bms.customer.customerinfo.domain.BmsCustomerOption;
|
||||
// 提成功能暂停使用:import com.bms.price.domain.PrcProfitCommissionRate;
|
||||
import com.bms.price.domain.PrcProfitReportExport;
|
||||
@@ -14,6 +15,8 @@ public interface IPrcProfitReportService
|
||||
{
|
||||
List<BmsCustomerOption> selectCustomerOptions(String keywords);
|
||||
|
||||
Map<String, String> selectAreaRules();
|
||||
|
||||
List<PrcProfitReportOrderRow> selectOrderRows(PrcProfitReportQuery query);
|
||||
|
||||
List<PrcProfitReportProductRow> selectProductRows(PrcProfitReportQuery query);
|
||||
|
||||
+20
-1
@@ -3,6 +3,7 @@ package com.bms.price.service.impl;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
// 提成功能暂停使用:import java.math.BigDecimal;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -19,6 +20,7 @@ import com.bms.price.domain.vo.PrcProfitReportOrderRow;
|
||||
import com.bms.price.domain.vo.PrcProfitReportProductRow;
|
||||
import com.bms.price.domain.vo.PrcProfitReportQuery;
|
||||
import com.bms.price.domain.vo.PrcProfitReportSummary;
|
||||
import com.bms.price.enums.ProfitAreaRule;
|
||||
import com.bms.price.mapper.PrcProfitReportMapper;
|
||||
import com.bms.price.service.IPrcProfitReportService;
|
||||
|
||||
@@ -48,6 +50,12 @@ public class PrcProfitReportServiceImpl implements IPrcProfitReportService
|
||||
return customerMapper.selectCustomerOptions(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> selectAreaRules()
|
||||
{
|
||||
return ProfitAreaRule.areaRules();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PrcProfitReportOrderRow> selectOrderRows(PrcProfitReportQuery query)
|
||||
{
|
||||
@@ -105,12 +113,23 @@ public class PrcProfitReportServiceImpl implements IPrcProfitReportService
|
||||
{
|
||||
if (query == null)
|
||||
{
|
||||
return;
|
||||
throw new ServiceException("请选择客户区域");
|
||||
}
|
||||
if ("COMMISSION_MISSING".equals(query.getDetailType()))
|
||||
{
|
||||
throw new ServiceException("提成功能已暂停使用");
|
||||
}
|
||||
if (query.getCustomerArea() == null || query.getCustomerArea().trim().isEmpty())
|
||||
{
|
||||
throw new ServiceException("请选择客户区域");
|
||||
}
|
||||
ProfitAreaRule rule = ProfitAreaRule.fromCustomerArea(query.getCustomerArea());
|
||||
if (rule == null)
|
||||
{
|
||||
throw new ServiceException("该客户区域未配置毛利规则");
|
||||
}
|
||||
query.setCustomerArea(query.getCustomerArea().trim());
|
||||
query.setProfitRule(rule.name());
|
||||
query.setOrderNos(splitFilterValues(query.getOrderNo(), "订单号"));
|
||||
query.setCustomerCodes(splitFilterValues(query.getCustomerCode(), "客户代码"));
|
||||
query.setCustomerNames(splitFilterValues(query.getCustomerName(), "客户名称"));
|
||||
|
||||
@@ -200,8 +200,25 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<!-- 红线毛利 = 产品价 - 红线价;红线毛利率 = 红线毛利 / 红线价 * 100%。汇总先逐单计算再求和。 -->
|
||||
<!-- 广州缺少有效销售价或红线价时不计算毛利;计费失败留下的双零占位也不参与计算。 -->
|
||||
<sql id="guangzhouProfitAvailable">
|
||||
i.sales_amount is not null and i.redline_amount is not null
|
||||
and not (coalesce(p.billing_fail_status, 0) in (23, 24, 25) and i.sales_amount = 0 and i.redline_amount = 0)
|
||||
</sql>
|
||||
|
||||
<sql id="profitExpressions">
|
||||
<choose>
|
||||
<when test="profitRule == 'GUANGZHOU'">
|
||||
null as cost_amount, i.redline_amount,
|
||||
null as redline_gross_profit, null as redline_gross_margin_rate,
|
||||
i.sales_amount,
|
||||
case when <include refid="guangzhouProfitAvailable"/>
|
||||
then i.sales_amount - i.redline_amount else null end as sales_gross_profit,
|
||||
case when <include refid="guangzhouProfitAvailable"/> and i.sales_amount != 0
|
||||
then round((i.sales_amount - i.redline_amount) * 100 / i.sales_amount, 4)
|
||||
else null end as sales_gross_margin_rate
|
||||
</when>
|
||||
<otherwise>
|
||||
i.product_amount as cost_amount,
|
||||
i.redline_amount,
|
||||
case when i.product_amount is not null and i.redline_amount is not null
|
||||
@@ -213,11 +230,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
then i.sales_amount - i.product_amount else null end as sales_gross_profit,
|
||||
case when i.product_amount is not null and i.sales_amount is not null and i.sales_amount != 0
|
||||
then round((i.sales_amount - i.product_amount) * 100 / i.sales_amount, 4) else null end as sales_gross_margin_rate
|
||||
<!-- 提成比例与金额计算暂停使用;恢复时包含前置逗号。
|
||||
, cr.commission_rate,
|
||||
case when cr.commission_rate is not null and i.product_amount is not null and i.sales_amount is not null
|
||||
then round((i.sales_amount - i.product_amount) * cr.commission_rate / 100, 4) else null end as commission_amount
|
||||
-->
|
||||
</otherwise>
|
||||
</choose>
|
||||
</sql>
|
||||
|
||||
<select id="selectOrderRows" resultMap="PrcProfitReportOrderResult">
|
||||
@@ -234,9 +248,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
order by p.biz_date desc, p.bill_id desc
|
||||
</select>
|
||||
|
||||
<select id="selectProductRows" resultMap="PrcProfitReportProductResult">
|
||||
select p.product_code, p.product_name, p.country_code, p.country_name,
|
||||
i.currency, count(*) as order_count,
|
||||
<!-- 汇总和产品维度使用同一套逐单有效数据计算,毛利率按有效销售额加权。 -->
|
||||
<sql id="profitAggregateExpressions">
|
||||
<choose>
|
||||
<when test="profitRule == 'GUANGZHOU'">
|
||||
null as cost_amount,
|
||||
sum(i.redline_amount) as redline_amount,
|
||||
null as redline_gross_profit, null as redline_gross_margin_rate,
|
||||
sum(i.sales_amount) as sales_amount,
|
||||
sum(case when <include refid="guangzhouProfitAvailable"/>
|
||||
then i.sales_amount - i.redline_amount else null end) as sales_gross_profit,
|
||||
case when sum(case when <include refid="guangzhouProfitAvailable"/>
|
||||
then i.sales_amount else null end) is null
|
||||
or sum(case when <include refid="guangzhouProfitAvailable"/>
|
||||
then i.sales_amount else null end) = 0
|
||||
then null
|
||||
else round(sum(case when <include refid="guangzhouProfitAvailable"/>
|
||||
then i.sales_amount - i.redline_amount else null end) * 100 /
|
||||
sum(case when <include refid="guangzhouProfitAvailable"/>
|
||||
then i.sales_amount else null end), 4)
|
||||
end as sales_gross_margin_rate
|
||||
</when>
|
||||
<otherwise>
|
||||
sum(i.product_amount) as cost_amount,
|
||||
sum(i.redline_amount) as redline_amount,
|
||||
sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
@@ -266,12 +299,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
sum(case when i.product_amount is not null and i.sales_amount is not null
|
||||
then i.sales_amount else null end), 4)
|
||||
end as sales_gross_margin_rate
|
||||
<!-- 提成金额与未计算订单数暂停使用。
|
||||
sum(case when cr.commission_rate is not null and i.product_amount is not null and i.sales_amount is not null
|
||||
then (i.sales_amount - i.product_amount) * cr.commission_rate / 100 else null end) as commission_amount,
|
||||
sum(case when cr.commission_rate is null or i.product_amount is null or i.sales_amount is null
|
||||
then 1 else 0 end) as commission_missing_order_count,
|
||||
-->
|
||||
</otherwise>
|
||||
</choose>
|
||||
</sql>
|
||||
|
||||
<select id="selectProductRows" resultMap="PrcProfitReportProductResult">
|
||||
select p.product_code, p.product_name, p.country_code, p.country_name,
|
||||
i.currency, count(*) as order_count,
|
||||
<include refid="profitAggregateExpressions"/>
|
||||
<include refid="profitReportFromAndWhere"/>
|
||||
group by p.product_code, p.product_name, p.country_code, p.country_name, i.currency
|
||||
order by p.product_code, p.country_code, i.currency
|
||||
@@ -279,41 +314,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
|
||||
<select id="selectSummary" resultMap="PrcProfitReportSummaryResult">
|
||||
select i.currency, count(*) as order_count,
|
||||
sum(i.product_amount) as cost_amount,
|
||||
sum(i.redline_amount) as redline_amount,
|
||||
sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.product_amount - i.redline_amount else null end) as redline_gross_profit,
|
||||
case when sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount else null end) is null
|
||||
or sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount else null end) = 0
|
||||
then null
|
||||
else round(
|
||||
sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.product_amount - i.redline_amount else null end) * 100 /
|
||||
sum(case when i.product_amount is not null and i.redline_amount is not null
|
||||
then i.redline_amount else null end), 4)
|
||||
end as redline_gross_margin_rate,
|
||||
sum(i.sales_amount) as sales_amount,
|
||||
sum(case when i.product_amount is not null and i.sales_amount is not null
|
||||
then i.sales_amount - i.product_amount else null end) as sales_gross_profit,
|
||||
case when sum(case when i.product_amount is not null and i.sales_amount is not null
|
||||
then i.sales_amount else null end) is null
|
||||
or sum(case when i.product_amount is not null and i.sales_amount is not null
|
||||
then i.sales_amount else null end) = 0
|
||||
then null
|
||||
else round(
|
||||
sum(case when i.product_amount is not null and i.sales_amount is not null
|
||||
then i.sales_amount - i.product_amount else null end) * 100 /
|
||||
sum(case when i.product_amount is not null and i.sales_amount is not null
|
||||
then i.sales_amount else null end), 4)
|
||||
end as sales_gross_margin_rate
|
||||
<!-- 提成汇总计算暂停使用;恢复时包含前置逗号。
|
||||
, sum(case when cr.commission_rate is not null and i.product_amount is not null and i.sales_amount is not null
|
||||
then (i.sales_amount - i.product_amount) * cr.commission_rate / 100 else null end) as commission_amount,
|
||||
sum(case when cr.commission_rate is null or i.product_amount is null or i.sales_amount is null
|
||||
then 1 else 0 end) as commission_missing_order_count
|
||||
-->
|
||||
<include refid="profitAggregateExpressions"/>
|
||||
<include refid="profitReportFromAndWhere"/>
|
||||
<if test="arBillStatus != null and arBillStatus != ''">
|
||||
and p.ar_bill_status = #{arBillStatus}
|
||||
|
||||
Reference in New Issue
Block a user