diff --git a/css/bts_timesheet.css b/css/bts_timesheet.css index b7fd08b..8db6c5f 100644 --- a/css/bts_timesheet.css +++ b/css/bts_timesheet.css @@ -675,6 +675,18 @@ div.blueTable.emptyrecord { background-color: #eeeeee; } +div.workspace div.blueTable.disabled *{ + background-color:lightgrey; + color: black; +} + +div.workspace div.blueTable.disabled span.ticon-trash, +div.workspace div.blueTable.disabled span.ticon-copy, +div.workspace div.blueTable.disabled span.ticon-save +{ + display:none; +} + .divTable.blueTable .divTableCell, .divTable.blueTable .divTableHead, { @@ -750,12 +762,17 @@ div.blueTable.emptyrecord { margin: 3px 0px 3px 0px; } -.divTable.highlight { +.divTable:not(.disabled).highlight { box-shadow: 1px 1px 10px green; } +.divTable.disabled.highlight { + box-shadow: 1px 1px 10px yellow; +} + + .divTable.invalidjob.highlight { - box-shadow: 1px 1px 10px #f50202; + box-shadow: 1px 1px 10px red; } .divTable.highlight.newcopy { @@ -852,8 +869,8 @@ div.brating { direction: rtl; } -div.workspace .brating > span:hover:before, -div.workspace .brating > span:hover ~ span:before { +div.workspace .divTable:not(.disabled) .brating > span:hover:before, +div.workspace .divTable:not(.disabled) .brating > span:hover ~ span:before { content: "\2605"; position: absolute; } @@ -892,7 +909,7 @@ div.bdelete span.ticon-trash { cursor: pointer; } -div.workspace div > span:hover { +div.workspace .divTable:not(.disabled) div > span:hover { box-shadow: 0px 0px 10px black; } diff --git a/js/bts_timesheet.js b/js/bts_timesheet.js index 26811de..7dda02c 100644 --- a/js/bts_timesheet.js +++ b/js/bts_timesheet.js @@ -259,6 +259,21 @@ add_new_empty_job(); }); + + function get_workspace_start_date(){ + return new Date($('span[name="w1d1"]').data().date) ; + } + function get_payroll_start() + { + return new Date(bts().pay_calendar.start + " 00:00:00"); + } + +// function allow_add_new(){ +// var w1_begin = get_workspace_start_date(); +// var pay_begin = get_payroll_start(); +// return w1_begin > pay_begin; +// } + function add_new_empty_job(){ var o = new Job({empty:true}); $('div.workspace').append(o.el); @@ -272,7 +287,11 @@ $(document).on('click', 'div.divTableCell.bdelete', function(){ var job = $(this).closest('.divTable').data().job; - var el = $(this).closest('div.divTable'); + var el = $(this).closest('div.divTable'); + + if (job.data.disabled) + return; + if ( job.get_job_id() == '') el.remove(); else{ @@ -322,6 +341,10 @@ return; var table = $(this).closest('div.divTable'); var job = table.data().job; + if (job.data.disabled){ + alert("Job disabled, cannot copy"); + return; + } var newj = clone_data_create_new_job(job.get_record_from_ui()); $('div.workspace').append(newj.el); newj.el.get(0).scrollIntoView();//make sure it's visible; @@ -329,6 +352,7 @@ dtp_init(); }); + class Job{ //save data for the record, and display it as GUI constructor(data){ var html = jQuery("#job_item").html(); @@ -341,17 +365,25 @@ init_start_rating(){ var self = this; this.el.find("div.brating span").click(function(){ + if (self.data.disabled) + return; var r = $(this).attr('data-rating'); self.mark_dirty(); self.set_rating(r); }) this.el.find("div.brating").mouseenter(function(){ + if (self.data.disabled) + return; + //change to all hollow star $(this).find('span').html('☆'); }); this.el.find("div.brating").mouseleave(function(){ + if (self.data.disabled) + return; + self.set_rating(self.data.rating); }); @@ -359,8 +391,10 @@ load_data(data) { - //save to html element + //check is disabled? this.data = data; + this.is_disabled(); + //save to html element this.el.data({job:this, data:data}); //draw GUI @@ -376,11 +410,19 @@ this.set_rating(data.rating); //draw GUI by other + this.mark_disabled(); this.mark_dirty_on_new_record(data); this.mark_week_color(); this.validate(); //also triggers mark errors } + is_disabled() + { + var s = new Date(this.data.start); + var pay_roll_start = get_payroll_start(); + this.data.disabled = s < pay_roll_start; + } + get_job_id(){ return this.el.find('input[name="id"]').attr('value'); } @@ -393,15 +435,22 @@ } set_tos(val) { + if (this.data.disabled) + this.el.find('div.btos select').prop('disabled', 'disabled'); + if (typeof(val) =="undefined") return; this.el.find('div.btos select option[value="'+val+'"]').prop('selected',true); + } get_start(){ return this.el.find('div.bstart input').attr('value'); } set_start(val) { + if (this.data.disabled) + this.el.find('div.bstart input').prop('disabled', 'disabled'); + if (typeof(val) =="undefined") return; this.el.find('div.bstart input').attr('value', val); @@ -412,6 +461,9 @@ } set_finish(val) { + if (this.data.disabled) + this.el.find('div.bfinish input').prop('disabled', 'disabled'); + if (typeof(val) == "undefined") return; this.el.find('div.bfinish input').attr('value', val); @@ -422,6 +474,9 @@ } set_rate(val) { + if (this.data.disabled) + this.el.find('div.brate select').prop('disabled', 'disabled'); + if (typeof(val) =="undefined") return; this.el.find('div.brate select option[value="'+val+'"]').prop('selected',true); @@ -432,6 +487,9 @@ } set_staff(val) { + if (this.data.disabled) + this.el.find('div.bstaff select').prop('disabled', 'disabled'); + if (typeof(val) =="undefined") return; this.el.find('div.bstaff select option[value="'+val+'"]').prop('selected',true); @@ -442,6 +500,9 @@ } set_client(val) { + if (this.data.disabled) + this.el.find('div.bclient select').prop('disabled', 'disabled'); + if (typeof(val) =="undefined") return; this.el.find('div.bclient select option[value="'+val+'"]').prop('selected',true); @@ -452,6 +513,9 @@ } set_ack(val) { + if (this.data.disabled) + this.el.find('div.bconfirmed input').prop('disabled', 'disabled'); + if (typeof(val) =="undefined") return; return this.el.find('div.bconfirmed input').prop('checked', val!=0); @@ -540,6 +604,14 @@ },1000); } + mark_disabled() + { + if (this.data.disabled) + this.el.addClass('disabled'); + else + this.el.removeClass('disabled'); + } + //newly created empty record mark_new() { @@ -890,8 +962,10 @@ { var now = new Date(curr); var d1 = new Date(now.setDate(i)); + d1.setHours(0,0,0,0); //0 hour, 0 minute, 0 second, 0 milliseconds, now = new Date(curr); var d2 = new Date(now.setDate(i+7)); + d2.setHours(0,0,0,0); set_day_number(1,pos, d1); //week 1 set_day_number(2,pos, d2); //week 2 pos +=1; @@ -1002,14 +1076,17 @@ var el = $(e).closest('div.divTable'); if (el.is(":visible")){ var j = el.data().job; - var newj = clone_data_create_new_job(j.get_record_from_ui(),7);//add 7 days - job_els.push(newj.el); + if (! j.data.disabled ){ + var newj = clone_data_create_new_job(j.get_record_from_ui(),7);//add 7 days + job_els.push(newj.el); + } } } }); }); show_jobs(job_els); debounced_calculate(); + alert("Copied .. (" + job_els.length + ") jobs"); }); $('div.weekly div.weekname.next > input').click(function(e){ @@ -1032,11 +1109,12 @@ $('div.week1 > div').click(function(e){ e.stopPropagation(); + if ($('div.bstart input.blink_me').length == 0){ alert("nothing to copy"); return; } - if (!confirm ('copy to next week')) + if (!confirm ('copy to next week?')) return; var jobs_el = []; $('div.bstart input.blink_me').each(function(i,e){ @@ -1046,6 +1124,7 @@ }); show_jobs(jobs_el); unblink_all_date(); + alert('Copied (' +jobs_el.length + ") jobs"); }); $('div.week1,div.week2').click(function(e){ @@ -1058,6 +1137,8 @@ var tb = $(el).closest('div.divTable'); if (tb.is(':visible')){ var j = $(tb).data().job; + if (j.data.disabled) + return false; var newj = clone_data_create_new_job(j.get_record_from_ui() , 7); // +7 days return newj; } @@ -1104,14 +1185,12 @@ var strDate = format_date(date); //yyyy-mm-dd var els=[]; unblink_all_date(); - $('div.bstart input').each(function(i,e){ - if ( $(e).is(":visible") ){ - var value = $(e).attr('value'); - if( -1 != value.indexOf(strDate) ) //found - { - els.push(e); - $(e).addClass('blink_me'); - } + $('div.bstart input:visible').each(function(i,e){ + var value = $(e).attr('value'); + if( -1 != value.indexOf(strDate) ) //found + { + els.push(e); + $(e).addClass('blink_me'); } }); } @@ -1363,9 +1442,7 @@ people.reset_summary(); }); - $('div.workspace > .divTable').each(function(i,e){ - if (! $(e).is(':visible')) - return; + $('div.workspace > .divTable:visible').each(function(i,e){ var job = $(e).data().job; //class Job if (typeof job === 'undefined') diff --git a/ts.php b/ts.php index 262eb3c..83f59af 100644 --- a/ts.php +++ b/ts.php @@ -518,6 +518,7 @@ class AcareOffice{ 'load_job_img'=> plugins_url('img/loading_job.gif', __FILE__), 'driving' => "259ee8e8-a1e5-42e4-9c14-517543ecdc4b", 'high_pay_keywords' => ['sat ', 'sun ', 'high ', 'public holiday'], //space is important + 'pay_calendar'=> get_option('bts_pay_roll_calendar'), ) ); } @@ -1105,10 +1106,13 @@ ZOT; $response['sql'] = $query; $jobs = $this->db->get_results($query); + + $calendar = get_option('bts_pay_roll_calendar'); + if (! empty($jobs)){ $response['status'] = 'success'; foreach( $jobs as $s){ - $response['jobs'][] = array( + $item = array( 'id' => $s->id, 'tos' => $s->tos, 'start'=> $s->start, @@ -1119,6 +1123,7 @@ ZOT; 'ack' => $s->ack, 'rating' =>$s->rating, ); + $response['jobs'][] = $item; } } wp_send_json($response);