| @@ -0,0 +1,2 @@ | |||
| ALTER TABLE wx_pay_account_bill ADD COLUMN pay_channel INT(3) COMMENT '支付通道'; | |||
| ALTER TABLE wx_pay_account_bill ADD COLUMN pay_config VARCHAR(300) COMMENT '支付配置'; | |||
| @@ -11,11 +11,14 @@ import com.iformall.domain.po.WxBillAction; | |||
| import com.iformall.domain.po.WxFlowModel; | |||
| import com.iformall.domain.po.WxMerchant; | |||
| import com.iformall.domain.po.WxMerchantBUser; | |||
| import com.iformall.domain.po.WxPayAccountBill; | |||
| import com.iformall.domain.po.WxUserDataRule; | |||
| import com.iformall.domain.po.base.WxBillBaseEntity; | |||
| import com.iformall.domain.vo.WxBillAll; | |||
| import com.iformall.domain.vo.WxBillHotNotify; | |||
| import com.iformall.enums.EnumBillAllType; | |||
| import com.iformall.enums.EnumBillOweOrNearType; | |||
| import com.iformall.enums.EnumBillPayChannel; | |||
| import com.iformall.enums.EnumBillUpdateType; | |||
| import com.iformall.enums.EnumFilterSettle; | |||
| import com.iformall.enums.EnumFlowKey; | |||
| @@ -27,7 +30,9 @@ import com.iformall.service.WxBillAllService; | |||
| import com.iformall.service.WxBillSettleService; | |||
| import com.iformall.service.WxFlowService; | |||
| import com.iformall.service.WxMerchantService; | |||
| import com.iformall.service.WxPayAccountBillService; | |||
| import com.iformall.service.helper.WxBillAllHelper; | |||
| import com.iformall.service.payBill.PayBillServiceFactory; | |||
| import com.iformall.utils.Constant; | |||
| import io.swagger.annotations.Api; | |||
| @@ -70,6 +75,12 @@ public class WxBillController extends BaseController { | |||
| @Autowired | |||
| private WxBillActionService wxBillActionService; | |||
| @Autowired | |||
| private PayBillServiceFactory payBillServiceFactory; | |||
| @Autowired | |||
| WxPayAccountBillService wxPayAccountBillService; | |||
| /** | |||
| * 账单类型 | |||
| @@ -214,25 +225,54 @@ public class WxBillController extends BaseController { | |||
| return new ResultData(result); | |||
| } | |||
| @ApiOperation("支付") | |||
| //必要的参数是这三个,其他根据每个支付方式来传参数 | |||
| @ApiOperation(value = "支付", notes = "{\"billTypeValue\":\"string\",\"billId\":\"string\",\"payMoney\":\"string\"}") | |||
| @PostMapping("payBill") | |||
| public ResultData payBill(@RequestBody WxBillPayDTO payDto) { | |||
| if (null == payDto.getBillTypeValue() || null == payDto.getId() || StringUtils.isBlank(payDto.getAddpay())) { | |||
| public ResultData payBill(@RequestBody Map<String, String> paramMap) { | |||
| String billTypeValueStr = paramMap.get("billTypeValue"); | |||
| String billIdStr = paramMap.get("billId"); | |||
| String payMoney = paramMap.get("payMoney"); | |||
| if (StringUtils.isBlank(billTypeValueStr) || StringUtils.isBlank(billIdStr) || StringUtils.isBlank(payMoney) ) { | |||
| return new ResultData(Result.ERROR,"参数错误"); | |||
| } | |||
| // EnumBillAllType btype; | |||
| // if (billTypeValue.intValue() == Constant.bill_all_type_manage_fee) { | |||
| // btype = EnumBillAllType.RENT_BUSSINESS_MANAGE; | |||
| // }else { | |||
| // btype = EnumBillAllType.getEnum(billTypeValue); | |||
| // if (null == btype) { | |||
| // return new ResultData(Result.ERROR,"分类非法"); | |||
| // } | |||
| // } | |||
| // wxMerchant.setId(this.getLoginBUser().getMerchantId()); | |||
| // wxMerchant.updateTenantInfo(getTenantInfo()); | |||
| // return new ResultData(billAllHelper.getBillList(btype, wxMerchant,pageNum,pageSize)); | |||
| return null; | |||
| Integer billTypeValue = Integer.parseInt(billTypeValueStr); | |||
| Long billId = Long.parseLong(billIdStr); | |||
| EnumBillAllType btype; | |||
| if (billTypeValue.intValue() == Constant.bill_all_type_manage_fee) { | |||
| btype = EnumBillAllType.RENT_BUSSINESS_MANAGE; | |||
| }else { | |||
| btype = EnumBillAllType.getEnum(billTypeValue); | |||
| if (null == btype) { | |||
| return new ResultData(Result.ERROR,"分类非法"); | |||
| } | |||
| } | |||
| WxMerchant wxMerchant = new WxMerchant(); | |||
| wxMerchant.setId(this.getLoginBUser().getMerchantId()); | |||
| wxMerchant.updateTenantInfo(getTenantInfo()); | |||
| WxBillBaseEntity billdetail = billAllHelper.getBillDetail(btype, wxMerchant,billId); | |||
| if (null == billdetail) { | |||
| return new ResultData(Result.ERROR,"账单支付未查询到"); | |||
| } | |||
| WxPayAccountBill wxPayAccountBill = wxPayAccountBillService.getByTenantInfo(wxMerchant); | |||
| if (null == wxPayAccountBill || null == wxPayAccountBill.getPayChannel()) { | |||
| return new ResultData(Result.ERROR,"账单支付配置错误,请联系管理员"); | |||
| } | |||
| try { | |||
| Object result = payBillServiceFactory.getPayAdapterService(wxPayAccountBill.getPayChannel()) | |||
| .createPay(wxPayAccountBill,billdetail,Double.parseDouble(payMoney), paramMap); | |||
| if (null == result) { | |||
| return new ResultData(Result.ERROR,"账单支付错误,请联系管理员"); | |||
| } | |||
| Map retMap = new HashMap(); | |||
| retMap.put("payChannel", wxPayAccountBill.getPayChannel()); | |||
| retMap.put("payChannelName", EnumBillPayChannel.getEnum(wxPayAccountBill.getPayChannel()).getMessage()); | |||
| retMap.put("result", result); | |||
| return new ResultData(retMap); | |||
| }catch(Exception e) { | |||
| logger.error("payBill error.",e); | |||
| return new ResultData(Result.ERROR,"账单支付错误:"+e.getMessage()); | |||
| } | |||
| } | |||
| @@ -1,5 +1,8 @@ | |||
| package com.iformall.domain.po; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils; | |||
| import com.baomidou.mybatisplus.annotation.TableName; | |||
| import com.iformall.domain.po.base.TenantEntity; | |||
| import lombok.Data; | |||
| @@ -26,5 +29,31 @@ public class WxPayAccountBill extends TenantEntity { | |||
| @io.swagger.annotations.ApiModelProperty(value="手续费费率",name="serviceChargeRate") | |||
| private Integer serviceChargeRate; | |||
| @io.swagger.annotations.ApiModelProperty(value="支付渠道 EnumBillPayChannel",name="payChannel") | |||
| private Integer payChannel; | |||
| @io.swagger.annotations.ApiModelProperty(value="支付配置",name="payConfig") | |||
| private String payConfig; | |||
| public String getPayConfigString(String key) { | |||
| if (StringUtils.isNotBlank(payConfig)) { | |||
| JSONObject pc = JSON.parseObject(payConfig); | |||
| if (null != pc) { | |||
| return pc.getString(key); | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| public Integer getPayConfigInteger(String key) { | |||
| if (StringUtils.isNotBlank(payConfig)) { | |||
| JSONObject pc = JSON.parseObject(payConfig); | |||
| if (null != pc) { | |||
| return pc.getInteger(key); | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| } | |||
| @@ -0,0 +1,33 @@ | |||
| package com.iformall.enums; | |||
| /** | |||
| */ | |||
| public enum EnumBillPayChannel { | |||
| WX_MINI_PROGRAM(1, "微信小程序支付"), | |||
| BANK_JIANSHE_MA(2, "建设银行收款码"); | |||
| public static EnumBillPayChannel getEnum(Integer code) { | |||
| for (EnumBillPayChannel value : values()) { | |||
| if (value.getCode().equals(code)) { | |||
| return value; | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| private Integer code; | |||
| private String message; | |||
| EnumBillPayChannel(Integer code, String message) { | |||
| this.code = code; | |||
| this.message = message; | |||
| } | |||
| public Integer getCode() { | |||
| return code; | |||
| } | |||
| public String getMessage() { | |||
| return message; | |||
| } | |||
| } | |||
| @@ -0,0 +1,14 @@ | |||
| package com.iformall.service.payBill; | |||
| import java.util.Map; | |||
| import com.iformall.domain.po.WxPayAccountBill; | |||
| import com.iformall.domain.po.base.WxBillBaseEntity; | |||
| public interface PayBillAdapterService { | |||
| //发起支付,有可能是码,小程序支付,或者其他支付 | |||
| public Object createPay(WxPayAccountBill wxPayAccountBill,WxBillBaseEntity billdetail,Double money,Map<String,String> params); | |||
| //支付通知处理 | |||
| } | |||
| @@ -0,0 +1,78 @@ | |||
| package com.iformall.service.payBill; | |||
| import com.iformall.common.ErrorCode; | |||
| import com.iformall.enums.EnumAppPlat; | |||
| import com.iformall.enums.EnumBillPayChannel; | |||
| import com.iformall.enums.EnumBillPayWay; | |||
| import com.iformall.enums.EnumPayVersion; | |||
| import com.iformall.enums.EnumPayWay; | |||
| import com.iformall.exception.MallinkException; | |||
| import com.iformall.service.pay.service.cashout.CashOutAdapterService; | |||
| import com.iformall.service.pay.service.cashout.wx.sft.WxCashOutSFTAdapterService; | |||
| import com.iformall.service.pay.service.cashout.wx.v2.WxCashOutQYFKAdapterService; | |||
| import com.iformall.service.pay.service.fee.ServiceFeeAdapterService; | |||
| import com.iformall.service.pay.service.fee.TtServiceFeeService; | |||
| import com.iformall.service.pay.service.fee.WxServiceFeeService; | |||
| import com.iformall.service.pay.service.pay.CDrivingPayService; | |||
| import com.iformall.service.pay.service.pay.CPassivePayService; | |||
| import com.iformall.service.pay.service.pay.PayAdapterService; | |||
| import com.iformall.service.pay.service.pay.douyin.v2.miniApp.TtMiniAppPayAdapterService; | |||
| import com.iformall.service.pay.service.pay.douyin.v3.open.TtOpenPayAdapterService; | |||
| import com.iformall.service.pay.service.pay.wx.sft.h5.WxH5PaySFTService; | |||
| import com.iformall.service.pay.service.pay.wx.sft.miniApp.appPay.WxMiniAppPaySFTAdapterService; | |||
| import com.iformall.service.pay.service.pay.wx.v2.h5.WxH5PayService; | |||
| import com.iformall.service.pay.service.pay.wx.v2.miniApp.appPay.WxMiniAppPayAdapterService; | |||
| import com.iformall.service.pay.service.pay.wx.v2.miniApp.maPay.WxMiniMaPayAdapterService; | |||
| import com.iformall.service.pay.service.pay.wx.v3.miniApp.appPay.WxMiniAppPayV3AdapterService; | |||
| import com.iformall.service.pay.service.refund.RefundPayAdapterService; | |||
| import com.iformall.service.pay.service.refund.douyin.v2.TtRefundAdapterService; | |||
| import com.iformall.service.pay.service.refund.douyin.v3.TtOpenRefundAdapterService; | |||
| import com.iformall.service.pay.service.refund.wx.v2.WxRefundAdapterService; | |||
| import com.iformall.service.pay.service.refund.wx.v3.WxRefundV3AdapterService; | |||
| import com.iformall.service.pay.service.share.PayShareAdapterService; | |||
| import com.iformall.service.pay.service.share.douyin.v2.TtPayShareService; | |||
| import com.iformall.service.pay.service.share.douyin.v3.TtOpenShareService; | |||
| import com.iformall.service.pay.service.share.wx.sft.WxPayShareSFTService; | |||
| import com.iformall.service.pay.service.share.wx.v2.WxPayShareService; | |||
| import com.iformall.service.pay.service.share.wx.v3.WxPayShareV3Service; | |||
| import com.iformall.service.payBill.impl.JianHangMaServiceImpl; | |||
| import com.iformall.service.payBill.impl.WxMiniProgramServiceImpl; | |||
| import org.springframework.beans.factory.annotation.Autowired; | |||
| import org.springframework.stereotype.Service; | |||
| import java.util.Map; | |||
| import java.util.concurrent.ConcurrentHashMap; | |||
| /** | |||
| * 支付方式工厂 | |||
| * @author alascor | |||
| */ | |||
| @Service | |||
| public class PayBillServiceFactory { | |||
| private Map<String,PayBillAdapterService> serviceMap = null; | |||
| @Autowired | |||
| JianHangMaServiceImpl jianHangMaService; | |||
| @Autowired | |||
| WxMiniProgramServiceImpl wxMiniProgramService; | |||
| private Map<String,PayBillAdapterService> getServiceMap() { | |||
| if (null == serviceMap) { | |||
| serviceMap = new ConcurrentHashMap<String,PayBillAdapterService>(); | |||
| serviceMap.put(EnumBillPayChannel.BANK_JIANSHE_MA.getCode()+"", jianHangMaService); | |||
| serviceMap.put(EnumBillPayChannel.WX_MINI_PROGRAM.getCode()+"", wxMiniProgramService); | |||
| } | |||
| return serviceMap; | |||
| } | |||
| public PayBillAdapterService getPayAdapterService(Integer type) throws MallinkException{ | |||
| PayBillAdapterService service = getServiceMap().get(type+""); | |||
| if (null == service) { | |||
| throw new MallinkException(ErrorCode.SYS_SERVER_ERROR.getCode(),"payChannel["+type+"] 支付service未找到"); | |||
| } | |||
| return service; | |||
| } | |||
| } | |||
| @@ -0,0 +1,79 @@ | |||
| package com.iformall.service.payBill.impl; | |||
| import java.io.UnsupportedEncodingException; | |||
| import java.net.URLDecoder; | |||
| import java.net.URLEncoder; | |||
| import java.util.Date; | |||
| import java.util.Map; | |||
| import org.apache.commons.codec.digest.DigestUtils; | |||
| import org.springframework.stereotype.Service; | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.alibaba.fastjson.JSONObject; | |||
| import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils; | |||
| import com.iformall.domain.po.WxPayAccountBill; | |||
| import com.iformall.domain.po.base.WxBillBaseEntity; | |||
| import com.iformall.service.payBill.PayBillAdapterService; | |||
| import com.iformall.service.payBill.impl.entity.JianHangMaRequest; | |||
| import com.iformall.utils.DateUtils; | |||
| import com.iformall.utils.HttpUtil; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| @Slf4j | |||
| @Service | |||
| public class JianHangMaServiceImpl implements PayBillAdapterService { | |||
| private static final String url = "https://ibsbjstar.ccb.com.cn/CCBIS/ccbMain?CCB_IBSVersion=V6"; | |||
| //建行动态二维码接口 | |||
| @Override | |||
| public Object createPay(WxPayAccountBill wxPayAccountBill,WxBillBaseEntity billdetail,Double money,Map<String, String> params) { | |||
| JianHangMaRequest request = new JianHangMaRequest(); | |||
| request.setMERCHANTID(wxPayAccountBill.getPayConfigString("MERCHANTID")); | |||
| request.setPOSID(wxPayAccountBill.getPayConfigString("POSID")); | |||
| request.setBRANCHID(wxPayAccountBill.getPayConfigString("BRANCHID")); | |||
| request.setORDERID(billdetail.getBillType()+"_"+billdetail.getId()); | |||
| request.setPAYMENT(money); | |||
| try { | |||
| request.setREMARK1(URLEncoder.encode(billdetail.getBillTypeName(),"utf-8")); | |||
| } catch (UnsupportedEncodingException e) { | |||
| log.error("JianHangMaServiceImpl createPay setREMARK1 error.",e); | |||
| } | |||
| request.setTIMEOUT(DateUtils.date2String(DateUtils.getSecondsTimeAfter(10*60, new Date()), DateUtils.DATE_PATTERN_ALL_NOSPACE)); | |||
| try { | |||
| request.setMAC(DigestUtils.md5Hex(request.toMacString().getBytes("UTF-8"))); | |||
| } catch (UnsupportedEncodingException e) { | |||
| log.error("JianHangMaServiceImpl createPay setMAC error.",e); | |||
| return null; | |||
| } | |||
| String full_url = url + "&"+request.toMacString()+"&MAC="+request.getMAC(); | |||
| String response = HttpUtil.doPost(full_url, null); | |||
| log.debug("url:"+full_url+">>>>reponse:"+response); | |||
| if (StringUtils.isBlank(response)) { | |||
| return null; | |||
| } | |||
| JSONObject rb = JSON.parseObject(response); | |||
| if ("true".equals(rb.getString("SUCCESS"))) { | |||
| String payurl = rb.getString("PAYURL"); | |||
| String qrresponse = HttpUtil.doPost(payurl, null); | |||
| log.debug("url:"+payurl+">>>>qrreponse:"+qrresponse); | |||
| if (StringUtils.isBlank(qrresponse)) { | |||
| return null; | |||
| } | |||
| JSONObject qb = JSON.parseObject(qrresponse); | |||
| if ("true".equals(qb.getString("SUCCESS"))) { | |||
| String qrurl = qb.getString("QRURL"); | |||
| try { | |||
| return URLDecoder.decode(qrurl, "utf-8"); | |||
| } catch (UnsupportedEncodingException e) { | |||
| log.error("JianHangMaServiceImpl createPay decode error.",e); | |||
| return null; | |||
| } | |||
| } | |||
| } | |||
| return null; | |||
| } | |||
| } | |||
| @@ -0,0 +1,22 @@ | |||
| package com.iformall.service.payBill.impl; | |||
| import java.util.Map; | |||
| import org.springframework.stereotype.Service; | |||
| import com.iformall.domain.po.WxPayAccountBill; | |||
| import com.iformall.domain.po.base.WxBillBaseEntity; | |||
| import com.iformall.service.payBill.PayBillAdapterService; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| @Slf4j | |||
| @Service | |||
| public class WxMiniProgramServiceImpl implements PayBillAdapterService { | |||
| @Override | |||
| public Object createPay(WxPayAccountBill wxPayAccountBill,WxBillBaseEntity billdetail,Double money,Map<String, String> params) { | |||
| return null; | |||
| } | |||
| } | |||
| @@ -0,0 +1,47 @@ | |||
| package com.iformall.service.payBill.impl.entity; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import lombok.Data; | |||
| @Data | |||
| public class JianHangMaRequest { | |||
| //商户代码 CHAR(15) 由建行统一分配 | |||
| private String MERCHANTID; | |||
| //商户柜台代码 CHAR(9) 由建行统一分配 | |||
| private String POSID; | |||
| //分行代码 CHAR(9) 由建行统一指定 | |||
| private String BRANCHID; | |||
| //定单号 CHAR(30) 由商户提供,最长30位 | |||
| private String ORDERID; | |||
| //付款金额 NUMBER(16,2) | |||
| private Double PAYMENT; | |||
| //币种 CHAR(2) 缺省为01-人民币 | |||
| private String CURCODE = "01"; | |||
| //备注1 CHAR(30) 商户自定义备注信息使用,可在对账单中显示 中文需使用escape编码 | |||
| private String REMARK1; | |||
| //备注2 CHAR(30) 商户自定义备注信息使用,可在对账单中显示 中文需使用escape编码 | |||
| private String REMARK2; | |||
| //交易码 CHAR(6) 由建行统一分配为530550 | |||
| private String TXCODE = "530550"; | |||
| /** | |||
| * 返回类型 CHAR(6) | |||
| * 0或空:返回二维码页面,只支持建行龙支付; | |||
| 1:返回JSON格式【二维码信息串】,只支持建行龙支付; | |||
| 2:返回聚合扫码二维码页面; | |||
| 3:返回聚合扫码JSON 格式【二维码信息串】 | |||
| 聚合扫码只能上送2或3 4:返回聚合银联二维码信息串 | |||
| */ | |||
| private String RETURNTYPE = "3"; | |||
| //订单超时时间 CHAR(14) YYYYMMDDHHMMSS 如:20120214143005 | |||
| private String TIMEOUT; | |||
| //MAC校验域 CHAR(32) 采用标准MD5算法,由商户实现 | |||
| private String MAC; | |||
| public String toMacString() { | |||
| return "MERCHANTID="+this.MERCHANTID+"&POSID="+this.POSID+"&BRANCHID="+this.BRANCHID+"&ORDERID="+this.ORDERID | |||
| +"&PAYMENT="+this.PAYMENT+"&CURCODE="+this.CURCODE+"&REMARK1="+this.REMARK1+"&REMARK2="+StringUtils.trimToEmpty(this.REMARK2) | |||
| +"&TXCODE="+this.TXCODE+"&RETURNTYPE="+this.RETURNTYPE+"&TIMEOUT="+this.TIMEOUT; | |||
| } | |||
| } | |||
| @@ -121,16 +121,18 @@ public class HttpUtil { | |||
| HttpPost request = new HttpPost(); | |||
| request.setURI(new URI(url)); | |||
| //设置参数 | |||
| List<NameValuePair> nvps = new ArrayList<NameValuePair>(); | |||
| for (Iterator iter = params.keySet().iterator(); iter.hasNext();) { | |||
| String name = (String) iter.next(); | |||
| String value = String.valueOf(params.get(name)); | |||
| nvps.add(new BasicNameValuePair(name, value)); | |||
| //System.out.println(name +"-"+value); | |||
| if (null != params) { | |||
| //设置参数 | |||
| List<NameValuePair> nvps = new ArrayList<NameValuePair>(); | |||
| for (Iterator iter = params.keySet().iterator(); iter.hasNext();) { | |||
| String name = (String) iter.next(); | |||
| String value = String.valueOf(params.get(name)); | |||
| nvps.add(new BasicNameValuePair(name, value)); | |||
| //System.out.println(name +"-"+value); | |||
| } | |||
| request.setEntity(new UrlEncodedFormEntity(nvps,HTTP.UTF_8)); | |||
| } | |||
| request.setEntity(new UrlEncodedFormEntity(nvps,HTTP.UTF_8)); | |||
| HttpResponse response = client.execute(request); | |||
| int code = response.getStatusLine().getStatusCode(); | |||
| @@ -156,7 +158,7 @@ public class HttpUtil { | |||
| } | |||
| } | |||
| catch(Exception e){ | |||
| logger.error(e.getMessage()); | |||
| logger.error(e.getMessage(),e); | |||
| return null; | |||
| } | |||
| @@ -10,10 +10,13 @@ | |||
| <result column="social_credit_code" jdbcType="VARCHAR" property="socialCreditCode"/> | |||
| <result column="bank_name" jdbcType="VARCHAR" property="bankName"/> | |||
| <result column="service_charge_rate" property="serviceChargeRate"/> | |||
| <result column="pay_channel" property="payChannel"/> | |||
| <result column="pay_config" property="payConfig"/> | |||
| </resultMap> | |||
| <sql id="allColumns"> | |||
| `id`,`tenant_id`,`parent_tenant_id`,`bank_account_name`,`bank_card_id`,`social_credit_code`,`bank_name`,`service_charge_rate` | |||
| `id`,`tenant_id`,`parent_tenant_id`,`bank_account_name`,`bank_card_id`,`social_credit_code`,`bank_name`, | |||
| `service_charge_rate`,`pay_channel`,`pay_config` | |||
| </sql> | |||
| <sql id="dynamicWhereConditions"> | |||