Progress on order progress
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user