最近公司要求完善我们商城的运费模板功能,使运费计算更加精确。我接到任务之后就着手分析,到目前为止已实现了一部分。现在把相关的东西记录在这里,为了方便日后自己查看,也希望能够帮助部分初学者,给他们一个个参照;在功能上有不同想法的人希望不要吝惜自己的智慧,能够在评论中提点一二。
刚接到任务,我是想当然的根据公司的业务来分析的,感觉到很复杂,逻辑不清不楚,各种关系也理不顺。之后我就从淘宝的运费模板去分析,还有淘宝开放平台上的运费模板API,里面有数据结构,再结合ECShop等有名的开源电子商城系统的运费模板的设计方法去分析,然后把分析到的各种逻辑、关系在纸上记录下来;比如有几个对象,有哪些属性,各个对象之间的关系,有哪些约束条件等等一一记录下来,你用甘特图也好,用草图也行,但是一定要自己看得懂,最好别人也看得懂,我是用草图画的,因为这个功能是我一个人单独来实现,所以我自己能看懂就行了。之后我根据自己画的草图就整理出来了概要设计说明书,因为这只是一个功能,所以我并没有按照软件工程的那种格式去写这个概要说明书,而是把一些必须要记录的重点的东西记录下来,整理的一篇文档而已。我这个设计基本是按淘宝的来的,但是跟它的数据结构不一样,下面我把它贴出来。
一:需求说明
1.1 用户需求说明
客户在商城下单的时候能够能够根据客户选择的运送方式和用户所在地区自动计算运费
1.2 设计需求和约束说明
1:模板有包邮和不包邮两种,不包邮需要自己定义;
2:计价方式分为按件数、按重量两种;(业务的特殊性,不需要按体积计价)
3:运送方式有EMS、天天快递、顺丰快递、赣农速配四种;(赣农速配是自有物流,其他三种是合作物流)
4:一个运费模板可以有多个运送方式,每种运送方式必须要有一种运送到全国的默认运费,非默认的运费需要设置地区
5:每个运费模板可以设置是否指定条件包邮,并且多种条件可以同时存在
6:每个产品必须绑定一个运费模板
二:页面设计(参照淘宝的运费模板页面设计)
2.1 列表页
2.2 新增页和编辑页
三:数据结构
3.1 模板表设计(FareTemplate)
列名
|
数据类型
|
空值
|
默认值
|
备注
|
ID
|
int
|
Not null
|
|
主键
|
模板名称
|
string
|
Not null
|
|
|
宝贝地址
|
string
|
Not null
|
|
|
发货时间
|
Datetime
|
null
|
|
几小时内发货 |
是否包邮
|
bit
|
|
否
|
不包邮约束运送方式不能为空
|
计价方式
|
int
|
Not null
|
|
按件数、按重量、按体积
|
是否指定条件包邮
|
bit
|
Not null
|
否
|
|
3.2 包邮条件表(InclPostageProviso)
列名 |
数据类型 |
空值 |
默认值 |
备注 |
ID |
Int |
Not null |
|
主键 |
关联模板 |
Int |
Not null |
|
模板表外键 |
包邮地区 |
string |
null |
|
省-市-区 |
包邮件数 |
Int |
Null |
|
|
包邮重量 |
Decimal |
Null |
|
单位KG |
包邮体积 |
Decimal |
Null |
|
单位m³ |
包邮金额 |
Decimal |
Null |
|
|
3.3 运送方式表(CarryMode)
列名 |
数据类型 |
空值 |
默认值 |
备注 |
ID |
Int |
Not null |
|
主键 |
关联模板 |
Int |
Not null |
|
模板表外键 |
运送地区
|
string
|
Not null
|
|
与地区表一对多关系
|
首件
|
int
|
null
|
|
依据计价方式来选择 |
首重
|
decimal
|
null
|
|
|
首体积
|
decimal
|
null
|
|
|
首费
|
decimal
|
Not null
|
|
|
续重
|
decimal
|
null
|
|
依据计价方式来选择 |
续体积
|
decimal
|
null
|
|
|
续件
|
int
|
Null
|
|
|
续费
|
Decimal
|
Not null
|
|
|
运送方式
|
Int
|
Not null
|
|
EMS、顺丰、天天等 |
是否默认
|
int
|
Not null
|
是
|
3.4 数据库实现代码
use nopCommerce go ------------ /*运费模板*/ ------------ --模板表-- create table FareTemplate ( Id int not null identity(1,1) primary key,--主键 Name varchar(20) not null ,--模板名称 ShopAddr varchar(100) null,--宝贝地址 DispatchTime varchar(20) null,--发货时间 IsInclPostage bit default(1),--是否包邮 ValuationModel int not null,--计价方式(1:按件 2:按重量 3:按体积) IsInclPostageByif bit default(0) --是否指定条件包邮 ) --包邮条件表-- create table InclPostageProviso ( Id int not null identity(1,1) primary key,--主键 FareId int not null foreign key(FareId) references FareTemplate,--模板表外键 Region varchar(50) null,--包邮地区(存id,格式为'省-市-区',以'|'分隔) PieceNo int null,--包邮件数 WeightNo decimal(18,2) null,--包邮重量 BulkNo decimal(18,2) null,--包邮体积 Amount decimal(18,2) null,--包邮金额 ) --运送方式表-- create table CarryMode ( Id int not null identity(1,1) primary key,--主键 FareId int not null foreign key(FareId) references FareTemplate,--模板表外键 Region varchar(50) null,--运送地区(存id,格式为'省-市-区',以'|'分隔) FirstPiece int null,--首件数量 FirstWeight decimal(18,2) null,--首重重量 FirstBulk decimal(18,2) null,--首体积大小 FirstAmount decimal(18,2) not null,--首费 SecondPiece int null,--续件 SecondWeight decimal(18,2) null,--续重 SecondBulk decimal(18,2) null,--续体积 SecondAmount decimal(18,2) not null,--续费 CarryWay int default(0),--运送方式(赣农速运,ems,顺丰,天天) IsDefault bit default(1) --是否默认的运送方式 ) --插入默认模板-- insert into FareTemplate(Name,ShopAddr,DispatchTime,IsInclPostage,ValuationModel,IsInclPostageByif) values('默认模板','江西省南昌市高新区','24小时','0','1','1') insert into InclPostageProviso(FareId,Amount) values('1','199') insert into CarryMode(FareId,FirstPiece,FirstAmount,SecondPiece,SecondAmount,CarryWay,IsDefault) values('1','1','8','1','2','0','1') insert into CarryMode(FareId,FirstPiece,FirstAmount,SecondPiece,SecondAmount,CarryWay,IsDefault) values('1','1','20','1','5','1','1') insert into CarryMode(FareId,FirstPiece,FirstAmount,SecondPiece,SecondAmount,CarryWay,IsDefault) values('1','1','22','1','10','2','1') insert into CarryMode(FareId,FirstPiece,FirstAmount,SecondPiece,SecondAmount,CarryWay,IsDefault) values('1','1','8','1','5','3','1') --插入权限-- insert into PermissionRecord(Name,SystemName,Category) values('运费模板管理','ManageFareTemplate','Configuration') --更新产品表并向产品表插入默认模板-- alter table Product add FareId int null foreign key(FareId) references FareTemplate --模板表外键 update Product set FareId=1 --查询模板-- select * from FareTemplate select * from CarryMode select * from InclPostageProviso
四:运费计算算法设计
4.1 单商品算法:判断是否包邮->判断是否满足条件包邮->根据客户选择的运送方式判断地区->没有所在地区则使用默认运费->求最大首费和最小续费
4.2 购物车算法:先计算单品的运送方式->求最大首费和最小续费
解释:一种商品可能存在多种合适的运送方式,最大首费就是这几种运送方式里的首费最大的值,最小续费类似。
基本的设计思想就是这些,希望大家能看懂,不清楚的可以评论留言,大家一起交流。我的实现是在.net平台使用MVC+EF技术来实现的,后续等我全部实现了之后,我会贴出部分实现的代码来一起交流。