From 4165f0912fd8d952badc4813de69a8210fef96ca Mon Sep 17 00:00:00 2001 From: xiaofajia <1665375861@qq.com> Date: Mon, 28 Oct 2024 23:09:02 +0800 Subject: [PATCH] =?UTF-8?q?=E6=89=93=E5=8D=B0=E5=B7=A5=E5=8D=951/2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cn/iocoder/yudao/common/RepairCons.java | 2 + .../impl/DlRepairTicketsServiceImpl.java | 204 +++++++++++++++++- .../yudao/module/tickets/vo/NoticeCusVO.java | 6 + .../src/main/resources/templates/gdmb.docx | Bin 14825 -> 16155 bytes .../common/util/number/MoneyUtils.java | 79 +++++++ 5 files changed, 284 insertions(+), 7 deletions(-) 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 6d061efae58adb65ca9daace959f7ea8bddae9e9..ed3cbca59b12d54005d5f365447ab3e58de8890e 100644 GIT binary patch literal 16155 zcmeHu1A8Xh*6kac9ox3mNrxSDYp@3YUj_x^zIt30Xa zty(qas#?#O3uCS+BLM=60ssd<0ssI)K#V?Zh5--&kPZd_d;&lMs|#9L+8bEfYb&@| z8`x>mIa`<$lI88J zColKct|_eSFq*DI639oYTN4sDJp1fa76y@9&$@)HJG~xXrhTIVF6ElPR;G_1oA{Dp z0Oc>=?F>P>@vryY4OA49T#G^tr>^rR&k(0dG&FvvZ2r|0blw8T4*#GuBZ%k9 z@tVycu1^n+83G#)4?igycZqL$E=lq}~`+GGv!AWz>=T;Vgo9J26V$>RsMX z_`?7!3_j5!>JAXcW_GTWB2;}nq)SDWqit$@RAntX8p_ZeHVE6Nl4)c$k5jaq#3ocOx%FqT z-gVxSJkR9&i_18Ia{C-lQO3DDeEsW{=H=rin*gNS%Z>`tnA@Rieh+L4883qoVF4@Y zes(s9O?S7S@Esq-dVdE2$o!jkCM$Y^y?vByeK;S?hj(h*8kpPB)BSe-U$6Wh?23Q+ z^s*R92@poafODUB!qGPF6)K|XH7%h7N&QzKL8fQ#RD_t~hWB-f5W3m=Ks;ub{UK(- z`P4StIqCrxXXUOM3jXSub=Zp1&7UqRt3Kia)_S;Z)qG@Hf(x2?*#e9#;;+l!r(n$x9Oox9f$dK?z zUTkxV{`nI~OjJk!7za>yV$8KuSFgEW7Ry{+nrBq#KxbmhT%OXxk)TI4~p2y+w$!8cE%gpC++E)JEzfX*_^Srn3&L2I(ijjvXItnP^qc* z*2nsas^cqsAvk;b32CpmF0^mQ4x`nU##DEaDlu)#59t=0y2NJl_VuK=wejN2u&`mRJ7PfYCHtGS=p3P?Q30v(eCLIEhjc^+! zYLX)zV#Z9)U;3*~oS5r^;;`h5t8Zsf9>hnAQzaXCv$i$V&YJGT72e`?T$XR*tK97| z5*Sj4N=WB|QLh6wZeI9R*`XYDY*?9SfJ{*r%#m?$SIksSvmJ~L@R6b%IGGIkfh(NNI_>zM>lW7=mg< zO+LUvc76i29{YAc1J2?XB$Dr#w-y%>FH;U~FHj-FHIGz9kPR2cZs_-=Ej9#HAL29% zLe1STLHYhT+>ulLlktQ!w z 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

=>5{ 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 f%J~{GKa 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 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(); + } }