diff --git a/public/assets/css/style.css b/public/assets/css/style.css
index 1fcf51dd..5d856433 100644
--- a/public/assets/css/style.css
+++ b/public/assets/css/style.css
@@ -86,6 +86,30 @@ span.has-danger,
font-weight: 300 !important;
}
+.table-compact th {
+ font-size: 0.9rem !important;
+ background-color: #F4F3F8;
+ color: #575962;
+}
+
+.table-compact > tbody > tr:nth-child(odd) {
+ background-color: #F7F6FA;
+}
+
+.table-compact td {
+ font-size: 0.9rem !important;
+}
+
+.table-compact td {
+ font-weight: 400;
+}
+
+.placeholder-row {
+ background-color: #fff !important;
+ padding: 32px 0 !important;
+ text-align: center;
+}
+
@media (min-width: 995px) {
.modal-lg {
max-width: 1024px;
diff --git a/src/Controller/JobOrderController.php b/src/Controller/JobOrderController.php
index 5e0e36e5..d818781f 100644
--- a/src/Controller/JobOrderController.php
+++ b/src/Controller/JobOrderController.php
@@ -6,6 +6,7 @@ use App\Ramcar\BaseController;
use App\Ramcar\ServiceType;
use App\Ramcar\JOStatus;
use App\Entity\JobOrder;
+use App\Entity\BatteryManufacturer;
use App\Entity\Customer;
use App\Entity\CustomerVehicle;
use App\Entity\Outlet;
@@ -40,6 +41,7 @@ class JobOrderController extends BaseController
$em = $this->getDoctrine()->getManager();
// get parent associations
+ $params['bmfgs'] = $em->getRepository(BatteryManufacturer::class)->findAll();
$params['customers'] = $em->getRepository(Customer::class)->findAll();
$params['outlet'] = $em->getRepository(Outlet::class)->findAll();
$params['rider'] = $em->getRepository(Rider::class)->findAll();
diff --git a/templates/job-order/incoming.html.twig b/templates/job-order/incoming.html.twig
index e905787a..744419a5 100644
--- a/templates/job-order/incoming.html.twig
+++ b/templates/job-order/incoming.html.twig
@@ -226,9 +226,74 @@
Invoice
+
+
@@ -328,6 +393,9 @@ $(function() {
var fields = form.serializeArray().map(function(x){this[x.name] = x.value; return this;}.bind({}))[0];
disabled.prop('disabled', true);
+ // add invoice items to data
+ fields['invoice_items'] = invoiceItems;
+
e.preventDefault();
$.ajax({
@@ -485,6 +553,156 @@ $(function() {
tp.prop('disabled', true).timepicker('setTime', tp.data('default-value'));
}
}).change();
+
+ // update battery list when changing manufacturer
+ $("#invoice-bmfg").change(function() {
+ var id = $(this).val();
+ var field = $("#invoice-battery");
+
+ // no id specified
+ if (!id) {
+ field.html('').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 = '';
+
+ // TODO: Battery unit price is static for now
+ var unitPrice = 1000;
+
+ $.each(response.data, function(index, battery) {
+ html += '';
+ });
+
+ field.html(html).prop('disabled', false);
+ } else {
+ field.html('').prop('disabled', true);
+ }
+ });
+ });
+
+ // mask quantity field
+ $("#invoice-quantity").inputmask("mask", {
+ mask: "9999999",
+ placeholder: ""
+ });
+
+ var invoiceItems = [];
+ var invoiceDiscount = 0;
+ var invoiceTax = 0;
+ var invoiceTotal = 0;
+
+ // add to invoice
+ $("#btn-add-to-invoice").click(function() {
+ var bmfg = $("#invoice-bmfg");
+ var battery = $("#invoice-battery");
+ var qty = $("#invoice-quantity");
+ var tbody = $("#invoice-table tbody");
+ var unitPrice = parseFloat(battery.find('option:selected').data('unit-price'));
+
+ if (!bmfg.val() || !battery.val() || !qty.val()) {
+ swal({
+ title: 'Whoops!',
+ text: 'Please fill in all the invoice fields.',
+ type: 'warning'
+ });
+
+ return false;
+ }
+
+ if (isNaN(qty.val())) {
+ swal({
+ title: 'Whoops!',
+ text: 'Invalid quantity specified.',
+ type: 'warning'
+ });
+
+ return false;
+ }
+
+ var qtyVal = parseInt(qty.val());
+ var subtotal = unitPrice * qtyVal;
+
+ // add to invoice array for form submission
+ invoiceItems.push({
+ 'battery_manufacturer': bmfg.val(),
+ 'battery': battery.val(),
+ 'battery_price': unitPrice,
+ 'quantity': qtyVal,
+ 'subtotal': subtotal
+ });
+
+ // build row html
+ // TODO: Fill with actual data for the rest of the columns
+ var html = '' +
+ '| ' + battery.find('option:selected').text() + ' | ' +
+ '' + qty.val() + ' | ' +
+ 'Base Price | ' + // TODO: static for now
+ '' + (Math.round(unitPrice * 100) / 100).toFixed(2) + ' | ' + // TODO: not sure if this is correct since it says w/ tax
+ '0.00 | ' + // TODO: static for now
+ '' + (Math.round(subtotal * 100) / 100).toFixed(2) + ' | ' + // TODO: I assumed this is unit price * qty
+ 'Yes | ' + // TODO: static for now
+ 'Regular | ' +
+ ' | ' +
+ ' | ' +
+ ' | ' +
+ ' | ' +
+ ' | ' +
+ ' | ' +
+ '
';
+
+ // save to invoice table
+ tbody.find('.placeholder-row').addClass('hide');
+ tbody.append(html);
+
+ // add to invoice total and recompute
+ invoiceTotal += subtotal;
+ updateInvoiceFigures();
+ });
+
+ function updateInvoiceFigures() {
+ var amountField = $("#invoice-amount");
+ var taxField = $("#invoice-tax");
+ var discountField = $("#invoice-discount");
+ var finalAmountField = $("#invoice-final-amount");
+ var finalAmount = invoiceTotal + invoiceTax - invoiceDiscount;
+
+ amountField.val(parseFloat(Math.round(invoiceTotal * 100) / 100).toFixed(2));
+ taxField.val(parseFloat(Math.round(invoiceTax * 100) / 100).toFixed(2));
+ discountField.val(parseFloat(Math.round(invoiceDiscount * 100) / 100).toFixed(2));
+ finalAmountField.val(parseFloat(Math.round(finalAmount * 100) / 100).toFixed(2));
+ }
+
+ // remove from invoice table
+ $(document).on("click", ".btn-invoice-delete", function() {
+ var row = $(this).closest('tr');
+ var qty = row.find('.col-quantity').html();
+ var unitPrice = row.find('.col-unit-price').html();
+
+ // set defaults if for whatever reason they are not valid numbers
+ if (isNaN(qty)) {
+ qty = 1;
+ }
+
+ if (isNaN(unitPrice)) {
+ unitPrice = 0;
+ }
+
+ // subtract from totals
+ var subtotal = parseFloat(unitPrice) * parseInt(qty);
+ invoiceTotal -= subtotal;
+ updateInvoiceFigures();
+
+ // remove from table
+ row.remove();
+ });
});
{% endblock %}