Add supplier linking
This commit is contained in:
parent
a1fd36aa6f
commit
2722c92bcf
67
app/Console/Commands/SupplierAccountSync.php
Normal file
67
app/Console/Commands/SupplierAccountSync.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Facades\Config;
|
||||||
|
|
||||||
|
use App\Models\{Site,Supplier,User};
|
||||||
|
|
||||||
|
class SupplierAccountSync extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'supplier:account:sync'
|
||||||
|
.' {siteid : Site ID}'
|
||||||
|
.' {supplier : Supplier Name}'
|
||||||
|
.' {--f|forceprod : Force Prod API on dev environment}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = 'Sync accounts with a supplier';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
Config::set('site',Site::findOrFail($this->argument('siteid')));
|
||||||
|
$so = Supplier::where('name',$this->argument('supplier'))->singleOrFail();
|
||||||
|
|
||||||
|
foreach ($so->API($this->option('forceprod'))->getCustomers(['fetchall'=>true]) as $customer) {
|
||||||
|
// Check if we have this customer already (by ID)
|
||||||
|
if ($so->users->where('pivot.id',$customer->id)->count()) {
|
||||||
|
$this->info(sprintf('User already linked (%s:%s)',$customer->id,$customer->email));
|
||||||
|
|
||||||
|
} elseif ($x=User::where('email',$customer->email)->single()) {
|
||||||
|
//dump($x->suppliers->first());
|
||||||
|
if ($x->suppliers->count()) {
|
||||||
|
$this->alert(sprintf('User [%d:%s] already linked to this supplier with ID (%s)',$customer->id,$customer->email,$x->suppliers->first()->pivot->id));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$this->warn(sprintf('User [%d:%s] has same email (%s:%s) - Linked',$x->id,$x->email,$customer->id,$customer->email));
|
||||||
|
|
||||||
|
$so->users()->syncWithoutDetaching([
|
||||||
|
$x->id => [
|
||||||
|
'id'=>$customer->id,
|
||||||
|
'site_id'=>$x->site_id, // @todo See if we can have this handled automatically
|
||||||
|
'created_at'=>Carbon::create($customer->date_added),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
$this->error(sprintf('User doesnt exist with email (%s)',$customer->email));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,7 @@ use Illuminate\Support\Collection;
|
|||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Illuminate\Support\Facades\Gate;
|
use Illuminate\Support\Facades\Gate;
|
||||||
|
|
||||||
use App\Models\{Account,Invoice,Payment,Service,Service\Broadband,Service\Phone,User};
|
use App\Models\{Account,Invoice,Payment,Service,Supplier,User};
|
||||||
|
|
||||||
class SearchController extends Controller
|
class SearchController extends Controller
|
||||||
{
|
{
|
||||||
@ -39,7 +39,18 @@ class SearchController extends Controller
|
|||||||
->orderBy('firstname')
|
->orderBy('firstname')
|
||||||
->limit(10)->get() as $o)
|
->limit(10)->get() as $o)
|
||||||
{
|
{
|
||||||
$result->push(['name'=>sprintf('%s (%s)',$o->name,$o->lid),'value'=>'/u/home/'.$o->id,'category'=>'Users']);
|
$result->push(['name'=>sprintf('%s (%s) - %s',$o->name,$o->lid,$o->email),'value'=>'/u/home/'.$o->id,'category'=>'Users']);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Look for User by Supplier
|
||||||
|
if (is_numeric($request->input('term')))
|
||||||
|
foreach (Supplier::Search($request->input('term'))
|
||||||
|
->whereIN('user_id',$user_ids)
|
||||||
|
->orderBy('name')
|
||||||
|
->limit(10)->get() as $o)
|
||||||
|
{
|
||||||
|
$oo = $o->users->filter(function($item) use ($request) { return str_contains($item->pivot->id,$request->input('term')); })->pop();
|
||||||
|
$result->push(['name'=>sprintf('%s (%s:%s)',$oo->name,$o->name,$oo->pivot->id),'value'=>'/u/home/'.$oo->id,'category'=>'Suppliers']);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Look for Account
|
# Look for Account
|
||||||
|
55
app/Http/Controllers/UserController.php
Normal file
55
app/Http/Controllers/UserController.php
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Session;
|
||||||
|
|
||||||
|
use App\Models\{Supplier,User};
|
||||||
|
|
||||||
|
class UserController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Add a supplier to a user's profile
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
* @param User $o
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function supplier_addedit(Request $request,User $o)
|
||||||
|
{
|
||||||
|
Session::put('supplier_update',true);
|
||||||
|
|
||||||
|
$validated = $request->validate([
|
||||||
|
'id'=>'required|string',
|
||||||
|
'supplier_id'=>'required|exists:suppliers,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$o->suppliers()->attach([
|
||||||
|
$validated['supplier_id'] => [
|
||||||
|
'id'=>$validated['id'],
|
||||||
|
'site_id'=>$o->site_id,
|
||||||
|
'created_at'=>Carbon::now(),
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect()->back()->with('success','Supplier Added');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a supplier from a user's profile
|
||||||
|
*
|
||||||
|
* @param User $o
|
||||||
|
* @param Supplier $so
|
||||||
|
* @return \Illuminate\Http\RedirectResponse
|
||||||
|
*/
|
||||||
|
public function supplier_delete(User $o,Supplier $so)
|
||||||
|
{
|
||||||
|
Session::put('supplier_update',true);
|
||||||
|
|
||||||
|
$o->suppliers()->detach([$so->id]);
|
||||||
|
|
||||||
|
return redirect()->back()->with('success','Supplier Deleted');
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ use Illuminate\Support\Arr;
|
|||||||
use Illuminate\Support\Collection;
|
use Illuminate\Support\Collection;
|
||||||
use Leenooks\Traits\ScopeActive;
|
use Leenooks\Traits\ScopeActive;
|
||||||
|
|
||||||
|
use App\Models\Scopes\SiteScope;
|
||||||
use App\Models\Supplier\{Broadband,Domain,Email,Ethernet,Generic,Host,HSPA,Phone,SSL,Type};
|
use App\Models\Supplier\{Broadband,Domain,Email,Ethernet,Generic,Host,HSPA,Phone,SSL,Type};
|
||||||
|
|
||||||
class Supplier extends Model
|
class Supplier extends Model
|
||||||
@ -98,17 +99,72 @@ class Supplier extends Model
|
|||||||
|
|
||||||
/* RELATIONS */
|
/* RELATIONS */
|
||||||
|
|
||||||
// @todo Need to put in an integrity constraint to support the hasOne()
|
/**
|
||||||
// @todo Some suppliers have multiple different configuration urls/passwords and contacts for different types of services, perhaps this should be hasMany()?
|
* Supplier Detail Configuration
|
||||||
// EG: Crazy Domains, "domains" and "hosting".
|
*
|
||||||
|
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||||
|
*/
|
||||||
public function detail()
|
public function detail()
|
||||||
{
|
{
|
||||||
return $this->hasOne(SupplierDetail::class)
|
return $this->hasOne(SupplierDetail::class)
|
||||||
->withoutGlobalScope(\App\Models\Scopes\SiteScope::class);
|
->withoutGlobalScope(SiteScope::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function users()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(User::class)
|
||||||
|
->withPivot('id','created_at');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Search for a record
|
||||||
|
*
|
||||||
|
* @param $query
|
||||||
|
* @param string $term
|
||||||
|
*/
|
||||||
|
public function scopeSearch($query,string $term)
|
||||||
|
{
|
||||||
|
if (is_numeric($term)) {
|
||||||
|
$query->select('suppliers.*')
|
||||||
|
->join('supplier_user',['supplier_user.supplier_id'=>'suppliers.id'])
|
||||||
|
->orWhere('supplier_user.id','like','%'.$term.'%');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* METHODS */
|
/* METHODS */
|
||||||
|
|
||||||
|
public function api_class(): ?string
|
||||||
|
{
|
||||||
|
return config('services.supplier.'.strtolower($this->name).'.api');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function api_key(): string
|
||||||
|
{
|
||||||
|
return Arr::get($this->detail->connections,'api_key');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function api_secret(): string
|
||||||
|
{
|
||||||
|
return Arr::get($this->detail->connections,'api_secret');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function API(bool $forceprod=FALSE): mixed
|
||||||
|
{
|
||||||
|
return $this->hasAPIdetails() ? new ($this->api_class())($this->api_key(),$this->api_secret(),$forceprod) : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do we have API details for this supplier
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasAPIdetails(): bool
|
||||||
|
{
|
||||||
|
return $this->api_class() && (collect(['api_key','api_secret'])->diff($this->detail->connections->keys())->count() === 0);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the traffic records, that were not matched to a service.
|
* Return the traffic records, that were not matched to a service.
|
||||||
*
|
*
|
||||||
|
@ -161,6 +161,13 @@ class User extends Authenticatable implements IDs
|
|||||||
->active();
|
->active();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function suppliers()
|
||||||
|
{
|
||||||
|
return $this->belongsToMany(Supplier::class)
|
||||||
|
->where('supplier_user.site_id',$this->site_id)
|
||||||
|
->withPivot('id','created_at');
|
||||||
|
}
|
||||||
|
|
||||||
/* ATTRIBUTES */
|
/* ATTRIBUTES */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -231,7 +238,7 @@ class User extends Authenticatable implements IDs
|
|||||||
});
|
});
|
||||||
|
|
||||||
} elseif (is_numeric($term)) {
|
} elseif (is_numeric($term)) {
|
||||||
$query->where('id','like','%'.$term.'%');
|
$query->where('users.id','like','%'.$term.'%');
|
||||||
|
|
||||||
} elseif (preg_match('/\@/',$term)) {
|
} elseif (preg_match('/\@/',$term)) {
|
||||||
$query->where('email','like','%'.$term.'%');
|
$query->where('email','like','%'.$term.'%');
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('supplier_details', function (Blueprint $table) {
|
||||||
|
$table->foreign(['supplier_id'])->references(['id'])->on('suppliers');
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::create('supplier_user', function (Blueprint $table) {
|
||||||
|
$table->integer('site_id')->unsigned();
|
||||||
|
$table->integer('supplier_id')->unsigned();
|
||||||
|
$table->integer('user_id')->unsigned();
|
||||||
|
$table->string('id');
|
||||||
|
$table->dateTime('created_at');
|
||||||
|
|
||||||
|
$table->unique(['supplier_id','user_id']);
|
||||||
|
$table->foreign(['supplier_id'])->references(['id'])->on('suppliers');
|
||||||
|
$table->foreign(['user_id','site_id'])->references(['id','site_id'])->on('users');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('supplier_details', function (Blueprint $table) {
|
||||||
|
$table->dropForeign(['supplier_id']);
|
||||||
|
});
|
||||||
|
|
||||||
|
Schema::dropIfExists('supplier_user');
|
||||||
|
}
|
||||||
|
};
|
@ -24,7 +24,7 @@
|
|||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="card-header bg-white">
|
<div class="card-header bg-white">
|
||||||
<ul class="nav nav-pills">
|
<ul class="nav nav-pills">
|
||||||
<li class="nav-item"><a class="nav-link active" href="#tab-services" data-toggle="tab">Services</a></li>
|
<li class="nav-item"><a class="nav-link {{ (! session()->has('supplier_update')) ? 'active' : '' }}" href="#tab-services" data-toggle="tab">Services</a></li>
|
||||||
{{--
|
{{--
|
||||||
<!-- @todo this is not working -->
|
<!-- @todo this is not working -->
|
||||||
<li class="nav-item"><a class="nav-link" href="#tab-nextinvoice" data-toggle="tab">Next Invoice</a></li>
|
<li class="nav-item"><a class="nav-link" href="#tab-nextinvoice" data-toggle="tab">Next Invoice</a></li>
|
||||||
@ -36,12 +36,15 @@
|
|||||||
<li class="nav-item ml-auto"><a class="nav-link" href="#tab-reseller" data-toggle="tab">Reseller</a></li>
|
<li class="nav-item ml-auto"><a class="nav-link" href="#tab-reseller" data-toggle="tab">Reseller</a></li>
|
||||||
@endcanany
|
@endcanany
|
||||||
@endif
|
@endif
|
||||||
|
@canany('reseller','wholesaler')
|
||||||
|
<li class="nav-item ml-auto"><a class="nav-link {{ session()->has('supplier_update') ? 'active' : '' }}" href="#tab-supplier" data-toggle="tab">Supplier</a></li>
|
||||||
|
@endcanany
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-body pl-0 pr-0">
|
<div class="card-body pl-0 pr-0">
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="active tab-pane" id="tab-services">
|
<div class="tab-pane {{ (! session()->has('supplier_update')) ? 'active' : '' }}" id="tab-services">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-xl-7">
|
<div class="col-12 col-xl-7">
|
||||||
@include('service.widget.active')
|
@include('service.widget.active')
|
||||||
@ -83,6 +86,11 @@
|
|||||||
</div>
|
</div>
|
||||||
@endcanany
|
@endcanany
|
||||||
@endif
|
@endif
|
||||||
|
@canany('reseller','wholesaler')
|
||||||
|
<div class="tab-pane {{ session()->pull('supplier_update') ? 'active' : '' }}" id="tab-supplier">
|
||||||
|
@include('user.widget.supplier')
|
||||||
|
</div>
|
||||||
|
@endcanany
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -128,9 +128,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@if($x=config('services.supplier.'.$o->name.'.api'))
|
@if($o->api_class())
|
||||||
<hr>
|
<hr>
|
||||||
<p class="h6"><i class="fa-fw fas fa-sitemap"></i> <strong>{{ $x }}</strong></p>
|
<p class="h6"><i class="fa-fw fas fa-sitemap"></i> <strong>{{ $o->api_class() }}</strong></p>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<!-- API Details -->
|
<!-- API Details -->
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
<!-- $o=User::class -->
|
||||||
|
<!-- Suppliers Configuration for this User -->
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
@include('adminlte::widget.success_button')
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Supplier</th>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Added</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
@foreach ($o->suppliers as $so)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $so->name }}</td>
|
||||||
|
<td>{{ $so->pivot->id }}</td>
|
||||||
|
<td>{{ $so->pivot->created_at }} <a class="float-right" href="{{ url('a/user/supplier/delete',[$o->id,$so->id]) }}"><i class=" fa-fw fas fa-trash"></i></a></td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
@if(($x=\App\Models\Supplier::active()->whereNotIn('id',$o->suppliers->pluck('id'))->orderBy('name')->get())->count())
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<td colspan="3">
|
||||||
|
<form class="g-0 needs-validation" method="POST" action="{{ url('a/user/supplier/add',[$o->id]) }}" enctype="multipart/form-data" role="form">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-6">
|
||||||
|
@include('adminlte::widget.form_select',[
|
||||||
|
'label'=>'Add Supplier',
|
||||||
|
'icon'=>'fas fa-handshake',
|
||||||
|
'id'=>'supplier_id',
|
||||||
|
'old'=>'supplier_id',
|
||||||
|
'options'=>$x->transform(function($item) { return ['id'=>$item->id,'value'=>$item->name]; }),
|
||||||
|
'value'=>'',
|
||||||
|
])
|
||||||
|
</div>
|
||||||
|
<div class="col-4">
|
||||||
|
@include('adminlte::widget.form_text',[
|
||||||
|
'label'=>'ID',
|
||||||
|
'icon'=>'fas fa-hashtag',
|
||||||
|
'id'=>'id',
|
||||||
|
'old'=>'id',
|
||||||
|
'name'=>'id',
|
||||||
|
'value'=>'',
|
||||||
|
])
|
||||||
|
</div>
|
||||||
|
<div class="col-2">
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="submit" class="mt-4 float-right btn btn-sm btn-success">Add</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
@endif
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -14,6 +14,7 @@ use App\Http\Controllers\{AdminController,
|
|||||||
SearchController,
|
SearchController,
|
||||||
ServiceController,
|
ServiceController,
|
||||||
SupplierController,
|
SupplierController,
|
||||||
|
UserController,
|
||||||
WelcomeController,
|
WelcomeController,
|
||||||
Wholesale\ReportController};
|
Wholesale\ReportController};
|
||||||
use App\Models\Supplier;
|
use App\Models\Supplier;
|
||||||
@ -109,6 +110,13 @@ Route::group(['middleware'=>['theme:adminlte-be','auth','role:wholesaler'],'pref
|
|||||||
Route::post('service/update/{o}',[ServiceController::class,'update'])
|
Route::post('service/update/{o}',[ServiceController::class,'update'])
|
||||||
->where('o','[0-9]+');
|
->where('o','[0-9]+');
|
||||||
|
|
||||||
|
// Linking supplier to user
|
||||||
|
Route::post('user/supplier/add/{o}',[UserController::class,'supplier_addedit'])
|
||||||
|
->where('o','[0-9]+');
|
||||||
|
Route::get('user/supplier/delete/{o}/{so}',[UserController::class,'supplier_delete'])
|
||||||
|
->where('o','[0-9]+')
|
||||||
|
->where('so','[0-9]+');
|
||||||
|
|
||||||
//@deprecated
|
//@deprecated
|
||||||
// Route::get('service/{o}','AdminHomeController@service');
|
// Route::get('service/{o}','AdminHomeController@service');
|
||||||
// Route::post('service/{o}','AdminHomeController@service_update');
|
// Route::post('service/{o}','AdminHomeController@service_update');
|
||||||
|
Loading…
Reference in New Issue
Block a user