Created Suppliers

This commit is contained in:
Deon George 2021-12-20 14:25:43 +11:00
parent 0aa7ff3b2c
commit bdcfe07fb0
12 changed files with 504 additions and 33 deletions

View File

@ -6,15 +6,22 @@ use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use App\Models\{Account,Charge,InvoiceItem,Payment,PaymentItem,Service,SiteDetail};
use App\Models\{Account,Charge,InvoiceItem,Payment,PaymentItem,Service,SiteDetail,Supplier,SupplierDetail};
/**
* The AdminController governs all routes that are prefixed with 'a/'.
*
* This is everything about the configuration of the application as a whole, or administration of a site.
*/
class AdminController extends Controller
{
// @todo Move to reseller
public function service(Service $o)
{
return View('a.service',['o'=>$o]);
}
// @todo Move to reseller
public function charge_addedit(Request $request,Charge $o)
{
if ($request->post()) {
@ -47,6 +54,7 @@ class AdminController extends Controller
->with('o',$o);
}
// @todo Move to reseller
public function charge_pending_account(Request $request,Account $o)
{
return view('a.charge.widgets.pending')
@ -58,6 +66,7 @@ class AdminController extends Controller
*
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
*/
// @todo Move to reseller
public function charge_unprocessed()
{
return view('a.charge.unprocessed');
@ -70,6 +79,7 @@ class AdminController extends Controller
* @param Payment $o
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
*/
// @todo Move to reseller
public function pay_addedit(Request $request,Payment $o)
{
if ($request->post()) {
@ -131,6 +141,7 @@ class AdminController extends Controller
*
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
*/
// @todo Move to reseller
public function pay_unapplied()
{
return view('a.payment.unapplied');
@ -143,6 +154,7 @@ class AdminController extends Controller
* @param Account $o
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
*/
// @todo Move to reseller
public function pay_invoices(Request $request,Account $o)
{
return view('a.payment.widgets.invoices')
@ -150,6 +162,71 @@ class AdminController extends Controller
->with('o',$o);
}
/**
* Site up site wide suppliers, or a site's supplier details
*
* @note This method is protected by the routes
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View
*/
public function supplier()
{
return view('a.supplier');
}
/**
* Update a suppliers details
*
* @param Request $request
* @param Supplier $o
* @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\View\Factory|\Illuminate\Contracts\View\View|\Illuminate\Http\RedirectResponse
*/
public function supplier_addedit(Request $request,Supplier $o)
{
if ($request->post()) {
$validation = $request->validate([
'name' => 'required|string|min:2|max:255',
'active' => 'sometimes|accepted',
'address1' => 'required|string|min:2|max:255',
'address2' => 'nullable|string|min:2|max:255',
'city' => 'required|string|min:2|max:64',
'state' => 'required|string|min:2|max:32',
'postcode' => 'required|string|min:2|max:8',
'supplier_details.notes' => 'nullable|string|min:3',
'supplier_details.accounts' => 'nullable|email',
'supplier_details.support' => 'nullable|email',
'supplier_details.payments' => 'nullable|string|min:3',
]);
foreach (collect($validation)->except('supplier_details') as $key => $item)
$o->{$key} = $item;
$o->active = (bool)$request->active;
try {
$o->save();
} catch (\Exception $e) {
return redirect()->back()->withErrors($e->getMessage())->withInput();
}
$o->load(['detail']);
$oo = $o->detail ?: new SupplierDetail;
foreach (collect($validation)->get('supplier_details',[]) as $key => $item)
$oo->{$key} = $item;
$o->detail()->save($oo);
return redirect()->back()
->with('success','Supplier saved');
}
if (! $o->exists && $request->name)
$o = Supplier::where('name',$request->name)->with(['details'])->firstOrNew();
return view('a.supplierdetails')
->with('o',$o);
}
/**
* Site setup
*
@ -161,13 +238,13 @@ class AdminController extends Controller
{
if ($request->post()) {
$validated = $request->validate([
'site_name' => 'required|string|max:255',
'site_name' => 'required|string|min:2|max:255',
'site_email' => 'required|string|email|max:255',
'site_address1' => 'required|string|max:255',
'site_address2' => 'nullable|string|max:255',
'site_city' => 'required|string|max:64',
'site_state' => 'required|string|max:32',
'site_postcode' => 'required|string|max:8',
'site_address1' => 'required|string|min:2|max:255',
'site_address2' => 'nullable|string|min:2|max:255',
'site_city' => 'required|string|min:2|max:64',
'site_state' => 'required|string|min:2|max:32',
'site_postcode' => 'required|string|min:2|max:8',
'site_description' => 'nullable|string|min:5',
'site_phone' => 'nullable|regex:/[0-9 ]+/|min:6|max:12',
'site_fax' => 'nullable|regex:/[0-9 ]+/|min:6|max:12',

View File

@ -3,8 +3,18 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Leenooks\Traits\ScopeActive;
class Supplier extends Model
{
//
use ScopeActive;
public $timestamps = FALSE;
/* RELATIONS */
public function detail()
{
return $this->hasOne(SupplierDetail::class);
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Traits\SiteID;
class SupplierDetail extends Model
{
use SiteID;
/* RELATIONS */
public function supplier()
{
return $this->belongsTo(Supplier::class);
}
}

View File

@ -0,0 +1,55 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateSuppliers extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('suppliers', function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->boolean('active');
$table->string('name')->unique();
$table->string('address1');
$table->string('address2')->nullable();
$table->string('city',64);
$table->string('state',32);
$table->string('postcode',8);
});
Schema::create('supplier_details', function (Blueprint $table) {
$table->integer('id',TRUE)->unsigned();
$table->timestamps();
$table->text('notes')->nullable();
$table->string('accounts')->nullable();
$table->string('support')->nullable();
$table->string('payments')->nullable();
$table->integer('supplier_id')->unsigned();
$table->integer('site_id');
$table->unique(['supplier_id','site_id']);
$table->foreign(['supplier_id'])->references(['id'])->on('suppliers');
$table->foreign(['site_id'])->references(['id'])->on('sites');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('supplier_details');
Schema::dropIfExists('suppliers');
}
}

17
public/css/fixes.css vendored
View File

@ -82,7 +82,6 @@ table.dataTable thead .sorting {
/* Fix selected item is positioned correctly */
span.select2-selection.select2-selection--single > span.select2-selection__rendered {
margin-top: -9px;
margin-left: -9px;
}
@ -90,3 +89,19 @@ span.select2-selection.select2-selection--single > span.select2-selection__rende
.select2-selection.select2-selection--single {
height: calc(2.25rem + 2px) !important;
}
/* Fix dark background nav pills */
.card-header.bg-dark .nav-pills .nav-link.active, .nav-pills .show>.nav-link {
background-color: #ffffff;
color: #343a40;
}
.card-header.bg-dark .nav-pills .nav-link:hover {
background-color: #6c757d;
color: #ffffff;
}
.card-header.bg-dark .nav-pills .nav-link:not(.active):hover {
background-color: #6c757d;
color: #ffffff;
}

View File

@ -0,0 +1,8 @@
$(document).on('select2:open',(event) => {
const searchField = document.querySelector(
`.select2-search__field[aria-controls="select2-${event.target.getAttribute('data-select2-id')}-results"]`,
);
if (searchField) {
searchField.focus();
}
});

View File

@ -99,7 +99,7 @@
<div class="row">
<div class="col-12">
<div class="form-group has-validation">
<label for="site_address">City</label>
<label for="site_city">City</label>
<input type="text" class="form-control form-control-border @error('site_city') is-invalid @enderror" id="site_city" name="site_city" placeholder="City" value="{{ old('site_city',$site->site_city) }}">
<span class="invalid-feedback" role="alert">
@error('site_city')
@ -115,7 +115,7 @@
<div class="row">
<div class="col-12" style="display: inline-flex;">
<div class="form-group has-validation">
<label for="site_address">State</label>
<label for="site_state">State</label>
<input type="text" class="form-control form-control-border @error('site_state') is-invalid @enderror col-5" id="site_state" name="site_state" placeholder="State" value="{{ old('site_state',$site->site_state) }}">
<span class="invalid-feedback" role="alert">
@error('site_state')
@ -127,7 +127,7 @@
</div>
<div class="form-group has-validation">
<label for="site_address">Postal Code</label>
<label for="site_postcode">Postal Code</label>
<input type="text" class="form-control form-control-border @error('site_postcode') is-invalid @enderror col-5" id="site_postcode" name="site_postcode" placeholder="Postal Code" value="{{ old('site_postcode',$site->site_postcode) }}">
<span class="invalid-feedback" role="alert">
@error('site_postcode')

View File

@ -0,0 +1,70 @@
@extends('adminlte::layouts.app')
@section('htmlheader_title')
Supplier
@endsection
@section('page_title')
Supplier
@endsection
@section('contentheader_title')
Supplier
@endsection
@section('contentheader_description')
@endsection
@section('main-content')
<div class="row">
<div class="col-12">
<div class="card card-dark">
<div class="card-header">
<h1 class="card-title">Supplier Configuration</h1>
</div>
<div class="card-body">
<form class="g-0 needs-validation" method="POST" enctype="multipart/form-data" role="form">
@csrf
<div class="row">
<div class="col-4">
<div class="form-group has-validation">
<label for="name">Supplier Name</label>
<select class="form-control form-control-border" id="name" name="supplier_id">
<option value=""></option>
<option value="">Add New</option>
@foreach(\App\Models\Supplier::orderBy('name')->get() as $o)
<option value="{{ $o->id }}">{{ $o->name }}</option>
@endforeach
</select>
<span class="invalid-feedback" role="alert">
@error('name')
{{ $message }}
@else
Supplier Name is required.
@enderror
</span>
<span class="input-helper">Suppliers Name</span>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
@endsection
@section('page-scripts')
@css(select2)
@js(select2,autofocus)
<script type="text/javascript">
$(document).ready(function() {
$('#name').select2()
.on('change',function(item) {
window.location.href = '{{ url('a/supplier/addedit') }}/'+item.target.value;
});
});
</script>
@endsection

View File

@ -0,0 +1,225 @@
@extends('adminlte::layouts.app')
@section('htmlheader_title')
{{ $o->name ?: 'New Supplier' }}
@endsection
@section('page_title')
{{ $o->name ?: 'New Supplier' }}
@endsection
@section('contentheader_title')
{{ $o->name ?: 'New Supplier' }}
@endsection
@section('contentheader_description')
@endsection
@section('main-content')
<div class="row">
<div class="col-12">
@include('adminlte::widget.status')
</div>
</div>
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header bg-dark d-flex p-0">
<ul class="nav nav-pills w-100 p-2">
<li class="nav-item"><a class="nav-link active" href="#details" data-toggle="tab">Details</a></li>
<li class="nav-item"><a class="nav-link " href="#products" data-toggle="tab">Products</a></li>
</ul>
</div>
<div class="card-body">
<div class="tab-content">
<div class="tab-pane fade active show" id="details" role="tabpanel">
<h3>Supplier Details</h3>
<hr>
@if(session()->has('success'))
<span class="ml-3 pt-0 pb-0 pr-1 pl-1 btn btn-outline-success"><small>{{ session()->get('success') }}</small></span>
@endif
<form class="g-0 needs-validation" method="POST" enctype="multipart/form-data" role="form">
@csrf
<div class="row">
<div class="col-4">
<div class="row">
<!-- Supplier Name -->
<div class="col-9">
<div class="form-group has-validation">
<label for="name">Supplier Name</label>
<input type="text" class="form-control form-control-border @error('name') is-invalid @enderror" id="name" name="name" placeholder="Supplier Name" value="{{ old('name',$o->name) }}" required>
<span class="invalid-feedback" role="alert">
@error('name')
{{ $message }}
@else
Supplier Name required.
@enderror
</span>
</div>
</div>
<!-- Supplier Name -->
<div class="col-3">
<div class="form-group">
<div class="custom-control custom-switch custom-switch-off-danger custom-switch-on-success">
<input type="checkbox" class="custom-control-input" id="active" name="active" {{ old('active',$o->active) ? 'checked' : '' }}>
<label class="custom-control-label" for="active">Active</label>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Address Lines -->
<div class="col-12">
<div class="form-group has-validation">
<label for="address1">Address Lines</label>
<input type="text" class="form-control form-control-border @error('address1') is-invalid @enderror" id="address1" name="address1" placeholder="Address1" value="{{ old('address1',$o->address1) }}" required>
<input type="text" class="form-control form-control-border" id="address2" name="address2" placeholder="Address2" value="{{ old('address2',$o->address2) }}">
<span class="invalid-feedback" role="alert">
@error('address1')
{{ $message }}
@else
Atleast 1 address line required.
@enderror
</span>
</div>
</div>
</div>
<div class="row">
<!-- City -->
<div class="col-12">
<div class="form-group has-validation">
<label for="city">City</label>
<input type="text" class="form-control form-control-border @error('city') is-invalid @enderror" id="city" name="city" placeholder="City" value="{{ old('city',$o->city) }}">
<span class="invalid-feedback" role="alert">
@error('city')
{{ $message }}
@else
City is required.
@enderror
</span>
</div>
</div>
</div>
<div class="row">
<!-- State -->
<div class="col-9">
<div class="form-group has-validation">
<label for="state">State</label>
<input type="text" class="form-control form-control-border @error('state') is-invalid @enderror" id="state" name="state" placeholder="State" value="{{ old('state',$o->state) }}">
<span class="invalid-feedback" role="alert">
@error('state')
{{ $message }}
@else
State is required.
@enderror
</span>
</div>
</div>
<!-- Postal Code -->
<div class="col-3">
<div class="form-group has-validation">
<label for="postcode">Postal Code</label>
<input type="text" class="form-control form-control-border @error('postcode') is-invalid @enderror" id="postcode" name="postcode" placeholder="Postal Code" value="{{ old('postcode',$o->postcode) }}">
<span class="invalid-feedback" role="alert">
@error('postcode')
{{ $message }}
@else
Postcode is required.
@enderror
</span>
</div>
</div>
</div>
</div>
<div class="offset-1 col-4">
<div class="row">
<!-- Accounts Email -->
<div class="col-12">
<div class="form-group has-validation">
<label for="accounts">Accounts Email</label>
<input type="accounts" class="form-control form-control-border @error('supplier_details.accounts') is-invalid @enderror" id="accounts" name="supplier_details[accounts]" placeholder="Accounts Email" value="{{ old('supplier_details.accounts',($o->detail ? $o->detail->accounts : '')) }}">
<span class="invalid-feedback" role="alert">
@error('supplier_details.accounts')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
<div class="row">
<!-- Support Email -->
<div class="col-12">
<div class="form-group has-validation">
<label for="support">Support Email</label>
<input type="support" class="form-control form-control-border @error('supplier_details.support') is-invalid @enderror" id="support" name="supplier_details[support]" placeholder="Support Email" value="{{ old('supplier_details.support',($o->detail ? $o->detail->support : '')) }}">
<span class="invalid-feedback" role="alert">
@error('supplier_details.support')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
<div class="row">
<!-- Payment Details -->
<div class="col-12">
<div class="form-group has-validation">
<label for="payments">Payment Details</label>
<input type="payments" class="form-control form-control-border @error('supplier_details.payments') is-invalid @enderror" id="payments" name="supplier_details[payments]" placeholder="Payment Details" value="{{ old('supplier_details.payments',($o->detail ? $o->detail->payments : '')) }}">
<span class="invalid-feedback" role="alert">
@error('supplier_details.payments')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Notes -->
<div class="col-12">
<div class="form-group has-validation">
<label for="notes">Notes</label>
<textarea class="form-control @error('supplier_details.notes') is-invalid @enderror" id="notes" name="supplier_details[notes]" placeholder="Notes...">{{ old('supplier_details.notes',($o->detail ? $o->detail->notes : '')) }}</textarea>
<span class="input-helper">Notes.</span>
<span class="invalid-feedback" role="alert">
@error('supplier_details.notes')
{{ $message }}
@enderror
</span>
</div>
</div>
</div>
<div class="row">
<!-- Buttons -->
<div class="col-12">
<a href="{{ url('/home') }}" class="btn btn-danger">Cancel</a>
@can('wholesaler')
<button type="submit" name="submit" class="btn btn-success mr-0 float-right">@if ($o->exists)Save @else Add @endif</button>
@endcan
</div>
</div>
</form>
</div>
<div class="tab-pane fade" id="products" role="tabpanel">
Products.
</div>
</div>
</div>
</div>
</div>
</div>
@endsection

View File

@ -102,22 +102,3 @@
</div>
</div>
@endsection
@section('page-scripts')
<style>
.nav-pills .nav-link.active, .nav-pills .show>.nav-link {
background-color: #ffffff;
color: #343a40;
}
.nav-pills .nav-link:hover {
background-color: #6c757d;
color: #ffffff;
}
.nav-pills .nav-link:not(.active):hover {
background-color: #6c757d;
color: #ffffff;
}
</style>
@append

View File

@ -77,6 +77,12 @@
</a>
</li>
<li class="nav-item">
<a href="{{ url('a/supplier') }}" class="nav-link @if(preg_match('#^a/supplier#',Route::current()->uri())) active @endif">
<i class="nav-icon fas fa-user-tag"></i> <p>Suppliers</p>
</a>
</li>
<li class="nav-item has-treeview @if(preg_match('#^a/report/(products)#',request()->path()))menu-open @else menu-closed @endif">
<a href="#" class="nav-link @if(preg_match('#^a/report/(products)#',request()->path())) active @endif">
<i class="nav-icon fas fa-list"></i> <p>REPORT<i class="fas fa-angle-left right"></i></p>

View File

@ -39,7 +39,12 @@ Route::get('image/generic/{width}/{height}/{color}/{name?}',[MediaController::cl
// Our Admin Routes
Route::group(['middleware'=>['theme:adminlte-be','auth','role:wholesaler'],'prefix'=>'a'],function() {
// Site Setup
Route::match(['get','post'],'setup',[AdminController::class,'setup']);
// Supplier Setup
Route::match(['get'],'supplier',[AdminController::class,'supplier']);
Route::match(['get','post'],'supplier/addedit/{o?}',[AdminController::class,'supplier_addedit']);
// Route::get('service/{o}','AdminHomeController@service');
// Route::post('service/{o}','AdminHomeController@service_update');
// Route::get('report/products','Wholesale\ReportController@products');