数据建模草稿/报价/订单/发票
Posted
技术标签:
【中文标题】数据建模草稿/报价/订单/发票【英文标题】:Data modelling draft/quote/order/invoice 【发布时间】:2011-08-07 06:25:20 【问题描述】:我目前正在做一个小项目,我需要对以下场景进行建模:
场景
-
客户来电,他想要一辆新车的报价。
销售代表。注册客户信息。
销售代表。在系统中创建报价,并将项目添加到报价(汽车)中。
销售代表。通过电子邮件将报价发送给客户。
客户接受报价,现在报价不再是报价而是订单。
销售代表。检查订单,一切正常,他为订单开具发票。该订单现在不再是订单,而是发票。
想法
我需要一些帮助来找出理想的建模方法,但我有一些想法。
-
我认为草稿/报价/发票基本上都是一个订单。
草稿/报价/发票需要单独的唯一编号(ID),所以我正在考虑为所有这些单独的表格。
型号
这是我的数据模型 v.1.0,请告诉我你的想法。
关注
不过,我对这个模型有些担心:
-
草稿/报价单/发票在订单行上可能有不同的项目和价格。在此模型中,所有草稿/报价/发票都连接到同一订单和订单行,因此不可能有单独的报价行/草稿行/发票行。也许我会为此制作新表,但是基本上相同的信息会存储在多个表中,这也不好。
有时两个或多个报价会变成发票,该模型将如何处理这个问题?
如果您对如何更好地建模有任何提示,请告诉我!
编辑:数据模型 v.1.4
【问题讨论】:
所有子类型共有的列应该向上移动到超类型中。如果每个子类型都有一个 subtype_date 列,它可能应该移到超类型中。 (删除 quote_date、order_date、invo_date;只需使用 stmt_date。)对于 subtype_canceled 也是如此。 order_id 和 invo_id 列需要保留在它们的子类型中,因为您需要考虑每个 id 号。 (没有间隙。)引号也可能是这样。我不知道。 好的,我明白了。以为我误会了。我在子类型中添加 order_date 的原因是我希望报价/订单/发票日期彼此不同,我还认为所有报价/订单/发票的声明都是相同的。但是我看到,对于您制作的每份报价/发票/订单,您也会做出一份声明,对吗?但是当报价被接受并需要变成订单时会发生什么?我是否只是创建一个新订单并复制报价详细信息,以便旧报价和新订单都存在?是否也是两个陈述,每个陈述一个?我可以将 Q 与 I 联系起来吗? 如果您以这种方式构建表格,“statement”中的每一行都是报价单、发票或订单。当报价“变成”订单时,您在可更新视图“订单”中插入一行(请参阅下面的答案),然后复制报价行项目。 (您只需要一个订单项表格;我稍后会尝试发布。)如果订单项从未有任何更改 - 这是一个hard never --您可以使用不同的、更简单的结构。 (我经常看到类似“是的,我们为此报价 39.95 美元,但我们感谢您的业务,因此我们将免费提供”之类的内容。) 而且,是的,您可以将报价与发票相关联。只需将报价单号(我想还有订单号)存储在发票子类型中。 所以您认为我应该在 Invoice 表中为 Quote-/OrderID 添加一个字段?如果没有报价或订单相关,那么这些字段将是空白的怎么办?那是好的数据库设计吗? 【参考方案1】:看起来您已经对这些事物中的每一个进行了建模——报价单、订单、草稿、发票——在结构上与所有其他事物相同。如果是这种情况,那么您可以将所有相似的属性“推送”到一个表中。
create table statement (
stmt_id integer primary key,
stmt_type char(1) not null check (stmt_type in ('d', 'q', 'o', 'i')),
stmt_date date not null default current_date,
customer_id integer not null -- references customer (customer_id)
);
create table statement_line_items (
stmt_id integer not null references statement (stmt_id),
line_item_number integer not null,
-- other columns for line items
primary key (stmt_id, line_item_number)
);
我认为这适用于您所描述的模型,但我认为从长远来看,将它们建模为超类型/子类型会更好地为您服务。所有子类型共有的列被“向上”推入超类型;每个子类型都有一个单独的表,用于记录该子类型独有的属性。
This SO question 及其接受的答案(和 cmets)说明了博客 cmets 的超类型/子类型设计。 Another question 与个人和组织有关。 Yet another 与人员配备和电话号码有关。
稍后。 . .
这还不完整,但我没时间了。我知道它不包括订单项。可能漏掉了别的东西。
-- "Supertype". Comments appear above the column they apply to.
create table statement (
-- Autoincrement or serial is ok here.
stmt_id integer primary key,
stmt_type char(1) unique check (stmt_type in ('d','q','o','i')),
-- Guarantees that only the order_st table can reference rows having
-- stmt_type = 'o', only the invoice_st table can reference rows having
-- stmt_type = 'i', etc.
unique (stmt_id, stmt_type),
stmt_date date not null default current_date,
cust_id integer not null -- references customers (cust_id)
);
-- order "subtype"
create table order_st (
stmt_id integer primary key,
stmt_type char(1) not null default 'o' check (stmt_type = 'o'),
-- Guarantees that this row references a row having stmt_type = 'o'
-- in the table "statement".
unique (stmt_id, stmt_type),
-- Don't cascade deletes. Don't even allow deletes. Every order given
-- an order number must be maintained for accountability, if not for
-- accounting.
foreign key (stmt_id, stmt_type) references statement (stmt_id, stmt_type)
on delete restrict,
-- Autoincrement or serial is *not* ok here, because they can have gaps.
-- Database must account for each order number.
order_num integer not null,
is_canceled boolean not null
default FALSE
);
-- Write triggers, rules, whatever to make this view updatable.
-- You build one view per subtype, joining the supertype and the subtype.
-- Application code uses the updatable views, not the base tables.
create view orders as
select t1.stmt_id, t1.stmt_type, t1.stmt_date, t1.cust_id,
t2.order_num, t2.is_canceled
from statement t1
inner join order_st t2 on (t1.stmt_id = t2.stmt_id);
【讨论】:
是的,我一开始就是这样,但后来我遇到了一个问题。我需要发票/草稿/报价单有单独的数字(ID)。订单和发票的编号系列需要与订单不同。 只是一个整数;你可以在里面放任何你想要的数字。如果您更改主键以使其成为(stmt_id,stmt_type),则可以为每种语句进行独立编号。但是你提出的问题正是超类型/子类型设计很好地解决的问题。订单号将进入实现子类型“订单”的表中;实现子类型“发票”的表格中的发票编号。 嗯.. 有道理。我已经更新了我的模型,请你看一下。 @Martin:我认为您需要再次阅读我链接的问题和答案。 @Catcall:我已经阅读了它们,我得到了它的插入部分。如果要创建报价,我在语句和报价表中添加一行。这很好,但我不能 100% 确定当报价变成订单/发票时,需要进行哪些操作?【参考方案2】:应该有一个表格“quotelines”,类似于“orderlines”。同样,您应该有一个“invoicelines”表。所有这些表都应该有一个“价格”字段(名义上将是零件的默认价格)以及一个“折扣”字段。您还可以在“报价”、“订单”和“发票”表中添加“折扣”字段,以处理现金折扣或特别优惠等事项。尽管您写了些什么,但最好有单独的表格,因为报价中的数量和价格可能与客户实际订购的不符,而且它可能与您实际供应的数量不同.
我不确定“草稿”表是什么 - 您可以将“草稿”和“发票”表结合起来,因为它们包含相同的信息,其中一个字段包含发票的状态 - 草稿或最终。将发票数据与订单数据分开很重要,因为您可能会根据收入(发票)纳税。
“Quotes”、“Orders”和“Invoices”都应该有一个字段(外键)来保存销售代表的值;该字段将指向不存在的“SalesRep”表。您还可以在“客户”表中添加一个“销售代表”字段,该字段指向客户的默认代表。该值将被复制到“报价”表中,但如果与默认值不同的代表给出报价,则可以更改它。同样,当根据报价生成订单并根据订单生成发票时,应复制此字段。
我可能会添加更多内容,但这完全取决于您想要制作的系统的复杂程度和详细程度。如果汽车根据其选项进行配置并相应定价,您可能需要添加某种形式的“材料清单”。
【讨论】:
感谢您的cmets,我已经更新了我的数据模型,您现在可以看一下吗? 'Orders' 应该有一个指向 'quotes' 的链接,而不是相反。顺序应该是报价 -> 订单 -> 发票(我省略了草稿,因为我认为没有必要),其中每个表格都包含指向前一个表格的链接。【参考方案3】:向 line_items 添加一个新列(例如:Status as smallint)
当 quote_line 变成 order_line 时,然后设置您从 0 到 3 到 1 选择的位。
但是当 qty 改变时,添加一个带有新 qte 的新行并保持最后一行不变。
卡德。
【讨论】:
以上是关于数据建模草稿/报价/订单/发票的主要内容,如果未能解决你的问题,请参考以下文章
SAP Cloud for Customer里Sales Order和Sales Quote的建模方式