discount entity for ERD- onine shopping - mysql

I'm currently making an ER diagram for my product model. But I'm confused that the DISCOUNT needs an entity to connect with the product module or it can just be an attributes of the product?
my current product module:
the
PRODUCT
PRODUCT_ID(PK)
PRODUCT_NAME
PRODUCT_PRICE
PRODUCT_TYPE
PRODUCT_COLOUR
PRODUCT_SIZE
STOCK_UNIT (FK)
this is the entity i try to make for DISCOUNT
PRODUCT_ID (PK,FK)
ADMIN_ID(FK)
DISCOUNT_DATE
DISCOUNTED_PRICE
In my scenario, some of the specific product prices can be discounted with value/ per centage. But I am confused that do i need to put the discount value/percentage as an attribute or an entity in the product module because there are only some products that have the discounted price.
I hope that my explanation is clear enough ><

Based on question and comments, I suggest:
Discount Table
--------------
DISCOUNT_ID (PrimaryKey)
PRODUCT_ID (ForeignKey)
IsPERCENT (Bool)
DISCOUNT (Float|Double)
FROM_DATE (DateTime)
TILL_DATE (DateTime)
IsPercent should be True if discount is to calculated using Percentage.
Discount should be value (treated as percent or Currency depending on IsPercent)
Also in your program, validate that Discount value doesn't go above 100 if IsPercent is TRUE

Related

How can I deal with Coupon database design?

I have create a simple e-commerce via Laravel, and have some questions about COUPON database design, what I need as follows:
1- I need a normal coupon for checkout (when the user adds all products that he needs then put the coupon this will discount from the total price ). I'm done with this:
Schema::create('coupons', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('code');
$table->enum('type', ['percentage', 'numeric']);
$table->integer('value');
$table->integer('count')->nullable();
$table->date('expired_at');
$table->timestamps();
});
2- I need to put a discount on products of a single category (to put a discount on the whole products that belong to the T-Shirt category).
How the design structure of this point?
3- I need to put a discount on a specific product or products that I want to put on it.
How the design structure of this point?
Could anyone pls help me with this? So confused!
Update:
products table:
id - name - price - quantity - category_id - brand_id - created_at
categories table
id - category_name - created_at
Orders table
id - status - user_id - address_id - coupon_id - created_at
order_product pivot table
order_id - product_id - quantity
Very interesting! I think may be a good approach should be a pivot table with a polymorphic relation. Somthing like this:
id - couponable_type - couponable_id - coupon_id - "whatever_data"
------------------------------------------------------------------
1 - category - 1 - 1 - ....
2 - order - 1 - 2 - ....
3 - product - 1 - 1 - ....
Since the COUPON ** has a relation by default with **PRODUCTS, it will be great to make some relationship, like so:
Does the product will have one coupon or many?
Does the coupon will belong to one product or many?
I think it's good to give product ability to use many **coupons and the coupon FOR SURE will belong to many products. In that case, you should add Many To Many Relationship between coupons and products.
The same thing with products and categories, the product should have many categories and the later should have or belong to many **products.
If you go with that approach you can achieve the Points 01 and 02 easily. You can then create coupons then attach them to specific product or products, or a product category.
To list the coupons of a product or category, you can do something like this:
$product_coupons = Product::findOrFail($id)->coupons;
$category_coupons = ProductCategory::findOrFail($id)->coupons;
In Blade you access the coupons like this:
#foreach($product->coupons as $coupon)
{{ $coupon->code }}
#endforeach
But #Nahuelsgk approach is a good one, advanced but it's clean, I think it's better to use polymorphic

What is the best DB schema to handle exceptions and prevent redundancy?

There are some products that can be sold in multiple units and the base unit is kilogram. The unit of each product has different weight, for example a Bundle of product A is 20kg but a Bundle of product B is 30kg
The following is my initial design.
product:
id name
product_variation:
id product_id name price
product_variation_unit:
id product_variation_id unit_id
product_variation_unit_weight:
product_variation_unit_id weight
The problem is than most of the variation of a product have the same unit and weight. So here is my solution but I'm not sure it's a good idea:
selectable_unit:
id selectable_id selectable_type unit_id
1 10 product 100
2 20 product_variation 101
selectable_unit_weight:
selectable_unit_id weight
And when I want to get the unit and weight of a variation, first I will check the variation and if there isn't, I will check it's product.
I't a little complicated, can you help me to find a better solution or improve it?
Have a look at the following diagram (Oracle Data Modeler notation). Usually, a price is depending on the SKU (stock keeping unit) and the period; a weight is depending on the SKU (packed product).
An SKU weight is limited by units allowed for its product (foreign key contains 2 columns).
SKU.value is the value in the unit to sell, i.e. kg, pcs, liters etc.

How to store product quantity in database

I have database with three tables
product (productID,productName,productDescription)
size (sizeID , sizeName) eg. s ,m ,l ,8,10,12,37,35..etc
ProductDetails (ProductDetailsID, productID(FK) , sizeID (FK))
I want to store the quantity of each product and it size for example there are 5 in stock for product 1 of size s, 10 in stock for product 4 size 37 ..etc
In which table should I place the quantity ?
You can store it in ProductDetails only as the quantity is dependent upon the product and its size both.
You should use another table.
It could be called ProductSizeQuantity(id, ProductId, sizeID, Quantity)
you have
product (productID,productName,productDescription)
size (sizeID , sizeName)
ProductDetails (ProductDetailsID, productID(FK) , sizeID (FK))
in my opinion you need:
product (productID[PK], productName, productDescription)
size (size[PK])
ProductDetails (productID[PK] , size[PK], quantity)
notes:
for size it is not required sizeid + sizeName, but only one column with size name
quantity is in product details table, in this table id your PK is productId+Size you'll have one tuple for each for each size of the product
You can do something like this.
Product table :
id
name
description
Size table :
id
product_id
size
Quantity table :
id
size_id
stock
Fetch product first, fetch sizes based on product and fetch its Quantity based on size id.

MySQL Query Customers Who Have Not Bought

Background:
We are setting up a promotions system to give away free products to registered customers. We're trying to design a database which is flexible enough to handle multiple products, and giveaways. The requirements are that products may be given away on a drip basis on a first come basis to qualified customers.
Example:
Apple wants to give away 1000 ipads in March.
They want to give away maximum of 1 per hour.
They want to give it to customers who are in California or New York.
They want to limit how many free ipads a customer can get (limit 1 per 15 days).
Data Structure:
Products - 1 entry per unique product. e.g. Apple iPad
ProductGiveAways
ProductID: AppleIpad
Quantity:1000
StartDate: 03/01/2014
End Date 03/31/2014
CustomerState: California,NewYork
PurchaseLimitDays: 15
Problem:
With the above structure we are able to do a query against our customers table and find out which are qualified for the promotion.
What I cannot figure out is the best way to:
Query customers in California or New York (is this a good use case for a join and another table?)
When a customer logs in to see what free items are not available to him, how can I exclude the Apple iPad if the customer has already gotten this freebie?
In other words:
Say amazon.com wants to show me DVDs which I have not already bought. What is the proper way to query that?
Is the right approach to first get a list of previously bought products and then Query with a NOT clause?
I'm assuming you'll have a table for what has been given away. In this table I would include a column for recipient id which can map back to the customer table. You can then create queries to find eligible recipients by searching for customers who have not met disqualifying conditions.
select customerid
from customer
where customerid not in (
select recipientid
from givenaway
where ..... and ....
)
Because there's not a definitive data structure defined, I'm going to use the following which you can tailor to whatever data structure you have designed yourself:
Product
ProductId - INTEGER (IDENTITY and PRIMARY KEY)
ProductName - VARCHAR
States
StateId - INTEGER (IDENTITY and PRIMARY KEY)
StateName - VARCHAR
Customer
CustomerId - INTEGER (IDENTITY and PRIMARY KEY)
StateId - INTEGER (FOREIGN KEY)
Promotion
PromotionId - INTEGER (IDENTITY and PRIMARY KEY)
ProductId - INTEGER (FOREIGN KEY)
Quantity - INTEGER
StartDate - DATETIME
End Date - DATETIME
PurchaseLimitDays - INTEGER
PromotionState
PromotionId - INTEGER (FOREIGN KEY)
StateId - INTEGER (FOREIGN KEY)
So in answer to your questions:
Query customers in California or New York (is this a good use case for a join and another table?)
Personally I would join to a centralized state table (PromotionState) in my above example, I'm sure there's a better way but you could do a condition such as:
WHERE
(SELECT COUNT * FROM PromotionState x WHERE x.PromotionId = p.PromotionId) = 0
OR NOT(ps.PromotionId IS NULL)
Alternatively you could do a GROUP BY and HAVING, using all the other columns as the items to GROUP BY and something like HAVING COUNT * = 0 OR HAVING SUM CASE WHEN (Conditions met) THEN 1 ELSE 0 END = 0
When a customer logs in to see what free items are not available to him, how can I exclude the Apple iPad if the customer has already gotten this freebie?
Say amazon.com wants to show me DVDs which I have not already bought. What is the proper way to query that?
As I've said you could use GROUP BY and HAVING to determine whether an item has been previously "won" by either using COUNT or SUM
Is the right approach to first get a list of previously bought products and then Query with a NOT clause?
There are probably better ways, sub queries can get very heavy and sluggish, I'd recommend trying some of the above techniques and then using a profiler to hopefully make it more efficient.
Some database design
First, when you set the CustomerState to California,NewYork you are violating the First Normal Form of database design.
So let's reorganize your domain model.
State - 1 Entry per unique state
...
Customer - 1 Entry per unique customer
StateId: (California|NewYork|...)
...
Product - 1 Entry per unique product
...
ProductGiveAways - Many entries per product
ProductID
Quantity
StartDate
End Date
PurchaseLimitDays
...
ProductGiveAways_State
ProductGiveAwaysId
StateId
...
Customer_Product - 1 Entry per bought product by customer
CustomerId
ProductId
PurchaseDate
...
Technical issues
When you want to query custoners in California or New York, all you have to do now is :
// This is just an example, you have to change the 'California', 'New York' with their ids
SELECT * FROM Customer WHERE StateId IN ('California', 'New York')
When a customer logs in to see what free items are available to him :
// It's not an accurate sql, just an example
SELECT Product.*
FROM Product
JOIN ProductGiveAways ON ProductId
JOIN ProductGiveAways_State ON ProductGiveAwaysId
WHERE ProductId NOT IN (
SELECT ProductId FROM Customer_Product JOIN ProductGiveAways ON ProductId
WHERE CustomerId = /* the customer id */
AND ( TO_DAYS(now()) - TO_DAYS(PurchaseDate) ) < PurchaseLimitDays
)
AND StateId = /* customer StateId */
AND StartDate < now() < End Date // Elligible ProductGiveAways
For Laravel We Use Something Like this, i hope you can relate to this query or you can use online laravel query converter for using it in mysql ( orator )
$user_id = auth()->user()->id;
Product::where('status', 'active')->whereNotIn('id', function($query) use ($user_id) { $query->select('product_id')->from(new OrderProduct->getTable())->where('user_id', $user_id)->where('status', 'delivered'); });

How do we store cascading taxes in a database? or database structure for storing taxes

Hi i have to create a database structure for storing tax details.
I have an itemDetails table which has the details of the item like name and price.
The problem is for each item there are two taxes service charge (10%) and VAT (4%)
but the taxes are cascaded i.e after I apply servicecharge, then on the new total I have to apply I apply vat.
I want to store this in a database; I can acheive this with hard coding it but I want it in a database so that in the future if the customer wants he can store more taxes by specifying which order the taxes apply and weather they cascade or not. And each item may have a different tax structure.. (Ex. one item may have the above mentioned tax structure, another item has only vat, another item has a completely diffenet structure etc)
I have a tax category table where the user can store a tax structure and each item will belong to a tax category i.e the itemDetailsTable has TaxCategory_id in it. I need your help figuring it out from there.
You could add another table that has a many-to-one relationship with TaxCategory that uses a ranking column to define what order the taxes are applied in.
TaxCategoryRates
taxCategoryId taxRate taxRank taxDescription
------------- ------- ------- --------------
1 10 1 Service Charge
1 4 2 VAT
2 3 NULL Local Sales Tax
2 4.5 NULL State Sales Tax
Your logic then applies the taxes in order of taxRank. If you have other tax categories where order doesn't matter (as in taxCategoryId 2), you can just leave the rank NULL and have your logic sum the tax rates and apply them.