Explorar el Código

duplicate detection improved

master
patrick hace 6 años
padre
commit
0946619c2a
Se han modificado 5 ficheros con 213 adiciones y 105 borrados
  1. +0
    -1
      Xero.php
  2. +19
    -4
      css/bts_office.css
  3. +5
    -1
      html/jobv1.html
  4. +1
    -1
      html/jobv1_editor.html
  5. +188
    -98
      js/bts_office.js

+ 0
- 1
Xero.php Ver fichero

@@ -99,7 +99,6 @@ class Xero {
$msg= "Xero API resource not found rate limit exceeded, please try again later, existing sync within 600 seconds will by passed automatically\n";
$this->logConsole($msg);
}
}
private function sync_clients(){
$contacts = $this->getClients($this->clientgroup);

+ 19
- 4
css/bts_office.css Ver fichero

@@ -942,6 +942,7 @@ div.bsave span.ticon-save {
cursor: pointer;
}

div.jobTable.to_be_deleted_duplicate div.bsave span.ticon-save,
div.jobTable.saved div.bsave span.ticon-save {
display: none;
}
@@ -964,8 +965,8 @@ div.jobTable.dirty div.bsave span{
animation-name: blinker;
}

div.bdelete span.ticon-trash,
div.bedit span.ticon-edit {
div.workspace div.bdelete span.ticon-trash,
div.workspace div.bedit span.ticon-edit {
display: inline-block;
border: 3px solid lightgrey;
padding: 5px;
@@ -973,7 +974,7 @@ div.bedit span.ticon-edit {
color: red;
cursor: pointer;
}
div.bedit span.ticon-edit{
div.workspace div.bedit span.ticon-edit{
color:blue;
}

@@ -989,12 +990,26 @@ div.jobTable.to_be_deleted_duplicate span.ticon-trash
{
animation: blinker 0.3s linear infinite;
}

div.jobTable.to_be_deleted_duplicate span.ticon-copy,
div.jobTable.to_be_deleted_duplicate span.ticon-edit{
display:none !important;
}
div.jobTable:not(.to_be_deleted_duplicate) span.ticon-check-circle{
display:none !important;
}
div.jobTable.to_be_deleted_duplicate span.ticon-check-circle{
display: inline-block;
border: 3px solid green;
padding: 5px;
border-radius: 10px;
color: green;
cursor: pointer;
font-size: 1.1em;
}

div.divTableHeading div > span:hover {
div.divTableHeading div > span.ticon-trash:hover,
div.divTableHeading div > span.ticon-search:hover {
cursor: pointer;
animation: blinker 0.3s linear infinite;
}

+ 5
- 1
html/jobv1.html Ver fichero

@@ -1,7 +1,9 @@
{{#jobs}}
<div class="divTable jobTable blueTable {{#saved}} saved {{/saved}} {{^saved}} dirty {{/saved}} {{#is_week1}}week1job{{/is_week1}} {{#is_week2}} week2job {{/is_week2}}"
{{#id}} id="job_{{id}}" {{/id}} {{^id}} id="{{newjob_id}}" {{/id}}
data-id="{{id}}" {{^id}} data-newjob_id="{{newjob_id}}" {{/id}} data-tos="{{tos}}" data-rate="{{rate}}" data-staff="{{staff}}" data-client="{{client}}">
data-id="{{id}}" {{^id}} data-newjob_id="{{newjob_id}}" {{/id}}
data-tos="{{tos}}" data-rate="{{rate}}" data-staff="{{staff}}" data-client="{{client}}"
data-start="{{start}}" data-finish="{{finish}}">
<div class="divTableBody">
<div class="divTableRow">
<div class="divTableCell btos {{#tos_err}}error{{/tos_err}}" title="{{tos_err}}">
@@ -15,6 +17,7 @@
<div class="divTableCell bconfirmed"><input name="ack" type=checkbox {{#is_confirmed}}checked{{/is_confirmed}} onclick="return false;"></div>
<div class="divTableCell brating {{#rating_err}} error {{/rating_err}}">{{rating}}</div>
<div class="divTableCell bedit">
<span class="ticon ticon-check-circle"></span>
<span class="ticon ticon-edit"></span>
</div>
<div class="divTableCell bdelete">
@@ -22,6 +25,7 @@
</div>
<div class="divTableCell bsave ">
<span class="ticon ticon-copy"></span>
<span class="ticon ticon-save"></span>
</div>
</div>
<div class="divTableRow errmsg">

+ 1
- 1
html/jobv1_editor.html Ver fichero

@@ -41,7 +41,7 @@
</select>
</div>
<div class="divTableCell bdelete">
<span class="ticon ticon-plus"></span>
<span class="ticon ticon-plus-not-exist"></span>
</div>
<div class="divTableCell bsave ">
<span class="ticon ticon-save"></span>

+ 188
- 98
js/bts_office.js Ver fichero

@@ -340,41 +340,8 @@
});
$(document).on('click', 'div.divTableHead.bdelete span.ticon-trash', function(){
var len = $('div.jobTable.to_be_deleted_duplicate').length;
if (len <= 0){
if (confirm("No duplicates to delete, trying to find duplicates?")){
check_duplicate();
}
return;
}else{
if (!confirm("Delete " + len + " duplicates? "))
return;
}
var ids = [];
$('div.jobTable.to_be_deleted_duplicate').each(function(){
var id = $(this).attr('data-id');
ids.push(id);
});

$.post(bts().ajax_url, { // POST request
_ajax_nonce: bts().nonce, // nonce
action: "delete_jobv1", // action
jobs: ids, //delete multiple ids
}, function(response, status, xhr){
if (response.status=='success'){
$('div.jobTable.to_be_deleted_duplicate').each(function(){
var id = $(this).attr('data-id');
delete bts().job_map[id];
$(this).get(0).scrollIntoView();
fade_and_delete(this);
});
debounced_calculate();
}else{
alert( 'error deleting duplicates:\n\nError:\n\n' + response.error + "\n\n");
}
});

check_duplicate();
setTimeout(do_delete_duplicate, 200);//200ms make GUI refresh
});

function fade_and_delete(el)
@@ -413,12 +380,30 @@
add_new_empty_job();
});
function remove_job_from_gui(el)
{
el = $(el);
var newjob_id = el.data().newjob_id;
var id = el.data().id;
if (typeof newjob_id != 'undefined' && newjob_id !=''){
delete bts().job_map_new[newjob_id];
}else if (typeof id != 'undefined' && id != ''){
delete bts().job_map[id];
}
el.addClass('blink_me');
el.fadeOut(500);
setTimeout(function(){
el.remove();
debounced_calculate();
}, 500);
}
$(document).on('click', 'div.divTableCell.bdelete', function(){
var el = $(this).closest('div.jobTable');
var data = el.data();
if (typeof data.id =='undefined' || data.id == '')
el.remove();
else{
if (typeof data.id =='undefined' || data.id == ''){//not saved
remove_job_from_gui(el);//remove direclty
}else{
var id = data.id;
if (confirm('delete this job?')){
$.post(bts().ajax_url, { // POST request
@@ -427,22 +412,13 @@
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[%s]=%o ", id, id, bts().job_map[id]);
el.addClass('blink_me');
el.fadeOut(900);
setTimeout(function(){
el.remove();
}, 900);
remove_job_from_gui(el);
}else{
alert( 'error saving data, please check your network');
alert( 'error deleting job, please check your network');
}
});
}
}
debounced_calculate();
});
$(document).on('mouseenter', 'div.divTableCell', function(){
@@ -453,9 +429,18 @@
});
$(document).on('click', 'div.workspace span.ticon.ticon-save', function(){
var table = $(this).closest('div.divTable');
table.data().job.do_save_record();
var table = $(this).closest('div.jobTable');
var data = table.data();
if (data.id == "" && data.newjob_id != "" && data.newjob_id.substring(0,4) == "new_" ){
job = bts().job_map_new[data.newjob_id];
console.assert(typeof job != 'undefined');
do_save_new_job(job.get_record(), table);
return;
}
alert("Error occured");
$(this).fadeOut();
});
$(document).on('click', '.divTableHeading span.ticon.ticon-save', function(){
//save all
$('div.workspace span.ticon.ticon-save').each(function (i,e){
@@ -472,7 +457,31 @@
add_new_empty_job(newj);
});
});
function do_save_new_job(job_tobe_saved, table){
$.post(bts().ajax_url, { // POST request
_ajax_nonce: bts().nonce, // nonce
action: "save_job", // action
record: job_tobe_saved,
}, function(response, status, xhr){
if (response.status=='success'){
var job = new Job(response.newdata);
job.saved = true;
job.is_new = response.isNew;
bts().job_map[job.id] = job;
//delete that old job and display the new one
var jobs=[job];
var html = Mustache.render($('#jobv1_item').html(), {jobs:jobs});
delete bts().job_map_new[table.data().newjob_id];
table.after(html);
table.remove();
}else{
console.error("error saving job %o, response=%o", job_tobe_saved, response);
alert( 'error saving data, please check your network');
}
});
}
function mark_highlight_me(el, ms){
el.addClass('blink_me');
@@ -1272,26 +1281,17 @@
$(s).data();
}

// setTimeout(function(){
// set_modal_title('warning', 'suck title');
// set_modal_content('warning', 'fucking details');
// //open_modal('warning');
// }, 1000);
//
// setTimeout(function(){
// set_modal_title('error', 'error title');
// set_modal_content('error', 'error details');
// //open_modal('error');
// }, 5000);
$(document).on('mouseenter', 'div.week1 div', function(){
$(this).addClass('blink_me');
get_week2_partner(this).addClass('blink_me');
blink_same_date_by_div(this);
var blink_by_date_timer;
$(document).on('mouseenter', 'div.week1 > div, div.week2 > div', function(){
var self = this;
blink_by_date_timer = setTimeout (function(){
$(self).addClass('blink_me');
get_week2_partner(self).addClass('blink_me');
blink_same_date_by_div(self);
}, 1500);
});
$(document).on('mouseleave', 'div.week1 div', function(){
$(document).on('mouseleave', 'div.week1 div, div.week2 > div', function(){
clearTimeout(blink_by_date_timer);
$(this).removeClass('blink_me');
get_week2_partner(this).removeClass('blink_me');
unblink_all_date();
@@ -1472,6 +1472,7 @@

$('div.week1 > div').click(function(e){
e.stopPropagation();
blink_same_date_by_div(this);
if ($('div.bstart.blink_me').length == 0){
alert("nothing to copy");
return;
@@ -1559,22 +1560,23 @@
var els=[];
unblink_all_date();
var first_into_view = false; //make sure first row in match is visible
$('div.bstart').each(function(i,e){
if ( $(e).is(":visible") ){
var value = $(e).html();
if( -1 != value.indexOf(strDate) ) //found
{
if ( !first_into_view ){ //scroll to top
first_into_view = true;
$(e).get(0).scrollIntoView();
}
els.push(e);
$(e).addClass('blink_me');
}
$('div.workspace div.bstart:visible').each(function(i,e){
var value = $(e).html();
if( -1 != value.indexOf(strDate) ) //found
{
if ( !first_into_view ){ //scroll to top
first_into_view = true;
ensure_visible(e);
}
els.push($(e));
$(e).addClass('blink_me');
}
});
}
function ensure_visible(el){
$(el).get(0).scrollIntoView();
}
function unblink_all_date(){
$('div.bstart').removeClass('blink_me');
@@ -1705,6 +1707,9 @@
//clear datetime picker
$('div.xdsoft_datetimepicker').remove();
//
bts().job_map = {};
bts().job_map_new = {};
show_loading_jobs();
}
@@ -1721,7 +1726,7 @@
return false;
}
$('button[name="confirmschedule"]').click(function(){//TODO: check error before confirm
$('button[name="confirmschedule"]').click(function(){
if( check_workspace_error() ){
return;
}
@@ -2034,13 +2039,58 @@
});
}
function do_delete_duplicate()
{
var len = $('div.jobTable.to_be_deleted_duplicate').length;
if (len <= 0){
return;
}
if (!confirm("Delete " + len + " duplicates? ")){
return;
}
$('div.jobTable.to_be_deleted_duplicate:not(.saved)').each(function(){
remove_job_from_gui(this);
});
var ids = [];
$('div.jobTable.to_be_deleted_duplicate.saved').each(function(){
var id = $(this).attr('data-id');
if (id != '')
ids.push(id);
});
if ( ids.length >0 ){
$.post(bts().ajax_url, { // POST request
_ajax_nonce: bts().nonce, // nonce
action: "delete_jobv1", // action
jobs: ids, //delete multiple ids
}, function(response, status, xhr){
if (response.status=='success'){
$('div.jobTable.to_be_deleted_duplicate.saved').each(function(){
remove_job_from_gui(this);
});
debounced_calculate();
}else{
alert( 'error deleting duplicates:\n\nError:\n\n' + response.error + "\n\n");
}
});
}
}

function check_duplicate()
{
var to_be_deleted=[];
//make a copy of all jobs
var alljobs = {};
$('div.jobTable:visible').each(function(e){
alljobs[$(this).attr('id')] = $.extend({}, $(this).data());
});
//loop through jobs
for(var id1 in bts().job_map){
var job1 = bts().job_map[id1];
for(var id1 in alljobs){
var job1 = alljobs[id1];
if (typeof job1.parent != 'undefined')
continue; //bypass it it has already found parents

@@ -2048,8 +2098,12 @@
job1.duplicates={};
//console.log('investigating %s' , job1.id);
//match job2
for(var id2 in bts().job_map){
var job2 = bts().job_map[id2];
for(var id2 in alljobs){
if (id1 == id2)
continue;
var job2 = alljobs[id2];
if (typeof job2.compared_as_master != 'undefined')
continue;
@@ -2068,17 +2122,21 @@
alert("No duplicate found!");
return;
}
bts().to_be_deleted_duplicate = to_be_deleted;
//console.log('all-done, found %d duplicates: %o', to_be_deleted.length, to_be_deleted);
mark_duplicate(to_be_deleted);
return to_be_deleted;
}
function is_same_job(job1, job2)
{
var s1 = new Date(job1.start);
var s2 = new Date(job2.start);
var f1 = new Date(job1.finish);
var f2 = new Date(job2.finish);
if ( (job1.tos == job2.tos) &&
(job1.staff == job2.staff) &&
(job1.client == job2.client) &&
(job1.start == job2.start) &&
(job1.finish == job2.finish) )
(s1 - s2 == 0) &&
(f1 - f2 == 0) )
{
return true;
}
@@ -2087,8 +2145,8 @@
function mark_duplicate(ids)
{
ids.forEach(function(id){
var selector = '#job_' +id;
$(selector).get(0).scrollIntoView();
var selector = '#' + id;
ensure_visible(selector);
$(selector).addClass('to_be_deleted_duplicate');
});
}
@@ -2155,12 +2213,44 @@
});
init_ts();
$('div.divTableHeading div.bsave span.ticon-search').mouseenter(function(){//highlight unsaved
var el = $('div.jobTable.dirty .bsave');
if (el.length > 0){
el.addClass('blink_me');
el.get(0).scrollIntoView();
}
})
$('div.divTableHeading div.bsave span.ticon-search').mouseleave(function(){//highlight unsaved
var el = $('div.jobTable.dirty .bsave');
if (el.length > 0 ) {
el.removeClass('blink_me');
}
})
$('div.divTableHeading div.bsave span.ticon-search').click(do_test);
function do_test(){ //TODO: remove this search function
open_modal('editor');
set_modal_title('editor', "title");
set_modal_content('editor', $('div.workspace').html());
$(document).on('click', 'div.jobTable.to_be_deleted_duplicate div.bedit span.ticon-check-circle',function(){//highlight unsaved
var el = $(this).closest('div.jobTable');
if (!confirm ("Mark this is none duplicate?")){
return;
}
el.removeClass('to_be_deleted_duplicate');
});
$('div.divTableHeading div.bsave span.ticon-search').click(do_delete_unsaved_copy);
function do_delete_unsaved_copy()
{ //TODO: remove this search function
var num = $('div.jobTable.dirty').length;
if (num > 0){
if ( !confirm('delete all '+ num + ' unsaved?')){
return;
}
$('div.jobTable.dirty').each(function(){
var newjob_id = $(this).data().newjob_id;
delete bts().job_map_new[newjob_id]
$(this).remove();
})
}else{
alert("nothing to clean up");
}
}
/*________________________________________________________________________*/

Cargando…
Cancelar
Guardar