我正在为租赁发票生成创建一些数据库模型。 发票包含N个预订时间范围。
每个预订都属于价格模型。价格模型是一组确定最终价格的规则(基价+季节价格+数量弃用+ ...)。
这意味着发票中N个预订的最终价格可能是一个复杂的计算,当然我想跟踪最终价格计算的各个方面,以便以后查看发票。
问题是,价格模型将来可能会发生变化。因此,在生成发票时,有两种可能性:
(a)永远不要更改价格模型。只需通过版本化使其变为不可变,并从发票中引用具体版本。
(b)将所有价格信息,折扣和额外费用放入发票中。这意味着很多数据,因为发票包含N个预订,可能部分在季节价格的范围内。 基本上,我会将每个预订细分为日期,每天我会有N行计算基本价格,折扣和额外费用。
可能的表格型号:
Invoice
id: int
InvoiceBooking # Each booking. One invoice has N bookings
id: int
invoiceId: int
(other data, e.g. guest information)
InvoiceBookingDay # Days of a booking. Each booking has N days
id: int
invoiceBookingId: id
date: date
InvoiceBookingDayPriceItem # Concrete discounts, etc. One days has many items
id: int
invoiceBookingDayId: int
price: decimal
title: string
我的问题是,我应该选择哪种方式以及为什么。
我的考虑因素:
使用解决方案(a),每次查看数据时,都会使用价格模型信息重新计算发票。我不喜欢这样,因为算法可以改变。对于"只读"并不自然。发票的性质。 此外,价格模型的版本处理不是一项简单的任务,用户需要了解版本概念,这会增加应用程序的复杂性。
使用解决方案(b),我会生成一堆嵌套数据,这会给架构增加很多复杂性。
您更喜欢哪种方式?我错过了什么吗?
谢谢
答案 0 :(得分:2)
我推荐第三种选择。我称之为临时(时间)版本控制,表格的布局非常简单。您没有描述您的定价数据,所以我只是展示一个简单的例子。
Table: DailyPricing
ID EffDate Price ...
A 01/01/2015 17.50 ...
B 01/01/2015 20.00 ...
C 01/01/2015 22.50 ...
B 01/01/2016 19.50 ...
C 07/01/2016 24.00 ...
这表明所有三个价格表(A,B和C仅代表您用来区分价格水平的任何方法)都在2015年1月1日给出了价格。2016年1月1日,B计划的价格是降低。 7月,计划C的价格上涨了。
要获取计划的当前价格,查询为:
select dp.Price
from DailyPricing dp
where dp.ID = 'A'
and dp.Effdate =(
select Max( dp2.EffDate )
from DailyPricing dp2
where dp2.ID = dp.ID
and dp2.EffDate >= :DateOfInterest);
DateOfInterest
变量将加载当前日期/时间。此查询返回当前有效的一个价格。在这种情况下,2015年1月1日的价格自生效以来从未改变。如果搜索是针对计划B,则2016年1月1日设定的价格将被退回,而计划C将于2016年7月1日设定价格。这些是为每个计划设定的最新价格;也就是说,当前的价格。
这样的查询更可能是与发票表的联接,因此您可以执行价格计算。
select ...
from Invoices i
join DailyPricing dp
on dp.ID = i.ID
and dp.Effdate =(
select Max( dp2.EffDate )
from DailyPricing dp2
where dp2.ID = dp.ID
and dp2.EffDate >= i.InvoiceDate )
where i.ID = 1234;
这比简单查询稍微复杂一点,但是您要求更复杂的数据(或者更复杂的数据视图)。但是,此计算可能只执行一次,最终价格存回发票数据或其他地方。
只有在客户进行了一些更改或您正在进行审核时,才会再次计算,重新检查计算的准确性。
然而,注意一些微妙但非常重要的东西。如果正在为刚刚创建的发票执行上述查询,则InvoiceDate将是当前日期,并且返回的价格将是当前价格。但是,如果查询是作为两年前发票上的验证运行的,那么InvoiceDate将在两年前,而且返回的价格将是两年前生效的价格。
换句话说,返回当前数据的查询和返回过去数据的查询是同一个查询。
这是因为当前数据和过去的数据保留在同一个表中,仅由数据生效的日期区分。我认为,这是关于你想做什么的最简单的解决方案。
答案 1 :(得分:1)
A 和 B怎么样?
重新计算发票的任何组成部分并非最佳做法,尤其是在打印组件时。发票和发票详细信息应该是不可变的,您应该能够重新生成它而无需重新计算。
如果您在弄清楚如何达到一定数量时遇到问题,或者您的计划中存在错误,您会很高兴获得详细信息,特别是如果计算结果复杂的话。 / p>
此外,保留定价模型的历史记录是一个好主意,这样您就可以验证如何达到特定价格。您可以向用户简化这一过程。他们不必查看历史记录 - 但您应该在历史记录中记录他们的更改。