Invoice & Invoice lines: How do you store customer address information?
Asked Answered
I

3

7

Hi I'm developing an invoicing application.

So the general idea is to have two tables:

Invoice (ID, Date, CustomerAddress, CustomerState, CustomerCountry, VAT, Total);

InvoiceLine (Invoice_ID, ID, Concept, Units, PricePerUnit, Total); 

As you can see this basic design leads to a lot of repetiton of records where the client will have the same addrres, state and country.

So the alternative is to have an address table and then make a relationship Address<-Invoice.

However I think that an invoice is immutable document and should be stored just the way it was first made. Sometimes customers change their addresses, or states and if it was coming from an Address catalog that will change all the previously made invoices.

So What is your experience?

How is the customer address stored in an invoice? In the Invoice table? an Address Table? or something else?

Can you provide pointers to a book, article or document where this is discussed in further detail?

Instance answered 2/6, 2010 at 0:22 Comment(0)
T
8

I would strongly recommend against storing any customer details like that in the Invoice.

Instead, I would have a structure like:

Customer table, with a primary key of id

Customer address table (as each customer may have different addresses over time), with the customer id as a foreign key

Invoice table, with an address field that is a foreign key to a customer address table.

BTW, I would consider adding a VAT field per line item. There are countries where there are different VAT rates for different item types.

Tube answered 2/6, 2010 at 0:23 Comment(7)
Don't you think an invoice table is almost like historical table and therefore duplication of information on how the invoice was originally printed is valid?Instance
@elviejo, arguably you are correct with that, but you have to evaluate whether you want to store the same info over and over, or whether you just store a foriegn key to the address that was used. If you store a foriegn key then it should mean that you cannot change old addresses once an invoice has been linked to it, instead any changes would have to become a new address record and you just maintain a flag on the address table which indicates that the address is active or not.Margarine
@elviejo You can also do this without having to alter the whole address maintenance process for your customers. At the time an order becomes an invoice, you can link to a customer entity AND an "anonymous" address entity (perhaps in both a bill-to and ship-to roles) which simply contains the address at the time of the invoice. You look up on all the address columns and get a surrogate key. This "address" history is never updated, only inserted. And previous addresses are simply re-used. Thus you get point-in-time data without having to alter your entire customer maintenance design.Mangosteen
@elviejo: From a legal point of view, duplication is clearly best since you can't "retroeactively" change data accidentally. In fact, paper copies are even better.Tube
@uri in this question: #317257 They make the point that storing calculated VAT is good practice. And I think the address would fail in the same category. maybe there is no definitive answer to this question?Instance
@elviejo: I think you misunderstood me about the VAT. My point was that VAT should be at the level of the line item, not just at the level of the entire invoice. For instance, in my state (PA) we pay a different tax level on each item we buy at the store. Meanwhile, at a restaurant, we pay a different tax to the state (for the food), and a different tax to the city (for alcohol). My point is that for better traceability/accounting, you may want to do taxes at a line item level rather than a whole invoice. For instance, if someone returns an item, you need to reimburse them whatthat they paid.Tube
Why do you have a foreign key to a customer address table in the Invoice table and not to the Customer table? I mean that Invoice table and Customer address table have the foreign key ref to the same primary key in the Customer table. I'am still learning.Frisian
S
2

Most standard product/order databases will have

a products table (ProductId, product info fields)  
a customers table (CustomerID, customer info like address etc) 
and an orders table  (OrderNumber, CustomerID, date, etc)

Then your order items become a many-many relationship table between orders and products.

orderItems (OrderNumber, ProductID, quantity, purchasePrice, vat, etc)

To get a full invoice you'd query the orders table and join it with the OrderItems table. OrderItem usually has purchase price and such because the price in the product table may change after the order is created and that information is often useful to store.

Saxon answered 2/6, 2010 at 0:31 Comment(1)
while I agree with your general design, I have been criticized in the past for the fact that orderItems does not follow normalization, in the sense that you will have thousands or millions (Billions?) of the same pieces of information in the productID, price, etc. How do you account for this or is this an example where normalization fails?Belding
P
1

I'd consider doing it with three tables: Customer, Invoice and Address, but construct it so that once an address is entered, it is never updated or deleted, only deprecated. You can have an IsDeprecated or IsActive boolean field in your address table. Then when you create an invoice, the invoice links to the CustomerID AND to the AddressID being used at the time. When the customer changes their address, you create a new record with a new AddressID and deprecate the old one with the boolean field. Or if you really want to keep good records and/or will ever need to look up this data, you could have an AddressActiveStartDate and AddressActiveEndDate, but this will make queries a little more complicated.

That way you still store the old address, with it still being linked to the customer for reference, while also allowing the customer to have more than one listed address (e.g. one for shipping, one for billing).

You can add more tables as necessary, e.g. Product, InvoiceLine, State, etc.

Platitudinize answered 2/6, 2010 at 0:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.