Просмотр исходного кода

staff wages can be calculated on start up

master
patrick 6 лет назад
Родитель
Сommit
0ff21dd013
5 измененных файлов: 272 добавлений и 71 удалений
  1. +20
    -2
      css/bts_timesheet.css
  2. +14
    -1
      html/job.html
  3. +4
    -3
      html/staff.html
  4. +232
    -65
      js/bts_timesheet.js
  5. +2
    -0
      ts.php

+ 20
- 2
css/bts_timesheet.css Просмотреть файл

@@ -661,14 +661,24 @@ div.blueTable.emptyrecord{
}

.divTable.highlight{
box-shadow: 1px 1px 10px green;
}

.divTable.invalidjob.highlight{
box-shadow: 1px 1px 10px #f50202;
}


.divTableRow {
display: table-row;
}

.divTableRow.errmsg{
background-color:white;
font-weight:bolder;
color:red;
}

.divTableHeading {
display: table-header-group;
}
@@ -760,7 +770,15 @@ div.btos select,
div.bstart input,
div.bfinish input{
width: 100%;
height: 100%;
height: 98%;
}

div.divTable.validjob{
border: 0px solid white;
}

div.divTable.invalidjob{
border-left: 2px solid red;
border-right: 2px solid red;
}
/* end of div table */

+ 14
- 1
html/job.html Просмотреть файл

@@ -24,7 +24,20 @@
<div class="divTableCell bsave saved">
<span class="ticon ticon-save"></span>
</div>
</div>
<div class="divTableRow errmsg">
<div class="divTableCell btos_err"> e tos
</div>
<div class="divTableCell bstart_err">es</div>
<div class="divTableCell bfinish_err">ef</div>
<div class="divTableCell brate_err">er</div>
<div class="divTableCell bstaff_err">estaf</div>
<div class="divTableCell bclient_err">ecli</div>
<div class="divTableCell bconfirmed_err">econfirm</div>
<div class="divTableCell brating_err">erat</div>
<div class="divTableCell bdelete_err">edel</div>
<div class="divTableCell bsave_err">eeave</div>
</div>
</div>
</div>

+ 4
- 3
html/staff.html Просмотреть файл

@@ -2,11 +2,12 @@
<label class='peopleitem' data-id=p{{login}} > <input type="checkbox"/>
<div class="card">
<div class="front">
<span name='iccon' class='ticon ticon-user'></span> <span
<span
name='badge' class='badge blue'><a href="/pending-jobs/{{login}}"></a>{{unconfirmedjob}}</span>
<div name='title'><a href='/user/{{login}}' target="_blank"> {{firstname}},{{lastname}} </a></div>
<div name='wages'>${{wages}} ({{hour}}hr + {{OT}}hr)</div>
<div name='patrol'>petrol:{{petrol}} km</div>
<div name='wages'>${{wages}} </div>
<div name='hours'>({{hour}}+{{OT}}hr)</div>
<div name='petrol'>petrol:{{petrol}} km</div>
</div>
<div class="back">
<span name='badge' class='badge pink'><a href="/pending-jobs/{{login}}">{{unconfirmedjob}}</a></span> <span

+ 232
- 65
js/bts_timesheet.js Просмотреть файл

@@ -1,5 +1,6 @@
(function ($) {
$(function () {
// http://davidwalsh.name/javascript-debounce-function
function debounce(func, wait, immediate) {
var timeout;
@@ -43,7 +44,7 @@
var html = Mustache.render(template, data);
$(this.selector).html(html);
//save it
$(this.selector).data(data);
$(this.selector).data({obj:this, data:data});
//draw rating star
this.set_ratings(this.data.rating);
this.set_unconfirmed_job(this.data.unconfirmedjob);
@@ -68,6 +69,38 @@
this.data.unconfirmedjob = num;
}
reset_summary() {
this.summary = {
wages : 0,
normal_hour : 0,
ot_hour : 0,
petrol : 0,
};
this.update_summary_in_gui();
}
add_payment_summary(ps)
{
//{ot: false, hour: "2.67", money: "76.90"}
this.summary.wages += ps.money;
if (! ps.ot )
this.summary.normal_hour += ps.hour;
else
this.summary.ot_hour += ps.hour;
this.update_summary_in_gui();
}
update_summary_in_gui()
{
var msg = '$' + this.summary.wages.toFixed(2);
$(this.selector).find('div[name="wages"]').html(msg);
msg = this.summary.normal_hour.toFixed(2) + '+' +this.summary.ot_hour.toFixed(2) + 'hr';
$(this.selector).find('div[name="hours"]').html(msg);
msg = 'petrol:' + this.summary.petrol.toFixed(2) + 'km';
$(this.selector).find('div[name="petrol"]').html(msg);
}
}//end of class People
function bts_staff_html(data){
@@ -112,12 +145,13 @@
action: "list_staff", // action
}, function(response, status, xhr){
if (response.status =='success'){
hide_loading_staff();
response.users.forEach(function(u){
var html = bts_staff_html(u);
jQuery('div.stafflist').append(html);
new People("#p" + u.login,'#staff_item', u);
});
hide_loading_staff();
calculate_total_working_hour();
}else{
alert('error getting staff list');
}
@@ -209,26 +243,6 @@
return selector;
}
function init_ts(){
list_staff();
list_clients();
xero(false);
wifi(false);
init_user_search();
ajax_earning_rate();
}
function ajax_earning_rate(){
$.post(bts().ajax_url, { // POST request
_ajax_nonce: bts().nonce, // nonce
action: "earnings_rate", // action
}, function(response, status, xhr){
bts().earnings_rate = response;
console.log("%o", bts().earnings_rate);
});
}
init_ts();
$(document).on('click', 'div.divTableHead.bdelete', function(){
var o = new Job({empty:true});
@@ -275,7 +289,7 @@
});
$(document).on('click', 'span.ticon.ticon-save', function(){
var table = $(this).closest('div.divTable')
var table = $(this).closest('div.divTable');
table.data().job.do_save_record();
});
@@ -333,8 +347,9 @@
else{
this.mark_saved();
}
this.mark_week_color();
console.log('this job money = %o', this.get_payment_summary());
this.validate();
}
get_job_id(){
@@ -520,11 +535,100 @@
validate()
{
if (this.is_finish_resonable()){
this.el.addClass('validjob');
this.clear_err_msg();
var ok = this.validate_start() &&
this.validate_finish() &&
this.validate_rate();
if (ok){
this.el.removeClass('invalidjob');
}else{
this.el.addClass('invalidjob');
}
return ok;
}
validate_start(){
var str = this.get_start();
if ( is_valid_date_str(str) ){
this.mark_start_valid();
this.set_err_msg_start('');
return true;
}else{
this.mark_start_invalid();
this.set_err_msg_start('wrong date');
return false;
}
}
validate_finish()
{
var str = this.get_finish();
if (! is_valid_date_str(str)){
this.set_err_msg_finish('wront date');
this.mark_finish_invalid();
return false;
}
if (!this.is_finish_resonable()){
this.set_err_msg_finish("older than start")
this.mark_finish_invalid();
return false;
}
this.mark_finish_valid();
this.set_err_msg_finish('');
return true;
}
validate_rate()
{
var rate_info = this.get_rate_info_by_id(this.get_rate());
if ( rate_info.RatePerUnit <= 0){
this.set_err_msg_rate('bad rate');
this.mark_rate_invalid();
return false;
}
this.set_err_msg_rate('');
this.mark_rate_valid();
return true;
}
clear_err_msg(){
this.el.find('.divTableRow.errmsg > div').html('');
}
set_err_msg_start(str)
{
this.el.find('div.bstart_err').html(str);
}
set_err_msg_finish(str)
{
this.el.find('div.bfinish_err').html(str);
}
set_err_msg_rate(str)
{
this.el.find('div.brate_err').html(str);
}
set_err_msg_save(str)
{
this.el.find('div.bsave_err').html(str);
}

mark_start_valid(){
this.el.find('div.bstart input').removeClass('invalid');
}
mark_start_invalid(){
this.el.find('div.bstart input').addClass('invalid');
}
mark_finish_valid(){
this.el.find('div.bfinish input').removeClass('invalid');
}
mark_finish_invalid(){
this.el.find('div.bfinish input').addClass('invalid');
}
mark_rate_valid(){
this.el.find('div.brate select').removeClass('invalid');
}
mark_rate_invalid(){
this.el.find('div.brate select').addClass('invalid');
}
mark_week_color(){
@@ -555,8 +659,58 @@
var me = new Date(this.data.start);
return (w2_begin <= me && me <= w2_end );
}
get_payment_summary(){
var result ={};
result.ot = this.get_is_high_pay();
result.hour = this.get_working_duration();
result.money = this.get_wages();
return result;
}
get_is_high_pay()
{
var rate_info = this.get_rate_info_by_id(this.get_rate());
return this.is_high_pay_hour(rate_info);
}
get_working_duration()
{
//finish - start
var f = new Date(this.get_finish());
var s = new Date(this.get_start());
var diff = f.getTime() - s.getTime();
var hours = Math.floor(diff / 1000 / 60 / 60);
diff -= hours * 1000 * 60 * 60;
var minutes = Math.floor(diff / 1000 / 60);
var minute_to_hour = minutes/60;
return (hours + minute_to_hour);
}
get_wages(){
var hour = this.get_working_duration();
var rate_info = this.get_rate_info_by_id(this.get_rate());
return hour * rate_info.RatePerUnit;
}
get_rate_info_by_id(id){
var rate_info = {};
var rates = bts().earnings_rate;
for(var i =0; i< rates.length; i++){
var r = rates[i];
if(r.EarningsRateID == id){
rate_info = $.extend(true,{}, r);//make a copy
break;
}
}
return rate_info;
}
is_high_pay_hour(rate_info){
var keywords =bts().high_pay_keywords;
var found = false;
keywords.forEach(function(e){
if (-1 != rate_info.Name.toLowerCase().indexOf(e.toLowerCase()) )
found = true;
});
return found;
}
}//end of class Job
//global GUI summary
@@ -809,19 +963,17 @@
$('div.sheettitle h1').click(function(){
reset_title_to_today();
})
});

function reset_title_to_today(){
set_today();
init_weekdays();
set_week_number();
load_timesheet();
}

function load_timesheet()
{
show_loading_jobs();
clear_workspace();
var first = $('span[name="w1d1"]').data().date;
var last = $('span[name="w2d7"]').data().date;
@@ -880,7 +1032,8 @@
}
$('button[name="confirmschedule"]').click(function(){
$('span.ticon.ticon-save').trigger('click');
//$('div.workspace span.ticon.ticon-save').trigger('click');
});
@@ -901,10 +1054,8 @@
clients.push(id.substring(1));
});
console.log('staffs %o' , staffs);
console.log('clients %o' , clients);
filter_workspace(staffs, clients);
calculate_total_working_hour();
}
function filter_workspace(staffs, clients){
@@ -932,7 +1083,29 @@
function calculate_total_working_hour()
{
//init pays for all staff;
var pays=[];
$('.stafflist > div.peopleitem').each(function(i,e){
var people = $(this).data().obj;
people.reset_summary();
});
$('div.workspace > .divTable').each(function(i,e){
var job = $(e).data().job; //class Job
var ps = job.get_payment_summary();
var staff = job.get_staff();
var people = find_staff(staff); //class People
if (people !=false)
people.add_payment_summary(ps);
});
}
function find_staff(login)
{
var d = $('#p'+login).data();
if (typeof d === 'undefined')
return false;
return $('#p'+login).data().obj;
}
function calculate_total_money()
@@ -940,43 +1113,37 @@
}
//visually hint whether start is correct;
$(document).on('change','div.bstart input', function(){
var str = $(this).attr('value');
if ( ! is_valid_date_str(str) )
$(this).css('background-color', 'orange');
else
$(this).css('background-color', 'white');
});
//visually hint whether finish date is correct;
$(document).on('change','div.bfinish input', function(){
var job = $(this).closest('div.divTable').data().job;
var str = $(this).attr('value');
if ( ! is_valid_date_str(str) ){
$(this).css('background-color', 'orange');
return;
}else
$(this).css('background-color', 'white');

//must be later than start
if (! job.is_finish_resonable()){
alert('finish date should be bigger than start date');
$(this).css('background-color', 'orange');
}else{
$(this).css('background-color', 'white');
}
});
$(document).on('change', '.divTableRow select, .divTableRow input', function() {
var job = $(this).closest('.divTable').data().job;
job.validate();
job.mark_dirty();
});
reset_title_to_today();
function init_ts(){
show_loading_jobs();
list_staff();
list_clients();
xero(false);
wifi(false);
init_user_search();
//ajax_earning_rate();
reset_title_to_today();
load_timesheet();
}
// function ajax_earning_rate(){
// $.post(bts().ajax_url, { // POST request
// _ajax_nonce: bts().nonce, // nonce
// action: "earnings_rate", // action
// }, function(response, status, xhr){
// bts().earnings_rate = response;
// console.log("%o", bts().earnings_rate);
// });
// }
init_ts();

/*________________________________________________________________________*/
});
})(jQuery);

+ 2
- 0
ts.php Просмотреть файл

@@ -136,6 +136,8 @@ class AcareOffice{
'userid'=> $this->acaresydney_userid,
'load_user_img'=> plugins_url('img/loading_user.gif', __FILE__),
'load_job_img'=> plugins_url('img/loading_job.gif', __FILE__),
'earnings_rate'=> get_option('bts_payitem_earnings_rate'),
'high_pay_keywords' => ['sat ', 'sun ', 'high ', 'public holiday'], //space is important
) );
}

Загрузка…
Отмена
Сохранить