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:
co-authored by
Claude Sonnet 5
parent
7edb80e498
commit
39e6fd5642
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user