package com.jsowell.service; import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONObject; import com.alibaba.fastjson2.TypeReference; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Maps; import com.huifu.adapay.core.exception.BaseAdaPayException; import com.huifu.adapay.model.Payment; import com.jsowell.adapay.common.CreateAdaPaymentParam; import com.jsowell.common.constant.CacheConstants; import com.jsowell.common.constant.Constants; import com.jsowell.common.core.page.PageResponse; import com.jsowell.common.core.redis.RedisCache; import com.jsowell.common.enums.TitleTypeEnum; import com.jsowell.common.enums.uniapp.BalanceChangesEnum; import com.jsowell.common.enums.ykc.OrderStatusEnum; import com.jsowell.common.enums.ykc.ReturnCodeEnum; import com.jsowell.common.enums.ykc.ScenarioEnum; import com.jsowell.common.enums.ykc.StartModeEnum; import com.jsowell.common.exception.BusinessException; import com.jsowell.common.util.AdapayUtil; import com.jsowell.common.util.JWTUtils; import com.jsowell.common.util.StringUtils; import com.jsowell.common.util.id.IdUtils; import com.jsowell.common.util.id.SnowflakeIdWorker; import com.jsowell.pile.domain.*; import com.jsowell.pile.dto.*; import com.jsowell.pile.service.*; import com.jsowell.pile.transaction.dto.MemberTransactionDTO; import com.jsowell.pile.transaction.service.TransactionService; import com.jsowell.pile.vo.uniapp.InvoiceTitleVO; import com.jsowell.pile.vo.uniapp.MemberVO; import com.jsowell.pile.vo.uniapp.MemberWalletLogVO; import com.jsowell.pile.vo.uniapp.OrderVO; import com.jsowell.wxpay.service.WxAppletRemoteService; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.compress.utils.Lists; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.cglib.beans.BeanMap; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.text.ParseException; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @Service public class MemberService { private final Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private RedisCache redisCache; @Autowired private TransactionService transactionService; @Autowired private IMemberBasicInfoService memberBasicInfoService; @Autowired private IPileMerchantInfoService pileMerchantInfoService; @Autowired private WxAppletRemoteService wxAppletRemoteService; @Autowired private IMemberPlateNumberRelationService memberPlateNumberRelationService; @Autowired private IPileAuthCardService pileAuthCardService; @Autowired private IMemberInvoiceTitleService memberInvoiceTitleService; @Autowired private PileRemoteService pileRemoteService; @Autowired private IOrderBasicInfoService orderBasicInfoService; @Autowired private OrderService orderService; @Value("${adapay.appId}") private String ADAPAY_APP_ID; @Value("${adapay.callback}") private String ADAPAY_CALLBACK_URL; /** * 校验短信验证码 * @param dto */ public void checkVerificationCode(MemberRegisterAndLoginDTO dto) { // 取出缓存中的验证码进行对比,如果缓存中没有,则超时 String captchaCode = redisCache.getCacheObject(CacheConstants.SMS_VERIFICATION_CODE_KEY + dto.getMobileNumber()); if (StringUtils.isEmpty(captchaCode)) { throw new BusinessException(ReturnCodeEnum.CODE_VERIFICATION_CODE_TIMEOUT_ERROR); } // 如果缓存中有,但与实际不一致,则为验证码错误 if (!StringUtils.equals(captchaCode, dto.getVerificationCode())) { throw new BusinessException(ReturnCodeEnum.CODE_VERIFICATION_CODE_ERROR); } } /** * 短信验证码登录注册 * @param dto * @return */ public String memberRegisterAndLogin(MemberRegisterAndLoginDTO dto) { // 校验短信验证码 两种情况不能通过校验,1-验证码错误;2-超时 验证码10分钟有效 checkVerificationCode(dto); String merchantId = ""; return memberRegisterAndLogin(dto.getMobileNumber(), dto.getMerchantId(), dto.getOpenId()); } /** * 公共登陆注册方法 * @param phoneNumber 手机号 * @param merchantId 商户id * @return token返给前端 */ private String memberRegisterAndLogin(String phoneNumber, String merchantId, String openId) { if (StringUtils.isBlank(phoneNumber)) { throw new BusinessException(ReturnCodeEnum.CODE_GET_MOBILE_NUMBER_BY_CODE_ERROR); } // if (Objects.isNull(merchantId)) { // throw new BusinessException(ReturnCodeEnum.CODE_GET_MERCHANT_ID_BY_APP_ID_ERROR); // } // 查询手机号码是否注册过 MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMobileNumberAndMerchantId(phoneNumber, merchantId); if (Objects.isNull(memberBasicInfo)) { // 不存在则新增数据 String memberId = generateNewMemberId(); memberBasicInfo = new MemberBasicInfo(); memberBasicInfo.setStatus(Constants.ONE); memberBasicInfo.setMemberId(memberId); memberBasicInfo.setNickName("会员" + memberId); memberBasicInfo.setMobileNumber(phoneNumber); memberBasicInfo.setMerchantId(Long.valueOf(merchantId)); memberBasicInfo.setOpenId(openId); // 首次新建会员,同时新建会员钱包 MemberWalletInfo memberWalletInfo = MemberWalletInfo.builder().memberId(memberId).build(); MemberTransactionDTO memberTransactionDTO = MemberTransactionDTO.builder() .memberBasicInfo(memberBasicInfo) .memberWalletInfo(memberWalletInfo) .build(); transactionService.createMember(memberTransactionDTO); } else { if (StringUtils.isBlank(memberBasicInfo.getOpenId()) && StringUtils.isNotBlank(openId)) { memberBasicInfo.setOpenId(openId); memberBasicInfoService.updateMemberBasicInfo(memberBasicInfo); } } // 服务器生成token返给前端 String memberToken = JWTUtils.createMemberToken(memberBasicInfo.getMemberId(), memberBasicInfo.getNickName()); // log.info("memToken:{}", memberToken); return memberToken; } private String generateNewMemberId() { while (true) { String memberId = IdUtils.getMemberId(); // 通过memberId查询是否已经存在 MemberVO memberVO = memberBasicInfoService.queryMemberInfoByMemberId(memberId); if (memberVO == null) { return memberId; } } } /** * 微信一键登录 * @param dto */ public String wechatLogin(WechatLoginDTO dto) { // 通过微信传的code获取手机号码 String mobileNumber = wxAppletRemoteService.getMobileNumberByCode(dto.getCode()); if (StringUtils.isBlank(mobileNumber)) { throw new BusinessException(ReturnCodeEnum.CODE_GET_MOBILE_NUMBER_BY_CODE_ERROR); } // 通过appid获取运营商id String merchantId = pileMerchantInfoService.getMerchantIdByAppId(dto.getAppId()); // if (Objects.isNull(merchantId)) { // throw new BusinessException(ReturnCodeEnum.CODE_GET_MERCHANT_ID_BY_APP_ID_ERROR); // } // 通过code获取openId String openId = ""; try { openId = getOpenIdByCode(dto.getOpenIdCode()); } catch (Exception e) { log.error("getOpenIdByCode发生异常", e); } // 查询手机号码是否注册过 return memberRegisterAndLogin(mobileNumber, merchantId, openId); } /** * 获取openId * @param code * @return */ public String getOpenIdByCode(String code) { return wxAppletRemoteService.getOpenIdByCode(code); } /** * 处理用户信息 * * @param memberId * @param dto 用户个人信息 */ public void handleUserInfo(String memberId, MemberRegisterDTO dto) { // 通过用户手机号查询数据库,如果数据库中存在,则更新 // MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMobileNumber(dto.getMobileNumber()); MemberBasicInfo memberBasicInfo = memberBasicInfoService.selectInfoByMemberId(memberId); if (Objects.nonNull(memberBasicInfo)) { if (StringUtils.isNotBlank(dto.getAvatarUrl())) { memberBasicInfo.setAvatarUrl(dto.getAvatarUrl()); } if (StringUtils.isNotBlank(dto.getMobileNumber())) { memberBasicInfo.setMobileNumber(dto.getMobileNumber()); } if (StringUtils.isNotBlank(dto.getNickName())) { memberBasicInfo.setNickName(dto.getNickName()); } memberBasicInfoService.updateMemberBasicInfo(memberBasicInfo); } } /** * 通过memberToken获取用户账户信息 * * @param memberId * @return */ public MemberVO getMemberInfoByMemberId(String memberId) { MemberVO memberVO = memberBasicInfoService.queryMemberInfoByMemberId(memberId); return memberVO; } /** * 查询用户账户余额变动信息 * * @param dto */ public PageResponse getMemberBalanceChanges(UniAppQueryMemberBalanceDTO dto) { // 获取分页信息以及memberId int pageNum = dto.getPageNum() == 0 ? 1 : dto.getPageNum(); int pageSize = dto.getPageSize() == 0 ? 10 : dto.getPageSize(); String memberId = dto.getMemberId(); String type = dto.getType(); if (!StringUtils.equals("1", type) && !StringUtils.equals("2", type)) { type = ""; } // 分页 PageHelper.startPage(pageNum, pageSize); List list = memberBasicInfoService.getMemberBalanceChanges(memberId, type); PageInfo pageInfo = new PageInfo<>(list); for (MemberWalletLogVO walletLogVO : pageInfo.getList()) { String subType = walletLogVO.getSubType(); String subTypeValue = BalanceChangesEnum.getValueByCode(subType); if (StringUtils.isNotBlank(subTypeValue)) { walletLogVO.setSubType(subTypeValue); } // walletLogVO.setTotalAccountAmount(walletLogVO.getPrincipalBalance().add(walletLogVO.getGiftBalance())); } PageResponse pageResponse = PageResponse.builder() .pageSize(pageSize) .pageNum(pageNum) .list(pageInfo.getList()) .pages(pageInfo.getPages()) .total(pageInfo.getTotal()) .build(); return pageResponse; } /** * 用户绑定车牌号 * @param dto */ public void memberBindingCarNo(BindingCarNoDTO dto){ // 校验短信验证码 MemberRegisterAndLoginDTO registerAndLoginDTO = MemberRegisterAndLoginDTO.builder() .mobileNumber(dto.getPhoneNumber()) .verificationCode(dto.getVerificationCode()) .build(); checkVerificationCode(registerAndLoginDTO); // 判断当前车牌号是否已经绑定 MemberPlateNumberRelation relation = new MemberPlateNumberRelation(); relation.setMemberId(dto.getMemberId()); relation.setLicensePlateNumber(dto.getCarNo()); List list = memberPlateNumberRelationService.selectMemberPlateNumberRelationList(relation); if (CollectionUtils.isNotEmpty(list)) { // 不为空说明该用户绑定过此车牌号 throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARNO_HAS_BEEN_BINDING); } relation.setPhoneNumber(dto.getPhoneNumber()); if (StringUtils.isNotBlank(dto.getVinCode())) { // 判断当前vin是否被绑定 MemberPlateNumberRelation memberPlateInfoByVinCode = memberPlateNumberRelationService.getMemberPlateInfoByVinCode(dto.getVinCode()); if (memberPlateInfoByVinCode == null) { throw new BusinessException(ReturnCodeEnum.CODE_THIS_VIN_HAS_BEEN_BINDING); } relation.setVinCode(dto.getVinCode().toUpperCase(Locale.ROOT)); relation.setVinStatus(Constants.ONE); // 1-正常使用 } memberPlateNumberRelationService.insertMemberPlateNumberRelation(relation); } /** * 用户绑定鉴权卡 * @param dto */ public int memberBindCard(BindingCardDTO dto){ // 校验短信验证码 MemberRegisterAndLoginDTO registerAndLoginDTO = MemberRegisterAndLoginDTO.builder() .mobileNumber(dto.getPhoneNumber()) .verificationCode(dto.getVerificationCode()) .build(); checkVerificationCode(registerAndLoginDTO); // 判断当前鉴权卡是否被绑定过 PileAuthCard pileAuthCardInfo = pileAuthCardService.selectCardInfoByLogicCard(dto.getLogicCard()); if (pileAuthCardInfo == null){ // 为空说明没查到此卡信息 throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARD_HAS_NO_INFO); } if (StringUtils.isNotBlank(pileAuthCardInfo.getMemberId())) { // memberId 不为空,说明此卡已被绑定 throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARD_HAS_BEEN_BINDING); } if (!StringUtils.equals(pileAuthCardInfo.getSecretKey(), dto.getSecretKey().toUpperCase(Locale.ROOT))) { // 密钥不一致,不能绑定 throw new BusinessException(ReturnCodeEnum.CODE_SECRET_KEY_NOT_SAME); } PileAuthCard authCard = PileAuthCard.builder() .memberId(dto.getMemberId()) .status("1") // 1-正常使用 .createBy(dto.getMemberId()) .id(pileAuthCardInfo.getId()) .build(); return pileAuthCardService.updatePileAuthCard(authCard); } /** * 用户解绑鉴权卡 * @param dto * @return */ public int memberUnbindCard(BindingCardDTO dto) { // 校验短信验证码 MemberRegisterAndLoginDTO registerAndLoginDTO = MemberRegisterAndLoginDTO.builder() .mobileNumber(dto.getPhoneNumber()) .verificationCode(dto.getVerificationCode()) .build(); // checkVerificationCode(registerAndLoginDTO); // 校验身份信息 PileAuthCard authCard = PileAuthCard.builder() .logicCard(dto.getLogicCard()) .memberId(dto.getMemberId()) .build(); PileAuthCard pileAuthCardInfo = pileAuthCardService.selectPileAuthCardInfo(authCard); if (pileAuthCardInfo == null){ // 为空说明没查到此卡信息 throw new BusinessException(ReturnCodeEnum.CODE_THIS_CARD_HAS_NO_INFO); } // 解绑鉴权卡 return pileAuthCardService.unBindingCard(authCard); } public List queryMemberInvoiceTitles(String memberId) { List resultList = Lists.newArrayList(); List memberInvoiceTitles = memberInvoiceTitleService.selectMemberInvoiceTitleList(memberId); if (CollectionUtils.isEmpty(memberInvoiceTitles)) { return resultList; } for (MemberInvoiceTitle memberInvoiceTitle : memberInvoiceTitles) { String reception = StringUtils.isNotEmpty(memberInvoiceTitle.getEmail()) ? memberInvoiceTitle.getEmail() : memberInvoiceTitle.getPhoneNumber(); resultList.add( InvoiceTitleVO.builder() .titleId(memberInvoiceTitle.getId() + "") .titleName(memberInvoiceTitle.getName()) .titleType(TitleTypeEnum.getLabel(memberInvoiceTitle.getTitleType())) .taxId(memberInvoiceTitle.getTaxId()) .unitAddress(memberInvoiceTitle.getUnitAddress()) .phoneNumber(memberInvoiceTitle.getPhoneNumber()) .email(memberInvoiceTitle.getEmail()) .reception(reception) .bankName(memberInvoiceTitle.getBankName()) .bankAccountNumber(memberInvoiceTitle.getBankAccountNumber()) .defaultFlag(memberInvoiceTitle.getDefaultFlag()) .build() ); } return resultList; } public void createMemberInvoiceTitle(InvoiceTitleDTO dto) { MemberInvoiceTitle title = new MemberInvoiceTitle(); BeanUtils.copyProperties(dto, title); title.setName(dto.getTitleName()); if (StringUtils.isEmail(dto.getReception())) { title.setEmail(dto.getReception()); } else { title.setPhoneNumber(dto.getReception()); } int i = memberInvoiceTitleService.insertMemberInvoiceTitle(title); // log.info("新增{}条发票抬头", i); } public void updateMemberInvoiceTitle(InvoiceTitleDTO dto) { MemberInvoiceTitle title = new MemberInvoiceTitle(); BeanUtils.copyProperties(dto, title); title.setId(Long.valueOf(dto.getTitleId())); title.setName(dto.getTitleName()); if (StringUtils.isEmail(dto.getReception())) { title.setEmail(dto.getReception()); } else { title.setPhoneNumber(dto.getReception()); } int i = memberInvoiceTitleService.updateMemberInvoiceTitle(title); } /** * 删除会员发票抬头 * @param dto */ public void deleteMemberInvoiceTitle(InvoiceTitleDTO dto) { memberInvoiceTitleService.deleteMemberInvoiceTitleById(Long.valueOf(dto.getTitleId())); } public Map rechargeBalance(WeixinPayDTO dto) throws Exception { PaymentScenarioDTO paymentScenarioDTO = new PaymentScenarioDTO(); paymentScenarioDTO.setType(ScenarioEnum.BALANCE.getValue()); paymentScenarioDTO.setMemberId(dto.getMemberId()); dto.setAttach(JSONObject.toJSONString(paymentScenarioDTO)); dto.setDescription("会员充值余额"); return orderService.weixinPayV3(dto); } /** * 使用汇付支付充值余额 * @param dto * @return * @throws Exception */ public Map rechargeBalanceWithAdapay(WeixinPayDTO dto) throws Exception { // 封装对象 CreateAdaPaymentParam createAdaPaymentParam = new CreateAdaPaymentParam(); createAdaPaymentParam.setOrder_no(SnowflakeIdWorker.getSnowflakeId()); createAdaPaymentParam.setPay_amt(AdapayUtil.formatAmount(dto.getAmount())); createAdaPaymentParam.setApp_id(ADAPAY_APP_ID); // 移动到配置文件中 createAdaPaymentParam.setPay_channel("wx_lite"); // todo 如果以后有支付宝等别的渠道,这里需要做修改,判断是什么渠道的请求 createAdaPaymentParam.setGoods_title("余额"); createAdaPaymentParam.setGoods_desc("会员充值余额"); // createAdaPaymentParam.setDescription("充电费用3"); createAdaPaymentParam.setExpend(JSONObject.toJSONString( ImmutableMap.of("open_id", dto.getOpenId()))); //异步通知地址,url为http/https路径,服务器POST回调,URL 上请勿附带参数 createAdaPaymentParam.setNotify_url(ADAPAY_CALLBACK_URL); Map map = Maps.newHashMap(); map.put("type", ScenarioEnum.BALANCE.getValue()); map.put("memberId", dto.getMemberId()); createAdaPaymentParam.setDescription(JSON.toJSONString(map)); try { log.info("创建汇付支付参数:{}", JSONObject.toJSONString(createAdaPaymentParam)); Map response = Payment.create(BeanMap.create(createAdaPaymentParam)); log.info("创建汇付支付参数反参:{}", JSONObject.toJSONString(response)); if (response != null && !response.isEmpty()) { JSONObject jsonObject = JSONObject.parseObject(response.get("expend").toString()); JSONObject pay_info = jsonObject.getJSONObject("pay_info"); Map resultMap = JSONObject.parseObject(pay_info.toJSONString(), new TypeReference>() {}); return resultMap; } } catch (BaseAdaPayException e) { log.error("汇付-获取支付对象发生异常", e); } return null; } /** * 充值订单金额 * @param dto * @throws ParseException */ public void rechargeOrderAmount(RechargeOrderAmountDTO dto) throws ParseException { // 根据memberId查询出当前用户正在充电的 vin启动订单 或 卡启动订单 UniAppQueryOrderDTO orderDTO = new UniAppQueryOrderDTO(); orderDTO.setOrderStatus("4"); // 4-正在充电中 PageResponse pageResponse = orderService.getListByMemberIdAndOrderStatus(dto.getMemberId(), orderDTO); if (pageResponse == null) { return; } List list = (List) pageResponse.getList(); List chargingList = list.stream() .filter(orderVO -> orderVO.getOrderStatus().equals(OrderStatusEnum.IN_THE_CHARGING.getValue())) .collect(Collectors.toList()); for (OrderVO orderVO : chargingList) { if (StringUtils.equals(orderVO.getStartMode(), StartModeEnum.AUTH_CARD.getValue()) || StringUtils.equals(orderVO.getStartMode(), StartModeEnum.OFFLINE_CARD.getValue()) || StringUtils.equals(orderVO.getStartMode(), StartModeEnum.VIN_CODE.getValue())) { // 将充值后的余额计算出来 BigDecimal rechargeAmount = new BigDecimal(dto.getRechargeAmount()); BigDecimal payAmount = orderVO.getPayAmount().add(rechargeAmount); orderVO.setPayAmount(payAmount); // 发送0x41指令更新账户余额 RemoteAccountBalanceUpdateDTO remoteDTO = new RemoteAccountBalanceUpdateDTO(); remoteDTO.setPileSn(orderVO.getPileSn()); remoteDTO.setConnectorCode(orderVO.getConnectorCode()); remoteDTO.setAccountBalance(String.valueOf(orderVO.getPayAmount())); pileRemoteService.remoteAccountBalanceUpdate(remoteDTO); // 将支付金额修改数据库 OrderBasicInfo basicInfo = new OrderBasicInfo(); basicInfo.setId(Long.parseLong(orderVO.getId())); basicInfo.setPayAmount(payAmount); orderBasicInfoService.updateOrderBasicInfo(basicInfo); } } } }