Merge branch '679-separate-screen-for-resq-transations' into 'master'
Resolve "Separate screen for RESQ transations" Closes #679 See merge request jankstudio/resq!793
This commit is contained in:
commit
f90badd331
7 changed files with 361 additions and 4 deletions
|
|
@ -272,6 +272,8 @@ access_keys:
|
|||
label: Hub View
|
||||
- id: jo_cancel.fulfill
|
||||
label: Fulfill Cancelled JO
|
||||
- id: jo_resq_proc.list
|
||||
label: RESQ Dispatch
|
||||
|
||||
- id: support
|
||||
label: Customer Support Access
|
||||
|
|
|
|||
|
|
@ -132,6 +132,10 @@ main_menu:
|
|||
acl: jo_proc.list
|
||||
label: Dispatch
|
||||
parent: joborder
|
||||
- id: jo_resq_proc
|
||||
acl: jo_resq_proc.list
|
||||
label: RESQ Dispatch
|
||||
parent: joborder
|
||||
- id: jo_assign
|
||||
acl: jo_assign.list
|
||||
label: Rider Assignment
|
||||
|
|
|
|||
9
config/routes/resq_job_order.yaml
Normal file
9
config/routes/resq_job_order.yaml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
jo_resq_proc:
|
||||
path: /resq-job-order/processing
|
||||
controller: App\Controller\ResqJobOrderController::listProcessing
|
||||
methods: [GET]
|
||||
|
||||
jo_resq_proc_rows:
|
||||
path: /resq-job-order/processing-rows
|
||||
controller: App\Controller\ResqJobOrderController::datatableRows
|
||||
methods: [POST]
|
||||
|
|
@ -316,7 +316,7 @@ class JobOrderController extends Controller
|
|||
/**
|
||||
* @Menu(selected="jo_proc")
|
||||
*/
|
||||
public function processingForm(HubSelector $hub_selector, $id, JobOrderHandlerInterface $jo_handler, GISManagerInterface $gis, MotivConnector $motiv)
|
||||
public function processingForm(HubSelector $hub_selector, $id, JobOrderHandlerInterface $jo_handler, GISManagerInterface $gis, MotivConnector $motiv, Request $req)
|
||||
{
|
||||
$this->denyAccessUnlessGranted('jo_proc.list', null, 'No access.');
|
||||
|
||||
|
|
@ -337,6 +337,18 @@ class JobOrderController extends Controller
|
|||
$params['return_url'] = $this->generateUrl('jo_proc');
|
||||
$params['map_js_file'] = $gis->getJSJOFile();
|
||||
|
||||
// check for origin parameter
|
||||
$origin = $req->query->get('origin', '');
|
||||
if (empty($origin))
|
||||
{
|
||||
// set return url to default dispatch
|
||||
$params['return_url'] = $this->generateUrl('jo_proc');
|
||||
}
|
||||
else
|
||||
{
|
||||
// set return url to resq dispatch
|
||||
$params['return_url'] = $this->generateUrl('jo_resq_proc');
|
||||
}
|
||||
$template = $params['template'];
|
||||
|
||||
// response
|
||||
|
|
@ -795,15 +807,25 @@ class JobOrderController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
public function unlockProcessor($id, JobOrderHandlerInterface $jo_handler)
|
||||
public function unlockProcessor($id, JobOrderHandlerInterface $jo_handler, Request $req)
|
||||
{
|
||||
$this->denyAccessUnlessGranted('jo_proc.unlock', null, 'No access.');
|
||||
|
||||
// call unlockProcessor in job order service
|
||||
$jo_handler->unlockProcessor($id);
|
||||
|
||||
// redirect to list
|
||||
return $this->redirectToRoute('jo_proc');
|
||||
// get the origin
|
||||
$origin = $req->query->get('origin', '');
|
||||
if (empty($origin))
|
||||
{
|
||||
// redirect to list
|
||||
return $this->redirectToRoute('jo_proc');
|
||||
}
|
||||
else
|
||||
{
|
||||
// redirect to resq list
|
||||
return $this->redirectToRoute('jo_resq_proc');
|
||||
}
|
||||
}
|
||||
|
||||
public function unlockAssignor($id, JobOrderHandlerInterface $jo_handler)
|
||||
|
|
|
|||
158
src/Controller/ResqJobOrderController.php
Normal file
158
src/Controller/ResqJobOrderController.php
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
|
||||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use Catalyst\MenuBundle\Annotation\Menu;
|
||||
|
||||
use App\Entity\JobOrder;
|
||||
|
||||
use App\Service\JobOrderHandlerInterface;
|
||||
|
||||
use App\Ramcar\TransactionOrigin;
|
||||
use App\Ramcar\JOStatus;
|
||||
use App\Ramcar\ServiceType;
|
||||
use App\Ramcar\WillingToWaitContent;
|
||||
use App\Ramcar\CustomerClassification;
|
||||
|
||||
class ResqJobOrderController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Menu(selected="jo_resq_proc")
|
||||
* @IsGranted("jo_resq_proc.list")
|
||||
*/
|
||||
public function listProcessing()
|
||||
{
|
||||
$params['table_refresh_rate'] = $this->container->getParameter('job_order_refresh_interval');
|
||||
|
||||
return $this->render('resq-job-order/list.processing.html.twig', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @IsGranted("jo_resq_proc.list")
|
||||
*/
|
||||
public function datatableRows(Request $req, JobOrderHandlerInterface $jo_handler)
|
||||
{
|
||||
// get query builder
|
||||
$qb = $this->getDoctrine()
|
||||
->getRepository(JobOrder::class)
|
||||
->createQueryBuilder('q');
|
||||
|
||||
// get datatable params
|
||||
$datatable = $req->request->get('datatable');
|
||||
|
||||
// count total records
|
||||
$tquery = $qb->select('COUNT(q)');
|
||||
|
||||
$this->setQueryFilters($datatable, $tquery, $qb, JOStatus::PENDING, TransactionOrigin::MOBILE_APP);
|
||||
|
||||
$total = $tquery->getQuery()
|
||||
->getSingleScalarResult();
|
||||
|
||||
// get current page number
|
||||
$page = $datatable['pagination']['page'] ?? 1;
|
||||
|
||||
$perpage = $datatable['pagination']['perpage'];
|
||||
$offset = ($page - 1) * $perpage;
|
||||
|
||||
// add metadata
|
||||
$meta = [
|
||||
'page' => $page,
|
||||
'perpage' => $perpage,
|
||||
'pages' => ceil($total / $perpage),
|
||||
'total' => $total,
|
||||
'sort' => 'asc',
|
||||
'field' => 'id'
|
||||
];
|
||||
|
||||
// build query
|
||||
$query = $qb->select('q');
|
||||
|
||||
$this->setQueryFilters($datatable, $query, $qb, JOStatus::PENDING, TransactionOrigin::MOBILE_APP);
|
||||
|
||||
// check if sorting is present, otherwise use default
|
||||
if (isset($datatable['sort']['field']) && !empty($datatable['sort']['field'])) {
|
||||
$order = $datatable['sort']['sort'] ?? 'asc';
|
||||
$query->orderBy('q.' . $datatable['sort']['field'], $order);
|
||||
} else {
|
||||
$query->orderBy('q.date_schedule', 'asc');
|
||||
}
|
||||
|
||||
// get rows for this page
|
||||
$query_obj = $query->setFirstResult($offset)
|
||||
->setMaxResults($perpage)
|
||||
->getQuery();
|
||||
|
||||
$obj_rows = $query_obj->getResult();
|
||||
|
||||
$statuses = JOStatus::getCollection();
|
||||
$service_types = ServiceType::getCollection();
|
||||
|
||||
// process rows
|
||||
$rows = [];
|
||||
foreach ($obj_rows as $orow) {
|
||||
$is_vip = false;
|
||||
$is_emergency = false;
|
||||
|
||||
// check if customer is vip
|
||||
$cust_class = $orow->getCustomer()->getCustomerClassification();
|
||||
if ($cust_class == CustomerClassification::VIP)
|
||||
$is_vip = true;
|
||||
|
||||
// check if customer is not willing to wait
|
||||
$will_not_wait = $orow->getWillWait();
|
||||
if ($will_not_wait == WillingToWaitContent::NOT_WILLING_TO_WAIT)
|
||||
$is_emergency = true;
|
||||
|
||||
// add row data
|
||||
$row['id'] = $orow->getID();
|
||||
$row['customer_name'] = $orow->getCustomer()->getFirstName() . ' ' . $orow->getCustomer()->getLastName();
|
||||
$row['delivery_address'] = $orow->getDeliveryAddress();
|
||||
$row['date_schedule'] = $orow->getDateSchedule()->format("d M Y g:i A");
|
||||
$row['type'] = $orow->isAdvanceOrder() ? 'Advanced Order' : 'Immediate';
|
||||
$row['service_type'] = $service_types[$orow->getServiceType()];
|
||||
$row['status'] = $statuses[$orow->getStatus()];
|
||||
$row['flag_advance'] = $orow->isAdvanceOrder();
|
||||
$row['plate_number'] = $orow->getCustomerVehicle()->getPlateNumber();
|
||||
$row['is_mobile'] = $orow->getSource() == TransactionOrigin::MOBILE_APP;
|
||||
$row['is_vip'] = $is_vip;
|
||||
$row['is_emergency'] = $is_emergency;
|
||||
|
||||
$processor = $orow->getProcessedBy();
|
||||
if ($processor == null)
|
||||
$row['processor'] = '';
|
||||
else
|
||||
$row['processor'] = $orow->getProcessedBy()->getFullName();
|
||||
|
||||
// add the items for Actions
|
||||
$jo_id = $orow->getID();
|
||||
|
||||
$row['meta']['update_url'] = $this->generateUrl('jo_proc_form', ['id' => $jo_id, 'origin' => 'resq']);
|
||||
$row['meta']['unlock_url'] = $this->generateUrl('jo_proc_unlock', ['id' => $jo_id, 'origin' => 'resq']);
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
// response
|
||||
return $this->json([
|
||||
'meta' => $meta,
|
||||
'data' => $rows
|
||||
]);
|
||||
}
|
||||
|
||||
protected function setQueryFilters($datatable, &$query, $qb, $status, $source)
|
||||
{
|
||||
$query->where('q.status = :status')
|
||||
->andWhere('q.source = :source')
|
||||
->setParameter('status', $status)
|
||||
->setParameter('source', $source);
|
||||
}
|
||||
}
|
||||
|
|
@ -3628,6 +3628,13 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
->setParameter('end_current_date', $end_current_date)
|
||||
->setParameter('statuses', $status, Connection::PARAM_STR_ARRAY);
|
||||
}
|
||||
break;
|
||||
case 'proc':
|
||||
$query->where('q.status = :status')
|
||||
->andWhere('q.source <> :source')
|
||||
->setParameter('status', $status)
|
||||
->setParameter('source', TransactionOrigin::MOBILE_APP);
|
||||
|
||||
break;
|
||||
default:
|
||||
$query->where('q.status = :status')
|
||||
|
|
|
|||
155
templates/resq-job-order/list.processing.html.twig
Normal file
155
templates/resq-job-order/list.processing.html.twig
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
{% extends 'base.html.twig' %}
|
||||
|
||||
{% block body %}
|
||||
<!-- BEGIN: Subheader -->
|
||||
<div class="m-subheader">
|
||||
<div class="d-flex align-items-center">
|
||||
<div class="mr-auto">
|
||||
<h3 class="m-subheader__title">
|
||||
RESQ Job Orders (Dispatch)
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END: Subheader -->
|
||||
<div class="m-content">
|
||||
<!--Begin::Section-->
|
||||
<div class="row">
|
||||
<div class="col-xl-12">
|
||||
<div class="m-portlet m-portlet--mobile">
|
||||
<div class="m-portlet__body">
|
||||
<div class="m-form m-form--label-align-right m--margin-top-20 m--margin-bottom-30">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-xl-12">
|
||||
<div class="form-group m-form__group row align-items-center">
|
||||
<div class="col-md-4">
|
||||
<div class="m-input-icon m-input-icon--left">
|
||||
<input type="text" class="form-control m-input m-input--solid" placeholder="Search..." id="data-rows-search">
|
||||
<span class="m-input-icon__icon m-input-icon__icon--left">
|
||||
<span><i class="la la-search"></i></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--begin: Datatable -->
|
||||
<div id="data-rows"></div>
|
||||
<!--end: Datatable -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(function() {
|
||||
var options = {
|
||||
data: {
|
||||
type: 'remote',
|
||||
source: {
|
||||
read: {
|
||||
url: '{{ url('jo_resq_proc_rows') }}',
|
||||
method: 'POST'
|
||||
}
|
||||
},
|
||||
saveState: {
|
||||
cookie: false,
|
||||
webstorage: false
|
||||
},
|
||||
pageSize: 10,
|
||||
serverPaging: true,
|
||||
serverFiltering: true,
|
||||
serverSorting: true
|
||||
},
|
||||
rows: {
|
||||
beforeTemplate: function (row, data, index) {
|
||||
var attribute = getRowAttribute(data);
|
||||
// check if we have to apply a background color for the row
|
||||
if (attribute) {
|
||||
var row_class = "m-table__row--" + attribute;
|
||||
$(row).addClass(row_class);
|
||||
}
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'JO Number'
|
||||
},
|
||||
{
|
||||
field: 'delivery_address',
|
||||
title: 'Customer Area'
|
||||
},
|
||||
{
|
||||
field: 'type',
|
||||
title: 'Schedule'
|
||||
},
|
||||
{
|
||||
field: 'date_schedule',
|
||||
title: 'Scheduled Date'
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
title: 'Status'
|
||||
},
|
||||
{
|
||||
field: 'processor',
|
||||
title: 'Dispatcher'
|
||||
},
|
||||
{
|
||||
field: 'Actions',
|
||||
width: 110,
|
||||
title: 'Actions',
|
||||
sortable: false,
|
||||
overflow: 'visible',
|
||||
template: function (row, index, datatable) {
|
||||
var actions = '<a href="' + row.meta.update_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" title="View / Edit"><i class="la la-edit"></i></a>';
|
||||
|
||||
{% if is_granted('jo_proc.unlock') %}
|
||||
if (row.meta.unlock_url != '') {
|
||||
actions += '<a href="' + row.meta.unlock_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit" title="Unlock"><i class="fa fa-unlock"></i></a>';
|
||||
}
|
||||
{% endif %}
|
||||
|
||||
return actions;
|
||||
},
|
||||
}
|
||||
],
|
||||
search: {
|
||||
onEnter: false,
|
||||
input: $('#data-rows-search'),
|
||||
delay: 400
|
||||
}
|
||||
};
|
||||
|
||||
var table = $("#data-rows").mDatatable(options);
|
||||
|
||||
// auto refresh table
|
||||
setInterval(function() {
|
||||
table.reload();
|
||||
}, {{ table_refresh_rate }});
|
||||
});
|
||||
|
||||
function getRowAttribute(data) {
|
||||
if (data.is_vip) {
|
||||
return 'is_vip';
|
||||
}
|
||||
if (data.is_emergency) {
|
||||
return 'is_emergency';
|
||||
}
|
||||
if (data.flag_advance) {
|
||||
return 'danger';
|
||||
}
|
||||
if (data.is_mobile) {
|
||||
return 'is_mobile';
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
Loading…
Reference in a new issue