package com.pj.api.open.service; import cn.hutool.cache.CacheUtil; import cn.hutool.cache.impl.TimedCache; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import cn.hutool.log.StaticLog; import com.alibaba.druid.sql.visitor.functions.If; import com.pj.api.open.ResultJson; import com.pj.api.open.bo.CheckCarNumberBO; import com.pj.api.open.bo.InRecordBO; import com.pj.api.wx.bo.ManagerBO; import com.pj.constants.business.CarEnum; import com.pj.constants.business.GoodsEnum; import com.pj.constants.business.PayEnum; import com.pj.current.config.PartConfig; import com.pj.current.config.SystemObject; import com.pj.current.task.TaskService; import com.pj.project.sync.SyncService; import com.pj.project.sync.request.item.IOrderItem; import com.pj.project.sync.response.IOrderPriceRes; import com.pj.project.tb_account.AutomaticPay; import com.pj.project.tb_business.TbBusiness; import com.pj.project.tb_business.TbBusinessService; import com.pj.project.tb_business_car.TbBusinessCar; import com.pj.project.tb_business_car.TbBusinessCarService; import com.pj.project.tb_business_item.TbBusinessItem; import com.pj.project.tb_business_item.TbBusinessItemService; import com.pj.project.tb_car.TbCar; import com.pj.project.tb_car.TbCarService; import com.pj.project.tb_car_weight.TbCarWeight; import com.pj.project.tb_car_weight.TbCarWeightService; import com.pj.project.tb_channel_config.TbChannelConfig; import com.pj.project.tb_channel_config.TbChannelConfigService; import com.pj.project.tb_deduction_bind.TbDeductionBindService; import com.pj.project.tb_goods.TbGoods; import com.pj.project.tb_goods.TbGoodsService; import com.pj.project.tb_item.TbItem; import com.pj.project.tb_item.TbItemService; import com.pj.project.tb_mild_car.TbMildCar; import com.pj.project.tb_mild_car.TbMildCarService; import com.pj.utils.cache.RedisUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Lazy; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @Service @Transactional @Slf4j public class OpenService { @Resource @Lazy private TbBusinessService tbBusinessService; @Resource @Lazy private TbBusinessCarService tbBusinessCarService; @Resource private TbCarService tbCarService; @Resource TaskService taskService; @Resource private TbGoodsService tbGoodsService; @Resource @Lazy AutomaticPay automaticPay; @Resource private TbChannelConfigService tbChannelConfigService; @Resource private PartConfig partConfig; @Resource private TbMildCarService tbMildCarService; @Resource private TbBusinessItemService tbBusinessItemService; @Resource private SyncService syncService; @Resource private TbCarWeightService tbCarWeightService; @Resource private TbItemService tbItemService; public ResultJson checkCarNumber(CheckCarNumberBO checkCarNumberBO) { String carNo = checkCarNumberBO.getCarNumber(); int inOrOut = checkCarNumberBO.getInOrOut(); String image = checkCarNumberBO.getImageData(); if (inOrOut == 1) { return handlerIn(carNo, checkCarNumberBO.getChannelName(), image); } return handlerOut(carNo, checkCarNumberBO.getChannelName(), image); } private ResultJson handlerIn(String carNo, String channel, String image) { carNo = carNo.toUpperCase(); if (StrUtil.isNotEmpty(image)) { StaticLog.error("缓存入场图片:{}", carNo); IMAGE_CACHE.put(carNo, image); } List notOutList = tbBusinessCarService.findNotOutCar(carNo); if (!notOutList.isEmpty()) { String msg = "车辆有" + notOutList.size() + "条未离场记录"; log.error("入场返回:{}", msg); return ResultJson.error(msg); } TbBusinessCar tbBusinessCar = tbBusinessCarService.findTheLastRecord(carNo); Date now = new Date(); TbCar tbCar = tbCarService.findByCardNo(carNo); //1、记录不存在; // 2、已离场重新入场; if (tbBusinessCar == null || (tbBusinessCar.getRealInTime() != null && tbBusinessCar.getRealOutTime() != null) ) { //=======创建新的放行记录========== tbBusinessCar = new TbBusinessCar(); tbBusinessCar.setCarNo(carNo).setPay(0).setCarSize(0D).setIsLock(0).setPayType(CarEnum.PayTypeEnum.NO_PAY_TYPE.getType()) .setPay(0) .setCarCompany(tbCar != null ? tbCar.getCustomerName() : "临时").setCreateTime(now) .setInChannel(channel).setRealInTime(now).setCarType(CarEnum.CarTypeEnum.EMPTY_TYPE.getType()) .setBasePartMoney(new BigDecimal("0")).setTimeUpdate(now).setConfirmJudge(CarEnum.ConfirmJudgeEnum.NO_NEED_JUDGE.getCode()) .setNo(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmm")) + RandomUtil.randomNumbers(4)); tbBusinessCarService.save(tbBusinessCar); CoverBase64ToUrl(image, tbBusinessCar.getId(), carNo, 1); String msg = "无业务车辆"; log.error("入场返回:{}", JSONUtil.toJsonStr(ResultJson.success(msg, msg))); return ResultJson.success(msg, msg); } tbBusinessCar.setRealInTime(now).setInChannel(channel).setTimeUpdate(now) .setCarCompany(tbCar != null ? tbCar.getCustomerName() : "临时"); tbBusinessCarService.saveOrUpdate(tbBusinessCar); CoverBase64ToUrl(image, tbBusinessCar.getId(), carNo, 1); return ResultJson.success(); } private void CoverBase64ToUrl(String base64image, String carId, String carNo, int inOrOut) { String cacheBase64 = IMAGE_CACHE.get(carNo); if (StrUtil.isEmpty(base64image)) { base64image = cacheBase64; } if (StrUtil.isEmpty(base64image)) { log.error("无出场图片:{}", carNo); return; } taskService.addTask(new CoverBase64ToImageTask("=======" + carId + "", 2000, carId, base64image, inOrOut)); IMAGE_CACHE.remove(carNo); } final TimedCache IMAGE_CACHE = CacheUtil.newTimedCache(30 * 60 * 1000); /** * 离场处理逻辑 * * @param carNo * @param channel * @param image * @return */ private ResultJson handlerOut(String carNo, String channel, String image) { carNo = carNo.toUpperCase(); TbBusinessCar tbBusinessCar = tbBusinessCarService.findTheLastRecord(carNo); if (tbBusinessCar == null || tbBusinessCar.getRealInTime() == null || tbBusinessCar.getRealOutTime() != null) { log.error("请求返回【未查询到入场记录】:{}", carNo); return ResultJson.error("未查询到入场记录"); } Date now = new Date(); Date realInTime = tbBusinessCar.getRealInTime(); if (now.getTime() / 1000 - realInTime.getTime() / 1000 < partConfig.getMinSeconds()) { log.error("请求返回【无效离场记录,返回到设备端为:“未查询到入场记录”让其停止轮询】:{}", carNo); return ResultJson.error("无效离场记录"); } if (StrUtil.isNotEmpty(image)) { StaticLog.error("缓存离场图片,{}", carNo); IMAGE_CACHE.put(carNo, image); } //判断是否4.2米以下蓝色车牌===免停车费 if (StrUtil.isNotEmpty(tbBusinessCar.getColor())) { String freeColor = partConfig.getFreeColor(); //4蓝色车辆 if (tbBusinessCar.getColor().contains(freeColor)) { log.error("请求返回【蓝牌未备案车辆,放行】:{},{}", carNo, ResultJson.success()); List carWeights = tbCarWeightService.findByBusinessCarId(tbBusinessCar.getId()); carWeights = carWeights.stream().filter(tbCarWeight -> tbCarWeight.getPayStatus() == 0).collect(Collectors.toList()); BigDecimal weightMoney = BigDecimal.ZERO; if (!carWeights.isEmpty()) { for (TbCarWeight carWeight : carWeights) { weightMoney = carWeight.getWeightPrice().add(weightMoney); } } double wMoney = weightMoney.doubleValue(); if (wMoney > 0) { log.info("请求返回【蓝牌车过磅费】,{},{}", carNo, wMoney); return ResultJson.error("过磅费" + wMoney); } freeOut(tbBusinessCar, now, channel, image); return ResultJson.success(); } } //是否行政车辆===== if (checkFree(carNo, 2, now)) { freeOut(tbBusinessCar, now, channel, image); return ResultJson.success(); } String businessCarId = tbBusinessCar.getId(); String carType = tbBusinessCar.getCarType(); IOrderPriceRes partMoneyRes; IOrderPriceRes businessRes = new IOrderPriceRes(); List expenses = new ArrayList<>(); List businessList = tbBusinessService.findOtherBusinessByCarId(businessCarId); long judgeCount = businessList.stream().filter(tbBusiness -> tbBusiness.getConfirmJudge() == CarEnum.ConfirmJudgeEnum.JUDGE_PASS.getCode()).count(); int size = businessList.size(); if (size > judgeCount) { //业务未审核完 log.error("请求返回【业务未审核】:{}", carNo); return ResultJson.error("业务未审核"); } if (businessList.isEmpty()) { //地磅费--->无业务地磅费 List carWeights = tbCarWeightService.findByBusinessCarId(tbBusinessCar.getId()); carWeights = carWeights.stream().filter(tbCarWeight -> tbCarWeight.getPayStatus() == 0).collect(Collectors.toList()); BigDecimal weightMoney = BigDecimal.ZERO; if (!carWeights.isEmpty()) { for (TbCarWeight carWeight : carWeights) { weightMoney = carWeight.getWeightPrice().add(weightMoney); } } double wMoney = weightMoney.doubleValue(); //无业务车辆===>计算停车费 //如果已经支付过,则从支付时间算起,重新计算停车费 Date inTime = tbBusinessCar.getRealInTime(); if (CarEnum.PayTypeEnum.HAS_PAY_TYPE.getType().equals(tbBusinessCar.getPayType()) && tbBusinessCar.getPayTime() != null) { inTime = tbBusinessCar.getPayTime(); } IOrderPriceRes res = tbBusinessService.getPartMoney(inTime, now, carNo, tbBusinessCar.getColor()); double dif = res.getTotalOrderPrice().subtract(tbBusinessCar.getMoney()).doubleValue(); double total = NumberUtil.add(dif, wMoney); if (total > 0) { String desc = "请缴费用" + total + "元"; log.error("请求返回:{},{}", carNo, desc); return ResultJson.error(desc); } //无需交停车费,又没有支付的--->设置成免费车辆 if (tbBusinessCar.getPayTime() == null) { tbBusinessCar.setPayType(CarEnum.PayTypeEnum.FEE_TYPE.getType()).setPay(1); } freeOut(tbBusinessCar, now, channel, image); return ResultJson.success(); } else { //有业务的车--->都要交停车费====>除了大头车,拦车 //该车所有的业务都是到达卡口才进行扣费才会进入自动扣费 Date inTime = tbBusinessCar.getRealInTime(); if (CarEnum.PayTypeEnum.HAS_PAY_TYPE.getType().equals(tbBusinessCar.getPayType()) && tbBusinessCar.getPayTime() != null) { inTime = tbBusinessCar.getPayTime(); } partMoneyRes = tbBusinessService.getPartMoney(inTime, now, carNo, tbBusinessCar.getColor()); double dif = partMoneyRes.getTotalOrderPrice().doubleValue(); if (dif > 0) { log.error("停车费:{},{}元", carNo, dif); } else { if (tbBusinessCar.getPayTime() == null) { tbBusinessCar.setPayType(CarEnum.PayTypeEnum.FEE_TYPE.getType()).setPay(1); } } } //============业务费计算是否交完 for (TbBusiness tbBusiness : businessList) { List businessItems = tbBusinessItemService.findByBusinessId(tbBusiness.getId()); if (businessItems.isEmpty()) { continue; } //是否支付完 boolean pay = businessItems.stream().noneMatch(item -> item.getPayStatus() == 0); TbGoods tbGoods = tbGoodsService.getById(tbBusiness.getGoodsId()); //重车离场限制 int weiCarLeave = tbGoods.getVietnamCarLeave(); //空车离场限制 int emptyCarLeave = tbGoods.getChinaCarLeave(); //需要交业务费 if (CarEnum.CarTypeEnum.WEIGHT_TYPE.getType().equals(carType)) {//==重车 if (GoodsEnum.LeaveEnum.PART_MONEY.getCode() != weiCarLeave && !pay) { RedisUtil.setByMINUTES(channel, carNo, 5); tbBusinessItemService.buildExpenses(businessItems, expenses); log.error("==重车:缴纳业务费用:{}", carNo); } } else { if (GoodsEnum.LeaveEnum.PART_MONEY.getCode() != emptyCarLeave && !pay) { RedisUtil.setByMINUTES(channel, carNo, 5); tbBusinessItemService.buildExpenses(businessItems, expenses); } } } if (!expenses.isEmpty()) { businessRes = syncService.orderPriceCal(expenses); } BigDecimal carMoney = partMoneyRes.getTotalOrderPrice(); BigDecimal businessMoney = businessRes.getTotalOrderPrice(); BigDecimal total = businessMoney.add(carMoney); //地磅费 List carWeights = tbCarWeightService.findByBusinessCarId(tbBusinessCar.getId()); //未支付的过磅费用 carWeights = carWeights.stream().filter(tbCarWeight -> tbCarWeight.getPayStatus() == 0).collect(Collectors.toList()); BigDecimal weightMoney = BigDecimal.ZERO; if (!carWeights.isEmpty()) { for (TbCarWeight carWeight : carWeights) { weightMoney = carWeight.getWeightPrice().add(weightMoney); } total = total.add(weightMoney); } if (total.doubleValue() > 0) { String desc = "请缴"+total+"费用"; boolean flag = automaticPay.payBusinessAndPartMoney(businessList, tbBusinessCar, partMoneyRes, businessRes, carWeights); if (flag) { log.error("预存款扣款成功,返回:{},{}", carNo, desc); freeOut(tbBusinessCar, now, channel, image); return ResultJson.success(); } log.error("请求返回:{},{}", carNo, desc); return ResultJson.error(desc); } freeOut(tbBusinessCar, now, channel, image); return ResultJson.success(); } private void freeOut(TbBusinessCar tbBusinessCar, Date now, String outChannel, String base64Image) { tbBusinessCar.setRealOutTime(now).setTimeUpdate(now).setOutChannel(outChannel); if (tbBusinessCar.getPay() == 0) { tbBusinessCar.setPay(1); } tbBusinessCarService.updateById(tbBusinessCar); String carNo = tbBusinessCar.getCarNo(); CoverBase64ToUrl(base64Image, tbBusinessCar.getId(), carNo, 2); RedisUtil.del(outChannel); log.error("请求返回【放行】:{}", carNo); } private boolean checkFree(String carNo, int inOrOut, Date now) { TbCar tbCar = tbCarService.findByCardNo(carNo); if (tbCar != null) { if (inOrOut == 1) { tbCar.setLastInTime(now); } else { tbCar.setLastOutTime(now); } tbCarService.updateById(tbCar); } return tbCar != null && !TbCar.CarTypeEnum.BUSINESS_CAR.getType().equals(tbCar.getCarType()); } @Async public void handlerInRecord(InRecordBO inRecordBO) { String carNo = inRecordBO.getCarNumber().trim().toUpperCase(); // 入场==>取车牌颜色 TbBusinessCar tbBusinessCar = tbBusinessCarService.findTheLastRecord(carNo); if (tbBusinessCar != null) { String color = inRecordBO.getCarColor(); TbMildCar tbMildCar = tbMildCarService.findByCarNo(carNo); if (tbMildCar != null) {//车长 tbBusinessCar.setCarSize(tbMildCar.getCarLength()); } //蓝牌 4.2米以及以下 if (color.contains(partConfig.getFreeColor())) { if (tbMildCar == null) { tbBusinessCar.setPayType(CarEnum.PayTypeEnum.FEE_TYPE.getType()).setPay(1); } } TbCar tbCar = tbCarService.findByCardNo(tbBusinessCar.getCarNo()); if (tbCar != null && !TbCar.CarTypeEnum.BUSINESS_CAR.getType().equals(tbCar.getCarType())) { tbBusinessCar.setPayType(CarEnum.PayTypeEnum.FEE_TYPE.getType()); List businessList = tbBusinessService.findOtherBusinessByCarId(tbBusinessCar.getId()); if (businessList.isEmpty()) { //无业务&免费车===>无需审核 tbBusinessCar.setConfirmJudge(CarEnum.ConfirmJudgeEnum.NO_NEED_JUDGE.getCode()); } } tbBusinessCar.setColor(color); tbBusinessCarService.updateById(tbBusinessCar); } } final TimedCache WEIGHT_IMAGE_CACHE = CacheUtil.newTimedCache(30 * 60 * 1000); final TimedCache REQ_CACHE = CacheUtil.newTimedCache(60 * 1000); /** * @param checkCarNumberBO * @return */ public ResultJson reqWeighbridge(CheckCarNumberBO checkCarNumberBO) { String carNo = checkCarNumberBO.getCarNumber(); String channel = checkCarNumberBO.getChannelName(); TbChannelConfig tbChannelConfig = tbChannelConfigService.findByName(channel); if (tbChannelConfig == null) { StaticLog.error("通道未配置,{}", channel); return ResultJson.error("通道未配置"); } Integer weight = WEIGHT_CACHE.get(tbChannelConfig.getMatchChannelName()); String image = checkCarNumberBO.getImageData(); if (StrUtil.isNotEmpty(image)) { StaticLog.error("缓存称重图片,{}", carNo); WEIGHT_IMAGE_CACHE.put(carNo, image); } if (weight == null) { log.error("车辆未过磅:{},{}", channel, carNo); return ResultJson.error("请先过磅"); } Integer hasRecord = REQ_CACHE.get(carNo, false); if (hasRecord != null) { log.info("重复识别,已过磅:{}", carNo); return ResultJson.error("已过磅"); } TbBusinessCar tbBusinessCar = tbBusinessCarService.findTheLastRecord(carNo); //--------------------------------------------这个地方会出问题,如果车辆离场了再称重------------------ if (tbBusinessCar == null || tbBusinessCar.getRealOutTime() != null) { log.error("未找到有效入场记录:{},{}", channel, carNo); return ResultJson.error("未找到有效入场记录"); } Date now = new Date(); double weighbridge = NumberUtil.div(Double.valueOf(weight).doubleValue(), 1000, 2); tbBusinessCar.setNetWeight(weighbridge + ""); TbItem tbItem = tbItemService.findByAliasName(SystemObject.config.getWeighbridge()); IOrderItem iOrderItem = new IOrderItem(); iOrderItem.setUniqExpenseId(tbItem.getItemCode()).setExpenseNum(weighbridge + ""); IOrderPriceRes res = syncService.orderPriceCal(Collections.singletonList(iOrderItem)); BigDecimal weightMoney = res.getTotalOrderPrice(); tbBusinessCar.setNetweightMoney(weightMoney.add(tbBusinessCar.getNetweightMoney())); tbBusinessCarService.updateById(tbBusinessCar); WEIGHT_CACHE.remove(channel); TbCarWeight carWeight = new TbCarWeight(); String no = DateUtil.format(now, "yyyyMMddHHmm") + RandomUtil.randomLong(1000, 9999); carWeight.setCarNo(carNo).setTotalWeight(BigDecimal.valueOf(weighbridge)).setCalculateId(res.getCalculateId()) .setChannelName(channel).setCreateTime(now).setInTime(now).setOutTime(now).setCustomerId(tbBusinessCar.getCustomerId()) .setBusinessCarId(tbBusinessCar.getId()).setNo(no).setWeightPrice(weightMoney); tbCarWeightService.save(carWeight); taskService.addTask(new CoverWeightBase64ToImageTask("=======" + carWeight.getId() + "", 2000, carWeight.getId(), WEIGHT_IMAGE_CACHE.get(carNo))); WEIGHT_CACHE.remove(carNo); REQ_CACHE.put(carNo, 1); if (tbChannelConfig.getHandlerUp() == 1) { return ResultJson.success(tbBusinessCar.getNetWeight()); } else { return ResultJson.error("过磅完成" + tbBusinessCar.getNetWeight()); } } private final TimedCache WEIGHT_CACHE = CacheUtil.newTimedCache(120000); /** * 缓存地磅数据 * * @param channel * @param weight kg====> */ public void cacheWeighbridge(String channel, Integer weight) { WEIGHT_CACHE.put(channel, weight); } /** * 清除缓存 * * @param channel */ public void cleanWeighbridge(String channel) { WEIGHT_CACHE.remove(channel); } }