Имя: Пароль:
1C
1C 7.7
v7: ТиС 9.2, глВернутьЦену() - не въезжаю по коду в глубокий смысл написанного
,
0 Злопчинский
 
27.11.19
08:39
//******************************************************************************
// глВернутьЦену(Номенклатура, ТипЦены, ДатаЦены, ЦенаЦены, ЕдЦены, ВалЦены, НаценкаЦены, НайденнаяЦена)
//
// Параметры:
//  Номенклатура  - элемент справочника "Номенклатура"
//  ТипЦены       - элемент справочника "ТипыЦен"
//  ДатаЦены      - дата, на которую надо получить цену
//  ЦенаЦены      - переменная, которую надо заполнитиь значением (число) полученной цены
//  ЕдЦены        - переменная, которую надо заполнитиь значением
//                  (элемент справочника Единицы) единицы, за которую дается цена
//  ВалЦены       - переменная, которую надо заполнитиь значением валюты, в которой выражена цена
//  НайденнаяЦена - переменная, которую надо заполнить найденным элементом справочника цен
//
// Возвращаемое значение:
//  1 - если есть такая цена, пераметры цены заполнены
//  0 - нет такой цены
// -1 - есть только цены, помеченные на удаление
//
// Описание:
//  Формирует ценовые характеристики номенклатурной единицы по заданному типу цен.
//
Функция глВернутьЦену(Номенклатура, ТипЦены, ДатаЦены = 0, ЦенаЦены = 0, ЕдЦены = 0, ВалЦены = 0, НаценкаЦены = 0, НайденнаяЦена = 0) Экспорт
    Перем ЦеныНоменклатуры;
    Перем Рассчетная;
    Перем НужныйТипЦен;
    Перем ЕстьУдаленные;
    
    Рез = 1;
    НайденнаяЦена = ПолучитьПустоеЗначение("Справочник.Цены");
    
    Если ПустоеЗначение(ДатаЦены) = 1 Тогда
        ДатаЦены = РабочаяДата();
    КонецЕсли;

    // Найдет или нужную цену в справочнике
    // если она рассчитывается, то найдем базовую цену
    Рассчетная        = ТипЦены.Рассчитывается;
    НужныйТипЦен    = ?(ПустоеЗначение(Рассчетная) = 1, ТипЦены, ТипЦены.БазовыйТипЦен);
    
    ЦеныНоменклатуры= СоздатьОбъект("Справочник.Цены");
    ЦеныНоменклатуры.ИспользоватьВладельца(Номенклатура);
    ЦеныНоменклатуры.ВыбратьЭлементы();
    
    Пока ЦеныНоменклатуры.ПолучитьЭлемент()  = 1 Цикл    
        Если ЦеныНоменклатуры.ТипЦен <> НужныйТипЦен Тогда
            Продолжить;
        КонецЕсли;
        

        // КТ1 === ??? =======
        НайденнаяЦена = ЦеныНоменклатуры.ТекущийЭлемент();
        
        Если ЦеныНоменклатуры.ПометкаУдаления() = 1 Тогда
            Рез = - 1; // Цена есть, но помечена на удаление
            Продолжить; // КТ2 === ВОТ ЗДЕСЬ КАКОЙ ГЛУБОКИЙ СМЫСЛ. почему не ПРЕРВАТЬ ..? =======
        Иначе
            Прервать;
        КонецЕсли;
        
    КонецЦикла;      
    
    Если ПустоеЗначение(НайденнаяЦена) = 1 Тогда
        
        // Нет такой цены
        Возврат 0;
    КонецЕсли;
    
    // Заполним все ценовые характериситики
    
    // если не задана единица цены на эту дату, то потом придется обрабатывать случай нулевого коэффициента у  пустой единицы
    ЕдЦены        = НайденнаяЦена.Единица.Получить(ДатаЦены);
    
    Если ПустоеЗначение(Рассчетная) = 1 Тогда
        
        //Если цена не рассчитывается
        ЦенаЦены    = НайденнаяЦена.Цена.Получить(ДатаЦены);
        
        // элемент справочника существует Валюту и Наценку возьмем из него
        ВалЦены        = НайденнаяЦена.Валюта;
        НаценкаЦены    = НайденнаяЦена.Процент;
    Иначе
        
        //Если цена рассчитывается
        БазоваяЦена     = НайденнаяЦена.Цена.Получить(ДатаЦены);
        БазоваяВалюта    = НайденнаяЦена.Валюта;
        
        // Цены у базового типа могут отличаться
        ЦенаЦены    = глПересчет(БазоваяЦена, БазоваяВалюта, ДатаЦены, ТипЦены.Валюта, ДатаЦены);
        ЦенаЦены    = глОкруглить(ЦенаЦены * (100 + ТипЦены.Процент) / 100, ТипЦены.ПорядокОкругления);
        
        // элемент справочника Цены не существует (расчетный). Валюту и Наценку возьмем из типа цены
        ВалЦены        = ТипЦены.Валюта;
        НаценкаЦены    = ТипЦены.Процент;
    КонецЕсли;
    
    Возврат Рез;
КонецФункции // глВернутьЦену()
1 Kigo_Kigo
 
27.11.19
08:42
А что не понятного то?
2 Злопчинский
 
27.11.19
08:43
сек, пишу...
3 Kigo_Kigo
 
27.11.19
08:44
Потому что может быть другой такой же тип цен, не помеченный на удаление иначе прервать
4 Кодер
 
27.11.19
08:45
Дальше по коду отлови ситуацию, когда на твоих данных цена всё же получена, и запиши (в ЖР, мыло, в крайнем случае сообщением пользователю - только дойдёт несколько % таких сообщений) себе этот случай.
5 Злопчинский
 
27.11.19
08:46
1. допустим, что вот так вот получилось что в Спр.Цены "задвоены" записи для ТипЦены, первая запись помечена на удаление, вторая - норм.
получится что через _параметры_ вернет норм.цену (для второй записи), а как результат функции вернет -1 (для первой записи) - НЕХОРОШО.

2. допустим, что вот так вот получилось что в Спр.Цены "задвоены" записи для ТипЦены, первая запись норм, вторая - помечена на удаление.
получится что через _параметры_ вернет норм.цену (для первой записи), а как результат функции вернет 1 (для первой записи) - хорошо.
6 Kigo_Kigo
 
27.11.19
08:47
Может быть 2 цены - тип - розничная, если одна помеченна на удаление - тоищем дальше, до первого вхождения не помеченной
7 Злопчинский
 
27.11.19
08:47
По идее в КТ1 надо поставить
Рез = 1;

????
8 Злопчинский
 
27.11.19
08:48
(6) кривой результат будет, сп. п.5.1
9 Kigo_Kigo
 
27.11.19
08:49
(5) п.1 вернет "-1" если не найдет НЕ помеченную на уделения цену, найдет вернет 1
п.2 до втрой не дойдет, потому что там прервать!
10 Sserj
 
27.11.19
08:51
Смысл в том что это то что обычно называется "овнокод" :)
Функция возвращает цену побочным эффектом в передваемый параметр ЦенаЦены. А сам результат функции якобы используется для каких то проверок.
11 Kigo_Kigo
 
27.11.19
08:54
Но вот здесь я вижу вот так
Если ЦеныНоменклатуры.ПометкаУдаления() = 1 Тогда
            Рез = - 1; // Цена есть, но помечена на удаление
            Продолжить; // КТ2 === ВОТ ЗДЕСЬ КАКОЙ ГЛУБОКИЙ СМЫСЛ. почему не ПРЕРВАТЬ ..? =======
        Иначе
            Рез = 1;// переприсвоить результат после помеченой на удаление
            Прервать;
        КонецЕсли;
12 Kigo_Kigo
 
27.11.19
08:59
(10) Кроме ЦенаЦены, она еще возвращает ссылку на подчиненный справочник цены подчиненный номенклатуре по типу цены со всеми его атрибутами
13 Злопчинский
 
27.11.19
09:01
(12) это несущественно сейчас
14 Sserj
 
27.11.19
09:01
(12) Так вот и нужно смотреть контекст вызова этой функции. Она видимо может вызываться
когда в любом случае нужно получить актуальную цену или это контекст где проверяется
что цена с требуемым типом помечена на удаление.
15 Злопчинский
 
27.11.19
09:01
(9) кто-то из нас тупит.
по 5.1 - если НАЙДЕТ удаленую - вернет -1, при этом параметрами вернет ПРО НЕУДАЛЕННУЮ
16 Kigo_Kigo
 
27.11.19
09:03
(15) Читай (11)
17 Kigo_Kigo
 
27.11.19
09:03
проеп 1с кодеров однозначно
18 Kigo_Kigo
 
27.11.19
09:04
но кстати такие ситуации крайне редки ИМХО, по крайней мере у меня такого не было
19 Злопчинский
 
27.11.19
09:05
(16) ну да так тоже можно
20 Злопчинский
 
27.11.19
09:07
(18) ну, у меня тоже не было, бо штатно такой ситуации с задвоением хрен получишь (урбд нет), но потенциально - можно
21 Злопчинский
 
27.11.19
09:07
(17) то есть согласен что диагноз я поставил верно?
22 Kigo_Kigo
 
27.11.19
09:08
(21) да, согласен
23 Злопчинский
 
27.11.19
09:12
(22) ок
24 Злопчинский
 
27.11.19
09:14
Есть в типовой еще один косяк, он достаточно тяжелый, приводит к неявным труднообнаруживаемым пересортам, но проявляется когда включена партионока, в партиях задаются свойства (например, цвет) и по продаже идет ВозвратОтПокупателя - могут пересортиться на остатках, возвращают допустим красный цвет, а на остатки ляжет синий...
25 Галахад
 
гуру
27.11.19
09:17
Гм. А занимательно читать записки археологов. :-)
26 Злопчинский
 
27.11.19
09:23
(25) Без знания прошлого - нет будущего! что мы и видим в тупиковом развитии 8-ки ;-)
27 VladZ
 
27.11.19
10:36
Мы в свое время оптимизировали эту функцию.
Делали отбор по реквизиту "Тип цен"

и в коде

ЦеныНоменклатуры.ИспользоватьВладельца(Номенклатура);
ЦеныНоменклатуры.ВыбратьЭлементы();

добавляли выборку по реквизиту "Тип цены".
В базах данных с большим количеством типов цен это значительно повышало производительность.
28 Злопчинский
 
27.11.19
10:41
Если принять что для помеченых на удаление цен (элементов СПр.Цены) числовое значение цены должно трактоваться как 0(ноль) - т.е. цены нет - то все правик сводятся к трем операторам в функции глВернутьЦену.
.
Прошерстил глоб.модуль и конфигу (974 релиз) - более никаких доработок по коду не требуется, все остается работоспособным "автоматом".
.
Типа вот так получается, тестирвоание на юзверях покажет ;-)
.
//******************************************************************************
//[*]progadmin, 27.11.2019, НЕТИПОВОЕ
//// глВернутьЦену(Номенклатура, ТипЦены, ДатаЦены, ЦенаЦены, ЕдЦены, ВалЦены, НаценкаЦены, НайденнаяЦена)
// -------------
// глВернутьЦену(Номенклатура, ТипЦены, ДатаЦены, ЦенаЦены, ЕдЦены, ВалЦены, НаценкаЦены, НайденнаяЦена, ВозвращатьУдаленнуюЦенаЦены)
// Параметры:
//  ВозвращатьУдаленнуюЦенаЦены - 0/1, если для удаленных цен значение ЦенаЦены считается незаданным/заданным (0/1 соответственно)
//[*]_progadmin, 27.11.2019, НЕТИПОВОЕ
//
// Параметры:
//  Номенклатура  - элемент справочника "Номенклатура"
//  ТипЦены       - элемент справочника "ТипыЦен"
//  ДатаЦены      - дата, на которую надо получить цену
//  ЦенаЦены      - переменная, которую надо заполнитиь значением (число) полученной цены
//  ЕдЦены        - переменная, которую надо заполнитиь значением
//                  (элемент справочника Единицы) единицы, за которую дается цена
//  ВалЦены       - переменная, которую надо заполнитиь значением валюты, в которой выражена цена
//  НайденнаяЦена - переменная, которую надо заполнить найденным элементом справочника цен
//
// Возвращаемое значение:
//  1 - если есть такая цена, пераметры цены заполнены
//  0 - нет такой цены
// -1 - есть только цены, помеченные на удаление
//
// Описание:
//  Формирует ценовые характеристики номенклатурной единицы по заданному типу цен.
//
//[*]progadmin, 27.11.2019, НЕТИПОВОЕ
//Функция глВернутьЦену(Номенклатура, ТипЦены, ДатаЦены = 0, ЦенаЦены = 0, ЕдЦены = 0, ВалЦены = 0, НаценкаЦены = 0, НайденнаяЦена = 0) Экспорт
// -------------
Функция глВернутьЦену(Номенклатура, ТипЦены, ДатаЦены = 0, ЦенаЦены = 0, ЕдЦены = 0, ВалЦены = 0, НаценкаЦены = 0, НайденнаяЦена = 0, ВозвращатьУдаленнуюЦенаЦены=0) Экспорт
//[*]_progadmin, 27.11.2019, НЕТИПОВОЕ
    Перем ЦеныНоменклатуры;
    Перем Рассчетная;
    Перем НужныйТипЦен;
    Перем ЕстьУдаленные;
    
    
    Рез = 1;
    НайденнаяЦена = ПолучитьПустоеЗначение("Справочник.Цены");
    
    Если ПустоеЗначение(ДатаЦены) = 1 Тогда
        ДатаЦены = РабочаяДата();
    КонецЕсли;

    // Найдет или нужную цену в справочнике
    // если она рассчитывается, то найдем базовую цену
    Рассчетная        = ТипЦены.Рассчитывается;
    НужныйТипЦен    = ?(ПустоеЗначение(Рассчетная) = 1, ТипЦены, ТипЦены.БазовыйТипЦен);
    
    ЦеныНоменклатуры= СоздатьОбъект("Справочник.Цены");
    ЦеныНоменклатуры.ИспользоватьВладельца(Номенклатура);
    ЦеныНоменклатуры.ВыбратьЭлементы();
    
    Пока ЦеныНоменклатуры.ПолучитьЭлемент()  = 1 Цикл    
        Если ЦеныНоменклатуры.ТипЦен <> НужныйТипЦен Тогда
            Продолжить;
        КонецЕсли;
        
        НайденнаяЦена = ЦеныНоменклатуры.ТекущийЭлемент();
        
        Если ЦеныНоменклатуры.ПометкаУдаления() = 1 Тогда
            Рез = - 1; // Цена есть, но помечена на удаление
            Продолжить;
        Иначе
            Рез = 1; //[+]progadmin, 27.11.2019, НЕТИПОВОЕ, косяк писателей типовых
            Прервать;
        КонецЕсли;
        
    КонецЦикла;      
    
    Если ПустоеЗначение(НайденнаяЦена) = 1 Тогда
        
        // Нет такой цены
        Возврат 0;
    КонецЕсли;
    
    Множитель = ?(Рез=-1,ВозвращатьУдаленнуюЦенаЦены,1); //[+]progadmin, 27.11.2019, НЕТИПОВОЕ
    
    // Заполним все ценовые характериситики
    
    // если не задана единица цены на эту дату, то потом придется обрабатывать случай нулевого коэффициента у  пустой единицы
    ЕдЦены        = НайденнаяЦена.Единица.Получить(ДатаЦены);
    
    Если ПустоеЗначение(Рассчетная) = 1 Тогда
        
        //Если цена не рассчитывается
        ЦенаЦены    = НайденнаяЦена.Цена.Получить(ДатаЦены);
        
        // элемент справочника существует Валюту и Наценку возьмем из него
        ВалЦены        = НайденнаяЦена.Валюта;
        НаценкаЦены    = НайденнаяЦена.Процент;
    Иначе
        
        //Если цена рассчитывается
        БазоваяЦена     = НайденнаяЦена.Цена.Получить(ДатаЦены);
        БазоваяВалюта    = НайденнаяЦена.Валюта;
        
        // Цены у базового типа могут отличаться
        ЦенаЦены    = глПересчет(БазоваяЦена, БазоваяВалюта, ДатаЦены, ТипЦены.Валюта, ДатаЦены);
        ЦенаЦены    = глОкруглить(ЦенаЦены * (100 + ТипЦены.Процент) / 100, ТипЦены.ПорядокОкругления);
        
        // элемент справочника Цены не существует (расчетный). Валюту и Наценку возьмем из типа цены
        ВалЦены        = ТипЦены.Валюта;
        НаценкаЦены    = ТипЦены.Процент;
    КонецЕсли;
    
    ЦенаЦены = ЦенаЦены * Множитель; //[+]progadmin, 27.11.2019, НЕТИПОВОЕ
    Возврат Рез;
КонецФункции // глВернутьЦену()
29 Злопчинский
 
27.11.19
10:45
(27) ага, спсб.
я где-то тоже так делал,

ЦеныНоменклатуры.ИспользоватьВладельца(Номенклатура);
ЦеныНоменклатуры.ВыбратьЭлементыПоРеквизиту(....); //здеся...

в 974 релизе (клиентовском) Сортировка=1 и Отбор=1 (не знаю штатно или нет это)
30 Злопчинский
 
27.11.19
10:46
для ВыбратьПоРеквизиту() достаточно Сортировка=1
Отбор=1 - он для интерактивных отборов работает только.
31 Злопчинский
 
27.11.19
10:49
И раз уже про глВернутьЦену() - то вот тоже еще полезняшка
http://catalog.mista.ru/public/76287/ - ускорение для конструкций типа Цикл ГлВернутьЦену() КОнецЦикла;
32 Djelf
 
27.11.19
10:50
(28) Ээээ....
Если ЦеныНоменклатуры.ПометкаУдаления() = 1 Тогда Продолжить;
с учетом твоего ВозвращатьУдаленнуюЦенаЦены должно быть
Если ВозвращатьУдаленнуюЦенаЦены = 1 Тогда Прервать;
ИначеЕсли ЦеныНоменклатуры.ПометкаУдаления() = 1 Тогда Продолжить;
33 Злопчинский
 
27.11.19
10:52
И, наверное, можно еще так сказать:
в спр.Цены - помечать на удаление имеет смысл только если цены надо удалить кардинально с концами. если история нужна, то лучше оставлять цену "живой", но значение цены _на нужную_ (_с нужной даты_) ставить = 0
34 Злопчинский
 
27.11.19
10:53
вот, ух блин, работун страшный напал
35 Злопчинский
 
27.11.19
10:56
(32) не въехал (целый код давай ;-), бошка не варит уже после ночи.
мои исправления вроде все правильно должны дать (может и не оптимально).
36 Kigo_Kigo
 
27.11.19
10:57
(32) Я честно не пнял замысел Злопа в этом кодинке, смысл этого всего
Есть не помеченная на удаления цена(совместно с помеченной) возвращаем не помеченную
нет, возвращаем помеченную но с результатом "-1" далее в коде уже анализируем
Если глВернутьЦену(трататата) = , тут уже варианты 0 -нет такой цены для переанного типацен, 1 есть цена, -1 естьцена но помечена на удаление, вот и вся арифметика
37 Kigo_Kigo
 
27.11.19
10:58
(35) Твои исправления дадут отрицательную цену, вопрос, зачем?
38 Kigo_Kigo
 
27.11.19
10:58
ЦенаЦены = ЦенаЦены * Множитель;//[+]progadmin, 27.11.2019, НЕТИПОВОЕ
39 Djelf
 
27.11.19
11:00
(35) Да вот же

Пока ЦеныНоменклатуры.ПолучитьЭлемент()  = 1 Цикл    
        Если ЦеныНоменклатуры.ТипЦен <> НужныйТипЦен Тогда
            Продолжить;
        КонецЕсли;
        
        НайденнаяЦена = ЦеныНоменклатуры.ТекущийЭлемент();
        
        // Если ЦеныНоменклатуры.ПометкаУдаления() = 1 Тогда // ВозвращатьУдаленнуюЦенаЦены  не сработает
        //    Рез = - 1;// Цена есть, но помечена на удаление
        //    Продолжить;
        Если ВозвращатьУдаленнуюЦенаЦены = 1 Тогда
             Прервать;
        ИначеЕсли ЦеныНоменклатуры.ПометкаУдаления() = 1 Тогда
             Продолжить;

40 Злопчинский
 
27.11.19
11:03
(39) я подумаю.
41 Kigo_Kigo
 
27.11.19
11:04
(39) Так вы лишаете себя найти не удаленную цену, нахуя?
42 Злопчинский
 
27.11.19
11:06
а все почему: начал блок производства тихонька впиливать.
Печать техкарт с полным разузлованием (так это называется?) для расчета плановой себестоимости изделия (кузяво получается, из карточки номенклатуры, из комплектации или из документов заявкапокупателя/реализация).

ну и наткнулся... чувствую, что где-то криво...
43 Kigo_Kigo
 
27.11.19
11:07
ВозвращатьУдаленнуюЦенаЦены
Вообще эта врезка нахер не нужна
44 pechkin
 
27.11.19
11:08
по хорошему не нужно останавдиваться когда нашел свой тип цен.
но это утормозит вс процедуру.
поэтому на дубли просто забили
45 Kigo_Kigo
 
27.11.19
11:23
(44) Ну если уж получать саму актульную цену из набора одинаковых типов цен для номенклатры, то тут уже через "переодический" кмк оптимальнее лезть
46 Arbuz
 
27.11.19
15:20
мда... заменил

    //ЦеныНоменклатуры.ВыбратьЭлементы();
    //
    //Пока ЦеныНоменклатуры.ПолучитьЭлемент()  = 1 Цикл    
    //    Если ЦеныНоменклатуры.ТипЦен <> НужныйТипЦен Тогда
    //        Продолжить;
    //    КонецЕсли;
    // -------------
    ЦеныНоменклатуры.ВыбратьЭлементыПоРеквизиту("ТипЦен", НужныйТипЦен,, 0);

и вынес из функции

глПустаяЦена = ПустоеЗначение("Справочник.Цены");
глСпрЦены = СоздатьОбъект("Справочник.Цены");

получил почти 25% ускорения на функции глВернутьЦену, неплохо
47 Злопчинский
 
27.11.19
16:21
(46) ну, это критично на больших массивах вызовов глВернутьЦену, штатно таких глобальных потоковых глвернутьцену - разве что в отчете по опстаткам со столбиком цены.

а так, я давно обрабатывал (без прямых запросов) приличные массивы истории изменения нескольких цен. там использование объекта "Периодический" само по себе дает до 25% выигрыша по скорости
48 Кодер
 
27.11.19
17:49
Всё не читал, если туплю - прошу извинить.
Добавлял одну константу и одну ТЗ. ПриНачалеСистемы заполнял ТЗ текущими ценами и устанавливал флажок "брать цены из ТЗ". В 1с++, наверное, можно индексированную ТЗ.

Соответственно для быстрого получения цены смотрел на флаг, если он взведён - брал из ТЗ, это не дёргало БД, т.к. ТЗ была в ОЗУ.
49 Злопчинский
 
27.11.19
18:45
(48) а как актуализировал ТЗ при изменении цен в базе?
50 Duke1C
 
27.11.19
19:05
(49) Видимо, никак. Либо обработкой ожидания, но это то ещё "гумно" в данном случае...
51 Кодер
 
27.11.19
22:37
Извините, отъезжал.

(49) При изменении цен сбрасывал флаг и всё работало типовым образом.
52 Злопчинский
 
27.11.19
22:43
(51), ну... это неинтересно... ;-)
Закон Брукера: Даже маленькая практика стоит большой теории.