diff --git a/css/bts_office.css b/css/bts_office.css index c320fbc..f0c8db8 100644 --- a/css/bts_office.css +++ b/css/bts_office.css @@ -18,7 +18,7 @@ body { } } -@keyframes bolder { +@keyframes swing { 0% { padding-left:0px; background-color:yellow;} 50% { padding-left:10px; background-color: lightyellow;} 100% { padding-left:0px; background-color:yellow;} @@ -547,13 +547,21 @@ div.week2.filtered { filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ebf1f6', endColorstr='#d5ebfb',GradientType=0 ); /* IE6-9 */ } -div.week1:after, -div.week2:after { +div.week1::after, +div.week2::after { content: ''; display: inline-block; width: 100%; } +div.week1.filtered span, +div.week2.filtered span, +div.week1.filtered div.week1color, +div.week2.filtered div.week2color +{ + visibility: hidden; +} + div.week1 { position: relative; left: -10px; @@ -843,8 +851,19 @@ div.brate { } div.brate.error{ + position:relative; background-color: red !important; - animation: bolder 1s linear infinite; + animation: swing 1s linear infinite; +} +div.error::after{ + position:absolute; + right:0px; + bottom:0px; + color:red; + font-family: "ticons"; + font-weight: 900; + content: "\f071"; + animation: blinker 0.3s linear infinite; } .divTable div > select { diff --git a/html/jobv1.html b/html/jobv1.html index caee06b..52eeb12 100644 --- a/html/jobv1.html +++ b/html/jobv1.html @@ -1,5 +1,5 @@ {{#jobs}} -
@@ -8,10 +8,10 @@
{{start}}
{{finish}}
-
{{rate_name}}
+
{{rate_name}}
{{staff_name}}
{{client_name}}
-
+
{{rating}}
diff --git a/js/bts_office.js b/js/bts_office.js index eed04cd..3bde9ed 100644 --- a/js/bts_office.js +++ b/js/bts_office.js @@ -147,11 +147,13 @@ if (response.status =='success'){ bts().staff = response.users; bts().staff_map = {}; + bts().staff_people= {}; response.users.forEach(function(u){ bts().staff_map[u.login] = u; var html = bts_staff_html(u); jQuery('div.stafflist').append(html); - new People("#p" + u.login,'#staff_item', u); + var staff_obj = new People("#p" + u.login,'#staff_item', u); + bts().staff_people[u.login] = staff_obj; }); hide_loading_staff(); calculate_total_hour_and_money(); @@ -304,6 +306,9 @@ jobid: id, }, function(response, status, xhr){ if (response.status=='success'){ + var id = el.attr('data-id'); + delete bts().job_map[id]; + console.log("delete %s , job_map[%d]=%o ", id, id, bts().job_map[id]); el.addClass('blink_me'); el.fadeOut(900); setTimeout(function(){ @@ -1187,10 +1192,13 @@ (typeof b.tos != "undefined" && Object.keys(b.tos).length > 0 ) && (typeof b.earnings_rate != "undefined" && Object.keys(b.earnings_rate).length > 0 )) { + var job_map={}; //map data for each jobTable response.jobs.forEach(function(e){ job_derive_attr(e); + job_map[e.id] = e; }); + bts().job_map = job_map; //we do works, load timesheets var template = $("#jobv1_item").html(); @@ -1217,6 +1225,7 @@ if (! has_txt_hour( bts().earnings_rate[e.rate].TypeOfUnits )){ e.non_hour = true; + e.brate_err = "Rate type is not Hours - Not allowed"; } if (job_is_week1(e.start)){ @@ -1402,18 +1411,19 @@ if (hide_week1 && hide_week2 ){ alert("You are hiding both weeks"); + $('div.jobTable').show();//show non-week1 and none-week2 + $('div.jobTable.week1job,div.jobTable.week2job').hide(); //hide week1 or week2; + }else if (hide_week1){ + $('div.jobTable:not(.week1job)').show();//show non-week1 + $('div.jobTable.week1job').hide(); //hide week1; + }else if (hide_week2){ + $('div.jobTable.week2job').hide(); //show non-week2 + $('div.jobTable:not(.week2job)').show(); //hide week2 } - $('div.workspace div.divTable').each(function(i,e){ - var job = $(e).data().job; - if ((hide_week1 && job.is_week1()) || - (hide_week2 && job.is_week2()) ){ - $(e).fadeOut(); - } - }); } - var debounced_calculate = debounce(calculate_total_hour_and_money, 2000); + var debounced_calculate = debounce(calculate_total_hour_and_money, 500); function calculate_total_hour_and_money() { @@ -1427,20 +1437,21 @@ people.reset_summary(); }); - $('div.workspace > .divTable').each(function(i,e){ + $('div.workspace > .divTable.jobTable').each(function(i,e){ if (! $(e).is(':visible')) return; - var job = $(e).data().job; //class Job + var id = $(e).attr('data-id'); + var job = bts().job_map[id]; if (typeof job === 'undefined') return; - var ps = job.get_payment_summary(); + var ps = job_get_payment_summary(job); pays.total += ps.money; pays.hours += ps.hour; - var staff = job.get_staff(); - var people = find_staff(staff); //class People + var staff = job.staff; + var people = bts().staff_people[staff]; //class People if (people !=false) people.add_payment_summary(ps); }); @@ -1448,6 +1459,56 @@ set_working_hours(pays.hours.toFixed(2)); } + function job_get_payment_summary(job) + { + var result ={}; + result.ot = job_get_is_high_pay(job); + result.hour = job_get_working_duration(job); + result.money = job_get_wages(job); + return result; + } + + function job_get_is_high_pay(job) + { + var rate_info = bts().earnings_rate[job.rate]; + + 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; + } + + function job_get_working_duration(job) + { + //finish - start + var f = new Date(job.finish); + var s = new Date(job.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); + } + + function job_get_wages(job) + { + var hour = job_get_working_duration(job); + var rate_info = bts().earnings_rate[job.rate]; + if ( has_txt_hour( bts().earnings_rate[job.rate].TypeOfUnits ) ) + { + return hour * rate_info.RatePerUnit; + }else{ + return 1 * rate_info.RatePerUnit; + } + } + + + + function find_staff(login) { var d = $('#p'+login).data(); @@ -1578,11 +1639,62 @@ response.options.forEach(function(e){ bts().earnings_rate[e.EarningsRateID]=e; }); - console.log("%o", bts().earnings_rate); + //console.log("%o", bts().earnings_rate); }); } + function check_duplicate() + { + var count= 0; + var to_be_delete=[]; + //loop through jobs + for(var id1 in bts().job_map){ + var job1 = bts().job_map[id1]; + if (typeof job1.parent != 'undefined') + continue; //bypass it it has already found parents + + job1.compared_as_master = true;//mark it + job1.duplicates={}; + //console.log('investigating %s' , job1.id); + //match job2 + for(var id2 in bts().job_map){ + var job2 = bts().job_map[id2]; + if (typeof job2.compared_as_master != 'undefined') + continue; + + if (typeof job2.parent != "undefined") + continue; //it has already parent; + //console.log('comareing %s vs %s', job1.id, job2.id); + if (is_same_job(job1,job2)){ + job2.parent = job1.id; + job1.duplicates[id2] = job2; + console.warn("found: %s = %s", job1.id, job2.id); + count++; + to_be_delete.push(id2); + } + } + } + console.log('all-done, found %d duplicates: %o', count, to_be_delete); + } + + $('div.wages').click(check_duplicate); + + function is_same_job(job1, job2) + { + if ( (job1.tos == job2.tos) && + (job1.staff == job2.staff) && + (job1.client == job2.client) && + (job1.start == job2.start) && + (job1.finish == job2.finish) ) + { + return true; + } + return false; + } + + + $( ".boundary_datepicker" ).datepicker(); $( ".boundary_datepicker" ).datepicker("option", "dateFormat", "yy-mm-dd");