统计 成本价 部分

This commit is contained in:
2025-11-25 11:49:40 +08:00
parent a995e8db25
commit ec46d876b1
3 changed files with 140 additions and 69 deletions

View File

@@ -14,9 +14,5 @@ import java.math.BigDecimal;
public class ProductCostAmountVO {
private Long productId;
private Long skuId;
//向上取整 保留两位小数
private BigDecimal costAmount;
private Long count;
private BigDecimal totalCostAmount;
}

View File

@@ -1,8 +1,10 @@
package com.czg.service.order.mapper;
import com.czg.order.vo.ProductCostAmountVO;
import com.czg.order.vo.TotalVo;
import com.mybatisflex.core.BaseMapper;
import com.czg.order.entity.ShopOrderStatistic;
import org.apache.ibatis.annotations.MapKey;
import org.apache.ibatis.annotations.Select;
import java.math.BigDecimal;
@@ -68,6 +70,7 @@ public interface ShopOrderStatisticMapper extends BaseMapper<ShopOrderStatistic>
" AND statistic_date BETWEEN #{start} AND #{end} ")
ShopOrderStatistic countStatistic(Long shopId, LocalDate start, LocalDate end);
//---------------------------------------------金额统计---------------------------------------------------
/**
* 订单金额统计 当日实时数据
*/
@@ -255,16 +258,43 @@ public interface ShopOrderStatisticMapper extends BaseMapper<ShopOrderStatistic>
* 商品成本 productCostAmount
*/
@Select("SELECT" +
" SUM(CASE WHEN sku.cost_price IS NULL OR sku.cost_price <= 0 THEN 0 ELSE sku.cost_price END) AS productCostAmount " +
" sku.id AS skuId," +
" sku.cost_price AS costAmount " +
"FROM" +
" tb_product product" +
" LEFT JOIN tb_prod_sku sku ON product.id = sku.product_id " +
" AND product.shop_id = sku.shop_id " +
"WHERE" +
" product.shop_id = #{shopId} " +
" AND sku.cost_price > 0")
@MapKey("skuId")
Map<Long, BigDecimal> getSkuCostAmount(Long shopId);
@Select("SELECT" +
" relation.product_id as productId," +
" ROUND(relation.surplus_stock * cons.price, 2) AS costAmount" +
" FROM" +
" tb_prod_cons_relation relation " +
" INNER JOIN tb_cons_info cons on relation.cons_info_id = cons.id and relation.shop_id = cons.shop_id and price > 0" +
" WHERE" +
" relation.shop_id = #{shopId} " +
" order by relation.product_id")
@MapKey("productId")
Map<Long, BigDecimal> getConsCostAmount(Long shopId);
@Select("SELECT " +
" detail.product_id as productId," +
" detail.sku_id as skuId," +
" sum(detail.num - detail.return_num) as count " +
"FROM " +
" tb_order_info `order` " +
" INNER JOIN tb_order_detail detail ON `order`.id = detail.order_id " +
" AND is_temporary = 0 " +
" LEFT JOIN tb_prod_sku sku ON detail.sku_id = sku.id " +
" INNER JOIN tb_order_detail detail ON `order`.id = detail.order_id AND is_temporary = 0 " +
"WHERE " +
" `order`.shop_id = #{shopId} " +
" and trade_day = #{tradeDay} " +
" and paid_time is not null")
BigDecimal countProductCostAmount(Long shopId, LocalDate tradeDay);
" and paid_time is not null" +
" order by detail.product_id, detail.sku_id")
List<ProductCostAmountVO> getOrderDetailProduct(Long shopId, LocalDate tradeDay);
}

View File

@@ -2,11 +2,13 @@ package com.czg.service.order.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.exception.CzgException;
import com.czg.order.entity.ShopOrderStatistic;
import com.czg.order.service.ShopOrderStatisticService;
import com.czg.order.vo.CountPayTypeVo;
import com.czg.order.vo.ProductCostAmountVO;
import com.czg.order.vo.TotalVo;
import com.czg.service.order.mapper.ShopOrderStatisticMapper;
import com.mybatisflex.core.query.QueryWrapper;
@@ -18,7 +20,9 @@ import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
/**
@@ -53,6 +57,7 @@ public class ShopOrderStatisticServiceImpl extends ServiceImpl<ShopOrderStatisti
ShopOrderStatistic statDateRange = getStatDateRange(shopId, start, end);
ShopOrderStatistic shopOrderStatistic = ShopOrderStatistic.mergeStatistics(realTimeDataByDay, statDateRange);
shopOrderStatistic.setShopId(shopId);
calculateShopOrderStatistic(shopOrderStatistic);
return shopOrderStatistic;
}
}
@@ -106,16 +111,17 @@ public class ShopOrderStatisticServiceImpl extends ServiceImpl<ShopOrderStatisti
ShopOrderStatistic result = new ShopOrderStatistic();
ShopOrderStatistic onlineStat = mapper.getOnlineStatSingleDate(shopId, day);
log.info("onlineStat:{}", JSONObject.toJSONString(onlineStat));
// log.info("onlineStat:{}", JSONObject.toJSONString(onlineStat));
ShopOrderStatistic orderStat = mapper.getOrderStatSingleDate(shopId, day);
log.info("orderStat:{}", JSONObject.toJSONString(orderStat));
// log.info("orderStat:{}", JSONObject.toJSONString(orderStat));
ShopOrderStatistic userFlowStat = mapper.getShopUserFlowStatSingleDate(shopId, day);
log.info("userFlowStat:{}", JSONObject.toJSONString(userFlowStat));
// log.info("userFlowStat:{}", JSONObject.toJSONString(userFlowStat));
Long discountCount = mapper.countDiscountOrder(shopId, day);
BigDecimal discountAmount = mapper.countDiscountAmount(shopId, day);
Long tableCount = mapper.countShopTable(shopId);
Long newMemberCount = mapper.countNewMember(shopId, day);
BigDecimal productCostAmount = mapper.countProductCostAmount(shopId, day);
//获取商品成本金额
BigDecimal productCostAmount = getProductCostAmount(shopId, day);
// 合并结果
CopyOptions copyOptions = CopyOptions.create().setIgnoreNullValue(true);
if (onlineStat != null) {
@@ -134,11 +140,11 @@ public class ShopOrderStatisticServiceImpl extends ServiceImpl<ShopOrderStatisti
result.setShopId(shopId);
result.setStatisticDate(day);
result.setDiscountCount(discountCount);
result.setDiscountAmount(discountAmount);
result.setTableCount(tableCount);
result.setNewMemberCount(newMemberCount);
result.setProductCostAmount(productCostAmount);
result.setDiscountCount(Optional.ofNullable(discountCount).orElse(0L));
result.setDiscountAmount(Optional.ofNullable(discountAmount).orElse(BigDecimal.ZERO));
result.setNewMemberCount(Optional.ofNullable(newMemberCount).orElse(0L));
result.setTableCount(Optional.ofNullable(tableCount).orElse(0L));
result.setProductCostAmount(Optional.ofNullable(productCostAmount).orElse(BigDecimal.ZERO));
//会员充值退款 充值退款金额(线上退款+现金退款)
BigDecimal cashRechargeAmount = Objects.requireNonNullElse(result.getCashRechargeAmount(), BigDecimal.ZERO);
@@ -177,11 +183,49 @@ public class ShopOrderStatisticServiceImpl extends ServiceImpl<ShopOrderStatisti
.add(memberPayAmount)
.add(creditPayAmount);
result.setPayAmount(totalPayAmount);
//毛利润(订单实付金额-商品成本)
if (productCostAmount == null) {
productCostAmount = BigDecimal.ZERO;
calculateShopOrderStatistic(result);
return result;
}
result.setProfitAmount(result.getPayAmount().subtract(productCostAmount));
/**
* 获取商品成本价
*/
private BigDecimal getProductCostAmount(Long shopId, LocalDate day) {
//获取商品sku成本价 productId skuId price
Map<Long, BigDecimal> skuCostAmountList = mapper.getSkuCostAmount(shopId);
// //获取商品耗材成本价 productId price
Map<Long, BigDecimal> consCostAmountList = mapper.getConsCostAmount(shopId);
//获取orderDetail信息 productId skuId 数量
BigDecimal productCostAmount = BigDecimal.ZERO;
if (CollUtil.isEmpty(skuCostAmountList) && CollUtil.isEmpty(consCostAmountList)) {
return productCostAmount;
}
List<ProductCostAmountVO> orderDetailProduct = mapper.getOrderDetailProduct(shopId, day);
if (CollUtil.isEmpty(orderDetailProduct)) {
return productCostAmount;
}
for (ProductCostAmountVO productCostAmountVO : orderDetailProduct) {
if (skuCostAmountList.containsKey(productCostAmountVO.getSkuId())) {
BigDecimal costAmount = skuCostAmountList.get(productCostAmountVO.getSkuId());
productCostAmount = productCostAmount.add(costAmount.multiply(new BigDecimal(productCostAmountVO.getCount())).setScale(2, RoundingMode.HALF_UP));
} else if (consCostAmountList.containsKey(productCostAmountVO.getProductId())) {
BigDecimal costAmount = consCostAmountList.get(productCostAmountVO.getProductId());
productCostAmount = productCostAmount.add(costAmount.multiply(new BigDecimal(productCostAmountVO.getCount())).setScale(2, RoundingMode.HALF_UP));
}
}
return productCostAmount;
}
/**
* 计算 客单价 翻台率 净利润 净利率 毛利润 毛利率
*/
private void calculateShopOrderStatistic(ShopOrderStatistic result) {
//毛利润(订单实付金额-商品成本)
if (result.getProductCostAmount() == null) {
result.setProductCostAmount(BigDecimal.ZERO);
}
result.setProfitAmount(result.getPayAmount().subtract(result.getProductCostAmount()));
//毛利率(订单实付金额-商品成本)/订单实付金额*100%
if (result.getPayAmount().compareTo(BigDecimal.ZERO) > 0) {
BigDecimal profitRate = result.getProfitAmount().divide(result.getPayAmount(), 4, RoundingMode.HALF_DOWN).multiply(BigDecimal.valueOf(100));
@@ -199,13 +243,14 @@ public class ShopOrderStatisticServiceImpl extends ServiceImpl<ShopOrderStatisti
result.setAvgPayAmount(result.getPayAmount());
}
//翻台率 (订单数-桌台数)/桌台数*100%
if (tableCount > 0) {
BigDecimal turnoverRate = new BigDecimal(result.getOrderCount()).subtract(new BigDecimal(tableCount)).divide(new BigDecimal(tableCount), 4, RoundingMode.HALF_DOWN).multiply(BigDecimal.valueOf(100));
if (result.getTableCount() != null && result.getTableCount() > 0) {
BigDecimal turnoverRate = new BigDecimal(
result.getOrderCount()).subtract(new BigDecimal(result.getTableCount()))
.divide(new BigDecimal(result.getTableCount()), 4, RoundingMode.HALF_DOWN).multiply(BigDecimal.valueOf(100));
result.setTurnoverRate(turnoverRate);
} else {
result.setTurnoverRate(BigDecimal.ZERO);
}
return result;
}