ldc-boutique-cnc/app/Models/Product.php
2022-09-03 16:56:16 +02:00

511 lines
13 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;
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
*/
/**
* Base Price
*
* @var float
*/
protected $priceHt;
/**
* Base Price after discount
*
* @var float
*/
protected $discountedPriceHt;
/**
* Price VAT included
*
* @var float
*/
protected $priceTtc;
/**
* Price after discount VAT included
*
* @var float
*/
protected $discountedPriceTtc;
/**
* Discount amount
*
* @var float
*/
protected $discountAmount;
/**
* Dsicount rate
*
* @var float
*/
protected $discountRate;
/**
* Bootstrap the model and its traits.
*
* @return void
*/
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
*
* @return array
*/
public function getCalcPrices()
{
$prices = array(
'priceHt' => $this->priceHt,
'discountAmount' => $this->discountAmount,
'discountRate' => $this->discountRate,
'discountedPriceHt' => $this->discountedPriceHt,
'priceTtc' => $this->priceTtc,
'discountedPriceTtc' => $this->discountedPriceTtc,
);
return $prices;
}
/**
* Mutator method to set priceHt's value gross price
*
* @param float $value
* @return void
*/
public function setPriceHtAttribute(float $value)
{
$this->priceHt = $value;
}
/**
* Get the gross price
* Accessor method for priceHt
*
* @author Olivier Legat <olivier.legat@ldc.fr>
*
* @return float
*/
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]);
$this->priceHt = round($weighted_price * 1000) / 1000;
return $this->priceHt;
} else {
// No calculations, alias of db property.
$this->priceHt = $this->attributes['price'];
return $this->priceHt;
}
}//end if
}
/**
* setter for dicounted price
*
* @param float $value
* @return void
*/
public function setDiscountedPriceHtAttribute(float $value)
{
$this->discountedPriceHt = $value;
}
/**
* getter for discounted price
*
* @return float
*/
public function getDiscountedPriceHtAttribute()
{
if (isset($this->discountedPriceHt)) {
return $this->discountedPriceHt;
} else {
$discountedPriceHt = $this->priceHt - $this->discountAmount;
$roundingdiscountedPriceHt = round($discountedPriceHt * 1000) / 1000;
$this->discountedPriceHt = $roundingdiscountedPriceHt;
return $this->discountedPriceHt;
}
}
/**
* setter for net price
*
* @param float $value
* @return void
*/
public function setPriceTtcAttribute(float $value)
{
$this->priceTtc = $value;
}
/**
* getter for net price
*
* @return float
*/
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
* on augmente la précision à 3 digits, l'affichage formate les prix sur 2 décimales
*/
$roundingPriceTtc = round($priceTtc * 1000) / 1000;
$this->priceTtc = $roundingPriceTtc;
return $this->priceTtc;
}
}
/**
* setter for net dscounted price
*
* @param float $value
* @return void
*/
public function setDiscountedPriceTtcAttribute(float $value)
{
$this->discountedPriceTtc = $value;
}
/**
* getter for net dscounted price
*
* @return float
*/
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 * 1000) / 1000;
$this->discountedPriceTtc = $roundingDiscountedPriceTTC;
$showPrice = $this->discountedPriceTtc;
}
// 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 calculators
*/
/**
* set discoutn amount
*
* @param float $value
* @return void
*/
public function setDiscountAmountAttribute(float $value)
{
$this->discountAmount = $value;
}
/**
* Getter for discount amount
*
* @return float
*/
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 {
// On augmente la précision à 3 digits, l'affichage formate les prix sur 2 décimales.
$discountAmount = $this->priceHt * ($applicablePromotion->discount_value / 100);
$discountAmount = round($discountAmount * 1000) / 1000;
}
} else {
$discountAmount = 0;
}
$this->discountAmount = $discountAmount;
return $this->discountAmount;
}
}
/**
* set discount rate
*
* @param float $value
* @return void
*/
public function setDiscountRateAttribute(float $value)
{
$this->discountRate = $value;
}
/**
* get discount rate
*
* @return float
*/
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;
}
$this->discountRate = $discountRate;
return $this->discountRate;
}
}
/**
* buyablePrice attribute alias
*
* @param mixed $options
* @return float
*
* @phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClass
*/
public function getBuyablePrice($options = null)
{
// @phpcs:enable
return $this->priceHt;
}
/**
* BelongsTo range relation
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function range()
{
return $this->belongsTo('App\Models\Range', 'range_id');
}
/**
* hasMany old_slugs relation
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function oldSlugs()
{
return $this->hasMany('App\Model\OldSlug', 'product_id');
}
/**
* hasMany stats relation
*
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public function stats()
{
return $this->hasMany('App\Models\Stat', 'product_id');
}
/**
* belongsToMany orders relation
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function orders()
{
return $this->belongsToMany('App\Models\Order', 'orders_products', 'product_id', 'order_id')
->withPivot('quantity');
}
/**
* Pseudo relationship to additionnal product info
*
* @param string $productType
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function additionnalProductInfo(string $productType)
{
return $this->$productType;
}
/**
* hasOne foodProduct relation
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function foodProduct()
{
return $this->hasOne(FoodProduct::class, 'product_id');
}
/**
* hasOne anifoodProduct relation
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function anifoodProduct()
{
return $this->hasOne(AnifoodProduct::class, 'product_id');
}
/**
* hasOne toolProduct relation
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function toolProduct()
{
return $this->hasOne(ToolProduct::class, 'product_id');
}
/**
* hasOne garmentProduct relation
*
* @return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function garmentProduct()
{
return $this->hasOne(GarmentProduct::class, 'product_id');
}
/**
* belongsToMany products relation
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function products()
{
return $this->belongsToMany(Product::class, 'products_products', 'product_id', 'associated_id');
}
/**
* belongsToMany promotions relation
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function promotions()
{
$now = Carbon::now();
return $this->belongsToMany(Promotion::class)
->whereDate('date_start', '<=', $now)
->whereDate('date_end', '>=', $now);
}
/**
* belongsTo tax relation
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
*/
public function tax()
{
return $this->belongsTo(TaxRate::class, 'tax_rate_id');
}
/**
* belongsToMany tags relation
*
* @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
*/
public function tags()
{
return $this->belongsToMany(Tag::class);
}
}