401 lines
14 KiB
PHP
401 lines
14 KiB
PHP
<?php
|
|
|
|
namespace App\Modules\CRM\Controllers;
|
|
|
|
use App\Controllers\BaseController;
|
|
use App\Modules\CRM\Models\ContactModel;
|
|
use App\Modules\Clients\Models\ClientModel;
|
|
|
|
class ContactsController extends BaseController
|
|
{
|
|
protected ContactModel $contactModel;
|
|
protected ClientModel $clientModel;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->contactModel = new ContactModel();
|
|
$this->clientModel = new ClientModel();
|
|
}
|
|
|
|
/**
|
|
* Конфигурация таблицы контактов
|
|
*/
|
|
protected function getContactsTableConfig(): array
|
|
{
|
|
$organizationId = $this->requireActiveOrg();
|
|
|
|
return [
|
|
'id' => 'contacts-table',
|
|
'url' => '/crm/contacts/table',
|
|
'model' => $this->contactModel,
|
|
'columns' => [
|
|
'id' => ['label' => 'ID', 'width' => '60px'],
|
|
'name' => ['label' => 'Имя'],
|
|
'email' => ['label' => 'Email', 'width' => '180px'],
|
|
'phone' => ['label' => 'Телефон', 'width' => '140px'],
|
|
'position' => ['label' => 'Должность', 'width' => '150px'],
|
|
'customer_name' => ['label' => 'Клиент'],
|
|
'created_at' => ['label' => 'Дата', 'width' => '100px'],
|
|
],
|
|
'searchable' => ['name', 'email', 'phone', 'position', 'customer_name'],
|
|
'sortable' => ['id', 'name', 'created_at'],
|
|
'defaultSort' => 'created_at',
|
|
'order' => 'desc',
|
|
'fieldMap' => [
|
|
'customer_name' => 'customers.name',
|
|
'name' => 'contacts.name',
|
|
'email' => 'contacts.email',
|
|
'phone' => 'contacts.phone',
|
|
'position' => 'contacts.position',
|
|
'created_at' => 'contacts.created_at',
|
|
'id' => 'contacts.id',
|
|
],
|
|
'scope' => function($builder) use ($organizationId) {
|
|
$builder->from('contacts')
|
|
->select('contacts.id, contacts.name, contacts.email, contacts.phone, contacts.position, contacts.created_at, contacts.deleted_at, customers.name as customer_name')
|
|
->join('organizations_clients customers', 'customers.id = contacts.customer_id', 'left')
|
|
->where('contacts.organization_id', $organizationId)
|
|
->where('contacts.deleted_at', null);
|
|
},
|
|
'actions' => ['label' => 'Действия', 'width' => '120px'],
|
|
'actionsConfig' => [
|
|
[
|
|
'label' => '',
|
|
'url' => '/crm/contacts/{id}/edit',
|
|
'icon' => 'fa-solid fa-pen',
|
|
'class' => 'btn-outline-primary',
|
|
'title' => 'Редактировать',
|
|
],
|
|
],
|
|
'emptyMessage' => 'Контактов пока нет',
|
|
'emptyIcon' => 'fa-solid fa-users',
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Список контактов
|
|
*/
|
|
public function index()
|
|
{
|
|
$config = $this->getContactsTableConfig();
|
|
$tableHtml = $this->renderTable($config);
|
|
|
|
return $this->renderTwig('@CRM/contacts/index', [
|
|
'title' => 'Контакты',
|
|
'tableHtml' => $tableHtml,
|
|
'config' => $config,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* AJAX таблица контактов
|
|
*/
|
|
public function contactsTable()
|
|
{
|
|
return parent::table($this->getContactsTableConfig(), '/crm/contacts');
|
|
}
|
|
|
|
/**
|
|
* Форма создания контакта
|
|
*/
|
|
public function create()
|
|
{
|
|
$organizationId = $this->requireActiveOrg();
|
|
|
|
$clients = $this->clientModel
|
|
->where('organization_id', $organizationId)
|
|
->findAll();
|
|
|
|
return $this->renderTwig('@CRM/contacts/form', [
|
|
'title' => 'Новый контакт',
|
|
'actionUrl' => '/crm/contacts',
|
|
'clients' => $clients,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Сохранить новый контакт
|
|
*/
|
|
public function store()
|
|
{
|
|
$organizationId = $this->requireActiveOrg();
|
|
|
|
$data = [
|
|
'organization_id' => $organizationId,
|
|
'customer_id' => $this->request->getPost('customer_id') ?: null,
|
|
'name' => $this->request->getPost('name'),
|
|
'email' => $this->request->getPost('email') ?: null,
|
|
'phone' => $this->request->getPost('phone') ?: null,
|
|
'position' => $this->request->getPost('position') ?: null,
|
|
'is_primary' => $this->request->getPost('is_primary') ? 1 : 0,
|
|
'notes' => $this->request->getPost('notes') ?: null,
|
|
];
|
|
|
|
$this->contactModel->save($data);
|
|
$contactId = $this->contactModel->getInsertID();
|
|
|
|
if ($contactId) {
|
|
return redirect()->to('/crm/contacts')->with('success', 'Контакт успешно создан');
|
|
}
|
|
|
|
return redirect()->back()->with('error', 'Ошибка при создании контакта')->withInput();
|
|
}
|
|
|
|
/**
|
|
* Форма редактирования контакта
|
|
*/
|
|
public function edit(int $id)
|
|
{
|
|
$organizationId = $this->requireActiveOrg();
|
|
|
|
$contact = $this->contactModel->find($id);
|
|
|
|
if (!$contact || $contact->organization_id !== $organizationId) {
|
|
return redirect()->to('/crm/contacts')->with('error', 'Контакт не найден');
|
|
}
|
|
|
|
$clients = $this->clientModel
|
|
->where('organization_id', $organizationId)
|
|
->findAll();
|
|
|
|
return $this->renderTwig('@CRM/contacts/form', [
|
|
'title' => 'Редактирование контакта',
|
|
'actionUrl' => "/crm/contacts/{$id}",
|
|
'contact' => $contact,
|
|
'clients' => $clients,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Обновить контакт
|
|
*/
|
|
public function update(int $id)
|
|
{
|
|
$organizationId = $this->requireActiveOrg();
|
|
|
|
$contact = $this->contactModel->find($id);
|
|
|
|
if (!$contact || $contact->organization_id !== $organizationId) {
|
|
return redirect()->to('/crm/contacts')->with('error', 'Контакт не найден');
|
|
}
|
|
|
|
$data = [
|
|
'customer_id' => $this->request->getPost('customer_id') ?: null,
|
|
'name' => $this->request->getPost('name'),
|
|
'email' => $this->request->getPost('email') ?: null,
|
|
'phone' => $this->request->getPost('phone') ?: null,
|
|
'position' => $this->request->getPost('position') ?: null,
|
|
'is_primary' => $this->request->getPost('is_primary') ? 1 : 0,
|
|
'notes' => $this->request->getPost('notes') ?: null,
|
|
];
|
|
|
|
$this->contactModel->update($id, $data);
|
|
|
|
return redirect()->to('/crm/contacts')->with('success', 'Контакт обновлён');
|
|
}
|
|
|
|
/**
|
|
* Удалить контакт
|
|
*/
|
|
public function destroy(int $id)
|
|
{
|
|
$organizationId = $this->requireActiveOrg();
|
|
|
|
$contact = $this->contactModel->find($id);
|
|
|
|
if (!$contact || $contact->organization_id !== $organizationId) {
|
|
return redirect()->to('/crm/contacts')->with('error', 'Контакт не найден');
|
|
}
|
|
|
|
$this->contactModel->delete($id);
|
|
|
|
return redirect()->to('/crm/contacts')->with('success', 'Контакт удалён');
|
|
}
|
|
|
|
// =========================================================================
|
|
// AJAX API для inline-редактирования в модуле Clients
|
|
// =========================================================================
|
|
|
|
/**
|
|
* Получить список контактов клиента (AJAX)
|
|
* GET /crm/contacts/list/{clientId}
|
|
*/
|
|
public function ajaxList(int $clientId)
|
|
{
|
|
$organizationId = $this->requireActiveOrg();
|
|
|
|
// Проверяем что клиент принадлежит организации
|
|
$client = $this->clientModel->forCurrentOrg()->find($clientId);
|
|
if (!$client) {
|
|
return $this->response->setJSON([
|
|
'success' => false,
|
|
'message' => 'Клиент не найден',
|
|
]);
|
|
}
|
|
|
|
$contacts = $this->contactModel
|
|
->where('organization_id', $organizationId)
|
|
->where('customer_id', $clientId)
|
|
->orderBy('name', 'ASC')
|
|
->findAll();
|
|
|
|
$items = array_map(function ($contact) {
|
|
return [
|
|
'id' => $contact->id,
|
|
'name' => $contact->name,
|
|
'email' => $contact->email,
|
|
'phone' => $contact->phone,
|
|
'position' => $contact->position,
|
|
];
|
|
}, $contacts);
|
|
|
|
return $this->response->setJSON([
|
|
'success' => true,
|
|
'items' => $items,
|
|
'total' => count($items),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Создать контакт (AJAX)
|
|
* POST /crm/contacts/store
|
|
*/
|
|
public function ajaxStore()
|
|
{
|
|
$organizationId = $this->requireActiveOrg();
|
|
$customerId = $this->request->getPost('customer_id');
|
|
|
|
// Проверяем клиента если указан
|
|
if ($customerId) {
|
|
$client = $this->clientModel->forCurrentOrg()->find($customerId);
|
|
if (!$client) {
|
|
return $this->response->setJSON([
|
|
'success' => false,
|
|
'message' => 'Клиент не найден',
|
|
])->setStatusCode(422);
|
|
}
|
|
}
|
|
|
|
$data = [
|
|
'organization_id' => $organizationId,
|
|
'customer_id' => $customerId ?: null,
|
|
'name' => $this->request->getPost('name'),
|
|
'email' => $this->request->getPost('email') ?: null,
|
|
'phone' => $this->request->getPost('phone') ?: null,
|
|
'position' => $this->request->getPost('position') ?: null,
|
|
];
|
|
|
|
// Валидация
|
|
if (empty($data['name'])) {
|
|
return $this->response->setJSON([
|
|
'success' => false,
|
|
'message' => 'Имя контакта обязательно',
|
|
'errors' => ['name' => 'Имя контакта обязательно'],
|
|
])->setStatusCode(422);
|
|
}
|
|
|
|
$contactId = $this->contactModel->insert($data);
|
|
|
|
if (!$contactId) {
|
|
return $this->response->setJSON([
|
|
'success' => false,
|
|
'message' => 'Ошибка при создании контакта',
|
|
'errors' => $this->contactModel->errors(),
|
|
])->setStatusCode(422);
|
|
}
|
|
|
|
return $this->response->setJSON([
|
|
'success' => true,
|
|
'message' => 'Контакт создан',
|
|
'item' => [
|
|
'id' => $contactId,
|
|
'name' => $data['name'],
|
|
'email' => $data['email'],
|
|
'phone' => $data['phone'],
|
|
'position' => $data['position'],
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Обновить контакт (AJAX)
|
|
* POST /crm/contacts/update/{id}
|
|
*/
|
|
public function ajaxUpdate(int $id)
|
|
{
|
|
$organizationId = $this->requireActiveOrg();
|
|
|
|
$contact = $this->contactModel->find($id);
|
|
|
|
if (!$contact || $contact->organization_id !== $organizationId) {
|
|
return $this->response->setJSON([
|
|
'success' => false,
|
|
'message' => 'Контакт не найден',
|
|
])->setStatusCode(404);
|
|
}
|
|
|
|
$data = [
|
|
'name' => $this->request->getPost('name'),
|
|
'email' => $this->request->getPost('email') ?: null,
|
|
'phone' => $this->request->getPost('phone') ?: null,
|
|
'position' => $this->request->getPost('position') ?: null,
|
|
];
|
|
|
|
// Валидация
|
|
if (empty($data['name'])) {
|
|
return $this->response->setJSON([
|
|
'success' => false,
|
|
'message' => 'Имя контакта обязательно',
|
|
'errors' => ['name' => 'Имя контакта обязательно'],
|
|
])->setStatusCode(422);
|
|
}
|
|
|
|
$result = $this->contactModel->update($id, $data);
|
|
|
|
if (!$result) {
|
|
return $this->response->setJSON([
|
|
'success' => false,
|
|
'message' => 'Ошибка при обновлении контакта',
|
|
'errors' => $this->contactModel->errors(),
|
|
])->setStatusCode(422);
|
|
}
|
|
|
|
return $this->response->setJSON([
|
|
'success' => true,
|
|
'message' => 'Контакт обновлён',
|
|
'item' => [
|
|
'id' => $id,
|
|
'name' => $data['name'],
|
|
'email' => $data['email'],
|
|
'phone' => $data['phone'],
|
|
'position' => $data['position'],
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Удалить контакт (AJAX)
|
|
* POST /crm/contacts/delete/{id}
|
|
*/
|
|
public function ajaxDelete(int $id)
|
|
{
|
|
$organizationId = $this->requireActiveOrg();
|
|
|
|
$contact = $this->contactModel->find($id);
|
|
|
|
if (!$contact || $contact->organization_id !== $organizationId) {
|
|
return $this->response->setJSON([
|
|
'success' => false,
|
|
'message' => 'Контакт не найден',
|
|
])->setStatusCode(404);
|
|
}
|
|
|
|
$this->contactModel->delete($id);
|
|
|
|
return $this->response->setJSON([
|
|
'success' => true,
|
|
'message' => 'Контакт удалён',
|
|
]);
|
|
}
|
|
}
|