Merge branch '341-cmb-add-service-charge-dropdown' into '270-final-cmb-fixes'

Resolve "CMB - add service charge dropdown"

See merge request jankstudio/resq!387
This commit is contained in:
Kendrick Chan 2020-02-18 01:43:00 +00:00
commit 1c9ce12595
9 changed files with 309 additions and 44 deletions

View file

@ -0,0 +1 @@
INSERT INTO `service_charge` VALUES(1,'Bangi',20),(2,'Banting',30),(3,'Bdr Saujana Utama',20),(4,'Bdr Seri Coalfields',30),(5,'Bdr Baru Bangi',20),(6,'Bdr Saujana Putra',20),(7,'Bukit Beruntung',30),(8,'Cyberjaya',20),(9,'Dengkil',30),(10,'Hulu Langat',20),(11,'Jenjarom',30),(12,'Klia',30),(13,'Meru',20),(14,'Port Klang',20),(15,'Pulau Indah',30),(16,'Puncak Alam',20),(17,'Putrajaya',20),(18,'Rawang',30),(19,'Salak Tinggi',30),(20,'Semenyih',20),(21,'Sepang',30),(22,'Serendah',30),(23,'Sungai Buloh',20),(24,'Teluk Panglima Garang',30),(25,'Uitm Puncak Alam',20),(26,'12am - 7am',10),(27,'Out of define Klg Valley',20),(28,'Airport',35),(29,'Jump start',50),(30,'Product warranty service charge - existing BA customer',20),(31,'Product warranty service charge - non BA customer',40);

View file

@ -694,6 +694,7 @@ class JobOrderController extends Controller
$items = $req->request->get('items');
$promo_id = $req->request->get('promo');
$cvid = $req->request->get('cvid');
$service_charges = $req->request->get('service_charges');
$em = $this->getDoctrine()->getManager();
@ -740,6 +741,9 @@ class JobOrderController extends Controller
// TODO: this snippet should be in the invoice generator
$error = $ic->validateDiscount($criteria, $promo_id);
// process service charges
$error = $ic->invoiceServiceCharges($criteria, $service_charges);
if (!$error)
$error = $ic->invoiceBatteries($criteria, $items);

View file

@ -821,4 +821,5 @@ class JobOrder
{
return $this->meta[$id];
}
}

View file

@ -0,0 +1,64 @@
<?php
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table(name="service_charge")
*/
class ServiceCharge
{
// unique id
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
// name
/**
* @ORM\Column(type="string", length=80)
*/
protected $name;
// amount
/**
* @ORM\Column(type="decimal", precision=9, scale=2)
*/
protected $amount;
public function __construct()
{
$this->amount = 0;
}
public function getID()
{
return $this->id;
}
public function setName($name)
{
$this->name = $name;
return $this;
}
public function getName()
{
return $this->name;
}
public function setAmount($amount)
{
$this->amount = $amount;
return $this;
}
public function getAmount()
{
return $this->amount;
}
}

View file

@ -5,6 +5,7 @@ namespace App\Ramcar;
use App\Entity\Battery;
use App\Entity\Promo;
use App\Entity\CustomerVehicle;
use App\Entity\ServiceCharge;
class InvoiceCriteria
{
@ -13,6 +14,7 @@ class InvoiceCriteria
protected $cv;
protected $flag_coolant;
protected $discount;
protected $service_charges;
// entries are battery and trade-in combos
protected $entries;
@ -25,6 +27,7 @@ class InvoiceCriteria
$this->cv = null;
$this->flag_coolant = false;
$this->discount = 0;
$this->service_charges = [];
}
public function setServiceType($stype)
@ -138,4 +141,16 @@ class InvoiceCriteria
{
return $this->discount;
}
public function addServiceCharge(ServiceCharge $service_charge)
{
$this->service_charges[] = $service_charge;
return $this;
}
public function getServiceCharges()
{
return $this->service_charges;
}
}

View file

@ -18,6 +18,7 @@ use App\Entity\Invoice;
use App\Entity\InvoiceItem;
use App\Entity\Battery;
use App\Entity\User;
use App\Entity\ServiceCharge;
use App\Service\InvoiceGeneratorInterface;
@ -105,6 +106,13 @@ class CMBInvoiceGenerator implements InvoiceGeneratorInterface
// break;
}
// process service charges if any
$service_charges = $criteria->getServiceCharges();
if (count($service_charges) > 0)
{
$this->processServiceCharges($total, $criteria, $invoice);
}
// get current user
$user = $this->security->getUser();
if ($user != null)
@ -126,7 +134,7 @@ class CMBInvoiceGenerator implements InvoiceGeneratorInterface
}
// generate invoice criteria
public function generateInvoiceCriteria($jo, $promo_id, $invoice_items, &$error_array)
public function generateInvoiceCriteria($jo, $discount, $invoice_items, &$error_array)
{
$em = $this->em;
@ -135,7 +143,6 @@ class CMBInvoiceGenerator implements InvoiceGeneratorInterface
$criteria->setServiceType($jo->getServiceType())
->setCustomerVehicle($jo->getCustomerVehicle());
$discount = $promo_id;
$ierror = $this->validateDiscount($criteria, $discount);
if (!$ierror && !empty($invoice_items))
@ -154,11 +161,19 @@ class CMBInvoiceGenerator implements InvoiceGeneratorInterface
$ierror = $this->invoiceBatteries($criteria, $invoice_items);
}
// get the meta for service charges
$service_charges = $jo->getMeta('service_charges');
if (!empty($service_charges))
{
$service_charges = $jo->getMeta('service_charges');
$this->invoiceServiceCharges($criteria, $service_charges);
}
if ($ierror)
{
$error_array['invoice'] = $ierror;
}
else
{
// generate the invoice
@ -287,6 +302,28 @@ class CMBInvoiceGenerator implements InvoiceGeneratorInterface
return null;
}
public function invoiceServiceCharges(InvoiceCriteria $criteria, $service_charges)
{
if (!empty($service_charges))
{
foreach ($service_charges as $service_charge)
{
// check if valid service charge
$sc = $this->em->getRepository(ServiceCharge::class)->find($service_charge['id']);
if (empty($sc))
{
$error = 'Invalid service charge specified.';
return $error;
}
$criteria->addServiceCharge($sc);
}
}
return null;
}
protected function processEntries(&$total, InvoiceCriteria $criteria, Invoice $invoice)
{
@ -605,4 +642,24 @@ class CMBInvoiceGenerator implements InvoiceGeneratorInterface
$total['vat'] = $vat;
}
protected function processServiceCharges(&$total, InvoiceCriteria $criteria, Invoice $invoice)
{
$service_charges = $criteria->getServiceCharges();
foreach ($service_charges as $service_charge)
{
$amount = $service_charge->getAmount();
$title = 'Service Charge - ' . $service_charge->getName();
$total['total_price'] += $amount;
// add item
$item = new InvoiceItem();
$item->setInvoice($invoice)
->setTitle($title)
->setQuantity(1)
->setPrice($amount);
$invoice->addItem($item);
}
}
}

View file

@ -26,6 +26,7 @@ use App\Entity\Rider;
use App\Entity\JORejection;
use App\Entity\Warranty;
use App\Entity\Customer;
use App\Entity\ServiceCharge;
use App\Ramcar\InvoiceCriteria;
use App\Ramcar\CMBServiceType;
@ -351,13 +352,13 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
// call service to generate job order and invoice
$invoice_items = $req->request->get('invoice_items', []);
$promo_id = $req->request->get('invoice_promo');
$discount = $req->request->get('invoice_discount');
$invoice_change = $req->request->get('invoice_change', 0);
// check if invoice changed
if ($invoice_change)
{
$this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $error_array);
$this->ic->generateInvoiceCriteria($jo, $discount, $invoice_items, $error_array);
}
// validate
@ -523,11 +524,14 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
}
// get discount and set to meta
$discount = $req->request->get('invoice_promo');
$discount = $req->request->get('invoice_discount', []);
// check if discount is greater than 50 or negative number
if (($discount > 50) || ($discount < 0))
$error_array['invoice_promo'] = 'Invalid discount specified';
$error_array['invoice_discount'] = 'Invalid discount specified';
// get list of service charges
$service_charges = $req->request->get('service_charges', []);
if (empty($error_array))
{
@ -559,6 +563,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
->setRider($rider);
$jo->addMeta('discount', $discount);
$jo->addMeta('service_charges', $service_charges);
// check if user is null, meaning call to create came from API
if ($user != null)
@ -580,13 +585,13 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
// call service to generate job order and invoice
$invoice_items = $req->request->get('invoice_items', []);
$promo_id = $req->request->get('invoice_promo');
$discount = $req->request->get('invoice_discount');
$invoice_change = $req->request->get('invoice_change', 0);
// check if invoice changed
if ($invoice_change)
{
$this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $error_array);
$this->ic->generateInvoiceCriteria($jo, $discount, $invoice_items, $error_array);
}
// validate
@ -1402,6 +1407,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
$params['mode'] = 'onestep-edit';
$params['cvid'] = $obj->getCustomerVehicle()->getID();
$params['vid'] = $obj->getCustomerVehicle()->getVehicle()->getID();
$params['jo_service_charges'] = $obj->getMeta('service_charges');
$this->fillDropdownParameters($params);
$this->fillFormTags($params);
@ -2498,11 +2504,11 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
}
// get discount and set to meta
$discount = $req->request->get('invoice_promo');
$discount = $req->request->get('invoice_discount');
// check if discount is greater than 50 or negative number
if (($discount > 50) || ($discount < 0))
$error_array['invoice_promo'] = 'Invalid discount specified';
$error_array['invoice_discount'] = 'Invalid discount specified';
if (empty($error_array))
{
@ -2551,13 +2557,13 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
// call service to generate job order and invoice
$invoice_items = $req->request->get('invoice_items', []);
$promo_id = $req->request->get('invoice_promo');
$discount = $req->request->get('invoice_discount');
$invoice_change = $req->request->get('invoice_change', 0);
// check if invoice changed
if ($invoice_change)
{
$this->ic->generateInvoiceCriteria($jo, $promo_id, $invoice_items, $error_array);
$this->ic->generateInvoiceCriteria($jo, $discount, $invoice_items, $error_array);
}
// validate
@ -2674,6 +2680,7 @@ class CMBJobOrderHandler implements JobOrderHandlerInterface
// db loaded
$params['bmfgs'] = $em->getRepository(BatteryManufacturer::class)->findAll();
$params['promos'] = $em->getRepository(Promo::class)->findAll();
$params['service_charges'] = $em->getRepository(ServiceCharge::class)->findAll();
// list of hubs
$hubs = $em->getRepository(Hub::class)->findBy([], ['name' => 'ASC']);

View file

@ -477,6 +477,40 @@
</div>
</div>
<div class="m-form__seperator m-form__seperator--dashed"></div>
<div class="m-form__section" id="sc-section">
<div class="m-form__heading">
<h3 class="m-form__heading-title">
Service Charges
</h3>
</div>
<div class="row m-form__group">
<div class="col-lg-12">
<button class="btn btn-primary" id="btn-sc-add">Add Service Charge</button>
</div>
</div>
<!-- TODO: loop through existing service charges for job order -->
{% for jo_sc_key, jo_sc in jo_service_charges %}
<div class="form-group m-form__group row">
<div class="col-lg-6">
<div class="col-lg-12 form-group-inner">
<select class="form-control m-input sc-select" name="service_charges[]">
{% for key, sc in service_charges %}
<option value="{{ sc.getID }}"{{ jo_sc.id == sc.getID ? ' selected' }}>{{ sc.getName }}</option>
{% endfor %}
</select>
</div>
</div>
<div class="col-lg-5">
<input class="form-control sc-amount" type="text" value="0" disabled>
</div>
<div class="col-lg-1">
<button class="btn btn-danger btn-sc-remove">X</button>
</div>
</div>
{% endfor %}
</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">
@ -498,12 +532,12 @@
</div>
<div class="form-group m-form__group row">
<div class="col-lg-6">
<label>Discount Type</label>
<label>Discount</label>
{% if ftags.invoice_edit %}
<input type="number" id="invoice-promo" name="invoice_promo" class="form-control m-input min = "0" max="50" value="{{ obj.getInvoice ? obj.getInvoice.getDiscount }}">
<div class="form-control-feedback hide" data-field="invoice_promo"></div>
<input type="number" id="invoice-discount" name="invoice_discount" class="form-control m-input min = "0" max="50" value="{{ obj.getInvoice ? obj.getInvoice.getDiscount }}">
<div class="form-control-feedback hide" data-field="invoice_discount"></div>
{% else %}
<input type="number" id="invoice-promo" name="invoice_promo" class="form-control m-input min="0" max="50" value="{{ obj.getInvoice ? obj.getInvoice.getDiscount }}" disabled>
<input type="number" id="invoice-discount" name="invoice_discount" class="form-control m-input min="0" max="50" value="{{ obj.getInvoice ? obj.getInvoice.getDiscount }}" disabled>
{% endif %}
</div>
<div class="col-lg-6">
@ -960,6 +994,9 @@ $(function() {
// add invoice items to data
fields['invoice_items'] = invoiceItems;
// add service charges to data
fields['service_charges'] = sc_array;
{% if mode in ['update-processing', 'update-reassign-hub'] %}
// add selected hub to data
fields['hub'] = selectedHub;
@ -1267,6 +1304,7 @@ $(function() {
});
var invoiceItems = [];
var sc_array = [];
// populate invoiceItems if editing so that we don't lose the battery
{% if mode in ['open-edit', 'onestep-edit', 'walk-in-edit'] %}
@ -1322,7 +1360,7 @@ $(function() {
});
// update invoice when promo is changed
$("#invoice-promo").change(function() {
$("#invoice-discount").change(function() {
generateInvoice();
});
@ -1333,8 +1371,9 @@ $(function() {
// reset the invoice table
$("#btn-reset-invoice").click(function() {
$("#invoice-promo").prop('selectedIndex', 0);
$("#invoice-discount").prop('selectedIndex', 0);
invoiceItems = [];
sc_array = [];
generateInvoice();
});
@ -1343,29 +1382,34 @@ $(function() {
generateInvoice();
});
function generateInvoice() {
var promo = $("#invoice-promo").val();
var table = $("#invoice-table tbody");
function generateInvoice() {
var discount = $("#invoice-discount").val();
var table = $("#invoice-table tbody");
var stype = $("#service_type").val();
var cvid = $("#customer-vehicle").val();
// generate invoice values
$.ajax({
method: "POST",
url: "{{ url('jo_gen_invoice') }}",
data: {
$.each(sc_array, function(index){
console.log('generateInvoice ' + this.id);
});
// generate invoice values
$.ajax({
method: "POST",
url: "{{ url('jo_gen_invoice') }}",
data: {
'stype': stype,
'items': invoiceItems,
'promo': promo,
'cvid': cvid
}
}).done(function(response) {
'items': invoiceItems,
'promo': discount,
'cvid': cvid,
'service_charges': sc_array,
}
}).done(function(response) {
// mark as invoice changed
$("#invoice-change").val(1);
var invoice = response.invoice;
var invoice = response.invoice;
// populate totals
$("#invoice-promo-discount").val(invoice.discount);
$("#invoice-discount").val(invoice.discount);
$("#invoice-price").val(invoice.price);
$("#invoice-trade-in").val(invoice.trade_in);
$("#invoice-vat").val(invoice.vat);
@ -1607,6 +1651,78 @@ $(function() {
});
});
});
// service charge add
$('#btn-sc-add').click(function(e) {
console.log('adding service charge');
// add dropdown before the button
var html = '<div class="form-group m-form__group row">';
html += '<div class="col-lg-6">';
html += '<div class="col-lg-12 form-group-inner">';
html += '<select class="form-control m-input sc-select" name="service_charges">';
{% for key, sc in service_charges %}
html += '<option value="{{ sc.getID }}" data-amount="{{ sc.getAmount }}">{{ sc.getName }}</option>';
{% endfor %}
html += '</select>';
html += '</div>';
html += '</div>';
html += '<div class="col-lg-5">';
html += '<input class="form-control sc-amount" type="text" value="0" disabled>';
html += '</div>';
html += '<div class="col-lg-1">';
html += '<button class="btn btn-danger btn-sc-remove">X</button>';
html += '</div>';
html += '</div>';
$('#sc-section').append(html);
// clear the sc_array
sc_array.length = 0;
// trigger change in select
$('#sc-section').find('.sc-select').last().change();
return false;
});
// service charge remove
$('body').on('click', '.btn-sc-remove', function(e) {
console.log('removing service charge');
$(this).closest('.row').remove();
sc_array.length = 0;
// get the service charges
$('.sc-select').each(function() {
var id = $(this).children('option:selected').val();
sc_array.push({
id: id,
});
});
generateInvoice();
return false;
});
$('body').on('change', '.sc-select', function(e) {
var amount = $(this).children('option:selected').data('amount');
$(this).closest('.row').find('.sc-amount').val(amount);
// clear the sc_array
sc_array.length = 0;
// get the service charges
$('.sc-select').each(function() {
var id = $(this).children('option:selected').val();
sc_array.push({
id: id,
});
});
generateInvoice();
});
});
</script>
{% endblock %}

View file

@ -393,12 +393,12 @@
</div>
<div class="form-group m-form__group row">
<div class="col-lg-6">
<label>Discount Type</label>
<label>Discount</label>
{% if ftags.invoice_edit %}
<input type="number" id="invoice-promo" name="invoice_promo" class="form-control m-input min = "0" max="50" value="{{ obj.getInvoice ? obj.getInvoice.getDiscount }}">
<div class="form-control-feedback hide" data-field="invoice_promo"></div>
<input type="number" id="invoice-discount" name="invoice_discount" class="form-control m-input min = "0" max="50" value="{{ obj.getInvoice ? obj.getInvoice.getDiscount }}">
<div class="form-control-feedback hide" data-field="invoice_discount"></div>
{% else %}
<input type="number" id="invoice-promo" name="invoice_promo" class="form-control m-input min="0" max="50" value="{{ obj.getInvoice ? obj.getInvoice.getDiscount }}" disabled>
<input type="number" id="invoice-discount" name="invoice_discount" class="form-control m-input min="0" max="50" value="{{ obj.getInvoice ? obj.getInvoice.getDiscount }}" disabled>
{% endif %}
</div>
<div class="col-lg-6">
@ -936,8 +936,8 @@ var vdata = false;
generateInvoice();
});
// update invoice when promo is changed
$("#invoice-promo").change(function() {
// update invoice when discount is changed
$("#invoice-discount").change(function() {
generateInvoice();
});
@ -948,7 +948,7 @@ var vdata = false;
// reset the invoice table
$("#btn-reset-invoice").click(function() {
$("#invoice-promo").prop('selectedIndex', 0);
$("#invoice-discount").prop('selectedIndex', 0);
invoiceItems = [];
generateInvoice();
});
@ -959,7 +959,7 @@ var vdata = false;
});
function generateInvoice() {
var promo = $("#invoice-promo").val();
var discount = $("#invoice-discount").val();
var table = $("#invoice-table tbody");
var stype = $("#service_type").val();
var cvid = $("#customer-vehicle").val();
@ -971,7 +971,7 @@ var vdata = false;
data: {
'stype': stype,
'items': invoiceItems,
'promo': promo,
'promo': discount,
'cvid': cvid
}
}).done(function(response) {
@ -980,7 +980,7 @@ var vdata = false;
var invoice = response.invoice;
// populate totals
$("#invoice-promo-discount").val(invoice.discount);
$("#invoice-discount").val(invoice.discount);
$("#invoice-price").val(invoice.price);
$("#invoice-trade-in").val(invoice.trade_in);
$("#invoice-vat").val(invoice.vat);