- Added comprehensive AI Assistant system (aiassist/ directory): * Vector search and embedding capabilities * Typebot proxy integration * Elastic search functionality * Message classification and chat history * MCP proxy for external integrations - Implemented Court Status API (GetCourtStatus.php): * Real-time court document status checking * Integration with external court systems * Comprehensive error handling and logging - Enhanced S3 integration: * Improved file backup system with metadata * Batch processing capabilities * Enhanced error logging and recovery * Copy operations with URL fixing - Added Telegram contact creation API - Improved error logging across all modules - Enhanced callback system for AI responses - Extensive backup file storage with timestamps - Updated documentation and README files - File storage improvements: * Thousands of backup files with proper metadata * Fix operations for broken file references * Project-specific backup and recovery systems * Comprehensive file integrity checking Total: 26,461+ files added/modified including AWS SDK, vendor dependencies, and extensive backup system.
598 lines
21 KiB
JavaScript
598 lines
21 KiB
JavaScript
/*+***********************************************************************************
|
||
* The contents of this file are subject to the vtiger CRM Public License Version 1.0
|
||
* ("License"); You may not use this file except in compliance with the License
|
||
* The Original Code is: vtiger CRM Open Source
|
||
* The Initial Developer of the Original Code is vtiger.
|
||
* Portions created by vtiger are Copyright (C) vtiger.
|
||
* All Rights Reserved.
|
||
*************************************************************************************/
|
||
|
||
Vtiger_Detail_Js("Project_Detail_Js",{
|
||
|
||
gantt: false,
|
||
|
||
getVideo: function (crmid) {
|
||
var settings = {
|
||
"url": "https://crm.clientright.ru/GetVideoLink.php?id="+crmid,
|
||
"method": "GET",
|
||
"timeout": 0,
|
||
};
|
||
|
||
$.ajax(settings).done(function (response) {
|
||
if (response == 'https://clientright.ktalk.ru/recordings/none') {
|
||
alert('У этого проекта нет видеовстреч с записью');
|
||
} else {
|
||
location.reload();
|
||
//window.location.href = response;
|
||
window.open(response, '_blank');
|
||
}
|
||
});
|
||
},
|
||
|
||
getText: function (crmid) {
|
||
var settings = {
|
||
"url": "https://crm.clientright.ru/GetMeetingText.php?id="+crmid,
|
||
"method": "POST",
|
||
"timeout": 0,
|
||
};
|
||
|
||
$.ajax(settings).done(function (response) {
|
||
if (response != 'ok') {
|
||
alert('У этого проекта нет видеовстреч с записью');
|
||
} else {
|
||
alert('Создан связанный текстовый Документ с транскрибацией диалога');
|
||
location.reload();
|
||
}
|
||
});
|
||
},
|
||
|
||
showEditColorModel: function (url, e) {
|
||
var element = jQuery(e);
|
||
app.helper.showProgress();
|
||
app.request.post({url: url}).then(function(error, data) {
|
||
if (data) {
|
||
app.helper.hideProgress();
|
||
var callback = function (data) {
|
||
Project_Detail_Js.registerEditColorPreSaveEvent(data, element);
|
||
var form = jQuery('#editColor');
|
||
var params = {
|
||
submitHandler: function(form) {
|
||
Project_Detail_Js.saveColor(jQuery(form));
|
||
}
|
||
};
|
||
form.vtValidate(params);
|
||
}
|
||
app.helper.showModal(data, {cb: callback});
|
||
}
|
||
});
|
||
},
|
||
|
||
registerEditColorPreSaveEvent: function (data, element) {
|
||
var selectedColorField = data.find('.selectedColor');
|
||
var color = element.data('color');
|
||
|
||
if (color) {
|
||
selectedColorField.val(color);
|
||
var customParams = {
|
||
color: color
|
||
};
|
||
} else {
|
||
//if color is not present select random color
|
||
var randomColor = '#' + (0x1000000 + (Math.random()) * 0xffffff).toString(16).substr(1, 6);
|
||
selectedColorField.val(randomColor);
|
||
//color picker params for add calendar view
|
||
var customParams = {
|
||
color: randomColor
|
||
};
|
||
}
|
||
|
||
//register color picker
|
||
var params = {
|
||
flat: true,
|
||
onChange: function (hsb, hex, rgb) {
|
||
var selectedColor = '#' + hex;
|
||
selectedColorField.val(selectedColor);
|
||
}
|
||
};
|
||
|
||
if (typeof customParams != 'undefined') {
|
||
params = jQuery.extend(params, customParams);
|
||
}
|
||
|
||
data.find('.colorPicker').ColorPicker(params);
|
||
|
||
//on change of status, update color picker with the status color
|
||
var selectElement = data.find('[name=taskstatus]');
|
||
selectElement.on('change', function () {
|
||
var selectedOption = selectElement.find('option:selected');
|
||
var color = selectedOption.data('color');
|
||
selectedColorField.val(color);
|
||
data.find('.colorPicker').ColorPickerSetColor(color);
|
||
});
|
||
},
|
||
|
||
saveColor: function (form) {
|
||
var color = form.find('.selectedColor').val();
|
||
var status = form.find('[name=taskstatus]').val();
|
||
|
||
app.helper.showProgress();
|
||
var params = {
|
||
'module': app.getModuleName(),
|
||
'action': 'SaveAjax',
|
||
'mode': 'saveColor',
|
||
'color': color,
|
||
'status': status
|
||
}
|
||
app.request.post({data: params}).then(
|
||
function(error, data) {
|
||
app.helper.hideProgress();
|
||
app.helper.hideModal();
|
||
if (!error) {
|
||
app.helper.showSuccessNotification({message: app.vtranslate('JS_COLOR_SAVED_SUCESSFULLY')});
|
||
// to reload chart
|
||
jQuery('[data-label-key=Chart]').click();
|
||
} else {
|
||
app.helper.showErrorNotification({message: error});
|
||
}
|
||
}
|
||
);
|
||
|
||
}
|
||
}, {
|
||
|
||
detailViewRecentTicketsTabLabel : 'HelpDesk',
|
||
detailViewRecentTasksTabLabel : 'Project Tasks',
|
||
detailViewRecentMileStonesLabel : 'Project Milestones',
|
||
|
||
/**
|
||
* Function to register event for create related record
|
||
* in summary view widgets
|
||
*/
|
||
registerSummaryViewContainerEvents : function(summaryViewContainer){
|
||
this._super(summaryViewContainer);
|
||
this.registerStatusChangeEventForWidget();
|
||
this.registerEventsForTasksWidget(summaryViewContainer);
|
||
},
|
||
|
||
/**
|
||
* Function to get records according to ticket status
|
||
*/
|
||
registerStatusChangeEventForWidget : function(){
|
||
var thisInstance = this;
|
||
jQuery('[name="ticketstatus"],[name="projecttaskstatus"],[name="projecttaskprogress"]').on('change',function(e){
|
||
var picklistName = this.name;
|
||
var statusCondition = {};
|
||
var params = {};
|
||
var currentElement = jQuery(e.currentTarget);
|
||
var summaryWidgetContainer = currentElement.closest('.summaryWidgetContainer');
|
||
var widgetDataContainer = summaryWidgetContainer.find('.widget_contents');
|
||
var referenceModuleName = widgetDataContainer.find('[name="relatedModule"]').val();
|
||
var recordId = thisInstance.getRecordId();
|
||
var module = app.getModuleName();
|
||
var selectedStatus = currentElement.find('option:selected').val();
|
||
if(selectedStatus.length > 0 && referenceModuleName == "HelpDesk"){
|
||
var searchInfo = new Array();
|
||
searchInfo.push('ticketstatus');
|
||
searchInfo.push('e');
|
||
searchInfo.push(selectedStatus);
|
||
statusCondition['ticketstatus'] = searchInfo;
|
||
params['whereCondition'] = JSON.stringify(statusCondition);
|
||
} else if(referenceModuleName == "ProjectTask" && picklistName == 'projecttaskstatus'){
|
||
if(selectedStatus.length > 0) {
|
||
var searchInfo = new Array();
|
||
searchInfo.push('projecttaskstatus');
|
||
searchInfo.push('e');
|
||
searchInfo.push(selectedStatus);
|
||
statusCondition['projecttaskstatus'] = searchInfo;
|
||
params['whereCondition'] = JSON.stringify(statusCondition);
|
||
}
|
||
jQuery('[name="projecttaskprogress"]').val('').select2("val", '');
|
||
}
|
||
else if(referenceModuleName == "ProjectTask" && picklistName == 'projecttaskprogress'){
|
||
if(selectedStatus.length > 0) {
|
||
var searchInfo = new Array();
|
||
searchInfo.push('projecttaskprogress');
|
||
searchInfo.push('e');
|
||
searchInfo.push(selectedStatus);
|
||
statusCondition['projecttaskprogress'] = searchInfo;
|
||
params['whereCondition'] = JSON.stringify(statusCondition);
|
||
}
|
||
jQuery('[name="projecttaskstatus"]').val('').select2("val", '');
|
||
}
|
||
|
||
params['record'] = recordId;
|
||
params['view'] = 'Detail';
|
||
params['module'] = module;
|
||
params['page'] = widgetDataContainer.find('[name="page"]').val();
|
||
params['limit'] = widgetDataContainer.find('[name="pageLimit"]').val();
|
||
params['relatedModule'] = referenceModuleName;
|
||
params['mode'] = 'showRelatedRecords';
|
||
app.helper.showProgress();
|
||
app.request.post({data: params}).then(
|
||
function(error, data) {
|
||
app.helper.hideProgress();
|
||
widgetDataContainer.html(data);
|
||
}
|
||
);
|
||
})
|
||
},
|
||
|
||
/**
|
||
* Function to load module summary of Projects
|
||
*/
|
||
loadModuleSummary : function(){
|
||
var summaryParams = {};
|
||
summaryParams['module'] = app.getModuleName();
|
||
summaryParams['view'] = "Detail";
|
||
summaryParams['mode'] = "showModuleSummaryView";
|
||
summaryParams['record'] = jQuery('#recordId').val();
|
||
|
||
app.request.post({data: summaryParams}).then(
|
||
function(error, data) {
|
||
jQuery('.summaryView').html(data);
|
||
}
|
||
);
|
||
},
|
||
|
||
/**
|
||
* Function to load the gantt chart
|
||
*/
|
||
loadGanttChart : function(container) {
|
||
var gantt;
|
||
//load templates
|
||
jQuery("#ganttemplates").loadTemplates();
|
||
|
||
// here starts gantt initialization
|
||
gantt = new GanttMaster();
|
||
var workSpace = $("#workSpace");
|
||
workSpace.css({height:$("#workSpace").parent().height() - 20});
|
||
gantt.init(workSpace);
|
||
|
||
var ret;
|
||
ret = JSON.parse($("#projecttasks").val());
|
||
|
||
gantt.loadProject(ret);
|
||
gantt.checkpoint(); //empty the undo stack
|
||
|
||
$(window).resize(function(){
|
||
workSpace.trigger("resize.gantt");
|
||
})
|
||
jQuery('.toggleButton').click(function() {
|
||
workSpace.trigger("resize.gantt");
|
||
});
|
||
|
||
Project_Detail_Js.gantt = gantt;
|
||
|
||
// Added to make default sortorder of startdate to be ascending
|
||
var element = jQuery('.gdfTable.fixHead').find('.gdfColHeader[data-name=startdate]');
|
||
element.data('nextorder', 'asc');
|
||
element.trigger('click');
|
||
},
|
||
|
||
loadContents : function(url,data) {
|
||
var detailContentsHolder = this.getContentHolder();
|
||
var thisInstance = this;
|
||
var aDeferred = jQuery.Deferred();
|
||
if(url.indexOf('index.php') < 0) {
|
||
url = 'index.php?' + url;
|
||
}
|
||
var params = [];
|
||
params.url = url;
|
||
if(typeof data != 'undefined'){
|
||
params.data = data;
|
||
}
|
||
app.helper.showProgress();
|
||
app.request.pjax(params).then(function(error,response){
|
||
detailContentsHolder.html(response);
|
||
aDeferred.resolve(response);
|
||
app.helper.hideProgress();
|
||
if(detailContentsHolder.find('#workSpace').length !=0) {
|
||
thisInstance.loadGanttChart(detailContentsHolder);
|
||
}
|
||
});
|
||
return aDeferred.promise();
|
||
},
|
||
|
||
/**
|
||
* Function to register events for project tasks widget
|
||
*/
|
||
registerEventsForTasksWidget : function(summaryViewContainer) {
|
||
var thisInstance = this;
|
||
var tasksWidget = summaryViewContainer.find('.widgetContainer_tasks');
|
||
tasksWidget.on('click', '.editTaskDetails', function(e) {
|
||
var currentTarget = jQuery(e.currentTarget);
|
||
var newValue = currentTarget.text();
|
||
var element = currentTarget.closest('ul.dropdown-menu');
|
||
var editElement = element.closest('.dropdown');
|
||
var oldValue = element.data('oldValue');
|
||
if(currentTarget.hasClass('emptyOption')) {
|
||
newValue = '';
|
||
}
|
||
vtUtils.hideValidationMessage(editElement);
|
||
if(element.data('mandatory') && newValue.length <= 0) {
|
||
var result = app.vtranslate('JS_REQUIRED_FIELD');
|
||
vtUtils.showValidationMessage(editElement, result);
|
||
return false;
|
||
}
|
||
if(oldValue != newValue) {
|
||
var params = {
|
||
action : 'SaveAjax',
|
||
record : element.data('recordid'),
|
||
field : element.data('fieldname'),
|
||
value : newValue,
|
||
module : 'ProjectTask'
|
||
};
|
||
app.helper.showProgress();
|
||
app.request.post({data: params}).then(
|
||
function(error, data) {
|
||
app.helper.hideProgress();
|
||
thisInstance.showRelatedRecords(tasksWidget);
|
||
}
|
||
);
|
||
}
|
||
})
|
||
},
|
||
|
||
/**
|
||
* Function to get the related records list
|
||
* summary view widget
|
||
*/
|
||
showRelatedRecords : function(summaryWidgetContainer) {
|
||
var widgetHeaderContainer = summaryWidgetContainer.find('.widget_header');
|
||
var widgetDataContainer = summaryWidgetContainer.find('.widget_contents');
|
||
var referenceModuleName = widgetHeaderContainer.find('[name="relatedModule"]').val();
|
||
var module = app.getModuleName();
|
||
var params = {};
|
||
|
||
if(referenceModuleName == 'ProjectTask') {
|
||
var statusCondition = {};
|
||
var selectedStatus = jQuery('[name="projecttaskstatus"]', widgetHeaderContainer).val();
|
||
if(typeof selectedStatus != "undefined" && selectedStatus.length > 0) {
|
||
statusCondition['vtiger_projecttask.projecttaskstatus'] = selectedStatus;
|
||
params['whereCondition'] = statusCondition;
|
||
}
|
||
var selectedProgress = jQuery('[name="projecttaskprogress"]', widgetHeaderContainer).val();
|
||
if(typeof selectedProgress != "undefined" && selectedProgress.length > 0) {
|
||
statusCondition['vtiger_projecttask.projecttaskprogress'] = selectedProgress;
|
||
params['whereCondition'] = statusCondition;
|
||
}
|
||
}
|
||
|
||
params['record'] = this.getRecordId();
|
||
params['view'] = 'Detail';
|
||
params['module'] = module;
|
||
params['page'] = widgetDataContainer.find('[name="page"]').val();
|
||
params['limit'] = widgetDataContainer.find('[name="pageLimit"]').val();
|
||
params['relatedModule'] = referenceModuleName;
|
||
params['mode'] = 'showRelatedRecords';
|
||
|
||
app.helper.showProgress();
|
||
app.request.post({data: params}).then(
|
||
function(error, data) {
|
||
app.helper.hideProgress();
|
||
widgetDataContainer.html(data);
|
||
}
|
||
);
|
||
},
|
||
|
||
registerGanttChartEvents : function(container) {
|
||
this.registerZoomButtons(container);
|
||
this.registerTaskEdit(container);
|
||
this.registerRecordUpdateEvent(container);
|
||
this.registerGanttSorting(container);
|
||
},
|
||
|
||
registerZoomButtons : function(container) {
|
||
|
||
container.on('click', '.zoomIn', function(e){
|
||
e.preventDefault();
|
||
jQuery("#workSpace").trigger('zoomPlus.gantt');
|
||
});
|
||
|
||
container.on('click', '.zoomOut', function(e){
|
||
e.preventDefault();
|
||
jQuery("#workSpace").trigger('zoomMinus.gantt');
|
||
});
|
||
},
|
||
|
||
registerTaskEdit : function (container) {
|
||
var thisInstance = this;
|
||
container.on('click', '.editTask', function(e) {
|
||
var element = jQuery(e.currentTarget);
|
||
var params = {
|
||
'module' : 'ProjectTask',
|
||
'view' : 'QuickEditAjax',
|
||
'returnview' : 'Detail',
|
||
'returnmode' : 'showChart',
|
||
'returnmodule' : app.getModuleName(),
|
||
'returnrecord' : thisInstance.getRecordId(),
|
||
'parentid' : thisInstance.getRecordId(),
|
||
'record' : element.data('recordid')
|
||
}
|
||
app.helper.showProgress();
|
||
app.request.post({data: params}).then(
|
||
function(error, data) {
|
||
app.helper.hideProgress();
|
||
var callBackFunction = function(data) {
|
||
var form = data.find('.recordEditView');
|
||
var params = {
|
||
submitHandler: function(form) {
|
||
form = jQuery(form);
|
||
if(form.attr('id') == 'projectTaskQuickEditForm') {
|
||
app.helper.showProgress();
|
||
thisInstance.saveTask(form).then(function(err, data) {
|
||
app.helper.hideProgress();
|
||
if (err === null) {
|
||
jQuery('.vt-notification').remove();
|
||
app.helper.hideModal();
|
||
// to reload chart
|
||
jQuery('[data-label-key=Chart]').click();
|
||
} else {
|
||
app.event.trigger('post.save.failed', err);
|
||
}
|
||
});
|
||
}
|
||
},
|
||
validationMeta: quickcreate_uimeta
|
||
};
|
||
form.vtValidate(params);
|
||
}
|
||
var modalWindowParams = {
|
||
cb : callBackFunction
|
||
}
|
||
app.helper.showModal(data, modalWindowParams);
|
||
}
|
||
);
|
||
});
|
||
},
|
||
|
||
registerRecordUpdateEvent : function(container) {
|
||
container.on('updateTaskRecord.gantt','#workSpace', function(e,task) {
|
||
var dateFormat = vtUtils.getMomentDateFormat();
|
||
var startDate = moment(task.start).format(dateFormat);
|
||
var endDate = moment(task.end).format(dateFormat);
|
||
if((task.oldstart != '' && task.oldend != '') && (task.oldstart != startDate || task.oldend != endDate)) {
|
||
var params = {
|
||
'module' : 'ProjectTask',
|
||
'action' : 'SaveTask',
|
||
'record' : task.recordid,
|
||
'startdate' : startDate,
|
||
'enddate' : endDate
|
||
}
|
||
app.helper.showProgress();
|
||
app.request.post({data: params}).then(
|
||
function(error, data) {
|
||
app.helper.hideProgress();
|
||
if (error === null) {
|
||
jQuery('.vt-notification').remove();
|
||
} else {
|
||
app.event.trigger('post.save.failed', error);
|
||
}
|
||
}
|
||
);
|
||
}
|
||
});
|
||
},
|
||
|
||
sortResults: function(arr, prop, asc) {
|
||
var thisInstance = this;
|
||
arr = arr.sort(function(a, b) {
|
||
if (asc) {
|
||
if (a[prop] === parseInt(a[prop], 10) && b[prop] === parseInt(b[prop], 10)) {
|
||
return a[prop]-b[prop];
|
||
} else if( thisInstance.isDate(a[prop]) && thisInstance.isDate(b[prop])) {
|
||
return new Date(a[prop]).getTime() - new Date(b[prop]).getTime();
|
||
} else {
|
||
return thisInstance.sortAlphabetically(a[prop], b[prop]);
|
||
}
|
||
} else {
|
||
if (a[prop] === parseInt(a[prop], 10) && b[prop] === parseInt(b[prop], 10)) {
|
||
return b[prop]-a[prop];
|
||
} else if( thisInstance.isDate(a[prop]) && thisInstance.isDate(b[prop])) {
|
||
return new Date(b[prop]).getTime() - new Date(a[prop]).getTime();
|
||
} else {
|
||
return thisInstance.sortAlphabetically(b[prop], a[prop]);
|
||
}
|
||
}
|
||
});
|
||
|
||
return arr;
|
||
},
|
||
|
||
isDate: function(date) {
|
||
return (new Date(date) !== "Invalid Date" && !isNaN(new Date(date)) ) ? true : false;
|
||
},
|
||
|
||
sortAlphabetically : function(a, b) {
|
||
var nameA = a.toLowerCase();
|
||
var nameB = b.toLowerCase()
|
||
if (nameA < nameB) {
|
||
return -1;
|
||
}
|
||
if (nameA > nameB) {
|
||
return 1;
|
||
}
|
||
|
||
return 0;
|
||
},
|
||
|
||
registerGanttSorting : function(container) {
|
||
var thisInstance = this;
|
||
container.on('click', '.gdfColHeader', function(e) {
|
||
var element = jQuery(e.currentTarget);
|
||
var text = element.data('text');
|
||
var name = element.data('name');
|
||
var order = element.data('nextorder');
|
||
if(name) {
|
||
container.find('.gdfColHeader .fa.fa-chevron-down').remove();
|
||
container.find('.gdfColHeader .fa.fa-chevron-up').remove();
|
||
var descTemplate = '<i class="fa fa-chevron-down"></i> ' + text;
|
||
var ascTemplate = '<i class="fa fa-chevron-up"></i>' + text ;
|
||
if(!order) {
|
||
order = false;
|
||
element.html(descTemplate);
|
||
} else if(order == 'asc') {
|
||
order = true;
|
||
element.html(ascTemplate);
|
||
} else if(order == 'desc') {
|
||
order = false;
|
||
element.html(descTemplate);
|
||
}
|
||
|
||
var data = JSON.parse($("#projecttasks").val());
|
||
data.tasks = thisInstance.sortResults(data.tasks, name, order);
|
||
if(order == false) {
|
||
order = 'asc';
|
||
} else {
|
||
order = 'desc';
|
||
}
|
||
element.data('nextorder', order);
|
||
var gantt = Project_Detail_Js.gantt;
|
||
gantt.loadProject(data);
|
||
gantt.checkpoint(); //empty the undo stack
|
||
}
|
||
});
|
||
},
|
||
|
||
saveTask : function(form) {
|
||
var aDeferred = jQuery.Deferred();
|
||
var formData = form.serializeFormData();
|
||
app.request.post({data: formData}).then(
|
||
function(error, data) {
|
||
//TODO: App Message should be shown
|
||
aDeferred.resolve(error, data);
|
||
},
|
||
function(textStatus, errorThrown) {
|
||
aDeferred.reject(textStatus, errorThrown);
|
||
}
|
||
);
|
||
return aDeferred.promise();
|
||
},
|
||
|
||
registerEvents : function(){
|
||
var detailContentsHolder = this.getContentHolder();
|
||
var thisInstance = this;
|
||
this._super();
|
||
|
||
detailContentsHolder.on('click','.moreRecentMilestones', function(){
|
||
var recentMilestonesTab = thisInstance.getTabByLabel(thisInstance.detailViewRecentMileStonesLabel);
|
||
recentMilestonesTab.trigger('click');
|
||
});
|
||
|
||
detailContentsHolder.on('click','.moreRecentTickets', function(){
|
||
var recentTicketsTab = thisInstance.getTabByLabel(thisInstance.detailViewRecentTicketsTabLabel);
|
||
recentTicketsTab.trigger('click');
|
||
});
|
||
|
||
detailContentsHolder.on('click','.moreRecentTasks', function(){
|
||
var recentTasksTab = thisInstance.getTabByLabel(thisInstance.detailViewRecentTasksTabLabel);
|
||
recentTasksTab.trigger('click');
|
||
});
|
||
|
||
var detailViewContainer = jQuery('.detailViewContainer');
|
||
thisInstance.registerGanttChartEvents(detailViewContainer);
|
||
if(detailViewContainer.find('#workSpace').length != 0) {
|
||
this.loadGanttChart(detailViewContainer);
|
||
}
|
||
}
|
||
}) |