Reputation:
I have these tables:
products
-- name
-- price
-- quantity
-- category_id
discounts
-- type('percentage','numeric')
-- value
-- expired_at
categories
-- name
discountables
-- discount_id
-- discountable_id
-- discountable_type
In discountables
there is many to many relationship between:
discounts and categories
also discounts and products
I'm done with how to discount between discounts and products
Now I'm confused How to discount the whole products that belongs to category that I add todiscountables
Relation:
Category Models
public function discounts()
{
return $this->morphToMany('App\Models\Discount', 'discountable');
}
Products Models
public function discounts()
{
return $this->morphToMany('App\Models\Discount', 'discountable');
}
Discount Model:
public function categories()
{
return $this->morphedByMany('App\Models\Category', 'discountable')->withTimestamps();
}
public function products()
{
return $this->morphedByMany('App\Models\Product', 'discountable')->withTimestamps();
}
MY code for discount the products directly discounts and products
/**
* get price of product after discount
*
* @return void
*/
public function getDiscountProductAttribute() {
foreach ($this->discounts as $discount) {
if($discount->expired_at > Carbon::now()){
if ($discount->type == 'numeric'){
return $this->price - $discount->value;
}else{
return $this->price - ($this->price * ($discount->value / 100));
}
}
}
}
So I need How to discount the whole products that belongs to category that I add todiscountables
?
Upvotes: 2
Views: 618
Reputation: 3035
Your relationships are fine. I just redesign a bit to solve the problem.
class Discount extends Model
{
/**
* Check whether this discount is expired.
*
* return bool
*/
public function expired()
{
// I assume that expired_at is also a Carbon instance.
return $this->expired_at->isPast();
}
/**
* Return the discount amount for each product.
*
* @return double
*/
public function apply(Product $product)
{
if ($this->type === 'numeric') {
$this->value;
}
if ($this->type === 'percentage') {
return $product->price * ($this->value / 100);
}
return 0;
}
}
class Product extends Model
{
public function allDiscounts()
{
return $this->discounts
->merge($this->category->discounts)
->unique();
}
pubic function getTotalDiscountAttribute()
{
return $this->allDiscounts()
->reject
->expired()
->map
->apply($this)
->sum();
}
public function getTotalPriceAttribute()
{
return $this->price - $this->total_discount;
}
}
So you can get the total price for a single product after applying all sort of discounts from itself and its category (if there's any) by simply saying:
$product->total_price;
I hope that helps. Let me know if it fails at any step.
By the way. Your question reminds me of a pretty good speech a few years back. Its about solving a some what similar problem using inheritance and Null Object Pattern. It's pretty cool. You don't need to rewrite it that way but its a pretty good design.
Upvotes: 0