namespace Bars.Alpha.Forms.Kb.EtlSteps.FormFilling.DSF
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Bars.Alpha.Data.Impl;
using Bars.Alpha.Forms.Kb.Utils;
using Bars.Calculator.Impl;
using Bars.Calculator.Impl.Conditions;
using Bars.Calculator.Impl.Expressions;
using Bars.Calculator.Impl.Functions;
using Bars.Calculator.Impl.Functions.Table;
using Bars.Calculator.Impl.Functions.Utils;
using Bars.Calculator.Interfaces;
[Step("Заполнения формы ДСФ", "Заполнение форм")]
internal class FoundsMoneysFilling : BaseFormFillingStep<EmptyStepData, EmptyStepData>
private List<string> groupingFieldList;
private List<string> agregationFieldList;
[StepConfig("Регулярное выражение для исключения форм по названию", 3)]
public virtual LexemString ExcludeFormByNameRegEx { get; set; }
protected override void ExecuteStep()
var storageMetadataList = this.GetSourceMetadataList();
if (storageMetadataList.Any())
var encludedFroms = storageMetadataList
string.Format("\"{0}\" ({1})", formStorage.Value, formStorage.Key.StorageName));
"Выбраны формы для загрузки в ДСФ: {0}".L("ETL"),
string.Join(", ", encludedFroms)),
IExpression fromUnionExpression = this.BuildUnionAllMetadatasExpression(storageMetadataList);
this.agregationFieldList = this.ExtractValueFieldsFromStorageMetadata(this.GetMetadata());
var unionGroupByExpression = this.BuildAgregateUnionExpression(fromUnionExpression);
var fromAggregatedExpression = new FromExpression()
.AddArgument(new AliasExpression(unionGroupByExpression, "t"));
var articleDdsMetadata = this.GetMetadata(Constants.TypeIdArticleDds);
var gettingUnitIdExpression = CalculatorExpressionHelper.GetIdSelectExpression(
Constants.FieldCodeUnitName,
this.GetMetadata(Constants.TypeIdUnit));
var gettingAuditIdExpression = CalculatorExpressionHelper.GetIdSelectExpression(
this.GetMetadata(Constants.TypeIdAudit));
var selectIncrementSumExpression = this.BuildSelectIncrementSum(
(FromExpression)fromAggregatedExpression,
new AliasExpression(gettingUnitIdExpression, Constants.CubeFieldCodeAdminCosts),
new AliasExpression(gettingAuditIdExpression, Constants.CubeFieldCodeAudit),
CalculatorExpressionHelper.GetIdSelectExpression(
Constants.FieldCodeStateDdsNumber,
Constants.ArticleDdsFoundsMoney2,
Constants.CubeFieldCodeArticleDds)
var selectIncrementSumOffsetExpression = this.BuildSelectIncrementOffsetSum(
(FromExpression)fromAggregatedExpression,
new AliasExpression(gettingUnitIdExpression, Constants.CubeFieldCodeAdminCosts),
new AliasExpression(gettingAuditIdExpression, Constants.CubeFieldCodeAudit),
CalculatorExpressionHelper.GetIdSelectExpression(
Constants.FieldCodeStateDdsNumber,
Constants.ArticleDdsFoundsMoney1,
Constants.CubeFieldCodeArticleDds)
var resultUnionExpression = new UnionExpression(
selectIncrementSumExpression,
selectIncrementSumOffsetExpression);
this.UpsertDataDocuments(resultUnionExpression, gettingUnitIdExpression, gettingAuditIdExpression);
protected override Metadata GetSourceMetadata()
private void UpsertDataDocuments(
IExpression resultExpression,
SelectExpression gettingUnitIdExpression,
SelectExpression gettingAuditIdExpression)
var keyFields = new List<string>
Constants.CubeFieldCodeArticleDds,
Constants.CubeFieldCodeBudgetKind,
Constants.CubeFieldCodeFinancingSources,
var constantFields = new Dictionary<string, IExpression>
{ Constants.CubeFieldCodeBudgetVersion, new ConstantExpression(this.BudgetVersionIdValue) },
Constants.CubeFieldCodeAdminCosts,
Constants.CubeFieldCodeAudit,
this.UpsertDataDocuments(
private Dictionary<Metadata, string> GetSourceMetadataList()
var resultList = new Dictionary<Metadata, string>();
var formList = this.FormService.GetAll()
.Where(form => form.Name != this.FormName)
this.Log(string.Format("Всего форм: {0}", formList.Count), EtlLogType.Debug);
var excludedForms = new Dictionary<Metadata, string>();
string regExString = this.ExcludeFormByNameRegEx;
Regex excludingRegExp = null;
excludingRegExp = new Regex(regExString);
catch (Exception exception)
"Ошибка при построении регулярного выражения \"{0}\": {1}".L("ETL"),
foreach (var form in formList)
Metadata formStorageMetadata;
if (form.MetadataId.HasValue)
formStorageMetadata = this.ExtractStorageMetadataFromFormMetadata(form.MetadataId.Value, false);
string.Format("У формы \"{0}\" нет ссылки на метаописание".L("ETL"), form.Name),
if (formStorageMetadata == null)
this.Log(string.Format("У формы \"{0}\" нет метаописания".L("ETL"), form.Name), EtlLogType.Debug);
if (formStorageMetadata.FindField(Constants.CubeFieldCodeBudgetVersion) == null)
"У формы \"{0}\" ({1}) нет поля версии бюджета".L("ETL"),
formStorageMetadata.StorageName),
var budgetVersionField = CalculatorExpressionHelper.GenerateAliasFieldExpression(
Constants.CubeFieldCodeBudgetVersion,
var filterCondition = new ConditionAndExpression(
new ConstantExpression(this.BudgetVersionIdValue)));
var selectExpression = new SkipTakeExpression()
.AddArgument(CalculatorExpressionHelper.GenerateQueryExpression(
new List<AliasExpression> { budgetVersionField },
.AddArgument(new ConstantExpression(0))
.AddArgument(new ConstantExpression(1));
var resultDocument = this.DataDocumentService.GetAll(selectExpression, formStorageMetadata)
if (resultDocument == null)
var logMessage = string.Format(
"У формы \"{0}\" ({1}) нет записей с указанной версией бюджета".L("ETL"),
formStorageMetadata.StorageName);
if (excludingRegExp != null && excludingRegExp.IsMatch(form.Name))
excludedForms[formStorageMetadata] = form.Name;
resultList[formStorageMetadata] = form.Name;
excludedForm => string.Format("\"{0}\" ({1})", excludedForm.Value, excludedForm.Key.StorageName));
this.Log(string.Format("Исключенные формы: {0}".L("ETL"), string.Join(", ", excludedFormList)));
private UnionExpression BuildUnionAllMetadatasExpression(Dictionary<Metadata, string> storageMetadataList)
var selectExpressionList = new List<IExpression>();
var destinationValueFieldList = this.ExtractValueFieldsFromStorageMetadata(this.GetMetadata());
var budgetKindMeta = this.GetMetadata(Constants.TypeIdBudgetKind);
var auditMeta = this.GetMetadata(Constants.TypeIdAudit);
var articleDdsMeta = this.GetMetadata(Constants.TypeIdArticleDds);
foreach (var storageMetadata in storageMetadataList.Keys)
var fieldCodeList = this.ExtractValueFieldsFromStorageMetadata(storageMetadata);
List<AliasExpression> aliasFieldList;
aliasFieldList = this.CombineSourceToDestinationFields(
destinationValueFieldList,
catch (Exception exception)
"Для хранилища формы \"{0}\" ({2}) при формировании полей обнаружена ошибка \"{1}\"".L("ETL"),
storageMetadataList[storageMetadata],
storageMetadata.StorageName));
var resultFields = this.GetGroupingFieldList()
.Select(x => this.GenerateAliasFieldExpression(x, sourceMetadata: storageMetadata))
resultFields.Add(this.GenerateAliasFieldExpression(
Constants.CubeFieldCodeAudit,
sourceMetadata: storageMetadata));
resultFields.AddRange(aliasFieldList);
var filterBudgetKindExpression = new InExpression()
new AliasExpression(Constants.CubeFieldCodeBudgetKind))
CalculatorExpressionHelper.GetIdSelectExpression(
Constants.FieldCodeScenarioName,
Constants.DsfBudgetKindCurrent,
Constants.DsfBudgetKindAdditionalCosts
var includeAudits = new List<object>
Constants.AuditAutofilling,
Constants.AuditBuildingCostsDistribution,
Constants.AuditExhibitionCostsDistribution
var filterAuditExpression = new InExpression()
new AliasExpression(Constants.CubeFieldCodeAudit))
CalculatorExpressionHelper.GetIdSelectExpression(
var filterBudgetVersionExpression = new EqualExpression(
new AliasExpression(Constants.CubeFieldCodeBudgetVersion),
new ConstantExpression(this.BudgetVersionIdValue));
var articleDdsExludeExpression = new NotExpression(new InExpression()
.AddArgument(new AliasExpression(Constants.CubeFieldCodeArticleDds))
.AddArgument(CalculatorExpressionHelper.GetIdSelectExpression(
Constants.FieldCodeStateDdsNumber,
var filterCondition = new ConditionAndExpression()
.AddArgument(filterBudgetKindExpression)
.AddArgument(filterAuditExpression)
.AddArgument(filterBudgetVersionExpression)
.AddArgument(articleDdsExludeExpression);
if (storageMetadata.IsVersionMetaStorage)
filterCondition.AddArgument(CalculatorExpressionHelper.BuildVersionBetweenExpression(
var selectExpression = CalculatorExpressionHelper.GenerateQueryExpression(
selectExpression.Arguments.RemoveAt(this.GetGroupingFieldList().Count + 1);
selectExpressionList.Add(selectExpression);
catch (Exception exception)
"Для хранилища формы \"{0}\" ({2}) при формировании запроса обнаружена ошибка \"{1}\"".L("ETL"),
storageMetadataList[storageMetadata],
storageMetadata.StorageName));
return new UnionExpression(selectExpressionList.ToArray());
private BaseFunctionalExpression BuildAgregateUnionExpression(IExpression fromUnionExpression)
var finansingSourceFromExpression = new FromExpression()
.AddArgument(new AliasExpression(this.GetMetadata(Constants.TypeIdFinancingSources), "fs"));
fromUnionExpression = new JoinExpression(
finansingSourceFromExpression,
new AliasExpression(fromUnionExpression, "t"),
new NativeExpression(string.Format("fs.\"{0}\"", Constants.FieldCodeId)),
new NativeExpression(string.Format("t.\"{0}\"", Constants.CubeFieldCodeFinancingSources))));
var agregationSelectExpression = new SelectExpression()
.AddArgument(fromUnionExpression);
this.GetGroupingFieldList().ForEach(field => agregationSelectExpression
.AddArgument(new NativeExpression(string.Format("t.\"{0}\"", field))));
agregationSelectExpression
.AddArgument(new NativeExpression(string.Format("fs.\"{0}\"", Constants.FieldCodeBalance)));
this.agregationFieldList.ForEach(field =>
agregationSelectExpression
.AddArgument(new AliasExpression(
new AggregateExpression()
new NativeExpression("SUM"),
new NativeExpression(string.Format("t.\"{0}\"", field))),
string.Format("\"{0}\"", field))));
return new GroupByExpression().AddArguments(
agregationSelectExpression,
new ConstantExpression(1),
new ConstantExpression(2),
new ConstantExpression(3),
new ConstantExpression(4),
new ConstantExpression(5));
private IExpression BuildSelectIncrementSum(
FromExpression fromAggregatedExpression,
List<IExpression> constantFieldExpressions)
var selectIncrementSumExpression = new SelectExpression(true)
.AddArgument(fromAggregatedExpression);
this.GetGroupingFieldList().ForEach(
field => selectIncrementSumExpression.AddArgument(string.Format("t.\"{0}\"", field)));
var incrementSumFields = new List<string>
string.Format("t.\"{0}\"", Constants.FieldCodeBalance)
selectIncrementSumExpression
.AddArgument(new NativeExpression(string.Format("t.\"{0}\"", Constants.FieldCodeBalance)));
this.agregationFieldList.ForEach(field =>
incrementSumFields.Add(string.Format("t.\"{0}\"", field));
var sumFields = string.Join(" + ", incrementSumFields);
selectIncrementSumExpression
.AddArgument(new NativeExpression(string.Format("{0} AS \"{1}\"", sumFields, field)));
selectIncrementSumExpression.AddArguments(constantFieldExpressions);
return selectIncrementSumExpression;
private IExpression BuildSelectIncrementOffsetSum(
FromExpression fromAggregatedExpression,
List<IExpression> constantFieldExpressions)
var selectIncrementSumOffsetExpression = new SelectExpression(true)
.AddArgument(fromAggregatedExpression);
this.GetGroupingFieldList().ForEach(
field => selectIncrementSumOffsetExpression.AddArgument(string.Format("t.\"{0}\"", field)));
var incrementSumOffsetFields = new List<string>
string.Format("t.\"{0}\"", Constants.FieldCodeBalance)
selectIncrementSumOffsetExpression
.AddArgument(new NativeExpression(string.Format("t.\"{0}\"", Constants.FieldCodeBalance)));
this.agregationFieldList.ForEach(field =>
var sumFields = string.Join(" + ", incrementSumOffsetFields);
selectIncrementSumOffsetExpression
.AddArgument(new NativeExpression(string.Format("{0} AS \"{1}\"", sumFields, field)));
incrementSumOffsetFields.Add(string.Format("t.\"{0}\"", field));
selectIncrementSumOffsetExpression.AddArguments(constantFieldExpressions);
return selectIncrementSumOffsetExpression;
private List<string> GetGroupingFieldList()
return this.groupingFieldList ??
(this.groupingFieldList = new List<string>
Constants.CubeFieldCodeBudgetKind,
Constants.CubeFieldCodeFinancingSources,
Constants.CubeFieldCodeBudgetVersion,
private List<string> ExtractValueFieldsFromStorageMetadata(Metadata storageMetadata)
var flattenValueFields = storageMetadata.FlattenFields()
.Where(field => (field.Field.Code == "summh" ||
field.Field.Code == "price") &&
(field.Field.FieldType == FieldType.Double ||
field.Field.FieldType == FieldType.Currency));
return flattenValueFields.Select(field => field.CodePath).ToList();
private List<AliasExpression> CombineSourceToDestinationFields(
List<string> sourceFields,
List<string> destinationFieldsAlias,
Metadata storageMetadata)
if (sourceFields.Count != destinationFieldsAlias.Count)
throw new Exception("Неверно выбран горизонт планирования и шаг планирования".L("ETL"));
var result = new List<AliasExpression>();
for (var i = 0; i < sourceFields.Count; i++)
var conditionExpression = new ConditionExpression();
conditionExpression.AddArgument(new EqualExpression(
this.GenerateAliasFieldExpression("dim9322_id.Dhd_Rskh.Tip_stat", sourceMetadata: storageMetadata),
new ConstantExpression(Constants.DsfExpenseArticleType)));
conditionExpression.AddArgument(new ConstantExpression(-1));
conditionExpression.AddArgument(new ConstantExpression(1));
var valueFieldExpression = new CoalesceExpression();
if (sourceFields[i].EndsWith(Constants.FieldCodeDestinationValue))
valueFieldExpression.AddArgument(this.GenerateAliasFieldExpression(
string.Format("\"{0}\"", sourceFields[i]),
sourceMetadata: storageMetadata));
var kolvoPriceMultiplicationExpression = new MultiplicationExpression();
var lastPointIndex = sourceFields[i].LastIndexOf(".", StringComparison.Ordinal);
var kolvoFieldCode = string.Format("{0}.kolvo", sourceFields[i].Substring(0, lastPointIndex));
kolvoPriceMultiplicationExpression.AddArgument(this.GenerateAliasFieldExpression(
string.Format("\"{0}\"", sourceFields[i]),
sourceMetadata: storageMetadata));
kolvoPriceMultiplicationExpression.AddArgument(this.GenerateAliasFieldExpression(
string.Format("\"{0}\"", kolvoFieldCode),
sourceMetadata: storageMetadata));
valueFieldExpression.AddArgument(kolvoPriceMultiplicationExpression);
valueFieldExpression.AddArgument(new ConstantExpression(0));
var multiplicationExpresison = new MultiplicationExpression();
multiplicationExpresison.AddArgument(conditionExpression);
multiplicationExpresison.AddArgument(valueFieldExpression);
result.Add(new AliasExpression(multiplicationExpresison, destinationFieldsAlias[i]));