微信缴费,下单账号与支付账微信号与手机号不一致致怎么办

如何避免订单重复支付? - PMCAFF产品经理社区 - 微信公众号文章
&如何避免订单重复支付?
如何避免订单重复支付?
日08时20分来源:
咖友提问: 如何设计避免订单出现重复支付的逻辑?
问题补充:假设有这么一种情况:
订单已下单成功并且正处于支付页面,用户调起支付网关进行支付。支付成功了一次,但是由于某种情况导致未接收到银行返回的【支付成功】等信号,系统此时还是认为未支付成功。用户此时又支付了一次并且成功了。
如果用户出现了2次支付并且都成功了,后台逻辑退款这一块如何设计?
是否可以避免这种情况的发生?如果可以怎么去避免呢。
来自 @妖之皇 的回答:
一、后台设计逻辑:
1、参与的主体:
电商系统;
网银或者第三方支付平台;
电商用的结算平台(如:商户支付宝和商户翼支付)
2、设计的主要流程:
电商系统调起网关支付,订单跳转到网银或者第三方支付平台中进行实际支付,这时订单中包含的信息是由电商用的结算平台先生成的一个支付订单信息(这个支付信息包含与电商系统与网银或者第三方支付平台的关联);用户在网银或者第三方支付平台中进行实际支付(这个支付交互是网银或者第三方支付平台与结算平台的交互),成功之后才是结算平台反馈支付信息给电商系统。下列图中:
①是用户调起网关支付,订单跳转到网银或者第三方支付平台中进行实际支付;
②是用户支付成功后,订单反馈至电商系统。
现在出现重复付款的问题就是出现在中的网银或者第三方支付平台到电商用的结算平台出现了延迟的情况,导致在电商系统中的订单一直处于未付款状态,部分用户以为未支付就最终产生了重复付款。
二、如何避免
针对这个问题,思考了各种场景以及情况,这种模式是无法避免重复付款的(必须得看结算平台的处理效率-一般情况下还是比较好的,还是少有延迟的情况)。只能后台检测重复付款的订单,异常走退款流程。
除非系统本身具有支付平台的功能。
三、延伸问题,如何处理因为支付成功后因延迟回调而订单被取消
这个问题的出现背景也是因为第三方结算平台延迟反馈而造成用户错以为没有支付而取消订单或者是系统到时时自动取消订单。
解决办法:建立异常处理机制。 结算平台延迟返回成功的支付信息给电商系统时,如果判断出此订单已经取消。则进入异常处理机制,更改订单为已收款状态,并再次扣减订单中库存以及各种优惠(例如:价保,返利,促销费,优惠等等)的回退。当然再此扣减的时候需要先判断相关产品的库存以及用户的各种优惠是否满足订单的扣减,不满足则不允许转化。
这里是应该先判断再次扣减的库存以及各种优惠,再修改订单状态,步骤以及相关的支付信息为成功。
本文由PMCAFF产品经理社区会员原创发布于社区(),未经许可,禁止转载。微信公众号支付(二)实现统一下单接口
字体:[ ] 类型:转载 时间:
本篇文章主要给大家介绍调用微信公众支付的统一下单API,通过参数封装为xml格式并发送到微信给的接口地址就可以获得返回内容,需要的朋友可以参考下本文
已经获取到了用户的OpenId
这篇主要是调用微信公众支付的统一下单API
看文档,主要流程就是把20个左右的参数封装为XML格式发送到微信给的接口地址,然后就可以获取到返回的内容了,如果成功里面就有支付所需要的预支付ID
请求参数就不解释了。
其中,随机字符串:我用的是UUID去中划线
public static String create_nonce_str() {
return UUID.randomUUID().toString().replace("-","");
商户订单号:每个订单号只能使用一次,所以用的是系统的订单号加的时间戳。
总金额:不能为
通知地址:微信支付成功或失败回调给系统的地址
import java.io.S
public class PayInfo implements Serializable{
private static final long serialVersionUID = L;
private String mch_
private String device_
private String nonce_
private String out_trade_
private int total_
private String spbill_create_
private String notify_
private String trade_
//下面是get,set方法
* 创建统一下单的xml的java对象
* @param bizOrder 系统中的业务单号
* @param ip 用户的ip地址
* @param openId 用户的openId
public PayInfo createPayInfo(BizOrder bizOrder,String ip,String openId) {
PayInfo payInfo = new PayInfo();
payInfo.setAppid(Constants.appid);
payInfo.setDevice_info("WEB");
payInfo.setMch_id(Constants.mch_id);
payInfo.setNonce_str(CommonUtil.create_nonce_str().replace("-", ""));
payInfo.setBody("这里是某某白米饭的body");
payInfo.setAttach(bizOrder.getId());
payInfo.setOut_trade_no(bizOrder.getOrderCode().concat("A").concat(DateFormatUtils.format(new Date(), "MMddHHmmss")));
payInfo.setTotal_fee((int)bizOrder.getFeeAmount());
payInfo.setSpbill_create_ip(ip);
payInfo.setNotify_url(Constants.notify_url);
payInfo.setTrade_type("JSAPI");
payInfo.setOpenid(openId);
return payI
获取签名:
* 获取签名
* @param payInfo
* @throws Exception
public String getSign(PayInfo payInfo) throws Exception {
String signTemp = "appid="+payInfo.getAppid()
+"&attach="+payInfo.getAttach()
+"&body="+payInfo.getBody()
+"&device_info="+payInfo.getDevice_info()
+"&mch_id="+payInfo.getMch_id()
+"&nonce_str="+payInfo.getNonce_str()
+"&notify_url="+payInfo.getNotify_url()
+"&openid="+payInfo.getOpenid()
+"&out_trade_no="+payInfo.getOut_trade_no()
+"&spbill_create_ip="+payInfo.getSpbill_create_ip()
+"&total_fee="+payInfo.getTotal_fee()
+"&trade_type="+payInfo.getTrade_type()
+"&key="+Constants. //这个key注意
MessageDigest md = MessageDigest.getInstance("MD");
md.reset();
md.update(signTemp.getBytes("UTF-"));
String sign = CommonUtil.byteToStr(md.digest()).toUpperCase();
注意:上面的Constants.key取值在商户号API安全的API密钥中。
一些工具方法:获取ip地址,将字节数组转换为十六进制字符串,将字节转换为十六进制字符串
* 将字节数组转换为十六进制字符串
* @param byteArray
public static String byteToStr(byte[] byteArray) {
String strDigest = "";
for (int i = ; i & byteArray. i++) {
strDigest += byteToHexStr(byteArray[i]);
return strD
* 将字节转换为十六进制字符串
* @param btyes
public static String byteToHexStr(byte bytes) {
char[] Digit = { '', '', '', '', '', '', '', '', '', '', 'A', 'B', 'C', 'D', 'E', 'F' };
char[] tempArr = new char[];
tempArr[] = Digit[(bytes &&& ) & XF];
tempArr[] = Digit[bytes & XF];
String s = new String(tempArr);
* 获取ip地址
* @param request
public static String getIpAddr(HttpServletRequest request) {
InetAddress addr =
addr = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
return request.getRemoteAddr();
byte[] ipAddr = addr.getAddress();
String ipAddrStr = "";
for (int i = ; i & ipAddr. i++) {
if (i & ) {
ipAddrStr += ".";
ipAddrStr += ipAddr[i] & xFF;
return ipAddrS
这样就获取了签名,把签名与PayInfo中的其他数据转成XML格式,当做参数传递给统一下单地址。
PayInfo pi = pu.createPayInfo(bo,"...","");
String sign = pu.getSign(pi);
pi.setSign(sign);
* 扩展xstream使其支持CDATA
private static XStream xstream = new XStream(new XppDriver() {
public HierarchicalStreamWriter createWriter(Writer out) {
return new PrettyPrintWriter(out) {
//增加CDATA标记
boolean cdata =
@SuppressWarnings("rawtypes")
public void startNode(String name, Class clazz) {
super.startNode(name, clazz);
protected void writeText(QuickWriter writer, String text) {
if (cdata) {
writer.write("&![CDATA[");
writer.write(text);
writer.write("]]&");
writer.write(text);
public static String payInfoToXML(PayInfo pi) {
xstream.alias("xml", pi.getClass());
return xstream.toXML(pi);
@SuppressWarnings("unchecked")
public static Map&String, String& parseXml(String xml) throws Exception {
Map&String, String& map = new HashMap&String, String&();
Document document = DocumentHelper.parseText(xml);
Element root = document.getRootElement();
List&Element& elementList = root.elements();
for (Element e : elementList)
map.put(e.getName(), e.getText());
下面就是调用统一下单的URL了
(MessageUtil.payInfoToXML(pi).replace("__", "_"));
  Map&String, String& map = CommonUtil.httpsRequestToXML("https://api.mch./pay/unifiedorder", "POST", MessageUtil.payInfoToXML(pi).replace("__", "_").replace("&![CDATA[", "").replace("]]&", ""));
public static Map&String, String& httpsRequestToXML(String requestUrl, String requestMethod, String outputStr) {
Map&String, String& result = new HashMap&&();
StringBuffer buffer = httpsRequest(requestUrl, requestMethod, outputStr);
result = MessageUtil.parseXml(buffer.toString());
} catch (ConnectException ce) {
log.error("连接超时:"+ce.getMessage());
} catch (Exception e) {
log.error("https请求异常:"+ece.getMessage());
httpsRequest()这个方法在第一篇中
上面获取到的Map如果成功的话,里面就会有
String return_code = map.get("return_code");
if(StringUtils.isNotBlank(return_code) && return_code.equals("SUCCESS")){
  String return_msg = map.get("return_msg");
if(StringUtils.isNotBlank(return_msg) && !return_msg.equals("OK")) {
  return "统一下单错误!";
  return "统一下单错误!";
String prepay_Id = map.get("prepay_id");
这个prepay_id就是预支付的ID。后面支付需要它。
您可能感兴趣的文章:
大家感兴趣的内容
12345678910
最近更新的内容
常用在线小工具supplierchannel为什么用户下单后却不付款?
如果说用户把商品加入购物车后却放弃了购买显得太可惜,那么,用户下单后最终未付款则着实可恨。加入购物车后放弃购买,好比姑娘有和你开房的想法但半途却改变主意;而下单后不付款则好比姑娘和你进入房间了最终你俩什么都没做。到了这个地步,你怎么也得分析原因吧!
为什么用户下单后却不付款?根据观察、调查和询问业内一些朋友,最终总结如下:
对商家(网站)来说有何影响
1、 资源的浪费,如果能在这里使一把劲提高支付成功率,比重新去拉用户下单容易许多;
2、 对库存紧张的商家来说,因为下单后库存临时冻结,导致其它用户不能购买,造成损失;
3、 对商家信誉或口碑造成影响(对第2、5、9点原因的客户来说,网站的体验很差)
发现问题容易,解决问题才是目的,有何应对良策?我提出几点理论方法,供参考:
下单后临时改变主意,不想买了,真的,单纯的不想买了
优化购物流程,照顾到冲动购买的用户,多折腾两下用户的激情就没了。不知道有没有人研究过用户&冲动&的时间有多长?
用户习惯问题,下单后再询问客服问题,因为不满意或无回复而取消订单
我想这种用户习惯多半是淘宝平台养成的,痛恨淘宝吧,强大的客服力量。在淘宝买东西不问客服两句心里都不舒服。
不想要客服?那么把常见问题和用户常询问的内容整合到网站内容、商品内容中吧,期望用户能多看几眼。
先下单,不立马付款,而是间隔一段时间再付款
用户很可能会忘记或失去兴趣,所以及时短信或者邮件提醒用户付款。及时是多久?有人说24小时内,有人说12小时内,你看
支付账户没钱,需要充值
及时短信提醒用户订单未付款,并告知可更换支付方式,网站支持COD
不能支付或者支付不顺利
允许用户更改支付方式,且方便。有网站把选择支付方式放在提交订单后是有道理的。
下单后临时想更换或增减商品
支持用户自助更改未付款的订单的商品,支持客服帮忙更改用户订单。
只是下着玩玩
参考某卖酒的网站,天天给这类用户发短信骚扰他 ^-^
下错单或者重复下单
下单后被告知没货
系统保证能下单就应该有货,对于不做库存的网站,这是痛点。
此外还可以考虑以下几个问题
1、下单后多久未付款系统自动取消订单?有的网站是7天,有的24小时,为什么?为什么要自动取消订单?
2、是否让用户自助取消订单?
3、对下了订单放弃支付的用户,意味着我们已经掌握了其个人信息和购买喜好,除了及时的短信或邮件唤回订单,后期的精准营销也很有意义。
作者:虫子
文章来源:
有好的文章希望站长之家帮助分享推广,猛戳这里
本网页浏览已超过3分钟,点击关闭或灰色背景,即可回到网页

我要回帖

更多关于 微信支付和账号不一致 的文章

 

随机推荐