diff --git a/mallinkCallback/src/main/java/com/iformall/controller/callback/car/lifang/WxCarLiFangCallBackController.java b/mallinkCallback/src/main/java/com/iformall/controller/callback/car/lifang/WxCarLiFangCallBackController.java new file mode 100644 index 000000000..89c2ab5bd --- /dev/null +++ b/mallinkCallback/src/main/java/com/iformall/controller/callback/car/lifang/WxCarLiFangCallBackController.java @@ -0,0 +1,134 @@ +package com.iformall.controller.callback.car.lifang; + +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("/liFangCarCallback") +public class WxCarLiFangCallBackController extends WxParkCallBackBaseController { + + @Autowired + WxParkService wxParkService; + + @Autowired + WxCarCmdLogService wxCarCmdLogService; + + @Autowired + WxCUserService wxCUserService; + + @Autowired + WxCUserCarService wxCUserCarService; + + @Autowired + WxCouponSendService wxCouponSendService; + + @Autowired + WxCarPayRecordService wxCarPayRecordService; + + @Autowired + WxCUserBasicInfoService wxCUserBasicInfoService; + + /** + * @description 捷顺 车辆入场通知 + * { + "carCode": "浙A5C393", + "inTime": "2016-10-18 16:44:44", + "passTime": "2016-10-28 16:44:44", + "parkID": "12222", + "inOrOut": "1", 0:进场,1:出场 + "GUID": "134589c1d68d44d38dcb7f084b9cf8a1", + "channelID": "1", + "channelName": "北大门出口", + "imagePath": "http://xxx.xxx.xx.xx:xx\\xxx\\xxx.jpg" +} + * @Params [paramMap] + * @return com.iformall.common.Result + * @Author furunxin + * @Date 2020/7/8 上午8:27 + **/ + @PostMapping(value = "/parkIn") + public Result parkInCallback(@RequestBody Map paramMap) { + log.info("["+getIpAddr()+"] liFangCarCallback parkIn: " + paramMap.toString()); + String inOrOut = (String) paramMap.get("inOrOut"); + if ("0".endsWith(inOrOut)) { + Result r = super.parkInCallBack(EnumCarVendor.CAR_LIFANG, EnumCarCmd.CAR_LIFANG_CALLBACK_PARK_IN, paramMap); + if (r.code == Result.SUCCESS) { + return new Result(0,"成功"); + }else { + return r; + } + } + return new Result(0,"成功"); + } + + + /** + * @description 车易付 车辆离场通知 + * @Params [param] + * @return java.util.Map + * @Author furunxin + * @Date 2020/7/12 上午9:00 + **/ + @PostMapping(value = "/parkOut") + public Result parkOutCallback(@RequestBody Map paramMap) { + log.info("["+getIpAddr()+"] lifangCarCallback parkOut: " + paramMap.toString()); + String inOrOut = (String) paramMap.get("inOrOut"); + if ("1".endsWith(inOrOut)) { + Result r = super.parkOutCallBack(EnumCarVendor.CAR_LIFANG, EnumCarCmd.CAR_LIFANG_CALLBACK_PARK_OUT, paramMap); + if (r.code == Result.SUCCESS) { + return new Result(0,"成功"); + }else { + return r; + } + } + return new Result(0,"成功"); + } + + @PostMapping(value = "/unbind") + public Result unbindCallback(@RequestBody Map paramMap) { + log.info("["+getIpAddr()+"] futeCarCallback unbind: " + paramMap.toString()); + //解析车易付参数 + return super.unbindCarCallBack(EnumCarVendor.CAR_FUTE, EnumCarCmd.CAR_FUTE_CALLBACK_UNBIND, paramMap); + } + + @PostMapping(value = "/paid") + public Result paidCallback(@RequestBody Map paramMap) { + log.info("["+getIpAddr()+"] futeCarCallback paid: " + paramMap.toString()); + //解析车易付参数 + return super.paidCallback(EnumCarVendor.CAR_FUTE, EnumCarCmd.CAR_FUTE_CALLBACK_PAID, paramMap); + } +} diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumCarCmd.java b/mallinkService/src/main/java/com/iformall/enums/EnumCarCmd.java index 66ae8bd10..8a62a911a 100644 --- a/mallinkService/src/main/java/com/iformall/enums/EnumCarCmd.java +++ b/mallinkService/src/main/java/com/iformall/enums/EnumCarCmd.java @@ -36,10 +36,15 @@ public enum EnumCarCmd { CAR_HAIKANGWEISHI_CALLBACK_UNBIND(630,"海康解绑车牌通知"), CAR_HAIKANGWEISHI_CALLBACK_PAID(631,"海康支付通知"), - CAR_FUTE_CALLBACK_PARK_IN(628,"福特进场通知"), - CAR_FUTE_CALLBACK_PARK_OUT(629,"福特出场通知"), - CAR_FUTE_CALLBACK_UNBIND(630,"福特解绑车牌通知"), - CAR_FUTE_CALLBACK_PAID(631,"福特支付通知") + CAR_FUTE_CALLBACK_PARK_IN(632,"福特进场通知"), + CAR_FUTE_CALLBACK_PARK_OUT(633,"福特出场通知"), + CAR_FUTE_CALLBACK_UNBIND(634,"福特解绑车牌通知"), + CAR_FUTE_CALLBACK_PAID(635,"福特支付通知"), + + CAR_LIFANG_CALLBACK_PARK_IN(636,"立方进场通知"), + CAR_LIFANG_CALLBACK_PARK_OUT(637,"立方出场通知"), + CAR_LIFANG_CALLBACK_UNBIND(638,"立方解绑车牌通知"), + CAR_LIFANG_CALLBACK_PAID(639,"立方支付通知") ; 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 e5ec26834..907f9bb44 100644 --- a/mallinkService/src/main/java/com/iformall/enums/EnumCarVendor.java +++ b/mallinkService/src/main/java/com/iformall/enums/EnumCarVendor.java @@ -14,9 +14,10 @@ public enum EnumCarVendor { CAR_BOLINK(5, "BoLink",false), CAE_CYF(6,"CYF",false), CAR_JIESHUN(7,"JIESHUN",true), - CAR_JIESHUN_V2(10,"JIESHUNV2",true), + CAR_JIESHUN_V2(10,"JIESHUNV2",true),//捷顺通用版本 CAR_HAIKANGWEISHI(8,"HAIKANGWEISHI",true), - CAR_FUTE(9,"FUTE",false)//深圳市福特智能科技有限公司 + CAR_FUTE(9,"FUTE",false),//深圳市福特智能科技有限公司 + CAR_LIFANG(10,"LIFANG",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 fecd5b148..978558c06 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.lifang.LiFangParkCallbackService; +import com.iformall.service.park.impl.lifang.LiFangParkService; import com.iformall.service.park.impl.shangan.ShangAnParkService; import com.iformall.service.park.impl.tjd.TJDParkService; @@ -45,6 +47,8 @@ public class ParkFactory { HaiKangWeiShiParkService haikangWeishiService; @Autowired FuteParkService futeParkService; + @Autowired + LiFangParkService lifangParkService; @Autowired CYFParkCallbackService cyfCallbackService; @@ -56,6 +60,9 @@ public class ParkFactory { HaiKangWeiShiParkCallbackService haikangWeishiCallBackService; @Autowired FuteParkCallbackService futeParkCallbackService; + @Autowired + LiFangParkCallbackService lifangParkCallbackService; + private Map parkServiceMap ; private Map enumMap ; @@ -77,6 +84,7 @@ public class ParkFactory { parkServiceMap.put(EnumCarVendor.CAR_JIESHUN_V2.getCode(), jieshunV2Service); parkServiceMap.put(EnumCarVendor.CAR_HAIKANGWEISHI.getCode(), haikangWeishiService); parkServiceMap.put(EnumCarVendor.CAR_FUTE.getCode(), futeParkService); + parkServiceMap.put(EnumCarVendor.CAR_LIFANG.getCode(), lifangParkService); return parkServiceMap; } @@ -99,6 +107,7 @@ public class ParkFactory { callBackServiceMap = new ConcurrentHashMap(); callBackServiceMap.put(EnumCarVendor.CAE_CYF.getCode(), cyfCallbackService); callBackServiceMap.put(EnumCarVendor.CAR_FUTE.getCode(), futeParkCallbackService); + callBackServiceMap.put(EnumCarVendor.CAR_LIFANG.getCode(), lifangParkCallbackService); return callBackServiceMap; } diff --git a/mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunV2ParkService.java b/mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunV2ParkService.java index 0b64aa371..864281b17 100644 --- a/mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunV2ParkService.java +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunV2ParkService.java @@ -203,7 +203,7 @@ public class JieShunV2ParkService extends BaseParkService implements ParkAdapter "0.00",appId,"payPath",null,msg,null); }else { //0元订单结清,查询是否用过打折方案,如果用过,则需要调用接口结清订单 - Integer used = ParkCacheUtils.getCarCouponUseCacheLock(redisTemplate, EnumCarVendor.CAR_JIESHUN.getMessage(), carNumber); + Integer used = ParkCacheUtils.getCarCouponUseCacheLock(redisTemplate, EnumCarVendor.CAR_JIESHUN_V2.getMessage(), carNumber); if (null == used || (null != used && used.intValue() < 1)) { //未使用停车券 return new ParkStopFee("-999",jieshun.utcToLocal(_createTime),jieshun.utcToLocal(_endTime), diff --git a/mallinkService/src/main/java/com/iformall/service/park/impl/lifang/LiFangAESUtils.java b/mallinkService/src/main/java/com/iformall/service/park/impl/lifang/LiFangAESUtils.java new file mode 100644 index 000000000..752cbc532 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/lifang/LiFangAESUtils.java @@ -0,0 +1,295 @@ +package com.iformall.service.park.impl.lifang; + +import java.security.Key; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import com.iformall.utils.Base64Util; +import org.apache.commons.codec.binary.Base64; + + +public class LiFangAESUtils { + /** + * 密钥算法 + */ + private static final String KEY_ALGORITHM = "AES"; + + private static final String DEFAULT_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding"; + + /** + * 初始化密钥 + * + * @return byte[] 密钥 + * @throws Exception + */ + public static byte[] initSecretKey() { + // 返回生成指定算法的秘密密钥的 KeyGenerator 对象 + KeyGenerator kg = null; + try { + kg = KeyGenerator.getInstance(KEY_ALGORITHM); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + return new byte[0]; + } + // 初始化此密钥生成器,使其具有确定的密钥大小 + // AES 要求密钥长度为 128 + kg.init(128); + // 生成一个密钥 + SecretKey secretKey = kg.generateKey(); + return secretKey.getEncoded(); + } + + /** + * 转换密钥 + * + * @param key + * 二进制密钥 + * @return 密钥 + */ + public static Key toKey(byte[] key) { + // 生成密钥 + return new SecretKeySpec(key, KEY_ALGORITHM); + } + + /** + * 加密 + * + * @param data + * 待加密数据 + * @param key + * 密钥 + * @return byte[] 加密数据 + * @throws Exception + */ + public static byte[] encrypt(byte[] data, Key key) throws Exception { + return encrypt(data, key, DEFAULT_CIPHER_ALGORITHM); + } + + /** + * 加密 + * + * @param data + * 待加密数据 + * @param key + * 二进制密钥 + * @return byte[] 加密数据 + * @throws Exception + */ + public static byte[] encrypt(byte[] data, byte[] key) throws Exception { + return encrypt(data, key, DEFAULT_CIPHER_ALGORITHM); + } + + /** + * 加密 + * + * @param data + * 待加密数据 + * @param key + * 二进制密钥 + * @param cipherAlgorithm + * 加密算法/工作模式/填充方式 + * @return byte[] 加密数据 + * @throws Exception + */ + public static byte[] encrypt(byte[] data, byte[] key, String cipherAlgorithm) throws Exception { + // 还原密钥 + Key k = toKey(key); + return encrypt(data, k, cipherAlgorithm); + } + + /** + * 加密 + * + * @param data + * 待加密数据 + * @param key + * 密钥 + * @param cipherAlgorithm + * 加密算法/工作模式/填充方式 + * @return byte[] 加密数据 + * @throws Exception + */ + public static byte[] encrypt(byte[] data, Key key, String cipherAlgorithm) throws Exception { + // 实例化 + Cipher cipher = Cipher.getInstance(cipherAlgorithm); + // 使用密钥初始化,设置为加密模式 + cipher.init(Cipher.ENCRYPT_MODE, key); + // 执行操作 + return cipher.doFinal(data); + } + + /** + * 解密 + * + * @param data + * 待解密数据 + * @param key + * 二进制密钥 + * @return byte[] 解密数据 + * @throws Exception + */ + public static byte[] decrypt(byte[] data, byte[] key) throws Exception { + return decrypt(data, key, DEFAULT_CIPHER_ALGORITHM); + } + + /** + * 解密 + * + * @param data + * 待解密数据 + * @param key + * 密钥 + * @return byte[] 解密数据 + * @throws Exception + */ + public static byte[] decrypt(byte[] data, Key key) throws Exception { + return decrypt(data, key, DEFAULT_CIPHER_ALGORITHM); + } + + /** + * 解密 + * + * @param data + * 待解密数据 + * @param key + * 二进制密钥 + * @param cipherAlgorithm + * 加密算法/工作模式/填充方式 + * @return byte[] 解密数据 + * @throws Exception + */ + public static byte[] decrypt(byte[] data, byte[] key, String cipherAlgorithm) throws Exception { + // 还原密钥 + Key k = toKey(key); + return decrypt(data, k, cipherAlgorithm); + } + + /** + * 解密 + * + * @param data + * 待解密数据 + * @param key + * 密钥 + * @param cipherAlgorithm + * 加密算法/工作模式/填充方式 + * @return byte[] 解密数据 + * @throws Exception + */ + public static byte[] decrypt(byte[] data, Key key, String cipherAlgorithm) throws Exception { + // 实例化 + Cipher cipher = Cipher.getInstance(cipherAlgorithm); + // 使用密钥初始化,设置为解密模式 + cipher.init(Cipher.DECRYPT_MODE, key); + // 执行操作 + return cipher.doFinal(data); + } + + public static String showByteArray(byte[] data) { + if (null == data) { + return null; + } + StringBuilder sb = new StringBuilder("{"); + for (byte b : data) { + sb.append(b).append(","); + } + sb.deleteCharAt(sb.length() - 1); + sb.append("}"); + return sb.toString(); + } + + /** + * 将16进制转换为二进制 + * + * @param hexStr + * @return + */ + public static byte[] parseHexStr2Byte(String hexStr) { + + if (hexStr.length() < 1) + return null; + byte[] result = new byte[hexStr.length() / 2]; + for (int i = 0; i < hexStr.length() / 2; i++) { + int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16); + int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16); + result[i] = (byte) (high * 16 + low); + } + return result; + } + + /** + * 将二进制转换成16进制 + * + * @param buf + * @return + */ + public static String parseByte2HexStr(byte buf[]) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < buf.length; i++) { + String hex = Integer.toHexString(buf[i] & 0xFF); + if (hex.length() == 1) { + hex = '0' + hex; + } + sb.append(hex.toUpperCase()); + } + return sb.toString(); + } + + /** + * @param str + * @param key + * @return + * @throws Exception + */ + public static String aesEncrypt(String str, String key) throws Exception { + if (str == null || key == null) + return null; + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "AES")); + byte[] bytes = cipher.doFinal(str.getBytes("utf-8")); + //return new BASE64Encoder().encode(bytes); + return Base64Util.encode(bytes); + } + + public static String aesDecrypt(String str, String key) throws Exception { + if (str == null || key == null) + return null; + Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); + cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "AES")); + //byte[] bytes = new BASE64Decoder().decodeBuffer(str); + byte[] bytes = Base64Util.decode(str); + bytes = cipher.doFinal(bytes); + return new String(bytes, "utf-8"); + } + + public static void main(String[] args) throws Exception { + byte[] key = initSecretKey(); + System.out.println("key:" + Base64.encodeBase64String(key)); + System.out.println("key:" + showByteArray(key)); + + // 指定key + String kekkk = "9iEepr1twrizIEKrs1hs2A=="; + System.out.println("kekkk:" + showByteArray(Base64.decodeBase64(kekkk))); + Key k = toKey(Base64.decodeBase64(kekkk)); + + String data = "{\"requestName\":\"BeforeIn\",\"requestValue\":{\"carCode\":\"浙AD0V07\",\"inTime\":\"2016-09-29 10:06:03\",\"inChannelId\":\"4\",\"GUID\":\"1403970b-4eb2-46bc-8f2b-eeec91ddcd5f\",\"inOrOut\":\"0\"},\"Type\":\"0\"}"; + System.out.println("加密前数据: string:" + data); + System.out.println("加密前数据: byte[]:" + showByteArray(data.getBytes("utf-8"))); + System.out.println(); + + byte[] encryptData = encrypt(data.getBytes("utf-8"), k); + String encryptStr=parseByte2HexStr(encryptData); + + System.out.println("加密后数据: byte[]:" + showByteArray(encryptData)); + System.out.println("加密后数据: Byte2HexStr:" + encryptStr); + System.out.println(); + + byte[] decryptData = decrypt(parseHexStr2Byte(encryptStr), k); + System.out.println("解密后数据: byte[]:" + showByteArray(decryptData)); + System.out.println("解密后数据: string:" + new String(decryptData,"utf-8")); + + } +} diff --git a/mallinkService/src/main/java/com/iformall/service/park/impl/lifang/LiFangParkCallbackService.java b/mallinkService/src/main/java/com/iformall/service/park/impl/lifang/LiFangParkCallbackService.java new file mode 100644 index 000000000..91b9b6958 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/lifang/LiFangParkCallbackService.java @@ -0,0 +1,167 @@ +package com.iformall.service.park.impl.lifang; + +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 LiFangParkCallbackService extends BaseParkService implements ParkCallBackAdapterService { + + + @Autowired + LiFangParkService liFangParkService; + + @Autowired + WxParkService wxParkService; + + @Autowired + WxCarJSOrderMapper wxCarJSOrderMapper; + + LiFangUtil lifang = new LiFangUtil(); + + /** + * { + "carCode": "浙A5C393", + "inTime": "2016-10-18 16:44:44", + "passTime": "2016-10-28 16:44:44", + "parkID": "12222", + "inOrOut": "1", + "GUID": "134589c1d68d44d38dcb7f084b9cf8a1", + "channelID": "1", + "channelName": "北大门出口", + "imagePath": "http://xxx.xxx.xx.xx:xx\\xxx\\xxx.jpg" + } + */ + @Override + public ParkNotifyParam parseInNoticyParam(Object param) { + Map paramMap = (Map) param; + String carNumber = paramMap.get("carCode").toString(); + String parkCode = paramMap.get("parkID").toString(); + String parkName = ""; + + String synId = paramMap.get("GUID").toString(); + Integer inTime = (Integer)paramMap.get("inTime"); + + ParkNotifyParam p = new ParkNotifyParam(); + p.setCarNumber(carNumber); + p.setParkId(parkCode); + p.setParkName(parkName); + p.setSynId(synId); + try { + p.setEntranceTime(new Date(inTime.longValue()*1000)); + } catch (Exception e) { + log.error("fute entranceTime format error",e); + return null; + } + return p; + } + + /** + * { + "carCode": "浙A5C393", + "inTime": "2016-10-18 16:44:44", + "passTime": "2016-10-28 16:44:44", + "parkID": "12222", + "inOrOut": "1", + "GUID": "134589c1d68d44d38dcb7f084b9cf8a1", + "channelID": "1", + "channelName": "北大门出口", + "imagePath": "http://xxx.xxx.xx.xx:xx\\xxx\\xxx.jpg" + } + */ + @Override + public ParkNotifyParam parseOutNoticyParam(Object param) { + Map paramMap = (Map) param; + String carNumber = paramMap.get("carCode").toString(); + String parkCode = paramMap.get("parkID").toString(); + String parkName = ""; + + String synId = paramMap.get("GUID").toString(); + Integer inTime = (Integer)paramMap.get("inTime"); + Integer outTime = (Integer)paramMap.get("passTime"); + + ParkNotifyParam p = new ParkNotifyParam(); + p.setCarNumber(carNumber); + p.setParkId(parkCode); + p.setParkName(parkName); + p.setSynId(synId); + try { + p.setEntranceTime(new Date(inTime.longValue()*1000)); + } catch (Exception e) { + log.error("lifang entranceTime format error",e); + return null; + } + try { + p.setOutTime(new Date(outTime.longValue()*1000)); + } catch (Exception e) { + log.error("lifang outTime format error",e); + return null; + } + p.setFee("0"); + return p; + } + + @Override + public ParkNotifyParam parseUnbindNoticyParam(Object param) { + return null; + } + + /** + * { + "recordID": "1", + "carCode": "浙A5C393", + "inTime": "2016-10-18 16:44:44", + "payTime": "2016-10-28 16:44:44", + "parkID": "12222", + "GUID": "134589c1d68d44d38dcb7f084b9cf8a1", + "chargeMoney": 1, + "paidMoney": 1, + "JMMoney": 0, + "chargeType": 0, + "chargeSource": 0, + "amountType": 0 +} + */ + @Override + public ParkNotifyParam parsePaidNoticyParam(Object param) { + Map paramm = (Map) param; + ParkNotifyParam p = new ParkNotifyParam(); + p.setCarNumber((String) paramm.get("carCode")); + p.setParkId((String) paramm.get("parkID")); + p.setParkOrderId((String) paramm.get("recordID")); + p.setSynId((String) paramm.get("GUID")); + p.setFee(paramm.get("paidMoney").toString()); + try { + p.setPayTime(lifang.utcToLocal((String)paramm.get("payTime"))); + } catch (ParseException e) { + e.printStackTrace(); + } + return p; + } +} diff --git a/mallinkService/src/main/java/com/iformall/service/park/impl/lifang/LiFangParkService.java b/mallinkService/src/main/java/com/iformall/service/park/impl/lifang/LiFangParkService.java new file mode 100644 index 000000000..52c435c69 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/lifang/LiFangParkService.java @@ -0,0 +1,216 @@ +package com.iformall.service.park.impl.lifang; + +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; + +/** + * + * token是和ip是一对一绑定,新的ip服务器调捷顺的接口会出现ip不合法,需把ip提供捷顺方,添加白名单。多个服务调捷顺接口共用一个ip情况下,只能共用一套登录获取token机制,各自登录会冲突 + * 捷顺参数: + * loginurl=http://syx.jslife.com.cn/jsaims/login + * funcurl=http://syx.jslife.com.cn/jsaims/as + * cid=880075500000002 + * usr=880075500000002 + * psw=888888 + * v=2 + * signKey=2f4ce8242b796e4adbb9bdad0794c898 + * parkcode=0020200529 + * + * https://syx.jslife.com.cn/store/index.html#/auth/login + * 您的登录帐号是880075500000002000019,登录密码为a9A3MYJK + * + * 跳转捷停车小程序参数:(生产环境) + appid:wx24b70f0ad2a9a89a + + 1>小程序首页 + path:pages/index/index + + 2>小程序页面 pages/thirdPayOrderByNo/payOrder?orderNo=订单编号&freeMinute=免费离场时间(分钟数) + + 找捷顺。顺易通开通下第三方小程序的捷停车支付方式 + */ +@Service +public class LiFangParkService 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; + + + LiFangUtil lifang = new LiFangUtil(); + + @Override + public ResultData parkInitConfig(WxPark park) throws Exception { + // TODO Auto-generated method stub + 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 "lifang"; + } + + + @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 lifangCarStopFee(paramMap, park,carNumber); + } + + private ParkStopFee lifangCarStopFee(Map paramMap, WxPark park,String carNumber) throws Exception{ + //下订单; + String retCode = lifang.getCarStopFee(park, carNumber); + if (StringUtils.isBlank(retCode)) { + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(), "lifang getCarStopFee error. has no result"); + } + JSONObject result = JSON.parseObject(retCode); + if (result.getInteger("resCode") != 0 ) { + String message = result.getString("resMsg"); + throw new MallinkException(result.getInteger("resCode"), "lifang getCarStopFee error."+message); + } + Integer totalFee = result.getInteger("paidMoney"); + String appId = "wx24b70f0ad2a9a89a"; + Integer freeMinute = result.getInteger("remainLeaveTime"); + String _createTime = result.getString("inTime");//计费时间,格式为“yyyy-MM-dd HH:mi:ss” + if (totalFee <= 0 ) { + String msg = result.getString("note"); + if (!StringUtils.isBlank(msg)) { + if (msg.contains("未入场")) { + return new ParkStopFee(null,lifang.utcToLocal(_createTime),new Date(), + "0.00",appId,"payPath",null,msg,null); + }else { + //0元订单结清,查询是否用过打折方案,如果用过,则需要调用接口结清订单 + Integer used = ParkCacheUtils.getCarCouponUseCacheLock(redisTemplate, EnumCarVendor.CAR_LIFANG.getMessage(), carNumber); + if (null == used || (null != used && used.intValue() < 1)) { + //未使用停车券 + return new ParkStopFee("-999",lifang.utcToLocal(_createTime),new Date(), + "0.00",appId,"payPath",null,msg,null); + }else { + return new ParkStopFee("-999",lifang.utcToLocal(_createTime),new Date(), + "0.00",appId,"payPath",null,msg,"用券抵扣后账单为0,获得"+freeMinute+"分钟免费出场时间"); + } + } + } + } + + String payPath = null;//"pages/thirdPayOrderByNo/payOrder?orderNo="+parkOrderId+"&freeMinute="+freeMinute; + //String payPath = "pages/thirdPayOrder/payOrder?carNo="+jieshun.handleCarNumber(carNumber)+"&parkCode="+park.getParkingId(); + return new ParkStopFee(null,lifang.utcToLocal(_createTime),new Date(), + String.valueOf(totalFee),appId,payPath,null,null,"请支付后"+freeMinute+"分钟内离场"); + } + + /** + * 使用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()); + } + + try { + ParkStopFee stopFee = lifangCarStopFee(paramMap, park, carNumber); + if (Integer.parseInt(stopFee.getRemainingFee()) <= 0 ) { + return new ResultData(ErrorCode.CYF_STOP_FEE_FAIL.getCode(),"0元无需使用优惠券"); + } + //coupon判断是小时券还是现金券 + String ret = lifang.addChargeInfo(park, carNumber, false, null, null); + logger.info("lifang addChargeInfo result:"+ret); + JSONObject retObj = JSON.parseObject(ret); + if (retObj.getIntValue("resCode") == 0){ + return new ResultData(); + }else { + return new ResultData(retObj.getIntValue("resCode"),"当前用户使用立方停打折方案失败。"+retObj.getString("resMsg")); + } + }catch(Exception e) { + return new ResultData(ErrorCode.CYF_STOP_FEE_FAIL.getCode(),e.getMessage()); + } + } + + @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/lifang/LiFangUtil.java b/mallinkService/src/main/java/com/iformall/service/park/impl/lifang/LiFangUtil.java new file mode 100644 index 000000000..8ed17ecdd --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/lifang/LiFangUtil.java @@ -0,0 +1,170 @@ +package com.iformall.service.park.impl.lifang; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.iformall.common.ErrorCode; +import com.iformall.domain.po.WxPark; +import com.iformall.exception.MallinkException; +import com.iformall.utils.DateUtils; + +import lombok.extern.slf4j.Slf4j; + +import org.apache.commons.lang3.StringUtils; +import org.apache.http.Consts; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +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.message.BasicHeader; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.protocol.HTTP; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; + + +/** + * @author: furunxin + * @Date: 2020/7/1 17:16 + * @Description: 车易付接口对接参数类 + */ + +@Slf4j +public class LiFangUtil { + + public static final String QUERY_CAR = "/GetCarInfo"; + public static final String ADD_CHARGE_INFO = "/AddChargeInfo"; + + /** + * @description UTC时间转化为本地时间 + * @Params [utcTime] + * @return java.util.Date + * @Author furunxin + * @Date 2020/7/8 下午12:45 + **/ + 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 static String getLocalDate(){ + LocalDateTime ldt = LocalDateTime.now(); + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + String nowDate = ldt.format(dtf); + return nowDate; + } + + /** + * 查询停车费 + **/ + public String getCarStopFee(WxPark wxPark,String carNumber){ + String vendroParams = wxPark.getVendorParams(); + JSONObject vp = JSON.parseObject(vendroParams); + Map params = new HashMap(); + params.put("carCode", carNumber); + log.info("lifang getCarStopFee :" + JSON.toJSONString(params)); + return ProcBussiness(vp,QUERY_CAR,params); + } + + /** + * 保存缴费信息 + */ + public String addChargeInfo(WxPark wxPark,String carNumber,boolean isReduceFee,Integer total,Integer reduce) { + try { + String vendroParams = wxPark.getVendorParams(); + JSONObject vp = JSON.parseObject(vendroParams); + Map params = new HashMap(); + params.put("carCode", carNumber); + if (isReduceFee) { + params.put("chargeMoney", total); + params.put("paidMoney", total-reduce); + params.put("JMMoney", reduce); + } + params.put("payTime", DateUtils.date2String(new Date())); + params.put("chargeType", 11); + params.put("chargeSource", "3"); + log.info("lifang addChargeInfo :" + JSON.toJSONString(params)); + return ProcBussiness(vp,ADD_CHARGE_INFO,params); + } catch (Exception e) { + log.error("lifang verifyuser error.park:"+wxPark.getId(),e); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"lifang addChargeInfo error.park:"+wxPark.getId()+".error"+e.getMessage()); + } + } + + private static String ProcBussiness(JSONObject vp,String api,Map params) { + String url = vp.getString("reqUrl")+api; + return Proc(url,params); + } + + private static String Proc(String url, Map 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"); + + if (null != params) { + try { + 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("lifang httpRequest:[url]"+url+"[params]"+JSON.toJSONString(params)); + }else { + log.info("lifang 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; + } +}