
cobra
striver
-
个人空间
相册
- 性别:
- 来自:拼吾爱
- 积分:7098
- 帖子:7010
- 注册:
2007-04-09
|
DiscuzNT 商品交易插件设计之[线下交易流程]
在上一篇文章中,大略说明了一个商品的添加编辑和删除操作。本文会继承其支付流程来展示如何购买商品以及系统设计。 首先打开一个有效的商品,在商品显示页面中单击“立刻购买”按钮,如下:  附件: 您所在的用户组无法下载或查看附件 这样就会跳转到“确认购买信息”页面(buygoods.aspx),如下:  附件: 您所在的用户组无法下载或查看附件 在这个页面中,系统会执行如下操作: 1. 进行商品信息有效性校验(如未通过则显示相应提示信息,从而中止后续操作),如下: privatebool IsConditionsValid() { if (goodsinfo.Expiration <= DateTime.Now) { AddErrLine("非常抱歉, 该宝贝不存在或已经结束了!"); returnfalse; }
if (goodsinfo.Closed ==1) { AddErrLine("此商品已关闭!"); returnfalse; }
if (goodsinfo.Selleruid <=0) { AddErrLine("商品卖家信息错误!"); returnfalse; }
if (userid == goodsinfo.Selleruid) { AddErrLine("买卖双方不能为同一用户!"); returnfalse; }
if (goodsinfo.Displayorder ==-1) { AddErrLine("此商品已被删除!"); returnfalse; }
if (goodsinfo.Displayorder ==-2) { AddErrLine("此商品未经审核!"); returnfalse; }  2. 当点击“确认购买”时,进行购买数量校验以及与剩余数量比较判断,如下: //如果是提交 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; }   } 3. 创建商品交易日志(CreateTradeLog):   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 />"); }
  这里的 TradeLogs.CreateTradeLog(goodstradelog)方法内容如下: ///<summary> /// 创建商品交易日志 ///</summary> ///<param name="__goodstradelog">要创建的商品交易日志</param> ///<returns>创建的商品交易日志id</returns> publicstaticint 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> /// 根据交易日志的状态发送相应短消息 ///</summary> ///<param name="__goodstradelog">交易日志信息</param> ///<returns>是否发送成功</returns> publicstaticbool 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); } returntrue; } 上面的代码主要是根据交易日志的状态,向买卖双方发送相应的短消息。而交易的状态采用了支付宝 文档中所述的17种状态,其说明如下(位于Discuz.Entity项目下的Mall/GoodsrateinfoCollection.cs): ///<summary> /// 交易状态枚举 ///</summary> publicenum 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) 当用户点击“我已付款,等待卖家发货”按钮时,会显示“买家已付款,等待卖家发货”的提示信息如下图:  附件: 您所在的用户组无法下载或查看附件 如果这时卖家(登陆后)进入到当前交易页面时,会显示如下信息:  附件: 您所在的用户组无法下载或查看附件 这里如果卖家确认买家并点击“我已发货”按钮后,当前交易状态会成“卖家已发货,买家确认中(即: WAIT_BUYER_CONFIRM_GOODS = 5)。 这时当买家(登陆后)进入到当前交易页面时,会显示如下信息:  附件: 您所在的用户组无法下载或查看附件 当买家最终确认并收货之后,点击“我收到货,交易成功结束”按钮,当前交易状态会变成“交易成功结束” (RADE_FINISHED = 7)。如下所示:  附件: 您所在的用户组无法下载或查看附件 这样本次交易流程基本上就结束了,当然最后买卖双方还要互评,以便为“信用机制”提供有效信息。如下 图(点击上图中的“评价”按钮):  附件: 您所在的用户组无法下载或查看附件 当买卖双方评价完成后,交易变成了“双方已评” 这时,当我们点击“商品显示页面”中的“信用链接”(如下图):  附件: 您所在的用户组无法下载或查看附件 系统会进入到“信用页面(eccredit.aspx)”, 如下图:  附件: 您所在的用户组无法下载或查看附件 在这里,我们就可以看到当前商品的卖家和买家信用,以及按时间(最近一周,一个月,六个月等)所获 得的“好,中,差”评的次数以及相应的评价内容。此外还包括"好评率”,“给他人评价”等信息。 这样,我们基本上完成了一个交易流程(线下交易,注:退货退款等交易中止流程本文未进行说明,大家可 安装之后一用便知)。 当然,我们这里在处理交易的页面中,只是在买卖双方的推动下,不断更新交易状态的过程,因为下面简要 介绍一下Discuz.Mall/Pages/offlinetrade.cs(线下交易页面)的代码: 首先是IsConditionsValid方法,该方法用户校验买家或卖家身份以及交易和商品的信息有效性,如下: 首先是 IsConditionsValid方法,该方法用户校验买家或卖家身份以及交易和商品的信息有效性,如下: privatebool IsConditionsValid() { if (goodstradelog.Offline ==0) { AddErrLine("当前交易为在线交易!"); returnfalse; }
//当前用户为买家时 if (goodstradelog.Buyerid == userid) { isbuyer =true; }
//当前用户为卖家时 if (goodstradelog.Sellerid == userid) { isseller =true; }
//当前用户既不是买家也不是卖家 if (!isbuyer &&!isseller) { AddErrLine("当前用户身份既不是买家也不是卖家!"); returnfalse; }
if (goodstradelog.Buyerid <=0) { AddErrLine("商品买家信息错误!"); returnfalse; }
if (goodstradelog.Sellerid <=0) { AddErrLine("商品卖家信息错误!"); returnfalse; }
int goodsid = goodstradelog.Goodsid; // 如果商品ID无效 if (goodsid <=0) { AddErrLine("无效的商品ID"); returnfalse; }
goodsinfo = Goods.GetGoodsInfo(goodsid);
if (goodsinfo.Displayorder ==-1) { AddErrLine("此商品已被删除!"); returnfalse; }
if (goodsinfo.Displayorder ==-2) { AddErrLine("此商品未经审核!"); returnfalse; }
if (goodsinfo.Expiration <= DateTime.Now) { AddErrLine("非常抱歉, 该商品不存在或已经到期!"); returnfalse; }
returntrue; } 当通过上面方法的校验并实例化相应的交易信息后,则进行更新当前交易状态的操作,其调用代码如下 ( Discuz.Mall/Pages/offlinetrade.cs): if (TradeLogs.UpdateTradeLog(goodstradelog, oldstatus, true)) { SetUrl("offlinetrade.aspx?goodstradelogid="+ goodstradelogid); SetMetaRefresh(); AddMsgLine("交易单已更新, 现在转入交易单页面<br />(<a href="""+"offlinetrade.aspx?goodstradelogid="+ goodstradelogid +""">如果您的浏览器没有自动跳转, 请点击这里</a>)<br />"); } 下面介绍一下 TradeLogs.UpdateTradeLog方法,该方法执行更新交易状态的操作(相关内容见注释): ///<summary> /// 更新交易信息 ///</summary> ///<param name="__goodstradelog">要更新的交易信息</param> ///<param name="oldstatus">更新之前的状态</param> ///<param name="issendpm">更新交易信息成功后, 是否发送短消息</param> ///<returns>是否更新成功</returns> publicstaticbool 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> publicstaticbool 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); }
当前在交易状态更新完成后,会最终发送短消息给买家或卖家,其方法在本文前面已介绍后,这里就不再 多说了。当然这里还有双方互评时的页面逻辑和方法没有介绍,这部分留到以后的“ 商品交易插件信用机制”一 文中再详加说明。 好了,今天的内容就先到这里了,因为一些细节暂未详细描述,只是粗略的浏览了一遍,如果大家感兴趣 欢迎在回复中讨论。 作者: 代震军, daizhj 原帖链接: http://www.cnblogs.com/daizhj/archive/2008/08/12/1265648.html| 感谢原创者的辛勤劳动,希望对您有所帮助,转载请注明原出处。 |
|