feat: вкладка Аренда — колонки Estimate/Цена продажи; lot_description для прайслистов

Вкладка «Аренда»: добавлены колонки Estimate и Цена продажи (+ итоги),
чекбокс «БУ» перенесён первым слева, таблица переведена на тот же
разметку/классы, что и таблицы вкладки «Ценообразование».

Прайслисты: local_pricelist_items получает lot_description (синхронизируется
из qt_pricelist_items.lot_description) вместо устаревших available_qty/
partnumbers, которые нигде не заполнялись.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Mikhail Chusavitin
2026-07-22 15:11:06 +03:00
co-authored by Claude Sonnet 5
parent 7edb80e498
commit 39e6fd5642
15 changed files with 236 additions and 130 deletions
+92
View File
@@ -129,6 +129,98 @@ var localMigrations = []localMigration{
name: "Add rental_enabled to local_projects",
run: addLocalProjectRentalEnabled,
},
{
id: "2026_07_22_pricelist_items_price_settings",
name: "Add lot_description and price settings columns to local_pricelist_items, drop unused available_qty/partnumbers",
run: addPricelistItemDescriptionAndPriceSettings,
},
}
func addPricelistItemDescriptionAndPriceSettings(tx *gorm.DB) error {
type columnInfo struct {
Name string `gorm:"column:name"`
}
var columns []columnInfo
if err := tx.Raw(`
SELECT name FROM pragma_table_info('local_pricelist_items')
WHERE name IN ('lot_description', 'price_method', 'price_period_days', 'price_coefficient', 'manual_price', 'meta_prices', 'available_qty', 'partnumbers')
`).Scan(&columns).Error; err != nil {
return fmt.Errorf("check local_pricelist_items columns: %w", err)
}
have := make(map[string]bool, len(columns))
for _, c := range columns {
have[c.Name] = true
}
if have["lot_description"] && have["price_method"] && have["price_period_days"] &&
have["price_coefficient"] && have["manual_price"] && have["meta_prices"] &&
!have["available_qty"] && !have["partnumbers"] {
slog.Info("local_pricelist_items already migrated to description/price-settings schema")
return nil
}
// SQLite: recreate table without the never-populated available_qty/partnumbers
// columns, adding lot_description and the price settings columns synced from
// qt_pricelist_items (needed to render the pricelist detail UI correctly).
if err := tx.Exec(`
CREATE TABLE local_pricelist_items_new (
id INTEGER PRIMARY KEY AUTOINCREMENT,
pricelist_id INTEGER NOT NULL,
lot_name TEXT NOT NULL,
lot_category TEXT,
lot_description TEXT,
price REAL NOT NULL,
price_method TEXT,
price_period_days INTEGER DEFAULT 90,
price_coefficient REAL DEFAULT 0,
manual_price REAL,
meta_prices TEXT
)
`).Error; err != nil {
return fmt.Errorf("create new local_pricelist_items table: %w", err)
}
if err := tx.Exec(`
INSERT INTO local_pricelist_items_new (id, pricelist_id, lot_name, lot_category, price)
SELECT id, pricelist_id, lot_name, lot_category, price
FROM local_pricelist_items
`).Error; err != nil {
return fmt.Errorf("copy data to new local_pricelist_items table: %w", err)
}
if err := tx.Exec(`DROP TABLE local_pricelist_items`).Error; err != nil {
return fmt.Errorf("drop old local_pricelist_items table: %w", err)
}
if err := tx.Exec(`ALTER TABLE local_pricelist_items_new RENAME TO local_pricelist_items`).Error; err != nil {
return fmt.Errorf("rename new local_pricelist_items table: %w", err)
}
if err := tx.Exec(`
CREATE INDEX IF NOT EXISTS idx_local_pricelist_items_pricelist_lot
ON local_pricelist_items(pricelist_id, lot_name)
`).Error; err != nil {
return fmt.Errorf("recreate idx_local_pricelist_items_pricelist_lot: %w", err)
}
if err := tx.Exec(`
CREATE UNIQUE INDEX IF NOT EXISTS idx_local_pricelist_items_pricelist_lot_unique
ON local_pricelist_items(pricelist_id, lot_name)
`).Error; err != nil {
return fmt.Errorf("recreate unique index on local_pricelist_items: %w", err)
}
if err := tx.Exec(`
CREATE INDEX IF NOT EXISTS idx_local_pricelist_items_lot_category
ON local_pricelist_items(lot_category)
`).Error; err != nil {
return fmt.Errorf("recreate idx_local_pricelist_items_lot_category: %w", err)
}
slog.Info("added lot_description/price settings columns to local_pricelist_items and dropped available_qty/partnumbers")
return nil
}
func addLocalProjectRentalEnabled(tx *gorm.DB) error {