diff --git a/README.md b/README.md
index 7ef04b3f..068bd779 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
[![Release](https://img.shields.io/github/v/release/firstBitSportivnaya/PSSL?include_prereleases&label=last%20release&style=badge)](https://github.com/firstBitSportivnaya/PSSL/releases/latest)
[![GitHub issues](https://img.shields.io/github/issues-raw/firstBitSportivnaya/PSSL?style=badge)](https://github.com/firstBitSportivnaya/PSSL/issues)
[![License](https://img.shields.io/github/license/firstBitSportivnaya/PSSL?style=badge)](https://github.com/firstBitSportivnaya/PSSL/blob/develop/LICENSE)
-[![OpenYellow](https://img.shields.io/endpoint?url=https://openyellow.neocities.org/badges/4/751858948.json)](https://openyellow.notion.site/openyellow/24727888daa641af95514b46bee4d6f2?p=aec5d010e2aa4fcf9ec351e0b013705e&pm=s)
+[![OpenYellow](https://img.shields.io/endpoint?url=https://openyellow.org/data/badges/4/751858948.json)](https://openyellow.org/grid?data=top&repo=751858948)
![image](https://repository-images.githubusercontent.com/751858948/a45ea547-c23c-4ce1-b30e-609d9ac8d558)
@@ -31,7 +31,6 @@
2. [Динамическое Формирование Интерфейса](https://github.com/KotovDima1C/DFI)
3. [Консоль кода](https://github.com/salexdv/bsl_console)
4. [Просмотр файлов JSON с разметкой](https://github.com/plastinin/AllYouNeedIsLove)
-5. [Универсальная загрузка XLS с приведением типов](https://github.com/Bayselonarrend/uniloadXLS)
## Информация для контрибьюторов
diff --git "a/docs/\320\227\320\260\320\263\321\200\321\203\320\267\320\272\320\260\320\244\320\260\320\271\320\273\320\260\320\247\320\265\321\200\320\265\320\267\320\242\320\260\320\261\320\273\320\270\321\207\320\275\321\213\320\271\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202.md" "b/docs/\320\227\320\260\320\263\321\200\321\203\320\267\320\272\320\260\320\244\320\260\320\271\320\273\320\260\320\247\320\265\321\200\320\265\320\267\320\242\320\260\320\261\320\273\320\270\321\207\320\275\321\213\320\271\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202.md"
index 42822d09..d1c2e066 100644
--- "a/docs/\320\227\320\260\320\263\321\200\321\203\320\267\320\272\320\260\320\244\320\260\320\271\320\273\320\260\320\247\320\265\321\200\320\265\320\267\320\242\320\260\320\261\320\273\320\270\321\207\320\275\321\213\320\271\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202.md"
+++ "b/docs/\320\227\320\260\320\263\321\200\321\203\320\267\320\272\320\260\320\244\320\260\320\271\320\273\320\260\320\247\320\265\321\200\320\265\320\267\320\242\320\260\320\261\320\273\320\270\321\207\320\275\321\213\320\271\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202.md"
@@ -1,29 +1,515 @@
# Подсистема загрузки файлов Excel через табличный документ
-Пример вызова на форме
+Предназначена для универсальной загрузки Excel-файлов (csv-файлов) через табличный документ.
+Преобразование происходит в два этапа:
+* Чтение файла и сопоставление его колонок с "макетом" - таблицей значений, где описаны свойства колонок и порядок конвертации;
+* Конвертация строковых значений в соответствии с "макетом": поиск ссылок для ссылочных объектов, конвертация базовых типов данных (Число, Дата, Булево).
-```BSL
+Результатом конвертации будет являтся таблица значений, сформированная по описанным в "макете" правилам.
+
+## Описание свойств колонок файла ("макета")
+
+Для того, чтобы сопоставить колонки файла со значениями 1С и конвертировать строковые значения, прочитанные из файла, необходимо заполнить "правила конвертации".
+Существует два варианта сопоставления колонок: по порядку и по наименованию колонок.
+Если установлен вариант "по порядку", тогда сопоставление колонок происходит в строгой последовательности макета. Например, если свойства инициализированы следующих образом
+```bsl
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Номенклатура";
+
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Артикул";
+
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Наименование";
+```
+то первая колонка файла всегда будет распознана как номенклатура, не смотря на то, что там может быть значение другого типа (например, контрагент).
+
+Если установлен вариант "по наименованию", то строка файла с номером начальной строки чтения будет идентифицирована как шапка таблицы. Колонки шапки таблицы будут проанализированы и сопоставлены по наименованию с таблицей свойств. Имя колонки файла должно быть равно либо свойству "ИмяВТабДоке", либо свойству "ИмяКолонки". В противном случае, колонка будет не идентифицирована. Все неидентифицированные колонки файла будут удалены из табличного документа, их значения не загрузятся из файла и не будут доступны для последующей обработки.
+
+Чтобы инициализировать таблицу свойств необходимо вызвать функцию в зависимости от контекста выполнения кода:
+
+##### С клиента:
+
+```bsl
+ТаблицаСвойств = пбп_ЗагрузкаФайлаЧерезТабличныйДокументВызовСервера.ИнициализироватьТаблицуСоСвойствамиКолонок()
+```
+
+##### С сервера:
+
+```bsl
+ТаблицаСвойств = пбп_ЗагрузкаФайлаЧерезТабличныйДокументСервер.ИнициализироватьТаблицуСоСвойствамиКолонок()
+```
+
+Таблица свойств содержит следующие колонки строкового типа:
+1) **ИмяКолонки** - имя колонки в итоговой таблице значений для последующего обращения к ней;
+2) **ИмяВТабДоке** - имя колонки в файле. Свойство учитывается при сопоставлении колонок по наименованию. Если не заполнено, то имя колонки считается равным значению из "ИмяКолонки", например:
+```bsl
+// Здесь ИмяВТабДоке не указано, поэтому колонка будет искаться по значению "ЕдиницаХранения"
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "ЕдиницаХранения";
+```
+```bsl
+// Здесь ИмяВТабДоке указано, поэтому колонка будет искаться по значению "Единица хранения"
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "ЕдиницаХранения";
+НоваяСтрока.ИмяВТабДоке = "Единица хранения";
+```
+3) **Группа** - имя колонки "группы" ячеек. Под группой подразумевается объединение ячеек строкой выше в шапке таблицы. Например, в примере ниже группой колонок будет являтся "Номенклатура":
+
+
+ Номенклатура |
+
+ Наименование |
+ Артикул |
+ Единица хранения |
+
+
+
+
+ Ложка |
+ 0000001 |
+ шт |
+
+
+
+
+Тогда инициализация группы в свойствах колонок будет выглядеть следующим образом:
+```bsl
+ГруппаЯчеек = "Номенклатура";
+
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Наименование";
+НоваяСтрока.Группа = ГруппаЯчеек;
+
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Артикул";
+НоваяСтрока.Группа = ГруппаЯчеек;
+
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "ЕдиницаХранения";
+НоваяСтрока.ИмяВТабДоке = "Единица хранения";
+НоваяСтрока.Группа = ГруппаЯчеек;
+```
+4) **ТипЗначения** - тип значения, в который будет конвертировано значение колонки. Может принимать значения базовых типов: Число, Булево, Дата,- так и ссылочные типы:
+```bsl
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Наименование";
+НоваяСтрока.ТипЗначения = "Строка";
+
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "ЕдиницаХранения";
+НоваяСтрока.ТипЗначения = "СправочникСсылка.УпаковкиЕдиницыИзмерения";
+НоваяСтрока.ПолеПоиска1 = "Наименование";
+```
+Для конвертации значений "булево" необходимо указывать строковое представление ИСТИНА (по умолчанию, если представление не указано, проверка на "да" и "истина"), для конвертации даты в параметрах чтения файла ключ КонвертироватьДаты должен быть Истина (подробно см. в главе [Параметры чтения файла](#параметры-чтения-файла)). Для конвертации ссылочных типов необходимо заполнить поля поиска. В указанном выше примере единица хранения будет искаться по полю "наименование".
+5) **ПолеПоиска1**, **ПолеПоиска2**, **ПолеПоиска3** - название реквизита объекта, по которому будет произведен поиск значения ссылочного типа.
+6) **ОператорУсловия** - оператор сравнения в условии соединения таблицы с типом значения между полями поиска. По умолчанию "ИЛИ", также может равняться "И" или "ВИРТ". Например, если в колонке файла "Контрагент" может быть указан либо ИНН, либо ОКПО, либо наименование, и, соответственно, поиск должен производится по этим полям объекта с указанным приоритетом (высший ИНН, низший - наименование), то указываем свойства в следующем порядке:
+```bsl
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Контрагент";
+НоваяСтрока.ТипЗначения = "СправочникСсылка.Контрагенты";
+НоваяСтрока.ПолеПоиска1 = "ИНН";
+НоваяСтрока.ПолеПоиска2 = "КодПоОКПО";
+НоваяСтрока.ПолеПоиска3 = "Наименование";
+```
+На выходе в итоговом запросе конвертации значений ссылочных типов получится следующее соединение:
+```bsl
+ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагенты1
+ ПО ВходнаяТаблица.Контрагент <> "" И ВходнаяТаблица.Контрагент <> 0
+ И (ВходнаяТаблица.Контрагент = Контрагенты1.ИНН
+ ИЛИ ВходнаяТаблица.Контрагент = Контрагенты1.КодПоОКПО
+ ИЛИ ВходнаяТаблица.Контрагент = Контрагенты1.Наименование)
+```
+При использовании оператора "И" имена полей поиска должны равняться именам колонок обрабатываемой таблицы. Например: если в свойствах макета у колонки заполнен тип ДокументСсылка., ПолеПоиска1 = "Номер", а ПолеПоиска2 = "Дата" И ОператорУсловия = "И", тогда таблица построителя должна иметь колонки "Номер", где лежит номер документа и "Дата", где лежит дата документа:
+
+
+
+ Номер |
+ Дата |
+ Контрагент |
+ ... |
+
+
+
+
+ 000000001 |
+ 01.01.2023 |
+ ООО "Ромашка" |
+ ... |
+
+
+
+
+```bsl
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Реализация";
+НоваяСтрока.ТипЗначения = "ДокументСсылка.РеализацияТоваровУслуг";
+НоваяСтрока.ПолеПоиска1 = "Номер";
+НоваяСтрока.ПолеПоиска2 = "Дата";
+НоваяСтрока.ОператорУсловия = "И";
+```
+Оператор "ВИРТ" предназначен для инициализации "виртуальных" полей ссылочных типов (которые не входят в логику оператора "И"), т.е. которых нет в исходном файле. Например, если колонки "Номенклатура" в файле нет, но есть одно из полей поиска номенклатуры, допустим "Артикул", то используя оператор "ВИРТ" в итоговой таблице мы получим ссылку на номенклатуру, полученную поиском по артикулу:
+```bsl
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Номенклатура";
+НоваяСтрока.ТипЗначения = "СправочникСсылка.Номенклатура";
+НоваяСтрока.ПолеПоиска1 = "Артикул";
+НоваяСтрока.ОператорУсловия = "ВИРТ";
+```
+В этом примере номенклатуру также можно найти с помощью оператора "ИЛИ" напрямую по артикулу
+```bsl
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Артикул";
+НоваяСтрока.ТипЗначения = "СправочникСсылка.Номенклатура";
+НоваяСтрока.ПолеПоиска1 = "Артикул";
+```
+но в этом случае имя колонки "Артикул" будет зарезервировано ссылкой на номенклатуру. Если нужно загрузить оба поля: и номенклатуру, и артикул,- то нужно объявить оба поля, одно из которых будет виртуальным, а другое загружаться из файла как строковое значение:
+```bsl
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Номенклатура";
+НоваяСтрока.ТипЗначения = "СправочникСсылка.Номенклатура";
+НоваяСтрока.ПолеПоиска1 = "Артикул";
+НоваяСтрока.ОператорУсловия = "ВИРТ";
+
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Артикул";
+НоваяСтрока.ТипЗначения = "Строка";
+```
+7) **ФункцияПреобразования** - имя экспортной функции в программном интерфейсе, которая будет вызвана для конвертации значения. Допустим, нам необходимо убрать лидирующие нули в колонке. Тогда в серверном общем модуле ("ТестЗагрузкиФайлаИзТабличногоДокумента") создаем экспортную функцию УбратьЛидирующиеНули с параметром "ВходящееЗначение" (в него придет строковое значение ячейки файла):
+```bsl
+Функция УбратьЛидирующиеНули(ВходящееЗначение) Экспорт
+ Возврат СтроковыеФункцииКлиентСервер.УдалитьПовторяющиесяСимволы(ВходящееЗначение, "0");
+КонецФункции
+```
+А в свойствах колонки прописываем отношение колонки к этой функции:
+```bsl
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "Наименование";
+НоваяСтрока.ТипЗначения = "Строка";
+НоваяСтрока.ФункцияПреобразования = "ТестЗагрузкиФайлаИзТабличногоДокумента.УбратьЛидирующиеНули";
+```
+8) **ФорматДаты** - формат даты строкой. Если указан, то строковое значение будет конвертироваться в дату по указаному формату. Сам формат представляет собой строку с номерами разрядов через разделитель "_" (например, "1_1_2"). Первый разряд показывает какой разделитель используется в представлении даты, второй разряд показывает положение дня, месяца и года по отношению друг к другу, третий разряд показывает представление времени в дате. Если номер формата "0_0_0" - преобразование происходит из функции XMLЗначение (ISO формат даты вида "2023-12-31T18:30:51").
+* Первый разряд принимает значения:
+ - 1 - разделитель ".";
+ - 2 - "/";
+ - 3 - "-";
+ - 4 - " ";
+* Второй разряд принимает значения:
+ - 0 - месяц, день, год
+ - 1 - год идет первым, потом месяц и день;
+ - 2 - сначала день, потом месяц и год;
+ - 3 - сначала день, месяц СТРОКОЙ и год;
+* Третий разряд принимает значения:
+ - 0 - время отсутствует;
+ - 1 - время стандартное, 24-часовое представление
+ - 2 - время в 12-ти часовом представлении (AM / PM)
+
+Примеры номеров форматов:
+ - 1_1_2 - "2021.12.01 8:10 PM";
+ - 2_1_0 - "2021/12/01";
+ - 1_3_1 - "01.дек.2021 20:10";
+ - 3_1_1 - "2021-12-01 20:10"
+
+Если формат даты колонки не указан в свойствах, а тип колонки "Дата", то ее формат будет определен по первому значению колонки в процессе конвертации строковых значений по типам, но только в том случае, если в параметрах чтения файла ключ КонвертироватьДаты равен Истина. Исключением из данного правила являются даты, где месяц указывается первым (например, 12/31/3999). В этом случае ФорматДаты колонки должен быть заполнен явным образом. В этом примере номер формата даты будет равен "2_0_0":
+```bsl
+НоваяСтрока = ТаблицаСвойств.Добавить();
+НоваяСтрока.ИмяКолонки = "ДатаДокумента";
+НоваяСтрока.ТипЗначения = "Дата";
+НоваяСтрока.ФорматДаты = "2_0_0"; // значение вида "12/31/3999"
+```
+
+## Параметры чтения файла
+
+Параметры влияют на чтение данных из файла и их конвертацию. Для того чтобы указать параметры чтения файла необходимо вызвать функцию ПолучитьПараметрыЧтенияФайла():
+```bsl
+ПараметрыЧтения = пбп_ЗагрузкаФайлаЧерезТабличныйДокументСервер.ПолучитьПараметрыЧтенияФайла();
+```
+При вызове функции клиентской загрузки из XLS (общий модуль "пбп_ЗагрузкаФайлаЧерезТабличныйДокументКлиент") параметры чтения передаются параметрами функции (пример см. в главе [Пример вызова с клиента](#пример-вызова-с-клиента)).
+
+Структура параметров имеют следующие ключи:
+1) **НазваниеЛиста** - Строка - название листа в исходном файле;
+2) **НомерСтроки** - Число - начальный номер строки, с которой начинается чтение файла. Обычно, это шапка таблицы. Строки до нее обрезаются;
+3) **СопоставлениеПоНаименованию** - Булево - если Истина, то колонки будут сравниваться по наименованию; если Ложь, то по порядку, указанном в таблице свойств колонок (подробно см. в начале главы [Описание свойств колонок файла](#описание-свойств-колонок-файла-макета)). По умолчанию Ложь;
+4) **КонвертироватьДаты** - Булево - если Истина, то колонки с типом Дата будут конвертироваться автоматически из строкового значения в дату, по умолчанию Истина;
+5) **ВыдаватьОшибкуПриОтсутствииЛиста** - Булево - если Истина, то при отсутствии листа с наименованием, указанном в ключе "НазваниыеЛиста", в файле обработка файла будет прервана с ошибкой. По умолчанию Ложь;
+6) **ЗначениеИстина** - Строка - строковое представление значения ИСТИНА для колонок с типом булево (например, "Y" или "Да"). Если не заполнено, то проверяется на равенство строке "истина" или "да";
+7) **ОставитьСтроковыеЗначения** - если Истина, то оставляет колонки с исходными строковыми значениями конвертируемых типов (Булево, Число, Дата) с постфиксом "Строкой". В противном случае удаляет их после конвертации. По умолчанию Ложь;
+8) **ИскатьПомеченныеНаУдаление** - если Истина, то при поиске ссылок на объекты игнорирует пометку на удаление. В противном случае, помеченные на удаление не будут учитываться. По умолчанию Истина.
+
+## Примеры вызова загрузки файла
+
+После изучения правил заполенения таблицы свойств колонок и параметров чтения можно рассмотреть вызовы загрузки файла на примерах. Дан следующий Excel-файл с данными реализаций товаров и услуг:
+
+
+
+
+ Номер |
+ Дата |
+ Номенклатура (Артикул) |
+ Цена |
+ Количество |
+ Сумма |
+
+
+
+
+ 000000001 |
+ 01.01.2023 10:30:13 |
+ 123 |
+ 100 |
+ 2 |
+ 200 |
+
+
+ 000000001 |
+ 01.01.2023 10:30:13 |
+ 789 |
+ 300 |
+ 1 |
+ 300 |
+
+
+ 000000002 |
+ 01.01.2023 15:14:01 |
+ 456 |
+ 200 |
+ 4 |
+ 800 |
+
+
+ 000000003 |
+ 02.01.2023 09:46:10 |
+ 123 |
+ 100 |
+ 15 |
+ 1500 |
+
+
+
+
+#### Пример вызова с клиента
+
+```bsl
&НаКлиенте
Асинх Процедура ЗагрузитьXLS(Команда)
- СтруктураКолонок = Новый Структура;
- СтруктураКолонок.Вставить("Спр2" , "СправочникСсылка.Спр2");
- СтруктураКолонок.Вставить("Перечисление1" , "ПеречислениеСсылка.Перечисление1");
- СтруктураКолонок.Вставить("ЛюбоеИмя" , "");
- СтруктураКолонок.Вставить("Док1" , "ДокументСсылка.Док1");
- СтруктураКолонок.Вставить("Спр1" , "СправочникСсылка.Спр1");
+ // Заполняем таблицу свойств колонок. Так как свойства лежат в таблице значений, на клиент возвращаем адрес временного хранилища с ТЗ
+ АдресХранилища = ПолучитьСтруктуруЗагружаемогоОбъекта();
+
+ ИмяСтраницы = "Лист1";
+ НомерПервойСтроки = 2;
- ИД = Ждать пбп_ЗагрузкаФайлаЧерезТабличныйДокументКлиент.ЗагрузитьИзXLS(СтруктураКолонок, , 2);
+ // Заполняем параметры чтения
+ ПараметрыЧтения = пбп_ЗагрузкаФайлаЧерезТабличныйДокументКлиент.ПолучитьПараметрыЧтенияФайла();
+ ПараметрыЧтения.НазваниеЛиста = ИмяСтраницы;
+ ПараметрыЧтения.НомерСтроки = НомерПервойСтроки;
+ ПараметрыЧтения.СопоставлениеПоНаименованию = Истина;
+ ПараметрыЧтения.ЗначениеИстина = "Y";
- Если ЗначениеЗаполнено(ИД) Тогда
+ // Переменная ИД равняется адресу итоговой таблицы во временном хранилище
+ ИД = Ждать пбп_ЗагрузкаФайлаЧерезТабличныйДокументКлиент.ЗагрузитьИзXLS(АдресХранилища, ПараметрыЧтения);
+
+ Если ЗначениеЗаполнено(ИД) Тогда
ЗагрузкаНаСервере(ИД);
КонецЕсли;
КонецПроцедуры
+&НаСервере
+Функция ПолучитьСтруктуруЗагружаемогоОбъекта()
+
+ СтруктураКолонок = пбп_ЗагрузкаФайлаЧерезТабличныйДокументСервер.ИнициализироватьТаблицуСоСвойствамиКолонок();
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Реализация";
+ НоваяСтрока.ТипЗначения = "ДокументСсылка.РеализацияТоваровУслуг";
+ НоваяСтрока.ПолеПоиска1 = "Номер";
+ НоваяСтрока.ПолеПоиска2 = "Дата";
+ НоваяСтрока.ОператорУсловия = "И";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Номер";
+ НоваяСтрока.ТипЗначения = "Строка";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Дата";
+ НоваяСтрока.ТипЗначения = "Дата";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Номенклатура";
+ НоваяСтрока.ИмяВТабДоке = "Номенклатура (Артикул)";
+ НоваяСтрока.ТипЗначения = "СправочникСсылка.РеализацияТоваровУслуг";
+ НоваяСтрока.ПолеПоиска1 = "Артикул";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Цена";
+ НоваяСтрока.ТипЗначения = "Число";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Количество";
+ НоваяСтрока.ТипЗначения = "Число";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Сумма";
+ НоваяСтрока.ТипЗначения = "Число";
+
+ АдресХранилища = ПоместитьВоВременноеХранилище(СтруктураКолонок, Новый УникальныйИдентификатор);
+
+ Возврат АдресХранилища;
+
+КонецПроцедуры
+
&НаСервере
Процедура ЗагрузкаНаСервере(ИД)
ТЗ = ПолучитьИзВременногоХранилища(ИД);
+
+ // Пост-обработка полученных данных
+ // ...
+КонецПроцедуры
+```
+
+#### Пример вызова с сервера
+
+```bsl
+Процедура ЗагрузитьXSL(ДвоичныеДанныеФайла, Расширение)
+
+ СтруктураКолонок = ПолучитьСтруктуруЗагружаемогоОбъекта();
+
+ // Инициализируем параметры чтения для дальнейшей передачи
+ // Для серверного контекста вызывается функция из серверного модуля
+ ПараметрыЧтения = пбп_ЗагрузкаФайлаЧерезТабличныйДокументСервер.ПолучитьПараметрыЧтенияФайла();
+ ПараметрыЧтения.НазваниеЛиста = "Лист1";
+ ПараметрыЧтения.НомерСтроки = 2;
+ ПараметрыЧтения.СопоставлениеПоНаименованию = Истина;
+ ПараметрыЧтения.КонвертироватьДаты = Истина;
+ ПараметрыЧтения.ВыдаватьОшибкуПриОтсутствииЛиста = Ложь;
+ ПараметрыЧтения.ЗначениеИстина = "Y";
+ ПараметрыЧтения.ОставитьСтроковыеЗначения = Ложь;
+ ПараметрыЧтения.ИскатьПомеченныеНаУдаление = Ложь;
+
+ // Помещаем файл в хранилище на сервере
+ АдресВХранилище = ПоместитьВоВременноеХранилище(ДвоичныеДанныеФайла, Новый УникальныйИдентификатор);
+ ТаблицаДанных = пбп_ЗагрузкаФайлаЧерезТабличныйДокументСервер
+ .КонвертироватьДанныеТабличногоДокументаВТаблицуЗначений(
+ АдресВХранилище, Расширение, ТаблицаСвойств, ПараметрыЧтения);
+
+ // Для не найденных значений в итоговой таблице будут Null. Уберем их
+ пбп_ЗагрузкаФайлаЧерезТабличныйДокументСервер.ТаблицаЗначенийБезNull(ТаблицаДанных);
+
+ // Пост-обработка полученных данных
+ // ...
+
+КонецПроцедуры
+
+Функция ПолучитьСтруктуруЗагружаемогоОбъекта()
+
+ СтруктураКолонок = пбп_ЗагрузкаФайлаЧерезТабличныйДокументСервер.ИнициализироватьТаблицуСоСвойствамиКолонок();
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Реализация";
+ НоваяСтрока.ТипЗначения = "ДокументСсылка.РеализацияТоваровУслуг";
+ НоваяСтрока.ПолеПоиска1 = "Номер";
+ НоваяСтрока.ПолеПоиска2 = "Дата";
+ НоваяСтрока.ОператорУсловия = "И";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Номер";
+ НоваяСтрока.ТипЗначения = "Строка";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Дата";
+ НоваяСтрока.ТипЗначения = "Дата";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Номенклатура";
+ НоваяСтрока.ИмяВТабДоке = "Номенклатура (Артикул)";
+ НоваяСтрока.ТипЗначения = "СправочникСсылка.РеализацияТоваровУслуг";
+ НоваяСтрока.ПолеПоиска1 = "Артикул";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Цена";
+ НоваяСтрока.ТипЗначения = "Число";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Количество";
+ НоваяСтрока.ТипЗначения = "Число";
+
+ НоваяСтрока = СтруктураКолонок.Добавить();
+ НоваяСтрока.ИмяКолонки = "Сумма";
+ НоваяСтрока.ТипЗначения = "Число";
+
+ Возврат СтруктураКолонок;
+
КонецПроцедуры
+```
+
+### Чтение CSV-файла
+
+Порядок вызова функций для чтения CSV-файлов будет немного отличаться от аналогичного чтения Excel-файлов. Подсистема распознает два вида заполнения файлов: где есть разделители, и где разделители условны, а значения колонок находятся на определенных позициях строки, например:
+
+
+123 Номенклатура №1 шт
+
+456 Номенклатура №2 исшт
+
+
+Во второй строке видно, что разделитель между наименованием номенклатуры и наименованием единицы измерения ("шт") отсутствует, но, очевидно, это разные колонки.
+
+Для файлов, где есть разделители, параметры чтения от Excel отличаться не будут, за исключением того, что чтение csv-файлов происходит в строгом порядке, указанном в таблице свойств колонок.
+Для файлов, где значения колонок стоят на определенных позициях строки, для каждой колонки необходимо заполнить начальный символ в строке файла и длину значения. Для этого свойства таблицы необходимо инициализоровать не посредством вызова функции "ИнициализироватьТаблицуСоСвойствамиКолонок", а посредством вызова "ИнициализироватьТаблицуСоСвойствамиCSV". Для выше указанного файла заполнение будет выглядеть следующим образом:
+```bsl
+СтруктураКолонок = пбп_ЗагрузкаФайлаЧерезТабличныйДокументСервер.ИнициализироватьТаблицуСоСвойствамиCSV();
+НоваяСтрока = СтруктураКолонок.Добавить();
+НоваяСтрока.ИмяКолонки = "Артикул";
+НоваяСтрока.ТипЗначения = "Строка";
+НоваяСтрока.Начало = 0;
+НоваяСтрока.Длина = 3;
+
+НоваяСтрока = СтруктураКолонок.Добавить();
+НоваяСтрока.ИмяКолонки = "Наименование";
+НоваяСтрока.ТипЗначения = "Строка";
+НоваяСтрока.Начало = 7;
+НоваяСтрока.Длина = 18;
+
+НоваяСтрока = СтруктураКолонок.Добавить();
+НоваяСтрока.ИмяКолонки = "ЕдиницаХранения";
+НоваяСтрока.ТипЗначения = "Строка";
+НоваяСтрока.Начало = 25;
+НоваяСтрока.Длина = 2;
```
+
+#### Пример чтения CSV-файла
+
+```bsl
+Процедура ЗагрузитьCSV(ДвоичныеДанныеФайла, Расширение)
+
+ // Либо аналогична примерам с Excel, либо свойства с началом и длиной
+ СтруктураКолонок = ПолучитьСтруктуруЗагружаемогоОбъекта();
+
+ // Помещаем файл во временное хранилище на сервере
+ ПутьКФайлу = ПолучитьИмяВременногоФайла(Расширение);
+ ДвоичныеДанныеФайла.Записать(ПутьКФайлу);
+
+ // Если загрузка файла с разделителями, то 4-ым параметром указывается разделитель, например ";"
+ // В противном случае не указывается
+ // 3-им параметром указывается кодировка файла. По умолчанию "UTF8"
+ СыраяТаблица = пбп_ЗагрузкаФайлаЧерезТабличныйДокументСервер
+ .ПолучитьПромежуточнуюТаблицуИзCSVФайла(ПутьКФайлу, СтруктураКолонок);
+
+ // Вызываем функцию конвертации строковых значений и передаем таблицу, полученную после чтения CSV-файла
+ ТаблицаРезультат = пбп_ЗагрузкаФайлаЧерезТабличныйДокументСервер
+ .ПреобразоватьСтроковыеЗначенияПоТипамСвойств(СыраяТаблица, СтруктураКолонок, Истина, "Y", , Ложь);
+
+ // Для не найденных значений в итоговой таблице будут Null. Уберем их
+ пбп_ЗагрузкаФайлаЧерезТабличныйДокументСервер.ТаблицаЗначенийБезNull(ТаблицаДанных);
+
+ // Пост-обработка полученных данных
+ // ...
+
+КонецПроцедуры
+```
+
+#### Благодарность
+
+Отдельная благодарность за идею реализации репозиторию [Универсальная загрузка XLS с приведением типов](https://github.com/Bayselonarrend/uniloadXLS)
\ No newline at end of file