Имя: Пароль:
1C
1С v8
Формула с условием в УНФ
,
0 vladimir80
 
11.04.17
17:21
Всем привет! В УНФ есть механизм динамического формирования цен в зависимости от статического, опорного типа цен. Весь механизм по сути - замена строки идентификатора типа цен на значение цены и вычисление  методом Вычислить()....

К сожалению, в нашем случае это не сильно удобно, т.к. существуют несколько статических типов цен (пример - Закупочная и РекомендованнаяЗаводом), и в зависимости от этих цен нужно формировать ту или иную цену по типу

Если [РекомендованнаяЗаводом] > 0 Тогда
[РекомендованнаяЗаводом]
Иначе
[Закупочная] * 1.35
КонецЕсли


Собственно вопрос - можно ли как-то оформить обработку такого кода, если да, то с помощью каких методов встроенного языка...
1 AlvlSpb
 
11.04.17
17:25
(0) Поясните задачу. Вам нужно формирование прайс листа или установка цен в документах? Т.е. оформляем приходную и в нее подтягиваются либо Рекомендованное заводом (при наличии) либо Закупочная (нет рекомендованных)
2 vladimir80
 
11.04.17
17:29
Формирование прайс-листа. Если быть совсем точным, то изменение процедуры

ЦенообразованиеФормулыСервер.РасчетДанныхПоФормуле()
3 AlvlSpb
 
11.04.17
17:35
(2) Еще одно уточнение. Вы хотите, чтобы в прайс выводились разные цены? Т.е. при наличии рекомендованных заводом - они, если таковых нет - закупочная*1,35. Правильно понял?
4 AlvlSpb
 
11.04.17
17:36
Какая версия УНФ? Не нашел что-то такой процедуры в своей 1.6.10.27
5 vladimir80
 
11.04.17
17:40
(3) Возможно Вы незнакомы с механизмом ценообразования в УНФ. Там не вывод в прайс, а именно формирование цен для динамического типа цены по формуле от опорного статического. Версия последняя, 1.6.9.36 (!), 10 еще нет...
6 AlvlSpb
 
11.04.17
17:40
(4) Вопрос снимаю. нашлась )), а вопрос (3) остается
7 AlvlSpb
 
11.04.17
17:45
(5) ))) есть есть, тестовая. Но это другой вопрос. Вы не ответили. Вернее ответили, что опять непонятно. С УНФ работаю с 2012-го, поэтому  уточняю: Динамическая цена вам нужна для предоставления прайс-листа покупателям или для подстановки в документы продажи?
8 vladimir80
 
11.04.17
17:47
По сути вопроса - да, =0, больше, меньше и т.п. Условия чисто математические.

Наверное можно распарсить конструкцию, или заключить условную конструкцию в спецсимволы и проверять истинность, а значения после Тогда и Иначе обрабатывать через Вычислить...

Динамическая цена нужна для подставновки в документы, выгрузки на сайт, и еще много где. Наверное я просто не понимаю цели вопроса. По сути хочу получить тип цен "Розничная".
9 AlvlSpb
 
11.04.17
17:47
Не поймите неправильно, это не занудство. Разные подходы возможны. Для формирования прайса, наверное, придется вносить изменения в общий модуль (то что вы написали), а если для документа, то проще расширением не формировать, а выбирать цену из регистра сведений
10 Вафель
 
11.04.17
17:49
(8) Открой для себя функцию "?"
11 vladimir80
 
11.04.17
17:51
Работаю через расширения, поэтому изменения меня не беспокоят. Я понял что есть смысл в вопросе. Но мне нужно получать цены в РС ЦеныНоменклатуры.

(10) Сразу нет, мне придется открыть тогда и язык 1с для людей, которые в экселе неспособны формулу написать, да и конструкции с иначеесли превратят ? в такую кашу, что разобрать ее визуально будет практически невозможно
12 Вафель
 
11.04.17
17:52
(11) Тогда мучайся дальше
13 Вафель
 
11.04.17
17:53
(11) напиши простой вид такого выражения из (0), которое может понять и менеджер-сапожник
14 vladimir80
 
11.04.17
17:59
(13) Это понятно, что за неимением служанки сойдет и дворецкий. Если обработать "Если" из 1с нельзя, напишу парсер выражения и сделаю красиво. Вопрос в том, что возможно кто-то решал уже подобную задачу, или имеет взгляд на решение, отличный от моего, в общем то поэтому и вопрос.

В итоге хочется получить решение, доступное пользователю, а не костыль. На сложных условиях, как по мне, будет некрасиво.
15 AlvlSpb
 
11.04.17
18:06
(11) В документ вставить несложно. В ПриСозданииНаСервере делаете Запрос к РС ЦеныНоменклатурыСрезПоследних Выбираете актуальные цены РекомендованныеЗаводом и Закупочные, а в выборке условие Если ЗначениеЗаполнено(Рекомендованные) Тогда Выборка.Рекомендованные Иначе Выборка.Закупочные*1,35
  А вот с прайсом, что-то первоначальная моя мысль не сработает. Там расчет по всем введенным товарам. Надо подумать
16 AlvlSpb
 
11.04.17
18:07
Если ЗначениеЗаполнено(Выборка.Рекомендованные)*
17 vladimir80
 
11.04.17
19:28
(16) написать в коде процедуры несложно... Сложно задать кучу разносторонних условий, вводимых пользователем, и обрабатывать это...

По склоняюсь к мысли парсить все в некий массив структур с ключами условие и формула. Если условие дает истину, то отдавать формулу, если нет переходить к следующему условию, если условие пустое (после Иначе), то отдавать последнее условие. По сути все реализуемо, главное правильно распарсить текст условия и добавить проверку на корректность введенных данных...
18 vladimir80
 
11.04.17
19:34
Написал, сам не понял...

Массив
значение элемента массива - структура

Ключи структуры
- "Условие" (формула строкой, берется между если и тогда)
- "Значение" (Формула строкой, берется между тогда и Иначе)

Если это последний сегмент, между иначе и конец если, то ключ условия пустой или заведомо истина, значение - формула

В цикле массив прогоняем через вычислить условие и если истина - отдаем вычислить значение с прерыванием цикла.

Как то так. Если есть мысли как сделать красивее - буду рад выслушать.
19 AlvlSpb
 
11.04.17
20:22
(18) Т.е. у вас регулярно меняются цены. Не проще тогда просто использовать минусовые процентные скидки от какой-то базовой цены (та же формула, установленная вручную), а чтобы не нервировать клиента просто переделать печатную форму, чтобы выводилась только цена уже со скидкой
20 vladimir80
 
11.04.17
20:38
(19) Ну и цены регулярно меняются, и цены поставщиков могут отличаться, и еще есть условие на ~15% ассортимента в виде РекЦены, ниже которой показывать нельзя.

Печатные формы меня сильно не интересуют, основной упор на интернет-магазины. РекЦены могут формироваться ооочень своеобразно, т.е. % скидки/наценки от дилерской цены это реализовать невозможно. Поэтому и пришла мысль сделать более вариативным ценообразование.

На самом деле механизм интересный, но кастрированный, уже допилил ТЧ в вид цены, для установки фиксированных цен, отдельных формул скидок по ценовым группам и т.п.
21 AlvlSpb
 
11.04.17
20:43
(20) Тогда опять как вариант. В расширении в форму ввести поле куда менеджер вводит формулу, а уже в документе во всех или только выделенных строках установленная рекомендованная цена пересчитывается по этой формуле
22 vladimir80
 
11.04.17
20:55
(21) Как вариант, да. Но на практике - костыль.

1 - неизвестно, в скольких местах придется внести эту формулу
2 - При изменении формулы будет невозможно отследить историю цен

В любом случае спасибо за варианты, интересно обдумать со всех сторон.
23 vladimir80
 
11.04.17
22:11
Вот что придумалось, криво конечно, буду рад советам по улучшению и упрощению...

Получив массив делаем цикл по нему, и если условие верно то передаем формулу. Последнее условие всегда верное.

Код должен быть в формате, указанном в (0)

Функция РазложитьУсловияВМассив(ТекстУсловия)
    
    МассивПодстрок = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(НРег(ТекстУсловия), "тогда", ложь);
    
    КоличествоПодстрок = МассивПодстрок.Количество();
    
    МассивУсловийЗначений = Новый Массив;
    
    индекс = 0;
    Для Каждого м ИЗ МассивПодстрок Цикл
        СтруктураУсловий = Новый Структура;
        
        Если индекс = 0 Тогда
             // получаем только условие
             СтруктураУсловий.Вставить( "Условие", ПочиститьСтроку(м));
             МассивУсловийЗначений.Добавить(СтруктураУсловий);
             индекс = индекс + 1;
             Продолжить;
        КонецЕсли;
        
        МассивСтроки = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(м, "иначе", ложь);
        
        Если индекс = (КоличествоПодстрок - 1) Тогда            
             МассивУсловийЗначений[индекс - 1].Вставить("Значение", ПочиститьСтроку(МассивСтроки[0]) );
             СтруктураУсловий = Новый Структура;
             СтруктураУсловий.Вставить("Условие", "1=1");
             СтруктураУсловий.Вставить("Значение", ПочиститьСтроку(МассивСтроки[1]));
             МассивУсловийЗначений.Добавить(СтруктураУсловий);
             Возврат МассивУсловийЗначений;
        КонецЕсли;
            
        МассивУсловийЗначений[индекс - 1].Вставить("Значение", ПочиститьСтроку(МассивСтроки[0]) );
        СтруктураУсловий.Вставить("Условие", ПочиститьСтроку(МассивСтроки[1]));
        
        МассивУсловийЗначений.Добавить(СтруктураУсловий);
        индекс = индекс + 1;
    КонецЦикла;
    
    Возврат МассивУсловийЗначений;
КонецФункции

Функция ПочиститьСтроку(Т)
             Т = СтрЗаменить(НРег(Т), "если", "");
             Т = СтрЗаменить(Т, "тогда", "");
             Т = СтрЗаменить(Т, "иначе", "");
             Т = СтрЗаменить(Т, "конец", "");
             Возврат СокрЛП(Т);
КонецФункции
24 Мимохожий Однако
 
11.04.17
23:16
Может быть, посмотреть в сторону видов расчета в ЗУП и регистров расчета? Смешно, конечно. Но там есть формулы
25 vladimir80
 
11.04.17
23:21
(24) да в принципе работает все... только синтаксис формулы бы еще проверять...
26 vladimir80
 
12.04.17
00:29
&НаСервере
&Вместо("РасчетДанныхПоФормуле")
Процедура Расш1_РасчетДанныхПоФормуле(Знач ФормулаСтрокой, СтруктураОперандов, РасчетныеДанные = Неопределено, ОкруглятьВБольшуюСторону = Неопределено, ПравилоОкругления = Неопределено) Экспорт
    
.......
    Для каждого Операнд Из СтруктураОперандов Цикл
        
        ФормулаСтрокой = СтрЗаменить(ФормулаСтрокой, Операнд.Ключ, Операнд.Значение);
        
    КонецЦикла;
    
    
    Если СтрНайти(ВРег(ФормулаСтрокой), "ЕСЛИ") > 0 Тогда
         ЗначениеФормулы = Неопределено;
         МассивУсловий = РазложитьУсловияВМассив(ФормулаСтрокой);
         Для Каждого Условие ИЗ МассивУсловий Цикл
                Если Вычислить(Условие.Условие) Тогда
                    ЗначениеФормулы = Условие.Значение;
                    Прервать;
                КонецЕсли;
         КонецЦикла;
    КонецЕсли;
    
    ФормулаСтрокой = ?(ЗначениеФормулы = Неопределено, ФормулаСтрокой, ЗначениеФормулы);
    
.........
КонецПроцедуры

Функция РазложитьУсловияВМассив(ТекстУсловия)
    
    МассивПодстрок = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(ТекстУсловия, "Тогда", ложь);
    
    КоличествоПодстрок = МассивПодстрок.Количество();
    
    МассивУсловийЗначений = Новый Массив;
    
    индекс = 0;
    Для Каждого м ИЗ МассивПодстрок Цикл
        СтруктураУсловий = Новый Структура;
        
        Если индекс = 0 Тогда
             // получаем только условие
             СтруктураУсловий.Вставить( "Условие", ПочиститьСтроку(м));
             МассивУсловийЗначений.Добавить(СтруктураУсловий);
             индекс = индекс + 1;
             Продолжить;
        КонецЕсли;
        
        МассивСтроки = СтроковыеФункцииКлиентСервер.РазложитьСтрокуВМассивПодстрок(м, "Иначе", ложь);
        
        Если индекс = (КоличествоПодстрок - 1) Тогда            
             МассивУсловийЗначений[индекс - 1].Вставить("Значение", ПочиститьСтроку(МассивСтроки[0]) );
             СтруктураУсловий = Новый Структура;
             СтруктураУсловий.Вставить("Условие", "1=1");
             СтруктураУсловий.Вставить("Значение", ПочиститьСтроку(МассивСтроки[1]));
             МассивУсловийЗначений.Добавить(СтруктураУсловий);
             Возврат МассивУсловийЗначений;
        КонецЕсли;
            
        МассивУсловийЗначений[индекс - 1].Вставить("Значение", ПочиститьСтроку(МассивСтроки[0]) );
        СтруктураУсловий.Вставить("Условие", ПочиститьСтроку(МассивСтроки[1]));
        
        МассивУсловийЗначений.Добавить(СтруктураУсловий);
        индекс = индекс + 1;
    КонецЦикла;
    
    Возврат МассивУсловийЗначений;
КонецФункции

Функция ПочиститьСтроку(Т)
             Т = СтрЗаменить(Т, "Если", "");
             Т = СтрЗаменить(Т, "Тогда", "");
             Т = СтрЗаменить(Т, "Иначе", "");
             Т = СтрЗаменить(Т, "Конец", "");
             Возврат СокрЛП(Т);
КонецФункции
27 vladimir80
 
12.04.17
00:32
Работает. Если кто-нибудь захочет упростить, добавить проверку синтаксиса или сделает красиво обход различного регистра идентификатора формул и слов конструкций - пишите!
Закон Брукера: Даже маленькая практика стоит большой теории.