I am curious what the best practice is. For example we have product entity, it has two fields: Price and VAT. What to save in Price value? Base price, and then calculate result price based on base price and VAT code. Or save calculated price and save VAT just for information purposes.
Without VAT, since it can change independently from prices.
Edit: by the way, why are you storing the VAT for each product? Isn't it better to categorize your products (if you have different types of VAT) instead?
Since VAT can change, I recommend storing the base price and the VAT percentage at the time of the sale. Then you can display the calculated price and the VAT percentage depending on what you need to report on.
Aside: The standard rate of VAT in the UK is due to change at the beginning of January 2011 from 17.5% to 20%, any solution should handle this kind of change.
The solution I've used previously is to have the following:
Product: NetPrice (MONEY, NOT NULL)
VATRateId (INT, NOT NULL, FK ->
VATRate.VATRateID)
VATRateVATRateId (INT, PK NOT NULL)
Description (TEXT NOT NULL)
VATRateValueVATRateValueId (INT, PK
NOT NULL)VATRate (MONEY NOT NULL)
EffectiveToDate (DATETIME NULLABLE)
That way I can store that Product X has a net price of 1.00, with a VAT Rate of {1, Standard Rate VAT}, which will apply the following rates { 17.5% until 2010/12/31, 20% thereafter}
The one thing this solution doesn't cater for is you changing the price of the product to ensure that, irrespective of the current VAT rate, the price always remaining at a certain "price-point" such as 4.99. What you could do here, for maxium flexibility (with increased complexity) is move the NetPrice field from the Product entity to a ProductPrice entity:
ProductPrice
ProductPriceId (INT, PK NOT NULL)
ProductId (INT, NOT NULL, FK -> Product.ProductId)
Price (MONEY, NOT NULL)
EffectiveToDate (DATETIME NULLABLE)
VAT in the UK has varied several times in the last year or so. I would keep Base Price separate from the variable VAT.
Product prices are best saved without VAT as already mentioned VAT rate can change independantly of prices, many of the databases I work on have the VAT rate(s) stored in a separate table, the price + vat is then calculated by picking a VAT rate from the VAT table.
Changes are easier to implement this way too, such as if the VAT rate changed from 17.5% to 20% you only have to change one row to have all your prices updated accordingly, rather than change every individual price.
If you store price + VAT, your database's integrity can be comprised if you update the VAT and forget to update the price + VAT. This won't occur if you store the raw price. In short, it is better not to store values that can be obtained by a calculation over the columns of a row.
In situations where there are three values to be stored in a database, such that knowing any two one can compute the third, I sometimes favor storing all three values along with an indicator of which two are "real" and which one is computed. The three values should always be equal; if they're not, one should examine what's going on and ascertain why.
For example, it may be useful to store timestamps as time zone, UTC, and local time, along with a "what is known" indicator. For example, if some time stamps are found to have been recorded using the wrong time zone, the "what is known" indicator can be used to determine whether the UTC or local time should be adjusted.
With regard to prospective rather than historical pricing information, I would think it might be helpful to store VAT-exclusive price, expected VAT, and VAT-inclusive price, along with a mode flag indicating various scenarios, such as
The VAT-inclusive price (VIP) should precisely track the VEP+VAT, to the nearest pence
The VAT-inclusive price (VIP) should precisely track the VEP+VAT, to the nearest 5p
The VAT-inclusive price (VIP) should precisely track the VEP+VAT, to the nearest 20p-1
The VAT-inclusive price (VIP) should precisely track the VEP+VAT, to the nearest 50p-1
The VAT-inclusive price (VIP) should precisely track the VEP+VAT, to the nearest 100p-1
The VAT-inclusive price should remain fixed if the VAT changes, but ip updating the VAT causes the VEP+VAT to exceed the VIP, the record should get flagged to suggest that someone consider increasing the VIP.
Basically, figure out what should happen if the VAT changes and adjust things accordingly.
Related
We would like to be able to add a extra price to the shipping (delivery) if a certain date was chosen. For example, if someone chooses 2/14/16 on the product page, we want to add $5 to the set BC delivery price in the checkout. Can this be done?
We already have a date picker communicating with BC that blocks delivery dates and sets daily cut off time for local delivery.
You cannot edit the order total at the point of checkout, except for two exceptions:
Coupon
Shipping
Since a coupon is used for decreasing the order total, this won't fit your use case.
So then I would recommend you somehow tie this $5 charge into a shipping method, and then select that shipping method with JS somehow, or hide the others. For example, copy your current shipping methods and add a $5 handling fee to them, and then hide your original methods when the specific date is chosen. Vice versa.
I am designing a database for an app to sell parking spot use. Customer can order n number of uses of parking spot uses or pay a flat rate and use it for monthly/weekly or yearly. They can do mix of those also. Like they can buy 9 parking spot uses and later decide they will pay for the whole month - in which case their charges are kind of pro-rated.
For this, I have a Customer table, an Order Table and then an order type table. However, I am having a slightly hard time with the order-type table.
Can some one please shed light on how to model the rate and get available spot-uses for a customer?
I want to have a table that will track all the commissions we are due from our wireless sales. Each plan pays a different Commission, not a problem. We do our reconciliation as sometimes the carriers don't pay (they may miss a line or 2).
The problem occurs when the carriers change how much they pay for the commissions. We want to be able to go back and see that there was 4 lines not paid for in January at commission rate x. but Feb the same types of plans were sold but their commission rates were x-10.
If I change the rate in the commission table for the plan, when i go back to pull the data from the January report I will get incorrect commission rates.
I have a table for sales set up with a date stamp so I was thinking i can cross reference that somehow.
Hope someone followed this.
I am looking for the best way to structure this.
You should "STAMP" the record with the commission rate. You could either stamp the actual rate into every record... or you could keep a commission ID and put that into each record.
I am making a small personal application regarding my trade of shares of various companies.
The actions can be selling shares of a company or buying. Therefore, the details to be saved in both cases would be:
Number of Shares
Average Price
Would it be better to use separate tables for "buy" and "sell" or just use one table for "trade" and keep a field that demarcates "buy" from "sell"?
Definitely the latter case - one table, simple one field (boolean) defining whether it's selling or buying. You should define tables by entities, not by actions taken on them.
This is actually a tricky one. The table you're talking about is basically a trade table, detailing all your buys and sells.
In that sense, you would think it would make sense to have both buys and sells in a single table.
However, in many jurisdictions, there is extra information for a sell order. That piece of information is which buy order to offset it against (for capital gains or profit purposes). While this is not necessary in a strict first-bought, first-sold (FBFS) environment, that's by no means the only possibility.
For example, under Australian law, you can actually offset a sale against your most recent purchase, as long as you have the rationale written down in clear language before-hand. Even though my company follow FBFS, I am allowed to receive bonus issues or supplemental shares which I can then sell immediately. These are offset against the most recent shares bought, not ones I've held for X number of years (this is often handy to minimise taxes payable).
If you follow a strict FBFS, then you don't need that extra information and your trades are symmetrical. Even where they're not, I've implemented it in one table with the extra information, useless for buy orders of course. That seemed the easiest way to go.
You could do it as two asymmetrical tables but that makes queries a bit more problematic since you often need to pull data from both tables. My advice is to stick with a single table with the extra information if needed.
I would also never store the average price. I prefer the quantity, the price per share and the brokerage costs. Every other figure can be calculated from those three, for example:
AvgPrice = (Brokerage + SharePrice * ShareQuant) / ShareQuant
but it's sometimes impossible to work backwards from just the average price, since you don't know what the brokerage was.
And I wouldn't have a boolean for buy/sell, it's just as easy to use negative numbers for the sell orders and it makes balance-sheet-type calculations a lot easier since you just sum values irrespective of the order type instead of needing to negate some of them depending on that order type.
Update: If, as you seem to indicate, you're only going to store aggregate information for each company, I would go for the following:
Companies:
CompanyId primary key
CompanyCode indexed
CompanyName
CompanyBuyQuant
CompanyBuyAvgPrice
CompanySellQuant
CompanySellAvgPrice
then you update the individual columns depending on whether it's a buy or sell. You don't need a separate row for the buy/sell stuff. When the company is first added, both quantities and prices are set to 0.
Your entity is now the company so this makes more sense. One thing you may want to consider is to store the aggregate values of shares bought and sold rather than the average buy and sell prices. That will simplify your update calculations and you can still easily get the averages by dividing the aggregate by the quantity.
So, the following table:
Companies:
CompanyId primary key
CompanyCode indexed
CompanyName
CompanyBuyQuant
CompanyBuyValue
CompanySellQuant
CompanySellValue
When adding a company, set all quanities and values to 0,
When buying M shares at N dollars each, add M to CompanyBuyQuant and N * M to CompanyBuyValue.
When selling M shares at N dollars each, add M to CompanySellQuant and N * M to CompanySellValue.
Get average buy price as CompanyBuyValue / CompanyBuyQuant.
Get average sell price as CompanySellValue / CompanySellQuant.
I'd go with a single table.
You can use negative quantities to indicate a sell. This is a fairly standard sort of indication. Subtraction is the same as adding a negative number!
One table. Each row/item is a trade, whether it's buy or sell.
Also, the aggregate of the quantity column will give you your current position. And cash too (-1 x quantity x price**) aggregated.
Buy or sell if inferred by the sign of the quantity: no need for separate column, unless you want to make a computed column derived from quantity.
**cash: When you sell (negative quantity) you get cash back (positive cash), hence -1 multiplier in case anyone wonders.
"Trade" can be ambiguous and it's not entirely clear to me what you want to do here. Are you interested in storing only your current position in each share or also the history of transactions that show how the position developed?
If you just want to record your holding ("position" might be a better word if you can be short) then I'd simply record for each share the number held. You mention average price, but I'd be cautious about that if you expect at any time to be able to sell part of a holding. What's the average price if you buy 100 at 50, 100 at 60 and sell 50 at 70?
Unless you expect your buy and sell transactions to number in the millions, I'd be more inclined to record each individual purchase or sale as a separate row in a single table and show the totals on demand as the derived results of a simple query.
I have a quote that contains items (store in table QuoteItem):
QuoteItemId, QuoteId, ItemId, Quantity etc.
Now, I need to be able to create a group of chosen items in the quote and apply a discount on it.
Well that's simple, I create two more tables:
Group: GroupId, DiscountPercentage
GroupQuoteItem: GroupId, QuoteItemId
Let's say I have 30 items in a quote.
I made a group that contains items 1-20 from the quote and I applied a discount on it.
Now I need to have another group that contains items 10-30, the problem is about those inner 10 items, I need to control whether the discount should apply on the items after the other discount or it should be on the items' base price.
For instance, I am gonna talk about item no. 15 in the quote: QuoteItem.Cost = 100
I applied 1st discount of 10% = 90.
Now I want to apply the second discount, I need to be able to control if the discount should be on the 100 or should be on the 90.
Same is when I have multiple discount groups and when I wanna apply a complex architecture of discounts.
Any assistance will be really appreciated.
I would look into adding a column to the GroupQuoteItem table, GroupQuoteItem.Priority. This column would be used in the query that determines the final price. If you have N discounts with the same, highest priority, they will be stacked atop each other (the order doesn't matter, thanks to associativity of multiplication).
If all of these high-priority discounts are later removed, lower-priority discounts can take their place. This should help you in setting up pretty complex discount structures.
I hope that at least gives you somewhere to start from.
It really depends on your own business rules. Do you want to apply the discounts on the price after discount or on the original price. When you ask questions like this it helps with SAMPLE Data then show us expected results.
This may be one of those rare times in normalization when you want to store data that you could calculate otherwise. So, in QuoteItem, you could have a Cost field and a DiscountedCost field. If they're the same, then you know no discount has been applied, if they are not, then a discount has been applied. By having this field, you would also be able to do comparisons on what the discount is already and whether you want to add the additional discount. In fact, you could also store that number in an ExistingDiscount field.
Why not store a column in the Group table that specifies whether or not the discount can be accumulated with other discounts versus if it must be applied to the base price only? You could name the field something like "ApplyToBasePriceOnly."
Other than that, I agree with JonH that a lot of this logic should be placed in business rules. I think your general database structure looks pretty good.