PHP Developers Network

A community of PHP developers offering assistance, advice, discussion, and friendship.
 
Loading
It is currently Sat Dec 16, 2017 12:25 am

All times are UTC - 5 hours




Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: SEPARATION OF CONCERN
PostPosted: Thu Feb 11, 2016 3:35 am 
Offline
Forum Newbie

Joined: Thu Feb 11, 2016 1:13 am
Posts: 15
Morning All.
I recently attended an Interview where, I was told I needed to invest more time in implementing SEPARATION OF CONCERN in my code.
This lead me to ask what he meant, as I am using the codeigniter framework and all relevant aspects are separated as default.
The example he mentioned from my software showcase, was a very involved sales order form.
This form has a lot of user interaction to do with delivery times, product look ups etc.

So to get to the point is there a best method to implementing Separation of concern when developing front end forms in php.
Is it better to pass every action back to the controller or to perform relevant operations using javascript/jquery client side.

And if using Javascript / Jquery is it better to include inline or reference an included script with the functions in.

This is meant to be a general question so any answers are welcome please.

Thank You very much for your time


Top
 Profile  
 
PostPosted: Thu Feb 11, 2016 7:28 am 
Offline
Moderator
User avatar

Joined: Tue Nov 09, 2010 3:39 pm
Posts: 6404
Location: Montreal, Canada
CI does provide you some level of separation of concerns out of the box but does nothing to enforce them. If you want 300 line controller methods, function calls in your views, and views littered with inline JS/CSS, it won't stop you.

_________________
Supported PHP versions No longer supported versions


Top
 Profile  
 
PostPosted: Thu Feb 11, 2016 10:30 am 
Offline
Site Administrator
User avatar

Joined: Wed Aug 25, 2004 7:54 pm
Posts: 13459
Location: New York, NY, US
We'd obviously need to review your code to give specific comments, or to confirm the assessment you got from the interview. It is a shame that you did not know more about Separation of Concerns so that you could have pushed back a little on this person's comments. I say that because an idea as far-ranging as Separation of Concerns can become a bit of a religion that may be more personal preference than practical. That is not to say that Separation of Concerns is not an important idea. It really underpins most Best Practices in software development.

Separation of Concerns implies that you break your application down into parts that have a specific purpose, and provide separation between those parts. The problem is that it does not define what a concern is or how multiple smaller concerns can be combined into a larger concern. It also done not enumerate the may types of separations that are important in software design. And it does not prioritize concerns and separations to provide guidance.

For example, two of the most common separations in used in software development are by file and by dependency. However, you can have code nicely divided into organized files but not have clear dependency separation. Conversely, you can have excellent dependency separation all in one file. Let me comment on some of the ideas above to give you an idea of the complexities.
terenceb wrote:
Is it better to pass every action back to the controller or to perform relevant operations using javascript/jquery client side.
In some ways this has nothing to do with Separation of Concerns. For example, you can choose to move all Presentation Layer code into HTML/CSS/Javascript and having the PHP code be clearly separated Business/Domain Layer code that just sends JSON. That can promote a clean separation. However, you can have just as clean a separation by submitting the form back to PHP and having Presentation Layer code generate the page. There are practical reasons to do one or the other and the choice may have nothing to do with Separation of Concerns. A problem with Javascript heavy solution is that Business/Domain Layer code can leak into the Presentation Layer and not be cleanly separated.
terenceb wrote:
And if using Javascript / Jquery is it better to include inline or reference an included script with the functions in.
It is a good practice to put Javascript code into separate files. Some small amount of invoking Javascript may remain in the HTML file. But note that just moving the Javascript to a separate file, while a good practice, does not mean that important concerns are automatically cleanly separated within the Javascript. You still need well designed Javascript libraries.

Separation of Concerns is a high-level goal in software design, but it manifests in a web of more specific ideas like SOLID, GRASP, DRY, etc. and in implementation practices like separating HTML and CSS, or dividing PHP apps into Model, View and Controller code. There are vertical separations based on dependency; there are horizontal separations based on packaging. Then there are Cross-Cutting Concerns that can bedevil developers and elude clean designs. And worse, poorly done Separation of Concerns may make things worse. All I can recommend any of us do is keep learning about these concepts, keep improving our software design skills, and keep refactoring our code.

_________________
(#10850)


Top
 Profile  
 
PostPosted: Fri Feb 12, 2016 12:57 am 
Offline
Forum Newbie

Joined: Thu Feb 11, 2016 1:13 am
Posts: 15
First Off.
Thanks For The Answers.
The specific example I used was involved.
A quick glance is around 700 odd lines of code.

Please let me know if I am allowed to post something that size and if it would then be possible for someone to rip it apart and give suggestions on what to move back to controller etc.

Once again thank you all for the time


Top
 Profile  
 
PostPosted: Fri Feb 12, 2016 7:27 am 
Offline
Moderator
User avatar

Joined: Tue Nov 09, 2010 3:39 pm
Posts: 6404
Location: Montreal, Canada
Absolutely post it. Here, in a gist, or just link to the repo. We'll be happy to provide what feedback we can.

_________________
Supported PHP versions No longer supported versions


Top
 Profile  
 
PostPosted: Fri Feb 12, 2016 9:53 am 
Offline
Site Administrator
User avatar

Joined: Wed Aug 25, 2004 7:54 pm
Posts: 13459
Location: New York, NY, US
Yes, it might be interesting to refactor the code here to show the kinds of questions software developers should ask about their design, and the options available to implement the answers to those questions.

_________________
(#10850)


Top
 Profile  
 
PostPosted: Sat Feb 13, 2016 2:35 am 
Offline
Forum Newbie

Joined: Thu Feb 11, 2016 1:13 am
Posts: 15
Here is the form the I am using.

I am going to seperate the code a little, as it says there is too many characters. ;)
php one reply and script the other.


Syntax: [ Download ] [ Hide ]
<!--<?php
date_default_timezone_set('Africa/Johannesburg');

?>-->

 
 <div class="form" style="width:96%;float:left;margin-top:10px;margin-left:10px;">
<div id="header">
 <span class="formheading">Order Information<?php if(isset($header)){echo ' Order No: '.$header->ordid;}?></span><input id="line_display" type="button" class="display" style="float: right; margin-right:25px;" value="Line Items"/>
 <hr/>
 <form name="orders" method="post" action="<?php echo base_url('fmcg/create_order');?>">
 
 <?php
         if(isset($header)){
                echo '<div id="left" style="width:30%; float:left;">';
                echo '<input type="hidden" id="order_id" value="'.$header->ordid.'"/>';
                echo '<input type="hidden" id="pid" value="'.$header->prid,'"/>';
                echo '<input type="text" id="customer" placeholder="Select Customer" size="45" value="'.$header->customer.'"/>
                      <input type="hidden" id="cid" name="customer" value="'
.$header->custid.'"/><br/>';
                echo '<input type="text" id="store" placeholder="Select Store" size="45" value="'.$header->store.'"/>
                          <input type="hidden" id="sid" name="site" value="'
.$header->siteid.'"/><br/>';
                echo '<input type="text" id="contact" placeholder="Contact Person" readonly size="20" value="'.$header->contact.'"/><br/>';
                echo '<input type="text" id="tel" placeholder="Telephone" readonly size="10" value="'.$header->tel.'"/><br/>';
                echo '<input type="text" id="email" placeholder="E-Mail" readonly size="45" value="'.$header->email.'"/>';
                echo '<input type="hidden" id="yardsize" name="yardsize" value="'.$header->yardsize.'"/>';
                echo '</div><!--header left panel-->';
                        if($header->timeslot == true){
                                echo '<input type="hidden" id="timeslot" value="true"/>';
                                echo '<input type="hidden" id="cut_off_time" value="'.$header->cut_off_time.'"/>';
                                echo '<input type="hidden" id="before_cutofftime" value="'.$header->before_cutofftime.'"/>';
                                echo '<input type="hidden" id="before_deliveryrequired" value="'.$header->before_deliveryrequired.'"/>';
                                echo '<input type="hidden" id="after_cutofftime" value="'.$header->after_cutofftime.'"/>';
                                echo '<input type="hidden" id="after_deliveryrequired" value="'.$header->after_deliveryrequired.'"/>';
                                echo '<input type="hidden" id="delivery_days" value="'.$header->delivery_days.'" />';
                        }
         }else if(isset($custonly)){
                echo '<div id="left" style="width:30%; float:left;">';
                echo '<input type="hidden" id="order_id" value=""/>';
                echo '<input type="hidden" id="pid" value="'.$this->ion_auth->user()->row()->comp_id.'"/>';
                echo '<input type="text" id="customer" placeholder="Select Customer" size="45" value="'.$custonly->companyname.'"readonly/>
                          <input type="hidden" id="cid" name="customer" value="'
.$custonly->customer_id.'"/><br/>';
                echo '<input type="text" id="store" placeholder="Select Store" size="45" value=""/>
                          <input type="hidden" id="sid" name="site" value=""/><br/>'
;
                echo '<input type="text" id="contact" placeholder="Contact Person" readonly size="20" value=""/><br/>';
                echo '<input type="text" id="tel" placeholder="Telephone" readonly size="10" value=""/><br/>';
                echo '<input type="text" id="email" placeholder="E-Mail" readonly size="45" value=""/>';
                echo '<input type="hidden" id="yardsize" name="yardsize" value=""/>';

                echo '</div><!--header left panel-->';
         }else if(isset($prepop)){
                echo '<div id="left" style="width:30%; float:left;">';
                echo '<input type="hidden" id="order_id" value=""/>';
                echo '<input type="hidden" id="pid" value="'.$this->ion_auth->user()->row()->comp_id.'"/>';
                echo '<input type="text" id="customer" placeholder="Select Customer" size="45" value="'.$prepop->customer.'" readonly/>
                          <input type="hidden" id="cid" name="customer" value="'
.$prepop->thiscust.'"/><br/>';
                echo '<input type="text" id="store" placeholder="Select Store" size="45" value="'.$prepop->companyname.'" readonly/>
                          <input type="hidden" id="sid" name="site" value="'
.$prepop->thissite.'"/><br/>';
                echo '<input type="text" id="contact" placeholder="Contact Person" readonly size="20" value="'.$prepop->contact1.'"/><br/>';
                echo '<input type="text" id="tel" placeholder="Telephone" readonly size="10" value="'.$prepop->tel1.'"/><br/>';
                echo '<input type="text" id="email" placeholder="E-Mail" readonly size="45" value="'.$prepop->email1.'"/>';
                echo '<input type="hidden" id="yardsize" name="yardsize" value="'.$prepop->yardsize.'"/>';
                if($prepop->timeslot == true){
                        echo '<input type="hidden" id="timeslot" value="true"/>';
                        echo '<input type="hidden" id="cut_off_time" value="'.$prepop->cut_off_time.'"/>';
                        echo '<input type="hidden" id="before_cutofftime" value="'.$prepop->before_cutofftime.'"/>';
                        echo '<input type="hidden" id="before_deliveryrequired" value="'.$prepop->before_deliveryrequired.'"/>';
                        echo '<input type="hidden" id="after_cutofftime" value="'.$prepop->after_cutofftime.'"/>';
                        echo '<input type="hidden" id="after_deliveryrequired" value="'.$prepop->after_deliveryrequired.'"/>';
                        echo '<input type="hidden" id="delivery_days" value="'.$prepop->delivery_days.'" />';
                }
                echo '</div><!--header left panel--> ';
         }else{
                echo '<div id="left" style="width:30%; float:left;">';
                echo '<input type="hidden" id="order_id" value=""/>';
                if(isset($principles)){
                        echo '<select name="pid" id="pid">';
                        echo '<option value="">Please Select Relevant Principle</option>';
                        foreach($principles as $principle){
                                echo '<option value="'.$principle->principle_id.'">'.$principle->companyname.'</option>';
                        }
                        echo '</select>';
                }else{
                        echo '<input type="hidden" id="pid" value=""/>';
                }      
                echo '<input type="text" id="customer" placeholder="Select Customer" size="45" value=""/><input type="hidden" id="cid" name="customer" value="<?php if(isset($header)){echo $header->customer_id;}?>"/><br/>';
                echo '<input type="text" id="store" placeholder="Select Store" size="45" value=""/><input type="hidden" id="sid" name="site" value=""/><br/>';
                echo '<input type="text" id="contact" placeholder="Contact Person" readonly size="20" value=""/><br/>';
                echo '<input type="text" id="tel" placeholder="Telephone" readonly size="10" value=""/><br/>';
                echo '<input type="text" id="email" placeholder="E-Mail" readonly size="45" value=""/>';
                echo '<input type="hidden" id="yardsize" name="yardsize" value=""/>';  
                echo '</div>';  
         }
 ?>
 
 <!-- middle block with order revision number etc -->
<?php
        if(isset($header)){
        echo '<div id="middle" style="width:25%; float:left;">';
        echo '<table>';
        echo '<tr><td>Order Version:</td><td><input type="text" id="version" value="'.($header->version + 1).'" readonly size="5"/></td></tr>';
        echo '<tr><td>Time Of Order:&nbsp;&nbsp;</td><td><input type="text" id="o_time" name="o_time" value="'.date('H:i').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Date Of Order:</td><td><input type="text" id="o_date" name="o_date" value="'.date('Y-m-d').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Captured By:</td><td><input type="text" id="captured" value="'.$header->captured.'" readonly size="15"/></td></tr>';
        echo '<tr><td>Order No:</td><td><input type="text" id="order_no" value="'.$header->order_no.'" size="15"/></td></tr>';
        echo '</table>';
        echo '</div><!--header middle panel-->';
        }else if(isset($custonly)){
        echo '<div id="middle" style="width:25%; float:left;">';
        echo '<table>';
        echo '<tr><td>Order Version:</td><td><input type="text" id="version" value="1" readonly size="5"/></td></tr>';
        echo '<tr><td>Time Of Order:&nbsp;&nbsp;</td><td><input type="text" id="o_time" name="o_time" value="'.date('H:i').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Date Of Order:</td><td><input type="text" id="o_date" name="o_date" value="'.date('Y-m-d').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Captured By:</td><td><input type="text" id="captured" value="'.$userid.'" readonly size="15"/></td></tr>';
        echo '<tr><td>Order No:</td><td><input type="text" id="order_no" size="15"/></td></tr>';
        echo '</table>';
        echo '</div><!--header middle panel-->';
        }else if(isset($prepop)){
        echo '<div id="middle" style="width:25%; float:left;">';
        echo '<table>';
        echo '<tr><td>Order Version:</td><td><input type="text" id="version" value="1" readonly size="5"/></td></tr>';
        echo '<tr><td>Time Of Order:&nbsp;&nbsp;</td><td><input type="text" id="o_time" name="o_time" value="'.date('H:i').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Date Of Order:</td><td><input type="text" id="o_date" name="o_date" value="'.date('Y-m-d').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Captured By:</td><td><input type="text" id="captured" value="'.$userid.'" readonly size="15"/></td></tr>';
        echo '<tr><td>Order No:</td><td><input type="text" id="order_no" size="15"/></td></tr>';
        echo '</table>';
        echo '</div><!--header middle panel-->';
        }else{
        echo '<div id="middle" style="width:25%; float:left;">';
        echo '<table>';
        echo '<tr><td>Order Version:</td><td><input type="text" id="version" value="1" readonly size="5"/></td></tr>';
        echo '<tr><td>Time Of Order:&nbsp;&nbsp;</td><td><input type="text" id="o_time" name="o_time" value="'.date('H:i').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Date Of Order:</td><td><input type="text" id="o_date" name="o_date" value="'.date('Y-m-d').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Captured By:</td><td><input type="text" id="captured" value="'.$userid.'" readonly size="15"/></td></tr>';
        echo '<tr><td>Order No:</td><td><input type="text" id="order_no" size="15"/></td></tr>';
        echo '</table>';
        echo '</div><!--header middle panel-->';       
        }
?>

<!-- last header block with delivery time and address-->
<?php
        if(isset($header)){
        echo '<div id="right" style="width:42%; float:left;">';
        echo '<table>';
        echo '<tr><td>Deliver To:</td><td><input id="delline1" type="text" name="delline1" size="40" value="'.$header->del_addr1.'"/></td></tr>';
        echo '<tr><td></td><td><input id="delline2" type="text" name="delline2" size="40" value="'.$header->del_addr2.'"/></td></tr>';
        echo '<tr id="dt"><td>Delivery Time:&nbsp;&nbsp;</td><td><input class="dtime" id="deltime" type="text" name="deltime" size="10" value="'.$header->del_time.'"/></td></tr>';
        echo '<tr id="dd"><td>Delivery Date:</td><td><input id="deldate" class="ddate" type="text" name="deldate" size="10" value="'.$header->del_date.'"/></td></tr>';
        echo '<tr id="lt"><td>Lead Time:</td><td><input id="leadtime" type="text" name="leadtime" size="10" value="'.$header->lead_time.'"/>(Hours : Minutes)</td></tr>';
        echo '</table>';
        echo '</div>';
        }else if(isset($custonly)){
        echo '<div id="right" style="width:42%; float:left;">';
        echo '<table>';
        echo '<tr><td>Deliver To:</td><td><input id="delline1" type="text" name="delline1" size="40" value=""/></td></tr>';
        echo '<tr><td></td><td><input id="delline2" type="text" name="delline2" size="40" value=""/></td></tr>';
        echo '<tr id="dt"><td>Delivery Time:&nbsp;&nbsp;</td><td><input class="dtime" id="deltime" type="text" name="deltime" size="10" value=""/></td></tr>';
        echo '<tr id="dd"><td>Delivery Date:</td><td><input id="deldate" class="ddate" type="text" name="deldate" size="10" value=""/></td></tr>';
        echo '<tr id="lt"><td>Lead Time:</td><td><input id="leadtime" type="text" name="leadtime" size="10" value=""/>(Hours : Minutes)</td></tr>';
        echo '</table>';
        echo '</div>';
        }else if(isset($prepop)){
        echo '<div id="right" style="width:42%; float:left;">';
        echo '<table>';
        echo '<tr><td>Deliver To:</td><td><input id="delline1" type="text" name="delline1" size="40" value="'.$prepop->address1.'"/></td></tr>';
        echo '<tr><td></td><td><input id="delline2" type="text" name="delline2" size="40" value="'.$prepop->address2.'"/></td></tr>';
        echo '<tr id="dt"><td>Delivery Time:&nbsp;&nbsp;</td><td><input class="dtime" id="deltime" type="text" name="deltime" size="10" value=""/></td></tr>';
        echo '<tr id="dd"><td>Delivery Date:</td><td><input id="deldate" class="ddate" type="text" name="deldate" size="10" value=""/></td></tr>';
        echo '<tr id="lt"><td>Lead Time:</td><td><input id="leadtime" type="text" name="leadtime" size="10" value=""/>(Hours : Minutes)</td></tr>';
        echo '</table>';
        echo '</div>';
        }else{
        echo '<div id="right" style="width:42%; float:left;">';
        echo '<table>';
        echo '<tr><td>Deliver To:</td><td><input id="delline1" type="text" name="delline1" size="50" value=""/></td></tr>';
        echo '<tr><td></td><td><input id="delline2" type="text" name="delline2" size="50" value=""/></td></tr>';
        echo '<tr id="dt"><td>Delivery Time:&nbsp;&nbsp;</td><td><input class="dtime" id="deltime" type="text" name="deltime" size="10" value=""/></td></tr>';
        echo '<tr id="dd"><td>Delivery Date:</td><td><input id="deldate" class="ddate" type="text" name="deldate" size="10" value=""/></td></tr>';
        echo '<tr id="lt"><td>Lead Time:</td><td><input id="leadtime" type="text" name="leadtime" size="10" value=""/>(Hours : Minutes)</td></tr>';
        echo '</table>';
        echo '</div>';
        }
?>


</div><!--header-->




<div id="content" style="display:none; min-height:450px;">
 <span class="formheading">Order Information</span>
 <input type="button" class="display" style="float: right; margin-right:25px;" value="Order Header"/>
 <hr/>
<div id="tablelines" style="float:left; margin-bottom:10px;">
 <table id="order_lines" style="text-align:center;">
        <thead>
        <tr><th>No</th><th>Sku No</th><th>Description</th><th>Weight</th><th></th><th>Price</th><th>Qty</th><th>Uom</th><th>Total</th><th></th></tr>           
        </thead>
        <tbody>
                        <?php
                        if(isset($lines)){
                                $linecount = 0;
                                $inclusive = 0;
                                $vatable = 0;
                                $weight = 0;
                                $cubes =0;
                                $lugs = 0;
                                $pallets = 0;

                                foreach($lines as $item){
                                        $linecount += 1;
                                        echo '<tr id="'.$linecount.'" class="inputs" ';
                                        if(is_null($item->percperlug)){
                                                echo 'data-perc="" ';
                                        }else{
                                                echo 'data-perc="'.$item->percperlug.'" ';
                                        }
                                       
                                        if(is_null($item->qtyperpal)){
                                                echo 'data-palqty="" ';
                                        }else{
                                                echo 'data-palqty="'.$item->percperlug.'" ';
                                        }                                      
                                        echo '><td>'.$linecount.'</td>';
                                        echo '<td><input type="text" class="sku" placeholder="Sku" size="10" value="'.$item->sku_number.'"/></td>';
                                        echo '<td><input type="text" class="product" placeholder="Product" value="'.$item->product.'" size="30"/><input type="hidden" class="cubic" value="'.$item->cubic_volume.'"/></td>';
                                        echo '<td><input type="text" class="weight" placeholder="Weight" readonly size="6" value="'.$item->weight.'"/></td>';
                                        echo '<td><input type="text" class="temp" placeholder="Temp" readonly size="6" value="'.$item->temp_type.'" style="display:none;"/></td>';
                                        echo '<td><input type="text" class="price" placeholder="Price" size="6" value="'.$item->price.'"/><input type="hidden" class="vatable" value="'.$item->vatable.'"/></td>';
                                        echo '<td><input id="tqty'.$linecount.'" type="text" class="qty" placeholder="Qty" size="6" value="'.$item->quantity.'"/></td>';
                                        echo '<td><input type="text" class="uom" placeholder="UOM" readonly size="6" value="'.$item->uom_name.'"/></td>';
                                        echo '<td><input type="text" class="total" placeholder="Total" readonly size="6" value="'.number_format($item->total, 2, '.', ',').'"/></td>';
                                        echo '<td><input type="button" class="reset" value="X" style="color:red; font-weight: bold; font-size:14px;"/></td>';
                                        echo '</tr>';
                                        $inclusive += $item->total;
                                        if($item->vatable == "true"){
                                                $vatable += $item->total;
                                        }
                                       
                                        $weight += ($item->weight * $item->quantity);
                                        $cubes += ($item->cubic_volume * $item->quantity);
                                       
                                        if(strtoupper($item->uom_name) == "LUG"){
                                                $lugs = $lugs + (1 * $item->quantity);
                                        }
                                                       
                                        $pallets = ceil($cubes / 1.9);
                                }
                               
                        }else{
                       
                        echo '<tr id="1" class="inputs" data-perc="" data-palqty="">';
                        echo '<td>1</td>';
                        echo '<td><input type="text" class="sku" placeholder="Sku" size="10"/></td>';
                        echo '<td><input type="text" class="product" placeholder="Product" size="30"/><input type="hidden" class="cubic"/></td>';
                        echo '<td><input type="text" class="weight" placeholder="Weight" readonly size="6"/></td>';
                        echo '<td><input type="text" class="temp" placeholder="Temp" readonly size="6" style="display:none;"/></td>';
                        echo '<td><input type="text" class="price" placeholder="Price" size="6"/><input type="hidden" class="vatable"/></td>';
                        echo '<td><input id="tqty1" type="text" class="qty" placeholder="Qty" size="6" /></td>';
                        echo '<td><input type="text" class="uom" placeholder="UOM" readonly size="6"/></td>';
                        echo '<td><input type="text" class="total" placeholder="Total" readonly size="6"/></td>';
                        echo '<td><input type="button" class="reset" value="X" style="color:red; font-weight: bold; font-size:14px;"/></td>';
                        echo '</tr>';
                 }?>
        </tbody>
        <tfoot>
        <tr><td></td><td></td><td>Total Weight:</td><td class="thickBorder" id="totalweight"><?php if(isset($weight)){ echo number_format($weight, 3, '.', ',');}?></td><td></td><td></td><td></td><td style="text-align:right;">Exclusive:</td><td class="thickBorder" id="excl_total"><?php if(isset($inclusive)){echo number_format($inclusive-($vatable*0.14), 2, '.', ',');}?></td><td></td></tr>
        <tr><td></td><td><input type="button" Value="Add Item" id="add"/></td><td>Total Cubes:</td><td class="thickBorder" id="totalcubes"><?php if(isset($cubes)){ echo number_format($cubes, 3, '.', ',');}?></td><td></td><td></td><td></td><td style="text-align:right";>Vat Amount:</td><td class="thickBorder" id="vat_total"><?php if(isset($vatable)){echo number_format($vatable*0.14, 2, '.', ',');}?></td><td></td></tr>
        <tr><td></td><td></td><td>Total Lugs:</td><td  class="thickBorder" id="totallugs"><?php if(isset($lugs)){ echo number_format($lugs, 3);}?></td><td></td><td></td><td></td><td style="text-align:right";>Inclusive:</td><td class="thickBorder" id="incl_total"><?php if(isset($inclusive)){echo number_format($inclusive, 2, '.', ',');}?></td><td></td></tr>
        <tr><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        <tr><td></td><td></td><td>Total Pallets:</td><td class="thickBorder" id="totalpallets"><?php if(isset($pallets)){ echo number_format($pallets, 3, '.', ',');}?></td><td></td><td></td><td></td><td></td><td></td><td></td></tr>
        </tfoot>
 </table>
 </div>
 <div id="tablespecials" style="float:right; margin-bottom:10px; margin-right:5px; border-left:solid 1px grey; margin-left:10px;">

 <h5 style="margin:2px 2px 2px 10px; font-weight:bolder;">Specials List</h5>
        <table id="specials" style="min-width:350px; max-width:350px;">
                <thead>
                        <tr>
                  <th style="max-width:30px;">sku</th>
                  <th style="max-width:80px;">product</th>
                  <th style="max-width:15px;">price</th>
                  <th style="max-width:15px;">qty</th>                 
                        </tr>
                </thead>
                <tbody id="data">

                </tbody>
        </table>


 </div>
 <hr style="clear:both;"/>
 
 
 <div id="info_left" style="float:left; margin-left:25px;">
 <table>
        <tr><td>Min Truck Size:</td><td><input type="text" id="trucksize" value="<?php if(isset($header)){echo $header->trucksize;}?>" readonly/></td></tr>
        <tr><td>Required Truck Type:&nbsp;</td><td><input type="text" id="trucktype" value="<?php if(isset($header)){echo $header->trucktype;}else{echo 'AMBIENT';}?>" readonly/>(default:Ambient)</td></tr>
        <tr><td>x-doc Service Site:</td><td><select id="service_site" name="service_site">
        <?php
        if(isset($header)){
                if($header->xdss != null){
                        echo '<option value="'.$header->xdss.'">'.$header->servicesite.'</option></select>';
                }else{
                        echo '<option value="">No xDoc Service Site Required</option>';                
                }
        }elseif(isset($ssites)){
                        echo '<option value="">xDoc Service Site</option>';
                foreach($ssites as $s){
                        echo '<option value="'.$s->site_id.'">'.$s->companyname.'</option>';
                }
        }else{
                echo '<option value="">No xDoc Service Site Required</option>';
        }

        ?>
        </select>
        </td></tr>
 </table>
 </div>
 <div id="actions" style="float:right; margin-right:25px;">
        <table>
                <tr><td><input type="button" id="draft" name="draft" Value="Save Draft"/></td><td>E-Mail To Contact:</td><td><input type="text" id="email2" value="<?php if(isset($header)){echo $header->email2;}?>" placeholder="Send Copy To:" readonly size="45"/></td></tr>
                <tr><td><input type="button" id="save" name="save" value="Save and Process"/>&nbsp;&nbsp;&nbsp;</td><td>Additional E-Mail To Send To:&nbsp;</td><td><input type="text" id="addemail" value="<?php if(isset($header)){echo $header->addemail;}?>" placeholder="Additional Copy To:" size="45"/></td></tr>
                <tr><td><input type="button" id="cancel" name="cancel" value="Cancel Order"/></td><td></td><td></td></tr>
        </table>
 </div>
</div>
</form>
 </div>

 <style>
        #left input{
                margin-bottom:5px;
        }
        #order_lines td{
                padding-right:3px;
        }
        td.thickBorder{
                border-bottom: solid grey 1px;
                padding-bottom:2px;
        }

        #data tr:hover {
          background-color: #bfd1d9;
        }
 </style>

 


Thank You all very much for the time taken on this.


Top
 Profile  
 
PostPosted: Sat Feb 13, 2016 2:36 am 
Offline
Forum Newbie

Joined: Thu Feb 11, 2016 1:13 am
Posts: 15
and here is the script.

Syntax: [ Download ] [ Hide ]
  <script>
        $(document).ready(function(){
 
                var pid = '';
                var specials = Array();
                var inclusive = 0;
                var customer = '';
                var site = '';
                var counter = 18;
                var is_timeSite = false;
                var is_cutofftime = '';
                var is_beforeTime = '';
                var is_beforeAction = '';
                var is_afterTime = '';
                var is_afterAction = '';
                var is_delDays = '';           
                var path = "<?php echo base_url('fmcg/get_store/');?>";
                var sizelist = <?php echo json_encode($sizes); ?>;
               
                var specs = <?php echo json_encode($specials)?>;
               
                var elementExists = document.getElementById('timeslot');
               
                $('.dtime').timepicker('setTime', new Date());
                $('.dtime').timepicker({ 'timeFormat': 'H:mm' ,'step': 15,'scrollDefaultNow': true,'forceRoundTime': true});
               
                $(".ddate").datepicker({
                dateFormat: "yy-mm-dd",
                showOtherMonths: true,
                selectOtherMonths: true
        });
         
                if(elementExists != null){
                                        is_cutofftime = $('#cut_off_time').val();
                                        is_beforeTime = $('#before_cutofftime').val();
                                        is_beforeAction = $('#before_deliveryrequired').val();
                                        is_afterTime = $('#after_cutofftime').val();
                                        is_afterAction = $('#after_deliveryrequired').val();
                                        is_delDays = $('#delivery_days').val().split(',');
                                        $('#dd, #dt, #lt').css('color','black');
                                calc_leadtime();
                }
               
                if(elementExists == null && $('#sid').val() != ''){
                                        $('#dd, #dt, #lt').css('color','red');
                                        $('#dd, #dt, #lt').val('');
                                        if(Date.today().add(1).day().is().weekday()){
                                                $('#deltime').val('08:00');
                                        $('#deldate').val(Date.today().add(1).day().toString('yyyy-MM-dd'));
                                        deldate = Date.today().add({days:1,hours:8});
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                                        }else if(Date.today().add(2).day().is().weekday()){
                                                $('#deltime').val('08:00');
                                        $('#deldate').val(Date.today().add(2).day().toString('yyyy-MM-dd'));
                                        deldate = Date.today().add({days:2,hours:8});
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);                                             
                                        }else if(Date.today().add(3).day().is().weekday()){
                                                $('#deltime').val('08:00');
                                        $('#deldate').val(Date.today().add(3).day().toString('yyyy-MM-dd'));
                                        deldate = Date.today().add({days:3,hours:8});
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);                                             
                                        }
                }
               
                $('#add').on('click',function(){
                        counter = $('#order_lines tbody tr').size() + 1;
                        //counter += 1;
                        var newRow = '<tr id="'+counter+'" class="inputs" data-perc="" data-palqty="">';
                        newRow += '<td style="text-align:center;">'+counter+'</td>';
                        newRow += '<td><input type="text" name="productcode[]" class="sku" placeholder="Sku" size="10"/></td>';
                        newRow += '<td><input type="text" class="product" placeholder="Product" size="30"/><input type="hidden" class="cubic"/></td>';
                        newRow += '<td><input type="text" class="weight" placeholder="Weight" size="6" readonly/></td>';
                        newRow += '<td><input type="text" class="temp" placeholder="Temp" size="6" readonly style="display:none;"/></td>';
                        newRow += '<td><input type="text" class="price" placeholder="Price" size="6"/><input type="hidden" class="vatable"/></td>';
                        newRow += '<td><input id="tqty'+counter+'" type="text" class="qty" name="qty[]" placeholder="Qty" size="6" form="orders"/></td>';
                        newRow += '<td><input type="text" class="uom" placeholder="UOM" size="6" readonly/></td>';
                        newRow += '<td><input type="text" class="total" name="total" placeholder="Total" size="6" readonly/></td>';
                        newRow += '<td><input type="button" class="reset" value="X" style="color:red; font-weight: bold; font-size:14px;"/></td>';
                        newRow += '</tr>';
               
            $('#order_lines tbody ').append(newRow);
            $('#products tr:last td:eq(1) select').focus();
            //$('#order_lines tbody tr:last td:eq(1) input').focus();
                        //$(newRow).appendTo('#order_lines tbody');
                });
               
                var oTable = $('#specials').dataTable( {
                        "lengthChange": false,
                        scrollY: 400,
                        "dom": '<"top"f>rt<"bottom"p>',
                        "columns":[{"data":"sku_number"},{"data":"product"},{"data":"price"},{"data":"qty"}]
                });

                if(specs){
                       
                                oTable.fnClearTable();
                                oTable.fnAddData(specs);
                                oTable.fnDraw();       
                }
                               
                $('.display').click(function(){
                        $('#header').slideToggle('slow');
                        $('#content').slideToggle('slow');
                });            

        $("#customer").autocomplete({
                source: function(request, response) {
                    $.ajax({
                        url: "<?php echo base_url('fmcg/get_customers');?>",
                        dataType: "json",
                        data: {
                            term : request.term,
                            pid : $("#pid").val()
                        },
                        success: function(data) {
                            response(data);
                        }
                    });
                },
                select:function(event,ui){
                                var item = ui.item;
                        if(item) {
                                $("#cid").val(item.cid);
                                $('#pid').val(item.pid);
                                customer = item.cid;
                                 }                     
                        },
                min_length: 3,
                delay: 300             
               
        });
       
        $(document).on("keydown.autocomplete",'#store',function(){
                $(this).autocomplete({
                        source: "<?php echo base_url('fmcg/get_store/"+$("#cid").val()+"');?>",
                        minLength: 2,
                        select: function (event, ui) {
                               

                        var item = ui.item;
                        if(item) {

                                $("#sid").val(item.sid);
                                $("#contact").val(item.contact);
                                $('#tel').val(item.tel);
                                $('#email').val(item.email);
                                $('#email2').val(item.email);
                                $('#delline1').val(item.address1);
                                $('#delline2').val(item.address2);
                                $('#yardsize').val(item.yardsize);
                                if(item.timeslot == true){
                                        is_timeSite = true;
                                                is_cutofftime = item.cut_off_time
                                                is_beforeTime = item.before_cutofftime;
                                                is_beforeAction = item.before_deliveryrequired;
                                                is_afterTime = item.after_cutofftime;
                                                is_afterAction = item.after_deliveryrequired;
                                                is_delDays = item.delivery_days.split(',');
                                                $('#dd, #dt, #lt').css('color','black');
                                        calc_leadtime();                                       
                                        }else{
                                                $('#dd, #dt, #lt').css('color','red');
                                                $('#dd, #dt, #lt').val('');
                                                if(Date.today().add(1).day().is().weekday()){
                                                        $('#deltime').val('08:00');
                                                $('#deldate').val(Date.today().add(1).day().toString('yyyy-MM-dd'));
                                                deldate = Date.today().add({days:1,hours:8});
                                                var startdate = new Date();
                                                var enddate = new Date(deldate);
                                                var time_difference = get_time_difference(startdate,enddate);
                                                $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                                                }else if(Date.today().add(2).day().is().weekday()){
                                                        $('#deltime').val('08:00');
                                                $('#deldate').val(Date.today().add(2).day().toString('yyyy-MM-dd'));
                                                deldate = Date.today().add({days:2,hours:8});
                                                var startdate = new Date();
                                                var enddate = new Date(deldate);
                                                var time_difference = get_time_difference(startdate,enddate);
                                                $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);                                             
                                                }else if(Date.today().add(3).day().is().weekday()){
                                                        $('#deltime').val('08:00');
                                                $('#deldate').val(Date.today().add(3).day().toString('yyyy-MM-dd'));
                                                deldate = Date.today().add({days:3,hours:8});
                                                var startdate = new Date();
                                                var enddate = new Date(deldate);
                                                var time_difference = get_time_difference(startdate,enddate);
                                                $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);                                             
                                                }
                                        }
                                        if(item.coldc){
                                                //$('#xdoc_service').css('display','block');
                                                do_service_xdoc_list(item.sid);
                                        }
                                        site = item.sid;
                                        populate_specials();
                                 }
                        }
                });            
        });

                $(document).on("keydown.autocomplete", ".sku", function(){

                         $(this).autocomplete({
                                //source: "<?php echo base_url('fmcg/get_sku/"+$("#sid").val()+"');?>",
                                 source: function( request, response ) {
                                                $.ajax({
                                                        url: "<?php echo base_url('fmcg/get_sku');?>",
                                                        dataType: "json",
                                                        data: {
                                                                q: request.term,
                                                                sid:$('#sid').val(),
                                                                cid:$('#cid').val(),
                                                                dated:$('#deldate').val()
                                                        },
                                                        success: function( data ) {
                                                                response( data );
                                                        }
                                                });
                                        },
                                minLength: 2,
                                autoFocus:true,
                                change: function (event, ui) {//select was original event
                                                                       
                                                trid = $(this).closest('tr').attr('id');

                                        var item = ui.item;
                               
                                        if(item) {
                                                $('#'+trid).data('perc',item.percperlug);
                                                $('#'+trid).data('palqty',item.qtyperpal);
                                                $('#'+trid+' td:eq(2) input.product').val(item.product);
                                                        $('#'+trid+' td:eq(2) input.cubic').val(item.cubic);
                                                        $('#'+trid+' td:eq(3) input.weight').val(item.weight);
                                                        $('#'+trid+' td:eq(4) input.temp').val(item.temp);
                                                        $('#'+trid+' td:eq(7) input.uom').val(item.uom);
                                                        if(item.temp == 'Refrigerated'){
                                                                $('#trucktype').val(item.temp);
                                                        }
                                               

                                                        if(item.raw_price == null && item.special > 0){
       
                                                                        $('#'+trid+' td:eq(5) input.price').val(item.special);
                                                                        $('#'+trid+' td:eq(5) input.price').css('color','green');                                                      
                                                        }else{
                                                                if(item.special != null && parseFloat(item.special) < parseFloat(item.price)){
                                                                        $('#'+trid+' td:eq(5) input.price').val(item.special);
                                                                        $('#'+trid+' td:eq(5) input.price').css('color','green');
                                                                }else{
                                                                        $('#'+trid+' td:eq(5) input.price').val(item.price);
                                                                }                                                      
                                                        }

                                                        if(item.vatable){
                                                                $('#'+trid+' td:eq(5) input.vatable').val(item.vatable);
                                                        }
                                                       
                                                        $('#'+trid+' td:eq(5) input.price').focus();
                                               
                                        }
                                       
                                }
                });
                });            

                $(document).on("keydown.autocomplete", ".product", function(){
                         $(this).autocomplete({
                                //source: "<?php echo base_url('fmcg/get_product/"+$("#sid").val()+"');?>",
                                 source: function( request, response ) {
                                                $.ajax({
                                                        url: "<?php echo base_url('fmcg/get_product');?>",
                                                        dataType: "json",
                                                        data: {
                                                                q: request.term,
                                                                sid:$('#sid').val(),
                                                                cid:$('#cid').val(),
                                                                dated:$('#deldate').val()
                                                        },
                                                        success: function( data ) {
                                                                response( data );
                                                        }
                                                });
                                        },                             
                                minLength: 2,
                                autoFocus:true,
                                change: function (event, ui) {
                                                                       
                                                trid = $(this).closest('tr').attr('id');

                                var item = ui.item;
                                if(item) {
                                        $('#'+trid).data('perc',item.percperlug);
                                        $('#'+trid).data('palqty',item.qtyperpal);
                                                $('#'+trid+' td:eq(1) input.sku').val(item.sku);
                                                $('#'+trid+' td:eq(2) input.cubic').val(item.cubic);
                                                $('#'+trid+' td:eq(3) input.weight').val(item.weight);
                                                $('#'+trid+' td:eq(4) input.temp').val(item.temp);
                                                $('#'+trid+' td:eq(5) input.price').val(item.price);
                                                $('#'+trid+' td:eq(7) input.uom').val(item.uom);
                                                if(item.temp == 'Refrigerated'){
                                                        $('#trucktype').val(item.temp);
                                                }
                                               
                                                if(item.raw_price == null && item.special > 0){

                                                                $('#'+trid+' td:eq(5) input.price').val(item.special);
                                                                $('#'+trid+' td:eq(5) input.price').css('color','green');                                                      
                                                }else{
                                                        if(item.special != null && parseFloat(item.special) < parseFloat(item.price)){
                                                                $('#'+trid+' td:eq(5) input.price').val(item.special);
                                                                $('#'+trid+' td:eq(5) input.price').css('color','green');
                                                        }else{
                                                                $('#'+trid+' td:eq(5) input.price').val(item.price);
                                                        }                                                      
                                                }

                                                if(item.vatable){
                                                        $('#'+trid+' td:eq(5) input.vatable').val(item.vatable);
                                                }
                                               
                                                $('#'+trid+' td:eq(5) input.price').focus();                                   

                                        }
                                }
                });
                });
               
                $(document).on("click",".reset",function(){
                        $(this).closest('tr').remove();
                                inclusive = 0;
                                weight = 0;
                                cubes = 0;
                                vatable = 0;
                               
                                $('#order_lines tbody tr').each(function(){
                                        cqty = $(this).find('td:eq(6) input.qty').val();
                                        cprice = $(this).find('td:eq(5) input.price').val();
                                        cweight =  $(this).find('td:eq(3) input.weight').val();
                                        ccubes = $(this).find('td:eq(2) input.cubic').val();
                                       
                                        if(!isNaN(cqty) && !isNaN(cprice)){
                                                inclusive += ( cqty * cprice );
                                                weight += (cweight * cqty);
                                                cubes += (ccubes * cqty);
                                                if($(this).find('td:eq(5) input.vatable').val() == 'true'){
                                                        vatable += ( cqty * cprice );
                                                }
                                        }
                                });
                                vatamount = vatable * 0.14;
                                //vatamount = inclusive * 0.14;
                                exclusive = inclusive - vatamount;
                                $('#incl_total').html(parseFloat(inclusive).toFixed(2));
                                $('#excl_total').html(parseFloat(exclusive).toFixed(2));
                                $('#vat_total').html(parseFloat(vatamount).toFixed(2));
                                $('#totalweight').html(parseFloat(weight).toFixed(3));
                                $('#totalcubes').html(parseFloat(cubes).toFixed(3));
                               
                                $.each(sizelist,function(i,elem){
                                        if(weight < elem.w_capacity && cubes < elem.v_capacity){
                                                $('#trucksize').val(elem.description);
                                                return false;
                                        }
                                });


                        $('#order_lines tbody tr').each(function(){
                                $(this).prop('id',$(this).index() + 1);
                                $(this).find('td:eq(0)').text(($(this).index() + 1));
                        });
       
                });
               
                $(document).on('focusin','.qty,.price',function(){
                        trid = $(this).closest('tr').attr('id');

                        var thisqty = $('#'+trid+' td:eq(6) input.qty').val();
                        var thisweight = $('#'+trid+' td:eq(3) input.weight').val();
                        var currentweight = parseFloat($('#totalweight').html());
                        var yardsize = $('#yardsize').val();

                        if(isNaN(currentweight)){
                                currentweight = 0;
                        }

                        if(isNaN(thisweight)){
                                thisweight = 0;
                        }

                        if(isNaN(thisqty)){
                                thisqty = 0;
                        }


                        if((thisweight * thisqty) + currentweight > yardsize){
                                                alert('Yard Size Limit Exceeded, Removing Current Item');
                                                $(this).closest('tr').remove();
                        }else if(isNaN($('#'+trid+' td:eq(6) input.qty').val())){
                                alert('Only Numeric Values Are Allowed');
                                        $(this).val('');
                                        $(this).focus();

                         }else{
                        //get site yardsize limit
                        qty = $('#'+trid+' td:eq(6) input.qty').val();
                        price = $('#'+trid+' td:eq(5) input.price').val();
                        //weight = $('#'+trid+' td:eq(3) input.weight').val();
                       
                        if(!isNaN(qty) && !isNaN(price)){
                                $('#'+trid+' td:eq(8) input.total').val(parseFloat(qty * price).toFixed(2));
                                inclusive = 0;
                                weight = 0;
                                cubes = 0;
                                vatable = 0;
                                lugs = 0;
                                pallets = 0;
                               
                                $('#order_lines tbody tr').each(function(){
                                        cqty = $(this).find('td:eq(6) input.qty').val();
                                        cprice = $(this).find('td:eq(5) input.price').val();
                                        cweight =  $(this).find('td:eq(3) input.weight').val();
                                        ccubes = $(this).find('td:eq(2) input.cubic').val();
                                       
                                        if(!isNaN(cqty) && !isNaN(cprice) && !isNaN(cweight) && !isNaN(ccubes)){
                                                inclusive += ( cqty * cprice );
                                                weight += (cweight * cqty);
                                                cubes += (ccubes * cqty);
                                                if($(this).find('td:eq(5) input.vatable').val() == 'true'){
                                                        vatable += ( cqty * cprice );
                                                }
                                               
                                                res = $(this).find('td:eq(7) input.uom').val();
                                                if(res.toUpperCase() == "LUG"){
                                                        lugs = lugs + (1 * cqty);
                                                }

                                                pallets = Math.ceil(cubes/1.9);
                                        }
                                });
                               

                                vatamount = vatable * 0.14;
                                exclusive = inclusive + vatamount;
                                $('#incl_total').html(parseFloat(inclusive).toFixed(2));
                                $('#excl_total').html(parseFloat(exclusive).toFixed(2));
                                $('#vat_total').html(parseFloat(vatamount).toFixed(2));
                                $('#totalweight').html(parseFloat(weight).toFixed(3));
                                $('#totalcubes').html(parseFloat(cubes).toFixed(3));
                                $('#totallugs').html(parseFloat(lugs).toFixed(2));
                                $('#totalpallets').html(parseFloat(pallets).toFixed(0));
                               
                                $.each(sizelist,function(i,elem){
                                        if(weight < elem.w_capacity && cubes < elem.v_capacity){
                                                $('#trucksize').val(elem.description);
                                                return false;
                                        }
                                });
                               
                                var lastrow = $('#order_lines tbody tr:last');
                                if($(lastrow).find('td:eq(1) input.sku').val() != '' ){
                                        $('#add').click();
                                }
                               
                        }
                        }
                       
                });

                $(document).on('focusout','.qty',function(){
                       
                        trid = $(this).closest('tr').attr('id');
                                                //get site yardsize limit
                        qty = $('#'+trid+' td:eq(6) input.qty').val();
                        price = $('#'+trid+' td:eq(5) input.price').val();
                        //weight = $('#'+trid+' td:eq(3) input.weight').val();
                       
                        if(!isNaN(qty) && !isNaN(price)){
                                $('#'+trid+' td:eq(8) input.total').val(parseFloat(qty * price).toFixed(2));
                                inclusive = 0;
                                weight = 0;
                                cubes = 0;
                                vatable = 0;
                                lugs = 0;
                                pallets = 0;
                               
                                $('#order_lines tbody tr').each(function(){
                                        cqty = $(this).find('td:eq(6) input.qty').val();
                                        cprice = $(this).find('td:eq(5) input.price').val();
                                        cweight =  $(this).find('td:eq(3) input.weight').val();
                                        ccubes = $(this).find('td:eq(2) input.cubic').val();
                                       
                                        if(!isNaN(cqty) && !isNaN(cprice) && !isNaN(cweight) && !isNaN(ccubes)){
                                                inclusive += ( cqty * cprice );
                                                weight += (cweight * cqty);
                                                cubes += (ccubes * cqty);
                                                if($(this).find('td:eq(5) input.vatable').val() == 'true'){
                                                        vatable += ( cqty * cprice );
                                                }
                                               
                                                res = $(this).find('td:eq(7) input.uom').val();
                                                if(res.toUpperCase() == "LUG"){
                                                        lugs = lugs + (1 * cqty);
                                                }

                                                pallets = Math.ceil(cubes/1.9);
                                        }
                                });
                               

                                vatamount = vatable * 0.14;
                                exclusive = inclusive + vatamount;
                                $('#incl_total').html(parseFloat(inclusive).toFixed(2));
                                $('#excl_total').html(parseFloat(exclusive).toFixed(2));
                                $('#vat_total').html(parseFloat(vatamount).toFixed(2));
                                $('#totalweight').html(parseFloat(weight).toFixed(3));
                                $('#totalcubes').html(parseFloat(cubes).toFixed(3));
                                $('#totallugs').html(parseFloat(lugs).toFixed(2));
                                $('#totalpallets').html(parseFloat(pallets).toFixed(0));
                               
                                $.each(sizelist,function(i,elem){
                                        if(weight < elem.w_capacity && cubes < elem.v_capacity){
                                                $('#trucksize').val(elem.description);
                                                return false;
                                        }
                                });
                               
                                var lastrow = $('#order_lines tbody tr:last');
                                if($(lastrow).find('td:eq(1) input.sku').val() != '' ){
                                        $('#add').click();
                                }
                               
                        }
                                $('#order_lines tbody tr:last td:eq(1) input').focus();                
                });
               
                $('#draft').click(function(){
                        if($('#service_site').val() == '' && $('#service_site').size() > 1){
                                alert('This is a xDoc Site Collection Site and must have a Collection Point selected');
                        }else{
                        var button = 'draft';
                        $('#save').css('display','none');
                        $('#cancel').css('display','none');
                        $('#draft').css('display','none');
                        skus = Array();
                        prices = Array();
                        qtys = Array();
                        desc = Array();
                        options = Array();
                        options.push($('#order_id').val());
                        options.push($('#pid').val());
                        options.push($('#cid').val());
                        options.push($('#sid').val());
                        options.push($('#version').val());
                        options.push($('#o_time').val());
                        options.push($('#o_date').val());
                        options.push($('#captured').val());
                        options.push($('#delline1').val());
                        options.push($('#delline2').val());
                        options.push($('#deltime').val());
                        options.push($('#deldate').val());
                        options.push($('#leadtime').val());
                        options.push($('#trucksize').val());
                        options.push($('#trucktype').val());
                        options.push($('#email2').val());
                        options.push($('#addemail').val());
                        options.push($('#totalweight').html());
                        options.push($('#totalcubes').html());
                        options.push($('#service_site').val());
                        options.push($('#yardsize').val());
                        options.push($('#totallugs').html());
                        options.push($('#order_no').val());
               

                        $('#order_lines tbody tr').each(function(){
                                trid = $(this).attr('id');
                                if($('#'+trid+' td:eq(1) input.sku').val() != '' && $('#'+trid+' td:eq(5) input.price').val() != '' && $('#'+trid+' td:eq(6) input.qty').val() != ''){
                                                skus.push($('#'+trid+' td:eq(1) input.sku').val());//product sku
                                                prices.push($('#'+trid+' td:eq(5) input.price').val());//price
                                                qtys.push($('#'+trid+' td:eq(6) input.qty').val());    
                                                desc.push($('#'+trid+' td:eq(2) input.product').val());
                                }
                        });
                       
                                var quantity = 0;
                                $('#order_lines tbody tr').each(function(){
                                        if(!isNaN(parseFloat($(this).find('td:eq(6) input.qty').val()))){
                                                quantity = quantity + parseFloat($(this).find('td:eq(6) input.qty').val());
                                        }
                                });
                               
                        options.push(quantity);
                        options.push($('#totalpallets').html());
                        $.post('<?php echo base_url("fmcg/create_order");?>',{'button':button,'skus':skus,'prices':prices,'qtys':qtys,'options':options,'desc':desc},
                        function(response){
                                if (response == true){
                                        window.location = '<?php echo site_url("fmcg/order_history");?>';
                                        //window.location = '<?php echo site_url("fmcg/order_listing");?>';
                                }else{
                                        $('#save').css('display','block');
                                        $('#cancel').css('display','block');
                                        $('#draft').css('display','block');
                                        alert('Operation Failed, Please Contact Administrator!!!');
                                        window.open('<?php echo site_url("auth/login");?>');
                                }              
                        },'json');
                        }
                });
               
                $('#save').click(function(){
                        if($('#order_no').val() == ''){
                                var r = confirm('Order No not supplied, press Ok to continue!\n or Cancel to go back.');
                                if (r != true) {
                                return;
                                }
                        }
                        //$("body").css("cursor", "progress");//wait
                        if($('#service_site').val() == '' && $('#service_site').size() > 1){
                                alert('This is a xDoc Site Collection Site and must have a Collection Point selected');
                        }else{
                        $('#save').css('display','none');
                        $('#cancel').css('display','none');
                        $('#draft').css('display','none');
                        var button = 'save';
                        skus = Array();
                        prices = Array();
                        qtys = Array();
                        desc = Array();
                        options = Array();
                        options.push($('#order_id').val());
                        options.push($('#pid').val());
                        options.push($('#cid').val());
                        options.push($('#sid').val());
                        options.push($('#version').val());
                        options.push($('#o_time').val());
                        options.push($('#o_date').val());
                        options.push($('#captured').val());
                        options.push($('#delline1').val());
                        options.push($('#delline2').val());
                        options.push($('#deltime').val());
                        options.push($('#deldate').val());
                        options.push($('#leadtime').val());
                        options.push($('#trucksize').val());
                        options.push($('#trucktype').val());
                        options.push($('#email2').val());
                        options.push($('#addemail').val());
                        options.push($('#totalweight').html());
                        options.push($('#totalcubes').html());
                        options.push($('#service_site').val());
                        options.push($('#yardsize').val());
                        options.push($('#totallugs').html());
                        options.push($('#order_no').val());

               
                        $('#order_lines tbody tr').each(function(){
                                trid = $(this).attr('id');
                        //alert($('#'+trid+' td:eq(1) input.sku').val());
                                if($('#'+trid+' td:eq(1) input.sku').val() != '' && $('#'+trid+' td:eq(5) input.price').val() != '' && $('#'+trid+' td:eq(6) input.qty').val() != ''){
                                                skus.push($('#'+trid+' td:eq(1) input.sku').val());//product sku
                                                prices.push($('#'+trid+' td:eq(5) input.price').val());//price
                                                qtys.push($('#'+trid+' td:eq(6) input.qty').val());
                                                desc.push($('#'+trid+' td:eq(2) input.product').val());                        
                                }
                        });
                                var quantity = 0;
                                $('#order_lines tbody tr').each(function(){
                                        if(!isNaN(parseFloat($(this).find('td:eq(6) input.qty').val()))){
                                                quantity = quantity + parseFloat($(this).find('td:eq(6) input.qty').val());
                                        }
                                });
                               
                        options.push(quantity);
                        options.push($('#totalpallets').html());
                        $.post('<?php echo base_url("fmcg/create_order");?>',{'button':button,'skus':skus,'prices':prices,'qtys':qtys,'options':options,'desc':desc},
                        function(response){
                                if (response == true){
                                        //window.open('<?php echo site_url("fmcg/order_listing");?>');
                                        //window.location = '<?php echo site_url("fmcg/order_listing");?>';
                                        //$("body").css("cursor", "default");
                                        window.location = '<?php echo site_url("fmcg/confirmation");?>';
                                }else{
                                        $('#save').css('display','block');
                                        $('#cancel').css('display','block');
                                        $('#draft').css('display','block');
                                        alert('Operation Failed, Please Contact Administrator!!!');
                                        window.open('<?php echo site_url("auth/login");?>');
                                }              
                        },'json');
                        }                      
                });
               
                $('#cancel').click(function(){
                        var button = 'cancel';
                        var id = $('#order_id').val();
                        $.post('<?php echo base_url("fmcg/create_order");?>',{'button':button,'id':id},
                        function(response){
                        if (response == true){
                                window.location = '<?php echo site_url("fmcg/order_listing");?>';
                        }                              
                        });                    
                });

                function calc_leadtime(){

                        var has_deldays = false;
                //check delivery days
                        for (var i = 0; i <= is_delDays.length; i++) {
                                if(is_delDays[i] == 'YES'){
                                        has_deldays = true;
                                }
                        };
               
                        if(is_cutofftime < Date.today().setTimeToNow().toString('HH:mm')){//cut off time missed so look at after actions
                       
                                var time = is_afterTime.split(':');
                        switch(is_afterAction){
                                case '1'://same day delivery
                                        $('#deltime').val(is_afterTime);
                                        $('#deldate').val($('#o_date').val());
                                        deldate = Date.today().add({hours:time[0],minutes:time[1]});
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);                             
                                break;
                                ;
                                case '2'://next day delivery
                                        $('#deltime').val(is_afterTime);
                                        $('#deldate').val(Date.today().add(1).day().toString('yyyy-MM-dd'));
                                        deldate = Date.today().add(1).day().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                                       
                                break;
                                ;
                                case '3'://In 2 Days/Or Next Viable Delivery Day
                                    $('#deltime').val(is_afterTime);
                                        $('#deldate').val(Date.today().add(2).day().toString('yyyy-MM-dd'));
                                        deldate = Date.today().add(2).day().add({hours:time[0],minutes:time[1]});
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                                break;
                                ;
                                case '4'://In 3 Days/Or Next Viable Delivery Day
                                    $('#deltime').val(is_afterTime);
                                        $('#deldate').val(Date.today().add(3).day().toString('yyyy-MM-dd'));
                                        deldate = Date.today().add(3).day().add({hours:time[0],minutes:time[1]});
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                                break;
                                ;
                                case '5'://First working day of coming week
                                    $('#deltime').val(is_afterTime);
                                        $('#deldate').val(Date.today().next().monday().toString('yyyy-MM-dd'));
                                        deldate = Date.today().next().monday().add({hours:time[0],minutes:time[1]});
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                                break;
                                ;
                                case '6'://first available selected delivery day, else first available week day
                                        if(has_deldays = true){
                                                        var d = new Date;
                                                        var n = d.getDay();
                                                        var deldate = null;
                                                       
                                                                //check if saturday
                                                                var i = ((n+1) < 7) ? n : 0;
                                                               
                                                                while(is_delDays[i] != 'YES'){
                                                                        i++;
                                                                        if(i == 7){
                                                                                i = 0;
                                                                        }
                                                                }
                                                               
                                                                switch(i){

                                                                        case 0:
                                                                                deldate = Date.today().next().sunday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                                $('#deldate').val(Date.today().next().sunday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;

                                                                        case 1:
                                                                                deldate = Date.today().next().monday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                                $('#deldate').val(Date.today().next().monday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;
                                                                       
                                                                        case 2:
                                                                        deldate = Date.today().next().tuesday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                        $('#deldate').val(Date.today().next().tuesday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;

                                                                        case 3:
                                                                        deldate = Date.today().next().wednesday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                        $('#deldate').val(Date.today().next().wednesday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;

                                                                        case 4:
                                                                        deldate = Date.today().next().thursday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                        $('#deldate').val(Date.today().next().thursday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;

                                                                        case 5:
                                                                        deldate = Date.today().next().friday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                        $('#deldate').val(Date.today().next().friday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;

                                                                        case 6:
                                                                        deldate = Date.today().next().saturday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                        $('#deldate').val(Date.today().next().saturday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;
                                                                }
                                                                $('#deltime').val(is_afterTime);
                                                        var startdate = new Date();
                                                        var enddate = new Date(deldate);
                                                        var time_difference = get_time_difference(startdate,enddate);
                                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);                                                                                                                                             
                                                                                       
                                                }else{
                                                        var d = new Date;
                                                        var n = d.getDay();
                                                        if(n == 5 || n == 6 || n == 0){

                                                $('#deltime').val(is_afterTime);
                                                        $('#deldate').val(Date.today().next().monday().toString('yyyy-MM-dd'));
                                                        deldate = Date.today().next().monday().add({hours:time[0],minutes:time[1]});
                                                        var startdate = new Date();
                                                        var enddate = new Date(deldate);
                                                        var time_difference = get_time_difference(startdate,enddate);
                                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);

                                                        }else{

                                                        $('#deltime').val(is_afterTime);
                                                        $('#deldate').val(Date.today().next().monday().toString('yyyy-MM-dd'));
                                                        deldate = Date.today().add(1).day().add({hours:time[0],minutes:time[1]});
                                                        var startdate = new Date();
                                                        var enddate = new Date(deldate);
                                                        var time_difference = get_time_difference(startdate,enddate);
                                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);

                                                        }                                              
                                                        }
                                        break;
                                        ;
                                        }
                                }else{
                        var time = is_beforeTime.split(':');
                        switch(is_beforeAction){
                                case '1'://same day delivery
                                        $('#deltime').val(is_beforeTime);
                                        $('#deldate').val($('#o_date').val());
                                        deldate = Date.today().add({hours:time[0],minutes:time[1]});
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);  
                                break;
                                ;
                                case '2'://next day delivery
                                        $('#deltime').val(is_afterTime);
                                        $('#deldate').val(Date.today().add(1).day().toString('yyyy-MM-dd'));
                                        deldate = Date.today().add(1).day().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                                       
                                break;
                                ;
                                case '3'://In 2 Days/Or Next Viable Delivery Day
                                    $('#deltime').val(is_afterTime);
                                        $('#deldate').val(Date.today().add(2).day().toString('yyyy-MM-dd'));
                                        deldate = Date.today().add(2).day().add({hours:time[0],minutes:time[1]});
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                                break;
                                ;
                                case '4'://In 3 Days/Or Next Viable Delivery Day
                                    $('#deltime').val(is_afterTime);
                                        $('#deldate').val(Date.today().add(3).day().toString('yyyy-MM-dd'));
                                        deldate = Date.today().add(3).day().add({hours:time[0],minutes:time[1]});
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                                break;
                                ;
                                case '5'://First working day of coming week
                                    $('#deltime').val(is_afterTime);
                                        $('#deldate').val(Date.today().next().monday().toString('yyyy-MM-dd'));
                                        deldate = Date.today().next().monday().add({hours:time[0],minutes:time[1]});
                                        var startdate = new Date();
                                        var enddate = new Date(deldate);
                                        var time_difference = get_time_difference(startdate,enddate);
                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                                break;
                                ;
                                case '6'://first available selected delivery day, else first available week day
                                        if(has_deldays = true){
                                                        var d = new Date;
                                                        var n = d.getDay();
                                                        var deldate = null;
                                                       
                                                                //check if saturday
                                                                var i = ((n+1) < 7) ? n : 0;
                                                               
                                                                while(is_delDays[i] != 'YES'){
                                                                        i++;
                                                                        if(i == 7){
                                                                                i = 0;
                                                                        }
                                                                }
                                                               
                                                                switch(i){

                                                                        case 0:
                                                                                deldate = Date.today().next().sunday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                                $('#deldate').val(Date.today().next().sunday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;

                                                                        case 1:
                                                                                deldate = Date.today().next().monday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                                $('#deldate').val(Date.today().next().monday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;
                                                                       
                                                                        case 2:
                                                                        deldate = Date.today().next().tuesday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                        $('#deldate').val(Date.today().next().tuesday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;

                                                                        case 3:
                                                                        deldate = Date.today().next().wednesday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                        $('#deldate').val(Date.today().next().wednesday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;

                                                                        case 4:
                                                                        deldate = Date.today().next().thursday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                        $('#deldate').val(Date.today().next().thursday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;

                                                                        case 5:
                                                                        deldate = Date.today().next().friday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                        $('#deldate').val(Date.today().next().friday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;

                                                                        case 6:
                                                                        deldate = Date.today().next().saturday().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                                                                        $('#deldate').val(Date.today().next().saturday().toString('yyyy-MM-dd'));
                                                                        break;
                                                                        ;
                                                                }
                                                                $('#deltime').val(is_afterTime);
                                                        var startdate = new Date();
                                                        var enddate = new Date(deldate);
                                                        var time_difference = get_time_difference(startdate,enddate);
                                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);                                                                                                                                             
                                                                                       
                                                }else{
                                                        var d = new Date;
                                                        var n = d.getDay();
                                                        if(n == 5 || n == 6 || n == 0){

                                                $('#deltime').val(is_afterTime);
                                                        $('#deldate').val(Date.today().next().monday().toString('yyyy-MM-dd'));
                                                        deldate = Date.today().next().monday().add({hours:time[0],minutes:time[1]});
                                                        var startdate = new Date();
                                                        var enddate = new Date(deldate);
                                                        var time_difference = get_time_difference(startdate,enddate);
                                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);

                                                        }else{

                                                        $('#deltime').val(is_afterTime);
                                                        $('#deldate').val(Date.today().next().monday().toString('yyyy-MM-dd'));
                                                        deldate = Date.today().add(1).day().add({hours:time[0],minutes:time[1]});
                                                        var startdate = new Date();
                                                        var enddate = new Date(deldate);
                                                        var time_difference = get_time_difference(startdate,enddate);
                                                        $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);

                                                        }                                              
                                                }
                                break;
                                ;
                                }                              
                        }
                }
       
                function get_time_difference(start,end){              
                start = new Date(start);
                end = new Date(end);
                var diff = end.getTime() - start.getTime();                
                var time_difference = new Object();

                time_difference.hours = Math.floor(diff/1000/60/60);        
                diff -= time_difference.hours*1000*60*60;
                if(time_difference.hours < 10) time_difference.hours = "0" + time_difference.hours;

                time_difference.minutes = Math.floor(diff/1000/60);    
                diff -= time_difference.minutes*1000*60;    
                if(time_difference.minutes < 10) time_difference.minutes = "0" + time_difference.minutes;                                  

                    return time_difference;              
                }

                function populate_specials(){
                        $('#data').empty();
                        $.post('<?php echo base_url("fmcg/get_specials");?>',{'id':site,'dated':$('#deldate').val()},
                        function(result){
                                if(result){
                                        oTable.fnClearTable();
                                        oTable.fnAddData(result);
                                        oTable.fnDraw();                               
                                }
                        },'json');
                }

                $(document).on('dblclick','#data tr',function(){

                        trid = $('#order_lines tbody tr:last-child').attr('id');
                        $.post('<?php echo base_url("fmcg/get_product_by_sku")?>',{'sku':$(this).find('td:eq(0)').text()},
                        function(data){
                                $.each(data,function(key,val){
                                        if($('#order_lines tbody tr:last-child').find('td:eq(2) input.product').val() == ''){
                                               
                                        $('#'+trid).data('perc',val.percperlug);
                                                $('#'+trid+' td:eq(1) input.sku').val(val.sku);
                                                $('#'+trid+' td:eq(2) input.product').val(val.product);
                                                $('#'+trid+' td:eq(2) input.cubic').val(val.cubic);
                                                $('#'+trid+' td:eq(3) input.weight').val(val.weight);
                                                $('#'+trid+' td:eq(4) input.temp').val(val.temp);
                                                $('#'+trid+' td:eq(7) input.uom').val(val.uom);
                                                if(val.temp == 'Refrigerated'){
                                                        $('#trucktype').val(val.temp);
                                                }

                                                if(val.special != null && (parseFloat(val.special) < parseFloat(val.price) || parseFloat(val.price) != null)){
                                                        $('#'+trid+' td:eq(5) input.price').val(val.special);
                                                        $('#'+trid+' td:eq(5) input.price').css('color','green');
                                                }else{
                                                        $('#'+trid+' td:eq(5) input.price').val(val.price);
                                                }                                              
                                        }else{
                                               
                                        }
                                });
                        },'json');

                });

                function do_service_xdoc_list(id){
                        $.ajax({
                                url:'<?php echo base_url("fmcg/get_servicesites");?>',
                                type:'post',
                                dataType:'json',
                                data:{
                                        customer_id:$('#cid').val(),
                                },
                                success:function(data){
                                        content = '<option value="">Xdoc Service Site</option>';
                                                $.each(data,function(key,val){
                                                        content += '<option value="'+val.site_id+'">'+val.companyname+'</option>';
                                                });
                                        $('#service_site').empty();
                                        $('#service_site').append(content);    
                                }
                               
                        });
                };
        });


 </script>


Top
 Profile  
 
PostPosted: Sat Feb 13, 2016 12:55 pm 
Offline
Site Administrator
User avatar

Joined: Wed Aug 25, 2004 7:54 pm
Posts: 13459
Location: New York, NY, US
Seeing the code is definitely informative. And your interviewer's comments about Separation of Concerns was probably not very helpful because it is too general and probably too advanced.

The two concepts that first come to mind when I look at this code are: 1) good old Structured Programming and 2) DRY (don't repeat yourself). Those two concepts really go together -- DRY being the goal, and Structured Programming being the means. The thing I see the most of above is a lot of duplication of very similar pieces of code. Basic encapsulation of the code into functions and the HTML into templates would have revealed that and lead to more reuse.

If we were pair programming, one of the first refactoring questions I would ask is: What are the states of this code? What are header, custonly, prepop, is_afterAction, etc. that cause so much duplication in this code? I definitely think you need to develop a much more Agile attitude to developing. Maybe not as extreme as Test First, but definitely identifying the priority and best practice solution, developing a running version, and spiraling through development refactoring as needed.

_________________
(#10850)


Top
 Profile  
 
PostPosted: Sun Feb 14, 2016 1:03 am 
Offline
Forum Newbie

Joined: Thu Feb 11, 2016 1:13 am
Posts: 15
Thanks for reply.
When I looked at this example, I was wondering the same thing if I had not regurgitated the same piece of code myself.

The header, custonly, prepop, is_afterAction, variables pertain to the current state of the order.
a.) header being a brand new order with no info captured. Meaning I have to allow for access to all drop down menu options etc.
b.) custonly means it is the customer creating the order and therefore some defaults are passed from controller. ie who the principle is, the customer is and their site information.
c.)prepop is a case of the order being pulled up for editing purposes with almost everything completed and the user adding new items etc.
d.) is_afteraction, right now not able to remember what this was for ;)

Ideas. ;)

Thanks All


Top
 Profile  
 
PostPosted: Sun Feb 14, 2016 1:43 pm 
Offline
Site Administrator
User avatar

Joined: Wed Aug 25, 2004 7:54 pm
Posts: 13459
Location: New York, NY, US
I'd be interested to also hear what Celauran, requinix or others have to say about this code. They will have more insights and recommendations.
terenceb wrote:
The header, custonly, prepop, is_afterAction, variables pertain to the current state of the order.
a.) header being a brand new order with no info captured. Meaning I have to allow for access to all drop down menu options etc.
b.) custonly means it is the customer creating the order and therefore some defaults are passed from controller. ie who the principle is, the customer is and their site information.
c.)prepop is a case of the order being pulled up for editing purposes with almost everything completed and the user adding new items etc.
d.) is_afteraction, right now not able to remember what this was for ;)
A minor point, but they fact that these had to be explained is a problem. A general Best Practice is good Naming Conventions. This is includes general conventions and recommendations (https://www.google.com/#q=software+code ... onventions) and high level naming concepts like Ubiquitous Language.

Beyond the naming, the next question I have is whether these are initialization states or are variations on what is presented to the user? I ask because my concept of a form is that it is populated with values and then submitted until valid. The initial value may be blank/default values or existing data to be edited, but the form does not really care which -- it only cares about whether the submitted values are all valid based on the rules of the form.

A separate question is how to deal with parts of the form that appear or not under different conditions. I typically still initialize all values, but change the validation rules of field that do not appear.

I pulled out an example if this from your code. Here is a section that shows these four nearly identical states:
Syntax: [ Download ] [ Hide ]
<!-- middle block with order revision number etc -->
<?php
        if(isset($header)){
        echo '<div id="middle" style="width:25%; float:left;">';
        echo '<table>';
        echo '<tr><td>Order Version:</td><td><input type="text" id="version" value="'.($header->version + 1).'" readonly size="5"/></td></tr>';
        echo '<tr><td>Time Of Order:&nbsp;&nbsp;</td><td><input type="text" id="o_time" name="o_time" value="'.date('H:i').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Date Of Order:</td><td><input type="text" id="o_date" name="o_date" value="'.date('Y-m-d').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Captured By:</td><td><input type="text" id="captured" value="'.$header->captured.'" readonly size="15"/></td></tr>';
        echo '<tr><td>Order No:</td><td><input type="text" id="order_no" value="'.$header->order_no.'" size="15"/></td></tr>';
        echo '</table>';
        echo '</div><!--header middle panel-->';
        }else if(isset($custonly)){
        echo '<div id="middle" style="width:25%; float:left;">';
        echo '<table>';
        echo '<tr><td>Order Version:</td><td><input type="text" id="version" value="1" readonly size="5"/></td></tr>';
        echo '<tr><td>Time Of Order:&nbsp;&nbsp;</td><td><input type="text" id="o_time" name="o_time" value="'.date('H:i').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Date Of Order:</td><td><input type="text" id="o_date" name="o_date" value="'.date('Y-m-d').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Captured By:</td><td><input type="text" id="captured" value="'.$userid.'" readonly size="15"/></td></tr>';
        echo '<tr><td>Order No:</td><td><input type="text" id="order_no" size="15"/></td></tr>';
        echo '</table>';
        echo '</div><!--header middle panel-->';
        }else if(isset($prepop)){
        echo '<div id="middle" style="width:25%; float:left;">';
        echo '<table>';
        echo '<tr><td>Order Version:</td><td><input type="text" id="version" value="1" readonly size="5"/></td></tr>';
        echo '<tr><td>Time Of Order:&nbsp;&nbsp;</td><td><input type="text" id="o_time" name="o_time" value="'.date('H:i').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Date Of Order:</td><td><input type="text" id="o_date" name="o_date" value="'.date('Y-m-d').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Captured By:</td><td><input type="text" id="captured" value="'.$userid.'" readonly size="15"/></td></tr>';
        echo '<tr><td>Order No:</td><td><input type="text" id="order_no" size="15"/></td></tr>';
        echo '</table>';
        echo '</div><!--header middle panel-->';
        }else{
        echo '<div id="middle" style="width:25%; float:left;">';
        echo '<table>';
        echo '<tr><td>Order Version:</td><td><input type="text" id="version" value="1" readonly size="5"/></td></tr>';
        echo '<tr><td>Time Of Order:&nbsp;&nbsp;</td><td><input type="text" id="o_time" name="o_time" value="'.date('H:i').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Date Of Order:</td><td><input type="text" id="o_date" name="o_date" value="'.date('Y-m-d').'" readonly size="10"/></td></tr>';
        echo '<tr><td>Captured By:</td><td><input type="text" id="captured" value="'.$userid.'" readonly size="15"/></td></tr>';
        echo '<tr><td>Order No:</td><td><input type="text" id="order_no" size="15"/></td></tr>';
        echo '</table>';
        echo '</div><!--header middle panel-->';       
        }
?>
 

Here is more how I would think about separate Domain and Presentation parts:
Syntax: [ Download ] [ Hide ]
<!-- middle block with order revision number etc -->
#
# Domain code
#
        if(isset($header)){
                $form['version'] = $header->version + 1;
                $form['o_time'] = date('H:i');
                $form['o_date'] = date('Y-m-d');
                $form['captured'] = $header->captured;
                $form['order_no'] = $header->order_no;
        }else if(isset($custonly)){
                $form['version'] = 1;
                $form['o_time'] = date('H:i');
                $form['o_date'] = date('Y-m-d');
                $form['captured'] = $userid;
                $form['order_no'] = '';
        }else if(isset($prepop)){
                $form['version'] = 1;
                $form['o_time'] = date('H:i');
                $form['o_date'] = date('Y-m-d');
                $form['captured'] = $userid;
                $form['order_no'] = '';
        }else{
                $form['version'] = 1;
                $form['o_time'] = date('H:i');
                $form['o_date'] = date('Y-m-d');
                $form['captured'] = $userid;
                $form['order_no'] = '';
        }
#
# Presentation code
#
        echo '<div id="middle" style="width:25%; float:left;">';
        echo '<table>';
        echo '<tr><td>Order Version:</td><td><input type="text" id="version" name="version" value="' . $form['version'] . '" readonly size="5"/></td></tr>';
        echo '<tr><td>Time Of Order:&nbsp;&nbsp;</td><td><input type="text" id="o_time" name="o_time" value=' . $form['o_time'] . '" readonly size="10"/></td></tr>';
        echo '<tr><td>Date Of Order:</td><td><input type="text" id="o_date" name="o_date" value="' . $form['o_date'] . '" readonly size="10"/></td></tr>';
        echo '<tr><td>Captured By:</td><td><input type="text" id="captured" name="captured" value="' . $form['captured'] . '" readonly size="15"/></td></tr>';
        echo '<tr><td>Order No:</td><td><input type="text" id="order_no" name="order_no" value="' . $form['order_no'] . '" size="15"/></td></tr>';
        echo '</table>';
        echo '</div><!--header middle panel-->';       
 

You can see this has simplified the code, separated the Domain and Presentation (i.e., "Concerns"), and in doing that revealed that the Domain can be further simplified to:
Syntax: [ Download ] [ Hide ]
<!-- middle block with order revision number etc -->
#
# Domain code
#
        $form['version'] = 1;
        $form['o_time'] = date('H:i');
        $form['o_date'] = date('Y-m-d');
        $form['captured'] = '';
        $form['order_no'] = '';
        if(isset($header)){
                $form['version'] += $header->version;
                $form['captured'] = $header->captured;
                $form['order_no'] = $header->order_no;
        } else {
                $form['captured'] = $userid;
        }

This same kind of refactoring can be done throughout this code. You will want to learn more about refactoring, because you want to make the change methodically. When refactoring, it is best to make small, testable changes so the code keeps working correctly after each change.

So a first phase would be to simplify this code so that it is procedural code where it is much clearer to see what is going. Once you are to that point, it could make sense to further refactor the code into separate classes and templates. E.g.:
Syntax: [ Download ] [ Hide ]
$form = $formModel->getValues();
$template->set('form', $form);
$template->show();

_________________
(#10850)


Top
 Profile  
 
PostPosted: Mon Feb 15, 2016 6:32 am 
Offline
Forum Newbie

Joined: Thu Feb 11, 2016 1:13 am
Posts: 15
Leaving this edit open so I can kick myself in the butt. for not thinking like that lol.


Top
 Profile  
 
PostPosted: Mon Feb 15, 2016 7:40 am 
Offline
Moderator
User avatar

Joined: Tue Nov 09, 2010 3:39 pm
Posts: 6404
Location: Montreal, Canada
Christopher has already tackled the real meat of the matter in getting rid of a lot of duplication. Let me grab some of the low-hanging fruit first. You've got JS and CSS mixed in with your view. Let's clear that out first off. That's really just a matter of moving those blocks of code into existing style sheets or JS files and ensuring they're being loaded on this request. Further, take Christopher's approach to your PHP here and apply it to your JS. Get rid of duplication there as much as possible, also. While you're cleaning that up, you should also consider getting rid of the inline styling you have littered about the form. You presumably already have dedicated CSS files, so create a few classes if you need to and clean up the view a little more. If ever you want to change the styling, you'll need to do it in fewer places.

_________________
Supported PHP versions No longer supported versions


Top
 Profile  
 
PostPosted: Mon Feb 15, 2016 9:03 am 
Offline
Moderator
User avatar

Joined: Tue Nov 09, 2010 3:39 pm
Posts: 6404
Location: Montreal, Canada
Syntax: [ Download ] [ Hide ]
        $('#dd, #dt, #lt').css('color','red');
        $('#dd, #dt, #lt').val('');
        if(Date.today().add(1).day().is().weekday()){
            $('#deltime').val('08:00');
            $('#deldate').val(Date.today().add(1).day().toString('yyyy-MM-dd'));
            deldate = Date.today().add({days:1,hours:8});
            var startdate = new Date();
            var enddate = new Date(deldate);
            var time_difference = get_time_difference(startdate,enddate);
            $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
        }else if(Date.today().add(2).day().is().weekday()){
            $('#deltime').val('08:00');
            $('#deldate').val(Date.today().add(2).day().toString('yyyy-MM-dd'));
            deldate = Date.today().add({days:2,hours:8});
            var startdate = new Date();
            var enddate = new Date(deldate);
            var time_difference = get_time_difference(startdate,enddate);
            $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);                                            
        }else if(Date.today().add(3).day().is().weekday()){
            $('#deltime').val('08:00');
            $('#deldate').val(Date.today().add(3).day().toString('yyyy-MM-dd'));
            deldate = Date.today().add({days:3,hours:8});
            var startdate = new Date();
            var enddate = new Date(deldate);
            var time_difference = get_time_difference(startdate,enddate);
            $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);                                            
 

Each of those blocks are mostly the same.


Syntax: [ Download ] [ Hide ]
    $(document).on("keydown.autocomplete", ".sku", function(){

        $(this).autocomplete({
            //source: "<?php echo base_url('fmcg/get_sku/"+$("#sid").val()+"');?>",
            source: function( request, response ) {
                $.ajax({
                    url: "<?php echo base_url('fmcg/get_sku');?>",
                    dataType: "json",
                    data: {
                        q: request.term,
                        sid:$('#sid').val(),
                        cid:$('#cid').val(),
                        dated:$('#deldate').val()
                    },
                    success: function( data ) {
                        response( data );
                    }
                });
            },
            minLength: 2,
            autoFocus:true,
            change: function (event, ui) {//select was original event

                trid = $(this).closest('tr').attr('id');

                var item = ui.item;

                if(item) {
                    $('#'+trid).data('perc',item.percperlug);
                    $('#'+trid).data('palqty',item.qtyperpal);
                    $('#'+trid+' td:eq(2) input.product').val(item.product);
                    $('#'+trid+' td:eq(2) input.cubic').val(item.cubic);
                    $('#'+trid+' td:eq(3) input.weight').val(item.weight);
                    $('#'+trid+' td:eq(4) input.temp').val(item.temp);
                    $('#'+trid+' td:eq(7) input.uom').val(item.uom);
                    if(item.temp == 'Refrigerated'){
                        $('#trucktype').val(item.temp);
                    }


                    if(item.raw_price == null && item.special > 0){

                        $('#'+trid+' td:eq(5) input.price').val(item.special);
                        $('#'+trid+' td:eq(5) input.price').css('color','green');                                                      
                    }else{
                        if(item.special != null && parseFloat(item.special) < parseFloat(item.price)){
                            $('#'+trid+' td:eq(5) input.price').val(item.special);
                            $('#'+trid+' td:eq(5) input.price').css('color','green');
                        }else{
                            $('#'+trid+' td:eq(5) input.price').val(item.price);
                        }                                                      
                    }

                    if(item.vatable){
                        $('#'+trid+' td:eq(5) input.vatable').val(item.vatable);
                    }

                    $('#'+trid+' td:eq(5) input.price').focus();

                }

            }
        });
 

This whole block is repeated elsewhere in the script.

Syntax: [ Download ] [ Hide ]
    $('#draft').click(function(){
        if($('#service_site').val() == '' && $('#service_site').size() > 1){
            alert('This is a xDoc Site Collection Site and must have a Collection Point selected');
        }else{
            var button = 'draft';
            $('#save').css('display','none');
            $('#cancel').css('display','none');
            $('#draft').css('display','none');
            skus = Array();
            prices = Array();
            qtys = Array();
            desc = Array();
            options = Array();
            options.push($('#order_id').val());
            options.push($('#pid').val());
            options.push($('#cid').val());
            options.push($('#sid').val());
            options.push($('#version').val());
            options.push($('#o_time').val());
            options.push($('#o_date').val());
            options.push($('#captured').val());
            options.push($('#delline1').val());
            options.push($('#delline2').val());
            options.push($('#deltime').val());
            options.push($('#deldate').val());
            options.push($('#leadtime').val());
            options.push($('#trucksize').val());
            options.push($('#trucktype').val());
            options.push($('#email2').val());
            options.push($('#addemail').val());
            options.push($('#totalweight').html());
            options.push($('#totalcubes').html());
            options.push($('#service_site').val());
            options.push($('#yardsize').val());
            options.push($('#totallugs').html());
            options.push($('#order_no').val());


            $('#order_lines tbody tr').each(function(){
                trid = $(this).attr('id');
                if($('#'+trid+' td:eq(1) input.sku').val() != '' && $('#'+trid+' td:eq(5) input.price').val() != '' && $('#'+trid+' td:eq(6) input.qty').val() != ''){
                    skus.push($('#'+trid+' td:eq(1) input.sku').val());//product sku
                    prices.push($('#'+trid+' td:eq(5) input.price').val());//price
                    qtys.push($('#'+trid+' td:eq(6) input.qty').val());    
                    desc.push($('#'+trid+' td:eq(2) input.product').val());
                }
            });

            var quantity = 0;
            $('#order_lines tbody tr').each(function(){
                if(!isNaN(parseFloat($(this).find('td:eq(6) input.qty').val()))){
                    quantity = quantity + parseFloat($(this).find('td:eq(6) input.qty').val());
                }
            });
            // more

This entire block of code is repeated

Syntax: [ Download ] [ Hide ]
            var time = is_afterTime.split(':');
            switch(is_afterAction){
                case '1'://same day delivery
                    $('#deltime').val(is_afterTime);
                    $('#deldate').val($('#o_date').val());
                    deldate = Date.today().add({hours:time[0],minutes:time[1]});
                    var startdate = new Date();
                    var enddate = new Date(deldate);
                    var time_difference = get_time_difference(startdate,enddate);
                    $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);                            
                    break;
                    ;
                case '2'://next day delivery
                    $('#deltime').val(is_afterTime);
                    $('#deldate').val(Date.today().add(1).day().toString('yyyy-MM-dd'));
                    deldate = Date.today().add(1).day().add({hours:time[0],minutes:time[1]});//.toString('yyyy-MM-dd HH:mm');
                    var startdate = new Date();
                    var enddate = new Date(deldate);
                    var time_difference = get_time_difference(startdate,enddate);
                    $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);

                    break;
                    ;
                case '3'://In 2 Days/Or Next Viable Delivery Day
                    $('#deltime').val(is_afterTime);
                    $('#deldate').val(Date.today().add(2).day().toString('yyyy-MM-dd'));
                    deldate = Date.today().add(2).day().add({hours:time[0],minutes:time[1]});
                    var startdate = new Date();
                    var enddate = new Date(deldate);
                    var time_difference = get_time_difference(startdate,enddate);
                    $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                    break;
                    ;
                case '4'://In 3 Days/Or Next Viable Delivery Day
                    $('#deltime').val(is_afterTime);
                    $('#deldate').val(Date.today().add(3).day().toString('yyyy-MM-dd'));
                    deldate = Date.today().add(3).day().add({hours:time[0],minutes:time[1]});
                    var startdate = new Date();
                    var enddate = new Date(deldate);
                    var time_difference = get_time_difference(startdate,enddate);
                    $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                    break;
                    ;
                case '5'://First working day of coming week
                    $('#deltime').val(is_afterTime);
                    $('#deldate').val(Date.today().next().monday().toString('yyyy-MM-dd'));
                    deldate = Date.today().next().monday().add({hours:time[0],minutes:time[1]});
                    var startdate = new Date();
                    var enddate = new Date(deldate);
                    var time_difference = get_time_difference(startdate,enddate);
                    $('#leadtime').val(time_difference.hours + ":" + time_difference.minutes);
                    break;
                    ;
 

Each of these cases is basically the same.

Plenty of room to reduce duplication here. I'm also seeing a lot of PHP echo statements in your JS. You want to eliminate that as well. If it's specific to a single view, you can declare those in a short script tag at the bottom of the view.

_________________
Supported PHP versions No longer supported versions


Top
 Profile  
 
PostPosted: Mon Feb 15, 2016 12:28 pm 
Offline
Site Administrator
User avatar

Joined: Wed Aug 25, 2004 7:54 pm
Posts: 13459
Location: New York, NY, US
Celauran has a ton of clear recommendations for improvements. Remember, when refactoring make small changes and keep the code always working. If the code is running you will have confidence to make the next change. Small change, test, small change, test...
terenceb wrote:
Leaving this edit open so I can kick myself in the butt. for not thinking like that lol.

You make the mistake of thinking that software development is intuitive -- it's not. Many great minds have developed the best practices we have today after trying the obvious and failing. We just stand on the shoulders of giants. The problem with learning software development is that you have to prove that intuitive solutions don't work well before you can be open to embracing many best practices. You now have that valuable knowledge about the WHY of some of these basic best practices.

_________________
(#10850)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 21 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group