Хранение остатков поставщика у себя в базе
Опубликовано Ср 05 Сентябрь 2012 в "Программирование"
Теги: Практика программирования 1С, Таблица значений, Запрос,
В этой статье, я хотел бы рассказать об опыте настройки хранения остатков по складу поставщика. Почему именно об этом? Потому что, заодно мы рассмотрим:
- Механизм обработки в запросе таблицы значений. Что в целом может пригодиться.
- Механизм формирования таблицы движений сразу в запросе.
Заказчиком было поставлено условие: изменение конфигурации, должно быть обоснованным и не происходить без надобности. Были найдены и рассмотрены следующие варианты:
- Добавление регистра в базу. Загрузка туда остатков, да и вообще всего что можно загрузить.
- Загрузка данных из экселя (Именно в этом формате поставщик хранит свои данные) каждый раз при открытии подбора в документ отгрузки.
- Создание нового склада, и загрузка данных туда корректирующим документом.
Первые два способа подразумевают модификацию обработки подбора в документ реализации а один из них еще и добавление регистра, что само по себе не страшно конечно, но для заказчика не желательно. А во втором случае, надо каждый раз читать эксель, что тоже не очень хорошо. После консультаций с комьюнити, было выяснено, что вроде как все считают, что хранить остатки у себя в базе нельзя, но почему, никто сказать не может. Решили остановиться на третьем варианте.
И так что мы будем делать: 1. Загрузим из подсунутого экселя остатки поставщика 2. Подсчитаем дельту, на которую надо скорректировать остатки. 3. Создадим документ «КоорректировкаЗаписейРегистраНакопления» и в него зальем движения.
Начинаем. Читаем эксель в таблицу значений.
Функция ПрочитатьЭксель()
КСАртикул = Новый КвалификаторыСтроки(25);
Массив = Новый Массив;
Массив.Добавить(Тип("Строка"));
ОписаниеТиповАртикул = Новый ОписаниеТипов(Массив, , КСАртикул);
Массив.Очистить();
КЧ = Новый КвалификаторыЧисла(10);
Массив.Добавить(Тип("Число"));
ОписаниеТиповЧ = Новый ОписаниеТипов(Массив, , ,КЧ);
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Артикул", ОписаниеТиповАртикул);
ТЗ.Колонки.Добавить("Количество", ОписаниеТиповЧ);
Попытка
Excel = Новый COMОбъект("Excel.Application");
Excel.WorkBooks.Open(ИмяФайла);
Состояние("Обработка файла Microsoft Excel");
ExcelЛист = Excel.Sheets(1);
Исключение
Сообщить("Не удалось обработать файл!");
Возврат "";
КонецПопытки;
Для СтрокаЭксель = СтрокаНачало По СтрокаОкончание Цикл
Прогресс = (СтрокаЭксель / СтрокаОкончание) * 100;
ЭлементыФормы.СтрокаСтатуса.Заголовок = "Считывается эксель в память " + СтрокаЭксель + " из " + СтрокаОкончание;
Зн = ExcelЛист.Cells(СтрокаЭксель, КолонкаАртикул).Text;
АртикулВДокумент = СокрЛ(ExcelЛист.Cells(СтрокаЭксель, КолонкаАртикул).Text);
КолвоВДокумент = СокрЛ(ExcelЛист.Cells(СтрокаЭксель, КолонкаКоличество).Text);
КолвоВДокумент = ?(КолвоВДокумент = "", 0, Число(КолвоВДокумент));
НоваяСтрокаТЗ = ТЗ.Добавить();
НоваяСтрокаТЗ.Артикул = АртикулВДокумент;
НоваяСтрокаТЗ.Количество = КолвоВДокумент;
КонецЦикла;
Excel.WorkBooks.Close();
Excel = 0;
Возврат ТЗ;
КонецФункции // ПрочитатьЭксель()
Я читаю эксель в типизизрованную таблицу значений, потому что для обработки таблицы запросом она должна быть типизирована. На форме есть надпись с названием "СтрокаСтатуса" которая рассказывает про текущий ход загрузки данных из экселя. Так же есть поля ввода в которых лежат номера колонок где артикул номенклатуры а где количество. Здесь вроде все настолько просто, что даже не знаю что тут прокомментировать. Ну раз с первым моментом нам все ясно, перейдем к вычислению дельты которую надо грузить в регистр. Для начала, что бы обращаться к этой таблице в запросе, надо ее поместить во временную таблицу, это не очень сложно и делается с помощью вот такого кода:
ТЗЭксель = ПрочитатьЭксель();
МВТ = Новый МенеджерВременныхТаблиц;
ТаблицаЭксель = Новый Запрос;
ТаблицаЭксель.МенеджерВременныхТаблиц = МВТ;
ТаблицаЭксель.Текст =
"Выбрать
|
|ПОМЕСТИТЬ ДокЭксель
|ИЗ
|&ТаблицаСДанными КАК Таблица";
ТаблицаЭксель.УстановитьПараметр("ТаблицаСДанными", ТЗЭксель);
ТаблицаЭксель.Выполнить();
Таблица есть, теперь перейдем к загрузке. Так как в экселе могут быть уже существующие записи или не быть тех которые есть в регистре, мы будем привязываться к справочнику номенклатура. Собственно вот он запрос:
ВЫБРАТЬ ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) КАК ОстатокНаСкладе, ЕСТЬNULL(ДокЭксель.Количество, 0) КАК КоличествоЭксель, ВЫБОР КОГДА ЕСТЬNULL(ДокЭксель.Количество, 0) - ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) < 0 ТОГДА 0 - (ЕСТЬNULL(ДокЭксель.Количество, 0) - ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0)) ИНАЧЕ ЕСТЬNULL(ДокЭксель.Количество, 0) - ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) КОНЕЦ КАК Количество, &Склад, Товар.Ссылка КАК Номенклатура, ЗНАЧЕНИЕ(Справочник.Качество.Новый) КАК Качество, ВЫБОР КОГДА ЕСТЬNULL(ДокЭксель.Количество, 0) - ЕСТЬNULL(ТоварыНаСкладахОстатки.КоличествоОстаток, 0) > 0 ТОГДА ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход) ИНАЧЕ ЗНАЧЕНИЕ(ВидДвиженияНакопления.Расход) КОНЕЦ КАК ВидДвижения, ИСТИНА КАК Активность, &Период, &Док КАК Регистратор ИЗ Справочник.Номенклатура КАК Товар ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &Склад) КАК ТоварыНаСкладахОстатки ПО Товар.Ссылка = ТоварыНаСкладахОстатки.Номенклатура ЛЕВОЕ СОЕДИНЕНИЕ ДокЭксель КАК ДокЭксель ПО Товар.Артикул = ДокЭксель.Артикул ГДЕ Товар.Артикул <> ""Не забываем, что для того что бы обратиться к временной таблице, нам надо указать менеджер временных таблиц:
Запрос.МенеджерВременныхТаблиц = МВТ;
ЕСТЬNULL
нам гарантирует возврат числа в случае работы соединений, разницу мы получаем в строках с 4 по 8, строки с 9й по 19ю формируют значения для загрузки данных в регистр, собственно все почти готово. Осталось выгрузить результат в таблицу и удалить те значения которые грузить не надо(количество = 0) :
ДвиженияВДокумент = Запрос.Выполнить().Выгрузить();//"Склад,Номенклатура,Качество,Количество"
НулевыеДвижения = ДвиженияВДокумент.НайтиСтроки(Новый Структура("Количество",0));
Для Каждого СтрокаТаблицы Из НулевыеДвижения Цикл
ДвиженияВДокумент.Удалить(СтрокаТаблицы);
КонецЦикла;
Создать документ корректировки и добавить строку в ТЧ которая укажет на регистр, это нужно для отображения документа и обеспечения возможности его редактировать.
НовыйДок = Документы.КорректировкаЗаписейРегистров.СоздатьДокумент();
НовыйДок.Дата = ТекущаяДата();
СтрокаТЧ = НовыйДок.ТаблицаРегистровНакопления.Добавить();
СтрокаТЧ.Имя = "ТоварыНаСкладах";
СтрокаТЧ.Представление = "Товары на складах";
НовыйДок.Записать();
НовыйДок = НовыйДок.Ссылка;
И собственно загрузить данные в регистр
НаборВРегистр = РегистрыНакопления.ТоварыНаСкладах.СоздатьНаборЗаписей();
НаборВРегистр.Отбор.Регистратор.Значение = НовыйДок;
НаборВРегистр.Загрузить(ДвиженияВДокумент.Скопировать(,"Период,Регистратор,Активность,ВидДвижения,Склад,Номенклатура,Качество,Количество"));
НаборВРегистр.Записать();
Как вы могли заметить документ мы уже не трогаем, его не надо, не записывать, не проводить, он просто является основанием для записи в регистр.
Собственно на этом все, внимательный читатель наверняка уже нашел ошибку а вы? ;)
Как обычно для тех кто дочитал или прокрутил до конца как обычно бонус: Обработка про которую я рассказывал в этом посте.