Progress on order progress
This commit is contained in:
parent
e6f823da39
commit
6480f40b22
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@
|
||||
/storage/*.key
|
||||
/vendor
|
||||
/.idea
|
||||
.editorconfig
|
||||
/.vscode
|
||||
/.vagrant
|
||||
Homestead.json
|
||||
|
@ -17,55 +17,6 @@ class AdminHomeController extends Controller
|
||||
return View('a.service',['o'=>$o]);
|
||||
}
|
||||
|
||||
public function service_update(Request $request, Service $o)
|
||||
{
|
||||
if (! $o->validStatus(strtolower($request->input('action'))))
|
||||
return $this->service($o);
|
||||
|
||||
$action = strtolower($request->input('action'));
|
||||
|
||||
switch ($action)
|
||||
{
|
||||
case 'approve':
|
||||
// Send an email to the supplier.
|
||||
// @todo Change to address to suppliers email address.
|
||||
Mail::to('help@graytech.net.au')
|
||||
->queue((new OrderRequestApprove($o,$request->input('order_notes') ?: 'NONE'))->onQueue('high'));
|
||||
|
||||
// Send an email to the client.
|
||||
// @todo Your order has been submitted to supplier.
|
||||
|
||||
// Update the service to "ORDER-SENT"
|
||||
$o->nextStatus($action);
|
||||
|
||||
break;
|
||||
|
||||
case 'reject':
|
||||
$o->order_info = array_merge($o->order_info ? $o->order_info : [],['reason'=>$request->input('notes')]);
|
||||
|
||||
// Send mail to user
|
||||
Mail::to($o->orderby->email)->queue((new OrderRequestReject($o,$request->input('notes')))->onQueue('email'));
|
||||
|
||||
$o->nextStatus($action);
|
||||
break;
|
||||
|
||||
case 'hold':
|
||||
case 'release':
|
||||
$o->nextStatus($action);
|
||||
break;
|
||||
|
||||
case 'update_reference':
|
||||
$o->order_info = array_merge($o->order_info ? $o->order_info : [],['order_reference'=>$request->input('notes')]);
|
||||
$o->save();
|
||||
|
||||
// No action specified.
|
||||
default:
|
||||
return $this->service($o);
|
||||
}
|
||||
|
||||
return redirect(url('/a/service',[$o->id]));
|
||||
}
|
||||
|
||||
public function setup()
|
||||
{
|
||||
return view('a.setup');
|
||||
|
50
app/Http/Controllers/ServiceController.php
Normal file
50
app/Http/Controllers/ServiceController.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
use App\Models\Service;
|
||||
|
||||
class ServiceController extends Controller
|
||||
{
|
||||
/**
|
||||
* Update a service
|
||||
*
|
||||
* @note: Route Middleware protects this path
|
||||
* @param Service $o
|
||||
* @return View|void
|
||||
*/
|
||||
public function update(Request $request,Service $o)
|
||||
{
|
||||
switch ($o->order_status) {
|
||||
case 'ORDER-SENT':
|
||||
if ($request->post()) {
|
||||
foreach (['reference','notes'] as $key) {
|
||||
$o->setOrderInfo($key,$request->post($key));
|
||||
}
|
||||
|
||||
$o->save();
|
||||
|
||||
foreach ($request->post($o->stype) as $k=>$v) {
|
||||
$o->type->{$k} = $v;
|
||||
}
|
||||
|
||||
$o->type->save();
|
||||
|
||||
return redirect()->to(url('u/service',$o->id))->with('updated','Order sent notes updated.');
|
||||
}
|
||||
|
||||
return $this->update_order_status($o);
|
||||
|
||||
default:
|
||||
abort(499,'Not yet implemented');
|
||||
}
|
||||
}
|
||||
|
||||
private function update_order_status(Service $o)
|
||||
{
|
||||
return View('r.service.order.sent',['o'=>$o]);
|
||||
}
|
||||
}
|
@ -87,6 +87,19 @@ class UserHomeController extends Controller
|
||||
*/
|
||||
public function service(Service $o): View
|
||||
{
|
||||
return View('u.service',['o'=>$o]);
|
||||
return View('u.service.home',['o'=>$o]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Progress the order to the next stage
|
||||
*
|
||||
* @note: Route Middleware protects this path
|
||||
* @param Service $o
|
||||
* @param string $status
|
||||
* @return \Illuminate\Http\RedirectResponse
|
||||
*/
|
||||
public function service_progress(Service $o,string $status)
|
||||
{
|
||||
return redirect()->to($o->action($status) ?: url('u/service',$o->id));
|
||||
}
|
||||
}
|
@ -23,10 +23,10 @@ class ServicePolicy
|
||||
// If this is a service for an account managed by a user.
|
||||
return ($user->services->pluck('id')->search($o->id))
|
||||
|
||||
// The user is the wholesaler
|
||||
// The user is the wholesaler
|
||||
OR $user->isWholesaler()
|
||||
|
||||
// The user is the reseller
|
||||
// The user is the reseller
|
||||
OR $user->all_accounts()->pluck('id')->search($o->account_id);
|
||||
}
|
||||
|
||||
@ -41,6 +41,18 @@ class ServicePolicy
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the user progress an order status
|
||||
*
|
||||
* @param User $user
|
||||
* @param Service $o
|
||||
* @return bool
|
||||
*/
|
||||
public function progress(User $user, Service $o,string $next)
|
||||
{
|
||||
return $o->actions()->has($next);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the user can update the service.
|
||||
*
|
||||
|
@ -11,9 +11,12 @@ use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
use App\Traits\NextKey;
|
||||
use Leenooks\Carbon;
|
||||
use App\User;
|
||||
use App\Traits\NextKey;
|
||||
|
||||
class Service extends Model
|
||||
{
|
||||
@ -45,7 +48,7 @@ class Service extends Model
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
'order_info'=>'array',
|
||||
'order_info'=>'collection',
|
||||
];
|
||||
public $dateFormat = 'U';
|
||||
|
||||
@ -92,9 +95,58 @@ class Service extends Model
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $valid_status = [
|
||||
public static $action_progress = [
|
||||
// Order Submitted
|
||||
'ORDER-SUBMIT' => ['approve'=>'ORDER-SENT','hold'=>'ORDER-HOLD','reject'=>'ORDER-REJECTED','cancel'=>'ORDER-CANCELLED'],
|
||||
'ORDER-SUBMIT' => [
|
||||
'fail'=>FALSE,
|
||||
// Progress to next stages by who
|
||||
'next'=>[
|
||||
'ORDER-ACCEPT'=>['customer'],
|
||||
'SETUP-PAYMENT-WAIT'=>['reseller','wholesaler']
|
||||
],
|
||||
// Manual or System moves to the next stage
|
||||
'system'=>TRUE,
|
||||
'method'=>'action_order_submit',
|
||||
'title'=>'Order Submit',
|
||||
],
|
||||
// Client accepts order, if performed by RW
|
||||
'ORDER-ACCEPT' => [
|
||||
'fail'=>FALSE,
|
||||
'next'=>[
|
||||
'SETUP-PAYMENT-WAIT'=>['customer'],
|
||||
],
|
||||
'system'=>FALSE,
|
||||
'method'=>'action_order_accept',
|
||||
'title'=>'Client Accept Order',
|
||||
],
|
||||
// If the product has a setup, collect payment information
|
||||
'SETUP-PAYMENT-WAIT' => [
|
||||
'fail'=>FALSE,
|
||||
'next'=>[
|
||||
'PAYMENT-WAIT'=>['customer'],
|
||||
],
|
||||
'system'=>FALSE,
|
||||
'method'=>'action_setup_payment_wait',
|
||||
'title'=>'Setup Payment',
|
||||
],
|
||||
'PAYMENT-WAIT' => [
|
||||
'fail'=>FALSE,
|
||||
'next'=>[
|
||||
'PAYMENT-CHECK'=>['reseller','wholesaler'],
|
||||
],
|
||||
'system'=>FALSE,
|
||||
'method'=>'action_payment_wait',
|
||||
'title'=>'Service Payment',
|
||||
],
|
||||
'PAYMENT-CHECK' => [
|
||||
'fail'=>'ORDER-HOLD',
|
||||
'next'=>[
|
||||
'ORDER-SENT'=>[],
|
||||
],
|
||||
'system'=>TRUE,
|
||||
'method'=>'action_payment_check',
|
||||
'title'=>'Validate Payment Method',
|
||||
],
|
||||
// Order On Hold (Reason)
|
||||
'ORDER-HOLD' => ['release'=>'ORDER-SUBMIT','update_reference'=>'ORDER-SENT'],
|
||||
// Order Rejected (Reason)
|
||||
@ -102,7 +154,15 @@ class Service extends Model
|
||||
// Order Cancelled
|
||||
'ORDER-CANCELLED' => [],
|
||||
// Order Sent to Supplier
|
||||
'ORDER-SENT' => ['update_reference'=>'ORDER-SENT','confirm'=>'ORDERED'],
|
||||
'ORDER-SENT' => [
|
||||
'fail'=>'ORDER-HOLD',
|
||||
'next'=>[
|
||||
'ORDERED'=>['wholesaler'],
|
||||
],
|
||||
'system'=>FALSE,
|
||||
'method'=>'action_order_sent',
|
||||
'title'=>'Send Order',
|
||||
],
|
||||
// Order Confirmed by Supplier
|
||||
'ORDERED' => ['update_reference'=>'ORDER-SENT'],
|
||||
];
|
||||
@ -493,7 +553,7 @@ class Service extends Model
|
||||
*/
|
||||
public function getNameShortAttribute()
|
||||
{
|
||||
return $this->type ? $this->type->service_name : $this->id;
|
||||
return $this->type ? $this->type->name : $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -504,25 +564,14 @@ class Service extends Model
|
||||
return $this->getInvoiceNextAttribute();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will present the Order Info Details
|
||||
*/
|
||||
public function getOrderInfoDetailsAttribute(): string
|
||||
public function getOrderInfoNotesAttribute(): ?string
|
||||
{
|
||||
if (! $this->order_info)
|
||||
return '';
|
||||
return $this->getOrderInfoValue('notes');
|
||||
}
|
||||
|
||||
$result = '';
|
||||
|
||||
foreach ($this->order_info as $k=>$v)
|
||||
{
|
||||
if (in_array($k,['order_reference']))
|
||||
continue;
|
||||
|
||||
$result .= sprintf('%s: <b>%s</b><br>',ucfirst($k),$v);
|
||||
}
|
||||
|
||||
return $result;
|
||||
public function getOrderInfoReferenceAttribute(): ?string
|
||||
{
|
||||
return $this->getOrderInfoValue('reference');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -738,6 +787,218 @@ class Service extends Model
|
||||
|
||||
/** FUNCTIONS **/
|
||||
|
||||
// The action methods will return: NULL for no progress|FALSE for a failed status|next stage name.
|
||||
|
||||
/**
|
||||
* Process for an order when status ORDER-ACCEPT stage.
|
||||
* This method should have the client confirm/accept the order, if it was placed by a reseller/wholesaler.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function action_order_accept(): ?bool
|
||||
{
|
||||
// @todo TO IMPLEMENT
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Action method when status ORDER_SENT
|
||||
* This method redirects to a form, where updating the form will progress to the next stage.
|
||||
*/
|
||||
private function action_order_sent()
|
||||
{
|
||||
throw new HttpException(301,url('r/service/update',$this->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Action method when status ORDER_SUBMIT
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function action_order_submit(): ?bool
|
||||
{
|
||||
// @todo TO IMPLEMENT
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process for an order when status SETUP-PAYMENT-WAIT stage.
|
||||
* This method should collect any setup fees payment.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function action_setup_payment_wait(): ?bool
|
||||
{
|
||||
// @todo TO IMPLEMENT
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process for an order when status PAYMENT-CHECK stage.
|
||||
* This method should validate any payment details.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function action_payment_check(): ?bool
|
||||
{
|
||||
// @todo TO IMPLEMENT
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process for an order when status PAYMENT-WAIT stage.
|
||||
* This method should collect any service payment details.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function action_payment_wait(): ?bool
|
||||
{
|
||||
// @todo TO IMPLEMENT
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
private function getOrderInfoValue(string $key): ?string
|
||||
{
|
||||
return $this->order_info ? $this->order_info->get($key) : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current stage parameters
|
||||
*
|
||||
* @param string $stage
|
||||
* @return array
|
||||
*/
|
||||
private function getStageParameters(string $stage): Collection
|
||||
{
|
||||
$result = collect(Arr::get(self::$action_progress,$stage));
|
||||
$myrole = array_search(Auth::user()->role(),User::$role_order);
|
||||
|
||||
// If we have no valid next stage, return an empty collection.
|
||||
if (! $result->count() OR $myrole===FALSE)
|
||||
return $result;
|
||||
|
||||
// Filter the result based on who we are
|
||||
$next = collect();
|
||||
|
||||
foreach ($result->get('next') as $action=>$roles) {
|
||||
|
||||
// Can the current user do this role?
|
||||
$cando = FALSE;
|
||||
foreach ($roles as $role) {
|
||||
if ($myrole < array_search($role,User::$role_order)) {
|
||||
$cando = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//dd($action,$roles,$result);
|
||||
if ($cando OR $result->get('system')) {
|
||||
$next->put($action,$roles);
|
||||
}
|
||||
}
|
||||
|
||||
$result->put('next',$next);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @notes
|
||||
* + When progressing stages, we know who the user is that initiated the stage,
|
||||
* + If no user, then we perform stages SYSTEM=TRUE
|
||||
* + We need to validate that the current stage is complete, before progressing to the next stage
|
||||
* + The current stage may require input from a user, or automation process to progress
|
||||
* + Before leaving this method, we update the service with the stage that it is currently on.
|
||||
*
|
||||
* @param string $stage
|
||||
* @return bool|int|string|null
|
||||
*/
|
||||
public function action(string $stage)
|
||||
{
|
||||
// While stage has a string value, that indicates the next stage we want to go to
|
||||
// If stage is NULL, the current stage hasnt been completed
|
||||
// If stage is FALSE, then the current stage failed, and may optionally be directed to another stage.
|
||||
|
||||
while ($stage) {
|
||||
// Check that stage is a valid next action for the user currently performing it
|
||||
$current = $this->getStageParameters($this->order_status);
|
||||
$next = $this->getStageParameters($stage);
|
||||
|
||||
// If valid, call the method to confirm that the current stage is complete
|
||||
if (method_exists($this,$current['method'])) {
|
||||
try {
|
||||
$result = $this->{$current['method']}();
|
||||
|
||||
// If we have a form to complete, we need to return with a URL, so we can catch that with an Exception
|
||||
} catch (HttpException $e) {
|
||||
if ($e->getStatusCode() == 301)
|
||||
return ($e->getMessage());
|
||||
}
|
||||
|
||||
// @todo Implement a status message
|
||||
if (is_null($result)) {
|
||||
$stage = NULL;
|
||||
abort(500,'Current Method Cannot Proceed: '.$result);
|
||||
|
||||
// @todo Implement a status message
|
||||
} elseif (! $result) {
|
||||
$stage = NULL;
|
||||
abort(500,'Current Method FAILED: '.$result);
|
||||
|
||||
} else {
|
||||
$this->order_status = $stage;
|
||||
$this->save();
|
||||
|
||||
// If we have more than 1 next step for the next stage, we'll have to end.
|
||||
if ($this->actions()->count() > 1) {
|
||||
$stage = NULL;
|
||||
|
||||
} else {
|
||||
$stage = $this->actions()->keys()->first();
|
||||
}
|
||||
}
|
||||
|
||||
// @todo Implement a status message
|
||||
} else {
|
||||
// Cant do anything, dont have a method to check if we can leave
|
||||
$stage = NULL;
|
||||
abort(500,'NO Method Cannot Proceed to leave this stage: '.$next['method']);
|
||||
}
|
||||
|
||||
// If valid, call the method to start the next stage
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Work out the next applicable actions for this service status
|
||||
*
|
||||
* @notes
|
||||
* + Clients can only progress 1 step, if they are in the next step.
|
||||
* + Resellers/Wholesales can progress to the next Reseller/Wholesaler and any steps in between.
|
||||
*
|
||||
* @param bool $next Only show next actions
|
||||
* @return Collection
|
||||
*/
|
||||
public function actions(): Collection
|
||||
{
|
||||
$result = collect();
|
||||
$action = $this->getStageParameters($this->order_status);
|
||||
|
||||
if (! $action->count())
|
||||
return $result;
|
||||
|
||||
// Next Action
|
||||
foreach ($this->getStageParameters($this->order_status)->get('next') as $k=>$v) {
|
||||
$result->put($k,Arr::get(self::$action_progress,$k.'.title'));
|
||||
}
|
||||
|
||||
// No next actions, that will mean the current action hasnt completed.
|
||||
if (! $result->count())
|
||||
$result->put($this->order_status,Arr::get($action,'title'));
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add applicable tax to the cost
|
||||
*
|
||||
@ -802,7 +1063,7 @@ class Service extends Model
|
||||
*/
|
||||
public function next_invoice_items(bool $future): Collection
|
||||
{
|
||||
if ($this->wasCancelled() OR $this->suspend_billing OR ! $this->active)
|
||||
if ($this->wasCancelled() OR $this->suspend_billing OR $this->external_billing OR (! $future AND ! $this->active))
|
||||
return collect();
|
||||
|
||||
// If pending, add any connection charges
|
||||
@ -879,23 +1140,6 @@ class Service extends Model
|
||||
return $this->invoice_items->filter(function($item) { return ! $item->exists; });
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo
|
||||
* @param string $status
|
||||
* @return $this
|
||||
*/
|
||||
public function nextStatus(string $status) {
|
||||
if ($x=$this->validStatus($status))
|
||||
{
|
||||
$this->order_status = $x;
|
||||
$this->save();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
abort(500,'Next Status not set up for:'.$this->order_status);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return the associated service model for the product type
|
||||
* @deprecated use $this->type
|
||||
@ -919,22 +1163,17 @@ class Service extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Return if the proposed status is valid.
|
||||
* Store order info details
|
||||
*
|
||||
* @param string $status
|
||||
* @return string | NULL
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
*/
|
||||
private function testNextStatusValid(string $status)
|
||||
public function setOrderInfo(string $key,string $value): void
|
||||
{
|
||||
return Arr::get(Arr::get($this->valid_status,$this->order_status,[]),$status,NULL);
|
||||
}
|
||||
$x = is_null($this->order_info) ? collect() : $this->order_info;
|
||||
$x->put($key,$value);
|
||||
|
||||
/**
|
||||
* @deprecated use testNextStatusValid()
|
||||
*/
|
||||
public function validStatus(string $status)
|
||||
{
|
||||
return $this->testNextStatusValid($status);
|
||||
$this->order_info = $x;
|
||||
}
|
||||
|
||||
/**
|
||||
|
12
app/User.php
12
app/User.php
@ -64,6 +64,16 @@ class User extends Authenticatable
|
||||
|
||||
protected $with = ['accounts'];
|
||||
|
||||
/**
|
||||
* Role hierarchy order
|
||||
* @var array
|
||||
*/
|
||||
public static $role_order = [
|
||||
'wholesaler',
|
||||
'reseller',
|
||||
'customer',
|
||||
];
|
||||
|
||||
/**
|
||||
* The accounts that this user manages
|
||||
*
|
||||
@ -452,7 +462,7 @@ class User extends Authenticatable
|
||||
public function client_service_movements(): DatabaseCollection
|
||||
{
|
||||
return Service::active()
|
||||
->select(['id','account_id','product_id','order_status'])
|
||||
->select(['id','account_id','product_id','order_status','model'])
|
||||
->where('order_status','!=','ACTIVE')
|
||||
->whereIN('account_id',$this->all_accounts()->pluck('id')->unique()->toArray())
|
||||
->with(['account','product'])
|
||||
|
@ -3,7 +3,7 @@
|
||||
return [
|
||||
'pdf' => array(
|
||||
'enabled' => true,
|
||||
'binary' => '/usr/bin/wkhtmltopdf',
|
||||
'binary' => '/usr/local/bin/wkhtmltopdf',
|
||||
'timeout' => false,
|
||||
'options' => array('print-media-type' => true),
|
||||
'env' => array(),
|
||||
@ -11,7 +11,7 @@ return [
|
||||
|
||||
'image' => array(
|
||||
'enabled' => false,
|
||||
'binary' => '/var/www/html/vendor/bin/wkhtmltoimage',
|
||||
'binary' => '/usr/local/bin/wkhtmltoimage',
|
||||
'timeout' => false,
|
||||
'options' => array(),
|
||||
'env' => array(),
|
||||
|
@ -1,52 +0,0 @@
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">New Order Sent to Supplier</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse" data-toggle="tooltip" title="Collapse">
|
||||
<i class="fa fa-minus"></i></button>
|
||||
<button type="button" class="btn btn-box-tool" data-widget="remove" data-toggle="tooltip" title="Remove">
|
||||
<i class="fa fa-times"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<table class="table table-condensed" width="100%">
|
||||
<tr>
|
||||
<th>Account</th><td>{{ $o->account->company }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Product</th><td>{{ $o->product->name }}: {{ $o->name }}</td>
|
||||
</tr>
|
||||
@if($o->date_last_invoice)
|
||||
<tr>
|
||||
<th>Last Invoice</th><td>{{ $o->date_last_invoice }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Paid Until</th><td>{{ 'TBA' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Next Invoice</th><td>{{ $o->date_next_invoice }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
<tr>
|
||||
<th>Ordered</th><td>{{ $o->date_orig->format('Y-m-d') }}</td>
|
||||
</tr>
|
||||
@if ($o->date_last)
|
||||
<tr>
|
||||
<th>Update</th><td>{{ $o->date_last->format('Y-m-d') }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
<tr>
|
||||
<th>Order Details</th><td>{!! $o->order_info_details !!}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Reference:</th><td><input type="text" name="notes" class="" value="{{ \Illuminate\Support\Arr::get($o->order_info,'order_reference','') }}"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{--
|
||||
<div class="box-footer">
|
||||
</div>
|
||||
--}}
|
||||
</div>
|
@ -1,52 +0,0 @@
|
||||
<div class="box">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">New Order Submitted</h3>
|
||||
<div class="box-tools pull-right">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse" data-toggle="tooltip" title="Collapse">
|
||||
<i class="fa fa-minus"></i></button>
|
||||
<button type="button" class="btn btn-box-tool" data-widget="remove" data-toggle="tooltip" title="Remove">
|
||||
<i class="fa fa-times"></i></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="box-body">
|
||||
<table class="table table-condensed" width="100%">
|
||||
<tr>
|
||||
<th>Account</th><td>{{ $o->account->company }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Product</th><td>{{ $o->product->name }}: {{ $o->name }}</td>
|
||||
</tr>
|
||||
@if($o->date_last_invoice)
|
||||
<tr>
|
||||
<th>Last Invoice</th><td>{{ $o->date_last_invoice }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Paid Until</th><td>{{ 'TBA' }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Next Invoice</th><td>{{ $o->date_next_invoice }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
<tr>
|
||||
<th>Ordered</th><td>{{ $o->date_orig->format('Y-m-d') }}</td>
|
||||
</tr>
|
||||
@if ($o->date_last)
|
||||
<tr>
|
||||
<th>Update</th><td>{{ $o->date_last->format('Y-m-d') }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
<tr>
|
||||
<th>Order Details</th><td>{!! $o->order_info_details !!}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Save/Reject Note:</th><td><input type="text" name="notes" class=""></td>
|
||||
</th>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{{--
|
||||
<div class="box-footer">
|
||||
</div>
|
||||
--}}
|
||||
</div>
|
@ -0,0 +1,81 @@
|
||||
@extends('adminlte::layouts.app')
|
||||
|
||||
@section('htmlheader_title')
|
||||
{{ $o->sid }}
|
||||
@endsection
|
||||
@section('page_title')
|
||||
{{ $o->sid }}
|
||||
@endsection
|
||||
|
||||
@section('contentheader_title')
|
||||
Service: {{ $o->sid }} <strong>{{ $o->product->name }}</strong>
|
||||
@endsection
|
||||
@section('contentheader_description')
|
||||
{{ $o->sname }}: {{ $o->sdesc }}
|
||||
@endsection
|
||||
|
||||
@section('main-content')
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="card-title">Update Order Status: {{ $o->order_status }}</div>
|
||||
</div>
|
||||
|
||||
<form class="form-horizontal" method="post" action="{{ url('r/service/update',$o->id) }}">
|
||||
{{ csrf_field() }}
|
||||
|
||||
<div class="card-body">
|
||||
<div class="form-group row">
|
||||
<label for="reference" class="col-sm-2 col-form-label text-right">Order Ref</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-hashtag"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="reference" value="{{ $o->order_info_reference ?? '' }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@includeIf('u.service.widgets.'.$o->stype.'.order',['o'=>$o->type])
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="notes" class="col-sm-2 col-form-label text-right">Notes</label>
|
||||
<div class="col-sm-10">
|
||||
<textarea class="textarea" name="notes">{{ $o->order_info_notes ?? '' }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-footer">
|
||||
<button type="reset" class="btn btn-secondary mr-2" onclick="window.history.go(-1); return false;">Cancel</button>
|
||||
<button type="submit" class="btn btn-success">Submit</button>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section('page-scripts')
|
||||
@css('//cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote-bs4.css','summernote-css')
|
||||
@js('//cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote-bs4.js','summernote-js')
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
$('.textarea').summernote({
|
||||
minHeight: 350,
|
||||
toolbar: [
|
||||
['style', ['style']],
|
||||
['font', ['bold', 'underline', 'clear']],
|
||||
['color', ['color']],
|
||||
['para', ['ul', 'ol', 'paragraph']],
|
||||
['table', ['table']],
|
||||
['view', ['codeview', 'help']],
|
||||
],
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@append
|
@ -26,7 +26,7 @@
|
||||
<tr>
|
||||
<td><a href="{{ url('u/service',$o->id) }}">{{ $o->id }}</a></td>
|
||||
<td>{{ $o->account->name }}</td>
|
||||
<td>{{ $o->name }}</td>
|
||||
<td>{{ $o->name_short }}</td>
|
||||
<td>{{ $o->status }}</td>
|
||||
<td>{{ $o->product->name }}</td>
|
||||
</tr>
|
||||
|
@ -31,7 +31,9 @@
|
||||
<li class="nav-item"><a class="nav-link active" href="#product" data-toggle="tab">Product</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#traffic" data-toggle="tab">Traffic</a></li>
|
||||
--}}
|
||||
<li class="nav-item active"><a class="nav-link" href="#pending_items" data-toggle="tab">Pending Items</a></li>
|
||||
@if (! $o->suspend_billing AND ! $o->external_billing)
|
||||
<li class="nav-item active"><a class="nav-link" href="#pending_items" data-toggle="tab">Pending Items</a></li>
|
||||
@endif
|
||||
{{--
|
||||
<li class="nav-item"><a class="nav-link" href="#invoices" data-toggle="tab">Invoices</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#emails" data-toggle="tab">Emails</a></li>
|
||||
@ -48,11 +50,10 @@
|
||||
ACTION <span class="caret"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a class="dropdown-item" tabindex="-1" href="#tab_3">Action</a>
|
||||
<a class="dropdown-item" tabindex="-1" href="#">Another action</a>
|
||||
<a class="dropdown-item" tabindex="-1" href="#">Something else here</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" tabindex="-1" href="#">Separated link</a>
|
||||
@foreach($o->actions() as $action => $title)
|
||||
<a class="dropdown-item" tabindex="-1" href="{{ url('u/service/progress',['id'=>$o->id,'action'=>$action]) }}">{{ $title }}</a>
|
||||
@endforeach
|
||||
{{-- <div class="dropdown-divider"></div> --}}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
@ -67,9 +68,11 @@
|
||||
<div class="tab-pane fade" id="product" role="tabpanel">
|
||||
Product.
|
||||
</div>
|
||||
<div class="tab-pane fade show active" id="pending_items" role="tabpanel">
|
||||
@include('common.service.widget.invoice')
|
||||
</div>
|
||||
@if (! $o->suspend_billing AND ! $o->external_billing)
|
||||
<div class="tab-pane fade show active" id="pending_items" role="tabpanel">
|
||||
@include('common.service.widget.invoice')
|
||||
</div>
|
||||
@endif
|
||||
<div class="tab-pane fade" id="invoices" role="tabpanel">
|
||||
Invoices.
|
||||
</div>
|
@ -0,0 +1,11 @@
|
||||
<div class="form-group row">
|
||||
<label for="reference" class="col-sm-2 col-form-label text-right">Service Number</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text"><i class="fa fa-fw fa-phone"></i></span>
|
||||
</div>
|
||||
<input type="text" class="form-control" name="broadband[service_number]" value="{{ $o->service_number ?? '' }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,4 +1,12 @@
|
||||
<div class="card">
|
||||
@if($o->external_billing)
|
||||
<div class="ribbon-wrapper ribbon-lg">
|
||||
<div class="ribbon bg-danger">
|
||||
EXTERNAL BILLING
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card-header bg-light">
|
||||
<h3 class="card-title">Service Information</h3>
|
||||
</div>
|
||||
@ -13,7 +21,7 @@
|
||||
<th>Status</th>
|
||||
<td>{!! $o->status_html !!}</td>
|
||||
</tr>
|
||||
@if ($o->active or $o->isPending())
|
||||
@if (($o->active OR $o->isPending()) AND ! $o->external_billing)
|
||||
<tr>
|
||||
<th>Billed</th>
|
||||
<td>{{ $o->billing_period }}</td>
|
||||
@ -43,7 +51,7 @@
|
||||
<td>@if ($o->autopay)Direct Debit @else Invoice @endif</td>
|
||||
</tr>
|
||||
|
||||
@elseif(! $o->wasCancelled())
|
||||
@elseif($o->wasCancelled())
|
||||
<tr>
|
||||
<th>Cancelled</th>
|
||||
<td>{!! $o->date_end ? $o->date_end->format('Y-m-d') : $o->paid_to->format('Y-m-d').'<sup>*</sup>' !!}</td>
|
||||
|
@ -43,6 +43,9 @@ Route::group(['middleware'=>['theme:adminlte-be','auth','role:reseller'],'prefix
|
||||
Route::get('supplier/create','SuppliersController@create');
|
||||
Route::post('supplier/store','SuppliersController@store');
|
||||
Route::get('switch/start/{id}','\Leenooks\Controllers\AdminController@user_switch_start')->name('switch.user.stop');
|
||||
Route::match(['get','post'],'service/update/{o}','ServiceController@update')
|
||||
->where('o','[0-9]+')
|
||||
->middleware('can:update,o');
|
||||
});
|
||||
|
||||
// Our User Routes
|
||||
@ -63,6 +66,9 @@ Route::group(['middleware'=>['theme:adminlte-be','auth'],'prefix'=>'u'],function
|
||||
Route::get('service/{o}','UserHomeController@service')
|
||||
->where('o','[0-9]+')
|
||||
->middleware('can:view,o');
|
||||
Route::get('service/progress/{o}/{status}','UserHomeController@service_progress')
|
||||
->where('o','[0-9]+')
|
||||
->middleware('can:progress,o,status');
|
||||
});
|
||||
|
||||
// Frontend Routes (Non-Authed Users)
|
||||
|
Loading…
Reference in New Issue
Block a user