feat: world-прайслист как заглушка для отсутствующих цен
Там, где для LOT нет цены в estimate/warehouse/competitor, подставляется цена из world-прайслиста. Такие ячейки в таблицах «Цена покупки»/«Цена продажи» подсвечиваются (amber), участвуют в «Итого» и убирают красную «*». В CSV-экспорте добавлена колонка «Заглушка (world)» с перечнем столбцов, где сработал фолбэк. Добавлены Tx-версии GetLatestLocalPricelistBySource/GetLocalPricesForLots, чтобы резолв прайслистов внутри транзакции не дедлочил single-connection пул. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
498cbf5490
commit
70a3ff255f
@@ -1351,8 +1351,17 @@ func (l *LocalDB) GetLatestLocalPricelist() (*LocalPricelist, error) {
|
||||
|
||||
// GetLatestLocalPricelistBySource returns the most recently synced active pricelist for a source.
|
||||
func (l *LocalDB) GetLatestLocalPricelistBySource(source string) (*LocalPricelist, error) {
|
||||
return GetLatestLocalPricelistBySourceTx(l.db, source)
|
||||
}
|
||||
|
||||
// GetLatestLocalPricelistBySourceTx is the transaction-scoped variant of
|
||||
// GetLatestLocalPricelistBySource. Callers already inside an l.db.Transaction(...) callback
|
||||
// must use this with the given tx instead of the method above — the connection pool has a
|
||||
// single connection (see New()), so querying via l.db while the transaction holds that
|
||||
// connection deadlocks forever.
|
||||
func GetLatestLocalPricelistBySourceTx(tx *gorm.DB, source string) (*LocalPricelist, error) {
|
||||
var pricelist LocalPricelist
|
||||
if err := l.db.
|
||||
if err := tx.
|
||||
Where("source = ? AND is_active = ?", source, true).
|
||||
Where("EXISTS (SELECT 1 FROM local_pricelist_items WHERE local_pricelist_items.pricelist_id = local_pricelists.id)").
|
||||
Order("created_at DESC, id DESC").
|
||||
@@ -1545,6 +1554,13 @@ func (l *LocalDB) GetLocalPriceForLot(pricelistID uint, lotName string) (float64
|
||||
// legacy rows that were stored in mixed case before normalization was enforced at sync time.
|
||||
// Keys in the returned map are uppercased (matching the input lotNames).
|
||||
func (l *LocalDB) GetLocalPricesForLots(pricelistID uint, lotNames []string) (map[string]float64, error) {
|
||||
return GetLocalPricesForLotsTx(l.db, pricelistID, lotNames)
|
||||
}
|
||||
|
||||
// GetLocalPricesForLotsTx is the transaction-scoped variant of GetLocalPricesForLots. See
|
||||
// GetLatestLocalPricelistBySourceTx for why callers inside an l.db.Transaction(...) callback
|
||||
// must use this with the given tx instead of the method above.
|
||||
func GetLocalPricesForLotsTx(tx *gorm.DB, pricelistID uint, lotNames []string) (map[string]float64, error) {
|
||||
result := make(map[string]float64, len(lotNames))
|
||||
if len(lotNames) == 0 {
|
||||
return result, nil
|
||||
@@ -1556,7 +1572,7 @@ func (l *LocalDB) GetLocalPricesForLots(pricelistID uint, lotNames []string) (ma
|
||||
}
|
||||
var rows []row
|
||||
// Use UPPER(lot_name) so rows synced before normalization (mixed-case) are still matched.
|
||||
if err := l.db.Model(&LocalPricelistItem{}).
|
||||
if err := tx.Model(&LocalPricelistItem{}).
|
||||
Select("lot_name, price").
|
||||
Where("pricelist_id = ? AND UPPER(lot_name) IN ?", pricelistID, lotNames).
|
||||
Find(&rows).Error; err != nil {
|
||||
|
||||
Reference in New Issue
Block a user