订阅计费的数据库设计

Mar*_*cus 8 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 |
+----+--------+------------+------------+-------+--------------+-------+
Run Code Online (Sandbox Code Playgroud)

它必须支持以下用例:

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

    • 加入2012-09-04
    • 在一个月的试用期后,在2013-04-01上添加了订阅的附加组件
    • 没有更新太贵,所以在2014-09-03过期
    • 2015-10-14再次以更高的价格订购,付款未付

有什么指针吗?

Ben*_*ill 8

这是一个包含您的插件的表格。你没有明确说你的插件需要花钱,但你暗示了这一点,所以我已经包含了一个价格。我还假设插件与特定产品相关联。如果你的插件随着时间的推移而改变,我会在这个表中像在表中一样有一个beg_date和。end_dateproduct

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 |
| .. | .......... | ............... | ..... |
+----+------------+-----------------+-------+
Run Code Online (Sandbox Code Playgroud)

只是一张普通的旧customer桌子......

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

+----+------------+------------+-----+
| id | salutation | first_name | ... |
+----+------------+------------+-----+
|  1 |        Mr. |       John | ... |
|  2 |       Mrs. |       Jane | ... |
| .. | .......... | .......... | ... |
+----+------------+------------+-----+
Run Code Online (Sandbox Code Playgroud)

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 |
| .. | ........... | ........ | .......... | .......... | ..... | ....... | ................. |
+----+-------------+----------+------------+------------+-------+---------+-------------------+
Run Code Online (Sandbox Code Playgroud)

product是每位顾客购买过的所有商品。在此示例中,我end_date使用订阅应到期的计算日期进行填充。您可以看到客户为产品 2 支付了全价,但为产品 3 提供了折扣。

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 |
| .. | ........... | .......... | .......... | .......... | ..... | ....... | ................. |    +----+-------------+------------+------------+------------+-------+---------+-------------------+
Run Code Online (Sandbox Code Playgroud)

拒绝原因表。

decline_reason
    id              unsigned int(P)
    description     varchar(50)

+----+----------------+
| id | description    |
+----+----------------+
|  1 | Too expensive  |
|  2 | Didn't like it |
| .. | .............. |
+----+----------------+
Run Code Online (Sandbox Code Playgroud)

A table of all the plans to which customer's could have subscribed. You'll note there are two Plan 1 products - the first Plan 1 was offered from January 1, 2013 to January 1, 2014 and was $20.00. The next Plan 1 became effective January 1, 2014 but cost $25.00. Many products/services go up in price over time, this is one way to "version" your products.

product
    id              unsigned int(P)
    description     varchar(255)
    term            unsigned int
    price           double
    beg_date        date
    end_date        date

+----+-------------+------+--------+------------+------------+
| id | description | term | price  | beg_date   | end_date   |
+----+-------------+------+--------+------------+------------+
|  1 | Plan 1      |    1 | 20.00  | 2013-01-01 | 2014-01-01 |
|  2 | Plan 1      |    1 | 25.00  | 2014-01-01 | 2015-02-12 |
|  3 | Plan 2      |    3 | 100.00 | 2015-01-01 | 2015-09-15 |
|  4 | Plan 3      |    1 | 35.00  | 2015-01-01 | 2017-01-01 |
| .. | ........... | .... | ...... | .......... | .......... |
+----+-------------+------+--------+------------+------------+
Run Code Online (Sandbox Code Playgroud)

  • 伙计们,我知道这已经很旧了,但我找不到任何与 SaaS 产品相关的数据库设计的架构讨论相近的内容。Marcus 和 @BennyHill – 有没有什么资源可以推荐您阅读有关该主题的内容(显然,除了这个线程 - 这是黄金)? (2认同)