Merge branch 'refs/heads/feature/SuppplierPortal' into test
# Conflicts: # public/js/admin.js # public/js/module.js # public/mix-manifest.json
This commit is contained in:
commit
b107cbc0a9
25
app/Enums/StockStatusEnum.php
Normal file
25
app/Enums/StockStatusEnum.php
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Enums;
|
||||||
|
|
||||||
|
enum StockStatusEnum: string
|
||||||
|
{
|
||||||
|
case InStock = 'in_stock';
|
||||||
|
case OutOfStock = 'out_of_stock';
|
||||||
|
|
||||||
|
public function label(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::InStock => 'Raktáron',
|
||||||
|
self::OutOfStock => 'Nincs raktáron',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function color(): string
|
||||||
|
{
|
||||||
|
return match ($this) {
|
||||||
|
self::InStock => 'success',
|
||||||
|
self::OutOfStock => 'danger',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\SupplierPortal\Resources\ProductStocks\Pages;
|
||||||
|
|
||||||
|
use App\Filament\SupplierPortal\Resources\ProductStocks\ProductStockResource;
|
||||||
|
use Filament\Actions\Action;
|
||||||
|
use Filament\Resources\Pages\EditRecord;
|
||||||
|
|
||||||
|
class EditProductStock extends EditRecord
|
||||||
|
{
|
||||||
|
protected static string $resource = ProductStockResource::class;
|
||||||
|
|
||||||
|
protected function getHeaderActions(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
Action::make('back')
|
||||||
|
->label('Vissza a listához')
|
||||||
|
->url(fn () => ProductStockResource::getUrl('index'))
|
||||||
|
->color('gray'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getRedirectUrl(): string
|
||||||
|
{
|
||||||
|
return ProductStockResource::getUrl('index');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\SupplierPortal\Resources\ProductStocks\Pages;
|
||||||
|
|
||||||
|
use App\Filament\SupplierPortal\Resources\ProductStocks\ProductStockResource;
|
||||||
|
use Filament\Resources\Pages\ListRecords;
|
||||||
|
|
||||||
|
class ListProductStocks extends ListRecords
|
||||||
|
{
|
||||||
|
protected static string $resource = ProductStockResource::class;
|
||||||
|
}
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\SupplierPortal\Resources\ProductStocks;
|
||||||
|
|
||||||
|
use App\Filament\SupplierPortal\Resources\ProductStocks\Pages\EditProductStock;
|
||||||
|
use App\Filament\SupplierPortal\Resources\ProductStocks\Pages\ListProductStocks;
|
||||||
|
use App\Filament\SupplierPortal\Resources\ProductStocks\Schemas\ProductStockForm;
|
||||||
|
use App\Filament\SupplierPortal\Resources\ProductStocks\Tables\ProductStocksTable;
|
||||||
|
use App\Models\Product;
|
||||||
|
use BackedEnum;
|
||||||
|
use Filament\Resources\Resource;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
use Filament\Support\Icons\Heroicon;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
use Illuminate\Database\Eloquent\Builder;
|
||||||
|
|
||||||
|
class ProductStockResource extends Resource
|
||||||
|
{
|
||||||
|
protected static ?string $model = Product::class;
|
||||||
|
|
||||||
|
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedCube;
|
||||||
|
|
||||||
|
protected static ?string $navigationLabel = 'Termékeim';
|
||||||
|
|
||||||
|
protected static ?string $breadcrumb = 'Termékeim';
|
||||||
|
|
||||||
|
protected static ?string $modelLabel = 'Termék';
|
||||||
|
|
||||||
|
protected static ?string $pluralLabel = 'Termékeim';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Csak a bejelentkezett supplier saját termékei jelennek meg.
|
||||||
|
*/
|
||||||
|
public static function getEloquentQuery(): Builder
|
||||||
|
{
|
||||||
|
return parent::getEloquentQuery()
|
||||||
|
->where('supplier_id', auth()->user()->supplier_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function form(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return ProductStockForm::configure($schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function table(Table $table): Table
|
||||||
|
{
|
||||||
|
return ProductStocksTable::configure($table);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getPages(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'index' => ListProductStocks::route('/'),
|
||||||
|
'edit' => EditProductStock::route('/{record}/edit'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\SupplierPortal\Resources\ProductStocks\Schemas;
|
||||||
|
|
||||||
|
use App\Enums\StockStatusEnum;
|
||||||
|
use Filament\Forms\Components\Select;
|
||||||
|
use Filament\Schemas\Schema;
|
||||||
|
|
||||||
|
class ProductStockForm
|
||||||
|
{
|
||||||
|
public static function configure(Schema $schema): Schema
|
||||||
|
{
|
||||||
|
return $schema->components([
|
||||||
|
Select::make('stock_status')
|
||||||
|
->label('Készlet státusz')
|
||||||
|
->options(
|
||||||
|
collect(StockStatusEnum::cases())
|
||||||
|
->mapWithKeys(fn (StockStatusEnum $case) => [$case->value => $case->label()])
|
||||||
|
)
|
||||||
|
->required(),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Filament\SupplierPortal\Resources\ProductStocks\Tables;
|
||||||
|
|
||||||
|
use App\Enums\StockStatusEnum;
|
||||||
|
use Filament\Tables\Columns\TextColumn;
|
||||||
|
use Filament\Tables\Columns\ToggleColumn;
|
||||||
|
use Filament\Tables\Table;
|
||||||
|
|
||||||
|
class ProductStocksTable
|
||||||
|
{
|
||||||
|
public static function configure(Table $table): Table
|
||||||
|
{
|
||||||
|
return $table
|
||||||
|
->columns([
|
||||||
|
TextColumn::make('name')
|
||||||
|
->label('Termék neve')
|
||||||
|
->searchable()
|
||||||
|
->sortable(),
|
||||||
|
|
||||||
|
TextColumn::make('sku')
|
||||||
|
->label('Cikkszám')
|
||||||
|
->searchable(),
|
||||||
|
|
||||||
|
ToggleColumn::make('stock_status')
|
||||||
|
->label('Raktáron')
|
||||||
|
->onColor('success')
|
||||||
|
->offColor('danger')
|
||||||
|
->getStateUsing(fn ($record) => $record->stock_status === StockStatusEnum::InStock)
|
||||||
|
->updateStateUsing(function ($record, bool $state) {
|
||||||
|
$record->stock_status = $state
|
||||||
|
? StockStatusEnum::InStock
|
||||||
|
: StockStatusEnum::OutOfStock;
|
||||||
|
$record->save();
|
||||||
|
}),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -135,6 +135,11 @@ private function getSupplierDataFromRequest(Request $request)
|
|||||||
$data['profitCenterId'] = \App\Models\ProfitCenter::whereIn('name', (array) $profitCenterNames)->get()->pluck('id')->toArray();
|
$data['profitCenterId'] = \App\Models\ProfitCenter::whereIn('name', (array) $profitCenterNames)->get()->pluck('id')->toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$data['userId'] = [];
|
||||||
|
if ($userIds = $request->get('userId')) {
|
||||||
|
$data['userId'] = array_map('intval', (array) $userIds);
|
||||||
|
}
|
||||||
|
|
||||||
if ($request->file('logoFile')) {
|
if ($request->file('logoFile')) {
|
||||||
$disk = 'image';
|
$disk = 'image';
|
||||||
// A Storage::path('') visszaadja a disk root könyvtárát
|
// A Storage::path('') visszaadja a disk root könyvtárát
|
||||||
@ -267,6 +272,31 @@ public function destroy(int $SupplierId): Response|JsonResponse
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function createUser(): JsonResponse
|
||||||
|
{
|
||||||
|
$data = \request()->validate([
|
||||||
|
'name' => ['required', 'string', 'max:255'],
|
||||||
|
'email' => ['required', 'email', 'max:255', 'unique:users,email'],
|
||||||
|
'password' => ['required', 'string', 'min:8'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$user = \App\Models\User::create([
|
||||||
|
'name' => $data['name'],
|
||||||
|
'email' => $data['email'],
|
||||||
|
'password' => \Illuminate\Support\Facades\Hash::make($data['password']),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$supplierRole = \App\Models\Role::where('name', 'supplier')->first();
|
||||||
|
if ($supplierRole) {
|
||||||
|
$user->addRole($supplierRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'user' => ['id' => $user->id, 'name' => $user->name, 'email' => $user->email],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function getDataTableContent(): JsonResponse
|
public function getDataTableContent(): JsonResponse
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,10 @@ public function authenticate(Request $request)
|
|||||||
)) {
|
)) {
|
||||||
$request->session()->regenerate();
|
$request->session()->regenerate();
|
||||||
|
|
||||||
|
if (Auth::user()->supplier_id !== null) {
|
||||||
|
return redirect('/supplier-portal/product-stocks');
|
||||||
|
}
|
||||||
|
|
||||||
return redirect()->intended('/');
|
return redirect()->intended('/');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use App\Enums\StockStatusEnum;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
@ -15,6 +16,13 @@ class Product extends BaseAuditable
|
|||||||
protected $guarded = ['id'];
|
protected $guarded = ['id'];
|
||||||
// protected $fillable=['name'];
|
// protected $fillable=['name'];
|
||||||
|
|
||||||
|
protected function casts(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'stock_status' => StockStatusEnum::class,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
public function ProductGroup(): BelongsTo
|
public function ProductGroup(): BelongsTo
|
||||||
{
|
{
|
||||||
return $this->belongsTo(ProductGroup::class);
|
return $this->belongsTo(ProductGroup::class);
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||||
|
|
||||||
class Supplier extends BaseAuditable
|
class Supplier extends BaseAuditable
|
||||||
@ -43,6 +44,11 @@ public function profitCenter(): BelongsToMany
|
|||||||
return $this->belongsToMany(ProfitCenter::class)->withTimestamps();
|
return $this->belongsToMany(ProfitCenter::class)->withTimestamps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function users(): HasMany
|
||||||
|
{
|
||||||
|
return $this->hasMany(User::class);
|
||||||
|
}
|
||||||
|
|
||||||
public function attachment(): \Illuminate\Database\Eloquent\Relations\MorphMany
|
public function attachment(): \Illuminate\Database\Eloquent\Relations\MorphMany
|
||||||
{
|
{
|
||||||
return $this->morphMany(Attachment::class, 'attachable');
|
return $this->morphMany(Attachment::class, 'attachable');
|
||||||
|
|||||||
@ -2,7 +2,10 @@
|
|||||||
|
|
||||||
namespace App\Models;
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Filament\Models\Contracts\FilamentUser;
|
||||||
|
use Filament\Panel;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||||
use Illuminate\Notifications\Notifiable;
|
use Illuminate\Notifications\Notifiable;
|
||||||
@ -14,7 +17,7 @@
|
|||||||
/**
|
/**
|
||||||
* @property Collection<ProfitCenter> profitCenters
|
* @property Collection<ProfitCenter> profitCenters
|
||||||
*/
|
*/
|
||||||
class User extends Authenticatable implements LaratrustUser
|
class User extends Authenticatable implements LaratrustUser, FilamentUser
|
||||||
{
|
{
|
||||||
use HasApiTokens, HasFactory, Notifiable;
|
use HasApiTokens, HasFactory, Notifiable;
|
||||||
use HasRolesAndPermissions;
|
use HasRolesAndPermissions;
|
||||||
@ -29,6 +32,7 @@ class User extends Authenticatable implements LaratrustUser
|
|||||||
'name',
|
'name',
|
||||||
'email',
|
'email',
|
||||||
'password',
|
'password',
|
||||||
|
'supplier_id',
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -60,4 +64,18 @@ public function profitCenters(): BelongsToMany
|
|||||||
{
|
{
|
||||||
return $this->belongsToMany(ProfitCenter::class, 'profit_center_users')->withTimestamps();
|
return $this->belongsToMany(ProfitCenter::class, 'profit_center_users')->withTimestamps();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function supplier(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Supplier::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canAccessPanel(Panel $panel): bool
|
||||||
|
{
|
||||||
|
return match ($panel->getId()) {
|
||||||
|
'admin' => $this->hasRole(['root', 'developer', 'admin', 'profit-center']),
|
||||||
|
'supplierPortal' => $this->hasRole('supplier'),
|
||||||
|
default => false,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
75
app/Policies/ProductPolicy.php
Normal file
75
app/Policies/ProductPolicy.php
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Policies;
|
||||||
|
|
||||||
|
use App\Models\Product;
|
||||||
|
use App\Models\User;
|
||||||
|
use Illuminate\Auth\Access\Response;
|
||||||
|
|
||||||
|
class ProductPolicy
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view any models.
|
||||||
|
*/
|
||||||
|
public function viewAny(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->hasRole(['root', 'developer', 'admin', 'supplier']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view the model.
|
||||||
|
*/
|
||||||
|
public function view(User $user, Product $product): bool
|
||||||
|
{
|
||||||
|
if ($user->hasRole('supplier')) {
|
||||||
|
return $user->supplier_id === $product->supplier_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user->hasRole(['root', 'developer', 'admin']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can create models.
|
||||||
|
*/
|
||||||
|
public function create(User $user): bool
|
||||||
|
{
|
||||||
|
return $user->hasRole(['root', 'developer', 'admin']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Csak akkor engedélyezett a szerkesztés, ha a termék
|
||||||
|
* a bejelentkezett supplier-hez tartozik.
|
||||||
|
*/
|
||||||
|
public function update(User $user, Product $product): bool
|
||||||
|
{
|
||||||
|
if ($user->hasRole('supplier')) {
|
||||||
|
return $user->supplier_id === $product->supplier_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $user->hasRole(['root', 'developer', 'admin']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can delete the model.
|
||||||
|
*/
|
||||||
|
public function delete(User $user, Product $product): bool
|
||||||
|
{
|
||||||
|
return $user->hasRole(['root', 'developer', 'admin']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can restore the model.
|
||||||
|
*/
|
||||||
|
public function restore(User $user, Product $product): bool
|
||||||
|
{
|
||||||
|
return $user->hasRole(['root', 'developer', 'admin']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can permanently delete the model.
|
||||||
|
*/
|
||||||
|
public function forceDelete(User $user, Product $product): bool
|
||||||
|
{
|
||||||
|
return $user->hasRole(['root', 'developer', 'admin']);
|
||||||
|
}
|
||||||
|
}
|
||||||
83
app/Providers/Filament/SupplierPanelProvider.php
Normal file
83
app/Providers/Filament/SupplierPanelProvider.php
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Providers\Filament;
|
||||||
|
|
||||||
|
use Filament\Http\Middleware\Authenticate;
|
||||||
|
use Filament\Http\Middleware\AuthenticateSession;
|
||||||
|
use Filament\Http\Middleware\DisableBladeIconComponents;
|
||||||
|
use Filament\Http\Middleware\DispatchServingFilamentEvent;
|
||||||
|
use Filament\Panel;
|
||||||
|
use Filament\PanelProvider;
|
||||||
|
use Filament\Support\Colors\Color;
|
||||||
|
use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
|
||||||
|
use Illuminate\Cookie\Middleware\EncryptCookies;
|
||||||
|
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken;
|
||||||
|
use Illuminate\Routing\Middleware\SubstituteBindings;
|
||||||
|
use Illuminate\Session\Middleware\StartSession;
|
||||||
|
use Illuminate\View\Middleware\ShareErrorsFromSession;
|
||||||
|
|
||||||
|
class SupplierPanelProvider extends PanelProvider
|
||||||
|
{
|
||||||
|
public function panel(Panel $panel): Panel
|
||||||
|
{
|
||||||
|
return $panel
|
||||||
|
->id('supplierPortal')
|
||||||
|
->path('supplier-portal')
|
||||||
|
->login()
|
||||||
|
->brandName(fn () => auth()->check() && auth()->user()->supplier
|
||||||
|
? 'Beszállítói Portál – ' . auth()->user()->supplier->name
|
||||||
|
: 'Beszállítói Portál')
|
||||||
|
->colors([
|
||||||
|
'primary' => '#b83400',
|
||||||
|
'gray' => [
|
||||||
|
50 => '#f6f5f0',
|
||||||
|
100 => '#eceadf',
|
||||||
|
200 => '#d1cfc0',
|
||||||
|
300 => '#b4b19b',
|
||||||
|
400 => '#9e9b81',
|
||||||
|
500 => '#7d775c',
|
||||||
|
600 => '#6d6850',
|
||||||
|
700 => '#453821',
|
||||||
|
800 => '#3a301c',
|
||||||
|
900 => '#2d2516',
|
||||||
|
950 => '#1f1a0f',
|
||||||
|
],
|
||||||
|
'danger' => Color::Red,
|
||||||
|
'info' => Color::Blue,
|
||||||
|
'success' => Color::Emerald,
|
||||||
|
'warning' => Color::Orange,
|
||||||
|
])
|
||||||
|
->font('Trebuchet MS')
|
||||||
|
->discoverResources(
|
||||||
|
in: app_path('Filament/SupplierPortal/Resources'),
|
||||||
|
for: 'App\Filament\SupplierPortal\Resources'
|
||||||
|
)
|
||||||
|
->discoverPages(
|
||||||
|
in: app_path('Filament/SupplierPortal/Pages'),
|
||||||
|
for: 'App\Filament\SupplierPortal\Pages'
|
||||||
|
)
|
||||||
|
->pages([])
|
||||||
|
->discoverWidgets(
|
||||||
|
in: app_path('Filament/SupplierPortal/Widgets'),
|
||||||
|
for: 'App\Filament\SupplierPortal\Widgets'
|
||||||
|
)
|
||||||
|
->widgets([])
|
||||||
|
->middleware([
|
||||||
|
EncryptCookies::class,
|
||||||
|
AddQueuedCookiesToResponse::class,
|
||||||
|
StartSession::class,
|
||||||
|
AuthenticateSession::class,
|
||||||
|
ShareErrorsFromSession::class,
|
||||||
|
VerifyCsrfToken::class,
|
||||||
|
SubstituteBindings::class,
|
||||||
|
DisableBladeIconComponents::class,
|
||||||
|
DispatchServingFilamentEvent::class,
|
||||||
|
])
|
||||||
|
->authMiddleware([
|
||||||
|
Authenticate::class,
|
||||||
|
])
|
||||||
|
->darkMode(false)
|
||||||
|
->breadcrumbs(false)
|
||||||
|
->navigation(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -9,7 +9,7 @@ class SupplierRepository extends RepositoryBase implements SupplierRepositoryInt
|
|||||||
/**
|
/**
|
||||||
* @var array[]
|
* @var array[]
|
||||||
*/
|
*/
|
||||||
private array $defaultRelations = ['contact', 'productGroup', 'attachment', 'service'];
|
private array $defaultRelations = ['contact', 'productGroup', 'attachment', 'service', 'users'];
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@ -96,6 +96,16 @@ public function syncProfitCenter($supplierId, $profitCenterIds = []): bool
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function syncUsers($supplierId, $userIds = []): bool
|
||||||
|
{
|
||||||
|
\App\Models\User::where('supplier_id', $supplierId)->whereNotIn('id', $userIds)->update(['supplier_id' => null]);
|
||||||
|
if (count($userIds) > 0) {
|
||||||
|
\App\Models\User::whereIn('id', $userIds)->update(['supplier_id' => $supplierId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get's a record by it's ID
|
* Get's a record by it's ID
|
||||||
*
|
*
|
||||||
|
|||||||
@ -19,4 +19,6 @@ public function syncProductGroup($supplierId, $productGroupIds = []): bool;
|
|||||||
public function syncService($supplierId, $productGroupIds = []): bool;
|
public function syncService($supplierId, $productGroupIds = []): bool;
|
||||||
|
|
||||||
public function syncProfitCenter($supplierId, $profitCenterIds = []): bool;
|
public function syncProfitCenter($supplierId, $profitCenterIds = []): bool;
|
||||||
|
|
||||||
|
public function syncUsers($supplierId, $userIds = []): bool;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,13 +53,19 @@ public function syncProfitCenter($supplierId, $profitCenterIds = []): bool
|
|||||||
return $this->Repository->syncProfitCenter($supplierId, $profitCenterIds);
|
return $this->Repository->syncProfitCenter($supplierId, $profitCenterIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function syncUsers($supplierId, $userIds = []): bool
|
||||||
|
{
|
||||||
|
return $this->Repository->syncUsers($supplierId, $userIds);
|
||||||
|
}
|
||||||
|
|
||||||
public function add($data): ?int
|
public function add($data): ?int
|
||||||
{
|
{
|
||||||
$contactIds = $data['contactId'];
|
$contactIds = $data['contactId'];
|
||||||
$productGroupId = $data['productGroupId'];
|
$productGroupId = $data['productGroupId'];
|
||||||
$serviceId = $data['serviceId'];
|
$serviceId = $data['serviceId'];
|
||||||
$profitCenterId = $data['profitCenterId'];
|
$profitCenterId = $data['profitCenterId'];
|
||||||
unset($data['contactId'],$data['productGroupId']);
|
$userIds = $data['userId'] ?? [];
|
||||||
|
unset($data['contactId'], $data['productGroupId'], $data['userId']);
|
||||||
if (! $supplierId = parent::add($data)) {
|
if (! $supplierId = parent::add($data)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -67,6 +73,7 @@ public function add($data): ?int
|
|||||||
$this->addProductGroup($supplierId, $productGroupId);
|
$this->addProductGroup($supplierId, $productGroupId);
|
||||||
$this->syncService($supplierId, $serviceId);
|
$this->syncService($supplierId, $serviceId);
|
||||||
$this->syncProfitCenter($supplierId, $profitCenterId);
|
$this->syncProfitCenter($supplierId, $profitCenterId);
|
||||||
|
$this->syncUsers($supplierId, $userIds);
|
||||||
|
|
||||||
return $supplierId;
|
return $supplierId;
|
||||||
}
|
}
|
||||||
@ -83,12 +90,14 @@ public function update($id, array $data): bool
|
|||||||
$productGroupId = $data['productGroupId'];
|
$productGroupId = $data['productGroupId'];
|
||||||
$serviceId = $data['serviceId'];
|
$serviceId = $data['serviceId'];
|
||||||
$profitCenterId = $data['profitCenterId'];
|
$profitCenterId = $data['profitCenterId'];
|
||||||
unset($data['contactId'],$data['productGroupId']);
|
$userIds = $data['userId'] ?? [];
|
||||||
|
unset($data['contactId'], $data['productGroupId'], $data['userId']);
|
||||||
if ($this->Repository->update($id, $data)) {
|
if ($this->Repository->update($id, $data)) {
|
||||||
$this->syncContact($id, $contactIds);
|
$this->syncContact($id, $contactIds);
|
||||||
$this->syncProductGroup($id, $productGroupId);
|
$this->syncProductGroup($id, $productGroupId);
|
||||||
$this->syncService($id, $serviceId);
|
$this->syncService($id, $serviceId);
|
||||||
$this->syncProfitCenter($id, $profitCenterId);
|
$this->syncProfitCenter($id, $profitCenterId);
|
||||||
|
$this->syncUsers($id, $userIds);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,4 +3,5 @@
|
|||||||
return [
|
return [
|
||||||
App\Providers\AppServiceProvider::class,
|
App\Providers\AppServiceProvider::class,
|
||||||
App\Providers\Filament\AdminPanelProvider::class,
|
App\Providers\Filament\AdminPanelProvider::class,
|
||||||
|
App\Providers\Filament\SupplierPanelProvider::class,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->foreignId('supplier_id')->nullable()->after('id')->constrained('suppliers')->nullOnDelete();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->dropForeign(['supplier_id']);
|
||||||
|
$table->dropColumn('supplier_id');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('products', function (Blueprint $table) {
|
||||||
|
$table->string('stock_status')->default('in_stock')->after('status');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('products', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('stock_status');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
34
database/seeders/SupplierRoleSeeder.php
Normal file
34
database/seeders/SupplierRoleSeeder.php
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use App\Models\Permission;
|
||||||
|
use App\Models\Role;
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
|
||||||
|
class SupplierRoleSeeder extends Seeder
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the database seeds.
|
||||||
|
*/
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
$permission = Permission::firstOrCreate(
|
||||||
|
['name' => 'update_own_product_stock_status'],
|
||||||
|
[
|
||||||
|
'display_name' => 'Saját termék készlet státusz módosítása',
|
||||||
|
'description' => 'A beszállító módosíthatja a saját termékei raktárkészlet státuszát',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$role = Role::firstOrCreate(
|
||||||
|
['name' => 'supplier'],
|
||||||
|
[
|
||||||
|
'display_name' => 'Beszállító',
|
||||||
|
'description' => 'Supplier Portal hozzáférés',
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$role->givePermission($permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -51,6 +51,7 @@ window.SupplierAdmin=function (options,SupplierItem) {
|
|||||||
destroy:'',
|
destroy:'',
|
||||||
attachFile:'',
|
attachFile:'',
|
||||||
detachFile:'',
|
detachFile:'',
|
||||||
|
createUser:'',
|
||||||
},
|
},
|
||||||
dataTable:{
|
dataTable:{
|
||||||
orderDirective:[1, 'asc']
|
orderDirective:[1, 'asc']
|
||||||
@ -255,6 +256,9 @@ window.SupplierAdmin=function (options,SupplierItem) {
|
|||||||
if(typeof root.Supplier['logoFile']!='undefined' && (root.Supplier['logoFile'])){
|
if(typeof root.Supplier['logoFile']!='undefined' && (root.Supplier['logoFile'])){
|
||||||
$(CSSSelectorForm+' img.imageLogo').attr('src',root.Supplier['logoFile']);
|
$(CSSSelectorForm+' img.imageLogo').attr('src',root.Supplier['logoFile']);
|
||||||
}
|
}
|
||||||
|
if(typeof root.Supplier.users !== 'undefined'){
|
||||||
|
root.resetUserTable();
|
||||||
|
}
|
||||||
|
|
||||||
//debug(APP.SupplierAdmin.formDataToDataObjectAPICall('.supplierForm')['productGroup']);
|
//debug(APP.SupplierAdmin.formDataToDataObjectAPICall('.supplierForm')['productGroup']);
|
||||||
//$('[name=productGroup]').val(['Büféáru_édesipari_termékek','Tojás']).change();
|
//$('[name=productGroup]').val(['Büféáru_édesipari_termékek','Tojás']).change();
|
||||||
@ -300,6 +304,7 @@ window.SupplierAdmin=function (options,SupplierItem) {
|
|||||||
$('form.supplierForm button.FormSaveButton').off('click');
|
$('form.supplierForm button.FormSaveButton').off('click');
|
||||||
$('form.supplierForm button.FormSaveButton').on('click',root.clickSaveButton);
|
$('form.supplierForm button.FormSaveButton').on('click',root.clickSaveButton);
|
||||||
root.setDetailsViewData();
|
root.setDetailsViewData();
|
||||||
|
root.initUserCreate();
|
||||||
$(".productCategorySelect").select2();
|
$(".productCategorySelect").select2();
|
||||||
$(".serviceSelect").select2({
|
$(".serviceSelect").select2({
|
||||||
tags: true,
|
tags: true,
|
||||||
@ -834,5 +839,93 @@ window.SupplierAdmin=function (options,SupplierItem) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.resetUserTable=function (){
|
||||||
|
$('.supplierUserTable tbody tr').remove();
|
||||||
|
root.renderUsers();
|
||||||
|
}
|
||||||
|
this.renderUsers=function (){
|
||||||
|
let rowNum=1;
|
||||||
|
let users=root.Supplier.users||[];
|
||||||
|
$.each(users,function (){
|
||||||
|
let userData=$.extend({},this);
|
||||||
|
userData.rowNum=rowNum;
|
||||||
|
let template=$('template[data-name="supplierUserTableRow"]').html();
|
||||||
|
let render=Mustache.render(template,userData);
|
||||||
|
$('.supplierUserTable tbody').append(render);
|
||||||
|
rowNum++;
|
||||||
|
});
|
||||||
|
root.bindUserClickAction();
|
||||||
|
}
|
||||||
|
this.bindUserClickAction=function (){
|
||||||
|
let node=$('.supplierUserTable .buttonDelete');
|
||||||
|
node.unbind('click');
|
||||||
|
node.bind('click',root.userDeleteClick);
|
||||||
|
}
|
||||||
|
this.userDeleteClick=function (){
|
||||||
|
let row=$(this).closest('tr');
|
||||||
|
let id=row.find('input[name=userId]').val()*1;
|
||||||
|
root.Supplier.users=root.Supplier.users.filter(function (value){
|
||||||
|
return value.id!==id;
|
||||||
|
});
|
||||||
|
row.remove();
|
||||||
|
root.resetUserTable();
|
||||||
|
}
|
||||||
|
this.addUser=function (userData){
|
||||||
|
if(!root.Supplier.users){ root.Supplier.users=[]; }
|
||||||
|
let alreadyAdded=root.Supplier.users.some(function(u){ return u.id===userData.id; });
|
||||||
|
if(alreadyAdded){ return; }
|
||||||
|
root.Supplier.users.push(userData);
|
||||||
|
userData.rowNum=root.Supplier.users.length;
|
||||||
|
let template=$('template[data-name="supplierUserTableRow"]').html();
|
||||||
|
let render=Mustache.render(template,userData);
|
||||||
|
$('.supplierUserTable tbody').append(render);
|
||||||
|
root.bindUserClickAction();
|
||||||
|
Toast.enableTimers(false);
|
||||||
|
Toast.create({ title: 'Felhasználó hozzáadva!', message: userData.name+' hozzárendelve', status: TOAST_STATUS.SUCCESS, timeout: 3000 });
|
||||||
|
}
|
||||||
|
this.initUserCreate=function (){
|
||||||
|
let createUrl=Opts.URL.createUser||'';
|
||||||
|
let container=$(Opts.containerCssSelector);
|
||||||
|
function clearForm(){
|
||||||
|
container.find('.supplierNewUserName').val('');
|
||||||
|
container.find('.supplierNewUserEmail').val('');
|
||||||
|
container.find('.supplierNewUserPassword').val('');
|
||||||
|
container.find('.supplierNewUserError').hide().text('');
|
||||||
|
}
|
||||||
|
container.find('.buttonCreateUser').off('click').on('click',function(){
|
||||||
|
let name=container.find('.supplierNewUserName').val().trim();
|
||||||
|
let email=container.find('.supplierNewUserEmail').val().trim();
|
||||||
|
let password=container.find('.supplierNewUserPassword').val();
|
||||||
|
let errorEl=container.find('.supplierNewUserError');
|
||||||
|
errorEl.hide().text('');
|
||||||
|
if(!name||!email||!password){
|
||||||
|
errorEl.text('Minden mező kitöltése kötelező!').show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.ajax({
|
||||||
|
url:createUrl,
|
||||||
|
type:'POST',
|
||||||
|
data:{name:name, email:email, password:password},
|
||||||
|
headers:{'X-CSRF-TOKEN': $('input[name="_token"]').val()},
|
||||||
|
success:function(data){
|
||||||
|
if(data.success){
|
||||||
|
root.addUser(data.user);
|
||||||
|
clearForm();
|
||||||
|
}else{
|
||||||
|
errorEl.text('Hiba történt a felhasználó létrehozásakor!').show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error:function(xhr){
|
||||||
|
let msg='Hiba történt!';
|
||||||
|
if(xhr.responseJSON&&xhr.responseJSON.errors){
|
||||||
|
let errors=xhr.responseJSON.errors;
|
||||||
|
let firstKey=Object.keys(errors)[0];
|
||||||
|
msg=errors[firstKey][0];
|
||||||
|
}
|
||||||
|
errorEl.text(msg).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
this.construct(options,SupplierItem);
|
this.construct(options,SupplierItem);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -118,6 +118,71 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-sm-2 col-form-label">Supplier Portal felhasználók:</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<div class="card mb-2">
|
||||||
|
<div class="card-header">Új felhasználó hozzáadása</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="form-group row mb-2">
|
||||||
|
<label class="col-sm-2 col-form-label col-form-label-sm">Név</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="text" class="form-control form-control-sm supplierNewUserName" placeholder="Felhasználó neve">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row mb-2">
|
||||||
|
<label class="col-sm-2 col-form-label col-form-label-sm">E-mail</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="email" class="form-control form-control-sm supplierNewUserEmail" placeholder="E-mail cím">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row mb-2">
|
||||||
|
<label class="col-sm-2 col-form-label col-form-label-sm">Jelszó</label>
|
||||||
|
<div class="col-sm-10">
|
||||||
|
<input type="password" class="form-control form-control-sm supplierNewUserPassword" placeholder="Jelszó">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row mb-0">
|
||||||
|
<div class="col-sm-10 offset-sm-2">
|
||||||
|
<button type="button" class="btn btn-primary btn-sm buttonCreateUser">Felhasználó létrehozása</button>
|
||||||
|
<span class="supplierNewUserError text-danger ml-2" style="display:none;"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group row">
|
||||||
|
<div class="col">
|
||||||
|
<table class="table table-striped table-hover table-sm supplierUserTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col">#</th>
|
||||||
|
<th scope="col">Név</th>
|
||||||
|
<th scope="col">E-mail</th>
|
||||||
|
<th scope="col">Akció</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<template data-name="supplierUserTableRow">
|
||||||
|
<tr>
|
||||||
|
<th scope="row">[[rowNum]]
|
||||||
|
<input type="hidden" name="userId" value="[[id]]"/>
|
||||||
|
</th>
|
||||||
|
<td>[[name]]</td>
|
||||||
|
<td>[[email]]</td>
|
||||||
|
<td>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm buttonDelete" data-toggle="tooltip" data-placement="bottom" title="Törlés">
|
||||||
|
<span class="fas fa-trash"></span>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group row">
|
<div class="form-group row">
|
||||||
<label for="OrderEmail" class="col-sm-2 col-form-label" >E-mail:</label>
|
<label for="OrderEmail" class="col-sm-2 col-form-label" >E-mail:</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
|||||||
@ -81,6 +81,7 @@
|
|||||||
destroy:'{{route('admin.supplier.destroy',"%id%")}}',
|
destroy:'{{route('admin.supplier.destroy',"%id%")}}',
|
||||||
attachFile:'{{route('admin.supplier.attachFile',"%id%")}}',
|
attachFile:'{{route('admin.supplier.attachFile',"%id%")}}',
|
||||||
detachFile:'{{route('admin.supplier.detachFile',"%id%")}}',
|
detachFile:'{{route('admin.supplier.detachFile',"%id%")}}',
|
||||||
|
createUser:'{{route('admin.supplier.createUser')}}',
|
||||||
},
|
},
|
||||||
testMode:{{$testMode}}
|
testMode:{{$testMode}}
|
||||||
},APP.Supplier);
|
},APP.Supplier);
|
||||||
|
|||||||
@ -186,6 +186,7 @@ function () {
|
|||||||
// Route::resource('/supplier', SupplierControllerAdmin::class);
|
// Route::resource('/supplier', SupplierControllerAdmin::class);
|
||||||
Route::prefix('supplier')->name('supplier.')->group(function () {
|
Route::prefix('supplier')->name('supplier.')->group(function () {
|
||||||
Route::get('getDataTableContent', [SupplierControllerAdmin::class, 'getDataTableContent'])->name('getDataTableContent');
|
Route::get('getDataTableContent', [SupplierControllerAdmin::class, 'getDataTableContent'])->name('getDataTableContent');
|
||||||
|
Route::post('createUser', [SupplierControllerAdmin::class, 'createUser'])->name('createUser');
|
||||||
Route::post('/{id}/attachFile', [SupplierControllerAdmin::class, 'attachFile'])->name('attachFile');
|
Route::post('/{id}/attachFile', [SupplierControllerAdmin::class, 'attachFile'])->name('attachFile');
|
||||||
Route::post('/{id}/detachFile', [SupplierControllerAdmin::class, 'detachFile'])->name('detachFile');
|
Route::post('/{id}/detachFile', [SupplierControllerAdmin::class, 'detachFile'])->name('detachFile');
|
||||||
Route::resource('/', SupplierControllerAdmin::class)->parameters(['' => 'supplier']);
|
Route::resource('/', SupplierControllerAdmin::class)->parameters(['' => 'supplier']);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user