DiscountServiceImpl.java 20.4 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
package com.zteits.bill.biz.discount;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import org.apache.commons.collections4.CollectionUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import cn.hutool.cache.impl.TimedCache;
import com.clouds.common.constants.CarTypeEnum;
import com.clouds.common.constants.HolidayEnum;
import com.clouds.common.utils.BeanValidatorsUtils;
import com.clouds.common.utils.ResultUtils;
import com.github.pagehelper.util.StringUtil;
import com.zteits.bill.configuration.TimedCacheFactory;
import com.zteits.bill.dao.discount.ActivityDiscountDao;
import com.zteits.bill.dao.discount.ActivityDiscountRuleDao;
import com.zteits.bill.domain.DiscontRuleForParkDO;
import com.zteits.bill.domain.TActivityDiscountRule;
import com.zteits.clouds.api.apibase.bean.BizResult;
import com.zteits.clouds.api.apibase.constants.BasicEnum;
import com.zteits.clouds.api.apibase.constants.ErrorType;
import com.zteits.clouds.api.apibase.constants.ParkDetailTypeEnum;
import com.zteits.clouds.api.apibase.constants.PayTypeEnum;
import com.zteits.clouds.api.apibase.exception.BizException;
import com.zteits.clouds.api.dto.bill.discount.dto.ActivityDiscountRuleDTO;
import com.zteits.clouds.api.dto.bill.discount.dto.BillingOfDiscountDTO;
import com.zteits.clouds.api.dto.bill.discount.dto.DiscontRuleForParkDTO;
import com.zteits.clouds.api.dto.bill.discount.dto.TActivityDiscountSpecialCarDTO;
import com.zteits.clouds.api.dto.bill.discount.param.BillingOfDiscountReq;
import com.zteits.clouds.api.dto.bill.discount.param.CheckDiscountUniqueByPlNoRequest;
import com.zteits.clouds.api.dto.bill.discount.param.QueryDiscountRuleRequest;
import com.zteits.clouds.api.dto.bill.discount.param.QueryDiscountSpecialCarRequest;
import com.zteits.clouds.api.dto.bill.holiday.dto.SpHolidaysDTO;
import com.zteits.clouds.api.dto.bill.holiday.param.DaysInfoQueryReq;
import com.zteits.clouds.api.dto.bill.vipcard.param.NewEnergyCarDiscountQueryReq;
import com.zteits.clouds.api.dto.bill.whitelist.CarNumIsFreeDTO;
import com.zteits.clouds.api.dto.bill.whitelist.param.QueryCarNumIsWhitelistRequest;
import com.zteits.clouds.api.service.bill.billrule.DiscountSpecialCarService;
import com.zteits.clouds.api.service.bill.discount.DiscountService;
import com.zteits.clouds.api.service.bill.holiday.HolidayService;
import com.zteits.clouds.api.service.bill.whitelist.WhitelistService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

/**
 * Copyright: Copyright (c) 2017  zteits
 *
 * @ClassName: com.zteits.billing.biz.discount
 * @Description:
 * @version: v1.0.0
 * @author: atao
 * @date: 2017/11/6   下午1:49
 * Modification History:
 * Date         Author          Version      Description
 * ---------------------------------------------------------*
 * 2017/11/6      atao          v1.0.0          创建
 */
@Service("com.zteits.bill.biz.discount.DiscountServiceImpl")
public class DiscountServiceImpl implements DiscountService {

    private static final Logger logger = LoggerFactory.getLogger(DiscountServiceImpl.class);

    @Autowired
    private ActivityDiscountRuleDao activityDiscountRuleDao;

    @Autowired
    private ActivityDiscountDao activityDiscountDao;

    @Autowired
    private HolidayService holidayService;
    @Autowired
    private WhitelistService whitelistService;
    @Autowired
    private DiscountSpecialCarService discountSpecialCarService;

    /**
     * 是否有时间限制:1:是 0:否.
     */
    private static final Integer IS_TIMME_LIMIT = 1;

    @Override
    public BizResult<BillingOfDiscountDTO> billingOfDiscount(BillingOfDiscountReq req) {
        if (StringUtils.isEmpty(req.getDiscountRuleNo())) {
            throw new BizException(ErrorType.PARAMM_NULL, "折扣规则编码");
        }

        if (null == req.getFee()) {
            throw new BizException(ErrorType.PARAMM_NULL, "应收金额");
        }

        BillingOfDiscountDTO result = new BillingOfDiscountDTO();

        TActivityDiscountRule discountRule = activityDiscountRuleDao.queryDiscountRuleByDiscNo(req.getDiscountRuleNo());
        if (null == discountRule) {
            //没有折扣规则
            result.setDiscountRuleDTO(null);
            result.setDiscValue(null);
            result.setRealFee(req.getFee());
            result.setReceFee(req.getFee());
        } else {
            //有折扣规则
            ActivityDiscountRuleDTO dto = new ActivityDiscountRuleDTO();
            BeanUtils.copyProperties(discountRule, dto);
            result.setDiscountRuleDTO(dto);
            result.setDiscValue(dto.getDiscValue());
            result.setRealFee(req.getFee() * Math.round(Double.valueOf(dto.getDiscValue()) / 10));
            result.setReceFee(req.getFee());
        }

        return new BizResult<>(result);
    }

    /**
     * 通过停车场编码,折扣类型,终端来源,车辆类型,出场时间查询停车场所有折扣规则.<br/>
     *
     * @param request
     * @return
     */
    @Override
    public BizResult<List<DiscontRuleForParkDTO>> queryDiscontRuleForList(QueryDiscountRuleRequest request)
        throws Exception {
        logger.info("---begin停车场所有折扣规则,入参={}", JSONObject.toJSON(request));
        List<DiscontRuleForParkDTO> listDTO = new ArrayList<DiscontRuleForParkDTO>();

        //查询车辆是否属于每天只收一次费用 的白名单车辆
        try {
            QueryCarNumIsWhitelistRequest queryCarNumIsWhitelistRequest = new QueryCarNumIsWhitelistRequest();
            queryCarNumIsWhitelistRequest.setPlNo(request.getPlNo());
            queryCarNumIsWhitelistRequest.setCarNumber(request.getCarNo());
            queryCarNumIsWhitelistRequest.setCarType(request.getDisCarTpye());
            BizResult<CarNumIsFreeDTO> carNumIsFreeDTOBizResult = whitelistService.queryCarNumIsOnlyOneFeeEveryDay(
                queryCarNumIsWhitelistRequest);
            CarNumIsFreeDTO carNumIsFreeDTO = ResultUtils.getBizResultData(carNumIsFreeDTOBizResult);
            logger.info("查询车辆信息是否属于每天只收一次费用的白名单车辆用户信息 carNumber={},plNo={},响应为:{}", request.getCarNo(),
                request.getPlNo(), JSONObject.toJSONString(carNumIsFreeDTOBizResult));
            if (null != carNumIsFreeDTO.getFreeReason() && ParkDetailTypeEnum.WhiteListCar.equals(
                carNumIsFreeDTO.getFreeReason())) {
                return new BizResult<>(listDTO);
            }
        } catch (Exception e) {
            logger.error("查询车辆信息是否属于每天只收一次费用的白名单车辆用户信息 carNumber={},plNo={}, 捕获异常:", request.getCarNo(),
                request.getPlNo(), e);
            throw new BizException(ErrorType.BIZ_ERROR,"查询白名单车辆用户信息失败!");
        }

        //折扣缓存1分钟
        TimedCache<String, String> timedCache = TimedCacheFactory.getTimedCache();
        String key = "";
        if (StringUtils.isEmpty(request.getCarNo())) {
            key = request.getPlNo() + request.getDiscTerminalRes() + request.getDisCarTpye() + request.getDiscType();
        } else {
            key = request.getPlNo() + request.getDiscTerminalRes() + request.getDisCarTpye() + request.getDiscType()
                + request.getCarNo();
        }
        if(request.getPayType() != null){
            key += request.getPayType(); // getPayType V5 V36
        }
        logger.info("缓存对应折扣key"+key);
        String value = timedCache.get(key, false);
        logger.info("缓存对应折扣value"+value);
        if (StringUtils.isEmpty(value)) {
            logger.info("缓存没有找到对应折扣,调用服务查询");
            listDTO = getDiscontRuleForParkDTOS(request);
            if (CollectionUtils.isEmpty(listDTO)) {
                timedCache.put(key, "no discont");
            }
            timedCache.put(key, JSON.toJSONString(listDTO));
            logger.info("缓存timedCache put");
            return new BizResult<List<DiscontRuleForParkDTO>>(listDTO);
        }
        logger.info("缓存中已经存在折扣值:" + value);
        if (!"no discont".equals(value)) {
            listDTO = JSON.parseArray(value, DiscontRuleForParkDTO.class);
        }
        return new BizResult<List<DiscontRuleForParkDTO>>(listDTO);
    }

    private List<DiscontRuleForParkDTO> getDiscontRuleForParkDTOS(QueryDiscountRuleRequest request)
        throws ParseException {
        //判断是否为新能源车,位数大于7 且不是无牌车
        if (request.getCarNo().length() > 7 && !request.getCarNo().startsWith("无")) {
            request.setDisCarTpye(CarTypeEnum.GREEN_ENERGY_CAR.val());
        }
        //小型货车取小型车计费折扣
        if (CarTypeEnum.TRUCK_SMALL_CAR.val().equals(request.getDisCarTpye())) {
            request.setDisCarTpye(CarTypeEnum.SMALL_CAR.val());
        }
        //大型货车取大型车型车计费折扣
        if ( CarTypeEnum.TRUCK_LARGE_CAR.val().equals(request.getDisCarTpye())) {
            request.setDisCarTpye(CarTypeEnum.LARGE_CAR.val());
        }
        if (CarTypeEnum.GREEN_ENERGY_CAR.val().equals(request.getDisCarTpye())) {
            //新能源车折扣,调用白名单获取,后续修改为放到折扣规则中,暂时求稳定,过个好年
            NewEnergyCarDiscountQueryReq newEnergyCarDiscountQueryReq = new NewEnergyCarDiscountQueryReq();
            newEnergyCarDiscountQueryReq.setPlNo(request.getPlNo());
            newEnergyCarDiscountQueryReq.setCarNum(request.getCarNo());
            newEnergyCarDiscountQueryReq.setSysCode(BasicEnum.SYS_CODE.getValue());
            BizResult<String> integerBizResult = whitelistService.queryNewEnergyCarDiscount(
                newEnergyCarDiscountQueryReq);
            //新能源车折扣
            String newEngerdis = ResultUtils.getBizResultData(integerBizResult);
            //返回折扣信息
            if (StringUtils.isEmpty(newEngerdis)) {
                return new ArrayList<>();
            } else {
                //模拟折扣返回列表返回新能源车折扣
                DiscontRuleForParkDTO discontRuleForParkDTO = new DiscontRuleForParkDTO();
                discontRuleForParkDTO.setDisCarTpye(request.getDisCarTpye());
                discontRuleForParkDTO.setDiscNo("GREEN_CAR_DISC_NO");//新能源车折扣编码
                discontRuleForParkDTO.setDiscRuleNo("GREEN_CAR_DISC_RULE_NO");//新能源车折扣规则编码
                discontRuleForParkDTO.setDiscPayType(-1);//支付方式不限
                discontRuleForParkDTO.setDiscTerminalRes(request.getDiscTerminalRes());
                discontRuleForParkDTO.setDiscType(request.getDiscType());
                discontRuleForParkDTO.setDiscValue(newEngerdis);
                discontRuleForParkDTO.setPlNo(request.getPlNo());
                return Arrays.asList(discontRuleForParkDTO);
            }
        }
        //其他车辆类型折扣查询
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        //校验入参数
        BeanValidatorsUtils.validateWithException(request);
        List<DiscontRuleForParkDTO> listDTO = new ArrayList<DiscontRuleForParkDTO>();
        Date parkOutTime = null;
        if (request.getParkOutTime() == null) {
            throw new BizException(ErrorType.PARAMM_NULL, "出场厂时间为空!");
        }
        parkOutTime = format.parse(request.getParkOutTime().substring(request.getParkOutTime().length() - 8));
        /**判断是否为节假日非工作日():true ,false:工作日.*/
        Boolean isHolidays = this.queryDaysInfoOfSolar(request.getParkOutTime());
        /**通过停车场编码,折扣类型,终端来源,车辆类型,出场时间查询停车场所有折扣规则.*/
        List<DiscontRuleForParkDO> list = activityDiscountRuleDao.queryDiscontRuleForList(request);
        logger.info("查询停车场所有折扣规则list:" + JSONObject.toJSON(list));
        if (CollectionUtils.isNotEmpty(list)) {
            for (DiscontRuleForParkDO discontRuleDO : list) {
                //有时间限制
                if (discontRuleDO != null && IS_TIMME_LIMIT.equals(discontRuleDO.getIsTLimit())) {
                    //出场时间(HH:mm:ss) 不在在限制时间范围内
                    if (parkOutTime.getTime() <= discontRuleDO.getEffDate().getTime()
                        || parkOutTime.getTime() >= discontRuleDO.getExpDate().getTime()) {
                        continue;
                    }
                    //判断节假日限制是否符合 特征日标识: -1:不限 1:工作日 2:非工作日
                    if ((discontRuleDO.getSpecialDayType() == HolidayEnum.IS_NOT_HOLIDAY.value() && isHolidays) ||
                        (discontRuleDO.getSpecialDayType() == HolidayEnum.IS_HOLIDAY.value() && !isHolidays)) {
                        continue;
                    }
                }

                DiscontRuleForParkDTO discontRuleDTO = new DiscontRuleForParkDTO();
                BeanUtils.copyProperties(discontRuleDO, discontRuleDTO);
                listDTO.add(discontRuleDTO);
            }
        } else {
            logger.info("没有符合条件的停车场所有折扣规则");
        }
        //判断该车场是否有特殊用户折扣,且该车牌是否为特定车牌,如果是,则获取特定用户折扣规则;否则获取停车场折扣规则
        List<DiscontRuleForParkDTO> discontRuleForParkDTOs = this.getRealDiscountRuleByCarNo(request.getCarNo(),
            listDTO);
        return discontRuleForParkDTOs;
    }

    /**
     * 判断该车场是否有特殊用户折扣,且该车牌是否为特定车牌,如果是,则获取特定用户折扣规则;否则获取停车场折扣规则
     *
     * @param carNo
     * @param discontRuleForParkDTOS
     * @return
     */
    private List<DiscontRuleForParkDTO> getRealDiscountRuleByCarNo(String carNo,
        List<DiscontRuleForParkDTO> discontRuleForParkDTOS) {
        if (CollectionUtils.isEmpty(discontRuleForParkDTOS)) {
            return null;
        }
        /**折扣类型:1.停车支付活动 2:购买会员卡活动 3:特殊用户折扣*/
        Map<Integer, List<DiscontRuleForParkDTO>> map = discontRuleForParkDTOS.stream().collect(
            Collectors.groupingBy(DiscontRuleForParkDTO::getDiscType, Collectors.toList()));
        //判断是否有特定用户折扣
        if (map.containsKey(3)) {
            List<DiscontRuleForParkDTO> specifieDiscountRules = map.get(3);
            DiscontRuleForParkDTO specifieDiscountDto = specifieDiscountRules.get(0);
            //判断该车辆是否为特定车辆
            QueryDiscountSpecialCarRequest queryDiscountSpecialCarRequest = new QueryDiscountSpecialCarRequest();
            queryDiscountSpecialCarRequest.setSysCode(BasicEnum.SYS_CODE.getValue());
            queryDiscountSpecialCarRequest.setPlNo(specifieDiscountDto.getPlNo());
            queryDiscountSpecialCarRequest.setCarNumber(carNo);
            queryDiscountSpecialCarRequest.setDiscNo(specifieDiscountDto.getDiscNo());
            BizResult<TActivityDiscountSpecialCarDTO> bizResult = discountSpecialCarService
                .queryDiscountSpecialCarByCarNumber(queryDiscountSpecialCarRequest);
            if (ResultUtils.getBizResultData(bizResult) != null && ResultUtils.getBizResultData(bizResult).getId()
                != null) {
                //是特定车辆
                return specifieDiscountRules;
            }
        }
        if (map.containsKey(1)) {
            return map.get(1);
        }
        return null;
    }

    /**
     * 查询制定日期是否为节假日.<b>
     *
     * @param parkOutTime
     * @return
     */
    private Boolean queryDaysInfoOfSolar(String parkOutTime) {
        logger.info("begin查询给定日期是否节假日,入参={}", parkOutTime);
        Boolean flg = false;
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        /**查询是否为节假日.*/
        DaysInfoQueryReq req = new DaysInfoQueryReq();
        List<Date> dataList = new ArrayList<>();
        try {
            dataList.add(format.parse(parkOutTime));
            req.setQueryDates(dataList);
            BizResult<List<SpHolidaysDTO>> holidaysRestlt = holidayService.queryDaysInfoOfSolar(req);
            if (holidaysRestlt != null && CollectionUtils.isNotEmpty(holidaysRestlt.getData())) {
                for (SpHolidaysDTO holidaysDTO : holidaysRestlt.getData()) {
                    if (holidaysDTO != null && HolidayEnum.IS_HOLIDAY.value().equals(holidaysDTO.getIsHolidays())) {
                        flg = true;
                        break;
                    }
                }
            }
        } catch (ParseException e) {
            e.printStackTrace();
            throw new BizException(ErrorType.BIZ_ERROR, "查询是否是节假日");
        }
        logger.info("begin查询给定日期是否节假日,结果:{} true=非工作日,false=工作日", flg);
        return flg;

    }

    @Override
    public BizResult<Map<String, List<DiscontRuleForParkDTO>>> queryDiscontRuleForMap(
        QueryDiscountRuleRequest request) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        logger.info("---begin停车场所有折扣规则,入参={}", JSONObject.toJSON(request));
        //校验入参数
        BeanValidatorsUtils.validateWithException(request);
        List<DiscontRuleForParkDTO> listDTO = new ArrayList<DiscontRuleForParkDTO>();
        Date parkOutTime = format.parse(request.getParkOutTime());
        /**判断是否为节假日非工作日():true ,false:工作日.*/
        Boolean isHolidays = this.queryDaysInfoOfSolar(request.getParkOutTime());
        /**通过停车场编码,折扣类型,终端来源,车辆类型,出场时间查询停车场所有折扣规则.*/
        List<DiscontRuleForParkDO> list = activityDiscountRuleDao.queryDiscontRuleForList(request);
        if (CollectionUtils.isNotEmpty(list)) {
            for (DiscontRuleForParkDO discontRuleDO : list) {
                //有时间限制
                if (discontRuleDO != null && IS_TIMME_LIMIT.equals(discontRuleDO.getIsTLimit())) {
                    //出场时间(HH:mm:ss) 不在在限制时间范围内
                    if (parkOutTime.getTime() <= discontRuleDO.getEffDate().getTime()
                        || parkOutTime.getTime() >= discontRuleDO.getExpDate().getTime()) {
                        continue;
                    }
                    //判断节假日限制是否符合 特征日标识: -1:不限 1:工作日 2:非工作日
                    if ((discontRuleDO.getSpecialDayType() == HolidayEnum.IS_NOT_HOLIDAY.value() && isHolidays) ||
                        (discontRuleDO.getSpecialDayType() == HolidayEnum.IS_HOLIDAY.value() && !isHolidays)) {
                        continue;
                    }
                }

                DiscontRuleForParkDTO discontRuleDTO = new DiscontRuleForParkDTO();
                BeanUtils.copyProperties(discontRuleDO, discontRuleDTO);
                listDTO.add(discontRuleDTO);
            }
        } else {
            logger.info("没有符合条件的停车场所有折扣规则");
        }
        logger.info("---begin停车场所有折扣规则");
        Map<String, List<DiscontRuleForParkDTO>> dataMap = Optional.ofNullable(listDTO).orElse(new ArrayList<>())
            .stream()
            .collect(Collectors.groupingBy(DiscontRuleForParkDTO::getPlNo));
        return new BizResult<Map<String, List<DiscontRuleForParkDTO>>>(dataMap);
    }

    /**
     * 通过停车场编码校验折扣唯一性.<br/>
     *
     * @param request
     * @return 2018年1月15日  wangfs.<br/>
     */
    @Override
    public BizResult<Boolean> checkDiscountUniqueByPlNo(CheckDiscountUniqueByPlNoRequest request) {
        logger.info("begin通过停车场编码校验折扣唯一性,入参={}", JSONObject.toJSON(request));
        //校验入参数
        BeanValidatorsUtils.validateWithException(request);
        Boolean flg = activityDiscountDao.checkDiscountUniqueByPlNo(request);
        logger.info("end通过停车场编码校验折扣唯一性,结果={}", flg + "。");
        return new BizResult<Boolean>(flg);
    }
}