← вся теориятеория к собесу · Проведение документов

Контроль остатков и резервы в 1С

разбор писал Даниил, автор Сеньорчика

Зачем это спрашивают

Контроль остатков отказывает в проведении, если расход уводит остаток в минус. Платформа сама этого не делает, поэтому собес проверяет, умеешь ли ты его написать, учесть резервы и показать пользователю внятную ошибку.

// Так спрашивают: «Как посчитать свободный остаток?» «Почему нельзя проверять остатки в форме?» «Что делать, если пользователи долго ждут блокировок?» «Как показать ошибку на конкретной строке?»

Свободный остаток

Резерв закрепляет часть остатка за заказом. Свободный остаток равен остатку минус резервы, и продать можно только его. Остатки и резервы лежат в разных регистрах, поэтому их соединяют левым соединением: у товара без резервов резерв придёт NULL, и его закрывают ЕСТЬNULL.

Без ЕСТЬNULL хлеб получил бы NULL вместо 10: вычитание NULL даёт NULL, и товар без резервов выглядел бы недоступным. Отгрузка по заказу уменьшает и остаток, и резерв. Если резерв не снять, свободный остаток навсегда занизится на отгруженное.

ВЫБРАТЬ
    Остатки.Номенклатура,
    Остатки.КоличествоОстаток - ЕСТЬNULL(Резервы.КоличествоОстаток, 0) КАК Свободно
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыВРезерве.Остатки КАК Резервы
        ПО Остатки.Номенклатура = Резервы.Номенклатура
            И Остатки.Склад = Резервы.Склад

Почему не в форме

Проверка в форме при выборе товара удобна пользователю, но ничего не гарантирует: форма видит остаток на момент открытия, а параллельно продают кассы и другие менеджеры. Гарантию даёт только проверка при проведении под блокировкой, внутри транзакции.

Минус бывает нормой: для виртуальных складов, товаров под заказ, комиссии. Такие склады исключают условием в запросе проверки, а не отключают контроль целиком.

Сообщение на строке

Пользователь должен увидеть, какая строка не прошла и сколько не хватает. Сообщение привязывают к полю табличной части путём вида Товары[3].Количество, и форма подсветит ячейку. В типовых на библиотеке стандартных подсистем (БСП) для этого есть ОбщегоНазначения.СообщитьПользователю:

Текст = СтрШаблон(НСтр("ru = 'Не хватает %1: нужно %2, свободно %3'"),
    Выборка.Номенклатура, Выборка.Нужно, Выборка.Свободно);
Поле = ОбщегоНазначенияКлиентСервер.ПутьКТабличнойЧасти("Товары", Выборка.НомерСтроки, "Количество");
ОбщегоНазначения.СообщитьПользователю(Текст, ЭтотОбъект, Поле, , Отказ);

Когда ждут блокировок

Ожидание блокировки равно времени транзакции того, кто её держит. Поэтому долгое ожидание лечат не отключением блокировок, а короткой транзакцией: без внешних вызовов, без записи справочников, без запросов в цикле. Отключение блокировок возвращает гонки, и два документа снова спишут один остаток.

Как отвечать: «Как посчитать свободный остаток и где его проверять?»

Свободный остаток равен остатку на складе минус резервы. Беру виртуальную таблицу остатков склада и левым соединением резервы по товару и складу, резерв закрываю ЕСТЬNULL, иначе товар без резервов получит NULL. Проверяю при проведении под управляемой блокировкой, потому что форма не видит параллельных документов. А при отгрузке по заказу списываю и резерв, иначе свободный остаток занизится.

В ответе есть формула, техника соединения с ЕСТЬNULL, место проверки и побочный эффект отгрузки. Всё, на чём реально ломается контроль резервов.

На чём валят

  • −Проверяют остатки только в форме при выборе товара. Форма не видит параллельных документов. Проверка при проведении под блокировкой.
  • −Соединяют остатки с резервами без ЕСТЬNULL. Товар без резервов получит NULL. Резерв закрывают ЕСТЬNULL(…, 0).
  • −Отгружают по заказу и не снимают резерв. Свободный остаток занижается навсегда. Отгрузка списывает и остаток, и резерв.
  • −Отключают блокировки, чтобы не ждать. Возвращаются гонки и минусы. Сокращают транзакцию.

Проверь себя

Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.

  1. #oc_balance_control1 / 5
    Свободный остаток = остаток на складе минус резервы. Как получить его запросом?
    A)Сумма остатков и резервов
    B)Внутреннее соединение остатков и резервов по товару
    C)Остатки ЛЕВОЕ резервы, разность
    D)Остатки склада с условием по резервам в ГДЕ
    показать ответ и разбор
    +C)Остатки ЛЕВОЕ резервы, разность

    // разбор: Резервы есть не у каждого товара, поэтому остатки склада соединяют с резервами левым соединением и вычитают ЕСТЬNULL(Резерв, 0). Внутреннее соединение выкинет товары без резервов, сумма даст бессмыслицу. Аккуратнее — объединение двух таблиц с разными знаками и группировка.

  2. #oc_balance_control2 / 5
    Заказ клиента резервирует товар. Что должно произойти с резервом при отгрузке по этому заказу?
    A)Резерв сохраняется до закрытия заказа
    B)Резерв снимается, остаток уменьшается
    C)Резерв переходит на следующий заказ клиента
    D)Резерв остаётся, а остаток уменьшается вдвое
    показать ответ и разбор
    +B)Резерв снимается, остаток уменьшается

    // разбор: Отгрузка уменьшает фактический остаток и одновременно снимает резерв по заказу: товар ушёл к клиенту, держать его больше не нужно. Документ реализации пишет расход в регистр остатков и расход в регистр резервов по заказу. Если резерв не снять, свободный остаток занизится навсегда.

  3. #oc_balance_control3 / 5
    Документ задним числом списывает товар, на момент документа остаток есть, но на сегодня товара уже нет. Как поведёт себя контроль по текущему остатку?
    A)Откажет: итог уходит в минус
    B)Пропустит: на момент документа остаток есть
    C)Пропустит без проверки: документ прошлой датой
    D)Перепроведёт хвост
    показать ответ и разбор
    +A)Откажет: итог уходит в минус

    // разбор: Если проверять остаток на конец учёта, списание задним числом уведёт его в минус, и документ не проведётся. Если проверять на момент документа, он пройдёт, а минус появится у последующих операций. Выбор зависит от политики компании, но второй вариант требует перепроведения последующих документов.

  4. #oc_balance_control4 / 5
    Как сообщить пользователю о нехватке так, чтобы клик по сообщению вёл к строке табличной части?
    A)ПоказатьПредупреждение с номером строки на сервере
    B)Сообщить() с номером строки
    C)ВызватьИсключение с номером строки в тексте
    D)Сообщение с путём к полю строки
    показать ответ и разбор
    +D)Сообщение с путём к полю строки

    // разбор: Сообщение пользователю можно привязать к полю: объекту и пути вида Товары[3].Количество. Тогда клик переводит курсор на ячейку. В БСП это функция СообщитьПользователю с параметрами КлючДанных и Поле, внутри — объект СообщениеПользователю. Обычный Сообщить привязки не даёт.

  5. #oc_balance_control5 / 5
    Два кассира одновременно проводят чеки на последнюю единицу товара. Контроль по новой методике с БлокироватьДляИзменения. Что произойдёт?
    A)Второй проведётся раньше первого и заберёт товар
    B)Оба чека проведутся, остаток станет -1
    C)Оба получат отказ из-за конфликта
    D)Второй дождётся первого и получит отказ
    показать ответ и разбор
    +D)Второй дождётся первого и получит отказ

    // разбор: Первый чек пишет движения и блокирует сочетание товара и склада. Второй при записи своих движений ждёт снятия блокировки. Первый фиксируется с остатком 0, второй после ожидания записывает расход, проверка видит -1, и проведение отменяется.

дальше

Теорию прочитал. Навык ставится повторением

В Сеньорчике эта подтема идёт в ежедневных сессиях: движок возвращает её, пока ответы не станут уверенными, и ведёт прогресс отдельно по каждой подтеме. Теория внутри тоже бесплатна, бесплатная часть практики — одна сессия дня в сутки.