Resolve "Edit jo feature" #889

Merged
jankstudio merged 1 commit from 93-edit-jo-feature into master 2018-04-18 04:09:34 +00:00
7 changed files with 234 additions and 17 deletions

View file

@ -201,6 +201,8 @@ access_keys:
label: View All
- id: jo_pdf.list
label: PDF
- id: jo_open.edit
label: Edit
- id: joborder.cancel
label: Cancel

View file

@ -160,3 +160,13 @@ jo_pdf_form:
path: /job-order/pdf/{id}
controller: App\Controller\JobOrderController::pdfForm
methods: [GET]
jo_open_edit_form:
path: /job-order/{id}/open-edit
controller: App\Controller\JobOrderController::openEditForm
methods: [GET]
jo_open_edit_submit:
path: /job-order/{id}/open-edit
controller: App\Controller\JobOrderController::openEditSubmit
methods: [POST]

View file

@ -143,6 +143,44 @@ class JobOrderController extends BaseController
$params['sources'] = TransactionOrigin::getCollection();
}
protected function initFormTags(&$params)
{
// default to editing, as we have more forms editing than creating
$params['ftags'] = [
'title' => 'Job Order Form',
'vehicle_dropdown' => false,
'invoice_edit' => false,
'set_map_coordinate' => true,
'preset_vehicle' => false,
'ticket_table' => true,
];
}
protected function fillFormTags(&$params)
{
$this->initFormTags($params);
switch ($params['mode'])
{
case 'create':
$params['ftags']['vehicle_dropdown'] = true;
$params['ftags']['set_map_coordinate'] = false;
$params['ftags']['invoice_edit'] = true;
$params['ftags']['ticket_table'] = false;
break;
case 'create_vehicle':
$params['ftags']['set_map_coordinate'] = false;
$params['ftags']['invoice_edit'] = true;
$params['ftags']['preset_vehicle'] = true;
$params['ftags']['ticket_table'] = false;
break;
case 'open_edit':
$params['ftags']['invoice_edit'] = true;
$params['ftags']['preset_vehicle'] = true;
break;
}
}
public function incomingForm()
{
$this->denyAccessUnlessGranted('jo_in.list', null, 'No access.');
@ -156,11 +194,162 @@ class JobOrderController extends BaseController
$em = $this->getDoctrine()->getManager();
$this->fillDropdownParameters($params);
$this->fillFormTags($params);
// response
return $this->render('job-order/form.html.twig', $params);
}
public function openEditForm($id)
{
$this->denyAccessUnlessGranted('jo_open.edit', null, 'No access.');
$em = $this->getDoctrine()->getManager();
$jo = $em->getRepository(JobOrder::class)->find($id);
$params = $this->initParameters('jo_in');
$params['obj'] = $jo;
$params['mode'] = 'open_edit';
$params['submit_url'] = $this->generateUrl('jo_open_edit_submit', ['id' => $id]);
$params['return_url'] = $this->generateUrl('jo_open');
$params['cvid'] = $jo->getCustomerVehicle()->getID();
$params['vid'] = $jo->getCustomerVehicle()->getVehicle()->getID();
$em = $this->getDoctrine()->getManager();
$this->fillDropdownParameters($params);
$this->fillFormTags($params);
// response
return $this->render('job-order/form.html.twig', $params);
}
public function openEditSubmit(Request $req, ValidatorInterface $validator, InvoiceCreator $ic, $id)
{
$this->denyAccessUnlessGranted('jo_open.edit', null, 'No access.');
// get object data
$em = $this->getDoctrine()->getManager();
$obj = $em->getRepository(JobOrder::class)->find($id);
$user = $this->getUser();
// initialize error list
$error_array = [];
// make sure this object exists
if (empty($obj))
throw $this->createNotFoundException('The item does not exist');
// check if lat and lng are provided
if (empty($req->request->get('coord_lng')) || empty($req->request->get('coord_lat'))) {
$error_array['coordinates'] = 'No map coordinates provided. Please click on a location on the map.';
}
if (empty($error_array)) {
// coordinates
$point = new Point($req->request->get('coord_lng'), $req->request->get('coord_lat'));
$stype = $req->request->get('service_type');
// set and save values
$obj->setDateSchedule(DateTime::createFromFormat("d M Y h:i A", $req->request->get('date_schedule_date') . " " . $req->request->get('date_schedule_time')))
->setCoordinates($point)
->setAdvanceOrder($req->request->get('flag_advance') ?? false)
->setServiceType($stype)
->setWarrantyClass($req->request->get('warranty_class'))
->setSource($req->request->get('source'))
->setStatus(JOStatus::RIDER_ASSIGN)
->setDeliveryInstructions($req->request->get('delivery_instructions'))
->setTier1Notes($req->request->get('tier1_notes'))
->setTier2Notes($req->request->get('tier2_notes'))
->setDeliveryAddress($req->request->get('delivery_address'))
->setORName($req->request->get('or_name'))
->setPromoDetail($req->request->get('promo_detail'))
->setModeOfPayment($req->request->get('mode_of_payment'))
->setLandmark($req->request->get('landmark'));
// did they change invoice?
$invoice_items = $req->request->get('invoice_items');
if (!empty($invoice_items))
{
// instantiate invoice criteria
$criteria = new InvoiceCriteria();
$criteria->setServiceType($stype);
$ierror = $this->invoicePromo($em, $criteria, $req->request->get('invoice_promo'));
if (!$ierror)
$ierror = $this->invoiceBatteries($em, $criteria, $invoice_items);
if ($ierror)
{
$error_array['invoice'] = $ierror;
}
else
{
// generate the invoice
$iobj = $ic->processCriteria($criteria);
$iobj->setStatus(InvoiceStatus::DRAFT)
->setCreatedBy($this->getUser());
// validate
$ierrors = $validator->validate($iobj);
// add errors to list
foreach ($ierrors as $error) {
$error_array[$error->getPropertyPath()] = $error->getMessage();
}
// remove previous invoice
$old_invoice = $obj->getInvoice();
$em->remove($old_invoice);
$em->flush();
// add invoice to JO
$obj->setInvoice($iobj);
// persist invoice
$em->persist($iobj);
}
}
// validate
$errors = $validator->validate($obj);
// 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);
}
// the event
$event = new JOEvent();
$event->setDateHappen(new DateTime())
->setTypeID(JOEventType::OPEN_EDIT)
->setUser($this->getUser())
->setJobOrder($obj);
$em->persist($event);
// validated! save the entity
$em->flush();
// return successful response
return $this->json([
'success' => 'Changes have been saved!'
]);
}
public function incomingVehicleForm($cvid)
{
$this->denyAccessUnlessGranted('jo_in.list', null, 'No access.');
@ -190,6 +379,7 @@ class JobOrderController extends BaseController
$params['obj'] = $jo;
$this->fillDropdownParameters($params);
$this->fillFormTags($params);
// response
return $this->render('job-order/form.html.twig', $params);
@ -581,6 +771,7 @@ class JobOrderController extends BaseController
{
$row['meta']['reassign_hub_url'] = $this->generateUrl('jo_open_hub_form', ['id' => $row['id']]);
$row['meta']['reassign_rider_url'] = $this->generateUrl('jo_open_rider_form', ['id' => $row['id']]);
$row['meta']['edit_url'] = $this->generateUrl('jo_open_edit_form', ['id' => $row['id']]);
}
else
{
@ -659,6 +850,7 @@ class JobOrderController extends BaseController
$params['status_cancelled'] = JOStatus::CANCELLED;
$this->fillDropdownParameters($params);
$this->fillFormTags($params);
// get closest hubs
$hubs = $map_tools->getClosestHubs($obj->getCoordinates(), 20, date("H:i:s"));
@ -859,6 +1051,7 @@ class JobOrderController extends BaseController
}
$this->fillDropdownParameters($params);
$this->fillFormTags($params);
$params['obj'] = $obj;
$params['status_cancelled'] = JOStatus::CANCELLED;
@ -997,6 +1190,7 @@ class JobOrderController extends BaseController
}
$this->fillDropdownParameters($params);
$this->fillFormTags($params);
$params['obj'] = $obj;
$params['status_cancelled'] = JOStatus::CANCELLED;
@ -1189,6 +1383,7 @@ class JobOrderController extends BaseController
}
$this->fillDropdownParameters($params);
$this->fillFormTags($params);
// get closest hubs
$hubs = $map_tools->getClosestHubs($obj->getCoordinates(), 10, date("H:i:s"));
@ -1349,6 +1544,7 @@ class JobOrderController extends BaseController
}
$this->fillDropdownParameters($params);
$this->fillFormTags($params);
$params['obj'] = $obj;
$params['status_cancelled'] = JOStatus::CANCELLED;
@ -1464,6 +1660,7 @@ class JobOrderController extends BaseController
throw $this->createNotFoundException('The job order does not exist');
$this->fillDropdownParameters($params);
$this->fillFormTags($params);
$params['obj'] = $obj;
$params['status_cancelled'] = JOStatus::CANCELLED;
@ -1520,6 +1717,7 @@ class JobOrderController extends BaseController
throw $this->createNotFoundException('The job order does not exist');
$this->fillDropdownParameters($params);
$this->fillFormTags($params);
$params['obj'] = $obj;
$params['status_cancelled'] = JOStatus::CANCELLED;

View file

@ -55,7 +55,7 @@ class Invoice
// invoice items
/**
* @ORM\OneToMany(targetEntity="InvoiceItem", mappedBy="invoice", cascade={"persist"})
* @ORM\OneToMany(targetEntity="InvoiceItem", mappedBy="invoice", cascade={"persist", "remove"})
*/
protected $items;

View file

@ -9,6 +9,7 @@ class JOEventType extends NameValue
const RIDER_ASSIGN = 'rider_assign';
const CANCEL = 'cancel';
const FULFILL = 'fulfill';
const OPEN_EDIT = 'open_edit';
const COLLECTION = [
'create' => 'Created',
@ -16,5 +17,6 @@ class JOEventType extends NameValue
'rider_assign' => 'Assigned Rider',
'cancel' => 'Cancelled',
'fulfill' => 'Fulfilled',
'open_edit' => 'Open Edit',
];
}

View file

@ -47,7 +47,7 @@
<form id="row-form" class="m-form m-form--fit m-form--label-align-right" method="post" action="{{ submit_url }}">
<div class="m-portlet__body">
{% if mode == 'create' %}
{% if ftags.vehicle_dropdown %}
<div class="m-form__section m-form__section--first">
<div class="form-group m-form__group row">
<div class="col-lg-6">
@ -72,7 +72,10 @@
</div>
</div>
</div>
{% elseif obj.getReferenceJO %}
{% elseif cvid|default(false) %}
<input type="hidden" name="customer_vehicle" value="{{ cvid }}">
{% endif %}
{% if obj.getReferenceJO %}
<div class="m-form__section m-form__section--first">
<div class="form-group m-form__group row">
<div class="col-lg-6">
@ -82,9 +85,7 @@
</div>
</div>
</div>
{% elseif mode == 'create_vehicle' %}
<input type="hidden" name="customer_vehicle" value="{{ cvid }}">
{% endif %}
{% endif %}
<div class="m-form__section{{ mode != 'create' and not obj.getReferenceJO ? ' m-form__section--first' }}">
<div class="m-form__heading">
@ -203,7 +204,7 @@
</div>
<div class="col-lg-3">
<label data-field="warranty_expiration">Warranty Expiration Date</label>
<input type="text" name="warranty_expiration" id="warranty-expiration" class="form-control m-input" value="{{ obj.getCustomerVehicle ? obj.getCustomerVehicle.getWarrantyExpiration|date("d M Y") }}" data-vehicle-field="1" disabled>
<input type="text" name="warranty_expiration" id="warranty-expiration" class="form-control m-input" value="{{ obj.getCustomerVehicle.getCurrentBattery|default(false) ? obj.getCustomerVehicle.getWarrantyExpiration|date("d M Y") : '' }}" data-vehicle-field="1" disabled>
<div class="form-control-feedback hide" data-field="warranty_expiration"></div>
</div>
</div>
@ -382,7 +383,7 @@
</div>
</div>
<div class="m-form__seperator m-form__seperator--dashed"></div>
<div class="m-form__section{{ mode == 'create' or mode == 'create_vehicle' ? ' m-form__section--last' }}">
<div class="m-form__section{{ ftags.invoice_edit ? ' m-form__section--last' }}">
<div class="m-form__heading">
<h3 class="m-form__heading-title">
Invoice
@ -403,7 +404,7 @@
<div class="form-group m-form__group row">
<div class="col-lg-6">
<label>Discount Type</label>
{% if mode == 'create' or mode == 'create_vehicle' %}
{% if ftags.invoice_edit %}
<select class="form-control m-input" id="invoice-promo" name="invoice_promo">
<option value="">None</option>
{% for promo in promos %}
@ -471,7 +472,7 @@
</table>
</div>
</div>
{% if mode == 'create' or mode == 'create_vehicle' %}
{% if ftags.invoice_edit %}
<div class="form-group m-form__group row">
<div class="col-lg-2 hide">
<label for="invoice-bmfg">Manufacturer</label>
@ -748,7 +749,7 @@
</div>
{% endif %}
{% if mode != 'create' %}
{% if ftags.ticket_table %}
<div class="m-form__seperator m-form__seperator--dashed"></div>
<div class="m-form__section m-form__section--last">
@ -857,14 +858,14 @@ $(function() {
}
});
{% if mode != 'create' and mode != 'create_vehicle'%}
{% if ftags.set_map_coordinate %}
// check if we need to set map
var latlng = new google.maps.LatLng({{ obj.getCoordinates.getLatitude }}, {{ obj.getCoordinates.getLongitude }});
selectPoint(map, latlng);
// remove placeholder text
$("[data-vehicle-field='1']").prop('placeholder', '');
{% endif %}
{% endif %}
{% if mode in ['update-processing', 'update-reassign-hub'] %}
// display hub map
@ -1110,7 +1111,7 @@ $(function() {
// update battery list when changing manufacturer
$("#invoice-bmfg").change(function() {
{% if mode == 'create_vehicle' %}
{% if ftags.preset_vehicle %}
vdata = {
'vehicle': {
'id': {{ vid }}
@ -1157,7 +1158,7 @@ $(function() {
});
// populate battery dropdown for create from vehicle mode
{% if mode == 'create_vehicle' %}
{% if ftags.preset_vehicle %}
$("#invoice-bmfg").change();
{% endif %}
@ -1362,7 +1363,7 @@ $(function() {
});
{% endif %}
{% if mode != 'create' %}
{% if ftags.ticket_table %}
var ticketRows = [];
{% for ticket in obj.getTickets %}

View file

@ -109,7 +109,11 @@
overflow: 'visible',
template: function (row, index, datatable) {
var actions = '<a href="' + row.meta.reassign_hub_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-reassign-hub" title="Re-assign Hub"><i class="fa fa-home"></i></a>' +
(row.status != '{{ statuses["pending"] }}' ? '<a href="' + row.meta.reassign_rider_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-focus m-btn--icon m-btn--icon-only m-btn--pill btn-reassign-rider" title="Re-assign Rider"><i class="fa fa-truck"></i></a>' : '');
(row.status != '{{ statuses["pending"] }}' ? '<a href="' + row.meta.reassign_rider_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-focus m-btn--icon m-btn--icon-only m-btn--pill btn-reassign-rider" title="Re-assign Rider"><i class="fa fa-truck"></i></a>' : '');
{% if is_granted('jo_open.edit') %}
actions += '<a href="' + row.meta.edit_url + '" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-reassign-hub" title="Edit"><i class="fa fa-file"></i></a>';
{% endif %}
return actions;
},