РК_ЗагрузкаОстатков 1.3.1.57: документы ввода и понятные ошибки подключения.

Создание ВводОстатковТоваров по сопоставленным строкам; перехват ошибок на форме;
сообщение про флажок «Активно» при рабочих вызовах Transfer API.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
mihailkudravcev
2026-08-12 15:00:49 +03:00
parent 95c6315feb
commit 63f453a8b1
8 changed files with 520 additions and 7 deletions
@@ -136,6 +136,74 @@
<ChoiceHistoryOnInput>Auto</ChoiceHistoryOnInput>
</Properties>
</Attribute>
<Attribute uuid="12cf6acc-d041-4fd5-bc4f-1c34fa0bc654">
<Properties>
<Name>Организация</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Организация</v8:content>
</v8:item>
</Synonym>
<Comment/>
<Type>
<v8:Type>cfg:CatalogRef.Организации</v8:Type>
</Type>
<PasswordMode>false</PasswordMode>
<Format/>
<EditFormat/>
<ToolTip/>
<MarkNegatives>false</MarkNegatives>
<Mask/>
<MultiLine>false</MultiLine>
<ExtendedEdit>false</ExtendedEdit>
<MinValue xsi:nil="true"/>
<MaxValue xsi:nil="true"/>
<FillChecking>ShowError</FillChecking>
<ChoiceFoldersAndItems>Items</ChoiceFoldersAndItems>
<ChoiceParameterLinks/>
<ChoiceParameters/>
<QuickChoice>Auto</QuickChoice>
<CreateOnInput>Auto</CreateOnInput>
<ChoiceForm/>
<LinkByType/>
<ChoiceHistoryOnInput>Auto</ChoiceHistoryOnInput>
</Properties>
</Attribute>
<Attribute uuid="26959905-0b22-424b-962e-0d306a2b9b35">
<Properties>
<Name>ПерезаписатьДокументы</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Перезаписать документы</v8:content>
</v8:item>
</Synonym>
<Comment>Удалить непроведённые документы волны перед созданием</Comment>
<Type>
<v8:Type>xs:boolean</v8:Type>
</Type>
<PasswordMode>false</PasswordMode>
<Format/>
<EditFormat/>
<ToolTip/>
<MarkNegatives>false</MarkNegatives>
<Mask/>
<MultiLine>false</MultiLine>
<ExtendedEdit>false</ExtendedEdit>
<MinValue xsi:nil="true"/>
<MaxValue xsi:nil="true"/>
<FillChecking>DontCheck</FillChecking>
<ChoiceFoldersAndItems>Items</ChoiceFoldersAndItems>
<ChoiceParameterLinks/>
<ChoiceParameters/>
<QuickChoice>Auto</QuickChoice>
<CreateOnInput>Auto</CreateOnInput>
<ChoiceForm/>
<LinkByType/>
<ChoiceHistoryOnInput>Auto</ChoiceHistoryOnInput>
</Properties>
</Attribute>
<TabularSection uuid="11e438df-e73c-44d2-b3ed-08c04b320d8e">
<InternalInfo>
<xr:GeneratedType name="DataProcessorTabularSection.РК_ЗагрузкаОстатков.ВходящиеДанные" category="TabularSection">
@@ -1307,6 +1375,78 @@
<ChoiceHistoryOnInput>Auto</ChoiceHistoryOnInput>
</Properties>
</Attribute>
<Attribute uuid="7cd14970-3b1d-46ef-87db-8c86937ea3f9">
<Properties>
<Name>ДокументВвода</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Документ ввода</v8:content>
</v8:item>
</Synonym>
<Comment/>
<Type>
<v8:Type>cfg:DocumentRef.ВводОстатковТоваров</v8:Type>
</Type>
<PasswordMode>false</PasswordMode>
<Format/>
<EditFormat/>
<ToolTip/>
<MarkNegatives>false</MarkNegatives>
<Mask/>
<MultiLine>false</MultiLine>
<ExtendedEdit>false</ExtendedEdit>
<MinValue xsi:nil="true"/>
<MaxValue xsi:nil="true"/>
<FillFromFillingValue>false</FillFromFillingValue>
<FillValue xsi:nil="true"/>
<FillChecking>DontCheck</FillChecking>
<ChoiceFoldersAndItems>Items</ChoiceFoldersAndItems>
<ChoiceParameterLinks/>
<ChoiceParameters/>
<QuickChoice>Auto</QuickChoice>
<CreateOnInput>Auto</CreateOnInput>
<ChoiceForm/>
<LinkByType/>
<ChoiceHistoryOnInput>Auto</ChoiceHistoryOnInput>
</Properties>
</Attribute>
<Attribute uuid="3ddb1d09-f4c4-4f2c-9c48-597e0c63296b">
<Properties>
<Name>ЗагруженоВДокумент</Name>
<Synonym>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Загружено в документ</v8:content>
</v8:item>
</Synonym>
<Comment/>
<Type>
<v8:Type>xs:boolean</v8:Type>
</Type>
<PasswordMode>false</PasswordMode>
<Format/>
<EditFormat/>
<ToolTip/>
<MarkNegatives>false</MarkNegatives>
<Mask/>
<MultiLine>false</MultiLine>
<ExtendedEdit>false</ExtendedEdit>
<MinValue xsi:nil="true"/>
<MaxValue xsi:nil="true"/>
<FillFromFillingValue>false</FillFromFillingValue>
<FillValue xsi:type="xs:boolean">false</FillValue>
<FillChecking>DontCheck</FillChecking>
<ChoiceFoldersAndItems>Items</ChoiceFoldersAndItems>
<ChoiceParameterLinks/>
<ChoiceParameters/>
<QuickChoice>Auto</QuickChoice>
<CreateOnInput>Auto</CreateOnInput>
<ChoiceForm/>
<LinkByType/>
<ChoiceHistoryOnInput>Auto</ChoiceHistoryOnInput>
</Properties>
</Attribute>
</ChildObjects>
</TabularSection>
<Form>Форма</Form>
@@ -113,10 +113,236 @@
КонецФункции
// Создание документов ВводОстатковТоваров по сопоставленным строкам (1 документ на склад).
// Себестоимость не заполняется (нет данных в API) — только оперативный учёт количества.
//
// Параметры:
// РежимТест - Булево - только подсчёт без записи
//
// Возвращаемое значение:
// Структура - СозданоДокументов, УдаленоДокументов, СтрокВДокументах, Пропущено, Ошибок, ТекстТега
//
Функция СоздатьДокументыВводаОстатков(РежимТест = Истина) Экспорт
Результат = Новый Структура;
Результат.Вставить("СозданоДокументов", 0);
Результат.Вставить("УдаленоДокументов", 0);
Результат.Вставить("СтрокВДокументах", 0);
Результат.Вставить("Пропущено", 0);
Результат.Вставить("Ошибок", 0);
Результат.Вставить("ТекстТега", "");
Если Не ЗначениеЗаполнено(Организация) Тогда
ВызватьИсключение "Укажите организацию для документов ввода остатков";
КонецЕсли;
Если Не ЗначениеЗаполнено(ДатаДокументовВвода) Тогда
ВызватьИсключение "Укажите дату документов ввода";
КонецЕсли;
ТекстТега = ТегКомментарияДокументов();
Результат.ТекстТега = ТекстТега;
СтрокиПоСкладу = СгруппироватьСопоставленныеСтрокиПоСкладу();
Если СтрокиПоСкладу.Количество() = 0 Тогда
Возврат Результат;
КонецЕсли;
Если ПерезаписатьДокументы И Не РежимТест Тогда
Результат.УдаленоДокументов = УдалитьПрежниеДокументыВолны(ТекстТега);
КонецЕсли;
Для Каждого ЭлементСклада Из СтрокиПоСкладу Цикл
СкладДок = ЭлементСклада.Ключ;
СтрокиСклада = ЭлементСклада.Значение;
Если СтрокиСклада.Количество() = 0 Тогда
Продолжить;
КонецЕсли;
Попытка
Если РежимТест Тогда
Результат.СозданоДокументов = Результат.СозданоДокументов + 1;
Результат.СтрокВДокументах = Результат.СтрокВДокументах + СтрокиСклада.Количество();
Продолжить;
КонецЕсли;
Док = СоздатьДокументПоСкладу(СкладДок, СтрокиСклада, ТекстТега);
Если ЗначениеЗаполнено(Док) Тогда
Результат.СозданоДокументов = Результат.СозданоДокументов + 1;
Результат.СтрокВДокументах = Результат.СтрокВДокументах + Док.Товары.Количество();
Для Каждого СтрТ Из СтрокиСклада Цикл
СтрТ.ДокументВвода = Док.Ссылка;
СтрТ.ЗагруженоВДокумент = Истина;
КонецЦикла;
КонецЕсли;
Исключение
Результат.Ошибок = Результат.Ошибок + 1;
КонецПопытки;
КонецЦикла;
Возврат Результат;
КонецФункции
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
Функция ТегКомментарияДокументов()
Суффикс = Формат(ДатаДокументовВвода, "ДФ=yyyyMMdd");
Если ПустаяСтрока(Суффикс) Тогда
Суффикс = Формат(ДатаОстатков, "ДФ=yyyyMMdd");
КонецЕсли;
Возврат "РК_ПереносОстатков " + Суффикс;
КонецФункции
Функция СгруппироватьСопоставленныеСтрокиПоСкладу()
Группы = Новый Соответствие;
Для Каждого СтрТ Из ВходящиеДанные Цикл
Если Не СтрТ.Сопоставлено Тогда
Продолжить;
КонецЕсли;
Если Не ЗначениеЗаполнено(СтрТ.Склад) Или Не ЗначениеЗаполнено(СтрТ.Номенклатура) Тогда
Продолжить;
КонецЕсли;
Если СтрТ.Количество <= 0 Тогда
Продолжить;
КонецЕсли;
КлючСклада = Строка(СтрТ.Склад.УникальныйИдентификатор());
СтрокиСклада = Группы.Получить(КлючСклада);
Если СтрокиСклада = Неопределено Тогда
СтрокиСклада = Новый Массив;
Группы.Вставить(КлючСклада, СтрокиСклада);
КонецЕсли;
СтрокиСклада.Добавить(СтрТ);
КонецЦикла;
// Переключить ключи на ссылки складов для удобства обхода.
Результат = Новый Соответствие;
Для Каждого СтрТ Из ВходящиеДанные Цикл
Если Не СтрТ.Сопоставлено Или Не ЗначениеЗаполнено(СтрТ.Склад) Тогда
Продолжить;
КонецЕсли;
КлючСклада = Строка(СтрТ.Склад.УникальныйИдентификатор());
СтрокиСклада = Группы.Получить(КлючСклада);
Если СтрокиСклада <> Неопределено И Результат.Получить(СтрТ.Склад) = Неопределено Тогда
Результат.Вставить(СтрТ.Склад, СтрокиСклада);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Функция УдалитьПрежниеДокументыВолны(ТекстТега)
Удалено = 0;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Ввод.Ссылка КАК Ссылка
|ИЗ
| Документ.ВводОстатковТоваров КАК Ввод
|ГДЕ
| НЕ Ввод.ПометкаУдаления
| И НЕ Ввод.Проведен
| И Ввод.Организация = &Организация
| И Ввод.Комментарий ПОДОБНО &Тег
| И Ввод.ХозяйственнаяОперация = ЗНАЧЕНИЕ(Перечисление.ХозяйственныеОперации.ВводОстатковСобственныхТоваров)";
Запрос.УстановитьПараметр("Организация", Организация);
Запрос.УстановитьПараметр("Тег", "%" + ТекстТега + "%");
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
Попытка
ДокОб = Выборка.Ссылка.ПолучитьОбъект();
ДокОб.Удалить();
Удалено = Удалено + 1;
Исключение
КонецПопытки;
КонецЦикла;
Возврат Удалено;
КонецФункции
Функция СоздатьДокументПоСкладу(СкладДок, СтрокиСклада, ТекстТега)
Док = Документы.ВводОстатковТоваров.СоздатьДокумент();
Док.Дата = ДатаДокументовВвода;
Док.Организация = Организация;
Док.Склад = СкладДок;
Док.ХозяйственнаяОперация = Перечисления.ХозяйственныеОперации.ВводОстатковСобственныхТоваров;
Док.Комментарий = ТекстТега + ", склад " + СокрЛП(Строка(СкладДок));
Док.ОтражатьВОперативномУчете = Истина;
Док.ОтражатьСебестоимость = Ложь;
Док.ЦенаВключаетНДС = Ложь;
Попытка
Док.Подразделение = ОбщегоНазначения.ЗначениеРеквизитаОбъекта(СкладДок, "Подразделение");
Исключение
КонецПопытки;
Попытка
Док.Валюта = ЗначениеНастроекПовтИсп.ВалютаРегламентированногоУчетаОрганизации(Организация);
Исключение
Док.Валюта = Константы.ВалютаРегламентированногоУчета.Получить();
КонецПопытки;
Если Не ЗначениеЗаполнено(Док.НалогообложениеНДС) Тогда
Док.НалогообложениеНДС = Перечисления.ТипыНалогообложенияНДС.ПродажаОблагаетсяНДС;
КонецЕсли;
Попытка
ПараметрыНДС = Документы.ВводОстатковТоваров.ИнициализироватьПараметрыВидовДеятельностиНДС(Док);
УчетНДСУП.ЗаполнитьВидДеятельностиНДС(Док.ВидДеятельностиНДС, ПараметрыНДС);
Исключение
КонецПопытки;
Для Каждого СтрТ Из СтрокиСклада Цикл
НовСтр = Док.Товары.Добавить();
НовСтр.Номенклатура = СтрТ.Номенклатура;
НовСтр.Характеристика = СтрТ.Характеристика;
НовСтр.Серия = СтрТ.СерияСсылка;
НовСтр.Количество = СтрТ.Количество;
НовСтр.КоличествоУпаковок = СтрТ.Количество;
НовСтр.Цена = 0;
НовСтр.Сумма = 0;
Попытка
НовСтр.СтавкаНДС = СтрТ.Номенклатура.СтавкаНДС;
Исключение
КонецПопытки;
Если ЗначениеЗаполнено(СтрТ.НомерГТДСсылка) Тогда
НовСтр.НомерГТД = СтрТ.НомерГТДСсылка;
КонецЕсли;
Если ЗначениеЗаполнено(СтрТ.СерияСсылка) Тогда
СтрСер = Док.Серии.Добавить();
СтрСер.Номенклатура = НовСтр.Номенклатура;
СтрСер.Характеристика = НовСтр.Характеристика;
СтрСер.Серия = СтрТ.СерияСсылка;
СтрСер.Количество = НовСтр.Количество;
СтрСер.КоличествоУпаковок = НовСтр.Количество;
КонецЕсли;
КонецЦикла;
Если Док.Товары.Количество() = 0 Тогда
Возврат Документы.ВводОстатковТоваров.ПустаяСсылка();
КонецЕсли;
ОбщегоНазначенияУТ.ЗаполнитьИдентификаторыДокумента(Док, "Товары");
Попытка
ПараметрыУказанияСерий = НоменклатураСервер.ПараметрыУказанияСерий(Док, Документы.ВводОстатковТоваров);
НоменклатураСервер.ЗаполнитьСтатусыУказанияСерий(Док, ПараметрыУказанияСерий);
Исключение
КонецПопытки;
Док.ОбменДанными.Загрузка = Ложь;
Док.Записать(РежимЗаписиДокумента.Запись);
Возврат Док;
КонецФункции
Процедура ЗаполнитьСтрокуВходящихДанныхИзAPI(НовСтр, СтрокаAPI)
НовСтр.НоменклатураИдентификатор = UUIDИзСтроки(ЗначениеСвойства(СтрокаAPI, "nomenclature_guid", ""));
@@ -19,6 +19,11 @@
<CommandName>Form.Command.Сопоставить</CommandName>
<ExtendedTooltip name="ФормаСопоставитьРасширеннаяПодсказка" id="116"/>
</Button>
<Button name="ФормаСоздатьДокументы" id="123">
<Type>CommandBarButton</Type>
<CommandName>Form.Command.СоздатьДокументы</CommandName>
<ExtendedTooltip name="ФормаСоздатьДокументыРасширеннаяПодсказка" id="124"/>
</Button>
</ChildItems>
</AutoCommandBar>
<Events>
@@ -43,6 +48,25 @@
<ContextMenu name="ДатаДокументовВводаКонтекстноеМеню" id="37"/>
<ExtendedTooltip name="ДатаДокументовВводаРасширеннаяПодсказка" id="38"/>
</InputField>
<InputField name="Организация" id="117">
<DataPath>Объект.Организация</DataPath>
<ExtendedEditMultipleValues>true</ExtendedEditMultipleValues>
<ContextMenu name="ОрганизацияКонтекстноеМеню" id="118"/>
<ExtendedTooltip name="ОрганизацияРасширеннаяПодсказка" id="119"/>
</InputField>
<CheckBoxField name="ПерезаписатьДокументы" id="120">
<DataPath>Объект.ПерезаписатьДокументы</DataPath>
<ToolTip>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Удалить непроведённые документы этой волны перед созданием</v8:content>
</v8:item>
</ToolTip>
<ToolTipRepresentation>ShowRight</ToolTipRepresentation>
<CheckBoxType>Auto</CheckBoxType>
<ContextMenu name="ПерезаписатьДокументыКонтекстноеМеню" id="121"/>
<ExtendedTooltip name="ПерезаписатьДокументыРасширеннаяПодсказка" id="122"/>
</CheckBoxField>
<Pages name="ГруппаСтраницы" id="1">
<Title>
<v8:item>
@@ -227,6 +251,19 @@
<ContextMenu name="ВходящиеДанныеКомментарийСопоставленияКонтекстноеМеню" id="111"/>
<ExtendedTooltip name="ВходящиеДанныеКомментарийСопоставленияРасширеннаяПодсказка" id="112"/>
</InputField>
<InputField name="ВходящиеДанныеДокументВвода" id="125">
<DataPath>Объект.ВходящиеДанные.ДокументВвода</DataPath>
<EditMode>EnterOnInput</EditMode>
<ContextMenu name="ВходящиеДанныеДокументВводаКонтекстноеМеню" id="126"/>
<ExtendedTooltip name="ВходящиеДанныеДокументВводаРасширеннаяПодсказка" id="127"/>
</InputField>
<CheckBoxField name="ВходящиеДанныеЗагруженоВДокумент" id="128">
<DataPath>Объект.ВходящиеДанные.ЗагруженоВДокумент</DataPath>
<EditMode>EnterOnInput</EditMode>
<CheckBoxType>Auto</CheckBoxType>
<ContextMenu name="ВходящиеДанныеЗагруженоВДокументКонтекстноеМеню" id="129"/>
<ExtendedTooltip name="ВходящиеДанныеЗагруженоВДокументРасширеннаяПодсказка" id="130"/>
</CheckBoxField>
</ChildItems>
</Table>
</ChildItems>
@@ -439,5 +476,20 @@
</ToolTip>
<Action>Сопоставить</Action>
</Command>
<Command name="СоздатьДокументы" id="4">
<Title>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Создать документы</v8:content>
</v8:item>
</Title>
<ToolTip>
<v8:item>
<v8:lang>ru</v8:lang>
<v8:content>Создать ВводОстатковТоваров по сопоставленным строкам</v8:content>
</v8:item>
</ToolTip>
<Action>СоздатьДокументы</Action>
</Command>
</Commands>
</Form>
@@ -32,7 +32,12 @@
Возврат;
КонецЕсли;
ПодобратьСкладыНаСервере();
Попытка
ПодобратьСкладыНаСервере();
Исключение
ПоказатьПредупреждение(, КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат;
КонецПопытки;
Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.ГруппаОтбор;
КонецПроцедуры
@@ -49,7 +54,12 @@
Возврат;
КонецЕсли;
Количество = ЗагрузитьОстаткиНаСервере();
Попытка
Количество = ЗагрузитьОстаткиНаСервере();
Исключение
ПоказатьПредупреждение(, КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат;
КонецПопытки;
Элементы.ГруппаСтраницы.ТекущаяСтраница = Элементы.ГруппаВходящиеДанные;
ПоказатьОповещениеПользователя("Загрузка остатков", , "Загружено строк: " + Формат(Количество, "ЧГ=0"));
@@ -79,11 +89,53 @@
Возврат;
КонецЕсли;
РежимТест = (РезультатВопроса <> КодВозвратаДиалога.Да);
Текст = СопоставитьНаСервере(РежимТест);
Попытка
Текст = СопоставитьНаСервере(РежимТест);
Исключение
ПоказатьПредупреждение(, КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат;
КонецПопытки;
ПоказатьОповещениеПользователя("Сопоставление", , Текст);
КонецПроцедуры
&НаКлиенте
Процедура СоздатьДокументы(Команда)
Если Не ЗначениеЗаполнено(Объект.Организация) Тогда
ПоказатьПредупреждение(, "Укажите организацию");
Возврат;
КонецЕсли;
Если Не ЗначениеЗаполнено(Объект.ДатаДокументовВвода) Тогда
ПоказатьПредупреждение(, "Укажите дату документов ввода");
Возврат;
КонецЕсли;
Описание = Новый ОписаниеОповещения("СоздатьДокументыПослеВопроса", ЭтотОбъект);
ПоказатьВопрос(Описание,
"Создать документы ВводОстатковТоваров?" + Символы.ПС
+ "Да — запись; Нет — только подсчёт (тест); Отмена — прервать.",
РежимДиалогаВопрос.ДаНетОтмена);
КонецПроцедуры
&НаКлиенте
Процедура СоздатьДокументыПослеВопроса(РезультатВопроса, ДопПараметры) Экспорт
Если РезультатВопроса = КодВозвратаДиалога.Отмена Тогда
Возврат;
КонецЕсли;
РежимТест = (РезультатВопроса <> КодВозвратаДиалога.Да);
Попытка
Текст = СоздатьДокументыНаСервере(РежимТест);
Исключение
ПоказатьПредупреждение(, КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
Возврат;
КонецПопытки;
ПоказатьОповещениеПользователя("Документы ввода", , Текст);
КонецПроцедуры
#КонецОбласти
#Область СлужебныеПроцедурыИФункции
@@ -210,6 +262,24 @@
КонецФункции
&НаСервере
Функция СоздатьДокументыНаСервере(РежимТест)
ОбъектОбработки = РеквизитФормыВЗначение("Объект");
Результат = ОбъектОбработки.СоздатьДокументыВводаОстатков(РежимТест);
ЗначениеВРеквизитФормы(ОбъектОбработки, "Объект");
Возврат СтрШаблон(
"Документов: %1; строк: %2; удалено прежних: %3; ошибок: %4; тег: %5%6",
Формат(Результат.СозданоДокументов, "ЧН=0; ЧГ=0"),
Формат(Результат.СтрокВДокументах, "ЧН=0; ЧГ=0"),
Формат(Результат.УдаленоДокументов, "ЧН=0; ЧГ=0"),
Формат(Результат.Ошибок, "ЧН=0; ЧГ=0"),
Результат.ТекстТега,
?(РежимТест, " (тест)", ""));
КонецФункции
&НаСервере
Функция ЗначениеСвойстваОтвета(Источник, Имя)