订阅计费的数据库设计

时间:2015-10-25 14:07:09

标签: database-design recurring-billing

寻找有关定期结算系统数据库基本设计的一些指导。

我提出的设计有一个表来存储下一个订阅周期(相同或新的计划,相同或不同的价格,或不续订),另一个存储应用的订阅(以什么价格购买什么产品。这就是我所拥有的:

Subscriptions
+----+------------+--------+-----------------+------------------+-------------------+
| ID | customerID | itemID | nextBillingDate | nextBillingPrice | notRenewingReason |
+----+------------+--------+-----------------+------------------+-------------------+
|  1 |         10 |      2 | NULL            |              280 | Too expensive     |
|  2 |         10 |      3 | NULL            |              120 | Too expensive     |
|  3 |         11 |      2 | 2015-06-18      |              290 |                   |
|  4 |         10 |      2 | 2016-10-14      |              290 |                   |
+----+------------+--------+-----------------+------------------+-------------------+


SubscriptionHistory

+----+--------+------------+------------+-------+--------------+-------+
| ID | subsID | startDate  |  endDate   | price | extInvoiceID | paid  |
+----+--------+------------+------------+-------+--------------+-------+
|  1 |      1 | 2012-09-04 | 2013-09-03 |   280 | 81654        | TRUE  |
|  2 |      2 | 2013-03-01 | 2013-03-31 |     0 | NULL         | TRUE  |
|  3 |      2 | 2013-04-01 | 2013-09-03 |   120 | 81812        | TRUE  |
|  4 |      1 | 2013-09-04 | 2014-09-03 |   280 | 84221        | TRUE  |
|  5 |      2 | 2013-09-04 | 2014-09-03 |   120 | 84221        | TRUE  |
|  6 |      3 | 2014-06-18 | 2015-06-17 |   290 | 85312        | TRUE  |
|  7 |      4 | 2015-10-14 | 2016-10-13 |   290 | 87421        | FALSE |
+----+--------+------------+------------+-------+--------------+-------+

它必须支持以下用例:

  1. 订阅为期一年或三年
  2. 客户订阅产品计划
  3. 客户可以订阅多种产品
  4. 产品的附加组件可以包含在订阅中
  5. 可以通过订阅部分添加加载项
  6. 可以在订阅期间将附加组件作为试用添加一段时间
  7. 有些订阅可能会降低费率(例如,因特殊情况而同意免费第二次订阅)
  8. 续订时,计划,附加组件和价格可能会发生变化
  9. 能够记录不续订的原因
  10. 任何客户都应该可以看到完整的历史记录,例如在上面的数据库中您可以看到客户10:

    • 加入2012-09-04
    • 在一个月的试用期后,在2013-04-01添加了订阅附加组件
    • 没有更新太昂贵,于2014-09-03过期
    • 2015-10-14以更高的价格再次订阅,未付款
  11. 任何指针?

1 个答案:

答案 0 :(得分:4)

这是一个包含你的插件的表格。你没有明确说你的插件花钱,但你提到了这一点,所以我已经包含了一个价格。我还假设插件与特定产品相关联。如果您的插件随着时间的推移而发生变化,我会在此表中显示beg_dateend_date,就像在product表中一样。

addon
    id              unsigned int(P)
    product_id      unsigned int(F product_id)
    description     varchar(255)
    price           double

+----+------------+-----------------+-------+
| id | product_id | description     | price |
+----+------------+-----------------+-------+
|  1 |          1 | This is addon 1 | 11.25 |
|  2 |          1 | This is addon 2 | 22.50 |
|  3 |          1 | This is addon 3 | 15.00 |
| .. | .......... | ............... | ..... |
+----+------------+-----------------+-------+

只是一个普通的旧customer表...

customer
    id              unsigned int(P)
    salutation      varchar(4)
    first_name      varchar(50)
    ...

+----+------------+------------+-----+
| id | salutation | first_name | ... |
+----+------------+------------+-----+
|  1 |        Mr. |       John | ... |
|  2 |       Mrs. |       Jane | ... |
| .. | .......... | .......... | ... |
+----+------------+------------+-----+

以下是每个客户购买或试用过的所有addon。在此示例中,end_date默认为NULL,并且在客户停止使用插件之前,其中没有值。或者,您可以根据关联的end_date设置为过期的时间填写product。请注意,客户为插件1支付了全价,没有用于插件2(因为他们只是试用了它),他们以折扣价格获得了插件3。

customer_addon
    id                      unsigned int(P)
    customer_id             unsigned int(F customer.id)
    addon_id                unsigned int(F addon.id)
    beg_date                date
    end_date                date // default NULL
    price                   double
    renewed                 enum('f','t')
    decline_reason_id       unsigned int(F decline_reason.id)

+----+-------------+----------+------------+------------+-------+---------+-------------------+
| id | customer_id | addon_id | beg_date   | end_date   | price | renewed | decline_reason_id |
+----+-------------+----------+------------+------------+-------+---------+-------------------+
|  1 |           1 |        1 | 2015-01-10 | 2016-01-10 | 11.25 |       f |                 1 |
|  2 |           1 |        2 | 2015-01-10 | 2015-02-10 |  0.00 |       f |                 2 |
|  3 |           1 |        3 | 2015-10-25 |       NULL | 10.00 |    NULL |              NULL |
| .. | ........... | ........ | .......... | .......... | ..... | ....... | ................. |
+----+-------------+----------+------------+------------+-------+---------+-------------------+

以下是每个客户购买的所有product。在这个例子中,我用{4}}填充订阅应该到期的计算日期。您可以看到客户支付了产品2的全价,但获得了产品3的折扣。

end_date

拒绝理由表。

customer_product
    id                      unsigned int(P)
    customer_id             unsigned int(F customer.id)
    product_id              unsigned int(F product.id)
    beg_date                date
    end_date                date
    price                   double
    renewed                 enum('f','t')
    decline_reason_id       unsigned int(F decline_reason.id)

+----+-------------+------------+------------+------------+-------+---------+-------------------+
| id | customer_id | product_id | beg_date   | end_date   | price | renewed | decline_reason_id |
+----+-------------+------------+------------+------------+-------+---------+-------------------+
|  1 |           1 |          2 | 2015-01-10 | 2016-01-10 | 25.00 |    NULL |              NULL |
|  2 |           1 |          3 | 2015-02-10 | 2018-02-10 | 75.00 |    NULL |              NULL |
|  3 |           1 |          4 | 2016-01-10 | 2017-01-10 | 28.00 |    NULL |              NULL |
| .. | ........... | .......... | .......... | .......... | ..... | ....... | ................. |    +----+-------------+------------+------------+------------+-------+---------+-------------------+

decline_reason id unsigned int(P) description varchar(50) +----+----------------+ | id | description | +----+----------------+ | 1 | Too expensive | | 2 | Didn't like it | | .. | .............. | +----+----------------+ 可以订阅的所有计划的表格。您会注意到有两个Plan 1产品 - 第一个Plan 1从2013年1月1日到2014年1月1日提供,价格为20.00美元。下一个计划1于2014年1月1日生效,但成本为25.00美元。随着时间的推移,许多产品/服务的价格会上涨,这是“版本化”产品的一种方式。

customer