diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RepairCons.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RepairCons.java index 3efdec5f..9a338279 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RepairCons.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/common/RepairCons.java @@ -20,4 +20,6 @@ public class RepairCons { public static final String DICT_REPAIR_UNIT = "repair_unit"; /**数据字典常量-repair_unit-*/ public static final String DICT_REPAIR_WORK_TYPE = "repair_work_type"; + /** 数据字典常量-repair_part_disposal */ + public static final String REPAIR_PART_DISPOSAL = "repair_part_disposal"; } diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java index fc7a20c9..7f5112be 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/service/impl/DlRepairTicketsServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.common.*; +import cn.iocoder.yudao.framework.common.util.number.MoneyUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.module.base.entity.RepairWorker; import cn.iocoder.yudao.module.base.service.RepairRecordsService; @@ -12,11 +13,10 @@ import cn.iocoder.yudao.module.base.vo.RepairRecordsPageReqVO; import cn.iocoder.yudao.module.base.vo.RepairRecordsRespVO; import cn.iocoder.yudao.module.booking.entity.DlRepairBooking; import cn.iocoder.yudao.module.booking.service.DlRepairBookingService; -import cn.iocoder.yudao.module.custom.entity.CustomerCar; -import cn.iocoder.yudao.module.custom.entity.CustomerMain; -import cn.iocoder.yudao.module.custom.service.CarMainService; -import cn.iocoder.yudao.module.custom.service.CustomerCarService; -import cn.iocoder.yudao.module.custom.service.CustomerMainService; +import cn.iocoder.yudao.module.conf.entity.BaseType; +import cn.iocoder.yudao.module.conf.service.BaseTypeService; +import cn.iocoder.yudao.module.custom.entity.*; +import cn.iocoder.yudao.module.custom.service.*; import cn.iocoder.yudao.module.custom.vo.CarMainRespVO; import cn.iocoder.yudao.module.custom.vo.CustomerMainRespVO; import cn.iocoder.yudao.module.order.entity.RepairOrderInfo; @@ -57,6 +57,9 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.deepoove.poi.XWPFTemplate; +import com.deepoove.poi.config.Configure; +import com.deepoove.poi.config.ConfigureBuilder; +import com.deepoove.poi.plugin.table.HackLoopTableRenderPolicy; import org.apache.commons.lang3.StringUtils; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -67,6 +70,7 @@ import java.io.FileOutputStream; import java.io.InputStream; import java.math.BigDecimal; import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.stream.Collectors; @@ -154,6 +158,17 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl titems = titemService.list(new LambdaQueryWrapper().in(DlRepairTitem::getTicketId, id)); + // 时间和日期格式化 + DateTimeFormatter time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + DateTimeFormatter date = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + // 构建数据对象 Map params = new HashMap<>(); - params.put("jobNumber", "123456789"); String fileName = "结算单.docx"; String tmpPath = "D:\\" + fileName; + // 设置列表配置,如果有多个列表时需加.bind("list1", policy) 新列表配置即可 + ConfigureBuilder configureBuilder = Configure.builder(); + /* + 数据填入 以下带序号都是在模板的角度在分 + */ + + /* + 1、工单基础信息(模板前四行) + */ + // 工号(这里用的工单号) + params.put("jobNumber", tickets.getTicketNo()); + + // 客户信息(名称、送修人、送修人电话,用的工单中存的用户信息) + params.put("customerName", tickets.getUserName()); + params.put("repairer", tickets.getUserName()); + params.put("repairerTelephone", tickets.getUserMobile()); + + // 车辆信息(车牌、车架号、开单时间、已行里程、旧件处理,这些是工单中有的) + params.put("plate", tickets.getCarNo()); + params.put("frameNumber", tickets.getCarVin()); + params.put("billingTime", time.format(tickets.getCreateTime())); + // todo 已行里程 + // 取不到先给未知 + params.put("mileage", "未知"); + // 旧件处理 + // 获取字典数据 + List dataList = dictDataApi.getDictDataList(REPAIR_PART_DISPOSAL); + // 找到对应的处理方式 + DictDataRespDTO dictDataRespDTO = dataList.stream().filter(item -> item.getValue().equals(tickets.getPartDisposal())).findFirst().orElse(null); + params.put("oldhandle", Objects.requireNonNull(dictDataRespDTO).getLabel()); + + // 车辆其他信息(发动机号码、三包单位、保险名称、车型) + CarMain carMain = carMainService.getById(tickets.getCarId()); + params.put("engineNumber", carMain.getEngineNumber()); + // todo 三包单位、保险名称 + // 取不到先给未知 + params.put("tripleUnit", "未知"); + params.put("insuranceName", "未知"); + // 先查车辆对应的品牌 + String brandAndModel = ""; + if (ObjectUtil.isNotEmpty(carMain.getCarBrand())) { + CarBrand brand = carBrandService.getById(carMain.getCarBrand()); + if (ObjectUtil.isNotEmpty(brand)) { + brandAndModel += brand.getBrandName(); + // 在查车辆对应的型号 + CarModel carModel = carModelService.getById(carMain.getCarModel()); + brandAndModel += " " + (carModel == null ? "" : carModel.getModelName()); + } + } + params.put("carType", brandAndModel); + /* + 2、维修项目 + */ + // 取出维修工单子表的维修项目 + List projectList = titems.stream().filter(item -> item.getItemType().equals("01")).collect(Collectors.toList()); + // 构建导出对象 + List> projects = new ArrayList<>(); + if (CollectionUtil.isNotEmpty(projectList)) { + projectList.forEach(item -> { + Map project = new HashMap<>(); + project.put("repRort", projects.size() + 1); + project.put("repItem", item.getItemName()); + project.put("repPrice", item.getItemPrice()); + project.put("repCount", item.getItemCount()); + project.put("repDiscount", item.getItemDiscount() == null ? "无折扣" : item.getItemDiscount()); + // todo 工时费 + // 取不到先给0 + project.put("labourAmount", 0.00); + project.put("major", item.getRepairNames()); + project.put("repRemark", item.getRemark()); + if (ObjectUtil.isNotEmpty(item.getItemTypeId())) { + BaseType baseType = baseTypeService.getById(item.getItemTypeId()); + project.put("repNature", baseType == null ? "" : baseType.getName()); + } + projects.add(project); + }); + } + configureBuilder.bind("projects", new HackLoopTableRenderPolicy()); + // todo 有问题,不渲染 + params.put("projects", projects); + + /* + 3、材料清单 + */ + // 取出维修工单子表的配件 + List waresList = titems.stream().filter(item -> item.getItemType().equals("02")).collect(Collectors.toList()); + List> wares = new ArrayList<>(); + if (CollectionUtil.isNotEmpty(waresList)) { + waresList.forEach(item -> { + Map ware = new HashMap<>(); + ware.put("matRort", wares.size() + 1); + // todo 配件号 + ware.put("matNum", ""); + ware.put("matName", item.getItemName()); + // todo 单位 + ware.put("matUnit", item.getItemUnit()); + ware.put("matPrice", item.getItemPrice()); + ware.put("matCount", item.getItemCount()); + ware.put("matDiscount", item.getItemDiscount() == null ? "无折扣" : item.getItemDiscount()); + ware.put("matAmount", item.getItemMoney()); + ware.put("matRemark", item.getRemark()); + if (ObjectUtil.isNotEmpty(item.getItemTypeId())) { + BaseType baseType = baseTypeService.getById(item.getItemTypeId()); + ware.put("matNature", baseType == null ? "" : baseType.getName()); + } + wares.add(ware); + }); + } + configureBuilder.bind("wares", new HackLoopTableRenderPolicy()); + // todo 同样是不渲染 + params.put("wares", wares); + // 小计 + params.put("matTotalAmount", tickets.getPartPrice()); + + /* + 4、其他信息 + */ + // 目前能取到:材料费、材料费优惠、总费用、应收费、大写、工单备注 + // 计算配件没打折的总金额 + BigDecimal matCost = waresList.stream() + .map(item -> item.getItemPrice().multiply(BigDecimal.valueOf(item.getItemCount()))) + .reduce(BigDecimal.ZERO, BigDecimal::add); + params.put("matCost", matCost); + // 没打折的金额减去打折后的总金额得到优惠了多少钱 + params.put("matFavorable", matCost.subtract(tickets.getPartPrice())); + // 计算没打折的工单总价 + BigDecimal matTotalCost = titems.stream().map(item -> item.getItemPrice().multiply(BigDecimal.valueOf(item.getItemCount()))).reduce(BigDecimal.ZERO, BigDecimal::add); + params.put("matTotalCost", matTotalCost); + // 应收费目前是工单的打折后的总价 + params.put("allCost", tickets.getTotalPrice()); + // 应收费转大写 + String bigAllCost = MoneyUtils.toChinese(tickets.getTotalPrice()); + params.put("bigAllCost", bigAllCost); + // 这个备注现在是工单备注 + params.put("paperRemark", tickets.getRemark()); + // todo 目前取不到:管理费、工时费、工时费优惠、其他费、材料工时优惠、救援费、三包费、定损费、付款情况、结算备注(这个是因为和工单备注用的同一个)、客户签字 + // 取不到的先默认为0或未知 + params.put("manageCost", 0.00); + params.put("labourCost", 0.00); + params.put("labourFavorable", 0.00); + params.put("otherCost", 0.00); + params.put("matlabourFavorable", 0.00); + params.put("rescueCost", 0.00); + params.put("tripleCost", 0.00); + params.put("lossCost", 0.00); + params.put("costCondition", "未知"); + params.put("costRemark", "未知"); + /* + 5、最后结尾 + */ + // 目前能取到:服务顾问、联系电话、结算日期 + params.put("serviceConsultant", tickets.getAdviserName()); + AdminUserRespDTO adviser = adminUserApi.getUser(Long.valueOf(tickets.getAdviserId())); + if (ObjectUtil.isNotEmpty(adviser) && ObjectUtil.isNotEmpty(adviser.getMobile())) { + params.put("serviceTelephone", adviser.getMobile()); + } + RepairOrderInfo orderInfo = repairOrderInfoService.getOne(new LambdaQueryWrapper().eq(RepairOrderInfo::getGoodsId, tickets.getId())); + if (ObjectUtil.isNotEmpty(orderInfo) && ObjectUtil.isNotEmpty(orderInfo.getPayTime())) { + params.put("settleDate", date.format(orderInfo.getPayTime())); + } + // todo 目前取不到:单位、开户行、地址、账号 + // 取不到的先给未知 + params.put("corporation", "未知"); + params.put("bank", "未知"); + params.put("bankAddress", "未知"); + params.put("account", "未知"); + + Configure config = configureBuilder.build(); try { InputStream inputStream = XWPFTemplate.class.getResourceAsStream("/templates/gdmb.docx"); - XWPFTemplate template = XWPFTemplate.compile(inputStream); + XWPFTemplate template = XWPFTemplate.compile(inputStream, config); template.render(params); FileOutputStream fos = new FileOutputStream(tmpPath); template.write(fos); diff --git a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/NoticeCusVO.java b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/NoticeCusVO.java index c1ad5192..4b306896 100644 --- a/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/NoticeCusVO.java +++ b/dl-module-repair/src/main/java/cn/iocoder/yudao/module/tickets/vo/NoticeCusVO.java @@ -8,6 +8,12 @@ import java.util.Date; import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; +/** + * 通知客户 + * + * @author 小李 + * @date 16:56 2024/10/28 +**/ @Data public class NoticeCusVO { diff --git a/dl-module-repair/src/main/resources/templates/gdmb.docx b/dl-module-repair/src/main/resources/templates/gdmb.docx index 6d061efa..ed3cbca5 100644 Binary files a/dl-module-repair/src/main/resources/templates/gdmb.docx and b/dl-module-repair/src/main/resources/templates/gdmb.docx differ diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java index 90888d7d..1651f6ec 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/number/MoneyUtils.java @@ -13,6 +13,11 @@ import java.math.RoundingMode; */ public class MoneyUtils { + /** 用于数字转大写的中文定义 */ + private static final String[] CHINESE_NUMBERS = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"}; + private static final String[] CHINESE_UNITS = {"", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "万"}; + private static final String DECIMAL_UNITS = "角分"; + /** * 金额的小数位数 */ @@ -128,4 +133,78 @@ public class MoneyUtils { return price.multiply(percent).divide(PERCENT_100, PRICE_SCALE, RoundingMode.HALF_UP); } + /** + * 用户数字转大写 + * + * @author 小李 + * @date 20:31 2024/10/28 + * @param inputData 需要转的数据 + **/ + public static String toChinese(Object inputData) { + BigDecimal bigDecimalAmount; + + // 统一类型 + if (inputData instanceof Integer) { + bigDecimalAmount = new BigDecimal((Integer) inputData); + } else if (inputData instanceof String) { + bigDecimalAmount = new BigDecimal((String) inputData); + } else if (inputData instanceof Double) { + bigDecimalAmount = new BigDecimal((Double) inputData); + } else if (inputData instanceof BigDecimal) { + bigDecimalAmount = (BigDecimal) inputData; + } else { + throw new IllegalArgumentException("Unsupported type: " + inputData.getClass().getName()); + } + + long integerPart = bigDecimalAmount.longValue(); + int decimalPart = bigDecimalAmount.subtract(new BigDecimal(integerPart)).multiply(new BigDecimal(100)).intValue(); + + StringBuilder chineseAmount = new StringBuilder(); + boolean isZero = false; + + // 处理整数部分 + if (integerPart == 0) { + chineseAmount.append(CHINESE_NUMBERS[0]); + } else { + for (int i = 0; integerPart > 0; i++) { + int digit = (int) (integerPart % 10); + if (digit != 0 || (i > 0 && (i + 1) % 4 == 0 && (integerPart / 10) % 10 != 0)) { + if (isZero && chineseAmount.length() > 0 && !chineseAmount.toString().endsWith("零")) { + chineseAmount.insert(0, CHINESE_NUMBERS[0]); + } + if (digit != 0) { + chineseAmount.insert(0, CHINESE_UNITS[i]); + chineseAmount.insert(0, CHINESE_NUMBERS[digit]); + } + isZero = false; + } else { + isZero = true; + } + integerPart /= 10; + } + } + + // 确保以“元”结尾 + if (chineseAmount.length() > 0 && !chineseAmount.toString().endsWith("元")) { + chineseAmount.append("元"); + } + + // 处理小数部分 + if (decimalPart > 0) { + StringBuilder decimalPartStr = new StringBuilder(); + for (int i = 0; i < DECIMAL_UNITS.length(); i++) { + int digit = decimalPart % 10; + if (digit != 0) { + decimalPartStr.insert(0, DECIMAL_UNITS.charAt(i)); + decimalPartStr.insert(0, CHINESE_NUMBERS[digit]); + } + decimalPart /= 10; + } + chineseAmount.append(decimalPartStr.toString()); + } else { + chineseAmount.append("整"); + } + + return chineseAmount.toString(); + } }