reupload
This commit is contained in:
21
app/Models/Auth/Verification.php
Normal file
21
app/Models/Auth/Verification.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Auth;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Verification extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'username',
|
||||
'code',
|
||||
];
|
||||
}
|
||||
47
app/Models/CMS/Forms/ContactUS.php
Normal file
47
app/Models/CMS/Forms/ContactUS.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\CMS\Forms;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class ContactUS extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*/
|
||||
protected $table = 'contact_us';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* title - string
|
||||
* phone - string
|
||||
* content - text
|
||||
* type - string | in: website,admin,mobile_admin,mobile_app
|
||||
* user_id - int
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'phone',
|
||||
'content',
|
||||
'type',
|
||||
'user_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* User
|
||||
*
|
||||
* User that submitted form
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
25
app/Models/CMS/Marketing/Newsletter.php
Normal file
25
app/Models/CMS/Marketing/Newsletter.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\CMS\Marketing;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Newsletter extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*/
|
||||
protected $table = 'newsletters';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'subject',
|
||||
'content',
|
||||
'sent',
|
||||
];
|
||||
}
|
||||
23
app/Models/CMS/Marketing/NewsletterUser.php
Normal file
23
app/Models/CMS/Marketing/NewsletterUser.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\CMS\Marketing;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class NewsletterUser extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*/
|
||||
protected $table = 'newsletter_users';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'email',
|
||||
];
|
||||
}
|
||||
246
app/Models/CMS/Media/Banner.php
Normal file
246
app/Models/CMS/Media/Banner.php
Normal file
@@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\CMS\Media;
|
||||
|
||||
use App\Models\Concerns\HasSchemalessAttributes;
|
||||
use App\Models\Ecommerce\Product\Brand\Brand;
|
||||
use App\Models\Ecommerce\Product\Category\Category;
|
||||
use App\Models\Ecommerce\Product\Collection\Collection;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Spatie\EloquentSortable\SortableTrait;
|
||||
use Spatie\Image\Manipulations;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class Banner extends Model implements HasMedia
|
||||
{
|
||||
use HasFactory;
|
||||
use HasSchemalessAttributes;
|
||||
use HasTranslations;
|
||||
use InteractsWithMedia;
|
||||
use SortableTrait;
|
||||
|
||||
/**
|
||||
* Table
|
||||
*/
|
||||
protected $table = 'banners';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'id',
|
||||
'app',
|
||||
'title',
|
||||
'description',
|
||||
'place',
|
||||
'link',
|
||||
'is_visible',
|
||||
'resource_id',
|
||||
'resource_type',
|
||||
'sort_order',
|
||||
'options',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable attributes
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = ['title', 'description'];
|
||||
|
||||
/**
|
||||
* Sortable attributes
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $sortable = [
|
||||
'order_column_name' => 'sort_order',
|
||||
'sort_when_creating' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Banner Position: First
|
||||
*/
|
||||
public const PLACE_FIRST = 'first';
|
||||
|
||||
/**
|
||||
* Banner Position: Market
|
||||
*/
|
||||
public const MARKET = 'market';
|
||||
|
||||
/**
|
||||
* Banner Position: Store
|
||||
*/
|
||||
public const STORE = 'store';
|
||||
|
||||
/**
|
||||
* Banner Position: Homepage Grids
|
||||
*/
|
||||
public const HOMEPAGE_2_GRIDS = 'homepage_2_grids';
|
||||
|
||||
/**
|
||||
* Banner Position: Homepage categories
|
||||
*/
|
||||
public const HOMEPAGE_CATEGORIES = 'homepage_categories';
|
||||
|
||||
/**
|
||||
* Media collections
|
||||
*/
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection('main')
|
||||
->singleFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Media conversations
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb350x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 350, 350);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
$this->addMediaConversion('thumb270x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 270, 350);
|
||||
}
|
||||
|
||||
/**
|
||||
* Category
|
||||
*/
|
||||
public function category(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Category::class, 'resource_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Collection
|
||||
*/
|
||||
public function collection(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Collection::class, 'resource_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Product
|
||||
*/
|
||||
public function product(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class, 'resource_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Brand
|
||||
*/
|
||||
public function brand(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Brand::class, 'resource_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Thumbnail URL
|
||||
*/
|
||||
public function thumbnail(string $resolution = '50x50'): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('main', 'thumb'.$resolution);
|
||||
}
|
||||
|
||||
/**
|
||||
* Original image
|
||||
*/
|
||||
public function image(): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('main');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to filter
|
||||
*
|
||||
* @param Builder $query
|
||||
* @param string $attribute
|
||||
* @param string $value
|
||||
* @return Builder $query
|
||||
*/
|
||||
public function scopeFilter($query, $attribute, $value): Builder
|
||||
{
|
||||
return $value ? $query->where($attribute, $value) : $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Text color
|
||||
*/
|
||||
public function textColor(): ?string
|
||||
{
|
||||
return $this->options->get('color');
|
||||
}
|
||||
|
||||
/**
|
||||
* Places for banner
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function places(): array
|
||||
{
|
||||
return [
|
||||
'first' => __('First banner'),
|
||||
'market' => 'Market Baş sahypa',
|
||||
'store' => 'Store Baş sahypa',
|
||||
'homepage_2_grid' => __('Homepage 2 grid'),
|
||||
'homepage_categories' => __('Homepage categories'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Attachable resourcec to banner
|
||||
*/
|
||||
public static function attachableResources(): array
|
||||
{
|
||||
return [
|
||||
'brand' => __('Brand'),
|
||||
'category' => __('Category'),
|
||||
'collection' => __('Collection'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Related resources
|
||||
*/
|
||||
public function relatedResources()
|
||||
{
|
||||
if ($this->place === 'homepage_categories') {
|
||||
if ($this->resource_type === 'category') {
|
||||
$this->load('category');
|
||||
|
||||
return $this->category->children()->enabled()->ordered()->get();
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
181
app/Models/CMS/Media/Carousel.php
Normal file
181
app/Models/CMS/Media/Carousel.php
Normal file
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\CMS\Media;
|
||||
|
||||
use App\Models\Concerns\HasSchemalessAttributes;
|
||||
use App\Models\Ecommerce\Product\Brand\Brand;
|
||||
use App\Models\Ecommerce\Product\Category\Category;
|
||||
use App\Models\Ecommerce\Product\Collection\Collection;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Spatie\EloquentSortable\SortableTrait;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class Carousel extends Model implements HasMedia
|
||||
{
|
||||
use HasFactory;
|
||||
use HasSchemalessAttributes;
|
||||
use HasTranslations;
|
||||
use InteractsWithMedia;
|
||||
use SortableTrait;
|
||||
|
||||
/**
|
||||
* Table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'carousels';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'id',
|
||||
'app',
|
||||
'title',
|
||||
'description',
|
||||
'place',
|
||||
'link',
|
||||
'is_visible',
|
||||
'resource_id',
|
||||
'resource_type',
|
||||
'sort_order',
|
||||
'options',
|
||||
];
|
||||
|
||||
/**
|
||||
* Transtable fields
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public array $translatable = ['title', 'description'];
|
||||
|
||||
/**
|
||||
* Sortable attributes
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $sortable = [
|
||||
'order_column_name' => 'sort_order',
|
||||
'sort_when_creating' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Category
|
||||
*/
|
||||
public function category(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Category::class, 'resource_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Collection
|
||||
*/
|
||||
public function collection(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Collection::class, 'resource_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Brand
|
||||
*/
|
||||
public function brand(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Brand::class, 'resource_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Media collections
|
||||
*/
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection('main')
|
||||
->singleFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Media conversations
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb50x50')
|
||||
->width(50)
|
||||
->height(50);
|
||||
|
||||
$this->addMediaConversion('thumb350x350')
|
||||
->width(350)
|
||||
->height(350);
|
||||
|
||||
$this->addMediaConversion('thumb650x650')
|
||||
->width(650)
|
||||
->height(650);
|
||||
}
|
||||
|
||||
/**
|
||||
* Thumbnail
|
||||
*/
|
||||
public function thumbnail(string $resolution = '50x50'): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('main', 'thumb'.$resolution);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to filter
|
||||
*
|
||||
* @param mixed $query
|
||||
* @param string $attribute
|
||||
* @param string $value
|
||||
* @return $query
|
||||
*/
|
||||
public function scopeFilter($query, $attribute, $value): Builder
|
||||
{
|
||||
return $value ? $query->where($attribute, $value) : $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main image
|
||||
*/
|
||||
public function image(): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('main');
|
||||
}
|
||||
|
||||
/**
|
||||
* Text color
|
||||
*/
|
||||
public function textColor(): string
|
||||
{
|
||||
return $this->options->get('color') ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Places for banner
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function places(): array
|
||||
{
|
||||
return [
|
||||
'homepage' => __('Homepage'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Attachable resourcec to banner
|
||||
*/
|
||||
public static function attachableResources(): array
|
||||
{
|
||||
return [
|
||||
'brand' => __('Brand'),
|
||||
'category' => __('Category'),
|
||||
'collection' => __('Collection'),
|
||||
];
|
||||
}
|
||||
}
|
||||
77
app/Models/CMS/Media/Gallery.php
Normal file
77
app/Models/CMS/Media/Gallery.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\CMS\Media;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Spatie\Image\Manipulations;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class Gallery extends Model implements HasMedia
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
use InteractsWithMedia;
|
||||
|
||||
/**
|
||||
* Table
|
||||
*/
|
||||
protected $table = 'galleries';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'description',
|
||||
'is_visible',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = ['title', 'description'];
|
||||
|
||||
/**
|
||||
* Media collections
|
||||
*/
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection('main')
|
||||
->singleFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Media conversations
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb')
|
||||
->width(470)
|
||||
->height(345)
|
||||
->fit(Manipulations::FIT_CONTAIN, 470, 345);
|
||||
}
|
||||
|
||||
/**
|
||||
* Thumbnail url
|
||||
*/
|
||||
public function thumbnail(): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('main', 'thumb');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope for visable galleries
|
||||
*
|
||||
* @param Builder $query
|
||||
*/
|
||||
public function scopeEnabled($query): void
|
||||
{
|
||||
$query->where('is_visible', true);
|
||||
}
|
||||
}
|
||||
42
app/Models/Common/Comment.php
Normal file
42
app/Models/Common/Comment.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Common;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
|
||||
class Comment extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'comment',
|
||||
'user_id',
|
||||
'active',
|
||||
];
|
||||
|
||||
/**
|
||||
* User
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Comment's attached product
|
||||
*/
|
||||
public function product(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Product::class);
|
||||
}
|
||||
}
|
||||
27
app/Models/Concerns/HasEcommerceChannels.php
Normal file
27
app/Models/Concerns/HasEcommerceChannels.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Concerns;
|
||||
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
|
||||
trait HasEcommerceChannels
|
||||
{
|
||||
/**
|
||||
* User ecommerce channels
|
||||
*/
|
||||
public function channels(): MorphMany
|
||||
{
|
||||
return $this->morphMany(Channel::class, 'channelables');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user's most recent image.
|
||||
*/
|
||||
public function channel(): ?Channel
|
||||
{
|
||||
return $this->relationLoaded('channels')
|
||||
? $this->channels->first()
|
||||
: $this->channels()->first();
|
||||
}
|
||||
}
|
||||
25
app/Models/Concerns/HasSchemalessAttributes.php
Normal file
25
app/Models/Concerns/HasSchemalessAttributes.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Concerns;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Spatie\SchemalessAttributes\Casts\SchemalessAttributes;
|
||||
|
||||
trait HasSchemalessAttributes
|
||||
{
|
||||
/**
|
||||
* Add Schemaless Attributes to casts
|
||||
*/
|
||||
public function initializeHasSchemalessAttributes(): void
|
||||
{
|
||||
$this->casts['options'] = SchemalessAttributes::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope for Extra attributes
|
||||
*/
|
||||
public function scopeWithExtraAttributes(): Builder
|
||||
{
|
||||
return $this->options->modelScope();
|
||||
}
|
||||
}
|
||||
26
app/Models/Concerns/InteractsWithNova.php
Normal file
26
app/Models/Concerns/InteractsWithNova.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Concerns;
|
||||
|
||||
trait InteractsWithNova
|
||||
{
|
||||
/**
|
||||
* Check if user can access nova
|
||||
*/
|
||||
public function canAccessNova(): bool
|
||||
{
|
||||
if ($this->isMe()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->hasRole(['admin', 'manager'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->hasRole('vendor') && $this->channel()->id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
52
app/Models/Concerns/InteractsWithRoles.php
Normal file
52
app/Models/Concerns/InteractsWithRoles.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Concerns;
|
||||
|
||||
trait InteractsWithRoles
|
||||
{
|
||||
/**
|
||||
* Check if user is Me :)
|
||||
*/
|
||||
public function isMe(): bool
|
||||
{
|
||||
return in_array($this->email, [
|
||||
'nurmuhammet@mail.com',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is admin
|
||||
*/
|
||||
public function isAdmin(): bool
|
||||
{
|
||||
if ($this->isMe()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->hasRole('admin');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is manager
|
||||
*/
|
||||
public function isManager(): bool
|
||||
{
|
||||
return $this->hasRole('manager');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is entrepreneur
|
||||
*/
|
||||
public function isEntrepreneur(): bool
|
||||
{
|
||||
return $this->hasRole('vendor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is vendor
|
||||
*/
|
||||
public function isVendor(): bool
|
||||
{
|
||||
return $this->hasRole('vendor');
|
||||
}
|
||||
}
|
||||
218
app/Models/Ecommerce/Channel/Channel.php
Normal file
218
app/Models/Ecommerce/Channel/Channel.php
Normal file
@@ -0,0 +1,218 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Channel;
|
||||
|
||||
use App\Events\Ecommerce\Channel\ChannelActiveStateChanged;
|
||||
use App\Models\Ecommerce\Product\Inventory\Inventory;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Models\User;
|
||||
use App\Repositories\Ecommerce\Channel\ChannelRepository;
|
||||
use App\Repositories\System\Cache\CacheRepository;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Laravel\Nova\Nova;
|
||||
use Spatie\EloquentSortable\Sortable;
|
||||
use Spatie\EloquentSortable\SortableTrait;
|
||||
use Spatie\Image\Manipulations;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
use Spatie\Sluggable\HasSlug;
|
||||
use Spatie\Sluggable\SlugOptions;
|
||||
|
||||
class Channel extends Model implements HasMedia, Sortable
|
||||
{
|
||||
use HasFactory;
|
||||
use HasSlug;
|
||||
use InteractsWithMedia;
|
||||
use SortableTrait;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'id',
|
||||
'name',
|
||||
'slug',
|
||||
'description',
|
||||
'timezone',
|
||||
'url',
|
||||
'sort_order',
|
||||
'is_default',
|
||||
'is_visible',
|
||||
'channelables_type',
|
||||
'channelables_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Sortable attributes
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $sortable = [
|
||||
'order_column_name' => 'sort_order',
|
||||
'sort_when_creating' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* The "booted" method of the model.
|
||||
*/
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::created(function (Channel $channel) {
|
||||
CacheRepository::forget(ChannelRepository::CHANNEL_CACHE_NAME_FOR_NOVA);
|
||||
});
|
||||
|
||||
static::updated(function (Channel $channel) {
|
||||
if ($channel->wasChanged('is_visible')) {
|
||||
ChannelActiveStateChanged::dispatch($channel);
|
||||
|
||||
CacheRepository::forget(ChannelRepository::CHANNEL_CACHE_NAME_FOR_NOVA);
|
||||
}
|
||||
});
|
||||
|
||||
static::deleted(function (Channel $channel) {
|
||||
CacheRepository::forget(ChannelRepository::CHANNEL_CACHE_NAME_FOR_NOVA);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the options for generating the slug.
|
||||
*/
|
||||
public function getSlugOptions(): SlugOptions
|
||||
{
|
||||
return SlugOptions::create()
|
||||
->generateSlugsFrom('name')
|
||||
->saveSlugsTo('slug');
|
||||
}
|
||||
|
||||
/**
|
||||
* Media collections
|
||||
*/
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection('uploads')
|
||||
->singleFile()
|
||||
->useFallbackUrl(
|
||||
sprintf('%s/logo-space.png', config('app.url'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Media conversations
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb150x150')
|
||||
->fit(Manipulations::FIT_CONTAIN, 150, 150);
|
||||
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
$this->addMediaConversion('thumb270x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 270, 350);
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel thumbnail
|
||||
*/
|
||||
public function thumbnail(string $size = '200x200'): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('uploads', 'thumb'.$size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the parent channelables model.
|
||||
*/
|
||||
public function channelables(): MorphTo
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
/**
|
||||
* User
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'channelables_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Default tmpost inventory
|
||||
*/
|
||||
public static function tmpostDefault(): static
|
||||
{
|
||||
return static::where('slug', 'tmpost')->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Channels inventories
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
// public function inventories(): HasMany
|
||||
// {
|
||||
// return $this->hasMany(Inventory::class);
|
||||
// }
|
||||
|
||||
/**
|
||||
* Products
|
||||
*/
|
||||
public function products(): MorphToMany
|
||||
{
|
||||
return $this->morphToMany(Product::class, 'productable', 'product_has_relations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show products link
|
||||
*/
|
||||
public function productsPage(): string
|
||||
{
|
||||
return route('web.entrepreneurs.show', ['entrepreneur' => $this->slug]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Image
|
||||
*/
|
||||
public function image(): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('main');
|
||||
}
|
||||
|
||||
/**
|
||||
* Channels inventories
|
||||
*/
|
||||
public function inventories(): HasMany
|
||||
{
|
||||
return $this->hasMany(Inventory::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nova detail page
|
||||
*/
|
||||
public function novaDetailPage(): string
|
||||
{
|
||||
return Nova::url('/resources/channels/'.$this->id);
|
||||
}
|
||||
}
|
||||
86
app/Models/Ecommerce/Payouts/Payout.php
Normal file
86
app/Models/Ecommerce/Payouts/Payout.php
Normal file
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Payouts;
|
||||
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use App\Models\Ecommerce\Product\Order\OrderItem;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class Payout extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* Protected fields
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'channel_id',
|
||||
'start_date',
|
||||
'end_date',
|
||||
'total_sum',
|
||||
'postshop_total',
|
||||
'entrepreneur_total',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'start_date' => 'date',
|
||||
'end_date' => 'date',
|
||||
];
|
||||
|
||||
/**
|
||||
* Related channel
|
||||
*/
|
||||
public function channel(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Channel::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* The "booted" method of the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::updated(function ($payout) {
|
||||
$order_item_ids = [];
|
||||
|
||||
foreach ($payout->order_items_ids as $key => $value) {
|
||||
if (! $value) {
|
||||
$order_item_ids[] = $key;
|
||||
}
|
||||
}
|
||||
|
||||
DB::table('payout_items')
|
||||
->where('payout_id', $payout->id)
|
||||
->whereIntegerInRaw('order_item_id', $order_item_ids)
|
||||
->delete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Order items
|
||||
*/
|
||||
public function orderItems(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(OrderItem::class, 'payout_items');
|
||||
}
|
||||
}
|
||||
39
app/Models/Ecommerce/Payouts/PayoutItem.php
Normal file
39
app/Models/Ecommerce/Payouts/PayoutItem.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Payouts;
|
||||
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class PayoutItem extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* Protected fields
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'payout_id',
|
||||
'channel_id',
|
||||
'order_item_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Related channel
|
||||
*/
|
||||
public function channel(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Channel::class);
|
||||
}
|
||||
}
|
||||
169
app/Models/Ecommerce/Product/Brand/Brand.php
Normal file
169
app/Models/Ecommerce/Product/Brand/Brand.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Brand;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Spatie\EloquentSortable\Sortable;
|
||||
use Spatie\EloquentSortable\SortableTrait;
|
||||
use Spatie\Image\Manipulations;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
use Spatie\Sluggable\HasSlug;
|
||||
use Spatie\Sluggable\SlugOptions;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class Brand extends Model implements HasMedia, Sortable
|
||||
{
|
||||
use HasFactory;
|
||||
use HasSlug;
|
||||
use HasTranslations;
|
||||
use InteractsWithMedia;
|
||||
use SortableTrait;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'slug',
|
||||
'type',
|
||||
'website',
|
||||
'description',
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'is_visible',
|
||||
'sort_order',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = ['description'];
|
||||
|
||||
/**
|
||||
* Sortable attributes
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $sortable = [
|
||||
'order_column_name' => 'sort_order',
|
||||
'sort_when_creating' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the options for generating the slug.
|
||||
*/
|
||||
public function getSlugOptions(): SlugOptions
|
||||
{
|
||||
return SlugOptions::create()
|
||||
->generateSlugsFrom('name')
|
||||
->saveSlugsTo('slug');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register media collections
|
||||
*/
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection('uploads')
|
||||
->singleFile()
|
||||
->acceptsMimeTypes(['image/jpg', 'image/jpeg', 'image/png'])
|
||||
->useFallbackUrl(
|
||||
sprintf('%s/logo-space.png', config('app.url'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Media Conversions
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
$this->addMediaConversion('thumb270x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 270, 350);
|
||||
}
|
||||
|
||||
/**
|
||||
* Brand thumbnail
|
||||
*/
|
||||
public function thumbnail(string $size = '200x200'): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('uploads', 'thumb'.$size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Original image
|
||||
*/
|
||||
public function image(): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('uploads');
|
||||
}
|
||||
|
||||
/**
|
||||
* Brand Products
|
||||
*/
|
||||
public function products(): HasMany
|
||||
{
|
||||
return $this->hasMany(Product::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope for visable models
|
||||
*/
|
||||
public function scopeEnabled(Builder $query): void
|
||||
{
|
||||
$query->where('is_visible', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Brand Types
|
||||
*/
|
||||
public static function types(): array
|
||||
{
|
||||
return [
|
||||
'market',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if brand belongs to market
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isMarketCategory(): string
|
||||
{
|
||||
return $this->type === 'market';
|
||||
}
|
||||
|
||||
/**
|
||||
* Brand's Products web page
|
||||
*/
|
||||
public function productsPage(): string
|
||||
{
|
||||
return route('web.brands.products', ['brand' => $this->slug]);
|
||||
}
|
||||
}
|
||||
46
app/Models/Ecommerce/Product/Cart/CartItem.php
Normal file
46
app/Models/Ecommerce/Product/Cart/CartItem.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Cart;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class CartItem extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*/
|
||||
protected $table = 'cart_items';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'product_id',
|
||||
'product_quantity',
|
||||
];
|
||||
|
||||
/**
|
||||
* Cart Item user
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cart Item product
|
||||
*/
|
||||
public function product(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class);
|
||||
}
|
||||
}
|
||||
205
app/Models/Ecommerce/Product/Category/Category.php
Normal file
205
app/Models/Ecommerce/Product/Category/Category.php
Normal file
@@ -0,0 +1,205 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Category;
|
||||
|
||||
use App\Events\Ecommerce\Product\Category\CategoryTaxChanged;
|
||||
use App\Models\Concerns\HasSchemalessAttributes;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Spatie\EloquentSortable\Sortable;
|
||||
use Spatie\EloquentSortable\SortableTrait;
|
||||
use Spatie\Image\Manipulations;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
use Spatie\Sluggable\HasSlug;
|
||||
use Spatie\Sluggable\SlugOptions;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
use Staudenmeir\EloquentEagerLimitXLaravelAdjacencyList\Eloquent\HasEagerLimitAndRecursiveRelationships;
|
||||
|
||||
class Category extends Model implements HasMedia, Sortable
|
||||
{
|
||||
use HasEagerLimitAndRecursiveRelationships;
|
||||
use HasFactory;
|
||||
use HasSchemalessAttributes;
|
||||
use HasSlug;
|
||||
use HasTranslations;
|
||||
use InteractsWithMedia;
|
||||
use SortableTrait;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'parent_id',
|
||||
'name',
|
||||
'slug',
|
||||
'type',
|
||||
'description',
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'is_visible',
|
||||
'tax_percentage',
|
||||
'sort_order',
|
||||
'options',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = ['name', 'description'];
|
||||
|
||||
/**
|
||||
* Sortable attributes
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $sortable = [
|
||||
'order_column_name' => 'sort_order',
|
||||
'sort_when_creating' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the options for generating the slug.
|
||||
*/
|
||||
public function getSlugOptions(): SlugOptions
|
||||
{
|
||||
return SlugOptions::create()
|
||||
->generateSlugsFrom('name')
|
||||
->saveSlugsTo('slug');
|
||||
}
|
||||
|
||||
/**
|
||||
* Media Collections
|
||||
*/
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection('uploads')
|
||||
->singleFile()
|
||||
->acceptsMimeTypes(['image/jpg', 'image/jpeg', 'image/png'])
|
||||
->useFallbackUrl(
|
||||
sprintf('%s/logo-space.png', config('app.url'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Media Conversions
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
$this->addMediaConversion('thumb270x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 270, 350);
|
||||
|
||||
$this->addMediaConversion('thumb657x230')
|
||||
->fit(Manipulations::FIT_CROP, 657, 230);
|
||||
}
|
||||
|
||||
/**
|
||||
* Brand thumbnail
|
||||
*/
|
||||
public function thumbnail(string $size = '200x200'): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('uploads', 'thumb'.$size);
|
||||
}
|
||||
|
||||
/**
|
||||
* The "booted" method of the model.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected static function booted()
|
||||
{
|
||||
static::updated(function ($category) {
|
||||
if ($category->wasChanged('tax_percentage')) {
|
||||
CategoryTaxChanged::dispatch($category);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Attributes (properties) of Category
|
||||
*/
|
||||
public function properties(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Attribute::class, 'attributes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Category Products
|
||||
*/
|
||||
public function products(): MorphToMany
|
||||
{
|
||||
return $this->morphToMany(Product::class, 'productable', 'product_has_relations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope for visable models
|
||||
*/
|
||||
public function scopeEnabled(Builder $query): void
|
||||
{
|
||||
$query->where('is_visible', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Color attribute
|
||||
*/
|
||||
public function color(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('color'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Category's Parent name
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public function parentName(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->parent?->name
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if model belongs to Market
|
||||
*/
|
||||
public function isMarketCategory(): bool
|
||||
{
|
||||
return $this->type === 'market';
|
||||
}
|
||||
|
||||
/**
|
||||
* Category's Products webpage
|
||||
*/
|
||||
public function productsPage(): string
|
||||
{
|
||||
return route('web.categories.products', ['category' => $this->slug]);
|
||||
}
|
||||
}
|
||||
124
app/Models/Ecommerce/Product/Collection/Collection.php
Normal file
124
app/Models/Ecommerce/Product/Collection/Collection.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Collection;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
use Spatie\EloquentSortable\Sortable;
|
||||
use Spatie\EloquentSortable\SortableTrait;
|
||||
use Spatie\Image\Manipulations;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
use Spatie\Sluggable\HasSlug;
|
||||
use Spatie\Sluggable\SlugOptions;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
use Staudenmeir\EloquentEagerLimitXLaravelAdjacencyList\Eloquent\HasEagerLimitAndRecursiveRelationships;
|
||||
|
||||
class Collection extends Model implements HasMedia, Sortable
|
||||
{
|
||||
use HasEagerLimitAndRecursiveRelationships;
|
||||
use HasFactory;
|
||||
use HasSlug;
|
||||
use HasTranslations;
|
||||
use InteractsWithMedia;
|
||||
use SortableTrait;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'slug',
|
||||
'description',
|
||||
'sort_order',
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'is_visible',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = ['name', 'description'];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $sortable = [
|
||||
'order_column_name' => 'sort_order',
|
||||
'sort_when_creating' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the options for generating the slug.
|
||||
*/
|
||||
public function getSlugOptions(): SlugOptions
|
||||
{
|
||||
return SlugOptions::create()
|
||||
->generateSlugsFrom('name')
|
||||
->saveSlugsTo('slug');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Media Collections
|
||||
*/
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection('uploads')
|
||||
->singleFile()
|
||||
->acceptsMimeTypes(['image/jpg', 'image/jpeg', 'image/png'])
|
||||
->useFallbackUrl(
|
||||
sprintf('%s/logo-space.png', config('app.url'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register Media Conversions
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
$this->addMediaConversion('thumb270x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 270, 350);
|
||||
}
|
||||
|
||||
/**
|
||||
* Products
|
||||
*/
|
||||
public function products(): MorphToMany
|
||||
{
|
||||
return $this->morphToMany(Product::class, 'productable', 'product_has_relations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Brand's Products web page
|
||||
*/
|
||||
public function productsPage(): string
|
||||
{
|
||||
return route('web.collections.products', ['collection' => $this->slug]);
|
||||
}
|
||||
}
|
||||
51
app/Models/Ecommerce/Product/Coupon/Coupon.php
Normal file
51
app/Models/Ecommerce/Product/Coupon/Coupon.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Coupon;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Coupon extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* Discount by percentage (%)
|
||||
*/
|
||||
public const DISCOUNT_PERCENTAGE = 'percentage';
|
||||
|
||||
/**
|
||||
* Discount by fixed amount (ex: -10 TMT)
|
||||
*/
|
||||
public const DISCOUNT_FIXED = 'fixed_amount';
|
||||
|
||||
/**
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'code',
|
||||
'discount_type',
|
||||
'discount_value',
|
||||
'notes',
|
||||
'is_active',
|
||||
];
|
||||
|
||||
/**
|
||||
* Discount types
|
||||
*/
|
||||
public static function discountTypes(): array
|
||||
{
|
||||
return [
|
||||
self::DISCOUNT_PERCENTAGE => __('Percentage'),
|
||||
self::DISCOUNT_FIXED => __('Fixed Amount'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Default discount type
|
||||
*/
|
||||
public static function defaultDiscountType(): string
|
||||
{
|
||||
return self::DISCOUNT_PERCENTAGE;
|
||||
}
|
||||
}
|
||||
45
app/Models/Ecommerce/Product/Favorite/Favorite.php
Normal file
45
app/Models/Ecommerce/Product/Favorite/Favorite.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Favorite;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Favorite extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*/
|
||||
protected $table = 'favorites';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'product_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Favourite Product
|
||||
*/
|
||||
public function product(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class, 'product_id', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Favourite model User (Owner)
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
}
|
||||
89
app/Models/Ecommerce/Product/Inventory/Inventory.php
Normal file
89
app/Models/Ecommerce/Product/Inventory/Inventory.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Inventory;
|
||||
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Spatie\Sluggable\HasSlug;
|
||||
use Spatie\Sluggable\SlugOptions;
|
||||
|
||||
class Inventory extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasSlug;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'code',
|
||||
'description',
|
||||
'email',
|
||||
'phone_number',
|
||||
'street_address',
|
||||
'zipcode',
|
||||
'region',
|
||||
'province_id',
|
||||
'longitude',
|
||||
'latitude',
|
||||
'is_default',
|
||||
'channel_id',
|
||||
'shareable',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the options for generating the slug.
|
||||
*/
|
||||
public function getSlugOptions(): SlugOptions
|
||||
{
|
||||
return SlugOptions::create()
|
||||
->generateSlugsFrom('name')
|
||||
->saveSlugsTo('code')
|
||||
->doNotGenerateSlugsOnUpdate();
|
||||
}
|
||||
|
||||
/**
|
||||
* User Channel
|
||||
*/
|
||||
public function channel(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Channel::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Products
|
||||
*/
|
||||
public function products()
|
||||
{
|
||||
return $this->belongsToMany(Product::class)->withPivot('stock');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tmpost default inventory
|
||||
*/
|
||||
public static function tmpostDefault(): Inventory
|
||||
{
|
||||
return static::where('code', 'tmpost')->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* History
|
||||
*/
|
||||
public function history(): HasMany
|
||||
{
|
||||
return $this->hasMany(InventoryHistory::class, 'inventory_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* History removed
|
||||
*/
|
||||
public function historyRemoved(): HasMany
|
||||
{
|
||||
return $this->hasMany(InventoryHistoryRemoved::class, 'inventory_id');
|
||||
}
|
||||
}
|
||||
61
app/Models/Ecommerce/Product/Inventory/InventoryHistory.php
Normal file
61
app/Models/Ecommerce/Product/Inventory/InventoryHistory.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Inventory;
|
||||
|
||||
use App\Models\Concerns\HasSchemalessAttributes;
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class InventoryHistory extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasSchemalessAttributes;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'date',
|
||||
'inventory_id',
|
||||
'channel_id',
|
||||
'notes',
|
||||
'total',
|
||||
'options',
|
||||
];
|
||||
|
||||
/**
|
||||
* Attributes that are casted
|
||||
*/
|
||||
protected $casts = [
|
||||
'date' => 'date',
|
||||
];
|
||||
|
||||
/**
|
||||
* Channel
|
||||
*/
|
||||
public function channel(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Channel::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inventory
|
||||
*/
|
||||
public function inventory(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Inventory::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Items
|
||||
*/
|
||||
public function items(): HasMany
|
||||
{
|
||||
return $this->hasMany(InventoryHistoryItem::class, 'inventory_history_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Inventory;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class InventoryHistoryItem extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'inventory_history_id',
|
||||
'product_id',
|
||||
'quantity',
|
||||
'total',
|
||||
'cost_amount',
|
||||
];
|
||||
|
||||
/**
|
||||
* Inventory history
|
||||
*/
|
||||
public function inventoryHistory(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(InventoryHistory::class, 'inventory_history_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Product
|
||||
*/
|
||||
public function product(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Inventory;
|
||||
|
||||
use App\Models\Concerns\HasSchemalessAttributes;
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class InventoryHistoryRemoved extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasSchemalessAttributes;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'date',
|
||||
'inventory_id',
|
||||
'channel_id',
|
||||
'notes',
|
||||
'total',
|
||||
'options',
|
||||
];
|
||||
|
||||
/**
|
||||
* Attributes that are casted
|
||||
*/
|
||||
protected $casts = [
|
||||
'date' => 'date',
|
||||
];
|
||||
|
||||
/**
|
||||
* Channel
|
||||
*/
|
||||
public function channel(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Channel::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inventory
|
||||
*/
|
||||
public function inventory(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Inventory::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Items
|
||||
*/
|
||||
public function items(): HasMany
|
||||
{
|
||||
return $this->hasMany(InventoryHistoryRemovedItem::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Inventory;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class InventoryHistoryRemovedItem extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'inventory_history_removed_id',
|
||||
'product_id',
|
||||
'quantity',
|
||||
'total',
|
||||
'cost_amount',
|
||||
];
|
||||
|
||||
/**
|
||||
* Inventory history
|
||||
*/
|
||||
public function inventoryHistoryRemoved(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(InventoryHistoryRemoved::class, 'inventory_history_removed_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Product
|
||||
*/
|
||||
public function product(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class);
|
||||
}
|
||||
}
|
||||
30
app/Models/Ecommerce/Product/Order/Concerns/HasPayments.php
Normal file
30
app/Models/Ecommerce/Product/Order/Concerns/HasPayments.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Order\Concerns;
|
||||
|
||||
trait HasPayments
|
||||
{
|
||||
/**
|
||||
* Total price for order
|
||||
*/
|
||||
public function total(): float
|
||||
{
|
||||
return $this->items->sum('total');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return total order with shipping.
|
||||
*/
|
||||
public function fullPriceWithShipping(): string
|
||||
{
|
||||
return floatval($this->total()) + floatval($this->shippingPrice()) + floatval($this->additional_tax);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted payment type
|
||||
*/
|
||||
public function formattedPaymentType(): string
|
||||
{
|
||||
return $this->paymentType?->name;
|
||||
}
|
||||
}
|
||||
32
app/Models/Ecommerce/Product/Order/Concerns/HasShipping.php
Normal file
32
app/Models/Ecommerce/Product/Order/Concerns/HasShipping.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Order\Concerns;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
|
||||
|
||||
trait HasShipping
|
||||
{
|
||||
/**
|
||||
* Shipping price
|
||||
*/
|
||||
public function shippingPrice(): int
|
||||
{
|
||||
return intval($this->shipping_price) ?: OrderShipping::priceFor($this->shipping_method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted shipping method
|
||||
*/
|
||||
public function formattedShippingMethod(): string
|
||||
{
|
||||
return OrderShipping::formattedShippingMethod($this->shipping_method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Full address for the order
|
||||
*/
|
||||
public function fullAddress(): string
|
||||
{
|
||||
return OrderShipping::fullAddress($this->region, $this->province_id, $this->customer_address);
|
||||
}
|
||||
}
|
||||
72
app/Models/Ecommerce/Product/Order/Concerns/HasStatus.php
Normal file
72
app/Models/Ecommerce/Product/Order/Concerns/HasStatus.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Order\Concerns;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
|
||||
trait HasStatus
|
||||
{
|
||||
/**
|
||||
* Return the correct order status formatted.
|
||||
*/
|
||||
public function formatted_status(): string
|
||||
{
|
||||
return OrderStatus::formattedStatusFor($this->status);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can order be cancelled?
|
||||
*/
|
||||
public function canBeCancelled(): bool
|
||||
{
|
||||
return $this->isPending();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if order is pending
|
||||
*/
|
||||
public function isPending(): bool
|
||||
{
|
||||
return $this->status === OrderStatus::PENDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if order is registered
|
||||
*/
|
||||
public function isRegistered(): bool
|
||||
{
|
||||
return $this->status === OrderStatus::REGISTER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if order is paid
|
||||
*/
|
||||
public function isPaid(): bool
|
||||
{
|
||||
return $this->status === OrderStatus::PAID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if order is completed
|
||||
*/
|
||||
public function isCompleted(): bool
|
||||
{
|
||||
return $this->status === OrderStatus::COMPLETED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if order is completed
|
||||
*/
|
||||
public function isCancelled(): bool
|
||||
{
|
||||
return $this->status === OrderStatus::CANCELLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark order as paid
|
||||
*/
|
||||
public function markAsPaid(): void
|
||||
{
|
||||
$this->update(['status' => OrderStatus::PAID]);
|
||||
}
|
||||
}
|
||||
87
app/Models/Ecommerce/Product/Order/Order.php
Normal file
87
app/Models/Ecommerce/Product/Order/Order.php
Normal file
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Order;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Concerns\HasPayments;
|
||||
use App\Models\Ecommerce\Product\Order\Concerns\HasShipping;
|
||||
use App\Models\Ecommerce\Product\Order\Concerns\HasStatus;
|
||||
use App\Models\System\Settings\Location\Province;
|
||||
use App\Models\System\Settings\Payments\PaymentType;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
class Order extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasPayments;
|
||||
use HasShipping;
|
||||
use HasStatus;
|
||||
use SoftDeletes;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'number',
|
||||
'status',
|
||||
'shipping_method',
|
||||
'shipping_price',
|
||||
'payment_type_id',
|
||||
'notes',
|
||||
'customer_name',
|
||||
'customer_phone',
|
||||
'customer_address',
|
||||
'delivery_time',
|
||||
'delivery_at',
|
||||
'region',
|
||||
'user_id',
|
||||
'additional_tax',
|
||||
'province_id',
|
||||
'source_app',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*/
|
||||
protected $casts = [
|
||||
'delivery_at' => 'date',
|
||||
];
|
||||
|
||||
/**
|
||||
* User (customer)
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Related Province
|
||||
*/
|
||||
public function province(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Province::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Order items
|
||||
*/
|
||||
public function items(): HasMany
|
||||
{
|
||||
return $this->hasMany(OrderItem::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment types
|
||||
*/
|
||||
public function paymentType(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(PaymentType::class, 'payment_type_id');
|
||||
}
|
||||
}
|
||||
64
app/Models/Ecommerce/Product/Order/OrderItem.php
Normal file
64
app/Models/Ecommerce/Product/Order/OrderItem.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Order;
|
||||
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class OrderItem extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'product_name',
|
||||
'product_id',
|
||||
'order_id',
|
||||
'channel_id',
|
||||
'quantity',
|
||||
'unit_price_amount',
|
||||
'unit_cost_amount',
|
||||
];
|
||||
|
||||
/**
|
||||
* Related order (parent)
|
||||
*/
|
||||
public function order(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Order::class, 'order_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Related product
|
||||
*/
|
||||
public function product(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class, 'product_id', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Related Channel
|
||||
*/
|
||||
public function channel(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Channel::class, 'channel_id', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Total price
|
||||
*/
|
||||
public function total(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => (float) $this->unit_price_amount * (int) $this->quantity
|
||||
);
|
||||
}
|
||||
}
|
||||
88
app/Models/Ecommerce/Product/Order/Payment/OrderPayment.php
Normal file
88
app/Models/Ecommerce/Product/Order/Payment/OrderPayment.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Order\Payment;
|
||||
|
||||
use App\Models\System\Settings\Payments\PaymentType;
|
||||
use App\Repositories\System\Cache\CacheRepository;
|
||||
|
||||
class OrderPayment
|
||||
{
|
||||
/**
|
||||
* Cash
|
||||
*/
|
||||
public const CASH = 'cash';
|
||||
|
||||
/**
|
||||
* ATM
|
||||
*/
|
||||
public const ATM = 'atm';
|
||||
|
||||
/**
|
||||
* Online (halkbank)
|
||||
*/
|
||||
public const ONLINE = 'online';
|
||||
|
||||
/**
|
||||
* Online (halkbank)
|
||||
*/
|
||||
public const HALK_BANK = 'halk_bank';
|
||||
|
||||
/**
|
||||
* Online (senagat)
|
||||
*/
|
||||
public const SENAGAT_BANK = 'senegat_bank';
|
||||
|
||||
/**
|
||||
* Online (rysgal)
|
||||
*/
|
||||
public const RYSGAL_BANK = 'rysgal_bank';
|
||||
|
||||
/**
|
||||
* Online (wneshka)
|
||||
*/
|
||||
public const WNESHKA_BANK = 'wneshka_bank';
|
||||
|
||||
/**
|
||||
* Default payment value
|
||||
*/
|
||||
public static function default(): ?string
|
||||
{
|
||||
return CacheRepository::make(
|
||||
name: 'cs-nova-models-default-order-payment',
|
||||
value: fn () => PaymentType::where('code', 'cash')->pluck('id')->first(),
|
||||
time: 60 * 60 * 24
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Payment values
|
||||
*/
|
||||
public static function values(): array
|
||||
{
|
||||
return CacheRepository::make(
|
||||
name: 'cs-nova-models-order-payments',
|
||||
value: fn () => PaymentType::pluck('name', 'id')->toArray()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Old but good types
|
||||
*
|
||||
* @return array<int, string>
|
||||
*/
|
||||
public static function oldButGoodTypes(): array
|
||||
{
|
||||
return [
|
||||
static::ATM => __('ATM'),
|
||||
static::CASH => __('Cash'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted payment type for given "type"
|
||||
*/
|
||||
public static function formattedPaymentTypeFor(string $type): string
|
||||
{
|
||||
return static::values()[$type] ?? self::CASH;
|
||||
}
|
||||
}
|
||||
201
app/Models/Ecommerce/Product/Order/Shipping/OrderShipping.php
Normal file
201
app/Models/Ecommerce/Product/Order/Shipping/OrderShipping.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Order\Shipping;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Order;
|
||||
use App\Models\System\Settings\Location\Province;
|
||||
use App\Models\System\Settings\Location\Region;
|
||||
|
||||
class OrderShipping
|
||||
{
|
||||
/*
|
||||
* Shipping methods
|
||||
*
|
||||
* standart - basic
|
||||
* express - fast
|
||||
* self_pickup - self pickup
|
||||
* region - deliver to regions (mr, ah, dz, lb, bn)
|
||||
*/
|
||||
|
||||
/**
|
||||
* Standart shipping
|
||||
*/
|
||||
public const STANDART = 'standart';
|
||||
|
||||
/**
|
||||
* Express shipping
|
||||
*/
|
||||
public const EXPRESS = 'express';
|
||||
|
||||
/**
|
||||
* On own - self pickup
|
||||
*/
|
||||
public const SELF_PICKUP = 'self_pickup';
|
||||
|
||||
/**
|
||||
* Region - shipping to regions (mr, ah, ...)
|
||||
*/
|
||||
public const REGION = 'region';
|
||||
|
||||
/*
|
||||
* Shipping method prices
|
||||
*
|
||||
* standart - 20
|
||||
* express - 30
|
||||
* self pickup - 0
|
||||
* region - 40
|
||||
*/
|
||||
|
||||
/**
|
||||
* Standart shipping price
|
||||
*/
|
||||
public const STANDART_PRICE = 20;
|
||||
|
||||
/**
|
||||
* Express shipping price
|
||||
*/
|
||||
public const EXPRESS_PRICE = 30;
|
||||
|
||||
/**
|
||||
* Self pickup shipping price
|
||||
*/
|
||||
public const SELF_PICKUP_PRICE = 0;
|
||||
|
||||
/**
|
||||
* Region shipping price
|
||||
*/
|
||||
public const REGION_PRICE = 40;
|
||||
|
||||
/**
|
||||
* Order delivery times
|
||||
*
|
||||
* morning
|
||||
* evening
|
||||
*/
|
||||
|
||||
/**
|
||||
* Morning time 09 - 12:00
|
||||
*/
|
||||
public const MORNING = '09:00 - 12:00';
|
||||
|
||||
/**
|
||||
* Evening time 13:00 - 18:00
|
||||
*/
|
||||
public const EVENING = '13:00 - 18:00';
|
||||
|
||||
/**
|
||||
* Default shipping value
|
||||
*/
|
||||
public static function default(): string
|
||||
{
|
||||
return static::STANDART;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default shipping time value
|
||||
*/
|
||||
public static function defaultTime(): string
|
||||
{
|
||||
return static::EVENING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shipping values
|
||||
*/
|
||||
public static function values(): array
|
||||
{
|
||||
return [
|
||||
self::STANDART => __('Standart'),
|
||||
self::EXPRESS => __('Express'),
|
||||
self::SELF_PICKUP => __('Self Pickup'),
|
||||
self::REGION => __('Region'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prices
|
||||
*/
|
||||
public static function prices(): array
|
||||
{
|
||||
return [
|
||||
self::STANDART => self::STANDART_PRICE,
|
||||
self::EXPRESS => self::EXPRESS_PRICE,
|
||||
self::SELF_PICKUP => self::SELF_PICKUP_PRICE,
|
||||
self::REGION => self::REGION_PRICE,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Shipping times
|
||||
*/
|
||||
public static function times(): array
|
||||
{
|
||||
return [
|
||||
self::MORNING => self::MORNING,
|
||||
self::EVENING => self::EVENING,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get price for specific shipping
|
||||
*/
|
||||
public static function priceFor(string $type): int
|
||||
{
|
||||
return static::prices()[$type] ?? self::STANDART_PRICE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order shipping price
|
||||
*
|
||||
* @param Order $order
|
||||
*/
|
||||
public static function orderShippingPrice($order): int
|
||||
{
|
||||
if ($order->region === Region::AG) {
|
||||
return static::priceFor($order->shipping_method);
|
||||
}
|
||||
|
||||
if (in_array($order->province_id, [
|
||||
12,
|
||||
43,
|
||||
45,
|
||||
83,
|
||||
56,
|
||||
22,
|
||||
])) {
|
||||
return 30;
|
||||
}
|
||||
|
||||
return static::REGION_PRICE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted shipping method
|
||||
*/
|
||||
public static function formattedShippingMethod(string $shippingMethod): string
|
||||
{
|
||||
return static::values()[$shippingMethod] ?? __('Standart');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get full address
|
||||
*/
|
||||
public static function fullAddress($region, $province, $customer_address): string
|
||||
{
|
||||
$address = '';
|
||||
|
||||
if ($region) {
|
||||
$address .= Region::labelFor($region);
|
||||
}
|
||||
|
||||
if ($province = Province::where('id', $province)->first('name')) {
|
||||
$address .= ', '.$province->name;
|
||||
}
|
||||
|
||||
if ($customer_address) {
|
||||
$address .= ','.$customer_address;
|
||||
}
|
||||
|
||||
return $address;
|
||||
}
|
||||
}
|
||||
89
app/Models/Ecommerce/Product/Order/Status/OrderStatus.php
Normal file
89
app/Models/Ecommerce/Product/Order/Status/OrderStatus.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Order\Status;
|
||||
|
||||
class OrderStatus
|
||||
{
|
||||
/**
|
||||
* Pending orders are brand new orders that have not been processed yet.
|
||||
*/
|
||||
public const PENDING = 'pending';
|
||||
|
||||
/**
|
||||
* Orders that has been registered..
|
||||
*/
|
||||
public const REGISTER = 'register';
|
||||
|
||||
/**
|
||||
* Orders that has been paid..
|
||||
*/
|
||||
public const PAID = 'paid';
|
||||
|
||||
/**
|
||||
* Orders fulfilled completely.
|
||||
*/
|
||||
public const COMPLETED = 'completed';
|
||||
|
||||
/**
|
||||
* Order that has been cancelled.
|
||||
*/
|
||||
public const CANCELLED = 'cancelled';
|
||||
|
||||
/**
|
||||
* Default status value
|
||||
*/
|
||||
public static function default(): string
|
||||
{
|
||||
return static::PENDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status Values
|
||||
*/
|
||||
public static function values(): array
|
||||
{
|
||||
return [
|
||||
self::PENDING => __('Pending'),
|
||||
self::REGISTER => __('Registered'),
|
||||
self::PAID => __('Paid'),
|
||||
self::COMPLETED => __('Completed'),
|
||||
self::CANCELLED => __('Cancelled'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted status for given "status"
|
||||
*/
|
||||
public static function formattedStatusFor(string $status): string
|
||||
{
|
||||
return static::values()[$status] ?? __('None');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tailwind
|
||||
*/
|
||||
public static function classes(): array
|
||||
{
|
||||
return [
|
||||
self::PENDING => 'warning',
|
||||
self::REGISTER => 'info',
|
||||
self::PAID => 'primary',
|
||||
self::COMPLETED => 'success',
|
||||
self::CANCELLED => 'danger',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* HEX Colors
|
||||
*/
|
||||
public static function colors(): array
|
||||
{
|
||||
return [
|
||||
self::PENDING => '#F5573B',
|
||||
self::REGISTER => '#F2CB22',
|
||||
self::PAID => '#098F56',
|
||||
self::COMPLETED => '#8FC15D',
|
||||
self::CANCELLED => '#d70206',
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
use Laravel\Nova\Nova;
|
||||
|
||||
trait ProductFrontEndHelpers
|
||||
{
|
||||
/**
|
||||
* Show page
|
||||
*/
|
||||
public function showPage(): string
|
||||
{
|
||||
return route('web.products.show', ['product' => $this->slug]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nova page
|
||||
*/
|
||||
public function novaPage(): string
|
||||
{
|
||||
return Nova::url('/resources/products');
|
||||
}
|
||||
|
||||
/**
|
||||
* Nova detail page
|
||||
*/
|
||||
public function novaDetailPage(): string
|
||||
{
|
||||
return Nova::url('/resources/products/'.$this->id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
use Spatie\Image\Manipulations;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
|
||||
trait ProductMedia
|
||||
{
|
||||
/**
|
||||
* Media collections
|
||||
*/
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection('uploads')
|
||||
->useFallbackUrl(url('/assets/web/images/05.jpg'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Media Conversions
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb200x200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 200, 200);
|
||||
|
||||
$this->addMediaConversion('thumb400x400')
|
||||
->fit(Manipulations::FIT_CONTAIN, 400, 400);
|
||||
|
||||
$this->addMediaConversion('thumb720x720')
|
||||
->fit(Manipulations::FIT_CONTAIN, 720, 720);
|
||||
|
||||
$this->addMediaConversion('thumb800x800')
|
||||
->fit(Manipulations::FIT_CONTAIN, 800, 800);
|
||||
|
||||
$this->addMediaConversion('thumb1200x1200')
|
||||
->fit(Manipulations::FIT_CONTAIN, 1200, 1200);
|
||||
|
||||
$this->addMediaConversion('thumb288x431')
|
||||
->fit(Manipulations::FIT_CONTAIN, 288, 431);
|
||||
|
||||
$this->addMediaConversion('thumb270x350')
|
||||
->fit(Manipulations::FIT_CONTAIN, 270, 350);
|
||||
}
|
||||
|
||||
/**
|
||||
* Thumbnail
|
||||
*/
|
||||
public function thumbnail(string $size = '200x200'): string
|
||||
{
|
||||
return $this->getFirstMediaUrl('uploads', 'thumb'.$size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image when hovered (returns second image)
|
||||
*/
|
||||
public function getHoverImage(string $size = '270x350'): string
|
||||
{
|
||||
$media = $this->getMedia('uploads');
|
||||
$image_count = $media->count();
|
||||
|
||||
if ($image_count == 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return ($image_count == 1)
|
||||
? $media[0]->getUrl('thumb'.$size)
|
||||
: $media[1]->getUrl('thumb'.$size);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,436 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
use App\Models\Ecommerce\Product\Property\ProductProperty;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
|
||||
trait ProductProperties
|
||||
{
|
||||
/**
|
||||
* Check if given product has given property
|
||||
*/
|
||||
public function containsProperty(string $property): bool
|
||||
{
|
||||
return $this->properties->pluck('attribute.slug')->contains($property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product property
|
||||
*/
|
||||
public function getProperty(string $name): ?ProductProperty
|
||||
{
|
||||
return $this->properties->first(fn ($property) => $property->attribute->slug === $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if product has color variants
|
||||
*/
|
||||
public function hasColorVariants(): bool
|
||||
{
|
||||
return $this->containsProperty('colour');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product color property
|
||||
*/
|
||||
public function getColorProperty(): ?ProductProperty
|
||||
{
|
||||
return $this->getProperty('colour');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get product color property
|
||||
*/
|
||||
public function getSizeProperty(): ?ProductProperty
|
||||
{
|
||||
return $this->getProperty('size');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get color value of product
|
||||
*/
|
||||
public function getColorValue(): ?string
|
||||
{
|
||||
$colorProperty = $this->getColorProperty();
|
||||
|
||||
return $colorProperty ? $colorProperty->values->first()?->real_value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size value
|
||||
*/
|
||||
public function getSizeValue(): ?string
|
||||
{
|
||||
$sizeProperty = $this->getSizeProperty();
|
||||
|
||||
return $sizeProperty ? $sizeProperty->values->first()?->real_value : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if product has a color.
|
||||
*/
|
||||
public function hasColor(): bool
|
||||
{
|
||||
return $this->hasPropertyWithSlug('colour');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if product has a size.
|
||||
*/
|
||||
public function hasSize(): bool
|
||||
{
|
||||
return $this->hasPropertyWithSlug('size');
|
||||
}
|
||||
|
||||
/**
|
||||
* Color property
|
||||
*/
|
||||
public function getColor(): string
|
||||
{
|
||||
$product = 'productColor'.$this->id;
|
||||
|
||||
if (temp_cache($product)) {
|
||||
return temp_cache($product);
|
||||
}
|
||||
|
||||
cache()->put(
|
||||
key: 'productColor'.$this->id,
|
||||
value: $this->getPropertyValueBySlug('colour'),
|
||||
);
|
||||
|
||||
return temp_cache($product);
|
||||
}
|
||||
|
||||
/**
|
||||
* Size property
|
||||
*/
|
||||
public function getSize(): string
|
||||
{
|
||||
$product = 'productSize'.$this->id;
|
||||
|
||||
if (temp_cache($product)) {
|
||||
return temp_cache($product);
|
||||
}
|
||||
|
||||
cache()->put(
|
||||
'productSize'.$this->id,
|
||||
$this->getPropertyValueBySlug('size'),
|
||||
);
|
||||
|
||||
return temp_cache($product);
|
||||
}
|
||||
|
||||
/**
|
||||
* Color variants
|
||||
*/
|
||||
public function colorVariants(): array
|
||||
{
|
||||
if (temp_cache('productColorVariants')) {
|
||||
return temp_cache('productColorVariants');
|
||||
}
|
||||
|
||||
$this->loadMissing(['media', 'properties', 'variations' => ['media', 'properties']]);
|
||||
|
||||
$colorVariants = collect();
|
||||
|
||||
// Add parent product
|
||||
$colorVariants->push([
|
||||
'slug' => $this->slug,
|
||||
'id' => $this->id,
|
||||
'image' => $this->thumbnail(),
|
||||
'color' => $this->getColor(),
|
||||
]);
|
||||
|
||||
$this->variations->each(function ($variation) use ($colorVariants) {
|
||||
$colorVariants->push([
|
||||
'slug' => $variation->slug,
|
||||
'id' => $variation->id,
|
||||
'image' => $variation->thumbnail(),
|
||||
'color' => $variation->getColor(),
|
||||
]);
|
||||
});
|
||||
|
||||
cache()->put(
|
||||
'productColorVariants',
|
||||
$colorVariants->uniqueStrict('color')->toArray(),
|
||||
);
|
||||
|
||||
return $colorVariants->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a property with the given attribute slug exists
|
||||
*/
|
||||
protected function hasPropertyWithSlug(string $slug): bool
|
||||
{
|
||||
if ($this->relationLoaded('properties')) {
|
||||
return $this->checkLoadedPropertiesForSlug($slug);
|
||||
}
|
||||
|
||||
return $this->checkDatabaseForPropertySlug($slug);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check loaded properties for attribute slug
|
||||
*/
|
||||
protected function checkLoadedPropertiesForSlug(string $slug): bool
|
||||
{
|
||||
foreach ($this->properties as $property) {
|
||||
if ($property->attribute->slug === $slug) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check database for attribute slug
|
||||
*/
|
||||
protected function checkDatabaseForPropertySlug(string $slug): bool
|
||||
{
|
||||
return $this->properties()
|
||||
->where('attribute.slug', $slug)
|
||||
->exists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get property value by slug
|
||||
*/
|
||||
public function getPropertyValueBySlug(string $slug): string
|
||||
{
|
||||
return $this->properties->firstWhere('attribute.slug', 'colour')->values->first()->real_value ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size variants available for given color
|
||||
*/
|
||||
public function getSizeVariantsForColor(): array
|
||||
{
|
||||
if (temp_cache('productSizeVariantsForColor')) {
|
||||
return temp_cache('productSizeVariantsForColor');
|
||||
}
|
||||
|
||||
if ($this->parent_id) {
|
||||
return $this->childSizeVariantsForColor();
|
||||
}
|
||||
|
||||
$this->loadMissing(['properties', 'variations', 'variations.properties']);
|
||||
|
||||
$properties = $this->properties;
|
||||
$variations = $this->variations;
|
||||
|
||||
$productSize = [];
|
||||
$matchingProducts = [];
|
||||
|
||||
foreach ($properties as $property) {
|
||||
if ($property->attribute->slug === 'size') {
|
||||
$productSize = $property->values->first()->real_value;
|
||||
|
||||
$productSize = [
|
||||
'slug' => $this->slug,
|
||||
'id' => $this->id,
|
||||
'size' => $productSize,
|
||||
'parent_id' => null,
|
||||
];
|
||||
}
|
||||
|
||||
if ($property->attribute->slug === 'colour') {
|
||||
// Color found
|
||||
$productColor = $property->values->first()->real_value;
|
||||
|
||||
// Get All Sizes
|
||||
$variationAllSizes = [];
|
||||
|
||||
// Iterate over to find same colors in variants
|
||||
foreach ($variations as $variation) {
|
||||
foreach ($variation->properties as $variationProperty) {
|
||||
|
||||
if ($variationProperty->attribute->slug === 'size') {
|
||||
$productSize = $variationProperty->values->first()->real_value;
|
||||
|
||||
$variationAllSizes[] = [
|
||||
'slug' => $variation->slug,
|
||||
'id' => $variation->id,
|
||||
'parent_id' => $variation->parent_id,
|
||||
'size' => $productSize,
|
||||
];
|
||||
}
|
||||
|
||||
if ($variationProperty->attribute->slug === 'colour') {
|
||||
// If colors match, append to array
|
||||
$variationColor = $variationProperty->values->first()->real_value;
|
||||
|
||||
if ($productColor === $variationColor) {
|
||||
$matchingProducts[] = [
|
||||
'slug' => $variation->slug,
|
||||
'id' => $variation->id,
|
||||
'color' => $productColor,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} /* Color end */
|
||||
}
|
||||
|
||||
$result = collect();
|
||||
$result->push($productSize);
|
||||
|
||||
collect($variationAllSizes)->whereIn('id', collect($matchingProducts)->pluck('id'))
|
||||
->each(function ($variationSize) use ($result) {
|
||||
$result->push($variationSize);
|
||||
});
|
||||
|
||||
cache()->put(
|
||||
'productSizeVariantsForColor',
|
||||
$result->toArray(),
|
||||
);
|
||||
|
||||
return $result->toArray();
|
||||
}
|
||||
|
||||
public function childSizeVariantsForColor(): array
|
||||
{
|
||||
$this->loadMissing(['properties']);
|
||||
|
||||
$properties = $this->properties;
|
||||
$parent = $this->parent;
|
||||
$parent->load(['properties', 'variations', 'variations.properties']);
|
||||
$variations = $parent->variations;
|
||||
|
||||
$productSize = [];
|
||||
$matchingProducts = [];
|
||||
|
||||
foreach ($properties as $property) {
|
||||
if ($property->attribute->slug === 'size') {
|
||||
$productSize = $property->values->first()->real_value;
|
||||
|
||||
$productSize = [
|
||||
'slug' => $this->slug,
|
||||
'id' => $this->id,
|
||||
'size' => $productSize,
|
||||
'parent_id' => $this->parent_id,
|
||||
];
|
||||
}
|
||||
|
||||
if ($property->attribute->slug === 'colour') {
|
||||
// Color found
|
||||
$productColor = $property->values->first()->real_value;
|
||||
|
||||
// Get All Sizes
|
||||
$variationAllSizes = [];
|
||||
|
||||
// Iterate over to find same colors in variants
|
||||
foreach ($variations as $variation) {
|
||||
if ($variation->id === $this->id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($variation->properties as $variationProperty) {
|
||||
|
||||
if ($variationProperty->attribute->slug === 'size') {
|
||||
$productSize = $variationProperty->values->first()->real_value;
|
||||
|
||||
$variationAllSizes[] = [
|
||||
'slug' => $variation->slug,
|
||||
'id' => $variation->id,
|
||||
'parent_id' => $variation->parent_id,
|
||||
'size' => $productSize,
|
||||
];
|
||||
}
|
||||
|
||||
if ($variationProperty->attribute->slug === 'colour') {
|
||||
// If colors match, append to array
|
||||
$variationColor = $variationProperty->values->first()->real_value;
|
||||
|
||||
if ($productColor === $variationColor) {
|
||||
$matchingProducts[] = [
|
||||
'slug' => $variation->slug,
|
||||
'id' => $variation->id,
|
||||
'color' => $productColor,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
} /* Color end */
|
||||
}
|
||||
|
||||
$result = collect();
|
||||
$result->push($productSize);
|
||||
|
||||
collect($variationAllSizes)->whereIn('id', collect($matchingProducts)->pluck('id'))
|
||||
->each(function ($variationSize) use ($result) {
|
||||
$result->push($variationSize);
|
||||
});
|
||||
|
||||
return $result->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* All values of product properties
|
||||
*/
|
||||
public function allValuesOfProperties(): array
|
||||
{
|
||||
return $this->properties->flatMap(function ($property) {
|
||||
return $property->values->map(function ($value) {
|
||||
return $value->real_value;
|
||||
})->filter();
|
||||
})->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Name with properties
|
||||
*/
|
||||
public function nameWithProperties(): string
|
||||
{
|
||||
$properties = $this->allValuesOfProperties();
|
||||
|
||||
return sprintf(
|
||||
'%s %s %s',
|
||||
$this->name,
|
||||
count($properties) > 0 ? '-' : '',
|
||||
Blade::render('
|
||||
@foreach($datas as $data)
|
||||
<strong>{{ $data }}{{ $loop->last ? "" : "," }}</strong>
|
||||
@endforeach
|
||||
', ['datas' => $properties])
|
||||
);
|
||||
}
|
||||
|
||||
public function getSizeVariants(): array
|
||||
{
|
||||
$sizeVariants = [];
|
||||
|
||||
// Add parent product
|
||||
$sizeVariants[] = [
|
||||
'slug' => $this->slug,
|
||||
'id' => $this->id,
|
||||
'image' => $this->thumbnail(),
|
||||
'images_hd' => $this->getMedia('uploads')->map(fn ($media) => $media->getUrl('thumb720x720')),
|
||||
'size' => $this->getSizeValue(),
|
||||
];
|
||||
|
||||
$this->variations->each(function ($variation) use (&$sizeVariants) {
|
||||
$variationSize = $variation->getSizeValue();
|
||||
|
||||
if ($variationSize && ! keyValueExistsInArray(datas: $sizeVariants, key: 'size', value: $variationSize)) {
|
||||
$sizeVariants[] = [
|
||||
'slug' => $variation->slug,
|
||||
'id' => $variation->id,
|
||||
'image' => $variation->thumbnail(),
|
||||
'images_hd' => $variation->getMedia('uploads')->map(fn ($media) => $media->getUrl('thumb720x720')),
|
||||
'size' => $variationSize,
|
||||
];
|
||||
}
|
||||
});
|
||||
|
||||
return $sizeVariants;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
use App\Models\Common\Comment;
|
||||
use App\Models\Ecommerce\Channel\Channel;
|
||||
use App\Models\Ecommerce\Product\Brand\Brand;
|
||||
use App\Models\Ecommerce\Product\Cart\Cart;
|
||||
use App\Models\Ecommerce\Product\Category\Category;
|
||||
use App\Models\Ecommerce\Product\Collection\Collection;
|
||||
use App\Models\Ecommerce\Product\Inventory\Inventory;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Models\Ecommerce\Product\Property\ProductProperty;
|
||||
use App\Models\Ecommerce\Product\Review\Review;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphToMany;
|
||||
|
||||
trait ProductRelationships
|
||||
{
|
||||
/**
|
||||
* Product variations
|
||||
*/
|
||||
public function variations(): HasMany
|
||||
{
|
||||
return $this->hasMany(Product::class, 'parent_id');
|
||||
}
|
||||
|
||||
/**
|
||||
+ * Parent
|
||||
+ */
|
||||
public function parent(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class, 'parent_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Related Channels
|
||||
*/
|
||||
public function channels(): MorphToMany
|
||||
{
|
||||
return $this->morphedByMany(Channel::class, 'productable', 'product_has_relations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Firt channel
|
||||
*/
|
||||
public function owner(): ?Channel
|
||||
{
|
||||
return $this->relationLoaded('channels')
|
||||
? $this->channels->first()
|
||||
: $this->channels()->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* Related products (similar)
|
||||
*/
|
||||
public function relatedProducts(): MorphToMany
|
||||
{
|
||||
return $this->morphedByMany(Product::class, 'productable', 'product_has_relations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Related categories
|
||||
*/
|
||||
public function categories(): MorphToMany
|
||||
{
|
||||
return $this->morphedByMany(Category::class, 'productable', 'product_has_relations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Related Collections
|
||||
*/
|
||||
public function collections(): MorphToMany
|
||||
{
|
||||
return $this->morphedByMany(Collection::class, 'productable', 'product_has_relations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Related Brand
|
||||
*/
|
||||
public function brand(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Brand::class, 'brand_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Product Properties, same as attribtues
|
||||
*
|
||||
* (size, color, material, ..)
|
||||
*/
|
||||
public function properties(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProductProperty::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Related inventories
|
||||
*/
|
||||
public function inventories(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Inventory::class)
|
||||
->withPivot('stock');
|
||||
}
|
||||
|
||||
/**
|
||||
* Carts
|
||||
*/
|
||||
public function carts(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Cart::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Product's review
|
||||
*/
|
||||
public function reviews(): HasMany
|
||||
{
|
||||
return $this->hasMany(Review::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Product's comments
|
||||
*/
|
||||
public function comments(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Comment::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
trait ProductScopeQueries
|
||||
{
|
||||
/**
|
||||
* Visable products scope
|
||||
*
|
||||
* @param mixed $query
|
||||
*/
|
||||
public function scopeVisable($query): void
|
||||
{
|
||||
$query->where('is_visible', true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
trait ProductStates
|
||||
{
|
||||
/**
|
||||
* Check if product is new (one week range)
|
||||
*/
|
||||
public function isNew(): bool
|
||||
{
|
||||
return $this->created_at->greaterThan(now()->subWeek());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
|
||||
trait ProductStock
|
||||
{
|
||||
/**
|
||||
* Inventory history
|
||||
*/
|
||||
public function inventoryHistories(): MorphMany
|
||||
{
|
||||
return $this->morphMany(InventoryHistory::class, 'stockable')->orderBy('created_at', 'desc');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Spatie\Sluggable\SlugOptions;
|
||||
|
||||
trait ProductTransformers
|
||||
{
|
||||
/**
|
||||
* Get the options for generating the slug.
|
||||
*/
|
||||
public function getSlugOptions(): SlugOptions
|
||||
{
|
||||
return SlugOptions::create()
|
||||
->generateSlugsFrom('name')
|
||||
->saveSlugsTo('slug');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get discount difference
|
||||
*
|
||||
* @return int|float
|
||||
*/
|
||||
public function discountDifference(): Attribute
|
||||
{
|
||||
return Attribute::make(get: fn () => $this->caluculateDiscountDifference());
|
||||
}
|
||||
|
||||
/**
|
||||
* Discount percentage
|
||||
*/
|
||||
public function discountPercentage()
|
||||
{
|
||||
return number_format(($this->caluculateDiscountDifference() * 100) / $this->old_price_amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Caluculate Discount Difference
|
||||
*/
|
||||
public function caluculateDiscountDifference(int|float|null $price_amount = null): float
|
||||
{
|
||||
return $this->old_price_amount ? $this->old_price_amount - ($price_amount ?: $this->price_amount) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Full name
|
||||
*/
|
||||
public function fullName(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: function () {
|
||||
$brand = $this->brand ? "({$this->brand->name})" : '';
|
||||
|
||||
return $this->name.$brand.$this->colour.$this->size;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool backorder
|
||||
*/
|
||||
public function backOrder(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('back_order')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string weight_value
|
||||
*/
|
||||
public function weightValue(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('weight_value')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string weight_unit
|
||||
*/
|
||||
public function weightUnit(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('weight_unit')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string height_value
|
||||
*/
|
||||
public function heightValue(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('height_value')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string height_unit
|
||||
*/
|
||||
public function heightUnit(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('height_unit')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string width_value
|
||||
*/
|
||||
public function widthValue(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('width_value')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string width_unit
|
||||
*/
|
||||
public function widthUnit(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('width_unit')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string depth_value
|
||||
*/
|
||||
public function depthValue(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('depth_value')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string depth_unit
|
||||
*/
|
||||
public function depthUnit(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('depth_unit')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string volume_value
|
||||
*/
|
||||
public function volumeValue(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('volume_value')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string volume_unit
|
||||
*/
|
||||
public function volumeUnit(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('volume_unit')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flexible Content
|
||||
*/
|
||||
// public function flexibleContent(): Attribute
|
||||
// {
|
||||
// return Attribute::make(
|
||||
// get: fn () => $this->flexible('flexible-content')
|
||||
// );
|
||||
// }
|
||||
}
|
||||
121
app/Models/Ecommerce/Product/Product/Product.php
Normal file
121
app/Models/Ecommerce/Product/Product/Product.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Product;
|
||||
|
||||
use App\Models\Concerns\HasSchemalessAttributes;
|
||||
use App\Models\Ecommerce\Product\Product\Concerns\ProductFrontEndHelpers;
|
||||
use App\Models\Ecommerce\Product\Product\Concerns\ProductMedia;
|
||||
use App\Models\Ecommerce\Product\Product\Concerns\ProductProperties;
|
||||
use App\Models\Ecommerce\Product\Product\Concerns\ProductRelationships;
|
||||
use App\Models\Ecommerce\Product\Product\Concerns\ProductScopeQueries;
|
||||
use App\Models\Ecommerce\Product\Product\Concerns\ProductStates;
|
||||
use App\Models\Ecommerce\Product\Product\Concerns\ProductStock;
|
||||
use App\Models\Ecommerce\Product\Product\Concerns\ProductTransformers;
|
||||
use CyrildeWit\EloquentViewable\Contracts\Viewable;
|
||||
use CyrildeWit\EloquentViewable\InteractsWithViews;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
use Spatie\Sluggable\HasSlug;
|
||||
|
||||
class Product extends Model implements HasMedia, Viewable
|
||||
{
|
||||
/**
|
||||
* Has factory (laravel default)
|
||||
*/
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* Has Schemaless Attributes (spatie/laravel-schemaless-attributes)
|
||||
*/
|
||||
use HasSchemalessAttributes;
|
||||
|
||||
/**
|
||||
* Has Slug (spatie/laravel-sluggable)
|
||||
*/
|
||||
use HasSlug;
|
||||
|
||||
/**
|
||||
* Interacts with media (spatie/laravel-medialibrary)
|
||||
*/
|
||||
use InteractsWithMedia;
|
||||
|
||||
/**
|
||||
* Interacts with views (cyrildewit/eloquent-viewable)
|
||||
*/
|
||||
use InteractsWithViews;
|
||||
|
||||
/**
|
||||
* Product helpers for front end
|
||||
*/
|
||||
use ProductFrontEndHelpers;
|
||||
|
||||
/**
|
||||
* Media interactions
|
||||
*/
|
||||
use ProductMedia {
|
||||
ProductMedia::registerMediaCollections insteadof InteractsWithMedia;
|
||||
ProductMedia::registerMediaConversions insteadof InteractsWithMedia;
|
||||
}
|
||||
|
||||
/**
|
||||
* Product properties (attributes[EAV])
|
||||
*/
|
||||
use ProductProperties;
|
||||
|
||||
/**
|
||||
* Product relationships
|
||||
*/
|
||||
use ProductRelationships;
|
||||
|
||||
/**
|
||||
* Product scope queries
|
||||
*/
|
||||
use ProductScopeQueries;
|
||||
|
||||
/**
|
||||
* Product states (new, featured, ...)
|
||||
*/
|
||||
use ProductStates;
|
||||
|
||||
/**
|
||||
* Products stocks
|
||||
*/
|
||||
use ProductStock;
|
||||
|
||||
/**
|
||||
* Interacts with media (whitecube/nova-flexible-content)
|
||||
*/
|
||||
// use HasFlexible;
|
||||
|
||||
/**
|
||||
* Product Data Transformers
|
||||
*/
|
||||
use ProductTransformers;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'id',
|
||||
'parent_id',
|
||||
'brand_id',
|
||||
'name',
|
||||
'slug',
|
||||
'description',
|
||||
'sku',
|
||||
'barcode',
|
||||
'stock',
|
||||
'security_stock',
|
||||
'cost_amount',
|
||||
'price_amount',
|
||||
'old_price_amount',
|
||||
'seo_title',
|
||||
'seo_description',
|
||||
'options',
|
||||
'is_visible',
|
||||
'colour',
|
||||
'size',
|
||||
];
|
||||
}
|
||||
103
app/Models/Ecommerce/Product/Property/Attribute.php
Normal file
103
app/Models/Ecommerce/Product/Property/Attribute.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Property;
|
||||
|
||||
use App\Models\Ecommerce\Product\Category\Category;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Spatie\EloquentSortable\Sortable;
|
||||
use Spatie\EloquentSortable\SortableTrait;
|
||||
use Spatie\Sluggable\HasSlug;
|
||||
use Spatie\Sluggable\SlugOptions;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class Attribute extends Model implements Sortable
|
||||
{
|
||||
use HasFactory;
|
||||
use HasSlug;
|
||||
use HasTranslations;
|
||||
use SortableTrait;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'slug',
|
||||
'description',
|
||||
'type',
|
||||
'is_visible',
|
||||
'is_required',
|
||||
'is_searchable',
|
||||
'is_filterable',
|
||||
'sort_order',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = ['name', 'description'];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $sortable = [
|
||||
'order_column_name' => 'sort_order',
|
||||
'sort_when_creating' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the options for generating the slug.
|
||||
*/
|
||||
public function getSlugOptions(): SlugOptions
|
||||
{
|
||||
return SlugOptions::create()
|
||||
->generateSlugsFrom('name')
|
||||
->saveSlugsTo('slug');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute values (color: red, black, ...)
|
||||
*/
|
||||
public function values(): HasMany
|
||||
{
|
||||
return $this->hasMany(AttributeValue::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute Category
|
||||
*/
|
||||
public function category(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Category::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attributes categories as belongs-to-many
|
||||
*/
|
||||
public function categories(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Category::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return available fields types.
|
||||
*
|
||||
* @return array<string, string>
|
||||
*/
|
||||
public static function typesFields(): array
|
||||
{
|
||||
return [
|
||||
'text' => __('Text'),
|
||||
'number' => __('Number'),
|
||||
'select' => __('Select option'),
|
||||
];
|
||||
}
|
||||
}
|
||||
65
app/Models/Ecommerce/Product/Property/AttributeValue.php
Normal file
65
app/Models/Ecommerce/Product/Property/AttributeValue.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Property;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Spatie\EloquentSortable\Sortable;
|
||||
use Spatie\EloquentSortable\SortableTrait;
|
||||
use Spatie\Sluggable\HasSlug;
|
||||
use Spatie\Sluggable\SlugOptions;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class AttributeValue extends Model implements Sortable
|
||||
{
|
||||
use HasFactory;
|
||||
use HasSlug;
|
||||
use HasTranslations;
|
||||
use SortableTrait;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'value',
|
||||
'key',
|
||||
'attribute_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = ['value'];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string, mixed>
|
||||
*/
|
||||
public $sortable = [
|
||||
'order_column_name' => 'sort_order',
|
||||
'sort_when_creating' => true,
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the options for generating the slug.
|
||||
*/
|
||||
public function getSlugOptions(): SlugOptions
|
||||
{
|
||||
return SlugOptions::create()
|
||||
->generateSlugsFrom('name')
|
||||
->usingSeparator('_')
|
||||
->saveSlugsTo('key');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute
|
||||
*/
|
||||
public function attribute(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Attribute::class, 'attribute_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Property;
|
||||
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class ProductAttributeValue extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* Table name
|
||||
*/
|
||||
protected $table = 'attribute_value_product_attribute';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'product_attribute_id',
|
||||
'attribute_value_id',
|
||||
'product_custom_value',
|
||||
];
|
||||
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*/
|
||||
protected $with = ['value'];
|
||||
|
||||
/**
|
||||
* The accessors to append to the model's array form.
|
||||
*/
|
||||
protected $appends = ['real_value'];
|
||||
|
||||
/**
|
||||
* Return exact product attribute value.
|
||||
*
|
||||
* @return string|int
|
||||
*/
|
||||
public function realValue(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->product_custom_value ?: ($this->value?->value ?? '')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute Value for forms
|
||||
*/
|
||||
public function valueForForms(): null|int|string
|
||||
{
|
||||
return $this->product_custom_value ?: $this->attribute_value_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Value
|
||||
*/
|
||||
public function value(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(AttributeValue::class, 'attribute_value_id');
|
||||
}
|
||||
}
|
||||
65
app/Models/Ecommerce/Product/Property/ProductProperty.php
Normal file
65
app/Models/Ecommerce/Product/Property/ProductProperty.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Property;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
|
||||
class ProductProperty extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'product_attributes';
|
||||
|
||||
/**
|
||||
* Indicates if the model should be timestamped.
|
||||
*/
|
||||
public $timestamps = false;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'product_id',
|
||||
'attribute_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*/
|
||||
protected $with = [
|
||||
'attribute',
|
||||
'values',
|
||||
];
|
||||
|
||||
/**
|
||||
* Attribute
|
||||
*/
|
||||
public function attribute(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Attribute::class, 'attribute_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Product
|
||||
*/
|
||||
public function product(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class, 'product_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Property values
|
||||
*/
|
||||
public function values(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProductAttributeValue::class, 'product_attribute_id');
|
||||
}
|
||||
}
|
||||
44
app/Models/Ecommerce/Product/Review/Review.php
Normal file
44
app/Models/Ecommerce/Product/Review/Review.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Ecommerce\Product\Review;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class Review extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'product_id',
|
||||
'rating',
|
||||
'title',
|
||||
'content',
|
||||
'is_visible',
|
||||
'is_recommended',
|
||||
'source',
|
||||
];
|
||||
|
||||
/**
|
||||
* Author
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Product
|
||||
*/
|
||||
public function product(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Product::class);
|
||||
}
|
||||
}
|
||||
51
app/Models/Legal/LegalPage.php
Normal file
51
app/Models/Legal/LegalPage.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Legal;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class LegalPage extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*/
|
||||
protected $table = 'legal_pages';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'slug',
|
||||
'title',
|
||||
'content',
|
||||
'is_active',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = ['title', 'content'];
|
||||
|
||||
/**
|
||||
* Retrieve the model for a bound value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|null $field
|
||||
* @return \Illuminate\Database\Eloquent\Model|null
|
||||
*/
|
||||
public function resolveRouteBinding($value, $field = null)
|
||||
{
|
||||
return $this->where('slug', $value)
|
||||
->where('is_active', true)
|
||||
->firstOrFail();
|
||||
}
|
||||
}
|
||||
74
app/Models/Legal/User/EntrepreneurDocs.php
Normal file
74
app/Models/Legal/User/EntrepreneurDocs.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Legal\User;
|
||||
|
||||
use App\Models\Concerns\HasSchemalessAttributes;
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class EntrepreneurDocs extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasSchemalessAttributes;
|
||||
use HasTranslations;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*/
|
||||
protected $table = 'entrepreneur_docs';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'corporation_type',
|
||||
'corporation_name',
|
||||
'options',
|
||||
'user_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = ['corporation_name'];
|
||||
|
||||
/**
|
||||
* User, Document owner, Entrepreneur
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted corporation type
|
||||
*/
|
||||
protected function formattedCorporationType(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => match ($this->corporation_type) {
|
||||
'hk' => __('Private enterprise'),
|
||||
'hj' => __('Partnership enterprise'),
|
||||
default => __('Entrepreneur')
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Corporatoin name full name: "Web ulgam" HJ
|
||||
*/
|
||||
protected function formattedCorporationName(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->corporation_name.' '.$this->formatted_corporation_type
|
||||
);
|
||||
}
|
||||
}
|
||||
64
app/Models/Post/PostBranch.php
Normal file
64
app/Models/Post/PostBranch.php
Normal file
@@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Post;
|
||||
|
||||
use App\Models\System\Settings\Location\Province;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class PostBranch extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
|
||||
/**
|
||||
* Table name
|
||||
*/
|
||||
protected $table = 'post_branches';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'province_id',
|
||||
'name',
|
||||
'address',
|
||||
'description',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = [
|
||||
'name',
|
||||
'address',
|
||||
'description',
|
||||
];
|
||||
|
||||
/**
|
||||
* Related Province
|
||||
*/
|
||||
public function province(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Province::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope to filter
|
||||
*
|
||||
* @param Builder $query
|
||||
* @param string $value
|
||||
* @return Builder $query
|
||||
*/
|
||||
public function scopeByRegion($query, $value): Builder
|
||||
{
|
||||
return $value
|
||||
? $query->whereIn('province_id', fn ($builder) => $builder->select('id')->from('provinces')->where('region', $value))
|
||||
: $query;
|
||||
}
|
||||
}
|
||||
134
app/Models/Post/User/UserDoc.php
Normal file
134
app/Models/Post/User/UserDoc.php
Normal file
@@ -0,0 +1,134 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\Post\User;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Spatie\Image\Manipulations;
|
||||
use Spatie\MediaLibrary\HasMedia;
|
||||
use Spatie\MediaLibrary\InteractsWithMedia;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
|
||||
class UserDoc extends Model implements HasMedia
|
||||
{
|
||||
use HasFactory;
|
||||
use InteractsWithMedia;
|
||||
|
||||
/**
|
||||
* Attributes that are guarded
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $guarded = [];
|
||||
|
||||
/**
|
||||
* Table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'user_docs';
|
||||
|
||||
/**
|
||||
* The relations to eager load on every query.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = [
|
||||
'media',
|
||||
];
|
||||
|
||||
/**
|
||||
* Media collections
|
||||
*/
|
||||
public function registerMediaCollections(): void
|
||||
{
|
||||
$this->addMediaCollection('main');
|
||||
}
|
||||
|
||||
/**
|
||||
* Media conversations
|
||||
*/
|
||||
public function registerMediaConversions(?Media $media = null): void
|
||||
{
|
||||
$this->addMediaConversion('thumb150x150')
|
||||
->fit(Manipulations::FIT_CONTAIN, 150, 150);
|
||||
}
|
||||
|
||||
/**
|
||||
* User
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Entrepreneurship types
|
||||
*
|
||||
* ENTREPRENEUR
|
||||
*/
|
||||
public const ENTREPRENEUR = 'tel';
|
||||
|
||||
/**
|
||||
* PRIVATE ENTERPRISE
|
||||
*/
|
||||
public const PRIVATE_ENTERPRISE = 'hk';
|
||||
|
||||
/**
|
||||
* PARTNERSHIP ENTERPRISE
|
||||
*/
|
||||
public const PARTNERSHIP_ENTERPRISE = 'hj';
|
||||
|
||||
/**
|
||||
* Government
|
||||
*/
|
||||
public const GOVERNMENT = 'gov';
|
||||
|
||||
/**
|
||||
* Closed joint stock
|
||||
*/
|
||||
public const CLOSED_JOINT_STOCK = 'closed_joint_stock';
|
||||
|
||||
/**
|
||||
* Open joint stock
|
||||
*/
|
||||
public const OPEN_JOINT_STOCK = 'open_joint_stock';
|
||||
|
||||
/**
|
||||
* Corparation types
|
||||
*/
|
||||
public static function corparationTypes(): array
|
||||
{
|
||||
return [
|
||||
self::ENTREPRENEUR => __('Entrepreneur'),
|
||||
self::PRIVATE_ENTERPRISE => __('Private enterprise'),
|
||||
self::PARTNERSHIP_ENTERPRISE => __('Partnership enterprise'),
|
||||
self::GOVERNMENT => __('Government company'),
|
||||
self::CLOSED_JOINT_STOCK => __('Closed joint stock company'),
|
||||
self::OPEN_JOINT_STOCK => __('Open joint-stock company'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted corparation type
|
||||
*/
|
||||
public function formattedCorparationType(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => self::corparationTypes()[$this->corporation_type] ?? ''
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formatted corparation name
|
||||
*/
|
||||
public function formattedCorparationName(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->formattedCorparationType.' '.$this->corporation_name
|
||||
);
|
||||
}
|
||||
}
|
||||
7
app/Models/System/Roles/Permission.php
Normal file
7
app/Models/System/Roles/Permission.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\System\Roles;
|
||||
|
||||
use Spatie\Permission\Models\Permission as SpatiePermission;
|
||||
|
||||
class Permission extends SpatiePermission {}
|
||||
7
app/Models/System/Roles/Role.php
Normal file
7
app/Models/System/Roles/Role.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\System\Roles;
|
||||
|
||||
use Spatie\Permission\Models\Role as SpatieRole;
|
||||
|
||||
class Role extends SpatieRole {}
|
||||
28
app/Models/System/Settings/Currency.php
Normal file
28
app/Models/System/Settings/Currency.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\System\Settings;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Currency extends Model
|
||||
{
|
||||
/**
|
||||
* Default currency
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public const DEFAULT = 'TMT';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'code',
|
||||
'symbol',
|
||||
'format',
|
||||
'exchange_rate',
|
||||
];
|
||||
}
|
||||
40
app/Models/System/Settings/Location/Province.php
Normal file
40
app/Models/System/Settings/Location/Province.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\System\Settings\Location;
|
||||
|
||||
use App\Models\Post\PostBranch;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class Province extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'region',
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = ['name'];
|
||||
|
||||
/**
|
||||
* Post branches
|
||||
*/
|
||||
public function postBranches(): HasMany
|
||||
{
|
||||
return $this->hasMany(PostBranch::class);
|
||||
}
|
||||
}
|
||||
73
app/Models/System/Settings/Location/Region.php
Normal file
73
app/Models/System/Settings/Location/Region.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\System\Settings\Location;
|
||||
|
||||
class Region
|
||||
{
|
||||
/**
|
||||
* Mary
|
||||
*/
|
||||
public const MR = 'mr';
|
||||
|
||||
/**
|
||||
* Aşgabat
|
||||
*/
|
||||
public const AG = 'ag';
|
||||
|
||||
/**
|
||||
* Arkadag
|
||||
*/
|
||||
public const AK = 'ak';
|
||||
|
||||
/**
|
||||
* Ahal
|
||||
*/
|
||||
public const AH = 'ah';
|
||||
|
||||
/**
|
||||
* Lebap
|
||||
*/
|
||||
public const LB = 'lb';
|
||||
|
||||
/**
|
||||
* Balkan
|
||||
*/
|
||||
public const BN = 'bn';
|
||||
|
||||
/**
|
||||
* Daşoguz
|
||||
*/
|
||||
public const DZ = 'dz';
|
||||
|
||||
/**
|
||||
* Regions
|
||||
*/
|
||||
public static function values(): array
|
||||
{
|
||||
return [
|
||||
self::AG => __('Ashgabat'),
|
||||
self::AK => __('Arkadag'),
|
||||
self::MR => __('Mary'),
|
||||
self::AH => __('Ahal'),
|
||||
self::LB => __('Lebap'),
|
||||
self::BN => __('Balkan'),
|
||||
self::DZ => __('Dashoguz'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Default value
|
||||
*/
|
||||
public static function default(): string
|
||||
{
|
||||
return self::AG;
|
||||
}
|
||||
|
||||
/**
|
||||
* Label for given region
|
||||
*/
|
||||
public static function labelFor(string $region): string
|
||||
{
|
||||
return static::values()[$region] ?? '';
|
||||
}
|
||||
}
|
||||
73
app/Models/System/Settings/Location/UserAddress.php
Normal file
73
app/Models/System/Settings/Location/UserAddress.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\System\Settings\Location;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
|
||||
class UserAddress extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'last_name',
|
||||
'first_name',
|
||||
'company_name',
|
||||
'street_address',
|
||||
'street_address_plus',
|
||||
'zipcode',
|
||||
'city',
|
||||
'phone_number',
|
||||
'is_default',
|
||||
'type',
|
||||
'user_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* The dynamic attributes from mutators that should be returned with the user object.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = [
|
||||
'full_name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Define if an address is default or not.
|
||||
*/
|
||||
public function isDefault(): bool
|
||||
{
|
||||
return $this->is_default === true;
|
||||
}
|
||||
|
||||
/**
|
||||
* User
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'user_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap the model and its traits.
|
||||
*/
|
||||
protected static function boot()
|
||||
{
|
||||
parent::boot();
|
||||
|
||||
static::creating(function ($address) {
|
||||
if ($address->is_default) {
|
||||
$address->user->addresses()->where('type', $address->type)->update([
|
||||
'is_default' => false,
|
||||
]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
85
app/Models/System/Settings/OS.php
Normal file
85
app/Models/System/Settings/OS.php
Normal file
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\System\Settings;
|
||||
|
||||
class OS
|
||||
{
|
||||
/**
|
||||
* MacOS
|
||||
*/
|
||||
public const MACOS = 'macos';
|
||||
|
||||
/**
|
||||
* Linux
|
||||
*/
|
||||
public const LINUX = 'linux';
|
||||
|
||||
/**
|
||||
* Windows
|
||||
*/
|
||||
public const WINDOWS = 'windows';
|
||||
|
||||
/**
|
||||
* IOS
|
||||
*/
|
||||
public const IOS = 'ios';
|
||||
|
||||
/**
|
||||
* Android
|
||||
*/
|
||||
public const ANDROID = 'android';
|
||||
|
||||
/**
|
||||
* Operationg systems
|
||||
*/
|
||||
public static function types(): array
|
||||
{
|
||||
return [
|
||||
self::IOS => 'IOS',
|
||||
self::ANDROID => 'Android',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Website - shop.post.tm
|
||||
*/
|
||||
public const WEBSITE = 'site';
|
||||
|
||||
/**
|
||||
* Admin panel - admin shop.post.tm
|
||||
*/
|
||||
public const ADMIN = 'admin';
|
||||
|
||||
/**
|
||||
* Ecommerce app - postshop
|
||||
*/
|
||||
public const MOBILE_APP = 'mobile_app';
|
||||
|
||||
/**
|
||||
* Seller app - postshop satyjy
|
||||
*/
|
||||
public const MOBILE_ADMIN = 'mobile_admin';
|
||||
|
||||
/**
|
||||
* Our Apps
|
||||
*/
|
||||
public static function apps(): array
|
||||
{
|
||||
return [
|
||||
self::WEBSITE => __('Website'),
|
||||
self::ADMIN => __('Admin Panel'),
|
||||
self::MOBILE_APP => __('Mobile app'),
|
||||
self::MOBILE_ADMIN => __('Mobile admin'),
|
||||
self::ANDROID => __('Android'),
|
||||
self::IOS => __('IOS'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Default value
|
||||
*/
|
||||
public static function default(): string
|
||||
{
|
||||
return self::WEBSITE;
|
||||
}
|
||||
}
|
||||
83
app/Models/System/Settings/Payments/PaymentType.php
Normal file
83
app/Models/System/Settings/Payments/PaymentType.php
Normal file
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\System\Settings\Payments;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Spatie\Sluggable\HasSlug;
|
||||
use Spatie\Sluggable\SlugOptions;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class PaymentType extends Model
|
||||
{
|
||||
use HasSlug;
|
||||
use HasTranslations;
|
||||
|
||||
/**
|
||||
* Table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'payment_types';
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
public $translatable = [
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'code',
|
||||
'name',
|
||||
'tax',
|
||||
'is_enabled',
|
||||
'options',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the options for generating the slug.
|
||||
*/
|
||||
public function getSlugOptions(): SlugOptions
|
||||
{
|
||||
return SlugOptions::create()
|
||||
->generateSlugsFrom('name')
|
||||
->saveSlugsTo('code');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create base payments
|
||||
*/
|
||||
public static function createBaseRecords(): void
|
||||
{
|
||||
collect([
|
||||
[
|
||||
'code' => 'cash',
|
||||
'name' => ['en' => 'Cash', 'tk' => 'Nagt', 'ru' => 'Näliçni'],
|
||||
'tax' => 0,
|
||||
'is_enabled' => true,
|
||||
'options' => null,
|
||||
],
|
||||
[
|
||||
'code' => 'atm',
|
||||
'name' => ['en' => 'ATM', 'tk' => 'Terminal', 'ru' => 'ATM'],
|
||||
'tax' => 0,
|
||||
'is_enabled' => true,
|
||||
'options' => null,
|
||||
],
|
||||
[
|
||||
'code' => 'online_halkbank',
|
||||
'name' => ['en' => 'Online (halkbank)', 'tk' => 'Onlaýn (halkbank)', 'ru' => 'Onlaýn (halkbank)'],
|
||||
'tax' => 0,
|
||||
'is_enabled' => true,
|
||||
'options' => null,
|
||||
],
|
||||
])->each(fn ($data) => static::create($data));
|
||||
}
|
||||
}
|
||||
40
app/Models/System/Settings/Settings.php
Normal file
40
app/Models/System/Settings/Settings.php
Normal file
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\System\Settings;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Spatie\Translatable\HasTranslations;
|
||||
|
||||
class Settings extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
use HasTranslations;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'key',
|
||||
'value',
|
||||
'display_name',
|
||||
'locked',
|
||||
];
|
||||
|
||||
/**
|
||||
* Translatable fields
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public $translatable = ['display_name'];
|
||||
|
||||
/**
|
||||
* Sms token
|
||||
*/
|
||||
public static function smsToken(): string
|
||||
{
|
||||
return config('sms.api.token');
|
||||
}
|
||||
}
|
||||
44
app/Models/System/VersionManagement/AppVersion.php
Normal file
44
app/Models/System/VersionManagement/AppVersion.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\System\VersionManagement;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property string $version
|
||||
* @property string $os
|
||||
* @property bool $important
|
||||
* @property string $notes
|
||||
* @property \Carbon\Carbon|null $created_at
|
||||
* @property \Carbon\Carbon|null $updated_at
|
||||
*/
|
||||
class AppVersion extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'app_versions';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* version - string
|
||||
* os - string | in: ios, android
|
||||
* important - bool
|
||||
* notes - ?string
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'version',
|
||||
'os',
|
||||
'important',
|
||||
'notes',
|
||||
];
|
||||
}
|
||||
23
app/Models/System/Warning.php
Normal file
23
app/Models/System/Warning.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models\System;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Warning extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'content',
|
||||
'where',
|
||||
'notes',
|
||||
'resolved_at',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'resolved_at' => 'datetime',
|
||||
];
|
||||
}
|
||||
203
app/Models/User.php
Normal file
203
app/Models/User.php
Normal file
@@ -0,0 +1,203 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Models\Concerns\HasEcommerceChannels;
|
||||
use App\Models\Concerns\HasSchemalessAttributes;
|
||||
use App\Models\Concerns\InteractsWithNova;
|
||||
use App\Models\Concerns\InteractsWithRoles;
|
||||
use App\Models\Ecommerce\Product\Cart\CartItem;
|
||||
use App\Models\Ecommerce\Product\Favorite\Favorite;
|
||||
use App\Models\Ecommerce\Product\Order\Order;
|
||||
use App\Models\Ecommerce\Product\Review\Review;
|
||||
use App\Models\Post\User\UserDoc;
|
||||
use App\Models\System\Settings\Location\UserAddress;
|
||||
use App\Repositories\System\Cache\CacheRepository;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use Spatie\DeletedModels\Models\Concerns\KeepsDeletedModels;
|
||||
use Spatie\Permission\Traits\HasRoles;
|
||||
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use HasApiTokens;
|
||||
use HasEcommerceChannels;
|
||||
use HasFactory;
|
||||
use HasRoles;
|
||||
use HasSchemalessAttributes;
|
||||
use InteractsWithNova;
|
||||
use InteractsWithRoles;
|
||||
use KeepsDeletedModels;
|
||||
use Notifiable;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'phone_number',
|
||||
'verified',
|
||||
'password',
|
||||
'options',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be hidden for serialization.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
protected $hidden = [
|
||||
'password',
|
||||
'remember_token',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'email_verified_at' => 'datetime',
|
||||
'password' => 'hashed',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get fullname of user
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function fullname(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => sprintf('%s %s', $this->first_name, $this->last_name)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get users locale
|
||||
*/
|
||||
public function locale(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->options->get('locale'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all role names
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function roleNames(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
get: fn () => $this->getRoleNames()->implode(', ')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Addresses
|
||||
*/
|
||||
public function addresses(): HasMany
|
||||
{
|
||||
return $this->hasMany(UserAddress::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* User's carts
|
||||
*/
|
||||
public function carts(): HasMany
|
||||
{
|
||||
return $this->hasMany(CartItem::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* User's favorite products
|
||||
*/
|
||||
public function favorites(): HasMany
|
||||
{
|
||||
return $this->hasMany(Favorite::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* User's favorite products
|
||||
*/
|
||||
public function reviews(): HasMany
|
||||
{
|
||||
return $this->hasMany(Review::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Orders
|
||||
*/
|
||||
public function orders(): HasMany
|
||||
{
|
||||
return $this->hasMany(Order::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Documents
|
||||
*/
|
||||
public function documents(): HasOne
|
||||
{
|
||||
return $this->hasOne(UserDoc::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Company name
|
||||
*/
|
||||
public function companyName(): ?string
|
||||
{
|
||||
$this->loadMissing('documents');
|
||||
|
||||
return $this->documents?->formattedCorparationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* User owns product
|
||||
*/
|
||||
public function ownsProduct($product): bool
|
||||
{
|
||||
return true;
|
||||
// return CacheRepository::make();
|
||||
}
|
||||
|
||||
/**
|
||||
* Owns inventory
|
||||
*/
|
||||
public function ownsInventory($inventory): bool
|
||||
{
|
||||
return $this->channel()->id === $inventory->channel_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user does not own any inventories
|
||||
*/
|
||||
public function doesntOwnInventory(): bool
|
||||
{
|
||||
return $this->inventoryCount() === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inventory count
|
||||
*/
|
||||
public function inventoryCount(): int
|
||||
{
|
||||
$inventoryCount = cache()->store('array')->get('user_inventory_count');
|
||||
|
||||
if (! $inventoryCount) {
|
||||
cache()->store('array')->put('user_inventory_count', $this->channel()->inventories()->count());
|
||||
}
|
||||
|
||||
return cache()->store('array')->get('user_inventory_count');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user