fix: 平台总收入分析-数据分类与电站收入分析同口径(近6月+当月)
底部数据分类原为全量统计(结算账单/停车记录/购物会员合计无日期过滤),
与上方「电站收入分析」近6月图表口径不一致,电站筛选后数据对不上。改为:
- 电费/服务费复用 charge() 聚合(历史月结算账单+当月原始订单),
保证底部合计=图表6个月相加,与加盟商收支同口径
- countAll/合作商分成/超时占位费/购物收益/会员费 均加 sixBefore 近6月过滤
- 抽出 buildLastSixMonths 供 /six/charge 与 /six/total 共用
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| | |
| | | } |
| | | |
| | | @Override |
| | | public R<BigDecimal> getRecordAmount(List<Integer> siteIds) { |
| | | public R<BigDecimal> getRecordAmount(List<Integer> siteIds, String sixBefore) { |
| | | return R.fail("获取数据失败:" + throwable.getMessage()); |
| | | } |
| | | |
| | |
| | | R<TParkingRecord> getRecordById(@RequestParam("id") Long siteId); |
| | | |
| | | @PostMapping(value = "/t-parking-lot/getRecordAmount") |
| | | R<BigDecimal> getRecordAmount(@RequestParam(value = "siteIds", required = false) List<Integer> siteIds); |
| | | R<BigDecimal> getRecordAmount(@RequestParam(value = "siteIds", required = false) List<Integer> siteIds, |
| | | @RequestParam(value = "sixBefore", required = false) String sixBefore); |
| | | |
| | | |
| | | /** |
| | |
| | | import com.ruoyi.common.log.enums.OperatorType; |
| | | import com.ruoyi.common.security.annotation.Logical; |
| | | import com.ruoyi.common.security.annotation.RequiresPermissions; |
| | | import java.time.LocalDate; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | |
| | | |
| | | @PostMapping(value = "/getRecordAmount") |
| | | public R<BigDecimal> getRecordAmount(@RequestParam(value = "siteIds", required = false) List<Integer> siteIds){ |
| | | BigDecimal sum = parkingRecordService.getSum(siteIds); |
| | | public R<BigDecimal> getRecordAmount(@RequestParam(value = "siteIds", required = false) List<Integer> siteIds, |
| | | @RequestParam(value = "sixBefore", required = false) String sixBefore){ |
| | | LocalDate sixBeforeDate = sixBefore == null || sixBefore.isEmpty() ? null : LocalDate.parse(sixBefore); |
| | | BigDecimal sum = parkingRecordService.getSum(siteIds, sixBeforeDate); |
| | | return R.ok(sum); |
| | | } |
| | | |
| | |
| | | */ |
| | | public interface TParkingRecordMapper extends BaseMapper<TParkingRecord> { |
| | | |
| | | BigDecimal getSum(@Param("siteIds") List<Integer> siteIds); |
| | | BigDecimal getSum(@Param("siteIds") List<Integer> siteIds, @Param("sixBefore") LocalDate sixBefore); |
| | | |
| | | /** |
| | | * 停车缴费订单列表 |
| | |
| | | */ |
| | | public interface TParkingRecordService extends IService<TParkingRecord> { |
| | | |
| | | BigDecimal getSum(List<Integer> siteIds); |
| | | BigDecimal getSum(List<Integer> siteIds, LocalDate sixBefore); |
| | | |
| | | /** |
| | | * 停车缴费订单列表 |
| | |
| | | private SiteClient siteClient; |
| | | |
| | | @Override |
| | | public BigDecimal getSum(List<Integer> siteIds) { |
| | | return this.baseMapper.getSum(siteIds); |
| | | public BigDecimal getSum(List<Integer> siteIds, LocalDate sixBefore) { |
| | | return this.baseMapper.getSum(siteIds, sixBefore); |
| | | } |
| | | |
| | | @Autowired |
| | |
| | | from t_parking_record tpr |
| | | left join t_parking_lot tpl on tpr.parking_lot_id = tpl.id |
| | | <where> |
| | | <if test="sixBefore != null"> |
| | | tpr.in_parking_time >= #{sixBefore} |
| | | </if> |
| | | <if test="siteIds != null and siteIds.size() > 0"> |
| | | tpl.site_id in |
| | | AND tpl.site_id in |
| | | <foreach collection="siteIds" item="siteId" open="(" separator="," close=")"> |
| | | #{siteId} |
| | | </foreach> |
| | |
| | | public R<List<SixChargingDto>> charge(Integer siteId, Integer partnerId) { |
| | | Long userId = tokenService.getLoginUser().getUserid(); |
| | | SysUser sysUser = sysUserClient.getSysUser(userId).getData(); |
| | | boolean partnerView = isPartnerView(sysUser); |
| | | List<Integer> siteIds = resolvePlatformRevenueSiteIds(userId, sysUser, siteId, partnerId); |
| | | LocalDate sixBefore = PreviousSixMonths.get(); |
| | | //通过siteIds进行sql查询统计 |
| | | List<SixChargingDto> chargingDtos = chargingOrderService.charge(sixBefore, siteIds, false); |
| | | return R.ok(buildLastSixMonths(siteIds, false)); |
| | | } |
| | | |
| | | /** |
| | | * 近6月+当月电站收入:历史月读结算账单、当月补原始订单。 |
| | | * 与「电站收入分析」图表、底部数据分类及加盟商收支同口径。 |
| | | */ |
| | | private List<SixChargingDto> buildLastSixMonths(List<Integer> siteIds, boolean partnerView) { |
| | | LocalDate sixBefore = PreviousSixMonths.get(); |
| | | List<SixChargingDto> chargingDtos = chargingOrderService.charge(sixBefore, siteIds, partnerView); |
| | | LocalDate statisticsEndMonth = resolveStatisticsEndMonth(LocalDate.now(), chargingDtos); |
| | | List<SixChargingDto> sixChargingDtos = generateLastSixMonths(statisticsEndMonth); |
| | | for (SixChargingDto sixChargingDto : sixChargingDtos) { |
| | |
| | | } |
| | | |
| | | } |
| | | |
| | | return R.ok(sixChargingDtos); |
| | | |
| | | return sixChargingDtos; |
| | | } |
| | | |
| | | |
| | |
| | | SysUser sysUser = sysUserClient.getSysUser(userId).getData(); |
| | | boolean partnerView = isPartnerView(sysUser); |
| | | List<Integer> siteIds = resolvePlatformRevenueSiteIds(userId, sysUser, siteId, partnerId); |
| | | Map<String,Object> map = chargingOrderService.countAll(siteIds, false); |
| | | if (map == null) { |
| | | map = new HashMap<String,Object>(); |
| | | } |
| | | LocalDate sixBefore = PreviousSixMonths.get(); |
| | | Map<String,Object> map = new HashMap<String,Object>(); |
| | | // 电费/服务费与上方「电站收入分析」图表同口径:近6月结算账单 + 当月原始订单,保证底部合计=图表6个月相加 |
| | | List<SixChargingDto> sixChargingDtos = buildLastSixMonths(siteIds, false); |
| | | map.put("electrovalence", sixChargingDtos.stream() |
| | | .filter(Objects::nonNull) |
| | | .map(SixChargingDto::getElectrovalence) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add)); |
| | | map.put("service_charge", sixChargingDtos.stream() |
| | | .filter(Objects::nonNull) |
| | | .map(SixChargingDto::getServiceCharge) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add)); |
| | | // 合作商分成/三方平台分佣按近6月结算口径统计(与图表月份窗口一致) |
| | | Map<String,Object> sub = chargingOrderService.countAll(siteIds, false, sixBefore); |
| | | map.put("commission_amount", sub == null ? BigDecimal.ZERO : sub.get("commission_amount")); |
| | | map.put("sharing_amount", sub == null ? BigDecimal.ZERO : sub.get("sharing_amount")); |
| | | boolean platformVisible = !partnerView; |
| | | if(platformVisible){ |
| | | R<BigDecimal> parkingAmountResult = parkingLotClient.getRecordAmount(siteIds); |
| | | R<BigDecimal> parkingAmountResult = parkingLotClient.getRecordAmount(siteIds, sixBefore.toString()); |
| | | BigDecimal data = parkingAmountResult == null || parkingAmountResult.getData() == null |
| | | ? BigDecimal.ZERO : parkingAmountResult.getData(); |
| | | map.put("parkingAmount",data); |
| | | BigDecimal data1 = shoppingOrderService.getSumAmount(); |
| | | BigDecimal data1 = shoppingOrderService.getSumAmount(sixBefore); |
| | | map.put("shopAmount",data1); |
| | | BigDecimal data2 = vipOrderService.getSumAmout(); |
| | | BigDecimal data2 = vipOrderService.getSumAmout(sixBefore); |
| | | map.put("vipAmount",data2); |
| | | }else{ |
| | | map.put("parkingAmount",0); |
| | |
| | | |
| | | List<SixCircleDto> circle(@Param("siteIds") List<Integer> siteIds, @Param("sixBefore") LocalDate sixBefore, @Param("partnerView") Boolean partnerView); |
| | | |
| | | BigDecimal sumSuccessfulShareAmount(@Param("siteIds") List<Integer> siteIds); |
| | | BigDecimal sumSuccessfulShareAmount(@Param("siteIds") List<Integer> siteIds, @Param("sixBefore") LocalDate sixBefore); |
| | | |
| | | Map<String, Object> countAll(@Param("siteIds") List<Integer> siteIds, @Param("partnerView") Boolean partnerView); |
| | | Map<String, Object> countAll(@Param("siteIds") List<Integer> siteIds, @Param("partnerView") Boolean partnerView, @Param("sixBefore") LocalDate sixBefore); |
| | | |
| | | List<Map<String, Object>> chargingOrderShareIncomeByPayChannel(@Param("sixBefore") LocalDate sixBefore, @Param("siteIds") List<Integer> siteIds); |
| | | |
| | |
| | | |
| | | List<SixShopDto> sixBefore(@Param("sixBefore")LocalDate sixBefore,@Param("status") Integer status); |
| | | |
| | | BigDecimal getSumAmount(); |
| | | BigDecimal getSumAmount(@Param("sixBefore") LocalDate sixBefore); |
| | | |
| | | List<Map<String, Object>> getData(@Param("statisticsQueryDto")ChargingStatisticsQueryDto statisticsQueryDto); |
| | | } |
| | |
| | | |
| | | List<SixVipDto> sixBefore(@Param("sixBefore")LocalDate sixBefore); |
| | | |
| | | BigDecimal getSumAmout(); |
| | | BigDecimal getSumAmout(@Param("sixBefore") LocalDate sixBefore); |
| | | } |
| | |
| | | |
| | | List<SixCircleDto> circle(List<Integer> siteIds,LocalDate sixBefore, Boolean partnerView); |
| | | |
| | | Map<String, Object> countAll(List<Integer> siteIds, Boolean partnerView); |
| | | Map<String, Object> countAll(List<Integer> siteIds, Boolean partnerView, LocalDate sixBefore); |
| | | |
| | | List<SixIncomeCircleDto> payTypeCircle(LocalDate sixBefore, List<Integer> siteIds, Boolean partnerView); |
| | | |
| | |
| | | |
| | | List<SixShopDto> sixBefore(LocalDate sixBefore, Integer status); |
| | | |
| | | BigDecimal getSumAmount(); |
| | | BigDecimal getSumAmount(LocalDate sixBefore); |
| | | |
| | | List<Map<String, Object>> getData(ChargingStatisticsQueryDto statisticsQueryDto); |
| | | } |
| | |
| | | |
| | | List<SixVipDto> sixBefore(LocalDate sixBefore); |
| | | |
| | | BigDecimal getSumAmout(); |
| | | BigDecimal getSumAmout(LocalDate sixBefore); |
| | | |
| | | void payBack(String outTradeNo); |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | public Map<String, Object> countAll(List<Integer> siteIds, Boolean partnerView) { |
| | | Map<String, Object> result = this.baseMapper.countAll(siteIds, partnerView); |
| | | public Map<String, Object> countAll(List<Integer> siteIds, Boolean partnerView, LocalDate sixBefore) { |
| | | Map<String, Object> result = this.baseMapper.countAll(siteIds, partnerView, sixBefore); |
| | | if (!Boolean.TRUE.equals(partnerView) && result != null) { |
| | | result.put("commission_amount", this.baseMapper.sumSuccessfulShareAmount(siteIds)); |
| | | result.put("commission_amount", this.baseMapper.sumSuccessfulShareAmount(siteIds, sixBefore)); |
| | | } |
| | | return result; |
| | | } |
| | |
| | | } |
| | | |
| | | @Override |
| | | public BigDecimal getSumAmount() { |
| | | return this.baseMapper.getSumAmount(); |
| | | public BigDecimal getSumAmount(LocalDate sixBefore) { |
| | | return this.baseMapper.getSumAmount(sixBefore); |
| | | } |
| | | |
| | | @Override |
| | |
| | | } |
| | | |
| | | @Override |
| | | public BigDecimal getSumAmout() { |
| | | return this.baseMapper.getSumAmout(); |
| | | public BigDecimal getSumAmout(LocalDate sixBefore) { |
| | | return this.baseMapper.getSumAmout(sixBefore); |
| | | } |
| | | |
| | | @Override |
| | |
| | | 0 AS sharing_amount |
| | | FROM t_charging_order_share_record |
| | | WHERE del_flag = 0 AND online_share_status IN ('SUCCESS', 'RECORDED') |
| | | <if test="sixBefore != null"> |
| | | AND create_time >= #{sixBefore} |
| | | </if> |
| | | <if test="siteIds != null and siteIds.size() > 0"> |
| | | AND site_id IN |
| | | <foreach collection="siteIds" item="siteId" open="(" separator="," close=")"> |
| | |
| | | COALESCE(ROUND(SUM(IFNULL(tripartite_commission, 0)), 2), 0) AS sharing_amount |
| | | FROM t_charging_settlement_bill |
| | | WHERE statistical_date_type = 1 AND site_id != 0 |
| | | <if test="sixBefore != null"> |
| | | AND billing_cycle >= #{sixBefore} |
| | | AND billing_cycle < DATE_FORMAT(CURDATE(), '%Y-%m-01') |
| | | </if> |
| | | <if test="siteIds != null and siteIds.size() > 0"> |
| | | AND site_id IN |
| | | <foreach collection="siteIds" item="siteId" open="(" separator="," close=")"> |
| | |
| | | SELECT COALESCE(ROUND(SUM(IFNULL(share_amount, 0)), 2), 0) |
| | | FROM t_charging_order_share_record |
| | | WHERE del_flag = 0 AND online_share_status IN ('SUCCESS', 'RECORDED') |
| | | <if test="sixBefore != null"> |
| | | AND create_time >= #{sixBefore} |
| | | </if> |
| | | <if test="siteIds != null and siteIds.size() > 0"> |
| | | AND site_id IN |
| | | <foreach collection="siteIds" item="siteId" open="(" separator="," close=")"> |
| | |
| | | select sum(payment_amount) |
| | | from t_shopping_order |
| | | where del_flag = 0 and payment_status = 2 and ISNULL(refund_status) and status!=4 |
| | | <if test="sixBefore != null"> |
| | | and DATE_FORMAT(create_time, '%Y-%m-%d') >= DATE_FORMAT(#{sixBefore}, '%Y-%m-%d') |
| | | </if> |
| | | </select> |
| | | <select id="getData" resultType="java.util.Map"> |
| | | |
| | |
| | | WHERE |
| | | del_flag = ${@com.ruoyi.common.core.enums.DelFlagEnum@NO.getCode()} AND |
| | | payment_status = 2 |
| | | <if test="sixBefore != null"> |
| | | AND create_time > #{sixBefore} |
| | | </if> |
| | | </select> |
| | | |
| | | </mapper> |
| | |
| | | private TChargingOrderServiceImpl service; |
| | | private TChargingOrderMapper mapper; |
| | | private List<Integer> siteIds; |
| | | private LocalDate sixBefore; |
| | | |
| | | @BeforeEach |
| | | void setUp() { |
| | |
| | | siteIds = new ArrayList<>(); |
| | | siteIds.add(122); |
| | | siteIds.add(123); |
| | | sixBefore = LocalDate.of(2026, 1, 1); |
| | | ReflectionTestUtils.setField(service, "baseMapper", mapper); |
| | | } |
| | | |
| | |
| | | void platformViewAddsSuccessfulPartnerShareAmount() { |
| | | Map<String, Object> totals = new HashMap<>(); |
| | | totals.put("electrovalence", new BigDecimal("100.00")); |
| | | when(mapper.countAll(siteIds, false)).thenReturn(totals); |
| | | when(mapper.sumSuccessfulShareAmount(siteIds)).thenReturn(new BigDecimal("12.34")); |
| | | when(mapper.countAll(siteIds, false, sixBefore)).thenReturn(totals); |
| | | when(mapper.sumSuccessfulShareAmount(siteIds, sixBefore)).thenReturn(new BigDecimal("12.34")); |
| | | |
| | | Map<String, Object> result = service.countAll(siteIds, false); |
| | | Map<String, Object> result = service.countAll(siteIds, false, sixBefore); |
| | | |
| | | assertSame(totals, result); |
| | | assertEquals(new BigDecimal("12.34"), result.get("commission_amount")); |
| | | verify(mapper).sumSuccessfulShareAmount(siteIds); |
| | | verify(mapper).sumSuccessfulShareAmount(siteIds, sixBefore); |
| | | } |
| | | |
| | | @Test |
| | | void partnerViewUsesShareRecordTotalsWithoutASecondQuery() { |
| | | Map<String, Object> totals = new HashMap<>(); |
| | | totals.put("commission_amount", new BigDecimal("8.90")); |
| | | when(mapper.countAll(siteIds, true)).thenReturn(totals); |
| | | when(mapper.countAll(siteIds, true, sixBefore)).thenReturn(totals); |
| | | |
| | | Map<String, Object> result = service.countAll(siteIds, true); |
| | | Map<String, Object> result = service.countAll(siteIds, true, sixBefore); |
| | | |
| | | assertSame(totals, result); |
| | | assertEquals(new BigDecimal("8.90"), result.get("commission_amount")); |
| | | verify(mapper, never()).sumSuccessfulShareAmount(siteIds); |
| | | verify(mapper, never()).sumSuccessfulShareAmount(siteIds, sixBefore); |
| | | } |
| | | |
| | | @Test |