Commit Graph

75 Commits

Author SHA1 Message Date
Exest
96aa963c27 версия 2.0.10: после загрузки прайса — сразу в «Прайс-лист»; Enter в поле кол-ва добавляет в заказ
Some checks failed
Desktop tests / test (push) Has been cancelled
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-25 12:59:07 +03:00
Exest
3d89fac6e0 тесты: автотесты десктопа (xUnit) + CI
Some checks failed
Desktop tests / test (push) Has been cancelled
- проект tests/Elfisa.Tests: 56 юнит-тестов на Elfisa.Core + Elfisa.Avalonia:
  версии апдейтера, срок JWT-сессии, ApiClient (URL/ошибки/ретраи/парсинг),
  DTO-контракты, черновики, корзина, дрилдаун прайса (МГ/базовое имя)
- тест-швы: internal-методы через InternalsVisibleTo, ApiClient(HttpMessageHandler)
- CI .github/workflows/desktop-tests.yml — dotnet test при пуше (GitHub/Gitea Actions)
- README с описанием покрытия

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-17 11:51:50 +03:00
Exest
60ab620608 версия 2.0.9: размер шрифта/текста (масштаб интерфейса) в Настройках
- Настройки: выпадающий список «Размер шрифта / текста» (90/100/115/130/150%)
- масштаб применяется ко всему главному окну (LayoutTransform), сохраняется
  и восстанавливается при старте

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-13 16:39:46 +03:00
Exest
c808d62188 версия 2.0.8: выбор шрифта интерфейса в Настройках
- Настройки: выпадающий список «Шрифт» со всеми системными шрифтами
  (+ «По умолчанию»), с превью каждого шрифта в себе самом
- шрифт применяется ко всему приложению (ресурс AppFontFamily + стиль Window),
  сохраняется и восстанавливается при старте

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-13 16:21:00 +03:00
Exest
4e341f76c3 версия 2.0.7: надёжный автоапдейт (CDN) + кнопка проверки + без лимита листания
- UpdateService: проверка через публичный CDN latest.json (тот же хост, что и
  установщик — надёжнее поддомена git), fallback на Gitea, лог в %TEMP%\elfisa-update.log
- Настройки: кнопка «Проверить обновления» (ручной триггер + видимый результат)
- Прайс-лист: убран лимит показа (300 → весь прайс/все совпадения одним запросом)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-13 15:35:24 +03:00
Exest
23f34cc769 версия 2.0.6: Enter в поле поиска прайса запускает поиск
Раньше поиск шёл только кнопкой «Найти». Добавлен KeyBinding Enter → SearchCommand
прямо в поле ввода: набрал название, нажал Enter — ищет.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-13 15:11:18 +03:00
Exest
cc2c128cb2 версия 2.0.5: сводный прайс — весь одним запросом (быстрее при всех прайсах)
LoadPrice дробил прайс на страницы по 20000, а сервер на каждую страницу заново
прогонял тяжёлую оконную дедупликацию + COUNT. При всех подключённых прайсах
(~52к позиций) это ~6-7с. Тянем всё одним запросом → один прогон (~1.2с).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-13 12:54:14 +03:00
Exest
e8357bab1e версия 2.0.4: авто-обновление в Avalonia-клиенте
- UpdateService (Core): проверка Gitea releases/latest + скачивание установщика с CDN
- UpdateWindow/VM: уведомление «доступно обновление», тихая установка поверх с перезапуском
- ShellView: проверка при старте (один раз, офлайн/ошибки игнорируются)

Закрывает пробел: Avalonia-клиент раньше не умел обновляться (апдейтер был только в WinForms).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-13 10:10:13 +03:00
Exest
436bbb8bfb версия 2.0.3: запоминание входа, быстрая загрузка прайса, повтор при SSL
- Session: сохранение/восстановление сессии между запусками (JWT exp-проверка)
- LoadPrice: страница 20000 вместо 500 — прайс грузится одним запросом
- ApiClient: повтор запроса на транзиентных сбоях TLS (поиск/загрузка)
- download-страница: реальный размер, macOS помечен «скоро»

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-13 09:23:29 +03:00
Exest
8242184c18 версия 2.0.2 (раздел «Отправить» — отправка накладных)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-11 13:47:15 +03:00
Exest
124a891025 Отправить: отправка неотправленных накладных (из Заказы), без поиска/наименований
Раздел переделан: вместо поиска по прайсу и корзины с наименованиями — список
неотправленных накладных (черновиков) и кнопка «Отправить все» (плюс отправка
по одной). Отправка создаёт реальный заказ у поставщика и убирает черновик.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-11 13:41:34 +03:00
Exest
f98978a5d2 2.0.1: «Мои прайсы» в Прайс-листе + подключённые прайсы в «Загрузить»
- Прайс-лист: дропдаун «Мои прайсы» (подключённые прайсы + «Все прайсы»),
  выбор фильтрует каталог по price_list_id; один прайс — выбирается сам
- Загрузить: показывает список подключённых прайсов и качает их
- Core: GetBuyerPriceListsAsync + priceListId в GetPriceSummaryAsync

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-10 17:42:53 +03:00
Exest
028c588d2a Релиз 2.0: кросс-платформа, брендовый установщик, страница загрузки
- Версия 2.0.0, self-contained публикация под win/osx/linux
- Установщик Inno перенастроен на Avalonia + брендовые картинки мастера
  (бирюзовый градиент, аптечный крест, ЭльФиСА)
- exe переименовывается в «Электронная Фармация.exe» (совместимо с авто-обновлением)
- Иконки приложения 256/512/1024
- Красивая страница загрузки web/download с авто-определением ОС (Win/Mac/Linux)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-10 12:41:14 +03:00
Exest
3fc825e54b Avalonia: Прайс-лист как в WinForms — дрилдаун Название→МГ→Предложения + ввод количества с клавиатуры
- База/дозировка вычисляются на клиенте (порт BuildBaseName/ExtractDosage)
- Три панели: базовые наименования → дозировки (МГ) → предложения поставщиков
- Колонка «Заказ»: ввод числа с клавиатуры (многозначно), Enter — добавить
- Фикс: null-безопасная привязка KeyDown (падало в конструкторе → пустой экран)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-10 12:02:41 +03:00
Exest
0536d480cb Avalonia: вкладки-документы + нижняя строка состояния + монохромные иконки
- Вкладки-документы: разделы открываются вкладками (несколько сразу),
  закрываются, активная синхронизирована с верхней навигацией
  (ShellViewModel.Tabs/ActiveTab, CloseTabCommand)
- Нижняя строка состояния: Пользователь | Аптека + кнопка «Настройки»
- Монохромные иконки Segoe MDL2 (те же глифы, что в WinForms):
  Прайс E14C, Заказы E7BF, Накладные E8A5, Отчёты EB05, Загрузить E896,
  Отправить E725, Отказы E7BA, Справочник E8F1
- контент показывает активную вкладку

Оболочка приведена к виду исходной программы. Проверено вживную.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 13:00:03 +03:00
Exest
cd2fb57bca Avalonia: черновики получают реальный номер EX-####### (как в WinForms)
- при «Сохранить заказ» резервируется настоящий номер через
  GET /api/buyer/global-sign/next (fallback ЧРН-… если офлайн)
- при отправке черновика этот EX-номер передаётся в заказ (global_sign),
  заказ сохраняет тот же номер
- ApiClient.NextGlobalSignAsync, BuyerOrderCreateRequest.GlobalSign
- DraftStore: номер задаёт вызывающий

Проверено: черновик = EX-0000018, статус «Не отправлен».

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 11:54:43 +03:00
Exest
2420a71ace Avalonia: сборка заказа в Прайс-листе (панель «Мой заказ») + черновики в «Заказы»
- Прайс-лист: 2 колонки — каталог + «Мой заказ» (состав/кол-во/итог/
  грузополучатель/комментарий) + «Сохранить заказ»
- Сохранить -> локальный черновик (DraftStore, %APPDATA%)
- Заказы: черновики вверху «Не отправлен» + «Отправить заказ»/«Удалить»
- как в WinForms: собрал -> сохранил (не отправлен) -> отправил отдельно

Проверено вживую: сборка, сохранение, черновик в Заказах.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 11:43:47 +03:00
Exest
c677345ba6 Avalonia: общая корзина, добавление из Прайс-листа, Настройки
- CartService: единая корзина для Прайс-листа и Отправить
- Прайс-лист: выбор позиции + кол-во + «Добавить в заказ», индикатор корзины
- Настройки (диалог ⚙ в шапке): адрес API, тема (свет/тьма, применяется
  сразу), грузополучатель по умолчанию; сохранение в %APPDATA%
- SettingsStore (Core) + AppConfig читает сохранённый API-адрес
- тема применяется на старте

Проверено вживую: добавление из Прайс-листа в корзину, диалог настроек.
Реальная отправка заказа (POST) — собрана и связана, живой заказ по явному «да»
(автозащита блокирует боевую транзакцию без подтверждения).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 11:26:53 +03:00
Exest
43468ac693 Avalonia: раздел «Загрузить» (скачивание прайса) + уплотнение верхней панели
- Добавлена вкладка «Загрузить» (между Отчёты и Отправить, как в исходной
  программе): постраничная загрузка прайса с прогрессом, кэш в памяти
  (PriceCache), итог «N позиций от K поставщиков» + timestamp
- Верхняя навигация уплотнена под 8 вкладок (Справочник больше не обрезается)
- Core: PriceCache

Проверено вживую: все 8 вкладок влезают, загрузка прайса работает (500 поз.).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 11:05:52 +03:00
Exest
b13a867f8d Avalonia: раздел «Отправить» (корзина + создание заказа)
- Отправить: поиск по прайсу → корзина (кол-во через NumericUpDown,
  сумма/итого) → выбор грузополучателя + комментарий → создание заказа
  POST /api/buyer/orders
- Core: CreateOrderAsync + DTO (BuyerOrderCreateRequest/ItemReq/Response)
- Отказы: заглушка с точным пояснением (нужен серверный эндпоинт;
  RefuseItemsCount живёт только в локальной SQLite WinForms)

Итог: 6/7 разделов функциональны (Прайс-лист, Заказы, Накладные, Отчёты,
Справочник, Отправить), Отказы — заглушка. Собирается.
⚠️ Реальная отправка заказа (POST) не тестировалась — создаёт заказ на
проде; проверять вживую отдельно.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 10:30:57 +03:00
Exest
77dfb08ef4 Avalonia: Прайс-лист, Накладные, Справочник (5/7 разделов рабочие)
- Прайс-лист: поиск + грид на рабочем /api/supplier-prices/summary
  (наименование, форма, производитель, поставщик, цена)
- Накладные: реестр приходных документов (из buyer/report)
- Справочник: профиль покупателя + грузополучатели (buyer/locations)
- Core: GetPriceSummaryAsync, GetBuyerLocationsAsync + DTO
- README: статус разделов + примечание про buyer/orders 500 (фикс застейджен)

Рабочие: Прайс-лист, Заказы, Накладные, Отчёты, Справочник.
Осталось: Отправить (корзина+DBF), Отказы (нужен эндпоинт), автообновление.
Собирается; рантайм новых 3 разделов не проверен (клиент за игрой — окна не поднимал).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 10:20:36 +03:00
Exest
132ce1531f Avalonia: верхняя навигация (как в WinForms) + раздел «Заказы»
- Навигация перенесена из левого сайдбара в ВЕРХНЮЮ горизонтальную
  панель, как в исходной программе: логотип слева, вкладки
  (иконка+подпись) по центру, пользователь+Выйти справа
- Раздел «Заказы»: мастер-детали (список слева, состав заказа справа
  с позициями и итогом), на данных /api/buyer/report
- Числовые колонки выровнены вправо (стиль DataGridCell.num)
- Отчёты: тулбар на WrapPanel, стабильные ширины колонок

Проверено запуском (скриншоты): верхняя навигация, отчёты, заказы.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-08 10:00:57 +03:00
Exest
f6a1012e9b Avalonia кросс-платформенный клиент: фундамент + раздел «Отчёты»
Порт десктопа с WinForms на Avalonia (.NET 8, Win/macOS/Linux).

- Elfisa.Core: переносимая логика (ApiClient: логин/отчёт/ИИ, DTO, Session)
- Дизайн-система в бирюзе #0F766E (свет/тьма, кнопки/поля/карточки/таблица/сайдбар)
- Экран входа (реальный /auth/login), шелл с сайдбар-навигацией
- «Отчёты»: 4 типа + авто-загрузка + ИИ-запрос -> Word/Excel, динамические колонки
- Заглушки остальных разделов + README с дорожной картой портирования

Проверено запуском: логин, живые данные покупателя, тема, таблица (скриншот).
dev-автологин по ELF_DEV_USER/ELF_DEV_PASS.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-07 18:21:10 +03:00
Exest
a4880d7c50 v1.0.29: раздел «Отчёты» в стиле приложения
- бирюзовые кнопки (#0F766E) как в шапке, «Сформировать» больше не обрезано
- убрана криво рендерившаяся эмодзи с кнопки ИИ
- поле «Запрос ИИ» нормальной ширины (не на весь экран), фиксированные позиции
- таблица: бирюзовая шапка с белым текстом, чередование строк,
  бирюзовое выделение, числа выровнены вправо, сбалансированные ширины колонок

Проверено рендером с тестовыми данными.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-07 16:57:22 +03:00
Exest
4b43907353 v1.0.28: фикс раскладки раздела «Отчёты»
Во второй строке (ИИ) убраны конфликтующие якоря — поле «Запрос ИИ»
тянется по ширине, формат и кнопка пиннятся вправо с пересчётом при
ресайзе, контролы больше не наезжают друг на друга.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-07 16:45:52 +03:00
Exest
4d398aca84 v1.0.27: ИИ-отчёты по запросу в разделе «Отчёты»
Клиент пишет запрос словами («закупки по поставщикам за июль»,
«топ товаров за 3 месяца», «заказы у Farmsnab»), ИИ на Мак-мини
подбирает тип/период/фильтр, платформа отдаёт данные строго этого
покупателя, собирается Word/Excel и открывается автоматически.

- UCReports: строка «Запрос ИИ» + Word/Excel + кнопка
- ApiClient.GenerateAiReportAsync -> POST {AiBase}/generate
- AppConfig.AiBaseUrl (default https://24pharmdata.ru/ai,
  override ELF_AI_BASE_URL для локального теста)

Сервер: Caddy проксирует /ai/* -> Мак-мини (Ollama qwen2.5:7b +
FastAPI). LLM только распознаёт запрос, цифры считает код.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-07 16:24:19 +03:00
Exest
f7fb7ed1b0 Release v1.0.26: раздел «Отчёты» для покупателя
Новый раздел «Отчёты» в десктопе (buyer-scoped, данные с сервера):
- Мои заказы за период, По поставщикам, По товарам, По аптекам
- фильтр по датам, агрегация клиентски из одного набора строк
- сервер: GET /api/buyer/report скоупит строки по JWT покупателя
  (клиент видит ТОЛЬКО свои заказы)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-07 14:06:41 +03:00
Exest
557f8667ad Release v1.0.25: fix auto-updater elevation
Апдейтер: повышение прав через cmd.exe /c вместо запуска .cmd напрямую
(ShellExecute runas на .cmd срабатывал не на всех системах — elevated
процесс молча не стартовал, обновление в Program Files не применялось,
клиент зацикливался на уведомлении). Payload переносится в ASCII-путь,
чтобы имя папки из архива не ломало аргумент SRC для robocopy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-07 10:38:08 +03:00
Exest
b10eba0984 Release v1.0.24
Версия десктопа поднята до 1.0.24.0. Сопровождает серверные фиксы,
которые уже на проде: отправка заказа (глобальный номер заявки),
скоуп прайса покупателя по назначенному прайс-листу.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-06 18:03:00 +03:00
Exest
63abfd4e31 Release v1.0.23: global order numbers EX-####### (GLOBAL_SIGN).
Desktop reserves/sends EX numbers from server; supplier DBF gets GLOBAL_SIGN column.
2026-08-05 18:59:43 +03:00
Exest
d2a1a86794 Release v1.0.22: fix auto-update loop on Program Files installs.
Auto-updater now requests UAC elevation, force-unlocks the exe, and verifies the copy before restart.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-05 17:09:57 +03:00
2659de14b9 Release v1.0.21: consignees from web, remove test pharmacies. 2026-08-05 15:22:44 +03:00
Exest
166a431bda Release v1.0.20: fix Orders date filter hiding new carts.
Compare OrderDate as real dates (dd.MM.yyyy storage broke across month boundaries) and bump AssemblyVersion so desktop picks up the Gitea release.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 14:01:44 +03:00
Exest
cdb2d353a5 Release v1.0.19 desktop build.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 17:21:07 +03:00
Exest
0253bdf022 Bump to v1.0.18 with valid release timestamp.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 17:21:07 +03:00
Exest
621f6a6cf3 Bump to v1.0.17 retest after hang fix.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 17:18:59 +03:00
Exest
03c71b8e78 Fix update hang: allow dialog close after download; harden updater wait.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 17:18:11 +03:00
Exest
2230d4c73f Bump to v1.0.15 auto-update retest target.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 13:49:23 +03:00
Exest
28f0886b32 Fix auto-update exit crash after download (Application.Exit from async).
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 13:48:56 +03:00
Exest
d80953baad Bump to v1.0.13 to exercise in-app auto-updater.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 13:45:39 +03:00
Exest
3039c324be Add in-app auto-updater that preserves local database.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 13:44:44 +03:00
Exest
7497ee2d4f Bump desktop to v1.0.11 for forced-update smoke test.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 13:39:46 +03:00
Exest
b69e1b4498 Add forced update check against Gitea releases.
Block startup when a newer Release exists; keep offline pharmacies working.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 12:58:36 +03:00
Magomed
09535e9b02 Optimize price-list name search for large catalogs.
Replace O(n^2) per-keystroke rebuild with indexed unique names, a single-pass filter, and debounce so typing stays responsive with ~15k items.
2026-07-30 18:36:35 +03:00
Exest
9dfdb913cb Use server final price on download without local markup math.
Server now sums price-list, region and buyer markups; desktop must not re-apply discounts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-30 15:40:36 +03:00
Magomed
d68155b8ef Persist per-pharmacy markup percent and simplify consignee picker UI.
Store client markup on each Consignee so it survives restarts and price refresh; show only name and address in the selection dialog with a wider window.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-30 14:53:28 +03:00
Magomed
3d253a2f54 Fix SQLite BadImageFormat by disabling Prefer32Bit and syncing interop arch.
Ensure SQLite.Interop.dll next to the exe always matches process bitness from x86/x64.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-30 14:27:41 +03:00
Magomed
fd5bd18c66 Add per-pharmacy carts and client-side summed discount pricing.
Apply available buyer/price-list/region discounts to summary.price on download, keep consignee carts separate, and harden SQLite startup/migrations.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-30 14:07:47 +03:00
Magomed
458b70e036 Add multi-pharmacy LocationId, batched price download, and SQL debug tools.
Persist last successful login only, show active pharmacy in the status bar, and keep settings compact at the bottom-right.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-29 10:09:04 +03:00
Magomed
babc067863 Add dedicated settings dialog in main window and keep auth form login-only.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-28 12:26:16 +03:00