wip
This commit is contained in:
68
app/Nova/Actions/Ecommerce/Product/ProductImportAction.php
Normal file
68
app/Nova/Actions/Ecommerce/Product/ProductImportAction.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Actions\Ecommerce\Product;
|
||||
|
||||
use App\Imports\Ecommerce\Product\ProductImport;
|
||||
use App\Repositories\Ecommerce\Channel\ChannelRepository;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Collection;
|
||||
use Laravel\Nova\Actions\Action;
|
||||
use Laravel\Nova\Fields\ActionFields;
|
||||
use Laravel\Nova\Fields\File;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
|
||||
class ProductImportAction extends Action
|
||||
{
|
||||
use InteractsWithQueue, Queueable;
|
||||
|
||||
/**
|
||||
* The displayable name of the action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $name = 'Import product';
|
||||
|
||||
/**
|
||||
* Perform the action on the given models.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(ActionFields $fields, Collection $models)
|
||||
{
|
||||
$file = $fields->files->store(sprintf('public/product-exports/user/%s/%s/', auth()->user()->id, now()->format('H_i_d_m_Y')));
|
||||
|
||||
Excel::import(new ProductImport($fields->channel_id), $file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields available on the action.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
Select::make(__('Channel'), 'channel_id')
|
||||
->fullWidth()
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(function () {
|
||||
if (auth()->user()->isAdmin()) {
|
||||
return ChannelRepository::values();
|
||||
}
|
||||
|
||||
$channel = auth()->user()->channel();
|
||||
|
||||
return [$channel->id => $channel->name];
|
||||
})
|
||||
->rules('required'),
|
||||
|
||||
File::make(__('Products excel'), 'files')
|
||||
->fullWidth()
|
||||
->rules('required'),
|
||||
];
|
||||
}
|
||||
}
|
||||
34
app/Nova/Dashboards/Main.php
Normal file
34
app/Nova/Dashboards/Main.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Dashboards;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\Metrics\NewOrders;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\Metrics\OrdersPerStatus;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\Metrics\ProductSoldPerDay;
|
||||
use Laravel\Nova\Dashboards\Main as Dashboard;
|
||||
|
||||
class Main extends Dashboard
|
||||
{
|
||||
/**
|
||||
* Get the displayable name of the dashboard.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Panel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards for the dashboard.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards()
|
||||
{
|
||||
return [
|
||||
NewOrders::make()->canSeeWhen('isAdmin', User::class),
|
||||
ProductSoldPerDay::make()->canSeeWhen('isAdmin', User::class),
|
||||
OrdersPerStatus::make()->canSeeWhen('isAdmin', User::class),
|
||||
];
|
||||
}
|
||||
}
|
||||
55
app/Nova/Fields/FieldHelpers.php
Normal file
55
app/Nova/Fields/FieldHelpers.php
Normal file
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Fields;
|
||||
|
||||
use Closure;
|
||||
|
||||
class FieldHelpers
|
||||
{
|
||||
/**
|
||||
* Format products stock for better visability
|
||||
*/
|
||||
public static function formatQuantity(null|int|float|string $count = null): Closure
|
||||
{
|
||||
return function ($resource) use ($count) {
|
||||
$stock = $count ?: $resource->stock;
|
||||
|
||||
return sprintf('
|
||||
<div class="flex items-center">
|
||||
<span class="text-xs px-1 inline-flex leading-5 font-semibold rounded-full %s" style="padding-right: 7px;padding-left: 7px;">
|
||||
%s
|
||||
</span>
|
||||
</div>
|
||||
',
|
||||
$stock < 10 ? 'bg-red-100 text-red-800' : 'bg-green-100 text-green-darker',
|
||||
$stock
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Show as link
|
||||
*
|
||||
* @param string $title
|
||||
*/
|
||||
public static function asLink(string $link, int|string|null $title): Closure
|
||||
{
|
||||
return fn () => sprintf('<a href="%s" target="_blank" class="link-default"> %s </a>', $link, $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* To turkmen date d.m.Y
|
||||
*/
|
||||
public static function tmDate(): Closure
|
||||
{
|
||||
return fn ($value) => $value?->format('d.m.Y');
|
||||
}
|
||||
|
||||
/**
|
||||
* Has permission for canSee or canRun methods
|
||||
*/
|
||||
public static function hasPermission(string $permissionName = 'systemUsers'): Closure
|
||||
{
|
||||
return fn ($request) => $request->user()->can('isAdmin');
|
||||
}
|
||||
}
|
||||
39
app/Nova/Filters/AppTypeFilter.php
Normal file
39
app/Nova/Filters/AppTypeFilter.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Filters;
|
||||
|
||||
use App\Models\System\Settings\OS;
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class AppTypeFilter extends Filter
|
||||
{
|
||||
/**
|
||||
* The filter's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'select-filter';
|
||||
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
return $value
|
||||
? $query->where('app', $value)
|
||||
: $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*/
|
||||
public function options(NovaRequest $request): array
|
||||
{
|
||||
return array_flip(OS::apps());
|
||||
}
|
||||
}
|
||||
47
app/Nova/Filters/RegionFilter.php
Normal file
47
app/Nova/Filters/RegionFilter.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Filters;
|
||||
|
||||
use App\Models\System\Settings\Location\Region;
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class RegionFilter extends Filter
|
||||
{
|
||||
/**
|
||||
* The filter's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'select-filter';
|
||||
|
||||
/**
|
||||
* Get the displayable name of the filter.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Region');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
return $value ? $query->where('region', $value) : $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function options(NovaRequest $request)
|
||||
{
|
||||
return array_flip(Region::values());
|
||||
}
|
||||
}
|
||||
45
app/Nova/Filters/ResourceLimitFilter.php
Normal file
45
app/Nova/Filters/ResourceLimitFilter.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Filters;
|
||||
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class ResourceLimitFilter extends Filter
|
||||
{
|
||||
/**
|
||||
* The filter's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'select-filter';
|
||||
|
||||
/**
|
||||
* Resource
|
||||
*/
|
||||
public function __construct(
|
||||
protected $resource
|
||||
) {
|
||||
//...
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*/
|
||||
public function options(NovaRequest $request): array
|
||||
{
|
||||
return $this->resource::perPageOptions();
|
||||
}
|
||||
}
|
||||
45
app/Nova/Filters/StatusFilter.php
Normal file
45
app/Nova/Filters/StatusFilter.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Filters;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class StatusFilter extends Filter
|
||||
{
|
||||
/**
|
||||
* The filter's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'select-filter';
|
||||
|
||||
/**
|
||||
* Get the displayable name of the filter.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Status');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
return $value ? $query->where('status', $value) : $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*/
|
||||
public function options(NovaRequest $request): array
|
||||
{
|
||||
return array_flip(OrderStatus::values());
|
||||
}
|
||||
}
|
||||
49
app/Nova/Filters/UserRoleFilter.php
Normal file
49
app/Nova/Filters/UserRoleFilter.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Filters;
|
||||
|
||||
use App\Models\System\Roles\Role;
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class UserRoleFilter extends Filter
|
||||
{
|
||||
/**
|
||||
* The filter's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'select-filter';
|
||||
|
||||
/**
|
||||
* Get the displayable name of the filter.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Role');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
return $value
|
||||
? $query->join('model_has_roles', 'id', '=', 'model_id')->where('role_id', $value)
|
||||
: $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function options(NovaRequest $request)
|
||||
{
|
||||
return Role::pluck('name', 'id')->map(fn ($data) => __($data))->flip();
|
||||
}
|
||||
}
|
||||
49
app/Nova/Filters/VerifiedUsersFilter.php
Normal file
49
app/Nova/Filters/VerifiedUsersFilter.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Filters;
|
||||
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class VerifiedUsersFilter extends Filter
|
||||
{
|
||||
/**
|
||||
* The filter's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'select-filter';
|
||||
|
||||
/**
|
||||
* Get the displayable name of the filter.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Verified user');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
return $value
|
||||
? $query->where('verified', $value)
|
||||
: $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*/
|
||||
public function options(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
__('Verified') => true,
|
||||
__('Unverified') => false,
|
||||
];
|
||||
}
|
||||
}
|
||||
53
app/Nova/Filters/VisableFilter.php
Normal file
53
app/Nova/Filters/VisableFilter.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Filters;
|
||||
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class VisableFilter extends Filter
|
||||
{
|
||||
/**
|
||||
* The filter's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'select-filter';
|
||||
|
||||
/**
|
||||
* Get the displayable name of the filter.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Visability');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
if ($value) {
|
||||
return $query->where('is_visible', $value);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function options(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
__('Visible') => true,
|
||||
__('Hidden') => false,
|
||||
];
|
||||
}
|
||||
}
|
||||
94
app/Nova/Forms/NovaForm.php
Normal file
94
app/Nova/Forms/NovaForm.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Forms;
|
||||
|
||||
use Closure;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class NovaForm
|
||||
{
|
||||
/**
|
||||
* Fill resource empty
|
||||
*/
|
||||
public static function fillEmpty(): Closure
|
||||
{
|
||||
return function ($request, $model, $attribute, $requestAttribute) {};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill attribute
|
||||
*/
|
||||
public static function fillAttribute($key, $value): Closure
|
||||
{
|
||||
return function ($request, $model, $attribute, $requestAttribute) use ($key, $value) {
|
||||
$model->{$key} = $request->input($value);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill schemaless
|
||||
*/
|
||||
public static function fillSchemalessField($schemalessAttribute = 'options'): Closure
|
||||
{
|
||||
return function ($request, $model, $attribute, $requestAttribute) use ($schemalessAttribute) {
|
||||
$model->{$schemalessAttribute}->set($attribute, $request->input($attribute));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Save by capitalizing firrt letter
|
||||
*/
|
||||
public static function capitalize(): Closure
|
||||
{
|
||||
return function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->{$attribute} = ucfirst($request->input($attribute));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the slug field
|
||||
*/
|
||||
public static function fillSlug(string|array $from, ?string $resource): Closure
|
||||
{
|
||||
return function ($request, $model, $attribute, $requestAttribute) use ($from, $resource) {
|
||||
$slugSource = is_array($from) ? data_get($request, implode('.', $from)) : data_get($request, $from);
|
||||
$slug = Str::slug($slugSource);
|
||||
|
||||
$query = $resource ? $resource::where('slug', $slug) : $model::where('slug', $slug);
|
||||
|
||||
if ($query->exists()) {
|
||||
$slug .= Str::random(6);
|
||||
}
|
||||
|
||||
$model->{$attribute} = $slug;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill media file name
|
||||
*/
|
||||
public static function fillMediaFileName(): Closure
|
||||
{
|
||||
return fn ($originalFilename, $extension, $model) => sprintf('%s.%s', md5($originalFilename), $extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value from cache
|
||||
*/
|
||||
public static function setValueFromCache(string $dependsOnKey, string $cacheKey): Closure
|
||||
{
|
||||
return function ($field, $request, $formData) use ($dependsOnKey, $cacheKey) {
|
||||
if ($formData->{$dependsOnKey}) {
|
||||
$field->setValue(cache($cacheKey));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash file name
|
||||
*/
|
||||
public static function hashFileName(): Closure
|
||||
{
|
||||
return fn ($originalFilename, $extension, $model) => sprintf('%s.%s', md5($originalFilename), $extension);
|
||||
}
|
||||
}
|
||||
123
app/Nova/Lenses/MostSoldProducts.php
Normal file
123
app/Nova/Lenses/MostSoldProducts.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Lenses;
|
||||
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\LensRequest;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Lenses\Lens;
|
||||
|
||||
class MostSoldProducts extends Lens
|
||||
{
|
||||
/**
|
||||
* Get the displayable name of the lens.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Most sold products');
|
||||
}
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [];
|
||||
|
||||
/**
|
||||
* Get the query builder / paginator for the lens.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
*/
|
||||
public static function query(LensRequest $request, $query): mixed
|
||||
{
|
||||
$query->with('media');
|
||||
|
||||
return $request->withOrdering($request->withFilters(
|
||||
$query
|
||||
->select('products.*', DB::raw('SUM(order_items.quantity) AS sold_count'))
|
||||
->join('order_items', 'order_items.product_id', '=', 'products.id')
|
||||
->join('orders', function ($join) {
|
||||
$join->on('orders.id', '=', 'order_items.order_id')
|
||||
->on('orders.status', '=', DB::raw("'completed'"));
|
||||
})
|
||||
->groupBy('products.id')
|
||||
->orderBy('sold_count', 'DESC')
|
||||
->withCasts([
|
||||
'sold_count' => 'int',
|
||||
])
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields available to the lens.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make(__('ID'), 'id')->sortable(),
|
||||
Images::make(__('Image'), 'uploads')->conversionOnIndexView('thumb200x200'),
|
||||
Text::make(__('Name'), 'name')->sortable(),
|
||||
Number::make(__('Price'), 'price_amount')->sortable(),
|
||||
|
||||
Text::make(__('Count'), 'sold_count', function ($value) {
|
||||
return sprintf('
|
||||
<div class="flex items-center">
|
||||
<span class="text-xs px-1 inline-flex leading-5 font-semibold rounded-full %s" style="padding-right: 7px;padding-left: 7px;">
|
||||
%s
|
||||
</span>
|
||||
</div>
|
||||
',
|
||||
$value < 10 ? 'bg-red-100 text-red-800' : 'bg-green-100 text-green-darker',
|
||||
$value
|
||||
);
|
||||
})->asHtml(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available on the lens.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the lens.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available on the lens.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return parent::actions($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URI key for the lens.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function uriKey()
|
||||
{
|
||||
return 'most-sold-products';
|
||||
}
|
||||
}
|
||||
24
app/Nova/Permissions/NovaPermission.php
Normal file
24
app/Nova/Permissions/NovaPermission.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Permissions;
|
||||
|
||||
use Closure;
|
||||
|
||||
class NovaPermission
|
||||
{
|
||||
/**
|
||||
* Can?
|
||||
*/
|
||||
public static function can(string $permission): Closure
|
||||
{
|
||||
return fn () => auth()->user()->can();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is entrepreneur
|
||||
*/
|
||||
public static function canSeeIfUserIsEntrepreneur(): Closure
|
||||
{
|
||||
return fn () => auth()->user()->isEntrepreneur();
|
||||
}
|
||||
}
|
||||
23
app/Nova/Repeater/InventoryHistoryItemRepeater.php
Normal file
23
app/Nova/Repeater/InventoryHistoryItemRepeater.php
Normal file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Repeater;
|
||||
|
||||
use Laravel\Nova\Fields\Repeater\Repeatable;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Nurmuhammet\InventoryHistoryItems\InventoryHistoryItems;
|
||||
|
||||
class InventoryHistoryItemRepeater extends Repeatable
|
||||
{
|
||||
/**
|
||||
* Get the fields displayed by the repeatable.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
InventoryHistoryItems::make(__('Products'), 'quantity')
|
||||
->fullWidth()
|
||||
->options([])
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {}),
|
||||
];
|
||||
}
|
||||
}
|
||||
196
app/Nova/Repos/Payouts/PayoutsRepo.php
Normal file
196
app/Nova/Repos/Payouts/PayoutsRepo.php
Normal file
@@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Repos\Payouts;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\OrderItem;
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use Closure;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class PayoutsRepo
|
||||
{
|
||||
/**
|
||||
* Order items ids element "depends on"
|
||||
*/
|
||||
public static function orderItemIdsDependsOn(): Closure
|
||||
{
|
||||
return function ($field, $request, $formData) {
|
||||
if (
|
||||
! $formData->channel_id ||
|
||||
! $formData->start_date ||
|
||||
! $formData->end_date ||
|
||||
$request->isUpdateOrUpdateAttachedRequest()
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
$paid_products = DB::table('payout_items')
|
||||
->where('channel_id', $formData->channel_id)
|
||||
->distinct('order_item_id')
|
||||
->pluck('order_item_id');
|
||||
|
||||
$order_items = OrderItem::query()
|
||||
->with(['product' => ['media']])
|
||||
->join(
|
||||
table: 'orders',
|
||||
first: fn ($join) => $join->on('order_items.order_id', '=', 'orders.id')
|
||||
->where('orders.status', '=', OrderStatus::COMPLETED)
|
||||
)
|
||||
->where('order_items.channel_id', $formData->channel_id)
|
||||
->whereIntegerNotInRaw('order_items.id', $paid_products)
|
||||
->whereRaw('(order_items.created_at >= ? AND order_items.created_at <= ?)', [
|
||||
$formData->start_date.' 00:00:00',
|
||||
$formData->end_date.' 23:59:59',
|
||||
])
|
||||
->orderBy('order_items.order_id')
|
||||
->get([
|
||||
'order_items.id',
|
||||
'order_items.order_id',
|
||||
'order_items.product_name',
|
||||
'order_items.product_id',
|
||||
'order_items.quantity',
|
||||
'order_items.unit_price_amount',
|
||||
'order_items.unit_cost_amount',
|
||||
'order_items.channel_id',
|
||||
'order_items.created_at',
|
||||
])->map(fn ($orderItem) => [
|
||||
'id' => $orderItem->id,
|
||||
'product_name' => $orderItem->product_name,
|
||||
'product_id' => $orderItem->product_id,
|
||||
'order_id' => $orderItem->order_id,
|
||||
'channel_id' => $orderItem->channel_id,
|
||||
'quantity' => $orderItem->quantity,
|
||||
'unit_price_amount' => $orderItem->unit_price_amount,
|
||||
'product_cost_amount' => $orderItem->unit_cost_amount ?: $orderItem->product->cost_amount,
|
||||
'created_at' => $orderItem->created_at,
|
||||
'updated_at' => $orderItem->updated_at,
|
||||
'product_thumbnail' => $orderItem->product->thumbnail() ?? null,
|
||||
]);
|
||||
|
||||
$field->products($order_items);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Total element "depends on"
|
||||
*/
|
||||
public static function totalDependsOn(): Closure
|
||||
{
|
||||
return function ($field, $request, $formData) {
|
||||
if (! $formData->order_items_ids || ! $request->prices) {
|
||||
return;
|
||||
}
|
||||
|
||||
$orderItems = OrderItem::whereIntegerInRaw('id', $formData->order_items_ids)->get();
|
||||
|
||||
$products = collect($request->prices)
|
||||
->map(fn ($product) => is_string($product) ? json_decode($product) : null)
|
||||
->filter();
|
||||
|
||||
$total_sum = 0;
|
||||
$entrepreneur_total = 0;
|
||||
$postshop_total = 0;
|
||||
foreach ($orderItems as $item) {
|
||||
$percentage_difference =
|
||||
$item->unit_price_amount - $products->firstWhere('product_id', $item->product_id)->cost_amount;
|
||||
|
||||
$total_sum += $item->unit_price_amount * $item->quantity;
|
||||
$postshop_total += $percentage_difference * $item->quantity;
|
||||
$entrepreneur_total += $products->firstWhere('product_id', $item->product_id)->cost_amount * $item->quantity;
|
||||
}
|
||||
|
||||
$field->setValue(number_format($total_sum, 2, '.', ''));
|
||||
|
||||
cache(['nova.entrepreneur_total' => number_format($entrepreneur_total, 2, '.', '')]);
|
||||
cache(['nova.postshop_total' => number_format($postshop_total, 2, '.', '')]);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Order item ids fill
|
||||
*/
|
||||
public static function orderItemIdsFill(NovaRequest $request, Model $model): void
|
||||
{
|
||||
$model::withoutEvents(function () use ($request, $model) {
|
||||
$order_item_ids = [];
|
||||
|
||||
$products = collect($request->prices)
|
||||
->map(fn ($product) => is_string($product) ? json_decode($product) : null)
|
||||
->filter()
|
||||
->each(function ($product) {
|
||||
DB::table('order_items')
|
||||
->where('id', $product->order_item_id)
|
||||
->update(['unit_cost_amount' => $product->cost_amount]);
|
||||
});
|
||||
|
||||
if ($request->filled('order_items_ids')) {
|
||||
foreach ($request->order_items_ids as $id) {
|
||||
if (! $id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$order_item_ids[] = [
|
||||
'payout_id' => $model->id,
|
||||
'channel_id' => $model->channel_id,
|
||||
'order_item_id' => $id,
|
||||
'created_at' => $model->created_at,
|
||||
'updated_at' => now(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (! empty($order_item_ids)) {
|
||||
DB::table('payout_items')->insert($order_item_ids);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve order items
|
||||
*/
|
||||
public static function resolveOrderItems($request, $resource): Closure
|
||||
{
|
||||
return function () use ($request, $resource) {
|
||||
if (! $request->isResourceDetailRequest()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$items = $resource->orderItems;
|
||||
|
||||
$media = DB::table('media')
|
||||
->where('model_type', 'product')
|
||||
->whereIntegerInRaw('model_id', $items->pluck('product_id'))
|
||||
->get(['id', 'model_id', 'file_name']);
|
||||
|
||||
return $items->map(function ($orderItem) use ($media) {
|
||||
return [
|
||||
'id' => $orderItem->id,
|
||||
'product_name' => $orderItem->product_name,
|
||||
'product_id' => $orderItem->product_id,
|
||||
'order_id' => $orderItem->order_id,
|
||||
'channel_id' => $orderItem->channel_id,
|
||||
'quantity' => $orderItem->quantity,
|
||||
'unit_price_amount' => $orderItem->unit_price_amount,
|
||||
'unit_cost_amount' => $orderItem->unit_cost_amount,
|
||||
'created_at' => $orderItem->created_at,
|
||||
'updated_at' => $orderItem->updated_at,
|
||||
'product_thumbnail' => url(
|
||||
sprintf(
|
||||
'storage/%s/%s',
|
||||
$media->firstWhere(
|
||||
'model_id',
|
||||
$orderItem->product_id
|
||||
)?->id,
|
||||
$media->firstWhere(
|
||||
'model_id',
|
||||
$orderItem->product_id
|
||||
)?->file_name
|
||||
)
|
||||
),
|
||||
];
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
80
app/Nova/Resource.php
Normal file
80
app/Nova/Resource.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Resource as NovaResource;
|
||||
|
||||
abstract class Resource extends NovaResource
|
||||
{
|
||||
/**
|
||||
* Indicates whether Nova should check for modifications between viewing and updating a resource.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $trafficCop = false;
|
||||
|
||||
/**
|
||||
* Indicates if the resource should be globally searchable.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $globallySearchable = false;
|
||||
|
||||
/**
|
||||
* Determine if the current user can replicate the given resource.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorizedToReplicate(Request $request)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query)
|
||||
{
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a Scout search query for the given resource.
|
||||
*
|
||||
* @param \Laravel\Scout\Builder $query
|
||||
* @return \Laravel\Scout\Builder
|
||||
*/
|
||||
public static function scoutQuery(NovaRequest $request, $query)
|
||||
{
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a "detail" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function detailQuery(NovaRequest $request, $query)
|
||||
{
|
||||
return parent::detailQuery($request, $query);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a "relatable" query for the given resource.
|
||||
*
|
||||
* This query determines which instances of the model may be attached to other resources.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function relatableQuery(NovaRequest $request, $query)
|
||||
{
|
||||
return parent::relatableQuery($request, $query);
|
||||
}
|
||||
}
|
||||
132
app/Nova/Resources/CMS/Forms/ContactUS.php
Normal file
132
app/Nova/Resources/CMS/Forms/ContactUS.php
Normal file
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\CMS\Forms;
|
||||
|
||||
use App\Models\CMS\Forms\ContactUS as ContactUSModel;
|
||||
use App\Models\System\Settings\OS;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\DateTime;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Textarea;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class ContactUS extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<ContactUSModel>
|
||||
*/
|
||||
public static $model = ContactUSModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'title';
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['user'];
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'title', 'phone',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Messages');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Message');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
BelongsTo::make(__('User'), 'user', User::class),
|
||||
|
||||
Text::make(__('Phone'), 'phone')->rules('required'),
|
||||
|
||||
Text::make(__('Title'), 'title')->rules('required'),
|
||||
|
||||
Textarea::make(__('Content'), 'content')->rules('required')->alwaysShow(),
|
||||
|
||||
Select::make(__('Type'), 'type')
|
||||
->options(OS::apps())
|
||||
->displayUsingLabels()
|
||||
->rules('required'),
|
||||
|
||||
DateTime::make(__('Created at'), 'created_at')
|
||||
->turkmenDate()
|
||||
->exceptOnForms(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
116
app/Nova/Resources/CMS/Marketing/Newsletter.php
Normal file
116
app/Nova/Resources/CMS/Marketing/Newsletter.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\CMS\Marketing;
|
||||
|
||||
use App\Nova\Resource;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Trix;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Newsletter extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Resources\CMS\Marketing\Newsletter>
|
||||
*/
|
||||
public static $model = \App\Models\CMS\Marketing\Newsletter::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'subject';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'subject',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Email Newsletters');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Email Newsletter');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Subject'), 'subject')
|
||||
->rules('required'),
|
||||
|
||||
Trix::make(__('Content'), 'content')
|
||||
->withFiles('public')
|
||||
->rules('required'),
|
||||
|
||||
Boolean::make('sent')
|
||||
->exceptOnForms()
|
||||
->default(false),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
109
app/Nova/Resources/CMS/Marketing/NewsletterUser.php
Normal file
109
app/Nova/Resources/CMS/Marketing/NewsletterUser.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\CMS\Marketing;
|
||||
|
||||
use App\Nova\Resource;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class NewsletterUser extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Resources\CMS\Marketing\NewsletterUser>
|
||||
*/
|
||||
public static $model = \App\Models\CMS\Marketing\NewsletterUser::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'email';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'email',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Email Newsletter').' '.__('subscribed').' '.__('users');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('User');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Email'), 'email')
|
||||
->sortable()
|
||||
->rules('required', 'email', 'max:254')
|
||||
->creationRules('unique:newsletter_users,email')
|
||||
->updateRules('unique:newsletter_users,email,{{resourceId}}'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
179
app/Nova/Resources/CMS/Media/Banner.php
Normal file
179
app/Nova/Resources/CMS/Media/Banner.php
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\CMS\Media;
|
||||
|
||||
use App\Models\CMS\Media\Banner as BannerModel;
|
||||
use App\Models\System\Settings\OS;
|
||||
use App\Nova\Filters\AppTypeFilter;
|
||||
use App\Nova\Filters\VisableFilter;
|
||||
use App\Nova\Resource;
|
||||
use App\Repositories\CMS\Media\Banner\BannerRepository;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\URL;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Panel;
|
||||
use Outl1ne\NovaSortable\Traits\HasSortableRows;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class Banner extends Resource
|
||||
{
|
||||
/**
|
||||
* Sortable behavior
|
||||
*/
|
||||
use HasSortableRows;
|
||||
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\CMS\Media\Banner>
|
||||
*/
|
||||
public static $model = BannerModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'id';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['media'];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Banners');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Banner');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
new Panel(__('Basic information'), [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'main')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
Select::make(__('App'), 'app')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OS::apps())
|
||||
->default(OS::WEBSITE),
|
||||
|
||||
Select::make(__('Place'), 'place')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(BannerModel::places())
|
||||
->rules('required'),
|
||||
|
||||
Text::make(__('Name'), 'title')
|
||||
->translatable()
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
|
||||
URL::make(__('Link'), 'link')
|
||||
->displayUsing(fn () => $this->link)
|
||||
->rules('nullable', 'string', 'max:2048')
|
||||
->hideFromIndex(),
|
||||
|
||||
NovaSwitcher::make(__('Visible'), 'is_visible')
|
||||
->default(true),
|
||||
]),
|
||||
|
||||
new Panel(__('Additional information'), [
|
||||
Select::make(__('Resource type to attach'), 'resource_type')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(BannerModel::attachableResources())
|
||||
->rules('nullable')
|
||||
->onlyOnForms(),
|
||||
|
||||
Select::make(__('Resource to attach'), 'resource_id')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->rules('nullable')
|
||||
->dependsOn(['resource_type'], function ($field, $request, $formData) {
|
||||
if ($formData->resource_type) {
|
||||
$field->options(BannerRepository::getNovaResource($formData->resource_type))->rules('required');
|
||||
}
|
||||
})
|
||||
->onlyOnForms(),
|
||||
|
||||
Text::make(
|
||||
__('Attached resource'),
|
||||
fn () => view('vendor.nova.resources.banner.resource-type', ['resource' => $this])->render()
|
||||
)->asHtml()->hideFromIndex(),
|
||||
|
||||
Text::make(__('Note'), 'description')
|
||||
->translatable()
|
||||
->rules('nullable', 'string', 'max:255')
|
||||
->hideFromIndex(),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*/
|
||||
public function cards(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*/
|
||||
public function filters(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
new VisableFilter(),
|
||||
new AppTypeFilter(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*/
|
||||
public function lenses(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*/
|
||||
public function actions(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
190
app/Nova/Resources/CMS/Media/Carousel.php
Normal file
190
app/Nova/Resources/CMS/Media/Carousel.php
Normal file
@@ -0,0 +1,190 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\CMS\Media;
|
||||
|
||||
use App\Models\CMS\Media\Carousel as CarouselModel;
|
||||
use App\Models\System\Settings\OS;
|
||||
use App\Nova\Filters\AppTypeFilter;
|
||||
use App\Nova\Filters\VisableFilter;
|
||||
use App\Nova\Resource;
|
||||
use App\Repositories\CMS\Media\Banner\BannerRepository;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\URL;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Panel;
|
||||
use Outl1ne\NovaSortable\Traits\HasSortableRows;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class Carousel extends Resource
|
||||
{
|
||||
/**
|
||||
* Sortable behavior
|
||||
*/
|
||||
use HasSortableRows;
|
||||
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<CarouselModel>
|
||||
*/
|
||||
public static $model = CarouselModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'id';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'title',
|
||||
];
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['media'];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Carousels');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Carousel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
new Panel(__('Basic information'), [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'main')
|
||||
->conversionOnIndexView('thumb50x50')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
Select::make(__('App'), 'app')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OS::apps())
|
||||
->default(OS::WEBSITE)
|
||||
->rules('required'),
|
||||
|
||||
Select::make(__('Place'), 'place')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(CarouselModel::places())
|
||||
->default('homepage')
|
||||
->rules('required'),
|
||||
|
||||
Text::make(__('Name'), 'title')
|
||||
->translatable()
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
|
||||
URL::make(__('Link'), 'link')
|
||||
->displayUsing(fn () => $this->link)
|
||||
->rules('nullable', 'string', 'max:2048')
|
||||
->hideFromIndex(),
|
||||
|
||||
NovaSwitcher::make(__('Is visible'), 'is_visible')
|
||||
->default(true)
|
||||
->sortable(),
|
||||
]),
|
||||
|
||||
new Panel(__('Additional information'), [
|
||||
Select::make(__('Resource type to attach'), 'resource_type')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(CarouselModel::attachableResources())
|
||||
->rules('nullable')
|
||||
->onlyOnForms(),
|
||||
|
||||
Select::make(__('Resource to attach'), 'resource_id')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->rules('nullable')
|
||||
->dependsOn(['resource_type'], function ($field, $request, $formData) {
|
||||
if ($formData->resource_type) {
|
||||
$field->options(BannerRepository::getNovaResource($formData->resource_type))->rules('required');
|
||||
}
|
||||
})
|
||||
->onlyOnForms(),
|
||||
|
||||
Text::make(
|
||||
__('Attached resource'),
|
||||
fn () => view('vendor.nova.resources.banner.resource-type', ['resource' => $this])->render()
|
||||
)->asHtml()->hideFromIndex(),
|
||||
|
||||
Text::make(__('Note'), 'description')
|
||||
->translatable()
|
||||
->rules('nullable', 'string', 'max:255')
|
||||
->hideFromIndex(),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
new VisableFilter(),
|
||||
new AppTypeFilter(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
119
app/Nova/Resources/CMS/Media/Gallery.php
Normal file
119
app/Nova/Resources/CMS/Media/Gallery.php
Normal file
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\CMS\Media;
|
||||
|
||||
use App\Nova\Resource;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Gallery extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Resources\CMS\Media\Gallery>
|
||||
*/
|
||||
public static $model = \App\Models\CMS\Media\Gallery::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'title';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'title',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Galleries');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Gallery');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'main')
|
||||
->conversionOnIndexView('thumb')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
Text::make(__('Title'), 'title')
|
||||
->rules('required', 'string')
|
||||
->translatable(),
|
||||
|
||||
Text::make(__('Description'), 'description')
|
||||
->translatable(),
|
||||
|
||||
Boolean::make(__('Active'), 'is_visible')->default(true),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
168
app/Nova/Resources/Ecommerce/Channel/Channel.php
Normal file
168
app/Nova/Resources/Ecommerce/Channel/Channel.php
Normal file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Channel;
|
||||
|
||||
use App\Models\Ecommerce\Channel\Channel as ChannelModel;
|
||||
use App\Models\User;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Channel\Fields\ChannelFieldsForIndex;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product;
|
||||
use App\Nova\Resources\User\UserSearchResource;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\DateTime;
|
||||
use Laravel\Nova\Fields\Hidden;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\MorphMany;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\URL;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Outl1ne\NovaSortable\Traits\HasSortableRows;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class Channel extends Resource
|
||||
{
|
||||
/**
|
||||
* Sortable behavior
|
||||
*/
|
||||
use HasSortableRows;
|
||||
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<ChannelModel>
|
||||
*/
|
||||
public static $model = ChannelModel::class;
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['media', 'user'];
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Channels');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Channel');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fields for index
|
||||
*/
|
||||
public function fieldsForIndex(): array
|
||||
{
|
||||
return ChannelFieldsForIndex::make();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->rules(['required', 'string', 'max:255']),
|
||||
|
||||
Text::make(__('Description'), 'description')
|
||||
->rules(['nullable', 'string', 'max:255']),
|
||||
|
||||
URL::make('URL'),
|
||||
Hidden::make('is_default')->default(true),
|
||||
Hidden::make('timezone')->default('Asia/Ashgabat'),
|
||||
|
||||
DateTime::make(__('Created at'), 'created_at')
|
||||
->default(now())
|
||||
->displayUsing(fn ($value) => $value->format('H:i, d.m.Y'))
|
||||
->exceptOnForms()
|
||||
->sortable(),
|
||||
|
||||
BelongsTo::make(__('User'), 'user', UserSearchResource::class)
|
||||
->searchable()
|
||||
->withSubtitles()
|
||||
->readonly(fn () => $this->id === tmpostChannel()->id)
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->channelables_type = User::class;
|
||||
$model->channelables_id = $request->input('user');
|
||||
}),
|
||||
|
||||
NovaSwitcher::make(__('Active'), 'is_visible')
|
||||
->default(true),
|
||||
|
||||
MorphMany::make(__('Products'), 'products', Product::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Channel\Fields;
|
||||
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Laravel\Nova\Fields\DateTime;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
|
||||
class ChannelFieldsForIndex
|
||||
{
|
||||
/**
|
||||
* Fields for index
|
||||
*/
|
||||
public static function make(): array
|
||||
{
|
||||
return [
|
||||
ID::make()->hidden(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200'),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('User'), fn ($model) => $model->user?->fullname ?? '-'),
|
||||
|
||||
DateTime::make(__('Created at'), 'created_at')
|
||||
->turkmenDate()
|
||||
->sortable(),
|
||||
];
|
||||
}
|
||||
}
|
||||
174
app/Nova/Resources/Ecommerce/Payout/PayoutResource.php
Normal file
174
app/Nova/Resources/Ecommerce/Payout/PayoutResource.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Payout;
|
||||
|
||||
use App\Models\Ecommerce\Payouts\Payout;
|
||||
use App\Nova\Repos\Payouts\PayoutsRepo;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\Actions\ExportEvidenceForProducts;
|
||||
use App\Repositories\CMS\Icon\IconRepository;
|
||||
use App\Repositories\Ecommerce\Channel\ChannelRepository;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\Date;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Textarea;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Nurmuhammet\PayoutProducts\PayoutProducts;
|
||||
|
||||
class PayoutResource extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Ecommerce\Payout>
|
||||
*/
|
||||
public static $model = Payout::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'id';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id',
|
||||
];
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['channel'];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Payout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Payouts');
|
||||
}
|
||||
|
||||
/**
|
||||
* After resource has been created
|
||||
*/
|
||||
public static function afterCreate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
PayoutsRepo::orderItemIdsFill($request, $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Select::make(__('Channel'), 'channel_id')
|
||||
->fullWidth()
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(ChannelRepository::values())
|
||||
->rules('required')
|
||||
->canSeeWhen('isAdmin', $this),
|
||||
|
||||
Date::make(__('Start date'), 'start_date')
|
||||
->rules('required')
|
||||
->fullWidth()
|
||||
->displayUsing(fn ($value) => $value->format('d.m.Y'))
|
||||
->readonly(fn ($request) => $request->isUpdateOrUpdateAttachedRequest())
|
||||
->sortable(),
|
||||
|
||||
Date::make(__('End date'), 'end_date')
|
||||
->rules('required')
|
||||
->fullWidth()
|
||||
->displayUsing(fn ($value) => $value->format('d.m.Y'))
|
||||
->readonly(fn ($request) => $request->isUpdateOrUpdateAttachedRequest())
|
||||
->sortable(),
|
||||
|
||||
PayoutProducts::make(__('Products'), 'order_items_ids')
|
||||
->dependsOn(['channel_id', 'start_date', 'end_date'], PayoutsRepo::orderItemIdsDependsOn())
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->total_sum = $request->total_sum;
|
||||
$model->entrepreneur_total = $request->entrepreneur_total;
|
||||
$model->postshop_total = $request->postshop_total;
|
||||
})
|
||||
->products(PayoutsRepo::resolveOrderItems($request, $this))
|
||||
->fullWidth()
|
||||
->hideFromIndex(),
|
||||
|
||||
Text::make(__('Hasap'), 'total_sum')
|
||||
->fullWidth()
|
||||
->exceptOnForms()
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Entrepreneur Total'), 'entrepreneur_total')
|
||||
->fullWidth()
|
||||
->exceptOnForms()
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('POSTSHOP Total'), 'postshop_total')
|
||||
->fullWidth()
|
||||
->exceptOnForms()
|
||||
->sortable(),
|
||||
|
||||
Textarea::make(__('Notes'), 'notes')->fullWidth(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*/
|
||||
public function cards(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*/
|
||||
public function filters(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*/
|
||||
public function lenses(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*/
|
||||
public function actions(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ExportEvidenceForProducts::make()
|
||||
->confirmText('Delilnama çykarmak isleýarmisiňiz?')
|
||||
->confirmButtonText('Hawa')
|
||||
->cancelButtonText('Ýok')
|
||||
->icon(IconRepository::make()->documentDownload()),
|
||||
];
|
||||
}
|
||||
}
|
||||
166
app/Nova/Resources/Ecommerce/Product/Attribute/Attribute.php
Normal file
166
app/Nova/Resources/Ecommerce/Product/Attribute/Attribute.php
Normal file
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Attribute;
|
||||
|
||||
use App\Models\Ecommerce\Product\Property\Attribute as AttributeModel;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Category\Category;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\HasMany;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Trix;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use NovaAttachMany\AttachMany;
|
||||
use Outl1ne\MultiselectField\Multiselect;
|
||||
use Outl1ne\NovaSortable\Traits\HasSortableRows;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class Attribute extends Resource
|
||||
{
|
||||
/**
|
||||
* Sortable behavior
|
||||
*/
|
||||
use HasSortableRows;
|
||||
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<AttributeModel>
|
||||
*/
|
||||
public static $model = AttributeModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Attributes');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Attribute');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->rules('required', 'string')
|
||||
->translatable(),
|
||||
|
||||
Select::make(__('Type'), 'type')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->default(AttributeModel::typesFields()['text'])
|
||||
->options(AttributeModel::typesFields())
|
||||
->rules('required'),
|
||||
|
||||
Trix::make(__('Description'), 'description')
|
||||
->translatable(),
|
||||
|
||||
NovaSwitcher::make(__('Is enabled'), 'is_visible')
|
||||
->default(true)
|
||||
->canSeeWhen('systemUser', $this),
|
||||
|
||||
NovaSwitcher::make(__('Is required'), 'is_required')
|
||||
->default(true)
|
||||
->canSeeWhen('systemUser', $this),
|
||||
|
||||
NovaSwitcher::make(__('Is searchable'), 'is_searchable')
|
||||
->default(false)
|
||||
->canSeeWhen('systemUser', $this),
|
||||
|
||||
NovaSwitcher::make(__('Is filterable'), 'is_filterable')
|
||||
->default(false)
|
||||
->canSeeWhen('systemUser', $this),
|
||||
|
||||
Boolean::make(__('Is enabled'), 'is_visible')
|
||||
->canSeeWhen('vendor', $this),
|
||||
|
||||
Boolean::make(__('Is required'), 'is_required')
|
||||
->canSeeWhen('vendor', $this),
|
||||
|
||||
Boolean::make(__('Is searchable'), 'is_searchable')
|
||||
->canSeeWhen('vendor', $this),
|
||||
|
||||
Boolean::make(__('Is filterable'), 'is_filterable')
|
||||
->canSeeWhen('vendor', $this),
|
||||
|
||||
AttachMany::make(__('Categories'), 'categories', Category::class),
|
||||
Multiselect::make(__('Categories'), 'categories')->belongsToMany(Category::class)
|
||||
->onlyOnDetail(),
|
||||
|
||||
HasMany::make(__('Attribute values'), 'values', AttributeValue::class)
|
||||
->hideFromDetail(function (NovaRequest $request, $resource) {
|
||||
return $this->type !== 'select';
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Attribute;
|
||||
|
||||
use App\Models\Ecommerce\Product\Property\AttributeValue as AttributeValueModel;
|
||||
use App\Nova\Resource;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class AttributeValue extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<AttributeValueModel>
|
||||
*/
|
||||
public static $model = AttributeValueModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'value';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'value',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Attribute Values');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Attribute Value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after creation.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterCreate(NovaRequest $request, $resource): string
|
||||
{
|
||||
return sprintf('/resources/attributes/%s', $resource->attribute_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after update.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterUpdate(NovaRequest $request, $resource)
|
||||
{
|
||||
return sprintf('/resources/attributes/%s', $resource->attribute_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Value'), 'value')
|
||||
->translatable()
|
||||
->rules('required'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
174
app/Nova/Resources/Ecommerce/Product/Brand/Brand.php
Normal file
174
app/Nova/Resources/Ecommerce/Product/Brand/Brand.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Brand;
|
||||
|
||||
use App\Models\Ecommerce\Product\Brand\Brand as BrandModel;
|
||||
use App\Nova\Filters\VisableFilter;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\HasMany;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Textarea;
|
||||
use Laravel\Nova\Fields\Trix;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Outl1ne\NovaSortable\Traits\HasSortableRows;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class Brand extends Resource
|
||||
{
|
||||
/**
|
||||
* Sortable behavior
|
||||
*/
|
||||
use HasSortableRows;
|
||||
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $model = BrandModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['media'];
|
||||
|
||||
/**
|
||||
* Indicates if the resource should be globally searchable.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $globallySearchable = true;
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'name', 'slug',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Brands');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Brand');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query)
|
||||
{
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->rules(['required', 'max:150'])
|
||||
->creationRules('unique:brands,name'),
|
||||
|
||||
Text::make(__('Web site'), 'website')
|
||||
->hideFromIndex(),
|
||||
|
||||
Trix::make(__('description'), 'description')
|
||||
->translatable(),
|
||||
|
||||
Boolean::make(__('Market related'), 'type')
|
||||
->sortable()
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->{$attribute} = $request->boolean('type') ? 'market' : '';
|
||||
}),
|
||||
|
||||
Text::make(__('Seo title'), 'seo_title')
|
||||
->hideFromIndex(),
|
||||
|
||||
Textarea::make(__('Seo description'), 'seo_description'),
|
||||
|
||||
NovaSwitcher::make(__('Is enabled'), 'is_visible')
|
||||
->default(true)
|
||||
->canSeeWhen('systemUser', $this)
|
||||
->sortable(),
|
||||
|
||||
HasMany::make('Products', 'products', Product::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
VisableFilter::make(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
181
app/Nova/Resources/Ecommerce/Product/Category/Category.php
Normal file
181
app/Nova/Resources/Ecommerce/Product/Category/Category.php
Normal file
@@ -0,0 +1,181 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Category;
|
||||
|
||||
use App\Models\Ecommerce\Product\Category\Category as CategoryModel;
|
||||
use App\Nova\Filters\VisableFilter;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Category\Filters\Level;
|
||||
use App\Nova\Resources\Ecommerce\Product\Category\Filters\RelatedToMarket;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product;
|
||||
use App\Repositories\Ecommerce\Product\Category\CategoryRepository;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\Color;
|
||||
use Laravel\Nova\Fields\HasMany;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\MorphMany;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Textarea;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Outl1ne\NovaSortable\Traits\HasSortableRows;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class Category extends Resource
|
||||
{
|
||||
/**
|
||||
* Sortable behavior
|
||||
*/
|
||||
use HasSortableRows;
|
||||
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<CategoryModel>
|
||||
*/
|
||||
public static $model = CategoryModel::class;
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array<string>
|
||||
*/
|
||||
public static $with = ['parent', 'media'];
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'name', 'slug',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Category');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Categories');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
Color::make(__('Color'), 'color')
|
||||
->rules('required')
|
||||
->hideFromIndex()
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->options->set([
|
||||
'color' => $request->input($attribute),
|
||||
]);
|
||||
}),
|
||||
|
||||
Select::make(__('Parent Category'), 'parent_id')
|
||||
->searchable()
|
||||
->options(fn () => (new CategoryRepository(request()))->getNamesForNova())
|
||||
->onlyOnForms(),
|
||||
|
||||
BelongsTo::make(__('Parent'), 'parent', self::class)
|
||||
->exceptOnForms(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->rules('required', 'min:2')
|
||||
->translatable(),
|
||||
|
||||
Textarea::make(__('Description'), 'description'),
|
||||
|
||||
Text::make(__('Tax percentage'), 'tax_percentage')
|
||||
->rules('required', 'numeric', 'max:100'),
|
||||
|
||||
NovaSwitcher::make(__('Is enabled'), 'is_visible')
|
||||
->default(true)
|
||||
->canSeeWhen('systemUser', $this)
|
||||
->sortable(),
|
||||
|
||||
NovaSwitcher::make(__('Market related'), 'type')
|
||||
->canSeeWhen('systemUser', $this)
|
||||
->sortable()
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->{$attribute} = $request->boolean('type') ? 'market' : '';
|
||||
}),
|
||||
|
||||
Text::make(__('Seo title'), 'seo_title')
|
||||
->hideFromIndex(),
|
||||
|
||||
Textarea::make(__('Seo description'), 'seo_description'),
|
||||
|
||||
HasMany::make(__('Children'), 'children', self::class),
|
||||
|
||||
MorphMany::make('Products', 'products', Product::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*/
|
||||
public function filters(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
RelatedToMarket::make(),
|
||||
Level::make(),
|
||||
VisableFilter::make(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Category\Filters;
|
||||
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Level extends Filter
|
||||
{
|
||||
/**
|
||||
* The filter's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'select-filter';
|
||||
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
if ($value == 1) {
|
||||
return $query->where('parent_id', null);
|
||||
}
|
||||
|
||||
if ($value == 2) {
|
||||
$query->whereNotNull('parent_id');
|
||||
}
|
||||
|
||||
// if ($value == 3) {
|
||||
// $query->isLeaf();
|
||||
// }
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function options(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
1 => 1,
|
||||
2 => 2,
|
||||
// 3 => 3
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Category\Filters;
|
||||
|
||||
use Laravel\Nova\Filters\BooleanFilter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class RelatedToMarket extends BooleanFilter
|
||||
{
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
return $value['market']
|
||||
? $query->where('type', 'market')
|
||||
: $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function options(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
__('Market related') => 'market',
|
||||
];
|
||||
}
|
||||
}
|
||||
145
app/Nova/Resources/Ecommerce/Product/Collection/Collection.php
Normal file
145
app/Nova/Resources/Ecommerce/Product/Collection/Collection.php
Normal file
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Collection;
|
||||
|
||||
use App\Models\Ecommerce\Product\Collection\Collection as CollectionModel;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\MorphMany;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Trix;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Outl1ne\NovaSortable\Traits\HasSortableRows;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class Collection extends Resource
|
||||
{
|
||||
/**
|
||||
* Sortable behavior
|
||||
*/
|
||||
use HasSortableRows;
|
||||
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $model = CollectionModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['media'];
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Collections');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Collection');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->rules('required')
|
||||
->required(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->rules('required')
|
||||
->translatable(),
|
||||
|
||||
Trix::make(__('description'), 'description')
|
||||
->translatable(),
|
||||
|
||||
NovaSwitcher::make(__('Active'), 'is_visible')
|
||||
->canSeeWhen('systemUser', $this)
|
||||
->default(false),
|
||||
|
||||
Text::make(__('SEO title'), 'seo_title')->hideFromIndex(),
|
||||
Text::make(__('SEO description'), 'seo_description')->hideFromIndex(),
|
||||
|
||||
MorphMany::make('Products', 'products', Product::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
public static function canSort(NovaRequest $request, $resource): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
139
app/Nova/Resources/Ecommerce/Product/Coupon/Coupon.php
Normal file
139
app/Nova/Resources/Ecommerce/Product/Coupon/Coupon.php
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Coupon;
|
||||
|
||||
use App\Models\Ecommerce\Product\Coupon\Coupon as CouponModel;
|
||||
use App\Nova\Resource;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class Coupon extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<CouponModel>
|
||||
*/
|
||||
public static $model = CouponModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'id';
|
||||
|
||||
/**
|
||||
* Indicates if the resource should be globally searchable.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $globallySearchable = true;
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'code',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Coupons');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Coupon');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Code'), 'code')
|
||||
->rules('required', 'max:255')
|
||||
->creationRules('unique:coupons,code'),
|
||||
|
||||
Select::make(__('Discount Type'), 'discount_type')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(CouponModel::discountTypes())
|
||||
->default(CouponModel::defaultDiscountType())
|
||||
->rules('required'),
|
||||
|
||||
Text::make(__('Discount Value'), 'discount_value')
|
||||
->dependsOn('discount_type', function ($field, $request, $formData) {
|
||||
if ($formData->discount_type === 'percentage') {
|
||||
$field->rules('required', 'numeric', 'min:1', 'max:100');
|
||||
}
|
||||
})
|
||||
->rules('required', 'numeric'),
|
||||
|
||||
Text::make(__('Notes'), 'notes')
|
||||
->rules('nullable', 'max:255')
|
||||
->hideFromIndex(),
|
||||
|
||||
NovaSwitcher::make(__('Active'), 'is_active')
|
||||
->default(true),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
213
app/Nova/Resources/Ecommerce/Product/Inventory/Inventory.php
Normal file
213
app/Nova/Resources/Ecommerce/Product/Inventory/Inventory.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Inventory;
|
||||
|
||||
use App\Models\Ecommerce\Product\Inventory\Inventory as InventoryModel;
|
||||
use App\Models\System\Settings\Location\Province;
|
||||
use App\Models\System\Settings\Location\Region;
|
||||
use App\Nova\Permissions\NovaPermission;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Channel\Channel;
|
||||
use App\Nova\Resources\Ecommerce\Product\Inventory\Product\ProductResource;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\BelongsToMany;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\Currency;
|
||||
use Laravel\Nova\Fields\HasMany;
|
||||
use Laravel\Nova\Fields\Hidden;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Inventory extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Shop\Inventory\Inventory>
|
||||
*/
|
||||
public static $model = InventoryModel::class;
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['channel'];
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = ['name', 'code', 'email', 'phone_number'];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Inventories');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Inventory');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
if ($user->hasRole('vendor')) {
|
||||
$query->where('channel_id', $user->channel()->id);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
BelongsTo::make(__('Channel'), 'channel', Channel::class)
|
||||
->rules('required')
|
||||
->canSeeWhen('systemUser', $this)
|
||||
->sortable(),
|
||||
|
||||
Hidden::make('channel_id')
|
||||
->default(fn () => $request->isCreateOrAttachRequest() ? $request->user()->channel()?->id : null)
|
||||
->canSee(NovaPermission::canSeeIfUserIsEntrepreneur()),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->rules('required', 'string', 'max:255')
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Code'), 'code')->exceptOnForms()->sortable(),
|
||||
|
||||
Select::make(__('Region'), 'region')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(Region::values())
|
||||
->default(Region::AG)
|
||||
->rules('required')
|
||||
->sortable(),
|
||||
|
||||
Select::make(__('Province'), 'province_id')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->dependsOn(['region'], function ($field, $request, $formData) {
|
||||
if ($formData->region != 'ag') {
|
||||
$field->rules('required');
|
||||
}
|
||||
|
||||
$field->options(
|
||||
Province::where('region', $formData->region)->pluck(
|
||||
'name',
|
||||
'id'
|
||||
)
|
||||
);
|
||||
})
|
||||
->hideFromIndex()
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Address'), 'street_address')
|
||||
->rules('nullable', 'string', 'max:255')
|
||||
->hideFromIndex(),
|
||||
|
||||
Text::make(__('Description'), 'description')->hideFromIndex(),
|
||||
|
||||
Text::make(__('Email'), 'email')
|
||||
->rules('nullable', 'string', 'max:255')
|
||||
->hideFromIndex()
|
||||
->sortable(),
|
||||
|
||||
Currency::make(__('Phone'), 'phone_number')
|
||||
->symbol('+993')
|
||||
->displayUsing(fn ($value) => $value ? '+(993)-'.$value : '—')
|
||||
->textAlign('left')
|
||||
->rules('nullable', 'string', 'max:255')
|
||||
->sortable(),
|
||||
|
||||
Number::make(__('Zipcode'), 'zipcode')
|
||||
->rules('nullable', 'integer')
|
||||
->hideFromIndex()
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Longitude'), 'longitude')->hideFromIndex(),
|
||||
|
||||
Text::make(__('Latitude'), 'latitude')->hideFromIndex(),
|
||||
|
||||
Boolean::make(__('Sharable'), 'shareable')
|
||||
->canSeeWhen('isAdmin', $this)
|
||||
->sortable(),
|
||||
|
||||
HasMany::make(__('Inventory entry'), 'history', InventoryHistoryResource::class),
|
||||
HasMany::make(__('Inventory exit'), 'historyRemoved', InventoryHistoryRemovedResource::class),
|
||||
|
||||
BelongsToMany::make(__('Products'), 'products', ProductResource::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Inventory;
|
||||
|
||||
use App\Models\Ecommerce\Product\Inventory\InventoryHistoryItem;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class InventoryHistoryItemResource extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Ecommerce\Product\Inventory\InventoryHistory>
|
||||
*/
|
||||
public static $model = InventoryHistoryItem::class;
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['inventoryHistory', 'product'];
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'id';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Items');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Item');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource on detail page.
|
||||
*/
|
||||
public function fieldsForUpdate(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Number::make(__('Quantity'), 'quantity')
|
||||
->rules('required', 'min:1', 'numeric'),
|
||||
|
||||
Text::make(__('Cost amount'), 'cost_amount'),
|
||||
Text::make(__('Total'), 'total'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
BelongsTo::make(__('Inventory history'), 'inventoryHistory', InventoryHistoryResource::class),
|
||||
BelongsTo::make(__('Product'), 'product', Product::class),
|
||||
|
||||
Number::make(__('Quantity'), 'quantity')
|
||||
->rules('required', 'min:1', 'numeric'),
|
||||
|
||||
Number::make(__('Cost amount'), 'cost_amount'),
|
||||
Text::make(__('Total'), 'total'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after creation.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterUpdate(NovaRequest $request, $resource): string
|
||||
{
|
||||
return sprintf('/resources/inventory-history-resources/%s', $resource->inventory_history_id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Inventory;
|
||||
|
||||
use App\Models\Ecommerce\Product\Inventory\InventoryHistoryRemovedItem;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class InventoryHistoryRemovedItemResource extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Ecommerce\Product\Inventory\InventoryHistory>
|
||||
*/
|
||||
public static $model = InventoryHistoryRemovedItem::class;
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['inventoryHistoryRemoved', 'product'];
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'id';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Items');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Item');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource on detail page.
|
||||
*/
|
||||
public function fieldsForUpdate(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Number::make(__('Quantity'), 'quantity')
|
||||
->rules('required', 'min:1', 'numeric'),
|
||||
|
||||
Text::make(__('Cost amount'), 'cost_amount'),
|
||||
Text::make(__('Total'), 'total'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
BelongsTo::make(__('Inventory history'), 'inventoryHistoryRemoved', InventoryHistoryRemovedResource::class),
|
||||
BelongsTo::make(__('Product'), 'product', Product::class),
|
||||
|
||||
Number::make(__('Quantity'), 'quantity')
|
||||
->rules('required', 'min:1', 'numeric'),
|
||||
|
||||
Number::make(__('Cost amount'), 'cost_amount'),
|
||||
Text::make(__('Total'), 'total'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after creation.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterUpdate(NovaRequest $request, $resource): string
|
||||
{
|
||||
return sprintf('/resources/inventory-history-resources/%s', $resource->inventory_history_id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Inventory;
|
||||
|
||||
use App\Models\Ecommerce\Product\Inventory\InventoryHistoryRemoved;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Nova\Repeater\InventoryHistoryItemRepeater;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Channel\Channel;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\Date;
|
||||
use Laravel\Nova\Fields\HasMany;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Repeater;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class InventoryHistoryRemovedResource extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Ecommerce\Product\Inventory\InventoryHistoryRemoved>
|
||||
*/
|
||||
public static $model = InventoryHistoryRemoved::class;
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['channel', 'inventory'];
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'code';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Inventory exits');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Inventory exit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
if ($user->hasRole('vendor')) {
|
||||
$query->where('channel_id', $user->channel()->id);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after creation.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterCreate(NovaRequest $request, $resource): string
|
||||
{
|
||||
return 'resources/inventories/'.$resource->inventory_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Date::make(__('Date'), 'date')
|
||||
->rules('required')
|
||||
->displayUsing(fn ($value) => $value->format('d.m.Y'))
|
||||
->readonly(fn ($request) => $request->isUpdateOrUpdateAttachedRequest())
|
||||
->default(now()->toDate())
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('R. Number'), 'number')
|
||||
->rules('required')
|
||||
->readonly(fn ($request) => $request->isUpdateOrUpdateAttachedRequest())
|
||||
->sortable(),
|
||||
|
||||
BelongsTo::make(__('Inventory'), 'inventory', Inventory::class),
|
||||
BelongsTo::make(__('Channel'), 'channel', Channel::class),
|
||||
|
||||
Text::make(__('Notes'), 'notes')
|
||||
->rules('nullable', 'string', 'max:255')
|
||||
->hideFromIndex(),
|
||||
|
||||
Text::make(__('Total'), fn () => $this->total),
|
||||
|
||||
Text::make(__('Total'), 'readonly_total')
|
||||
->onlyOnForms()
|
||||
->readonly(),
|
||||
|
||||
Repeater::make('Options', 'options')
|
||||
->repeatables([
|
||||
InventoryHistoryItemRepeater::make(),
|
||||
])
|
||||
->asJson()
|
||||
->fullWidth()
|
||||
->hideWhenUpdating(),
|
||||
|
||||
HasMany::make(__('Items'), 'items', InventoryHistoryRemovedItemResource::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be called after the resource is created.
|
||||
*/
|
||||
public static function afterCreate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
$total = 0;
|
||||
$request->collect('options')->each(function ($item) use ($model, &$total) {
|
||||
$total = floatval($total) + floatval($item['fields']['total']);
|
||||
|
||||
$model->items()->create([
|
||||
'product_id' => $item['fields']['product_id'],
|
||||
'quantity' => $item['fields']['quantity'],
|
||||
'total' => floatval($item['fields']['total']),
|
||||
'cost_amount' => $item['fields']['cost_amount'],
|
||||
]);
|
||||
|
||||
$product = Product::find($item['fields']['product_id']);
|
||||
|
||||
$inventoryRecordQuery = DB::table('inventory_product')
|
||||
->where('product_id', $product->id)
|
||||
->where('inventory_id', $model->inventory_id);
|
||||
|
||||
$inventoryRecord = $inventoryRecordQuery->first();
|
||||
|
||||
$inventoryRecord
|
||||
? $inventoryRecordQuery->update([
|
||||
'stock' => intval($inventoryRecord->stock) - intval($item['fields']['quantity']),
|
||||
]) : DB::table('inventory_product')->insert([
|
||||
'product_id' => $product->id,
|
||||
'inventory_id' => $model->inventory_id,
|
||||
'stock' => -intval($item['fields']['quantity']),
|
||||
]);
|
||||
|
||||
$product->updateQuietly([
|
||||
'stock' => $product->inventories()->sum('inventory_product.stock'),
|
||||
]);
|
||||
});
|
||||
|
||||
$model->updateQuietly(['total' => $total]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current user can update the given resource.
|
||||
*/
|
||||
public function authorizedToUpdate(Request $request): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current user can delete the given resource.
|
||||
*/
|
||||
public function authorizedToDelete(Request $request): bool
|
||||
{
|
||||
if (auth()->user()->isMe()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Inventory;
|
||||
|
||||
use App\Models\Ecommerce\Product\Inventory\InventoryHistory;
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Nova\Repeater\InventoryHistoryItemRepeater;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Channel\Channel;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\Date;
|
||||
use Laravel\Nova\Fields\HasMany;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Repeater;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class InventoryHistoryResource extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Ecommerce\Product\Inventory\InventoryHistory>
|
||||
*/
|
||||
public static $model = InventoryHistory::class;
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['channel', 'inventory'];
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'code';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Inventory entries');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Inventory entry');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
if ($user->hasRole('vendor')) {
|
||||
$query->where('channel_id', $user->channel()->id);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after creation.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterCreate(NovaRequest $request, $resource): string
|
||||
{
|
||||
return 'resources/inventories/'.$resource->inventory_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Date::make(__('Date'), 'date')
|
||||
->rules('required')
|
||||
->displayUsing(fn ($value) => $value->format('d.m.Y'))
|
||||
->readonly(fn ($request) => $request->isUpdateOrUpdateAttachedRequest())
|
||||
->default(now()->toDate())
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('R. Number'), 'number')
|
||||
->rules('required')
|
||||
->readonly(fn ($request) => $request->isUpdateOrUpdateAttachedRequest())
|
||||
->sortable(),
|
||||
|
||||
BelongsTo::make(__('Inventory'), 'inventory', Inventory::class),
|
||||
BelongsTo::make(__('Channel'), 'channel', Channel::class),
|
||||
|
||||
Text::make(__('Notes'), 'notes')
|
||||
->rules('nullable', 'string', 'max:255')
|
||||
->hideFromIndex(),
|
||||
|
||||
Text::make(__('Total'), fn () => $this->total),
|
||||
|
||||
Text::make(__('Total'), 'readonly_total')
|
||||
->onlyOnForms()
|
||||
->readonly(),
|
||||
|
||||
Repeater::make('Options', 'options')
|
||||
->repeatables([
|
||||
InventoryHistoryItemRepeater::make(),
|
||||
])
|
||||
->asJson()
|
||||
->fullWidth()
|
||||
->hideWhenUpdating(),
|
||||
|
||||
HasMany::make(__('Items'), 'items', InventoryHistoryItemResource::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be called after the resource is created.
|
||||
*/
|
||||
public static function afterCreate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
$total = 0;
|
||||
$request->collect('options')->each(function ($item) use ($model, &$total) {
|
||||
$total = floatval($total) + floatval($item['fields']['total']);
|
||||
|
||||
$model->items()->create([
|
||||
'product_id' => $item['fields']['product_id'],
|
||||
'quantity' => $item['fields']['quantity'],
|
||||
'total' => floatval($item['fields']['total']),
|
||||
'cost_amount' => $item['fields']['cost_amount'],
|
||||
]);
|
||||
|
||||
$product = Product::find($item['fields']['product_id']);
|
||||
|
||||
$inventoryRecordQuery = DB::table('inventory_product')
|
||||
->where('product_id', $product->id)
|
||||
->where('inventory_id', $model->inventory_id);
|
||||
|
||||
$inventoryRecord = $inventoryRecordQuery->first();
|
||||
|
||||
$inventoryRecord
|
||||
? $inventoryRecordQuery->update([
|
||||
'stock' => intval($inventoryRecord->stock) + intval($item['fields']['quantity']),
|
||||
]) : DB::table('inventory_product')->insert([
|
||||
'product_id' => $product->id,
|
||||
'inventory_id' => $model->inventory_id,
|
||||
'stock' => intval($item['fields']['quantity']),
|
||||
]);
|
||||
|
||||
$product->updateQuietly([
|
||||
'stock' => $product->inventories()->sum('inventory_product.stock'),
|
||||
]);
|
||||
});
|
||||
|
||||
$model->updateQuietly(['total' => $total]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current user can update the given resource.
|
||||
*/
|
||||
public function authorizedToUpdate(Request $request): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the current user can delete the given resource.
|
||||
*/
|
||||
public function authorizedToDelete(Request $request): bool
|
||||
{
|
||||
if (auth()->user()->isMe()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Inventory\Product;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product;
|
||||
use App\Nova\Fields\FieldHelpers;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Brand\Brand;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class ProductResource extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<Product>
|
||||
*/
|
||||
public static $model = Product::class;
|
||||
|
||||
/**
|
||||
* The number of resources to show per page via relationships.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public static $perPageViaRelationship = 20;
|
||||
|
||||
/**
|
||||
* The pagination per-page options configured for this resource.
|
||||
*/
|
||||
public static function perPageOptions(): array
|
||||
{
|
||||
return [50, 100, 150];
|
||||
}
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['brand', 'media'];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Product');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Products');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query): Builder
|
||||
{
|
||||
return $query->where('parent_id', null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fields
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
Images::make(__('Image'), 'uploads')->conversionOnIndexView('thumb200x200'),
|
||||
Text::make(__('Name'), fn () => $this->novaDetailPage())
|
||||
->displayUsing(FieldHelpers::asLink(
|
||||
link: $this->novaDetailPage(),
|
||||
title: $this->name
|
||||
))
|
||||
->asHtml(),
|
||||
|
||||
BelongsTo::make(__('Brand'), 'brand', Brand::class)->sortable(),
|
||||
Number::make(__('Price'), 'cost_amount')->sortable(),
|
||||
Text::make(__('SKU'), 'sku')->sortable(),
|
||||
Text::make(__('Total count'), FieldHelpers::formatQuantity())->asHtml(),
|
||||
Text::make(__('Giriş çykyş boýunça'), FieldHelpers::formatQuantity(
|
||||
intval(DB::table('inventory_history_items')->where('product_id', $this->id)->sum('quantity'))
|
||||
-
|
||||
intval(DB::table('inventory_history_removed_items')->where('product_id', $this->id)->sum('quantity'))
|
||||
))->asHtml(),
|
||||
|
||||
Boolean::make(__('Active'), 'is_visible')
|
||||
->sortable()
|
||||
->canSeeWhen('isVendor', $this),
|
||||
|
||||
NovaSwitcher::make(__('Is visible'), 'is_visible')
|
||||
->sortable()
|
||||
->canSeeWhen('isAdmin', $this),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\Actions;
|
||||
|
||||
use App\Models\Ecommerce\Payouts\Payout;
|
||||
use App\Models\User;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Nova\Actions\Action;
|
||||
use Laravel\Nova\Fields\ActionFields;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use PhpOffice\PhpWord\SimpleType\TblWidth;
|
||||
|
||||
class ExportEvidenceForProducts extends Action
|
||||
{
|
||||
use InteractsWithQueue, Queueable;
|
||||
|
||||
/**
|
||||
* The displayable name of the action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Evidence for products');
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the action on the given models.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle(ActionFields $fields, Collection $models)
|
||||
{
|
||||
$payout = $models->first();
|
||||
$orderItems = $payout->orderItems;
|
||||
$channel = $payout->channel;
|
||||
$user = $channel->user;
|
||||
|
||||
exec('rm -rf app-docs/*');
|
||||
|
||||
$documentsPath = 'app-docs/'.Str::random();
|
||||
exec("mkdir {$documentsPath}");
|
||||
|
||||
$this->generatePriceNegotiationDocument($user, $payout, $orderItems, $documentsPath);
|
||||
$this->generateEvidenceForProductsDocument($user, $payout, $orderItems, $documentsPath);
|
||||
|
||||
return Action::openInNewTab(route('user.docs', ['folder' => $documentsPath]));
|
||||
}
|
||||
|
||||
protected function generatePriceNegotiationDocument(User $user, Payout $payout, Collection $orderItems, string $folder): void
|
||||
{
|
||||
$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor(resource_path('docs/order/evidence-price-negotiation.docx'));
|
||||
$templateProcessor->setValues([
|
||||
'year' => date('Y'),
|
||||
'product_owner' => $user->companyName(),
|
||||
]);
|
||||
|
||||
$table = new \PhpOffice\PhpWord\Element\Table([
|
||||
'borderSize' => 2,
|
||||
'borderColor' => 'black',
|
||||
'width' => 5000,
|
||||
'width' => 6000,
|
||||
'unit' => TblWidth::TWIP,
|
||||
]);
|
||||
$table->addRow();
|
||||
$table->addCell()->addText('');
|
||||
$table->addCell()->addText('Harydyň ady');
|
||||
$table->addCell()->addText('Komitentiň satyş bahasy, manat');
|
||||
$table->addCell()->addText('Komissioneriň satyş bahasy, manat');
|
||||
|
||||
$i = 0;
|
||||
$total_cost_amount = 0;
|
||||
$total_unit_price_amount = 0;
|
||||
foreach ($orderItems as $orderItem) {
|
||||
$i++;
|
||||
$table->addRow();
|
||||
|
||||
$table->addCell()->addText($i);
|
||||
$table->addCell()->addText($orderItem->product_name);
|
||||
$table->addCell()->addText($orderItem->unit_cost_amount);
|
||||
$table->addCell()->addText($orderItem->unit_price_amount);
|
||||
|
||||
$total_cost_amount += $orderItem->unit_cost_amount;
|
||||
$total_unit_price_amount += $orderItem->unit_price_amount;
|
||||
}
|
||||
|
||||
$table->addRow();
|
||||
$table->addCell()->addText();
|
||||
$table->addCell()->addText('Jemi');
|
||||
$table->addCell()->addText($total_cost_amount);
|
||||
$table->addCell()->addText($total_unit_price_amount);
|
||||
|
||||
$templateProcessor->setComplexBlock('products_table', $table);
|
||||
|
||||
$documentPath = "{$folder}/hasaplashyk-{$payout->id}-{$user->companyName()}-baha-ylalashyk.docx";
|
||||
$templateProcessor->saveAs(public_path($documentPath));
|
||||
}
|
||||
|
||||
public function generateEvidenceForProductsDocument(User $user, Payout $payout, Collection $orderItems, string $folder): void
|
||||
{
|
||||
$templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor(resource_path('docs/order/evidence.docx'));
|
||||
$templateProcessor->setValues([
|
||||
'date' => date('Y'),
|
||||
'o_date' => $payout->created_at->format('d.m.Y'),
|
||||
'product_owner' => $user->companyName(),
|
||||
]);
|
||||
|
||||
$table = new \PhpOffice\PhpWord\Element\Table([
|
||||
'borderSize' => 2,
|
||||
'borderColor' => 'black',
|
||||
'width' => 5000,
|
||||
'width' => 6000,
|
||||
'unit' => TblWidth::TWIP,
|
||||
]);
|
||||
$table->addRow();
|
||||
$table->addCell()->addText('No');
|
||||
$table->addCell()->addText('Harydyň ady');
|
||||
$table->addCell()->addText('Mukdary, san');
|
||||
$table->addCell()->addText('Biriniň bahasy, manat');
|
||||
$table->addCell()->addText('Jemi bahasy, manat');
|
||||
|
||||
$i = 0;
|
||||
$total_price = 0;
|
||||
foreach ($orderItems as $orderItem) {
|
||||
$i++;
|
||||
$table->addRow();
|
||||
|
||||
$table->addCell()->addText($i);
|
||||
$table->addCell()->addText($orderItem->product_name);
|
||||
$table->addCell()->addText($orderItem->quantity);
|
||||
$table->addCell()->addText($orderItem->unit_cost_amount);
|
||||
$table->addCell()->addText($orderItem->unit_cost_amount * $orderItem->quantity);
|
||||
|
||||
$total_price += $orderItem->unit_cost_amount * $orderItem->quantity;
|
||||
}
|
||||
|
||||
$table->addRow();
|
||||
$table->addCell()->addText('');
|
||||
$table->addCell()->addText('Jemi');
|
||||
$table->addCell()->addText($i);
|
||||
$table->addCell()->addText();
|
||||
$table->addCell()->addText($total_price);
|
||||
|
||||
$templateProcessor->setComplexBlock('products_table', $table);
|
||||
|
||||
$documentPath = "{$folder}/sargyt-{$payout->id}-{$user->companyName()}-delilnama.docx";
|
||||
$templateProcessor->saveAs(public_path($documentPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields available on the action.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\Actions;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Order;
|
||||
use App\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Collection;
|
||||
use Laravel\Nova\Actions\Action;
|
||||
use Laravel\Nova\Actions\ActionResponse;
|
||||
use Laravel\Nova\Fields\ActionFields;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use PhpOffice\PhpWord\Element\Table;
|
||||
use PhpOffice\PhpWord\SimpleType\TblWidth;
|
||||
use PhpOffice\PhpWord\TemplateProcessor;
|
||||
|
||||
class ExportOrderInvoiceAction extends Action
|
||||
{
|
||||
use InteractsWithQueue, Queueable;
|
||||
|
||||
/**
|
||||
* The displayable name of the action.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Invoice');
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the action on the given models.
|
||||
*/
|
||||
public function handle(ActionFields $fields, Collection $models): mixed
|
||||
{
|
||||
if ($models->count() !== 1) {
|
||||
return Action::danger(
|
||||
__('Please run this on only one user resource')
|
||||
);
|
||||
}
|
||||
|
||||
$order = $models->first();
|
||||
$products = $order
|
||||
->items()
|
||||
->with(['channel', 'product'])
|
||||
->get();
|
||||
|
||||
$documentPath = $this->generateDocument(
|
||||
order: $order,
|
||||
products: $products,
|
||||
templatePath: resource_path('docs/order/invoice.docx'),
|
||||
productsTotal: $products->sum('total')
|
||||
);
|
||||
|
||||
return ActionResponse::download(
|
||||
name: sprintf('sargyt-%s.docx', $order->id),
|
||||
url: url($documentPath)
|
||||
);
|
||||
}
|
||||
|
||||
private function generateDocument(
|
||||
Order $order,
|
||||
Collection $products,
|
||||
string $templatePath,
|
||||
float $productsTotal
|
||||
): string {
|
||||
$templateProcessor = new TemplateProcessor($templatePath);
|
||||
|
||||
$templateProcessor->setValues([
|
||||
'id' => $order->id,
|
||||
'payment_type' => $order->formattedPaymentType(),
|
||||
'created_at' => $order->created_at->format('H:i, d.m.Y'),
|
||||
'order_shipping_method' => $order->formattedShippingMethod(),
|
||||
|
||||
'shipping_price' => $order->shipping_method === OrderShipping::SELF_PICKUP
|
||||
? 'Özüm baryp aljak'
|
||||
: (string) $order->shippingPrice().' TMT',
|
||||
|
||||
'order_name' => $order->customer_name,
|
||||
'order_address' => $order->fullAddress(),
|
||||
'order_phone' => $order->customer_phone,
|
||||
'p_t' => $productsTotal,
|
||||
't' => $productsTotal + $order->shippingPrice(),
|
||||
'notes' => $order->notes,
|
||||
'adt_tax' => $order->additional_tax ?: '0.0',
|
||||
]);
|
||||
|
||||
$table = $this->generateTable($products);
|
||||
$templateProcessor->setComplexBlock('products_table', $table);
|
||||
|
||||
$documentPath = public_path(
|
||||
sprintf('app-docs/sargyt-%s.docx', $order->id)
|
||||
);
|
||||
$templateProcessor->saveAs($documentPath);
|
||||
|
||||
return sprintf('app-docs/sargyt-%s.docx', $order->id);
|
||||
}
|
||||
|
||||
private function generateTable(Collection $products): Table
|
||||
{
|
||||
$table = new Table([
|
||||
'borderSize' => 2,
|
||||
'borderColor' => 'black',
|
||||
'width' => 5000,
|
||||
'unit' => TblWidth::PERCENT,
|
||||
]);
|
||||
|
||||
$table->addRow();
|
||||
$table->addCell()->addText('№');
|
||||
$table->addCell()->addText('HARYDYŇ ADY');
|
||||
$table->addCell()->addText('BAHASY');
|
||||
$table->addCell()->addText('SATYJY');
|
||||
$table->addCell()->addText('MUKDARY');
|
||||
$table->addCell()->addText('ARZANLADYŞ');
|
||||
$table->addCell()->addText('JEMI BAHASY');
|
||||
|
||||
$products->each(function ($product, $index) use ($table) {
|
||||
$table->addRow();
|
||||
$table->addCell()->addText($index + 1);
|
||||
$table->addCell()->addText($product->product->name);
|
||||
$table->addCell()->addText($product->unit_price_amount);
|
||||
$table
|
||||
->addCell()
|
||||
->addText($product->channel?->name ?? 'Türkmenpoçta PAK');
|
||||
$table->addCell()->addText($product->quantity);
|
||||
$table
|
||||
->addCell()
|
||||
->addText(
|
||||
$product->product->caluculateDiscountDifference(
|
||||
$product->unit_price_amount
|
||||
)
|
||||
);
|
||||
$table
|
||||
->addCell()
|
||||
->addText($product->quantity * $product->unit_price_amount);
|
||||
});
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields available on the action.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\Actions;
|
||||
|
||||
use App\Exports\Ecommerce\Product\Order\ExportOrderReport;
|
||||
use App\Nova\Fields\FieldHelpers;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Laravel\Nova\Actions\Action;
|
||||
use Laravel\Nova\Fields\ActionFields;
|
||||
use Laravel\Nova\Fields\Date;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class ExportOrderReportAction extends Action
|
||||
{
|
||||
use InteractsWithQueue, Queueable;
|
||||
|
||||
/**
|
||||
* Get the displayable name of the action.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Export Order Report');
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the action on the given models.
|
||||
*/
|
||||
public function handle(ActionFields $fields, Collection $models): mixed
|
||||
{
|
||||
$start_date = Carbon::createFromFormat('Y-m-d', $fields->start_date)->format('d.m.Y');
|
||||
$end_date = Carbon::createFromFormat('Y-m-d', $fields->end_date)->format('d.m.Y');
|
||||
|
||||
(new ExportOrderReport(
|
||||
start_date: $fields->start_date,
|
||||
end_date: $fields->end_date
|
||||
))->store('order-reports.xlsx', 'order_reports');
|
||||
|
||||
return Action::download(
|
||||
url: Storage::disk('order_reports')->url('order-reports.xlsx'),
|
||||
name: sprintf('Hasabat %s - %s.xlsx', $start_date, $end_date)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields available on the action.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
Date::make(__('Start date'), 'start_date')
|
||||
->rules('required')
|
||||
->displayUsing(FieldHelpers::tmDate()),
|
||||
|
||||
Date::make(__('End date'), 'end_date')
|
||||
->rules('required')
|
||||
->displayUsing(FieldHelpers::tmDate()),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\Concerns;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use App\Models\System\Settings\Location\Region;
|
||||
use App\Nova\Fields\FieldHelpers;
|
||||
use Laravel\Nova\Fields\Badge;
|
||||
use Laravel\Nova\Fields\Date;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
trait HasFieldsForIndex
|
||||
{
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fieldsForIndex(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Customer'), 'customer_name')
|
||||
->canSeeWhen('systemUser', $this)
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Phone'), 'customer_phone')
|
||||
->canSeeWhen('systemUser', $this)
|
||||
->sortable(),
|
||||
|
||||
Select::make(__('Welaýat'), 'region')
|
||||
->displayUsingLabels()
|
||||
->options(Region::values())
|
||||
->canSeeWhen('systemUser', $this)
|
||||
->sortable(),
|
||||
|
||||
Select::make(__('Delivery time'), 'delivery_time')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OrderShipping::times())
|
||||
->rules('required')
|
||||
->sortable(),
|
||||
|
||||
Date::make(__('Delivery date'), 'delivery_at')
|
||||
->displayUsing(FieldHelpers::tmDate())
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Total'), fn () => $this->resource->fullPriceWithShipping().' TMT')
|
||||
->canSeeWhen('systemUser', $this)
|
||||
->sortable(),
|
||||
|
||||
Badge::make('Status')->map(OrderStatus::classes())->addTypes([
|
||||
'primary' => 'dark:bg-gray-900 bg-gray-600 text-white',
|
||||
])->labels(OrderStatus::values())->sortable(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\Concerns;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Payment\OrderPayment;
|
||||
use App\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use App\Models\System\Settings\Location\Province;
|
||||
use App\Models\System\Settings\Location\Region;
|
||||
use App\Models\System\Settings\OS;
|
||||
use App\Repositories\Ecommerce\Order\NovaOrderRepository;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Nova\Fields\Date;
|
||||
use Laravel\Nova\Fields\Hidden;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Nurmuhammet\NovaInputmask\NovaInputmask;
|
||||
|
||||
class OrderFieldsForCreate
|
||||
{
|
||||
/**
|
||||
* Order fields for create
|
||||
*/
|
||||
public static function make($resource, $request): array
|
||||
{
|
||||
return [
|
||||
Hidden::make('number')->default(Str::random(30)),
|
||||
Hidden::make('user_id')->default($request->user()->id),
|
||||
Hidden::make('source_app')->default(OS::ADMIN),
|
||||
|
||||
ID::make(),
|
||||
|
||||
Text::make(__('Customer name'), 'customer_name')
|
||||
->rules('nullable', 'string', 'max:255')
|
||||
->canSeeWhen('systemUser', $resource)
|
||||
->default('Walk in customer'),
|
||||
|
||||
NovaInputmask::make(__('Customer phone'), 'customer_phone')
|
||||
->mask(phoneMaskFormat())
|
||||
->storeRawValue()
|
||||
->canSeeWhen('systemUser', $resource),
|
||||
|
||||
Select::make(__('Region'), 'region')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(Region::values())
|
||||
->default(Region::default())
|
||||
->canSeeWhen('systemUser', $resource),
|
||||
|
||||
Select::make(__('Province'), 'province_id')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->dependsOn(['region'], NovaOrderRepository::dependsOnWhere('region', Province::class)),
|
||||
|
||||
Text::make(__('Customer address'), 'customer_address')
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
|
||||
Select::make(__('Payment type'), 'payment_type_id')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OrderPayment::values())
|
||||
->default(OrderPayment::default()),
|
||||
|
||||
Select::make(__('Shipping method'), 'shipping_method')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OrderShipping::values())
|
||||
->default(OrderShipping::default())
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Shipping price'), 'shipping_price')
|
||||
->rules('required', 'numeric')
|
||||
->dependsOn('shipping_method', function ($field, $request, $formData) {
|
||||
if ($formData->shipping_method) {
|
||||
$field->setValue(OrderShipping::priceFor($formData->shipping_method));
|
||||
}
|
||||
}),
|
||||
|
||||
Date::make(__('Delivery at'), 'delivery_at')
|
||||
->default(date('Y-m-d'))
|
||||
->rules('required'),
|
||||
|
||||
Select::make(__('Delivery time'), 'delivery_time')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OrderShipping::times())
|
||||
->default(OrderShipping::defaultTime()),
|
||||
|
||||
Text::make(__('Additional tax'), 'additional_tax')
|
||||
->rules('nullable', 'numeric'),
|
||||
|
||||
Select::make(__('Status'), 'status')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OrderStatus::values())
|
||||
->default(OrderStatus::default()),
|
||||
|
||||
Text::make(__('Notes'), 'notes')
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\Concerns;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use App\Models\System\Settings\OS;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\OrderItem;
|
||||
use App\Nova\Resources\System\Payments\PaymentType;
|
||||
use App\Nova\User;
|
||||
use Laravel\Nova\Fields\Badge;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\DateTime;
|
||||
use Laravel\Nova\Fields\HasMany;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Nurmuhammet\NovaInputmask\NovaInputmask;
|
||||
|
||||
class OrderFieldsForDetail
|
||||
{
|
||||
/**
|
||||
* Order fields for detail
|
||||
*/
|
||||
public static function make($resource, $request): array
|
||||
{
|
||||
// nova has a wierd bug, can load detail fields while on Index
|
||||
if (! $request->isResourceDetailRequest()) {
|
||||
if ($request->viaResource && $request->viaRelationship && $request->relationshipType) {
|
||||
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Customer name'), 'customer_name'),
|
||||
|
||||
NovaInputmask::make(__('Customer phone'), 'customer_phone')
|
||||
->mask(phoneMaskFormat())
|
||||
->storeRawValue(),
|
||||
|
||||
Text::make(
|
||||
name: __('Address'),
|
||||
attribute: fn ($model) => view('vendor.nova.resources.order.create-fields.address', [
|
||||
'model' => $model,
|
||||
])->render()
|
||||
)
|
||||
->asHtml(),
|
||||
|
||||
BelongsTo::make(__('Payment type'), 'paymentType', PaymentType::class),
|
||||
|
||||
Text::make(
|
||||
name: __('Shipping'),
|
||||
attribute: fn ($model) => view('vendor.nova.resources.order.create-fields.shipping', [
|
||||
'model' => $model,
|
||||
])->render()
|
||||
)
|
||||
->asHtml(),
|
||||
|
||||
Text::make(
|
||||
name: __('Shipping time'),
|
||||
attribute: fn ($model) => view('vendor.nova.resources.order.create-fields.shipping-time', [
|
||||
'model' => $model,
|
||||
])->render()
|
||||
)
|
||||
->asHtml(),
|
||||
|
||||
Select::make(__('App'), 'source_app')
|
||||
->displayUsingLabels()
|
||||
->options(OS::apps())
|
||||
->sortable(),
|
||||
|
||||
Badge::make('Status')->map(OrderStatus::classes())->addTypes([
|
||||
'primary' => 'dark:bg-gray-900 bg-gray-600 text-white',
|
||||
])->labels(OrderStatus::values())->sortable(),
|
||||
|
||||
Text::make(__('Notes'), 'notes'),
|
||||
|
||||
Text::make(__('Additional tax'), fn () => $resource->additional_tax.' TMT')
|
||||
->canSeeWhen('systemUser', $resource),
|
||||
|
||||
Text::make(__('Products total'), fn () => $resource->total().' TMT')
|
||||
->canSeeWhen('systemUser', $resource),
|
||||
|
||||
Text::make(__('Total'), fn () => $resource->fullPriceWithShipping().' TMT')
|
||||
->canSeeWhen('systemUser', $resource),
|
||||
|
||||
DateTime::make(__('Created at'), 'created_at')
|
||||
->turkmenDate(),
|
||||
|
||||
BelongsTo::make(__('Filled by:'), 'user', User::class),
|
||||
|
||||
HasMany::make(__('Products'), 'items', OrderItem::class),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\Concerns;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use App\Models\System\Settings\Location\Region;
|
||||
use App\Models\System\Settings\OS;
|
||||
use App\Nova\Fields\FieldHelpers;
|
||||
use Laravel\Nova\Fields\Badge;
|
||||
use Laravel\Nova\Fields\Date;
|
||||
use Laravel\Nova\Fields\DateTime;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Nurmuhammet\NovaInputmask\NovaInputmask;
|
||||
|
||||
class OrderFieldsForIndex
|
||||
{
|
||||
/**
|
||||
* Fields for index
|
||||
*/
|
||||
public static function make($resource, $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Customer'), 'customer_name')
|
||||
->sortable(),
|
||||
|
||||
NovaInputmask::make(__('Customer phone'), 'customer_phone')
|
||||
->mask(phoneMaskFormat())
|
||||
->storeRawValue()
|
||||
->sortable(),
|
||||
|
||||
Select::make(__('Welaýat'), 'region')
|
||||
->displayUsingLabels()
|
||||
->options(Region::values())
|
||||
->sortable(),
|
||||
|
||||
Select::make(__('Delivery time'), 'delivery_time')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OrderShipping::times())
|
||||
->rules('required')
|
||||
->sortable(),
|
||||
|
||||
Date::make(__('Delivery date'), 'delivery_at')
|
||||
->displayUsing(FieldHelpers::tmDate())
|
||||
->sortable(),
|
||||
|
||||
Select::make(__('Shipping method'), 'shipping_method')
|
||||
->displayUsingLabels()
|
||||
->options(OrderShipping::values())
|
||||
->default(OrderShipping::default())
|
||||
->sortable(),
|
||||
|
||||
Select::make(__('Source'), 'source_app')
|
||||
->displayUsingLabels()
|
||||
->options(OS::apps())
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Total'), fn () => $resource->fullPriceWithShipping().' TMT')
|
||||
->canSeeWhen('systemUser', $resource)
|
||||
->sortable(),
|
||||
|
||||
DateTime::make(__('Created at'), 'created_at')
|
||||
->turkmenDate(),
|
||||
|
||||
Badge::make('Status')
|
||||
->map(OrderStatus::classes())
|
||||
->labels(OrderStatus::values())
|
||||
->addTypes([
|
||||
'primary' => 'dark:bg-gray-900 bg-gray-600 text-white',
|
||||
])
|
||||
->sortable(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\Concerns;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Payment\OrderPayment;
|
||||
use App\Models\Ecommerce\Product\Order\Shipping\OrderShipping;
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use App\Models\System\Settings\Location\Province;
|
||||
use App\Models\System\Settings\Location\Region;
|
||||
use App\Repositories\Ecommerce\Order\NovaOrderRepository;
|
||||
use Laravel\Nova\Fields\Date;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Nurmuhammet\NovaInputmask\NovaInputmask;
|
||||
|
||||
class OrderFieldsForUpdate
|
||||
{
|
||||
/**
|
||||
* Order
|
||||
*/
|
||||
public static function make($resource, $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Customer name'), 'customer_name')
|
||||
->rules('nullable', 'string', 'max:255')
|
||||
->canSeeWhen('systemUser', $resource),
|
||||
|
||||
NovaInputmask::make(__('Customer phone'), 'customer_phone')
|
||||
->mask(phoneMaskFormat())
|
||||
->storeRawValue()
|
||||
->canSeeWhen('systemUser', $resource),
|
||||
|
||||
Select::make(__('Region'), 'region')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(Region::values())
|
||||
->default(Region::default())
|
||||
->canSeeWhen('systemUser', $resource),
|
||||
|
||||
Select::make(__('Province'), 'province_id')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->dependsOn(['region'], NovaOrderRepository::dependsOnWhere('region', Province::class)),
|
||||
|
||||
Text::make(__('Customer address'), 'customer_address')
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
|
||||
Select::make(__('Payment type'), 'payment_type_id')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OrderPayment::values())
|
||||
->default(OrderPayment::default()),
|
||||
|
||||
Select::make(__('Shipping method'), 'shipping_method')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OrderShipping::values())
|
||||
->default(OrderShipping::default())
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Shipping price'), 'shipping_price')
|
||||
->rules('required', 'numeric')
|
||||
->dependsOn('shipping_method', function ($field, $request, $formData) use ($resource) {
|
||||
if ($formData->shipping_price) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($formData->shipping_method) {
|
||||
$field->setValue(OrderShipping::orderShippingPrice($resource));
|
||||
}
|
||||
}),
|
||||
|
||||
Text::make(__('Additional tax'), 'additional_tax')
|
||||
->rules('nullable', 'numeric'),
|
||||
|
||||
Date::make(__('Delivery at'), 'delivery_at')
|
||||
->default(date('Y-m-d'))
|
||||
->rules('required'),
|
||||
|
||||
Select::make(__('Delivery time'), 'delivery_time')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OrderShipping::times())
|
||||
->default(OrderShipping::defaultTime()),
|
||||
|
||||
Select::make(__('Status'), 'status')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OrderStatus::values())
|
||||
->default(OrderStatus::default()),
|
||||
|
||||
Text::make(__('Notes'), 'notes')
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\Metrics;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Order;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Metrics\Value;
|
||||
|
||||
class NewOrders extends Value
|
||||
{
|
||||
/**
|
||||
* Calculate the value of the metric.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function calculate(NovaRequest $request)
|
||||
{
|
||||
if ($request->user()->hasRole('vendor')) {
|
||||
$channel = $request->user()->channel();
|
||||
|
||||
$vendor_orders = DB::table('order_items')->where('channel_id', $channel->id)->pluck('order_id');
|
||||
|
||||
return $this->count($request, Order::whereIntegerInRaw('id', $vendor_orders));
|
||||
}
|
||||
|
||||
return $this->count($request, Order::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ranges available for the metric.
|
||||
*/
|
||||
public function ranges(): array
|
||||
{
|
||||
return [
|
||||
'TODAY' => __('Today'),
|
||||
30 => __('30 Days'),
|
||||
60 => __('60 Days'),
|
||||
365 => __('365 Days'),
|
||||
'MTD' => __('Month To Date'),
|
||||
'QTD' => __('Quarter To Date'),
|
||||
'YTD' => __('Year To Date'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the amount of time the results of the metric should be cached.
|
||||
*
|
||||
* @return \DateTimeInterface|\DateInterval|float|int|null
|
||||
*/
|
||||
public function cacheFor()
|
||||
{
|
||||
return now()->addMinutes(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URI key for the metric.
|
||||
*/
|
||||
public function uriKey(): string
|
||||
{
|
||||
return 'orders-new-orders';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable name of the metric
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Orders');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\Metrics;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Order;
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use DateTimeInterface;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Metrics\Partition;
|
||||
|
||||
class OrdersPerStatus extends Partition
|
||||
{
|
||||
/**
|
||||
* Calculate the value of the metric.
|
||||
*/
|
||||
public function calculate(NovaRequest $request): mixed
|
||||
{
|
||||
$model = Order::class;
|
||||
|
||||
if ($request->user()->hasRole('vendor')) {
|
||||
$channel = $request->user()->channel();
|
||||
$vendor_orders = DB::table('order_items')->where('channel_id', $channel->id)->pluck('order_id');
|
||||
|
||||
$model = Order::whereIntegerInRaw('id', $vendor_orders);
|
||||
}
|
||||
|
||||
return $this->count($request, $model, 'status')
|
||||
->colors(OrderStatus::colors())
|
||||
->label(fn ($value) => OrderStatus::formattedStatusFor($value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the amount of time the results of the metric should be cached.
|
||||
*
|
||||
* @return \DateTimeInterface|\DateInterval|float|int|null
|
||||
*/
|
||||
public function cacheFor(): DateTimeInterface|DateInterval|float|int|null
|
||||
{
|
||||
return now()->addMinutes(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URI key for the metric.
|
||||
*/
|
||||
public function uriKey(): string
|
||||
{
|
||||
return 'orders-orders-per-status';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable name of the metric
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Order Per Status');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\Metrics;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\OrderItem;
|
||||
use DateTimeInterface;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Metrics\Trend;
|
||||
|
||||
class ProductSoldPerDay extends Trend
|
||||
{
|
||||
/**
|
||||
* Calculate the value of the metric.
|
||||
*/
|
||||
public function calculate(NovaRequest $request): mixed
|
||||
{
|
||||
if ($request->user()->hasRole('vendor')) {
|
||||
$channel = $request->user()->channel();
|
||||
|
||||
return $this->countByDays($request, OrderItem::where('channel_id', $channel->id))->showLatestValue();
|
||||
}
|
||||
|
||||
return $this->countByDays($request, OrderItem::class)->showLatestValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ranges available for the metric.
|
||||
*/
|
||||
public function ranges(): array
|
||||
{
|
||||
return [
|
||||
30 => __('30 Days'),
|
||||
60 => __('60 Days'),
|
||||
90 => __('90 Days'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the amount of time the results of the metric should be cached.
|
||||
*
|
||||
* @return \DateTimeInterface|\DateInterval|float|int|null
|
||||
*/
|
||||
public function cacheFor(): DateTimeInterface|DateInterval|float|int|null
|
||||
{
|
||||
return now()->addMinutes(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URI key for the metric.
|
||||
*/
|
||||
public function uriKey(): string
|
||||
{
|
||||
return 'orders-product-sold-per-day';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable name of the metric
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Product Sold Per Day');
|
||||
}
|
||||
}
|
||||
214
app/Nova/Resources/Ecommerce/Product/Order/Order.php
Normal file
214
app/Nova/Resources/Ecommerce/Product/Order/Order.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\Order as OrderModel;
|
||||
use App\Models\Ecommerce\Product\Order\Status\OrderStatus;
|
||||
use App\Nova\Filters\RegionFilter;
|
||||
use App\Nova\Filters\StatusFilter;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\Actions\ExportOrderInvoiceAction;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\Actions\ExportOrderReportAction;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\Concerns\OrderFieldsForCreate;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\Concerns\OrderFieldsForDetail;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\Concerns\OrderFieldsForIndex;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\Concerns\OrderFieldsForUpdate;
|
||||
use App\Repositories\CMS\Icon\IconRepository;
|
||||
use DigitalCreative\ColumnToggler\ColumnTogglerTrait;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Fields\HasMany;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Order extends Resource
|
||||
{
|
||||
use ColumnTogglerTrait;
|
||||
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $model = OrderModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'id';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'customer_name', 'customer_phone',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Orders');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Order');
|
||||
}
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['items'];
|
||||
|
||||
/**
|
||||
* Indicates whether the resource should automatically poll for new resources.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $polling = true;
|
||||
|
||||
/**
|
||||
* The interval at which Nova should poll for new resources.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public static $pollingInterval = 120;
|
||||
|
||||
/**
|
||||
* Indicates whether to show the polling toggle button inside Nova.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $showPollingToggle = true;
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query)
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
if ($user->hasRole('vendor')) {
|
||||
$order_ids = DB::table('order_items')->where('channel_id', $user->channel()->id)->distinct()->pluck('order_id');
|
||||
|
||||
$query->whereIntegerInRaw('id', $order_ids);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* After order was updated
|
||||
*/
|
||||
public static function afterUpdate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
if ($model->status === OrderStatus::CANCELLED) {
|
||||
$orderItems = $model->items()->with('product')->get(['id', 'product_id', 'order_id', 'quantity']);
|
||||
|
||||
$orderItems->each(function ($item) {
|
||||
$item->product->update([
|
||||
'stock' => intval($item->product->stock) + intval($item->quantity),
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields for index.
|
||||
*/
|
||||
public function fieldsForIndex(NovaRequest $request): array
|
||||
{
|
||||
return OrderFieldsForIndex::make($this, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields for create.
|
||||
*/
|
||||
public function fieldsForCreate(NovaRequest $request): array
|
||||
{
|
||||
return OrderFieldsForCreate::make($this, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource on detail page.
|
||||
*/
|
||||
public function fieldsForDetail(NovaRequest $request): array
|
||||
{
|
||||
return OrderFieldsForDetail::make($this, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource on detail page.
|
||||
*/
|
||||
public function fieldsForUpdate(NovaRequest $request): array
|
||||
{
|
||||
return OrderFieldsForUpdate::make($this, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
HasMany::make(__('Products'), 'items', OrderItem::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*/
|
||||
public function actions(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ExportOrderReportAction::make()
|
||||
->standalone()
|
||||
->canSeeWhen('isAdmin', $this)
|
||||
->onlyOnIndex()
|
||||
->icon(IconRepository::make()->documentReport()),
|
||||
|
||||
ExportOrderInvoiceAction::make()
|
||||
->confirmText(__('Are you sure you want to run this action?'))
|
||||
->confirmButtonText(__('Yes'))
|
||||
->cancelButtonText(__('No'))
|
||||
->exceptOnIndex()
|
||||
->icon(IconRepository::make()->documentDownload()),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*/
|
||||
public function filters(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
RegionFilter::make(),
|
||||
StatusFilter::make(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*/
|
||||
public function lenses(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
|
||||
];
|
||||
}
|
||||
}
|
||||
173
app/Nova/Resources/Ecommerce/Product/Order/OrderItem.php
Normal file
173
app/Nova/Resources/Ecommerce/Product/Order/OrderItem.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order;
|
||||
|
||||
use App\Models\Ecommerce\Product\Order\OrderItem as OrderItemModel;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\OrderItem\OrderItemFieldsForCreate;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\OrderItem\OrderItemFieldsForIndex;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\OrderItem\OrderItemFieldsForUpdate;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class OrderItem extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<OrderItemModel>
|
||||
*/
|
||||
public static $model = OrderItemModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'id';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id',
|
||||
];
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
// public static $with = ['product', 'product.media'];
|
||||
|
||||
/**
|
||||
* The number of resources to show per page via relationships.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public static $perPageViaRelationship = 20;
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query): Builder
|
||||
{
|
||||
$user = $request->user();
|
||||
|
||||
if ($user->hasRole('vendor')) {
|
||||
$query->with(['product', 'product.media'])
|
||||
->where('channel_id', $request->user()->channel()->id);
|
||||
} else {
|
||||
$query->with(['product', 'product.media', 'channel']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields for index.
|
||||
*/
|
||||
public function fieldsForIndex(NovaRequest $request): array
|
||||
{
|
||||
return OrderItemFieldsForIndex::make($this, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields for create.
|
||||
*/
|
||||
public function fieldsForCreate(NovaRequest $request): array
|
||||
{
|
||||
return OrderItemFieldsForCreate::make($this, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource on detail page.
|
||||
*/
|
||||
public function fieldsForUpdate(NovaRequest $request): array
|
||||
{
|
||||
return OrderItemFieldsForUpdate::make($this, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after creation.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterCreate(NovaRequest $request, $resource)
|
||||
{
|
||||
return sprintf('/resources/orders/%s', $resource->order_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after update.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterUpdate(NovaRequest $request, $resource)
|
||||
{
|
||||
return sprintf('/resources/orders/%s', $resource->order_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Quantity'), 'quantity'),
|
||||
BelongsTo::make(__('Order'), 'order', Order::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\OrderItem;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product as ProductModel;
|
||||
use App\Nova\Resources\Ecommerce\Product\Order\Order;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Fields\Hidden;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Outl1ne\MultiselectField\Multiselect;
|
||||
|
||||
class OrderItemFieldsForCreate
|
||||
{
|
||||
/**
|
||||
* Order item fields for create
|
||||
*/
|
||||
public static function make($resource, $request): array
|
||||
{
|
||||
return [
|
||||
ID::make(),
|
||||
|
||||
Hidden::make('order_id')
|
||||
->default($request->viaResource()),
|
||||
|
||||
Multiselect::make(__('Product'), 'product_id')
|
||||
->asyncResource(Product::class)
|
||||
->placeholder(__('Search by id, name, sku, barcode...'))
|
||||
->singleSelect()
|
||||
->rules('required'),
|
||||
|
||||
Number::make(__('Quantity'), 'quantity')
|
||||
->rules('required', 'min:1')
|
||||
->default(1),
|
||||
|
||||
Text::make(__('Price'), 'unit_price_amount')
|
||||
->rules('required')
|
||||
->dependsOn('product_id', function ($field, $request, $formData) {
|
||||
if (! $formData->product_id || ! is_int($formData->product_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$product = DB::table('products')->where('id', $formData->product_id)->first();
|
||||
|
||||
$field->setValue($product->price_amount);
|
||||
})->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$product = ProductModel::find($request->product_id);
|
||||
|
||||
$model->unit_price_amount = $request->unit_price_amount;
|
||||
$model->unit_cost_amount = $product->cost_amount;
|
||||
$model->product_name = $product->name;
|
||||
$model->channel_id = $product->channels()->first()?->id ?? tmpostChannel()->id;
|
||||
}),
|
||||
|
||||
Number::make(__('Total'), 'total')
|
||||
->dependsOn(['quantity', 'unit_price_amount'], function ($field, $request, $formData) {
|
||||
if (! $formData->unit_price_amount || ! $formData->quantity) {
|
||||
return;
|
||||
}
|
||||
|
||||
$field->setValue($formData->unit_price_amount * $formData->quantity);
|
||||
})->readonly(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\OrderItem;
|
||||
|
||||
use App\Repositories\Nova\NovaRepo;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\URL;
|
||||
|
||||
class OrderItemFieldsForIndex
|
||||
{
|
||||
/**
|
||||
* Order item's index fields
|
||||
*/
|
||||
public static function make($resource): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable()->hidden(),
|
||||
|
||||
Text::make(
|
||||
name: __('Image'),
|
||||
attribute: fn () => NovaRepo::rawImage(url: $resource->product?->thumbnail())
|
||||
)->asHtml(),
|
||||
|
||||
Text::make(
|
||||
name: __('Product name'),
|
||||
attribute: fn () => $resource->product?->novaDetailPage(),
|
||||
)->displayUsing(function () use ($resource) {
|
||||
$product = $resource->product;
|
||||
|
||||
if (! $product) {
|
||||
return;
|
||||
}
|
||||
|
||||
return sprintf('
|
||||
<a href="%s" target="_blank" class="link-default"> %s <span class="link-default">%s</span> <span class="link-default">%s</span></a>',
|
||||
$product->novaDetailPage(),
|
||||
$product->name,
|
||||
$product->color,
|
||||
$product->size,
|
||||
);
|
||||
})->asHtml(),
|
||||
|
||||
URL::make(
|
||||
name: __('Channel'),
|
||||
attribute: fn () => $resource->channel?->novaDetailPage(),
|
||||
)
|
||||
->displayUsing(fn () => $resource->channel?->name)
|
||||
->canSeeWhen('isAdmin', $resource),
|
||||
|
||||
Text::make(__('Cost amount'), fn () => $resource->product?->cost_amount),
|
||||
Text::make(__('Price'), 'unit_price_amount'),
|
||||
Text::make(__('Quantity'), 'quantity'),
|
||||
Text::make(__('Total'), fn () => intval($resource->quantity) * floatval($resource->unit_price_amount)),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Order\OrderItem;
|
||||
|
||||
use Laravel\Nova\Fields\Hidden;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
|
||||
class OrderItemFieldsForUpdate
|
||||
{
|
||||
/**
|
||||
* Order item fields for update
|
||||
*/
|
||||
public static function make($resource, $request): array
|
||||
{
|
||||
return [
|
||||
ID::make(),
|
||||
|
||||
Hidden::make('order_id'),
|
||||
|
||||
Text::make(__('Product name'), 'product_name')
|
||||
->readonly(),
|
||||
|
||||
Number::make(__('Quantity'), 'quantity')
|
||||
->rules('required', 'min:1'),
|
||||
|
||||
Text::make(__('Price'), 'unit_price_amount')
|
||||
->rules('required'),
|
||||
|
||||
Number::make(__('Total'), 'total')
|
||||
->dependsOn(['quantity', 'unit_price_amount'], function ($field, $request, $formData) {
|
||||
if (! $formData->unit_price_amount || ! $formData->quantity) {
|
||||
return;
|
||||
}
|
||||
|
||||
$field->setValue($formData->unit_price_amount * $formData->quantity);
|
||||
})->readonly(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
trait HandlesProductResourceEvents
|
||||
{
|
||||
public static function afterCreate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
ProductFieldsForCreate::afterCreate($request, $model);
|
||||
}
|
||||
|
||||
public static function afterUpdate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
ProductFieldsForUpdate::afterUpdate($request, $model);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
use App\Models\Ecommerce\Product\Property\ProductAttributeValue;
|
||||
use App\Models\Ecommerce\Product\Property\ProductProperty;
|
||||
use App\Nova\Forms\NovaForm;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product as ProductResource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\ProductVariant as ProductVariantResource;
|
||||
use App\Repositories\Ecommerce\Channel\ChannelRepository;
|
||||
use App\Repositories\Ecommerce\Collection\CollectionRepository;
|
||||
use App\Repositories\Ecommerce\Product\Barcode\BarcodeRepository;
|
||||
use App\Repositories\Ecommerce\Product\Brand\BrandRepository;
|
||||
use App\Repositories\Ecommerce\Product\Category\CategoryRepository;
|
||||
use App\Repositories\Ecommerce\Product\NovaProductRepository;
|
||||
use App\Repositories\Ecommerce\Product\ProductRepository;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\Hidden;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Trix;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Panel;
|
||||
use Nurmuhammet\DynamicFields\DynamicFields;
|
||||
use Nurmuhammet\InlineRelationship\InlineRelationship;
|
||||
use Nurmuhammet\ProductInventory\ProductInventory;
|
||||
use Outl1ne\MultiselectField\Multiselect;
|
||||
|
||||
class ProductFieldsForCreate
|
||||
{
|
||||
/**
|
||||
* Get the fields for create.
|
||||
*/
|
||||
public static function make(ProductResource $resource, NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
new Panel(__('Product relations'), [
|
||||
Hidden::make('is_visible')
|
||||
->default(function () {
|
||||
if (auth()->user()->isEntrepreneur()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}),
|
||||
|
||||
Select::make(__('Channel'), 'channel')
|
||||
->fullWidth()
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(ChannelRepository::values())
|
||||
->default(tmpostChannel()->id)
|
||||
->rules('required')
|
||||
->fillUsing(NovaForm::fillEmpty())
|
||||
->canSeeWhen('isAdmin', $resource),
|
||||
|
||||
Select::make(__('Brand'), 'brand_id')
|
||||
->fullWidth()
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(BrandRepository::values())
|
||||
->rules('nullable'),
|
||||
|
||||
Multiselect::make(__('Category'), 'categories')
|
||||
->fullWidth()
|
||||
->options(CategoryRepository::namesWithTaxes())
|
||||
->help(__('Biggest tax is chosen from categories'))
|
||||
->rules('required')
|
||||
->fillUsing(NovaForm::fillEmpty()),
|
||||
|
||||
Multiselect::make(__('Collection'), 'collections')
|
||||
->fullWidth()
|
||||
->options(CollectionRepository::values())
|
||||
->rules('nullable')
|
||||
->fillUsing(NovaForm::fillEmpty()),
|
||||
]),
|
||||
|
||||
new Panel(__('General information'), [
|
||||
Text::make(__('Ady'), 'name')
|
||||
->fullWidth()
|
||||
->rules('required', 'string', 'max:255'),
|
||||
|
||||
Trix::make(__('Description'), 'description')
|
||||
->fullWidth()
|
||||
->withFiles('public')
|
||||
->rules('nullable', 'string'),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200')
|
||||
->rules('required')
|
||||
->setFileName(NovaForm::fillMediaFileName())
|
||||
->required(),
|
||||
]),
|
||||
|
||||
new Panel(__('Prices'), [
|
||||
Text::make(__('Price'), 'cost_amount')
|
||||
->fullWidth()
|
||||
->rules('required', 'numeric'),
|
||||
|
||||
Text::make(__('Price without discount'), 'old_price_amount')
|
||||
->fullWidth()
|
||||
->rules('nullable', 'numeric', 'gt:readonly_price_amount'),
|
||||
|
||||
Text::make(__('Purchase price'), 'readonly_price_amount')
|
||||
->fullWidth()
|
||||
->readonly()
|
||||
->dependsOn(['cost_amount', 'categories'], NovaProductRepository::priceAmountDependsOn()),
|
||||
|
||||
Hidden::make('price_amount')
|
||||
->fillUsing(NovaForm::fillAttribute('price_amount', 'readonly_price_amount')),
|
||||
]),
|
||||
|
||||
new Panel(__('Inventory'), [
|
||||
Text::make('SKU', 'sku')
|
||||
->fullWidth()
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
|
||||
Boolean::make(__('Generate new barcode'), 'generate_new_barcode')
|
||||
->onlyOnForms()
|
||||
->fillUsing(NovaForm::fillEmpty()),
|
||||
|
||||
Text::make(__('Barcode'), 'barcode')
|
||||
->fullWidth()
|
||||
->rules('nullable', 'string', 'max:255', 'unique:products,barcode')
|
||||
->dependsOn(
|
||||
attributes: 'generate_new_barcode',
|
||||
mixin: fn ($field, $request, $formData) => boolval($formData->generate_new_barcode)
|
||||
? $field->setValue(BarcodeRepository::generateBarcode())
|
||||
: null
|
||||
),
|
||||
|
||||
ProductInventory::make(__('Inventory'), 'inventories')
|
||||
->fullWidth()
|
||||
->rules('required')
|
||||
->dependsOn('channel', NovaProductRepository::inventoryDependsOn('channel'))
|
||||
->fillUsing(NovaForm::fillEmpty()),
|
||||
|
||||
Hidden::make('stock')
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->{$attribute} = array_sum(array_values($request->input('inventories')));
|
||||
}),
|
||||
|
||||
Hidden::make('options')->default(json_encode(ProductRepository::shippingAttributes())),
|
||||
]),
|
||||
|
||||
new Panel(__('Attributes'), [
|
||||
DynamicFields::make(__('Attributes'), 'properties')
|
||||
->fullWidth()
|
||||
->fillWithArrayName('properties')
|
||||
->dependsOn(['categories'], NovaProductRepository::createRequestAttributesDependsOn($resource))
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$properties = $request->input('properties') ?? [];
|
||||
|
||||
foreach ($properties as $key => $value) {
|
||||
try {
|
||||
if (in_array($key, ['size', 'colour'])) {
|
||||
$model->{$key} = $value;
|
||||
}
|
||||
} catch (Exception) {
|
||||
}
|
||||
}
|
||||
}),
|
||||
]),
|
||||
|
||||
new Panel(__('Variations'), [
|
||||
// InlineRelationship::make(__('Variations'), 'variations', ProductVariantResource::class)
|
||||
// ->hide()
|
||||
// ->dependsOn(['categories'], NovaProductRepository::createRequestVariationsDependsOn()),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be called after the resource is created.
|
||||
*/
|
||||
public static function afterCreate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
$model::withoutEvents(function () use ($request, $model) {
|
||||
$user = $request->user();
|
||||
|
||||
$model->categories()->attach($request->input('categories'));
|
||||
$model->collections()->attach($request->input('collections'));
|
||||
|
||||
if ($user->isEntrepreneur()) {
|
||||
$model->channels()->attach($user->channel()->id);
|
||||
} else {
|
||||
$model->channels()->attach($request->input('channel'));
|
||||
}
|
||||
|
||||
$request->collect('inventories')->each(
|
||||
fn ($stockValue, $inventoryID) => $model->inventories()->attach($inventoryID, ['stock' => $stockValue])
|
||||
);
|
||||
|
||||
$properties = $request->input('properties');
|
||||
$attribute_ids = $properties
|
||||
? DB::table('attributes')->whereIn('slug', array_keys($properties))->get(['id', 'type', 'slug'])
|
||||
: collect();
|
||||
|
||||
$attribute_ids->each(function ($attribute) use ($model, $properties) {
|
||||
$productAttribute = ProductProperty::create([
|
||||
'product_id' => $model->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
]);
|
||||
|
||||
ProductAttributeValue::create([
|
||||
'product_attribute_id' => $productAttribute->id,
|
||||
'attribute_value_id' => in_array($attribute->type, ['text', 'number']) ? null : $properties[$attribute->slug],
|
||||
'product_custom_value' => in_array($attribute->type, ['text', 'number']) ? $properties[$attribute->slug] : null,
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
use App\Nova\Resources\Ecommerce\Channel\Channel;
|
||||
use App\Nova\Resources\Ecommerce\Product\Brand\Brand;
|
||||
use App\Nova\Resources\Ecommerce\Product\Category\Category;
|
||||
use App\Nova\Resources\Ecommerce\Product\Collection\Collection;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product as ProductResource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\ProductVariant;
|
||||
use App\Nova\Resources\Ecommerce\Product\Review\Review;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\HasMany;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Trix;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Milon\Barcode\Facades\DNS1DFacade;
|
||||
use Nurmuhammet\DynamicFields\DynamicFields;
|
||||
use Nurmuhammet\ProductInventory\ProductInventory;
|
||||
use Outl1ne\MultiselectField\Multiselect;
|
||||
use ShuvroRoy\NovaTabs\Tab;
|
||||
use ShuvroRoy\NovaTabs\Tabs;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class ProductFieldsForDetail
|
||||
{
|
||||
/**
|
||||
* Get the fields displayed by the resource on detail page.
|
||||
*/
|
||||
public static function make(ProductResource $resource, NovaRequest $request): array
|
||||
{
|
||||
// nova has a wierd bug, can load detail fields while on Index
|
||||
if (! $request->isResourceDetailRequest()) {
|
||||
if ($request->viaResource && $request->viaRelationship && $request->relationshipType) {
|
||||
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($request->viaResource === 'inventory-history-resources') {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
ID::make(),
|
||||
Text::make(__('Name'), 'name'),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200'),
|
||||
|
||||
Trix::make(__('Description'), 'description')->withFiles('public')->alwaysShow(),
|
||||
Text::make(__('Price'), 'cost_amount'),
|
||||
Text::make(__('Price For Sale'), 'price_amount'),
|
||||
Text::make(__('Price without discount'), 'old_price_amount'),
|
||||
NovaSwitcher::make(__('Active'), 'is_visible')->canSeeWhen('isAdmin', $resource),
|
||||
|
||||
Tabs::make('Main', [
|
||||
Tab::make(__('Product relations'), [
|
||||
BelongsTo::make(__('Brand'), 'brand', Brand::class),
|
||||
|
||||
Multiselect::make(__('Channel'), 'channels')
|
||||
->belongsToMany(Channel::class)
|
||||
->canSeeWhen('isAdmin', $resource),
|
||||
|
||||
Multiselect::make(__('Category'), 'categories')->belongsToMany(Category::class),
|
||||
Multiselect::make(__('Collection'), 'collections')->belongsToMany(Collection::class),
|
||||
]),
|
||||
Tab::make(__('Inventory'), [
|
||||
ProductInventory::make(
|
||||
name: __('Inventory'),
|
||||
attribute: fn () => $resource->inventories()
|
||||
->get(['inventories.name', 'inventories.id'])
|
||||
->map(fn ($inventory) => [
|
||||
'name' => Str::title($inventory->name),
|
||||
'value' => $inventory->pivot?->stock,
|
||||
])->toArray()
|
||||
)->fullWidth(),
|
||||
|
||||
Text::make('SKU', 'sku'),
|
||||
|
||||
Text::make(__('Barcode'), function () use ($resource) {
|
||||
if (! is_numeric($resource->barcode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return view('vendor.nova.products.barcode', [
|
||||
'barcode' => $resource->barcode,
|
||||
'image' => DNS1DFacade::getBarcodeHTML(
|
||||
code: $resource->barcode,
|
||||
type: config('barcode.default_type'),
|
||||
),
|
||||
])->render();
|
||||
})->asHtml()->showWhen(boolval($resource->barcode)),
|
||||
|
||||
Text::make(__('Stock'), 'stock'),
|
||||
Text::make(__('Security stock'), 'security_stock'),
|
||||
]),
|
||||
Tab::make(__('Shipping'), [
|
||||
Boolean::make(__('Back order'), 'back_order'),
|
||||
|
||||
Number::make(__('Weight value'), 'weight_value'),
|
||||
Select::make(__('Weight unit'), 'weight_unit'),
|
||||
|
||||
Number::make(__('Height value'), 'height_value'),
|
||||
Select::make(__('Height unit'), 'height_unit'),
|
||||
|
||||
Number::make(__('Width value'), 'width_value'),
|
||||
Select::make(__('Width unit'), 'width_unit'),
|
||||
|
||||
Number::make(__('Depth value'), 'depth_value'),
|
||||
Select::make(__('Depth unit'), 'depth_unit'),
|
||||
|
||||
Number::make(__('Volume value'), 'volume_value'),
|
||||
Select::make(__('Volume unit'), 'volume_unit'),
|
||||
]),
|
||||
Tab::make(__('SEO'), [
|
||||
Text::make(__('Seo title'), 'seo_title'),
|
||||
Text::make(__('Seo description'), 'seo_description'),
|
||||
]),
|
||||
]),
|
||||
|
||||
Tabs::make(__('Properties'), [
|
||||
DynamicFields::make('Attributes', 'attributes')
|
||||
->fields(function () use ($resource) {
|
||||
$attributes = $resource->properties()->with(['attribute.values', 'values.value'])->get()->map(fn ($property) => [
|
||||
'label' => $property->attribute->name,
|
||||
'name' => $property->attribute->slug,
|
||||
'type' => $property->attribute->type,
|
||||
'default' => $property->attribute->type === 'select'
|
||||
? $property->values->first()->value?->id
|
||||
: $property->values->first()->product_custom_value,
|
||||
'options' => $property->attribute->values->map(fn ($value) => [
|
||||
'label' => $value->value,
|
||||
'value' => $value->id,
|
||||
])->toArray(),
|
||||
]);
|
||||
|
||||
return $attributes->toArray();
|
||||
}),
|
||||
]),
|
||||
|
||||
HasMany::make(__('Variations'), 'variations', ProductVariant::class),
|
||||
HasMany::make(__('Reviews'), 'reviews', Review::class),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
use App\Nova\Fields\FieldHelpers;
|
||||
use App\Nova\Resources\Ecommerce\Product\Brand\Brand;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class ProductFieldsForIndex
|
||||
{
|
||||
/**
|
||||
* Get the fields for index.
|
||||
*/
|
||||
public static function make(NovaRequest $request, $resource): array
|
||||
{
|
||||
if ($request->filled('search') && is_null($request->filters)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
Images::make(__('Image'), 'uploads')->conversionOnIndexView('thumb200x200'),
|
||||
Text::make(__('Name'), 'name')->sortable(),
|
||||
|
||||
BelongsTo::make(__('Brand'), 'brand', Brand::class)
|
||||
->sortable()
|
||||
->searchable()
|
||||
->filterable(),
|
||||
|
||||
Number::make(__('Price'), 'cost_amount')
|
||||
->sortable()
|
||||
->filterable(),
|
||||
|
||||
Text::make(__('SKU'), 'sku')->sortable(),
|
||||
|
||||
Text::make(__('Count'), FieldHelpers::formatQuantity())->asHtml(),
|
||||
|
||||
// For filter
|
||||
Number::make(__('Count'), 'stock')
|
||||
->hideFromIndex()
|
||||
->filterable(),
|
||||
|
||||
Boolean::make(__('Active'), 'is_visible')
|
||||
->sortable()
|
||||
->canSeeWhen('isVendor', $resource),
|
||||
|
||||
NovaSwitcher::make(__('Is visible'), 'is_visible')
|
||||
->sortable()
|
||||
->canSeeWhen('isAdmin', $resource),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product\Concerns;
|
||||
|
||||
use App\Jobs\Ecommerce\Product\UpdateProductRelations;
|
||||
use App\Nova\Forms\NovaForm;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product as ProductResource;
|
||||
use App\Repositories\Ecommerce\Channel\ChannelRepository;
|
||||
use App\Repositories\Ecommerce\Collection\CollectionRepository;
|
||||
use App\Repositories\Ecommerce\Product\Barcode\BarcodeRepository;
|
||||
use App\Repositories\Ecommerce\Product\Brand\BrandRepository;
|
||||
use App\Repositories\Ecommerce\Product\Category\CategoryRepository;
|
||||
use App\Repositories\Ecommerce\Product\NovaProductRepository;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Str;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\Hidden;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Trix;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Nurmuhammet\DynamicFields\DynamicFields;
|
||||
use Nurmuhammet\ProductInventory\ProductInventory;
|
||||
use Outl1ne\MultiselectField\Multiselect;
|
||||
use ShuvroRoy\NovaTabs\Tab;
|
||||
use ShuvroRoy\NovaTabs\Tabs;
|
||||
|
||||
class ProductFieldsForUpdate
|
||||
{
|
||||
/**
|
||||
* Get the fields displayed by the resource on detail page.
|
||||
*/
|
||||
public static function make(ProductResource $resource, NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->rules('required', 'string', 'max:255'),
|
||||
|
||||
Trix::make(__('Description'), 'description')
|
||||
->withFiles('public')
|
||||
->rules('nullable', 'string'),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->required()
|
||||
->rules('required')
|
||||
->showStatistics()
|
||||
->setFileName(fn ($originalFilename, $extension, $model) => sprintf('%s.%s', Str::random(70), $extension)),
|
||||
|
||||
Text::make(__('Price'), 'cost_amount')
|
||||
->rules('required', 'numeric'),
|
||||
|
||||
Text::make(__('Purchase price'), 'readonly_price_amount')
|
||||
->readonly()
|
||||
->dependsOn(['cost_amount', 'categories'], NovaProductRepository::priceAmountDependsOn()),
|
||||
|
||||
Hidden::make('price_amount')
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->{$attribute} = $request->input('readonly_price_amount');
|
||||
}),
|
||||
|
||||
Text::make(__('Price without discount'), 'old_price_amount')
|
||||
->rules('nullable', 'gt:readonly_price_amount'),
|
||||
|
||||
Boolean::make(__('Active'), 'is_visible')
|
||||
->canSeeWhen('isAdmin', $resource),
|
||||
|
||||
Tabs::make('Main', [
|
||||
Tab::make(__('Product relations'), [
|
||||
Select::make(__('Brand'), 'brand_id')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(BrandRepository::values())
|
||||
->rules('nullable'),
|
||||
|
||||
Select::make(__('Channel'), 'channel')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(ChannelRepository::values())
|
||||
->rules('required')
|
||||
->resolveUsing(fn ($value, $resource, $attribute) => $resource->owner()?->id)
|
||||
->fillUsing(NovaForm::fillEmpty())
|
||||
->canSeeWhen('isAdmin', $resource),
|
||||
|
||||
Multiselect::make(__('Category'), 'categories')
|
||||
->options(CategoryRepository::namesWithTaxes())
|
||||
->help(__('Biggest tax is chosen from categories'))
|
||||
->rules('required')
|
||||
->resolveUsing(fn ($value, $resource, $attribute) => $value->pluck('id'))
|
||||
->fillUsing(NovaForm::fillEmpty()),
|
||||
|
||||
Multiselect::make(__('Collection'), 'collections')
|
||||
->options(CollectionRepository::values())
|
||||
->rules('nullable')
|
||||
->resolveUsing(fn ($value, $resource, $attribute) => $value->pluck('id'))
|
||||
->fillUsing(NovaForm::fillEmpty()),
|
||||
]),
|
||||
Tab::make(__('Inventory'), [
|
||||
ProductInventory::make(__('Inventory'), 'inventories')
|
||||
->rules('required')
|
||||
->dependsOn('channel', NovaProductRepository::inventoryDependsOn('channel'))
|
||||
->fillUsing(NovaForm::fillEmpty()),
|
||||
|
||||
Text::make('SKU', 'sku')
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
|
||||
Boolean::make(__('Generate new barcode'), 'generate_new_barcode')
|
||||
->onlyOnForms()
|
||||
->fillUsing(NovaForm::fillEmpty()),
|
||||
|
||||
Text::make(__('Barcode'), 'barcode')
|
||||
->rules('nullable', 'string', 'max:255', 'unique:products,barcode,{{resourceId}}')
|
||||
->dependsOn(
|
||||
attributes: 'generate_new_barcode',
|
||||
mixin: function ($field, $request, $formData) use ($resource) {
|
||||
if (boolval($formData->generate_new_barcode)) {
|
||||
$field->setValue(BarcodeRepository::generateBarcode());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$field->setValue($resource->barcode);
|
||||
}
|
||||
),
|
||||
|
||||
Number::make(__('Security stock'), 'security_stock')
|
||||
->rules('nullable', 'integer'),
|
||||
|
||||
Hidden::make('stock')
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->{$attribute} = array_sum(array_values($request->input('inventories')));
|
||||
}),
|
||||
]),
|
||||
Tab::make(__('Attributes'), [
|
||||
DynamicFields::make('Attributes', 'workingpn')
|
||||
->fillWithArrayName('properties')
|
||||
->dependsOn(['categories'], NovaProductRepository::updateRequestAttributesDependsOn($resource))
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$properties = $request->input('properties');
|
||||
|
||||
if (! $properties) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($properties as $key => $value) {
|
||||
try {
|
||||
if (in_array($key, ['size', 'colour'])) {
|
||||
$model->{$key} = $value;
|
||||
}
|
||||
} catch (Exception) {
|
||||
}
|
||||
}
|
||||
}),
|
||||
]),
|
||||
Tab::make(__('Shipping'), [
|
||||
Boolean::make(__('Back order'), 'back_order')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Number::make(__('Weight value'), 'weight_value')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Select::make(__('Weight unit'), 'weight_unit')
|
||||
->options(['kg' => 'kg'])
|
||||
->default('kg')
|
||||
->searchable()
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Number::make(__('Height value'), 'height_value')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Select::make(__('Height unit'), 'height_unit')
|
||||
->options(['cm' => 'cm'])
|
||||
->default('cm')
|
||||
->searchable()
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Number::make(__('Width value'), 'width_value')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Select::make(__('Width unit'), 'width_unit')
|
||||
->options(['cm' => 'cm'])
|
||||
->default('cm')
|
||||
->searchable()
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Number::make(__('Depth value'), 'depth_value')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Select::make(__('Depth unit'), 'depth_unit')
|
||||
->options(['cm' => 'cm'])
|
||||
->default('cm')
|
||||
->searchable()
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Number::make(__('Volume value'), 'volume_value')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Select::make(__('Volume unit'), 'volume_unit')
|
||||
->options(['kg' => 'kg'])
|
||||
->default('kg')
|
||||
->searchable()
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
]),
|
||||
Tab::make(__('SEO'), [
|
||||
Text::make(__('Seo title'), 'seo_title'),
|
||||
Text::make(__('Seo description'), 'seo_description'),
|
||||
]),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be called after the resource is updated.
|
||||
*/
|
||||
public static function afterUpdate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
UpdateProductRelations::dispatch(
|
||||
user: $request->user(),
|
||||
model: $model,
|
||||
categories: $request->input('categories'),
|
||||
collections: $request->input('collections'),
|
||||
channel: $request->input('channel'),
|
||||
properties: $request->input('properties'),
|
||||
inventories: $request->collect('inventories')
|
||||
->mapWithKeys(fn ($stockValue, $inventoryID) => [$inventoryID => ['stock' => $stockValue]])
|
||||
->toArray()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product\Concerns\Variant;
|
||||
|
||||
use App\Models\Ecommerce\Product\Inventory\Inventory;
|
||||
use App\Models\Ecommerce\Product\Product\Product as ProductModel;
|
||||
use App\Models\Ecommerce\Product\Property\ProductAttributeValue;
|
||||
use App\Models\Ecommerce\Product\Property\ProductProperty;
|
||||
use App\Nova\Forms\NovaForm;
|
||||
use App\Repositories\Ecommerce\Product\NovaProductRepository;
|
||||
use App\Repositories\Ecommerce\Product\ProductRepository;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Fields\Heading;
|
||||
use Laravel\Nova\Fields\Hidden;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Nurmuhammet\DynamicFields\DynamicFields;
|
||||
use Nurmuhammet\ProductInventory\ProductInventory;
|
||||
use Spatie\MediaLibrary\MediaCollections\Models\Media;
|
||||
|
||||
class VariantFieldsForCreate
|
||||
{
|
||||
/**
|
||||
* Get the fields for create.
|
||||
*/
|
||||
public static function make(NovaRequest $request): array
|
||||
{
|
||||
if ($request->viaRelationship()) {
|
||||
$parent = ProductModel::find($request->viaResourceId);
|
||||
$categories = $parent->categories;
|
||||
} else {
|
||||
$parent = null;
|
||||
$categories = session('product_categories') ?? [];
|
||||
}
|
||||
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
ProductInventory::make(__('Inventory'), 'inventories')
|
||||
->rules('required')
|
||||
->options(Inventory::pluck('name', 'id'))
|
||||
->fillUsing(NovaForm::fillEmpty()),
|
||||
|
||||
DynamicFields::make('Attributes', 'properties')
|
||||
->fillWithArrayName('properties')
|
||||
->fields(fn () => NovaProductRepository::attributeFields($categories))
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$properties = $request->input('properties');
|
||||
|
||||
foreach ($properties as $key => $value) {
|
||||
try {
|
||||
if (in_array($key, ['size', 'colour'])) {
|
||||
$model->{$key} = $value;
|
||||
}
|
||||
} catch (Exception) {
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
Heading::make(__('Leave empty to use original image')),
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb150x150')
|
||||
->showStatistics()
|
||||
->help(__('Leave empty to use original image')),
|
||||
|
||||
Text::make(__('Price'), 'cost_amount')
|
||||
->default(optional($parent)->cost_amount)
|
||||
->rules('nullable', 'numeric'),
|
||||
|
||||
Text::make(__('Price without discount'), 'old_price_amount')
|
||||
->default(optional($parent)->old_price_amount)
|
||||
->rules('nullable', 'numeric'),
|
||||
|
||||
Text::make(__('Purchase price'), 'readonly_price_amount')
|
||||
->readonly()
|
||||
->dependsOn(['cost_amount'], NovaProductRepository::priceAmountDependsOn($categories)),
|
||||
|
||||
Hidden::make('price_amount')
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->{$attribute} = $request->input('readonly_price_amount');
|
||||
}),
|
||||
|
||||
Text::make('SKU', 'sku')
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
|
||||
Number::make(__('Security stock'), 'security_stock')
|
||||
->rules('nullable', 'integer'),
|
||||
|
||||
Hidden::make('name')
|
||||
->default($parent->name ?? 'inlineCreated'),
|
||||
|
||||
Hidden::make('options')
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
if ($request->name === 'inlineCreated') {
|
||||
$model->options->set('inline_created', true);
|
||||
} else {
|
||||
json_encode(ProductRepository::shippingAttributes());
|
||||
}
|
||||
}),
|
||||
|
||||
Hidden::make('stock')
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->{$attribute} = array_sum(array_values($request->input('inventories')));
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* After resource has been created
|
||||
*/
|
||||
public static function afterCreate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
$model::withoutEvents(function () use ($request, $model) {
|
||||
if ($request->viaRelationship() && $request->missing('__media__')) {
|
||||
$parent = ProductModel::find($request->viaResourceId);
|
||||
|
||||
$parent->media->each(function (Media $media) use ($model) {
|
||||
$model->addMedia($media->getPath())
|
||||
->preservingOriginal()
|
||||
->toMediaCollection($media->collection_name);
|
||||
});
|
||||
}
|
||||
|
||||
$request->collect('inventories')->each(
|
||||
fn ($stockValue, $inventoryID) => $model->inventories()->attach($inventoryID, ['stock' => $stockValue])
|
||||
);
|
||||
|
||||
$properties = $request->input('properties');
|
||||
$attribute_ids = $properties
|
||||
? DB::table('attributes')->whereIn('slug', array_keys($properties))->get(['id', 'type', 'slug'])
|
||||
: collect();
|
||||
|
||||
$attribute_ids->each(function ($attribute) use ($model, $properties) {
|
||||
$productAttribute = ProductProperty::create([
|
||||
'product_id' => $model->id,
|
||||
'attribute_id' => $attribute->id,
|
||||
]);
|
||||
|
||||
ProductAttributeValue::create([
|
||||
'product_attribute_id' => $productAttribute->id,
|
||||
'attribute_value_id' => in_array($attribute->type, ['text', 'number']) ? null : $properties[$attribute->slug],
|
||||
'product_custom_value' => in_array($attribute->type, ['text', 'number']) ? $properties[$attribute->slug] : null,
|
||||
]);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product\Concerns\Variant;
|
||||
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Nurmuhammet\DynamicFields\DynamicFields;
|
||||
|
||||
class VariantFieldsForDetail
|
||||
{
|
||||
/**
|
||||
* Get the fields for create.
|
||||
*/
|
||||
public static function make(NovaRequest $request, $resource): array
|
||||
{
|
||||
if (! $request->isResourceDetailRequest()) {
|
||||
if ($request->viaResource && $request->viaRelationship && $request->relationshipType) {
|
||||
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
BelongsTo::make(__('Parent'), 'parent', Product::class),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200'),
|
||||
|
||||
Text::make(__('Price'), 'cost_amount')
|
||||
->rules('required', 'numeric'),
|
||||
|
||||
Text::make('SKU', 'sku')
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
|
||||
Number::make(__('Stock'), 'stock')
|
||||
->rules('required', 'integer'),
|
||||
|
||||
DynamicFields::make('Attributes', 'attributes')
|
||||
->fields(function () use ($resource) {
|
||||
$attributes = $resource->properties()->with(['attribute.values', 'values.value'])->get()->map(fn ($property) => [
|
||||
'label' => $property->attribute->name,
|
||||
'name' => $property->attribute->slug,
|
||||
'type' => $property->attribute->type,
|
||||
'default' => $property->attribute->type === 'select'
|
||||
? $property->values->first()->value?->id
|
||||
: $property->values->first()->product_custom_value,
|
||||
'options' => $property->attribute->values->map(fn ($value) => [
|
||||
'label' => $value->value,
|
||||
'value' => $value->id,
|
||||
])->toArray(),
|
||||
]);
|
||||
|
||||
return $attributes->toArray();
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product\Concerns\Variant;
|
||||
|
||||
use App\Repositories\Ecommerce\Product\Property\PropertyRepository;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class VariantFieldsForIndex
|
||||
{
|
||||
/**
|
||||
* Get the fields for create.
|
||||
*/
|
||||
public static function make(NovaRequest $request, $resource): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->conversionOnIndexView('thumb200x200'),
|
||||
|
||||
Text::make(__('Price'), 'cost_amount')
|
||||
->rules('required', 'numeric'),
|
||||
|
||||
Text::make(__('Color'), fn () => PropertyRepository::getRealValue('colour', $resource->colour)),
|
||||
Text::make(__('Size'), fn () => PropertyRepository::getRealValue('size', $resource->size)),
|
||||
|
||||
Number::make(__('Stock'), 'stock')
|
||||
->rules('required', 'integer'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product\Concerns\Variant;
|
||||
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Nurmuhammet\DynamicFields\DynamicFields;
|
||||
|
||||
class VariantFieldsForPreview
|
||||
{
|
||||
/**
|
||||
* Fields For Preview
|
||||
*/
|
||||
public static function make(NovaRequest $request, $resource): array
|
||||
{
|
||||
if (! $request->isResourcePreviewRequest()) {
|
||||
return [
|
||||
DynamicFields::make('Attributes', 'attributes')
|
||||
->fields([]),
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
DynamicFields::make('Attributes', 'attributes')
|
||||
->fields(function () use ($resource) {
|
||||
$attributes = $resource->properties()->with(['attribute.values', 'values.value'])->get()->map(fn ($property) => [
|
||||
'label' => $property->attribute->name,
|
||||
'name' => $property->attribute->slug,
|
||||
'type' => $property->attribute->type,
|
||||
'default' => $property->attribute->type === 'select'
|
||||
? $property->values->first()->value?->id
|
||||
: $property->values->first()->product_custom_value,
|
||||
'options' => $property->attribute->values->map(fn ($value) => [
|
||||
'label' => $value->value,
|
||||
'value' => $value->id,
|
||||
])->toArray(),
|
||||
]);
|
||||
|
||||
return $attributes->toArray();
|
||||
}),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product\Concerns\Variant;
|
||||
|
||||
use App\Jobs\Ecommerce\Product\UpdateProductRelations;
|
||||
use App\Models\Ecommerce\Product\Inventory\Inventory;
|
||||
use App\Nova\Forms\NovaForm;
|
||||
use App\Repositories\Ecommerce\Product\NovaProductRepository;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Exception;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\Hidden;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Laravel\Nova\Panel;
|
||||
use Nurmuhammet\DynamicFields\DynamicFields;
|
||||
use Nurmuhammet\ProductInventory\ProductInventory;
|
||||
|
||||
class VariantFieldsForUpdate
|
||||
{
|
||||
/**
|
||||
* Get the fields for create.
|
||||
*/
|
||||
public static function make(NovaRequest $request, $resource): array
|
||||
{
|
||||
$categories = $resource->parent->categories;
|
||||
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Images::make(__('Image'), 'uploads')
|
||||
->showStatistics()
|
||||
->setFileName(fn ($originalFilename, $extension, $model) => sprintf('%s.%s', md5($originalFilename), $extension)),
|
||||
|
||||
Text::make(__('Price'), 'cost_amount')
|
||||
->rules('required', 'numeric'),
|
||||
|
||||
Text::make(__('Price without discount'), 'old_price_amount')
|
||||
->rules('nullable', 'numeric'),
|
||||
|
||||
Text::make(__('Purchase price'), 'readonly_price_amount')
|
||||
->readonly()
|
||||
->dependsOn(['cost_amount'], NovaProductRepository::priceAmountDependsOn($categories)),
|
||||
|
||||
Hidden::make('price_amount')
|
||||
->fillUsing(NovaForm::fillAttribute('price_amount', 'readonly_price_amount')),
|
||||
|
||||
new Panel(__('Inventory'), [
|
||||
Text::make('SKU', 'sku')
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
|
||||
Text::make(__('Barcode'), 'barcode')
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
|
||||
ProductInventory::make(__('Inventory'), 'inventories')
|
||||
->rules('required')
|
||||
->options(Inventory::pluck('name', 'id'))
|
||||
->fillUsing(NovaForm::fillEmpty()),
|
||||
|
||||
Hidden::make('stock')
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$model->{$attribute} = array_sum(array_values($request->input('inventories')));
|
||||
}),
|
||||
|
||||
Number::make(__('Security stock'), 'security_stock')
|
||||
->rules('nullable', 'integer'),
|
||||
]),
|
||||
|
||||
new Panel(__('Attributes'), [
|
||||
DynamicFields::make('Attributes', 'workingpn')
|
||||
->fillWithArrayName('properties')
|
||||
->fields(fn () => NovaProductRepository::attributeFieldsWithValues($categories, $resource))
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {
|
||||
$properties = $request->input('properties');
|
||||
|
||||
foreach ($properties as $key => $value) {
|
||||
try {
|
||||
if (in_array($key, ['size', 'colour'])) {
|
||||
$model->{$key} = $value;
|
||||
}
|
||||
} catch (Exception) {
|
||||
}
|
||||
}
|
||||
}),
|
||||
]),
|
||||
|
||||
new Panel(__('Shipping'), [
|
||||
Boolean::make(__('Back order'), 'back_order')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Number::make(__('Weight value'), 'weight_value')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Select::make(__('Weight unit'), 'weight_unit')
|
||||
->options(['kg' => 'kg'])
|
||||
->default('kg')
|
||||
->searchable()
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Number::make(__('Height value'), 'height_value')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Select::make(__('Height unit'), 'height_unit')
|
||||
->options(['cm' => 'cm'])
|
||||
->default('cm')
|
||||
->searchable()
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Number::make(__('Width value'), 'width_value')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Select::make(__('Width unit'), 'width_unit')
|
||||
->options(['cm' => 'cm'])
|
||||
->default('cm')
|
||||
->searchable()
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Number::make(__('Depth value'), 'depth_value')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Select::make(__('Depth unit'), 'depth_unit')
|
||||
->options(['cm' => 'cm'])
|
||||
->default('cm')
|
||||
->searchable()
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Number::make(__('Volume value'), 'volume_value')
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
|
||||
Select::make(__('Volume unit'), 'volume_unit')
|
||||
->options(['kg' => 'kg'])
|
||||
->default('kg')
|
||||
->searchable()
|
||||
->fillUsing(NovaForm::fillSchemalessField()),
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be called after the resource is updated.
|
||||
*/
|
||||
public static function afterUpdate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
UpdateProductRelations::dispatch(
|
||||
model: $model,
|
||||
properties: $request->input('properties'),
|
||||
inventories: $request->collect('inventories')
|
||||
->mapWithKeys(fn ($stockValue, $inventoryID) => [$inventoryID => ['stock' => $stockValue]])
|
||||
->toArray()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product\Filters;
|
||||
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class ProductEntrepreneurFilter extends Filter
|
||||
{
|
||||
/**
|
||||
* The filter's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'select-filter';
|
||||
|
||||
/**
|
||||
* Get the displayable name of the filter.
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
return __('Entrepreneur');
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
$vendorProducts = DB::table('product_has_relations')
|
||||
->where('productable_type', 'channel')
|
||||
->where('productable_id', $value)
|
||||
->pluck('product_id');
|
||||
|
||||
$query->whereIntegerInRaw('id', $vendorProducts);
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function options(NovaRequest $request)
|
||||
{
|
||||
if (! Cache::has('channels')) {
|
||||
Cache::remember('channels', 60 * 5, fn () => DB::table('channels')->pluck('id', 'name'));
|
||||
}
|
||||
|
||||
return Cache::get('channels');
|
||||
}
|
||||
}
|
||||
216
app/Nova/Resources/Ecommerce/Product/Product/Product.php
Normal file
216
app/Nova/Resources/Ecommerce/Product/Product/Product.php
Normal file
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product as ProductModel;
|
||||
use App\Models\User;
|
||||
use App\Nova\Actions\Ecommerce\Product\ProductImportAction;
|
||||
use App\Nova\Filters\ResourceLimitFilter;
|
||||
use App\Nova\Filters\VisableFilter;
|
||||
use App\Nova\Lenses\MostSoldProducts;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Concerns\HandlesProductResourceEvents;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Concerns\ProductFieldsForCreate;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Concerns\ProductFieldsForDetail;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Concerns\ProductFieldsForIndex;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Concerns\ProductFieldsForUpdate;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Filters\ProductEntrepreneurFilter;
|
||||
use App\Repositories\CMS\Icon\IconRepository;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Laravel\Nova\Fields\HasMany;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use ShuvroRoy\NovaTabs\Traits\HasTabs;
|
||||
|
||||
class Product extends Resource
|
||||
{
|
||||
/**
|
||||
* Handles product resource events
|
||||
*/
|
||||
use HandlesProductResourceEvents;
|
||||
|
||||
/**
|
||||
* Supports tabs
|
||||
*/
|
||||
use HasTabs;
|
||||
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<ProductModel>
|
||||
*/
|
||||
public static $model = ProductModel::class;
|
||||
|
||||
/**
|
||||
* The number of resources to show per page via relationships.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
public static $perPageViaRelationship = 5;
|
||||
|
||||
/**
|
||||
* The pagination per-page options configured for this resource.
|
||||
*/
|
||||
public static function perPageOptions(): array
|
||||
{
|
||||
return [50, 100, 150];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value that should be displayed to represent the resource.
|
||||
*/
|
||||
public function title(): string
|
||||
{
|
||||
if (request()->filled('search') && is_null(request('filters'))) {
|
||||
return sprintf('%s (%s)', $this->name, $this->barcode);
|
||||
}
|
||||
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
// public static $with = ['brand', 'media'];
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'name', 'sku', 'barcode',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Product');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Products');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query): Builder
|
||||
{
|
||||
if ($request->filled('search') && is_null($request->filters)) {
|
||||
|
||||
} else {
|
||||
$query->with(['brand', 'media']);
|
||||
}
|
||||
|
||||
if ($request->viaResource() != Product::class) {
|
||||
$query->where('parent_id', null);
|
||||
// ->whereNot('name', 'inlineCreated');
|
||||
}
|
||||
|
||||
$user = $request->user();
|
||||
|
||||
if ($user->hasRole('vendor')) {
|
||||
$vendorProducts = DB::table('product_has_relations')
|
||||
->where('productable_type', 'channel')
|
||||
->where('productable_id', $user->channel()->id)
|
||||
->pluck('product_id');
|
||||
|
||||
$query->whereIntegerInRaw('id', $vendorProducts);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields for index.
|
||||
*/
|
||||
public function fieldsForIndex(NovaRequest $request): array
|
||||
{
|
||||
return ProductFieldsForIndex::make($request, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields for create.
|
||||
*/
|
||||
public function fieldsForCreate(NovaRequest $request): array
|
||||
{
|
||||
return ProductFieldsForCreate::make($this, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource on detail page.
|
||||
*/
|
||||
public function fieldsForDetail(NovaRequest $request): array
|
||||
{
|
||||
return ProductFieldsForDetail::make($this, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource on detail page.
|
||||
*/
|
||||
public function fieldsForUpdate(NovaRequest $request): array
|
||||
{
|
||||
return ProductFieldsForUpdate::make($this, $request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
Text::make(__('Ady'), 'name'),
|
||||
HasMany::make(__('Variations'), 'variations', ProductVariant::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*/
|
||||
public function filters(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ProductEntrepreneurFilter::make(),
|
||||
VisableFilter::make(),
|
||||
// ResourceLimitFilter::make($this),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*/
|
||||
public function lenses(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
MostSoldProducts::make()
|
||||
->canSeeWhen('isAdmin', User::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*/
|
||||
public function actions(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ProductImportAction::make()
|
||||
->standalone()
|
||||
->onlyOnIndex()
|
||||
->icon(IconRepository::make()->upload()),
|
||||
];
|
||||
}
|
||||
}
|
||||
177
app/Nova/Resources/Ecommerce/Product/Product/ProductVariant.php
Normal file
177
app/Nova/Resources/Ecommerce/Product/Product/ProductVariant.php
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Product;
|
||||
|
||||
use App\Models\Ecommerce\Product\Product\Product as ProductModel;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Concerns\Variant\VariantFieldsForCreate;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Concerns\Variant\VariantFieldsForDetail;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Concerns\Variant\VariantFieldsForIndex;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Concerns\Variant\VariantFieldsForPreview;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Concerns\Variant\VariantFieldsForUpdate;
|
||||
use App\Rules\CommaSeparatedIntegers;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use ShuvroRoy\NovaTabs\Traits\HasTabs;
|
||||
|
||||
class ProductVariant extends Resource
|
||||
{
|
||||
/**
|
||||
* Supports tabs
|
||||
*/
|
||||
use HasTabs;
|
||||
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<ProductModel>
|
||||
*/
|
||||
public static $model = ProductModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['media'];
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'name', 'sku', 'barcode',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Product Variations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Product Variation');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query)
|
||||
{
|
||||
if (Validator::make($request->all(), [
|
||||
'ids' => ['required', 'string', new CommaSeparatedIntegers()],
|
||||
])->passes()) {
|
||||
$query->whereIntegerInRaw('id', explode(',', $request->ids));
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
$query->whereNotNull('parent_id');
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields for index.
|
||||
*/
|
||||
public function fieldsForIndex(NovaRequest $request): array
|
||||
{
|
||||
return VariantFieldsForIndex::make($request, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get fields for preview
|
||||
*/
|
||||
public function fieldsForPreview(NovaRequest $request): array
|
||||
{
|
||||
return VariantFieldsForPreview::make($request, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields for create.
|
||||
*/
|
||||
public function fieldsForDetail(NovaRequest $request): array
|
||||
{
|
||||
return VariantFieldsForDetail::make($request, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields for create.
|
||||
*/
|
||||
public function fieldsForCreate(NovaRequest $request): array
|
||||
{
|
||||
return VariantFieldsForCreate::make($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource on detail page.
|
||||
*/
|
||||
public function fieldsForUpdate(NovaRequest $request): array
|
||||
{
|
||||
return VariantFieldsForUpdate::make($request, $this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* After resource has been created
|
||||
*/
|
||||
public static function afterCreate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
VariantFieldsForCreate::afterCreate($request, $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* After resource has been updated
|
||||
*/
|
||||
public static function afterUpdate(NovaRequest $request, Model $model): void
|
||||
{
|
||||
VariantFieldsForUpdate::afterUpdate($request, $model);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after creation.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterCreate(NovaRequest $request, $resource)
|
||||
{
|
||||
return sprintf('/resources/products/%s', $resource->parent_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after update.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterUpdate(NovaRequest $request, $resource)
|
||||
{
|
||||
return sprintf('/resources/products/%s', $resource->parent_id);
|
||||
}
|
||||
}
|
||||
149
app/Nova/Resources/Ecommerce/Product/Review/Review.php
Normal file
149
app/Nova/Resources/Ecommerce/Product/Review/Review.php
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Ecommerce\Product\Review;
|
||||
|
||||
use App\Models\Ecommerce\Product\Review\Review as ReviewModel;
|
||||
use App\Models\System\Settings\OS;
|
||||
use App\Nova\Filters\VisableFilter;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Product\Product\Product;
|
||||
use App\Nova\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\DateTime;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Number;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class Review extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<ReviewModel>
|
||||
*/
|
||||
public static $model = ReviewModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'title';
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['user', 'product'];
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'title',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Reviews');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Review');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
BelongsTo::make(__('User'), 'user', User::class)
|
||||
->searchable(),
|
||||
|
||||
BelongsTo::make(__('Product'), 'product', Product::class)
|
||||
->searchable(),
|
||||
|
||||
Number::make(__('Rating'), 'rating')
|
||||
->rules('required', 'integer', 'min:0', 'max:5'),
|
||||
|
||||
Text::make(__('Title'), 'title')
|
||||
->defaultStringRules(),
|
||||
|
||||
Text::make(__('Content'), 'content')
|
||||
->defaultStringRules()
|
||||
->hideFromIndex(),
|
||||
|
||||
Select::make(__('Source'), 'source')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OS::apps())
|
||||
->default(OS::default())
|
||||
->rules('required'),
|
||||
|
||||
NovaSwitcher::make(__('Active'), 'is_visible')
|
||||
->default(false),
|
||||
|
||||
NovaSwitcher::make(__('Is recommended'), 'is_recommended')
|
||||
->default(false),
|
||||
|
||||
DateTime::make(__('Created at'), 'created_at')
|
||||
->turkmenDate()
|
||||
->exceptOnForms(),
|
||||
|
||||
DateTime::make(__('Updated at'), 'updated_at')
|
||||
->turkmenDate()
|
||||
->exceptOnForms(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*/
|
||||
public function cards(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*/
|
||||
public function filters(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
VisableFilter::make(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*/
|
||||
public function lenses(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*/
|
||||
public function actions(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
121
app/Nova/Resources/Legal/LegalPage.php
Normal file
121
app/Nova/Resources/Legal/LegalPage.php
Normal file
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Legal;
|
||||
|
||||
use App\Models\Legal\LegalPage as LegalPageModel;
|
||||
use App\Nova\Filters\VisableFilter;
|
||||
use App\Nova\Forms\NovaForm;
|
||||
use App\Nova\Resource;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\Hidden;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Slug;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Trix;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class LegalPage extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<LegalPageModel>
|
||||
*/
|
||||
public static $model = LegalPageModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'title';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'slug', 'title',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Legal pages');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Legal page');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Slug::make(__('Slug'), 'slug')
|
||||
->hideWhenCreating(),
|
||||
|
||||
Hidden::make('slug')
|
||||
->fillUsing(NovaForm::fillSlug(['title', 'en'], LegalPageModel::class))
|
||||
->hideWhenUpdating(),
|
||||
|
||||
Text::make(__('Title'), 'title')
|
||||
->rules('required')
|
||||
->translatable(),
|
||||
|
||||
Trix::make(__('Content'), 'content')
|
||||
->rules('required')
|
||||
->alwaysShow()
|
||||
->translatable(),
|
||||
|
||||
NovaSwitcher::make(__('Active'), 'is_active')
|
||||
->default(true),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*/
|
||||
public function cards(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*/
|
||||
public function filters(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
VisableFilter::make(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*/
|
||||
public function lenses(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*/
|
||||
public function actions(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
39
app/Nova/Resources/Post/PostBranch/Filters/RegionFilter.php
Normal file
39
app/Nova/Resources/Post/PostBranch/Filters/RegionFilter.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Post\PostBranch\Filters;
|
||||
|
||||
use App\Models\System\Settings\Location\Region;
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class RegionFilter extends Filter
|
||||
{
|
||||
/**
|
||||
* The filter's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'select-filter';
|
||||
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
return $query->byRegion($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function options(NovaRequest $request)
|
||||
{
|
||||
return array_flip(Region::values());
|
||||
}
|
||||
}
|
||||
124
app/Nova/Resources/Post/PostBranch/PostBranch.php
Normal file
124
app/Nova/Resources/Post/PostBranch/PostBranch.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Post\PostBranch;
|
||||
|
||||
use App\Models\Post\PostBranch as PostBranchModel;
|
||||
use App\Models\System\Settings\Location\Province as ProvinceModel;
|
||||
use App\Models\System\Settings\Location\Region;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\System\Settings\Location\Province\Province;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Fields\Textarea;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class PostBranch extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<PostBranchModel>
|
||||
*/
|
||||
public static $model = PostBranchModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['province'];
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Post Branches');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Post Branch');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Select::make(__('Region'), 'region')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(Region::values())
|
||||
->default(Region::AG)
|
||||
->rules('required')
|
||||
->onlyOnForms()
|
||||
->fillUsing(function ($request, $model, $attribute, $requestAttribute) {})
|
||||
->resolveUsing(fn () => $this->province?->region)
|
||||
->sortable(),
|
||||
|
||||
Select::make(__('Province'), 'province_id')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->rules('required')
|
||||
->dependsOn(['region'], function ($field, $request, $formData) {
|
||||
if ($this->province || $formData->region) {
|
||||
$field->options(ProvinceModel::where('region', $formData->region ?: $this->province->region)->pluck('name', 'id'));
|
||||
}
|
||||
})->onlyOnForms(),
|
||||
|
||||
BelongsTo::make(__('Province'), 'province', Province::class)
|
||||
->exceptOnForms()
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->translatable()
|
||||
->sortable()
|
||||
->rules(['required', 'max:255']),
|
||||
|
||||
Textarea::make(__('Address'), 'address')
|
||||
->translatable()
|
||||
->alwaysShow()
|
||||
->rules('nullable'),
|
||||
|
||||
Textarea::make(__('Description'), 'description')
|
||||
->translatable()
|
||||
->alwaysShow()
|
||||
->rules('nullable'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*/
|
||||
public function filters(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
new Filters\RegionFilter(),
|
||||
];
|
||||
}
|
||||
}
|
||||
133
app/Nova/Resources/Post/UserDocs/UserDocResource.php
Normal file
133
app/Nova/Resources/Post/UserDocs/UserDocResource.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\Post\UserDocs;
|
||||
|
||||
use App\Models\Post\User\UserDoc;
|
||||
use App\Nova\Forms\NovaForm;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\User;
|
||||
use Ebess\AdvancedNovaMediaLibrary\Fields\Images;
|
||||
use Illuminate\Http\Request;
|
||||
use Laravel\Nova\Fields\BelongsTo;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Image;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class UserDocResource extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Post\User\UserDoc>
|
||||
*/
|
||||
public static $model = \App\Models\Post\User\UserDoc::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'id';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after creation.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterCreate(NovaRequest $request, $resource)
|
||||
{
|
||||
return sprintf('/resources/users/%s', $resource->user_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the location to redirect the user after update.
|
||||
*
|
||||
* @param \Laravel\Nova\Resource $resource
|
||||
* @return \Laravel\Nova\URL|string
|
||||
*/
|
||||
public static function redirectAfterUpdate(NovaRequest $request, $resource)
|
||||
{
|
||||
return sprintf('/resources/users/%s', $resource->user_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
BelongsTo::make(__('User'), 'user', User::class),
|
||||
|
||||
Select::make(__('Type'), 'corporation_type')
|
||||
->options(UserDoc::corparationTypes())
|
||||
->rules('required')
|
||||
->displayUsingLabels(),
|
||||
|
||||
Text::make(__('Name'), 'corporation_name')->rules('required'),
|
||||
|
||||
Image::make(__('Patent'), 'patent_data')
|
||||
->deletable(false)
|
||||
->creationRules('required'),
|
||||
|
||||
Images::make(__('Goşmaça'), 'main')
|
||||
->conversionOnIndexView('thumb150x150')
|
||||
->setFileName(NovaForm::hashFileName()),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
72
app/Nova/Resources/System/Payments/PaymentType.php
Normal file
72
app/Nova/Resources/System/Payments/PaymentType.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\System\Payments;
|
||||
|
||||
use App\Models\System\Settings\Payments\PaymentType as PaymentTypeModel;
|
||||
use App\Nova\Resource;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Trin4ik\NovaSwitcher\NovaSwitcher;
|
||||
|
||||
class PaymentType extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<PaymentTypeModel>
|
||||
*/
|
||||
public static $model = PaymentTypeModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Payment types');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Payment type');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->translatable()
|
||||
->rules('required', 'string', 'max:255'),
|
||||
|
||||
Text::make(__('Tax'), 'tax')
|
||||
->rules('nullable', 'string', 'max:255'),
|
||||
|
||||
NovaSwitcher::make(__('Is enabled'), 'is_enabled')
|
||||
->default(true),
|
||||
];
|
||||
}
|
||||
}
|
||||
92
app/Nova/Resources/System/Roles/Permission.php
Normal file
92
app/Nova/Resources/System/Roles/Permission.php
Normal file
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\System\Roles;
|
||||
|
||||
use App\Nova\Resource;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Permission extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\System\Roles\Permission>
|
||||
*/
|
||||
public static $model = \App\Models\System\Roles\Permission::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->rules('required', 'string', 'max:255', 'unique:permissions,name'),
|
||||
|
||||
Text::make(__('Guard name'), 'guard_name')
|
||||
->rules('required', 'string', 'max:255'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
108
app/Nova/Resources/System/Roles/Role.php
Normal file
108
app/Nova/Resources/System/Roles/Role.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\System\Roles;
|
||||
|
||||
use App\Nova\Resource;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Role extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Resources\System\Roles\Role>
|
||||
*/
|
||||
public static $model = \App\Models\System\Roles\Role::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Roles');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Role');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function fields(NovaRequest $request)
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->rules('required', 'string', 'max:255', 'unique:roles,name'),
|
||||
|
||||
Text::make(__('Guard name'), 'guard_name')
|
||||
->rules('required', 'string', 'max:255'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\System\Settings\Location\Province\Filters;
|
||||
|
||||
use App\Models\System\Settings\Location\Region;
|
||||
use Laravel\Nova\Filters\Filter;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class RegionFilter extends Filter
|
||||
{
|
||||
/**
|
||||
* The filter's component.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $component = 'select-filter';
|
||||
|
||||
/**
|
||||
* Apply the filter to the given query.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Database\Eloquent\Builder
|
||||
*/
|
||||
public function apply(NovaRequest $request, $query, $value)
|
||||
{
|
||||
return $value
|
||||
? $query->where('region', $value)
|
||||
: $query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter's available options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function options(NovaRequest $request)
|
||||
{
|
||||
return array_flip(Region::values());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\System\Settings\Location\Province;
|
||||
|
||||
use App\Models\System\Settings\Location\Province as ProvinceModel;
|
||||
use App\Models\System\Settings\Location\Region;
|
||||
use App\Nova\Resource;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class Province extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Resources\System\Settings\Location\Province\Province>
|
||||
*/
|
||||
public static $model = ProvinceModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'name';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Provinces');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Province');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Select::make(__('Region'), 'region')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(Region::values())
|
||||
->default(Region::AG)
|
||||
->rules('required')
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Name'), 'name')
|
||||
->rules('required', 'string', 'max:255')
|
||||
->translatable()
|
||||
->sortable(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*/
|
||||
public function filters(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
new Filters\RegionFilter(),
|
||||
];
|
||||
}
|
||||
}
|
||||
122
app/Nova/Resources/System/VersionManagement/AppVersion.php
Normal file
122
app/Nova/Resources/System/VersionManagement/AppVersion.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\System\VersionManagement;
|
||||
|
||||
use App\Models\System\Settings\OS;
|
||||
use App\Models\System\VersionManagement\AppVersion as AppVersionModel;
|
||||
use App\Nova\Resource;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\Select;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class AppVersion extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<AppVersionModel>
|
||||
*/
|
||||
public static $model = AppVersionModel::class;
|
||||
|
||||
/**
|
||||
* The single value that should be used to represent the resource when being displayed.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $title = 'version';
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'version',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('App Versions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('App Version');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
|
||||
Text::make(__('Version'), 'version')
|
||||
->rules('required', 'string', 'max:255')
|
||||
->sortable(),
|
||||
|
||||
Select::make(__('Operating System'), 'os')
|
||||
->displayUsingLabels()
|
||||
->searchable()
|
||||
->options(OS::types())
|
||||
->rules('required', 'string', 'max:255')
|
||||
->sortable(),
|
||||
|
||||
Boolean::make(__('Important'), 'important')
|
||||
->default(false)
|
||||
->rules('required')
|
||||
->sortable(),
|
||||
|
||||
Text::make(__('Notes'), 'notes'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cards(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function filters(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function lenses(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function actions(NovaRequest $request)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
67
app/Nova/Resources/User/UserSearchResource.php
Normal file
67
app/Nova/Resources/User/UserSearchResource.php
Normal file
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Resources\User;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Nova\Resource;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
|
||||
class UserSearchResource extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<\App\Models\Resources\User\UserSearchResource>
|
||||
*/
|
||||
public static $model = User::class;
|
||||
|
||||
/**
|
||||
* The debounce amount (in seconds) to use when searching this resource.
|
||||
*
|
||||
* @var float
|
||||
*/
|
||||
public static $debounce = 1;
|
||||
|
||||
/**
|
||||
* The number of results to display when searching for relatable resources without Scout.
|
||||
*
|
||||
* @var int|null
|
||||
*/
|
||||
public static $relatableSearchResults = 3;
|
||||
|
||||
/**
|
||||
* Get the value that should be displayed to represent the resource.
|
||||
*/
|
||||
public function title(): string
|
||||
{
|
||||
return $this->fullname.' - '.$this->email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the search result subtitle for the resource.
|
||||
*/
|
||||
public function subtitle(): string
|
||||
{
|
||||
return $this->phone_number ? mask_phone($this->phone_number) : '-';
|
||||
}
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'first_name', 'last_name', 'phone_number', 'email',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
];
|
||||
}
|
||||
}
|
||||
183
app/Nova/Seller/Seller.php
Normal file
183
app/Nova/Seller/Seller.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova\Seller;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Nova\Filters\UserRoleFilter;
|
||||
use App\Nova\Filters\VerifiedUsersFilter;
|
||||
use App\Nova\Resource;
|
||||
use App\Nova\Resources\Ecommerce\Channel\Channel;
|
||||
use App\Nova\Resources\Post\UserDocs\UserDocResource;
|
||||
use App\Nova\Resources\System\Roles\Role;
|
||||
use App\Repositories\System\Role\RoleRepository;
|
||||
use Illuminate\Contracts\Database\Eloquent\Builder;
|
||||
use Illuminate\Validation\Rules;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\DateTime;
|
||||
use Laravel\Nova\Fields\HasOne;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\MorphMany;
|
||||
use Laravel\Nova\Fields\MorphToMany;
|
||||
use Laravel\Nova\Fields\Password;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Nurmuhammet\NovaInputmask\NovaInputmask;
|
||||
|
||||
class Seller extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<UserModel::class>
|
||||
*/
|
||||
public static $model = UserModel::class;
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['roles'];
|
||||
|
||||
/**
|
||||
* Get the value that should be displayed to represent the resource.
|
||||
*/
|
||||
public function title(): string
|
||||
{
|
||||
return $this->fullname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the resource should be globally searchable.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $globallySearchable = true;
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'first_name', 'last_name', 'phone_number', 'email',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Sellers');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('Seller');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build an "index" query for the given resource.
|
||||
*
|
||||
* @param \Illuminate\Database\Eloquent\Builder $query
|
||||
*/
|
||||
public static function indexQuery(NovaRequest $request, $query): Builder
|
||||
{
|
||||
return $query->join('model_has_roles', 'id', '=', 'model_id')->where('role_id', RoleRepository::make()->vendorId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource on index page.
|
||||
*/
|
||||
public function fieldsForIndex(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
Text::make(__('Name'), 'fullname')->sortable(),
|
||||
Text::make(__('Phone'), 'phone_number')->sortable(),
|
||||
Text::make(__('Email'), 'email')->sortable(),
|
||||
Text::make(__('Roles'), 'role_names'),
|
||||
Boolean::make(__('Verified'), 'verified')->sortable(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
Text::make(__('First name'), 'first_name')
|
||||
->rules('required', 'string', 'max:255'),
|
||||
|
||||
Text::make(__('Last name'), 'last_name')
|
||||
->rules('required', 'string', 'max:255'),
|
||||
|
||||
Text::make(__('Email'), 'email')
|
||||
->rules('required', 'string', 'max:255')
|
||||
->creationRules('unique:users,email')
|
||||
->updateRules('unique:users,email,{{resourceId}}'),
|
||||
|
||||
NovaInputmask::make(__('Phone'), 'phone_number')
|
||||
->mask(phoneMaskFormat())
|
||||
->storeRawValue()
|
||||
->phoneNumberRule()
|
||||
->canSeeWhen('systemUser', $this)
|
||||
->sortable(),
|
||||
|
||||
Boolean::make(__('Verified'), 'verified')
|
||||
->default(true),
|
||||
|
||||
Password::make(__('Password'), 'password')
|
||||
->onlyOnForms()
|
||||
->creationRules('required', Rules\Password::defaults())
|
||||
->updateRules('nullable', Rules\Password::defaults()),
|
||||
|
||||
DateTime::make(__('Created at'), 'created_at')
|
||||
->displayUsing(fn ($value) => $value?->format('H:i, d.m.Y'))
|
||||
->exceptOnForms(),
|
||||
|
||||
HasOne::make(__('Documents'), 'documents', UserDocResource::class),
|
||||
MorphToMany::make(__('Roles'), 'roles', Role::class),
|
||||
MorphMany::make(__('Channels'), 'channels', Channel::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*/
|
||||
public function cards(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*/
|
||||
public function filters(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
new UserRoleFilter(),
|
||||
new VerifiedUsersFilter(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*/
|
||||
public function lenses(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*/
|
||||
public function actions(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
168
app/Nova/User.php
Normal file
168
app/Nova/User.php
Normal file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace App\Nova;
|
||||
|
||||
use App\Models\User as UserModel;
|
||||
use App\Nova\Resources\Ecommerce\Channel\Channel;
|
||||
use App\Nova\Resources\Post\UserDocs\UserDocResource;
|
||||
use App\Nova\Resources\System\Roles\Role;
|
||||
use Illuminate\Validation\Rules;
|
||||
use Laravel\Nova\Fields\Boolean;
|
||||
use Laravel\Nova\Fields\DateTime;
|
||||
use Laravel\Nova\Fields\HasOne;
|
||||
use Laravel\Nova\Fields\ID;
|
||||
use Laravel\Nova\Fields\MorphMany;
|
||||
use Laravel\Nova\Fields\MorphToMany;
|
||||
use Laravel\Nova\Fields\Password;
|
||||
use Laravel\Nova\Fields\Text;
|
||||
use Laravel\Nova\Http\Requests\NovaRequest;
|
||||
use Nurmuhammet\NovaInputmask\NovaInputmask;
|
||||
|
||||
class User extends Resource
|
||||
{
|
||||
/**
|
||||
* The model the resource corresponds to.
|
||||
*
|
||||
* @var class-string<UserModel::class>
|
||||
*/
|
||||
public static $model = UserModel::class;
|
||||
|
||||
/**
|
||||
* The relationships that should be eager loaded on index queries.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $with = ['roles'];
|
||||
|
||||
/**
|
||||
* Get the value that should be displayed to represent the resource.
|
||||
*/
|
||||
public function title(): string
|
||||
{
|
||||
return $this->fullname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the resource should be globally searchable.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public static $globallySearchable = true;
|
||||
|
||||
/**
|
||||
* The columns that should be searched.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $search = [
|
||||
'id', 'first_name', 'last_name', 'phone_number', 'email',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the displayable label of the resource.
|
||||
*/
|
||||
public static function label(): string
|
||||
{
|
||||
return __('Users');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the displayable singular label of the resource.
|
||||
*/
|
||||
public static function singularLabel(): string
|
||||
{
|
||||
return __('User');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource on index page.
|
||||
*/
|
||||
public function fieldsForIndex(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
ID::make()->sortable(),
|
||||
Text::make(__('Name'), 'fullname')->sortable(),
|
||||
Text::make(__('Phone'), 'phone_number')->sortable(),
|
||||
Text::make(__('Email'), 'email')->sortable(),
|
||||
Text::make(__('Roles'), 'role_names'),
|
||||
Boolean::make(__('Verified'), 'verified')->sortable(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fields displayed by the resource.
|
||||
*/
|
||||
public function fields(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
Text::make(__('First name'), 'first_name')
|
||||
->rules('required', 'string', 'max:255'),
|
||||
|
||||
Text::make(__('Last name'), 'last_name')
|
||||
->rules('required', 'string', 'max:255'),
|
||||
|
||||
Text::make(__('Email'), 'email')
|
||||
->rules('required', 'string', 'max:255')
|
||||
->creationRules('unique:users,email')
|
||||
->updateRules('unique:users,email,{{resourceId}}'),
|
||||
|
||||
NovaInputmask::make(__('Phone'), 'phone_number')
|
||||
->mask(phoneMaskFormat())
|
||||
->storeRawValue()
|
||||
->phoneNumberRule()
|
||||
->canSeeWhen('systemUser', $this)
|
||||
->sortable(),
|
||||
|
||||
Boolean::make(__('Verified'), 'verified')
|
||||
->default(true),
|
||||
|
||||
Password::make(__('Password'), 'password')
|
||||
->onlyOnForms()
|
||||
->creationRules('required', Rules\Password::defaults())
|
||||
->updateRules('nullable', Rules\Password::defaults()),
|
||||
|
||||
DateTime::make(__('Created at'), 'created_at')
|
||||
->displayUsing(fn ($value) => $value?->format('H:i, d.m.Y'))
|
||||
->exceptOnForms(),
|
||||
|
||||
HasOne::make(__('Documents'), 'documents', UserDocResource::class),
|
||||
MorphToMany::make(__('Roles'), 'roles', Role::class),
|
||||
MorphMany::make(__('Channels'), 'channels', Channel::class),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cards available for the request.
|
||||
*/
|
||||
public function cards(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filters available for the resource.
|
||||
*/
|
||||
public function filters(NovaRequest $request): array
|
||||
{
|
||||
return [
|
||||
new Filters\UserRoleFilter(),
|
||||
new Filters\VerifiedUsersFilter(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lenses available for the resource.
|
||||
*/
|
||||
public function lenses(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the actions available for the resource.
|
||||
*/
|
||||
public function actions(NovaRequest $request): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user