# Практические примеры
В этом разделе рассмотрены два практических сценария: автоматическое создание пунктов маршрута для складов и обработка перехода состояний документов с валидацией бизнес-правил.

## Создание пункта маршрута для каждого склада

**1. SQL-запрос для получения списка складов.** Получим ID и коды складов, у которых тип объекта "Склад" (stock) или "Склад в пути" (StockInWay). Полученные записи преобразуем в список с помощью метода `asList()`.
```
var sqlStock = sql(`
    SELECT stk.id as id, stk.sCode as sCode FROM stk_stock stk
    JOIN btk_objecttype ot ON ot.id = stk.idObjectType
    where ot.sCode = 'stock' OR ot.sCode = 'StockInWay'
`).asList()
```

**2. Поиск пункта маршрута по коду склада.** С помощью цикла `for` сделаем преобразование над полученными записями. По коду нашего склада получим id пункта маршрута.
```
var sqlStock = sql(`
    SELECT stk.id as id, stk.sCode as sCode FROM stk_stock stk
    JOIN btk_objecttype ot ON ot.id = stk.idObjectType
    where ot.sCode = 'stock' OR ot.sCode = 'StockInWay'
`).asList()

for(r: sqlStock) {
    var idvPoint = Tms_PointApi.findByMnemoCode(r.scode);
}
```
**3. Создание нового пункта маршрута (если не найден).** Если вернувшееся значение пункта маршрута равно null, то нужно создать его, заполнив код, название и привязку текущего склада.
```
var sqlStock = sql(`
    SELECT stk.id as id, stk.sCode as sCode FROM stk_stock stk
    JOIN btk_objecttype ot ON ot.id = stk.idObjectType
    where ot.sCode = 'stock' OR ot.sCode = 'StockInWay'
`).asList()

for(r: sqlStock) {
    var idvPoint = Tms_PointApi.findByMnemoCode(r.scode);
    if (isNull(idvPoint)) {
        var ropPoint = Tms_PointApi.insert();
        Tms_PointApi.setsCode(ropPoint, r.scode);
        Tms_PointApi.setsCaption(ropPoint, r.scode);
        Tms_PointApi.setidStock(ropPoint, r.id);
    }
}
```
**4. Обновление существующего пункта маршрута (если не привязан к складу).** Если полученный пункт маршрута существует, то загружаем его по полученному ранее id. Далее проверяем у полученного пункта маршрута привязку к складу, если значение равно null, то устанавливаем значение текущего склада.
```
var sqlStock = sql(`
    SELECT stk.id as id, stk.sCode as sCode FROM stk_stock stk
    JOIN btk_objecttype ot ON ot.id = stk.idObjectType
    where ot.sCode = 'stock' OR ot.sCode = 'StockInWay'
`).asList()

for(r: sqlStock) {
    var idvPoint = Tms_PointApi.findByMnemoCode(r.scode);
    if (isNull(idvPoint)) {
        var ropPoint = Tms_PointApi.insert();
        Tms_PointApi.setsCode(ropPoint, r.scode);
        Tms_PointApi.setsCaption(ropPoint, r.scode);
        Tms_PointApi.setidStock(ropPoint, r.id);
    } else {
        var ropPointW = Tms_PointApi.load(idvPoint);
        if (isNull(ropPointW.idStock)) {
            Tms_PointApi.setidStock(ropPointW, r.id);
        }
    }
}
```

## Пример расширения обработки состояния документа

**1. Проверка на пустое старое значение:**
```
if(isNull(oldValue)) return 0;
```
Если текущее состояние документа `oldValue` не задано, обработка прекращается (возвращается 0).

**2. Получение порядковых номеров состояний:**
```
var idStateFromOrder = Btk_ClassStateApi.getOrder(oldValue);
var idStateToOrder = Btk_ClassStateApi.getOrder(value);
```
- idStateFromOrder - порядковый номер старого состояния документа.
- idStateToOrder - порядковый номер нового состояния.

Получим текущее состояние документа, воспользовавшись API-методом класса состояния.

**3. Проверка условий для обработки:**
```
if(idStateFromOrder <= 100 && idStateToOrder > 100 && rop.idObjectType == Btk_ObjectTypeApi.findByMnemoCode("Tms_DeliveryAct"))
```
  - `idStateFromOrder <= 100` - проверяет, что текущее состояние документа имеет порядковый номер <= 100. Обычно это соответствует статусам "Аннулировано" или "Формируется".

  - `idStateToOrder > idStateFromOrder` - гарантирует, что новое состояние действительно является переходом ВВЕРХ по workflow. Исключает случаи, когда статус меняется на равный или более ранний.

  - `rop.idObjectType == Btk_ObjectTypeApi.findByMnemoCode("Tms_DeliveryAct")` - убеждается, что работаем именно с документом типа "Рейс" (Tms_DeliveryAct).

**4. Получение заказа (Stm_OrderOut):**
```
var ropOO = Stm_OrderOutApi.loadByGid(rop.gidSrc);
if(ropOO.idObjectType != Btk_ObjectTypeApi.findByMnemoCode("OrderOut_Service"))
```
Получаем ропу заказа с помощью Api-метода loadByGid по gidSrc(родитель) текущего документа. Если тип заказа **НЕ** "OrderOut_Service" (то есть это не сервисный заказ), выполняется дальнейшая проверка.

**5. Определение договора:**
```
var ropContract = null;
if(isNotNull(rop.idAddContract))
    ropContract = Cnt_ContractApi.load(rop.idAddContract);
else
    ropContract = Cnt_ContractApi.load(rop.idContract);
```
Если у заказа `rop` есть доп. договор `idAddContract`, он загружается. Иначе загружается основной договор (idContract).

**6. Проверка отложенного ценообразования:**
```
var bDeferredPricing = Cnt_ContractApi.getObjAttrValue(ropContract, "bDeferredPricing");
if(bDeferredPricing == true)
```
Получаем значение атрибута bDeferredPricing (флаг "Отложенное ценообразование"). Если флаг true, выполняется проверка даты.

**7. Проверка даты отложенного ценообразования:**
```
var dDeferredPricing = Stm_ActOutApi.getObjAttrValue(rop, "dDeferredPricing");
if(isNull(dDeferredPricing) || dDeferredPricing < sysDate())
    raise("Требуется выполнить корректировку цены");
```
Получаем дату dDeferredPricing (когда должна быть выполнена корректировка цены). Если дата **не задана** или **уже прошла**, выводится ошибка.

**Общий код:**
```
if(isNull(oldValue))return 0;
var idStateFromOrder = Btk_ClassStateApi.getOrder(oldValue)
var idStateToOrder = Btk_ClassStateApi.getOrder(value);

if(idStateFromOrder <= 100 && idStateToOrder > 100 && rop.idObjectType == Btk_ObjectTypeApi.findByMnemoCode("Tms_DeliveryAct")){
    var ropOO = Stm_OrderOutApi.loadByGid(rop.gidSrc)
    if(ropOO.idObjectType != Btk_ObjectTypeApi.findByMnemoCode("OrderOut_Service")){
        var ropContract = null
        if(isNotNull(rop.idAddContract))
            ropContract = Cnt_ContractApi.load(rop.idAddContract)
        else
            ropContract = Cnt_ContractApi.load(rop.idContract)
        var bDeferredPricing = Cnt_ContractApi.getObjAttrValue(ropContract, "bDeferredPricing")
        if(bDeferredPricing == true){
            var dDeferredPricing = Stm_ActOutApi.getObjAttrValue(rop, "dDeferredPricing")
            if(isNull(dDeferredPricing) || dDeferredPricing < sysDate()){
                raise("Требуется выполнить корректировку цены")
            }
        }
    }
}
```