买商品以及系统设计。
首先打开一个有效的商品,在商品显示页面中单击“立刻购买”按钮,如下:
这样就会跳转到“确认购买信息”页面(buygoods.aspx),如下:
在这个页面中,系统会执行如下操作:
1. 进行商品信息有效性校验(如未通过则显示相应提示信息,从而中止后续操作),如下:
{
if (goodsinfo.Expiration <= DateTime.Now)
{
AddErrLine( " 非常抱歉, 该宝贝不存在或已经结束了! " );
return false ;
}
if (goodsinfo.Closed == 1 )
{
AddErrLine( " 此商品已关闭! " );
return false ;
}
if (goodsinfo.Selleruid <= 0 )
{
AddErrLine( " 商品卖家信息错误! " );
return false ;
}
if (userid == goodsinfo.Selleruid)
{
AddErrLine( " 买卖双方不能为同一用户! " );
return false ;
}
if (goodsinfo.Displayorder == - 1 )
{
AddErrLine( " 此商品已被删除! " );
return false ;
}
if (goodsinfo.Displayorder == - 2 )
{
AddErrLine( " 此商品未经审核! " );
return false ;
}
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
2. 当点击“确认购买”时,进行购买数量校验以及与剩余数量比较判断,如下:
![](https://www.cnblogs.com/Images/dot.gif)
if (ispost)
{
// 创建商品交易日志
goodstradelog.Number = DNTRequest.GetInt( " number " , 0 );
// 商品数不正确
if (goodstradelog.Number <= 0 )
{
AddErrLine( " 请输入正确的商品数, 请返回修改. " );
return ;
}
if (goodsinfo.Amount < goodstradelog.Number)
{
AddErrLine( " 商品剩余数量不足 (剩余数量为 " + goodsinfo.Amount + " , 而购买数量为 " + goodstradelog.Number + " ). " );
return ;
}
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
}
3. 创建商品交易日志(CreateTradeLog):
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
goodstradelog.Baseprice = goodsinfo.Costprice;
goodstradelog.Discount = goodsinfo.Discount;
goodstradelog.Ratestatus = 0 ;
goodstradelog.Message = "" ;
int tradelogid = TradeLogs.CreateTradeLog(goodstradelog);
if (tradelogid > 0 )
{
string jumpurl = "" ;
if (goodstradelog.Offline == 0 )
{
jumpurl = " onlinetrade.aspx?goodstradelogid= " + tradelogid;
}
else
{
jumpurl = " offlinetrade.aspx?goodstradelogid= " + tradelogid;
}
SetUrl(jumpurl);
SetMetaRefresh();
AddMsgLine( " 交易单已创建, 现在将转入交易单页面<br />(<a href= """ + jumpurl + """ >如果您的浏览器没有自动跳转, 请点击这里</a>)<br /> " );
}
else
{
SetUrl( " buygoods.aspx?goodsid= " + goodsid);
SetMetaRefresh();
AddMsgLine( " 交易单创建错误, 请重新添写交易单<br />(<a href= """ + " buygoods.aspx?goodsid= " + goodsid + """ >如果您的浏览器没有自动跳转, 请点击这里</a>)<br /> " );
}
![](https://www.cnblogs.com/Images/dot.gif)
![](https://www.cnblogs.com/Images/dot.gif)
这里的 TradeLogs.CreateTradeLog(goodstradelog)方法内容如下:
/// 创建商品交易日志
/// </summary>
/// <param name="__goodstradelog"> 要创建的商品交易日志 </param>
/// <returns> 创建的商品交易日志id </returns>
public static int CreateTradeLog(Goodstradeloginfo __goodstradelog)
{
// 当为支付宝付款方式时,将订单号绑定到tradeno字段
if (__goodstradelog.Offline == 0 )
{
__goodstradelog.Tradeno = __goodstradelog.Orderid;
}
if (__goodstradelog.Buyermsg.Length > 100 )
{
__goodstradelog.Buyermsg = __goodstradelog.Buyermsg.Substring( 0 , 100 );
}
if (__goodstradelog.Buyercontact.Length > 100 )
{
__goodstradelog.Buyercontact = __goodstradelog.Buyercontact.Substring( 0 , 100 );
}
if (__goodstradelog.Number > 0 )
{
// 更新商品数量和最近交易信息
Goodsinfo __goodsinfo = Goods.GetGoodsInfo(__goodstradelog.Goodsid);
if (__goodsinfo != null && __goodsinfo.Goodsid > 0 )
{
// 当商品库存变为0(负)库存时
if (__goodsinfo.Amount > 0 && (__goodsinfo.Amount - __goodstradelog.Number) <= 0 )
{
DbProvider.GetInstance().UpdateCategoryGoodsCounts(__goodsinfo.Categoryid,
__goodsinfo.Parentcategorylist, -1);
}__goodsinfo.Totalitems = __goodsinfo.Totalitems + __goodstradelog.Number; // 累加总交易量
__goodsinfo.Amount = __goodsinfo.Amount - __goodstradelog.Number; // 减少当前商品数量
__goodsinfo.Tradesum = __goodsinfo.Tradesum + __goodstradelog.Tradesum; // 累加总交易额
__goodsinfo.Lastbuyer = __goodstradelog.Buyer;
__goodsinfo.Lasttrade = DateTime.Now;
Goods.UpdateGoods(__goodsinfo);
}
}
__goodstradelog.Id = DbProvider.GetInstance().CreateGoodsTradeLog(__goodstradelog);
SendPM(__goodstradelog);
return __goodstradelog.Id;
}
基本上是对要创建的交易信息进行数据修正,并更新商品表中的相应字段(Totalitems,Amount等)。
当创建交易日志完成之后,上面的SendPM(__goodstradelog);用于向卖家发送短消息。其代码段如下所示:
/// 根据交易日志的状态发送相应短消息
/// </summary>
/// <param name="__goodstradelog"> 交易日志信息 </param>
/// <returns> 是否发送成功 </returns>
public static bool SendPM(Goodstradeloginfo __goodstradelog)
{
string pm_content = " 这是由论坛系统自动发送的通知短消息.<BR /> " ;
string pm_title = "" ;
bool issendpm = false ;
int msgtoid = 0 ;
string msgto = "" ;
string pagename = __goodstradelog.Offline == 1 ? " offlinetrade.aspx " : " onlinetrade.aspx " ;
switch ((TradeStatusEnum)__goodstradelog.Status)
{
case TradeStatusEnum.UnStart:
{
pm_title = " [系统消息] 有买家购买您的商品 " ;
pm_content = pm_content + string .Format( " 买家 {0} 购买您的商品 {1}. 但交易尚未生效, 等待您的确认, 请<a href = """ + pagename + " ?goodstradelogid={2} "" >点击这里</a>查看详情. " ,
__goodstradelog.Buyer,
__goodstradelog.Subject,
__goodstradelog.Id);
issendpm = true ;
msgtoid = __goodstradelog.Sellerid;
msgto = __goodstradelog.Seller;
break ;
}
case TradeStatusEnum.WAIT_SELLER_SEND_GOODS:
{
pm_title = " [系统消息] 买家已付款, 等待您发货 " ;
pm_content = pm_content + string .Format( " 买家 {0} 购买您的商品 {1}. 买家已付款, 等待您发货, 请<a href = """ + pagename + " ?goodstradelogid={2} "" >点击这里</a>查看详情. " ,
__goodstradelog.Buyer,
__goodstradelog.Subject,
__goodstradelog.Id);
issendpm = true ;
msgtoid = __goodstradelog.Sellerid;
msgto = __goodstradelog.Seller;
break ;
}
case TradeStatusEnum.WAIT_BUYER_CONFIRM_GOODS:
{
pm_title = " [系统消息] 您购买的商品已经发货 " ;
pm_content = pm_content + string .Format( " 您购买的商品 {0} . 卖家 {1} 已发货, 等待您的确认, 请<a href = """ + pagename + " ?goodstradelogid={2} "" >点击这里</a>查看详情. " ,
__goodstradelog.Subject,
__goodstradelog.Seller,
__goodstradelog.Id);
msgtoid = __goodstradelog.Buyerid;
msgto = __goodstradelog.Buyer;
issendpm = true ;
issendpm = true ; break ;
}
case TradeStatusEnum.WAIT_SELLER_AGREE:
{
pm_title = " [系统消息] 有买家等待你同意退款 " ;
pm_content = pm_content + string .Format( " 买家 {0} 等待你同意退款, 请<a href = """ + pagename + " ?goodstradelogid={1} "" >点击这里</a>查看详情. " ,
__goodstradelog.Buyer,
__goodstradelog.Id);
issendpm = true ;
msgtoid = __goodstradelog.Sellerid;
msgto = __goodstradelog.Seller;
break ;
}
case TradeStatusEnum.SELLER_REFUSE_BUYER:
{
pm_title = " [系统消息] 有卖家拒绝您的条件, 等待您修改条件 " ;
pm_content = pm_content + string .Format( " 卖家 {0} 拒绝您的条件, 等待您修改条件, 请<a href = """ + pagename + " ?goodstradelogid={1} "" >点击这里</a>查看详情. " ,
__goodstradelog.Seller,
__goodstradelog.Id);
issendpm = true ;
msgtoid = __goodstradelog.Buyerid;
msgto = __goodstradelog.Buyer;
break ;
}
case TradeStatusEnum.WAIT_BUYER_RETURN_GOODS:
{
pm_title = " [系统消息] 有卖家同意退款, 等待您退货 " ;
pm_content = pm_content + string .Format( " 卖家 {0} 同意退款, 等待您退货, 请<a href = """ + pagename + " ?goodstradelogid={1} "" >点击这里</a>查看详情. " ,
__goodstradelog.Seller,
__goodstradelog.Id);
msgtoid = __goodstradelog.Buyerid;
msgto = __goodstradelog.Buyer;
issendpm = true ;
break ;
}
case TradeStatusEnum.WAIT_SELLER_CONFIRM_GOODS:
{
pm_title = " [系统消息] 有买家已退货, 等待您收货 " ;
pm_content = pm_content + string .Format( " 买家 {0} 已退货, 等待您收货, 请<a href = """ + pagename + " ?goodstradelogid={1} "" >点击这里</a>查看详情. " ,
__goodstradelog.Buyer,
__goodstradelog.Id);
msgtoid = __goodstradelog.Sellerid;
msgto = __goodstradelog.Seller;
issendpm = true ;
break ;
}
case TradeStatusEnum.TRADE_FINISHED:
{
pm_title = " [系统消息] 商品交易已成功完成 " ;
pm_content = pm_content + string .Format( " 商品 {0} 已交易成功, 请<a href = "" goodsrate.aspx?goodstradelogid={1} "" >点击这里</a>给对方评分. " ,
__goodstradelog.Subject,
__goodstradelog.Id);
msgtoid = __goodstradelog.Sellerid;
msgto = __goodstradelog.Seller;
issendpm = true ;
break ;
}
case TradeStatusEnum.TRADE_CLOSED:
{
pm_title = " [系统消息] 卖家已取消此次交易, 当前交易关闭 " ;
pm_content = pm_content + string .Format( " 商品 {0} 交易失败, 卖家取消交易, 请<a href = "" goodsrate.aspx?goodstradelogid={1} "" >点击这里</a>查看详情. " ,
__goodstradelog.Subject,
__goodstradelog.Id);
msgtoid = __goodstradelog.Sellerid;
msgto = __goodstradelog.Seller;
issendpm = true ;
break ;
}
case TradeStatusEnum.REFUND_SUCCESS:
{
pm_title = " [系统消息] 您购买的商品已成功退款 " ;
pm_content = pm_content + string .Format( " 商品 {0} 已退款成功, 请<a href = "" goodsrate.aspx?goodstradelogid={1} "" >点击这里</a>给对方评分. " ,
__goodstradelog.Subject,
__goodstradelog.Id);
msgtoid = __goodstradelog.Buyerid;
msgto = __goodstradelog.Buyer;
issendpm = true ;
break ;
}
}
// 发送短消息
if (issendpm)
{
PrivateMessageInfo __privatemessageinfo = new PrivateMessageInfo();
// 收件箱
__privatemessageinfo.Message = Utils.HtmlEncode(pm_content.ToString());
__privatemessageinfo.Subject = Utils.HtmlEncode(pm_title);
__privatemessageinfo.Msgto = msgto;
__privatemessageinfo.Msgtoid = msgtoid;
__privatemessageinfo.Msgfrom = " 系统 " ;
__privatemessageinfo.Msgfromid = 0 ;
__privatemessageinfo.New = 1 ;
__privatemessageinfo.Postdatetime = Utils.GetDateTime();
PrivateMessages.CreatePrivateMessage(__privatemessageinfo, 0 );
}
return true ;
}
上面的代码主要是根据交易日志的状态,向买卖双方发送相应的短消息。而交易的状态采用了支付宝
文档中所述的17种状态,其说明如下(位于Discuz.Entity项目下的Mall/GoodsrateinfoCollection.cs):
/// 交易状态枚举
/// </summary>
public enum TradeStatusEnum
{
/// <summary>
/// 未生效的交易
/// </summary>
UnStart = 0 ,
/// <summary>
/// 等待买家付款
/// </summary>
WAIT_BUYER_PAY = 1 ,
/// <summary>
/// 交易已创建,等待卖家确认
/// </summary>
WAIT_SELLER_CONFIRM_TRADE = 2 ,
/// <summary>
/// 确认买家付款中,暂勿发货
/// </summary>
WAIT_SYS_CONFIRM_PAY = 3 ,
/// <summary>
/// 买家已付款(或支付宝收到买家付款),请卖家发货
/// </summary>
WAIT_SELLER_SEND_GOODS = 4 ,
/// <summary>
/// 卖家已发货,买家确认中
/// </summary>
WAIT_BUYER_CONFIRM_GOODS = 5 ,
/// <summary>
/// 买家确认收到货,等待支付宝打款给卖家
/// </summary>
WAIT_SYS_PAY_SELLER = 6 ,
/// <summary>
/// 交易成功结束
/// </summary>
TRADE_FINISHED = 7 ,
/// <summary>
/// 交易中途关闭(未完成)
/// </summary>
TRADE_CLOSED = 8 ,
/// <summary>
/// 等待卖家同意退款
/// </summary>
WAIT_SELLER_AGREE = 10 ,
/// <summary>
/// 卖家拒绝买家条件,等待买家修改条件
/// </summary>
SELLER_REFUSE_BUYER = 11 ,
/// <summary>
/// 卖家同意退款,等待买家退货
/// </summary>
WAIT_BUYER_RETURN_GOODS = 12 ,
/// <summary>
/// 等待卖家收货
/// </summary>
WAIT_SELLER_CONFIRM_GOODS = 13 ,
/// <summary>
/// 双方已经一致,等待支付宝退款
/// </summary>
WAIT_ALIPAY_REFUND = 14 ,
/// <summary>
/// 支付宝处理中
/// </summary>
ALIPAY_CHECK = 15 ,
/// <summary>
/// 结束的退款
/// </summary>
OVERED_REFUND = 16 ,
/// <summary>
/// 退款成功(卖家已收到退货)
/// </summary>
REFUND_SUCCESS = 17 ,
/// <summary>
/// 退款关闭
/// </summary>
REFUND_CLOSED = 18
}
到这里,确认交易页面介绍的差不多了,当然上面所帖的图中“交易方式”选择“下同之后,则进入到offlinetrade.aspx中。
如下所示:
在这里,当前的交易状态为"未生效的交易"(即: UnStart = 0)
当用户点击“我已付款,等待卖家发货”按钮时,会显示“买家已付款,等待卖家发货”的提示信息如下图:
如果这时卖家(登陆后)进入到当前交易页面时,会显示如下信息:
![](https://daizhj.cnblogs.com/images/cnblogs_com/daizhj/discuznt_buygoods_seller_sendgoods.jpg)
这里如果卖家确认买家并点击“我已发货”按钮后,当前交易状态会成“卖家已发货,买家确认中(即:
WAIT_BUYER_CONFIRM_GOODS = 5)。
这时当买家(登陆后)进入到当前交易页面时,会显示如下信息:
![](https://daizhj.cnblogs.com/images/cnblogs_com/daizhj/discuz_nt_buygoods_buyer_getgoods.jpg)
当买家最终确认并收货之后,点击“我收到货,交易成功结束”按钮,当前交易状态会变成“交易成功结束”
(RADE_FINISHED = 7)。如下所示:
![](https://daizhj.cnblogs.com/images/cnblogs_com/daizhj/discuznt_buygoods_trade_finished.jpg)
这样本次交易流程基本上就结束了,当然最后买卖双方还要互评,以便为“信用机制”提供有效信息。如下
图(点击上图中的“评价”按钮):
![](https://daizhj.cnblogs.com/images/cnblogs_com/daizhj/discuznt_rate.jpg)
当买卖双方评价完成后,交易变成了“双方已评”
这时,当我们点击“商品显示页面”中的“信用链接”(如下图):
系统会进入到“信用页面(eccredit.aspx)”, 如下图:
![](https://daizhj.cnblogs.com/images/cnblogs_com/daizhj/discuznt_mall_eccredit.jpg)
在这里,我们就可以看到当前商品的卖家和买家信用,以及按时间(最近一周,一个月,六个月等)所获
得的“ 好,中,差”评的次数以及相应的评价内容。此外还包括" 好评率”,“ 给他人评价”等信息。
这样,我们基本上完成了一个交易流程(线下交易,注:退货退款等交易中止流程本文未进行说明,大家可
安装之后一用便知)。
当然,我们这里在处理交易的页面中,只是在买卖双方的推动下,不断更新交易状态的过程,因为下面简要
介绍一下 Discuz.Mall/Pages/offlinetrade.cs(线下交易页面)的代码:
首先是 IsConditionsValid方法,该方法用户校验买家或卖家身份以及交易和商品的信息有效性,如下:
{
if (goodstradelog.Offline == 0 )
{
AddErrLine( " 当前交易为在线交易! " );
return false ;
}
// 当前用户为买家时
if (goodstradelog.Buyerid == userid)
{
isbuyer = true ;
}
// 当前用户为卖家时
if (goodstradelog.Sellerid == userid)
{
isseller = true ;
}
// 当前用户既不是买家也不是卖家
if ( ! isbuyer && ! isseller)
{
AddErrLine( " 当前用户身份既不是买家也不是卖家! " );
return false ;
}
if (goodstradelog.Buyerid <= 0 )
{
AddErrLine( " 商品买家信息错误! " );
return false ;
}
if (goodstradelog.Sellerid <= 0 )
{
AddErrLine( " 商品卖家信息错误! " );
return false ;
}
int goodsid = goodstradelog.Goodsid;
// 如果商品ID无效
if (goodsid <= 0 )
{
AddErrLine( " 无效的商品ID " );
return false ;
}
goodsinfo = Goods.GetGoodsInfo(goodsid);
if (goodsinfo.Displayorder == - 1 )
{
AddErrLine( " 此商品已被删除! " );
return false ;
}
if (goodsinfo.Displayorder == - 2 )
{
AddErrLine( " 此商品未经审核! " );
return false ;
}
if (goodsinfo.Expiration <= DateTime.Now)
{
AddErrLine( " 非常抱歉, 该商品不存在或已经到期! " );
return false ;
}
return true ;
}
当通过上面方法的校验并实例化相应的交易信息后,则进行更新当前交易状态的操作,其调用代码如下
( Discuz.Mall/Pages/offlinetrade.cs):
{
SetUrl( " offlinetrade.aspx?goodstradelogid= " + goodstradelogid);
SetMetaRefresh();
AddMsgLine( " 交易单已更新, 现在转入交易单页面<br />(<a href= """ + " offlinetrade.aspx?goodstradelogid= " + goodstradelogid + """ >如果您的浏览器没有自动跳转, 请点击这里</a>)<br /> " );
}
下面介绍一下 TradeLogs.UpdateTradeLog方法,该方法执行更新交易状态的操作(相关内容见注释):
/// 更新交易信息
/// </summary>
/// <param name="__goodstradelog"> 要更新的交易信息 </param>
/// <param name="oldstatus"> 更新之前的状态 </param>
/// <param name="issendpm"> 更新交易信息成功后, 是否发送短消息 </param>
/// <returns> 是否更新成功 </returns>
public static bool UpdateTradeLog(Goodstradeloginfo __goodstradelog, int oldstatus, bool issendpm)
{
bool result = UpdateTradeLog(__goodstradelog, oldstatus); // 调用重载方法
if (result && issendpm)
{
SendPM(__goodstradelog);
}
return result;
}
/// <summary>
/// 更新交易信息
/// </summary>
/// <param name="__goodstradelog"> 要更新的交易信息 </param>
/// <param name="oldstatus"> 本次更新之前的状态 </param>
/// <returns> 是否更新成功 </returns>
public static bool UpdateTradeLog(Goodstradeloginfo __goodstradelog, int oldstatus)
{
if (__goodstradelog.Buyermsg.Length > 100 )
{
__goodstradelog.Buyermsg = __goodstradelog.Buyermsg.Substring( 0 , 100 );
}
if (__goodstradelog.Buyercontact.Length > 100 )
{
__goodstradelog.Buyercontact = __goodstradelog.Buyercontact.Substring( 0 , 100 );
}
__goodstradelog.Tradesum = __goodstradelog.Number * __goodstradelog.Price +
(__goodstradelog.Transportpay == 2 ? __goodstradelog.Transportfee : 0);
// 当交易状态发生变化时
if (__goodstradelog.Status != oldstatus)
{
if (__goodstradelog.Number > 0 )
{
// 获取当前交易的商品信息
Goodsinfo __goodsinfo = Goods.GetGoodsInfo(__goodstradelog.Goodsid);
// 当交易从中途关闭(未完成)状态变为生效(Status: 1为生效, 4为买家已付款等待卖家发货)时更新商品数量)
if (oldstatus == 8 && (__goodstradelog.Status == 1 || __goodstradelog.Status == 4 ))
{
// 当商品库存变为0(负)库存时
if (__goodsinfo.Amount > 0 && (__goodsinfo.Amount - __goodstradelog.Number) <= 0 )
{
DbProvider.GetInstance().UpdateCategoryGoodsCounts(__goodsinfo.Categoryid, __goodsinfo.Parentcategorylist, -1);
}__goodsinfo.Totalitems = __goodsinfo.Totalitems + __goodstradelog.Number; // 累加总交易量
__goodsinfo.Amount = __goodsinfo.Amount - __goodstradelog.Number; // 减少当前商品数量
__goodsinfo.Tradesum = __goodsinfo.Tradesum + __goodstradelog.Tradesum; // 累加总交易额
}
// 当退款成功后(Status = 17, 表示此次交易无效,同时更新商品信息并还原商品数目)
// 或交易中途关闭,未完成(Status = 8, 更新商品数量)
if (__goodstradelog.Status == 17 || __goodstradelog.Status == 8 )
{
// 当商品库存从0(负)库存变为有效库存时
if (__goodsinfo.Amount <= 0 && (__goodsinfo.Amount + __goodstradelog.Number) > 0 )
{
DbProvider.GetInstance().UpdateCategoryGoodsCounts(__goodsinfo.Categoryid,
__goodsinfo.Parentcategorylist, 1);
}
__goodsinfo.Totalitems = __goodsinfo.Totalitems - __goodstradelog.Number; // 减少总交易量
__goodsinfo.Amount = __goodsinfo.Amount + __goodstradelog.Number; // 还原当前商品数量
__goodsinfo.Tradesum = __goodsinfo.Tradesum - __goodstradelog.Tradesum; // 减少总交易额
}
__goodsinfo.Lastbuyer = __goodstradelog.Buyer;
__goodsinfo.Lasttrade = DateTime.Now;
Goods.UpdateGoods(__goodsinfo);
}
}
return DbProvider.GetInstance().UpdateGoodsTradeLog(__goodstradelog);
}
当前在交易状态更新完成后,会最终发送短消息给买家或卖家,其方法在本文前面已介绍后,这里就不再
多说了。当然这里还有双方互评时的页面逻辑和方法没有介绍,这部分留到以后的“商品交易插件信用机制”一
文中再详加说明。
好了,今天的内容就先到这里了,因为一些细节暂未详细描述,只是粗略的浏览了一遍,如果大家感兴趣
欢迎在回复中讨论。
tag : discuznt, mall, 交易, trade
作者: 代震军, daizhj
原帖链接: http://www.cnblogs.com/daizhj/archive/2008/08/12/1265648.html