logo

[ELMA3] Создания функции генератора для EQL-запроса

В статье приведен пример создания собственной функции генератора для использования в EQL-запросах. В примере она используется для поиска исключений по договорам, вариантов использования может быть множество.

Глобальный модуль проверки наличия исключений по договорам лизинга

using System;
using System.Collections.Generic;
using System.Linq;
using EleWise.ELMA.API;
using System.Text;
using EleWise.ELMA.Model.Common;
using EleWise.ELMA.Model.Entities.EntityReferences;
using EleWise.ELMA.Model.Services;
using EleWise.ELMA.Model.Entities;
using EleWise.ELMA.Model.Managers;
using EleWise.ELMA.Model.Types.Settings;
using EleWise.ELMA.Model.Metadata;
using EleWise.ELMA.Services;
using EleWise.ELMA.Exceptions;
using EleWise.ELMA.ConfigurationModel;
using EleWise.ELMA.Templates;

namespace EntityExtension
{
    public static class Extension
    {
        /// <summary>
        /// EQL проверка наличия исключений
        /// </summary>
        /// <param name="elmaEntity - любая сущность для которой необходимо произвести поиск. В данном случае договора лизинга">this IEntity long</param>
        /// <param name="eqlQuery - строка EQL-запроса с пользовательскими функциями">string</param>
        /// <returns>bool</returns>
        public static bool CheckEqlRules(this IEntity<long> elmaEntity, string eqlQuery)
        {
            if (string.IsNullOrWhiteSpace(eqlQuery))
            {
                return true;
            }
			//Форматируем строку поиска с учетом пользовательских функций GetAdvancePermissionLeaseContract и GetLimitBalanceProvider
            TextTemplateGenerator textTemplateGenerator = new TextTemplateGenerator(eqlQuery, null, TemplateRenderMode.Default);
            eqlQuery = textTemplateGenerator.Generate(elmaEntity);
			
            var type = elmaEntity.GetType();
            var manager = ModelHelper.GetEntityManager(type);
            var filterType = ModelHelper.GetEntityFilterType(type);
            var filter = (IEntityFilter)InterfaceActivator.Create(filterType);
            filter.Query = string.Format("({0}) AND Id={1}", eqlQuery, elmaEntity.Id);
            var count = manager.Count(filter);
            if (count > 1)
            {
                throw new EQLException(eqlQuery, string.Format("Ошибка в запросе ({0}) для {1}, результат вернул {2} значений, а должен 1 или 0", eqlQuery, elmaEntity, count));
            }
            return count > 0;
        }
    }
}

Глобальный модуль создания функции генератора для EQL-запроса

namespace EntityExtension
{
    [Component]
    public class EntityTemplateGenerate : ITemplateGeneratorFunctionsContainer
    {
        /// <summary>
        /// Функция EQL для проверки Дата поставки - (Последняя дата аванса +1) меньше количества дней на Авансирование в Договоре лизинга
        /// </summary>
        /// <param name="context">Дата поставки;Блок Авансы</param>
        /// <returns>AdvancePermission</returns>
        public static FormatedValue GetAdvancePermissionLeaseContract(FunctionEvaluationContext context)
        {
            if (context == null || context.Parameters == null || context.Parameters.Count <= 0) return new FormatedValue(AdvancePermission.NotAllowed);
            var ctxParamDeliveryDate = context.Parameters[0];
            if (ctxParamDeliveryDate == null) return new FormatedValue(AdvancePermission.NotAllowed);
            var DeliveryDate = ctxParamDeliveryDate.Value as DateTime?;
            var ctxParamPrepayments = context.Parameters[1];
            if (ctxParamPrepayments == null) return new FormatedValue(AdvancePermission.NotAllowed);
            var Prepayments = ctxParamPrepayments.Value as ISet<LeaseContract_Prepayments>;
            if (DeliveryDate == null || Prepayments == null || !Prepayments.Any())
            {
                return new FormatedValue(AdvancePermission.NotAllowed);
            }
            else
            {
                long countDay = 0;
                AdvancePermission? advpre = null;
                var startDate = Prepayments.OrderBy(pay => pay.PrepaymentDate).LastOrDefault().PrepaymentDate.Value.AddDays(+1);
                var endDate = DeliveryDate;
                if (startDate == null || endDate == null)
                {
                    return new FormatedValue(AdvancePermission.NotAllowed);
                }
                countDay = (long)Math.Abs((startDate - endDate).Value.TotalDays);
                if (countDay > 1 && countDay <= 15)
                {
                    advpre = AdvancePermission.AllowedTo15Days;
                }
                if (countDay > 15 && countDay <= 30)
                {
                    advpre = AdvancePermission.AllowedTo30Days;
                }
                if (countDay > 30 && countDay <= 60)
                {
                    advpre = AdvancePermission.AllowedTo60Days;
                }
                if (countDay > 60 && countDay <= 90)
                {
                    advpre = AdvancePermission.AllowedTo90Days;
                }
                if (advpre == null)
                {
                    return new FormatedValue(AdvancePermission.NotAllowed);
                }
                return new FormatedValue(advpre.ToString());
            }
        }
        /// <summary>
        /// Возвращает сумму на поставщика по Проекту указанному в Предмете лизинга
        /// </summary>
        /// <param name="context">Предмет лизинга</param>
        /// <returns>double</returns>
        public static FormatedValue GetLimitBalanceProvider(FunctionEvaluationContext context)
        {
        	if (context == null || context.Parameters == null || context.Parameters.Count <= 0) return new FormatedValue(0);
            var ctxParam = context.Parameters[0];
            if (ctxParam == null) return new FormatedValue(0);
			var leaseObject = ctxParam.Value as LeaseObject;
            if (leaseObject == null || leaseObject.Provider == null || leaseObject.Project == null || leaseObject.Project.LeasingItems == null || !leaseObject.Project.LeasingItems.Any())
            {
                return new FormatedValue(0);
            }
            else
            {
                return new FormatedValue(leaseObject.Project.LeasingItems.Where(c => c.SubjectOfLeasing.Provider != null && c.SubjectOfLeasing.Provider == leaseObject.Provider).ToList().Select(c => c.MarketPrice.Value).Sum());
            }
        }
	}
}

FormatedValue – это форматируемое значение Вашей функции.

FunctionEvaluationContext – это параметры для вычисления Вашей функции. Количество параметров может быть неограниченно. В функции параметры отделяются друг от друга точкой запятой, например,

{ GetAdvancePermissionLeaseContract({$DeliveryDate};{$Prepayments})} , где {$ DeliveryDate } и {$ Prepayments } являются параметрами.

Для того чтобы получить значение нужного параметра, необходимо ссылаться на номер его позиции. Если обратиться к вышеописанному примеру, то параметр {$ DeliveryDate } имеет порядковый номер, равный 0, {$ Prepayments } является номером 1 и так далее.

Чтобы записать значение параметра необходимо привести его к правильному формату, в этом поможет функция context.GenerationContext.FormatProvider.FormatValue(context.Parameters[Номер_Позиции_Параметра]). Необходимость приведения к правильному формату обусловлена тем, что в значении переменной могут находиться лишние символы, например, при передаче даты окончания пользовательской задачи без времени (дд.мм.гггг) без использования приведения к верному формату в оповещении будет дата начала, равная дд.мм.гггг 23:59:50, а если использовать приведение, то дата запишется в верном формате.

Пример вызова метода проверки исключений по договору лизинга в процессе

/// <summary>
/// Проверка исключений по договору лизинга
/// </summary>
/// <param name="context"></param>
public virtual void CheckExceptions(Context context)
{
	var eqlQuery = "Advancement = '{GetAdvancePermissionLeaseContract({$DeliveryDate};{$Prepayments})}' AND LimitBalance >= {GetLimitBalanceProvider({$LeaseObject})}";
	bool isExceptions = context.LeaseContract.CheckEqlRules(eqlQuery);
}

Метод CheckEqlRules глобального модуля можно вызывать из любого места системы. Это один из вариантов использования собственных функций для генератора.

Ссылка на элементы API

ITemplateGeneratorFunctionsContainer (для версий 3.13, 3.15, 4.0).

Ссылка на базу знаний

Список функций генерации документов по шаблону v3.10.