352 lines
15 KiB
Markdown
352 lines
15 KiB
Markdown
# Вопросы и Ответы - Отправка инвойсов в E-Taxes
|
||
|
||
Дата: 2025-12-15
|
||
Задача: Добавить функционал отправки Sales Invoice в E-Taxes
|
||
|
||
## Технические Вопросы и Ответы
|
||
|
||
### 1. Аутентификация
|
||
**Q:** Должны ли мы использовать существующую систему аутентификации ASAN Login (которая уже есть в приложении для импорта инвойсов), или нужны отдельные credentials для отправки?
|
||
|
||
**A:** Использовать существующий ASAN Login
|
||
|
||
---
|
||
|
||
### 2. Доступность кнопки
|
||
**Q:** Когда кнопка 'Отправить в E-Taxes' должна быть доступна?
|
||
|
||
**A:** После Submit (рекомендуется) - кнопка доступна только после того, как Sales Invoice в статусе Submitted
|
||
|
||
---
|
||
|
||
### 3. Процесс подписания
|
||
**Q:** Должен ли процесс подписания (sign/withAsanImza) происходить автоматически после создания инвойса, или это должна быть отдельная кнопка?
|
||
|
||
**A:** Да, автоматически после создания. Если у тебя есть еще вопросы - не стесняйся их задавать. Например где создавать кастомные поля, которые могут понадобится? Ответ - в приложении jey_erp, там файл custom_fields.
|
||
|
||
---
|
||
|
||
### 4. Данные клиента (TIN и Object Name)
|
||
**Q:** Где хранится информация о клиенте для отправки в E-Taxes (TIN, objectName)?
|
||
|
||
**A:** Так, поле TIN это tax_id а вот поля object_name не существует. ПОКА ЧТО пусть создастся тестовое поле с типом текст, потом что нибудь придумаем на замену.
|
||
|
||
---
|
||
|
||
### 5. Product Group Code для товаров
|
||
**Q:** Как определять productGroupCode для товаров (items)?
|
||
|
||
**A:** Есть поле в item называется product_group_code, текстового типа.
|
||
|
||
---
|
||
|
||
### 6. Сохранение данных после отправки
|
||
**Q:** Какие данные нужно сохранить после успешной отправки?
|
||
|
||
**A:**
|
||
- Invoice ID
|
||
- Serial Number
|
||
- Verification Code
|
||
- Статус отправки
|
||
|
||
---
|
||
|
||
### 7. Обработка ошибок API
|
||
**Q:** Как обрабатывать ошибки API?
|
||
|
||
**A:** Показать ошибку и остановить. Если есть еще какие то вопросы - не стесняйся задавать, чем большое понимания задачи - тем лучше исполнение.
|
||
|
||
---
|
||
|
||
### 8. Тип НДС для товаров
|
||
**Q:** Как определять тип НДС для товаров (vat18, vat0, vatFree, exempt)?
|
||
|
||
**A:** Проанализируй файл custom_fields.py, там вроде бы уже созданы поля для этих целей, вот код из этого файла:
|
||
```python
|
||
"Sales Invoice Item": [
|
||
dict(
|
||
fieldname='vat_18_percent_with_amount',
|
||
label='VAT 18% with amount',
|
||
fieldtype='Currency',
|
||
insert_after='amount',
|
||
in_list_view=1,
|
||
read_only=1,
|
||
columns=2,
|
||
precision=2
|
||
),
|
||
dict(
|
||
fieldname='vat_amount',
|
||
label='VAT Amount',
|
||
fieldtype='Currency',
|
||
insert_after='vat_18_percent_with_amount',
|
||
in_list_view=1,
|
||
columns=2,
|
||
precision=2,
|
||
read_only=1,
|
||
description='Calculated as: VAT 18% with amount - Amount'
|
||
),
|
||
dict(
|
||
fieldname='vat_0_percent_with_amount',
|
||
label='VAT 0% with amount',
|
||
fieldtype='Currency',
|
||
insert_after='vat_amount',
|
||
in_list_view=1,
|
||
read_only=1,
|
||
columns=2,
|
||
precision=2
|
||
),
|
||
dict(
|
||
fieldname='amount_without_vat',
|
||
label='Amount without VAT',
|
||
fieldtype='Currency',
|
||
insert_after='vat_0_percent_with_amount',
|
||
in_list_view=1,
|
||
read_only=1,
|
||
columns=2,
|
||
precision=2
|
||
),
|
||
dict(
|
||
fieldname='vat_free_amount',
|
||
label='VAT free amount',
|
||
fieldtype='Currency',
|
||
insert_after='amount_without_vat',
|
||
in_list_view=1,
|
||
read_only=1,
|
||
columns=2,
|
||
precision=2
|
||
),
|
||
dict(
|
||
fieldname='tax_article',
|
||
label='Tax Article',
|
||
fieldtype='Link',
|
||
options='Tax Article',
|
||
insert_after='vat_free_amount',
|
||
in_list_view=1,
|
||
columns=2,
|
||
description='Tax Article field for VAT purposes'
|
||
)
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### 9. Unit Code для единиц измерения
|
||
**Q:** Откуда брать unitCode для единиц измерения?
|
||
|
||
**A:** Вот список всех единиц измерений и их кодов из сайта:
|
||
```json
|
||
{
|
||
"items": [
|
||
{"code": "666", "name": {"az": "ədəd", "ru": "штук", "en": "piece"}},
|
||
{"code": "391836", "name": {"az": "km", "ru": "км", "en": "km"}},
|
||
{"code": "529937", "name": {"az": "kq", "ru": "кг", "en": "kg"}},
|
||
{"code": "581879", "name": {"az": "l", "ru": "л", "en": "l"}},
|
||
{"code": "207201", "name": {"az": "m", "ru": "м", "en": "m"}},
|
||
{"code": "6666", "name": {"az": "m2", "ru": "м2", "en": "m2"}},
|
||
{"code": "839111", "name": {"az": "m3", "ru": "м3", "en": "m3"}},
|
||
{"code": "525166", "name": {"az": "q", "ru": "г", "en": "g"}},
|
||
{"code": "116094", "name": {"az": "sm", "ru": "см", "en": "cm"}},
|
||
{"code": "864211", "name": {"az": "sm3", "ru": "см3", "en": "cm3"}},
|
||
{"code": "544580", "name": {"az": "t", "ru": "т", "en": "t"}}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 10. Дополнительные поля (senderObjectCode, vehicleRegistrationNumber)
|
||
**Q:** Что делать с полями senderObjectCode и vehicleRegistrationNumber?
|
||
|
||
**A:** Оставить пустыми
|
||
|
||
---
|
||
|
||
### 11. Предотвращение повторной отправки
|
||
**Q:** Должны ли мы предотвращать повторную отправку?
|
||
|
||
**A:** Да, блокировать повтор
|
||
|
||
---
|
||
|
||
### 12. Текст кнопки
|
||
**Q:** Какой текст должен быть на кнопке отправки?
|
||
|
||
**A:** Send to E-Taxes
|
||
|
||
---
|
||
|
||
### 13. Комментарии в инвойсе
|
||
**Q:** Что делать с полями invoiceComment и invoiceComment2?
|
||
|
||
**A:** Есть буквально поля который называются comment и additional_comment.
|
||
|
||
---
|
||
|
||
### 14. Диалог подтверждения
|
||
**Q:** Показывать ли диалог подтверждения перед отправкой?
|
||
|
||
**A:** Да, аж два, типа "вы точно уверены?" "точно при точно??" (ну не дословно так, но будет 2 вопроса).
|
||
|
||
---
|
||
|
||
### 15. Кнопка в списке инвойсов
|
||
**Q:** Нужна ли кнопка в list view (списке инвойсов)?
|
||
|
||
**A:** Вообще нужно, но давай пока что без этого. Если есть еще вопросы - задавай. Кстати, на всякий случай, если я захочу продолжить в другом чате - ответы на вопросы и план основанный на ответах создай в корневой папке приложения.
|
||
|
||
---
|
||
|
||
### 16. Генерация ID для товаров
|
||
**Q:** Как генерировать ID для товаров (item id в формате '44f5986a-2d3c-45d6-bb14-79a899******')?
|
||
|
||
**A:** Случайный UUID
|
||
|
||
---
|
||
|
||
### 17. Фиксированные поля JSON
|
||
**Q:** Какие значения использовать для полей type, kind, sourceSystem?
|
||
|
||
**A:** Как в примере (type='current', kind='defaultInvoice', sourceSystem='lk')
|
||
|
||
---
|
||
|
||
### 18. Валидация данных
|
||
**Q:** Нужно ли валидировать данные перед отправкой?
|
||
|
||
**A:**
|
||
- Проверить TIN клиента
|
||
- Проверить product codes
|
||
- Проверить unit codes
|
||
|
||
---
|
||
|
||
## Техническая Информация
|
||
|
||
### API Endpoints:
|
||
1. **Generate Serial Number**: `https://new.e-taxes.gov.az/api/po/invoice/public/v1/generateSerialNumber/defaultInvoice`
|
||
- Response: `{"serialNumber":"MT25121128****"}`
|
||
|
||
2. **Create Invoice**: `https://new.e-taxes.gov.az/api/po/invoice/public/v2/invoice`
|
||
- Response: `{"id":"b7bd1f20-4bdb-4e7b-bf18-c1f9bd******"}`
|
||
|
||
3. **Sign Invoice**: `https://new.e-taxes.gov.az/api/po/invoice/public/v1/invoice/sign/withAsanImza`
|
||
- Request: `{"type": "send", "invoiceIds": ["invoice-id-here"]}`
|
||
- Response: `{"status":"ok","error":null,"verificationCode":"4147"}`
|
||
|
||
### Примеры находятся в:
|
||
- `/home/frappe/frappe-bench/apps/invoice_az/invoice.txt` - пример создания инвойса
|
||
- `/home/frappe/frappe-bench/apps/invoice_az/invoice asan.txt` - пример подписания
|
||
|
||
### Кастомные поля создаются в:
|
||
- `/home/frappe/frappe-bench/apps/jey_erp/jey_erp/custom_fields.py`
|
||
|
||
### Существующие поля в Sales Invoice Item:
|
||
- vat_18_percent_with_amount
|
||
- vat_amount
|
||
- vat_0_percent_with_amount
|
||
- amount_without_vat
|
||
- vat_free_amount
|
||
- tax_article
|
||
|
||
### Существующие поля в Sales Invoice:
|
||
- comment
|
||
- additional_comment
|
||
- tax_id (в Customer)
|
||
|
||
### Существующие поля в Item:
|
||
- product_group_code
|
||
|
||
---
|
||
|
||
### 19. Маппинг единиц измерения (UOM)
|
||
**Q:** Как маппить единицы измерения из ERPNext UOM в коды E-Taxes? Например, если в Sales Invoice Item указано 'Nos' или 'Unit' - какой код использовать?
|
||
|
||
**A:** Короче, я только что путем эксперементов узнал что оказвыается поле unit_code необязательно, и вообще тот список ед. измерений который я тебе скинул - это просто шаблоны из сайта, то есть можно просто текстом написать ədəd, и сайт пропустит это, даже без кода, или вообще написать test123, и сайт всеравно пропустит. ПОэтому просто бери имя единицы измерений из табличной части и все.
|
||
|
||
---
|
||
|
||
### 20. Pricing поля для товаров
|
||
**Q:** Что использовать для pricePerUnit и cost в items? В примере оба = 1, но у нас есть rate, amount и т.д.
|
||
|
||
**A:** rate -> pricePerUnit, amount -> cost
|
||
|
||
---
|
||
|
||
### 21. Кнопка после отправки
|
||
**Q:** Что делать с кнопкой после успешной отправки (ты говорил блокировать повтор)?
|
||
|
||
**A:** Показать статус (заменить кнопку на индикатор статуса с информацией об отправке)
|
||
|
||
---
|
||
|
||
### 22. Язык сообщений
|
||
**Q:** На каком языке показывать сообщения об ошибках и подтверждения?
|
||
|
||
**A:** English
|
||
|
||
---
|
||
|
||
### 23. Receiver Name (юридическое название)
|
||
**Q:** Про receiver.name - нужно искать клиента в E-Taxes Customer Mappings, найти соответствующий E-Taxes Customers и оттуда брать name?
|
||
|
||
**A:** Да, из E-Taxes Customers. Короче ищи соответствие в e-taxes-settings (в том, который помечен как default), и там будет 100% название из сайта.
|
||
|
||
---
|
||
|
||
### 24. Частичная ошибка (создание успешно, подписание failed)
|
||
**Q:** Если создание инвойса (invoice create) прошло успешно, но подписание (signing) провалилось - что делать?
|
||
|
||
**A:** Сохранить ID, показать ошибку. Сохранить invoice ID и serial number, но показать ошибку подписания. Статус = 'Created, not signed'
|
||
|
||
---
|
||
|
||
### 25. Progress dialog
|
||
**Q:** Нужно ли показывать progress dialog во время отправки (как в существующей функции импорта)?
|
||
|
||
**A:** Простой loading (простой frappe.show_alert с loading индикатором)
|
||
|
||
---
|
||
|
||
### 26. Тексты подтверждения
|
||
**Q:** Тексты для двух диалогов подтверждения - какие должны быть?
|
||
|
||
**A:** Простые - 1) 'Send this invoice to E-Taxes?' 2) 'Are you sure?'
|
||
|
||
---
|
||
|
||
### 27. Tracking doctype
|
||
**Q:** Нужно ли создавать tracking doctype (типа E-Taxes Sales) для отправленных инвойсов?
|
||
|
||
**A:** Да, создать. (Создать E-Taxes Sales Outbox для отслеживания отправленных инвойсов)
|
||
|
||
---
|
||
|
||
## Workflow процесса отправки:
|
||
|
||
1. Пользователь нажимает "Send to E-Taxes" на submitted Sales Invoice
|
||
2. Первый диалог подтверждения: 'Send this invoice to E-Taxes?'
|
||
3. Второй диалог подтверждения: 'Are you sure?'
|
||
4. Показать простой loading индикатор
|
||
5. Валидация данных:
|
||
- Проверка TIN клиента (tax_id)
|
||
- Проверка product_group_code у всех товаров
|
||
- Проверка что инвойс еще не отправлен (блокировка повтора)
|
||
6. Получение serial number от API
|
||
7. Формирование JSON с данными инвойса:
|
||
- receiver.name - из E-Taxes Customers (через mapping)
|
||
- receiver.tin - из tax_id
|
||
- receiver.objectName - из custom field в Sales Invoice
|
||
- items: pricePerUnit = rate, cost = amount, unit = UOM name (текст)
|
||
- VAT: vat_18_percent_with_amount -> vat18, vat_0_percent_with_amount -> vat0, etc.
|
||
- comments: comment и additional_comment
|
||
8. Отправка на создание инвойса
|
||
9. Автоматическое подписание инвойса
|
||
10. Создание E-Taxes Sales Outbox tracking document
|
||
11. Сохранение результатов в Sales Invoice:
|
||
- Invoice ID
|
||
- Serial Number
|
||
- Verification Code (если успешно)
|
||
- Статус отправки ('Sent and Signed' или 'Created, not signed')
|
||
12. Заменить кнопку на индикатор статуса
|
||
13. Показать успешное сообщение пользователю
|