1214 lines
46 KiB
Twig
1214 lines
46 KiB
Twig
{% 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">Customers</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__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 Customer
|
||
<small>{{ obj.getFirstName() ~ ' ' ~ obj.getLastName() }}</small>
|
||
{% else %}
|
||
New Customer
|
||
{% endif %}
|
||
</h3>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<form id="row-form" class="m-form m-form--fit m-form--label-align-right" method="post" action="{{ mode == 'update' ? url('customer_update_submit', {'id': obj.getId()}) : url('customer_create_submit', {'ref':app.request.query.get('ref')|default('')}) }}">
|
||
<div class="m-portlet__body">
|
||
<div class="m-form__section m-form__section--first">
|
||
<div class="m-form__heading">
|
||
<h3 class="m-form__heading-title">
|
||
Customer Info
|
||
</h3>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-4">
|
||
<label data-field="title">
|
||
Title
|
||
</label>
|
||
<input type="text" name="title" class="form-control m-input" value="{{ obj.getTitle() }}" data-name="title">
|
||
<div class="form-control-feedback hide" data-field="title"></div>
|
||
</div>
|
||
<div class="col-lg-4">
|
||
<label data-field="first_name">
|
||
First Name
|
||
</label>
|
||
<input type="text" name="first_name" class="form-control m-input" value="{{ obj.getFirstName() }}" data-name="first_name">
|
||
<div class="form-control-feedback hide" data-field="first_name"></div>
|
||
</div>
|
||
<div class="col-lg-4">
|
||
<label data-field="last_name">
|
||
Last Name
|
||
</label>
|
||
<input type="text" name="last_name" class="form-control m-input" value="{{ obj.getLastName() }}" data-name="last_name">
|
||
<div class="form-control-feedback hide" data-field="last_name"></div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-4">
|
||
<label data-field="customer_classification">
|
||
Customer Classification
|
||
</label>
|
||
<select name="customer_classification" class="form-control m-input">
|
||
{% for key, classification in classifications %}
|
||
<option value="{{ key }}"{{ obj.getCustomerClassification == key ? ' selected' }}>{{ classification }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<div class="form-control-feedback hide" data-field="customer_classification"></div>
|
||
</div>
|
||
<div class="col-lg-8">
|
||
<label data-field="email">
|
||
E-mail
|
||
</label>
|
||
<input type="text" name="email" class="form-control m-input" value="{{ obj.getEmail }}" data-name="email">
|
||
</div>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-12">
|
||
<label data-field="customer_notes">
|
||
Customer Notes
|
||
</label>
|
||
<textarea name="customer_notes" class="form-control m-input" data-name="customer_notes" rows="4">{{ obj.getCustomerNotes() }}</textarea>
|
||
<div class="form-control-feedback hide" data-field="customer_notes"></div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-4">
|
||
<span class="m-switch m-switch--icon block-switch">
|
||
<label>
|
||
<input type="checkbox" name="flag_csat" id="flag_csat" value="1"{{ obj.isCSAT() ? ' checked' }}>
|
||
<label class="switch-label">CSAT</label>
|
||
<span></span>
|
||
</label>
|
||
</span>
|
||
<div class="form-control-feedback hide" data-field="flag_active"></div>
|
||
</div>
|
||
<div class="col-lg-4">
|
||
<div class="col-lg-12 form-group-inner">
|
||
<label data-field="source">Marketing Promo</label>
|
||
<div class="m-checkbox-list">
|
||
<label class="m-checkbox">
|
||
<input type="checkbox" name="flag_promo_sms" value="1"{{ obj.isPromoSms ? ' checked' }} >
|
||
SMS
|
||
<span></span>
|
||
<div class="form-control-feedback hide" data-field="flag_promo_sms"></div>
|
||
</label>
|
||
<label class="m-checkbox">
|
||
<input type="checkbox" name="flag_promo_email" value="1"{{ obj.isPromoEmail ? ' checked' }} >
|
||
Email
|
||
<span></span>
|
||
<div class="form-control-feedback hide" data-field="flag_promo_email"></div>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-4">
|
||
<input type="checkbox" name="flag_dpa_consent" id="flag-dpa_consent" value="1"{{ obj.isDpaConsent ? ' checked' }} >
|
||
<label class="switch-label">With DPA Consent</label>
|
||
<div class="form-control-feedback hide" data-field="flag_dpa_consent"></div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-12">
|
||
<span class="m-switch m-switch--icon block-switch">
|
||
<label>
|
||
<input type="checkbox" name="flag_active" id="flag_active" value="1"{{ obj.isActive() ? ' checked' }}>
|
||
<label class="switch-label">Active</label>
|
||
<span></span>
|
||
</label>
|
||
</span>
|
||
<div class="form-control-feedback hide" data-field="flag_active"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="m-form__seperator m-form__seperator--dashed"></div>
|
||
|
||
<div class="m-form__section">
|
||
<div class="m-form__heading">
|
||
<h3 class="m-form__heading-title">
|
||
Contact Numbers
|
||
</h3>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-4">
|
||
<label data-field="phone_mobile">
|
||
Mobile Phone
|
||
</label>
|
||
<div class="input-group m-input-group">
|
||
<span class="input-group-addon">{% trans %}country_code_prefix{% endtrans %}</span>
|
||
<input type="text" name="phone_mobile" class="form-control m-input" value="{{ obj.getPhoneMobile|default('') }}" data-name="phone_mobile">
|
||
<div class="form-control-feedback hide" data-field="phone_mobile"></div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-4">
|
||
<label data-field="phone_landline">
|
||
Landline
|
||
</label>
|
||
<div class="input-group m-input-group">
|
||
<span class="input-group-addon">{% trans %}country_code_prefix{% endtrans %}</span>
|
||
<input type="text" name="phone_landline" class="form-control m-input" value="{{ obj.getPhoneLandline|default('') }}" data-name="phone_landline">
|
||
<div class="form-control-feedback hide" data-field="phone_landline"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-4">
|
||
<label data-field="phone_office">
|
||
Office Phone
|
||
</label>
|
||
<div class="input-group m-input-group">
|
||
<span class="input-group-addon">{% trans %}country_code_prefix{% endtrans %}</span>
|
||
<input type="text" name="phone_office" class="form-control m-input" value="{{ obj.getPhoneOffice|default('') }}" data-name="phone_office">
|
||
<div class="form-control-feedback hide" data-field="phone_office"></div>
|
||
</div>
|
||
</div>
|
||
<div class="col-lg-4">
|
||
<label data-field="phone_fax">
|
||
Fax
|
||
</label>
|
||
<div class="input-group m-input-group">
|
||
<span class="input-group-addon">{% trans %}country_code_prefix{% endtrans %}</span>
|
||
<input type="text" name="phone_fax" class="form-control m-input" value="{{ obj.getPhoneFax|default('') }}" data-name="phone_fax">
|
||
<div class="form-control-feedback hide" data-field="phone_fax"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{#
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-12">
|
||
<div id="data-mobile-numbers"></div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-4">
|
||
<input type="number" class="form-control m-input" placeholder="Contact number" step="1" min="0" id="mobile-number">
|
||
<div class="form-control-feedback hide" data-field="mobile-number"></div>
|
||
<!--<span class="m-form__help">Use the format <span class="text-info">63xxxxxxxxxx</span></span>-->
|
||
</div>
|
||
<div class="col-lg-4">
|
||
<button type="button" class="btn btn-primary" id="btn-add-mobile-number" maxlength="12">Add to List</button>
|
||
</div>
|
||
</div>
|
||
#}
|
||
</div>
|
||
|
||
<div class="m-form__seperator m-form__seperator--dashed"></div>
|
||
|
||
<div class="m-form__section{{ mode == 'create' ? ' m-form__section--last' }}">
|
||
<div class="m-form__heading">
|
||
<h3 class="m-form__heading-title">
|
||
Vehicles
|
||
</h3>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-12">
|
||
<div class="m_datatable" id="data-vehicles"></div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-12">
|
||
<button type="button" class="btn btn-primary" id="add-vehicle">Add Vehicle</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{% if mode == 'update' %}
|
||
<div class="m-form__seperator m-form__seperator--dashed"></div>
|
||
|
||
<div class="m-form__section m-form__section--last">
|
||
<div class="m-form__heading">
|
||
<h3 class="m-form__heading-title">
|
||
Tickets
|
||
</h3>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-12">
|
||
<div class="m_datatable" id="data-tickets"></div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-12">
|
||
<a href="{{ url('ticket_create', {'customer_id': obj.getID}) }}" class="btn btn-primary">Create Ticket</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="m-form__section">
|
||
<div class="m-form__seperator m-form__seperator--dashed"></div>
|
||
|
||
<div class="m-form__section m-form__section--last">
|
||
<div class="m-form__heading">
|
||
<h3 class="m-form__heading-title">
|
||
Job Orders
|
||
</h3>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-12">
|
||
<div class="m_datatable" id="data-job-orders"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endif %}
|
||
</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('customer_list') }}" class="btn btn-secondary">Back</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal fade" id="vehicle-form-modal" tabindex="-1" role="dialog" aria-labelledby="vehicle-form-title" aria-hidden="true">
|
||
<div class="modal-dialog modal-lg" role="document">
|
||
<div class="modal-content">
|
||
<form class="m-form" id="vehicle-form" data-mode="create">
|
||
<div class="modal-header">
|
||
<h5 class="modal-title" id="vehicle-form-title">
|
||
Add Vehicle
|
||
</h5>
|
||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||
<span aria-hidden="true">
|
||
×
|
||
</span>
|
||
</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<div class="m-form__section m-form__section--first">
|
||
<div class="m-form__heading">
|
||
<h3 class="m-form__heading-title">
|
||
Vehicle Info
|
||
</h3>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-3">
|
||
<label for="vehicle-name" data-field="name">Vehicle Name</label>
|
||
<input type="text" name="name" id="vehicle-name" class="form-control m-input" data-required="0">
|
||
<div class="form-control-feedback hide" data-field="name"></div>
|
||
<span class="m-form__help">Display name for this vehicle</span>
|
||
</div>
|
||
<div class="col-lg-3">
|
||
<label for="vmfg" data-field="vmfg">Manufacturer</label>
|
||
<select name="vmfg" class="form-control m-input" id="vmfg" data-required="0">
|
||
<option value="">Select a manufacturer</option>
|
||
{% for manufacturer in vmfgs %}
|
||
<option value="{{ manufacturer.getID() }}">{{ manufacturer.getName() }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<div class="form-control-feedback hide" data-field="vmfg"></div>
|
||
</div>
|
||
<div class="col-lg-3">
|
||
<label for="vehicle" data-field="vehicle">Vehicle</label>
|
||
<select name="vehicle" class="form-control m-input" id="vehicle" data-value="" data-required="1" disabled>
|
||
<option value="">Select a manufacturer first</option>
|
||
</select>
|
||
<div class="form-control-feedback hide" data-field="vehicle"></div>
|
||
</div>
|
||
<div class="col-lg-3">
|
||
<label for="vehicle-year" data-field="model_year">Year</label>
|
||
<select class="form-control m-input" id="vehicle-year" name="model_year" data-required="1">
|
||
<option value=""></option>
|
||
{% for year in years %}
|
||
<option value="{{ year }}">{{ year }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<div class="form-control-feedback hide" data-field="model_year"></div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-3">
|
||
<label for="vehicle-plate-number" data-field="plate_number">Plate Number</label>
|
||
<input type="text" name="plate_number" id="vehicle-plate-number" class="form-control m-input" data-required="1">
|
||
<div class="form-control-feedback hide" data-field="plate_number"></div>
|
||
</div>
|
||
<div class="col-lg-3">
|
||
<label for="vehicle-color" data-field="color">Color</label>
|
||
<input type="text" name="color" id="vehicle-color" class="form-control m-input" data-required="1">
|
||
<div class="form-control-feedback hide" data-field="color"></div>
|
||
</div>
|
||
<div class="col-lg-3">
|
||
<label for="vehicle-status" data-field="status_condition">Status</label>
|
||
<select name="status_condition" class="form-control m-input" id="vehicle-status" data-required="1">
|
||
<option value=""></option>
|
||
{% for key, status_condition in status_conditions %}
|
||
<option value="{{ key }}">{{ status_condition }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<div class="form-control-feedback hide" data-field="status_condition"></div>
|
||
</div>
|
||
<div class="col-lg-3">
|
||
<label for="vehicle-fuel-type" data-field="fuel_type">Fuel Type</label>
|
||
<select name="fuel_type" class="form-control m-input" id="vehicle-fuel-type" data-required="1">
|
||
<option value=""></option>
|
||
{% for key, fuel_type in fuel_types %}
|
||
<option value="{{ key }}">{{ fuel_type }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<div class="form-control-feedback hide" data-field="fuel_type"></div>
|
||
</div>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-12">
|
||
<span class="m-switch m-switch--icon block-switch">
|
||
<label>
|
||
<input type="checkbox" name="flag_active" id="flag-active" value="1" checked>
|
||
<label class="switch-label">This vehicle is currently active</label>
|
||
<span></span>
|
||
</label>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="m-form__seperator m-form__seperator--dashed"></div>
|
||
<div class="m-form__section m-form__section--last">
|
||
<div class="m-form__heading">
|
||
<h3 class="m-form__heading-title">
|
||
Battery Info
|
||
</h3>
|
||
</div>
|
||
<div class="form-group m-form__group row">
|
||
<div class="col-lg-12">
|
||
<span class="m-switch m-switch--icon block-switch">
|
||
<label>
|
||
<input type="checkbox" name="flag_motolite_battery" id="flag-motolite-battery" value="1">
|
||
<label class="switch-label">{% trans %}add_cust_vehicle_battery_info{% endtrans %}</label>
|
||
<span></span>
|
||
</label>
|
||
</span>
|
||
</div>
|
||
</div>
|
||
<div class="form-group m-form__group row curr_battery_row hide">
|
||
<div class="col-lg-3">
|
||
<label for="bmfg" data-field="bmfg">Manufacturer</label>
|
||
<select name="bmfg" class="form-control m-input" id="bmfg" data-required="0">
|
||
<option value="">Select a manufacturer</option>
|
||
{% for manufacturer in bmfgs %}
|
||
<option value="{{ manufacturer.getID }}">{{ manufacturer.getName() }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<div class="form-control-feedback hide" data-field="bmfg"></div>
|
||
</div>
|
||
<div class="col-lg-3">
|
||
<label for="battery" data-field="battery">Product</label>
|
||
<select name="battery" class="form-control m-input" id="battery" data-value="" data-required="0">
|
||
<option value="">Select a battery</option>
|
||
{% for batt in batteries %}
|
||
<option value="{{ batt.getID }}">{{ batt.getModel.getName }} {{ batt.getSize.getName }}</option>
|
||
{% endfor %}
|
||
</select>
|
||
<div class="form-control-feedback hide" data-field="battery"></div>
|
||
</div>
|
||
<div class="col-lg-3">
|
||
<label for="battery-warranty-code" data-field="warranty_code">Serial Number</label>
|
||
<input type="text" name="warranty_code" id="battery-warranty-code" class="form-control m-input" data-required="0">
|
||
<div class="form-control-feedback hide" data-field="warranty_code"></div>
|
||
</div>
|
||
<div class="col-lg-3">
|
||
<label for="battery-warranty-expiration" data-field="warranty_expiration">Warranty Expiration</label>
|
||
<div class="input-group date dp">
|
||
<input type="text" name="warranty_expiration" id="battery-warranty-expiration" class="form-control m-input" readonly placeholder="Select a date" data-required="0">
|
||
<span class="input-group-addon">
|
||
<i class="la la-calendar glyphicon-th"></i>
|
||
</span>
|
||
</div>
|
||
<div class="form-control-feedback hide" data-field="warranty_expiration"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="modal-footer">
|
||
<input type="hidden" name="id" id="cv-id" value="" data-required="0">
|
||
<input type="hidden" name="index" id="row-index" value="" data-required="0">
|
||
<button type="button" class="btn btn-secondary" data-dismiss="modal">
|
||
Close
|
||
</button>
|
||
<button type="submit" class="btn btn-primary">
|
||
Save changes
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
|
||
{% block scripts %}
|
||
<script>
|
||
$(function() {
|
||
$("#row-form").submit(function(e) {
|
||
var form = $(this);
|
||
var formdata = form.serializeArray();
|
||
|
||
e.preventDefault();
|
||
|
||
// add vehicle data
|
||
formdata.push({
|
||
name: 'vehicles',
|
||
value: JSON.stringify(vehicleRows)
|
||
});
|
||
|
||
$.ajax({
|
||
method: "POST",
|
||
url: form.prop('action'),
|
||
data: formdata
|
||
}).done(function(response) {
|
||
// remove all error classes
|
||
removeErrors();
|
||
swal({
|
||
title: 'Done!',
|
||
text: 'Your changes have been saved!',
|
||
type: 'success',
|
||
onClose: function() {
|
||
{% if app.request.query.get('ref') == 'jo' %}
|
||
window.location.href = "{{ url('jo_in') }}";
|
||
{% else %}
|
||
window.location.href = "{{ url('customer_update_blank') }}/" + response.id;
|
||
{% endif %}
|
||
}
|
||
});
|
||
}).fail(function(response) {
|
||
if (response.status == 422) {
|
||
var json = response.responseJSON;
|
||
var errors = json.errors;
|
||
var nerrors = json.nerrors;
|
||
var verrors = json.verrors;
|
||
var firstfield = false;
|
||
|
||
// remove all error classes first
|
||
removeErrors();
|
||
|
||
// display errors contextually
|
||
$.each(errors, function(field, msg) {
|
||
var formfield = $("[data-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;
|
||
}
|
||
|
||
// add error class to this tab
|
||
var tabId = $(formfield).closest('.tab-pane').prop('id');
|
||
$("#customer-tabs").find("a[href='#" + tabId + "']").addClass('has-danger');
|
||
});
|
||
|
||
// loop through mobile number errors
|
||
$.each(nerrors, function(rowindex, errorlist) {
|
||
var row = $("#data-mobile-numbers table").find("[name='index'][value='" + rowindex + "']").closest('tr');
|
||
|
||
$.each(errorlist, function(field, msg) {
|
||
var msgbox = row.find(".form-control-feedback[data-field='" + field + "']");
|
||
var col = msgbox.closest('span');
|
||
|
||
// add error classes to bad fields
|
||
col.addClass('has-danger');
|
||
msgbox.html(msg).addClass('has-danger').removeClass('hide');
|
||
|
||
// check if this field comes first in DOM
|
||
var domfield = col.get(0);
|
||
|
||
if (!firstfield || (firstfield && firstfield.compareDocumentPosition(domfield) === 2)) {
|
||
firstfield = domfield;
|
||
}
|
||
|
||
// add error class to this tab
|
||
var tabId = $(col).closest('.tab-pane').prop('id');
|
||
$("#customer-tabs").find("a[href='#" + tabId + "']").addClass('has-danger');
|
||
});
|
||
});
|
||
|
||
// loop through vehicle errors
|
||
$.each(verrors, function(rowindex, errorlist) {
|
||
var row = $("#data-vehicles table").find("[name='index'][value='" + rowindex + "']").closest('tr');
|
||
|
||
$.each(errorlist, function(field, msg) {
|
||
var msgbox = row.find(".form-control-feedback[data-field='" + field + "']");
|
||
var col = msgbox.closest('span');
|
||
|
||
// add error classes to bad fields
|
||
col.addClass('has-danger');
|
||
msgbox.html(msg).addClass('has-danger').removeClass('hide');
|
||
|
||
// check if this field comes first in DOM
|
||
var domfield = col.get(0);
|
||
|
||
if (!firstfield || (firstfield && firstfield.compareDocumentPosition(domfield) === 2)) {
|
||
firstfield = domfield;
|
||
}
|
||
|
||
// add error class to this tab
|
||
var tabId = $(col).closest('.tab-pane').prop('id');
|
||
$("#customer-tabs").find("a[href='#" + tabId + "']").addClass('has-danger');
|
||
});
|
||
});
|
||
|
||
// focus on tab containing first field
|
||
var firstTabId = $(firstfield).closest('.tab-pane').prop('id');
|
||
$("#customer-tabs").find("a[href='#" + firstTabId + "']").tab('show');
|
||
|
||
// 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');
|
||
$(".has-danger").removeClass('has-danger');
|
||
$(".form-control-feedback[data-field]").addClass('hide');
|
||
}
|
||
|
||
// datetimepicker
|
||
$(".dtp").datetimepicker({
|
||
format: "dd M yyyy - HH:ii P",
|
||
showMeridian: true,
|
||
todayHighlight: true,
|
||
autoclose: true,
|
||
pickerPosition: 'top-left',
|
||
bootcssVer: 3,
|
||
todayBtn: true,
|
||
clearBtn: true
|
||
});
|
||
|
||
// datepicker
|
||
$(".dp").datepicker({
|
||
format: "dd M yyyy",
|
||
todayHighlight: true,
|
||
autoclose: true,
|
||
pickerPosition: 'top-left',
|
||
bootcssVer: 3,
|
||
clearBtn: true
|
||
});
|
||
|
||
// input mask
|
||
$("#mobile-number").inputmask("mask", {
|
||
mask: "639999999999",
|
||
placeholder: ""
|
||
});
|
||
|
||
$("#vehicle-year").inputmask("mask", {
|
||
mask: "9999",
|
||
placeholder: ""
|
||
});
|
||
|
||
// initialize arrays
|
||
var numberIds = [];
|
||
var mfgVehicles = [];
|
||
var vehicleRows = [];
|
||
var ticketRows = [];
|
||
var joRows = [];
|
||
|
||
var vrow = {};
|
||
|
||
{% for key, cv in obj.getVehicles() %}
|
||
{% set vehicle = cv.getVehicle() %}
|
||
{% set battery = cv.getCurrentBattery() %}
|
||
|
||
vrow = {
|
||
id: "{{ cv.getID() }}",
|
||
name: "{{ cv.getName() }}",
|
||
index: moment().unix() + {{ key }},
|
||
battery: "{{ battery ? battery.getID() }}",
|
||
battery_label: "{{ battery ? battery.getModel().getName() ~ ' ' ~ battery.getSize().getName() ~ ' (' ~ battery.getProductCode() ~ ')' }}",
|
||
bmfg: "{{ battery ? battery.getManufacturer().getID() }}",
|
||
color: "{{ cv.getColor() }}",
|
||
flag_active: {{ cv.isActive() ? 'true' : 'false' }},
|
||
flag_motolite_battery: {{ cv.hasMotoliteBattery() ? 'true' : 'false' }},
|
||
fuel_type: "{{ cv.getFuelType() }}",
|
||
model_year: "{{ cv.getModelYear() }}",
|
||
plate_number: "{{ cv.getPlateNumber() }}",
|
||
status_condition: "{{ cv.getStatusCondition() }}",
|
||
vehicle: "{{ vehicle ? vehicle.getID() }}",
|
||
vehicle_label: "{{ vehicle ? vehicle.getManufacturer().getName() ~ ' ' ~ vehicle.getMake() ~ ' (' ~ vehicle.getModelYearFrom() ~ ' ' ~ vehicle.getModelYearTo() ~ ')' }}",
|
||
vmfg: "{{ vehicle ? vehicle.getManufacturer().getID() }}",
|
||
warranty_code: "{{ cv.getWarrantyCode() }}",
|
||
warranty_expiration: "{{ cv.getWarrantyExpiration() ? cv.getWarrantyExpiration()|date('d M Y') }}"
|
||
};
|
||
|
||
vehicleRows.push(vrow);
|
||
{% endfor %}
|
||
|
||
{% for ticket in obj.getTickets %}
|
||
trow = {
|
||
id: "{{ ticket.getID }}",
|
||
date_create: "{{ ticket.getDateCreate|date('d M Y - h:i A') }}",
|
||
ticket_type: "{{ ticket.getTicketTypeText }}",
|
||
status: "{{ ticket.getStatusText }}",
|
||
edit_url: "{{ url('ticket_update', {'id': ticket.getID}) }}"
|
||
};
|
||
|
||
ticketRows.push(trow);
|
||
{% endfor %}
|
||
|
||
{% for jo in obj.getJobOrders %}
|
||
jorow = {
|
||
id: "{{ jo.getID }}",
|
||
date_schedule: "{{ jo.getDateSchedule|date('d M Y - h:i A') }}",
|
||
service_type: "{{ jo.getServiceTypeName }}",
|
||
plate_num: "{{ jo.getCustomerVehicle.getPlateNumber|default('') }}",
|
||
status: "{{ jo.getStatusText }}",
|
||
};
|
||
|
||
joRows.push(jorow);
|
||
{% endfor %}
|
||
|
||
// remove vehicle from table
|
||
$(document).on('click', '.btn-delete-vehicle', function(e) {
|
||
var btn = $(this);
|
||
var id = $(this).data('index');
|
||
var table = $(this).closest('table');
|
||
|
||
$.each(vehicleRows, function(index, row) {
|
||
if (row.index == id) {
|
||
vehicleRows.splice(index, 1);
|
||
return false;
|
||
}
|
||
});
|
||
|
||
// reload table
|
||
vehicleTable.row(btn.parents('tr')).remove();
|
||
vehicleTable.originalDataSet = vehicleRows;
|
||
vehicleTable.reload();
|
||
});
|
||
|
||
// display create vehicle form
|
||
$("#add-vehicle").click(function() {
|
||
$("#vehicle-form").data('mode', 'create');
|
||
$("#vehicle-form-title").html("Add Vehicle");
|
||
$("#vehicle-form-modal").modal('show');
|
||
});
|
||
|
||
// find vehicle row by index
|
||
function findVehicleRow(index) {
|
||
for (var i = 0, len = vehicleRows.length; i < len; i++) {
|
||
if (vehicleRows[i].index === index) {
|
||
return {
|
||
row: vehicleRows[i],
|
||
index: i
|
||
};
|
||
}
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
// forward to job edit form
|
||
$(document).on("click", ".btn-jo-vehicle", function() {
|
||
var form = $("#vehicle-form");
|
||
var tr = $(this).closest('tr');
|
||
var index = parseInt(tr.find("[name='index']").val());
|
||
var rowData = findVehicleRow(index);
|
||
|
||
if (!rowData) {
|
||
return;
|
||
}
|
||
|
||
row = rowData.row;
|
||
|
||
// check if we can forward to job order
|
||
if (row.id == '') {
|
||
alert('Customer has to be saved first.');
|
||
} else {
|
||
window.location.href = "{{ url("jo_in_vehicle_blank") }}/" + row.id;
|
||
}
|
||
});
|
||
|
||
// display edit vehicle form
|
||
$(document).on("click", ".btn-edit-vehicle", function() {
|
||
var form = $("#vehicle-form");
|
||
var tr = $(this).closest('tr');
|
||
var index = parseInt(tr.find("[name='index']").val());
|
||
var rowData = findVehicleRow(index);
|
||
|
||
if (!rowData) {
|
||
return;
|
||
}
|
||
|
||
row = rowData.row;
|
||
|
||
// set form mode
|
||
form.data('mode', 'update');
|
||
$("#vehicle-form-title").html("Edit Vehicle");
|
||
|
||
// set index
|
||
$("#row-index").val(row.index);
|
||
|
||
// set text/select field values manually
|
||
form.find("input[type='text'], select").each(function() {
|
||
var rowval = row[$(this).prop('name')];
|
||
|
||
if (typeof rowval !== 'undefined') {
|
||
$(this).val(rowval);
|
||
}
|
||
});
|
||
|
||
// set entity ids
|
||
$("#vehicle").data('id', row.vehicle);
|
||
$("#battery").data('id', row.battery);
|
||
$("#battery").val(row.battery);
|
||
$("#cv-id").val(row.id);
|
||
|
||
// set select box values
|
||
$("#vmfg").val(row.vmfg).change();
|
||
|
||
if (row.battery) {
|
||
$("#flag-motolite-battery").prop('checked', true).change();
|
||
}
|
||
|
||
$("#flag-active").prop('checked', row.flag_active);
|
||
|
||
// show modal
|
||
$("#vehicle-form-modal").modal('show');
|
||
});
|
||
|
||
// update vehicle list when changing manufacturer
|
||
$("#vmfg").change(function() {
|
||
var id = $(this).val();
|
||
var field = $("#vehicle");
|
||
|
||
// no id specified
|
||
if (!id) {
|
||
field.html('<option value="">Select a manufacturer first</option>').prop('disabled', true);
|
||
return true;
|
||
}
|
||
|
||
// get vehicles for this manufacturer
|
||
$.ajax({
|
||
method: "POST",
|
||
url: "{{ url('vmfg_vehicles') }}",
|
||
data: {id: id}
|
||
}).done(function(response) {
|
||
if (response.data.length > 0) {
|
||
var html = '';
|
||
|
||
$.each(response.data, function(index, vehicle) {
|
||
html += '<option value="' + vehicle.id + '" data-index="' + index + '">' + vehicle.make + ' (' + vehicle.model_year_from + '-' + vehicle.model_year_to + ')</option>';
|
||
});
|
||
|
||
field.html(html).prop('disabled', false);
|
||
field.val(field.data('id'));
|
||
} else {
|
||
field.html('<option value="">No vehicles found</option>').prop('disabled', true);
|
||
}
|
||
})
|
||
});
|
||
|
||
// update battery list when changing manufacturer
|
||
$("#bmfg").change(function() {
|
||
var id = $(this).val();
|
||
var field = $("#battery");
|
||
|
||
// no id specified
|
||
if (!id) {
|
||
field.html('<option value="">Select a manufacturer first</option>').prop('disabled', true);
|
||
return true;
|
||
}
|
||
|
||
// get vehicles for this manufacturer
|
||
$.ajax({
|
||
method: "POST",
|
||
url: "{{ url('bmfg_batteries') }}",
|
||
data: {id: id}
|
||
}).done(function(response) {
|
||
if (response.data.length > 0) {
|
||
var html = '';
|
||
|
||
$.each(response.data, function(index, battery) {
|
||
html += '<option value="' + battery.id + '" data-index="' + index + '">' + battery.model_name + ' ' + battery.size_name + ' (' + battery.prod_code + ')</option>';
|
||
});
|
||
|
||
field.html(html).prop('disabled', false);
|
||
} else {
|
||
field.html('<option value="">No batteries found</option>').prop('disabled', true);
|
||
}
|
||
})
|
||
});
|
||
|
||
// toggle motolite battery area
|
||
$("#flag-motolite-battery").change(function() {
|
||
var currBatteryRows = $(".curr_battery_row");
|
||
|
||
if ($(this).prop('checked') == true) {
|
||
currBatteryRows.removeClass('hide').find("[name='battery']").data('required', 1);
|
||
} else {
|
||
currBatteryRows.addClass('hide').find("[name='battery']").data('required', 0);
|
||
}
|
||
});
|
||
|
||
// save vehicle form
|
||
$("#vehicle-form").submit(function(e) {
|
||
var form = $(this);
|
||
var mode = form.data('mode');
|
||
|
||
// get all fields, including disabled ones
|
||
var disabled = form.find(":input:disabled").prop('disabled', false);
|
||
var fields = form.serializeArray().map(function(x){this[x.name] = x.value; return this;}.bind({}))[0];
|
||
disabled.prop('disabled', true);
|
||
|
||
e.preventDefault();
|
||
|
||
var errors = 0;
|
||
var firstfield = false;
|
||
|
||
// remove all error classes first
|
||
removeVehicleErrors();
|
||
|
||
// check for required fields
|
||
$.each(fields, function(field, value) {
|
||
var formfield = form.find("[name='" + field + "']");
|
||
var label = form.find("label[data-field='" + field + "']");
|
||
var msgbox = form.find(".form-control-feedback[data-field='" + field + "']");
|
||
var required = formfield.data('required');
|
||
|
||
if (required === 1 && !value) {
|
||
errors++;
|
||
|
||
// add error classes to bad fields
|
||
formfield.addClass('form-control-danger');
|
||
label.addClass('has-danger');
|
||
msgbox.html("This value should not be blank.").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;
|
||
}
|
||
}
|
||
});
|
||
|
||
// errors were found
|
||
if (errors > 0) {
|
||
// 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);
|
||
|
||
return false;
|
||
}
|
||
|
||
// build table row
|
||
var row = fields;
|
||
row.vehicle_label = $("#vmfg option:selected").text() + " " + $("#vehicle option:selected").text();
|
||
row.flag_active = row.flag_active == 1 ? true : false;
|
||
|
||
// add optional field
|
||
if (typeof fields.flag_motolite_battery === 'undefined') {
|
||
row.flag_motolite_battery = false;
|
||
row.battery_label = "";
|
||
} else {
|
||
row.flag_motolite_battery = true;
|
||
row.battery_label = $("#battery option:selected").text();
|
||
}
|
||
|
||
if (mode == 'create') {
|
||
// set an index
|
||
row.index = moment().unix();
|
||
|
||
// save to table
|
||
vehicleRows.push(row);
|
||
} else {
|
||
// get vehicle row by index
|
||
row.index = parseInt(row.index);
|
||
rowData = findVehicleRow(row.index);
|
||
vehicleRows[rowData.index] = row;
|
||
}
|
||
|
||
// refresh the data table
|
||
vehicleTable.originalDataSet = vehicleRows;
|
||
vehicleTable.reload();
|
||
|
||
// close modal
|
||
$("#vehicle-form-modal").modal('hide');
|
||
});
|
||
|
||
// reset vehicle form status on close
|
||
$("#vehicle-form-modal").on('hidden.bs.modal', function(e) {
|
||
$("#flag-motolite-battery").prop('checked', false).change();
|
||
$("#flag-active").prop('checked', true);
|
||
$("#vehicle-form").find("input[type='text'], input[type='hidden'], select").val("").change();
|
||
removeVehicleErrors();
|
||
});
|
||
|
||
// remove all error classes on vehicle form
|
||
function removeVehicleErrors() {
|
||
var form = $("#vehicle-form");
|
||
form.find(".form-control-danger").removeClass('form-control-danger');
|
||
form.find("[data-field]").removeClass('has-danger');
|
||
form.find(".form-control-feedback[data-field]").addClass('hide');
|
||
}
|
||
|
||
// vehicles data table
|
||
var vehicleOptions = {
|
||
data: {
|
||
type: 'local',
|
||
source: vehicleRows,
|
||
saveState: {
|
||
cookie: false,
|
||
webstorage: false
|
||
}
|
||
},
|
||
layout: {
|
||
scroll: true
|
||
},
|
||
columns: [
|
||
{
|
||
field: 'name',
|
||
title: 'Name',
|
||
template: function (row, index, datatable) {
|
||
return row.name + '<div class="form-control-feedback hide" data-field="name"></div>';
|
||
}
|
||
},
|
||
{
|
||
field: 'vehicle_label',
|
||
title: 'Vehicle',
|
||
width: 150,
|
||
template: function (row, index, datatable) {
|
||
return row.vehicle_label + '<div class="form-control-feedback hide" data-field="vehicle"></div>';
|
||
}
|
||
},
|
||
{
|
||
field: 'model_year',
|
||
title: 'Year',
|
||
template: function (row, index, datatable) {
|
||
return (typeof row.model_year !== 'undefined' ? row.model_year : '-') + '<div class="form-control-feedback hide" data-field="model_year"></div>';
|
||
}
|
||
},
|
||
{
|
||
field: 'plate_number',
|
||
title: 'Plate No.',
|
||
template: function (row, index, datatable) {
|
||
return row.plate_number + '<div class="form-control-feedback hide" data-field="plate_number"></div>';
|
||
}
|
||
},
|
||
{
|
||
field: 'color',
|
||
title: 'Color',
|
||
width: 70,
|
||
template: function (row, index, datatable) {
|
||
return row.color + '<div class="form-control-feedback hide" data-field="color"></div>';
|
||
}
|
||
},
|
||
{
|
||
field: 'status_condition',
|
||
title: 'Cond.',
|
||
template: function (row, index, datatable) {
|
||
var status_conditions = {
|
||
{% for key, status_condition in status_conditions %}
|
||
"{{ key }}": "{{ status_condition }}",
|
||
{% endfor %}
|
||
};
|
||
|
||
return status_conditions[row.status_condition] + '<div class="form-control-feedback hide" data-field="status_condition"></div>';
|
||
}
|
||
},
|
||
{
|
||
field: 'fuel_type',
|
||
title: 'Fuel Type',
|
||
template: function (row, index, datatable) {
|
||
var fuel_types = {
|
||
{% for key, fuel_type in fuel_types %}
|
||
"{{ key }}": "{{ fuel_type }}",
|
||
{% endfor %}
|
||
};
|
||
|
||
return fuel_types[row.fuel_type] + '<div class="form-control-feedback hide" data-field="fuel_type"></div>';
|
||
}
|
||
},
|
||
{
|
||
field: 'warranty_code',
|
||
title: 'Wty. Code',
|
||
template: function (row, index, datatable) {
|
||
return row.warranty_code + '<div class="form-control-feedback hide" data-field="warranty_code"></div>';
|
||
}
|
||
},
|
||
{
|
||
field: 'warranty_expiration',
|
||
title: 'Wty. Exp.',
|
||
width: 80,
|
||
template: function (row, index, datatable) {
|
||
return row.warranty_expiration + '<div class="form-control-feedback hide" data-field="warranty_expiration"></div>';
|
||
}
|
||
},
|
||
{
|
||
field: 'battery_label',
|
||
title: 'Battery',
|
||
width: 150,
|
||
template: function (row, index, datatable) {
|
||
return row.battery_label + '<div class="form-control-feedback hide" data-field="battery"></div>';
|
||
}
|
||
},
|
||
{
|
||
field: 'flag_active',
|
||
title: 'Status',
|
||
template: function (row, index, datatable) {
|
||
if (row.flag_active === true) {
|
||
html = '<span class="m-badge m-badge--success m-badge--wide">Active</span>';
|
||
} else {
|
||
html = '<span class="m-badge m-badge--danger m-badge--wide">Inactive</span>';
|
||
}
|
||
|
||
html += '<div class="form-control-feedback hide" data-field="flag_active"></div>';
|
||
|
||
return html;
|
||
}
|
||
},
|
||
{
|
||
field: 'Actions',
|
||
width: 100,
|
||
title: 'Actions',
|
||
sortable: false,
|
||
overflow: 'visible',
|
||
template: function (row, index, datatable) {
|
||
html = '<input type="hidden" name="index" value="' + row.index + '">';
|
||
|
||
html += '<button type="button" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-jo-vehicle" title="Job Order"><i class="flaticon-calendar-3"></i></button>';
|
||
html += '<button type="button" class="m-portlet__nav-link btn m-btn m-btn--hover-accent m-btn--icon m-btn--icon-only m-btn--pill btn-edit-vehicle" title="Edit"><i class="la la-edit"></i></button>';
|
||
html += '<button data-index="' + row.index + '" type="button" class="m-portlet__nav-link btn m-btn m-btn--hover-danger m-btn--icon m-btn--icon-only m-btn--pill btn-delete-vehicle" title="Delete"><i class="la la-trash"></i></button>';
|
||
|
||
return html;
|
||
},
|
||
}
|
||
],
|
||
pagination: false
|
||
};
|
||
|
||
var vehicleTable = $("#data-vehicles").mDatatable(vehicleOptions);
|
||
|
||
// tickets data table
|
||
var ticketOptions = {
|
||
data: {
|
||
type: 'local',
|
||
source: ticketRows,
|
||
saveState: {
|
||
cookie: false,
|
||
webstorage: false
|
||
}
|
||
},
|
||
layout: {
|
||
scroll: true
|
||
},
|
||
columns: [
|
||
{
|
||
field: 'id',
|
||
title: 'ID',
|
||
width: 30
|
||
},
|
||
{
|
||
field: 'date_create',
|
||
title: 'Date Created',
|
||
width: 200
|
||
},
|
||
{
|
||
field: 'ticket_type',
|
||
title: 'Ticket Type'
|
||
},
|
||
{
|
||
field: 'status',
|
||
title: 'Status'
|
||
},
|
||
{
|
||
field: 'Actions',
|
||
width: 70,
|
||
title: 'Actions',
|
||
sortable: false,
|
||
overflow: 'visible',
|
||
template: function (row, index, datatable) {
|
||
return '<a href="' + row.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-edit-ticket" title="Edit"><i class="la la-edit"></i></a>';
|
||
},
|
||
}
|
||
],
|
||
pagination: false
|
||
};
|
||
|
||
var ticketTable = $("#data-tickets").mDatatable(ticketOptions);
|
||
|
||
// job order history table
|
||
var joOptions = {
|
||
data: {
|
||
type: 'local',
|
||
source: joRows,
|
||
saveState: {
|
||
cookie: false,
|
||
webstorage: false
|
||
}
|
||
},
|
||
layout: {
|
||
scroll: true
|
||
},
|
||
columns: [
|
||
{
|
||
field: 'id',
|
||
title: 'ID',
|
||
width: 30
|
||
},
|
||
{
|
||
field: 'date_schedule',
|
||
title: 'Date Scheduled'
|
||
},
|
||
{
|
||
field: 'service_type',
|
||
title: 'Service Type'
|
||
},
|
||
{
|
||
field: 'plate_num',
|
||
title: 'Plate #'
|
||
},
|
||
{
|
||
field: 'status',
|
||
title: 'Status'
|
||
},
|
||
],
|
||
pagination: false
|
||
};
|
||
|
||
var joTable = $("#data-job-orders").mDatatable(joOptions);
|
||
});
|
||
</script>
|
||
{% endblock %}
|
||
|