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\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
|
||||
{
|
||||
@ -39,7 +39,18 @@ class SearchController extends Controller
|
||||
->orderBy('firstname')
|
||||
->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
|
||||
|
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 Leenooks\Traits\ScopeActive;
|
||||
|
||||
use App\Models\Scopes\SiteScope;
|
||||
use App\Models\Supplier\{Broadband,Domain,Email,Ethernet,Generic,Host,HSPA,Phone,SSL,Type};
|
||||
|
||||
class Supplier extends Model
|
||||
@ -98,17 +99,72 @@ class Supplier extends Model
|
||||
|
||||
/* 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()?
|
||||
// EG: Crazy Domains, "domains" and "hosting".
|
||||
/**
|
||||
* Supplier Detail Configuration
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
public function detail()
|
||||
{
|
||||
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 */
|
||||
|
||||
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.
|
||||
*
|
||||
|
@ -161,6 +161,13 @@ class User extends Authenticatable implements IDs
|
||||
->active();
|
||||
}
|
||||
|
||||
public function suppliers()
|
||||
{
|
||||
return $this->belongsToMany(Supplier::class)
|
||||
->where('supplier_user.site_id',$this->site_id)
|
||||
->withPivot('id','created_at');
|
||||
}
|
||||
|
||||
/* ATTRIBUTES */
|
||||
|
||||
/**
|
||||
@ -231,7 +238,7 @@ class User extends Authenticatable implements IDs
|
||||
});
|
||||
|
||||
} elseif (is_numeric($term)) {
|
||||
$query->where('id','like','%'.$term.'%');
|
||||
$query->where('users.id','like','%'.$term.'%');
|
||||
|
||||
} elseif (preg_match('/\@/',$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="card-header bg-white">
|
||||
<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 -->
|
||||
<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>
|
||||
@endcanany
|
||||
@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>
|
||||
</div>
|
||||
|
||||
<div class="card-body pl-0 pr-0">
|
||||
<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="col-12 col-xl-7">
|
||||
@include('service.widget.active')
|
||||
@ -83,6 +86,11 @@
|
||||
</div>
|
||||
@endcanany
|
||||
@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>
|
||||
|
@ -128,9 +128,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if($x=config('services.supplier.'.$o->name.'.api'))
|
||||
@if($o->api_class())
|
||||
<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">
|
||||
<!-- 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,
|
||||
ServiceController,
|
||||
SupplierController,
|
||||
UserController,
|
||||
WelcomeController,
|
||||
Wholesale\ReportController};
|
||||
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'])
|
||||
->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
|
||||
// Route::get('service/{o}','AdminHomeController@service');
|
||||
// Route::post('service/{o}','AdminHomeController@service_update');
|
||||
|
Loading…
Reference in New Issue
Block a user