HEX
Server: Microsoft-IIS/8.5
System: Windows NT YDAWBH120 6.3 build 9600 (Windows Server 2012 R2 Standard Edition) AMD64
User: tentjecom_web (0)
PHP: 7.4.14
Disabled: NONE
Upload Files
File: D:/HostingSpaces/SBogers10/farmfun.komma.pro/app/Komma/Products/Models/Product.php
<?php

namespace App\Komma\Products\Models;

use App\Komma\Documents\DocumentsTrait;
use App\Komma\Documents\Kms\DocumentableInterface;
use App\Komma\Documents\Models\Document;
use App\Komma\Globalization\Languages\Models\Language;
use App\Komma\Kms\Core\AbstractTranslatableModel;
use App\Komma\Kms\Core\Entities\DisplayNameInterface;
use App\Komma\Kms\Core\Entities\DisplayNameTrait;
use App\Komma\Locations\Models\Location;
use App\Komma\Sites\HasSitesInterface;
use App\Komma\Sites\Models\Site;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;

/**
 * Class Page
 *
 * @property int site_id
 * @property int lft
 * @property int rgt
 * @property int tree
 * @property-read Carbon $date
 * @property-read \App\Komma\Globalization\Languages\Models\Language[] $languages
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Komma\Sites\Models\Site[] $sites
 * @property-read \App\Komma\Products\Models\ProductTranslation $translation
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Komma\Products\Models\ProductTranslation[] $translations
 * @mixin \Eloquent
 * @property int $id
 * @property int $active
 * @property \Carbon\Carbon|null $created_at
 * @property \Carbon\Carbon|null $updated_at
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Komma\Products\Models\Product whereActive($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Komma\Products\Models\Product whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Komma\Products\Models\Product whereDate($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Komma\Products\Models\Product whereId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Komma\Products\Models\Product whereUpdatedAt($value)
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Komma\Documents\Models\Document[] $documents
 * @property-read \Illuminate\Database\Eloquent\Collection|\App\Komma\Documents\Models\Document[] $images
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Komma\Products\Models\Product newModelQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Komma\Products\Models\Product newQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Komma\Products\Models\Product query()
 */
final class Product extends AbstractTranslatableModel implements HasSitesInterface, DocumentableInterface, DisplayNameInterface
{
    use DocumentsTrait;
    use DisplayNameTrait;
    use SoftDeletes;

    // Maybe in future we want this as a own class
    public static $types = [
        'activity',
        'food',
    ];

    protected $class = self::class;

    protected $protected = ['id', 'created_at', 'updated_at'];

    /**
     * Gets the translation models for this model
     *
     * @return HasMany that resolves to AbstractTranslationModel instances
     */
    public function translations(): HasMany
    {
        return $this->hasMany(ProductTranslation::class);
    }

    public function languages(): BelongsToMany
    {
        return $this->belongsToMany(Language::class, 'product_translations')
            ->withPivot('slug', 'name', 'description')
            ->withTimestamps();
    }

    /**
     * Get the site or sites for this model
     *
     * @return BelongsToMany
     */
    public function locations(): BelongsToMany
    {
        return $this->belongsToMany(Location::class, 'location_products')
            ->withPivot('max_persons_each_block', 'available_each_block', 'capacity_type');
    }

    /**
     * Get the site or sites for this model
     *
     * @return BelongsToMany
     */
    public function sites(): BelongsToMany
    {
        return $this->belongsToMany(Site::class, 'site_products');
    }

    /**
     * Get the images through documents belonging to this model
     *
     * @return \Illuminate\Database\Eloquent\Relations\hasMany
     */
    public function overviewImage():MorphOne
    {
        return $this->morphOne(Document::class, 'documentable')
            ->where('key', '=', 'Documents-products_index_image');
    }

    /**
     * Get the images through documents belonging to this model
     *
     * @return \Illuminate\Database\Eloquent\Relations\hasMany
     */
    public function quoteImage():MorphOne
    {
        return $this->morphOne(Document::class, 'documentable')
            ->where('key', '=', 'Documents-products_quote_image');
    }

    /**
     * Get the images through documents belonging to this model
     *
     * @return \Illuminate\Database\Eloquent\Relations\hasMany
     */
    public function detailImages():MorphMany
    {
        return $this->morphMany(Document::class, 'documentable')
            ->where('key', '=', 'Documents-product_detail_images')
            ->orderBy('sort_order');
    }

    /**
     * Get score attributes
     *
     * @return object
     */
    public function getStats()
    {
        $attributes = $this->getAttributes();

        $stats = Arr::where($attributes, function ($value, $key) {
            if (Str::startsWith($key, 'score_') && $value != 0) {
                return $value;
            }
        });

        return (object) $stats;
    }

    /**
     * @return bool
     */
    public function hasTimeSelection(): bool
    {
        return ! in_array($this->id, [33, 34]);
    }

    /**
     * Get the label for pricing
     * We have defined this here to keep the blades clean.
     *
     * @param bool $withVat
     * @param bool $withCurrency
     * @param bool $withSmallTags
     * @return string
     */
    public function getPriceLabel(bool $withVat = true, bool $withCurrency = true, bool $withSmallTags = true)
    {
        // Price each person without start up
        if (! $this->has_fixed_price && $this->price_start_up === 0) {
            if ($withVat) {
                if ($withCurrency) {
                    return config('site.shop_currency').' '.euro_pricing_format($this->price_each_unit);
                } else {
                    return euro_pricing_format($this->price_each_unit);
                }
            } else {
                if ($withCurrency) {
                    return config('site.shop_currency').' '.euro_pricing_format($this->price_each_unit_excluding_vat);
                } else {
                    return euro_pricing_format($this->price_each_unit_excluding_vat);
                }
            }
        }

        //  Price is fixed
        if ($this->has_fixed_price) {
            if ($withVat) {
                return euro_pricing_format($this->price_start_up);
            } else {
                if ($withCurrency) {
                    return config('site.shop_currency').' '.euro_pricing_format($this->price_start_up_excluding_vat);
                } else {
                    return euro_pricing_format($this->price_start_up_excluding_vat);
                }
            }
        }

        // Price for each person and with additional start up price
        if (! $this->has_fixed_price && $this->price_start_up !== 0) {
            // In the main price (with vat) we only communicate the price each person, on the price line we notify the startup price
            if ($withVat) {
                $priceLabel = euro_pricing_format($this->price_each_unit);
                if ($withSmallTags) {
                    $priceLabel .= '<small>';
                }
                $priceLabel .= ' '.__('site/availability.price_each_person');
                if ($withSmallTags) {
                    $priceLabel .= '</small>';
                }

                return $priceLabel;
            } else {
                if ($withCurrency) {
                    return config('site.shop_currency').' '.euro_pricing_format($this->price_each_unit_excluding_vat).' + '.config('site.shop_currency').' '.euro_pricing_format($this->price_start_up);
                } else {
                    return euro_pricing_format($this->price_each_unit_excluding_vat).' + '.config('site.shop_currency').' '.euro_pricing_format($this->price_start_up);
                }
            }
        }

        throw new \UnexpectedValueException(self::class.': We have not defined the pricing label for the given situation "'.$this->code_name.'"');
    }

    /**
     * Get the label for the line below the price on the poster.
     * We have defined this here to keep the blades clean.
     *
     * @return array|string|null
     */
    public function getPosterLabel()
    {
        // Price each person without start up
        if (! $this->has_fixed_price && $this->price_start_up === 0) {
            return __('site/availability.price_each_person');
        }

        //  Price is fixed
        if ($this->has_fixed_price) {
            $customLabelKey = 'site/availability.custom_start_up.'.$this->code_name;
            $customLabel = __($customLabelKey);

            // If the translation is the same, it isn't found.
            if ($customLabelKey === $customLabel) {
                debug(self::class.': Custom key not found for "'.$this->code_name.'"');

                return __('site/availability.start_up');
            } else {
                return $customLabel;
            }
        }

        // Price for each person and with additional start up price
        if (! $this->has_fixed_price && $this->price_start_up !== 0) {
            return '+ '.config('site.shop_currency').' '.euro_pricing_format($this->price_start_up, ',', '', true).' '.__('site/availability.start_up');
        }

        throw new \UnexpectedValueException(self::class.': We have not defined the price line for the given situation "'.$this->code_name.'"');
    }

    /**
     * Get the label for the line below the price on the shopping cart
     * We have defined this here to keep the blades clean.
     *
     * @param bool $withVat
     * @param bool $formatted
     * @return array|string|null
     */
    public function getCartLabel(bool $withVat = true, bool $formatted = true)
    {
        // Price each person without start up
        if (! $this->has_fixed_price && $this->price_start_up === 0) {
            return config('site.shop_currency').' '.$this->getPriceLabel($withVat, $formatted).' '.__('site/availability.price_each_person');
        }

        //  Price is fixed
        if ($this->has_fixed_price) {
            // Is the same as the poster line
            return $this->getPosterLabel();
        }

        // Price for each person and with additional start up price
        if (! $this->has_fixed_price && $this->price_start_up !== 0) {
            $cartLine = config('site.shop_currency').' '.$this->getPriceLabel($withVat, $formatted, false);
            $cartLine .= ' <br/>+ '.config('site.shop_currency').' '.euro_pricing_format($this->price_start_up).' '.__('site/availability.start_up_small');

            return $cartLine;
        }
    }

    /**
     * Get the label for duration
     *
     * @return string
     */
    public function getDurationLabel()
    {
        // Makes sure that we don't have zero's add the end.
        $duration = floatval($this->duration);

        // Remove zero if not needed behind the digits
        $duration = str_replace('.0', '', $duration);

        // Replace . to ,
        $duration = str_replace('.', ',', $duration);

        return $duration.' '.__('site/availability.hour');
    }

    /**
     * Look up if this product has been marked
     * as available for this location.
     *
     * @param Location $location
     * @return bool
     */
    public function availableForLocation(Location $location): bool
    {
        $this->loadMissing('locations');

        $productCartLocation = $this->locations->first(fn ($l) => $l->id === $location->id);

        if ($productCartLocation) {
            return true;
        }

        return false;
    }
}