'bool', 'date_start' => 'datetime', 'date_end' => 'datetime', ]; /** * The attributes that should be cast to Enums. * * @var array */ protected $enumCasts = [ 'type' => DiscountType::class, ]; /** * The attributes that are mass assignable. * * @var array */ protected $fillable = [ 'type', 'discount_value', 'status', 'date_start', 'date_end', ]; /** * Perform any actions required after the model boots. * * @return void */ protected static function booted() { // * EVENT CLOSURES. static::creating(function (self $model) { // * ASSERTIONS self::assertIsAboveZero( 'discount_value', trans('Valeur de réduction'), $model->getAttributeFromArray('discount_value') ); // * TRANSFORMATIONS $model->makeStatusSense(); }); static::created(function (self $model) { $model->flashMessages(); }); static::updated(function (self $model) { $model->flashMessages(); }); static::updating(function (self $model) { // * ASSERTIONS self::assertIsAboveZero( 'discount_value', trans('Valeur de réduction'), $model->getAttributeFromArray('discount_value') ); // * TRANSFORMATIONS $model->makeStatusSense(); }); } // * RELATIONSHIPS /** * HasMany products relation * * @return \Illuminate\Database\Eloquent\Relations\hasMany */ public function products() { return $this->hasMany(Product::class); } // * GETTERS /** * Getter displayable_discount_value * * @return string */ public function getDisplayableDiscountValueAttribute(): string { return $this->type->equals(DiscountType::amount()) ? number_format($this->discount_value / 100, 2, ',', '') . ' €' : number_format($this->discount_value / 100, 2, ',', '') . ' %'; } /** * Getter discount_calculation * * @return float|integer */ public function getDiscountCalculationAttribute() { return $this->type->equals(DiscountType::amount()) ? // * Return value in cents $this->discount_value : // * return a ratio (percent) $this->discount_value / 10000; } // * METHODS /** * Associate Discount with product * * @param array $ids Array of \App\Models\Product ids. * @return void */ public function associateProducts(array $ids) { // * Tournicota, HasMany ne gere pas nullable, meme issue que sur gengame web $this->products->each(function (Product $product) { $product->discount()->dissociate(); $product->saveQuietly(); }); if (!empty($ids)) { /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Product> */ $products = Product::query()->whereIn('id', $ids)->get(); $products->each(function (Product $product) { $product->discount()->associate($this); $product->saveQuietly(); }); } } /** * Flash boolean attributes modification messages * * @param boolean $old Ignore old attribute comparison. * @return void */ public function flashMessages(bool $old = true) { $booleanChecks = [ 'status' => [ 'info' => trans(':model est maintenant pris en compte', [ 'model' => Str::singular(trans('models.classes.discounts')) ]), 'warning' => trans(':model n\'est maintenant plus pris en compte', [ 'model' => Str::singular(trans('models.classes.discounts')) ]) ], ]; $sessionMessages = []; // * Merge messages foreach ($booleanChecks as $attribute => $booleanCheck) { if ($old and $this->getOriginal($attribute) == $this->{$attribute}) { continue; } /** @var string $flashType */ $flashType = \array_keys($booleanCheck)[$this->{$attribute} ? 0 : 1]; if (!\array_key_exists($flashType, $sessionMessages)) { $sessionMessages[$flashType] = []; } $sessionMessages[$flashType][] = $booleanCheck[$flashType]; } foreach ($sessionMessages as $flashType => $messages) { session()->flash($flashType, collect($messages)->implode("\n")); } } /** * Assert Is Above Zero * * @param string $attribute * @param string $name * @param float $value * @return void * @throws \Illuminate\Validation\ValidationException If the value is less or equals to 0. */ private static function assertIsAboveZero(string $attribute, string $name, float $value): void { Validator::make([ $attribute => $value ], [ $attribute => 'numeric|min:0' ], [], [ $attribute => $name ])->validate(); } /** * Adjusts model status using current status and start and end dates * * @return void */ public function makeStatusSense(): void { /** @var \Carbon\Carbon|null */ $date_start = $this->date_start; /** @var \Carbon\Carbon|null */ $date_end = $this->date_end; // * Ignore unpublish_at in the past if ($date_end and $date_end->lessThan(now())) { return; } // * Ignore publish_at in the futur if ($date_start and $date_start->greaterThan(now())) { return; } if ($date_start or $date_end) { $this->status = $this->planificated_status; } } /** * Getter the current status following planification dates * * @return boolean */ public function getPlanificatedStatusAttribute(): bool { /** @var \Carbon\Carbon|null */ $date_start = $this->date_start; /** @var \Carbon\Carbon|null */ $date_end = $this->date_end; if ($date_start and $date_end) { return $date_end->greaterThanOrEqualTo(now()) and $date_start->lessThan(now()); } if ($date_start) { return $date_start->lessThan(now()); } if ($date_end) { return $date_end->greaterThanOrEqualTo(now()); } return false; } }