Продвинутый курс. Занятие №12

Второе занятие 2-го блока продвинутого курса.

Необходимо изучить следующие главы текущего блока.
Глава 3. Агрегаты
Глава 4. Запросы к регистрам
Глава 5. Блокировка данных
Глава 6. Последовательности
Глава 7. Складской учет

К сожалению, у Вас недостаточно прав для просмотра этой записи. Если Вы еще не залогинены на сайте
залогиньтесь.

Если не активировали токен — посмотрите видео-инструкцию (видео N5)

Если вы залогинены, у Вас активирован токен доступа, но вы все равно видите эту запись —
напишите нам на e-mail поддержки.

комментариев 12 на “Продвинутый курс. Занятие №12”

  1. Задание выполнено.

    Резервирование товара осуществляется документом “ЗаказКлиента”, который делает приход по регистру “РезервыТоваров” и расход по регистру “ОстаткиТоваров”.  Контроль наличия осуществляется по регистру “ОстаткиТоваров”.

    Документ реализации списывает товар по регистру “РезервыТоваров” (если указан заказ) и “ОстаткиТоваров” (если заказ не указан).

  2. Задание выполнила. Новый регистр накопления “Заказы покупателей”. Движение приход – документ “Заказ покупателя”,  расход – документ “Реализация товаров и услуг”. При проведении определяю свободный остаток как разницу между остатками регистра “Остатки товаров” и  “Заказы покупателей”.

  3. respublica 22.06.2011 в 20:04

    Задание выполнено. В выложенное решение не смотрел.
    1. Для учета товаров в резерве создал документ ЗаказТоваров и регистр накопления ТоварыВРезерве (остатки, изм. Номенклатура и ЗаказПокупателя, ресурс – Количество). Документ при проведении делает расход количества с рег.нак. ОстаткиТоваров и приход. на рег. нак.ТоварыВРезерве. Контроль остатков при проведении делают по “новой схеме”, которую реализовывали в предыдущем уроке.
    2. В документе реализация добавил реквизит ЗаказПокупателя. Так как по условиям задачи требуется, что при указании заказа списывается только резерв, а без указания заказа – списывается свободный остаток, то модернизация кода из предыдущего задания свелась к очень простым действиям: – в обработке проведения
    <code>
    СписыватьСРезерва = ЗначениеЗаполнено(ЗаказПокупателя);
    Для Каждого ТекСтрокаТовары Из Товары Цикл
    Если СписыватьСРезерва Тогда
    // регистр ТоварыВРезерве Расход
    Движение = Движения.ТоварыВРезерве.Добавить(); …
    Иначе
    Движение = Движения.ОстаткиТоваров.Добавить();….
    </code>
    – в подписке на событие
    <code>
    Если СписыватьСРезерва Тогда
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, “РегистрНакопления.ОстаткиТоваров”, “РегистрНакопления.ТоварыВРезерве”);
    КонецЕсли;
    </code>
    3. Для обеспечения комфортной многопользовательской работы устанавливаю блокировки с помощью свойства БлокироватьДляИзменения = Истина;

    П.С. Мне кажется, более реалистичной была бы задача, где документ реализации при указании заказа списывал бы зарезервированное количество с резерва, а недостающее – со свободного остатка (нет необходимости искусственно дублировать документы на один факт продажи). Поэтому я реализовал и этот вариант. Подписку на событие в этом случае не модифицирую, а в обработке проведения вначале добавляю код :
    <code>
    Движения.ТоварыВРезерве.Очистить();
    Движения.ТоварыВРезерве.Записать();

    ТекстЗапроса = “ВЫБРАТЬ
    | РеализацияТоваровИУслугТовары.Номенклатура КАК Номенклатура,
    | СУММА(РеализацияТоваровИУслугТовары.Количество) КАК Количество,
    | РеализацияТоваровИУслугТовары.Ссылка.ЗаказПокупателя КАК ЗаказПокупателя
    |ПОМЕСТИТЬ ВТТоварыДок
    |ИЗ
    | Документ.РеализацияТоваровИУслуг.Товары КАК РеализацияТоваровИУслугТовары
    |ГДЕ
    | РеализацияТоваровИУслугТовары.Ссылка = &ТекДокумент
    |
    |СГРУППИРОВАТЬ ПО
    | РеализацияТоваровИУслугТовары.Номенклатура,
    | РеализацияТоваровИУслугТовары.Ссылка.ЗаказПокупателя
    |
    |ИНДЕКСИРОВАТЬ ПО
    | Номенклатура
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    | ВТТоварыДок.Номенклатура КАК Номенклатура,
    | ВТТоварыДок.ЗаказПокупателя КАК ЗаказПокупателя,
    | ЕСТЬNULL(ТоварыВРезервеОстатки.КоличествоОстаток, 0) КАК Резерв,
    | ВТТоварыДок.Количество КАК КоличествоПоДокументу,
    | ВЫБОР
    | КОГДА ВТТоварыДок.Количество > ЕСТЬNULL(ТоварыВРезервеОстатки.КоличествоОстаток, 0)
    | ТОГДА ЕСТЬNULL(ТоварыВРезервеОстатки.КоличествоОстаток, 0)
    | ИНАЧЕ ВТТоварыДок.Количество
    | КОНЕЦ КАК СписыватьИзРезерва,
    | ВЫБОР
    | КОГДА ВТТоварыДок.Количество >= ЕСТЬNULL(ТоварыВРезервеОстатки.КоличествоОстаток, 0)
    | ТОГДА ВТТоварыДок.Количество – ЕСТЬNULL(ТоварыВРезервеОстатки.КоличествоОстаток, 0)
    | ИНАЧЕ 0
    | КОНЕЦ КАК ОсталосьСписать
    |ИЗ
    | ВТТоварыДок КАК ВТТоварыДок
    | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыВРезерве.Остатки(
    | &МоментВремени,
    | (Номенклатура, ЗаказПокупателя) В
    | (ВЫБРАТЬ
    | ВТТоварыДок.Номенклатура,
    | ВТТоварыДок.ЗаказПокупателя
    | ИЗ
    | ВТТоварыДок КАК ВТТоварыДок)) КАК ТоварыВРезервеОстатки
    | ПО ВТТоварыДок.Номенклатура = ТоварыВРезервеОстатки.Номенклатура
    | И ВТТоварыДок.ЗаказПокупателя = ТоварыВРезервеОстатки.ЗаказПокупателя”;

    ЗапросСписаниеРезерва = Новый Запрос(ТекстЗапроса);
    ЗапросСписаниеРезерва.УстановитьПараметр(“ТекДокумент”, Ссылка);
    ЗапросСписаниеРезерва.УстановитьПараметр(“МоментВремени”, МоментВремени());
    Выборка = ЗапросСписаниеРезерва.Выполнить().Выбрать();

    Движения.ТоварыВРезерве.Записывать = Истина;
    Пока Выборка.Следующий() Цикл
    Если Выборка.СписыватьИзРезерва > 0 Тогда
    Движение = Движения.ТоварыВРезерве.Добавить();
    Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
    Движение.Период = Дата;
    Движение.Номенклатура = Выборка.Номенклатура;
    Движение.Количество = Выборка.СписыватьИзРезерва;
    Движение.ЗаказПокупателя = Выборка.ЗаказПокупателя;
    КонецЕсли;
    Если Выборка.ОсталосьСписать > 0 Тогда
    Движение = Движения.ОстаткиТоваров.Добавить();
    Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
    Движение.Период = Дата;
    Движение.Номенклатура = Выборка.Номенклатура;
    Движение.Количество = Выборка.ОсталосьСписать;
    КонецЕсли;
    КонецЦикла;

    </code>

  4. Задание реализовала. Резерв товаров выполняю в документе ЗаказПокупателя, сам учет резерва в регистре ТоварыВРезерве(Изм:Номенклатура, ДокументРезерва;Ресурс:Количество). При проведении док-та Заказа выполняется проверка номенклатура по регистрам ОстаткиТоваров-ТоварыВРезерве, если проверка успешна – товар резервируется. В начале проведения исключительная блокировка на товар из табл. части в регистрах ОстаткиТоваров и ТоварыВРезерве.
    Запрос.Текст =
    “ВЫБРАТЬ
    | ЗаказПокупателяТовары.Номенклатура КАК Товар
    |ПОМЕСТИТЬ СписокТоваров
    |ИЗ
    | Документ.ЗаказПокупателя.Товары КАК ЗаказПокупателяТовары
    |ГДЕ
    | ЗаказПокупателяТовары.Ссылка = &Ссылка
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    | ОстаткиТоваровОстатки.Номенклатура КАК Номенклатура,
    | ОстаткиТоваровОстатки.КоличествоОстаток – ЕСТЬNULL(ТоварыВРезервеОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток
    |ИЗ
    | РегистрНакопления.ОстаткиТоваров.Остатки(
    |   ,
    |   Номенклатура В
    |    (ВЫБРАТЬ
    |     Т.Товар
    |    ИЗ
    |     СписокТоваров КАК Т)) КАК ОстаткиТоваровОстатки
    |  ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыВРезерве.Остатки(
    |    ,
    |    Номенклатура В
    |     (ВЫБРАТЬ
    |      Т.Товар
    |     ИЗ
    |      СписокТоваров КАК Т)) КАК ТоварыВРезервеОстатки
    |  ПО ОстаткиТоваровОстатки.Номенклатура = ТоварыВРезервеОстатки.Номенклатура”;
    Запрос.УстановитьПараметр(“Ссылка”, Ссылка);
    ТаблицаРезультатов = Запрос.Выполнить().Выгрузить();

    Для Каждого ТекСтрокаТовары Из Товары Цикл
    НайденнаяСтрока = ТаблицаРезультатов.Найти(ТекСтрокаТовары.Номенклатура, “Номенклатура”);
    Если (НайденнаяСтрока = Неопределено) Тогда
    Сообщить(“Товар отсутствует на складе!”);
    Отказ = Истина;
    ИначеЕсли НайденнаяСтрока.КоличествоОстаток – ТекСтрокаТовары.Количество < 0 Тогда
    Сообщить(“Товара “+ТекСтрокаТовары.Номенклатура+ ” не достаточно на складе! Присутствует только “+Строка(ТекСтрокаТовары.Количество));
    Отказ = Истина;
    Иначе
    Движение = Движения.ТоварыВРезерве.Добавить();
    Движение.ВидДвижения = ВидДвиженияНакопления.Приход;
    Движение.Период = Дата;
    Движение.Номенклатура = ТекСтрокаТовары.Номенклатура;
    Движение.ДокументРезерва = Ссылка;
    Движение.Количество = ТекСтрокаТовары.Количество;  
    КонецЕсли;
    КонецЦикла;
    В документ реализации добавила реквизит Заказ. В событии ПриЗаписи если заказ заполнен проверяю чтобы табличная часть не превышала остатки из регистра Резервы по выбранному заказу(если вдруг часть заказа уже списана). Тут вначале накладываю исключительную блокировку на номенклатуру в регистре ТоварыВРезерве, находящуюся в табличной части. В обработке проведения блокирую ОстаткиТоваров через БлокироватьДляИзменения. Далее в подписке на событие в проверке остатков добавила еще и регистр ТоварыВРезерве. Отнимаю от остатка из регистра ОстаткиТоваров резерв по этому товару если заказ в регистре <> заказу в документе. При успешном проведении снимаю резерв.
    Источник.Запрос.Текст =
    “ВЫБРАТЬ
    | Товары.Номенклатура КАК Товар
    |ПОМЕСТИТЬ СписокТоваров
    |ИЗ
    | (ВЫБРАТЬ
    |  РеализацияТоваровИУслугТовары.Номенклатура КАК Номенклатура,
    |  РеализацияТоваровИУслугТовары.Количество КАК Количество
    | ИЗ
    |  Документ.РеализацияТоваровИУслуг.Товары КАК РеализацияТоваровИУслугТовары
    | ГДЕ
    |  РеализацияТоваровИУслугТовары.Ссылка = &Ссылка) КАК Товары
    |  ЛЕВОЕ СОЕДИНЕНИЕ ДвижениеТоваров КАК ДвижениеТоваров
    |  ПО Товары.Номенклатура = ДвижениеТоваров.Номенклатура
    |ГДЕ
    | (Товары.Количество <> ДвижениеТоваров.Количество
    |   ИЛИ ДвижениеТоваров.Номенклатура ЕСТЬ NULL )
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    | ТоварыВРезервеОстатки.Номенклатура,
    | ТоварыВРезервеОстатки.КоличествоОстаток КАК Резерв
    |ПОМЕСТИТЬ СписокРезерв
    |ИЗ
    | РегистрНакопления.ТоварыВРезерве.Остатки(
    |   ,
    |   Номенклатура В
    |     (ВЫБРАТЬ
    |      Т.Товар
    |     ИЗ
    |      СписокТоваров КАК Т)
    |    И ДокументРезерва <> &Заказ) КАК ТоварыВРезервеОстатки
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    | Остатки.Номенклатура,
    | Остатки.КоличествоОстаток – Остатки.Резерв КАК КоличествоОстаток
    |ИЗ
    | (ВЫБРАТЬ
    |  ЕСТЬNULL(ОстаткиТоваровОстатки.Номенклатура, СписокРезерв.Номенклатура) КАК Номенклатура,
    |  ЕСТЬNULL(ОстаткиТоваровОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
    |  ЕСТЬNULL(СписокРезерв.Резерв, 0) КАК Резерв
    | ИЗ
    |  РегистрНакопления.ОстаткиТоваров.Остатки(
    |    ,
    |    Номенклатура В
    |     (ВЫБРАТЬ
    |      Т.Товар
    |     ИЗ
    |      СписокТоваров КАК Т)) КАК ОстаткиТоваровОстатки
    |   ПОЛНОЕ СОЕДИНЕНИЕ СписокРезерв КАК СписокРезерв
    |   ПО ОстаткиТоваровОстатки.Номенклатура = СписокРезерв.Номенклатура) КАК Остатки
    |ГДЕ
    | Остатки.КоличествоОстаток – Остатки.Резерв < 0”;

  5. Добавим документ ЗаказПокупателя, реквизит Контрагент, табличная часть Товары с реквизитами Номенклатура, Количество. Для учета резервов добавим регистр накопления Резервы, измерение ЗаказПокупателя, ресурс Количество. Регистраторы – ЗаказПокупателя (приход), РеализацияТоваровИУслуг (расход). Свободные остатки получаем как разницу между количеством по регистрам Остатки и Резервы. При проведении документа ЗаказПокупателя выполняем контроль остатков с учетом резервов.
    В табличную часть документа реализации добавим реквизит ЗаказПокупателя. Добавим ввод на основании ЗаказаПокупателя или заполнение табличной части по заказу.
    Разрешим дубли по номенклатуре в табличной части для случаев списания из резерва и из свободных остатков. 
    Движения по регистру остатков в обработке проведения Реализации товаров и услуг группируем по номенклатуре:

    Движения.ОстаткиТоваров.Записывать = Истина;

    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки=Блокировка.Добавить(“РегистрНакопления.ОстаткиТоваров”);
    ЭлементБлокировки.ИсточникДанных=Товары;
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных(“Номенклатура”, “Номенклатура”);
    Блокировка.Заблокировать();

    Запрос = Новый Запрос;
    Запрос.Текст =
    “ВЫБРАТЬ
    | РеализацияТоваровИУслугТовары.Номенклатура,
    | СУММА(РеализацияТоваровИУслугТовары.Количество) КАК Количество
    |ИЗ
    | Документ.РеализацияТоваровИУслуг.Товары КАК РеализацияТоваровИУслугТовары
    |ГДЕ
    | РеализацияТоваровИУслугТовары.Ссылка = &Ссылка
    |
    |СГРУППИРОВАТЬ ПО
    | РеализацияТоваровИУслугТовары.Номенклатура”;
    Запрос.УстановитьПараметр(“Ссылка”, Ссылка);
    Результат = Запрос.Выполнить();

    Выборка = Результат.Выбрать();

    Пока Выборка.Следующий() Цикл
    Движение = Движения.ОстаткиТоваров.Добавить();
    Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
    Движение.Период = Дата;
    Движение.Номенклатура = Выборка.Номенклатура;
    Движение.Количество = Выборка.Количество;
    КонецЦикла;

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

    Источник.Движения.Резервы.Записывать = Истина;
    Для Каждого ТекСтрокаТовары Из Источник.Товары Цикл
    Если ЗначениеЗаполнено(ТекСтрокаТовары.ЗаказПокупателя) тогда
    Движение = Источник.Движения.Резервы.Добавить();
    Движение.ВидДвижения = ВидДвиженияНакопления.Расход;
    Движение.Период = Источник.Дата;
    Движение.Номенклатура = ТекСтрокаТовары.Номенклатура;
    Движение.ЗаказПокупателя = ТекСтрокаТовары.ЗаказПокупателя;
    Движение.Контрагент = Источник.Контрагент;
    Движение.Количество = ТекСтрокаТовары.Количество;
    КонецЕсли;
    КонецЦикла;
    Источник.Движения.Резервы.БлокироватьДляИзменения=истина;
    Источник.Движения.Резервы.Записать();

    Запрос = Новый Запрос;
    МенеджерВТ = Новый МенеджерВременныхТаблиц;
    Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
    Запрос.Текст =
    “ВЫБРАТЬ
    | РеализацияТоваровИУслугТовары.ЗаказПокупателя КАК ЗаказПокупателя
    |ПОМЕСТИТЬ Заказы
    |ИЗ
    | Документ.РеализацияТоваровИУслуг.Товары КАК РеализацияТоваровИУслугТовары
    |ГДЕ
    | РеализацияТоваровИУслугТовары.Ссылка = &Ссылка
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    | РезервыОстатки.Номенклатура,
    | РезервыОстатки.ЗаказПокупателя,
    | РезервыОстатки.КоличествоОстаток
    |ИЗ
    | РегистрНакопления.Резервы.Остатки(
    | &МоментВремени,
    | ЗаказПокупателя В
    | (ВЫБРАТЬ РАЗЛИЧНЫЕ
    | Заказы.ЗаказПокупателя
    | ИЗ
    | Заказы КАК Заказы)) КАК РезервыОстатки
    |ГДЕ
    | РезервыОстатки.КоличествоОстаток < 0”;

    Запрос.УстановитьПараметр(“МоментВремени”, Новый Граница(Источник.МоментВремени(), ВидГраницы.Включая));
    Запрос.УстановитьПараметр(“Ссылка”, Источник.Ссылка);

    Результат = Запрос.Выполнить();

    Если НЕ Результат.Пустой() Тогда
    Отказ = Истина;
    ВыборкаДетальныеЗаписи = Результат.Выбрать();
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    Сообщить(“Образовались отрицательные остатки резервов по товару “+ВыборкаДетальныеЗаписи.Номенклатура+” в количестве “+ВыборкаДетальныеЗаписи.КоличествоОстаток +” по заказу “+ВыборкаДетальныеЗаписи.ЗаказПокупателя);
    КонецЦикла;
    Иначе
    Отказ = Ложь;
    КонецЕсли;

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

    Запрос.Текст =
    “ВЫБРАТЬ
    | ОстаткиТоваровОстатки.Номенклатура КАК Номенклатура,
    | ОстаткиТоваровОстатки.КоличествоОстаток – ЕСТЬNULL(РезервыОстатки.КоличествоОстаток, 0) КАК КоличествоОстаток,
    | ОстаткиТоваровОстатки.КоличествоОстаток КАК Остатки,
    | РезервыОстатки.КоличествоОстаток КАК Резервы
    |ИЗ
    | РегистрНакопления.ОстаткиТоваров.Остатки(
    | &МоментВремени,
    | Номенклатура В
    | (ВЫБРАТЬ
    | Т.Номенклатура
    | ИЗ
    | Товары КАК Т)) КАК ОстаткиТоваровОстатки
    | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Резервы.Остатки(
    | &МоментВремени,
    | Номенклатура В
    | (ВЫБРАТЬ
    | Т.Номенклатура
    | ИЗ
    | Товары КАК Т)) КАК РезервыОстатки
    | ПО ОстаткиТоваровОстатки.Номенклатура = РезервыОстатки.Номенклатура
    |ГДЕ
    | ОстаткиТоваровОстатки.КоличествоОстаток – ЕСТЬNULL(РезервыОстатки.КоличествоОстаток, 0) < 0”;
    Запрос.УстановитьПараметр(“МоментВремени”, Новый Граница(Источник.МоментВремени(), ВидГраницы.Включая));
    Результат = Запрос.Выполнить();

    Если НЕ Результат.Пустой() Тогда
    Отказ = Истина;
    ВыборкаДетальныеЗаписи = Результат.Выбрать();
    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    Сообщить(“Образовались отрицательные остатки по товару “+ВыборкаДетальныеЗаписи.Номенклатура
    +” в количестве “+ВыборкаДетальныеЗаписи.КоличествоОстаток
    + “, в т.ч. остатки “+ВыборкаДетальныеЗаписи.Остатки+ “, резервы “+ ВыборкаДетальныеЗаписи.Резервы);
    КонецЦикла;
    Иначе
    Отказ = Ложь;
    КонецЕсли;

  6. Задание выполнено.
    Создан новый документ ЗаказПокупателя, новый регистр накопление РезервыТоваров (измерения – Номенклатура, Заказ;  ресурс – Количество). Также в док-т РеализацияТоваровИУслуг в табл. часть Товары добавлен реквизит Заказ.
    Реализован ввод и заполнение документа РеализацияТоваров на основании Заказа, при этом в табл. часть реализации автоматически прописывается заказ-основание.
    При проведении документа заказа товар списывается по регистру ОстаткиТоваров и приходуется по регистру РезервыТоваров. Таким образом регистр ОстаткиТоваров теперь хранит “свободные” остатки товаров, не относящиеся ни к одному резерву. Такой подход позволил решить задачу довольно просто, после предыдущего задания потребовалось внести немного изменений.
    Документ реализации списывает товар в зависимости от заполненности поля Заказ – если заполнено, то по рег. РезервыТоваров, если нет – то свободные остатки по рег. ОстаткиТоваров.
    В источник для подписки на событие ПередЗаписью и ПриПроведении документов расхода добавлен ЗаказПокупателя, тем самым сразу получаем контроль правильности резервов по “новой” технологии, не получится поставить в резерв товар в количестве, превышающим свободный остаток. Также в этих обработчиках анализируются только товары, списывающиеся из свободных остатков. Если в табл. части документа нет поля Заказ, то это корректно учитывается (то есть не потеряна универсальность подписок).
    Для контроля возможного превышения имеющихся резервов при списании добавлена еще одна подписка, источниками для которой будут все документы, имеющие возможность списывать товар по заказам. В этой подписке также реализован контроль проведения по “новой” технологии.
    Для обеспечения корректности в клиент-серверном варианте в обработчике контроля свободных остатков устанавливается управляемая блокировка, источником данных для которой служит таблица значений, содержащая контролируемую номенклатуру. В обработчике контроля остатков резервов просто при записи набора записей устанавливается поле БлокироватьДляИзменения в значение Истина.

  7. Домашняя работа выполнена.
    1. Создан новый документ Заказ(Рекв. Контрагент, тч Товары: Номенклатура, Количество) , регистр накопления с видом остатки Заказы(изм.  Заказ, Номенклатура, Количество). В тч Товары док-та Реализация добавлен реквизит Заказ.
    2. В ОбработкеПроведения док-та Заказ вставлен код формирования движений+контроль остатков с учетом уже существующих заказов
    <code>
    Запрос = Новый Запрос;
    Запрос.Текст = “ВЫБРАТЬ
    | ЗаказТовары.НомерСтроки КАК НомерСтроки,
    | ЗаказТовары.Ссылка.Дата КАК Период,
    | ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход) КАК ВидДвижения,
    | ЗаказТовары.Ссылка.Организация,
    | ЗаказТовары.Ссылка КАК Заказ,
    | ЗаказТовары.Номенклатура,
    | ЗаказТовары.Количество
    |ИЗ
    | Документ.Заказ.Товары КАК ЗаказТовары
    |ГДЕ
    | ЗаказТовары.Ссылка = &Ссылка
    |
    |УПОРЯДОЧИТЬ ПО
    | НомерСтроки”;
    Запрос.УстановитьПараметр(“Ссылка”, Ссылка);

    РезультатЗапроса = Запрос.Выполнить();

    ДвиженияЗаказыПокупателей = Движения.Заказы;
    ДвиженияЗаказыПокупателей.Загрузить(РезультатЗапроса.Выгрузить());
    ДвиженияЗаказыПокупателей.Записать();

    Запрос = Новый Запрос;
    Запрос.Текст =
    “ВЫБРАТЬ РАЗЛИЧНЫЕ
    | ЗаказТовары.Номенклатура
    |ПОМЕСТИТЬ Товары
    |ИЗ
    | Документ.Заказ.Товары КАК ЗаказТовары
    |ГДЕ
    | ЗаказТовары.Ссылка = &Ссылка
    |
    |СГРУППИРОВАТЬ ПО
    | ЗаказТовары.Номенклатура
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    | Товары.Номенклатура,
    | ЕСТЬNULL(ОстаткиТоваровОстатки.КоличествоОстаток, 0) – ЕСТЬNULL(ЗаказыОстатки.КоличествоОстаток, 0) КАК Нехватка
    |ИЗ
    | Товары КАК Товары
    | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки(
    | &Граница,
    | Номенклатура В
    | (ВЫБРАТЬ
    | Товары.Номенклатура
    | ИЗ
    | Товары КАК Товары)) КАК ОстаткиТоваровОстатки
    | ПО Товары.Номенклатура = ОстаткиТоваровОстатки.Номенклатура
    | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Заказы.Остатки(
    | &Граница,
    | Номенклатура В
    | (ВЫБРАТЬ
    | Товары.Номенклатура
    | ИЗ
    | Товары КАК Товары)) КАК ЗаказыОстатки
    | ПО Товары.Номенклатура = ЗаказыОстатки.Номенклатура
    |ГДЕ
    | ЕСТЬNULL(ОстаткиТоваровОстатки.КоличествоОстаток, 0) – ЕСТЬNULL(ЗаказыОстатки.КоличествоОстаток, 0) < 0”;
    Запрос.УстановитьПараметр(“Ссылка”, Ссылка);
    Запрос.УстановитьПараметр(“Граница”, Новый Граница(МоментВремени(), ВидГраницы.Включая));

    РезультатЗапроса = Запрос.Выполнить();
    Если НЕ РезультатЗапроса.Пустой() Тогда

    Выборка = РезультатЗапроса.Выбрать();
    Пока Выборка.Следующий() Цикл

    Отказ = Истина;
    Сообщить(“Нехватка ” + Выборка.Номенклатура + ” в количестве ” + Строка(-Выборка.Нехватка), СтатусСообщения.Обычное);

    КонецЦикла;

    КонецЕсли;
    </code>
    3. В контроле остатков при списания также учитываю данные по рег-ру Заказы (за искл. тех записей, Заказы которые выбраны в реализации). Если контроль пройден, то гашу резервы по выбранным в документе Заказам.
    Организовать клиент-серверный вариант дома, к сожалению, нет возможности. В любом случае, в запросах, которые считывают остатки из регистров накопления организовал бы Блокировку записей регистра по полям номенклатуры, используемых при проведении.

  8. Кононов Сергей 19.06.2011 в 13:36

    Задание выполнил.
    1. Создал документ ЗаказКонтрагента. Создал регистр накопления ТоварыВРезерве, с следующими измерениями: Номенклатура и ДокументРезерва. Ресурс Количество. Регистраторами этого регистра являются ЗаказКонтрагента и РеализацияТоваров. В документе РеализацияТоваров я в табличной части создал еще один реквизит ЗаказКонтрагента.
    Далее я организовал проведение документа ЗаказКонтрагента и контроль остатков вынес в подписку на события туда же куда и контроль остатков при проведении документа Реализации. При проведении Заказа или реализации я блокирую соответс. записи регистров остатки и товары в резерве и контроль осуществляю в подписке на событии:
    Приведу обработку проведения Заказа
    <cod>
     
    Процедура ОбработкаПроведения(Отказ, РежимПроведения)

    Запрос = Новый Запрос;
    ВТ = Новый МенеджерВременныхТаблиц;
    Запрос.МенеджерВременныхТаблиц = ВТ;
    Запрос.Текст =
    “ВЫБРАТЬ РАЗЛИЧНЫЕ
    | ЗаказКонтрагентаТовары.Номенклатура
    |ПОМЕСТИТЬ Товары
    |ИЗ
    | Документ.ЗаказКонтрагента.Товары КАК ЗаказКонтрагентаТовары
    |ГДЕ
    | ЗаказКонтрагентаТовары.Ссылка = &Ссылка
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    | ЗаказКонтрагентаТовары.Номенклатура,
    | ЗаказКонтрагентаТовары.Количество,
    | ЗаказКонтрагентаТовары.Ссылка КАК ДокументРезерва,
    | ЗаказКонтрагентаТовары.Ссылка.Дата КАК Период
    |ИЗ
    | Документ.ЗаказКонтрагента.Товары КАК ЗаказКонтрагентаТовары
    |ГДЕ
    | ЗаказКонтрагентаТовары.Ссылка = &Ссылка”;
    Запрос.УстановитьПараметр(“Ссылка”, Ссылка);
    Результат = Запрос.Выполнить();
    ДополнительныеСвойства.Вставить(“МенеджерВТ”, Запрос.МенеджерВременныхТаблиц);

    Движения.ТоварыВРезерве.Загрузить(Результат.Выгрузить());

    Движения.ТоварыВРезерве.Записать();
    Движения.ТоварыВРезерве.БлокироватьДляИзменения = Истина;

    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить(“РегистрНакопления.ОстаткиТоваров”);
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    ЭлементБлокировки.ИсточникДанных = Товары;
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных(“Номенклатура”, “Номенклатура”);
    Блокировка.Заблокировать();

    КонецПроцедуры
    Процедура ОбработкаПроведения(Отказ, РежимПроведения)

    Запрос = Новый Запрос;
    ВТ = Новый МенеджерВременныхТаблиц;
    Запрос.МенеджерВременныхТаблиц = ВТ;
    Запрос.Текст =
    “ВЫБРАТЬ РАЗЛИЧНЫЕ
    | ЗаказКонтрагентаТовары.Номенклатура
    |ПОМЕСТИТЬ Товары
    |ИЗ
    | Документ.ЗаказКонтрагента.Товары КАК ЗаказКонтрагентаТовары
    |ГДЕ
    | ЗаказКонтрагентаТовары.Ссылка = &Ссылка
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    | ЗаказКонтрагентаТовары.Номенклатура,
    | ЗаказКонтрагентаТовары.Количество,
    | ЗаказКонтрагентаТовары.Ссылка КАК ДокументРезерва,
    | ЗаказКонтрагентаТовары.Ссылка.Дата КАК Период
    |ИЗ
    | Документ.ЗаказКонтрагента.Товары КАК ЗаказКонтрагентаТовары
    |ГДЕ
    | ЗаказКонтрагентаТовары.Ссылка = &Ссылка”;
     
    Запрос.УстановитьПараметр(“Ссылка”, Ссылка);
     
    Результат = Запрос.Выполнить();
     
    ДополнительныеСвойства.Вставить(“МенеджерВТ”, Запрос.МенеджерВременныхТаблиц);

    Движения.ТоварыВРезерве.Загрузить(Результат.Выгрузить());

    Движения.ТоварыВРезерве.Записать();
    Движения.ТоварыВРезерве.БлокироватьДляИзменения = Истина;

    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить(“РегистрНакопления.ОстаткиТоваров”);
    ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
    ЭлементБлокировки.ИсточникДанных = Товары;
    ЭлементБлокировки.ИспользоватьИзИсточникаДанных(“Номенклатура”, “Номенклатура”);
    Блокировка.Заблокировать();

    КонецПроцедуры
    </cod>

    Приведу обработку проведения Реализации:
    <cod>

    Процедура ОбработкаПроведения(Отказ, Режим)

    Движения.Взаиморасчеты.Записывать = Истина;
    Движение = Движения.Взаиморасчеты.ДобавитьПриход();
    Движение.Период = Дата;
    Движение.Контрагент = Контрагент;
    Движение.Сумма = Товары.Итог(“Сумма”);

    Запрос = Новый Запрос;
    ВТ = Новый МенеджерВременныхТаблиц;
    Запрос.МенеджерВременныхТаблиц = ВТ;
    Запрос.Текст =
    “ВЫБРАТЬ
    | РеализацияТоваровИУслугТовары.Номенклатура
    |ПОМЕСТИТЬ Товары
    |ИЗ
    | Документ.РеализацияТоваровИУслуг.Товары КАК РеализацияТоваровИУслугТовары
    | ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров КАК ОстаткиТоваров
    | ПО РеализацияТоваровИУслугТовары.Ссылка = ОстаткиТоваров.Регистратор
    | И РеализацияТоваровИУслугТовары.Номенклатура = ОстаткиТоваров.Номенклатура
    | И РеализацияТоваровИУслугТовары.Количество = ОстаткиТоваров.Количество
    |ГДЕ
    | РеализацияТоваровИУслугТовары.Ссылка = &Ссылка
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    | РеализацияТоваровИУслугТовары.Номенклатура,
    |   РеализацияТоваровИУслугТовары.Заказ Как ДокументРезерва
    |ПОМЕСТИТЬ ИзмененныеТовары
    |ИЗ
    | Документ.РеализацияТоваровИУслуг.Товары КАК РеализацияТоваровИУслугТовары
    |ГДЕ
    | РеализацияТоваровИУслугТовары.Ссылка = &Ссылка
    | И (НЕ РеализацияТоваровИУслугТовары.Номенклатура В
    | (ВЫБРАТЬ
    | Т.Номенклатура
    | ИЗ
    | Товары КАК Т))
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    | РеализацияТоваровИУслугТовары.Количество,
    | РеализацияТоваровИУслугТовары.Номенклатура,
    | ЗНАЧЕНИЕ(ВидДвиженияНакопления.Расход) КАК ВидДвижения,
    | РеализацияТоваровИУслугТовары.Ссылка.Дата КАК Период
    |ИЗ
    | Документ.РеализацияТоваровИУслуг.Товары КАК РеализацияТоваровИУслугТовары
    |ГДЕ
    | РеализацияТоваровИУслугТовары.Ссылка = &Ссылка
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    | РеализацияТоваровИУслугТовары.Номенклатура,
    | РеализацияТоваровИУслугТовары.Заказ КАК ДокументРезерва,
    | РеализацияТоваровИУслугТовары.Количество,
    | ЗНАЧЕНИЕ(ВидДвиженияНакопления.Расход) КАК ВидДвижения,
    | РеализацияТоваровИУслугТовары.Ссылка.Дата КАК Период
    |ИЗ
    | Документ.РеализацияТоваровИУслуг.Товары КАК РеализацияТоваровИУслугТовары
    |ГДЕ
    | (НЕ РеализацияТоваровИУслугТовары.Заказ ЕСТЬ NULL )
    | И РеализацияТоваровИУслугТовары.Ссылка = &Ссылка”;

    Запрос.УстановитьПараметр(“Ссылка”, Ссылка);
    Результат = Запрос.ВыполнитьПакет();
    ТаблицаЗаписей = Результат[2].Выгрузить();

    ДополнительныеСвойства.Вставить(“МенеджерВТ”, Запрос.МенеджерВременныхТаблиц);

    Движения.Продажи.Записывать = Истина;
    Движения.Продажи.Загрузить(ТаблицаЗаписей);

    Движения.ОстаткиТоваров.Загрузить(ТаблицаЗаписей);

    ТаблицаЗаписей = Результат[3].Выгрузить();
    Движения.ТоварыВРезерве.Загрузить(ТаблицаЗаписей);

    Движения.ОстаткиТоваров.Записать();
    Движения.ТоварыВРезерве.Записать();

    Движения.ТоварыВРезерве.БлокироватьДляИзменения = Истина;
    Движения.ОстаткиТоваров.БлокироватьДляИзменения = Истина;

    КонецПроцедуры

    </cod>

    И код самой подписки:
    <cod>

    Процедура КонтрольОстатковОбработкаПроведения(Источник, Отказ, РежимПроведения) Экспорт

    Запрос = Новый Запрос;

    Запрос.УстановитьПараметр(“МоментВремени”, Новый Граница(Источник.Дата, ВидГраницы.Включая));
    Запрос.УстановитьПараметр(“Ссылка”, Источник.Ссылка);
    Запрос.МенеджерВременныхТаблиц = Источник.ДополнительныеСвойства.МенеджерВТ;

    Если ТипЗнч(Источник) = Тип(“ДокументОбъект.РеализацияТоваровИУслуг”) Тогда
    Запрос.Текст =
    “ВЫБРАТЬ
    | ОстаткиТоваровОстатки.Номенклатура,
    | ОстаткиТоваровОстатки.КоличествоОстаток
    |ИЗ
    | РегистрНакопления.ОстаткиТоваров.Остатки(
    | &МоментВремени,
    | Номенклатура В
    | (ВЫБРАТЬ РАЗЛИЧНЫЕ
    | Т.Номенклатура
    | ИЗ
    | ИзмененныеТовары КАК Т)) КАК ОстаткиТоваровОстатки
    |ГДЕ
    | ОстаткиТоваровОстатки.КоличествоОстаток < 0
    |
    |ОБЪЕДИНИТЬ ВСЕ
    |
    |ВЫБРАТЬ
    | ТоварыВРезервеОстатки.Номенклатура,
    | ТоварыВРезервеОстатки.КоличествоОстаток
    |ИЗ
    | РегистрНакопления.ТоварыВРезерве.Остатки(
    | &МоментВремени,
    | (Номенклатура, ДокументРезерва) В
    | (ВЫБРАТЬ РАЗЛИЧНЫЕ
    | Т.Номенклатура,
    | Т.ДокументРезерва
    | ИЗ
    | ИзмененныеТовары КАК Т)) КАК ТоварыВРезервеОстатки
    |ГДЕ
    | ТоварыВРезервеОстатки.КоличествоОстаток < 0”;

    ИначеЕсли ТипЗнч(Источник) = Тип(“ДокументОбъект.ЗаказКонтрагента”) Тогда
    Запрос.Текст = “ВЫБРАТЬ
    | ТоварыВРезервеОстатки.Номенклатура,
    | ЕСТЬNULL(ОстаткиТоваровОстатки.КоличествоОстаток, 0) – ТоварыВРезервеОстатки.КоличествоОстаток КАК КоличествоОстаток
    |ИЗ
    | РегистрНакопления.ТоварыВРезерве.Остатки(
    | &МоментВремени,
    | Номенклатура В
    | (ВЫБРАТЬ РАЗЛИЧНЫЕ
    | Т.Номенклатура
    | ИЗ
    | Товары КАК Т)) КАК ТоварыВРезервеОстатки
    | ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиТоваров.Остатки(
    | &МоментВремени,
    | Номенклатура В
    | (ВЫБРАТЬ РАЗЛИЧНЫЕ
    | Т.Номенклатура
    | ИЗ
    | Товары КАК Т)) КАК ОстаткиТоваровОстатки
    | ПО ТоварыВРезервеОстатки.Номенклатура = ОстаткиТоваровОстатки.Номенклатура
    |ГДЕ
    | ЕСТЬNULL(ОстаткиТоваровОстатки.КоличествоОстаток, 0) – ТоварыВРезервеОстатки.КоличествоОстаток < 0”
    КонецЕсли;

    Результат = Запрос.Выполнить();

    Если Не Результат.Пустой() Тогда
    Отказ = Истина;
    ВыборкаДетальныеЗаписи = Результат.Выбрать();

    Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    Сообщить(“Не хватает остатков по номенклатуре ” + ВыборкаДетальныеЗаписи.Номенклатура + ” в кол-ве: ”
    + (-ВыборкаДетальныеЗаписи.КоличествоОстаток));
    КонецЦикла;

    КонецЕсли;

    КонецПроцедуры

    </cod>

  9. Задача решена следующим образом. Создан регистр накопления, который хранит информацию о товарах в резерве (измерения “Номенклатура”, “Заказ”, ресурс “Количество”). Также в конфигурации имеется регистр “СвободныеОстаткиТоваров”, который хранит информацию о свободных остатках (измерение “Номенклатура”, ресурс “Количество”). Создан документ “ЗаказПокупателя”; в шапке указывается контрагент, а в табличной части – номенклатура и количество. При проведении документ проверяет, есть ли необходимое для резервирования количество товара в свободном остатке. Если есть, то делается 2 записи: первая запись расходует товар в нужном количестве из регистра свободных остатков, а вторая – приходует в регистр резервов с указанием ссылки на проводимый заказ.
    В табличную часть документа реализации добавлена колонка “Заказ”. При этом можно выбирать только заказы того контрагента, который указан в шапке документа реализации. При проведении контроль остатков осуществляется сразу по 2-м регистрам. Если в строке табличной части заказ не указан, то считается, что товар списывается из свободного остатка.
    Контроль остатков выполняется по схеме: сначала запись движений в регистр, потом поиск отрицательных остатков. Перед вызовом метода “Записать” набора записей, свойство “БлокироватьДляИзменения” выставляется в значение “Истина”.

  10. Задание выполнено.  :)
    Создан документ “Заказ покупателя”. Заказ выполняет резерв товара по указанному складу, учитывая свободные остатки на складе. На основании него можно создать расходную накладную. Расходная накладная при вводе на основании дополнительно заполняет реквизит табличной части “Заказ”. При проведении реализации учитываются:
    – если указан заказ в ТЧ: отсутствие отрицательных остатков по резервам и/или остаткам
    – если не указан заказ в ТЧ: отсутствие отрицательных остатков по регистру остатков
    Т.е. согласно задания работа ведется со складами, то пришлось в РН остатков и резервов добавить измерение “Склад” и при проведении документов учитывать его (добавлять в движение, а также при контроле остатков)
    Т.к. согласно задания (в качестве примера) необходимо было отгрузить два одинаковых товара (один по заказу, другой без заказа), то возникла проблемка при логгировании цены (то, что было при выполнении задания №1). Т.е. нельзя было провести документ с несколькими одинаковыми товарами. Поэтому логгирование пришлось отключить.  :)
    Очень интересный последний пункт в задании. Ведь не у всех есть Сервер 1С.  :)

  11. В задании ошибочка.  :)
    >покупатель Алхимов зарезервировал 4 шт., значит, в свободном остатке осталось 6 единиц
    >необходимо сделать отгрузку 6 единиц по заказу и 4 единиц из свободного остатка (без указания заказа).