ldc-boutique-cnc/app/Models/Product.php
2021-11-09 15:38:52 +01:00

346 lines
10 KiB
PHP

<?php
namespace App\Models;
use App\Enums\InvoicingUnit;
use App\Enums\SellUnit;
use App\Enums\WeightUnit;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Gloudemans\Shoppingcart\Contracts\Buyable;
use Gloudemans\Shoppingcart\CanBeBought;
use Illuminate\Support\Facades\Auth;
/**
* @todo : unité de vente/unité de poids devrait être des énums (via table liée ou package enum)
*/
class Product extends Model implements Buyable
{
use HasFactory;
use SoftDeletes;
use CanBeBought;
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'orderable_start' => 'datetime',
'orderable_end' => 'datetime',
];
/**
* Store in protected variables instead of attributes
* Because those are not set in attributes, Laravel will not try to save it to database
*/
protected $priceHt;
protected $discountedPriceHt;
protected $priceTtc;
protected $discountedPriceTtc;
protected $discountAmount;
protected $discountRate;
/**
* init prices on boot
*/
protected static function boot()
{
parent::boot();
//on data retrived from DB
static::retrieved(function ($model) {
$model->priceHt = $model->getPriceHtAttribute();
$model->priceTtc = $model->getPriceTtcAttribute();
$model->discountAmount = $model->getDiscountAmountAttribute();
$model->discountRate = $model->getDiscountRateAttribute();
$model->discountedPriceHt = $model->getDiscountedPriceHtAttribute();
$model->discountedPriceTtc = $model->getDiscountedPriceTtcAttribute();
});
}
/**
* Price calculations
* We need : gross price (prix avant taxe et remises)
* discounted price (prix avant taxe avec remises)
* net price (prix avec taxe)
* net discounted proice (prix avec taxe et remises)
*/
//Utility to bring prices as a pseudo relation
public function getCalcPrices()
{
//$prices = new Collection();
$prices = array(
'priceHt' => $this->priceHt,
'discountAmount' => $this->discountAmount,
'discountRate' => $this->discountRate,
'discountedPriceHt' => $this->discountedPriceHt,
'priceTtc' => $this->priceTtc,
'discountedPriceTtc' => $this->discountedPriceTtc,
);
//$prices->add($cartextendedItem);
return $prices;
}
//gross price
/**
* Mutator method to set priceHt's value
*/
public function setPriceHtAttribute($value)
{
$this->priceHt = $value;
}
/**
* Get the gross price
* Accessor method for priceHt
*
* @author Olivier Legat <olivier.legat@ldc.fr>
*/
public function getPriceHtAttribute()
{
if(isset($this->priceHt)) {
return $this->priceHt;
} else {
//tenir compte de l'unité de facturation et de l'unité de vente (qui doit être stricte)
//si facturation KG et vente piece
// prendre le poids, convertir en KG => pre-requis l'unité de poids doit être un enum
// multiplier le $this->attributes['price'] par les KG
//sinon
// value => value
if (config('bosettings.sell_unit_management') == "strict") {
$calculate = ($this->invoicing_unit == InvoicingUnit::kgm()->value && $this->sell_unit == SellUnit::pce()->value);
} else {
$calculate = false;
}
if ($calculate) {
//weight converter
$weighted_price = $this->attributes['price'] * ($this->weight * WeightUnit::convert()[$this->weight_unit]);
return $this->priceHt = round($weighted_price * 100) / 100;
} else {
//no calculations, alias of db property
return $this->priceHt = $this->attributes['price'];
}
}
}
//discounted price
public function setDiscountedPriceHtAttribute($value)
{
$this->discountedPriceHt = $value;
}
public function getDiscountedPriceHtAttribute()
{
if (isset($this->discountedPriceHt)) {
return $this->discountedPriceHt;
} else {
$discountedPriceHt = $this->priceHt - $this->discountAmount;
$roundingdiscountedPriceHt = round($discountedPriceHt * 100) / 100;
return $this->discountedPriceHt = $roundingdiscountedPriceHt;
}
}
//net price
public function setPriceTtcAttribute($value)
{
$this->priceTtc = $value;
}
public function getPriceTtcAttribute()
{
if (isset($this->priceTtc)) {
return $this->priceTtc;
} else {
$priceTtc = $this->priceHt * ( 1 + ( $this->tax->rate / 100));
//on travaille avec des centimes puis on redivise par 100 pour avoir des unités monetaires
$roundingPriceTtc = round($priceTtc * 100) / 100;
return $this->priceTtc = $roundingPriceTtc;
}
}
//net discounted price
public function setDiscountedPriceTtcAttribute($value)
{
$this->discountedPriceTtc = $value;
}
public function getDiscountedPriceTtcAttribute()
{
if (isset($this->discountedPriceTtc)) {
$showPrice = $this->discountedPriceTtc;
} else {
$discountedPriceTtc = $this->discountedPriceHt * ( 1 + ( $this->tax->rate / 100));
//on travaille avec des centimes puis on redivise par 100 pour avoir des unités monetaires
$roundingDiscountedPriceTTC = round($discountedPriceTtc * 100) / 100;
$showPrice = $this->discountedPriceTtc = $roundingDiscountedPriceTTC;
}
//prix transmis en fonction du setting show_prices
if (config('bosettings.show_prices_authenticated') == "authenticated") {
{
if (Auth::guard('customer')->check()) {
return $showPrice;
}
}
}
if (config('bosettings.show_prices_guest') == "guest") {
return $showPrice;
}
return "-.--";
}
/**
* Discount calc
*/
//montant de remise
public function setDiscountAmountAttribute($value)
{
$this->discountAmount = $value;
}
public function getDiscountAmountAttribute()
{
if (isset($this->discountAmount)) {
return $this->discountAmount;
} else {
$applicablePromotion = $this->promotions->first();
if (null !== $applicablePromotion) {
$promo_type = $applicablePromotion->discount_type_id;
if ($promo_type == 1) {
$discountAmount = $applicablePromotion->discount_value;
} else {
//TODO : rounding au centime cf getDiscountedPriceTtcAttribute?
$discountAmount = $this->priceHt * ($applicablePromotion->discount_value / 100);
$discountAmount = round($discountAmount * 100) / 100;
}
} else {
$discountAmount = 0;
}
return $this->discountAmount = $discountAmount;
}
}
//taux de remise
public function setDiscountRateAttribute($value)
{
$this->discountRate = $value;
}
public function getDiscountRateAttribute()
{
if (isset($this->discountRate)) {
return $this->discountRate;
} else {
$applicablePromotion = $this->promotions->first();
if (null !== $applicablePromotion) {
$promo_type = $applicablePromotion->discount_type_id;
if ($promo_type == 1) {
//on veut un pourcentage
$discountRate = ($applicablePromotion->discount_value / $this->priceHt) * 100;
} else {
$discountRate = $applicablePromotion->discount_value;
}
} else {
$discountRate = 0;
}
return $this->discountRate = $discountRate;
}
}
// //Buyable interface
public function getBuyablePrice($options = null)
{
return $this->priceHt;
}
//Relations
public function range()
{
return $this->belongsTo('App\Models\Range', 'range_id');
}
public function old_slugs()
{
return $this->hasMany('App\Model\OldSlug', 'product_id');
}
public function stats()
{
return $this->hasMany('App\Models\Stat', 'product_id');
}
public function orders()
{
return $this->belongsToMany('App\Models\Order', 'orders_products', 'product_id', 'order_id')
->withPivot('quantity');
}
//relationship to additionnal product info
public function additionnalProductInfo($productType)
{
return $this->$productType;
}
//possible additionnals
public function foodProduct()
{
return $this->hasOne(FoodProduct::class, 'product_id');
}
public function anifoodProduct()
{
return $this->hasOne(AnifoodProduct::class, 'product_id');
}
public function toolProduct()
{
return $this->hasOne(ToolProduct::class, 'product_id');
}
public function garmentProduct()
{
return $this->hasOne(GarmentProduct::class, 'product_id');
}
//relationship to associated products
public function products()
{
return $this->belongsToMany(Product::class, 'products_products', 'product_id', 'associated_id');
}
//offres speciales
public function promotions()
{
$now = Carbon::now();
return $this->belongsToMany(Promotion::class)
->whereDate('date_start', '<=', $now)
->whereDate('date_end', '>=', $now);
}
//taxe
public function tax()
{
return $this->belongsTo(TaxRate::class, 'tax_rate_id');
}
//tags
public function tags()
{
return $this->belongsToMany(Tag::class);
}
}