Compare commits
11 commits
master
...
737-tapi-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12482db255 | ||
|
|
c9a362cd8f | ||
|
|
d1b8da24bf | ||
|
|
445ad87282 | ||
|
|
8cacfea279 | ||
|
|
d569ea55d1 | ||
|
|
b22a3464be | ||
|
|
0901555a0b | ||
|
|
f03d2bf7ef | ||
|
|
f8da38fd26 | ||
|
|
0a2bc1741b |
17 changed files with 1096 additions and 12 deletions
|
|
@ -65,6 +65,13 @@ class User extends BaseUser
|
|||
*/
|
||||
protected $metadata;
|
||||
|
||||
// third party job order source linked to api_user
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="App\Entity\JobOrderSource", inversedBy="api_users")
|
||||
* @ORM\JoinColumn(name="source_id", referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
protected $source;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
|
@ -76,6 +83,8 @@ class User extends BaseUser
|
|||
// set date created
|
||||
$this->date_create = new DateTime();
|
||||
$this->metadata = [];
|
||||
|
||||
$this->source = null;
|
||||
}
|
||||
|
||||
public function getID()
|
||||
|
|
@ -182,5 +191,17 @@ class User extends BaseUser
|
|||
{
|
||||
return $this->rider;
|
||||
}
|
||||
|
||||
public function setSource($source = null)
|
||||
{
|
||||
$this->source = $source;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSource()
|
||||
{
|
||||
return $this->source;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -586,3 +586,17 @@ access_keys:
|
|||
label: Update
|
||||
- id: ownership_type.delete
|
||||
label: Delete
|
||||
|
||||
- id: job_order_source
|
||||
label: Job Order Source Access
|
||||
acls:
|
||||
- id: job_order_source.menu
|
||||
label: Menu
|
||||
- id: job_order_source.list
|
||||
label: List
|
||||
- id: job_order_source.add
|
||||
label: Add
|
||||
- id: job_order_source.update
|
||||
label: Update
|
||||
- id: job_order_source.delete
|
||||
label: Delete
|
||||
|
|
|
|||
|
|
@ -249,3 +249,7 @@ main_menu:
|
|||
acl: ownership_type.menu
|
||||
label: Ownership Types
|
||||
parent: database
|
||||
- id: job_order_source_list
|
||||
acl: job_order_source.menu
|
||||
label: Job Order Source
|
||||
parent: database
|
||||
|
|
|
|||
35
config/routes/job_order_source.yaml
Normal file
35
config/routes/job_order_source.yaml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
job_order_source_list:
|
||||
path: /job-order-sources
|
||||
controller: App\Controller\JobOrderSourceController::index
|
||||
methods: [GET]
|
||||
|
||||
job_order_source_rows:
|
||||
path: /job-order-sources/rowdata
|
||||
controller: App\Controller\JobOrderSourceController::datatableRows
|
||||
methods: [POST]
|
||||
|
||||
job_order_source_add_form:
|
||||
path: /job-order-sources/newform
|
||||
controller: App\Controller\JobOrderSourceController::addForm
|
||||
methods: [GET]
|
||||
|
||||
job_order_source_add_submit:
|
||||
path: /job-order-sources
|
||||
controller: App\Controller\JobOrderSourceController::addSubmit
|
||||
methods: [POST]
|
||||
|
||||
job_order_source_update_form:
|
||||
path: /job-order-sources/{id}
|
||||
controller: App\Controller\JobOrderSourceController::updateForm
|
||||
methods: [GET]
|
||||
|
||||
job_order_source_update_submit:
|
||||
path: /job-order-sources/{id}
|
||||
controller: App\Controller\JobOrderSourceController::updateSubmit
|
||||
methods: [POST]
|
||||
|
||||
job_order_source_delete:
|
||||
path: /job-order-sources/{id}
|
||||
controller: App\Controller\JobOrderSourceController::deleteSubmit
|
||||
methods: [DELETE]
|
||||
|
||||
|
|
@ -15,6 +15,7 @@ use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
|||
use Catalyst\MenuBundle\Annotation\Menu;
|
||||
|
||||
use App\Entity\Rider;
|
||||
use App\Entity\JobOrderSource;
|
||||
|
||||
class APIUserController extends Controller
|
||||
{
|
||||
|
|
@ -138,6 +139,7 @@ class APIUserController extends Controller
|
|||
$em = $this->getDoctrine()->getManager();
|
||||
$params['roles'] = $em->getRepository(APIRole::class)->findAll();
|
||||
$params['riders'] = $em->getRepository(Rider::class)->findBy([], ['first_name' => 'asc']);
|
||||
$params['sources'] = $em->getRepository(JobOrderSource::class)->findBy([], ['name' => 'asc']);
|
||||
|
||||
// response
|
||||
return $this->render('api-user/form.html.twig', $params);
|
||||
|
|
@ -166,6 +168,15 @@ class APIUserController extends Controller
|
|||
->setMetadata($meta);
|
||||
}
|
||||
|
||||
// source, if any
|
||||
$source_id = $req->request->get('source_id', '');
|
||||
if (!empty($source_id))
|
||||
{
|
||||
$source = $em->getRepository(JobOrderSource::class)->find($source_id);
|
||||
if ($source != null)
|
||||
$obj->setSource($source);
|
||||
}
|
||||
|
||||
// set and save values
|
||||
$obj->setName($req->request->get('name'))
|
||||
->setEnabled($req->request->get('enabled') ? true : false)
|
||||
|
|
@ -239,6 +250,7 @@ class APIUserController extends Controller
|
|||
// get roles
|
||||
$params['roles'] = $em->getRepository(APIRole::class)->findAll();
|
||||
$params['riders'] = $em->getRepository(Rider::class)->findBy([], ['first_name' => 'asc']);
|
||||
$params['sources'] = $em->getRepository(JobOrderSource::class)->findBy([], ['name' => 'asc']);
|
||||
|
||||
$params['obj'] = $obj;
|
||||
|
||||
|
|
@ -260,15 +272,34 @@ class APIUserController extends Controller
|
|||
|
||||
// set and save values
|
||||
// metadata
|
||||
$rider_id = $req->request->get('rider_id');
|
||||
$rider_id = $req->request->get('rider_id', '');
|
||||
$rider = null;
|
||||
if (!empty($rider_id))
|
||||
{
|
||||
$rider = $em->getRepository(Rider::class)->find($rider_id);
|
||||
// TODO: check for null rider
|
||||
if ($rider != null)
|
||||
{
|
||||
// set api user in rider
|
||||
$rider->setAPIUser($obj);
|
||||
}
|
||||
}
|
||||
|
||||
$meta = $obj->getMetadata();
|
||||
$meta['rider_id'] = $rider_id;
|
||||
|
||||
// set api user in rider
|
||||
$rider->setAPIUser($obj);
|
||||
// source, if any
|
||||
$source_id = $req->request->get('source_id', '');
|
||||
if (!empty($source_id))
|
||||
{
|
||||
$source = $em->getRepository(JobOrderSource::class)->find($source_id);
|
||||
if ($source != null)
|
||||
$obj->setSource($source);
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset source to null, if source was removed from api_user
|
||||
$obj->setSource();
|
||||
}
|
||||
|
||||
$obj->setName($req->request->get('name'))
|
||||
->setEnabled($req->request->get('enabled') ? true : false)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ use App\Service\JobOrderHandlerInterface;
|
|||
use App\Service\InvoiceGeneratorInterface;
|
||||
use App\Service\RisingTideGateway;
|
||||
use App\Service\RiderTracker;
|
||||
use App\Service\JobOrderCallbackRouter;
|
||||
|
||||
use App\Ramcar\ServiceType;
|
||||
use App\Ramcar\TradeInType;
|
||||
|
|
@ -388,7 +389,7 @@ class RiderAppController extends APIController
|
|||
|
||||
}
|
||||
|
||||
public function acceptJobOrder(Request $req, EntityManagerInterface $em)
|
||||
public function acceptJobOrder(Request $req, EntityManagerInterface $em, JobOrderCallbackRouter $jo_callback)
|
||||
{
|
||||
$required_params = ['jo_id'];
|
||||
|
||||
|
|
@ -406,6 +407,9 @@ class RiderAppController extends APIController
|
|||
if (!empty($msg))
|
||||
return new APIResponse(false, $msg);
|
||||
|
||||
// get previous status
|
||||
$old_status = $jo->getStatus();
|
||||
|
||||
// TODO: refactor this into a jo handler class, so we don't have to repeat for control center
|
||||
|
||||
// set jo status to in transit
|
||||
|
|
@ -432,12 +436,16 @@ class RiderAppController extends APIController
|
|||
|
||||
$em->flush();
|
||||
|
||||
// get current status and send JO callback
|
||||
$current_status = $jo->getStatus();
|
||||
$jo_callback->sendJOStatusCallback($jo, $old_status, $current_status);
|
||||
|
||||
$data = [];
|
||||
return new APIResponse(true, 'Job order accepted.', $data);
|
||||
|
||||
}
|
||||
|
||||
public function cancelJobOrder(Request $req, EntityManagerInterface $em, MQTTClient $mclient)
|
||||
public function cancelJobOrder(Request $req, EntityManagerInterface $em, MQTTClient $mclient, JobOrderCallbackRouter $jo_callback)
|
||||
{
|
||||
$required_params = ['jo_id'];
|
||||
|
||||
|
|
@ -456,6 +464,9 @@ class RiderAppController extends APIController
|
|||
// TODO: this is a workaround for requeue, because rider app gets stuck in accept / decline screen
|
||||
return new APIResponse(true, $msg);
|
||||
|
||||
// get previous status
|
||||
$old_status = $jo->getStatus();
|
||||
|
||||
// requeue it, instead of cancelling it
|
||||
$jo->requeue();
|
||||
|
||||
|
|
@ -483,6 +494,10 @@ class RiderAppController extends APIController
|
|||
];
|
||||
$mclient->sendEvent($jo, $payload);
|
||||
|
||||
// get current status and send JO callback
|
||||
$current_status = $jo->getStatus();
|
||||
$jo_callback->sendJOStatusCallback($jo, $old_status, $current_status);
|
||||
|
||||
$data = [];
|
||||
return new APIResponse(true, 'Job order requeued.', $data);
|
||||
}
|
||||
|
|
@ -648,7 +663,7 @@ class RiderAppController extends APIController
|
|||
|
||||
}
|
||||
|
||||
public function arrive(Request $req, EntityManagerInterface $em, MQTTClient $mclient)
|
||||
public function arrive(Request $req, EntityManagerInterface $em, MQTTClient $mclient, JobOrderCallbackRouter $jo_callback)
|
||||
{
|
||||
$required_params = ['jo_id'];
|
||||
|
||||
|
|
@ -666,6 +681,9 @@ class RiderAppController extends APIController
|
|||
if (!empty($msg))
|
||||
return new APIResponse(false, $msg);
|
||||
|
||||
// get previous status
|
||||
$old_status = $jo->getStatus();
|
||||
|
||||
// TODO: refactor this into a jo handler class, so we don't have to repeat for control center
|
||||
|
||||
// set jo status to in progress
|
||||
|
|
@ -698,6 +716,10 @@ class RiderAppController extends APIController
|
|||
];
|
||||
$mclient->sendEvent($jo, $payload);
|
||||
|
||||
// get current status and send JO callback
|
||||
$current_status = $jo->getStatus();
|
||||
$jo_callback->sendJOStatusCallback($jo, $old_status, $current_status);
|
||||
|
||||
$data = [];
|
||||
return new APIResponse(true, 'Rider arrived at customer location.', $data);
|
||||
}
|
||||
|
|
@ -749,7 +771,8 @@ class RiderAppController extends APIController
|
|||
}
|
||||
|
||||
public function payment(Request $req, EntityManagerInterface $em, JobOrderHandlerInterface $jo_handler,
|
||||
RisingTideGateway $rt, WarrantyHandler $wh, MQTTClient $mclient, TranslatorInterface $translator)
|
||||
RisingTideGateway $rt, WarrantyHandler $wh, MQTTClient $mclient, TranslatorInterface $translator,
|
||||
JobOrderCallbackRouter $jo_callback)
|
||||
{
|
||||
$required_params = ['jo_id'];
|
||||
|
||||
|
|
@ -767,6 +790,9 @@ class RiderAppController extends APIController
|
|||
if (!empty($msg))
|
||||
return new APIResponse(false, $msg);
|
||||
|
||||
// get previous status
|
||||
$old_status = $jo->getStatus();
|
||||
|
||||
// set invoice to paid
|
||||
$jo->getInvoice()->setStatus(InvoiceStatus::PAID);
|
||||
|
||||
|
|
@ -815,6 +841,10 @@ class RiderAppController extends APIController
|
|||
|
||||
$em->flush();
|
||||
|
||||
// get current status and send JO callback
|
||||
$current_status = $jo->getStatus();
|
||||
$jo_callback->sendJOStatusCallback($jo, $old_status, $current_status);
|
||||
|
||||
// create warranty
|
||||
if($jo_handler->checkIfNewBattery($jo))
|
||||
{
|
||||
|
|
|
|||
256
src/Controller/JobOrderSourceController.php
Normal file
256
src/Controller/JobOrderSourceController.php
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
<?php
|
||||
|
||||
namespace App\Controller;
|
||||
|
||||
use App\Entity\JobOrderSource;
|
||||
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
|
||||
|
||||
use Catalyst\MenuBundle\Annotation\Menu;
|
||||
|
||||
class JobOrderSourceController extends Controller
|
||||
{
|
||||
/**
|
||||
* @Menu(selected="job_order_source_list")
|
||||
* @IsGranted("job_order_source.list")
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
$this->denyAccessUnlessGranted('job_order_source.list', null, 'No access.');
|
||||
|
||||
return $this->render('job-order-source/list.html.twig');
|
||||
}
|
||||
|
||||
/**
|
||||
* @IsGranted("job_order_source.list")
|
||||
*/
|
||||
public function datatableRows(Request $req)
|
||||
{
|
||||
// get query builder
|
||||
$qb = $this->getDoctrine()
|
||||
->getRepository(JobOrderSource::class)
|
||||
->createQueryBuilder('q');
|
||||
|
||||
// get datatable params
|
||||
$datatable = $req->request->get('datatable');
|
||||
|
||||
// count total records
|
||||
$tquery = $qb->select('COUNT(q)');
|
||||
$this->setQueryFilters($datatable, $tquery);
|
||||
$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);
|
||||
|
||||
// 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.id', 'asc');
|
||||
}
|
||||
|
||||
// get rows for this page
|
||||
$obj_rows = $query->setFirstResult($offset)
|
||||
->setMaxResults($perpage)
|
||||
->getQuery()
|
||||
->getResult();
|
||||
|
||||
// process rows
|
||||
$rows = [];
|
||||
foreach ($obj_rows as $orow) {
|
||||
// add row data
|
||||
$row['id'] = $orow->getID();
|
||||
$row['name'] = $orow->getName();
|
||||
|
||||
// add row metadata
|
||||
$row['meta'] = [
|
||||
'update_url' => '',
|
||||
'delete_url' => ''
|
||||
];
|
||||
|
||||
// add crud urls
|
||||
if ($this->isGranted('job_order_source.update'))
|
||||
$row['meta']['update_url'] = $this->generateUrl('job_order_source_update_form', ['id' => $row['id']]);
|
||||
if ($this->isGranted('job_order_source.delete'))
|
||||
$row['meta']['delete_url'] = $this->generateUrl('job_order_source_delete', ['id' => $row['id']]);
|
||||
|
||||
$rows[] = $row;
|
||||
}
|
||||
|
||||
// response
|
||||
return $this->json([
|
||||
'meta' => $meta,
|
||||
'data' => $rows
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Menu(selected="job_order_source.list")
|
||||
* @IsGranted("job_order_source.add")
|
||||
*/
|
||||
public function addForm()
|
||||
{
|
||||
$jo_source = new JobOrderSource();
|
||||
$params = [
|
||||
'jo_source' => $jo_source,
|
||||
'mode' => 'create',
|
||||
];
|
||||
|
||||
// response
|
||||
return $this->render('job-order-source/form.html.twig', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @IsGranted("job_order_source.add")
|
||||
*/
|
||||
public function addSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator)
|
||||
{
|
||||
$jo_source = new JobOrderSource();
|
||||
|
||||
$this->setObject($jo_source, $req);
|
||||
|
||||
// validate
|
||||
$errors = $validator->validate($jo_source);
|
||||
|
||||
// initialize error list
|
||||
$error_array = [];
|
||||
|
||||
// add errors to list
|
||||
foreach ($errors as $error) {
|
||||
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||
}
|
||||
|
||||
// check if any errors were found
|
||||
if (!empty($error_array)) {
|
||||
// return validation failure response
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'errors' => $error_array
|
||||
], 422);
|
||||
}
|
||||
|
||||
// validated! save the entity
|
||||
$em->persist($jo_source);
|
||||
$em->flush();
|
||||
|
||||
// return successful response
|
||||
return $this->json([
|
||||
'success' => 'Changes have been saved!'
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @Menu(selected="job_order_source_list")
|
||||
* @ParamConverter("jo_source", class="App\Entity\JobOrderSource")
|
||||
* @IsGranted("job_order_source.update")
|
||||
*/
|
||||
public function updateForm($id, EntityManagerInterface $em, JobOrderSource $jo_source)
|
||||
{
|
||||
$params = [];
|
||||
$params['jo_source'] = $jo_source;
|
||||
$params['mode'] = 'update';
|
||||
|
||||
// response
|
||||
return $this->render('job-order-source/form.html.twig', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ParamConverter("jo_source", class="App\Entity\JobOrderSource")
|
||||
* @IsGranted("job_order_source.update")
|
||||
*/
|
||||
public function updateSubmit(Request $req, EntityManagerInterface $em, ValidatorInterface $validator, JobOrderSource $jo_source)
|
||||
{
|
||||
$this->setObject($jo_source, $req);
|
||||
|
||||
// validate
|
||||
$errors = $validator->validate($jo_source);
|
||||
|
||||
// initialize error list
|
||||
$error_array = [];
|
||||
|
||||
// add errors to list
|
||||
foreach ($errors as $error) {
|
||||
$error_array[$error->getPropertyPath()] = $error->getMessage();
|
||||
}
|
||||
|
||||
// check if any errors were found
|
||||
if (!empty($error_array)) {
|
||||
// return validation failure response
|
||||
return $this->json([
|
||||
'success' => false,
|
||||
'errors' => $error_array
|
||||
], 422);
|
||||
}
|
||||
|
||||
// validated! save the entity
|
||||
$em->flush();
|
||||
|
||||
// return successful response
|
||||
return $this->json([
|
||||
'success' => 'Changes have been saved!'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ParamConverter("jo_source", class="App\Entity\JobOrderSource")
|
||||
* @IsGranted("job_order_source.update")
|
||||
*/
|
||||
public function deleteSubmit(EntityManagerInterface $em, JobOrderSource $jo_source)
|
||||
{
|
||||
// delete this object
|
||||
$em->remove($jo_source);
|
||||
$em->flush();
|
||||
|
||||
// response
|
||||
$response = new Response();
|
||||
$response->setStatusCode(Response::HTTP_OK);
|
||||
$response->send();
|
||||
}
|
||||
|
||||
|
||||
protected function setObject(JobOrderSource $obj, Request $req)
|
||||
{
|
||||
// set and save values
|
||||
$obj->setCode($req->request->get('code'))
|
||||
->setName($req->request->get('name'))
|
||||
->setCallbackURL($req->request->get('callback_url'));
|
||||
}
|
||||
|
||||
protected function setQueryFilters($datatable, QueryBuilder $query)
|
||||
{
|
||||
if (isset($datatable['query']['data-rows-search']) && !empty($datatable['query']['data-rows-search'])) {
|
||||
$query->where('q.name LIKE :filter')
|
||||
->setParameter('filter', '%' . $datatable['query']['data-rows-search'] . '%');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -43,6 +43,7 @@ use App\Service\HubFilteringGeoChecker;
|
|||
use App\Service\RiderTracker;
|
||||
use App\Service\PromoLogger;
|
||||
use App\Service\MapTools;
|
||||
use App\Service\JobOrderCallbackRouter;
|
||||
|
||||
use App\Entity\JobOrder;
|
||||
use App\Entity\CustomerVehicle;
|
||||
|
|
@ -75,7 +76,8 @@ class JobOrderController extends APIController
|
|||
InventoryManager $im, MQTTClient $mclient,
|
||||
RiderAssignmentHandlerInterface $rah, PromoLogger $promo_logger,
|
||||
HubSelector $hub_select, HubDistributor $hub_dist, HubFilterLogger $hub_filter_logger,
|
||||
HubFilteringGeoChecker $hub_geofence, EntityManagerInterface $em)
|
||||
HubFilteringGeoChecker $hub_geofence, EntityManagerInterface $em,
|
||||
JobOrderCallbackRouter $jo_callback)
|
||||
{
|
||||
$this->denyAccessUnlessGranted('tapi_jo.request', null, 'No access.');
|
||||
|
||||
|
|
@ -112,6 +114,10 @@ class JobOrderController extends APIController
|
|||
// geofence
|
||||
$is_covered = $geo->isCovered($data['long'], $data['lat']);
|
||||
|
||||
// get the api_user
|
||||
$api_user = $this->getUser();
|
||||
$jo_source = $api_user->getSource();
|
||||
|
||||
if (!$is_covered)
|
||||
{
|
||||
// TODO: put geofence error message in config file somewhere
|
||||
|
|
@ -133,7 +139,8 @@ class JobOrderController extends APIController
|
|||
->setModeOfPayment($data['payment_mode'])
|
||||
->setAdvanceOrder($data['is_advance_order'])
|
||||
->setStatusAutoAssign(AutoAssignStatus::NOT_ASSIGNED)
|
||||
->setLandmark($data['landmark']);
|
||||
->setLandmark($data['landmark'])
|
||||
->setJOSource($jo_source);
|
||||
|
||||
$jo->setCustomer($data['customer']);
|
||||
$jo->setCustomerVehicle($data['customer_vehicle']);
|
||||
|
|
@ -375,6 +382,10 @@ class JobOrderController extends APIController
|
|||
|
||||
$em->flush();
|
||||
|
||||
// send callback
|
||||
//$old_status = null;
|
||||
//$jo_callback->sendJOStatusCallback($jo, $old_status, $jo->getStatus());
|
||||
|
||||
// make invoice json data
|
||||
$invoice_data = [
|
||||
'total_price' => number_format($invoice->getTotalPrice(), 2, '.', ''),
|
||||
|
|
|
|||
|
|
@ -422,6 +422,13 @@ class JobOrder
|
|||
*/
|
||||
protected $ownership_type;
|
||||
|
||||
// third party jo source linked to job order
|
||||
/**
|
||||
* @ORM\ManyToOne(targetEntity="App\Entity\JobOrderSource", inversedBy="job_orders")
|
||||
* @ORM\JoinColumn(name="job_order_source_id", referencedColumnName="id", nullable=true)
|
||||
*/
|
||||
protected $jo_source;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->date_create = new DateTime();
|
||||
|
|
@ -446,6 +453,8 @@ class JobOrder
|
|||
$this->phone_mobile = '';
|
||||
|
||||
$this->will_wait = WillingToWaitContent::WILLING_TO_WAIT;
|
||||
|
||||
$this->jo_source = null;
|
||||
}
|
||||
|
||||
public function getID()
|
||||
|
|
@ -1199,4 +1208,15 @@ class JobOrder
|
|||
{
|
||||
return $this->ownership_type;
|
||||
}
|
||||
|
||||
public function setJOSource($jo_source = null)
|
||||
{
|
||||
$this->jo_source = $jo_source;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getJOSource()
|
||||
{
|
||||
return $this->jo_source;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
114
src/Entity/JobOrderSource.php
Normal file
114
src/Entity/JobOrderSource.php
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
|
||||
use Doctrine\Common\Collections\ArrayCollection;
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* @ORM\Entity
|
||||
* @ORM\Table(name="job_order_source")
|
||||
*/
|
||||
class JobOrderSource
|
||||
{
|
||||
// unique id
|
||||
/**
|
||||
* @ORM\Id
|
||||
* @ORM\Column(type="integer")
|
||||
* @ORM\GeneratedValue(strategy="AUTO")
|
||||
*/
|
||||
protected $id;
|
||||
|
||||
// third party JO source
|
||||
/**
|
||||
* @ORM\Column(type="string", length=80, unique=true)
|
||||
* @Assert\NotBlank()
|
||||
*/
|
||||
protected $code;
|
||||
|
||||
/**
|
||||
* @ORM\Column(type="string", length=80)
|
||||
* @Assert\NotBlank()
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
// callback URL
|
||||
/**
|
||||
* @ORM\Column(type="string", length=150, nullable=true)
|
||||
*/
|
||||
protected $callback_url;
|
||||
|
||||
// one job order source can be associated to many api_users
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="Catalyst\APIBundle\Entity\User", mappedBy="source")
|
||||
*/
|
||||
protected $api_users;
|
||||
|
||||
// one job order source can be associated to many job orders
|
||||
/**
|
||||
* @ORM\OneToMany(targetEntity="JobOrder", mappedBy="jo_source")
|
||||
*/
|
||||
protected $job_orders;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->code = '';
|
||||
$this->name = '';
|
||||
$this->callback_url = '';
|
||||
|
||||
$this->api_users = new ArrayCollection();
|
||||
$this->job_orders = new ArrayCollection();
|
||||
}
|
||||
|
||||
public function getID()
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setCode($code)
|
||||
{
|
||||
$this->code = $code;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCode()
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function setCallbackURL($callback_url)
|
||||
{
|
||||
$this->callback_url = $callback_url;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCallbackURL()
|
||||
{
|
||||
return $this->callback_url;
|
||||
}
|
||||
|
||||
public function getApiUsers()
|
||||
{
|
||||
return $this->api_users;
|
||||
}
|
||||
|
||||
public function getJobOrders()
|
||||
{
|
||||
return $this->job_orders;
|
||||
}
|
||||
}
|
||||
|
||||
54
src/EntityListener/JobOrderStatusListener.php
Normal file
54
src/EntityListener/JobOrderStatusListener.php
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
namespace App\EntityListener;
|
||||
|
||||
use Doctrine\ORM\Event\LifecycleEventArgs;
|
||||
use Doctrine\ORM\Event\PreFlushEventArgs;
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
|
||||
use App\Entity\JobOrder;
|
||||
|
||||
use App\Service\JobOrderCallbackRouter;
|
||||
|
||||
class JobOrderStatusListener
|
||||
{
|
||||
protected $jo_callback;
|
||||
|
||||
public function __construct(JobOrderCallbackRouter $jo_callback)
|
||||
{
|
||||
$this->jo_callback = $jo_callback;
|
||||
}
|
||||
|
||||
public function preUpdate(JobOrder $jo, PreUpdateEventArgs $args)
|
||||
{
|
||||
// error_log('PRE UPDATE');
|
||||
|
||||
// check if status of third party JO has changed
|
||||
// check if JO is third party
|
||||
$source = $jo->getJOSource();
|
||||
if ($source != null)
|
||||
{
|
||||
if ($args->hasChangedField('status'))
|
||||
{
|
||||
// error_log('status has changed');
|
||||
// send callback
|
||||
$this->jo_callback->sendJOStatusCallback($jo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function postPersist(JobOrder $jo, LifecycleEventArgs $args)
|
||||
{
|
||||
// error_log('POST PERSIST');
|
||||
|
||||
// check if JO is third party
|
||||
$source = $jo->getJOSource();
|
||||
if ($source != null)
|
||||
{
|
||||
// need to send a callback for a new third party JO
|
||||
$this->jo_callback->sendJOStatusCallback($jo);
|
||||
}
|
||||
}
|
||||
}
|
||||
71
src/Service/JobOrderCallbackRouter.php
Normal file
71
src/Service/JobOrderCallbackRouter.php
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Entity\JobOrder;
|
||||
|
||||
use App\Ramcar\JOStatus;
|
||||
|
||||
class JobOrderCallbackRouter
|
||||
{
|
||||
public function sendJOStatusCallback(JobOrder $jo, $old_status, $new_status)
|
||||
{
|
||||
// check status change
|
||||
$is_status_change = $this->checkStatusChange($old_status, $new_status);
|
||||
|
||||
if ($is_status_change)
|
||||
{
|
||||
// get the job order source
|
||||
$source = $jo->getJOSource();
|
||||
if ($source != null)
|
||||
{
|
||||
// check if source has a callback url
|
||||
$callback_url = $source->getCallbackURL();
|
||||
if ($callback_url != null)
|
||||
{
|
||||
// form the body for the callback
|
||||
$jo_data = [
|
||||
'job_id' => $jo->getID(),
|
||||
];
|
||||
|
||||
// send status
|
||||
$this->sendJOInfo($jo_data, $callback_url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function checkStatusChange($old_status, $new_status)
|
||||
{
|
||||
// NOTE: what do we do if a third party JO has been cancelled and is then fulfilled?
|
||||
// This is a request resq asked for, to be able to fulfill cancelled JOs.
|
||||
|
||||
if ($old_status != $new_status)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function sendJOInfo($jo_data, $callback_url)
|
||||
{
|
||||
$params = http_build_query($jo_data);
|
||||
|
||||
//error_log('Sending output to ' . $callback_url . $params);
|
||||
|
||||
$curl = curl_init();
|
||||
|
||||
$options = [
|
||||
CURLOPT_URL => $callback_url . $params,
|
||||
CURLOPT_POST => false,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
];
|
||||
|
||||
curl_setopt_array($curl, $options);
|
||||
$res = curl_exec($curl);
|
||||
|
||||
curl_close($curl);
|
||||
|
||||
// check result
|
||||
error_log('Result ' . $res);
|
||||
}
|
||||
}
|
||||
|
|
@ -64,6 +64,7 @@ use App\Service\PromoLogger;
|
|||
use App\Service\HubSelector;
|
||||
use App\Service\HubDistributor;
|
||||
use App\Service\HubFilteringGeoChecker;
|
||||
use App\Service\JobOrderCallbackRouter;
|
||||
|
||||
use CrEOF\Spatial\PHP\Types\Geometry\Point;
|
||||
|
||||
|
|
@ -90,6 +91,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
protected $hub_geofence;
|
||||
protected $cust_distance_limit;
|
||||
protected $hub_filter_enable;
|
||||
protected $jo_callback;
|
||||
|
||||
protected $template_hash;
|
||||
|
||||
|
|
@ -98,7 +100,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
TranslatorInterface $translator, RiderAssignmentHandlerInterface $rah,
|
||||
string $country_code, WarrantyHandler $wh, RisingTideGateway $rt,
|
||||
PromoLogger $promo_logger, HubDistributor $hub_dist, HubFilteringGeoChecker $hub_geofence,
|
||||
string $cust_distance_limit, string $hub_filter_enabled)
|
||||
string $cust_distance_limit, string $hub_filter_enabled, JobOrderCallbackRouter $jo_callback)
|
||||
{
|
||||
$this->em = $em;
|
||||
$this->ic = $ic;
|
||||
|
|
@ -114,6 +116,7 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
$this->hub_geofence = $hub_geofence;
|
||||
$this->cust_distance_limit = $cust_distance_limit;
|
||||
$this->hub_filter_enabled = $hub_filter_enabled;
|
||||
$this->jo_callback = $jo_callback;
|
||||
|
||||
$this->loadTemplates();
|
||||
}
|
||||
|
|
@ -916,6 +919,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
$ownertype_id = $req->request->get('ownership_type', 0);
|
||||
$owner_type = $em->getRepository(OwnershipType::class)->find($ownertype_id);
|
||||
|
||||
// get previous status
|
||||
$old_status = $obj->getStatus();
|
||||
|
||||
if (empty($error_array))
|
||||
{
|
||||
// coordinates
|
||||
|
|
@ -984,6 +990,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
|
||||
// update redis hub jo count
|
||||
$this->hub_dist->incrementJoCountForHub($hub);
|
||||
|
||||
// get current status and send JO callback
|
||||
$current_status = $obj->getStatus();
|
||||
$this->jo_callback->sendJOStatusCallback($obj, $old_status, $current_status);
|
||||
}
|
||||
|
||||
return $error_array;
|
||||
|
|
@ -1068,6 +1078,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
// get current user
|
||||
$user = $this->security->getUser();
|
||||
|
||||
// get previous status
|
||||
$old_status = $obj->getStatus();
|
||||
|
||||
if (empty($error_array)) {
|
||||
// coordinates
|
||||
$point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat'));
|
||||
|
|
@ -1140,6 +1153,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
|
||||
// call rider assignment handler's assignJobOrder
|
||||
$this->rah->assignJobOrder($obj, $rider);
|
||||
|
||||
// get current status and send JO callback
|
||||
$current_status = $obj->getStatus();
|
||||
$this->jo_callback->sendJOStatusCallback($obj, $old_status, $current_status);
|
||||
}
|
||||
|
||||
return $error_array;
|
||||
|
|
@ -1205,6 +1222,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
$ownertype_id = $req->request->get('ownership_type', 0);
|
||||
$owner_type = $em->getRepository(OwnershipType::class)->find($ownertype_id);
|
||||
|
||||
// get previous status
|
||||
$old_status = $obj->getStatus();
|
||||
|
||||
if (empty($error_array)) {
|
||||
// coordinates
|
||||
$point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat'));
|
||||
|
|
@ -1269,6 +1289,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
// validated! save the entity
|
||||
$em->flush();
|
||||
|
||||
// get current status and send JO callback
|
||||
$current_status = $obj->getStatus();
|
||||
$this->jo_callback->sendJOStatusCallback($obj, $old_status, $current_status);
|
||||
|
||||
// get rider
|
||||
$rider = $obj->getRider();
|
||||
|
||||
|
|
@ -1347,6 +1371,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
if (empty($obj))
|
||||
throw new NotFoundHttpException('The item does not exist');
|
||||
|
||||
// get previous status
|
||||
$old_status = $obj->getStatus();
|
||||
|
||||
$cancel_reason = $req->request->get('cancel_reason');
|
||||
//error_log('cancel_reason ' . $cancel_reason);
|
||||
|
||||
|
|
@ -1382,6 +1409,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
];
|
||||
$mclient->sendEvent($obj, $payload);
|
||||
$mclient->sendRiderEvent($obj, $payload);
|
||||
|
||||
// get current status and send JO callback
|
||||
$current_status = $obj->getStatus();
|
||||
$this->jo_callback->sendJOStatusCallback($obj, $old_status, $current_status);
|
||||
}
|
||||
|
||||
// set hub for job order
|
||||
|
|
@ -1465,6 +1496,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
// get previously assigned rider, if any
|
||||
$old_rider = $obj->getRider();
|
||||
|
||||
// get previous status
|
||||
$old_status = $obj->getStatus();
|
||||
|
||||
if (empty($error_array))
|
||||
{
|
||||
// rider mqtt event
|
||||
|
|
@ -1566,6 +1600,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
$this->hub_dist->decrementJoCountForHub($old_hub);
|
||||
if ($hub != null)
|
||||
$this->hub_dist->incrementJoCountForHub($hub);
|
||||
|
||||
// get current status and send JO callback
|
||||
$current_status = $obj->getStatus();
|
||||
$this->jo_callback->sendJOStatusCallback($obj, $old_status, $current_status);
|
||||
}
|
||||
|
||||
return $error_array;
|
||||
|
|
@ -1744,6 +1782,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
$ownertype_id = $req->request->get('ownership_type', 0);
|
||||
$owner_type = $em->getRepository(OwnershipType::class)->find($ownertype_id);
|
||||
|
||||
// get previous status
|
||||
$old_status = $obj->getStatus();
|
||||
|
||||
if (empty($error_array)) {
|
||||
// rider mqtt event
|
||||
// NOTE: need to send this before saving because rider will be cleared
|
||||
|
|
@ -1845,6 +1886,10 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
];
|
||||
$mclient->sendEvent($obj, $payload);
|
||||
$mclient->sendRiderEvent($obj, $payload);
|
||||
|
||||
// get current status and send JO callback
|
||||
$current_status = $obj->getStatus();
|
||||
$this->jo_callback->sendJOStatusCallback($obj, $old_status, $current_status);
|
||||
}
|
||||
|
||||
return $error_array;
|
||||
|
|
@ -3986,6 +4031,9 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
if (empty($obj))
|
||||
throw new NotFoundHttpException('The item does not exist');
|
||||
|
||||
// get previous status
|
||||
$old_status = $obj->getStatus();
|
||||
|
||||
$obj->fulfill();
|
||||
|
||||
// the event
|
||||
|
|
@ -4004,6 +4052,16 @@ class ResqJobOrderHandler implements JobOrderHandlerInterface
|
|||
$event->setUser($user);
|
||||
$em->persist($event);
|
||||
$em->flush();
|
||||
|
||||
// get current status and send JO callback
|
||||
$current_status = $obj->getStatus();
|
||||
$this->jo_callback->sendJOStatusCallback($obj, $old_status, $current_status);
|
||||
|
||||
$data = [
|
||||
'error_array' => $error_array,
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function sendSMSToCustomer($phone_number)
|
||||
|
|
|
|||
|
|
@ -45,6 +45,20 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group m-form__group row no-border">
|
||||
<div class="col-lg-8">
|
||||
<label data-field="source">
|
||||
Source
|
||||
</label>
|
||||
<select class="form-control m-input" id="source_id" name="source_id">
|
||||
<option value=""></option>
|
||||
{% for source in sources %}
|
||||
<option value="{{ source.getID }}"{{ source.getID == obj.getSource.getID|default(0) ? ' selected' }}>{{ source.getName }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<div class="form-control-feedback hide" data-field="source_id"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group m-form__group row no-border">
|
||||
<div class="col-lg-8">
|
||||
<label data-field="brand">
|
||||
|
|
|
|||
151
templates/job-order-source/form.html.twig
Normal file
151
templates/job-order-source/form.html.twig
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
{% 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">Job Order Sources</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- END: Subheader -->
|
||||
<div class="m-content">
|
||||
<!--Begin::Section-->
|
||||
<div class="row">
|
||||
<div class="col-xl-6">
|
||||
<div class="m-portlet m-portlet--mobile">
|
||||
<div class="m-portlet__head">
|
||||
<div class="m-portlet__head-caption">
|
||||
<div class="m-portlet__head-title">
|
||||
<span class="m-portlet__head-icon">
|
||||
<i class="la la-industry"></i>
|
||||
</span>
|
||||
<h3 class="m-portlet__head-text">
|
||||
{% if mode == 'update' %}
|
||||
Edit Job Order Source
|
||||
<small>{{ jo_source.getName }}</small>
|
||||
{% else %}
|
||||
New Job Order Source
|
||||
{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="row-form" class="m-form m-form--fit m-form--label-align-right m-form--group-seperator-dashed" method="post" action="{{ mode == 'update' ? url('job_order_source_update_submit', {'id': jo_source.getId()}) : url('job_order_source_add_submit') }}">
|
||||
<div class="m-portlet__body">
|
||||
<div class="form-group m-form__group row no-border">
|
||||
<label class="col-lg-3 col-form-label" data-field="code">
|
||||
Code:
|
||||
</label>
|
||||
<div class="col-lg-9">
|
||||
<input type="text" name="code" class="form-control m-input" value="{{ jo_source.getCode() }}">
|
||||
<div class="form-control-feedback hide" data-field="code"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group m-form__group row no-border">
|
||||
<label class="col-lg-3 col-form-label" data-field="name">
|
||||
Name:
|
||||
</label>
|
||||
<div class="col-lg-9">
|
||||
<input type="text" name="name" class="form-control m-input" value="{{ jo_source.getName() }}">
|
||||
<div class="form-control-feedback hide" data-field="name"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group m-form__group row">
|
||||
<label class="col-lg-3 col-form-label" data-field="callback_url">
|
||||
Callback URL:
|
||||
</label>
|
||||
<div class="col-lg-9">
|
||||
<input type="text" name="callback_url" class="form-control m-input" value="{{ jo_source.getCallbackURL() }}">
|
||||
<div class="form-control-feedback hide" data-field="callback_url"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="m-portlet__foot m-portlet__foot--fit">
|
||||
<div class="m-form__actions m-form__actions--solid m-form__actions--right">
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<button type="submit" class="btn btn-success">Submit</button>
|
||||
<a href="{{ url('job_order_source_list') }}" class="btn btn-secondary">Back</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script>
|
||||
$(function() {
|
||||
$("#row-form").submit(function(e) {
|
||||
var form = $(this);
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
$.ajax({
|
||||
method: "POST",
|
||||
url: form.prop('action'),
|
||||
data: form.serialize()
|
||||
}).done(function(response) {
|
||||
// remove all error classes
|
||||
removeErrors();
|
||||
swal({
|
||||
title: 'Done!',
|
||||
text: 'Your changes have been saved!',
|
||||
type: 'success',
|
||||
onClose: function() {
|
||||
window.location.href = "{{ url('job_order_source_list') }}";
|
||||
}
|
||||
});
|
||||
}).fail(function(response) {
|
||||
if (response.status == 422) {
|
||||
var errors = response.responseJSON.errors;
|
||||
var firstfield = false;
|
||||
|
||||
// remove all error classes first
|
||||
removeErrors();
|
||||
|
||||
// display errors contextually
|
||||
$.each(errors, function(field, msg) {
|
||||
var formfield = $("[name='" + field + "']");
|
||||
var label = $("label[data-field='" + field + "']");
|
||||
var msgbox = $(".form-control-feedback[data-field='" + field + "']");
|
||||
|
||||
// add error classes to bad fields
|
||||
formfield.addClass('form-control-danger');
|
||||
label.addClass('has-danger');
|
||||
msgbox.html(msg).addClass('has-danger').removeClass('hide');
|
||||
|
||||
// check if this field comes first in DOM
|
||||
var domfield = formfield.get(0);
|
||||
|
||||
if (!firstfield || (firstfield && firstfield.compareDocumentPosition(domfield) === 2)) {
|
||||
firstfield = domfield;
|
||||
}
|
||||
});
|
||||
|
||||
// focus on first bad field
|
||||
firstfield.focus();
|
||||
|
||||
// scroll to above that field to make it visible
|
||||
$('html, body').animate({
|
||||
scrollTop: $(firstfield).offset().top - 200
|
||||
}, 100);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// remove all error classes
|
||||
function removeErrors() {
|
||||
$(".form-control-danger").removeClass('form-control-danger');
|
||||
$("[data-field]").removeClass('has-danger');
|
||||
$(".form-control-feedback[data-field]").addClass('hide');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
146
templates/job-order-source/list.html.twig
Normal file
146
templates/job-order-source/list.html.twig
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
{% 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">
|
||||
Job Order Sources
|
||||
</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-8 order-2 order-xl-1">
|
||||
<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 class="col-xl-4 order-1 order-xl-2 m--align-right">
|
||||
<a href="{{ url('job_order_source_add_form') }}" class="btn btn-focus m-btn m-btn--custom m-btn--icon m-btn--air m-btn--pill">
|
||||
<span>
|
||||
<i class="la la-industry"></i>
|
||||
<span>New Job Order Source</span>
|
||||
</span>
|
||||
</a>
|
||||
<div class="m-separator m-separator--dashed d-xl-none"></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("job_order_source_rows") }}',
|
||||
method: 'POST'
|
||||
}
|
||||
},
|
||||
saveState: {
|
||||
cookie: false,
|
||||
webstorage: false
|
||||
},
|
||||
pageSize: 10,
|
||||
serverPaging: true,
|
||||
serverFiltering: true,
|
||||
serverSorting: true
|
||||
},
|
||||
layout: {
|
||||
scroll: true
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'id',
|
||||
title: 'ID',
|
||||
width: 30
|
||||
},
|
||||
{
|
||||
field: 'name',
|
||||
title: 'Name'
|
||||
},
|
||||
{
|
||||
field: 'Actions',
|
||||
width: 110,
|
||||
title: 'Actions',
|
||||
sortable: false,
|
||||
overflow: 'visible',
|
||||
template: function (row, index, datatable) {
|
||||
var actions = '';
|
||||
|
||||
if (row.meta.update_url != '') {
|
||||
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" data-id="' + row.id + '" title="Edit"><i class="la la-edit"></i></a>';
|
||||
}
|
||||
|
||||
if (row.meta.delete_url != '') {
|
||||
actions += '<a href="' + row.meta.delete_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete" data-id="' + row.id + '" title="Delete"><i class="la la-trash"></i></a>';
|
||||
}
|
||||
|
||||
return actions;
|
||||
},
|
||||
}
|
||||
],
|
||||
search: {
|
||||
onEnter: false,
|
||||
input: $('#data-rows-search'),
|
||||
delay: 400
|
||||
}
|
||||
};
|
||||
|
||||
var table = $("#data-rows").mDatatable(options);
|
||||
|
||||
$(document).on('click', '.btn-delete', function(e) {
|
||||
var url = $(this).prop('href');
|
||||
var id = $(this).data('id');
|
||||
var btn = $(this);
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
swal({
|
||||
title: 'Confirmation',
|
||||
html: 'Are you sure you want to delete <strong>' + id + '</strong>?',
|
||||
type: 'warning',
|
||||
showCancelButton: true
|
||||
}).then((result) => {
|
||||
if (result.value) {
|
||||
$.ajax({
|
||||
method: "DELETE",
|
||||
url: url
|
||||
}).done(function(response) {
|
||||
table.row(btn.parents('tr')).remove();
|
||||
table.reload();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
54
utils/job_order_sources/insert_job_order_source.sql
Normal file
54
utils/job_order_sources/insert_job_order_source.sql
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
-- MySQL dump 10.19 Distrib 10.3.36-MariaDB, for Linux (x86_64)
|
||||
--
|
||||
-- Host: localhost Database: resq
|
||||
-- ------------------------------------------------------
|
||||
-- Server version 10.3.36-MariaDB
|
||||
|
||||
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
|
||||
/*!40101 SET NAMES utf8mb4 */;
|
||||
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
|
||||
/*!40103 SET TIME_ZONE='+00:00' */;
|
||||
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
|
||||
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
|
||||
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
|
||||
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
|
||||
|
||||
--
|
||||
-- Table structure for table `job_order_source`
|
||||
--
|
||||
|
||||
DROP TABLE IF EXISTS `job_order_source`;
|
||||
/*!40101 SET @saved_cs_client = @@character_set_client */;
|
||||
/*!40101 SET character_set_client = utf8 */;
|
||||
CREATE TABLE `job_order_source` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`code` varchar(80) COLLATE utf8_unicode_ci NOT NULL,
|
||||
`callback_url` varchar(150) COLLATE utf8_unicode_ci DEFAULT NULL,
|
||||
`name` varchar(80) COLLATE utf8_unicode_ci NOT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `UNIQ_9366FA8977153098` (`code`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
|
||||
/*!40101 SET character_set_client = @saved_cs_client */;
|
||||
|
||||
--
|
||||
-- Dumping data for table `job_order_source`
|
||||
--
|
||||
|
||||
LOCK TABLES `job_order_source` WRITE;
|
||||
/*!40000 ALTER TABLE `job_order_source` DISABLE KEYS */;
|
||||
INSERT INTO `job_order_source` VALUES (1,'drivehub','https://ny61i0s3rj.execute-api.ap-southeast-1.amazonaws.com/dev/callback?','DriveHub');
|
||||
/*!40000 ALTER TABLE `job_order_source` ENABLE KEYS */;
|
||||
UNLOCK TABLES;
|
||||
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
|
||||
|
||||
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
|
||||
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
|
||||
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
|
||||
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
|
||||
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
|
||||
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
|
||||
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
|
||||
|
||||
-- Dump completed on 2023-02-21 3:08:45
|
||||
Loading…
Reference in a new issue