From 587554d7aee63d3d097cc025db125c07e0a7982f Mon Sep 17 00:00:00 2001 From: winter <664946893@qq.com> Date: Mon, 24 Apr 2023 19:22:52 +0800 Subject: [PATCH] fix car --- .../com/iformall/enums/EnumCarVendor.java | 1 + .../iformall/service/park/ParkFactory.java | 8 + .../park/impl/jieshunV2/JieShunUtilV2.java | 344 +++++++++++++++++ .../JieShunV2ParkCallbackService.java | 190 +++++++++ .../impl/jieshunV2/JieShunV2ParkService.java | 365 ++++++++++++++++++ 5 files changed, 908 insertions(+) create mode 100644 mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunUtilV2.java create mode 100644 mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunV2ParkCallbackService.java create mode 100644 mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunV2ParkService.java diff --git a/mallinkService/src/main/java/com/iformall/enums/EnumCarVendor.java b/mallinkService/src/main/java/com/iformall/enums/EnumCarVendor.java index 978c9b812..e5ec26834 100644 --- a/mallinkService/src/main/java/com/iformall/enums/EnumCarVendor.java +++ b/mallinkService/src/main/java/com/iformall/enums/EnumCarVendor.java @@ -14,6 +14,7 @@ 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_HAIKANGWEISHI(8,"HAIKANGWEISHI",true), CAR_FUTE(9,"FUTE",false)//深圳市福特智能科技有限公司 ; 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 da184f34a..fecd5b148 100644 --- a/mallinkService/src/main/java/com/iformall/service/park/ParkFactory.java +++ b/mallinkService/src/main/java/com/iformall/service/park/ParkFactory.java @@ -19,6 +19,8 @@ import com.iformall.service.park.impl.haikangweishi.HaiKangWeiShiParkCallbackSer import com.iformall.service.park.impl.haikangweishi.HaiKangWeiShiParkService; 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.shangan.ShangAnParkService; import com.iformall.service.park.impl.tjd.TJDParkService; @@ -38,6 +40,8 @@ public class ParkFactory { @Autowired JieShunParkService jieshunService; @Autowired + JieShunV2ParkService jieshunV2Service; + @Autowired HaiKangWeiShiParkService haikangWeishiService; @Autowired FuteParkService futeParkService; @@ -47,6 +51,8 @@ public class ParkFactory { @Autowired JieShunParkCallbackService jieshunCallBackService; @Autowired + JieShunV2ParkCallbackService jieshunV2CallBackService; + @Autowired HaiKangWeiShiParkCallbackService haikangWeishiCallBackService; @Autowired FuteParkCallbackService futeParkCallbackService; @@ -68,6 +74,7 @@ public class ParkFactory { parkServiceMap.put(EnumCarVendor.CAR_SHANGAN.getCode(), shangAnService); parkServiceMap.put(EnumCarVendor.CAR_TJD.getCode(), tjdService); parkServiceMap.put(EnumCarVendor.CAR_JIESHUN.getCode(), jieshunService); + parkServiceMap.put(EnumCarVendor.CAR_JIESHUN_V2.getCode(), jieshunV2Service); parkServiceMap.put(EnumCarVendor.CAR_HAIKANGWEISHI.getCode(), haikangWeishiService); parkServiceMap.put(EnumCarVendor.CAR_FUTE.getCode(), futeParkService); return parkServiceMap; @@ -101,6 +108,7 @@ public class ParkFactory { } batchCallBackServiceMap = new ConcurrentHashMap(); batchCallBackServiceMap.put(EnumCarVendor.CAR_JIESHUN.getCode(), jieshunCallBackService); + batchCallBackServiceMap.put(EnumCarVendor.CAR_JIESHUN_V2.getCode(), jieshunV2CallBackService); batchCallBackServiceMap.put(EnumCarVendor.CAR_HAIKANGWEISHI.getCode(), haikangWeishiCallBackService); return batchCallBackServiceMap; } diff --git a/mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunUtilV2.java b/mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunUtilV2.java new file mode 100644 index 000000000..6c0b6dae8 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunUtilV2.java @@ -0,0 +1,344 @@ +package com.iformall.service.park.impl.jieshunV2; + +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 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.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 JieShunUtilV2 { + + public static final String CYF_PARK_ID = "parkingId"; + public static final String CYF_CAR_NUMBER = "plate"; + public static final String CYF_PARK_NAME = "parking"; + public static final String CYF_SYN_ID = "recordOrderId"; + public static final String CYF_ENTRANCE_TIME = "inTime"; + + public static final String CYF_IS_RESULT = "result"; + public static final String CYF_ERR_MSG = "strError"; + public static final int CYF_SUC = 1; + public static final int CYF_ERR = 0; + + + public static final String TOKEN_URL = "http://syx.jslife.com.cn/jsaims/login"; + + public static final String CREATE_ORDER = "http://syx.jslife.com.cn/jsaims/as"; + + public static final String QUERY_ORDER = "http://syx.jslife.com.cn/jsaims/as"; + + public static final String GET_COUPON = "http://syx.jslife.com.cn/jsaims/as"; + public static final String COUPON_USE = "http://syx.jslife.com.cn/jsaims/as"; + + public static final String VERIFY_USER = "http://syx.jslife.com.cn/jsaims/as"; + public static final String QUERY_PLAN = "http://syx.jslife.com.cn/jsaims/as"; + public static final String PLAN_EXECUTE = "http://syx.jslife.com.cn/jsaims/as"; + + /** + * @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 getToken(WxPark wxPark) { + String vendroParams = wxPark.getVendorParams(); + JSONObject vp = JSON.parseObject(vendroParams); + String cid = vp.getString("cid"); + String userName = vp.getString("usr"); + String password = vp.getString("psw"); + return getToken(cid,userName,password); + } + + private String getToken(String cid,String userName,String password) { + String result = ProcLogin(cid, userName,password); + log.info("jieshunv2 token cid:"+cid+" userName:"+userName+" password:"+password+" result: "+result); + if (StringUtils.isBlank(result)) { + return null; + } + JSONObject res = JSON.parseObject(result); + Integer code = res.getInteger("resultCode"); + if (null == code || code.intValue() != 0) { + String msg = res.getString("message"); + throw new MallinkException(code,msg); + } + return res.getString("token"); + } + + private Map generateMap(String serviceId,Map param) { + Map map = new HashMap(); + map.put("serviceId", serviceId); + map.put("requestType", "DATA"); + map.put("attributes", param); + return map; + } + + public String handleCarNumber(String carNumber) { + if (carNumber.contains("-")) { + return carNumber; + }else { + carNumber = carNumber.substring(0,1)+"-"+carNumber.substring(1, carNumber.length()); + return carNumber; + } + } + /** + * 创建订单 + * @return + */ + public String createOrder(WxPark wxPark,String cardNumber,String token) { + String vendroParams = wxPark.getVendorParams(); + JSONObject vp = JSON.parseObject(vendroParams); + Map param = new HashMap(); + param.put("businesserCode", vp.get("businesserCode"));//商户编号 + param.put("parkCode", wxPark.getParkingId()); + param.put("orderType", "VNP"); + param.put("carNo", handleCarNumber(cardNumber)); + Map map = generateMap("3c.pay.createorderbycarno",param); + log.info("jieshunv2 create order :" + JSON.toJSONString(map)); + return ProcBussiness(CREATE_ORDER, wxPark.getParkId(), map, token,vp.getString("version"),vp.getString("signkey")); + } + + /** + * 查询停车费 + **/ + public String getCarStopFee(WxPark wxPark,String orderNo,String token){ + String vendroParams = wxPark.getVendorParams(); + JSONObject vp = JSON.parseObject(vendroParams); + Map param = new HashMap(); + param.put("orderNo", orderNo);//商户编号 + Map map = generateMap("3c.pay.queryorder",param); + log.info("jieshunv2 getCarStopFee :" + JSON.toJSONString(map)); + return ProcBussiness(QUERY_ORDER, wxPark.getParkId(), map, token,vp.getString("version"),vp.getString("signkey")); + } + + /** + * 打折登陆验证 + */ + public String verifyuser(WxPark wxPark,String token) { + try { + String vendroParams = wxPark.getVendorParams(); + JSONObject vp = JSON.parseObject(vendroParams); + Map param = new HashMap(); + param.put("userCode", vp.get("loginUser"));//商户编号 + + MessageDigest md5Tool = MessageDigest.getInstance("MD5"); + byte[] md5Data = md5Tool.digest((vp.getString("loginPassword")).getBytes("UTF-8")); + String sn = toHexString(md5Data); + param.put("password", sn.toLowerCase());//优惠券编号 + Map map = generateMap("3c.discount.verifyuser",param); + log.info("jieshunv2 verifyuser :" + JSON.toJSONString(map)); + return ProcBussiness(VERIFY_USER, wxPark.getParkId(), map, token,vp.getString("version"),vp.getString("signkey")); + } catch (NoSuchAlgorithmException e) { + log.error("jieshunv2 verifyuser error.park:"+wxPark.getId(),e); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"jieshunv2 verifyuser error.park:"+wxPark.getId()+".error"+e.getMessage()); + } catch (UnsupportedEncodingException e) { + log.error("jieshunv2 verifyuser error.park:"+wxPark.getId(),e); + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"jieshunv2 verifyuser error.park:"+wxPark.getId()+".error"+e.getMessage()); + } + } + + /** + * 查询门店打折方案 + */ + public String querySalePlan(WxPark wxPark,String token,String userId) { + String vendroParams = wxPark.getVendorParams(); + JSONObject vp = JSON.parseObject(vendroParams); + Map param = new HashMap(); + param.put("userId", userId);//商户编号 + Map map = generateMap("3c.discount.querysaleplan",param); + log.info("jieshunv2 querySalePlan :" + JSON.toJSONString(map)); + return ProcBussiness(QUERY_PLAN, wxPark.getParkId(), map, token,vp.getString("version"),vp.getString("signkey")); + } + + /** + * 使用打折方案 + */ + public String executediscount(WxPark wxPark,String planId,String userId,String carNumber,String token) { + String vendroParams = wxPark.getVendorParams(); + JSONObject vp = JSON.parseObject(vendroParams); + Map param = new HashMap(); + param.put("planId", planId);//商户编号 + param.put("userId", userId);//优惠券编号 + param.put("carOrCardNo", handleCarNumber(carNumber));//优惠券编号 + Map map = generateMap("3c.discount.executediscount",param); + log.info("jieshunv2 executediscount :" + JSON.toJSONString(map)); + return ProcBussiness(PLAN_EXECUTE, wxPark.getParkId(), map, token,vp.getString("version"),vp.getString("signkey")); + } + + /*token认证登陆**/ + private static String ProcLogin(String cid,String user,String password) { + String url = TOKEN_URL +"?cid="+cid+"&usr="+user+"&psw="+password; +// ArrayList list = new ArrayList(); +// list.add(new BasicNameValuePair("cid", cid)); +// list.add(new BasicNameValuePair("usr", user)); +// list.add(new BasicNameValuePair("psw",password)); + return Proc(url,null); + } + + /** + * 优惠券使用完毕,0元停车费需调用次接口结清订单 + * @param wxPark + * @param planId + * @param userId + * @param carNumber + * @param token + * @return + */ + public String notifyOrderResult(WxPark wxPark,String orderNo,String token) { + String vendroParams = wxPark.getVendorParams(); + JSONObject vp = JSON.parseObject(vendroParams); + Map param = new HashMap(); + param.put("orderNo", orderNo);//商户编号 + param.put("tradeStatus", 0);//优惠券编号 + param.put("isCallBack", 0);//优惠券编号 + Map map = generateMap("3c.pay.notifyorderresult",param); + log.info("jieshunv2 notifyOrderResult :" + JSON.toJSONString(map)); + return ProcBussiness(PLAN_EXECUTE, wxPark.getParkId(), map, token,vp.getString("version"),vp.getString("signkey")); + } + + private static String ProcBussiness(String url,String cid,Map param,String token,String version,String signKey) { + try { + MessageDigest md5Tool = MessageDigest.getInstance("MD5"); + String p = JSON.toJSONString(param); + byte[] md5Data = md5Tool.digest((p+signKey).getBytes("UTF-8")); + String sn = toHexString(md5Data); + if (url.contains("?")) { + url = url + "&"; + }else { + url = url + "?"; + } + + url = url+"cid="+cid+"&tn="+token+"&sn="+sn+"&v="+version+"&p="+URLEncoder.encode(p, "UTF-8"); +// +// ArrayList list = new ArrayList(); +// list.add(new BasicNameValuePair("cid", cid)); +// list.add(new BasicNameValuePair("v", version));//版本号 +// list.add(new BasicNameValuePair("p",p)); +// list.add(new BasicNameValuePair("sn",sn)); +// if (!StringUtils.isBlank(token)) { +// list.add(new BasicNameValuePair("tn",token)); +// } + return Proc(url,null); + } catch (NoSuchAlgorithmException e) { + log.error("jieshunv2 request error.",e); + } catch (UnsupportedEncodingException e) { + log.error("jieshunv2 request error.",e); + } + return null; + } + + private static String toHexString(byte[] bytes) { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + buffer.append(String.format("%02X", bytes[i])); + } + return buffer.toString(); + } + + private static String Proc(String url, List pairs) { + 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 != pairs) { + HttpEntity en; + try { + en = new UrlEncodedFormEntity(pairs, HTTP.UTF_8); + httpPost.setEntity(en); + } catch (UnsupportedEncodingException e) { + log.error(e.getLocalizedMessage(),e); + return null; + } + + } + + if (null != pairs) { + log.info("jieshunv2 httpRequest:[url]"+url+"[params]"+JSON.toJSONString(pairs)); + }else { + log.info("jieshunv2jieshunv2 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; + } +} diff --git a/mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunV2ParkCallbackService.java b/mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunV2ParkCallbackService.java new file mode 100644 index 000000000..f0b2598e7 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunV2ParkCallbackService.java @@ -0,0 +1,190 @@ +package com.iformall.service.park.impl.jieshunV2; + +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 JieShunV2ParkCallbackService extends BaseParkService implements ParkBatchCallBackAdapterService { + + + @Autowired + JieShunV2ParkService jieshunParkService; + + @Autowired + WxParkService wxParkService; + + @Autowired + WxCarJSOrderMapper wxCarJSOrderMapper; + + private String handleCarNumber(String carNumber) { + if (StringUtils.isBlank(carNumber)) { + return "空车牌"; + } + if (carNumber.contains("-")) { + carNumber = carNumber.replaceAll("-", ""); + } + return carNumber; + } + + /** + * {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 List parseInNoticyParam(Object param) { + Map paramm = (Map) param; + String liststr = (String) paramm.get("dataItems"); + JSONArray list = JSONArray.parseArray(liststr); + if (null != list && list.size() > 0 ) { + List retList = new ArrayList(); + for (int i = 0 ; i < list.size() ; i ++) { + Map map = (Map) list.get(i); + ParkNotifyParam ret = parseInNoticyParamSingle(map); + if (null != ret ) { + retList.add(ret); + } + } + return retList; + } + return null; + } + + private ParkNotifyParam parseInNoticyParamSingle(Map paramMap) { + String carNumber = paramMap.get("carNumber").toString(); + String parkCode = paramMap.get("parkCode").toString(); + String parkName = paramMap.get("parkName").toString(); + + String synId = paramMap.get("itemId").toString(); + String entranceTime = paramMap.get("inTime").toString(); + + ParkNotifyParam p = new ParkNotifyParam(); + String realCarNumber = handleCarNumber(carNumber); + p.setCarNumber(realCarNumber); + p.setParkId(parkCode); + p.setParkName(parkName); + p.setSynId(synId); + try { + p.setEntranceTime(JieShunUtilV2.utcToLocal(entranceTime)); + } catch (ParseException e) { + log.error("jieshun entranceTime format error",e); + return null; + } + return p; + } + + @Override + public List parseOutNoticyParam(Object param) { + Map paramm = (Map) param; + String liststr = (String) paramm.get("dataItems"); + JSONArray list = JSONArray.parseArray(liststr); + if (null != list && list.size() > 0 ) { + List retList = new ArrayList(); + for (int i = 0 ; i < list.size() ; i ++) { + Map map = (Map) list.get(i); + ParkNotifyParam ret = parseOutNoticyParamSingle(map); + if (null != ret ) { + retList.add(ret); + } + } + return retList; + } + return null; + } + + + private ParkNotifyParam parseOutNoticyParamSingle(Map paramMap) { + String carNumber = paramMap.get("carNumber").toString(); + String parkCode = paramMap.get("parkCode").toString(); + String parkName = paramMap.get("parkName").toString(); + + String synId = paramMap.get("itemId").toString(); + String entranceTime = paramMap.get("outTime").toString(); + + String realCarNumber = handleCarNumber(carNumber); + ParkNotifyParam p = new ParkNotifyParam(); + p.setCarNumber(realCarNumber); + p.setParkId(parkCode); + p.setParkName(parkName); + p.setSynId(synId); + try { + p.setEntranceTime(JieShunUtilV2.utcToLocal(entranceTime)); + } catch (ParseException e) { + log.error("cyf entranceTime format error",e); + return null; + } + try { + p.setOutTime(JieShunUtilV2.utcToLocal(entranceTime)); + } catch (ParseException e) { + log.error("cyf outTime format error",e); + return null; + } + p.setFee(String.valueOf(paramMap.get("ssMoney"))); + return p; + } + + @Override + public List parseUnbindNoticyParam(Object param) { + return null; + } + + @Override + public List parsePaidNoticyParam(Object param) { + Map paramm = (Map) param; + String liststr = (String) paramm.get("dataItems"); + JSONArray list = JSONArray.parseArray(liststr); + if (null != list && list.size() > 0 ) { + List retList = new ArrayList(); + for (int i = 0 ; i < list.size() ; i ++) { + Map map = (Map) list.get(i); + ParkNotifyParam ret = parsePaidNoticyParamSingle(map); + if (null != ret ) { + retList.add(ret); + } + } + return retList; + } + return null; + } + + JieShunUtilV2 jieshun = new JieShunUtilV2(); + private ParkNotifyParam parsePaidNoticyParamSingle(Map vo) { + ParkNotifyParam p = new ParkNotifyParam(); + p.setCarNumber(handleCarNumber((String) vo.get("carNumber"))); + p.setParkId(String.valueOf(vo.get("parkCode"))); + p.setParkOrderId((String) vo.get("itemId")); + p.setSynId((String) vo.get("itemId")); + p.setFee(vo.get("ssMoney").toString()); + try { + p.setPayTime(jieshun.utcToLocal((String)vo.get("feesTime"))); + } catch (ParseException e) { + e.printStackTrace(); + } + return p; + } +} 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 new file mode 100644 index 000000000..7b133ff31 --- /dev/null +++ b/mallinkService/src/main/java/com/iformall/service/park/impl/jieshunV2/JieShunV2ParkService.java @@ -0,0 +1,365 @@ +package com.iformall.service.park.impl.jieshunV2; + +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>小程序订单页(车牌+车场编号 ) path: pages/thirdPayOrder/payOrder?carNo=车牌&parkCode=车场编号 + + 3>小程序订单页(订单编号) path: pages/thirdPayOrderByNo/payOrder?orderNo=订单编号 + + */ +@Service +public class JieShunV2ParkService 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; + + + JieShunUtilV2 jieshun = new JieShunUtilV2(); + + + private String getCacheToken(WxPark park) { + String token = RedisCacheUtils.getCacheString(redisTemplate, "carStop:jieshuntokenV2:"+park.getId()); + if (StringUtils.isBlank(token)) { + String lockKey = "carStop:jieshuntokenlockV2:"+park.getTenantId(); + long time = System.currentTimeMillis() + 2000; + String timeStr = String.valueOf(time); + if (redisLock.lock2(lockKey, timeStr)) { + token = jieshun.getToken(park); + if (!StringUtils.isBlank(token)) { + setCacheToken(park, token); + } + redisLock.unlock(lockKey, timeStr); + } else { + try { + Thread.sleep(2000); + } catch (InterruptedException e) { + e.printStackTrace(); + }finally { + redisLock.unlock(lockKey, timeStr); + } + } + } + return RedisCacheUtils.getCacheString(redisTemplate, "carStop:jieshuntokenV2:"+park.getId()); + } + + private void setCacheToken(WxPark park,String token) { + RedisCacheUtils.cache(redisTemplate, "carStop:jieshuntokenV2:"+park.getId(), token, 3600); + } + + /** + * 先去捷顺注册,调用登陆获取令牌,然后根据令牌调用别的接口 + * 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 { + // 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 "jieshunV2"; + } + + + @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 jieshunCarStopFee(paramMap, park,carNumber); + } + + private ParkStopFee jieshunCarStopFee(Map paramMap, WxPark park,String carNumber) throws Exception{ + //如果车牌号是鄂AAAAAA, 为测试车牌 + if (carNumber.equals("鄂AAAAAA")) { + return new ParkStopFee("-111",jieshun.utcToLocal("2020-12-16 00:00:00"),jieshun.utcToLocal("2020-12-17 00:00:00"), + "0.01","wx24b70f0ad2a9a89a","payPath",null,"测试车牌,仅测试用",null); + }else if(carNumber.equals("鄂AAAAAB")) { + throw new MallinkException(21000,"车辆未入场"); + } + + //下订单; + String retCode = jieshun.createOrder(park, carNumber, getCacheToken(park)); + if (StringUtils.isBlank(retCode)) { + throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(), "jieshun createOrder error. has no result"); + } + JSONObject result = JSON.parseObject(retCode); + if (result.getInteger("resultCode") != 0 ) { + String message = result.getString("message"); + throw new MallinkException(result.getInteger("resultCode"), "jieshun createOrder error."+message); + } + JSONArray arrays = result.getJSONArray("dataItems"); + if (null == arrays || arrays.size() == 0) { + throw new MallinkException(result.getInteger("resultCode"), "jieshun createOrder error. no order result"+carNumber); + } + JSONObject attribute = arrays.getJSONObject(0).getJSONObject("attributes"); + Double totalFee = attribute.getDouble("totalFee"); + String appId = "wx24b70f0ad2a9a89a"; + String parkOrderId = attribute.getString("orderNo"); + if (totalFee <= 0 ) { + String _createTime = attribute.getString("startTime");//计费时间,格式为“yyyy-MM-dd HH:mi:ss” + String _endTime = attribute.getString("endTime");//离场时间,格式为“yyyy-MM-dd HH:mi:ss” + String msg = attribute.getString("retmsg"); + if (!StringUtils.isBlank(msg)) { + if (msg.contains("未入场")) { + return new ParkStopFee(null,jieshun.utcToLocal(_createTime),jieshun.utcToLocal(_endTime), + "0.00",appId,"payPath",null,msg,null); + }else { + //0元订单结清,查询是否用过打折方案,如果用过,则需要调用接口结清订单 + Integer used = ParkCacheUtils.getCarCouponUseCacheLock(redisTemplate, EnumCarVendor.CAR_JIESHUN.getMessage(), carNumber); + if (null == used || (null != used && used.intValue() < 1)) { + //未使用停车券 + return new ParkStopFee("-999",jieshun.utcToLocal(_createTime),jieshun.utcToLocal(_endTime), + "0.00",appId,"payPath",null,msg,null); + }else { + return new ParkStopFee("-999",jieshun.utcToLocal(_createTime),jieshun.utcToLocal(_endTime), + "0.00",appId,"payPath",null,msg,"用券抵扣后账单为0,获得15分钟免费出场时间"); +// String notifyResult = jieshun.notifyOrderResult(park, parkOrderId, getCacheToken(park)); +// JSONObject notiryRetObj = JSON.parseObject(notifyResult); +// String noticeErrorMsg = notiryRetObj.getString("message"); +// if (notiryRetObj.getIntValue("resultCode") == 0){ +// JSONArray notiryRetArrays = notiryRetObj.getJSONArray("dataItems"); +// if (null != notiryRetArrays && notiryRetArrays.size() == 0 ) { +// JSONObject notifyRetObject = notiryRetArrays.getJSONObject(0).getJSONObject("attributes"); +// if(notifyRetObject.getIntValue("retCode") == 0) { +// return new ResultData(new ParkStopFee("-999",jieshun.utcToLocal(_createTime),jieshun.utcToLocal(_endTime), +// "0.00",appId,"payPath",null,msg,"用券抵扣后账单为0,获得15分钟免费出场时间")); +// }else { +// return new ResultData(new ParkStopFee("-999",jieshun.utcToLocal(_createTime),jieshun.utcToLocal(_endTime), +// "0.00",appId,"payPath",null,msg,"用券抵扣后账单为0,但是结清订单失败["+noticeErrorMsg+"],无免费出场时间,请下拉刷新")); +// } +// }else { +// return new ResultData(new ParkStopFee("-999",jieshun.utcToLocal(_createTime),jieshun.utcToLocal(_endTime), +// "0.00",appId,"payPath",null,msg,"用券抵扣后账单为0,但是结清订单失败["+noticeErrorMsg+"],无免费出场时间,请下拉刷新")); +// } +// }else { +// return new ResultData(new ParkStopFee("-999",jieshun.utcToLocal(_createTime),jieshun.utcToLocal(_endTime), +// "0.00",appId,"payPath",null,msg,"用券抵扣后账单为0,但是结清订单失败["+noticeErrorMsg+"],无免费出场时间,请下拉刷新")); +// } + } + } + } + } + + + String ret = jieshun.getCarStopFee(park, parkOrderId, getCacheToken(park)); + JSONObject retObj = JSON.parseObject(ret); + if (retObj.getIntValue("resultCode") == 0){ + JSONArray retArrays = retObj.getJSONArray("dataItems"); + if (null == retArrays || retArrays.size() == 0 ) { + throw new MallinkException(result.getInteger("resultCode"), "jieshun getCarStopFee error. no order result"+carNumber); + } + + JSONObject retObject = retArrays.getJSONObject(0).getJSONObject("attributes"); + String createTime = retObject.getString("startTime");//计费时间,格式为“yyyy-MM-dd HH:mi:ss” + String endTime = retObject.getString("endTime");//离场时间,格式为“yyyy-MM-dd HH:mi:ss” + String payPath = "pages/thirdPayOrder/payOrder?carNo="+jieshun.handleCarNumber(carNumber)+"&parkCode="+park.getParkingId(); + return new ParkStopFee(parkOrderId,jieshun.utcToLocal(createTime),jieshun.utcToLocal(endTime), + String.valueOf(retObject.getDouble("totalFee")),appId,payPath,null,null,"请支付后15分钟内离场"); + }else { + logger.error("jieshunCarStopFee error. paramMap: {} . jieshunResult: {}",JSON.toJSONString(paramMap),ret); + String msg = retObj.getString("message"); + 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(),"当前停车券没有关联停车场优惠券配置[planNo]。"+coupon.getTitle()); + } + //String ret = jieshun.getCoupon(park, planNo,userCar.getCUserPhone(), getCacheToken(park)); + //打折登陆验证 + String ret = jieshun.verifyuser(park, getCacheToken(park)); + logger.info("jieshun verifyuser result:"+ret); + JSONObject retObj = JSON.parseObject(ret); + if (retObj.getIntValue("resultCode") == 0){ + JSONArray verfyArrays = retObj.getJSONArray("dataItems"); + if (null != verfyArrays && verfyArrays.size() > 0 ) { + JSONObject verfy = verfyArrays.getJSONObject(0).getJSONObject("attributes"); + String userId = verfy.getString("userId"); + //查询门店下打折方案 + String queryPlanRet = jieshun.querySalePlan(park, getCacheToken(park), userId); + logger.info("jieshun querySalePlan result:"+queryPlanRet); + JSONObject queryPlantRetObj = JSON.parseObject(queryPlanRet); + if (queryPlantRetObj.getIntValue("resultCode") == 0){ + JSONArray planArrays = queryPlantRetObj.getJSONArray("dataItems"); + if (null != planArrays && planArrays.size() > 0 ) { + boolean hasPlan = false; + for (int i = 0 ; i < planArrays.size(); i++) { + JSONObject plan = planArrays.getJSONObject(i); + String planId = plan.getJSONObject("attributes").getString("planId"); + if (planNo.equals(planId)) { + hasPlan = true; + break; + } + } + if (!hasPlan) { + return new ResultData(ErrorCode.CYF_STOP_FEE_FAIL.getCode(),"当前优惠券配置的捷顺编号无效,请联系管理员。"+coupon.getTitle()); + } + //使用打折方案 + String executeRet = jieshun.executediscount(park, planNo, userId, carNumber, getCacheToken(park)); + logger.info("jieshun executediscount result:"+executeRet); + JSONObject executeRetObj = JSON.parseObject(executeRet); + if (executeRetObj.getIntValue("resultCode") == 0){ + return new ResultData(); + }else { + return new ResultData(executeRetObj.getIntValue("resultCode"),"当前用户使用捷顺停打折方案失败。"+executeRetObj.getString("message")); + } + + }else { + return new ResultData(ErrorCode.CYF_STOP_FEE_FAIL.getCode(),"捷顺查询门店未查询到打折信息,请联系管理员。"+userCar.getcUserId()); + } + + }else { + logger.error("jieshun querySalePlan error. paramMap: {} . jieshunResult: {}",JSON.toJSONString(paramMap),queryPlanRet); + String msg = queryPlantRetObj.getString("message"); + return new ResultData(queryPlantRetObj.getIntValue("resultCode"), "捷顺查询门店打折方案失败:"+msg); + } + }else { + return new ResultData(ErrorCode.CYF_STOP_FEE_FAIL.getCode(),"捷顺门店账号登陆失败,请联系管理员。"+userCar.getcUserId()); + } + + }else { + logger.error("jieshun verifyuser error. paramMap: {} . jieshunResult: {}",JSON.toJSONString(paramMap),ret); + String msg = retObj.getString("message"); + return new ResultData(retObj.getIntValue("resultCode"), "当前用户领用到捷顺停车券失败:"+msg); + } + } + + @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; + } + +}