123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563 |
- package com.pj.project.tb_account;
- import cn.hutool.core.bean.BeanUtil;
- import cn.hutool.core.util.NumberUtil;
- import cn.hutool.core.util.RandomUtil;
- import cn.hutool.extra.spring.SpringUtil;
- import cn.hutool.log.StaticLog;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.pj.api.open.ResultJson;
- 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_deduction_bind.TbDeductionBind;
- import com.pj.project.tb_deduction_bind.TbDeductionBindService;
- import com.pj.project.tb_deduction_record.TbDeductionRecord;
- import com.pj.project.tb_fee_details.TbFeeDetails;
- import com.pj.project.tb_fee_details.TbFeeDetailsService;
- import com.pj.project.tb_goods.TbGoods;
- import com.pj.project.tb_goods.TbGoodsService;
- import com.pj.project.tb_invoice_order.TbInvoiceOrder;
- import com.pj.project.tb_invoice_order.TbInvoiceOrderService;
- import com.pj.project.tb_item.TbItem;
- import com.pj.utils.AesUtil;
- import com.pj.utils.cache.RedisUtil;
- import com.pj.utils.sg.NbUtil;
- import org.springframework.scheduling.annotation.Async;
- import org.springframework.stereotype.Component;
- import org.springframework.transaction.annotation.Transactional;
- import javax.annotation.Resource;
- import java.math.BigDecimal;
- import java.time.LocalDateTime;
- import java.time.format.DateTimeFormatter;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.List;
- import java.util.stream.Collectors;
- /**
- * 预充值自动缴费
- */
- @Component
- @Transactional
- public class AutomaticPay {
- @Resource
- TbBusinessCarService tbBusinessCarService;
- @Resource
- TbBusinessService tbBusinessService;
- @Resource
- TbDeductionBindService deductionBindService;
- @Resource
- TbBusinessItemService tbBusinessItemService;
- @Resource
- TbFeeDetailsService tbFeeDetailsService;
- @Resource
- TbAccountService tbAccountService;
- @Resource
- TbInvoiceOrderService invoiceOrderService;
- @Resource
- TbGoodsService tbGoodsService;
- private Integer feeType;
- /**
- * 异步扣费入口
- * @param businessId 业务id
- * @param plate 车牌号
- * @param feeType 收费类型,1-只收停车费、2-只收业务费,3-停车和业务费
- */
- //TODO 不要在此方法写逻辑
- @Async
- public void run(String businessId, String plate, Integer feeType) {
- this.feeType = feeType;
- task(businessId,plate,feeType);
- }
- /**
- * 异步解绑入口
- * @param plate
- */
- @Async
- public void unbindRun(String plate){
- if(isExistTask(null,plate)){
- return;
- }
- autoUnbindCarByPlate(plate);
- delRedisTask(null,plate);
- }
- /**
- * 分配任务
- */
- private void task(String businessId, String plate, Integer feeType){
- if(isExistTask(businessId,plate)){
- return;
- }
- if(feeType==1){
- doParkingFee(plate,0.0);
- }else if(feeType==2){
- List<TbBusinessCar> cars = tbBusinessCarService.findOtherBusinessCar(businessId);
- for (TbBusinessCar car : cars){
- this.doBusinessFee(businessId,car.getCarNo());
- }
- }else if(feeType==3){
- doOutFee(plate);
- }
- delRedisTask(businessId,plate);
- }
- /**
- * 收业务费
- * @param businessId
- */
- private void doBusinessFee(String businessId,String plate){
- if(!NumberUtil.isNumber(businessId) || NbUtil.isNull(plate)){
- return;
- }
- StaticLog.info("开始收取业务费:{}" , businessId);
- TbBusiness tbBusiness = tbBusinessService.getById(businessId);
- if(TbBusiness.PayStatus.NO_PAY.getCode()!=tbBusiness.getPayStatus()){
- StaticLog.info("已收取过业务费,退出收费程序:{}" , businessId);
- return;
- }
- if(!NumberUtil.isNumber(tbBusiness.getItemPrice().toString())){
- StaticLog.info("未获取到收费总金额或收费总金额非法,退出收费程序:{}" , businessId);
- return;
- }
- if(!deductionBindService.isBindCarByPlate(plate)){
- StaticLog.info("业务车辆未绑定指定客户的预存款账户,退出收费程序:{}{}",businessId,tbBusiness.getCustomerName());
- return;
- }
- List<TbBusinessCar> cars = tbBusinessCarService.findOtherBusinessCar(businessId);
- TbDeductionBind bind = deductionBindService.getBindCarByPlate(plate);
- TbAccount tbAccount = tbAccountService.getByCustomerId(bind.getCustomerId());
- String key = AesUtil.reverse(tbAccount.getAccSalt());
- String totalMoney = tbAccount.getTotalMoney();
- BigDecimal parkingMoneyBig = new BigDecimal(0);
- BigDecimal totalMoneyBig = new BigDecimal(totalMoney);
- BigDecimal balance = totalMoneyBig.subtract(tbBusiness.getItemPrice());
- boolean isOut = (TbGoods.DeductionTypeEnum.OUT_KK.getCode()==tbBusiness.getAutoDeductionType()) &&
- this.feeType==3;
- if(isOut){
- parkingMoneyBig = getParkings(cars);
- balance = balance.subtract(parkingMoneyBig);
- }
- if(balance.doubleValue()<0){
- StaticLog.info("支付账户余额不足!,退出收费程序:{}" , businessId);
- deductionBindService.setFeeFailRecord(bind.getCustomerId(),plate,
- AesUtil.toStr(tbBusiness.getGoodsName())+":因支付账户余额不足,自动缴费失败。。");
- return;
- }
- Date now = new Date();
- String no = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomNumbers(4);
- tbBusiness.setPayMoney(tbBusiness.getItemPrice()).setPayTime(now).setPayType(5)
- .setPayNo(no).setConfirmInput(1).setConfirmInputTime(now).setPayStatus(
- TbBusiness.PayStatus.HAS_PAY_CONFIRM.getCode());
- tbBusiness.updateById();
- List<TbBusinessItem> businessItems = tbBusinessItemService.findByBusinessId(businessId);
- for(TbBusinessItem businessItem:businessItems){
- if(businessItem.getPayStatus()==1){
- continue;
- }
- businessItem.setPayStatus(1).setPayTime(now);
- }
- tbBusinessItemService.updateBatchById(businessItems);
- if(isOut){
- this.updateTbBusinessCars(cars);
- }
- //更新账户余额
- tbAccount.setTotalMoney(AesUtil.encryptECB(balance.toString(),key));
- tbAccount.updateById();
- deductionBindService.setDeductMoney(bind.getCustomerId(),plate,tbBusiness.getItemPrice());
- //生成收费明细
- List<TbFeeDetails> tbFeeDetailsList = tbFeeDetailsService.autoChargeBusinessFee(
- businessItems,null,null,now);
- //生成扣费记录
- createTbDeductionRecord(tbFeeDetailsList,tbAccount, totalMoneyBig,plate,bind.getCustomerName(),no);
- //生成开票信息
- createTbInvoiceOrder(tbBusiness, cars, parkingMoneyBig, plate,bind.getCustomerId(),no,isOut);
- if(isOut){
- deductionBindService.setDeductMoney(bind.getCustomerId(),plate,parkingMoneyBig);
- List<TbFeeDetails> parkFeeDetailsList = tbFeeDetailsService.autoChargeParkFee(
- cars,null,null,now);
- createTbDeductionRecord(parkFeeDetailsList,tbAccount,
- totalMoneyBig.subtract(tbBusiness.getItemPrice()),plate,bind.getCustomerName(),no);
- deductionBindService.autoUnbindCar(cars);
- }
- StaticLog.info("预充值自动缴费成功!,退出收费程序:{}{}" , businessId,tbAccount.getCustomerId());
- }
- /**
- * 出场所收费,根据车牌号
- * @param plate
- */
- private void doOutFee(String plate){
- if(NbUtil.isNull(plate)){
- return;
- }
- TbBusinessCar tbBusinessCar = tbBusinessCarService.findTheLastRecord(plate);
- if(tbBusinessCar==null){
- return;
- }
- List<TbBusiness> businessList = tbBusinessService.findOtherBusinessByCarId(tbBusinessCar.getId());
- if(businessList==null){return;}
- for (TbBusiness business: businessList){
- List<TbBusinessCar> cars = tbBusinessCarService.findOtherBusinessCar(business.getId());
- if(cars==null)continue;
- for (TbBusinessCar car:cars){
- doBusinessFee(business.getId(), car.getCarNo());
- }
- }
- }
- /**
- * 收停车费,不判断免费车辆
- * @param plate
- * @param parkingFee
- */
- private void doParkingFee(String plate, double parkingFee){
- if(NbUtil.isNull(plate)){
- return;
- }
- TbBusinessCar car = tbBusinessCarService.findTheLastRecord(plate);
- if(car==null){
- return;
- }
- StaticLog.info("开始自动缴纳停车费:{}" , car.getCarNo());
- // if(car.getPay()==1 || car.getPayTime()!=null){
- // StaticLog.info("该车辆已缴纳过停车费!,退出收费程序:{}" , car.getCarNo());
- // return;
- // }
- TbAccount account = tbAccountService.getTbAccountByPlate(car.getCarNo());
- if (account==null){
- StaticLog.info("该车辆还未绑定客户预存款账户!,退出收费程序:{}" , car.getCarNo());
- return;
- }
- BigDecimal parkFeeBig = null;
- if(parkingFee>0){
- parkFeeBig = new BigDecimal(String.valueOf(parkingFee));
- }else {
- parkFeeBig = caulatePrice(car, new Date());
- }
- if(parkFeeBig==null ||parkFeeBig.doubleValue()<=0){
- StaticLog.info("该车辆无需缴纳停车费!,退出收费程序:{}" , car.getCarNo());
- return;
- }
- TbDeductionBind bind = deductionBindService.getBindCarByPlate(plate);
- BigDecimal totalBig = new BigDecimal("0");
- String key = null;
- if(!NumberUtil.isNumber(account.getTotalMoney())){
- key = AesUtil.reverse(account.getAccSalt());
- totalBig = new BigDecimal(AesUtil.decryptECB(account.getTotalMoney(),key));
- }
- BigDecimal balance = totalBig.subtract(parkFeeBig);
- if(balance.doubleValue()<0){
- StaticLog.info("支付账户余额不足!,退出收费程序:{}" , car.getCarNo());
- return;
- }
- String no = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + RandomUtil.randomNumbers(4);
- car.setMoney(parkFeeBig);
- updateTbBusinessCar(car);
- account.setTotalMoney(AesUtil.encryptECB(balance.toString(),key));
- account.updateById();
- deductionBindService.setDeductMoney(bind.getCustomerId(),plate,parkFeeBig);
- List<TbBusinessCar> cars = new ArrayList<TbBusinessCar>();
- cars.add(car);
- List<TbFeeDetails> parkFeeDetailsList = tbFeeDetailsService.autoChargeParkFee(
- cars,null,null,new Date());
- createTbDeductionRecord(parkFeeDetailsList,account, totalBig,plate,bind.getCustomerName(),no);
- createTbInvoiceOrderPark(car,account.getCustomerId(),no);
- deductionBindService.autoUnbindCar(cars);
- StaticLog.info("停车费自动缴费成功!,退出收费程序:{}" , car.getCarNo());
- }
- /**
- * 生成扣费记录
- * @param tbFeeDetailsList
- * @param tbAccount
- * @param totalMoneyBig
- */
- private void createTbDeductionRecord(List<TbFeeDetails> tbFeeDetailsList,TbAccount tbAccount,
- BigDecimal totalMoneyBig,String plate,String customerName,String no ){
- if(tbFeeDetailsList==null)return;
- int i = 0;
- String tempMoney = null;
- String bindIdStr = deductionBindService.getBindId(plate);
- for (TbFeeDetails feeDetails : tbFeeDetailsList){
- TbDeductionRecord deductionRecord = BeanUtil.toBean(feeDetails,TbDeductionRecord.class);
- String totalStr = null;
- if(totalMoneyBig!=null && feeDetails.getNoTaxPrice()!=null){
- if(i!=0){
- totalMoneyBig = new BigDecimal(tempMoney);
- }
- totalStr = totalMoneyBig.subtract(feeDetails.getItemPrice()).toString();
- tempMoney = totalStr;
- }
- deductionRecord.setId(null);
- deductionRecord.setDeductionBindId(bindIdStr);
- deductionRecord.setCustomerId(tbAccount.getCustomerId());
- deductionRecord.setCustomerName(customerName);
- deductionRecord.setFeeDetailsId(feeDetails.getId());
- deductionRecord.setOriginalMoney(totalMoneyBig.toString());
- deductionRecord.setDeductMoney(feeDetails.getItemPrice());
- deductionRecord.setTotalMoney(totalStr);
- deductionRecord.setReviewStatus(0);
- deductionRecord.setCarNo(plate);
- deductionRecord.setPreOrderNum(no);
- deductionRecord.insert();
- feeDetails.setCarNo(plate);
- feeDetails.setPreOrderNum(no);
- feeDetails.setCustomerId(tbAccount.getCustomerId());
- feeDetails.setCustomerName(customerName);
- tbFeeDetailsService.updateById(feeDetails);
- i++;
- }
- }
- /**
- * 更新停车费状态
- */
- private void updateTbBusinessCar(TbBusinessCar car){
- if(car == null)return;
- car.setPay(1).setPayTime(new Date());
- car.updateById();
- }
- /**
- * 更新停车费状态
- */
- private void updateTbBusinessCars(List<TbBusinessCar> cars){
- if(cars == null)return;
- for (TbBusinessCar car:cars){
- updateTbBusinessCar(car);
- }
- }
- /**
- * 生成开票订单信息
- * @param tbBusiness
- */
- private void createTbInvoiceOrder(TbBusiness tbBusiness,List<TbBusinessCar> cars, BigDecimal parkingFee,
- String plate, String customerId, String no, boolean isOut){
- TbInvoiceOrder invoiceOrder = new TbInvoiceOrder();
- List<String> businessNameList = new ArrayList<>();
- List<String> businessNoList = new ArrayList<>();
- List<String> carNos = new ArrayList<>();
- businessNoList.add(tbBusiness.getNo());
- carNos.add(plate);
- businessNameList.add(tbBusiness.getGoodsName());
- if(cars!=null){
- for (TbBusinessCar car : cars) {
- if(isOut){
- if(TbBusinessCar.PayTypeEnum.FEE_TYPE.getType().equals(car.getPayType())){
- continue;
- }
- if(!businessNameList.contains("停车费")){
- businessNameList.add("停车费");
- }
- }else {
- if(NbUtil.isNull(car.getCarNo()) || !car.getCarNo().equals(plate)){
- continue;
- }
- }
- if(!businessNoList.contains(car.getNo())){
- businessNoList.add(car.getNo());
- }
- if(!carNos.contains(car.getCarNo())){
- carNos.add(car.getCarNo());
- }
- }
- }
- String businessNameStr = businessNameList.stream().map(String::valueOf).collect(Collectors.joining(","));
- String businessNoStr = businessNoList.stream().map(String::valueOf).collect(Collectors.joining(","));
- String carNoStr = carNos.stream().map(String::valueOf).collect(Collectors.joining(","));
- BigDecimal billMoney = tbBusiness.getItemPrice();
- if(parkingFee!=null){
- billMoney = parkingFee.add(billMoney);
- }
- invoiceOrder.setBusinessName(businessNameStr).setBusinessNo(businessNoStr).setCarNo(carNoStr)
- .setTransactionId(null).setBillMoney(billMoney).setBusinessId(tbBusiness.getId())
- .setStatus(0).setCreateTime(new Date()).setCustomerId(customerId).setPreOrderNum(no);
- invoiceOrderService.save(invoiceOrder);
- }
- /**
- * 无业务车辆收停车费生成发票信息
- */
- private void createTbInvoiceOrderPark(TbBusinessCar car, String customerId,String no){
- TbInvoiceOrder invoiceOrder = new TbInvoiceOrder();
- invoiceOrder.setBusinessName("停车费").setBusinessNo(car.getNo()).setCarNo(car.getCarNo())
- .setTransactionId(null).setBillMoney(car.getMoney()).setBusinessId(null)
- .setStatus(0).setCreateTime(new Date()).setCustomerId(customerId).setPreOrderNum(no);
- invoiceOrderService.save(invoiceOrder);
- }
- /**
- * 生成停车费
- * @param tbBusinessCar
- * @param now
- * @return
- */
- private BigDecimal caulatePrice(TbBusinessCar tbBusinessCar, Date now) {
- if(tbBusinessCar==null || now==null) new BigDecimal("0");
- Date inTime = tbBusinessCar.getRealInTime();
- if (tbBusinessCar.getPay() == 1 && tbBusinessCar.getRealOutTime() == null && tbBusinessCar.getPayTime() != null) {
- inTime = tbBusinessCar.getPayTime();
- }
- BigDecimal price = tbBusinessService.calculationPartMoney(inTime, now);
- tbBusinessCar.setMoney(price);
- return price;
- }
- /**
- * 获取所有停车费总和
- * @param cars
- * @return
- */
- private BigDecimal getParkings(List<TbBusinessCar> cars){
- if(cars==null) new BigDecimal("0");
- Date now = new Date();
- BigDecimal value = new BigDecimal("0");
- for (TbBusinessCar car:cars){
- value = value.add(this.caulatePrice(car,now));
- car.setPayType(TbBusinessCar.PayTypeEnum.HAS_PAY_TYPE.getType());
- }
- return value;
- }
- /**
- * 获取所有停车费总和,过滤免费车
- * @param cars
- * @return
- */
- private BigDecimal getParkingsByBS(List<TbBusinessCar> cars,TbBusiness tbBusiness){
- if(cars==null) new BigDecimal("0");
- Date now = new Date();
- BigDecimal value = new BigDecimal("0");
- for (TbBusinessCar car:cars){
- if(isParkingFeeByBS(tbBusiness,car.getCarType())){
- car.setPayType(TbBusinessCar.PayTypeEnum.FEE_TYPE.getType());
- }else {
- value = value.add(this.caulatePrice(car,now));
- car.setPayType(TbBusinessCar.PayTypeEnum.HAS_PAY_TYPE.getType());
- }
- }
- return value;
- }
- /**
- * 判断有业务的车是否收停车费
- * @return true是免费
- */
- private boolean isParkingFeeByBS(TbBusiness tbBusiness,String carType){
- if (TbItem.ItemTypeEnum.EMPTY_TYPE.getType().equals(carType)) {
- TbGoods tbGoods = tbGoodsService.getById(tbBusiness.getGoodsId());
- return tbGoods.getChinaCarPay() == 1;
- } else {//越南车=重车
- TbGoods tbGoods = tbGoodsService.getById(tbBusiness.getGoodsId());
- return tbGoods.getVietnamCarPay() == 1;
- }
- }
- /**
- * 补录进场解绑逻辑
- * @return
- */
- private void autoUnbindCarByPlate(String plate){
- if(NbUtil.isNull(plate)) return;
- TbBusinessCar tbBusinessCar = tbBusinessCarService.findTheLastRecord(plate);
- //离场逻辑
- if (tbBusinessCar!=null){
- if(doUnbindCarByPlate(tbBusinessCar)){
- return;
- }
- }
- //进场逻辑
- TbDeductionBind bind = deductionBindService.getOne(new LambdaQueryWrapper<TbDeductionBind>().eq(
- TbDeductionBind::getBindCar,plate).isNull(TbDeductionBind::getUnbindTime));
- if(bind != null){
- TbDeductionRecord record = new TbDeductionRecord();
- Integer count = record.selectCount(new LambdaQueryWrapper<TbDeductionRecord>().like(
- TbDeductionRecord::getDeductionBindId,bind.getId()));
- if(count>0){
- bind.setUpdateBy("预充值自动缴费解绑");
- bind.setUpdateTime(new Date());
- bind.setUnbindTime(new Date());
- bind.updateById();
- }else {
- Integer buCount = tbBusinessService.count(new LambdaQueryWrapper<TbBusiness>().ne(
- TbBusiness::getPayStatus,1)
- .between(TbBusiness::getCreateTime,bind.getBindTime(),NbUtil.getNow()));
- if(buCount>0){
- bind.setUpdateBy("预充值自动缴费解绑");
- bind.setUpdateTime(new Date());
- bind.setUnbindTime(new Date());
- bind.updateById();
- }
- }
- }
- }
- /**
- * 补录出场解绑逻辑
- * @param tbBusinessCar
- */
- private boolean doUnbindCarByPlate(TbBusinessCar tbBusinessCar){
- if (tbBusinessCar==null || tbBusinessCar.getRealOutTime()==null){
- return false;
- }
- TbDeductionBind bind = deductionBindService.getOne(new LambdaQueryWrapper<TbDeductionBind>().eq(
- TbDeductionBind::getBindCar,tbBusinessCar.getCarNo())
- .lt(TbDeductionBind::getBindTime,tbBusinessCar.getRealOutTime())
- .isNull(TbDeductionBind::getUnbindTime));
- if(bind==null){
- return false;
- }
- bind.setUpdateBy("预充值自动缴费解绑");
- bind.setUpdateTime(new Date());
- bind.setUnbindTime(new Date());
- bind.updateById();
- return true;
- }
- /**
- * 缓存任务,如果存在任务不继续往下执行
- * @param businessId
- * @param plate
- * @return
- */
- private boolean isExistTask(String businessId, String plate){
- String key = getRedisKey(businessId,plate);
- if(NbUtil.isNullStr(RedisUtil.get(key))){
- RedisUtil.setByMINUTES(key,key,5);
- return false;
- }
- return true;
- }
- private void delRedisTask(String businessId, String plate){
- String key = getRedisKey(businessId,plate);
- RedisUtil.del(key);
- }
- private String getRedisKey(String businessId, String plate){
- if(NbUtil.isNullStr(businessId)){
- businessId = "100";
- }
- if(NbUtil.isNullStr(plate)){
- plate = "100";
- }
- String key = "autoPay:"+businessId+plate;
- return key;
- }
- }
|