From a5b8f547e7c2211f6095a7fcf75df14b1e31ba94 Mon Sep 17 00:00:00 2001 From: lin <642018748@qq.com> Date: Mon, 26 Jun 2023 19:36:48 +0800 Subject: [PATCH] add ketuo car --- .../ketuo/WxCarKeTuoCallBackController.java | 111 +++++++++ mallinkService/pom.xml | 7 +- .../java/com/iformall/enums/EnumCarCmd.java | 7 +- .../com/iformall/enums/EnumCarVendor.java | 15 +- .../iformall/service/park/ParkFactory.java | 8 + .../service/park/impl/BaseParkService.java | 26 +++ .../impl/ketuo/KeTuoParkCallbackService.java | 134 +++++++++++ .../park/impl/ketuo/KeTuoParkService.java | 200 +++++++++++++++++ .../service/park/impl/ketuo/KeTuoUtil.java | 212 ++++++++++++++++++ 9 files changed, 711 insertions(+), 9 deletions(-) create mode 100644 mallinkCallback/src/main/java/com/iformall/controller/callback/car/ketuo/WxCarKeTuoCallBackController.java create mode 100644 mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoParkCallbackService.java create mode 100644 mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoParkService.java create mode 100644 mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoUtil.java diff --git a/mallinkCallback/src/main/java/com/iformall/controller/callback/car/ketuo/WxCarKeTuoCallBackController.java b/mallinkCallback/src/main/java/com/iformall/controller/callback/car/ketuo/WxCarKeTuoCallBackController.java new file mode 100644 index 000000000..b2e769722 --- /dev/null +++ b/mallinkCallback/src/main/java/com/iformall/controller/callback/car/ketuo/WxCarKeTuoCallBackController.java @@ -0,0 +1,111 @@ +package com.iformall.controller.callback.car.ketuo; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageInfo; +import com.iformall.common.Result; +import com.iformall.controller.base.BaseController; +import com.iformall.controller.callback.car.WxParkCallBackBaseController; +import com.iformall.domain.po.*; +import com.iformall.domain.vo.WxCarCYFVo; +import com.iformall.enums.EnumCarCmd; +import com.iformall.enums.EnumCarVendor; +import com.iformall.enums.EnumCouponSendSendType; +import com.iformall.enums.EnumPayWay; +import com.iformall.service.*; +import com.iformall.service.park.impl.cyf.CYFUtil; +import com.iformall.service.park.impl.tjd.TJDUtil; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author: furunxin + * @Date: 2020/7/6 15:29 + * @Description: 车易付回调接口 + */ + +@Slf4j +@RestController +@RequestMapping("/keTuoCarCallback") +public class WxCarKeTuoCallBackController extends WxParkCallBackBaseController { + + @Autowired + WxParkService wxParkService; + + @Autowired + WxCarCmdLogService wxCarCmdLogService; + + @Autowired + WxCUserService wxCUserService; + + @Autowired + WxCUserCarService wxCUserCarService; + + @Autowired + WxCouponSendService wxCouponSendService; + + @Autowired + WxCarPayRecordService wxCarPayRecordService; + + @Autowired + WxCUserBasicInfoService wxCUserBasicInfoService; + + /** + * @description 科拓 车辆入场通知 + * {dataItems=[{"inTime":"2020-12-09 11:21:15","carNumber":"浙-AF81797","inCarPhoto":"p201127315/NISSP_IMG_PARK_IN/20201209/a9f1130651b9493f8eab64f14afbdd47","isReal":0,"itemId":"a9f1130651b9493f8eab64f14afbdd47","inOperator":"超级管理员","equipName":"东门入口","parkName":"杭州东站西子国际","vehicleInfo":"{\"plateNo\":\"浙-AF81797\",\"plateColor\":\"GREEN\",\"plateBackColor\":0,\"plateWordColor\":0,\"vehicleColor\":null,\"vehicleLogo\":null,\"vehicleModel\":null,\"mainModel\":0,\"subModel\":0,\"vehicleModelTrust\":0,\"mainModelTrust\":0,\"subModelTrust\":0,\"plateNoTrust\":1,\"vehicleLogoTrust\":0,\"vehicleColorTrust\":0}","equipCode":"208202496","parkCode":"p201127315"}], pno=dzxzgj, sn=6C958D99D2769AA16F3A3F06E962263F, tn=-2, ts=20201209112118886, ve=1.0} + * + * + * + * @Params [paramMap] + * @return com.iformall.common.Result + * @Author furunxin + * @Date 2020/7/8 上午8:27 + **/ + @PostMapping(value = "/PostCarInInfo") + public Result parkInCallback(@RequestBody Map paramMap) { + log.info("["+getIpAddr()+"] keTuoCarCallback parkIn: " + paramMap.toString()); + //解析车易付参数 + return super.parkInCallBack(EnumCarVendor.CAR_KETUO, EnumCarCmd.CAR_KETUO_CALLBACK_PARK_IN, paramMap); + } + + + /** + * @description 车易付 车辆离场通知 + * @Params [param] + * @return java.util.Map + * @Author furunxin + * @Date 2020/7/12 上午9:00 + **/ + @PostMapping(value = "/PostCarOutInfo") + public Result parkOutCallback(@RequestBody Map paramMap) { + log.info("["+getIpAddr()+"] keTuoCarCallback parkOut: " + paramMap.toString()); + return super.parkOutCallBack(EnumCarVendor.CAR_KETUO, EnumCarCmd.CAR_KETUO_CALLBACK_PARK_OUT, paramMap); + + } + + @PostMapping(value = "/unbind") + public Result unbindCallback(@RequestBody Map paramMap) { + log.info("["+getIpAddr()+"] keTuoCarCallback unbind: " + paramMap.toString()); + //解析车易付参数 + return super.unbindCarCallBack(EnumCarVendor.CAR_KETUO, EnumCarCmd.CAR_KETUO_CALLBACK_UNBIND, paramMap); + } + + @PostMapping(value = "/PostPayFeeInfo") + public Result paidCallback(@RequestBody Map paramMap) { + log.info("["+getIpAddr()+"] keTuoCarCallback paid: " + paramMap.toString()); + //解析车易付参数 + return super.paidCallback(EnumCarVendor.CAR_KETUO, EnumCarCmd.CAR_KETUO_CALLBACK_PAID, paramMap); + } +} diff --git a/mallinkService/pom.xml b/mallinkService/pom.xml index cf4cd961f..c08a17ef9 100644 --- a/mallinkService/pom.xml +++ b/mallinkService/pom.xml @@ -39,7 +39,12 @@ com.alipay.sdk alipay-easysdk 2.2.0 - + + + com.iformall + mallinkAdmin + 1.0 + \ No newline at end of file diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumCarCmd.java b/mallinkService/src/main/java/com/iformall/enums/EnumCarCmd.java index 8a62a911a..bb2b9409c 100644 --- a/mallinkService/src/main/java/com/iformall/enums/EnumCarCmd.java +++ b/mallinkService/src/main/java/com/iformall/enums/EnumCarCmd.java @@ -44,7 +44,12 @@ public enum EnumCarCmd { CAR_LIFANG_CALLBACK_PARK_IN(636,"立方进场通知"), CAR_LIFANG_CALLBACK_PARK_OUT(637,"立方出场通知"), CAR_LIFANG_CALLBACK_UNBIND(638,"立方解绑车牌通知"), - CAR_LIFANG_CALLBACK_PAID(639,"立方支付通知") + CAR_LIFANG_CALLBACK_PAID(639,"立方支付通知"), + + CAR_KETUO_CALLBACK_PARK_IN(640,"科拓进场通知"), + CAR_KETUO_CALLBACK_PARK_OUT(641,"科拓出场通知"), + CAR_KETUO_CALLBACK_UNBIND(642,"科拓解绑车牌通知"), + CAR_KETUO_CALLBACK_PAID(643,"科拓支付通知") ; public static EnumCarCmd getEnum(Integer code) { diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumCarVendor.java b/mallinkService/src/main/java/com/iformall/enums/EnumCarVendor.java index 907f9bb44..d7a738047 100644 --- a/mallinkService/src/main/java/com/iformall/enums/EnumCarVendor.java +++ b/mallinkService/src/main/java/com/iformall/enums/EnumCarVendor.java @@ -8,16 +8,17 @@ public enum EnumCarVendor { // 1-ETCP, 2-TJD停简单 3-Dahua大华, 4-ShangAn尚安, 5-BoLink泊链,6-车易付 CAR_NOTFOUND(0, "无",false), CAR_ETCP(1, "ETCP",false), - CAR_TJD(2, "TJD",false), - CAR_DAHUA(3, "DAHUA",false), - CAR_SHANGAN(4, "ShangAn",false), - CAR_BOLINK(5, "BoLink",false), - CAE_CYF(6,"CYF",false), - CAR_JIESHUN(7,"JIESHUN",true), + CAR_TJD(2, "TJD",false),// 【接口不支持未接通,不能使用】 + CAR_DAHUA(3, "DAHUA",false),// 【接口不支持未接通,不能使用】 + CAR_SHANGAN(4, "ShangAn",false),// 【接口不支持未接通,不能使用】 + CAR_BOLINK(5, "BoLink",false),// 【接口不支持未接通,不能使用】 + CAE_CYF(6,"CYF",false),// 【接口不支持未接通,不能使用】 + CAR_JIESHUN(7,"JIESHUN",true),//捷顺老版本,西子用 CAR_JIESHUN_V2(10,"JIESHUNV2",true),//捷顺通用版本 CAR_HAIKANGWEISHI(8,"HAIKANGWEISHI",true), CAR_FUTE(9,"FUTE",false),//深圳市福特智能科技有限公司 - CAR_LIFANG(10,"LIFANG",false)//立方停车 + CAR_LIFANG(10,"LIFANG",false),//立方停车【接口不支持未接通,不能使用】 + CAR_KETUO(11,"KETUO",false)//科拓停车 ; public static EnumCarVendor getEnum(Integer code) { diff --git a/mallinkService/src/main/java/com/iformall/service/park/ParkFactory.java b/mallinkService/src/main/java/com/iformall/service/park/ParkFactory.java index 978558c06..fd8653e61 100644 --- a/mallinkService/src/main/java/com/iformall/service/park/ParkFactory.java +++ b/mallinkService/src/main/java/com/iformall/service/park/ParkFactory.java @@ -21,6 +21,8 @@ import com.iformall.service.park.impl.jieshun.JieShunParkCallbackService; import com.iformall.service.park.impl.jieshun.JieShunParkService; import com.iformall.service.park.impl.jieshunV2.JieShunV2ParkCallbackService; import com.iformall.service.park.impl.jieshunV2.JieShunV2ParkService; +import com.iformall.service.park.impl.ketuo.KeTuoParkCallbackService; +import com.iformall.service.park.impl.ketuo.KeTuoParkService; import com.iformall.service.park.impl.lifang.LiFangParkCallbackService; import com.iformall.service.park.impl.lifang.LiFangParkService; import com.iformall.service.park.impl.shangan.ShangAnParkService; @@ -49,6 +51,8 @@ public class ParkFactory { FuteParkService futeParkService; @Autowired LiFangParkService lifangParkService; + @Autowired + KeTuoParkService keTuoParkService; @Autowired CYFParkCallbackService cyfCallbackService; @@ -62,6 +66,8 @@ public class ParkFactory { FuteParkCallbackService futeParkCallbackService; @Autowired LiFangParkCallbackService lifangParkCallbackService; + @Autowired + KeTuoParkCallbackService keTuoParkCallbackService; private Map parkServiceMap ; @@ -85,6 +91,7 @@ public class ParkFactory { parkServiceMap.put(EnumCarVendor.CAR_HAIKANGWEISHI.getCode(), haikangWeishiService); parkServiceMap.put(EnumCarVendor.CAR_FUTE.getCode(), futeParkService); parkServiceMap.put(EnumCarVendor.CAR_LIFANG.getCode(), lifangParkService); + parkServiceMap.put(EnumCarVendor.CAR_KETUO.getCode(), keTuoParkService); return parkServiceMap; } @@ -108,6 +115,7 @@ public class ParkFactory { callBackServiceMap.put(EnumCarVendor.CAE_CYF.getCode(), cyfCallbackService); callBackServiceMap.put(EnumCarVendor.CAR_FUTE.getCode(), futeParkCallbackService); callBackServiceMap.put(EnumCarVendor.CAR_LIFANG.getCode(), lifangParkCallbackService); + callBackServiceMap.put(EnumCarVendor.CAR_KETUO.getCode(), keTuoParkCallbackService); return callBackServiceMap; } diff --git a/mallinkService/src/main/java/com/iformall/service/park/impl/BaseParkService.java b/mallinkService/src/main/java/com/iformall/service/park/impl/BaseParkService.java index b374729fb..dab1e9d4f 100644 --- a/mallinkService/src/main/java/com/iformall/service/park/impl/BaseParkService.java +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/BaseParkService.java @@ -6,9 +6,12 @@ import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import com.iformall.common.ErrorCode; import com.iformall.common.ResultData; import com.iformall.domain.po.WxCUserBasicInfo; +import com.iformall.domain.po.WxCoupon; import com.iformall.domain.po.WxPark; +import com.iformall.exception.MallinkException; import com.iformall.service.park.impl.util.ParkHelper; @Service @@ -17,4 +20,27 @@ public class BaseParkService { @Autowired ParkHelper parkHelper; + protected boolean isReduceMoney(WxCoupon coupon) throws Exception{ + //抵扣时长 + if (coupon.getUnit().intValue() == 1 ) { + return false; + }else if (coupon.getUnit().intValue() == 0 ) { + return true; + }else { + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"coupon has no config [unit]"); + } + } + + protected Integer getReduceValue(WxCoupon coupon) throws Exception{ + //时长,小时 + if (coupon.getUnit().intValue() == 1 ) { + return coupon.getPrice()/100; + }else if (coupon.getUnit().intValue() == 0 ) { + //分 + return coupon.getPrice(); + }else { + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"coupon has no config [unit]"); + } + } + } diff --git a/mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoParkCallbackService.java b/mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoParkCallbackService.java new file mode 100644 index 000000000..92b689c41 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoParkCallbackService.java @@ -0,0 +1,134 @@ +package com.iformall.service.park.impl.ketuo; + +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.iformall.common.ErrorCode; +import com.iformall.common.IdWorker; +import com.iformall.domain.po.WxCarJSOrder; +import com.iformall.domain.po.WxPark; +import com.iformall.domain.vo.WxCarCYFVo; +import com.iformall.enums.EnumCarVendor; +import com.iformall.exception.MallinkException; +import com.iformall.mapper.WxCarJSOrderMapper; +import com.iformall.service.WxParkService; +import com.iformall.service.park.ParkBatchCallBackAdapterService; +import com.iformall.service.park.ParkCallBackAdapterService; +import com.iformall.service.park.entity.ParkNotifyParam; +import com.iformall.service.park.impl.BaseParkService; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class KeTuoParkCallbackService extends BaseParkService implements ParkCallBackAdapterService { + + + @Autowired + KeTuoParkService keTuoParkService; + + @Autowired + WxParkService wxParkService; + + @Autowired + WxCarJSOrderMapper wxCarJSOrderMapper; + + KeTuoUtil ketuo = new KeTuoUtil(); + + /** + * {dataItems=[{"inTime":"2020-12-09 11:21:15","carNumber":"浙-AF81797","inCarPhoto":"p201127315/NISSP_IMG_PARK_IN/20201209/a9f1130651b9493f8eab64f14afbdd47","isReal":0,"itemId":"a9f1130651b9493f8eab64f14afbdd47","inOperator":"超级管理员","equipName":"东门入口","parkName":"杭州东站西子国际","vehicleInfo":"{\"plateNo\":\"浙-AF81797\",\"plateColor\":\"GREEN\",\"plateBackColor\":0,\"plateWordColor\":0,\"vehicleColor\":null,\"vehicleLogo\":null,\"vehicleModel\":null,\"mainModel\":0,\"subModel\":0,\"vehicleModelTrust\":0,\"mainModelTrust\":0,\"subModelTrust\":0,\"plateNoTrust\":1,\"vehicleLogoTrust\":0,\"vehicleColorTrust\":0}","equipCode":"208202496","parkCode":"p201127315"}], pno=dzxzgj, sn=6C958D99D2769AA16F3A3F06E962263F, tn=-2, ts=20201209112118886, ve=1.0} + */ + @Override + public ParkNotifyParam parseInNoticyParam(Object param) { + Map paramm = (Map) param; + String carNumber = paramm.get("plateNo").toString(); + String parkCode = paramm.get("parkId").toString(); + + String synId = paramm.get("trafficId").toString(); + String entranceTime = paramm.get("entryTime").toString(); + + ParkNotifyParam p = new ParkNotifyParam(); + p.setCarNumber(carNumber); + p.setParkId(parkCode); + p.setParkName("ketuo"); + p.setSynId(synId); + try { + p.setEntranceTime(ketuo.utcToLocal(entranceTime)); + } catch (ParseException e) { + log.error("jieshun entranceTime format error",e); + return null; + } + return p; + } + + @Override + public ParkNotifyParam parseOutNoticyParam(Object param) { + Map paramm = (Map) param; + String carNumber = paramm.get("plateNo").toString(); + String parkCode = paramm.get("parkId").toString(); + + String synId = paramm.get("trafficId").toString(); + String entranceTime = paramm.get("entryTime").toString(); + String outTime = paramm.get("leaveTime").toString(); + + ParkNotifyParam p = new ParkNotifyParam(); + p.setCarNumber(carNumber); + p.setParkId(parkCode); + p.setParkName("ketuo"); + p.setSynId(synId); + try { + p.setEntranceTime(ketuo.utcToLocal(entranceTime)); + } catch (ParseException e) { + log.error("cyf entranceTime format error",e); + return null; + } + try { + p.setOutTime(ketuo.utcToLocal(outTime)); + } catch (ParseException e) { + log.error("cyf outTime format error",e); + return null; + } + Object payMentInfo = paramm.get("payMentInfo"); + String fee = "0"; + if (null != payMentInfo) { + JSONObject pay = JSON.parseObject(JSON.toJSONString(payMentInfo)); + if (null != pay) { + fee = String.valueOf(pay.getInteger("paidMoney")); + } + } + p.setFee(fee); + return p; + } + + @Override + public ParkNotifyParam parseUnbindNoticyParam(Object param) { + return null; + } + + @Override + public ParkNotifyParam parsePaidNoticyParam(Object param) { + Map paramm = (Map) param; + ParkNotifyParam p = new ParkNotifyParam(); + p.setCarNumber((String) paramm.get("plateNo")); + p.setParkId(String.valueOf(paramm.get("parkId"))); + p.setParkOrderId((String) paramm.get("billId")); + p.setSynId((String) paramm.get("reqId")); + p.setFee(paramm.get("paidMoney").toString()); + try { + p.setPayTime(ketuo.utcToLocal((String)paramm.get("payTime"))); + } catch (ParseException e) { + e.printStackTrace(); + } + return p; + } +} diff --git a/mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoParkService.java b/mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoParkService.java new file mode 100644 index 000000000..82f0a968b --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoParkService.java @@ -0,0 +1,200 @@ +package com.iformall.service.park.impl.ketuo; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.iformall.common.ErrorCode; +import com.iformall.common.IdWorker; +import com.iformall.common.ResultData; +import com.iformall.domain.po.WxCUserBasicInfo; +import com.iformall.domain.po.WxCarJSOrder; +import com.iformall.domain.po.WxCoupon; +import com.iformall.domain.po.WxPark; +import com.iformall.domain.vo.WxCouponOrderCarCVo; +import com.iformall.domain.vo.WxParkCouponConfig; +import com.iformall.enums.EnumCarVendor; +import com.iformall.enums.EnumCouponUnit; +import com.iformall.exception.MallinkException; +import com.iformall.mapper.WxCarJSOrderMapper; +import com.iformall.service.WxParkService; +import com.iformall.service.park.ParkAdapterService; +import com.iformall.service.park.entity.ParkCreatePayOrder; +import com.iformall.service.park.entity.ParkNotifyPaid; +import com.iformall.service.park.entity.ParkPaidNotifyResult; +import com.iformall.service.park.entity.ParkStopFee; +import com.iformall.service.park.impl.BaseParkService; +import com.iformall.service.park.impl.util.ParkHelper; +import com.iformall.service.park.utils.ParkCacheUtils; +import com.iformall.utils.RedisCacheUtils; +import com.iformall.utils.RedisLock; + +/** + * + */ +@Service +public class KeTuoParkService extends BaseParkService implements ParkAdapterService { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + ParkHelper parkHelper; + + @Autowired + @Qualifier("objectCommonRedisTemplate") + RedisTemplate redisTemplate; + + @Autowired + RedisLock redisLock; + + @Autowired + WxCarJSOrderMapper wxCarJSOrderMapper; + + + KeTuoUtil ketuo = new KeTuoUtil(); + + /** + * 先去捷顺注册,调用登陆获取令牌,然后根据令牌调用别的接口 + * http://ap.jieshun.cn:9088/apply/ 注册信息地址 fumao/iformall2020 + * + * 捷顺商户平台:http://merchant.jslife.com.cn/merchant/index.html#/auth/login + * 捷顺门店平台:http://merchant.jslife.com.cn/store/index.html#/auth/login + * 门店商户号 000000008032172000003 密码 ycHqp61Acudxz + * + * + * API对接注意事项: + 1、token有效期两个小时,每两小时内登录一次获取token,调业务接口不需要频繁登录用,建议获取一次token存本地缓存,之后从本地获取,两小时内刷新一次, + 为避免调业务接口时刚好token被刷新,导致token失效(无效的令牌或令牌已过期),可以做下容错,重新登录获取token或用最新token重新调业务接口。 + 2、token是和ip是一对一绑定,新的ip服务器调捷顺的接口会出现ip不合法,需把ip提供捷顺方,添加白名单。多个服务调捷顺接口共用一个ip情况下,只能共用一套登录获取token机制,各自登录会冲突。 + 3、所有接口要带车牌的一律带横杠。格式如:粤-B12345。 + 4、无效的数据签名是指sn加密方式不对。sn加密方式是对p+signkey进行Md5加密,加密后的字符串大写。 + */ + + @Override + public ResultData parkInitConfig(WxPark park) throws Exception { + return null; + } + + @Override + public String initLogin(Map paramMap, WxPark park, WxCUserBasicInfo member) throws Exception{ + return null; + } + + + @Override + public String bindCar(Map paramMap, WxPark park, WxCUserBasicInfo member) throws Exception{ + return "ketuo"; + } + + + @Override + public void unbindCar(Map paramMap, WxPark park, WxCUserBasicInfo member) throws Exception{ + } + + + /** + * 每一次查询都会产生订单,然后根据订单号查询 + */ + @Override + public ParkStopFee carStopFee(Map paramMap, WxPark park,String carNumber) throws Exception{ + return ketuoCarStopFee(paramMap, park,carNumber); + } + + private ParkStopFee ketuoCarStopFee(Map paramMap, WxPark park,String carNumber) throws Exception{ + String ret = ketuo.getCarStopFee(park, carNumber); + if (StringUtils.isBlank(ret)) { + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(), "ketuo getCarStopFee error. has no result"); + } + JSONObject retObj = JSON.parseObject(ret); + if (retObj.getIntValue("resCode") == 0){ + JSONObject retObject = retObj.getJSONObject("data"); + if (null == retObject ) { + throw new MallinkException(retObj.getInteger("resCode"), "ketuo getCarStopFee error. no order result"+carNumber); + } + Double totalFee = retObject.getDouble("payable"); + String appId = "wx54e676273869baa6"; + String parkOrderId = retObject.getString("orderNo"); + Integer freeMinute = (Integer)park.getVendorParamsByKey("freeMinute"); + String createTime = retObject.getString("entryTime");//计费时间,格式为“yyyy-MM-dd HH:mi:ss” + String endTime = retObject.getString("payTime");//离场时间,格式为“yyyy-MM-dd HH:mi:ss” + String payPath = "pages/index/index?lotId="+Integer.parseInt(park.getParkingId())+"&lpn="+carNumber; + return new ParkStopFee(parkOrderId,ketuo.utcToLocal(createTime),ketuo.utcToLocal(endTime), + String.valueOf(totalFee),appId,payPath,null,null,"请支付后"+freeMinute+"分钟内离场"); + }else { + logger.error("ketuoCarStopFee error. paramMap: {} . ketuoResult: {}",JSON.toJSONString(paramMap),ret); + String msg = retObj.getString("resMsg"); + throw new MallinkException(ErrorCode.CYF_STOP_FEE_FAIL.getCode(), "停车费获取失败:"+msg); + } + } + + /** + * 使用3.8打折方案,3.9有限制如果领券了之后未使用,不能再次领券。导致出现异常之后,用户永远无法使用优惠券。 + * @return + */ + @Override + public ResultData useCoupon(Map paramMap, WxPark park, WxCouponOrderCarCVo userCar,WxCoupon coupon,String carNumber) throws Exception{ + if (null == userCar) { + return new ResultData(ErrorCode.CYF_STOP_FEE_FAIL.getCode(),"当前用户未查询到优惠券!"); + } + + if (StringUtils.isBlank(userCar.getCUserPhone())) { + return new ResultData(ErrorCode.CYF_STOP_FEE_FAIL.getCode(),"当前用户未查询到手机号!"+userCar.getcUserId()); + } + + Map valueMap = WxParkCouponConfig.parseValue(userCar.getVendorParams()); + if (null == valueMap) { + return new ResultData(ErrorCode.COUPON_IS_EMPTY.getCode(),"当前停车券没有关联停车场优惠券配置。"+coupon.getTitle()); + } + //String orderNo = paramMap.get("parkOrderId"); + String planNo = valueMap.get("couponNo"); + if (StringUtils.isBlank(planNo)) { + return new ResultData(ErrorCode.COUPON_IS_EMPTY.getCode(),"当前停车券没有关联停车场优惠券配置[couponNo]。"+coupon.getTitle()); + } + //查询停车费 + ParkStopFee fee = ketuoCarStopFee(paramMap, park, carNumber); + //保存抵扣 + + boolean isReduceMoney = this.isReduceMoney(coupon); + Integer reduceValue = this.getReduceValue(coupon); + String executeRet = ketuo.executediscount(park, fee.getOrderId(), planNo, Integer.parseInt(fee.getRemainingFee()),isReduceMoney, reduceValue); + logger.info("ketuo executediscount result:"+executeRet); + JSONObject executeRetObj = JSON.parseObject(executeRet); + if (executeRetObj.getIntValue("resCode") == 0){ + return new ResultData(); + }else { + return new ResultData(executeRetObj.getIntValue("resCode"),"保存科拓支付信息失败。"+executeRetObj.getString("resMsg")); + } + } + + @Override + public ParkCreatePayOrder createPayOrder(Map paramMap, WxPark park, String carNumber) throws Exception { + return null; + } + + @Override + public ParkPaidNotifyResult notifyPaid(WxPark park,ParkNotifyPaid notifyPaid) throws Exception { + return null; + } + + @Override + public ResultData getParkStatus(WxPark park) throws Exception{ + return new ResultData(); + } + + @Override + public boolean ignoreUseCouponCache() { + return false; + } + +} diff --git a/mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoUtil.java b/mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoUtil.java new file mode 100644 index 000000000..0247b49b4 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/ketuo/KeTuoUtil.java @@ -0,0 +1,212 @@ +package com.iformall.service.park.impl.ketuo; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.google.common.base.Joiner; +import com.iformall.domain.po.WxPark; +import com.iformall.utils.Utility; +import lombok.extern.slf4j.Slf4j; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.protocol.HTTP; +import org.apache.http.util.EntityUtils; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + +/** + * @author: furunxin + * @Date: 2020/7/1 17:16 + * @Description: 车易付接口对接参数类 + */ + +@Slf4j +public class KeTuoUtil { + + public static final String QUERY_FEE = "/api/wec/GetParkingPaymentInfo"; + public static final String PAY_FEE = "/api/wec/PayParkingFee"; + + public static Date utcToLocal(String seconds) throws ParseException { + String format = "yyyy-MM-dd HH:mm:ss"; + SimpleDateFormat sdf = new SimpleDateFormat(format); + Date date=sdf.parse(seconds); + return date; + } + + /** + * 查询停车费 + **/ + public String getCarStopFee(WxPark wxPark,String carNumber){ + String vendroParams = wxPark.getVendorParams(); + JSONObject vp = JSON.parseObject(vendroParams); + JSONObject param = new JSONObject(); + param.put("plateNo", carNumber);//车牌号 + log.info("ketuo getCarStopFee :" + JSON.toJSONString(param)); + return Proc(QUERY_FEE,"getParkingPaymentInfo", vp.getString("appId"), vp.getString("appSercet"), Integer.parseInt(wxPark.getParkingId()),vp.getString("version"),param); + } + + /** + * 抵扣 + */ + public String executediscount(WxPark wxPark,String orderNo,String couponNo,int fee, boolean isDiscountMoney,int discountValue) { + String vendroParams = wxPark.getVendorParams(); + JSONObject vp = JSON.parseObject(vendroParams); + JSONObject param = new JSONObject(); + param.put("orderNo", orderNo);//车场订单号 + param.put("payableAmount", fee);//应付金额 + param.put("amount", 0);//支付金额(不包含减免部分),单位为分 + param.put("payType", 4);//收费终端 + param.put("payMethod", 1010);//付款方式 + if (isDiscountMoney) { + param.put("freeMoney", discountValue);//减免总金额(单位 分) + }else { + param.put("freeTime", discountValue*3600);//减免总时长(单位 秒) + } + param.put("isCarLeave", 0);//车辆是否离场 + Map freeDeail = new HashMap(); + if (isDiscountMoney) { + freeDeail.put("money", discountValue); + freeDeail.put("time", 0); + }else { + freeDeail.put("money", 0); + freeDeail.put("time", discountValue*3600); + } + freeDeail.put("code", couponNo);//车场券编码 + freeDeail.put("type", 1); + freeDeail.put("freeName", "fmMiniApp"); + + List freeDetails = new ArrayList(); + freeDetails.add(freeDeail); + param.put("freeDetail", JSON.toJSONString(freeDetails));//json数组字符串 + log.info("ketuo executediscount :" + JSON.toJSONString(param)); + return Proc(PAY_FEE,"payParkingFee", vp.getString("appId"), vp.getString("appSercet"), Integer.parseInt(wxPark.getParkingId()),vp.getString("version"),param); + } + + private static String Proc(String url, String serviceCode,String appId,String appSercet,Integer parkId,String version, JSONObject params) { + CloseableHttpClient httpClient = HttpClients.createDefault(); + HttpPost httpPost = new HttpPost(url); + httpPost.addHeader(HTTP.CONTENT_TYPE,"application/json"); + httpPost.addHeader("Accept", "application/json"); + httpPost.addHeader("Accept-Encoding", "UTF-8"); + httpPost.addHeader("version",version);//1.0.0 + + if (null != params) { + try { + params.put("appId", appId); + params.put("parkId", parkId); + params.put("serviceCode", serviceCode); + params.put("ts", String.valueOf(Calendar.getInstance().getTimeInMillis())); + params.put("key", paramsSign(params, appSercet)); + params.put("reqId", Utility.generate32UUID()+String.valueOf(Calendar.getInstance().getTimeInMillis())); + httpPost.setEntity(new StringEntity(JSONObject.toJSONString(params),ContentType.create("application/json","utf-8"))); + } catch (Exception e) { + log.error(e.getLocalizedMessage(),e); + return null; + } + } + + if (null != params) { + log.info("ketuo httpRequest:[url]"+url+"[params]"+JSON.toJSONString(params)); + }else { + log.info("ketuo httpRequest:[url]"+url); + } + HttpResponse response = null; + try { + response = httpClient.execute(httpPost); + } catch (Exception e) { + log.error(e.getLocalizedMessage(),e); + } + + String result = null; + + //打印StatusLine + log.debug("StatusLine: " + response.getStatusLine()); + try{ + //获取实体 + HttpEntity httpEntity= response.getEntity(); + result = EntityUtils.toString(httpEntity, "UTF-8"); + log.debug(result); + } catch (Exception e) { + log.error(e.getLocalizedMessage(),e); + } + + try { //关闭流并释放资源 + httpClient.close(); + } catch (IOException e) { + log.error(e.getLocalizedMessage()); + } + return result; + } + + private static String paramsSign(JSONObject requestBody, String appSecret) { + TreeMap params = new TreeMap<>(); + //过滤掉key,appId字段,空属性及Map或List等复杂对象 + requestBody.entrySet().stream().filter( + p -> !"key".equals(p.getKey()) + && !"appId".equals(p.getKey()) + && p.getValue() != null + && !(p.getValue() instanceof Map) + && !(p.getValue() instanceof Iterable)) + .forEach(p -> { + if (!p.getValue().equals("")) { + params.put(p.getKey(), p.getValue().toString()); + } + }); + //拼接appSecret + String temp = Joiner.on("&").withKeyValueSeparator("=").join(params).concat("&").concat(appSecret); + return md5(temp).toUpperCase(); + } + + /** + * 对文本执行 md5 摘要加密, 此算法与 mysql,JavaScript生成的md5摘要进行过一致性对比. + * + * @param plainText + * @return 返回值中的字母为小写 + */ + private static String md5(String plainText) { + if (null == plainText) { + plainText = ""; + } + String mD5Str = null; + try { + // JDK 支持以下6种消息摘要算法,不区分大小写 + // md5,sha(sha-1),md2,sha-256,sha-384,sha-512 + MessageDigest md = MessageDigest.getInstance("MD5"); + md.update(plainText.getBytes(StandardCharsets.UTF_8)); + byte[] b = md.digest(); + int i; + StringBuilder builder = new StringBuilder(32); + for (byte value : b) { + i = value; + if (i < 0) { + i += 256; + } + if (i < 16) { + builder.append("0"); + } + builder.append(Integer.toHexString(i)); + } + mD5Str = builder.toString(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return mD5Str; + } + + +}