DiscuzNT 商品交易插件设计之[线上交易]---业务流程
本文中,我们将会以一个线上支付流程来进一步介绍业务设计上的一些内容和思想。
在之前的线下支付流程中,我们看到交易是靠买卖双方不断更新本地的交易状态来进行推
动的。而线上支付这个过程的推动主要靠支付宝那面的操作来完成,而本地服务器只是提供了
交易信息并进行跳转(到支付宝)。并接受支付宝回传过来的交易信息,来更新本地数据库中的
交易状态并发送站内消息给买家或者卖家。
了解了上面的信息之后,我们通过一个简单的例子来加以说明,同时按“老规矩”,在介
绍过程中穿插对源代码的讲解。
当我们在商品显示页面中点击立即购买按钮之后,如下图:
我们会进入到“确认购买信息”页面,如下图:
当在“确认购买信息”页面中的交易方式选项中选择“支付宝在线交易”选项后,如上图所示,
点击确认购买后,系统会提示“交易单已创建”的成功信息,如下图所示:
然后系统会将页面重定向到onlinetrade.aspx页,如下所示:
当我们点击使用支付宝支付的按钮之后,系统会创建订单如下所示:
然后跳转到支付宝交易页面。如下图:
在点击“支付宝交易.付款”按钮后并正确输入相应登陆信息,我们就可以使用支付宝来逐步
完成交易流程了,因为这块操作只有使用过支付宝的朋友都有心得,所以就不再多说了。我们
假设在支付宝平台上付了款之后,这里支付宝会回传数据到我们的本地服务器上,而我们本地
接受回传数据并返回确认信息的页面是tradenofity.aspx(参见源代码cs文件),其内容如下
(详见注释):
/// 交易状态通知页面
/// </summary>
public class tradenotify : PageBase
{
protected override void ShowPage()
{
if (CheckPayment())
{
Goodstradeloginfo goodstradeloginfo = TradeLogs.GetGoodsTradeLogInfo(DNTRequest.GetString("out_trade_no"));
if (goodstradeloginfo != null && goodstradeloginfo.Id > 0)
{
switch (DNTRequest.GetString("trade_status"))
{
case "WAIT_BUYER_PAY": // 等待买家付款
{
goodstradeloginfo.Status = (int)TradeStatusEnum.WAIT_BUYER_PAY; break;
}
case "WAIT_SELLER_CONFIRM_TRADE": // 交易已创建,等待卖家确认
{
goodstradeloginfo.Status = (int)TradeStatusEnum.WAIT_SELLER_CONFIRM_TRADE; break;
}
case "WAIT_SYS_CONFIRM_PAY": // 确认买家付款中,暂勿发货
{
goodstradeloginfo.Status = (int)TradeStatusEnum.WAIT_SYS_CONFIRM_PAY; break;
}
case "WAIT_SELLER_SEND_GOODS": // 支付宝收到买家付款,请卖家发货
{
goodstradeloginfo.Status = (int)TradeStatusEnum.WAIT_SELLER_SEND_GOODS; break;
}
case "WAIT_BUYER_CONFIRM_GOODS": // 卖家已发货,买家确认中
{
goodstradeloginfo.Status = (int)TradeStatusEnum.WAIT_BUYER_CONFIRM_GOODS; break;
}
case "WAIT_SYS_PAY_SELLER": // 买家确认收到货,等待支付宝打款给卖家
{
goodstradeloginfo.Status = (int)TradeStatusEnum.WAIT_SYS_PAY_SELLER; break;
}
case "TRADE_FINISHED": // 交易成功结束
{
goodstradeloginfo.Status = (int)TradeStatusEnum.TRADE_FINISHED; break;
}
case "TRADE_CLOSED": // 交易中途关闭(未完成)
{
goodstradeloginfo.Status = (int)TradeStatusEnum.TRADE_CLOSED; break;
}
case "WAIT_SELLER_AGREE": // 等待卖家同意退款
{
goodstradeloginfo.Status = (int)TradeStatusEnum.WAIT_SELLER_AGREE; break;
}
case "SELLER_REFUSE_BUYER": // 卖家拒绝买家条件,等待买家修改条件
{
goodstradeloginfo.Status = (int)TradeStatusEnum.SELLER_REFUSE_BUYER; break;
}
case "WAIT_BUYER_RETURN_GOODS": // 卖家同意退款,等待买家退货
{
goodstradeloginfo.Status = (int)TradeStatusEnum.WAIT_BUYER_RETURN_GOODS; break;
}
case "WAIT_SELLER_CONFIRM_GOODS": // 等待卖家收货
{
goodstradeloginfo.Status = (int)TradeStatusEnum.WAIT_SELLER_CONFIRM_GOODS; break;
}
case "REFUND_SUCCESS": // 退款成功
{
goodstradeloginfo.Status = (int)TradeStatusEnum.REFUND_SUCCESS; break;
}
}
goodstradeloginfo.Lastupdate = DateTime.Now;
TradeLogs.UpdateTradeLog(goodstradeloginfo, goodstradeloginfo.Status, true);
}
HttpContext.Current.Response.Write("success"); //返回给支付宝消息,成功
}
else
{
HttpContext.Current.Response.Write("fail");
}
}
/// <summary>
/// 获取远程服务器ATN结果
/// </summary>
/// <param name="a_strUrl"></param>
/// <param name="timeout"></param>
/// <returns></returns>
public String Get_Http(String strUrl, int timeout)
{
string strResult;
try
{
HttpWebRequest myReq = (HttpWebRequest)HttpWebRequest.Create(strUrl);
myReq.Timeout = timeout;
HttpWebResponse HttpWResp = (HttpWebResponse)myReq.GetResponse();
Stream myStream = HttpWResp.GetResponseStream();
StreamReader sr = new StreamReader(myStream, Encoding.UTF8);
StringBuilder strBuilder = new StringBuilder();
while (-1 != sr.Peek())
{
strBuilder.Append(sr.ReadLine());
}
strResult = strBuilder.ToString();
}
catch (Exception exp)
{
strResult = "错误:" + exp.Message;
}
return strResult;
}
/// <summary>
/// 检查支付结果
/// </summary>
/// <returns></returns>
private bool CheckPayment()
{
AliPayConfigInfo aliPayConfigInfo = TradeConfigs.GetConfig().Alipayconfiginfo;
string alipay_notify_url = "https://www.alipay.com/cooperate/gateway.do?";
string key = aliPayConfigInfo.Sign; //partner 的对应交易安全校验码(必须填写)
string _input_charset = aliPayConfigInfo.Inputcharset;
string partner = aliPayConfigInfo.Partner; //partner合作伙伴id(必须填写)
alipay_notify_url = alipay_notify_url + "service=notify_verify" + "&partner=" + partner +
"¬ify_id=" + DNTRequest.GetString("notify_id");
//获取支付宝ATN返回结果,true是正确的订单信息,false 是无效的
string responseTxt = Get_Http(alipay_notify_url, 120000);
//排序
string[] Sortedstr = System.Web.HttpContext.Current.Request.Form.AllKeys;
AliPayment.QuickSort(Sortedstr, 0, Sortedstr.Length - 1);
//构造待md5摘要字符串
StringBuilder prestr = new StringBuilder();
for (int i = 0; i < Sortedstr.Length; i++)
{
if (DNTRequest.GetString(Sortedstr[i]) != "" && Sortedstr[i] != "sign" && Sortedstr[i] != "sign_type")
{
if (i == Sortedstr.Length - 1)
{
prestr.Append(Sortedstr[i] + "=" + DNTRequest.GetString(Sortedstr[i]));
}
else
{
prestr.Append(Sortedstr[i] + "=" + DNTRequest.GetString(Sortedstr[i]) + "&");
}
}
}
prestr.Append(key);
//生成Md5摘要
string mysign = AliPayment.GetMD5(prestr.ToString(), _input_charset);
//验证支付发过来的消息,签名是否正确
if (mysign == DNTRequest.GetString("sign") && responseTxt == "true")
{
return true;
}
else
{
return false;
}
}
}
上面的页面用于接受支付宝post过来的数据,并对其有效性进行校验,以避免是其它恶意请求。
这部分的工作是通过CheckPayment()方法来完成的。
当校验通过后,就要进行更新交易状态的操作了,正如我在线下支付一文中所说的,交易状态
共有17种,这里只有主要的交易状态进行了绑定并进行更新,参见如下代码:
而UpdateTradeLog方法在线下交易一文中已介绍过,这里就不多说了。
需要注意的一点就是,如果我们要想在本地测试该项功能,需要找网管协助将我们的机器IP地
址绑定(公布)到网上,使支付宝能够访问我们调试的机器,只有这样交易信息才能正常发送过来。
当交易状态更新结束之后,我们还要向支付宝平台发送一个确认信息,以通知它我们已收到了
它发过来的交易信息。如果不这样做的话,支付宝就会每隔一段时间来敲您网站的大门,不停的向
您发送该交易信息了。
当然这时相对于买家已经向交易成功迈出了第一步,而卖家因为本地数据库中交易状态已更新,
同时也收到了买家已付款的站内短消息(UpdateTradeLog方法中实现)。这时就要登陆支付宝平
台来进行发货或其它与本次交易有关的操作了,而这部分的内容很接近于线下支付流程,只不过是
将这个业务过程搬到了支付宝上来而已,这里就不再多说什么了。
到这里系统要做的就是不停的接受支付宝post过来的交易数据来更新本地数据库中的交易状态,
从而最终完成本次交易操作。当买卖双方交易完成后,依旧会像在线下支付流程一样,出现进行双
方互评的交易链接,以便为信用机制提供数据支持,如下图所示:
点击后,我们会进入到评价页面,如下:
当评价完成后,我们就可以去信用页面看当前买卖双方的信用,好评率等信息了,而信用机
制这方面的内容,会在下一篇文章中详加说明。
到这里,我们完成了一个线上交易。当然我们可以通“用户中心”来查看我们关注或进行中的
交易等信息,如下图所示:
好了,今天的内容就先到这里。
tag:alipay,支付宝,discuznt,online trade,在线交易
作者:代震军,daizhj
原文链接:http://www.cnblogs.com/daizhj/archive/2008/08/18/1270227.html