package cc.mrbird.febs.pay.service.impl;
|
|
import cc.mrbird.febs.common.entity.FebsResponse;
|
import cc.mrbird.febs.common.enumerates.DataDictionaryEnum;
|
import cc.mrbird.febs.common.enumerates.FlowTypeEnum;
|
import cc.mrbird.febs.common.enumerates.MoneyFlowTypeEnum;
|
import cc.mrbird.febs.common.properties.XcxProperties;
|
import cc.mrbird.febs.common.utils.*;
|
import cc.mrbird.febs.mall.dto.ApiRechargeWalletDto;
|
import cc.mrbird.febs.mall.dto.RechargeWalletMessageSendDto;
|
import cc.mrbird.febs.mall.entity.*;
|
import cc.mrbird.febs.mall.mapper.*;
|
import cc.mrbird.febs.mall.service.IMallMoneyFlowService;
|
import cc.mrbird.febs.mall.vo.RechargeWalletMessageSendVo;
|
import cc.mrbird.febs.pay.model.*;
|
import cc.mrbird.febs.pay.service.IXcxPayService;
|
import cc.mrbird.febs.pay.util.WechatConfigure;
|
import cc.mrbird.febs.pay.util.WeixinServiceUtil;
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.text.StrFormatter;
|
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
import cn.hutool.http.HttpRequest;
|
import cn.hutool.http.HttpResponse;
|
import cn.hutool.json.JSONObject;
|
import cn.hutool.json.JSONUtil;
|
import com.alibaba.fastjson.JSON;
|
import com.baomidou.dynamic.datasource.toolkit.Base64;
|
import com.baomidou.mybatisplus.extension.exceptions.ApiException;
|
import lombok.RequiredArgsConstructor;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.httpclient.HttpStatus;
|
import org.apache.http.HttpEntity;
|
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.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.http.ResponseEntity;
|
import org.springframework.stereotype.Service;
|
import org.springframework.web.client.RestTemplate;
|
import cn.hutool.core.io.FileUtil;
|
|
import java.io.*;
|
import java.math.BigDecimal;
|
import java.net.*;
|
import java.nio.charset.Charset;
|
import java.util.ArrayList;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
|
@Slf4j
|
@Service
|
@RequiredArgsConstructor
|
public class XcxPayServiceImpl implements IXcxPayService {
|
|
@Autowired
|
private MallOrderInfoMapper mallOrderInfoMapper;
|
@Autowired
|
private MallMemberMapper mallMemberMapper;
|
@Autowired
|
WeixinServiceUtil weixinServiceUtil;
|
@Autowired
|
private DataDictionaryCustomMapper dataDictionaryCustomMapper;
|
@Autowired
|
private MallMoneyFlowMapper mallMoneyFlowMapper;
|
@Autowired
|
private MallMemberWithdrawMapper mallMemberWithdrawMapper;
|
private final IMallMoneyFlowService mallMoneyFlowService;
|
@Autowired
|
RedisUtils redisUtils;
|
|
private final SpringContextHolder springContextHolder;
|
|
private final XcxProperties xcxProperties = SpringContextHolder.getBean(XcxProperties.class);
|
|
@Override
|
public BrandWCPayRequestData startRechargeWallet(ApiRechargeWalletDto apiRechargeWalletDto) throws Exception {
|
BigDecimal unit = new BigDecimal("100");
|
BigDecimal money = new BigDecimal(apiRechargeWalletDto.getAmount().toString());
|
BrandWCPayRequestData payData;
|
String productNames = "小程序充值";
|
MallMember mallMember = mallMemberMapper.selectById(apiRechargeWalletDto.getMemberId());
|
String rechargeNo = "CZ_"+MallUtils.getOrderNum();
|
Boolean debug = xcxProperties.getDebug();
|
String attrStr = "{'rechargeNo':"+rechargeNo+",'memberId':"+mallMember.getId()+"}";
|
if (debug) {
|
payData = weixinServiceUtil.createRechargeWallet("[测试]" + productNames, rechargeNo,
|
1, mallMember.getOpenId(), attrStr);
|
} else {
|
payData = weixinServiceUtil.createRechargeWallet(productNames, rechargeNo,
|
unit.multiply(money).intValue(),mallMember.getOpenId(), attrStr);
|
}
|
mallMoneyFlowService.addMoneyFlow(
|
mallMember.getId(),
|
money,
|
MoneyFlowTypeEnum.RECHARGE.getValue(),
|
rechargeNo,
|
FlowTypeEnum.BALANCE.getValue(),
|
"余额充值",1);
|
return payData;
|
}
|
|
@Override
|
public void rechargeWalletMessageSend(RechargeWalletMessageSendDto info) {
|
RestTemplate restTemplate = new RestTemplate();
|
String url = WechatConfigure.SEND_INFO_URL + redisUtils.get(WechatConfigure.WX_ACCESS_TOKEN_REDIS_KEY);
|
//拼接推送的模版
|
RechargeWalletMessageSendVo orderStateMsgVo = new RechargeWalletMessageSendVo();
|
orderStateMsgVo.setTouser(info.getOpenId());//用户的openId
|
orderStateMsgVo.setTemplate_id(info.getTemplateId());//订阅消息模板id
|
orderStateMsgVo.setPage(info.getPage());
|
Map<String, WxTemplateData> m = new HashMap<>(4);
|
m.put("character_string1", new WxTemplateData(info.getRechargeNo()));
|
m.put("amount3", new WxTemplateData(info.getRechargeAmount()));
|
m.put("amount4", new WxTemplateData(info.getBalance()));
|
m.put("date5", new WxTemplateData(info.getCreateTime()));
|
orderStateMsgVo.setData(m);
|
String s = JSONUtil.toJsonStr(orderStateMsgVo);
|
log.info(s);
|
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, orderStateMsgVo, String.class);
|
log.info(responseEntity.getBody());
|
|
}
|
|
@Override
|
public Boolean memberWithdrawal(MemberWithdrawalDto info) {
|
log.info("后台同意提现申请..."+JSONUtil.toJsonStr(info));
|
boolean flag=false;
|
BigDecimal unit = new BigDecimal("100");
|
BigDecimal money = new BigDecimal(info.getTotalFee().toString());
|
String outTradeNo = info.getOutTradeNo();
|
String openid = info.getOpenid();
|
String desc = info.getDesc();
|
|
MallMember mallMember = mallMemberMapper.selectMemberByOpenId(openid);
|
if(ObjectUtil.isEmpty(mallMember)){
|
return flag;
|
}
|
MallMemberWithdraw mallMemberWithdraw = mallMemberWithdrawMapper.selectByWithDrawNoAndMemberIdAndState(outTradeNo,mallMember.getId(),1);
|
if(ObjectUtil.isEmpty(mallMemberWithdraw)){
|
return flag;
|
}
|
Boolean debug = xcxProperties.getDebug();
|
if (debug) {
|
flag = weixinServiceUtil.comPay("[测试]" + desc, outTradeNo,
|
1, openid);
|
} else {
|
flag = weixinServiceUtil.comPay(desc, outTradeNo,
|
unit.multiply(money).intValue(),openid);
|
}
|
return flag;
|
}
|
|
@Override
|
public FebsResponse getQrCode(WxGenerateQrCodeDto wxGenerateQrCodeDto) {
|
// //这里调用的是上面的获取access_token方法
|
// String access_token = redisUtils.get(WechatConfigure.WX_ACCESS_TOKEN_REDIS_KEY).toString();
|
// String url = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token="+access_token;
|
// String scene = wxGenerateQrCodeDto.getScene();
|
// Map<String, String> param = new HashMap<>();
|
// param.put("scene",scene);
|
// //这里的page如果没有的话可以不写,默认是跳主页,如果写了没有的页面的话,会返回错误信息
|
// param.put("page",wxGenerateQrCodeDto.getPage());
|
// String json = JSON.toJSONString(param);
|
// ByteArrayInputStream inputStream = sendPost(url, json);
|
// try {
|
// System.out.println(inputStream);
|
// //这里判断的是返回的图片还是错误信息,一般错误信息不会大于200
|
// if (inputStream.available() <= 200){
|
// ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
// int i;
|
// byte[] buffer = new byte[200];
|
// while ((i = inputStream.read(buffer)) != -1){
|
// byteArrayOutputStream.write(buffer,0,i);
|
// }
|
// String str = new String(byteArrayOutputStream.toByteArray());
|
// byteArrayOutputStream.close();
|
// //错误信息
|
// com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(str);
|
// if ("41030".equals(jsonObject.getString("errcode"))){
|
// return new FebsResponse().fail().data("所传page页面不存在,或者小程序没有发布");
|
// }else if ("45009".equals(jsonObject.getString("errcode"))){
|
// return new FebsResponse().fail().data("调用分钟频率受限");
|
// }
|
// }
|
// inputStream.close();
|
// }catch (Exception e){
|
// return new FebsResponse().fail().data("获取二维码失败");
|
// }
|
return new FebsResponse().success();
|
}
|
|
@Override
|
public BrandWCPayRequestData startPayment(MallOrderInfo mallOrderInfo) throws Exception {
|
BigDecimal unit = new BigDecimal("100");
|
BigDecimal money = new BigDecimal(mallOrderInfo.getAmount().toString());
|
BrandWCPayRequestData payData;
|
String productNames = getProductNames(mallOrderInfo.getMemberId(), mallOrderInfo.getId());
|
MallMember mallMember = mallMemberMapper.selectById(mallOrderInfo.getMemberId());
|
Boolean debug = xcxProperties.getDebug();
|
if (debug) {
|
payData = weixinServiceUtil.createOrder("[测试]" + productNames, mallOrderInfo.getOrderNo(),
|
1, mallMember.getOpenId(), String.valueOf(mallOrderInfo.getId()));
|
} else {
|
payData = weixinServiceUtil.createOrder(productNames, mallOrderInfo.getOrderNo(),
|
unit.multiply(money).intValue(),mallMember.getOpenId(), String.valueOf(mallOrderInfo.getId()));
|
}
|
mallOrderInfo.setWxOrderNo(payData.getPrepay_id());
|
mallOrderInfoMapper.updateById(mallOrderInfo);
|
return payData;
|
}
|
|
@Override
|
public void pushOrderToAddress(OrderStateDto info) {
|
RestTemplate restTemplate = new RestTemplate();
|
String url = WechatConfigure.SEND_INFO_URL + redisUtils.get(WechatConfigure.WX_ACCESS_TOKEN_REDIS_KEY);
|
//拼接推送的模版
|
OrderStateMsgVo orderStateMsgVo = new OrderStateMsgVo();
|
orderStateMsgVo.setTouser(info.getOpenId());//用户的openId
|
orderStateMsgVo.setTemplate_id(info.getTemplateId());//订阅消息模板id
|
orderStateMsgVo.setPage(info.getPage());
|
Map<String, WxTemplateData> m = new HashMap<>(4);
|
m.put("thing19.DATA", new WxTemplateData(info.getAddressArea()));
|
m.put("phone_number18.DATA", new WxTemplateData(info.getLeaderPhone()));
|
m.put("thing3.DATA", new WxTemplateData(info.getGoodsName()));
|
m.put("thing15.DATA", new WxTemplateData(info.getRemark()));
|
orderStateMsgVo.setData(m);
|
String s = JSONUtil.toJsonStr(orderStateMsgVo);
|
log.info(s);
|
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, orderStateMsgVo, String.class);
|
log.info(responseEntity.getBody());
|
}
|
|
private static final String WXAPPLETURl="https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";
|
|
@Override
|
public void uniformMessageSend(OrderStateDto info) {
|
RestTemplate restTemplate = new RestTemplate();
|
String url = WXAPPLETURl + redisUtils.get(WechatConfigure.WX_ACCESS_TOKEN_REDIS_KEY);
|
//拼接推送的模版
|
/**
|
* {
|
* "touser": "oJkRK4_pWN2kjp75B_G6oGSWawj0",
|
* "template_id": "Yk3_M11Pw5rablln7kQBpasfG9ynRNwD9OKsyvUSoWg",
|
* "page": "index",
|
* "miniprogram_state":"developer",
|
* "lang":"zh_CN",
|
* "data": {
|
* "character_string1": {
|
* "value": "2022081214472943380"
|
* },
|
* "thing16": {
|
* "value": "22704967"
|
* },
|
* "thing9": {
|
* "value": "商品"
|
* },
|
* "thing13": {
|
* "value": "测试"
|
* },
|
* "phrase2": {
|
* "value": "已送达"
|
* }
|
* }
|
* }
|
*/
|
OrderStateMsgVo orderStateMsgVo = new OrderStateMsgVo();
|
orderStateMsgVo.setTouser(info.getOpenId());//用户的openId
|
orderStateMsgVo.setTemplate_id(info.getTemplateId());//订阅消息模板id
|
orderStateMsgVo.setPage(info.getPage());
|
Map<String, WxTemplateData> m = new HashMap<>(4);
|
m.put("character_string2", new WxTemplateData(info.getOrderNo()));
|
m.put("thing11", new WxTemplateData(info.getGoodsName()));
|
m.put("amount1", new WxTemplateData(info.getAmount()));
|
m.put("character_string9", new WxTemplateData(info.getTakeCode()));
|
orderStateMsgVo.setData(m);
|
String s = JSONUtil.toJsonStr(orderStateMsgVo);
|
log.info(s);
|
ResponseEntity<String> responseEntity = restTemplate.postForEntity(url, orderStateMsgVo, String.class);
|
log.info(responseEntity.getBody());
|
}
|
|
@Override
|
public List<String> getTemplateId() {
|
List<String> wxTemplates = new ArrayList<>();
|
List<DataDictionaryCustom> wxTemplateList = dataDictionaryCustomMapper.selectDicByType(DataDictionaryEnum.WX_TEMPLATE_ID_THREE.getType());
|
if(CollUtil.isNotEmpty(wxTemplateList)){
|
for(DataDictionaryCustom dic : wxTemplateList){
|
wxTemplates.add(dic.getValue());
|
}
|
}
|
return wxTemplates;
|
}
|
|
@Autowired
|
private MallGoodsMapper mallGoodsMapper;
|
@Autowired
|
private MallTeamLeaderMapper mallTeamLeaderMapper;
|
|
@Override
|
public FebsResponse generateQrCode(WxGenerateQrCodeDto wxGenerateQrCodeDto) {
|
Integer type = wxGenerateQrCodeDto.getType();
|
if(1 == type){
|
long goodsId = StrUtil.isBlank(wxGenerateQrCodeDto.getTypeParam()) ? 0L : Long.parseLong(wxGenerateQrCodeDto.getTypeParam());
|
MallGoods mallGoods = mallGoodsMapper.selectById(goodsId);
|
if(ObjectUtil.isNotNull(mallGoods)){
|
String wxCodeImg = mallGoods.getWxCodeImg();
|
if(StrUtil.isNotBlank(wxCodeImg)){
|
return new FebsResponse().success().data(wxCodeImg);
|
}
|
}
|
}
|
if(2 == type){
|
String uniqueCode = wxGenerateQrCodeDto.getTypeParam();
|
MallTeamLeader mallTeamLeader = mallTeamLeaderMapper.selectLeaderByUniqueCode(uniqueCode);
|
if(ObjectUtil.isNotNull(mallTeamLeader)){
|
String wxCodeImg = mallTeamLeader.getWxCodeImg();
|
if(StrUtil.isNotBlank(wxCodeImg)){
|
return new FebsResponse().success().data(wxCodeImg);
|
}
|
}
|
}
|
|
String randomNum = MallUtils.getRandomNum(5);
|
String imgName="/user_" + randomNum + "_acode_1.jpg";
|
String codeImgPath = generateAcode(wxGenerateQrCodeDto.getScene(), wxGenerateQrCodeDto.getPage(), imgName, "400px", null);
|
if(1 == type){
|
long goodsId = StrUtil.isBlank(wxGenerateQrCodeDto.getTypeParam()) ? 0L : Long.parseLong(wxGenerateQrCodeDto.getTypeParam());
|
MallGoods mallGoods = mallGoodsMapper.selectById(goodsId);
|
mallGoods.setWxCodeImg(codeImgPath);
|
mallGoodsMapper.updateById(mallGoods);
|
}
|
if(2 == type){
|
String uniqueCode = wxGenerateQrCodeDto.getTypeParam();
|
MallTeamLeader mallTeamLeader = mallTeamLeaderMapper.selectLeaderByUniqueCode(uniqueCode);
|
mallTeamLeader.setWxCodeImg(codeImgPath);
|
mallTeamLeaderMapper.updateById(mallTeamLeader);
|
}
|
return new FebsResponse().success().data(codeImgPath);
|
}
|
|
public static ByteArrayInputStream sendPost(String URL, String json) {
|
InputStream inputStream = null;
|
ByteArrayInputStream byteArrayInputStream = null;
|
// 创建默认的httpClient实例.
|
CloseableHttpClient httpclient = HttpClients.createDefault();
|
// 创建httppost
|
HttpPost httppost = new HttpPost(URL);
|
httppost.addHeader("Content-type", "application/json; charset=utf-8");
|
httppost.setHeader("Accept", "application/json");
|
try {
|
StringEntity s = new StringEntity(json, Charset.forName("UTF-8"));
|
s.setContentEncoding("UTF-8");
|
httppost.setEntity(s);
|
org.apache.http.HttpResponse response = httpclient.execute(httppost);
|
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
|
// 获取相应实体
|
HttpEntity entity = response.getEntity();
|
inputStream = entity.getContent();
|
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
// 创建一个Buffer字符串
|
byte[] buffer = new byte[1024];
|
// 每次读取的字符串长度,如果为-1,代表全部读取完毕
|
int len = 0;
|
// 使用一个输入流从buffer里把数据读取出来
|
while ((len = inputStream.read(buffer)) != -1) {
|
// 用输出流往buffer里写入数据,中间参数代表从哪个位置开始读,len代表读取的长度
|
outStream.write(buffer, 0, len);
|
}
|
// 关闭输入流
|
inputStream.close();
|
// 把outStream里的数据写入内存
|
byteArrayInputStream = new ByteArrayInputStream(outStream.toByteArray());
|
}
|
} catch (Exception e) {
|
e.printStackTrace();
|
} finally {
|
// 关闭连接,释放资源
|
try {
|
httpclient.close();
|
} catch (IOException e) {
|
e.printStackTrace();
|
}
|
}
|
return byteArrayInputStream;
|
}
|
|
|
/**
|
* 生成小程序码
|
* @param scene 参数
|
* @param path 跳转路径
|
* @param imgName 图片唯一名称
|
* @return
|
*/
|
//图片上传路径
|
public static final String IMG_UPLOAD_PATH="/mnt/sdc/webresource/groupbuy/wxcode";
|
public String generateAcode(String scene,String path,String imgName,String width, Integer type){
|
String urlPrefix="https://hwfile.csxuncong.com/groupbuy/wxcode";
|
String imgPath=IMG_UPLOAD_PATH+imgName;
|
if(!FileUtil.exist(imgPath)){
|
|
cn.hutool.json.JSONObject obj = JSONUtil.createObj();
|
//调用二维码接口
|
String url = null;
|
if (type == null) {
|
// 该接口无数量限制,但是 scene 传参最大字符长度为32个字符
|
url = StrFormatter.format("https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token={}",redisUtils.get(WechatConfigure.WX_ACCESS_TOKEN_REDIS_KEY).toString());
|
obj.set("scene", scene);
|
obj.set("page", path);
|
} else {
|
// 该接口存在数量限制, 总共可生成10w个, 但参数是接在path后面
|
url = StrFormatter.format("https://api.weixin.qq.com/wxa/getwxacode?access_token={}", redisUtils.get(WechatConfigure.WX_ACCESS_TOKEN_REDIS_KEY).toString());
|
obj.set("page", path + "?" + scene );
|
}
|
|
//最小 280px,最大 1280px
|
obj.set("width", width);
|
obj.set("auto_color", false);
|
cn.hutool.json.JSONObject obj2 = JSONUtil.createObj();
|
obj2.set("r", 0);
|
obj2.set("g", 0);
|
obj2.set("b", 0);
|
obj.set("line_color", obj2);
|
//是否需要透明底色,为 true 时,生成透明底色的小程序码
|
obj.set("is_hyaline", false);
|
try {
|
HttpResponse execute = HttpRequest.post(url).body(obj.toString(), "application/json").execute();
|
InputStream inputStream = execute.bodyStream();
|
File file = new File(imgPath);
|
FileUtil.writeFromStream(inputStream, file);
|
long uploadUrl = FileUtil.size(file);
|
//小于10kb重新生成
|
if(uploadUrl<=10240){
|
log.error("生成微信小程序码失败:图片大小异常:{}",uploadUrl);
|
return null;
|
}
|
} catch (Exception e) {
|
log.error("生成微信小程序码失败",e);
|
return null;
|
}
|
|
}else {
|
//判断文件是否正常 不正常 删除
|
File file = new File(imgPath);
|
long uploadUrl = FileUtil.size(file);
|
if(uploadUrl<=10240){
|
FileUtil.del(file);
|
return null;
|
}
|
}
|
log.debug("生成微信小程序码成功,路径:" + imgPath);
|
return urlPrefix+"/"+imgName;
|
}
|
|
/**
|
* 根据用户ID和订单ID获取所购买商品名称
|
* @return 所含商品名称(多个以","隔开)
|
*/
|
public String getProductNames(Long memberId, Long orderId) {
|
MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectOrderByMemberIdAndId(memberId, orderId);
|
List<MallOrderItem> details = mallOrderInfo.getItems();
|
if (CollectionUtils.isEmpty(details)) {
|
return "";
|
}
|
StringBuffer productNameBuffer = new StringBuffer();
|
Integer maxLength = 30;
|
for (int i = 0; i< details.size(); i++) {
|
MallOrderItem mallOrderItem = details.get(i);
|
String goodsName = mallOrderItem.getGoodsName();
|
if (goodsName == null) {
|
continue;
|
}
|
if (i == 0 && goodsName.length() > maxLength) {
|
productNameBuffer.append(goodsName.substring(0, maxLength) + "...");
|
break;
|
}
|
if ((productNameBuffer.length() + goodsName.length()) > maxLength) {
|
productNameBuffer.append("等");
|
break;
|
}
|
productNameBuffer.append(goodsName + ",");
|
}
|
String productNames = productNameBuffer.toString();
|
if (productNames.endsWith(",")) {
|
productNames = productNames.substring(0, productNames.length() - 1);
|
}
|
if (productNames.endsWith(",等")) {
|
productNames = productNames.substring(0, productNames.length() - 2) + "等";
|
}
|
return productNames;
|
}
|
}
|