1
0
forked from BRT/arc
arc/docs/black_tasks.md
slava de8c2e84d0 - Add toggleMaterial logic to NetworkService for enabling/disabling materials via PATCH request.
- Implement `toggleMaterialStatus` in `AccountSettingsWindow` for UI control and threading integration.
- Enhance `MaterialDAO` with numeric validation for `lastNumbers` field to ensure data integrity.
- Update `PayByCardScript` and `PayByPhoneScript` to handle PIN entry if required after payment confirmation.
- Introduce dynamic UI adjustments for material toggling, including a new toggle button and layout refinements.
- Add documentation for task logic in `ozon_tasks.md` and `black_tasks.md`.
- Switch default currency in `GetCardInfoScript` (Black app) from USD to ARS.
2026-03-31 11:40:34 +07:00

369 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Black - Логика задач
[← Главная](index.md) | [События](events.md)
Описание логики всех типов задач для банка **Black** (appCode: `black`).
> Black — аргентинское банковское приложение. Интерфейс на испанском. Валюта: ARS (код 32). Таймзона: America/Argentina/Buenos_Aires (UTC-3).
---
## Общие механизмы (CommonScript)
### Запуск приложения (`runAppAndGoToHomeScreen`)
1. Убивает приложение если запущено
2. Запускает приложение
3. Ждёт 4.5 секунды
4. Цикл до 10 попыток:
- Получает XML-дамп экрана
- Проверяет `isHomeScreen()` (наличие "Saldo disponible" + content-desc "Inicio")
- Если экран с PIN-кодом (`isPinCodeScreen()` — "¿Olvidaste tu PIN?" или "Ingresá tu PIN"):
- Находит EditText с password=true
- Тапает для фокуса → ожидание 500мс
- Вводит PIN через `AdbUtils::inputText()`
- Ожидание 3 сек
- Ожидание 1 сек между попытками
5. При неудаче — скриншот
### Прокрутка к кнопке (`swipeToButton`)
- До 10 свайпов вверх
- После каждого свайпа парсит XML и ищет кнопку
- Аналогично Ozon
### Создание банковского профиля (`createBankProfileIfNeeded`)
- Аналогично Ozon (общий код в CommonScript)
- Валюта по умолчанию: ARS→32
---
## FETCH_PROFILE
**Скрипты:** `Black::LoginAndCheckAccountsScript``Black::GetProfileInfoScript``Black::GetCardInfoScript`
### Цель
Авторизация, сбор профиля (ФИО, телефон, email), получение CVU и баланса.
### Шаги LoginAndCheckAccountsScript
1. **Валидация** — получение DeviceInfo и BankProfileInfo из БД
2. **Запуск приложения**`runAppAndGoToHomeScreen()` с PIN-кодом
3. **Запуск GetProfileInfoScript** — синхронно, для сбора профиля
4. При ошибке: скриншот + лог + обновление комментария в `BankProfileDAO`
### Шаги GetProfileInfoScript
1. **Домашний экран** — проверка/перезапуск
2. **Парсинг с домашнего экрана**:
- fullName из `parseUserNameFromHomeScreen()` — формат "¡Hola!\nИМЯ\ninitials"
- Баланс из `parseBalanceFromHomeScreen()` — формат "$1.857,00" → 1857.00
- Обновление баланса в `BankProfileDAO`
3. **Навигация в боковое меню**:
- Поиск кнопки "¡Hola!" (аватар)
- Тап → ожидание 2 сек
- Ожидание `isSideMenu()` (5 × 1 сек) — маркеры: "Tu Información" + "Cerrar sesión"
4. **Навигация к профилю**:
- Тап "Tu Información" (content-desc)
- Ожидание 2.5 сек
- Ожидание `isProfilePage()` (5 × 1 сек) — маркер: content-desc "Tu información"
5. **Парсинг профиля**:
- Nombre, Apellido, Email — по hint-атрибутам EditText
- Свайп вниз → ожидание 1.5 сек
- Телефон — из hint-атрибута
- fullName = "nombre apellido" (или fallback на имя с домашнего экрана)
6. **Сохранение**: `BankProfileDAO::updateProfileInfo(id, fullName, phone, email)`
7. **Синхронизация с сервером**: `createBankProfileIfNeeded()`
8. **Отправка аккаунтов**: `postAccountsData()` для аккаунтов без materialId
9. **Завершение** — убийство приложения
### Шаги GetCardInfoScript (CVU)
1. **Домашний экран** — проверка/перезапуск
2. **Парсинг баланса** → обновление в БД
3. **Навигация к CVU**:
- Поиск кнопки "Tu CVU" (exact match)
- Тап → ожидание 2 сек
- Ожидание `isCVUScreen()` (5 × 1 сек)
4. **Парсинг CVU**:
- `parseCVUNumber()` — 22-значный номер после маркера "CVU"
- lastNumbers = последние 4 цифры CVU
5. **Сохранение в БД**:
- `MaterialDAO::upsertAccount()` с:
- cardNumber = полный CVU
- lastNumbers = CVU[-4:]
- currency = "USD" (хардкод)
- description = "CVU"
6. **Отправка материала на сервер**: `ns.postMaterial()` (если есть bankProfileId и нет materialId)
7. **Завершение** — убийство приложения
### Ответ серверу (при успехе)
```json
{
"type": "FETCH_PROFILE",
"material_id": "...",
"bank_name": "black",
"data": {
"bank_account_id": "",
"amount": 185700,
"currency": 32
}
}
```
---
## FETCH_TRANSACTIONS
**Скрипт:** `Black::GetLastTransactionsScript`
### Цель
Получение списка последних транзакций из истории операций.
### Шаги
1. **Домашний экран** — проверка/перезапуск
2. **Навигация к истории транзакций**:
- Поиск кнопки "Ver más" после секции "Tu actividad" через `findVerMasAfterTuActividad()`
- Если не найдена — до 5 свайпов вниз (1 сек между свайпами)
- Тап "Ver más" → ожидание 2 сек
3. **Ожидание загрузки** (15 × 1.5 сек):
- `isTransactionLoadingScreen()` = "Tu Actividad" есть, но транзакций нет (загрузка)
- `isTransactionListScreen()` = "Tu Actividad" + видимые транзакции
- Если после 15 попыток всё ещё loading → пустой аккаунт (нормально), возврат без ошибки
4. **Парсинг транзакций** (`parseTransactionItems()`):
- Источник: ImageView ноды с текстом формата:
```
Transferencia
DD de MES de YYYY - HH:MM
$amount,cents
```
или (входящие):
```
Transferencia externa de ИМЯ
DD de MES de YYYY - HH:MM
$amount,cents
```
- Отрицательные суммы: `$-amount` (исходящие переводы)
- Парсинг испанских дат (`parseSpanishDate()`): enero, febrero, ..., diciembre
5. **Сохранение в БД** (для каждой транзакции):
- bankName = "black"
- status = Complete
- timestamp = currentDateTimeUtc()
- Конвертация времени: парсинг испанской даты → таймзона Buenos Aires
- `TransactionDAO::insertTransactionIfNotExists()`
6. **Возврат**`goBack()` → ожидание 1 сек
### Retry-логика (EventHandler)
Аналогична Ozon:
```
"Transaction not found" + < 10 мин → повтор через 15 сек
"Transaction not found" + ≥ 10 мин → ошибка
```
### Ответ серверу
```json
{
"type": "FETCH_TRANSACTIONS",
"material_id": "...",
"bank_name": "black",
"data": [
{
"bank_transaction_id": null,
"amount": 185700,
"currency": 32,
"transaction_type": "bank",
"bank_participator_id": "+5491112345678",
"status": "completed",
"extra": { "fee": 0 },
"created_at": "2025-01-15T14:30:00.000-03:00"
}
]
}
```
---
## CREATE_TRANSACTION (bank — по CBU/CVU/Alias)
**Скрипт:** `Black::PayByCardScript`
### Цель
Перевод на CBU, CVU или Alias получателя.
### Входные параметры
- `event.phone` — CBU/CVU/Alias получателя (поле `m_cardNumber`)
- `event.amount` — сумма перевода
- `m_account` — аккаунт-отправитель
### Шаги
1. **Домашний экран** — проверка/перезапуск
2. **Поиск кнопки оплаты**:
- `findNodeByContentDesc("Enviar a\nCBU o alias", contains=true)`
- Если не найдена — до 5 свайпов вниз
- Тап → ожидание 2 сек
3. **Ввод реквизитов** (10 × 1.5 сек ожидание экрана):
- Экран `isPayInputCardNumberScreen()` — hint "Ingresar CBU, CVU o Alias"
- Тап на EditText → ожидание 500мс
- Ввод CBU/CVU/Alias
- Тап "Continuar" → ожидание 2 сек
4. **Подтверждение получателя** (10 × 1.5 сек):
- Экран `isPayTransferConfirmScreen()` — кнопка "Transferir" + поле "Alias:"
- Тап "Transferir" → ожидание 2 сек
5. **Ввод суммы** (10 × 1.5 сек):
- Экран `isPayInputSumScreen()` — "Cuánto vas a transferír"
- Тап на EditText → ожидание 500мс
- **Очистка поля**: 20 × keyevent 67 (backspace)
- **Ввод суммы в сентаво**: `int(amount * 100)` → строка
- Пример: 500.00 → "50000"
- Проверка: перечитывает поле, если не совпадает — повторяет ввод
- Тап "Continuar" → ожидание 2 сек
6. **Финальное подтверждение** (10 × 1.5 сек):
- Экран `isPayConfirmScreen()` — "Vas a transferir \na ИМЯ_ПОЛУЧАТЕЛЯ"
- Парсинг имени получателя (`parseRecipientNameFromConfirm()`)
- Тап "Transferir" → ожидание 3 сек
7. **Ввод PIN** (если запрошен):
- `isPinCodeScreen()``inputPinCode()`
- Ожидание 3 сек
8. **Проверка результата** (15 × 2 сек):
- **"Dinero enviado!"** → успех:
- Парсинг bankTime: `parsePaySuccessDateTime()` → "DD/MM/YY HH:MM"
- Парсинг ID: `parsePaySuccessCoelsaId()` → Coelsa transaction ID
- Скриншот как чек
- Если снова PIN-экран → повторный ввод PIN
- Таймаут → ошибка
9. **Сохранение транзакции**:
- amount = -m_amount (отрицательная)
- fee = 0
- type = Card, status = Complete
- name = имя получателя
- description = "Transferencia a ИМЯ"
- phone = CBU/CVU/Alias
- bankTrExternalId = Coelsa ID
- receiptImage = скриншот
- `TransactionDAO::insertTransaction()`
### Ответ серверу
```json
{
"type": "CREATE_TRANSACTION",
"material_id": "...",
"bank_name": "black",
"data": {
"amount": -50000,
"currency": 32,
"transaction_type": "bank",
"bank_participator_id": "0000003100012345678901",
"status": "completed",
"bank_transaction_id": "COELSA-12345",
"extra": { "fee": 0 },
"created_at": "2025-01-15T14:30:00.000-03:00"
}
}
```
---
## ScreenXmlParser (Black)
### Определение экранов
| Метод | Маркеры |
|-------|---------|
| `isHomeScreen()` | "Saldo disponible" + content-desc "Inicio" |
| `isPinCodeScreen()` | "¿Olvidaste tu PIN?" или "Ingresá tu PIN" |
| `isSideMenu()` | "Tu Información" + "Cerrar sesión" |
| `isProfilePage()` | content-desc "Tu información" |
| `isCVUScreen()` | маркер "CVU" |
| `isTransactionLoadingScreen()` | "Tu Actividad" без "Transferencia" |
| `isTransactionListScreen()` | "Tu Actividad" + транзакции |
| `isPayInputCardNumberScreen()` | EditText с hint "Ingresar CBU, CVU o Alias" |
| `isPayTransferConfirmScreen()` | "Transferir" + "Alias:" без "Vas a transferir" |
| `isPayInputSumScreen()` | "Cuánto vas a transferír" |
| `isPayConfirmScreen()` | "Vas a transferir" |
| `isPaySuccessScreen()` | "Dinero enviado!" |
### Парсинг данных
| Метод | Формат / Логика |
|-------|-----------------|
| `parseUserNameFromHomeScreen()` | "¡Hola!\nИМЯ\ninitials" → ИМЯ |
| `parseBalanceFromHomeScreen()` | "$1.857,00" → 1857.00 (аргентинский формат) |
| `parseProfileNombre/Apellido/Email/Phone()` | По hint-атрибутам EditText |
| `parseCVUNumber()` | 22-значный номер после маркера "CVU" |
| `parseTransactionItems()` | ImageView ноды с "Transferencia" |
| `parseSpanishDate()` | "DD de MES de YYYY - HH:MM" → QDateTime |
| `parseRecipientNameFromConfirm()` | "Vas a transferir \na ИМЯ" → ИМЯ |
| `parsePaySuccessDateTime()` | "DD/MM/YY HH:MM" |
| `parsePaySuccessCoelsaId()` | Текст после "Id Coelsa" |
### Парсинг транзакций
Формат элемента списка (ImageView text):
```
Transferencia // тип
15 de enero de 2025 - 14:30 // дата (испанский)
$1.500,00 // сумма (положительная = входящая)
```
или:
```
Transferencia externa de Juan Perez // тип + имя отправителя
15 de enero de 2025 - 14:30
$-1.500,00 // отрицательная = исходящая
```
### Испанские месяцы
| Месяц | Перевод |
|-------|---------|
| enero | январь |
| febrero | февраль |
| marzo | март |
| abril | апрель |
| mayo | май |
| junio | июнь |
| julio | июль |
| agosto | август |
| septiembre | сентябрь |
| octubre | октябрь |
| noviembre | ноябрь |
| diciembre | декабрь |