Создания функции генератора для 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).