From b14570835a0d026b78ae423cdd11f92c50fb7a75 Mon Sep 17 00:00:00 2001 From: mac Date: Fri, 3 Jul 2026 10:04:01 +0300 Subject: [PATCH] Actual prod --- engine/classes/Requisitions.php | 37 ++++- js/crm.js | 252 ++++++++++++++++++-------------- 2 files changed, 179 insertions(+), 110 deletions(-) diff --git a/engine/classes/Requisitions.php b/engine/classes/Requisitions.php index b0138e3..3a3c772 100644 --- a/engine/classes/Requisitions.php +++ b/engine/classes/Requisitions.php @@ -4836,6 +4836,36 @@ $sql = "SELECT * FROM `requisitions` WHERE id = $id"; $requisistion = $this->db->fetch_assoc($this->db->query($sql)); + // Вычисляем последний этап воронки + $lastStage = 8; // значение по умолчанию + $funnelId = intval($requisistion['funnel_id']); + if ($funnelId > 0) { + $q_step = $this->db->query("SELECT MAX(order_number) as last_stage FROM funnel_steps WHERE funnel_id = $funnelId AND deleted = 0"); + if ($q_step && $this->db->num_rows($q_step) > 0) { + $r_step = $this->db->fetch_assoc($q_step); + if ($r_step['last_stage'] !== null) { + $lastStage = intval($r_step['last_stage']); + } + } + } else { + // funnel_id = 0 — дефолтная воронка, берём по agency_id + $agencyId = $this->user->agencyId; + $q_default = $this->db->query("SELECT id FROM funnel_default WHERE agency_id = $agencyId LIMIT 1"); + if ($q_default && $this->db->num_rows($q_default) > 0) { + $r_default = $this->db->fetch_assoc($q_default); + $defaultFunnelId = intval($r_default['id']); + if ($defaultFunnelId > 0) { + $q_step = $this->db->query("SELECT MAX(order_number) as last_stage FROM funnel_steps WHERE funnel_id = $defaultFunnelId AND deleted = 0"); + if ($q_step && $this->db->num_rows($q_step) > 0) { + $r_step = $this->db->fetch_assoc($q_step); + if ($r_step['last_stage'] !== null) { + $lastStage = intval($r_step['last_stage']); + } + } + } + } + } + if ($requisistion['complex_status_id'] && $requisistion['complex_room_id']) { $complexStatus = new ComplexStatus((int)$requisistion['complex_status_id']); @@ -4845,11 +4875,12 @@ ], false, false); } - $sql = "UPDATE requisitions SET reason='".$select_text.". ".$post['reason']."', who_delete = '$user_id', deleted=1, stage=8, denial = $post[denial] WHERE id=$id"; + $sql = "UPDATE requisitions SET reason='".$select_text.". ".$post['reason']."', who_delete = '$user_id', deleted=1, stage=$lastStage, denial = $post[denial] WHERE id=$id"; if(isset($post['summa']) && $post['luck']){ if($dop_text != '') $dop_text .= " "; - $dop_text1 .= "Совершена сделка на ".$post['summa']." руб. ".$formatted_dateZajavki; - $sql = "UPDATE requisitions SET reason='$post[reason]', who_delete = '$user_id', deleted=1, summa='$post[summa]', confirm='$post[luck]' WHERE id=$id"; + $commission = isset($post['commission']) ? intval($post['commission']) : 0; + $dop_text1 = "Совершена сделка на ".$commission." руб. ".$formatted_dateZajavki; + $sql = "UPDATE requisitions SET reason='".$dop_text1."', who_delete = '$user_id', deleted=1, summa='$post[summa]', confirm='$post[luck]' WHERE id=$id"; } if ($this->db->query($sql)) { diff --git a/js/crm.js b/js/crm.js index c99b69f..838cf1a 100644 --- a/js/crm.js +++ b/js/crm.js @@ -1772,7 +1772,7 @@ function editEvent(id, type, client_id, req_id) { return false; } -function editEventObj(id, type) { +function editEventObj(id, type, object_id) { if (type != 'comment') { $("#addTaskBgObj").show(); @@ -1828,7 +1828,10 @@ function editEventObj(id, type) { } } else { - $.post("/ajax/getEventForObjId.php", { event_id: id }, function(data) { + // object_id (id найденного листинга) — чтобы getEventForObjId читал external_listing_events, + // а не чужую user_object_events при пересечении id; res.object_id вернётся id листинга и save (changeEventsObj) + // уйдёт в листинговую таблицу. + $.post("/ajax/getEventForObjId.php", { event_id: id, object_id: object_id }, function(data) { var res = JSON.parse(data); //console.log(type); @@ -1918,8 +1921,8 @@ function editEventObj(id, type) { } -function editNoteObj(id) { - $.post("/ajax/getNoteForObjId.php", { note_id: id }, function(data) { +function editNoteObj(id, object_id) { + $.post("/ajax/getNoteForObjId.php", { note_id: id, object_id: object_id }, function(data) { let res = JSON.parse(data); //console.log(data); @@ -2107,21 +2110,27 @@ function sendEventFilesWin(id, from) { $("body").addClass("lock"); } -function deleteEvent(id, from) { - if (confirm("Вы точно хотите удалить эту задачу?")) { - $.post('/ajax/deleteEvent.php', { - deleteId: id, - from: from || null - }, function() { - if ($('#chat_content_' + id).length > 0) { - $('#chat_content_' + id).closest('.chat-block').remove(); - } - $("#merepriation_bg").hide(); - $("#merepriation-history").hide(); - $("body").removeClass("lock"); - getCalendar(); - }); - } +function deleteEvent(id, from, kind) { + var isFile = (kind === 'file'); + jwConfirm({ + title: isFile ? 'Удаление файлов' : 'Удаление задачи', + text: isFile ? 'Вы точно хотите удалить эти файлы?' : 'Вы точно хотите удалить эту задачу?', + btnText: 'Удалить', + onConfirm: function() { + $.post('/ajax/deleteEvent.php', { + deleteId: id, + from: from || null + }, function() { + if ($('#chat_content_' + id).length > 0) { + $('#chat_content_' + id).closest('.chat-block').remove(); + } + $("#merepriation_bg").hide(); + $("#merepriation-history").hide(); + $("body").removeClass("lock"); + getCalendar(); + }); + } + }); } function showEventSubComment(id, from, event, sub_id) { @@ -2171,6 +2180,9 @@ function showEventSubComment(id, from, event, sub_id) { } function addEventSubComment(id, from, id_object, req_id, type = null) { + // листинг: id_object приходит числовым el.id без маркера; помечаем EXT-{n}, иначе reload панелей + // (getObjectInfoForEvents/getLogForEvents) примет el.id за objects.id (коллизия) → пустые паны (белая модалка) + if (from === 'listing' && String(id_object).indexOf('EXT-') !== 0) id_object = 'EXT-' + id_object; user_for = 0; if (!isEmpty(type) && type == 'moderation') { user_for = $('#sub_comment_who_work_' + id).val(); @@ -2215,75 +2227,95 @@ function addEventSubComment(id, from, id_object, req_id, type = null) { } function deleteEventSubComment(id, from, id_object, sub_id) { + // листинг: id_object приходит числовым el.id без маркера; помечаем EXT-{n}, иначе reload панелей + // (getObjectInfoForEvents/getLogForEvents) примет el.id за objects.id (коллизия) → пустые паны (белая модалка) + if (from === 'listing' && String(id_object).indexOf('EXT-') !== 0) id_object = 'EXT-' + id_object; var subId = 0; if (!isEmpty(sub_id)) { subId = sub_id; } - if (confirm("Вы точно хотите удалить комментарий МОП?")) { - $.post('/ajax/deleteEventSubComment.php', { - eventId: id, - from: from || null, - sub_id: subId - }, function() { - $.ajax({ - url: '/ajax/getObjectInfoForEvents.php?id=' + id_object, - success: function(data) { - $('#object-info-block').html(data); + jwConfirm({ + title: 'Удаление комментария', + text: 'Вы точно хотите удалить комментарий?', + btnText: 'Удалить', + onConfirm: function() { + $.post('/ajax/deleteEventSubComment.php', { + eventId: id, + from: from || null, + sub_id: subId + }, function() { + $.ajax({ + url: '/ajax/getObjectInfoForEvents.php?id=' + id_object, + success: function(data) { + $('#object-info-block').html(data); - $.ajax({ - url: '/ajax/getLogForEvents.php?object_id=' + id_object, - success: function(data) { - $('#event-chat').html(data); - $('.history__chat').scrollTop($('#event-chat').prop("scrollHeight")); - } - }); + $.ajax({ + url: '/ajax/getLogForEvents.php?object_id=' + id_object, + success: function(data) { + $('#event-chat').html(data); + $('.history__chat').scrollTop($('#event-chat').prop("scrollHeight")); + } + }); - setTimeout(function() { - $('#object-info-block .fotorama').fotorama(); - initializeMapOnEventWindow(); - }, 100); - } + setTimeout(function() { + $('#object-info-block .fotorama').fotorama(); + initializeMapOnEventWindow(); + }, 100); + } + }); }); - }); - } + } + }); } -function deleteNoteObj(id) { - if (confirm("Вы точно хотите удалить данное примечание?")) { - $.post('/ajax/deleteNote.php', { - deleteId: id - }, function() { +function deleteNoteObj(id, from) { + jwConfirm({ + title: 'Удаление примечания', + text: 'Вы точно хотите удалить данное примечание?', + btnText: 'Удалить', + onConfirm: function() { + // from='listing' → удаление в external_listing_notes, иначе object_notes (id-нумерации разные) + $.post('/ajax/deleteNote.php', { + deleteId: id, + from: from || 'objects' + }, function() { - if ($('#chat_content_' + id).length > 0) { + if ($('#chat_content_' + id).length > 0) { - let chat = $('#chat_content_' + id).closest('#object-notes'); - let object_id = chat.find('#submitTextButton2').data('id'); - $('#chat_content_' + id).closest('.chat-block').remove(); - if (chat.find('.chat-block').length == 0) - $('.addEditNote[data-id="' + object_id + '"]').removeClass('haveNotes'); + let chat = $('#chat_content_' + id).closest('#object-notes'); + let object_id = chat.find('#submitTextButton2').data('id'); + $('#chat_content_' + id).closest('.chat-block').remove(); + if (chat.find('.chat-block').length == 0) + $('.addEditNote[data-id="' + object_id + '"]').removeClass('haveNotes'); - } + } - $("body").removeClass("lock"); - }); - } + $("body").removeClass("lock"); + }); + } + }); } //Отменить задачу function cancelEvent(id) { - if (confirm("Вы точно хотите отменить эту задачу?")) { - $.post('/ajax/cancelEvent.php', { cancelId: id }, function() { - if ($('#chat_content_' + id).length > 0) { - $('#chat_content_' + id).closest('.chat-message').addClass('cancel'); - } - $('#groupAB__' + id).attr("data-cancel", "1"); + jwConfirm({ + title: 'Отмена задачи', + text: 'Вы точно хотите отменить эту задачу?', + btnText: 'Отменить задачу', + onConfirm: function() { + $.post('/ajax/cancelEvent.php', { cancelId: id }, function() { + if ($('#chat_content_' + id).length > 0) { + $('#chat_content_' + id).closest('.chat-message').addClass('cancel'); + } + $('#groupAB__' + id).attr("data-cancel", "1"); - /*$("#merepriation_bg").hide(); - $("#merepriation-history").hide(); - $("body").removeClass("lock");*/ - getCalendar(); - }); - } + /*$("#merepriation_bg").hide(); + $("#merepriation-history").hide(); + $("body").removeClass("lock");*/ + getCalendar(); + }); + } + }); } //Для фильтра клиентов в отправке презентаций @@ -3418,6 +3450,9 @@ function get_select_who_work_task(selector, section, id){ id = $('#submitTextButton').attr('data-id'); } + // offset-free: для найденного листинга (section=object) ответственного берём по иерархии видимости, а не по + // владельцу objects-строки (её нет, el.id коллизит). Маркер листинга — data-src="ext" окна задач (openEventsWindow). + var isExternal = (section == 'object') && ($('#submitTextButton').attr('data-src') === 'ext'); $(selector+" .check_who_work").html(''); if(id > 0) { @@ -3425,7 +3460,8 @@ function get_select_who_work_task(selector, section, id){ axios.post('/ajax/select_form_who_work_tasks.php', { id: id, - section: section + section: section, + is_external: isExternal ? 1 : 0 } ).then((response) => { @@ -4423,6 +4459,8 @@ $(document).ready(function() { $('body').on('click', '.complete-action-button-obj', function() { var event_id = $(this).attr('id').replace('groupAB__', ''); + // событие найденного листинга парсера завершается в своей таблице (data-from='listing'), иначе user_object_events + var from = $(this).attr('data-from') || 'objects'; var done = 0; $(this).toggleClass('active'); @@ -4430,7 +4468,7 @@ $(document).ready(function() { done = 1; } //console.log(done); - $.post('/ajax/addEditObject.php', { done_event: event_id, done: done }, function(data) { + $.post('/ajax/addEditObject.php', { done_event: event_id, done: done, from: from }, function(data) { //console.log(data); if (typeof type_calendar == 'object') { @@ -6249,11 +6287,12 @@ $(document).ready(function() { if (window.dealCloseData && window.dealCloseData.id) { param.luck = 10; var factPrice = $('#fact_contract_price').val(); + var factCommission = $('#fact_agent_commission').val(); param.summa = (factPrice !== '' && !isNaN(parseInt(factPrice))) ? parseInt(factPrice) : (window.dealCloseData.contract_price || 0); + param.commission = (factCommission !== '' && !isNaN(parseInt(factCommission))) ? parseInt(factCommission) : (window.dealCloseData.agent_commission || 0); param.datazakl = Date.parse(dataZZ); var factPayload = {}; - var factCommission = $('#fact_agent_commission').val(); if (factPrice !== '' && !isNaN(parseInt(factPrice))) factPayload.contract_price = parseInt(factPrice) || 0; if (factCommission !== '' && !isNaN(parseInt(factCommission))) factPayload.agent_commission = parseInt(factCommission) || 0; if (Object.keys(factPayload).length > 0) { @@ -6264,7 +6303,7 @@ $(document).ready(function() { data: JSON.stringify(factPayload) }); } - } else {Про + } else { if (isNaN(parseInt($('#summa_sdelki').val()))) { alert("Введите сумму сделки"); return; @@ -6275,46 +6314,45 @@ $(document).ready(function() { } $.post('/ajax/delClient.php', param, function(data) { - //console.log(data) - $('#client__' + id_client + ' .stage').addClass('active'); - $('#addEditNew .stage').addClass('active'); - requisitions_client.getList(); - $("#del_client_bg").fadeOut(500); - $("#del_client").toggle(10); - $("body").removeClass("lock"); - //$('#client__'+id_client+' .stagebar-title').text('Закрыт'); - //console.log($('#client_history').css('display')); - if ($('#client_history').css('display') != 'none') { - if (req_id > 0) { - openClientEventsWindowNew(0, $('#session_to_send').val(), 1, req_id); - } else { - openClientEventsWindowNew(id_client, $('#session_to_send').val(), 1); - } + //console.log(data) + $('#client__' + id_client + ' .stage').addClass('active'); + $('#addEditNew .stage').addClass('active'); + requisitions_client.getList(); + $("#del_client_bg").fadeOut(500); + $("#del_client").toggle(10); + $("body").removeClass("lock"); + //$('#client__'+id_client+' .stagebar-title').text('Закрыт'); + //console.log($('#client_history').css('display')); + if ($('#client_history').css('display') != 'none') { + if (req_id > 0) { + openClientEventsWindowNew(0, $('#session_to_send').val(), 1, req_id); + } else { + openClientEventsWindowNew(id_client, $('#session_to_send').val(), 1); } - if ($('.view-kanban.active').length > 0) { + } + if ($('.view-kanban.active').length > 0) { - var stage = $('#kanban_item_li_' + id_client).closest('.kanban__sortable').data("stage"); + var stage = $('#kanban_item_li_' + id_client).closest('.kanban__sortable').data("stage"); + if (document.location.pathname == '/requisitions.php') { + requisitions.getList(); + } else { + get_kanban_li(id_client, stage, 0); + } + } else { + if ($('#requisitions_list_object').css('display') == 'none') { + let sort_order = $('select[name=sort_order]').val(); + get_list($('.pagination li.active a').text(), sort_order, false); if (document.location.pathname == '/requisitions.php') { requisitions.getList(); - } else { - get_kanban_li(id_client, stage, 0); } } else { - if ($('#requisitions_list_object').css('display') == 'none') { - let sort_order = $('select[name=sort_order]').val(); - get_list($('.pagination li.active a').text(), sort_order, false); - if (document.location.pathname == '/requisitions.php') { - requisitions.getList(); - } - } else { - requisitions_object.getList(); + requisitions_object.getList(); - } } - $('#del_client #temp_id').val(0); - }); - } + } + $('#del_client #temp_id').val(0); + }); } else { param.denial = $('#denial_work').val(); //console.log(reason); @@ -11695,8 +11733,8 @@ function bindObjReq(clientId) { } //Открыть модл объекта -function openObjectModal(object_id, zindex) { - object_card.open(object_id, zindex); +function openObjectModal(object_id, zindex, is_external) { + object_card.open(object_id, zindex, is_external); } //Проверка на пустату