58 Commits

Author SHA1 Message Date
Mikhail Chusavitin
df5be91353 Improve performance on poor connections: local assets, gzip, caching
- Replace Tailwind CDN (~350KB) with purged local CSS (~22KB)
- Replace htmx unpkg CDN with local static file
- Add Gzip middleware (standard library, sync.Pool) for all responses
- Add Cache-Control: public, max-age=3600 for /static/* assets
- Reduce status polling interval from 5s to 30s
- Add scripts/build-css.sh for CSS regeneration after template changes
- Document in bible-local/operations.md and history.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.5.0
2026-03-14 14:51:21 +03:00
Mikhail Chusavitin
c53c484bde Replace competitor discount with price_uplift; stock pricelist detail UI
- Drop `expected_discount_pct`, add `price_uplift DECIMAL(8,4) DEFAULT 1.3`
  to `qt_competitors` (migration 040); formula: effective_price = price / uplift
- Extend `LoadLotMetrics` to return per-PN qty map (`pnQtysByLot`)
- Add virtual fields `CompetitorNames`, `PriceSpreadPct`, `PartnumberQtys`
  to `PricelistItem`; populate via `enrichWarehouseItems` / `enrichCompetitorItems`
- Competitor quotes filtered to qty > 0 before lot resolution
- New "stock layout" on pricelist detail page for warehouse/competitor:
  Partnumbers column (PN + qty, only qty>0), Поставщик column, no Настройки/Доступно
- Spread badge ±N% shown next to price for competitor rows
- Bible updated: pricelist.md, history.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.4.0
2026-03-13 12:58:41 +03:00
Mikhail Chusavitin
9b9b343f0c Update bible: competitors API endpoints and pricelist deletion/competitor sections
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
v0.3.0
2026-03-13 10:24:34 +03:00
Mikhail Chusavitin
9fde087d0a Wire competitor models, task type, usage count fix, and Competitors page handler
- Register Competitor + CompetitorQuote in AllModels()
- Add TaskTypeCompetitorImport task type constant
- CountUsage now checks pricelist_id, warehouse_pricelist_id, competitor_pricelist_id
- WebHandler: load competitors.html template, add Competitors() page handler

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 09:00:07 +03:00
Mikhail Chusavitin
ec182abe99 Competitor pricelist: aggregate all competitors, rebuild without re-import
- Add GetLatestQuotesAllCompetitors() repo method: latest quote per
  (competitor_id, partnumber) across all active competitors
- Add RebuildPricelist() service method: loads all quotes, applies each
  competitor's discount, aggregates with weighted_median per lot,
  creates single combined competitor pricelist
- Add POST /api/competitors/pricelist handler + route
- JS: "Создать прайслист" on competitor tab calls new endpoint instead
  of the generic one that required explicit items

This allows recreating the competitor pricelist after new lot mappings
are added, without requiring a new file upload.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 08:17:44 +03:00
Mikhail Chusavitin
592d77e30b Fix estimate data leaking into competitor/warehouse pricelists
The else branch in CreateForSourceWithProgress was reading from
qt_lot_metadata (estimate snapshot) for any source when no items
were provided. This caused estimate prices, coefficients, manual
prices and meta_prices to be copied verbatim into competitor/warehouse
pricelists when called with empty item list.

Fix: else branch is now guarded to source=="estimate" only.
Any other source with no items returns an explicit error instead
of silently falling back to estimate data.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 08:09:47 +03:00
Mikhail Chusavitin
f48615e8a9 Modularize Go files, extract JS to static, implement competitor pricelists
Go refactoring:
- Split handlers/pricing.go (2446→291 lines) into 5 focused files
- Split services/stock_import.go (1334→~400 lines) into stock_mappings.go + stock_parse.go
- Split services/sync/service.go (1290→~250 lines) into 3 files

JS extraction:
- Move all inline <script> blocks to web/static/js/ (6 files)
- Templates reduced: admin_pricing 2873→521, lot 1531→304, vendor_mappings 1063→169, etc.

Competitor pricelists (migrations 033-039):
- qt_competitors + partnumber_log_competitors tables
- Excel import with column mapping, dedup, bulk insert
- p/n→lot resolution via weighted_median, discount applied
- Unmapped p/ns written to qt_vendor_partnumber_seen
- Quote counts (unique/total) shown on /admin/competitors
- price_method="weighted_median", price_period_days=0 stored explicitly

Fix price_method/price_period_days for warehouse items:
- warehouse: weighted_avg, period=0
- competitor: weighted_median, period=0
- Removes misleading DB defaults (was: median/90)

Update bible: architecture.md, pricelist.md, history.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-13 07:44:10 +03:00
Mikhail Chusavitin
c0fecde34e Add new items section to price changes modal
Track positions added to a pricelist (not present in the previous one)
and display them in a separate "Новые позиции" section in the price
changes modal on both pricelists and admin_pricing pages.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 11:39:47 +03:00
Mikhail Chusavitin
d067a5890a Update bible submodule 2026-03-08 17:09:43 +03:00
Mikhail Chusavitin
3f26a2935a Refactor vendor mappings to canonical PN catalog v0.2.0 2026-03-07 23:11:42 +03:00
Mikhail Chusavitin
96572be712 Harden local admin and secret storage 2026-03-07 22:14:31 +03:00
Mikhail Chusavitin
08de9006ef Refactor partnumber book catalog storage 2026-03-07 22:10:05 +03:00
Mikhail Chusavitin
b2b2f4774c Refactor scheduler and settings UI 2026-03-07 21:10:20 +03:00
27e33db446 Restore previous bible/ content as bible-local/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 22:26:50 +03:00
f0c5aa8da3 Convert bible/ to git submodule (mchus/bible)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 22:25:55 +03:00
7e6a30fc39 Add bible submodule files (patterns, kit, exports, demo)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 22:25:01 +03:00
85b2f6169e Update bible paths kit/ → rules/
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 16:58:28 +03:00
Mikhail Chusavitin
04ce74ca1b Refine vendor mapping CSV operations and ignore import flow 2026-02-27 16:49:39 +03:00
Mikhail Chusavitin
6f1de7a20e Add vendor mappings CSV import modal and fix vendor rename save 2026-02-26 12:44:11 +03:00
Mikhail Chusavitin
63454554c1 Fix vendor mapping delete behavior and update docs 2026-02-25 19:06:28 +03:00
a4457a0a28 Add partnumber book snapshots for QuoteForge integration
- Migrations 026-028: qt_partnumber_books + qt_partnumber_book_items
  tables; is_primary_pn on lot_partnumbers; version VARCHAR(30);
  description VARCHAR(10000) on items (required by QuoteForge sync)
- Service: CreateSnapshot expands bundles, filters empty lot_name and
  ignored PNs, copies description, activates new book atomically,
  applies GFS retention (7d/5w/12m/10y) with explicit item deletion
- Task type TaskTypePartnumberBookCreate; handlers ListPartnumberBooks
  and CreatePartnumberBook; routes GET/POST /api/admin/pricing/partnumber-books
- UI: snapshot list + "Создать снапшот сопоставлений" button with
  progress polling on /vendor-mappings page
- Bible: history, api, background-tasks, vendor-mapping updated

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 22:16:16 +03:00
Mikhail Chusavitin
225e1beda9 Fix pricelist generation logic 2026-02-20 19:13:34 +03:00
Mikhail Chusavitin
c96a8806c4 Harden pricelist formation and document architecture decisions 2026-02-20 19:01:07 +03:00
Mikhail Chusavitin
d381a5833d Require bible updates before user-requested commits 2026-02-20 15:38:12 +03:00
Mikhail Chusavitin
60563509e4 Deduplicate vendor seen by partnumber and fix vendor mappings list 2026-02-20 15:37:41 +03:00
Mikhail Chusavitin
7d402b756d docs: add bible/ as single source of architectural truth
- Created bible/ with hierarchical documentation (architecture, pricelists,
  vendor mapping, background tasks, data rules, patterns, API, operations, history)
- CLAUDE.md reduced to one instruction: read and follow the bible
- README.md reduced to quick start only
- Removed MEMORY.md and csv_export.md (content consolidated into bible/)
- Fixed stale facts found during audit: weighted_avg (not weighted_median),
  correct API route names (/export-csv, /recalculate-all)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-20 14:16:47 +03:00
Mikhail Chusavitin
c22328bf03 Implement global vendor mappings with bundle support and seen-based ignore 2026-02-18 19:54:07 +03:00
Mikhail Chusavitin
b94dd3d015 warehouse: switch stock pricing to weighted_avg 2026-02-18 19:45:32 +03:00
Mikhail Chusavitin
9eb573ca90 Restore lot mappings tools and ignore rules 2026-02-18 11:03:10 +03:00
Mikhail Chusavitin
221e414e2f Default lot category to PART_ when missing 2026-02-18 10:32:51 +03:00
Mikhail Chusavitin
0827c501df Update lot recalc flow 2026-02-18 10:32:36 +03:00
Mikhail Chusavitin
d55f484616 Update admin pricing recalc flow 2026-02-18 10:32:13 +03:00
Mikhail Chusavitin
50d1e281a5 Update pricing handler counts and defaults 2026-02-18 10:31:35 +03:00
Mikhail Chusavitin
c939ce18ad Merge origin/main 2026-02-18 10:12:07 +03:00
985e64d1b5 chore: apply pending changes 2026-02-18 07:01:49 +03:00
f64c4fd6b2 feat: optimize background tasks and fix warehouse pricelist workflow
Optimize task retention from 5 minutes to 30 seconds to reduce polling overhead since toast notifications are shown only once. Add conditional warehouse pricelist creation via checkbox. Fix category storage in warehouse pricelists to properly load from lot table. Replace SSE with task polling for all long operations. Add comprehensive logging for debugging while minimizing noise from polling endpoints.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-16 11:08:10 +03:00
Mikhail Chusavitin
c8ad43677d refactor: separate LOT management to dedicated page
- Create new /lot page with two tabs:
  1. LOT: component management (formerly in /admin/pricing)
  2. Сопоставления: partnumber ↔ LOT mappings (formerly in Warehouse tab)
- Remove LOT tab from Pricing Admin page
- Remove stock mappings section from Warehouse tab
- Update main menu: LOT link now points to /lot
- Default tab in Pricing Admin changed to Estimate
- Add Lot() handler in web.go
- Add /lot route in main.go

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-02-10 16:13:04 +03:00
Mikhail Chusavitin
9b07262514 chore: remove compiled binary from tracking 2026-02-10 15:25:35 +03:00
Mikhail Chusavitin
70bcb428cc fix: handle MySQL 'Cannot change column' error in migrations
Added handling for Error 1833 (Cannot change column used in foreign key)
in the auto-migration process. This allows migrations to skip gracefully
when encountering columns that cannot be modified due to existing
foreign key constraints from other databases.

The Configuration model has a uuid column that's referenced by a foreign
key in RFQ_LOG.qt_configurations, preventing GORM from modifying it
during auto-migration. Now this error is caught and skipped like other
constraint-related errors.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-02-10 15:25:17 +03:00
Mikhail Chusavitin
c47c93ab31 fix: потоковая отправка прогресса создания прайслиста и исправление маппинга колонки категории
Две ключевые исправления:

1. Потоковая отправка прогресса создания (SSE):
   - Эндпоинт CreateWithProgress теперь отправляет Server-Sent Events
     вместо возврата JSON с task_id
   - Полирует статус задачи и отправляет обновления прогресса в реальном времени
   - Отправляет финальное событие с данными прайслиста или ошибкой
   - Фронтенд уже ожидал этого формата SSE

2. Исправление маппинга колонки lot_category:
   - Добавлен явный тег column в поле Category модели PricelistItem
     чтобы маппиться на колонку 'lot_category' в БД
   - Категория теперь хранится как снимок в таблице pricelist_items
   - Обновлены запросы репозитория для использования сохраненной
     категории вместо динамических JOIN с таблицей lot

Это исправляет ошибки:
- "Создание прервано: не получен результат" (фронтенд ожидал streaming)
- "Unknown column 'category' in 'INSERT INTO'" (несоответствие схемы БД)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-02-10 15:17:16 +03:00
c9f7f4e908 release binary 2026-02-08 21:39:59 +03:00
7d671203d7 feat: add timeout utility for database operations
Added a new timeout utility file to help manage database operation timeouts more effectively.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 21:31:41 +03:00
e97cd5048c feat: implement background task system with notifications
- Added background task manager with goroutine execution and panic recovery
- Replaced SSE streaming with background task execution for:
  * Price recalculation (RecalculateAll)
  * Stock import (ImportStockLog)
  * Pricelist creation (CreateWithProgress)
- Implemented unified polling for task status and DB connection in frontend
- Added task indicator in top bar showing running tasks count
- Added toast notifications for task completion/error
- Tasks automatically cleaned up after 10 minutes
- Tasks show progress (0-100%) with descriptive messages
- Updated handler constructors to receive task manager
- Added API endpoints for task status (/api/tasks, /api/tasks/:id)

Fixes issue with SSE disconnection on slow connections during long-running operations
2026-02-08 20:39:59 +03:00
06aa7c7067 docs: add CSV export pattern documentation
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 13:14:12 +03:00
9bc01831c9 feat: add pricelist CSV export and improve description display
- Add CSV export functionality for pricelists with download button
- Export includes all pricelist items with proper UTF-8 encoding
- Support both warehouse and estimate pricelist sources
- Remove description column from admin pricing tables
- Show description as tooltip on row hover instead
- Improve table layout by removing redundant column

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 12:26:45 +03:00
ed339a172b fix: prevent duplicate partnumbers in stock mappings table
Add duplicate detection before batch insert of auto-mappings:
- Query existing partnumbers from lot_partnumbers table
- Build case-insensitive set of existing entries
- Filter out duplicates before CreateInBatches
- Also prevent duplicates within single batch

This ensures partnumber uniqueness as primary key requires.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 11:58:13 +03:00
85062e007c feat: add LOT creation, auto-save mappings, disable auto warehouse pricelist
- Add LOT creation functionality in pricing admin
  - New API endpoint POST /api/admin/pricing/lots
  - Modal form for creating new LOT with auto-category detection
  - Creates entries in both lot and qt_lot_metadata tables

- Implement auto-save for stock mappings
  - Auto-save on change for partnumber → LOT mappings
  - Visual feedback (orange during save, green on success, red on error)
  - Works in both main mappings table and import suggestions

- Improve stock import suggestions UI
  - Remove "Причина" column from suggestions table
  - Increase LOT and Partnumber column widths to 33% each
  - Better visual balance in the table layout

- Disable automatic warehouse pricelist creation on stock_log import
  - Import now completes at 100% after stock_log update
  - Manual pricelist creation available via UI when needed
  - Faster import process without auto-generation overhead

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-08 11:34:43 +03:00
319400106c Restore connection settings modal from top nav 2026-02-08 10:54:31 +03:00
8fbdcb1d86 docs: remove obsolete integration and migration notes 2026-02-08 09:01:59 +03:00
d8954c411c lincense initial commit 2026-02-08 08:57:52 +03:00