7 Commits

Author SHA1 Message Date
87eb66f06b WIP
Some checks failed
Telegram Mini App Shop Builder / Compute version metadata (push) Has been cancelled
Telegram Mini App Shop Builder / Run Frontend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run Backend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run PHP_CodeSniffer (push) Has been cancelled
Telegram Mini App Shop Builder / Build module. (push) Has been cancelled
Telegram Mini App Shop Builder / release (push) Has been cancelled
2026-03-11 21:52:01 +03:00
47bffc90b2 WIP 2026-03-11 21:49:07 +03:00
02ad7d83ef WIP 2026-03-11 21:48:59 +03:00
980f656a0a feat(admin): telegram settings improvements (#63)
Some checks failed
Telegram Mini App Shop Builder / Compute version metadata (push) Has been cancelled
Telegram Mini App Shop Builder / Run Frontend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run Backend tests (push) Has been cancelled
Telegram Mini App Shop Builder / Run PHP_CodeSniffer (push) Has been cancelled
Telegram Mini App Shop Builder / Build module. (push) Has been cancelled
Telegram Mini App Shop Builder / release (push) Has been cancelled
2026-02-23 15:17:34 +03:00
c0ca0c731d feat(cron): add scheduled jobs configuration in admin (#59)
* feat(cron): add database schedule jobs instead of file

* feat(cron): add scheduled jobs configuration in admin (#59)

* reformat: fix codestyle (#59)

* reformat: fix codestyle (#59)

* feat: disable cron debug (#59)
2026-02-23 15:17:33 +03:00
0295a4b28b feat(spa): Increase max page limit to product lists 2026-02-23 15:16:13 +03:00
91c5d56903 feat(sentry): Implement Sentry tracing (#50) 2026-02-23 15:16:11 +03:00
440 changed files with 5612 additions and 4852 deletions

Binary file not shown.

64
.cursor/agents.md Normal file
View File

@@ -0,0 +1,64 @@
# Cursor AI Agents Configuration
## Роли и правила поведения ИИ
### Основная роль: Senior Full-Stack Developer
Вы - опытный full-stack разработчик, специализирующийся на:
- OpenCart модульной разработке
- Кастомных фреймворках (OpenCart Framework)
- PHP 7.4+ с современными практиками
- Vue.js 3 (Composition API)
- Telegram Mini App разработке
### Правила работы с кодом
1. **Всегда используй существующие паттерны проекта**
2. **Не создавай дубликаты - используй существующие утилиты**
3. **Следуй соглашениям именования проекта**
4. **Тестируй изменения перед коммитом**
5. **Документируй публичные API**
6. **Комментарии только на английском языке и только если они действительно оправданы**
### Правила коммитов
1. **Следование Conventional Commits**
- Используй префиксы: `feat:`, `fix:`, `chore:`, `refactor:`, `style:`, `test:`, `docs:`
- Формат: `<type>: <subject>` (первая строка до 72 символов)
- После пустой строки - подробное описание изменений
2. **Язык коммитов**
- Все коммиты на **английском языке**
- Подробное описание изменений в теле коммита
- Перечисляй все измененные файлы и ключевые изменения
3. **Примеры правильных коммитов**
```
feat: add setting to control category products button visibility
- Add show_category_products_button field to StoreDTO
- Update SettingsSerializerService to support new field
- Add setting in admin panel on 'Store' tab with toggle
- Pass setting to SPA through SettingsHandler
- Button displays only for categories with child categories
- Add default value true to configuration
```
### Запрещено
- Хардкод значений (используй конфиги/настройки)
- Игнорирование обработки ошибок
- Создание циклических зависимостей
Для разработки FrontEnd используй:
- Vue.js 3 (Composition API)
- Старайся избегать функций watch там, где это возможно и где можно сделать более красиво.
- Для frontend/admin используй Tailwind 4 с префиксом `tw:`.
- Для frontend/spa используй Tailwind 4 без префикса.
- Для frontend/admin используй иконки от FontAwesome 4, потому что это уже встроено в OpenCart 3.
- Для frontend/admin используй компоненты VuePrime 4.
- Для frontend/spa используй Daisy UI.
- Чтобы получить название стандартной таблицы OpenCart, используй хелпер `db_table`, либо добавляй константу DB_PREFIX перед названием таблицы. Так ты получишь название таблицы с префиксом.
- Все таблицы моего модуля MegaPay начинаются с префикса `megapay_`. Примеры миграций лежат в `module/oc_telegram_shop/upload/oc_telegram_shop/database/migrations`

44
.cursor/config.json Normal file
View File

@@ -0,0 +1,44 @@
{
"rules": {
"preferCompositionAPI": true,
"strictTypes": true,
"noHardcodedValues": true,
"useDependencyInjection": true
},
"paths": {
"megapay_module": "module/oc_telegram_shop/upload/oc_telegram_shop",
"frontendAdmin": "frontend/admin",
"telegramShopSpa": "frontend/spa",
"migrations": "module/oc_telegram_shop/upload/oc_telegram_shop/database/migrations",
"megapayHandlers": "module/oc_telegram_shop/upload/oc_telegram_shop/src/Handlers",
"adminHandlers": "module/oc_telegram_shop/upload/oc_telegram_shop/bastion/Handlers",
"models": "module/oc_telegram_shop/upload/oc_telegram_shop/src/Models",
"framework": "module/oc_telegram_shop/upload/oc_telegram_shop/framework"
},
"naming": {
"classes": "PascalCase",
"methods": "camelCase",
"variables": "camelCase",
"constants": "UPPER_SNAKE_CASE",
"files": "PascalCase for classes, kebab-case for others",
"tables": "snake_case with megapay_ prefix"
},
"php": {
"version": "7.4+",
"preferVersion": "7.4+",
"psr12": true
},
"javascript": {
"version": "ES2020+",
"framework": "Vue 3 Composition API",
"stateManagement": "Pinia",
"uiLibrary": "PrimeVue (admin), Tailwind (spa)"
},
"database": {
"queryBuilder": true,
"migrations": true,
"tablePrefix": "megapay_",
"noForeignKeys": true
}
}

View File

@@ -0,0 +1,38 @@
## MegaPay Pulse Heartbeat Telemetry
### Цель
Раз в час отправлять телеметрию (heartbeat) на MegaPay Pulse, чтобы фиксировать состояние магазина и версии окружения без участия пользователя.
### Backend (`module/oc_telegram_shop/upload/oc_telegram_shop`)
- `framework/MegaPayPulse/MegaPayPulseService.php`
- Новый метод `handleHeartbeat()` собирает данные: домен (через `Utils::getCurrentDomain()`), username бота (через `TelegramService::getMe()`), версии PHP, модуля (из `composer.json`), OpenCart (`VERSION` и `VERSION_CORE`), текущий UTC timestamp.
- Последний успешный пинг кешируется (ключ `megapay_pulse_heartbeat`, TTL 1 час) через существующий `CacheInterface`.
- Подпись heartbeat выполняется через отдельный `PayloadSigner`, который использует секрет `pulse.heartbeat_secret`/`PULSE_HEARTBEAT_SECRET`. Логируются предупреждения при ошибках кеша/бота/подписи.
- Отправка идет на эндпоинт `heartbeat` с таймаутом 2 секунды и заголовком `X-MEGAPAY-VERSION`, взятым из `composer.json`.
- `framework/MegaPayPulse/MegaPayPulseServiceProvider.php`
- Регистрирует основной `PayloadSigner` (по `pulse.api_key`) и отдельный heartbeat signer (по `pulse.heartbeat_secret` или `PULSE_HEARTBEAT_SECRET`), инжектит `LoggerInterface`.
- `src/Handlers/TelemetryHandler.php` + `src/routes.php`
- Добавлен маршрут `heartbeat`, который вызывает `handleHeartbeat()` и возвращает `{ status: "ok" }`. Логгер пишет warning при проблемах.
### Frontend (`frontend/spa`)
- `src/utils/ftch.js`: новая функция `heartbeat()` вызывает `api_action=heartbeat`.
- `src/stores/Pulse.js`: добавлен action `heartbeat`, использующий новую API-функцию и логирующий результат.
- `src/main.js`: после `pulse.ingest(...)` вызывается `pulse.heartbeat()` без блокировки цепочки.
### Конфигурация / ENV
- `PULSE_API_HOST` — базовый URL MegaPay Pulse (используется и для events, и для heartbeat).
- `PULSE_TIMEOUT` — общий таймаут HTTP (для heartbeat принудительно 2 секунды).
- `PULSE_HEARTBEAT_SECRET` (или `pulse.heartbeat_secret` в настройках) — общий секрет для подписания heartbeat. Обязателен, иначе heartbeat не будет отправляться.
- `pulse.api_key` — прежний API ключ, используется только для event-инджеста.
### Поведение
1. Frontend (SPA) вызывает `heartbeat` при инициализации приложения (fire-and-forget).
2. Backend проверяет кеш. Если часа еще не прошло, `handleHeartbeat()` возвращает без запросов.
3. При необходимости собираются данные, подписываются через heartbeat signer и отправляются POST-запросом на `/heartbeat`.
4. Любые сбои (bot info, подпись, HTTP) логируются как warning, чтобы не тревожить пользователей.
### TODO / Возможные улучшения
- При необходимости вынести heartbeat запуск в крон/CLI, чтобы не зависеть от фронтенда.
- Добавить метрики успешности heartbeat в админку.

View File

@@ -0,0 +1,128 @@
# Промпты для генерации API
## Создание нового API endpoint
```
Создай новый API endpoint [ENDPOINT_NAME] для [DESCRIPTION]:
1. Handler в [HANDLER_PATH]:
- Метод handle() принимает Request
- Валидация входных данных
- Использование Service для бизнес-логики
- Возврат JsonResponse с правильной структурой
- Обработка ошибок с логированием
2. Service в [SERVICE_PATH]:
- Бизнес-логика
- Работа с Model
- Валидация данных
- Обработка исключений
3. Model в [MODEL_PATH] (если нужен):
- Методы для работы с БД
- Использование Query Builder
- Типизация методов
4. Route в routes.php:
- Добавь маршрут с правильным именем
5. Миграция (если нужна новая таблица):
- Создай миграцию в database/migrations/
- Используй фиксированный префикс megapay_
- Добавь индексы где необходимо
Следуй архитектуре MVC-L проекта и используй существующие паттерны.
```
## Создание CRUD API
```
Создай полный CRUD API для сущности [ENTITY_NAME]:
1. Handler с методами:
- list() - список с пагинацией и фильтрацией
- get() - получение одной записи
- create() - создание
- update() - обновление
- delete() - удаление
2. Service с бизнес-логикой для всех операций
3. Model с методами:
- findAll() - список
- findById() - по ID
- create() - создание
- update() - обновление
- delete() - удаление
4. DTO для валидации данных
5. Миграция для таблицы [TABLE_NAME]
6. Routes для всех endpoints
Используй серверную пагинацию, фильтрацию и сортировку для list().
```
## Создание Admin API endpoint
```
Создай Admin API endpoint [ENDPOINT_NAME] в bastion/Handlers/:
1. Handler в bastion/Handlers/[HANDLER_NAME].php:
- Используй Request для получения параметров
- Валидация данных
- Работа через Service
- Возврат JsonResponse с структурой { data: { data: [...], totalRecords: ... } }
- Обработка ошибок
2. Service в bastion/Services/ (если нужен):
- Бизнес-логика для админки
- Работа с Models
3. Route в bastion/routes.php
4. Frontend компонент (если нужен UI):
- Vue компонент в frontend/admin/src/views/
- Используй PrimeVue компоненты
- Серверная пагинация/фильтрация
- Обработка ошибок с toast уведомлениями
Следуй существующим паттернам проекта.
```
## Создание Frontend API клиента
```
Создай функцию для работы с API endpoint [ENDPOINT_NAME]:
1. В frontend/[admin|spa]/src/utils/http.js:
- Функция api[Method] для вызова endpoint
- Правильная обработка ошибок
- Возврат структурированного ответа
2. Использование:
- В компонентах через import
- Обработка loading states
- Toast уведомления для ошибок
Следуй существующим паттернам в http.js.
```
## Создание миграции
```
Создай миграцию для таблицы [TABLE_NAME]:
1. Файл: database/migrations/[TIMESTAMP]_[DESCRIPTION].php
2. Используй фиксированный префикс megapay_ для таблицы
3. Добавь все необходимые поля с правильными типами
4. Добавь индексы для часто используемых полей
5. Используй utf8mb4_unicode_ci collation
6. Используй InnoDB engine
7. Добавь created_at и updated_at timestamps
8. Не создавай foreign keys (используй только индексы)
Следуй структуре существующих миграций.
```

View File

@@ -0,0 +1,106 @@
# Правила оформления Changelog для документации
## Общие требования
- **Формат**: Markdown
- **Структура**: Одна версия = одна страница
- **Стиль**: Профессиональный, лаконичный, без маркетинговых лозунгов
- **Язык**: Русский
- **Целевая аудитория**: Разработчики и владельцы магазинов
- **Содержимое**: Только ключевые изменения, без лишних технических деталей
## Структура страницы
### Вводный абзац
- Краткое описание релиза (1-2 предложения)
- Дополнить 1-2 предложениями о ключевых изменениях
- Упоминать основные фичи и улучшения
### Разделы (строго в этом порядке)
1. **🚀 Добавлено** - новые функции и возможности
2. **✨ Улучшено** - улучшения существующих функций
3. **🐞 Исправлено** - исправленные ошибки
4. **⚠️ Несовместимые изменения** - изменения без обратной совместимости
5. **🔧 Технические изменения** - технические изменения (отдельный раздел)
### Правила для разделов
- Раздел **НЕ** добавлять, если в нём нет пунктов
- Использовать маркдаун-списки, без нумерации
- Не добавлять ссылок, если они явно не указаны
- Не добавлять лишних пояснений, выводов и заключений
- Выводить только содержимое Markdown-файла, без комментариев
## Разделение изменений
### Бизнес-логика и процессы
Разделы "Добавлено", "Улучшено", "Исправлено", "Несовместимые изменения" содержат только изменения, связанные с:
- Бизнес-процессами магазина
- Пользовательским опытом
- Функциональностью для владельцев магазинов
- Продающими фичами
### Технические изменения
Все технические изменения выносятся в отдельный раздел **🔧 Технические изменения**:
- Без подразделов, всё в одном списке
- Только самые ключевые технические изменения
- Не расписывать детали, которые не интересны пользователю
## Стиль написания
### Терминология
- Английские термины писать по-английски (например: "navbar", а не "навбар")
- Избегать технических терминов в бизнес-разделах (например: "customer_id" → "автоматическое связывание покупателей")
### Описания
**Для ключевых продающих фич:**
- Давать подробное описание с деталями
- Указывать возможности и преимущества
- Подчеркивать ценность для пользователя
**Для технических изменений:**
- Кратко, только ключевое
- Без лишних деталей
**Для обычных функций:**
- Лаконично, но информативно
- Фокус на пользе для пользователя
## Порядок размещения
### В разделе "Добавлено"
Ключевые продающие фичи размещать **первыми**:
1. Система конфигурации главной страницы через блоки
2. Конструктор форм на базе FormKit
3. Интеграция с Яндекс.Метрикой
4. Политика конфиденциальности
5. Поддержка купонов и подарочных сертификатов
6. Остальные функции
## Примеры правильных формулировок
### ✅ Хорошо
- "Автоматическое связывание покупателей Telegram с покупателями OpenCart: система автоматически находит и связывает покупателей из Telegram-магазина с существующими покупателями в OpenCart по email или номеру телефона, создавая единую базу клиентов"
### ❌ Плохо
- "Сохранение customer_id вместе с заказом для связи с клиентами OpenCart: автоматическая связь заказов из Telegram с покупателями в OpenCart, единая база клиентов"
### ✅ Хорошо
- "Navbar с логотипом и названием приложения"
### ❌ Плохо
- "Навбар с логотипом и названием приложения"
## Что не включать
- Внутренние детали разработки (тесты, статический анализ, обфускация)
- Технические детали, не интересные пользователям
- Избыточные технические описания
- Маркетинговые лозунги и призывы

View File

@@ -0,0 +1,62 @@
# Промпты для документирования
## Документирование класса
```
Добавь PHPDoc документацию для класса [CLASS_NAME]:
1. Описание класса и его назначения
2. @package тег
3. @author тег
4. Документация для всех публичных методов
5. Документация для публичных свойств
6. Примеры использования где уместно
```
## Документирование метода
```
Добавь PHPDoc для метода [METHOD_NAME]:
1. Описание метода
2. @param для всех параметров с типами
3. @return с типом возвращаемого значения
4. @throws для всех исключений
5. Примеры использования если сложная логика
```
## Документирование API endpoint
```
Создай документацию для API endpoint [ENDPOINT_NAME]:
1. Описание назначения
2. HTTP метод и путь
3. Параметры запроса (query/body)
4. Формат ответа (JSON структура)
5. Коды ошибок
6. Примеры запросов/ответов
7. Требования к авторизации
```
## Документирование Vue компонента
```
Добавь документацию для Vue компонента [COMPONENT_NAME]:
1. Описание компонента
2. Props с типами и описаниями
3. Emits с описаниями
4. Slots если есть
5. Примеры использования
6. Зависимости от других компонентов
```
## Создание README
```
Создай README.md для [MODULE/COMPONENT]:
1. Описание назначения
2. Установка/настройка
3. Использование с примерами
4. API документация
5. Конфигурация
6. Troubleshooting
```

View File

@@ -0,0 +1,88 @@
# Промпты для рефакторинга
## Общий рефакторинг
```
Проанализируй код в файле [FILE_PATH] и выполни рефакторинг:
1. Убери дублирование кода
2. Улучши читаемость
3. Примени принципы SOLID
4. Добавь обработку ошибок где необходимо
5. Улучши типизацию
6. Добавь документацию для публичных методов
7. Убедись что код следует архитектуре MVC-L проекта
8. Используй существующие утилиты и сервисы проекта вместо создания новых
```
## Рефакторинг Handler
```
Рефакторинг Handler [HANDLER_NAME]:
1. Вынеси бизнес-логику в отдельный Service
2. Добавь валидацию входных данных
3. Улучши обработку ошибок с логированием
4. Используй DTO для передачи данных
5. Добавь PHPDoc комментарии
6. Убедись что используется Dependency Injection
7. Оптимизируй запросы к БД если необходимо
```
## Рефакторинг Model
```
Рефакторинг Model [MODEL_NAME]:
1. Убедись что все запросы используют Query Builder
2. Добавь методы для частых операций (findBy, findAll, create, update)
3. Добавь валидацию данных перед сохранением
4. Улучши типизацию методов
5. Добавь PHPDoc комментарии
6. Используй транзакции для сложных операций
```
## Рефакторинг Vue компонента
```
Рефакторинг Vue компонента [COMPONENT_NAME]:
1. Вынеси логику в composable функции
2. Улучши типизацию props и emits
3. Оптимизируй computed properties
4. Добавь обработку ошибок
5. Улучши структуру template
6. Добавь loading states
7. Используй существующие утилиты проекта
```
## Удаление дублирования
```
Найди и устрани дублирование кода в:
- [FILE_PATH_1]
- [FILE_PATH_2]
- [FILE_PATH_3]
Создай общие утилиты/сервисы где необходимо, следуя архитектуре проекта.
```
## Улучшение производительности
```
Проанализируй производительность кода в [FILE_PATH]:
1. Оптимизируй запросы к БД (используй индексы, избегай N+1)
2. Добавь кэширование где уместно
3. Оптимизируй алгоритмы
4. Уменьши количество запросов к API
5. Используй ленивую загрузку на фронтенде
```
## Улучшение безопасности
```
Улучши безопасность кода в [FILE_PATH]:
1. Добавь валидацию всех входных данных
2. Используй prepared statements (Query Builder)
3. Добавь CSRF защиту где необходимо
4. Валидируй права доступа
5. Санитизируй выходные данные
6. Добавь rate limiting где необходимо
```

View File

@@ -0,0 +1,53 @@
# Промпты для тестирования
## Создание unit теста
```
Создай unit тест для [CLASS_NAME] в tests/Unit/:
1. Используй PHPUnit
2. Покрой все публичные методы
3. Тестируй успешные сценарии
4. Тестируй обработку ошибок
5. Используй моки для зависимостей
6. Следуй структуре существующих тестов
7. Используй TestCase базовый класс проекта
```
## Создание integration теста
```
Создай integration тест для [FEATURE_NAME] в tests/Integration/:
1. Тестируй полный flow от запроса до ответа
2. Используй тестовую БД
3. Очищай данные после тестов
4. Тестируй реальные сценарии использования
5. Проверяй валидацию данных
6. Проверяй обработку ошибок
```
## Создание Vue компонент теста
```
Создай тест для Vue компонента [COMPONENT_NAME] в frontend/[admin|spa]/tests/:
1. Используй Vitest
2. Тестируй рендеринг компонента
3. Тестируй props
4. Тестируй события (emits)
5. Тестируй пользовательские взаимодействия
6. Используй моки для API вызовов
7. Следуй структуре существующих тестов
```
## Покрытие тестами
```
Проанализируй покрытие тестами для [FILE_PATH]:
1. Определи какие методы не покрыты тестами
2. Создай тесты для критичных методов
3. Убедись что тестируются граничные случаи
4. Добавь тесты для обработки ошибок
```

View File

@@ -0,0 +1,201 @@
# Архитектурные правила
## OpenCart Framework Architecture
### MVC-L Pattern
Проект использует модифицированный паттерн MVC-L (Model-View-Controller-Language):
- **Model**: Классы в `src/Models/` - работа с данными, доступ к БД
- **View**: Vue компоненты на фронтенде, JSON ответы на бэкенде
- **Controller**: Handlers в `src/Handlers/` и `bastion/Handlers/`
- **Language**: Переводчик в `framework/Translator/`
### Dependency Injection
Все зависимости внедряются через Container:
```php
// ✅ Правильно
public function __construct(
private Builder $builder,
private TelegramCustomer $telegramCustomerModel
) {}
// ❌ Неправильно
public function __construct() {
$this->builder = new Builder(...);
}
```
### Service Providers
Регистрация сервисов через Service Providers:
```php
class MyServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(MyService::class, function ($app) {
return new MyService($app->get(Dependency::class));
});
}
}
```
### Routes
Маршруты определяются в `routes.php`:
```php
return [
'actionName' => [HandlerClass::class, 'methodName'],
];
```
### Handlers (Controllers)
Handlers обрабатывают HTTP запросы:
```php
class MyHandler
{
public function handle(Request $request): JsonResponse
{
// Валидация
// Бизнес-логика через Services
// Возврат JsonResponse
}
}
```
### Models
Models работают с данными:
```php
class MyModel
{
public function __construct(
private ConnectionInterface $database,
private Builder $builder
) {}
public function findById(int $id): ?array
{
return $this->builder->newQuery()
->from($this->tableName)
->where('id', '=', $id)
->firstOrNull();
}
}
```
### Services
Services содержат бизнес-логику:
```php
class MyService
{
public function __construct(
private MyModel $model
) {}
public function doSomething(array $data): array
{
// Бизнес-логика
return $this->model->create($data);
}
}
```
### Migrations
Миграции в `database/migrations/`:
```php
return new class extends Migration {
public function up(): void
{
$this->database->statement('CREATE TABLE ...');
}
};
```
### Query Builder
Всегда используй Query Builder вместо прямых SQL:
```php
// ✅ Правильно
$query = $this->builder->newQuery()
->select(['id', 'name'])
->from('table_name')
->where('status', '=', 'active')
->get();
// ❌ Неправильно
$result = $this->database->query("SELECT * FROM table_name WHERE status = 'active'");
```
### Frontend Architecture
#### Admin Panel (Vue 3)
- Composition API
- Pinia для state management
- PrimeVue для UI компонентов
- Axios для HTTP запросов
- Vue Router для навигации
#### SPA (Telegram Mini App)
- Composition API
- Pinia stores
- Tailwind CSS для стилей
- Telegram WebApp API
- Vue Router
### Naming Conventions
- **Classes**: PascalCase (`TelegramCustomerService`)
- **Methods**: camelCase (`getCustomers`)
- **Variables**: camelCase (`$customerData`)
- **Constants**: UPPER_SNAKE_CASE (`MAX_RETRIES`)
- **Files**: PascalCase для классов, kebab-case для остального
- **Tables**: snake_case с префиксом `megapay_`
### Error Handling
Всегда обрабатывай ошибки:
```php
try {
$result = $this->service->doSomething();
} catch (SpecificException $e) {
$this->logger->error('Error message', ['exception' => $e]);
throw new UserFriendlyException('User message');
}
```
### Configuration
Используй конфигурационные файлы в `configs/`:
```php
$config = $this->app->getConfigValue('app.setting_name');
```
### Caching
Используй Cache Service для кэширования:
```php
$cache = $this->app->get(CacheInterface::class);
$value = $cache->get('key', function() {
return expensiveOperation();
});
```

View File

@@ -0,0 +1,70 @@
# FormBuilder System Context
## Architectural Overview
The FormBuilder ecosystem is a strictly typed Vue 3 application module designed to generate standard FormKit Schema JSON. It eschews internal DTOs in favor of direct schema manipulation.
### Core Components
1. **FormBuilderView (`views/FormBuilderView.vue`)**:
* **Role**: Smart container / Data fetcher.
* **Responsibility**: Fetches form data from API (`GET /api/admin/forms/{alias}`), handles loading states, and passes data to `FormBuilder`.
* **Contract**: Expects API response `{ data: { schema: Array, is_custom: Boolean, ... } }`.
2. **FormBuilder (`components/FormBuilder/FormBuilder.vue`)**:
* **Role**: Main Orchestrator / State Owner.
* **Responsibility**: Manages `v-model` (schema), mode switching (Visual/Code/Preview), and provides state to children.
* **State Management**: Uses `defineModel` for `formFields` (schema) and `isCustom` (mode flag). Uses `provide('formFields')` and `provide('selectedFieldId')` for deep dependency injection.
* **Modes**:
* **Visual**: Drag-and-drop interface using `vuedraggable`.
* **Code**: Direct JSON editing of the FormKit schema. Sets `isCustom = true`.
* **Preview**: Renders the current schema using `FormKit`.
3. **FormCanvas (`components/FormBuilder/FormCanvas.vue`)**:
* **Role**: Visual Editor Surface.
* **Responsibility**: Renders the draggable list of fields.
* **Implementation**: Uses `vuedraggable` bound to `formFields`.
* **UX**: Implements "Ghost" and "Drag" classes for visual feedback. Handles selection logic.
4. **FieldsPanel (`components/FormBuilder/FieldsPanel.vue`)**:
* **Role**: Component Palette.
* **Responsibility**: Source of truth for available field types.
* **Implementation**: Uses `vuedraggable` with `pull: 'clone', put: false` to spawn new fields.
5. **FieldSettings (`components/FormBuilder/FieldSettings.vue`)**:
* **Role**: Property Editor.
* **Responsibility**: Edits properties of the `selectedFieldId`.
* **Constraint**: Must use PrimeVue components for all inputs.
## Data Flow & Invariants
1. **Schema Authority**: The FormKit Schema JSON is the single source of truth. There is no "internal model" separate from the schema.
2. **Reactivity**:
* `formFields` is an Array of Objects.
* Mutations must preserve reactivity. When using `v-model` or `provide/inject`, ensure array methods (splice, push, filter) are used correctly or replace the entire array reference if needed to trigger watchers.
* **Immutability**: `useFormFields` composable uses immutable patterns (returning new array references) to ensure `defineModel` in parent detects changes.
3. **Mode Logic**:
* Switching to **Code** mode sets `isCustom = true`.
* Switching to **Visual** mode sets `isCustom = false`.
* **Safety**: Switching modes triggers JSON validation. Invalid JSON prevents mode switch.
4. **Drag and Drop**:
* Powered by `vuedraggable` (Sortable.js).
* **Clone Logic**: `FieldsPanel` clones from `availableFields`. `FormCanvas` receives the clone.
* **ID Generation**: Unique IDs are generated upon cloning/addition to ensure key stability.
## Naming & Conventions
* **Tailwind**: Use `tw:` prefix for all utility classes (e.g., `tw:flex`, `tw:p-4`).
* **Components**: PrimeVue components are the standard UI kit (Button, Panel, InputText, etc.).
* **Icons**: FontAwesome (`fa fa-*`).
* **Files**: PascalCase for components (`FormBuilder.vue`), camelCase for logic (`useFormFields.js`).
## Integration Rules
* **Backend**: The backend stores the JSON blob directly. `FormBuilder` does not transform data before save; it emits the raw schema.
* **API**: `useFormsStore` handles API communication.
## Pitfalls & Warnings
* **vuedraggable vs @formkit/drag-and-drop**: We strictly use `vuedraggable`. Do not re-introduce `@formkit/drag-and-drop`.
* **Watchers**: Avoid `watch` where `computed` or event handlers suffice, to prevent infinite loops in bidirectional data flow.
* **Tailwind Config**: Do not use `@apply` with `tw:` prefixed classes in `<style>` blocks; standard CSS properties should be used if custom classes are needed.
## Future Modifications
* **Adding Fields**: Update `constants/availableFields.js` and ensure `utils/fieldHelpers.js` supports the new type.
* **Validation**: FormKit validation rules string (e.g., "required|email") is edited as a raw string in `FieldSettings`. Complex validation builders would require a new UI component.

332
.cursor/rules/javascript.md Normal file
View File

@@ -0,0 +1,332 @@
# JavaScript/TypeScript Code Style Rules
## JavaScript Version
- ES2020+ features
- Modern async/await
- Optional chaining (`?.`)
- Nullish coalescing (`??`)
- Template literals
## Code Style
### Variable Declarations
```javascript
// ✅ Используй const по умолчанию
const customers = [];
const totalRecords = 0;
// ✅ let только когда нужно переназначение
let currentPage = 1;
currentPage = 2;
// ❌ Не используй var
var oldVariable = 'bad';
```
### Arrow Functions
```javascript
// ✅ Предпочтительно для коротких функций
const filtered = items.filter(item => item.isActive);
// ✅ Для методов объектов
const api = {
get: async (url) => {
return await fetch(url);
}
};
// ✅ Для сложной логики - обычные функции
function complexCalculation(data) {
// много строк кода
return result;
}
```
### Template Literals
```javascript
// ✅ Предпочтительно
const message = `User ${userId} not found`;
const url = `${baseUrl}/api/${endpoint}`;
// ❌ Не используй конкатенацию
const message = 'User ' + userId + ' not found';
```
### Optional Chaining
```javascript
// ✅ Используй optional chaining
const name = user?.profile?.name;
const count = data?.items?.length ?? 0;
// ❌ Избегай длинных проверок
const name = user && user.profile && user.profile.name;
```
### Nullish Coalescing
```javascript
// ✅ Используй ?? для значений по умолчанию
const page = params.page ?? 1;
const name = user.name ?? 'Unknown';
// ❌ Не используй || для чисел/булевых
const page = params.page || 1; // 0 будет заменено на 1
```
### Destructuring
```javascript
// ✅ Используй деструктуризацию
const { data, totalRecords } = response.data;
const [first, second] = items;
// ✅ В параметрах функций
function processUser({ id, name, email }) {
// ...
}
// ✅ С значениями по умолчанию
const { page = 1, limit = 20 } = params;
```
### Async/Await
```javascript
// ✅ Предпочтительно
async function loadCustomers() {
try {
const response = await apiGet('getCustomers', params);
return response.data;
} catch (error) {
console.error('Error:', error);
throw error;
}
}
// ❌ Избегай .then() цепочек
function loadCustomers() {
return apiGet('getCustomers', params)
.then(response => response.data)
.catch(error => console.error(error));
}
```
## Vue.js 3 Composition API
### Script Setup
```vue
<script setup>
// ✅ Используй <script setup>
import { ref, computed, onMounted } from 'vue';
import { apiGet } from '@/utils/http.js';
const customers = ref([]);
const loading = ref(false);
const totalRecords = computed(() => customers.value.length);
async function loadCustomers() {
loading.value = true;
try {
const result = await apiGet('getCustomers');
customers.value = result.data || [];
} finally {
loading.value = false;
}
}
onMounted(() => {
loadCustomers();
});
</script>
```
### Reactive State
```javascript
// ✅ Используй ref для примитивов
const count = ref(0);
const name = ref('');
// ✅ Используй reactive для объектов
import { reactive } from 'vue';
const state = reactive({
customers: [],
loading: false
});
// ✅ Или ref для объектов (предпочтительно)
const state = ref({
customers: [],
loading: false
});
```
### Computed Properties
```javascript
// ✅ Используй computed для производных значений
const filteredCustomers = computed(() => {
return customers.value.filter(c => c.isActive);
});
// ❌ Не используй методы для вычислений
function filteredCustomers() {
return customers.value.filter(c => c.isActive);
}
```
### Props
```vue
<script setup>
// ✅ Определяй props с типами
const props = defineProps({
customerId: {
type: Number,
required: true
},
showDetails: {
type: Boolean,
default: false
}
});
</script>
```
### Emits
```vue
<script setup>
// ✅ Определяй emits
const emit = defineEmits(['update', 'delete']);
function handleUpdate() {
emit('update', data);
}
</script>
```
## Pinia Stores
```javascript
// ✅ Используй setup stores
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useCustomersStore = defineStore('customers', () => {
const customers = ref([]);
const loading = ref(false);
const totalRecords = computed(() => customers.value.length);
async function loadCustomers() {
loading.value = true;
try {
const result = await apiGet('getCustomers');
customers.value = result.data || [];
} finally {
loading.value = false;
}
}
return {
customers,
loading,
totalRecords,
loadCustomers
};
});
```
## Error Handling
```javascript
// ✅ Всегда обрабатывай ошибки
async function loadData() {
try {
const result = await apiGet('endpoint');
if (result.success) {
return result.data;
} else {
throw new Error(result.error);
}
} catch (error) {
console.error('Failed to load data:', error);
toast.error('Не удалось загрузить данные');
throw error;
}
}
```
## Naming Conventions
### Variables and Functions
```javascript
// ✅ camelCase
const customerData = {};
const totalRecords = 0;
function loadCustomers() {}
// ✅ Константы UPPER_SNAKE_CASE
const MAX_RETRIES = 3;
const API_BASE_URL = '/api';
```
### Components
```vue
<!-- PascalCase для компонентов -->
<CustomerCard />
<ProductsList />
```
### Files
```javascript
// ✅ kebab-case для файлов
// customers-view.vue
// http-utils.js
// customer-service.js
```
## Imports
```javascript
// ✅ Группируй импорты
// 1. Vue core
import { ref, computed, onMounted } from 'vue';
// 2. Third-party
import { apiGet } from '@/utils/http.js';
import { useToast } from 'primevue';
// 3. Local components
import CustomerCard from '@/components/CustomerCard.vue';
// 4. Types (если TypeScript)
import type { Customer } from '@/types';
```
## TypeScript (где используется)
```typescript
// ✅ Используй типы
interface Customer {
id: number;
name: string;
email?: string;
}
function getCustomer(id: number): Promise<Customer> {
return apiGet(`customers/${id}`);
}
```

243
.cursor/rules/php.md Normal file
View File

@@ -0,0 +1,243 @@
# PHP Code Style Rules
## PHP Version
Проект поддерживает PHP 7.4+
## PSR Standards
- **PSR-1**: Basic Coding Standard
- **PSR-4**: Autoloading Standard
- **PSR-12**: Extended Coding Style
## Code Style
### Type Declarations
```php
// ✅ Правильно - строгая типизация
public function getCustomers(Request $request): JsonResponse
{
$id = (int) $request->get('id');
return new JsonResponse(['data' => $customers]);
}
// ❌ Неправильно - без типов
public function getCustomers($request)
{
return ['data' => $customers];
}
```
### Nullable Types
```php
// ✅ Правильно
public function findById(?int $id): ?array
{
if ($id === null) {
return null;
}
return $this->query->where('id', '=', $id)->firstOrNull();
}
```
### Strict Types
Всегда используй `declare(strict_types=1);`:
```php
<?php
declare(strict_types=1);
namespace App\Services;
```
### Array Syntax
```php
// ✅ Предпочтительно - короткий синтаксис
$array = ['key' => 'value'];
// ❌ Не использовать
$array = array('key' => 'value');
```
### String Interpolation
```php
// ✅ Предпочтительно
$message = "User {$userId} not found";
// ✅ Альтернатива
$message = sprintf('User %d not found', $userId);
```
### Arrow Functions (PHP 7.4+)
```php
// ✅ Для простых операций
$filtered = array_filter($items, fn($item) => $item->isActive());
// ❌ Для сложной логики - используй обычные функции
```
### Nullsafe Operator (PHP 8.0+)
```php
// ✅ Для PHP 7.4
$name = $user && $user->profile ? $user->profile->name : null;
```
## Naming Conventions
### Classes
```php
// ✅ PascalCase
class TelegramCustomerService {}
class UserRepository {}
```
### Methods
```php
// ✅ camelCase
public function getCustomers(): array {}
public function saveOrUpdate(array $data): array {}
```
### Variables
```php
// ✅ camelCase
$customerData = [];
$totalRecords = 0;
```
### Constants
```php
// ✅ UPPER_SNAKE_CASE
private const MAX_RETRIES = 3;
public const DEFAULT_PAGE_SIZE = 20;
```
### Private Properties
```php
// ✅ camelCase с модификатором доступа
private string $tableName;
private Builder $builder;
```
## Documentation
### PHPDoc
```php
/**
* @throws ValidationException Если параметры невалидны
*/
public function getCustomers(Request $request): JsonResponse
{
// ...
}
```
### Inline Comments
```php
// ✅ Полезные комментарии
// Применяем фильтры для подсчета общего количества записей
$countQuery = $this->buildCountQuery($filters);
// ❌ Очевидные комментарии
// Получаем данные
$data = $this->getData();
```
## Error Handling
### Exceptions
```php
// ✅ Специфичные исключения
if (!$userId) {
throw new InvalidArgumentException('User ID is required');
}
// ✅ Логирование
try {
$result = $this->service->process();
} catch (Exception $e) {
$this->logger->error('Processing failed', [
'exception' => $e,
'context' => $context,
]);
throw new ProcessingException('Failed to process', 0, $e);
}
```
## Query Builder Usage
### Always Use Query Builder
```php
// ✅ Правильно
$customers = $this->builder->newQuery()
->select(['id', 'name', 'email'])
->from('megapay_customers')
->where('status', '=', 'active')
->orderBy('created_at', 'DESC')
->get();
// В крайних случаях можно использовать прямые SQL
$result = $this->database->query("SELECT * FROM megapay_customers");
```
### Parameter Binding
```php
// ✅ Query Builder автоматически биндит параметры
$query->where('name', 'LIKE', "%{$search}%");
// ❌ Никогда не конкатенируй значения в SQL, избегай SQL Injection.
```
## Array Access
### Safe Array Access
```php
// ✅ Используй Arr::get()
use Openguru\OpenCartFramework\Support\Arr;
$value = Arr::get($data, 'key', 'default');
// ❌ Небезопасно
$value = $data['key']; // может вызвать ошибку
```
## Return Types
```php
// ✅ Всегда указывай return type
public function getData(): array {}
public function findById(int $id): ?array {}
public function process(): void {}
// ❌ Без типа
public function getData() {}
```
## Visibility Modifiers
```php
// ✅ Всегда указывай модификатор доступа
private string $tableName;
protected Builder $builder;
public function getData(): array {}
```

370
.cursor/rules/vue.md Normal file
View File

@@ -0,0 +1,370 @@
# Vue.js 3 Rules
## Component Structure
### Template
```vue
<template>
<!-- Логическая структура -->
<div class="container">
<header>
<h2>{{ title }}</h2>
</header>
<main>
<DataTable :value="items" />
</main>
<footer>
<Button @click="handleSave">Save</Button>
</footer>
</div>
</template>
```
### Script Setup
```vue
<script setup>
// ✅ Всегда используй <script setup>
import { ref, computed, onMounted } from 'vue';
import DataTable from 'primevue/datatable';
import { apiGet } from '@/utils/http.js';
// Props
const props = defineProps({
title: {
type: String,
required: true
}
});
// Emits
const emit = defineEmits(['update', 'delete']);
// State
const items = ref([]);
const loading = ref(false);
// Computed
const totalItems = computed(() => items.value.length);
// Methods
async function loadItems() {
loading.value = true;
try {
const result = await apiGet('getItems');
items.value = result.data || [];
} finally {
loading.value = false;
}
}
// Lifecycle
onMounted(() => {
loadItems();
});
</script>
```
### Styles
```vue
<style scoped>
/* ✅ Используй scoped стили */
.container {
padding: 1rem;
}
/* ✅ Используй :deep() для доступа к дочерним компонентам */
:deep(.p-datatable) {
border: 1px solid #ccc;
}
</style>
```
## Component Naming
```vue
<!-- PascalCase для компонентов -->
<CustomerCard />
<ProductsList />
<OrderDetails />
<!-- kebab-case в шаблоне тоже работает -->
<customer-card />
```
## Props
```vue
<script setup>
// ✅ Всегда определяй типы и валидацию
const props = defineProps({
customerId: {
type: Number,
required: true,
validator: (value) => value > 0
},
showDetails: {
type: Boolean,
default: false
},
items: {
type: Array,
default: () => []
}
});
</script>
```
## Emits
```vue
<script setup>
// ✅ Определяй emits с типами
const emit = defineEmits<{
update: [id: number, data: object];
delete: [id: number];
cancel: [];
}>();
// ✅ Или с валидацией
const emit = defineEmits({
update: (id: number, data: object) => {
if (id > 0 && typeof data === 'object') {
return true;
}
console.warn('Invalid emit arguments');
return false;
}
});
</script>
```
## Reactive State
```vue
<script setup>
// ✅ ref для примитивов
const count = ref(0);
const name = ref('');
// ✅ ref для объектов (предпочтительно)
const customer = ref({
id: null,
name: '',
email: ''
});
// ✅ reactive только если нужно
import { reactive } from 'vue';
const state = reactive({
items: [],
loading: false
});
</script>
```
## Computed Properties
```vue
<script setup>
// ✅ Используй computed для производных значений
const filteredItems = computed(() => {
return items.value.filter(item => item.isActive);
});
// ✅ Computed с getter/setter
const fullName = computed({
get: () => `${firstName.value} ${lastName.value}`,
set: (value) => {
const parts = value.split(' ');
firstName.value = parts[0];
lastName.value = parts[1];
}
});
</script>
```
## Event Handlers
```vue
<template>
<!-- Используй kebab-case для событий -->
<Button @click="handleClick" />
<Input @input="handleInput" />
<Form @submit.prevent="handleSubmit" />
</template>
<script setup>
// ✅ Именуй обработчики с префиксом handle
function handleClick() {
// ...
}
function handleInput(event) {
// ...
}
function handleSubmit() {
// ...
}
</script>
```
## Conditional Rendering
```vue
<template>
<!-- Используй v-if для условного рендеринга -->
<div v-if="loading">
<LoadingSpinner />
</div>
<!-- v-show для частых переключений -->
<div v-show="hasItems">
<ItemsList :items="items" />
</div>
<!-- v-else для альтернатив -->
<div v-else>
<EmptyState />
</div>
</template>
```
## Lists
```vue
<template>
<!-- Всегда используй :key -->
<div v-for="item in items" :key="item.id">
{{ item.name }}
</div>
<!-- Для индексов -->
<div v-for="(item, index) in items" :key="`item-${index}`">
{{ item.name }}
</div>
</template>
```
## Form Handling
```vue
<template>
<form @submit.prevent="handleSubmit">
<!-- Используй v-model -->
<InputText v-model="form.name" />
<Textarea v-model="form.description" />
<!-- Для кастомных компонентов -->
<CustomInput v-model="form.email" />
</form>
</template>
<script setup>
const form = ref({
name: '',
description: '',
email: ''
});
function handleSubmit() {
// Валидация и отправка
}
</script>
```
## PrimeVue Components
```vue
<template>
<!-- Используй PrimeVue компоненты в админке -->
<DataTable
:value="customers"
:loading="loading"
paginator
:rows="20"
@page="onPage"
>
<Column field="name" header="Name" sortable />
</DataTable>
</template>
```
## Styling
```vue
<style scoped>
/* ✅ Используй scoped -->
.container {
padding: 1rem;
}
/* ✅ :deep() для дочерних компонентов */
:deep(.p-datatable) {
border: 1px solid #ccc;
}
/* ✅ :slotted() для слотов */
:slotted(.header) {
font-weight: bold;
}
</style>
```
## Composition Functions
```vue
<script setup>
// ✅ Выноси сложную логику в composables
import { useCustomers } from '@/composables/useCustomers.js';
const {
customers,
loading,
loadCustomers,
totalRecords
} = useCustomers();
onMounted(() => {
loadCustomers();
});
</script>
```
## Error Handling
```vue
<script setup>
import { useToast } from 'primevue';
const toast = useToast();
async function loadData() {
try {
const result = await apiGet('endpoint');
if (result.success) {
data.value = result.data;
} else {
toast.add({
severity: 'error',
summary: 'Ошибка',
detail: result.error
});
}
} catch (error) {
console.error('Error:', error);
toast.add({
severity: 'error',
summary: 'Ошибка',
detail: 'Не удалось загрузить данные'
});
}
}
</script>
```

View File

@@ -4,6 +4,7 @@ on:
push: push:
branches: branches:
- master - master
- 'issue/**'
- develop - develop
pull_request: pull_request:
types: types:
@@ -134,11 +135,6 @@ jobs:
MODULE_ROOT="module/oc_telegram_shop/upload/oc_telegram_shop" MODULE_ROOT="module/oc_telegram_shop/upload/oc_telegram_shop"
echo "${{ needs.version_meta.outputs.tag }}" > "${MODULE_ROOT}/version.txt" echo "${{ needs.version_meta.outputs.tag }}" > "${MODULE_ROOT}/version.txt"
- name: Set version in install.xml
run: |
TAG="${{ needs.version_meta.outputs.tag }}"
sed -i "s#<version>.*</version>#<version>${TAG}</version>#" module/oc_telegram_shop/install.xml
- name: Build module - name: Build module
run: | run: |
bash scripts/ci/build.sh "${GITHUB_WORKSPACE}" bash scripts/ci/build.sh "${GITHUB_WORKSPACE}"

View File

@@ -4,576 +4,539 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
<!--- END HEADER --> <!--- END HEADER -->
## [2.3.0](https://github.com/telecart-labs/telecart/compare/v2.2.2...v2.3.0) (2026-05-25) ## [2.2.1](https://github.com/megapay-labs/megapay/compare/v2.2.0...v2.2.1) (2026-02-22)
---
## [2.2.0](https://github.com/megapay-labs/megapay/compare/v2.1.0...v2.2.0) (2026-01-09)
### Features ### Features
* Add BETA label and UI improvements for MegaPay Pulse tab ([551c4a](https://github.com/megapay-labs/megapay/commit/551c4a3506ddedb1b11851e3d3cbcb4f3ed34e03))
* Add cache:clear CLI command for module cache clearing (#46) ([3d0a75](https://github.com/megapay-labs/megapay/commit/3d0a7536a64bc88dbb349a9640260757b46009c4))
* Add changelog ([bf99bf](https://github.com/megapay-labs/megapay/commit/bf99bfe8a442c8eaad64f348792b7ddcbfb4486c))
* Add config redis cache, categories cache (#44) ([0798f5](https://github.com/megapay-labs/megapay/commit/0798f5c3e98721efbb45e2988350364b606622cd))
* Add customer account page with profile information and actions ([ad94af](https://github.com/megapay-labs/megapay/commit/ad94afda6826dd1d120599353121bad000b675a7))
* Add customizable text for manager contact button ([0a7877](https://github.com/megapay-labs/megapay/commit/0a7877ddbe7908d6a17089e1005308a945d3d21f))
* Add haptic feedback toggle setting ([afade8](https://github.com/megapay-labs/megapay/commit/afade85d004872d10929119db3ac95ee3acd0251))
* Add product interaction mode selector with three scenarios ([ecf4df](https://github.com/megapay-labs/megapay/commit/ecf4df363d49bf0d8bdc1b9ca3a241f99f26cfb8))
* Add store_id conditions (#43) ([846418](https://github.com/megapay-labs/megapay/commit/84641868e98786264f517865d48619ac4bc1ef7a))
* Add system information drawer (#44) ([9da605](https://github.com/megapay-labs/megapay/commit/9da605b9eac82045b46c3edbb998d28a63c22188))
* Increase dock icons size and add click animation ([ce2ea9](https://github.com/megapay-labs/megapay/commit/ce2ea9dea1fcd24d70ea66345d761a739d25f9d1))
##### Admin ##### Admin
* Telegram settings improvements (#63) ([80c246](https://github.com/telecart-labs/telecart/commit/80c2467b4a7c2cb1c4101c483fe3ac31a5ad0cf1)) * Improve navigation UI and move logs to drawer ([6a635e](https://github.com/megapay-labs/megapay/commit/6a635e189614c50c8d4bdbeb2486eb5b32ba7da0))
##### Ocmod
* Add TeleCart admin sidebar menu and local dev setup (#57) ([28c8ce](https://github.com/telecart-labs/telecart/commit/28c8ce3b6841ca1d4cc98c8e7bb275e1ad3adcf3))
##### Spa
* Increase max page limit to product lists (#88) ([a3f54a](https://github.com/telecart-labs/telecart/commit/a3f54a87dc8799b3355b294fc155c3cf9d22c3eb))
### Bug Fixes
##### Spa
* Handle empty category and products in carousel block ([d43564](https://github.com/telecart-labs/telecart/commit/d43564481d1e35ea8bb92310d20bff2989ca6ea7))
* Visual fixes for SPA (#106) ([c24e30](https://github.com/telecart-labs/telecart/commit/c24e30f14cef8a4b6956aaa2ada5dc9b12fbb9cb))
---
## [2.2.2](https://github.com/telecart-labs/telecart/compare/v2.2.1...v2.2.2) (2026-03-15)
### Bug Fixes
* Normalize order response to valid UTF-8 before JSON encoding (#83) ([f894d3](https://github.com/telecart-labs/telecart/commit/f894d33c464e28a15cbdcd5c72dfd90bd5379e92))
---
## [2.2.1](https://github.com/telecart-labs/telecart/compare/v2.2.0...v2.2.1) (2026-02-22)
---
## [2.2.0](https://github.com/telecart-labs/telecart/compare/v2.1.0...v2.2.0) (2026-01-09)
### Features
* Add BETA label and UI improvements for TeleCart Pulse tab ([551c4a](https://github.com/telecart-labs/telecart/commit/551c4a3506ddedb1b11851e3d3cbcb4f3ed34e03))
* Add cache:clear CLI command for module cache clearing (#46) ([3d0a75](https://github.com/telecart-labs/telecart/commit/3d0a7536a64bc88dbb349a9640260757b46009c4))
* Add changelog ([bf99bf](https://github.com/telecart-labs/telecart/commit/bf99bfe8a442c8eaad64f348792b7ddcbfb4486c))
* Add config redis cache, categories cache (#44) ([0798f5](https://github.com/telecart-labs/telecart/commit/0798f5c3e98721efbb45e2988350364b606622cd))
* Add customer account page with profile information and actions ([ad94af](https://github.com/telecart-labs/telecart/commit/ad94afda6826dd1d120599353121bad000b675a7))
* Add customizable text for manager contact button ([0a7877](https://github.com/telecart-labs/telecart/commit/0a7877ddbe7908d6a17089e1005308a945d3d21f))
* Add haptic feedback toggle setting ([afade8](https://github.com/telecart-labs/telecart/commit/afade85d004872d10929119db3ac95ee3acd0251))
* Add product interaction mode selector with three scenarios ([ecf4df](https://github.com/telecart-labs/telecart/commit/ecf4df363d49bf0d8bdc1b9ca3a241f99f26cfb8))
* Add store_id conditions (#43) ([846418](https://github.com/telecart-labs/telecart/commit/84641868e98786264f517865d48619ac4bc1ef7a))
* Add system information drawer (#44) ([9da605](https://github.com/telecart-labs/telecart/commit/9da605b9eac82045b46c3edbb998d28a63c22188))
* Increase dock icons size and add click animation ([ce2ea9](https://github.com/telecart-labs/telecart/commit/ce2ea9dea1fcd24d70ea66345d761a739d25f9d1))
##### Admin
* Improve navigation UI and move logs to drawer ([6a635e](https://github.com/telecart-labs/telecart/commit/6a635e189614c50c8d4bdbeb2486eb5b32ba7da0))
##### Search ##### Search
* Improvement search cache (#44) ([8a9bac](https://github.com/telecart-labs/telecart/commit/8a9bac8221146b5db4960cc10de3e29dcd75c9bf)) * Improvement search cache (#44) ([8a9bac](https://github.com/megapay-labs/megapay/commit/8a9bac8221146b5db4960cc10de3e29dcd75c9bf))
##### Spa ##### Spa
* Add UTM markers for product view on OpenCart (#47) ([647e20](https://github.com/telecart-labs/telecart/commit/647e20c6b093f3de5e6aafcad474cf1a99189d2e)) * Add UTM markers for product view on OpenCart (#47) ([647e20](https://github.com/megapay-labs/megapay/commit/647e20c6b093f3de5e6aafcad474cf1a99189d2e))
### Bug Fixes ### Bug Fixes
* Correct external .env loading ([089b68](https://github.com/telecart-labs/telecart/commit/089b68672262286f4568a6a40627a0c2e0c51b14)) * Correct external .env loading ([089b68](https://github.com/megapay-labs/megapay/commit/089b68672262286f4568a6a40627a0c2e0c51b14))
* Correctly work with telecart customers without usernames ([0312b8](https://github.com/telecart-labs/telecart/commit/0312b882e1ad5596e823943924d1b284d5592b14)) * Correctly work with megapay customers without usernames ([0312b8](https://github.com/megapay-labs/megapay/commit/0312b882e1ad5596e823943924d1b284d5592b14))
* Missing store_id for carousel products ([3a1f8d](https://github.com/telecart-labs/telecart/commit/3a1f8dbf948c65c6f2d94392c277317f1ce5da75)) * Missing store_id for carousel products ([3a1f8d](https://github.com/megapay-labs/megapay/commit/3a1f8dbf948c65c6f2d94392c277317f1ce5da75))
##### Admin ##### Admin
* Correct logs sorting by datetime with milliseconds ([115c13](https://github.com/telecart-labs/telecart/commit/115c13393f045a8f2eb7992be11ce20e94b23b96)) * Correct logs sorting by datetime with milliseconds ([115c13](https://github.com/megapay-labs/megapay/commit/115c13393f045a8f2eb7992be11ce20e94b23b96))
##### Spa ##### Spa
* Correct line breaks for long attribute names and values in Product.vue ([ff7263](https://github.com/telecart-labs/telecart/commit/ff7263649c208449f0b0b65df3e6088115ec78f6)) * Correct line breaks for long attribute names and values in Product.vue ([ff7263](https://github.com/megapay-labs/megapay/commit/ff7263649c208449f0b0b65df3e6088115ec78f6))
* Correct privacy policy message margin ([79f234](https://github.com/telecart-labs/telecart/commit/79f23400d20ba3cb43160cf898ea589f30c7aa83)) * Correct privacy policy message margin ([79f234](https://github.com/megapay-labs/megapay/commit/79f23400d20ba3cb43160cf898ea589f30c7aa83))
--- ---
## [2.1.0](https://github.com/telecart-labs/telecart/compare/v2.0.0...v2.1.0) (2025-12-24) ## [2.1.0](https://github.com/megapay-labs/megapay/compare/v2.0.0...v2.1.0) (2025-12-24)
### Features ### Features
* Add setting to control category products button visibility ([c3994b](https://github.com/telecart-labs/telecart/commit/c3994b2291790f21cd219d1c5e820c274cb6e085)) * Add setting to control category products button visibility ([c3994b](https://github.com/megapay-labs/megapay/commit/c3994b2291790f21cd219d1c5e820c274cb6e085))
--- ---
## [2.0.0](https://github.com/telecart-labs/telecart/compare/v1.3.2...v2.0.0) (2025-12-23) ## [2.0.0](https://github.com/megapay-labs/megapay/compare/v1.3.2...v2.0.0) (2025-12-23)
### ⚠ BREAKING CHANGES ### ⚠ BREAKING CHANGES
* None ([9a93cc](https://github.com/telecart-labs/telecart/commit/9a93cc73421c9c85e3cfbe403cd2c8fb41ba3406)) * None ([9a93cc](https://github.com/megapay-labs/megapay/commit/9a93cc73421c9c85e3cfbe403cd2c8fb41ba3406))
### Features ### Features
* Add aspect ratio selector for products_carousel ([615e8c](https://github.com/telecart-labs/telecart/commit/615e8c54a60d076a65bc04e60d26c5cbb21c264f)) * Add aspect ratio selector for products_carousel ([615e8c](https://github.com/megapay-labs/megapay/commit/615e8c54a60d076a65bc04e60d26c5cbb21c264f))
* Add cron service to run telecart schedule tasks ([16a258](https://github.com/telecart-labs/telecart/commit/16a258ab682947f9856459797bc99b0adbf0d335)) * Add cron service to run megapay schedule tasks ([16a258](https://github.com/megapay-labs/megapay/commit/16a258ab682947f9856459797bc99b0adbf0d335))
* Add debug mode for developers. Logs improvements ([fbccd5](https://github.com/telecart-labs/telecart/commit/fbccd506752e8cdada461e92a85b7603335a8f23)) * Add debug mode for developers. Logs improvements ([fbccd5](https://github.com/megapay-labs/megapay/commit/fbccd506752e8cdada461e92a85b7603335a8f23))
* Add default configs ([2bc751](https://github.com/telecart-labs/telecart/commit/2bc751119cb5c55c7d29a90d28a24f015ba76692)) * Add default configs ([2bc751](https://github.com/megapay-labs/megapay/commit/2bc751119cb5c55c7d29a90d28a24f015ba76692))
* Added new products_carousel bock type ([f0837e](https://github.com/telecart-labs/telecart/commit/f0837e5c94ef3327f0d249e1994dc73a6da1c42b)) * Added new products_carousel bock type ([f0837e](https://github.com/megapay-labs/megapay/commit/f0837e5c94ef3327f0d249e1994dc73a6da1c42b))
* Add FormKit framework support and update dependencies ([6a59dc](https://github.com/telecart-labs/telecart/commit/6a59dcc0c9b4f8e6ee003c7e168b632d8199981e)) * Add FormKit framework support and update dependencies ([6a59dc](https://github.com/megapay-labs/megapay/commit/6a59dcc0c9b4f8e6ee003c7e168b632d8199981e))
* Add hide keyboard button on search page ([17ff88](https://github.com/telecart-labs/telecart/commit/17ff888c053983a7ae334ba695338ccd8b2db3ab)) * Add hide keyboard button on search page ([17ff88](https://github.com/megapay-labs/megapay/commit/17ff888c053983a7ae334ba695338ccd8b2db3ab))
* Add html editor for telegram messages ([97df5b](https://github.com/telecart-labs/telecart/commit/97df5b4c0aa1d5fbf19c2132436045af0846b5f1)) * Add html editor for telegram messages ([97df5b](https://github.com/megapay-labs/megapay/commit/97df5b4c0aa1d5fbf19c2132436045af0846b5f1))
* Add italy dump ([13f63e](https://github.com/telecart-labs/telecart/commit/13f63e09fcc3c33cb4de2e809a981a0bf532bb63)) * Add italy dump ([13f63e](https://github.com/megapay-labs/megapay/commit/13f63e09fcc3c33cb4de2e809a981a0bf532bb63))
* Add migrations, mantenance tasks, database cache, blocks cache ([c0a6cb](https://github.com/telecart-labs/telecart/commit/c0a6cb17b3fa5a75185ad2e42e8979b1c848c285)) * Add migrations, mantenance tasks, database cache, blocks cache ([c0a6cb](https://github.com/megapay-labs/megapay/commit/c0a6cb17b3fa5a75185ad2e42e8979b1c848c285))
* Add old browser checks ([76c32c](https://github.com/telecart-labs/telecart/commit/76c32c53200f33a5de8fee3587b6aa597ce6d04a)) * Add old browser checks ([76c32c](https://github.com/megapay-labs/megapay/commit/76c32c53200f33a5de8fee3587b6aa597ce6d04a))
* Add options to select aspect ratio and cron algo for product images ([e9c6ed](https://github.com/telecart-labs/telecart/commit/e9c6ed8ddf801d3cfbb91c08733ab118fec3de21)) * Add options to select aspect ratio and cron algo for product images ([e9c6ed](https://github.com/megapay-labs/megapay/commit/e9c6ed8ddf801d3cfbb91c08733ab118fec3de21))
* Add reactivity to formkit ([fdcfce](https://github.com/telecart-labs/telecart/commit/fdcfce0a79af94f5f7ff05e19b4edec0fad4d452)) * Add reactivity to formkit ([fdcfce](https://github.com/megapay-labs/megapay/commit/fdcfce0a79af94f5f7ff05e19b4edec0fad4d452))
* Add redis cache driver ([2b0f04](https://github.com/telecart-labs/telecart/commit/2b0f04eb9455e2f1abb5b9374f3348072ffd1d6a)) * Add redis cache driver ([2b0f04](https://github.com/megapay-labs/megapay/commit/2b0f04eb9455e2f1abb5b9374f3348072ffd1d6a))
* Add scheduler module ([65973d](https://github.com/telecart-labs/telecart/commit/65973d2d79a8c6bfbfc367b56a2b83e465fa2e32)) * Add scheduler module ([65973d](https://github.com/megapay-labs/megapay/commit/65973d2d79a8c6bfbfc367b56a2b83e465fa2e32))
* Add TeleCart Pulse heartbeat telemetry ([b60c77](https://github.com/telecart-labs/telecart/commit/b60c77e4539aab9d2cdb1e9916b7e60c9848d686)) * Add MegaPay Pulse heartbeat telemetry ([b60c77](https://github.com/megapay-labs/megapay/commit/b60c77e4539aab9d2cdb1e9916b7e60c9848d686))
* Add TeleCartPulse telemetry system and ETL endpoints ([e8d0f8](https://github.com/telecart-labs/telecart/commit/e8d0f8a8190c2877ac5aa1e0cc7a5a1663598fe5)) * Add MegaPayPulse telemetry system and ETL endpoints ([e8d0f8](https://github.com/megapay-labs/megapay/commit/e8d0f8a8190c2877ac5aa1e0cc7a5a1663598fe5))
* Add Telegram customers management system with admin panel ([9a93cc](https://github.com/telecart-labs/telecart/commit/9a93cc73421c9c85e3cfbe403cd2c8fb41ba3406)) * Add Telegram customers management system with admin panel ([9a93cc](https://github.com/megapay-labs/megapay/commit/9a93cc73421c9c85e3cfbe403cd2c8fb41ba3406))
* Add texts configuration ([34dfe9](https://github.com/telecart-labs/telecart/commit/34dfe9028693ad488d40f2015af482d789f012c6)) * Add texts configuration ([34dfe9](https://github.com/megapay-labs/megapay/commit/34dfe9028693ad488d40f2015af482d789f012c6))
* Add UI for CRON Scheduler ([7372b9](https://github.com/telecart-labs/telecart/commit/7372b9c330ba4ba83458ca8d722cc71f57316180)) * Add UI for CRON Scheduler ([7372b9](https://github.com/megapay-labs/megapay/commit/7372b9c330ba4ba83458ca8d722cc71f57316180))
* Add warmup images command ([ecd372](https://github.com/telecart-labs/telecart/commit/ecd372dad30e05c5913fa489e561475584b89079)) * Add warmup images command ([ecd372](https://github.com/megapay-labs/megapay/commit/ecd372dad30e05c5913fa489e561475584b89079))
* Better algorythm for image resize ([13e5bc](https://github.com/telecart-labs/telecart/commit/13e5bce8a548439da3dcd892b0c5600ffc995be6)) * Better algorythm for image resize ([13e5bc](https://github.com/megapay-labs/megapay/commit/13e5bce8a548439da3dcd892b0c5600ffc995be6))
* Button to show all products from category ([b2d29f](https://github.com/telecart-labs/telecart/commit/b2d29fd3e288991f77ba6c0bee4bc7c5092b6594)) * Button to show all products from category ([b2d29f](https://github.com/megapay-labs/megapay/commit/b2d29fd3e288991f77ba6c0bee4bc7c5092b6594))
* Change image crop algorythm for product view page ([262f52](https://github.com/telecart-labs/telecart/commit/262f52929063802404af6f0592741ca836c91bcd)) * Change image crop algorythm for product view page ([262f52](https://github.com/megapay-labs/megapay/commit/262f52929063802404af6f0592741ca836c91bcd))
* Clear cache after settings update ([6f9855](https://github.com/telecart-labs/telecart/commit/6f9855995dd3603b622a9e601162ac0b6da9a694)) * Clear cache after settings update ([6f9855](https://github.com/megapay-labs/megapay/commit/6f9855995dd3603b622a9e601162ac0b6da9a694))
* Correct stats for telecart dashboard ([05af49](https://github.com/telecart-labs/telecart/commit/05af4949bfcf2a42ece30f1d77816a3c3018eae2)) * Correct stats for megapay dashboard ([05af49](https://github.com/megapay-labs/megapay/commit/05af4949bfcf2a42ece30f1d77816a3c3018eae2))
* Design update, show avatar in navbar ([6ac6a4](https://github.com/telecart-labs/telecart/commit/6ac6a42e2105bb6f234c108e3a5d21096b87660f)) * Design update, show avatar in navbar ([6ac6a4](https://github.com/megapay-labs/megapay/commit/6ac6a42e2105bb6f234c108e3a5d21096b87660f))
* Disable source maps for frontend production builds ([770ec8](https://github.com/telecart-labs/telecart/commit/770ec81fdcd1456ad7787c9d1e31d92383849f8f)) * Disable source maps for frontend production builds ([770ec8](https://github.com/megapay-labs/megapay/commit/770ec81fdcd1456ad7787c9d1e31d92383849f8f))
* Dont migrate tg messages from v1 ([b87797](https://github.com/telecart-labs/telecart/commit/b87797ee6728523d8e17eeab13b85b014c157d95)) * Dont migrate tg messages from v1 ([b87797](https://github.com/megapay-labs/megapay/commit/b87797ee6728523d8e17eeab13b85b014c157d95))
* Expose module version ([f1a39e](https://github.com/telecart-labs/telecart/commit/f1a39eeb0023d9fdf99cfd95b21288d950730b23)) * Expose module version ([f1a39e](https://github.com/megapay-labs/megapay/commit/f1a39eeb0023d9fdf99cfd95b21288d950730b23))
* Fixed width and preloader for product view page ([5d775e](https://github.com/telecart-labs/telecart/commit/5d775e8eb6710cc1ca3501be1fdfc957582e8663)) * Fixed width and preloader for product view page ([5d775e](https://github.com/megapay-labs/megapay/commit/5d775e8eb6710cc1ca3501be1fdfc957582e8663))
* Fix opecart module status, remove .vite ([e72948](https://github.com/telecart-labs/telecart/commit/e729484fd7a698fcadacdfc99a30beb9d4acbb09)) * Fix opecart module status, remove .vite ([e72948](https://github.com/megapay-labs/megapay/commit/e729484fd7a698fcadacdfc99a30beb9d4acbb09))
* Hide greeting image from frontend ([2ec683](https://github.com/telecart-labs/telecart/commit/2ec683f0163804e7562de14d098b8a0c0f0f28da)) * Hide greeting image from frontend ([2ec683](https://github.com/megapay-labs/megapay/commit/2ec683f0163804e7562de14d098b8a0c0f0f28da))
* Image processing improve ([38668f](https://github.com/telecart-labs/telecart/commit/38668fb4a7f2a3f94a85e06e20ecdff98f5d160d)) * Image processing improve ([38668f](https://github.com/megapay-labs/megapay/commit/38668fb4a7f2a3f94a85e06e20ecdff98f5d160d))
* Images and products loading optimization ([bf6744](https://github.com/telecart-labs/telecart/commit/bf674473e97111aa7a2acad9c835fcea37c3b2ec)) * Images and products loading optimization ([bf6744](https://github.com/megapay-labs/megapay/commit/bf674473e97111aa7a2acad9c835fcea37c3b2ec))
* Improve mainpage ui/ux ([f5d9d4](https://github.com/telecart-labs/telecart/commit/f5d9d417b3b86c7b710da5751a1d50af10a42b6e)) * Improve mainpage ui/ux ([f5d9d4](https://github.com/megapay-labs/megapay/commit/f5d9d417b3b86c7b710da5751a1d50af10a42b6e))
* Increase default per_page products ([6ed2fd](https://github.com/telecart-labs/telecart/commit/6ed2fd2062295bc4296d9ef5c4852541e0e4138f)) * Increase default per_page products ([6ed2fd](https://github.com/megapay-labs/megapay/commit/6ed2fd2062295bc4296d9ef5c4852541e0e4138f))
* Integrate yandex metrika ecommerce ([2f74ab](https://github.com/telecart-labs/telecart/commit/2f74aba35f548d632beed65d81693483942289d5)) * Integrate yandex metrika ecommerce ([2f74ab](https://github.com/megapay-labs/megapay/commit/2f74aba35f548d632beed65d81693483942289d5))
* Maintenance tasks, logs ([ae9771](https://github.com/telecart-labs/telecart/commit/ae9771dec436bd3ff619b26c9c6ce811b1e876dd)) * Maintenance tasks, logs ([ae9771](https://github.com/megapay-labs/megapay/commit/ae9771dec436bd3ff619b26c9c6ce811b1e876dd))
* More fluent vuejs app error handler ([955747](https://github.com/telecart-labs/telecart/commit/955747334d7a7f4863e145f52bcc2864beb8818e)) * More fluent vuejs app error handler ([955747](https://github.com/megapay-labs/megapay/commit/955747334d7a7f4863e145f52bcc2864beb8818e))
* Move getImage response to admin ([f539bb](https://github.com/telecart-labs/telecart/commit/f539bbfbbf023995f88b684406ac5eb8f16fff66)) * Move getImage response to admin ([f539bb](https://github.com/megapay-labs/megapay/commit/f539bbfbbf023995f88b684406ac5eb8f16fff66))
* New settings and mainpage blocks ([6176c7](https://github.com/telecart-labs/telecart/commit/6176c720b1f4c0ce9f06a3cc4ff50b72a52ab0fb)) * New settings and mainpage blocks ([6176c7](https://github.com/megapay-labs/megapay/commit/6176c720b1f4c0ce9f06a3cc4ff50b72a52ab0fb))
* Provide current opencart timezone to App ([51f462](https://github.com/telecart-labs/telecart/commit/51f462922ec49c8cc5e1b0c7909a69180cbe8e72)) * Provide current opencart timezone to App ([51f462](https://github.com/megapay-labs/megapay/commit/51f462922ec49c8cc5e1b0c7909a69180cbe8e72))
* Remove unused js libs ([08f0e2](https://github.com/telecart-labs/telecart/commit/08f0e24859c4e201e85075f2186ed741e3180b38)) * Remove unused js libs ([08f0e2](https://github.com/megapay-labs/megapay/commit/08f0e24859c4e201e85075f2186ed741e3180b38))
* Send xdebug trigger from frontend ([2743b8](https://github.com/telecart-labs/telecart/commit/2743b83a2c624191d2b65a1b13f5b3645e69b71a)) * Send xdebug trigger from frontend ([2743b8](https://github.com/megapay-labs/megapay/commit/2743b83a2c624191d2b65a1b13f5b3645e69b71a))
* Separated coupon and voucher errors ([dd12cb](https://github.com/telecart-labs/telecart/commit/dd12cb8c3434cd3d6f3b8eed4e469db8cd02e3f5)) * Separated coupon and voucher errors ([dd12cb](https://github.com/megapay-labs/megapay/commit/dd12cb8c3434cd3d6f3b8eed4e469db8cd02e3f5))
* Set environment variables ([3716e8](https://github.com/telecart-labs/telecart/commit/3716e89811f2a4135d644cb5a6bae0bb57c367ee)) * Set environment variables ([3716e8](https://github.com/megapay-labs/megapay/commit/3716e89811f2a4135d644cb5a6bae0bb57c367ee))
* Show module version in admin ([116821](https://github.com/telecart-labs/telecart/commit/116821a20946bf3f341e1589af2b24ace1e904da)) * Show module version in admin ([116821](https://github.com/megapay-labs/megapay/commit/116821a20946bf3f341e1589af2b24ace1e904da))
* Store customer_id in with order ([8260d2](https://github.com/telecart-labs/telecart/commit/8260d2bc96bfb256e73673e13740b242756eede2)) * Store customer_id in with order ([8260d2](https://github.com/megapay-labs/megapay/commit/8260d2bc96bfb256e73673e13740b242756eede2))
* Tg bot start message customization ([152e6d](https://github.com/telecart-labs/telecart/commit/152e6d715bfff1cfd05bdab72c4d4b54f7878e4a)) * Tg bot start message customization ([152e6d](https://github.com/megapay-labs/megapay/commit/152e6d715bfff1cfd05bdab72c4d4b54f7878e4a))
* Track and push TeleCart Pulse events ([ef7856](https://github.com/telecart-labs/telecart/commit/ef785654b969e7abc955ed452d8367d6cf3aa55e)) * Track and push MegaPay Pulse events ([ef7856](https://github.com/megapay-labs/megapay/commit/ef785654b969e7abc955ed452d8367d6cf3aa55e))
* UI/UX, add reset cache to admin ([09f1e5](https://github.com/telecart-labs/telecart/commit/09f1e514a975fea5c4fcd3b8cc587f906ab30bd3)) * UI/UX, add reset cache to admin ([09f1e5](https://github.com/megapay-labs/megapay/commit/09f1e514a975fea5c4fcd3b8cc587f906ab30bd3))
* Update admin page ([cd818d](https://github.com/telecart-labs/telecart/commit/cd818d3356d5738a9fb534e056d2e1055b2016ce)) * Update admin page ([cd818d](https://github.com/megapay-labs/megapay/commit/cd818d3356d5738a9fb534e056d2e1055b2016ce))
* Update design for product and product cards ([8a777c](https://github.com/telecart-labs/telecart/commit/8a777cd4d280b7049b60fdd0d3fa0586561e0a65)) * Update design for product and product cards ([8a777c](https://github.com/megapay-labs/megapay/commit/8a777cd4d280b7049b60fdd0d3fa0586561e0a65))
* Update product page design ([c64170](https://github.com/telecart-labs/telecart/commit/c64170f2d8058d99ae60323d907579b59566c119)) * Update product page design ([c64170](https://github.com/megapay-labs/megapay/commit/c64170f2d8058d99ae60323d907579b59566c119))
* Update readme ([5fb450](https://github.com/telecart-labs/telecart/commit/5fb45000ac77de0019a256150089256d5c423d68), [540595](https://github.com/telecart-labs/telecart/commit/540595c9f0661a2ca4c16d8876be54f9258bc0a3), [1361fe](https://github.com/telecart-labs/telecart/commit/1361fea993bcc37b0495b8fff7c20a45ccbd8ca2)) * Update readme ([5fb450](https://github.com/megapay-labs/megapay/commit/5fb45000ac77de0019a256150089256d5c423d68), [540595](https://github.com/megapay-labs/megapay/commit/540595c9f0661a2ca4c16d8876be54f9258bc0a3), [1361fe](https://github.com/megapay-labs/megapay/commit/1361fea993bcc37b0495b8fff7c20a45ccbd8ca2))
* Update styles for swipe to back ([e6a9e6](https://github.com/telecart-labs/telecart/commit/e6a9e6797f518d27caba507ac79d07ac8c113b06)) * Update styles for swipe to back ([e6a9e6](https://github.com/megapay-labs/megapay/commit/e6a9e6797f518d27caba507ac79d07ac8c113b06))
* Use yaMetrika number in settings ([cedc49](https://github.com/telecart-labs/telecart/commit/cedc49f0d5c3107791c1e6ff87a2f024a8baf828)) * Use yaMetrika number in settings ([cedc49](https://github.com/megapay-labs/megapay/commit/cedc49f0d5c3107791c1e6ff87a2f024a8baf828))
* Visualize swipe back ([50bdb8](https://github.com/telecart-labs/telecart/commit/50bdb8601c04799a4ecdb1b854ee1151a02f00f1)) * Visualize swipe back ([50bdb8](https://github.com/megapay-labs/megapay/commit/50bdb8601c04799a4ecdb1b854ee1151a02f00f1))
* WIP add yandex metrika goals ([4e59c4](https://github.com/telecart-labs/telecart/commit/4e59c4e7888925a87ce63eb53587d5e21fec4561)) * WIP add yandex metrika goals ([4e59c4](https://github.com/megapay-labs/megapay/commit/4e59c4e7888925a87ce63eb53587d5e21fec4561))
* добавлена функциональность политики конфиденциальности и согласия на обработку ПД ([7a5eeb](https://github.com/telecart-labs/telecart/commit/7a5eebec91ee73a2d38509cfa4f9bbb87cb75225)) * добавлена функциональность политики конфиденциальности и согласия на обработку ПД ([7a5eeb](https://github.com/megapay-labs/megapay/commit/7a5eebec91ee73a2d38509cfa4f9bbb87cb75225))
* добавлен жест swipe back для навигации назад ([179729](https://github.com/telecart-labs/telecart/commit/17972993ca815072ad5ded2bbc7a29e97f1abc6f)) * добавлен жест swipe back для навигации назад ([179729](https://github.com/megapay-labs/megapay/commit/17972993ca815072ad5ded2bbc7a29e97f1abc6f))
##### Admin ##### Admin
* Add more details for admin errors ([17865d](https://github.com/telecart-labs/telecart/commit/17865d8af4ed4b7f1f02a5b065847281fa5ede5f)) * Add more details for admin errors ([17865d](https://github.com/megapay-labs/megapay/commit/17865d8af4ed4b7f1f02a5b065847281fa5ede5f))
* Refactor logs viewer with table display and detailed dialog ([b39a34](https://github.com/telecart-labs/telecart/commit/b39a344a7dac32225d6fe939ea81fcc67f4b5750)) * Refactor logs viewer with table display and detailed dialog ([b39a34](https://github.com/megapay-labs/megapay/commit/b39a344a7dac32225d6fe939ea81fcc67f4b5750))
* Remove legacy setting keys that not defined in defaults ([107741](https://github.com/telecart-labs/telecart/commit/1077417d717cbd601bdff82ab3dfbb61402c3640)) * Remove legacy setting keys that not defined in defaults ([107741](https://github.com/megapay-labs/megapay/commit/1077417d717cbd601bdff82ab3dfbb61402c3640))
##### Banner ##### Banner
* Add banner feature ([05e7ca](https://github.com/telecart-labs/telecart/commit/05e7cafd0f36b204e0dea51a0f46f1a2c795dceb)) * Add banner feature ([05e7ca](https://github.com/megapay-labs/megapay/commit/05e7cafd0f36b204e0dea51a0f46f1a2c795dceb))
##### Customers ##### Customers
* Track order meta and OC sync ([952d8e](https://github.com/telecart-labs/telecart/commit/952d8e58da2972ff834d7f6609749b6dbd15a938)) * Track order meta and OC sync ([952d8e](https://github.com/megapay-labs/megapay/commit/952d8e58da2972ff834d7f6609749b6dbd15a938))
##### Products-feed ##### Products-feed
* Replace fixed image dimensions with aspect ratio selection ([cd0606](https://github.com/telecart-labs/telecart/commit/cd060610fe991c7c6d0db81a24bfa2b062192d20)) * Replace fixed image dimensions with aspect ratio selection ([cd0606](https://github.com/megapay-labs/megapay/commit/cd060610fe991c7c6d0db81a24bfa2b062192d20))
##### Pulse ##### Pulse
* Implement reliable event tracking and delivery system ([4a3dcc](https://github.com/telecart-labs/telecart/commit/4a3dcc11d161420c58494d744909f48982bd2582)) * Implement reliable event tracking and delivery system ([4a3dcc](https://github.com/megapay-labs/megapay/commit/4a3dcc11d161420c58494d744909f48982bd2582))
##### Search ##### Search
* Add keyboard hide button and auto-hide Dock ([db8d13](https://github.com/telecart-labs/telecart/commit/db8d1360fc9d8702fa7f2607337ac447ea646c5d)) * Add keyboard hide button and auto-hide Dock ([db8d13](https://github.com/megapay-labs/megapay/commit/db8d1360fc9d8702fa7f2607337ac447ea646c5d))
* Improve search UI with sticky bar and keyboard handling ([64ead2](https://github.com/telecart-labs/telecart/commit/64ead29583086dc55ae59e5d2b775dae31f36944)) * Improve search UI with sticky bar and keyboard handling ([64ead2](https://github.com/megapay-labs/megapay/commit/64ead29583086dc55ae59e5d2b775dae31f36944))
##### Slider ##### Slider
* Add slider feature ([3049bd](https://github.com/telecart-labs/telecart/commit/3049bd3101a44259f2883b351244c6eb5564cf89)) * Add slider feature ([3049bd](https://github.com/megapay-labs/megapay/commit/3049bd3101a44259f2883b351244c6eb5564cf89))
##### Spa ##### Spa
* Add custom dock ([4936e6](https://github.com/telecart-labs/telecart/commit/4936e6f16c0cd44299d086911a347cd3626fa2af)) * Add custom dock ([4936e6](https://github.com/megapay-labs/megapay/commit/4936e6f16c0cd44299d086911a347cd3626fa2af))
* Add dock ([2e699e](https://github.com/telecart-labs/telecart/commit/2e699eb0d6aca08d3f87030ea822c1fc79d3d477)) * Add dock ([2e699e](https://github.com/megapay-labs/megapay/commit/2e699eb0d6aca08d3f87030ea822c1fc79d3d477))
* Correct radius for floating panel, small ui fixes ([72ab84](https://github.com/telecart-labs/telecart/commit/72ab842a95f090b886787f551bee274fc2f6932c)) * Correct radius for floating panel, small ui fixes ([72ab84](https://github.com/megapay-labs/megapay/commit/72ab842a95f090b886787f551bee274fc2f6932c))
* Show navbar with app logo and app name ([c3c0d6](https://github.com/telecart-labs/telecart/commit/c3c0d6d2c179c83a1700d773c496ff7a44cce99c)) * Show navbar with app logo and app name ([c3c0d6](https://github.com/megapay-labs/megapay/commit/c3c0d6d2c179c83a1700d773c496ff7a44cce99c))
* UI changes ([ed8592](https://github.com/telecart-labs/telecart/commit/ed8592c19dabf4f26d6ed45e55a3c6f7398d667e)) * UI changes ([ed8592](https://github.com/megapay-labs/megapay/commit/ed8592c19dabf4f26d6ed45e55a3c6f7398d667e))
##### Telecart ##### Megapay
* Add vouchers and coupons (#9) ([ac24f0](https://github.com/telecart-labs/telecart/commit/ac24f0376bee13cc14db49a2904867ef173dcf95)) * Add vouchers and coupons (#9) ([ac24f0](https://github.com/megapay-labs/megapay/commit/ac24f0376bee13cc14db49a2904867ef173dcf95))
##### Texts ##### Texts
* Add options to redefine text for zero product prices ([1fbbb7](https://github.com/telecart-labs/telecart/commit/1fbbb7b6db13a9dac745c32d11f2e71ed79e854e)) * Add options to redefine text for zero product prices ([1fbbb7](https://github.com/megapay-labs/megapay/commit/1fbbb7b6db13a9dac745c32d11f2e71ed79e854e))
##### Ya metrika ##### Ya metrika
* WIP yandex metrika ([d7666f](https://github.com/telecart-labs/telecart/commit/d7666f94ba22fc1a808299e9a91ead14e6b58b25)) * WIP yandex metrika ([d7666f](https://github.com/megapay-labs/megapay/commit/d7666f94ba22fc1a808299e9a91ead14e6b58b25))
### Bug Fixes ### Bug Fixes
* Admin mainpage builder drawer doesnot show ([ad54b1](https://github.com/telecart-labs/telecart/commit/ad54b14c6804fae8960a5e15dbceb0549d91c732)) * Admin mainpage builder drawer doesnot show ([ad54b1](https://github.com/megapay-labs/megapay/commit/ad54b14c6804fae8960a5e15dbceb0549d91c732))
* Base header color ([28d80d](https://github.com/telecart-labs/telecart/commit/28d80d0f19ee31fea5011c2b466edea1590ab71e)) * Base header color ([28d80d](https://github.com/megapay-labs/megapay/commit/28d80d0f19ee31fea5011c2b466edea1590ab71e))
* Browser check ([4cd49b](https://github.com/telecart-labs/telecart/commit/4cd49b17a6df65863dc9fd32efdd0bba4b4e44ff)) * Browser check ([4cd49b](https://github.com/megapay-labs/megapay/commit/4cd49b17a6df65863dc9fd32efdd0bba4b4e44ff))
* Center image on product view ([dc198c](https://github.com/telecart-labs/telecart/commit/dc198c63b7c4f66b92eeb55958983d8eaed0260f)) * Center image on product view ([dc198c](https://github.com/megapay-labs/megapay/commit/dc198c63b7c4f66b92eeb55958983d8eaed0260f))
* Correct cli.php path for phar ([57c840](https://github.com/telecart-labs/telecart/commit/57c8400904b74569c843cd898fe6c39552f91e6b)) * Correct cli.php path for phar ([57c840](https://github.com/megapay-labs/megapay/commit/57c8400904b74569c843cd898fe6c39552f91e6b))
* Correct counter id for yandex metrika test ([9870f2](https://github.com/telecart-labs/telecart/commit/9870f2f36364ec7d968b3aec14091aefae774199)) * Correct counter id for yandex metrika test ([9870f2](https://github.com/megapay-labs/megapay/commit/9870f2f36364ec7d968b3aec14091aefae774199))
* Correct crontab line ([613ce5](https://github.com/telecart-labs/telecart/commit/613ce520ee53be47ee06e101daf54c8f5136184b)) * Correct crontab line ([613ce5](https://github.com/megapay-labs/megapay/commit/613ce520ee53be47ee06e101daf54c8f5136184b))
* Correct path for cron ([185f30](https://github.com/telecart-labs/telecart/commit/185f3096e1e17507f4191104794991448d4d44bb)) * Correct path for cron ([185f30](https://github.com/megapay-labs/megapay/commit/185f3096e1e17507f4191104794991448d4d44bb))
* Correct url for hit ([515b82](https://github.com/telecart-labs/telecart/commit/515b82302ba603f61324ace576e23adbf82560fd)) * Correct url for hit ([515b82](https://github.com/megapay-labs/megapay/commit/515b82302ba603f61324ace576e23adbf82560fd))
* Disable fullscreen for desktop ([bf32d9](https://github.com/telecart-labs/telecart/commit/bf32d9081169206cef62d92f27338321d1cc1e69)) * Disable fullscreen for desktop ([bf32d9](https://github.com/megapay-labs/megapay/commit/bf32d9081169206cef62d92f27338321d1cc1e69))
* Fix dock layout ([bdbdfc](https://github.com/telecart-labs/telecart/commit/bdbdfc3650ff24e77f7f35059ac72e87cd02ddf2)) * Fix dock layout ([bdbdfc](https://github.com/megapay-labs/megapay/commit/bdbdfc3650ff24e77f7f35059ac72e87cd02ddf2))
* Fix errors and small improvements ([3b2e2c](https://github.com/telecart-labs/telecart/commit/3b2e2cb656bb8db6feebdbb23612202f96cdde3f)) * Fix errors and small improvements ([3b2e2c](https://github.com/megapay-labs/megapay/commit/3b2e2cb656bb8db6feebdbb23612202f96cdde3f))
* Fix search issues ([2f9a55](https://github.com/telecart-labs/telecart/commit/2f9a553ae356fe4fb7ee3a481010d14be7d94ad7)) * Fix search issues ([2f9a55](https://github.com/megapay-labs/megapay/commit/2f9a553ae356fe4fb7ee3a481010d14be7d94ad7))
* Fix type error ([836161](https://github.com/telecart-labs/telecart/commit/8361616dd647397777849fd87267134e0bc1fb9b)) * Fix type error ([836161](https://github.com/megapay-labs/megapay/commit/8361616dd647397777849fd87267134e0bc1fb9b))
* Glob not work with phar ([24db69](https://github.com/telecart-labs/telecart/commit/24db69fbbad6758d11dabdac54f075611cde9593)) * Glob not work with phar ([24db69](https://github.com/megapay-labs/megapay/commit/24db69fbbad6758d11dabdac54f075611cde9593))
* Grant +x permissions for cli.php ([0ee3b7](https://github.com/telecart-labs/telecart/commit/0ee3b7d091da970d19a755207c73c28689bfd2a4)) * Grant +x permissions for cli.php ([0ee3b7](https://github.com/megapay-labs/megapay/commit/0ee3b7d091da970d19a755207c73c28689bfd2a4))
* Handle missing tags in workflow ([bc50cf](https://github.com/telecart-labs/telecart/commit/bc50cf064854ad0597f1d7a39b0eb32d88d2598a)) * Handle missing tags in workflow ([bc50cf](https://github.com/megapay-labs/megapay/commit/bc50cf064854ad0597f1d7a39b0eb32d88d2598a))
* Image picker component name type ([30b010](https://github.com/telecart-labs/telecart/commit/30b0108fe78b2a594db0c749f563577921c189d0)) * Image picker component name type ([30b010](https://github.com/megapay-labs/megapay/commit/30b0108fe78b2a594db0c749f563577921c189d0))
* Many products in search ([a5e91d](https://github.com/telecart-labs/telecart/commit/a5e91dd488b1f13abf739797e75400ddf36ba7e1)) * Many products in search ([a5e91d](https://github.com/megapay-labs/megapay/commit/a5e91dd488b1f13abf739797e75400ddf36ba7e1))
* Order creation ([82ab81](https://github.com/telecart-labs/telecart/commit/82ab8134e19f2cc4066de5241e7ff29905d79b17)) * Order creation ([82ab81](https://github.com/megapay-labs/megapay/commit/82ab8134e19f2cc4066de5241e7ff29905d79b17))
* Pulse ingest ([95dd54](https://github.com/telecart-labs/telecart/commit/95dd545dc5718046cd421d70ad2d4ea137919852)) * Pulse ingest ([95dd54](https://github.com/megapay-labs/megapay/commit/95dd545dc5718046cd421d70ad2d4ea137919852))
* Scroll behaviour ([359395](https://github.com/telecart-labs/telecart/commit/359395b7e880d72dd34da504f6d9fe001d6f0aff)) * Scroll behaviour ([359395](https://github.com/megapay-labs/megapay/commit/359395b7e880d72dd34da504f6d9fe001d6f0aff))
* Search ([e5792a](https://github.com/telecart-labs/telecart/commit/e5792a059a0986b6d6c86df9dbcbda212bc0f548)) * Search ([e5792a](https://github.com/megapay-labs/megapay/commit/e5792a059a0986b6d6c86df9dbcbda212bc0f548))
* Settings numeric error ([44d2af](https://github.com/telecart-labs/telecart/commit/44d2af3b30a7133b550e56385c3096c0e8848df5)) * Settings numeric error ([44d2af](https://github.com/megapay-labs/megapay/commit/44d2af3b30a7133b550e56385c3096c0e8848df5))
* Store error ([ab5c2f](https://github.com/telecart-labs/telecart/commit/ab5c2f42b907d19f0c52c631cea02b981a199c39)) * Store error ([ab5c2f](https://github.com/megapay-labs/megapay/commit/ab5c2f42b907d19f0c52c631cea02b981a199c39))
* Switch between code and visual for custom forms ([0ab09a](https://github.com/telecart-labs/telecart/commit/0ab09aad10eb724cf0378bcc2f46001b5108fade)) * Switch between code and visual for custom forms ([0ab09a](https://github.com/megapay-labs/megapay/commit/0ab09aad10eb724cf0378bcc2f46001b5108fade))
* Test ([c4b192](https://github.com/telecart-labs/telecart/commit/c4b19286f36ad166a1092dda86e65d48e3390723)) * Test ([c4b192](https://github.com/megapay-labs/megapay/commit/c4b19286f36ad166a1092dda86e65d48e3390723))
* Use html for tg bot ([7e6502](https://github.com/telecart-labs/telecart/commit/7e6502b07e74e27e27326c9593f25c2c9c03418b)) * Use html for tg bot ([7e6502](https://github.com/megapay-labs/megapay/commit/7e6502b07e74e27e27326c9593f25c2c9c03418b))
##### Admin ##### Admin
* Fix error when chat_id is string ([8f6af0](https://github.com/telecart-labs/telecart/commit/8f6af04e732f853eb79504676dc5ae83ba151c93)) * Fix error when chat_id is string ([8f6af0](https://github.com/megapay-labs/megapay/commit/8f6af04e732f853eb79504676dc5ae83ba151c93))
##### Spa ##### Spa
* Remove html in price for some opencart custom themes ([3423dd](https://github.com/telecart-labs/telecart/commit/3423dd172748845ce5177ea6bf5894a6da977c37), [d6a436](https://github.com/telecart-labs/telecart/commit/d6a43605acaff1cf335dc044e2b297132d6eb2ce)) * Remove html in price for some opencart custom themes ([3423dd](https://github.com/megapay-labs/megapay/commit/3423dd172748845ce5177ea6bf5894a6da977c37), [d6a436](https://github.com/megapay-labs/megapay/commit/d6a43605acaff1cf335dc044e2b297132d6eb2ce))
##### Telecart ##### Megapay
* Fix products search ([98ee6d](https://github.com/telecart-labs/telecart/commit/98ee6d9ecac4349cad847bdba1b10cf8660c251f)) * Fix products search ([98ee6d](https://github.com/megapay-labs/megapay/commit/98ee6d9ecac4349cad847bdba1b10cf8660c251f))
--- ---
## [1.3.2](https://github.com/telecart-labs/telecart/compare/v1.3.1...v1.3.2) (2025-10-24) ## [1.3.2](https://github.com/megapay-labs/megapay/compare/v1.3.1...v1.3.2) (2025-10-24)
### Bug Fixes ### Bug Fixes
##### Products ##### Products
* Encode html for title on products page ([78ca4f](https://github.com/telecart-labs/telecart/commit/78ca4fd309e2254771a01ade75197d46e149c5f3)) * Encode html for title on products page ([78ca4f](https://github.com/megapay-labs/megapay/commit/78ca4fd309e2254771a01ade75197d46e149c5f3))
--- ---
## [1.3.1](https://github.com/telecart-labs/telecart/compare/v1.3.0...v1.3.1) (2025-10-19) ## [1.3.1](https://github.com/megapay-labs/megapay/compare/v1.3.0...v1.3.1) (2025-10-19)
### Bug Fixes ### Bug Fixes
##### App ##### App
* Fix unhandled exceptions ([aa4264](https://github.com/telecart-labs/telecart/commit/aa42643c34c1a7cb11aae2d3191ac63c0af3236a)) * Fix unhandled exceptions ([aa4264](https://github.com/megapay-labs/megapay/commit/aa42643c34c1a7cb11aae2d3191ac63c0af3236a))
--- ---
## [1.3.0](https://github.com/telecart-labs/telecart/compare/v1.2.0...v1.3.0) (2025-10-19) ## [1.3.0](https://github.com/megapay-labs/megapay/compare/v1.2.0...v1.3.0) (2025-10-19)
### Features ### Features
* Add filters to mainpage ([1e2a9b](https://github.com/telecart-labs/telecart/commit/1e2a9bc7051e14c65eb44b392dba11f766b95d33)) * Add filters to mainpage ([1e2a9b](https://github.com/megapay-labs/megapay/commit/1e2a9bc7051e14c65eb44b392dba11f766b95d33))
* Handle start command for telecart bot ([c936d7](https://github.com/telecart-labs/telecart/commit/c936d727b495b06f63d7f15949d540f2c9a2b9c0)) * Handle start command for megapay bot ([c936d7](https://github.com/megapay-labs/megapay/commit/c936d727b495b06f63d7f15949d540f2c9a2b9c0))
##### Admin ##### Admin
* Do not log assets cleanup message if nothing deleted ([00165b](https://github.com/telecart-labs/telecart/commit/00165b3b61841303a6eff0447ee134d860f4a8b9)) * Do not log assets cleanup message if nothing deleted ([00165b](https://github.com/megapay-labs/megapay/commit/00165b3b61841303a6eff0447ee134d860f4a8b9))
* Remove old assets ([01368b](https://github.com/telecart-labs/telecart/commit/01368bbfce831cd8949500ffdf5f5e4614316459)) * Remove old assets ([01368b](https://github.com/megapay-labs/megapay/commit/01368bbfce831cd8949500ffdf5f5e4614316459))
* Remove old maps ([31a990](https://github.com/telecart-labs/telecart/commit/31a9909cc37c953113c743d248c9dd4065f89acb)) * Remove old maps ([31a990](https://github.com/megapay-labs/megapay/commit/31a9909cc37c953113c743d248c9dd4065f89acb))
##### Bot ##### Bot
* Add bot commands ([023ace](https://github.com/telecart-labs/telecart/commit/023acee68fb8f247a5e84f62aade44c77cfc0ed5)) * Add bot commands ([023ace](https://github.com/megapay-labs/megapay/commit/023acee68fb8f247a5e84f62aade44c77cfc0ed5))
##### Filters ##### Filters
* Add filters for the main page ([e7e045](https://github.com/telecart-labs/telecart/commit/e7e045b695d227d2d895242b4c0f19883d07f69e)) * Add filters for the main page ([e7e045](https://github.com/megapay-labs/megapay/commit/e7e045b695d227d2d895242b4c0f19883d07f69e))
##### Spa ##### Spa
* Hide floating cart btn for filters page ([259154](https://github.com/telecart-labs/telecart/commit/259154e4f1ca2ac0e2e6a357e8a53be78a00441a)) * Hide floating cart btn for filters page ([259154](https://github.com/megapay-labs/megapay/commit/259154e4f1ca2ac0e2e6a357e8a53be78a00441a))
* Lock vertical orientation ([646721](https://github.com/telecart-labs/telecart/commit/6467216775c44a7f4cc924d4551cc88ca246b757)) * Lock vertical orientation ([646721](https://github.com/megapay-labs/megapay/commit/6467216775c44a7f4cc924d4551cc88ca246b757))
* Update Telegram Mini App to 59 version ([3ecb51](https://github.com/telecart-labs/telecart/commit/3ecb51b5cd1751f4e2ace73171225ee3a33e46c4)) * Update Telegram Mini App to 59 version ([3ecb51](https://github.com/megapay-labs/megapay/commit/3ecb51b5cd1751f4e2ace73171225ee3a33e46c4))
### Bug Fixes ### Bug Fixes
* Escape character for start message command ([a051ff](https://github.com/telecart-labs/telecart/commit/a051ff545e920760e3a0e6c34ef3cc94a0c1bfdb)) * Escape character for start message command ([a051ff](https://github.com/megapay-labs/megapay/commit/a051ff545e920760e3a0e6c34ef3cc94a0c1bfdb))
--- ---
## [1.2.0](https://github.com/telecart-labs/telecart/compare/v1.1.0...v1.2.0) (2025-09-27) ## [1.2.0](https://github.com/megapay-labs/megapay/compare/v1.1.0...v1.2.0) (2025-09-27)
### Features ### Features
##### Product ##### Product
* Add option to disable store feature ([d7dd05](https://github.com/telecart-labs/telecart/commit/d7dd055e245a5bb0772b382ca8542394e92fecd5)) * Add option to disable store feature ([d7dd05](https://github.com/megapay-labs/megapay/commit/d7dd055e245a5bb0772b382ca8542394e92fecd5))
### Bug Fixes ### Bug Fixes
* Correct update opencart config after defaults diff update ([e24e7c](https://github.com/telecart-labs/telecart/commit/e24e7c6d106597c627451abf8014723f42fdda34)) * Correct update opencart config after defaults diff update ([e24e7c](https://github.com/megapay-labs/megapay/commit/e24e7c6d106597c627451abf8014723f42fdda34))
--- ---
## [1.1.0](https://github.com/telecart-labs/telecart/compare/v1.0.7...v1.1.0) (2025-09-26) ## [1.1.0](https://github.com/megapay-labs/megapay/compare/v1.0.7...v1.1.0) (2025-09-26)
--- ---
## [1.0.7](https://github.com/telecart-labs/telecart/compare/v1.0.6...v1.0.7) (2025-09-26) ## [1.0.7](https://github.com/megapay-labs/megapay/compare/v1.0.6...v1.0.7) (2025-09-26)
### Features ### Features
##### Categories ##### Categories
* Added animations for categories list ([b7b255](https://github.com/telecart-labs/telecart/commit/b7b255887db2d04b8ba70a966382f44c92475df0)) * Added animations for categories list ([b7b255](https://github.com/megapay-labs/megapay/commit/b7b255887db2d04b8ba70a966382f44c92475df0))
* Add skeleton for categories loading ([294e0c](https://github.com/telecart-labs/telecart/commit/294e0cd17e2038f3088b504331ad9b009129e8ed)) * Add skeleton for categories loading ([294e0c](https://github.com/megapay-labs/megapay/commit/294e0cd17e2038f3088b504331ad9b009129e8ed))
* Hide button from categories ([f06606](https://github.com/telecart-labs/telecart/commit/f066069a1b6cf186046e272bc7af61ab46f79c0e)) * Hide button from categories ([f06606](https://github.com/megapay-labs/megapay/commit/f066069a1b6cf186046e272bc7af61ab46f79c0e))
##### Design ##### Design
* Add safe top padding for product page ([a3e5b8](https://github.com/telecart-labs/telecart/commit/a3e5b8b07a28813115662b566284f8622f0b3722)) * Add safe top padding for product page ([a3e5b8](https://github.com/megapay-labs/megapay/commit/a3e5b8b07a28813115662b566284f8622f0b3722))
* Product link in cart ([39a350](https://github.com/telecart-labs/telecart/commit/39a350d517d5d762720236f0e9b682299fd2b746)) * Product link in cart ([39a350](https://github.com/megapay-labs/megapay/commit/39a350d517d5d762720236f0e9b682299fd2b746))
##### Products ##### Products
* Show correct product prices ([35dd0d](https://github.com/telecart-labs/telecart/commit/35dd0de261a4497c01cd6eb54ed0d7032cea5f8b)) * Show correct product prices ([35dd0d](https://github.com/megapay-labs/megapay/commit/35dd0de261a4497c01cd6eb54ed0d7032cea5f8b))
### Bug Fixes ### Bug Fixes
##### Product ##### Product
* Decode html entities for product and category names ([acbfae](https://github.com/telecart-labs/telecart/commit/acbfaebcf415f42c6fb16c6a39d5e10f0776da90)) * Decode html entities for product and category names ([acbfae](https://github.com/megapay-labs/megapay/commit/acbfaebcf415f42c6fb16c6a39d5e10f0776da90))
* Fix error when image not found ([a381b3](https://github.com/telecart-labs/telecart/commit/a381b3a6ee6972775815db382269ec8ab3d31a4f)) * Fix error when image not found ([a381b3](https://github.com/megapay-labs/megapay/commit/a381b3a6ee6972775815db382269ec8ab3d31a4f))
* Fix select product option UI ([22a783](https://github.com/telecart-labs/telecart/commit/22a783f0ef833f5797e798222dce65493d71b34b)) * Fix select product option UI ([22a783](https://github.com/megapay-labs/megapay/commit/22a783f0ef833f5797e798222dce65493d71b34b))
--- ---
## [1.0.6](https://github.com/telecart-labs/telecart/compare/v1.0.5...v1.0.6) (2025-09-24) ## [1.0.6](https://github.com/megapay-labs/megapay/compare/v1.0.5...v1.0.6) (2025-09-24)
### Bug Fixes ### Bug Fixes
* Fix possible foreign error message on telecart page ([016eeb](https://github.com/telecart-labs/telecart/commit/016eeb445db7ce692825d323bed7c1dd815e30af)) * Fix possible foreign error message on megapay page ([016eeb](https://github.com/megapay-labs/megapay/commit/016eeb445db7ce692825d323bed7c1dd815e30af))
##### Categories ##### Categories
* Fix nested lvl > 2 categories rendering ([0f04cb](https://github.com/telecart-labs/telecart/commit/0f04cbf105252b88358095ae5be33fedca6f1e63)) * Fix nested lvl > 2 categories rendering ([0f04cb](https://github.com/megapay-labs/megapay/commit/0f04cbf105252b88358095ae5be33fedca6f1e63))
* Increase max categories count to display up to 100 ([9f6416](https://github.com/telecart-labs/telecart/commit/9f6416a1b7b7f065b558ecd3089c42ef397bd817)) * Increase max categories count to display up to 100 ([9f6416](https://github.com/megapay-labs/megapay/commit/9f6416a1b7b7f065b558ecd3089c42ef397bd817))
##### Database ##### Database
* Fix db connection error when not standard mysql port ([ec5cdf](https://github.com/telecart-labs/telecart/commit/ec5cdfcaa9321cb824c858df91ce4464d6158a2c)) * Fix db connection error when not standard mysql port ([ec5cdf](https://github.com/megapay-labs/megapay/commit/ec5cdfcaa9321cb824c858df91ce4464d6158a2c))
--- ---
## [1.0.5](https://github.com/telecart-labs/telecart/compare/v1.0.4...v1.0.5) (2025-09-24) ## [1.0.5](https://github.com/megapay-labs/megapay/compare/v1.0.4...v1.0.5) (2025-09-24)
### Features ### Features
##### Categories ##### Categories
* Add options to select what categories to show on front page ([9e4022](https://github.com/telecart-labs/telecart/commit/9e4022f64856082fffa7a0264949373319cdf9ff)) * Add options to select what categories to show on front page ([9e4022](https://github.com/megapay-labs/megapay/commit/9e4022f64856082fffa7a0264949373319cdf9ff))
--- ---
## [1.0.4](https://github.com/telecart-labs/telecart/compare/v1.0.3...v1.0.4) (2025-09-24) ## [1.0.4](https://github.com/megapay-labs/megapay/compare/v1.0.3...v1.0.4) (2025-09-24)
### Bug Fixes ### Bug Fixes
* Error when category doesnt have image ([490cbf](https://github.com/telecart-labs/telecart/commit/490cbfacf72095001dccaf374034292ea247e21b)) * Error when category doesnt have image ([490cbf](https://github.com/megapay-labs/megapay/commit/490cbfacf72095001dccaf374034292ea247e21b))
--- ---
## [1.0.3](https://github.com/telecart-labs/telecart/compare/v1.0.2...v1.0.3) (2025-09-24) ## [1.0.3](https://github.com/megapay-labs/megapay/compare/v1.0.2...v1.0.3) (2025-09-24)
### Bug Fixes ### Bug Fixes
* Init exception for some opencart versions ([0cf0c4](https://github.com/telecart-labs/telecart/commit/0cf0c438433f8c1895bef5f490bc0f9af86b0c04)) * Init exception for some opencart versions ([0cf0c4](https://github.com/megapay-labs/megapay/commit/0cf0c438433f8c1895bef5f490bc0f9af86b0c04))
--- ---
## [1.0.2](https://github.com/telecart-labs/telecart/compare/v1.0.1...v1.0.2) (2025-08-16) ## [1.0.2](https://github.com/megapay-labs/megapay/compare/v1.0.1...v1.0.2) (2025-08-16)
### Bug Fixes ### Bug Fixes
* UI fixes ([854dfd](https://github.com/telecart-labs/telecart/commit/854dfdf7f2dba7bc78b53c19f345c1909298c474)) * UI fixes ([854dfd](https://github.com/megapay-labs/megapay/commit/854dfdf7f2dba7bc78b53c19f345c1909298c474))
--- ---
## [1.0.1](https://github.com/telecart-labs/telecart/compare/v1.0.0...v1.0.1) (2025-08-16) ## [1.0.1](https://github.com/megapay-labs/megapay/compare/v1.0.0...v1.0.1) (2025-08-16)
### Bug Fixes ### Bug Fixes
* Check code phrase when configure chat_id ([a0abc1](https://github.com/telecart-labs/telecart/commit/a0abc14c6db91fb6cec14f8aa64297d671e88a7e)) * Check code phrase when configure chat_id ([a0abc1](https://github.com/megapay-labs/megapay/commit/a0abc14c6db91fb6cec14f8aa64297d671e88a7e))
--- ---
## [1.0.0](https://github.com/telecart-labs/telecart/compare/v0.0.2...v1.0.0) (2025-08-16) ## [1.0.0](https://github.com/megapay-labs/megapay/compare/v0.0.2...v1.0.0) (2025-08-16)
### Features ### Features
* Add bot_token validation ([d7df5a](https://github.com/telecart-labs/telecart/commit/d7df5a4b5c8abdf5117c07a9bb7fc7744c23eb1d)) * Add bot_token validation ([d7df5a](https://github.com/megapay-labs/megapay/commit/d7df5a4b5c8abdf5117c07a9bb7fc7744c23eb1d))
* Add carousel for images ([a40089](https://github.com/telecart-labs/telecart/commit/a40089ef553eaf30d813a9e2b2495fe3aa7dd0d4)) * Add carousel for images ([a40089](https://github.com/megapay-labs/megapay/commit/a40089ef553eaf30d813a9e2b2495fe3aa7dd0d4))
* Add Categories ([6a8ea0](https://github.com/telecart-labs/telecart/commit/6a8ea048ea52e6bd3c146b4ec311e9633fce269a)) * Add Categories ([6a8ea0](https://github.com/megapay-labs/megapay/commit/6a8ea048ea52e6bd3c146b4ec311e9633fce269a))
* Add custom BottomButton instead of TG ([b0cc02](https://github.com/telecart-labs/telecart/commit/b0cc0237af12ea5560835092bb808e4bc742c380)) * Add custom BottomButton instead of TG ([b0cc02](https://github.com/megapay-labs/megapay/commit/b0cc0237af12ea5560835092bb808e4bc742c380))
* Add fullscreen viewer ([4ae8d5](https://github.com/telecart-labs/telecart/commit/4ae8d593280774527fbeda3e52d924bd23a12813)) * Add fullscreen viewer ([4ae8d5](https://github.com/megapay-labs/megapay/commit/4ae8d593280774527fbeda3e52d924bd23a12813))
* Add fulscreen mode, dark mode ([252854](https://github.com/telecart-labs/telecart/commit/252854e67ea93716c271e2e20d25b0d73e24e380)) * Add fulscreen mode, dark mode ([252854](https://github.com/megapay-labs/megapay/commit/252854e67ea93716c271e2e20d25b0d73e24e380))
* Add haptictouch to bottom buttons ([51ce6e](https://github.com/telecart-labs/telecart/commit/51ce6ed959e9b673a0cfd9fac614f743b24d582f)) * Add haptictouch to bottom buttons ([51ce6e](https://github.com/megapay-labs/megapay/commit/51ce6ed959e9b673a0cfd9fac614f743b24d582f))
* Add hero block ([3c819e](https://github.com/telecart-labs/telecart/commit/3c819e6c6cf9d25088c2a8024da13e8e0180bde7)) * Add hero block ([3c819e](https://github.com/megapay-labs/megapay/commit/3c819e6c6cf9d25088c2a8024da13e8e0180bde7))
* Add manufacturer to product view ([b25f6d](https://github.com/telecart-labs/telecart/commit/b25f6d3c7335c42487702aa7fff2c5003fd63046)) * Add manufacturer to product view ([b25f6d](https://github.com/megapay-labs/megapay/commit/b25f6d3c7335c42487702aa7fff2c5003fd63046))
* Add new mainpage products options, hide attributes ([d9fd26](https://github.com/telecart-labs/telecart/commit/d9fd26d3541e02d4656d32af547a3e338bbbc4ff)) * Add new mainpage products options, hide attributes ([d9fd26](https://github.com/megapay-labs/megapay/commit/d9fd26d3541e02d4656d32af547a3e338bbbc4ff))
* Add preloader for product page ([b66a02](https://github.com/telecart-labs/telecart/commit/b66a02fd57a2f0233b37bb76b30a360e71333256)) * Add preloader for product page ([b66a02](https://github.com/megapay-labs/megapay/commit/b66a02fd57a2f0233b37bb76b30a360e71333256))
* Add product view page ([f13e12](https://github.com/telecart-labs/telecart/commit/f13e128d03831598ecd058217a0e8874f0831f75)) * Add product view page ([f13e12](https://github.com/megapay-labs/megapay/commit/f13e128d03831598ecd058217a0e8874f0831f75))
* Add telegram api ([b958fe](https://github.com/telecart-labs/telecart/commit/b958feaec751b2e3a4134f925a74c75d5d2d1b42)) * Add telegram api ([b958fe](https://github.com/megapay-labs/megapay/commit/b958feaec751b2e3a4134f925a74c75d5d2d1b42))
* Add telegram safe content area ([1715c0](https://github.com/telecart-labs/telecart/commit/1715c01b1d1b99d4e99a8fe6f40107a384250326)) * Add telegram safe content area ([1715c0](https://github.com/megapay-labs/megapay/commit/1715c01b1d1b99d4e99a8fe6f40107a384250326))
* Add validation and use opencart logger ([9f35ac](https://github.com/telecart-labs/telecart/commit/9f35acf39935416bfbb35735c3749baf0af20995)) * Add validation and use opencart logger ([9f35ac](https://github.com/megapay-labs/megapay/commit/9f35acf39935416bfbb35735c3749baf0af20995))
* Allow only vertical orientation ([fe4188](https://github.com/telecart-labs/telecart/commit/fe4188eb8b3d58cb5fa25c267e0e0ba46effbbac)) * Allow only vertical orientation ([fe4188](https://github.com/megapay-labs/megapay/commit/fe4188eb8b3d58cb5fa25c267e0e0ba46effbbac))
* Cache frontpage products and categories ([5f785e](https://github.com/telecart-labs/telecart/commit/5f785e82e6689283526dd5a218d76908078e7942)) * Cache frontpage products and categories ([5f785e](https://github.com/megapay-labs/megapay/commit/5f785e82e6689283526dd5a218d76908078e7942))
* Create new order ([c057f4](https://github.com/telecart-labs/telecart/commit/c057f4be76544466af62556237f7031c874f5f51)) * Create new order ([c057f4](https://github.com/megapay-labs/megapay/commit/c057f4be76544466af62556237f7031c874f5f51))
* Deny direct access to the spa ([41e74b](https://github.com/telecart-labs/telecart/commit/41e74bad121d76b9a4be2a2f02822d8323e739cc)) * Deny direct access to the spa ([41e74b](https://github.com/megapay-labs/megapay/commit/41e74bad121d76b9a4be2a2f02822d8323e739cc))
* Diplicate webhook info request ([6249b2](https://github.com/telecart-labs/telecart/commit/6249b218a137e105e64fbfb0b6c8829e2ca01349)) * Diplicate webhook info request ([6249b2](https://github.com/megapay-labs/megapay/commit/6249b218a137e105e64fbfb0b6c8829e2ca01349))
* Display product options ([f47bb4](https://github.com/telecart-labs/telecart/commit/f47bb46751fea79e43a96e2b63afde4cb7ef801b)) * Display product options ([f47bb4](https://github.com/megapay-labs/megapay/commit/f47bb46751fea79e43a96e2b63afde4cb7ef801b))
* Do not check signature if bot token not set ([1d892f](https://github.com/telecart-labs/telecart/commit/1d892f7d090a1ff91f724871e688b18a40df768e)) * Do not check signature if bot token not set ([1d892f](https://github.com/megapay-labs/megapay/commit/1d892f7d090a1ff91f724871e688b18a40df768e))
* Encode images to webp for telegram mini app ([c282b6](https://github.com/telecart-labs/telecart/commit/c282b6ea3b5c04ae92708eb1984ad14d2ea46cfa)) * Encode images to webp for telegram mini app ([c282b6](https://github.com/megapay-labs/megapay/commit/c282b6ea3b5c04ae92708eb1984ad14d2ea46cfa))
* Expand mini app on mounted ([1e454b](https://github.com/telecart-labs/telecart/commit/1e454b8f2387d9a4e2e4316253d7f8bddadccc1c)) * Expand mini app on mounted ([1e454b](https://github.com/megapay-labs/megapay/commit/1e454b8f2387d9a4e2e4316253d7f8bddadccc1c))
* Fix module name in admin ([9770a0](https://github.com/telecart-labs/telecart/commit/9770a09fc0abe57d7b97137c9fef4bfaf5687278)) * Fix module name in admin ([9770a0](https://github.com/megapay-labs/megapay/commit/9770a09fc0abe57d7b97137c9fef4bfaf5687278))
* Infinity scroll, load more, resore scroll ([bb2ee3](https://github.com/telecart-labs/telecart/commit/bb2ee38118e8626f8d85070047e256ad8305c1e5)) * Infinity scroll, load more, resore scroll ([bb2ee3](https://github.com/megapay-labs/megapay/commit/bb2ee38118e8626f8d85070047e256ad8305c1e5))
* Make two columns grid for product list ([34bd64](https://github.com/telecart-labs/telecart/commit/34bd64e9025fbd61cd3c64c1e9a9bebb4bf98e5d)) * Make two columns grid for product list ([34bd64](https://github.com/megapay-labs/megapay/commit/34bd64e9025fbd61cd3c64c1e9a9bebb4bf98e5d))
* Product options, speedup home page, themes ([e3cc0d](https://github.com/telecart-labs/telecart/commit/e3cc0d4b10edf3a7c655a8e6d9a39ca587d6ecbc)) * Product options, speedup home page, themes ([e3cc0d](https://github.com/megapay-labs/megapay/commit/e3cc0d4b10edf3a7c655a8e6d9a39ca587d6ecbc))
* Remove cache, refactor ([7404ec](https://github.com/telecart-labs/telecart/commit/7404ecb33e1289439a3b4b9b5926175fe5d3872d)) * Remove cache, refactor ([7404ec](https://github.com/megapay-labs/megapay/commit/7404ecb33e1289439a3b4b9b5926175fe5d3872d))
* Remove prefilled fields in checkout ([33b350](https://github.com/telecart-labs/telecart/commit/33b3500aa470438963af90ee2edccdff9a27233d)) * Remove prefilled fields in checkout ([33b350](https://github.com/megapay-labs/megapay/commit/33b3500aa470438963af90ee2edccdff9a27233d))
* Safe-top and search ([a8bb5e](https://github.com/telecart-labs/telecart/commit/a8bb5eb493ab329bebca8c7903d4facf4a22d76a)) * Safe-top and search ([a8bb5e](https://github.com/megapay-labs/megapay/commit/a8bb5eb493ab329bebca8c7903d4facf4a22d76a))
* Search component and loading splashscreen ([2fb841](https://github.com/telecart-labs/telecart/commit/2fb841ef08027eeabdade90d9a4725ea602b3f48)) * Search component and loading splashscreen ([2fb841](https://github.com/megapay-labs/megapay/commit/2fb841ef08027eeabdade90d9a4725ea602b3f48))
* Show tg app link ([b1ea16](https://github.com/telecart-labs/telecart/commit/b1ea169e2f83cd3d3108d9d11d2b9bb8ee234211)) * Show tg app link ([b1ea16](https://github.com/megapay-labs/megapay/commit/b1ea169e2f83cd3d3108d9d11d2b9bb8ee234211))
* UI changes ([d522cb](https://github.com/telecart-labs/telecart/commit/d522cbef8389adb05cc6e70ed6665db37915233c)) * UI changes ([d522cb](https://github.com/megapay-labs/megapay/commit/d522cbef8389adb05cc6e70ed6665db37915233c))
* Ui improvements, show only active products, limit max page for infinity scroll ([d499d7](https://github.com/telecart-labs/telecart/commit/d499d7d846d55cc158306160c51d4b871f5b6376)) * Ui improvements, show only active products, limit max page for infinity scroll ([d499d7](https://github.com/megapay-labs/megapay/commit/d499d7d846d55cc158306160c51d4b871f5b6376))
* Update styles ([ca3a59](https://github.com/telecart-labs/telecart/commit/ca3a59f43ae19f9c8417993e45c63f29696f46c8)) * Update styles ([ca3a59](https://github.com/megapay-labs/megapay/commit/ca3a59f43ae19f9c8417993e45c63f29696f46c8))
##### Admin ##### Admin
* Correct getting chat_id ([1e80fd](https://github.com/telecart-labs/telecart/commit/1e80fdb2ebaf47e39a6cbd45438860428146aac6)) * Correct getting chat_id ([1e80fd](https://github.com/megapay-labs/megapay/commit/1e80fdb2ebaf47e39a6cbd45438860428146aac6))
* Correct merge new default settings after initializing app ([469077](https://github.com/telecart-labs/telecart/commit/469077d0c9006f3bcfffcecf4454f2e5e4492fac)) * Correct merge new default settings after initializing app ([469077](https://github.com/megapay-labs/megapay/commit/469077d0c9006f3bcfffcecf4454f2e5e4492fac))
* Update disclaimer text ([133bad](https://github.com/telecart-labs/telecart/commit/133badf45b9727fbf2bee7c9b9f74ff274fa3cc8)) * Update disclaimer text ([133bad](https://github.com/megapay-labs/megapay/commit/133badf45b9727fbf2bee7c9b9f74ff274fa3cc8))
##### App ##### App
* Add maintenance mode ([2752ec](https://github.com/telecart-labs/telecart/commit/2752ec3dd18261af9894c8a28a6775bdb22301c3)) * Add maintenance mode ([2752ec](https://github.com/megapay-labs/megapay/commit/2752ec3dd18261af9894c8a28a6775bdb22301c3))
* Telegram init data signature validator ([350ec4](https://github.com/telecart-labs/telecart/commit/350ec4f64bf6534e57cf613e6b38d39a052fd646)) * Telegram init data signature validator ([350ec4](https://github.com/megapay-labs/megapay/commit/350ec4f64bf6534e57cf613e6b38d39a052fd646))
##### Order ##### Order
* Add success haptic for order created event ([858be6](https://github.com/telecart-labs/telecart/commit/858be67c89130ab291b34d8bd7fb4340b6fff422)) * Add success haptic for order created event ([858be6](https://github.com/megapay-labs/megapay/commit/858be67c89130ab291b34d8bd7fb4340b6fff422))
* Order default status and customer group ([14d42c](https://github.com/telecart-labs/telecart/commit/14d42c6ecb1967cc626c57ae7ccb60f66b361aec)) * Order default status and customer group ([14d42c](https://github.com/megapay-labs/megapay/commit/14d42c6ecb1967cc626c57ae7ccb60f66b361aec))
* Order process enchancements ([85101b](https://github.com/telecart-labs/telecart/commit/85101b988140c1d0114d3176115aab0864011b16)) * Order process enchancements ([85101b](https://github.com/megapay-labs/megapay/commit/85101b988140c1d0114d3176115aab0864011b16))
* WIP: telegram notifications ([454bd3](https://github.com/telecart-labs/telecart/commit/454bd39f1f12a6fa004f80c3b13ebc17032a35f9)) * WIP: telegram notifications ([454bd3](https://github.com/megapay-labs/megapay/commit/454bd39f1f12a6fa004f80c3b13ebc17032a35f9))
##### Orders ##### Orders
* Tg notifications, ya metrika, meta tags ([86d0fa](https://github.com/telecart-labs/telecart/commit/86d0fa95941fd2b1d491de8280817d0e80b461f2)) * Tg notifications, ya metrika, meta tags ([86d0fa](https://github.com/megapay-labs/megapay/commit/86d0fa95941fd2b1d491de8280817d0e80b461f2))
##### Product ##### Product
* Change router history driver, change add to cart behaviour ([ebc352](https://github.com/telecart-labs/telecart/commit/ebc352dcdfcf08694d2590ee94c9e799e795a2fc)) * Change router history driver, change add to cart behaviour ([ebc352](https://github.com/megapay-labs/megapay/commit/ebc352dcdfcf08694d2590ee94c9e799e795a2fc))
* Display attributes ([63adf9](https://github.com/telecart-labs/telecart/commit/63adf96908137ab0c173415f77278ee7483a2fb8)) * Display attributes ([63adf9](https://github.com/megapay-labs/megapay/commit/63adf96908137ab0c173415f77278ee7483a2fb8))
##### Shop ##### Shop
* Change grid image resize algorythm ([c3c256](https://github.com/telecart-labs/telecart/commit/c3c25619326e292575236979e389f8ddb68b6958)) * Change grid image resize algorythm ([c3c256](https://github.com/megapay-labs/megapay/commit/c3c25619326e292575236979e389f8ddb68b6958))
##### Style ##### Style
* Change pagination swiper styles ([50bf90](https://github.com/telecart-labs/telecart/commit/50bf9061be778b37f7f6869f4c39a4833af31b1d)) * Change pagination swiper styles ([50bf90](https://github.com/megapay-labs/megapay/commit/50bf9061be778b37f7f6869f4c39a4833af31b1d))
### Bug Fixes ### Bug Fixes
* Add CORS headers, make ci builds as preleases ([551535](https://github.com/telecart-labs/telecart/commit/55153531fb4899d0f3e699b70231d32290800ee2)) * Add CORS headers, make ci builds as preleases ([551535](https://github.com/megapay-labs/megapay/commit/55153531fb4899d0f3e699b70231d32290800ee2))
* Add route names ([47bb2c](https://github.com/telecart-labs/telecart/commit/47bb2cae85e9a16b0076898cd6265512c3adfc3c)) * Add route names ([47bb2c](https://github.com/megapay-labs/megapay/commit/47bb2cae85e9a16b0076898cd6265512c3adfc3c))
* Change hardcoded axios url ([4bb983](https://github.com/telecart-labs/telecart/commit/4bb983e4af53baf2a7a5aa39f15b5389906a4c71)) * Change hardcoded axios url ([4bb983](https://github.com/megapay-labs/megapay/commit/4bb983e4af53baf2a7a5aa39f15b5389906a4c71))
* Correct back button work ([08af20](https://github.com/telecart-labs/telecart/commit/08af204d7403572dbc45f3a74e13cf5d3d560a42)) * Correct back button work ([08af20](https://github.com/megapay-labs/megapay/commit/08af204d7403572dbc45f3a74e13cf5d3d560a42))
* Correct controller class ([5af66d](https://github.com/telecart-labs/telecart/commit/5af66d228a3defbc6f0b4fd15a9e2a3c192bf41d)) * Correct controller class ([5af66d](https://github.com/megapay-labs/megapay/commit/5af66d228a3defbc6f0b4fd15a9e2a3c192bf41d))
* Corrent telegram mini app url in settings ([ea2a60](https://github.com/telecart-labs/telecart/commit/ea2a60b59b20d2bede9d6884349b09e55e345774)) * Corrent telegram mini app url in settings ([ea2a60](https://github.com/megapay-labs/megapay/commit/ea2a60b59b20d2bede9d6884349b09e55e345774))
* Exception if no images ([9bcf32](https://github.com/telecart-labs/telecart/commit/9bcf32841ebd4663b5c6bd5e855b18e8cd486e45)) * Exception if no images ([9bcf32](https://github.com/megapay-labs/megapay/commit/9bcf32841ebd4663b5c6bd5e855b18e8cd486e45))
* Fullscreen slide index ([4114c3](https://github.com/telecart-labs/telecart/commit/4114c3366e4090e41e29bf6e48fe5f54d0dd4a9c)) * Fullscreen slide index ([4114c3](https://github.com/megapay-labs/megapay/commit/4114c3366e4090e41e29bf6e48fe5f54d0dd4a9c))
* Glitch ([db24be](https://github.com/telecart-labs/telecart/commit/db24be6f92bbe485985892ea017f4e4ef457cd52)) * Glitch ([db24be](https://github.com/megapay-labs/megapay/commit/db24be6f92bbe485985892ea017f4e4ef457cd52))
* Icon error ([19911c](https://github.com/telecart-labs/telecart/commit/19911c8f871e456c51836c3d07add3f066744ace)) * Icon error ([19911c](https://github.com/megapay-labs/megapay/commit/19911c8f871e456c51836c3d07add3f066744ace))
* Infinity scroll, init data in base64 ([f2f161](https://github.com/telecart-labs/telecart/commit/f2f1618e0ee591bc58a830a333b1f759b0a860d6)) * Infinity scroll, init data in base64 ([f2f161](https://github.com/megapay-labs/megapay/commit/f2f1618e0ee591bc58a830a333b1f759b0a860d6))
* Night theme ([06a6dc](https://github.com/telecart-labs/telecart/commit/06a6dca656871a920092dc6767990ab70b9fc6c2)) * Night theme ([06a6dc](https://github.com/megapay-labs/megapay/commit/06a6dca656871a920092dc6767990ab70b9fc6c2))
* Router in opencart ([ad92db](https://github.com/telecart-labs/telecart/commit/ad92dbfad48f993e2393c0e235083614581ae0c6)) * Router in opencart ([ad92db](https://github.com/megapay-labs/megapay/commit/ad92dbfad48f993e2393c0e235083614581ae0c6))
* Router scroll scrollBehavior ([08d245](https://github.com/telecart-labs/telecart/commit/08d2453df92ffc89c5e6c4e264370d8b9c32a432)) * Router scroll scrollBehavior ([08d245](https://github.com/megapay-labs/megapay/commit/08d2453df92ffc89c5e6c4e264370d8b9c32a432))
* Totals ([eb1f1d](https://github.com/telecart-labs/telecart/commit/eb1f1dc9c1de7c4733d0117257f7902f145614b2)) * Totals ([eb1f1d](https://github.com/megapay-labs/megapay/commit/eb1f1dc9c1de7c4733d0117257f7902f145614b2))
* Watch router ([1ffb1c](https://github.com/telecart-labs/telecart/commit/1ffb1cef12df1bde4330a7c9531b6574a07d2fe6)) * Watch router ([1ffb1c](https://github.com/megapay-labs/megapay/commit/1ffb1cef12df1bde4330a7c9531b6574a07d2fe6))
##### Admin ##### Admin
* Fix shop url ([c61dfd](https://github.com/telecart-labs/telecart/commit/c61dfd824a532512703c207c464954b51dbcce5a)) * Fix shop url ([c61dfd](https://github.com/megapay-labs/megapay/commit/c61dfd824a532512703c207c464954b51dbcce5a))
--- ---
## [0.0.2](https://github.com/telecart-labs/telecart/compare/v0.0.1+a26c8ba...v0.0.2) (2025-07-10) ## [0.0.2](https://github.com/megapay-labs/megapay/compare/v0.0.1+a26c8ba...v0.0.2) (2025-07-10)
### Bug Fixes ### Bug Fixes
* Add CORS headers, make ci builds as preleases ([551535](https://github.com/telecart-labs/telecart/commit/55153531fb4899d0f3e699b70231d32290800ee2)) * Add CORS headers, make ci builds as preleases ([551535](https://github.com/megapay-labs/megapay/commit/55153531fb4899d0f3e699b70231d32290800ee2))
* Correct controller class ([5af66d](https://github.com/telecart-labs/telecart/commit/5af66d228a3defbc6f0b4fd15a9e2a3c192bf41d)) * Correct controller class ([5af66d](https://github.com/megapay-labs/megapay/commit/5af66d228a3defbc6f0b4fd15a9e2a3c192bf41d))
--- ---
## [0.0.1+a26c8ba](https://github.com/telecart-labs/telecart/compare/v0.0.1...v0.0.1+a26c8ba) (2025-07-10) ## [0.0.1+a26c8ba](https://github.com/megapay-labs/megapay/compare/v0.0.1...v0.0.1+a26c8ba) (2025-07-10)
### Bug Fixes ### Bug Fixes
* Add CORS headers, make ci builds as preleases ([551535](https://github.com/telecart-labs/telecart/commit/55153531fb4899d0f3e699b70231d32290800ee2)) * Add CORS headers, make ci builds as preleases ([551535](https://github.com/megapay-labs/megapay/commit/55153531fb4899d0f3e699b70231d32290800ee2))
* Correct controller class ([5af66d](https://github.com/telecart-labs/telecart/commit/5af66d228a3defbc6f0b4fd15a9e2a3c192bf41d)) * Correct controller class ([5af66d](https://github.com/megapay-labs/megapay/commit/5af66d228a3defbc6f0b4fd15a9e2a3c192bf41d))
* Move files to the correct folder ([9735d4](https://github.com/telecart-labs/telecart/commit/9735d48957b7d9947be5a1be18edba8aebc45531)) * Move files to the correct folder ([9735d4](https://github.com/megapay-labs/megapay/commit/9735d48957b7d9947be5a1be18edba8aebc45531))
--- ---
## [0.0.1](https://github.com/telecart-labs/telecart/compare/c3664025ba6b608920a0182799102a207980d7be...v0.0.1) (2025-07-10) ## [0.0.1](https://github.com/megapay-labs/megapay/compare/c3664025ba6b608920a0182799102a207980d7be...v0.0.1) (2025-07-10)
### Features ### Features
* WIP ([846fa6](https://github.com/telecart-labs/telecart/commit/846fa64fb4db9760c4264179098c43e7f53b557c)) * WIP ([846fa6](https://github.com/megapay-labs/megapay/commit/846fa64fb4db9760c4264179098c43e7f53b557c))
--- ---

147
CLAUDE.md
View File

@@ -1,147 +0,0 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Overview
TeleCart — коммерческий модуль для OpenCart, превращающий магазин в Telegram Mini App. Это монорепозиторий из трёх
частей:
- **PHP-модуль OpenCart** — `module/oc_telegram_shop/upload/` (вся бизнес-логика и собственный фреймворк).
- **SPA** — `frontend/spa/` (Telegram Mini App, витрина для покупателей).
- **Admin** — `frontend/admin/` (панель управления настройками модуля).
`src/` в корне — это распакованная установка OpenCart (генерируется скриптами, **не редактировать**; код модуля
«линкуется» в неё через `make link`).
## Документация по фичам (`docs/features/`)
Контекстная документация хранится в `docs/features/` — по одной поддиректории на фичу, внутри индексный
`CLAUDE.md`. Вложенные `CLAUDE.md` Claude Code подхватывает автоматически при чтении файлов из их директории,
поэтому индекс фичи читается «по требованию», когда работа касается этой фичи.
Перед тем как трогать незнакомую часть системы — загляни в её папку в `docs/features/`. Конвенции, шаблон новой
фичи и **реестр всех фич с прямыми путями** — в [`docs/features/CLAUDE.md`](docs/features/CLAUDE.md). Шаблон для
новой фичи — `docs/features/_TEMPLATE.md`. При изменении фичи поддерживай её доку в актуальном состоянии (код —
источник истины; при расхождении правь доку).
## Где живёт код модуля
Сердце проекта — `module/oc_telegram_shop/upload/oc_telegram_shop/` (далее «корень модуля»). Его структура:
| Каталог | Namespace | Назначение |
|------------------------|-------------------------------|-----------------------------------------------------------------------------------------------------------------------------|
| `framework/` | `Openguru\OpenCartFramework\` | Собственный Laravel-подобный фреймворк: Container (DI), Router, QueryBuilder, Cache, Migrations, Telegram, Http, Translator |
| `src/` | `App\` | API витрины/SPA (catalog). Handlers, Services, Models, DTO, Filters, ServiceProviders |
| `bastion/` | `Bastion\` | API админ-панели. Handlers, Services, Tasks, ScheduledTasks |
| `console/` | `Console\` | CLI-команды (Symfony Console), точка входа `upload/cli.php` |
| `database/migrations/` | — | Миграции БД |
| `configs/` | — | `app.php`, `maintenance.php`, `schedule.php` |
| `tests/` | `Tests\` | `Unit/`, `Integration/`, `Telegram/` |
**Маршрутизация.** Запросы приходят через action-параметр и резолвятся по двум картам:
- `src/routes.php` — действия SPA (`products`, `getCart`, `checkout`, `webhook`, …)
- `bastion/routes.php` — действия админки (`getSettingsForm`, `getTelegramCustomers`, `getDashboardStats`, …)
Каждая запись — `'actionName' => [HandlerClass::class, 'method']`.
**Точки входа OpenCart** (тонкие обёртки, грузят autoload и поднимают `App\ApplicationFactory`):
- `module/.../upload/catalog/controller/extension/tgshop/handle.php` — SPA API
- `module/.../upload/admin/controller/extension/module/tgshop.php` — админка
В продакшене модуль собирается в `oc_telegram_shop.phar` и подключается из `system/library/oc_telegram_shop/`; в dev —
из исходников через `vendor/autoload.php`.
## Архитектурные правила (бэкенд)
Паттерн — MVC-L поверх собственного фреймворка. Соблюдай строго:
- **Совместимость с PHP 7.4.** Минимальные требования OpenCart и модуля — PHP 7.4 (`composer.json`: `^7.4`). Не используй синтаксис и функции PHP 8.0+ (named arguments, `match`, constructor property promotion, `enum`, `readonly`, nullsafe `?->`, union types и т.п.).
- **Dependency Injection через конструктор.** Никогда не создавай зависимости через `new` внутри классов — внедряй их.
Регистрация сервисов идёт в Service Providers (`src/ServiceProviders/`) через `$this->app->singleton(...)`.
- **Query Builder вместо сырого SQL.** Используй `$this->builder->newQuery()->from(...)->where(...)->get()`. Прямой
SQL — только в крайних случаях; никогда не конкатенируй значения в запрос (SQL injection).
- **Слои:** Handler (валидация + вызов сервиса + `JsonResponse`) → Service (бизнес-логика) → Model (доступ к данным). Не
смешивай.
- **Строгая типизация:** `declare(strict_types=1)`, типы аргументов и возвращаемых значений, nullable где нужно. PSR-12.
- **Безопасный доступ к массивам:** `Arr::get($data, 'key', $default)` вместо `$data['key']`.
- **Таблицы:** префикс OpenCart (`oc_`) + собственные таблицы модуля.
## Архитектура фронтенда
Оба приложения — Vue 3, **только `<script setup>` + Composition API**, Pinia (setup-stores), Vue Router.
- **SPA** (`frontend/spa/`): Tailwind CSS, FormKit, Swiper, `ofetch`. Сборка →
`module/.../upload/image/catalog/tgshopspa/`. Тесты — Vitest.
- **Admin** (`frontend/admin/`): PrimeVue (основной UI-кит), Tailwind/DaisyUI, axios, CodeMirror, `vuedraggable`.
Сборка → `module/.../upload/admin/view/javascript/telecart/`.
Конвенции: компоненты — PascalCase, файлы логики — camelCase; обработчики событий с префиксом `handle`; `computed` для
производных значений; `??` (не `||`) для дефолтов чисел/булевых; сложную логику выносить в composables. Ошибки API
ловить и показывать через toast (admin: `useToast` из PrimeVue).
**FormBuilder** (admin) — отдельная подсистема визуального конструктора форм. Единственный источник истины — FormKit
Schema JSON (без промежуточных DTO). Drag-and-drop строго на `vuedraggable` (не `@formkit/drag-and-drop`).
Tailwind-классы там идут с префиксом `tw:`.
## Команды
Все `make`-цели выполняются **внутри Docker-контейнера `web`** — нужен запущенный `docker compose`.
**Старт / окружение:**
```bash
make setup # первичная установка: скачать OpenCart, установить, поднять, link
make start # поднять контейнеры
make dev # link + параллельно vite dev для SPA и Admin
make dev-spa # только SPA (vite)
make dev-admin # только Admin (vite)
make link # «слинковать» код модуля в установку OpenCart (после правок структуры)
make ssh # шелл в контейнер в каталоге модуля
```
**Тесты (PHP, PHPUnit в контейнере):**
```bash
make test # все тесты (--testdox)
make test-unit # tests/Unit
make test-integration # tests/Integration
make test-telegram # tests/Telegram
make test-coverage # HTML-покрытие в coverage/
```
Запуск одного теста — через ssh в контейнер:
```bash
make ssh
./vendor/bin/phpunit --filter testMethodName tests/Unit/SomeTest.php
```
**Тесты фронтенда (SPA):** `cd frontend/spa && npm run test` (Vitest), `npm run test:run` для однократного прогона.
**Линтеры / статический анализ:**
```bash
make lint # PHPStan (level 1) по src, bastion, framework, console
make phpcs # PHP_CodeSniffer PSR-12 (проверка)
make phpcbf # PHP_CodeSniffer PSR-12 (автофикс)
```
Admin-фронтенд: `cd frontend/admin && npm run lint` (oxlint + eslint), `npm run format` (prettier).
**Сборка / релиз:**
```bash
make phar # собрать oc_telegram_shop.phar (через docker/build.dockerfile)
make ocmod # применить OCMOD-модификации
make cli ARGS="..." # запустить console-команду модуля
make changelog # сгенерировать CHANGELOG из conventional commits
make release # changelog + commit релиза
```
## Коммиты
Используются **Conventional Commits** (`feat:`, `fix:`, `chore:`, `build(deps):` …) — CHANGELOG и версии генерируются
автоматически. **Не делать `git commit`/`git push` без явного указания пользователя.**

View File

@@ -42,12 +42,9 @@ dev-spa:
dev-admin: dev-admin:
rm -rf module/oc_telegram_shop/upload/admin/view/javascript && \ rm -rf module/oc_telegram_shop/upload/admin/view/javascript && \
rm -rf module/oc_telegram_shop/upload/system/library/oc_telegram_shop && \ rm -rf module/oc_telegram_shop/upload/system/library/oc_telegram_shop && \
rm -rf src/upload/admin/view/javascript/telecart && \ rm -rf src/upload/admin/view/javascript/megapay && \
cd frontend/admin && npm run dev cd frontend/admin && npm run dev
ocmod:
./scripts/apply_ocmod.sh
lint: lint:
docker compose exec -w /module/oc_telegram_shop/upload/oc_telegram_shop web bash -c "./vendor/bin/phpstan analyse" docker compose exec -w /module/oc_telegram_shop/upload/oc_telegram_shop web bash -c "./vendor/bin/phpstan analyse"
@@ -73,8 +70,8 @@ test-coverage:
docker compose exec -w /module/oc_telegram_shop/upload/oc_telegram_shop web bash -c "./vendor/bin/phpunit --coverage-html coverage tests/" docker compose exec -w /module/oc_telegram_shop/upload/oc_telegram_shop web bash -c "./vendor/bin/phpunit --coverage-html coverage tests/"
phar: phar:
docker build -t telecart_local_build -f ./docker/build.dockerfile . && \ docker build -t megapay_local_build -f ./deployment/build.dockerfile . && \
docker run -v "./src/upload/system/library/oc_telegram_shop:/build" telecart_local_build sh -c 'sh /scripts/build_phar.sh' docker run -v "./src/upload/system/library/oc_telegram_shop:/build" megapay_local_build sh -c 'sh /scripts/build_phar.sh'
cli: cli:
docker compose exec -w /module/oc_telegram_shop/upload web bash -c "/usr/local/bin/php cli.php $(ARGS)" docker compose exec -w /module/oc_telegram_shop/upload web bash -c "/usr/local/bin/php cli.php $(ARGS)"

View File

@@ -1,83 +1 @@
# TeleCart 2.0 # Demo code for interviewing
[![CI/CD](https://github.com/telecart-labs/telecart/actions/workflows/main.yaml/badge.svg)](https://github.com/telecart-labs/telecart/actions/workflows/main.yaml)
[![License](https://img.shields.io/badge/license-Commercial-red.svg)](LICENSE)
[![PHP Version](https://img.shields.io/badge/PHP-%3E%3D7.4-blue.svg)](https://php.net)
[![Vue.js](https://img.shields.io/badge/Vue.js-3.5.22-4FC08D?logo=vue.js&logoColor=white)](https://vuejs.org)
[![Docker](https://img.shields.io/badge/Docker-Ready-2496ED?logo=docker&logoColor=white)](docker-compose.yaml)
[![OpenCart](https://img.shields.io/badge/OpenCart-Module-FF6B35?logo=opencart)](https://www.opencart.com)
Telegram магазин на базе OpenCart. Позволяет создать полноценный интернет-магазин в виде Telegram Mini App.
## 🚀 Возможности
- 📱 Telegram Mini App интерфейс
- 🛒 Полноценная корзина и оформление заказов
- 🎨 Адаптивный дизайн с поддержкой темной/светлой темы
- 📊 Административная панель для управления настройками
- 🔍 Поиск и фильтрация товаров
- 📦 Интеграция с OpenCart
## 🛠 Технологии
- **Backend**: PHP (OpenCart), Composer
- **Frontend**: Vue.js 3, Vite, Tailwind CSS, Pinia
- **Инфраструктура**: Docker, Docker Compose
- **Тестирование**: PHPUnit, Vitest
## 📦 Структура проекта
```
telecart/
├── frontend/
│ ├── admin/ # Административная панель
│ └── spa/ # Telegram Mini App
├── module/ # Модуль OpenCart
├── docker/ # Docker конфигурации
└── src/ # Исходный код OpenCart
```
## 🚀 Быстрый старт
### Требования
- Docker и Docker Compose
- PHP >= 7.4
- Node.js >= 20.19.0 или >= 22.12.0
### Установка
```bash
# Клонировать репозиторий
git clone git@github.com:telecart-labs/telecart.git
cd telecart
# Настроить проект
make setup
# Запустить в режиме разработки
make dev
```
### Доступные команды
- `make setup` - Первоначальная настройка проекта
- `make start` - Запустить контейнеры
- `make stop` - Остановить контейнеры
- `make dev` - Запустить в режиме разработки
- `make dev-admin` - Запустить админ-панель в режиме разработки
- `make test` - Запустить тесты
- `make lint` - Проверить код линтером
## 📝 Лицензия
Это коммерческий платный модуль. Все права защищены. Использование модуля возможно только после приобретения лицензии.
## 🤝 Вклад в проект
Мы приветствуем вклад в развитие проекта! Пожалуйста, создавайте issue и pull request'ы.
## 📄 Документация
Дополнительная документация находится в папке [`docs/`](docs/).

12
backend/src/.env.example Executable file
View File

@@ -0,0 +1,12 @@
APP_DEBUG=true
PULSE_API_HOST=https://pulse.megapay.pro/api/
PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb
MEGAPAY_CACHE_DRIVER=redis
#MEGAPAY_REDIS_HOST=redis
#MEGAPAY_REDIS_PORT=6379
#MEGAPAY_REDIS_DATABASE=0
SENTRY_ENABLED=false
SENTRY_DSN=
SENTRY_ENABLE_LOGS=false

11
backend/src/.env.production Executable file
View File

@@ -0,0 +1,11 @@
APP_DEBUG=false
PULSE_API_HOST=https://pulse.megapay.pro/api/
PULSE_HEARTBEAT_SECRET=c5261f5d-529e-45ad-a69c-9778b755b7cb
MEGAPAY_CACHE_DRIVER=mysql
MEGAPAY_REDIS_HOST=redis
MEGAPAY_REDIS_PORT=6379
MEGAPAY_REDIS_DATABASE=0
SENTRY_ENABLED=false
SENTRY_DSN=
SENTRY_ENABLE_LOGS=false

View File

@@ -10,7 +10,8 @@ use Openguru\OpenCartFramework\ImageTool\ImageToolServiceProvider;
use Openguru\OpenCartFramework\QueryBuilder\QueryBuilderServiceProvider; use Openguru\OpenCartFramework\QueryBuilder\QueryBuilderServiceProvider;
use Openguru\OpenCartFramework\Router\RouteServiceProvider; use Openguru\OpenCartFramework\Router\RouteServiceProvider;
use Openguru\OpenCartFramework\Support\Arr; use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\TeleCartPulse\TeleCartPulseServiceProvider; use Openguru\OpenCartFramework\MegaPayPulse\MegaPayPulseServiceProvider;
use Openguru\OpenCartFramework\Scheduler\SchedulerServiceProvider;
use Openguru\OpenCartFramework\Telegram\TelegramServiceProvider; use Openguru\OpenCartFramework\Telegram\TelegramServiceProvider;
use Openguru\OpenCartFramework\Telegram\TelegramValidateInitDataMiddleware; use Openguru\OpenCartFramework\Telegram\TelegramValidateInitDataMiddleware;
use Openguru\OpenCartFramework\Validator\ValidatorServiceProvider; use Openguru\OpenCartFramework\Validator\ValidatorServiceProvider;
@@ -31,8 +32,9 @@ class ApplicationFactory
RouteServiceProvider::class, RouteServiceProvider::class,
AppServiceProvider::class, AppServiceProvider::class,
TelegramServiceProvider::class, TelegramServiceProvider::class,
SchedulerServiceProvider::class,
ValidatorServiceProvider::class, ValidatorServiceProvider::class,
TeleCartPulseServiceProvider::class, MegaPayPulseServiceProvider::class,
ImageToolServiceProvider::class, ImageToolServiceProvider::class,
]) ])
->withMiddlewares([ ->withMiddlewares([

View File

@@ -3,7 +3,6 @@
namespace App\Handlers; namespace App\Handlers;
use App\Services\CartService; use App\Services\CartService;
use App\Support\Utf8Cleaner;
use Cart\Cart; use Cart\Cart;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Openguru\OpenCartFramework\Http\Request; use Openguru\OpenCartFramework\Http\Request;
@@ -24,7 +23,7 @@ class CartHandler
$items = $this->cartService->getCart(); $items = $this->cartService->getCart();
return new JsonResponse([ return new JsonResponse([
'data' => Utf8Cleaner::clean($items), 'data' => $items,
]); ]);
} }
@@ -49,7 +48,7 @@ class CartHandler
} }
return new JsonResponse([ return new JsonResponse([
'data' => Utf8Cleaner::clean($items), 'data' => $items,
]); ]);
} }
} }

View File

@@ -0,0 +1,58 @@
<?php
namespace App\Handlers;
use Openguru\OpenCartFramework\Config\Settings;
use Openguru\OpenCartFramework\Http\Request;
use Openguru\OpenCartFramework\Scheduler\SchedulerService;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
class CronHandler
{
private Settings $settings;
private SchedulerService $schedulerService;
public function __construct(Settings $settings, SchedulerService $schedulerService)
{
$this->settings = $settings;
$this->schedulerService = $schedulerService;
}
/**
* Запуск планировщика по HTTP (для cron-job.org и аналогов).
* Требует api_key в query, совпадающий с настройкой cron.api_key.
*/
public function runSchedule(Request $request): JsonResponse
{
$mode = $this->settings->get('cron.mode', 'disabled');
if ($mode !== 'cron_job_org') {
return new JsonResponse(['error' => 'Scheduler is not in cron-job.org mode'], Response::HTTP_FORBIDDEN);
}
$apiKey = $request->get('api_key', '');
$expectedKey = $this->settings->get('cron.api_key', '');
if ($expectedKey === '' || $apiKey === '' || !hash_equals($expectedKey, $apiKey)) {
return new JsonResponse(['error' => 'Invalid or missing API key'], Response::HTTP_UNAUTHORIZED);
}
// Увеличиваем лимит времени выполнения при запуске по HTTP, чтобы снизить риск timeout
$limit = 300; // 5 минут
if (function_exists('set_time_limit')) {
@set_time_limit($limit);
}
if (function_exists('ini_set')) {
@ini_set('max_execution_time', (string) $limit);
}
$result = $this->schedulerService->run(true);
$data = [
'success' => true,
'executed' => count($result->executed),
'failed' => count($result->failed),
'skipped' => count($result->skipped),
];
return new JsonResponse($data);
}
}

View File

@@ -32,9 +32,9 @@ class ETLHandler
COALESCE(( COALESCE((
SELECT MAX(date_modified) SELECT MAX(date_modified)
FROM oc_order as o FROM oc_order as o
where o.customer_id = telecart_customers.oc_customer_id where o.customer_id = megapay_customers.oc_customer_id
), 0), ), 0),
telecart_customers.updated_at megapay_customers.updated_at
) )
'; ';
} }
@@ -44,7 +44,7 @@ class ETLHandler
$lastUpdatedAtSql = $this->getLastUpdatedAtSql(); $lastUpdatedAtSql = $this->getLastUpdatedAtSql();
return $this->builder->newQuery() return $this->builder->newQuery()
->from('telecart_customers') ->from('megapay_customers')
->where('allows_write_to_pm', '=', 1) ->where('allows_write_to_pm', '=', 1)
->when($updatedAt !== null, function (Builder $builder) use ($lastUpdatedAtSql, $updatedAt) { ->when($updatedAt !== null, function (Builder $builder) use ($lastUpdatedAtSql, $updatedAt) {
$builder->where(new RawExpression($lastUpdatedAtSql), '>=', $updatedAt); $builder->where(new RawExpression($lastUpdatedAtSql), '>=', $updatedAt);
@@ -101,7 +101,7 @@ class ETLHandler
'username', 'username',
'photo_url', 'photo_url',
'telegram_user_id' => 'tg_user_id', 'telegram_user_id' => 'tg_user_id',
'telecart_customers.oc_customer_id', 'megapay_customers.oc_customer_id',
'is_premium', 'is_premium',
'last_seen_at', 'last_seen_at',
'orders_count' => 'orders_count_total', 'orders_count' => 'orders_count_total',
@@ -110,14 +110,14 @@ class ETLHandler
'( '(
SELECT MIN(date_added) SELECT MIN(date_added)
FROM oc_order FROM oc_order
WHERE oc_order.customer_id = telecart_customers.oc_customer_id WHERE oc_order.customer_id = megapay_customers.oc_customer_id
) AS first_order_date' ) AS first_order_date'
), ),
new RawExpression( new RawExpression(
'( '(
SELECT MAX(date_added) SELECT MAX(date_added)
FROM oc_order FROM oc_order
WHERE oc_order.customer_id = telecart_customers.oc_customer_id WHERE oc_order.customer_id = megapay_customers.oc_customer_id
) AS last_order_date' ) AS last_order_date'
), ),
new RawExpression( new RawExpression(
@@ -127,7 +127,7 @@ class ETLHandler
FROM FROM
oc_order oc_order
WHERE WHERE
oc_order.customer_id = telecart_customers.oc_customer_id oc_order.customer_id = megapay_customers.oc_customer_id
AND oc_order.order_status_id IN ($successOrderStatusIds) AND oc_order.order_status_id IN ($successOrderStatusIds)
), 0) AS total_spent" ), 0) AS total_spent"
), ),
@@ -138,7 +138,7 @@ class ETLHandler
FROM FROM
oc_order oc_order
WHERE WHERE
oc_order.customer_id = telecart_customers.oc_customer_id oc_order.customer_id = megapay_customers.oc_customer_id
AND oc_order.order_status_id IN ($successOrderStatusIds) AND oc_order.order_status_id IN ($successOrderStatusIds)
), 0) AS orders_count_success" ), 0) AS orders_count_success"
), ),

View File

@@ -32,7 +32,7 @@ class FormsHandler
} }
$form = $this->builder->newQuery() $form = $this->builder->newQuery()
->from('telecart_forms') ->from('megapay_forms')
->where('alias', '=', $alias) ->where('alias', '=', $alias)
->firstOrNull(); ->firstOrNull();

View File

@@ -4,7 +4,6 @@ namespace App\Handlers;
use App\Exceptions\OrderValidationFailedException; use App\Exceptions\OrderValidationFailedException;
use App\Services\OrderCreateService; use App\Services\OrderCreateService;
use App\Support\Utf8Cleaner;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Openguru\OpenCartFramework\Http\Request; use Openguru\OpenCartFramework\Http\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@@ -27,11 +26,11 @@ class OrderHandler
]); ]);
return new JsonResponse([ return new JsonResponse([
'data' => Utf8Cleaner::clean($order), 'data' => $order,
], Response::HTTP_CREATED); ], Response::HTTP_CREATED);
} catch (OrderValidationFailedException $exception) { } catch (OrderValidationFailedException $exception) {
return new JsonResponse([ return new JsonResponse([
'data' => Utf8Cleaner::clean($exception->getErrorBag()->firstOfAll()), 'data' => $exception->getErrorBag()->firstOfAll(),
], Response::HTTP_UNPROCESSABLE_ENTITY); ], Response::HTTP_UNPROCESSABLE_ENTITY);
} }
} }

View File

@@ -4,12 +4,12 @@ declare(strict_types=1);
namespace App\Handlers; namespace App\Handlers;
use App\Services\TelecartCustomerService; use App\Services\MegapayCustomerService;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Openguru\OpenCartFramework\Http\Request; use Openguru\OpenCartFramework\Http\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Openguru\OpenCartFramework\Support\Arr; use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\TeleCartPulse\TrackingIdGenerator; use Openguru\OpenCartFramework\MegaPayPulse\TrackingIdGenerator;
use Openguru\OpenCartFramework\Telegram\Enums\TelegramHeader; use Openguru\OpenCartFramework\Telegram\Enums\TelegramHeader;
use Openguru\OpenCartFramework\Telegram\Exceptions\DecodeTelegramInitDataException; use Openguru\OpenCartFramework\Telegram\Exceptions\DecodeTelegramInitDataException;
use Openguru\OpenCartFramework\Telegram\TelegramInitDataDecoder; use Openguru\OpenCartFramework\Telegram\TelegramInitDataDecoder;
@@ -19,12 +19,12 @@ use Throwable;
class TelegramCustomerHandler class TelegramCustomerHandler
{ {
private TelecartCustomerService $telegramCustomerService; private MegapayCustomerService $telegramCustomerService;
private LoggerInterface $logger; private LoggerInterface $logger;
private TelegramInitDataDecoder $initDataDecoder; private TelegramInitDataDecoder $initDataDecoder;
public function __construct( public function __construct(
TelecartCustomerService $telegramCustomerService, MegapayCustomerService $telegramCustomerService,
LoggerInterface $logger, LoggerInterface $logger,
TelegramInitDataDecoder $initDataDecoder TelegramInitDataDecoder $initDataDecoder
) { ) {

View File

@@ -5,8 +5,8 @@ declare(strict_types=1);
namespace App\Handlers; namespace App\Handlers;
use Openguru\OpenCartFramework\Http\Request; use Openguru\OpenCartFramework\Http\Request;
use Openguru\OpenCartFramework\TeleCartPulse\PulseIngestException; use Openguru\OpenCartFramework\MegaPayPulse\PulseIngestException;
use Openguru\OpenCartFramework\TeleCartPulse\TeleCartPulseService; use Openguru\OpenCartFramework\MegaPayPulse\MegaPayPulseService;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
@@ -14,14 +14,14 @@ use Throwable;
class TelemetryHandler class TelemetryHandler
{ {
private TeleCartPulseService $teleCartPulseService; private MegaPayPulseService $megaPayPulseService;
private LoggerInterface $logger; private LoggerInterface $logger;
public function __construct( public function __construct(
TeleCartPulseService $teleCartPulseService, MegaPayPulseService $megaPayPulseService,
LoggerInterface $logger LoggerInterface $logger
) { ) {
$this->teleCartPulseService = $teleCartPulseService; $this->megaPayPulseService = $megaPayPulseService;
$this->logger = $logger; $this->logger = $logger;
} }
@@ -30,7 +30,7 @@ class TelemetryHandler
*/ */
public function ingest(Request $request): JsonResponse public function ingest(Request $request): JsonResponse
{ {
$this->teleCartPulseService->handleIngest($request->json()); $this->megaPayPulseService->handleIngest($request->json());
return new JsonResponse([], Response::HTTP_NO_CONTENT); return new JsonResponse([], Response::HTTP_NO_CONTENT);
} }
@@ -38,9 +38,9 @@ class TelemetryHandler
public function heartbeat(): JsonResponse public function heartbeat(): JsonResponse
{ {
try { try {
$this->teleCartPulseService->handleHeartbeat(); $this->megaPayPulseService->handleHeartbeat();
} catch (Throwable $e) { } catch (Throwable $e) {
$this->logger->warning('TeleCart Pulse Heartbeat failed: ' . $e->getMessage(), ['exception' => $e]); $this->logger->warning('MegaPay Pulse Heartbeat failed: ' . $e->getMessage(), ['exception' => $e]);
} }
return new JsonResponse(['status' => 'ok']); return new JsonResponse(['status' => 'ok']);

View File

@@ -7,12 +7,12 @@ namespace App\Models;
use Carbon\Carbon; use Carbon\Carbon;
use Openguru\OpenCartFramework\QueryBuilder\Builder; use Openguru\OpenCartFramework\QueryBuilder\Builder;
use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface; use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface;
use Openguru\OpenCartFramework\TeleCartPulse\TrackingIdGenerator; use Openguru\OpenCartFramework\MegaPayPulse\TrackingIdGenerator;
use RuntimeException; use RuntimeException;
class TelegramCustomer class TelegramCustomer
{ {
private const TABLE_NAME = 'telecart_customers'; private const TABLE_NAME = 'megapay_customers';
private ConnectionInterface $database; private ConnectionInterface $database;
private Builder $builder; private Builder $builder;

View File

@@ -44,7 +44,7 @@ class AppServiceProvider extends ServiceProvider
$registry->addCommand( $registry->addCommand(
'start', 'start',
StartCommand::class, StartCommand::class,
'Базовая команда Telegram бота. Присылает ссылку на открытие Telecart магазина.' 'Базовая команда Telegram бота. Присылает ссылку на открытие Megapay магазина.'
); );
} }

View File

@@ -17,7 +17,7 @@ class OcCustomerService
$this->database = $database; $this->database = $database;
} }
public function create(array $orderData, ?int $telecartCustomerId): ?int public function create(array $orderData, ?int $megapayCustomerId): ?int
{ {
$customerData = [ $customerData = [
'customer_group_id' => $orderData['customer_group_id'], 'customer_group_id' => $orderData['customer_group_id'],
@@ -41,10 +41,10 @@ class OcCustomerService
$this->database->insert(db_table('customer'), $customerData); $this->database->insert(db_table('customer'), $customerData);
$lastInsertId = $this->database->lastInsertId(); $lastInsertId = $this->database->lastInsertId();
if ($telecartCustomerId) { if ($megapayCustomerId) {
$this->builder $this->builder
->where('id', '=', $telecartCustomerId) ->where('id', '=', $megapayCustomerId)
->update('telecart_customers', [ ->update('megapay_customers', [
'oc_customer_id' => $lastInsertId, 'oc_customer_id' => $lastInsertId,
]); ]);
} }
@@ -52,15 +52,15 @@ class OcCustomerService
return $lastInsertId; return $lastInsertId;
} }
public function findByTelecartCustomerId(int $telegramCustomerId): ?array public function findByMegapayCustomerId(int $telegramCustomerId): ?array
{ {
return $this->builder->newQuery() return $this->builder->newQuery()
->select(['oc_customers.*']) ->select(['oc_customers.*'])
->from(db_table('customer'), 'oc_customers') ->from(db_table('customer'), 'oc_customers')
->join('telecart_customers', function (JoinClause $join) { ->join('megapay_customers', function (JoinClause $join) {
$join->on('telecart_customers.oc_customer_id', '=', 'oc_customers.customer_id'); $join->on('megapay_customers.oc_customer_id', '=', 'oc_customers.customer_id');
}) })
->where('telecart_customers.id', '=', $telegramCustomerId) ->where('megapay_customers.id', '=', $telegramCustomerId)
->firstOrNull(); ->firstOrNull();
} }
@@ -73,12 +73,12 @@ class OcCustomerService
->firstOrNull(); ->firstOrNull();
} }
public function findOrCreateByTelecartCustomerId(int $telecartCustomerId, array $orderData): ?array public function findOrCreateByMegapayCustomerId(int $megapayCustomerId, array $orderData): ?array
{ {
$ocCustomer = $this->findByTelecartCustomerId($telecartCustomerId); $ocCustomer = $this->findByMegapayCustomerId($megapayCustomerId);
if (! $ocCustomer) { if (! $ocCustomer) {
$ocCustomerId = $this->create($orderData, $telecartCustomerId); $ocCustomerId = $this->create($orderData, $megapayCustomerId);
return $this->findById($ocCustomerId); return $this->findById($ocCustomerId);
} }

View File

@@ -23,7 +23,7 @@ class OrderCreateService
private SettingsService $settings; private SettingsService $settings;
private TelegramService $telegramService; private TelegramService $telegramService;
private LoggerInterface $logger; private LoggerInterface $logger;
private TelecartCustomerService $telecartCustomerService; private MegapayCustomerService $megapayCustomerService;
private OcCustomerService $ocCustomerService; private OcCustomerService $ocCustomerService;
private OrderMetaService $orderMetaService; private OrderMetaService $orderMetaService;
@@ -34,7 +34,7 @@ class OrderCreateService
SettingsService $settings, SettingsService $settings,
TelegramService $telegramService, TelegramService $telegramService,
LoggerInterface $logger, LoggerInterface $logger,
TelecartCustomerService $telegramCustomerService, MegapayCustomerService $telegramCustomerService,
OcCustomerService $ocCustomerService, OcCustomerService $ocCustomerService,
OrderMetaService $orderMetaService OrderMetaService $orderMetaService
) { ) {
@@ -44,7 +44,7 @@ class OrderCreateService
$this->settings = $settings; $this->settings = $settings;
$this->telegramService = $telegramService; $this->telegramService = $telegramService;
$this->logger = $logger; $this->logger = $logger;
$this->telecartCustomerService = $telegramCustomerService; $this->megapayCustomerService = $telegramCustomerService;
$this->ocCustomerService = $ocCustomerService; $this->ocCustomerService = $ocCustomerService;
$this->orderMetaService = $orderMetaService; $this->orderMetaService = $orderMetaService;
} }
@@ -110,9 +110,9 @@ class OrderCreateService
try { try {
$this->database->beginTransaction(); $this->database->beginTransaction();
$telecartCustomer = $this->telecartCustomerService->saveOrUpdate($telegramUserdata); $megapayCustomer = $this->megapayCustomerService->saveOrUpdate($telegramUserdata);
$telecartCustomerId = (int) $telecartCustomer['id']; $megapayCustomerId = (int) $megapayCustomer['id'];
$ocCustomer = $this->ocCustomerService->findOrCreateByTelecartCustomerId($telecartCustomerId, $orderData); $ocCustomer = $this->ocCustomerService->findOrCreateByMegapayCustomerId($megapayCustomerId, $orderData);
$ocCustomerId = (int) $ocCustomer['customer_id']; $ocCustomerId = (int) $ocCustomer['customer_id'];
$orderData['customer_id'] = $ocCustomerId; $orderData['customer_id'] = $ocCustomerId;
@@ -131,10 +131,10 @@ class OrderCreateService
// Insert order meta data // Insert order meta data
if ($customOrderFields) { if ($customOrderFields) {
$this->orderMetaService->insert($orderId, $storeId, $customOrderFields, $telecartCustomerId); $this->orderMetaService->insert($orderId, $storeId, $customOrderFields, $megapayCustomerId);
} }
$this->telecartCustomerService->increaseOrdersCount($telecartCustomerId); $this->megapayCustomerService->increaseOrdersCount($megapayCustomerId);
$this->database->commitTransaction(); $this->database->commitTransaction();
} catch (Throwable $exception) { } catch (Throwable $exception) {

View File

@@ -13,15 +13,15 @@ class OrderMetaService
$this->connection = $connection; $this->connection = $connection;
} }
public function insert(int $orderId, int $storeId, array $fields, ?int $telecartCustomerId = null): void public function insert(int $orderId, int $storeId, array $fields, ?int $megapayCustomerId = null): void
{ {
$orderMeta = [ $orderMeta = [
'oc_order_id' => $orderId, 'oc_order_id' => $orderId,
'oc_store_id' => $storeId, 'oc_store_id' => $storeId,
'telecart_customer_id' => $telecartCustomerId, 'megapay_customer_id' => $megapayCustomerId,
'meta_data' => json_encode($fields, JSON_THROW_ON_ERROR), 'meta_data' => json_encode($fields, JSON_THROW_ON_ERROR),
]; ];
$this->connection->insert('telecart_order_meta', $orderMeta); $this->connection->insert('megapay_order_meta', $orderMeta);
} }
} }

View File

@@ -16,6 +16,7 @@ use Openguru\OpenCartFramework\QueryBuilder\Builder;
use Openguru\OpenCartFramework\QueryBuilder\JoinClause; use Openguru\OpenCartFramework\QueryBuilder\JoinClause;
use Openguru\OpenCartFramework\QueryBuilder\RawExpression; use Openguru\OpenCartFramework\QueryBuilder\RawExpression;
use Openguru\OpenCartFramework\QueryBuilder\Table; use Openguru\OpenCartFramework\QueryBuilder\Table;
use Openguru\OpenCartFramework\Sentry\SentryService;
use Openguru\OpenCartFramework\Support\Arr; use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\Support\PaginationHelper; use Openguru\OpenCartFramework\Support\PaginationHelper;
use Openguru\OpenCartFramework\Support\Str; use Openguru\OpenCartFramework\Support\Str;
@@ -157,6 +158,7 @@ class ProductsService
->get(); ->get();
} }
$span = SentryService::startSpan('crop_images', 'image.process');
$productsImagesMap = []; $productsImagesMap = [];
foreach ($productsImages as $item) { foreach ($productsImages as $item) {
$productId = $item['product_id']; $productId = $item['product_id'];
@@ -174,6 +176,8 @@ class ProductsService
} }
} }
SentryService::endSpan($span);
$debug = []; $debug = [];
if (env('APP_DEBUG')) { if (env('APP_DEBUG')) {
$debug = [ $debug = [
@@ -283,7 +287,7 @@ class ProductsService
$data['share'] = Str::htmlEntityEncode( $data['share'] = Str::htmlEntityEncode(
$this->oc->url->link('product/product', [ $this->oc->url->link('product/product', [
'product_id' => $productId, 'product_id' => $productId,
'utm_source' => 'telecart', 'utm_source' => 'megapay',
'utm_medium' => 'telegram', 'utm_medium' => 'telegram',
'utm_campaign' => 'product_click', 'utm_campaign' => 'product_click',
'utm_content' => 'product_button', 'utm_content' => 'product_button',

View File

@@ -11,7 +11,7 @@ use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\Support\Utils; use Openguru\OpenCartFramework\Support\Utils;
use RuntimeException; use RuntimeException;
class TelecartCustomerService class MegapayCustomerService
{ {
private TelegramCustomer $telegramCustomer; private TelegramCustomer $telegramCustomer;
private Settings $settings; private Settings $settings;
@@ -87,7 +87,7 @@ class TelecartCustomerService
} }
/** /**
* Assign OpenCart Customer to Telegram User ID and return Telecart Customer ID if it exists. * Assign OpenCart Customer to Telegram User ID and return Megapay Customer ID if it exists.
* *
* @param $telegramUserId * @param $telegramUserId
* @param int $ocCustomerId * @param int $ocCustomerId
@@ -111,9 +111,9 @@ class TelecartCustomerService
return (int)$customer['id']; return (int)$customer['id'];
} }
public function increaseOrdersCount(int $telecartCustomerId): void public function increaseOrdersCount(int $megapayCustomerId): void
{ {
$this->telegramCustomer->increase($telecartCustomerId, 'orders_count'); $this->telegramCustomer->increase($megapayCustomerId, 'orders_count');
} }
/** /**

View File

@@ -42,7 +42,7 @@ class LinkCommand extends TelegramCommand
$greeting = $this->telegram->escapeTgSpecialCharacters( $greeting = $this->telegram->escapeTgSpecialCharacters(
<<<HTML <<<HTML
Это удобный инструмент, который поможет вам 📎 создать красивое Это удобный инструмент, который поможет вам 📎 создать красивое
сообщение с кнопкой для открытия вашего 🛒 Telecart магазина. сообщение с кнопкой для открытия вашего 🛒 Megapay магазина.
📌 Такое сообщение можно закрепить в канале или группе. 📌 Такое сообщение можно закрепить в канале или группе.
📤 Переслать клиентам в личные сообщения. 📤 Переслать клиентам в личные сообщения.
@@ -102,7 +102,7 @@ HTML;
MARKDOWN; MARKDOWN;
$text = $this->telegram->prepareMessage($template, [ $text = $this->telegram->prepareMessage($template, [
'{LINK}' => 'https://telecart-labs.github.io/docs/telegram/telegram/#direct-link', '{LINK}' => 'https://megapay-labs.github.io/docs/telegram/telegram/#direct-link',
]); ]);
$this->telegram->sendMessage($chatId, $text); $this->telegram->sendMessage($chatId, $text);

View File

@@ -3,6 +3,7 @@
use App\Handlers\BlocksHandler; use App\Handlers\BlocksHandler;
use App\Handlers\CartHandler; use App\Handlers\CartHandler;
use App\Handlers\CategoriesHandler; use App\Handlers\CategoriesHandler;
use App\Handlers\CronHandler;
use App\Handlers\ETLHandler; use App\Handlers\ETLHandler;
use App\Handlers\FiltersHandler; use App\Handlers\FiltersHandler;
use App\Handlers\FormsHandler; use App\Handlers\FormsHandler;
@@ -24,6 +25,7 @@ return [
'getForm' => [FormsHandler::class, 'getForm'], 'getForm' => [FormsHandler::class, 'getForm'],
'health' => [HealthCheckHandler::class, 'handle'], 'health' => [HealthCheckHandler::class, 'handle'],
'ingest' => [TelemetryHandler::class, 'ingest'], 'ingest' => [TelemetryHandler::class, 'ingest'],
'runSchedule' => [CronHandler::class, 'runSchedule'],
'heartbeat' => [TelemetryHandler::class, 'heartbeat'], 'heartbeat' => [TelemetryHandler::class, 'heartbeat'],
'processBlock' => [BlocksHandler::class, 'processBlock'], 'processBlock' => [BlocksHandler::class, 'processBlock'],
'product_show' => [ProductsHandler::class, 'show'], 'product_show' => [ProductsHandler::class, 'show'],

View File

@@ -12,7 +12,7 @@ use Openguru\OpenCartFramework\ImageTool\ImageToolServiceProvider;
use Openguru\OpenCartFramework\QueryBuilder\QueryBuilderServiceProvider; use Openguru\OpenCartFramework\QueryBuilder\QueryBuilderServiceProvider;
use Openguru\OpenCartFramework\Router\RouteServiceProvider; use Openguru\OpenCartFramework\Router\RouteServiceProvider;
use Openguru\OpenCartFramework\Support\Arr; use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\TeleCartPulse\TeleCartPulseServiceProvider; use Openguru\OpenCartFramework\MegaPayPulse\MegaPayPulseServiceProvider;
use Openguru\OpenCartFramework\Telegram\TelegramServiceProvider; use Openguru\OpenCartFramework\Telegram\TelegramServiceProvider;
class ApplicationFactory class ApplicationFactory
@@ -33,7 +33,7 @@ class ApplicationFactory
AppServiceProvider::class, AppServiceProvider::class,
CacheServiceProvider::class, CacheServiceProvider::class,
TelegramServiceProvider::class, TelegramServiceProvider::class,
TeleCartPulseServiceProvider::class, MegaPayPulseServiceProvider::class,
ImageToolServiceProvider::class, ImageToolServiceProvider::class,
]); ]);
} }

View File

@@ -33,7 +33,7 @@ class FormsHandler
} }
$form = $this->builder->newQuery() $form = $this->builder->newQuery()
->from('telecart_forms') ->from('megapay_forms')
->where('alias', '=', $alias) ->where('alias', '=', $alias)
->firstOrNull(); ->firstOrNull();

View File

@@ -198,7 +198,7 @@ class LogsHandler
private function findLastLogsFileInDir(string $dir): ?string private function findLastLogsFileInDir(string $dir): ?string
{ {
$files = glob($dir . '/telecart-*.log'); $files = glob($dir . '/megapay-*.log');
return $files ? end($files) : null; return $files ? end($files) : null;
} }

View File

@@ -87,7 +87,7 @@ class SendMessageHandler
* Извлечь ID записи из запроса * Извлечь ID записи из запроса
* *
* @param Request $request HTTP запрос * @param Request $request HTTP запрос
* @return int ID записи в таблице telecart_customers * @return int ID записи в таблице megapay_customers
* @throws RuntimeException Если ID отсутствует или невалиден * @throws RuntimeException Если ID отсутствует или невалиден
*/ */
private function extractCustomerId(Request $request): int private function extractCustomerId(Request $request): int

View File

@@ -4,7 +4,9 @@ namespace Bastion\Handlers;
use Bastion\Exceptions\BotTokenConfiguratorException; use Bastion\Exceptions\BotTokenConfiguratorException;
use Bastion\Services\BotTokenConfigurator; use Bastion\Services\BotTokenConfigurator;
use Bastion\Services\CronApiKeyRegenerator;
use Bastion\Services\SettingsService; use Bastion\Services\SettingsService;
use Carbon\Carbon;
use Exception; use Exception;
use Openguru\OpenCartFramework\Cache\CacheInterface; use Openguru\OpenCartFramework\Cache\CacheInterface;
use Openguru\OpenCartFramework\Config\Settings; use Openguru\OpenCartFramework\Config\Settings;
@@ -13,35 +15,56 @@ use Openguru\OpenCartFramework\Http\Request;
use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpFoundation\Response;
use Openguru\OpenCartFramework\QueryBuilder\Builder; use Openguru\OpenCartFramework\QueryBuilder\Builder;
use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface; use Openguru\OpenCartFramework\QueryBuilder\Connections\ConnectionInterface;
use Openguru\OpenCartFramework\Scheduler\Models\ScheduledJob;
use Openguru\OpenCartFramework\Support\Arr; use Openguru\OpenCartFramework\Support\Arr;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
class SettingsHandler class SettingsHandler
{ {
private BotTokenConfigurator $botTokenConfigurator; private BotTokenConfigurator $botTokenConfigurator;
private CronApiKeyRegenerator $cronApiKeyRegenerator;
private Settings $settings; private Settings $settings;
private SettingsService $settingsUpdateService; private SettingsService $settingsUpdateService;
private CacheInterface $cache; private CacheInterface $cache;
private LoggerInterface $logger; private LoggerInterface $logger;
private Builder $builder; private Builder $builder;
private ConnectionInterface $connection; private ConnectionInterface $connection;
private ScheduledJob $scheduledJob;
public function __construct( public function __construct(
BotTokenConfigurator $botTokenConfigurator, BotTokenConfigurator $botTokenConfigurator,
CronApiKeyRegenerator $cronApiKeyRegenerator,
Settings $settings, Settings $settings,
SettingsService $settingsUpdateService, SettingsService $settingsUpdateService,
CacheInterface $cache, CacheInterface $cache,
LoggerInterface $logger, LoggerInterface $logger,
Builder $builder, Builder $builder,
ConnectionInterface $connection ConnectionInterface $connection,
ScheduledJob $scheduledJob
) { ) {
$this->botTokenConfigurator = $botTokenConfigurator; $this->botTokenConfigurator = $botTokenConfigurator;
$this->cronApiKeyRegenerator = $cronApiKeyRegenerator;
$this->settings = $settings; $this->settings = $settings;
$this->settingsUpdateService = $settingsUpdateService; $this->settingsUpdateService = $settingsUpdateService;
$this->cache = $cache; $this->cache = $cache;
$this->logger = $logger; $this->logger = $logger;
$this->builder = $builder; $this->builder = $builder;
$this->connection = $connection; $this->connection = $connection;
$this->scheduledJob = $scheduledJob;
}
/**
* Перегенерировать секретный ключ в URL для cron-job.org (сохраняет cron.api_key).
*/
public function regenerateCronScheduleUrl(Request $request): JsonResponse
{
$newApiKey = $this->cronApiKeyRegenerator->regenerate();
$scheduleUrl = $this->buildCronScheduleUrl(
$this->settings->get('app.shop_base_url', ''),
$newApiKey
);
return new JsonResponse(['api_key' => $newApiKey, 'schedule_url' => $scheduleUrl]);
} }
public function configureBotToken(Request $request): JsonResponse public function configureBotToken(Request $request): JsonResponse
@@ -81,9 +104,15 @@ class SettingsHandler
// Add CRON system details (read-only) // Add CRON system details (read-only)
$data['cron']['cli_path'] = BP_REAL_BASE_PATH . '/cli.php'; $data['cron']['cli_path'] = BP_REAL_BASE_PATH . '/cli.php';
$data['cron']['last_run'] = $this->getLastCronRunDate(); $data['cron']['last_run'] = $this->getLastCronRunDate();
$data['cron']['schedule_url'] = $this->buildCronScheduleUrl(
$this->settings->get('app.shop_base_url', ''),
$this->settings->get('cron.api_key', '')
);
$data['scheduled_jobs'] = $this->scheduledJob->all();
$forms = $this->builder->newQuery() $forms = $this->builder->newQuery()
->from('telecart_forms') ->from('megapay_forms')
->get(); ->get();
if ($forms) { if ($forms) {
@@ -106,6 +135,21 @@ class SettingsHandler
return new JsonResponse(compact('data')); return new JsonResponse(compact('data'));
} }
private function buildCronScheduleUrl(string $shopBaseUrl, string $apiKey): string
{
$base = rtrim($shopBaseUrl, '/');
if ($base === '') {
return '';
}
$params = http_build_query([
'route' => 'extension/tgshop/handle',
'api_action' => 'runSchedule',
'api_key' => $apiKey,
]);
return $base . '/index.php?' . $params;
}
public function saveSettingsForm(Request $request): JsonResponse public function saveSettingsForm(Request $request): JsonResponse
{ {
$input = $request->json(); $input = $request->json();
@@ -116,6 +160,7 @@ class SettingsHandler
if (isset($input['cron'])) { if (isset($input['cron'])) {
unset($input['cron']['cli_path']); unset($input['cron']['cli_path']);
unset($input['cron']['last_run']); unset($input['cron']['last_run']);
unset($input['cron']['schedule_url']);
} }
$this->settingsUpdateService->update( $this->settingsUpdateService->update(
@@ -139,13 +184,32 @@ class SettingsHandler
$schema = json_encode($form['schema'], JSON_THROW_ON_ERROR); $schema = json_encode($form['schema'], JSON_THROW_ON_ERROR);
$this->builder->newQuery() $this->builder->newQuery()
->where('alias', '=', $form['alias']) ->where('alias', '=', $form['alias'])
->update('telecart_forms', [ ->update('megapay_forms', [
'friendly_name' => $form['friendly_name'], 'friendly_name' => $form['friendly_name'],
'is_custom' => $form['is_custom'], 'is_custom' => $form['is_custom'],
'schema' => $schema, 'schema' => $schema,
]); ]);
} }
// Update scheduled jobs is_enabled and cron_expression
$scheduledJobs = Arr::get($input, 'scheduled_jobs', []);
foreach ($scheduledJobs as $job) {
$id = (int) ($job['id'] ?? 0);
if ($id <= 0) {
continue;
}
$isEnabled = filter_var($job['is_enabled'] ?? false, FILTER_VALIDATE_BOOLEAN);
if ($isEnabled) {
$this->scheduledJob->enable($id);
} else {
$this->scheduledJob->disable($id);
}
$cronExpression = trim((string) ($job['cron_expression'] ?? ''));
if ($cronExpression !== '') {
$this->scheduledJob->updateCronExpression($id, $cronExpression);
}
}
return new JsonResponse([], Response::HTTP_ACCEPTED); return new JsonResponse([], Response::HTTP_ACCEPTED);
} }
@@ -174,7 +238,7 @@ class SettingsHandler
$lastRunTimestamp = $this->cache->get("scheduler.global_last_run"); $lastRunTimestamp = $this->cache->get("scheduler.global_last_run");
if ($lastRunTimestamp) { if ($lastRunTimestamp) {
return date('d.m.Y H:i:s', (int)$lastRunTimestamp); return Carbon::createFromTimestamp($lastRunTimestamp)->toDateTimeString();
} }
return null; return null;
@@ -203,7 +267,7 @@ class SettingsHandler
$info['MySQL Version'] = 'Error: ' . $e->getMessage(); $info['MySQL Version'] = 'Error: ' . $e->getMessage();
} }
$cacheDriver = env('TELECART_CACHE_DRIVER', 'mysql'); $cacheDriver = env('MEGAPAY_CACHE_DRIVER', 'mysql');
$cacheClass = get_class($this->cache); $cacheClass = get_class($this->cache);
$info['Cache Driver'] = $cacheDriver . ' (' . basename(str_replace('\\', '/', $cacheClass)) . ')'; $info['Cache Driver'] = $cacheDriver . ' (' . basename(str_replace('\\', '/', $cacheClass)) . ')';

View File

@@ -30,12 +30,12 @@ class StatsHandler
new RawExpression('SUM(orders.total) AS orders_total_amount'), new RawExpression('SUM(orders.total) AS orders_total_amount'),
]) ])
->from(db_table('order'), 'orders') ->from(db_table('order'), 'orders')
->join('telecart_customers', function (JoinClause $join) { ->join('megapay_customers', function (JoinClause $join) {
$join->on('orders.customer_id', '=', 'telecart_customers.oc_customer_id'); $join->on('orders.customer_id', '=', 'megapay_customers.oc_customer_id');
}) })
->join('telecart_order_meta', function (JoinClause $join) { ->join('megapay_order_meta', function (JoinClause $join) {
$join->on('orders.order_id', '=', 'telecart_order_meta.oc_order_id') $join->on('orders.order_id', '=', 'megapay_order_meta.oc_order_id')
->whereRaw('orders.store_id = telecart_order_meta.oc_store_id'); ->whereRaw('orders.store_id = megapay_order_meta.oc_store_id');
}) })
->firstOrNull(); ->firstOrNull();
@@ -54,7 +54,7 @@ class StatsHandler
private function countCustomersCount(): int private function countCustomersCount(): int
{ {
return $this->builder->newQuery() return $this->builder->newQuery()
->from('telecart_customers') ->from('megapay_customers')
->count(); ->count();
} }
} }

View File

@@ -3,17 +3,17 @@
namespace Bastion\Handlers; namespace Bastion\Handlers;
use Openguru\OpenCartFramework\Cache\CacheInterface; use Openguru\OpenCartFramework\Cache\CacheInterface;
use Openguru\OpenCartFramework\TeleCartPulse\TeleCartEvent; use Openguru\OpenCartFramework\MegaPayPulse\MegaPayEvent;
use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\JsonResponse;
class TeleCartPulseStatsHandler class MegaPayPulseStatsHandler
{ {
private TeleCartEvent $eventModel; private MegaPayEvent $eventModel;
private CacheInterface $cache; private CacheInterface $cache;
private const CACHE_KEY = 'telecart_pulse_stats'; private const CACHE_KEY = 'megapay_pulse_stats';
private const CACHE_TTL = 3600; // 1 час private const CACHE_TTL = 3600; // 1 час
public function __construct(TeleCartEvent $eventModel, CacheInterface $cache) public function __construct(MegaPayEvent $eventModel, CacheInterface $cache)
{ {
$this->eventModel = $eventModel; $this->eventModel = $eventModel;
$this->cache = $cache; $this->cache = $cache;

View File

@@ -12,7 +12,7 @@ use Openguru\OpenCartFramework\Support\Arr;
class TelegramCustomersHandler class TelegramCustomersHandler
{ {
private const TABLE_NAME = 'telecart_customers'; private const TABLE_NAME = 'megapay_customers';
private const DEFAULT_PAGE = 1; private const DEFAULT_PAGE = 1;
private const DEFAULT_ROWS = 20; private const DEFAULT_ROWS = 20;
private const DEFAULT_SORT_FIELD = 'last_seen_at'; private const DEFAULT_SORT_FIELD = 'last_seen_at';

View File

@@ -6,15 +6,15 @@ use GuzzleHttp\Exception\GuzzleException;
use Openguru\OpenCartFramework\Cache\CacheInterface; use Openguru\OpenCartFramework\Cache\CacheInterface;
use Openguru\OpenCartFramework\Config\Settings; use Openguru\OpenCartFramework\Config\Settings;
use Openguru\OpenCartFramework\Scheduler\TaskInterface; use Openguru\OpenCartFramework\Scheduler\TaskInterface;
use Openguru\OpenCartFramework\TeleCartPulse\TeleCartEvent; use Openguru\OpenCartFramework\MegaPayPulse\MegaPayEvent;
use Openguru\OpenCartFramework\TeleCartPulse\TeleCartPulseEventsSender; use Openguru\OpenCartFramework\MegaPayPulse\MegaPayPulseEventsSender;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Throwable; use Throwable;
class TeleCartPulseSendEventsTask implements TaskInterface class MegaPayPulseSendEventsTask implements TaskInterface
{ {
private TeleCartEvent $eventModel; private MegaPayEvent $eventModel;
private TeleCartPulseEventsSender $eventsSender; private MegaPayPulseEventsSender $eventsSender;
private LoggerInterface $logger; private LoggerInterface $logger;
private CacheInterface $cache; private CacheInterface $cache;
private Settings $settings; private Settings $settings;
@@ -23,8 +23,8 @@ class TeleCartPulseSendEventsTask implements TaskInterface
public function __construct( public function __construct(
Settings $settings, Settings $settings,
TeleCartEvent $eventModel, MegaPayEvent $eventModel,
TeleCartPulseEventsSender $eventsSender, MegaPayPulseEventsSender $eventsSender,
LoggerInterface $logger, LoggerInterface $logger,
CacheInterface $cache CacheInterface $cache
) { ) {
@@ -82,7 +82,7 @@ class TeleCartPulseSendEventsTask implements TaskInterface
'failed' => $failed, 'failed' => $failed,
]); ]);
} catch (Throwable $e) { } catch (Throwable $e) {
$this->logger->error("TeleCartPulseSendEventsTask failed: " . $e->getMessage(), [ $this->logger->error("MegaPayPulseSendEventsTask failed: " . $e->getMessage(), [
'exception' => $e, 'exception' => $e,
]); ]);
} finally { } finally {
@@ -117,8 +117,8 @@ class TeleCartPulseSendEventsTask implements TaskInterface
return true; return true;
} }
// TeleCart Pulse не вернул подтверждение // MegaPay Pulse не вернул подтверждение
$errorReason = 'No confirmation received from TeleCart Pulse'; $errorReason = 'No confirmation received from MegaPay Pulse';
$this->handleFailedAttempt($eventId, $attemptsCount, $errorReason); $this->handleFailedAttempt($eventId, $attemptsCount, $errorReason);
} catch (GuzzleException $e) { } catch (GuzzleException $e) {
// Ошибка HTTP запроса // Ошибка HTTP запроса
@@ -170,6 +170,6 @@ class TeleCartPulseSendEventsTask implements TaskInterface
*/ */
private function clearStatsCache(): void private function clearStatsCache(): void
{ {
$this->cache->delete('telecart_pulse_stats'); $this->cache->delete('megapay_pulse_stats');
} }
} }

View File

@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
namespace Bastion\Services;
use Openguru\OpenCartFramework\Config\Settings;
class CronApiKeyRegenerator
{
private Settings $settings;
private SettingsService $settingsUpdateService;
public function __construct(Settings $settings, SettingsService $settingsUpdateService)
{
$this->settings = $settings;
$this->settingsUpdateService = $settingsUpdateService;
}
/**
* Генерирует новый API-ключ для URL cron-job.org и сохраняет в настройки.
*
* @return string новый api_key
*/
public function regenerate(): string
{
$newApiKey = bin2hex(random_bytes(32));
$all = $this->settings->getAll();
if (! isset($all['cron'])) {
$all['cron'] = [];
}
$all['cron']['api_key'] = $newApiKey;
$this->settingsUpdateService->update($all);
return $newApiKey;
}
}

View File

@@ -23,8 +23,8 @@ class SettingsService
public function update(array $data): void public function update(array $data): void
{ {
$this->connection->transaction(function () use ($data) { $this->connection->transaction(function () use ($data) {
$this->registry->model_setting_setting->editSetting('module_telecart', [ $this->registry->model_setting_setting->editSetting('module_megapay', [
'module_telecart_settings' => $data, 'module_megapay_settings' => $data,
]); ]);
$this->registry->model_setting_setting->editSetting('module_tgshop', [ $this->registry->model_setting_setting->editSetting('module_tgshop', [

View File

@@ -8,7 +8,7 @@ use Bastion\Handlers\LogsHandler;
use Bastion\Handlers\SendMessageHandler; use Bastion\Handlers\SendMessageHandler;
use Bastion\Handlers\SettingsHandler; use Bastion\Handlers\SettingsHandler;
use Bastion\Handlers\StatsHandler; use Bastion\Handlers\StatsHandler;
use Bastion\Handlers\TeleCartPulseStatsHandler; use Bastion\Handlers\MegaPayPulseStatsHandler;
use Bastion\Handlers\TelegramCustomersHandler; use Bastion\Handlers\TelegramCustomersHandler;
use Bastion\Handlers\TelegramHandler; use Bastion\Handlers\TelegramHandler;
@@ -27,10 +27,11 @@ return [
'getSettingsForm' => [SettingsHandler::class, 'getSettingsForm'], 'getSettingsForm' => [SettingsHandler::class, 'getSettingsForm'],
'getTelegramCustomers' => [TelegramCustomersHandler::class, 'getCustomers'], 'getTelegramCustomers' => [TelegramCustomersHandler::class, 'getCustomers'],
'resetCache' => [SettingsHandler::class, 'resetCache'], 'resetCache' => [SettingsHandler::class, 'resetCache'],
'regenerateCronScheduleUrl' => [SettingsHandler::class, 'regenerateCronScheduleUrl'],
'saveSettingsForm' => [SettingsHandler::class, 'saveSettingsForm'], 'saveSettingsForm' => [SettingsHandler::class, 'saveSettingsForm'],
'getSystemInfo' => [SettingsHandler::class, 'getSystemInfo'], 'getSystemInfo' => [SettingsHandler::class, 'getSystemInfo'],
'sendMessageToCustomer' => [SendMessageHandler::class, 'sendMessage'], 'sendMessageToCustomer' => [SendMessageHandler::class, 'sendMessage'],
'testTgMessage' => [TelegramHandler::class, 'testTgMessage'], 'testTgMessage' => [TelegramHandler::class, 'testTgMessage'],
'tgGetMe' => [TelegramHandler::class, 'tgGetMe'], 'tgGetMe' => [TelegramHandler::class, 'tgGetMe'],
'getTeleCartPulseStats' => [TeleCartPulseStatsHandler::class, 'getStats'], 'getMegaPayPulseStats' => [MegaPayPulseStatsHandler::class, 'getStats'],
]; ];

View File

@@ -5,7 +5,6 @@ use Console\ApplicationFactory;
use Console\Commands\CacheClearCommand; use Console\Commands\CacheClearCommand;
use Console\Commands\CustomerCountsCommand; use Console\Commands\CustomerCountsCommand;
use Console\Commands\PulseSendEventsCommand; use Console\Commands\PulseSendEventsCommand;
use Console\Commands\ScheduleListCommand;
use Console\Commands\ScheduleRunCommand; use Console\Commands\ScheduleRunCommand;
use Console\Commands\VersionCommand; use Console\Commands\VersionCommand;
use Console\Commands\ImagesWarmupCacheCommand; use Console\Commands\ImagesWarmupCacheCommand;
@@ -21,7 +20,7 @@ if (PHP_SAPI !== 'cli') {
} }
$baseDir = __DIR__; $baseDir = __DIR__;
$debug = true; $debug = false;
if (is_readable($baseDir . '/oc_telegram_shop.phar')) { if (is_readable($baseDir . '/oc_telegram_shop.phar')) {
require_once "phar://{$baseDir}/oc_telegram_shop.phar/vendor/autoload.php"; require_once "phar://{$baseDir}/oc_telegram_shop.phar/vendor/autoload.php";
@@ -33,8 +32,6 @@ if (is_readable($baseDir . '/oc_telegram_shop.phar')) {
throw new RuntimeException('Unable to locate application directory.'); throw new RuntimeException('Unable to locate application directory.');
} }
date_default_timezone_set('UTC');
// Get Settings from Database // Get Settings from Database
$host = DB_HOSTNAME; $host = DB_HOSTNAME;
$username = DB_USERNAME; $username = DB_USERNAME;
@@ -45,12 +42,15 @@ $prefix = DB_PREFIX;
$dsn = "mysql:host=$host;port=$port;dbname=$dbName"; $dsn = "mysql:host=$host;port=$port;dbname=$dbName";
$pdo = new PDO($dsn, $username, $password); $pdo = new PDO($dsn, $username, $password);
$connection = new MySqlConnection($pdo); $connection = new MySqlConnection($pdo);
$raw = $connection->select("SELECT value FROM `{$prefix}setting` WHERE `key` = 'module_telecart_settings'"); $raw = $connection->select("SELECT value FROM `{$prefix}setting` WHERE `key` = 'module_megapay_settings'");
$timezone = $connection->select("SELECT value FROM `{$prefix}setting` WHERE `key` = 'config_timezone'");
$timezone = $timezone[0]['value'] ?? 'UTC';
$json = json_decode($raw[0]['value'], true, 512, JSON_THROW_ON_ERROR); $json = json_decode($raw[0]['value'], true, 512, JSON_THROW_ON_ERROR);
$items = Arr::mergeArraysRecursively($json, [ $items = Arr::mergeArraysRecursively($json, [
'app' => [ 'app' => [
'shop_base_url' => HTTPS_CATALOG, // for catalog: HTTPS_SERVER, for admin: HTTPS_CATALOG 'shop_base_url' => HTTPS_CATALOG, // for catalog: HTTPS_SERVER, for admin: HTTPS_CATALOG
'language_id' => 1, 'language_id' => 1,
'oc_timezone' => $timezone,
], ],
'paths' => [ 'paths' => [
'images' => DIR_IMAGE, 'images' => DIR_IMAGE,
@@ -79,24 +79,20 @@ $items = Arr::mergeArraysRecursively($json, [
], ],
]); ]);
// Create logger $logger = new Logger('MegaPay_CLI', [], [], new DateTimeZone('UTC'));
$logger = new Logger('TeleCart_CLI', [], [], new DateTimeZone('UTC'));
$logger->pushHandler( $logger->pushHandler(
new RotatingFileHandler( new RotatingFileHandler(
DIR_LOGS . '/telecart.log', 14, $debug ? Logger::DEBUG : Logger::INFO DIR_LOGS . '/megapay.log', 14, $debug ? Logger::DEBUG : Logger::INFO
), ),
); );
// Creates TeleCart application.
$app = ApplicationFactory::create($items); $app = ApplicationFactory::create($items);
$app->setLogger($logger); $app->setLogger($logger);
$app->boot(); $app->boot();
// Creates Console and bind commands. $console = new Application('MegaPay', module_version());
$console = new Application('TeleCart', module_version());
$console->add($app->get(VersionCommand::class)); $console->add($app->get(VersionCommand::class));
$console->add($app->get(ScheduleRunCommand::class)); $console->add($app->get(ScheduleRunCommand::class));
$console->add($app->get(ScheduleListCommand::class));
$console->add($app->get(PulseSendEventsCommand::class)); $console->add($app->get(PulseSendEventsCommand::class));
$console->add($app->get(ImagesWarmupCacheCommand::class)); $console->add($app->get(ImagesWarmupCacheCommand::class));
$console->add($app->get(ImagesCacheClearCommand::class)); $console->add($app->get(ImagesCacheClearCommand::class));

View File

@@ -4,7 +4,7 @@
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Openguru\\OpenCartFramework\\": "framework/", "Openguru\\OpenCartFramework\\": "framework/",
"App\\": "src/", "App\\": "app/",
"Bastion\\": "bastion/", "Bastion\\": "bastion/",
"Console\\": "console/", "Console\\": "console/",
"Tests\\": "tests/" "Tests\\": "tests/"
@@ -36,7 +36,8 @@
"ramsey/uuid": "^4.2", "ramsey/uuid": "^4.2",
"symfony/http-foundation": "^5.4", "symfony/http-foundation": "^5.4",
"symfony/console": "^5.4", "symfony/console": "^5.4",
"dragonmantank/cron-expression": "^3.5" "dragonmantank/cron-expression": "^3.5",
"sentry/sentry": "^4.19"
}, },
"require-dev": { "require-dev": {
"doctrine/sql-formatter": "^1.3", "doctrine/sql-formatter": "^1.3",

View File

@@ -137,16 +137,16 @@
}, },
{ {
"name": "doctrine/dbal", "name": "doctrine/dbal",
"version": "3.10.5", "version": "3.10.4",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/dbal.git", "url": "https://github.com/doctrine/dbal.git",
"reference": "95d84866bf3c04b2ddca1df7c049714660959aef" "reference": "63a46cb5aa6f60991186cc98c1d1b50c09311868"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/95d84866bf3c04b2ddca1df7c049714660959aef", "url": "https://api.github.com/repos/doctrine/dbal/zipball/63a46cb5aa6f60991186cc98c1d1b50c09311868",
"reference": "95d84866bf3c04b2ddca1df7c049714660959aef", "reference": "63a46cb5aa6f60991186cc98c1d1b50c09311868",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -167,9 +167,9 @@
"jetbrains/phpstorm-stubs": "2023.1", "jetbrains/phpstorm-stubs": "2023.1",
"phpstan/phpstan": "2.1.30", "phpstan/phpstan": "2.1.30",
"phpstan/phpstan-strict-rules": "^2", "phpstan/phpstan-strict-rules": "^2",
"phpunit/phpunit": "9.6.34", "phpunit/phpunit": "9.6.29",
"slevomat/coding-standard": "8.27.1", "slevomat/coding-standard": "8.24.0",
"squizlabs/php_codesniffer": "4.0.1", "squizlabs/php_codesniffer": "4.0.0",
"symfony/cache": "^5.4|^6.0|^7.0|^8.0", "symfony/cache": "^5.4|^6.0|^7.0|^8.0",
"symfony/console": "^4.4|^5.4|^6.0|^7.0|^8.0" "symfony/console": "^4.4|^5.4|^6.0|^7.0|^8.0"
}, },
@@ -231,7 +231,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/doctrine/dbal/issues", "issues": "https://github.com/doctrine/dbal/issues",
"source": "https://github.com/doctrine/dbal/tree/3.10.5" "source": "https://github.com/doctrine/dbal/tree/3.10.4"
}, },
"funding": [ "funding": [
{ {
@@ -247,7 +247,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-02-24T08:03:57+00:00" "time": "2025-11-29T10:46:08+00:00"
}, },
{ {
"name": "doctrine/deprecations", "name": "doctrine/deprecations",
@@ -517,26 +517,25 @@
}, },
{ {
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",
"version": "7.13.1", "version": "7.10.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/guzzle.git", "url": "https://github.com/guzzle/guzzle.git",
"reference": "55901a76dfd2006a0cc012b9e3c5b487f796478d" "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/guzzle/zipball/55901a76dfd2006a0cc012b9e3c5b487f796478d", "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"reference": "55901a76dfd2006a0cc012b9e3c5b487f796478d", "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"ext-json": "*", "ext-json": "*",
"guzzlehttp/promises": "^2.5", "guzzlehttp/promises": "^2.3",
"guzzlehttp/psr7": "^2.12.3", "guzzlehttp/psr7": "^2.8",
"php": "^7.2.5 || ^8.0", "php": "^7.2.5 || ^8.0",
"psr/http-client": "^1.0", "psr/http-client": "^1.0",
"symfony/deprecation-contracts": "^2.5 || ^3.0", "symfony/deprecation-contracts": "^2.2 || ^3.0"
"symfony/polyfill-php80": "^1.25"
}, },
"provide": { "provide": {
"psr/http-client-implementation": "1.0" "psr/http-client-implementation": "1.0"
@@ -545,9 +544,8 @@
"bamarni/composer-bin-plugin": "^1.8.2", "bamarni/composer-bin-plugin": "^1.8.2",
"ext-curl": "*", "ext-curl": "*",
"guzzle/client-integration-tests": "3.0.2", "guzzle/client-integration-tests": "3.0.2",
"guzzlehttp/test-server": "^0.6",
"php-http/message-factory": "^1.1", "php-http/message-factory": "^1.1",
"phpunit/phpunit": "^8.5.52 || ^9.6.34", "phpunit/phpunit": "^8.5.39 || ^9.6.20",
"psr/log": "^1.1 || ^2.0 || ^3.0" "psr/log": "^1.1 || ^2.0 || ^3.0"
}, },
"suggest": { "suggest": {
@@ -625,7 +623,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/guzzle/issues", "issues": "https://github.com/guzzle/guzzle/issues",
"source": "https://github.com/guzzle/guzzle/tree/7.13.1" "source": "https://github.com/guzzle/guzzle/tree/7.10.0"
}, },
"funding": [ "funding": [
{ {
@@ -641,29 +639,28 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-06-29T20:14:18+00:00" "time": "2025-08-23T22:36:01+00:00"
}, },
{ {
"name": "guzzlehttp/promises", "name": "guzzlehttp/promises",
"version": "2.5.0", "version": "2.3.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/promises.git", "url": "https://github.com/guzzle/promises.git",
"reference": "4360e982f87f5f258bf872d094647791db2f4c8e" "reference": "481557b130ef3790cf82b713667b43030dc9c957"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/promises/zipball/4360e982f87f5f258bf872d094647791db2f4c8e", "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957",
"reference": "4360e982f87f5f258bf872d094647791db2f4c8e", "reference": "481557b130ef3790cf82b713667b43030dc9c957",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.2.5 || ^8.0", "php": "^7.2.5 || ^8.0"
"symfony/deprecation-contracts": "^2.5 || ^3.0"
}, },
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2", "bamarni/composer-bin-plugin": "^1.8.2",
"phpunit/phpunit": "^8.5.52 || ^9.6.34" "phpunit/phpunit": "^8.5.44 || ^9.6.25"
}, },
"type": "library", "type": "library",
"extra": { "extra": {
@@ -709,7 +706,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/promises/issues", "issues": "https://github.com/guzzle/promises/issues",
"source": "https://github.com/guzzle/promises/tree/2.5.0" "source": "https://github.com/guzzle/promises/tree/2.3.0"
}, },
"funding": [ "funding": [
{ {
@@ -725,29 +722,27 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-06-02T12:23:43+00:00" "time": "2025-08-22T14:34:08+00:00"
}, },
{ {
"name": "guzzlehttp/psr7", "name": "guzzlehttp/psr7",
"version": "2.12.3", "version": "2.8.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/guzzle/psr7.git", "url": "https://github.com/guzzle/psr7.git",
"reference": "7ec62dc3f44aa218487dbed81a9bf9bc647be55d" "reference": "21dc724a0583619cd1652f673303492272778051"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/7ec62dc3f44aa218487dbed81a9bf9bc647be55d", "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051",
"reference": "7ec62dc3f44aa218487dbed81a9bf9bc647be55d", "reference": "21dc724a0583619cd1652f673303492272778051",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": "^7.2.5 || ^8.0", "php": "^7.2.5 || ^8.0",
"psr/http-factory": "^1.0", "psr/http-factory": "^1.0",
"psr/http-message": "^1.1 || ^2.0", "psr/http-message": "^1.1 || ^2.0",
"ralouphie/getallheaders": "^3.0", "ralouphie/getallheaders": "^3.0"
"symfony/deprecation-contracts": "^2.5 || ^3.0",
"symfony/polyfill-php80": "^1.25"
}, },
"provide": { "provide": {
"psr/http-factory-implementation": "1.0", "psr/http-factory-implementation": "1.0",
@@ -755,9 +750,8 @@
}, },
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.8.2", "bamarni/composer-bin-plugin": "^1.8.2",
"http-interop/http-factory-tests": "1.1.0", "http-interop/http-factory-tests": "0.9.0",
"jshttp/mime-db": "1.54.0.1", "phpunit/phpunit": "^8.5.44 || ^9.6.25"
"phpunit/phpunit": "^8.5.52 || ^9.6.34"
}, },
"suggest": { "suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
@@ -828,7 +822,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/guzzle/psr7/issues", "issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/2.12.3" "source": "https://github.com/guzzle/psr7/tree/2.8.0"
}, },
"funding": [ "funding": [
{ {
@@ -844,7 +838,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-06-23T15:21:08+00:00" "time": "2025-08-23T21:21:41+00:00"
}, },
{ {
"name": "intervention/image", "name": "intervention/image",
@@ -1870,16 +1864,16 @@
}, },
{ {
"name": "symfony/cache", "name": "symfony/cache",
"version": "v5.4.53", "version": "v5.4.46",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/cache.git", "url": "https://github.com/symfony/cache.git",
"reference": "bf581474737420d5c932ae80b868e253f465ee5b" "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/cache/zipball/bf581474737420d5c932ae80b868e253f465ee5b", "url": "https://api.github.com/repos/symfony/cache/zipball/0fe08ee32cec2748fbfea10c52d3ee02049e0f6b",
"reference": "bf581474737420d5c932ae80b868e253f465ee5b", "reference": "0fe08ee32cec2748fbfea10c52d3ee02049e0f6b",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1947,7 +1941,7 @@
"psr6" "psr6"
], ],
"support": { "support": {
"source": "https://github.com/symfony/cache/tree/v5.4.53" "source": "https://github.com/symfony/cache/tree/v5.4.46"
}, },
"funding": [ "funding": [
{ {
@@ -1958,16 +1952,12 @@
"url": "https://github.com/fabpot", "url": "https://github.com/fabpot",
"type": "github" "type": "github"
}, },
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{ {
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-05-24T08:41:21+00:00" "time": "2024-11-04T11:43:55+00:00"
}, },
{ {
"name": "symfony/cache-contracts", "name": "symfony/cache-contracts",
@@ -2631,7 +2621,7 @@
}, },
{ {
"name": "symfony/polyfill-php73", "name": "symfony/polyfill-php73",
"version": "v1.37.0", "version": "v1.33.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php73.git", "url": "https://github.com/symfony/polyfill-php73.git",
@@ -2687,7 +2677,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php73/tree/v1.37.0" "source": "https://github.com/symfony/polyfill-php73/tree/v1.33.0"
}, },
"funding": [ "funding": [
{ {
@@ -2711,16 +2701,16 @@
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.37.0", "version": "v1.33.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411" "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/dfb55726c3a76ea3b6459fcfda1ec2d80a682411", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
"reference": "dfb55726c3a76ea3b6459fcfda1ec2d80a682411", "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2771,7 +2761,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.37.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0"
}, },
"funding": [ "funding": [
{ {
@@ -2791,7 +2781,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-04-10T16:19:22+00:00" "time": "2025-01-02T08:10:11+00:00"
}, },
{ {
"name": "symfony/polyfill-php81", "name": "symfony/polyfill-php81",
@@ -3929,11 +3919,11 @@
}, },
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "2.1.40", "version": "2.1.39",
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224",
"reference": "9b2c7aeb83a75d8680ea5e7c9b7fca88052b766b", "reference": "c6f73a2af4cbcd99c931d0fb8f08548cc0fa8224",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -3978,7 +3968,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2026-02-23T15:04:35+00:00" "time": "2026-02-11T14:48:56+00:00"
}, },
{ {
"name": "phpunit/php-code-coverage", "name": "phpunit/php-code-coverage",
@@ -4416,18 +4406,18 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git", "url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "0d2dce39eb2bce812e8c71a73be98b0f5d78f489" "reference": "92c5ec5685cfbcd7ef721a502e6622516728011c"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/0d2dce39eb2bce812e8c71a73be98b0f5d78f489", "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/92c5ec5685cfbcd7ef721a502e6622516728011c",
"reference": "0d2dce39eb2bce812e8c71a73be98b0f5d78f489", "reference": "92c5ec5685cfbcd7ef721a502e6622516728011c",
"shasum": "" "shasum": ""
}, },
"conflict": { "conflict": {
"3f/pygmentize": "<1.2", "3f/pygmentize": "<1.2",
"adaptcms/adaptcms": "<=1.3", "adaptcms/adaptcms": "<=1.3",
"admidio/admidio": "<5.0.6", "admidio/admidio": "<=4.3.16",
"adodb/adodb-php": "<=5.22.9", "adodb/adodb-php": "<=5.22.9",
"aheinze/cockpit": "<2.2", "aheinze/cockpit": "<2.2",
"aimeos/ai-admin-graphql": ">=2022.04.1,<2022.10.10|>=2023.04.1,<2023.10.6|>=2024.04.1,<2024.07.2", "aimeos/ai-admin-graphql": ">=2022.04.1,<2022.10.10|>=2023.04.1,<2023.10.6|>=2024.04.1,<2024.07.2",
@@ -4478,7 +4468,7 @@
"automattic/jetpack": "<9.8", "automattic/jetpack": "<9.8",
"awesome-support/awesome-support": "<=6.0.7", "awesome-support/awesome-support": "<=6.0.7",
"aws/aws-sdk-php": "<3.368", "aws/aws-sdk-php": "<3.368",
"azuracast/azuracast": "<=0.23.3", "azuracast/azuracast": "<=0.23.1",
"b13/seo_basics": "<0.8.2", "b13/seo_basics": "<0.8.2",
"backdrop/backdrop": "<=1.32", "backdrop/backdrop": "<=1.32",
"backpack/crud": "<3.4.9", "backpack/crud": "<3.4.9",
@@ -4550,7 +4540,7 @@
"commerceteam/commerce": ">=0.9.6,<0.9.9", "commerceteam/commerce": ">=0.9.6,<0.9.9",
"components/jquery": ">=1.0.3,<3.5", "components/jquery": ">=1.0.3,<3.5",
"composer/composer": "<1.10.27|>=2,<2.2.26|>=2.3,<2.9.3", "composer/composer": "<1.10.27|>=2,<2.2.26|>=2.3,<2.9.3",
"concrete5/concrete5": "<9.4.8", "concrete5/concrete5": "<9.4.3",
"concrete5/core": "<8.5.8|>=9,<9.1", "concrete5/core": "<8.5.8|>=9,<9.1",
"contao-components/mediaelement": ">=2.14.2,<2.21.1", "contao-components/mediaelement": ">=2.14.2,<2.21.1",
"contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4", "contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4",
@@ -4564,8 +4554,8 @@
"cosenary/instagram": "<=2.3", "cosenary/instagram": "<=2.3",
"couleurcitron/tarteaucitron-wp": "<0.3", "couleurcitron/tarteaucitron-wp": "<0.3",
"cpsit/typo3-mailqueue": "<0.4.3|>=0.5,<0.5.1", "cpsit/typo3-mailqueue": "<0.4.3|>=0.5,<0.5.1",
"craftcms/cms": "<=4.17.3|>=5,<=5.9.8", "craftcms/cms": "<4.17.0.0-beta1|>=5,<5.9.0.0-beta1",
"craftcms/commerce": ">=4,<4.11|>=5,<5.6", "craftcms/commerce": ">=4.0.0.0-RC1-dev,<=4.10|>=5,<=5.5.1",
"craftcms/composer": ">=4.0.0.0-RC1-dev,<=4.10|>=5.0.0.0-RC1-dev,<=5.5.1", "craftcms/composer": ">=4.0.0.0-RC1-dev,<=4.10|>=5.0.0.0-RC1-dev,<=5.5.1",
"craftcms/craft": ">=3.5,<=4.16.17|>=5.0.0.0-RC1-dev,<=5.8.21", "craftcms/craft": ">=3.5,<=4.16.17|>=5.0.0.0-RC1-dev,<=5.8.21",
"croogo/croogo": "<=4.0.7", "croogo/croogo": "<=4.0.7",
@@ -4643,7 +4633,7 @@
"drupal/umami_analytics": "<1.0.1", "drupal/umami_analytics": "<1.0.1",
"duncanmcclean/guest-entries": "<3.1.2", "duncanmcclean/guest-entries": "<3.1.2",
"dweeves/magmi": "<=0.7.24", "dweeves/magmi": "<=0.7.24",
"ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.3.1", "ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.1.2",
"ecodev/newsletter": "<=4", "ecodev/newsletter": "<=4",
"ectouch/ectouch": "<=2.7.2", "ectouch/ectouch": "<=2.7.2",
"egroupware/egroupware": "<23.1.20260113|>=26.0.20251208,<26.0.20260113", "egroupware/egroupware": "<23.1.20260113|>=26.0.20251208,<26.0.20260113",
@@ -4700,7 +4690,6 @@
"flarum/flarum": "<0.1.0.0-beta8", "flarum/flarum": "<0.1.0.0-beta8",
"flarum/framework": "<1.8.10", "flarum/framework": "<1.8.10",
"flarum/mentions": "<1.6.3", "flarum/mentions": "<1.6.3",
"flarum/nicknames": "<1.8.3",
"flarum/sticky": ">=0.1.0.0-beta14,<=0.1.0.0-beta15", "flarum/sticky": ">=0.1.0.0-beta14,<=0.1.0.0-beta15",
"flarum/tags": "<=0.1.0.0-beta13", "flarum/tags": "<=0.1.0.0-beta13",
"floriangaerber/magnesium": "<0.3.1", "floriangaerber/magnesium": "<0.3.1",
@@ -4723,10 +4712,10 @@
"friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6", "friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6",
"froala/wysiwyg-editor": "<=4.3", "froala/wysiwyg-editor": "<=4.3",
"frosh/adminer-platform": "<2.2.1", "frosh/adminer-platform": "<2.2.1",
"froxlor/froxlor": "<=2.3.3", "froxlor/froxlor": "<=2.2.5",
"frozennode/administrator": "<=5.0.12", "frozennode/administrator": "<=5.0.12",
"fuel/core": "<1.8.1", "fuel/core": "<1.8.1",
"funadmin/funadmin": "<=7.1.0.0-RC4", "funadmin/funadmin": "<=5.0.2",
"gaoming13/wechat-php-sdk": "<=1.10.2", "gaoming13/wechat-php-sdk": "<=1.10.2",
"genix/cms": "<=1.1.11", "genix/cms": "<=1.1.11",
"georgringer/news": "<1.3.3", "georgringer/news": "<1.3.3",
@@ -4747,7 +4736,7 @@
"gp247/core": "<1.1.24", "gp247/core": "<1.1.24",
"gree/jose": "<2.2.1", "gree/jose": "<2.2.1",
"gregwar/rst": "<1.0.3", "gregwar/rst": "<1.0.3",
"grumpydictator/firefly-iii": "<6.1.17|>=6.4.23,<=6.5", "grumpydictator/firefly-iii": "<6.1.17",
"gugoan/economizzer": "<=0.9.0.0-beta1", "gugoan/economizzer": "<=0.9.0.0-beta1",
"guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5",
"guzzlehttp/oauth-subscriber": "<0.8.1", "guzzlehttp/oauth-subscriber": "<0.8.1",
@@ -4773,7 +4762,7 @@
"ibexa/solr": ">=4.5,<4.5.4", "ibexa/solr": ">=4.5,<4.5.4",
"ibexa/user": ">=4,<4.4.3|>=5,<5.0.4", "ibexa/user": ">=4,<4.4.3|>=5,<5.0.4",
"icecoder/icecoder": "<=8.1", "icecoder/icecoder": "<=8.1",
"idno/known": "<1.6.4", "idno/known": "<=1.6.2",
"ilicmiljan/secure-props": ">=1.2,<1.2.2", "ilicmiljan/secure-props": ">=1.2,<1.2.2",
"illuminate/auth": "<5.5.10", "illuminate/auth": "<5.5.10",
"illuminate/cookie": ">=4,<=4.0.11|>=4.1,<6.18.31|>=7,<7.22.4", "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<6.18.31|>=7,<7.22.4",
@@ -4823,7 +4812,7 @@
"kelvinmo/simplexrd": "<3.1.1", "kelvinmo/simplexrd": "<3.1.1",
"kevinpapst/kimai2": "<1.16.7", "kevinpapst/kimai2": "<1.16.7",
"khodakhah/nodcms": "<=3", "khodakhah/nodcms": "<=3",
"kimai/kimai": "<=2.50", "kimai/kimai": "<2.46",
"kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4",
"klaviyo/magento2-extension": ">=1,<3", "klaviyo/magento2-extension": ">=1,<3",
"knplabs/knp-snappy": "<=1.4.2", "knplabs/knp-snappy": "<=1.4.2",
@@ -4848,7 +4837,7 @@
"lavalite/cms": "<=10.1", "lavalite/cms": "<=10.1",
"lavitto/typo3-form-to-database": "<2.2.5|>=3,<3.2.2|>=4,<4.2.3|>=5,<5.0.2", "lavitto/typo3-form-to-database": "<2.2.5|>=3,<3.2.2|>=4,<4.2.3|>=5,<5.0.2",
"lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5",
"league/commonmark": "<=2.8", "league/commonmark": "<2.7",
"league/flysystem": "<1.1.4|>=2,<2.1.1", "league/flysystem": "<1.1.4|>=2,<2.1.1",
"league/oauth2-server": ">=8.3.2,<8.4.2|>=8.5,<8.5.3", "league/oauth2-server": ">=8.3.2,<8.4.2|>=8.5,<8.5.3",
"leantime/leantime": "<3.3", "leantime/leantime": "<3.3",
@@ -4857,7 +4846,7 @@
"librenms/librenms": "<26.2", "librenms/librenms": "<26.2",
"liftkit/database": "<2.13.2", "liftkit/database": "<2.13.2",
"lightsaml/lightsaml": "<1.3.5", "lightsaml/lightsaml": "<1.3.5",
"limesurvey/limesurvey": "<6.15.4", "limesurvey/limesurvey": "<6.5.12",
"livehelperchat/livehelperchat": "<=3.91", "livehelperchat/livehelperchat": "<=3.91",
"livewire-filemanager/filemanager": "<=1.0.4", "livewire-filemanager/filemanager": "<=1.0.4",
"livewire/livewire": "<2.12.7|>=3.0.0.0-beta1,<3.6.4", "livewire/livewire": "<2.12.7|>=3.0.0.0-beta1,<3.6.4",
@@ -4885,7 +4874,7 @@
"marshmallow/nova-tiptap": "<5.7", "marshmallow/nova-tiptap": "<5.7",
"matomo/matomo": "<1.11", "matomo/matomo": "<1.11",
"matyhtf/framework": "<3.0.6", "matyhtf/framework": "<3.0.6",
"mautic/core": "<5.2.10|>=6,<6.0.8|>=7.0.0.0-alpha,<7.0.1", "mautic/core": "<5.2.9|>=6,<6.0.7",
"mautic/core-lib": ">=1.0.0.0-beta,<4.4.13|>=5.0.0.0-alpha,<5.1.1", "mautic/core-lib": ">=1.0.0.0-beta,<4.4.13|>=5.0.0.0-alpha,<5.1.1",
"mautic/grapes-js-builder-bundle": ">=4,<4.4.18|>=5,<5.2.9|>=6,<6.0.7", "mautic/grapes-js-builder-bundle": ">=4,<4.4.18|>=5,<5.2.9|>=6,<6.0.7",
"maximebf/debugbar": "<1.19", "maximebf/debugbar": "<1.19",
@@ -4918,7 +4907,7 @@
"mongodb/mongodb": ">=1,<1.9.2", "mongodb/mongodb": ">=1,<1.9.2",
"mongodb/mongodb-extension": "<1.21.2", "mongodb/mongodb-extension": "<1.21.2",
"monolog/monolog": ">=1.8,<1.12", "monolog/monolog": ">=1.8,<1.12",
"moodle/moodle": "<4.5.9|>=5.0.0.0-beta,<5.0.5|>=5.1.0.0-beta,<5.1.2", "moodle/moodle": "<4.4.12|>=4.5.0.0-beta,<4.5.8|>=5.0.0.0-beta,<5.0.4|>=5.1.0.0-beta,<5.1.1",
"moonshine/moonshine": "<=3.12.5", "moonshine/moonshine": "<=3.12.5",
"mos/cimage": "<0.7.19", "mos/cimage": "<0.7.19",
"movim/moxl": ">=0.8,<=0.10", "movim/moxl": ">=0.8,<=0.10",
@@ -5036,7 +5025,7 @@
"pimcore/demo": "<10.3", "pimcore/demo": "<10.3",
"pimcore/ecommerce-framework-bundle": "<1.0.10", "pimcore/ecommerce-framework-bundle": "<1.0.10",
"pimcore/perspective-editor": "<1.5.1", "pimcore/perspective-editor": "<1.5.1",
"pimcore/pimcore": "<=11.5.14.1|>=12,<12.3.3", "pimcore/pimcore": "<=11.5.13|>=12.0.0.0-RC1-dev,<12.3.1",
"pimcore/web2print-tools-bundle": "<=5.2.1|>=6.0.0.0-RC1-dev,<=6.1", "pimcore/web2print-tools-bundle": "<=5.2.1|>=6.0.0.0-RC1-dev,<=6.1",
"piwik/piwik": "<1.11", "piwik/piwik": "<1.11",
"pixelfed/pixelfed": "<0.12.5", "pixelfed/pixelfed": "<0.12.5",
@@ -5086,7 +5075,7 @@
"reportico-web/reportico": "<=8.1", "reportico-web/reportico": "<=8.1",
"rhukster/dom-sanitizer": "<1.0.7", "rhukster/dom-sanitizer": "<1.0.7",
"rmccue/requests": ">=1.6,<1.8", "rmccue/requests": ">=1.6,<1.8",
"robrichards/xmlseclibs": "<3.1.5", "robrichards/xmlseclibs": "<=3.1.3",
"roots/soil": "<4.1", "roots/soil": "<4.1",
"roundcube/roundcubemail": "<1.5.10|>=1.6,<1.6.11", "roundcube/roundcubemail": "<1.5.10|>=1.6,<1.6.11",
"rudloff/alltube": "<3.0.3", "rudloff/alltube": "<3.0.3",
@@ -5102,8 +5091,8 @@
"setasign/fpdi": "<2.6.4", "setasign/fpdi": "<2.6.4",
"sfroemken/url_redirect": "<=1.2.1", "sfroemken/url_redirect": "<=1.2.1",
"sheng/yiicms": "<1.2.1", "sheng/yiicms": "<1.2.1",
"shopware/core": "<6.6.10.15-dev|>=6.7,<6.7.8.1-dev", "shopware/core": "<6.6.10.9-dev|>=6.7,<6.7.6.1-dev",
"shopware/platform": "<6.6.10.15-dev|>=6.7,<6.7.8.1-dev", "shopware/platform": "<6.6.10.7-dev|>=6.7,<6.7.3.1-dev",
"shopware/production": "<=6.3.5.2", "shopware/production": "<=6.3.5.2",
"shopware/shopware": "<=5.7.17|>=6.4.6,<6.6.10.10-dev|>=6.7,<6.7.6.1-dev", "shopware/shopware": "<=5.7.17|>=6.4.6,<6.6.10.10-dev|>=6.7,<6.7.6.1-dev",
"shopware/storefront": "<6.6.10.10-dev|>=6.7,<6.7.5.1-dev", "shopware/storefront": "<6.6.10.10-dev|>=6.7,<6.7.5.1-dev",
@@ -5137,7 +5126,7 @@
"simplesamlphp/simplesamlphp-module-openid": "<1", "simplesamlphp/simplesamlphp-module-openid": "<1",
"simplesamlphp/simplesamlphp-module-openidprovider": "<0.9", "simplesamlphp/simplesamlphp-module-openidprovider": "<0.9",
"simplesamlphp/xml-common": "<1.20", "simplesamlphp/xml-common": "<1.20",
"simplesamlphp/xml-security": "<2.3.1", "simplesamlphp/xml-security": "==1.6.11",
"simplito/elliptic-php": "<1.0.6", "simplito/elliptic-php": "<1.0.6",
"sitegeist/fluid-components": "<3.5", "sitegeist/fluid-components": "<3.5",
"sjbr/sr-feuser-register": "<2.6.2|>=5.1,<12.5", "sjbr/sr-feuser-register": "<2.6.2|>=5.1,<12.5",
@@ -5147,7 +5136,7 @@
"slim/slim": "<2.6", "slim/slim": "<2.6",
"slub/slub-events": "<3.0.3", "slub/slub-events": "<3.0.3",
"smarty/smarty": "<4.5.3|>=5,<5.1.1", "smarty/smarty": "<4.5.3|>=5,<5.1.1",
"snipe/snipe-it": "<8.3.7", "snipe/snipe-it": "<=8.3.4",
"socalnick/scn-social-auth": "<1.15.2", "socalnick/scn-social-auth": "<1.15.2",
"socialiteproviders/steam": "<1.1", "socialiteproviders/steam": "<1.1",
"solspace/craft-freeform": "<4.1.29|>=5,<=5.14.6", "solspace/craft-freeform": "<4.1.29|>=5,<=5.14.6",
@@ -5165,7 +5154,7 @@
"starcitizentools/short-description": ">=4,<4.0.1", "starcitizentools/short-description": ">=4,<4.0.1",
"starcitizentools/tabber-neue": ">=1.9.1,<2.7.2|>=3,<3.1.1", "starcitizentools/tabber-neue": ">=1.9.1,<2.7.2|>=3,<3.1.1",
"starcitizenwiki/embedvideo": "<=4", "starcitizenwiki/embedvideo": "<=4",
"statamic/cms": "<5.73.11|>=6,<6.6.2", "statamic/cms": "<5.73.9|>=6,<6.3.2",
"stormpath/sdk": "<9.9.99", "stormpath/sdk": "<9.9.99",
"studio-42/elfinder": "<=2.1.64", "studio-42/elfinder": "<=2.1.64",
"studiomitte/friendlycaptcha": "<0.1.4", "studiomitte/friendlycaptcha": "<0.1.4",
@@ -5184,7 +5173,7 @@
"sylius/grid-bundle": "<1.10.1", "sylius/grid-bundle": "<1.10.1",
"sylius/paypal-plugin": "<1.6.2|>=1.7,<1.7.2|>=2,<2.0.2", "sylius/paypal-plugin": "<1.6.2|>=1.7,<1.7.2|>=2,<2.0.2",
"sylius/resource-bundle": ">=1,<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", "sylius/resource-bundle": ">=1,<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4",
"sylius/sylius": "<1.9.12|>=1.10,<1.10.16|>=1.11,<1.11.17|>=1.12,<=1.12.22|>=1.13,<=1.13.14|>=1.14,<=1.14.17|>=2,<=2.0.15|>=2.1,<=2.1.11|>=2.2,<=2.2.2", "sylius/sylius": "<1.12.19|>=1.13.0.0-alpha1,<1.13.4",
"symbiote/silverstripe-multivaluefield": ">=3,<3.1", "symbiote/silverstripe-multivaluefield": ">=3,<3.1",
"symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4",
"symbiote/silverstripe-seed": "<6.0.3", "symbiote/silverstripe-seed": "<6.0.3",
@@ -5239,7 +5228,7 @@
"thelia/thelia": ">=2.1,<2.1.3", "thelia/thelia": ">=2.1,<2.1.3",
"theonedemon/phpwhois": "<=4.2.5", "theonedemon/phpwhois": "<=4.2.5",
"thinkcmf/thinkcmf": "<6.0.8", "thinkcmf/thinkcmf": "<6.0.8",
"thorsten/phpmyfaq": "<4.0.18|>=4.1.0.0-alpha,<=4.1.0.0-beta2", "thorsten/phpmyfaq": "<=4.0.16|>=4.1.0.0-alpha,<=4.1.0.0-beta2",
"tikiwiki/tiki-manager": "<=17.1", "tikiwiki/tiki-manager": "<=17.1",
"timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1", "timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1",
"tinymce/tinymce": "<7.2", "tinymce/tinymce": "<7.2",
@@ -5257,7 +5246,6 @@
"ttskch/pagination-service-provider": "<1", "ttskch/pagination-service-provider": "<1",
"twbs/bootstrap": "<3.4.1|>=4,<4.3.1", "twbs/bootstrap": "<3.4.1|>=4,<4.3.1",
"twig/twig": "<3.11.2|>=3.12,<3.14.1|>=3.16,<3.19", "twig/twig": "<3.11.2|>=3.12,<3.14.1|>=3.16,<3.19",
"typicms/core": "<16.1.7",
"typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2",
"typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1",
"typo3/cms-belog": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", "typo3/cms-belog": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2",
@@ -5312,9 +5300,8 @@
"wallabag/wallabag": "<2.6.11", "wallabag/wallabag": "<2.6.11",
"wanglelecc/laracms": "<=1.0.3", "wanglelecc/laracms": "<=1.0.3",
"wapplersystems/a21glossary": "<=0.4.10", "wapplersystems/a21glossary": "<=0.4.10",
"web-auth/webauthn-framework": ">=3.3,<3.3.4|>=4.5,<4.9|>=5.2,<5.2.4", "web-auth/webauthn-framework": ">=3.3,<3.3.4|>=4.5,<4.9",
"web-auth/webauthn-lib": ">=4.5,<4.9|>=5.2,<5.2.4", "web-auth/webauthn-lib": ">=4.5,<4.9",
"web-auth/webauthn-symfony-bundle": ">=5.2,<5.2.4",
"web-feet/coastercms": "==5.5", "web-feet/coastercms": "==5.5",
"web-tp3/wec_map": "<3.0.3", "web-tp3/wec_map": "<3.0.3",
"webbuilders-group/silverstripe-kapost-bridge": "<0.4", "webbuilders-group/silverstripe-kapost-bridge": "<0.4",
@@ -5326,7 +5313,7 @@
"wikibase/wikibase": "<=1.39.3", "wikibase/wikibase": "<=1.39.3",
"wikimedia/parsoid": "<0.12.2", "wikimedia/parsoid": "<0.12.2",
"willdurand/js-translation-bundle": "<2.1.1", "willdurand/js-translation-bundle": "<2.1.1",
"winter/wn-backend-module": "<1.2.12", "winter/wn-backend-module": "<1.2.4",
"winter/wn-cms-module": "<=1.2.9", "winter/wn-cms-module": "<=1.2.9",
"winter/wn-dusk-plugin": "<2.1", "winter/wn-dusk-plugin": "<2.1",
"winter/wn-system-module": "<1.2.4", "winter/wn-system-module": "<1.2.4",
@@ -5339,8 +5326,7 @@
"wpanel/wpanel4-cms": "<=4.3.1", "wpanel/wpanel4-cms": "<=4.3.1",
"wpcloud/wp-stateless": "<3.2", "wpcloud/wp-stateless": "<3.2",
"wpglobus/wpglobus": "<=1.9.6", "wpglobus/wpglobus": "<=1.9.6",
"wpmetabox/meta-box": "<5.11.2", "wwbn/avideo": "<21",
"wwbn/avideo": "<25",
"xataface/xataface": "<3", "xataface/xataface": "<3",
"xpressengine/xpressengine": "<3.0.15", "xpressengine/xpressengine": "<3.0.15",
"yab/quarx": "<2.4.5", "yab/quarx": "<2.4.5",
@@ -5438,7 +5424,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2026-03-13T21:11:59+00:00" "time": "2026-02-20T22:06:39+00:00"
}, },
{ {
"name": "sebastian/cli-parser", "name": "sebastian/cli-parser",

View File

@@ -3,7 +3,7 @@
return [ return [
'app' => [ 'app' => [
'app_enabled' => true, 'app_enabled' => true,
'app_name' => 'Telecart', 'app_name' => 'Megapay',
'app_icon' => null, 'app_icon' => null,
"theme_light" => "light", "theme_light" => "light",
"theme_dark" => "dark", "theme_dark" => "dark",
@@ -85,7 +85,6 @@ HTML,
'pulse' => [ 'pulse' => [
'api_key' => '', 'api_key' => '',
'heartbeat_enabled' => false,
'batch_size' => 50, 'batch_size' => 50,
'max_attempts' => 3, 'max_attempts' => 3,
], ],
@@ -105,18 +104,19 @@ HTML,
], ],
'cache' => [ 'cache' => [
'namespace' => 'telecart', 'namespace' => 'megapay',
'default_lifetime' => 60 * 60 * 24, 'default_lifetime' => 60 * 60 * 24,
'options' => [ 'options' => [
'db_table' => 'telecart_cache_items', 'db_table' => 'megapay_cache_items',
], ],
], ],
'paths' => [ 'paths' => [
'images_cache' => 'cache/telecart', 'images_cache' => 'cache/megapay',
], ],
'cron' => [ 'cron' => [
'mode' => 'disabled', 'mode' => 'disabled',
'api_key' => '',
], ],
]; ];

View File

@@ -10,7 +10,7 @@ use Openguru\OpenCartFramework\ImageTool\ImageToolServiceProvider;
use Openguru\OpenCartFramework\QueryBuilder\QueryBuilderServiceProvider; use Openguru\OpenCartFramework\QueryBuilder\QueryBuilderServiceProvider;
use Openguru\OpenCartFramework\Scheduler\SchedulerServiceProvider; use Openguru\OpenCartFramework\Scheduler\SchedulerServiceProvider;
use Openguru\OpenCartFramework\Support\Arr; use Openguru\OpenCartFramework\Support\Arr;
use Openguru\OpenCartFramework\TeleCartPulse\TeleCartPulseServiceProvider; use Openguru\OpenCartFramework\MegaPayPulse\MegaPayPulseServiceProvider;
use Openguru\OpenCartFramework\Telegram\TelegramServiceProvider; use Openguru\OpenCartFramework\Telegram\TelegramServiceProvider;
class ApplicationFactory class ApplicationFactory
@@ -28,7 +28,7 @@ class ApplicationFactory
AppServiceProvider::class, AppServiceProvider::class,
CacheServiceProvider::class, CacheServiceProvider::class,
TelegramServiceProvider::class, TelegramServiceProvider::class,
TeleCartPulseServiceProvider::class, MegaPayPulseServiceProvider::class,
SchedulerServiceProvider::class, SchedulerServiceProvider::class,
ImageToolServiceProvider::class, ImageToolServiceProvider::class,
]); ]);

Some files were not shown because too many files have changed in this diff Show More