打印工单1/2

This commit is contained in:
xiaofajia 2024-10-28 23:09:02 +08:00
parent 6a03253d26
commit 4165f0912f
5 changed files with 284 additions and 7 deletions

View File

@ -20,4 +20,6 @@ public class RepairCons {
public static final String DICT_REPAIR_UNIT = "repair_unit"; public static final String DICT_REPAIR_UNIT = "repair_unit";
/**数据字典常量-repair_unit-*/ /**数据字典常量-repair_unit-*/
public static final String DICT_REPAIR_WORK_TYPE = "repair_work_type"; public static final String DICT_REPAIR_WORK_TYPE = "repair_work_type";
/** 数据字典常量-repair_part_disposal */
public static final String REPAIR_PART_DISPOSAL = "repair_part_disposal";
} }

View File

@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.common.*; 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.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.base.entity.RepairWorker; import cn.iocoder.yudao.module.base.entity.RepairWorker;
import cn.iocoder.yudao.module.base.service.RepairRecordsService; 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.base.vo.RepairRecordsRespVO;
import cn.iocoder.yudao.module.booking.entity.DlRepairBooking; import cn.iocoder.yudao.module.booking.entity.DlRepairBooking;
import cn.iocoder.yudao.module.booking.service.DlRepairBookingService; import cn.iocoder.yudao.module.booking.service.DlRepairBookingService;
import cn.iocoder.yudao.module.custom.entity.CustomerCar; import cn.iocoder.yudao.module.conf.entity.BaseType;
import cn.iocoder.yudao.module.custom.entity.CustomerMain; import cn.iocoder.yudao.module.conf.service.BaseTypeService;
import cn.iocoder.yudao.module.custom.service.CarMainService; import cn.iocoder.yudao.module.custom.entity.*;
import cn.iocoder.yudao.module.custom.service.CustomerCarService; import cn.iocoder.yudao.module.custom.service.*;
import cn.iocoder.yudao.module.custom.service.CustomerMainService;
import cn.iocoder.yudao.module.custom.vo.CarMainRespVO; import cn.iocoder.yudao.module.custom.vo.CarMainRespVO;
import cn.iocoder.yudao.module.custom.vo.CustomerMainRespVO; import cn.iocoder.yudao.module.custom.vo.CustomerMainRespVO;
import cn.iocoder.yudao.module.order.entity.RepairOrderInfo; 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.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.deepoove.poi.XWPFTemplate; 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.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -67,6 +70,7 @@ import java.io.FileOutputStream;
import java.io.InputStream; import java.io.InputStream;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit; import java.time.temporal.ChronoUnit;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -154,6 +158,17 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl<DlRepairTicketsMappe
@Lazy @Lazy
private DlTwItemService twItemService; private DlTwItemService twItemService;
@Resource
@Lazy
private CarBrandService carBrandService;
@Resource
@Lazy
private CarModelService carModelService;
@Resource
@Lazy
private BaseTypeService baseTypeService;
/** /**
* 维修工单表 新增 * 维修工单表 新增
@ -458,13 +473,188 @@ public class DlRepairTicketsServiceImpl extends ServiceImpl<DlRepairTicketsMappe
**/ **/
@Override @Override
public void print(HttpServletResponse response, String id) { public void print(HttpServletResponse response, String id) {
// 预备工作
// 先把这个工单和工单的所有子表信息取出来备用
DlRepairTickets tickets = baseMapper.selectById(id);
List<DlRepairTitem> titems = titemService.list(new LambdaQueryWrapper<DlRepairTitem>().in(DlRepairTitem::getTicketId, id));
// 时间和日期格式化
DateTimeFormatter time = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
DateTimeFormatter date = DateTimeFormatter.ofPattern("yyyy-MM-dd");
// 构建数据对象
Map<String, Object> params = new HashMap<>(); Map<String, Object> params = new HashMap<>();
params.put("jobNumber", "123456789");
String fileName = "结算单.docx"; String fileName = "结算单.docx";
String tmpPath = "D:\\" + fileName; 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<DictDataRespDTO> 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<DlRepairTitem> projectList = titems.stream().filter(item -> item.getItemType().equals("01")).collect(Collectors.toList());
// 构建导出对象
List<Map<String, Object>> projects = new ArrayList<>();
if (CollectionUtil.isNotEmpty(projectList)) {
projectList.forEach(item -> {
Map<String, Object> 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<DlRepairTitem> waresList = titems.stream().filter(item -> item.getItemType().equals("02")).collect(Collectors.toList());
List<Map<String, Object>> wares = new ArrayList<>();
if (CollectionUtil.isNotEmpty(waresList)) {
waresList.forEach(item -> {
Map<String, Object> 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<RepairOrderInfo>().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 { try {
InputStream inputStream = XWPFTemplate.class.getResourceAsStream("/templates/gdmb.docx"); InputStream inputStream = XWPFTemplate.class.getResourceAsStream("/templates/gdmb.docx");
XWPFTemplate template = XWPFTemplate.compile(inputStream); XWPFTemplate template = XWPFTemplate.compile(inputStream, config);
template.render(params); template.render(params);
FileOutputStream fos = new FileOutputStream(tmpPath); FileOutputStream fos = new FileOutputStream(tmpPath);
template.write(fos); template.write(fos);

View File

@ -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; 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 @Data
public class NoticeCusVO { public class NoticeCusVO {

View File

@ -13,6 +13,11 @@ import java.math.RoundingMode;
*/ */
public class MoneyUtils { 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); 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();
}
} }