From 346618069e0fa94e73c4177825f9d8248e034b72 Mon Sep 17 00:00:00 2001 From: mac Date: Thu, 25 Jun 2026 17:37:32 +0300 Subject: [PATCH] Actual prod --- .../app/src/controllers/CommonController.php | 1194 +++++++++++++++-- 1 file changed, 1082 insertions(+), 112 deletions(-) diff --git a/api/v2/app/src/controllers/CommonController.php b/api/v2/app/src/controllers/CommonController.php index 694015a..7669984 100644 --- a/api/v2/app/src/controllers/CommonController.php +++ b/api/v2/app/src/controllers/CommonController.php @@ -5,6 +5,17 @@ namespace App\v2\Controller; class CommonController extends ApiController { + // Offset-free: листинг парсера (external_listings) различается по ЯВНОМУ флагу из запроса. + // Реальный el.id листинга коллизит с objects.id, поэтому различить его по id нельзя. + // Канон полей: is_external — объект-листинг; is_external_listing_event — событие листинга (echo'ит mJW обратно). + // Хелпер приводит присланный флаг (1 / '1' / true / 'true') к булеву признаку. + private static function _request_flag($src, $key) { + if (!is_array($src) || !isset($src[$key])) + return false; + $v = $src[$key]; + return ($v === true || $v === 1 || $v === '1' || $v === 'true'); + } + public function getEmployees($app, $get = null, $post = null) { $error = false; @@ -228,32 +239,46 @@ class CommonController extends ApiController $userIds[] = $userId; $who_work = 0; if($id > 0){ - - $sql = "SELECT * FROM clients where id = {$id}"; - if($section == 'requisitions'){ - $sql = "SELECT * FROM requisitions where id = {$id}"; - } - if($section == 'objects'){ - $sql = "SELECT id, id_add_user as who_work FROM objects WHERE id = {$id}"; - } - //echo $sql; - $q = mysql_query($sql); - $r = mysql_fetch_assoc($q); - - if (isset($r['doers']) && !empty($r['doers'])) { - $doers = json_decode(html_entity_decode($r['doers']), true); - - foreach ($doers as $user_id => $d){ - if ($d == 1){ - $userIds[] = (int)$user_id; + + // Найденный листинг парсера (offset-free): строки в objects нет — ни владельца, ни doers. + // Признак листинга — явный флаг is_external из запроса (id больше не диапазонный: el.id коллизит с objects.id). + // Ответственного выбираем по той же иерархии видимости, что и раздел «Задачи» (как на десктопе + // select_form_who_work_tasks.php): getUsersFilter вернёт подчинённых по правам (рядовой агент — только себя). + if($section == 'objects' && self::_request_flag($get, 'is_external')){ + $cl = new \Clients(); + $hierarchyIds = $cl->getUsersFilter(array(), $_SESSION['id'], $_SESSION['users_admin']); + if(is_array($hierarchyIds)){ + foreach($hierarchyIds as $hid){ + $userIds[] = (int)$hid; } } + } else { + $sql = "SELECT * FROM clients where id = {$id}"; + if($section == 'requisitions'){ + $sql = "SELECT * FROM requisitions where id = {$id}"; + } + if($section == 'objects'){ + $sql = "SELECT id, id_add_user as who_work FROM objects WHERE id = {$id}"; + } + //echo $sql; + $q = mysql_query($sql); + $r = mysql_fetch_assoc($q); + + if (isset($r['doers']) && !empty($r['doers'])) { + $doers = json_decode(html_entity_decode($r['doers']), true); + + foreach ($doers as $user_id => $d){ + if ($d == 1){ + $userIds[] = (int)$user_id; + } + } + } + if($r['who_work'] > 0){ + $userIds[] = (int)$r['who_work']; + $who_work = (int)$r['who_work']; + } } - if($r['who_work'] > 0){ - $userIds[] = (int)$r['who_work']; - $who_work = (int)$r['who_work']; - } - + } //Определение отделов @@ -2110,7 +2135,7 @@ class CommonController extends ApiController } $is_default = false; - if ($use_custom) { + /*if ($use_custom) { $is_default = true; $funnels[] = [ 'id' => 0, @@ -2154,6 +2179,29 @@ class CommonController extends ApiController } else { $error = true; $errors[] = mysql_error(); + }*/ + + $funnelClass = new \Funnel(); + $funnelClass->set_agency_id($agency_id); + $funnelClass->set_user_id($user_id); + $funnelsRaw = $funnelClass->get_funnels($section); + $funnels = array(); + if (is_array($funnelsRaw)) { + foreach ($funnelsRaw as $rF) { + $is_default_custom = false; + if (!$is_default && (int)$rF['$funnel'] == 0) { + $is_default_custom = true; + $is_default = true; + } + $funnels[] = array( + 'id' => (int)$rF['id'], + 'name' => (isset($rF['name']) && $rF['name'] !== null && $rF['name'] !== '') + ? (string)$rF['name'] + : 'Обычные', + 'count' => ($funnelCounts[intval($rF['id'])] > 0) ? intval($funnelCounts[intval($rF['id'])]) : null, + 'is_default' => $is_default_custom + ); + } } if (!$error) { @@ -3079,8 +3127,16 @@ class CommonController extends ApiController $protocol = (self::is_ssl()) ? 'https://' : 'http://'; $host = $protocol . $_SERVER['SERVER_NAME']; - $sql = "SELECT * FROM clients_files as c + // Найденный листинг парсера (offset-free): событие-родитель файла лежит в external_listing_events, + // event_id и object_id хранятся как РЕАЛЬНЫЕ el.id (без смещения) — валидируем владение по листинговой + // таблице. Признак листинга — явный флаг is_external из запроса (id больше не диапазонный: коллизит с objects.id). + if ($section == 'objects' && self::_request_flag($get, 'is_external')) { + $sql = "SELECT * FROM clients_files as c + WHERE object_id = {$source_id} AND event_id > 0 AND (SELECT id FROM external_listing_events WHERE id = c.event_id) > 0"; + } else { + $sql = "SELECT * FROM clients_files as c WHERE {$field} = {$source_id} AND event_id > 0 AND (SELECT id from {$table} WHERE id = c.event_id) > 0"; + } if ($q = $pdo->query($sql)) { if ($pdo->num_rows($q) > 0) { @@ -3849,6 +3905,20 @@ class CommonController extends ApiController if ($event_id && $type == 'transfer-object' && isset($data['object_id'])) { $object_id = (int)$data['object_id']; + + // Защитный отказ — приём передачи владения на найденном листинге парсера недоступен (offset-free). + // Признак листинга — явный флаг is_external из запроса. Передачи листинга быть не должно (инициация + // загейчена), гейтим от рассинхрона. Делать ДО UPDATE objects. + if (self::_request_flag($data, 'is_external')) { + $app->response->header('Content-Type', 'application/json'); + $app->response->setStatus(403); + $app->response->setBody(json_encode([ + 'success' => false, + 'errors' => ['Действие недоступно для найденного листинга. Скопируйте объект в свои, чтобы управлять им.'], + ], JSON_UNESCAPED_UNICODE)); + $app->stop(); + } + $sql = "SELECT * FROM objects_to_send WHERE id = $event_id AND object_id = $object_id"; if ($rez = mysql_query($sql)) { $row = mysql_fetch_assoc($rez); @@ -4076,6 +4146,16 @@ class CommonController extends ApiController $error = true; $errors[] = mysql_error(); } + + // синкаем нормализованную таблицу, которую читает десктоп (Clients → clients_doers WHERE confirm=1) + $sql = "UPDATE clients_doers SET confirm = 1 WHERE client_id = $client_id AND user_id = $user_id"; + if ($requisition_id > 0) + $sql = "UPDATE requisition_doers SET confirm = 1 WHERE requisition_id = $requisition_id AND user_id = $user_id"; + + if (!mysql_query($sql)) { + $error = true; + $errors[] = mysql_error(); + } } } else { $error = true; @@ -4634,23 +4714,50 @@ class CommonController extends ApiController if (!is_null($object_id)) { - $sql = "SELECT * FROM objects WHERE id=$object_id"; + // Найденный листинг парсера (offset-free): строки в objects нет, образ собираем из external_listings + // по РЕАЛЬНОМУ el.id. Признак листинга — явный флаг is_external из запроса (id коллизит с objects.id). + require_once $_SERVER['DOCUMENT_ROOT'] . '/engine/helpers/external_listing_legacy.php'; + $is_listing = self::_request_flag($data, 'is_external'); - if ($rez = mysql_query($sql)) { - $obj = mysql_fetch_assoc($rez); + $obj = false; + $obj_found = false; + if ($is_listing) { + $obj = \external_listing_object_row($object_id, false); + if (is_null($obj)) { + // Листинг удалён по TTL — отвечаем ошибкой, как для ненайденного объекта. + $error = true; + $errors[] = 'Объявление снято с публикации'; + } else { + // Поля внешнего источника экранируем для прямой подстановки в SQL. + $obj['nazv'] = mysql_real_escape_string($obj['nazv']); + $obj['adres'] = mysql_real_escape_string($obj['adres']); + $obj_found = true; + } + } else { + $sql = "SELECT * FROM objects WHERE id=$object_id"; + if ($rez = mysql_query($sql)) { + $obj = mysql_fetch_assoc($rez); + $obj_found = true; + } + } + + if ($obj_found) { + + // Листинг адресуется явным маркером src=ext (bare id уже не различает листинг от своего объекта). + $src_marker = $is_listing ? '&src=ext' : ''; if ($send_type == 2) { - $pdfs = $this->_getPDF([$object_id], $descriptions, $new_prices, $hide_contacts); + $pdfs = $this->_getPDF([$object_id], $descriptions, $new_prices, $hide_contacts, $is_listing ? [$object_id] : []); if (isset($pdfs[$object_id]['link'])) $linkUrl = $pdfs[$object_id]['link']; } else { if (self::is_ssl()) - $linkUrl = "https://joywork.ru/object-view.php?id=$object_id&token=" . md5($user_id); + $linkUrl = "https://joywork.ru/object-view.php?id=$object_id&token=" . md5($user_id) . $src_marker; else - $linkUrl = "http://joywork.ru/object-view.php?id=$object_id&token=" . md5($user_id); + $linkUrl = "http://joywork.ru/object-view.php?id=$object_id&token=" . md5($user_id) . $src_marker; } @@ -4667,14 +4774,32 @@ class CommonController extends ApiController if (in_array($object_id, $hide_contacts)) $close_contact = 1; - $sql_up = "INSERT INTO user_object_contact_close SET close={$close_contact}, user_id={$user_id}, object_id = {$object_id}, client_id = {$client_id}"; - if (!mysql_query($sql_up)) { - $error = true; - $errors[] = mysql_error(); + // Для найденного листинга флаг скрытия контакта не пишем — его контакт скрыт всегда. + if (!$is_listing) { + $sql_up = "INSERT INTO user_object_contact_close SET close={$close_contact}, user_id={$user_id}, object_id = {$object_id}, client_id = {$client_id}"; + if (!mysql_query($sql_up)) { + $error = true; + $errors[] = mysql_error(); + } } $token = md5(microtime()); - $sql = "INSERT INTO sended_pdf(id_agent, id_object, date_send, id_client, nazv, path, send_type, close_contact, token, new_price) VALUES('$user_id', '$object_id', NOW(), '$client_id', '$obj[nazv] $obj[adres]', '$linkUrl', $send_type, $close_contact, '$token', '$new_price')"; + + // Per-send описание, переданное mJW в POST-параметре `descriptions`. + $descriptionForInsert = "NULL"; + if (isset($descriptions[intval($object_id)]) && $descriptions[intval($object_id)] !== '') { + $cleanedDesc = cleanHtml($descriptions[intval($object_id)], '