wip
This commit is contained in:
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),
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user