Bläddra i källkod

Added orders pages

Alexander Musikhin 9 månader sedan
förälder
incheckning
973de21df3

+ 5 - 0
app/Http/Controllers/AreaController.php

@@ -45,4 +45,9 @@ class AreaController extends Controller
 
         return response()->json();
     }
+
+    public function ajaxGetAreasByDistrict($district_id = null)
+    {
+        return Area::query()->where('district_id', '=', (int) $district_id)->pluck('name', 'id')->toArray();
+    }
 }

+ 8 - 2
app/Http/Controllers/OrderController.php

@@ -2,8 +2,11 @@
 
 namespace App\Http\Controllers;
 
+use App\Models\Brigadier;
 use App\Models\Dictionary\Area;
 use App\Models\Dictionary\District;
+use App\Models\ObjectType;
+use App\Models\OrderStatus;
 use Illuminate\Http\Request;
 
 class OrderController extends Controller
@@ -46,8 +49,11 @@ class OrderController extends Controller
      */
     public function create()
     {
-        $this->data['districts'] = District::get()->pluck('name', 'id');
-        $this->data['areas'] = Area::get()->pluck('name', 'id');
+        $this->data['districts'] = District::query()->get()->pluck('name', 'id');
+        $this->data['areas'] = Area::query()->get()->pluck('name', 'id');
+        $this->data['objectTypes'] = ObjectType::query()->get()->pluck('name', 'id');
+        $this->data['orderStatuses'] =OrderStatus::query()->get()->pluck('name', 'id');
+        $this->data['brigadiers'] = Brigadier::query()->get()->pluck('name', 'id');
         return view('orders.edit', $this->data);
     }
 

+ 36 - 3
app/Models/Order.php

@@ -2,23 +2,56 @@
 
 namespace App\Models;
 
+use App\Models\Dictionary\Area;
+use App\Models\Dictionary\District;
 use Illuminate\Database\Eloquent\Model;
+use Illuminate\Database\Eloquent\Relations\BelongsTo;
 
 class Order extends Model
 {
     protected $fillable = [
-        'client_id',
         'user_id',
         'district_id',
         'area_id',
         'object_address',
-        'object_type',
+        'object_type_id',
         'contract_date',
         'contract_number',
         'comment',
         'installation_date',
-        'brigadier',
+        'brigadier_id',
+        'order_status_id',
         'tg_group_name',
         'tg_group_link',
     ];
+
+    public function manager(): BelongsTo
+    {
+        return $this->belongsTo(User::class, 'user_id', 'id');
+    }
+
+    public function district(): BelongsTo
+    {
+        return $this->belongsTo(District::class);
+    }
+
+    public function area(): BelongsTo
+    {
+        return $this->belongsTo(Area::class);
+    }
+
+    public function objectType(): BelongsTo
+    {
+        return $this->belongsTo(ObjectType::class);
+    }
+
+    public function brigadier(): BelongsTo
+    {
+        return $this->belongsTo(Brigadier::class);
+    }
+
+    public function orderStatus(): BelongsTo
+    {
+        return $this->belongsTo(OrderStatus::class);
+    }
 }

+ 5 - 6
database/migrations/2025_03_24_153700_create_orders_table.php

@@ -13,12 +13,11 @@ return new class extends Migration
     {
         Schema::create('orders', function (Blueprint $table) {
             $table->id();
-            $table->foreignId('client_id')->constrained('clients')->restrictOnDelete();    // клиент
-            $table->foreignId('user_id')->constrained('users')->restrictOnDelete();        // менеджер
-            $table->foreignId('district_id')->constrained('districts')->restrictOnDelete();// округ
-            $table->foreignId('area_id')->constrained('areas')->restrictOnDelete();        // район
-            $table->string('object_address');                                                   // адрес объекта
-            $table->foreignId('object_type_id')->constrained('object_types')->restrictOnDelete();// тип объекта
+            $table->foreignId('user_id')->constrained('users')->restrictOnDelete();                 // менеджер
+            $table->foreignId('district_id')->constrained('districts')->restrictOnDelete();         // округ
+            $table->foreignId('area_id')->constrained('areas')->restrictOnDelete();                 // район
+            $table->string('object_address');                                                            // адрес объекта
+            $table->foreignId('object_type_id')->constrained('object_types')->restrictOnDelete();   // тип объекта
             $table->date('contract_date')->nullable();                                          // дата договора
             $table->string('contract_number')->nullable();                                      // номер дог-ра
             $table->text('comment')->nullable();                                                // комментарий

+ 1 - 0
database/seeders/DatabaseSeeder.php

@@ -26,5 +26,6 @@ class DatabaseSeeder extends Seeder
         $this->call(AreaSeeder::class);
         $this->call(ObjectTypeSeeder::class);
         $this->call(OrderStatusSeeder::class);
+        $this->call(BrigadierSeeder::class);
     }
 }

+ 3 - 1
resources/views/layouts/menu.blade.php

@@ -1,5 +1,7 @@
+<li class="nav-item"><a class="nav-link" href="{{ route('order.index') }}">Заказы (площадки)</a></li>
+
+<li class="nav-item"><a class="nav-link" href="{{ route('catalog.index') }}">Каталог</a></li>
 
 @if(hasrole('admin'))
     <li class="nav-item"><a class="nav-link" href="{{ route('user.index') }}">Пользователи</a></li>
 @endif
-<li class="nav-item"><a class="nav-link" href="{{ route('catalog.index') }}">Каталог</a></li>

+ 58 - 0
resources/views/orders/edit.blade.php

@@ -0,0 +1,58 @@
+@extends('layouts.app')
+
+@section('content')
+    <div class="px-3">
+        <div class="col-xxl-6 offset-xxl-2">
+            <form action="{{ route('order.store') }}" method="post">
+                @csrf
+
+                @if(isset($order))
+                    <input type="hidden" name="id" value="{{ $order->id }}">
+                @endif
+
+                @include('partials.select', ['name' => 'district_id', 'title' => 'Округ', 'options' => $districts, 'value' => $order?->$district_id ?? null, 'first_empty' => true, 'required' => true])
+
+                @include('partials.select', ['name' => 'area_id', 'title' => 'Район', 'options' => [] /* $areas */, 'value' => $order?->area_id ?? null, 'required' => true])
+
+                @include('partials.input', ['name' => 'object_address', 'title' => 'Адрес объекта', 'value' => $order->object_address ?? '', 'required' => true])
+
+                @include('partials.select', ['name' => 'object_type', 'title' => 'Тип объекта', 'options' => $objectTypes, 'value' => $order->object_type ?? null, 'required' => true, 'first_empty' => true])
+
+                @include('partials.input', ['name' => 'contract_date', 'title' => 'Дата договора', 'type' => 'date', 'value' => $order->contract_date ?? ''])
+
+                @include('partials.input', ['name' => 'contract_number', 'title' => 'Номер договора', 'value' => $order->contract_number ?? ''])
+
+                @include('partials.textarea', ['name' => 'comment', 'title' => 'Комментарий', 'value' => $order->comment ?? ''])
+
+                @include('partials.input', ['name' => 'installation_date', 'title' => 'Дата выхода на монтаж', 'type' => 'date', 'value' => $order->installation_date ?? ''])
+
+                @include('partials.select', ['name' => 'brigadier', 'title' => 'Бригадир', 'options' => $brigadiers, 'value' => $order->brigadier ?? ''])
+
+                @include('partials.input', ['name' => 'tg_group_name', 'title' => 'Группа в ТГ', 'value' => $order->tg_group_name ?? ''])
+
+                @include('partials.submit')
+            </form>
+        </div>
+    </div>
+@endsection
+
+@push('scripts')
+    <script type="module">
+        $('#district_id').on('change', function () {
+            // load areas of selected district
+            console.log($(this).val());
+
+            $.get('{{ route('area.ajax-get-areas-by-district') }}/'+$(this).val(),
+                function (data) {
+                    $('#area_id').children().remove();
+                    $.each(data, function (id, name) {
+                        $('#area_id').append('<option value=\'' + id + '\'>' + name + '</option>');
+                    });
+                    console.log(data);
+                }
+            );
+        });
+
+    </script>
+
+@endpush

+ 13 - 0
resources/views/orders/index.blade.php

@@ -0,0 +1,13 @@
+@extends('layouts.app')
+
+@section('content')
+    <a href="{{ route('order.create') }}" class="btn btn-sm btn-primary">Создать</a>
+    <div class="px-md-3 px-2">
+        orders
+    </div>
+
+    @if($errors->any())
+        @dump($errors)
+    @endif
+
+@endsection

+ 12 - 2
resources/views/partials/select.blade.php

@@ -1,7 +1,17 @@
 <div class="row mb-{{ ($mb ?? 3) }}">
-    <label for="{{ $name }}" class="col-form-label @if(!($right ?? null)) col-md-4 text-md-end @endif mt-1">{{ $title }}</label>
+    <label for="{{ $name }}" class="col-form-label @if(!($right ?? null)) col-md-4 text-md-end @endif mt-1">
+        {{ $title }}
+        @isset($required) <sup>*</sup> @endisset
+    </label>
     <div class="@if(!($right ?? null)) col-md-8 @endif">
-        <select name="{{ $name }}" id="{{ $name }}" class="form-select @error($name) is-invalid @enderror" >
+        <select name="{{ $name }}"
+                id="{{ $name }}"
+                class="form-select @error($name) is-invalid @enderror class-{{ $name }}"
+                @required($required ?? null)
+                @disabled($disabled ?? null)>
+            @if(isset($first_empty))
+                <option value="" class="first-empty-{{ $name }}">Выберите...</option>
+            @endif
             @foreach($options as $k => $v)
                 @php
                     if(isset($key_as_val)) $k = $v;

+ 14 - 0
routes/web.php

@@ -1,5 +1,7 @@
 <?php
 
+use App\Http\Controllers\AreaController;
+use App\Http\Controllers\OrderController;
 use App\Http\Controllers\ProductController;
 use App\Http\Controllers\UserController;
 use App\Models\Role;
@@ -32,11 +34,23 @@ Route::middleware('auth:web')->group(function () {
     Route::get('profile', [UserController::class, 'profile'])->name('user.profile');
     Route::post('profile/store', [UserController::class, 'storeProfile'])->name('profile.store');
 
+    // catalog
     Route::get('catalog', [ProductController::class, 'index'])->name('catalog.index');
     Route::get('catalog/{product}', [ProductController::class, 'show'])->name('catalog.show');
     Route::post('catalog/import', [ProductController::class, 'import'])->name('catalog.import');
     Route::post('catalog/export', [ProductController::class, 'export'])->name('catalog.export');
 
+    // orders
+    Route::get('order', [OrderController::class, 'index'])->name('order.index');
+    Route::get('order/create', [OrderController::class, 'create'])->name('order.create');
+    Route::get('order/{order}', [OrderController::class, 'show'])->name('order.show');
+    Route::post('order/store', [OrderController::class, 'store'])->name('order.store');
+    Route::post('order/{order}/store', [OrderController::class, 'store'])->name('order.update');
+    Route::get('order/destroy', [OrderController::class, 'destroy'])->name('order.destroy');
+
+    // ajax get areas by district
+    Route::get('areas/{district_id?}', [AreaController::class, 'ajaxGetAreasByDistrict'])->name('area.ajax-get-areas-by-district');
+
 
 
 });

+ 1 - 1
todo.md

@@ -6,7 +6,7 @@
 - [x] каталог товаров: экспорт
 - [x] каталог товаров: импорт
 - [ ] складские остатки товаров
-- [x] Клиенты
+- [ ] Добавить ответственных и привязать к району: ФИО, телефон
 - [ ] заказы (площадки)
 - [ ] заказы поставщику
 - [ ] импорт площадок