2

我正在编写一个应用程序来管理酒店的房间,我必须设计数据库来管理折扣价。我已经制作了 Room 和 Price 表,现在我必须创建一些表,我可以在其中存储管理员可以根据某些条件应用的折扣。管理员也可以创建新的折扣。例如:

  • 如果预订在 9 月开始,用户可以获得 10% 的折扣。
  • 如果用户在 2 周内预订房间,则可以获得 10% 的折扣

所以,这是我的简化表格(我省略了与问题无关的字段和关系):

房间:

id | name
---|----------------
 1 | Trafalgar Square
 2 | Piccadilly

价格:

id | room_id  | base | promotion 
---|----------|------|-----------
 1 |    1     | 10   | 8
 2 |    2     | 25   | 20

如何存储上述条件?我正在使用 Rails,我想到的第一个解决方案是创建一个表,我可以在其中存储要应用的折扣以及应用它的条件。我认为字段条件是一个 SQL 片段;之类Reservation.start_date > [date]的,因此我可以在 Rails 中应用更多折扣将它们连接起来。但这是一个非常丑陋的解决方案,并且与 DBRMS 相结合,所以我想避免这种选择。

你知道我怎样才能解决这个问题吗?我希望已经清楚地解释了这个问题。

4

4 回答 4

2

我强烈建议您调查使用某种类型的规则引擎来处理此问题。

问题在于,与许多行业一样,酒店使用极其灵活的定价方式。其中一些似乎异想天开,另一些与思想几乎没有相似之处,而且所有这些都很难为其创建结构化的方法。

例如,如果预订了一晚,并且客户在晚上 11:00 之后进行预订,则客房可享受 10% 的折扣……除非是周五或周六晚上,或者酒店的客流量为 80% 以上。

如果标准折扣为 15% 的 1 月份,此规则可能会中断。

如果计划在城里举行会议,该规则可能会被打断。届时房价将提高 30%。


另一种方法是简单地放弃让系统自动计算房价,而是依靠酒店工作人员在预订时进行设置。在这种情况下,您只需显示有关当前“特价商品”的一些指南。

诚然,这并不像自动进行那样性感,但如果有问题的酒店不打算购买已经这样做的 COTS,那么他们可能不会支付适当开发它所需的成本。

于 2012-05-21T21:16:23.213 回答
2

绝妙的问题。

我从来没有做过酒店预订系统,但做过有折扣策略的电子商务项目,坏消息是这很快就会变得非常复杂。

例如,您可能有多个适用于给定预订的折扣,您需要确定它们是累积的还是互斥的(如果有“每次预订的 10%”折扣,并且预订符合“新-wed 25% offer”,你给 10%、25% 还是 35%?)。如果你必须处理税收,那就更奇怪了——如果总预订中有多种产品,税率不同,你如何在应用折扣后计算税收?

如果您正在构建一个允许用户指定新的(类型的)折扣的系统,以及与之相关的所有规则,那么您的项目将变得相当大,非常复杂,并且痴迷于折扣引擎。

如果这就是您所处的世界,请接受@Chris Lively 的回答。投资一个规则引擎,并准备花下一段重要的时间来解释折扣是如何工作的,“and”、“or”、“xor”等是什么意思。

不过,理想情况下,您可能会花费更多时间来完善当前的实际需求。如果您只需要解决 5 个真实示例,则选项比构建通用折扣引擎要有限得多。查看策略模式和复合模式。如果它不是“通用目的”,那么制定“2012 年夏季”折扣策略并使用硬编码而不是存储在数据库中的有效日期并不可耻。

于 2012-05-21T21:42:42.053 回答
2

通常情况下,预订人员有权应用不同的折扣。换句话说,折扣规则只是回顾性的抽查。

让系统自动检查给定折扣的资格将很快变成:

  • 太复杂而无法理解(对于试图添加新折扣及其规则的管理员而言)
  • 实施系统过于复杂(需要预测不断增长的情况列表)
  • 太脆弱(总会有完全合理和适当的“例外”。)
  • 一些折扣是不可能的。例如,某人如何“证明”他们正在参加婚礼并因此有资格获得婚礼团体的折扣。

折扣通常是营销问题。在这种情况下,您想知道客户要求的折扣(“琼斯婚礼折扣”),而不是通过规则严格控制折扣的资格。

折扣系统的一个更有用的方面是让登记系统查看折扣是否要求客户出示折扣资格证明,如果需要,则提示登记员。例如,如果在预订中使用公司的合同折扣率,则要求提供员工 ID。

酒店预订和房间管理系统非常复杂。您应该了解酒店为什么不使用 COTS(现成的商业)软件。

于 2012-05-21T21:58:56.477 回答
1

这是我评论的扩展版本。我同意在数据库中放入 SQL/可执行代码通常是一个坏主意,我认为在这种情况下你可以避免这种情况。

我会这样做:

晋升
-------------------------------------------------- ----------
标识 (pk) | 短名称 (uniq) | 参数?| 序列化参数?
1 | 九月促销| ... |
2 | 长期住宿 | ... |
-------------------------------------------------- ----------

room_promotion
-------------------------------------------------- --
room_id (fk) | Promotion_id (fk) | 序列化参数
1 | 1 | {折扣=10;开始日期=x;结束日期=y }
2 | 2 | { 长度=14 }
-------------------------------------------------- --

这种方法为您可能想要运行的促销类型提供了最大的灵活性。由于每个促销活动都有许多取决于业务逻辑的参数,我建议在每个房间的情况下,您有一列序列化参数,因此该表中没有大量未使用的列。请记住,这确实打破了一些关系规则,但谨慎使用并意识到其局限性,这是一种有用的方法

您同样可以针对每个促销行设置参数或序列化参数(例如,如果您知道“long_stay”促销的所有使用期限为 14 天)。

请注意,我已经安排了“room_promotion”表,以便可以将多个促销活动应用于一个房间。(room_id, promotion_id)如果您确定一个主键始终只适用于一次,您可以创建一个主键。

好的,现在您有了一个可以应用“促销规则”的机制。但是,业务逻辑仍然属于您的代码。因此,查找短名称,驼峰式,然后使用 Ruby 中的动态查找机制来应用折扣。我不使用 Ruby,但在 PHP 草图形式中它可能看起来像这样:

    获取对象 $Bill(在应用折扣之前)
    $Discount = DiscountFactory::getInstance(
        'september_promo',
        反序列化($序列化)
    );
    $Bill->applyDiscount($Discount);
    显示修改后的账单

在内部,我认为september_promo会转换为SeptemberPromo,因此这是一个类(对不起,再次是 PHP):

类九月促销扩展促销
{
    // 这里添加抽象方法的具体实现
    公共函数 executeDiscount($Bill) { ... }
}

反过来,Promotion 可以有一个抽象方法,用于根据applyDiscount()每个房间的价值、每个促销的价值和账单的详细信息来确定要应用的折扣。

只要您保持折扣业务逻辑相当通用,您的酒店经理就可以使用序列化参数对其进行自定义,而不需要为每个新促销活动都需要新的 Ruby 代码(除非他们想要一个新的促销类型)。考虑到这一点,SeptemberPromo可能过于具体 - 也许MonthSpecial

显然,您需要构建一个 UI 来让酒店经理存储新的promotionroom_promotion行,但这应该很容易。

于 2012-05-21T20:59:14.550 回答