Merge branch '2.2' of http://120.76.84.145:10101/gitblit/r/java/mx_charging_pile into 2.2
| | |
| | | import com.ruoyi.order.api.vo.TOrderInvoiceVO; |
| | | import com.ruoyi.order.dto.*; |
| | | import com.ruoyi.order.export.OrderInvoiceExport; |
| | | import com.ruoyi.order.export.InvoiceApplicationWorkbookBuilder; |
| | | import com.ruoyi.order.service.TOrderInvoiceService; |
| | | import io.swagger.annotations.Api; |
| | | import io.swagger.annotations.ApiOperation; |
| | |
| | | } |
| | | |
| | | private Workbook buildInvoiceWorkbook(TOrderInvoiceVO invoice) { |
| | | OrderInvoiceExport export = new OrderInvoiceExport(); |
| | | BeanUtils.copyProperties(invoice, export); |
| | | if (invoice.getCreateTime() != null) { |
| | | export.setApplyTime(DateUtils.localDateTimeToString(invoice.getCreateTime())); |
| | | } |
| | | if (invoice.getBillingTime() != null) { |
| | | export.setBillingTime(DateUtils.localDateTimeToString(invoice.getBillingTime())); |
| | | } |
| | | return ExcelExportUtil.exportExcel( |
| | | new ExportParams(), |
| | | OrderInvoiceExport.class, |
| | | new ArrayList<>(Collections.singletonList(export))); |
| | | return InvoiceApplicationWorkbookBuilder.build(invoice); |
| | | } |
| | | |
| | | private String buildInvoiceFileName(TOrderInvoiceVO invoice) { |
| | |
| | | import lombok.Data; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | /** |
| | | * @author zhibing.pu |
| | |
| | | private BigDecimal chargingCost; |
| | | @ApiModelProperty("充电状态(0=未知,1=等待中,2=启动中,3=充电中,4=停止中,5=已结束)") |
| | | private Integer status; |
| | | @ApiModelProperty("预约充电时间") |
| | | private LocalDateTime reservationTime; |
| | | } |
| New file |
| | |
| | | package com.ruoyi.order.export; |
| | | |
| | | import com.ruoyi.order.api.vo.TOrderInvoiceVO; |
| | | import org.apache.poi.hssf.usermodel.HSSFWorkbook; |
| | | import org.apache.poi.ss.usermodel.BorderStyle; |
| | | import org.apache.poi.ss.usermodel.Cell; |
| | | import org.apache.poi.ss.usermodel.CellStyle; |
| | | import org.apache.poi.ss.usermodel.Font; |
| | | import org.apache.poi.ss.usermodel.HorizontalAlignment; |
| | | import org.apache.poi.ss.usermodel.Sheet; |
| | | import org.apache.poi.ss.usermodel.VerticalAlignment; |
| | | import org.apache.poi.ss.usermodel.Workbook; |
| | | import org.apache.poi.ss.util.CellRangeAddress; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.time.LocalDateTime; |
| | | import java.time.format.DateTimeFormatter; |
| | | |
| | | /** Builds the fixed-format invoice application form used by the finance department. */ |
| | | public final class InvoiceApplicationWorkbookBuilder { |
| | | private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd"); |
| | | |
| | | private InvoiceApplicationWorkbookBuilder() { |
| | | } |
| | | |
| | | public static Workbook build(TOrderInvoiceVO invoice) { |
| | | Workbook workbook = new HSSFWorkbook(); |
| | | Sheet sheet = workbook.createSheet("开票申请表"); |
| | | int[] widths = {14, 3, 18, 16, 16, 16, 16}; |
| | | for (int i = 0; i < widths.length; i++) { |
| | | sheet.setColumnWidth(i, widths[i] * 256); |
| | | } |
| | | sheet.getPrintSetup().setLandscape(false); |
| | | sheet.getPrintSetup().setFitWidth((short) 1); |
| | | sheet.setFitToPage(true); |
| | | sheet.setMargin(Sheet.LeftMargin, 0.25); |
| | | sheet.setMargin(Sheet.RightMargin, 0.25); |
| | | sheet.setMargin(Sheet.TopMargin, 0.35); |
| | | sheet.setMargin(Sheet.BottomMargin, 0.35); |
| | | |
| | | CellStyle title = style(workbook, false, true, (short) 16); |
| | | CellStyle label = style(workbook, true, false, (short) 11); |
| | | CellStyle value = style(workbook, false, false, (short) 11); |
| | | CellStyle footer = style(workbook, false, false, (short) 11); |
| | | |
| | | merged(sheet, 0, 0, 0, 6, "开票申请表", title, 30); |
| | | row(sheet, 1, "开票申请时间", value(invoice == null ? null : invoice.getCreateTime()), label, value, 28); |
| | | row(sheet, 2, "充电站名称", text(invoice == null ? null : invoice.getSiteName()), label, value, 28); |
| | | row(sheet, 3, "发票抬头", text(invoice == null ? null : invoice.getName()), label, value, 28); |
| | | row(sheet, 4, "纳税人识别号", text(invoice == null ? null : invoice.getTaxIdentificationNumber()), label, value, 28); |
| | | |
| | | merged(sheet, 5, 0, 5, 1, "税率%", label, 28); |
| | | merged(sheet, 5, 2, 5, 2, taxRate(invoice), value, 28); |
| | | merged(sheet, 5, 3, 5, 4, "应(已)开票金额(元)", label, 28); |
| | | Cell amountCell = merged(sheet, 5, 5, 5, 6, null, value, 28); |
| | | if (invoice != null && invoice.getTotalAmount() != null) { |
| | | amountCell.setCellValue(invoice.getTotalAmount().doubleValue()); |
| | | amountCell.setCellStyle(value); |
| | | } |
| | | |
| | | row(sheet, 6, "发票类型", text(invoice == null ? null : invoice.getInvoiceType()), label, value, 28); |
| | | row(sheet, 7, "预计回款时间", "", label, value, 28); |
| | | merged(sheet, 8, 0, 8, 6, "", value, 28); |
| | | merged(sheet, 9, 0, 9, 1, "财务科:", footer, 28); |
| | | merged(sheet, 9, 2, 9, 4, "新能源业务中心:", footer, 28); |
| | | merged(sheet, 9, 5, 9, 6, "经办人:", footer, 28); |
| | | return workbook; |
| | | } |
| | | |
| | | private static void row(Sheet sheet, int row, String labelText, String valueText, |
| | | CellStyle labelStyle, CellStyle valueStyle, int height) { |
| | | merged(sheet, row, 0, row, 1, labelText, labelStyle, height); |
| | | merged(sheet, row, 2, row, 6, valueText, valueStyle, height); |
| | | } |
| | | |
| | | private static Cell merged(Sheet sheet, int firstRow, int firstColumn, int lastRow, |
| | | int lastColumn, String text, CellStyle style, int height) { |
| | | org.apache.poi.ss.usermodel.Row row = sheet.getRow(firstRow); |
| | | if (row == null) { |
| | | row = sheet.createRow(firstRow); |
| | | } |
| | | row.setHeightInPoints(height); |
| | | for (int column = firstColumn; column <= lastColumn; column++) { |
| | | Cell cell = row.getCell(column); |
| | | if (cell == null) { |
| | | cell = row.createCell(column); |
| | | } |
| | | cell.setCellStyle(style); |
| | | } |
| | | Cell cell = row.getCell(firstColumn); |
| | | if (text != null) { |
| | | cell.setCellValue(text); |
| | | } |
| | | if (firstColumn != lastColumn || firstRow != lastRow) { |
| | | sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstColumn, lastColumn)); |
| | | } |
| | | return cell; |
| | | } |
| | | |
| | | private static CellStyle style(Workbook workbook, boolean red, boolean bold, short fontSize) { |
| | | CellStyle style = workbook.createCellStyle(); |
| | | style.setAlignment(HorizontalAlignment.CENTER); |
| | | style.setVerticalAlignment(VerticalAlignment.CENTER); |
| | | style.setWrapText(true); |
| | | style.setBorderTop(BorderStyle.THIN); |
| | | style.setBorderBottom(BorderStyle.THIN); |
| | | style.setBorderLeft(BorderStyle.THIN); |
| | | style.setBorderRight(BorderStyle.THIN); |
| | | Font font = workbook.createFont(); |
| | | font.setFontName("宋体"); |
| | | font.setFontHeightInPoints(fontSize); |
| | | font.setBold(bold); |
| | | if (red) { |
| | | font.setColor((short) 10); |
| | | } |
| | | style.setFont(font); |
| | | return style; |
| | | } |
| | | |
| | | private static String text(String value) { |
| | | return value == null ? "" : value; |
| | | } |
| | | |
| | | private static String value(LocalDateTime value) { |
| | | return value == null ? "" : value.format(DATE_FORMAT); |
| | | } |
| | | |
| | | private static String taxRate(TOrderInvoiceVO invoice) { |
| | | if (invoice == null) { |
| | | return ""; |
| | | } |
| | | BigDecimal rate = firstNonZero(invoice.getElectricityTariff(), invoice.getServiceTariff(), invoice.getAddedServiceTariff()); |
| | | if (rate == null) { |
| | | return ""; |
| | | } |
| | | if (rate.compareTo(BigDecimal.ONE) <= 0) { |
| | | rate = rate.multiply(BigDecimal.valueOf(100)); |
| | | } |
| | | return rate.stripTrailingZeros().setScale(0, RoundingMode.HALF_UP).toPlainString() + "%"; |
| | | } |
| | | |
| | | private static BigDecimal firstNonZero(BigDecimal... values) { |
| | | for (BigDecimal value : values) { |
| | | if (value != null && value.compareTo(BigDecimal.ZERO) != 0) { |
| | | return value; |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | } |
| | |
| | | } |
| | | return vipId == null ? null : vipClient.getInfo1(vipId).getData(); |
| | | } |
| | | |
| | | /** |
| | | * 将会员配置转换为订单统一使用的 0~1 折扣系数。 |
| | | * 常规会员的计费策略已按系数保存;内部会员后台按“8折”这种 0~10 数值保存。 |
| | | */ |
| | | BigDecimal resolveChargingVipDiscount(TVip vip, TAccountingStrategy accountingStrategy) { |
| | | if (vip == null) { |
| | | return null; |
| | | } |
| | | BigDecimal discount; |
| | | if (Integer.valueOf(1).equals(vip.getType())) { |
| | | discount = accountingStrategy == null ? null : accountingStrategy.getDiscount(); |
| | | } else { |
| | | discount = vip.getDiscount() == null ? null : vip.getDiscount().divide(BigDecimal.TEN); |
| | | } |
| | | return isEffectiveVipDiscount(discount) ? discount : null; |
| | | } |
| | | |
| | | boolean isEffectiveVipDiscount(BigDecimal discount) { |
| | | return discount != null |
| | | && discount.compareTo(BigDecimal.ZERO) > 0 |
| | | && discount.compareTo(BigDecimal.ONE) < 0; |
| | | } |
| | | |
| | | boolean shouldConsumeVipDiscount(BigDecimal discountAmount) { |
| | | return discountAmount != null && discountAmount.compareTo(BigDecimal.ZERO) > 0; |
| | | } |
| | | @Override |
| | | public AjaxResult paymentChargingOrder(AddChargingOrder addChargingOrder) { |
| | | Long userId = tokenService.getLoginUserApplet().getUserId(); |
| | |
| | | TAppUserVipDetail vipDetail = appUserVipDetailClient.getAppUserVipDetail(getAppUserVipDetail).getData(); |
| | | TVip vip = getVipSnapshot(vipDetail, appUser.getVipId()); |
| | | if (null != vip && null != vipDetail) { |
| | | BigDecimal discount = null; |
| | | if (Integer.valueOf(1).equals(vip.getType())) { |
| | | //普通会员折扣使用积分策略上的折扣,且有最高优惠金额 |
| | | discount = accountingStrategy.getDiscount(); |
| | | } else { |
| | | //内部会员使用会员信息设置的折扣,没有最高优惠金额 |
| | | discount = vip.getDiscount(); |
| | | } |
| | | BigDecimal discount = resolveChargingVipDiscount(vip, accountingStrategy); |
| | | Integer chargeNum = vipDetail.getChargeNum(); |
| | | if (null != discount && null != chargeNum && 0 < chargeNum) { |
| | | chargingOrder.setVipDiscount(discount); |
| | |
| | | recordBalanceConsume(chargingOrder, balancePayAmount); |
| | | } |
| | | if (thirdPayAmount.compareTo(BigDecimal.ZERO) == 0) { |
| | | return chargingOrderCallback(addChargingOrder.getPaymentType(), chargingOrder.getCode(), whitelistMatched ? "WHITELIST" : "BALANCE", null); |
| | | return completeChargingOrderPayment(chargingOrder, whitelistMatched ? "WHITELIST" : "BALANCE"); |
| | | } |
| | | //会员优惠折扣将其计入增加充电时长(增加总充电金额) |
| | | //如果充电总金额未使用完,则需要退回费用=(原金额/总金额)*(总金额-实际充电金额) |
| | |
| | | if (chargingOrder == null) { |
| | | return AjaxResult.error("支付回调订单不存在"); |
| | | } |
| | | return completeChargingOrderPayment(chargingOrder, transaction_id); |
| | | } |
| | | |
| | | /** |
| | | * 完成订单支付状态和充电额度初始化。 |
| | | * 本地余额、白名单零元支付直接传入刚保存的订单,避免读写分离下立即回查读不到新订单。 |
| | | */ |
| | | AjaxResult completeChargingOrderPayment(TChargingOrder chargingOrder, String transactionId) { |
| | | if (chargingOrder.getRechargePaymentStatus() == 2) { |
| | | if (isIcbcOrder(chargingOrder) && StringUtils.hasLength(transaction_id) |
| | | && !transaction_id.equals(chargingOrder.getRechargeSerialNumber())) { |
| | | chargingOrder.setRechargeSerialNumber(transaction_id); |
| | | if (isIcbcOrder(chargingOrder) && StringUtils.hasLength(transactionId) |
| | | && !transactionId.equals(chargingOrder.getRechargeSerialNumber())) { |
| | | chargingOrder.setRechargeSerialNumber(transactionId); |
| | | this.updateById(chargingOrder); |
| | | } |
| | | return AjaxResult.success(); |
| | |
| | | .eq(TChargingOrder::getId, chargingOrder.getId()) |
| | | .eq(TChargingOrder::getRechargePaymentStatus, 1) |
| | | .set(TChargingOrder::getRechargePaymentStatus, 2) |
| | | .set(TChargingOrder::getRechargeSerialNumber, transaction_id) |
| | | .set(TChargingOrder::getRechargeSerialNumber, transactionId) |
| | | .set(TChargingOrder::getStatus, 2) |
| | | .set(TChargingOrder::getPayTime, callbackPayTime)); |
| | | if (claimed == 0) { |
| | |
| | | recordBalanceConsume(chargingOrder, money(chargingOrder.getBalancePayAmount())); |
| | | } |
| | | chargingOrder.setRechargePaymentStatus(2); |
| | | chargingOrder.setRechargeSerialNumber(transaction_id); |
| | | chargingOrder.setRechargeSerialNumber(transactionId); |
| | | chargingOrder.setStatus(2); |
| | | chargingOrder.setPayTime(callbackPayTime); |
| | | |
| | |
| | | |
| | | TAppUser appUser = appUserClient.getUserById(chargingOrder.getAppUserId()).getData(); |
| | | //判断会员是否还有充电优惠次数,计算会员优惠的折扣金额 |
| | | if (!isWhitelistOrder(chargingOrder) && null != appUser.getVipId()) { |
| | | if (!isWhitelistOrder(chargingOrder) && null != appUser.getVipId() && isEffectiveVipDiscount(discount)) { |
| | | GetAppUserVipDetail getAppUserVipDetail = new GetAppUserVipDetail(); |
| | | getAppUserVipDetail.setAppUserId(chargingOrder.getAppUserId()); |
| | | getAppUserVipDetail.setVipId(appUser.getVipId()); |
| | | TAppUserVipDetail data = appUserVipDetailClient.getAppUserVipDetail(getAppUserVipDetail).getData(); |
| | | if (null != data && data.getChargeNum() > 0) { |
| | | if (null != data && data.getChargeNum() != null && data.getChargeNum() > 0) { |
| | | //计算折扣 |
| | | List<AccountingStrategyDetailOrder> list = accountingStrategyDetailOrderClient.getAllAccountingStrategyDetailOrder(chargingOrder.getId()).getData(); |
| | | list.get(list.size() - 1).setEndTime("23:59"); |
| | |
| | | } |
| | | } |
| | | } |
| | | if (null != discount) { |
| | | discountAmount = serviceCharge.multiply(new BigDecimal(1).subtract(discount)); |
| | | } |
| | | |
| | | if (discountAmount.compareTo(BigDecimal.ZERO) >= 0) { |
| | | //计算会员最大优惠金额 |
| | | TVip vip = getVipSnapshot(data, appUser.getVipId()); |
| | | BigDecimal maximumDeduction = vip == null ? null : vip.getMaximumDeduction(); |
| | | //普通会员有最高优惠限制 |
| | | if (vip != null && Integer.valueOf(1).equals(vip.getType()) && maximumDeduction != null && discountAmount.compareTo(maximumDeduction) > 0) { |
| | | discountAmount = maximumDeduction; |
| | | } |
| | | discountAmount = serviceCharge.multiply(BigDecimal.ONE.subtract(discount)); |
| | | |
| | | //计算会员最大优惠金额 |
| | | TVip vip = getVipSnapshot(data, appUser.getVipId()); |
| | | BigDecimal maximumDeduction = vip == null ? null : vip.getMaximumDeduction(); |
| | | //普通会员有最高优惠限制 |
| | | if (vip != null && Integer.valueOf(1).equals(vip.getType()) && maximumDeduction != null |
| | | && maximumDeduction.compareTo(BigDecimal.ZERO) >= 0 |
| | | && discountAmount.compareTo(maximumDeduction) > 0) { |
| | | discountAmount = maximumDeduction; |
| | | } |
| | | discountAmount = discountAmount.setScale(4, RoundingMode.HALF_EVEN); |
| | | if (discountAmount.compareTo(BigDecimal.ZERO) >= 0) { |
| | | if (shouldConsumeVipDiscount(discountAmount)) { |
| | | data.setChargeNum(data.getChargeNum() - 1); |
| | | appUserVipDetailClient.updateAppUserVipDetail(data); |
| | | } |
| | |
| | | public ChargingDetails getChargingDetails(Integer id) { |
| | | Long userId = tokenService.getLoginUserApplet().getUserId(); |
| | | TChargingOrder one = this.getOne(new LambdaQueryWrapper<TChargingOrder>().eq(TChargingOrder::getAppUserId, userId).eq(TChargingOrder::getChargingGunId, id) |
| | | .eq(TChargingOrder::getRechargePaymentStatus, 2).eq(TChargingOrder::getDelFlag, 0).orderByDesc(TChargingOrder::getStartTime).last(" limit 0, 1")); |
| | | .eq(TChargingOrder::getRechargePaymentStatus, 2) |
| | | .in(TChargingOrder::getStatus, Arrays.asList(2, 3, 4)) |
| | | .eq(TChargingOrder::getDelFlag, 0) |
| | | .orderByDesc(TChargingOrder::getCreateTime) |
| | | .last(" limit 0, 1")); |
| | | if (null == one || !one.getAppUserId().equals(userId)) { |
| | | return null; |
| | | } |
| | |
| | | Site site = siteClient.getSiteByIds(Arrays.asList(chargingPile.getSiteId())).getData().get(0); |
| | | chargingDetails.setName(site.getName() + "-" + chargingPile.getName()); |
| | | chargingDetails.setCode(one.getCode()); |
| | | chargingDetails.setStatus(one.getStatus()); |
| | | chargingDetails.setReservationTime(one.getReservationTime()); |
| | | boolean reservationPending = one.getReservationTime() != null |
| | | && one.getReservationTime().isAfter(LocalDateTime.now()) |
| | | && Integer.valueOf(2).equals(one.getStatus()); |
| | | chargingDetails.setStatus(reservationPending ? 1 : one.getStatus()); |
| | | chargingDetails.setChargingCost(one.getResidualAmount()); |
| | | UploadRealTimeMonitoringData data = uploadRealTimeMonitoringDataService.getLastDataById(one.getCode()); |
| | | if (null != data) { |
| | |
| | | |
| | | @Override |
| | | public List<SixChargingDto> charge(LocalDate sixBefore, List<Integer> siteIds, Boolean partnerView) { |
| | | return this.baseMapper.charge(sixBefore, siteIds, partnerView); |
| | | List<SixChargingDto> result = this.baseMapper.charge(sixBefore, siteIds, partnerView); |
| | | if (result != null) { |
| | | for (SixChargingDto item : result) { |
| | | if (item == null) { |
| | | continue; |
| | | } |
| | | if (item.getMonth() != null) { |
| | | try { |
| | | int month = Integer.parseInt(item.getMonth()); |
| | | if (month >= 1 && month <= 12) { |
| | | item.setMonth(String.format("%02d", month)); |
| | | } |
| | | } catch (NumberFormatException ignored) { |
| | | } |
| | | } |
| | | if (item.getElectrovalence() != null) { |
| | | item.setElectrovalence(item.getElectrovalence().setScale(2, RoundingMode.HALF_UP)); |
| | | } |
| | | if (item.getServiceCharge() != null) { |
| | | item.setServiceCharge(item.getServiceCharge().setScale(2, RoundingMode.HALF_UP)); |
| | | } |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | | public List<SixCircleDto> circle(List<Integer> siteIds, LocalDate sixBefore, Boolean partnerView) { |
| | | return this.baseMapper.circle(siteIds, sixBefore, partnerView); |
| | | List<SixCircleDto> result = this.baseMapper.circle(siteIds, sixBefore, partnerView); |
| | | if (result != null) { |
| | | for (SixCircleDto item : result) { |
| | | if (item != null && item.getPaymentAmount() != null) { |
| | | item.setPaymentAmount(item.getPaymentAmount().setScale(2, RoundingMode.HALF_UP)); |
| | | } |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | @Override |
| | |
| | | */ |
| | | private BigDecimal getThirdPayNetAmount(TChargingOrder order) { |
| | | BigDecimal payAmount = order.getThirdPayAmount(); |
| | | if (payAmount == null && Integer.valueOf(3).equals(order.getPayMethod())) { |
| | | payAmount = firstNonNull(order.getPaymentAmount(), order.getRechargeAmount()); |
| | | Integer payMethod = order.getPayMethod(); |
| | | BigDecimal totalPaidAmount = firstNonNull(order.getPaymentAmount(), order.getRechargeAmount()); |
| | | if (isNullOrZero(payAmount)) { |
| | | if (Integer.valueOf(3).equals(payMethod)) { |
| | | payAmount = totalPaidAmount; |
| | | } else if (Integer.valueOf(2).equals(payMethod) && totalPaidAmount != null) { |
| | | payAmount = nonNegative(totalPaidAmount.subtract(nullToZero(order.getBalancePayAmount()))); |
| | | } |
| | | } |
| | | BigDecimal refundAmount = order.getThirdRefundAmount(); |
| | | if (refundAmount == null && Integer.valueOf(3).equals(order.getPayMethod())) { |
| | | if (refundAmount == null && Integer.valueOf(3).equals(payMethod)) { |
| | | refundAmount = order.getRefundAmount(); |
| | | } |
| | | return nonNegative(nullToZero(payAmount).subtract(nullToZero(refundAmount))); |
| | |
| | | private BigDecimal getBalancePayNetAmount(TChargingOrder order) { |
| | | BigDecimal payAmount = order.getBalancePayAmount(); |
| | | Integer payMethod = order.getPayMethod(); |
| | | if (payAmount == null && (Integer.valueOf(1).equals(payMethod) || Integer.valueOf(2).equals(payMethod))) { |
| | | payAmount = order.getPaymentAmount(); |
| | | BigDecimal totalPaidAmount = firstNonNull(order.getPaymentAmount(), order.getRechargeAmount()); |
| | | if (isNullOrZero(payAmount)) { |
| | | if (Integer.valueOf(1).equals(payMethod)) { |
| | | payAmount = totalPaidAmount; |
| | | } else if (Integer.valueOf(2).equals(payMethod) && totalPaidAmount != null) { |
| | | payAmount = nonNegative(totalPaidAmount.subtract(nullToZero(order.getThirdPayAmount()))); |
| | | } |
| | | } |
| | | BigDecimal refundAmount = order.getBalanceRefundAmount(); |
| | | if (refundAmount == null && (Integer.valueOf(1).equals(payMethod) || Integer.valueOf(2).equals(payMethod))) { |
| | |
| | | return first != null ? first : second; |
| | | } |
| | | |
| | | private boolean isNullOrZero(BigDecimal value) { |
| | | return value == null || value.compareTo(BigDecimal.ZERO) == 0; |
| | | } |
| | | |
| | | private BigDecimal nullToZero(BigDecimal value) { |
| | | return value == null ? BigDecimal.ZERO : value; |
| | | } |
| | |
| | | <select id="charge" resultType="com.ruoyi.order.dto.SixChargingDto"> |
| | | <choose> |
| | | <when test="partnerView != null and partnerView"> |
| | | SELECT DATE_FORMAT(create_time, '%m') AS MONTH, |
| | | ROUND(SUM(IFNULL(electricity_share_amount, 0)), 2) AS electrovalence, |
| | | ROUND(SUM(IFNULL(service_share_amount, 0)), 2) AS service_charge |
| | | SELECT EXTRACT(MONTH FROM create_time) AS MONTH, |
| | | SUM(IFNULL(electricity_share_amount, 0)) AS electrovalence, |
| | | SUM(IFNULL(service_share_amount, 0)) AS service_charge |
| | | FROM t_charging_order_share_record |
| | | WHERE del_flag = 0 AND online_share_status IN ('SUCCESS', 'RECORDED') |
| | | <if test="sixBefore != null"> |
| | |
| | | #{siteId} |
| | | </foreach> |
| | | </if> |
| | | GROUP BY DATE_FORMAT(create_time, '%m') |
| | | GROUP BY EXTRACT(MONTH FROM create_time) |
| | | </when> |
| | | <otherwise> |
| | | SELECT DATE_FORMAT(billing_cycle, '%m') AS MONTH, |
| | | ROUND(SUM(IFNULL(total_electricity_charge, 0)), 2) AS electrovalence, |
| | | ROUND(SUM(IFNULL(total_service_fee, 0) - IFNULL(tripartite_commission, 0)), 2) AS service_charge |
| | | SELECT EXTRACT(MONTH FROM billing_cycle) AS MONTH, |
| | | SUM(IFNULL(total_electricity_charge, 0)) AS electrovalence, |
| | | SUM(IFNULL(total_service_fee, 0) - IFNULL(tripartite_commission, 0)) AS service_charge |
| | | FROM t_charging_settlement_bill |
| | | WHERE statistical_date_type = 1 AND site_id != 0 |
| | | <if test="sixBefore != null"> |
| | |
| | | #{siteId} |
| | | </foreach> |
| | | </if> |
| | | GROUP BY DATE_FORMAT(billing_cycle, '%m') |
| | | GROUP BY EXTRACT(MONTH FROM billing_cycle) |
| | | </otherwise> |
| | | </choose> |
| | | </select> |
| | |
| | | <choose> |
| | | <when test="partnerView != null and partnerView"> |
| | | SELECT site_id AS siteId, |
| | | ROUND(SUM(IFNULL(share_amount, 0)), 2) AS paymentAmount |
| | | SUM(IFNULL(share_amount, 0)) AS paymentAmount |
| | | FROM t_charging_order_share_record |
| | | WHERE del_flag = 0 AND online_share_status IN ('SUCCESS', 'RECORDED') |
| | | <if test="siteIds != null and siteIds.size() > 0"> |
| | |
| | | </when> |
| | | <otherwise> |
| | | SELECT site_id AS siteId, |
| | | ROUND(SUM(IFNULL(total_electricity_charge, 0) + IFNULL(total_service_fee, 0) |
| | | - IFNULL(tripartite_commission, 0)), 2) AS paymentAmount |
| | | SUM(IFNULL(total_electricity_charge, 0) + IFNULL(total_service_fee, 0) |
| | | - IFNULL(tripartite_commission, 0)) AS paymentAmount |
| | | FROM t_charging_settlement_bill |
| | | WHERE statistical_date_type = 1 AND site_id != 0 |
| | | <if test="siteIds != null and siteIds.size() > 0"> |
| | |
| | | package com.ruoyi.order.service.impl; |
| | | |
| | | import com.ruoyi.order.api.model.TChargingOrder; |
| | | import com.ruoyi.order.dto.SixCircleDto; |
| | | import com.ruoyi.order.mapper.TChargingOrderMapper; |
| | | import com.ruoyi.order.dto.SixChargingDto; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.test.util.ReflectionTestUtils; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDate; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | |
| | | assertEquals(new BigDecimal("8.90"), result.get("commission_amount")); |
| | | verify(mapper, never()).sumSuccessfulShareAmount(siteIds); |
| | | } |
| | | |
| | | @Test |
| | | void chargeRoundsMapperTotalsInJavaForMycatCompatibility() { |
| | | SixChargingDto item = new SixChargingDto(); |
| | | item.setMonth("7"); |
| | | item.setElectrovalence(new BigDecimal("1.234")); |
| | | item.setServiceCharge(new BigDecimal("2.345")); |
| | | when(mapper.charge(LocalDate.of(2026, 1, 1), siteIds, false)).thenReturn(Arrays.asList(item)); |
| | | |
| | | List<SixChargingDto> result = service.charge(LocalDate.of(2026, 1, 1), siteIds, false); |
| | | |
| | | assertEquals("07", result.get(0).getMonth()); |
| | | assertEquals(new BigDecimal("1.23"), result.get(0).getElectrovalence()); |
| | | assertEquals(new BigDecimal("2.35"), result.get(0).getServiceCharge()); |
| | | } |
| | | |
| | | @Test |
| | | void circleRoundsMapperTotalsInJavaForMycatCompatibility() { |
| | | SixCircleDto item = new SixCircleDto(); |
| | | item.setPaymentAmount(new BigDecimal("12.345")); |
| | | when(mapper.circle(siteIds, LocalDate.of(2026, 1, 1), false)).thenReturn(Arrays.asList(item)); |
| | | |
| | | List<SixCircleDto> result = service.circle(siteIds, LocalDate.of(2026, 1, 1), false); |
| | | |
| | | assertEquals(new BigDecimal("12.35"), result.get(0).getPaymentAmount()); |
| | | } |
| | | |
| | | @Test |
| | | void incomeCircleFallsBackWhenLegacyThirdPaySplitAmountIsZero() { |
| | | TChargingOrder order = new TChargingOrder(); |
| | | order.setPayMethod(3); |
| | | order.setThirdPayAmount(BigDecimal.ZERO); |
| | | order.setPaymentAmount(new BigDecimal("26.80")); |
| | | order.setThirdRefundAmount(BigDecimal.ZERO); |
| | | |
| | | BigDecimal amount = ReflectionTestUtils.invokeMethod(service, "getThirdPayNetAmount", order); |
| | | |
| | | assertEquals(new BigDecimal("26.80"), amount); |
| | | } |
| | | |
| | | @Test |
| | | void incomeCircleFallsBackWhenLegacyBalanceSplitAmountIsZero() { |
| | | TChargingOrder order = new TChargingOrder(); |
| | | order.setPayMethod(1); |
| | | order.setBalancePayAmount(BigDecimal.ZERO); |
| | | order.setPaymentAmount(new BigDecimal("18.60")); |
| | | order.setBalanceRefundAmount(BigDecimal.ZERO); |
| | | |
| | | BigDecimal amount = ReflectionTestUtils.invokeMethod(service, "getBalancePayNetAmount", order); |
| | | |
| | | assertEquals(new BigDecimal("18.60"), amount); |
| | | } |
| | | } |
| | |
| | | package com.ruoyi.order.service.impl; |
| | | |
| | | import com.baomidou.mybatisplus.core.conditions.Wrapper; |
| | | import com.baomidou.mybatisplus.core.MybatisConfiguration; |
| | | import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; |
| | | import com.ruoyi.common.core.domain.R; |
| | | import com.ruoyi.common.core.web.domain.AjaxResult; |
| | | import com.ruoyi.common.security.service.TokenService; |
| | | import com.ruoyi.chargingPile.api.model.TAccountingStrategy; |
| | | import com.ruoyi.order.api.model.TChargingOrder; |
| | | import com.ruoyi.order.mapper.TChargingOrderMapper; |
| | | import com.ruoyi.other.api.domain.TVip; |
| | | import com.ruoyi.payment.api.feignClient.IcbcPaymentClient; |
| | | import com.ruoyi.payment.api.vo.IcbcPaymentResp; |
| | | import com.ruoyi.system.api.model.LoginUserApplet; |
| | | import org.junit.jupiter.api.BeforeEach; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.apache.ibatis.builder.MapperBuilderAssistant; |
| | | import org.springframework.test.util.ReflectionTestUtils; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.Map; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | |
| | | import static org.junit.jupiter.api.Assertions.assertTrue; |
| | | import static org.mockito.ArgumentMatchers.any; |
| | | import static org.mockito.ArgumentMatchers.eq; |
| | | import static org.mockito.ArgumentMatchers.isNull; |
| | | import static org.mockito.Mockito.doReturn; |
| | | import static org.mockito.Mockito.mock; |
| | | import static org.mockito.Mockito.never; |
| | |
| | | |
| | | @BeforeEach |
| | | void setUp() { |
| | | TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), TChargingOrder.class); |
| | | service = spy(new TChargingOrderServiceImpl()); |
| | | TokenService tokenService = mock(TokenService.class); |
| | | icbcPaymentClient = mock(IcbcPaymentClient.class); |
| | |
| | | verify(service, never()).chargingOrderCallback(eq(1), eq(ORDER_CODE), any(), eq("1")); |
| | | } |
| | | |
| | | @Test |
| | | void localBalancePaymentUsesSavedOrderWithoutImmediateReadBack() { |
| | | TChargingOrderMapper mapper = mock(TChargingOrderMapper.class); |
| | | ReflectionTestUtils.setField(service, "baseMapper", mapper); |
| | | TChargingOrder order = new TChargingOrder(); |
| | | order.setId(9001L); |
| | | order.setCode("CD-BALANCE-WHITELIST"); |
| | | order.setRechargePaymentStatus(1); |
| | | when(mapper.update(isNull(), any(Wrapper.class))).thenReturn(0); |
| | | |
| | | AjaxResult result = service.completeChargingOrderPayment(order, "WHITELIST"); |
| | | |
| | | assertEquals(200, result.get("code")); |
| | | verify(service, never()).getOne(any(Wrapper.class)); |
| | | verify(mapper).update(isNull(), any(Wrapper.class)); |
| | | } |
| | | |
| | | @Test |
| | | void internalMemberEightZheIsStoredAsPointEight() { |
| | | TVip vip = new TVip(); |
| | | vip.setType(2); |
| | | vip.setDiscount(new BigDecimal("8")); |
| | | |
| | | BigDecimal discount = service.resolveChargingVipDiscount(vip, null); |
| | | |
| | | assertEquals(0, discount.compareTo(new BigDecimal("0.8"))); |
| | | } |
| | | |
| | | @Test |
| | | void regularMemberKeepsAccountingStrategyFactor() { |
| | | TVip vip = new TVip(); |
| | | vip.setType(1); |
| | | TAccountingStrategy strategy = new TAccountingStrategy(); |
| | | strategy.setDiscount(new BigDecimal("0.85")); |
| | | |
| | | BigDecimal discount = service.resolveChargingVipDiscount(vip, strategy); |
| | | |
| | | assertEquals(0, discount.compareTo(new BigDecimal("0.85"))); |
| | | } |
| | | |
| | | @Test |
| | | void zeroDiscountAmountDoesNotConsumeMemberUse() { |
| | | assertFalse(service.shouldConsumeVipDiscount(BigDecimal.ZERO)); |
| | | } |
| | | |
| | | @Test |
| | | void positiveDiscountAmountConsumesMemberUse() { |
| | | assertTrue(service.shouldConsumeVipDiscount(new BigDecimal("1.25"))); |
| | | } |
| | | |
| | | private TChargingOrder pendingIcbcOrder() { |
| | | TChargingOrder order = new TChargingOrder(); |
| | | order.setCode(ORDER_CODE); |