Compare commits
2 Commits
d53ffebc1c
...
9408b98775
Author | SHA1 | Date | |
---|---|---|---|
9408b98775 | |||
da8d666ffd |
@ -134,6 +134,8 @@ export default function AccountDashboard() {
|
||||
(result) => {
|
||||
if (result) {
|
||||
setAccountHistorical(result);
|
||||
console.log("Account Historical: ");
|
||||
console.log(accountHistorical);
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
@ -269,6 +271,14 @@ export default function AccountDashboard() {
|
||||
);
|
||||
}
|
||||
|
||||
function medianIncome()
|
||||
{
|
||||
if (accountHistorical.income === null || accountHistorical.income === undefined )
|
||||
return 0;
|
||||
|
||||
return accountHistorical.income.median;
|
||||
}
|
||||
|
||||
let transactionsContent = loading ? (
|
||||
<p>
|
||||
<em>Loading...</em>
|
||||
@ -307,7 +317,7 @@ export default function AccountDashboard() {
|
||||
<div className="row">
|
||||
<div className="col-md-6">
|
||||
<h3>Balance : <DataFormatter data={account.balance} renderType={RenderType.MoneyUnsigned} /></h3>
|
||||
<h4>Virtual Balance : <DataFormatter data={account.virtualBalance} renderType={RenderType.MoneyUnsigned} /> / <DataFormatter data={accountHistorical.meanIncome} renderType={RenderType.MoneyUnsigned} /></h4>
|
||||
<h4>Virtual Balance : <DataFormatter data={account.virtualBalance} renderType={RenderType.MoneyUnsigned} /> / <DataFormatter data={medianIncome()} renderType={RenderType.MoneyUnsigned} /></h4>
|
||||
<h5>Last activity: <DataFormatter data={account.lastActivity} renderType={RenderType.Date} /></h5>
|
||||
</div>
|
||||
<div className="col-md-6">
|
||||
|
@ -17,41 +17,44 @@ public class AutoclassExpression
|
||||
switch (TransactionField)
|
||||
{
|
||||
case AutoclassTransactionField.DATE:
|
||||
return evaluateDateType(transaction.Date);
|
||||
return EvaluateDateType(transaction.Date);
|
||||
|
||||
case AutoclassTransactionField.EXTERNAL_ID:
|
||||
return evaluateStringType(transaction.ExternalId);
|
||||
return EvaluateStringType(transaction.ExternalId);
|
||||
|
||||
case AutoclassTransactionField.DESCRIPTION:
|
||||
return evaluateStringType(transaction.Description);
|
||||
return EvaluateStringType(transaction.Description);
|
||||
|
||||
case AutoclassTransactionField.AMOUNT:
|
||||
return evaluateDecimalType(transaction.Amount);
|
||||
return EvaluateDecimalType(transaction.Amount);
|
||||
|
||||
case AutoclassTransactionField.IS_PENDING:
|
||||
return evaluateBoolType(transaction.IsPending);
|
||||
return EvaluateBoolType(transaction.IsPending);
|
||||
|
||||
case AutoclassTransactionField.DEBIT_ACCOUNT:
|
||||
return evaluateAccountType(transaction.DebitAccount);
|
||||
return EvaluateAccountType(transaction.DebitAccount);
|
||||
|
||||
case AutoclassTransactionField.CREDIT_ACCOUNT:
|
||||
return evaluateAccountType(transaction.CreditAccount);
|
||||
return EvaluateAccountType(transaction.CreditAccount);
|
||||
|
||||
case AutoclassTransactionField.DEBIT_ENVELOPE:
|
||||
return evaluateEnvelopeType(transaction.DebitEnvelope);
|
||||
return EvaluateEnvelopeType(transaction.DebitEnvelope);
|
||||
|
||||
case AutoclassTransactionField.CREDIT_ENVELOPE:
|
||||
return evaluateEnvelopeType(transaction.CreditEnvelope);
|
||||
return EvaluateEnvelopeType(transaction.CreditEnvelope);
|
||||
|
||||
case AutoclassTransactionField.CURRENCY_TYPE:
|
||||
return evaluateCurrencyType(transaction.CurrencyType);
|
||||
return EvaluateCurrencyType(transaction.CurrencyType);
|
||||
|
||||
case AutoclassTransactionField.TAGS:
|
||||
return EvaluateStringArrayType(transaction.Tags);
|
||||
|
||||
default:
|
||||
throw new Exception($"AutoclassExpression::Evaluate(Transaction) couldn't recognize the field '{TransactionField.ToString()}'.");
|
||||
throw new Exception($"AutoclassExpression::Evaluate(Transaction) couldn't recognize the field '{TransactionField}'.");
|
||||
}
|
||||
}
|
||||
|
||||
private bool evaluateDateType(DateTime currentValue)
|
||||
private bool EvaluateDateType(DateTime currentValue)
|
||||
{
|
||||
/*DateTime expValue = Convert.ToDateTime(Value);
|
||||
var dt = DateTime.ParseExact(Value , "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);*/
|
||||
@ -72,11 +75,11 @@ public class AutoclassExpression
|
||||
case AutoclassCompareOperator.LESS_THAN_OR_EQUAL:
|
||||
return currentValue.Date <= expValue.Date;
|
||||
default:
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator.ToString()}' for type 'DateTime'");
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator}' for type 'DateTime'");
|
||||
}
|
||||
}
|
||||
|
||||
private bool evaluateStringType(string currentValue)
|
||||
private bool EvaluateStringType(string currentValue)
|
||||
{
|
||||
switch (CompareOperator)
|
||||
{
|
||||
@ -89,11 +92,11 @@ public class AutoclassExpression
|
||||
case AutoclassCompareOperator.CONTAINS_INSENSITIVE:
|
||||
return currentValue.ToUpper().Contains(Value.ToUpper());
|
||||
default:
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator.ToString()}' for type 'string'");
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator}' for type 'string'");
|
||||
}
|
||||
}
|
||||
|
||||
private bool evaluateDecimalType(decimal currentValue)
|
||||
private bool EvaluateDecimalType(decimal currentValue)
|
||||
{
|
||||
decimal expValue = Convert.ToDecimal(Value);
|
||||
|
||||
@ -112,11 +115,11 @@ public class AutoclassExpression
|
||||
case AutoclassCompareOperator.LESS_THAN_OR_EQUAL:
|
||||
return currentValue <= expValue;
|
||||
default:
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator.ToString()}' for type 'decimal'");
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator}' for type 'decimal'");
|
||||
}
|
||||
}
|
||||
|
||||
private bool evaluateBoolType(bool currentValue)
|
||||
private bool EvaluateBoolType(bool currentValue)
|
||||
{
|
||||
bool expValue = Convert.ToBoolean(Value);
|
||||
|
||||
@ -127,11 +130,11 @@ public class AutoclassExpression
|
||||
case AutoclassCompareOperator.NOT_EQUAL:
|
||||
return currentValue != expValue;
|
||||
default:
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator.ToString()}' for type 'boolean'");
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator}' for type 'boolean'");
|
||||
}
|
||||
}
|
||||
|
||||
private bool evaluateAccountType(Account currentValue)
|
||||
private bool EvaluateAccountType(Account currentValue)
|
||||
{
|
||||
int expValue = Convert.ToInt32(Value);
|
||||
|
||||
@ -148,13 +151,13 @@ public class AutoclassExpression
|
||||
else
|
||||
return currentValue.Id != expValue;
|
||||
default:
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator.ToString()}' for type 'Account'");
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator}' for type 'Account'");
|
||||
}
|
||||
}
|
||||
|
||||
//evaluateEnvelopeType
|
||||
|
||||
private bool evaluateEnvelopeType(Envelope currentValue)
|
||||
private bool EvaluateEnvelopeType(Envelope currentValue)
|
||||
{
|
||||
int expValue = Convert.ToInt32(Value);
|
||||
|
||||
@ -171,11 +174,11 @@ public class AutoclassExpression
|
||||
else
|
||||
return currentValue.Id != expValue;
|
||||
default:
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator.ToString()}' for type 'Envelope'");
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator}' for type 'Envelope'");
|
||||
}
|
||||
}
|
||||
|
||||
private bool evaluateCurrencyType(CurrencyType currentValue)
|
||||
private bool EvaluateCurrencyType(CurrencyType currentValue)
|
||||
{
|
||||
int expValue = Convert.ToInt32(Value);
|
||||
|
||||
@ -192,7 +195,26 @@ public class AutoclassExpression
|
||||
else
|
||||
return currentValue.Id != expValue;
|
||||
default:
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator.ToString()}' for type 'CurrencyType'");
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator}' for type 'CurrencyType'");
|
||||
}
|
||||
}
|
||||
|
||||
private bool EvaluateStringArrayType(List<string> currentValue)
|
||||
{
|
||||
switch (CompareOperator)
|
||||
{
|
||||
case AutoclassCompareOperator.CONTAINS:
|
||||
if (currentValue == null)
|
||||
return false;
|
||||
else
|
||||
return currentValue.Any(s => s == Value);
|
||||
case AutoclassCompareOperator.CONTAINS_INSENSITIVE:
|
||||
if (currentValue == null)
|
||||
return false;
|
||||
else
|
||||
return currentValue.Any(s => s.ToUpper() == Value.ToUpper());
|
||||
default:
|
||||
throw new Exception($"Invalid compare operator '{CompareOperator}' for type 'string[]'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,5 +22,6 @@ public enum AutoclassType
|
||||
DATETIME,
|
||||
ACCOUNT,
|
||||
ENVELOPE,
|
||||
CURRENCYTYPE
|
||||
CURRENCYTYPE,
|
||||
STRING_ARRAY,
|
||||
}
|
@ -8,7 +8,7 @@ namespace ActiveAllocator.API.Entities;
|
||||
public class Statistic
|
||||
{
|
||||
//public int Id { get; set; }
|
||||
public Dictionary<DateTime, decimal> Values { get; set; } = null;
|
||||
public Dictionary<DateTime, decimal>? Values { get; set; } = null;
|
||||
public decimal? Median { get; set; } = null;
|
||||
public decimal? Mean { get; set; } = null;
|
||||
public decimal? High { get; set; } = null;
|
||||
|
@ -20,6 +20,7 @@ public class Transaction
|
||||
public CurrencyType CurrencyType { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public bool IsPending { get; set; }
|
||||
public List<string>? Tags { get; set; }
|
||||
}
|
||||
|
||||
public enum AutoclassTransactionField
|
||||
@ -34,4 +35,5 @@ public enum AutoclassTransactionField
|
||||
AMOUNT,
|
||||
CURRENCY_TYPE,
|
||||
IS_PENDING,
|
||||
TAGS
|
||||
}
|
@ -182,7 +182,8 @@ public class DataContext : DbContext
|
||||
Dictionary<DateTime, decimal> valuesCredit = new Dictionary<DateTime, decimal>();
|
||||
Dictionary<DateTime, decimal> valuesIncome = new Dictionary<DateTime, decimal>();
|
||||
|
||||
bool monthHasData = false;
|
||||
bool monthsHaveData = false;
|
||||
int monthsWithData = 0;
|
||||
|
||||
for (int i = 0; i < lookBack; i++)
|
||||
{
|
||||
@ -195,20 +196,33 @@ public class DataContext : DbContext
|
||||
|
||||
foreach (Transaction tran in monthTransactions)
|
||||
{
|
||||
monthHasData = true;
|
||||
monthsHaveData = true;
|
||||
|
||||
if (tran.CreditAccount != null && tran.CreditAccount.Id == id)
|
||||
{
|
||||
monthlySumCredit += tran.Amount;
|
||||
|
||||
// Place holder - Income Condition goes here
|
||||
if (false)
|
||||
if (tran.Tags != null && tran.Tags.Any(t => t.ToUpper() == "INCOME"))
|
||||
monthlySumIncome += tran.Amount;
|
||||
}
|
||||
else
|
||||
monthlySumDebit += tran.Amount;
|
||||
|
||||
if (tran.Amount != 0)
|
||||
monthsWithData = i + 1;
|
||||
}
|
||||
|
||||
if (monthsWithData == i + 1)
|
||||
{
|
||||
valuesDebit.Add(currentLookBackMonth, monthlySumDebit);
|
||||
valuesCredit.Add(currentLookBackMonth, monthlySumCredit);
|
||||
valuesIncome.Add(currentLookBackMonth, monthlySumIncome);
|
||||
}
|
||||
|
||||
// Now ignore months of Zero on the tail of the lookback
|
||||
_logger.LogInformation($"Lookback of: {lookBack}");
|
||||
_logger.LogInformation($"Last month of data: {monthsWithData}");
|
||||
|
||||
sumDebit += monthlySumDebit;
|
||||
sumCredit += monthlySumCredit;
|
||||
sumIncome += monthlySumIncome;
|
||||
@ -220,35 +234,34 @@ public class DataContext : DbContext
|
||||
lowDebit = i == 0 || monthlySumDebit < lowDebit ? monthlySumDebit : lowDebit;
|
||||
lowCredit = i == 0 || monthlySumCredit < lowCredit ? monthlySumCredit : lowCredit;
|
||||
lowIncome = i == 0 || monthlySumIncome < lowIncome ? monthlySumIncome : lowIncome;
|
||||
|
||||
valuesDebit.Add(currentLookBackMonth, monthlySumDebit);
|
||||
valuesCredit.Add(currentLookBackMonth, monthlySumCredit);
|
||||
valuesIncome.Add(currentLookBackMonth, monthlySumIncome);
|
||||
}
|
||||
|
||||
if (monthHasData == false)
|
||||
if (monthsHaveData == false)
|
||||
return hist;
|
||||
|
||||
|
||||
hist.Debit = new Statistic() {
|
||||
Median = HistoricalMedian(valuesDebit),
|
||||
Mean = sumDebit / (decimal)lookBack,
|
||||
Mean = sumDebit / (decimal)monthsWithData,
|
||||
High = highDebit,
|
||||
Low = lowDebit,
|
||||
Values = valuesDebit,
|
||||
};
|
||||
|
||||
hist.Credit = new Statistic() {
|
||||
Median = HistoricalMedian(valuesCredit),
|
||||
Mean = sumCredit / (decimal)lookBack,
|
||||
Mean = sumCredit / (decimal)monthsWithData,
|
||||
High = highCredit,
|
||||
Low = lowCredit,
|
||||
Values = valuesCredit,
|
||||
};
|
||||
|
||||
hist.Income = new Statistic() {
|
||||
Median = HistoricalMedian(valuesIncome),
|
||||
Mean = sumIncome / (decimal)lookBack,
|
||||
Mean = sumIncome / (decimal)monthsWithData,
|
||||
High = highIncome,
|
||||
Low = lowIncome,
|
||||
Values = valuesIncome,
|
||||
};
|
||||
|
||||
return hist;
|
||||
@ -280,10 +293,6 @@ public class DataContext : DbContext
|
||||
DateTime lastOfLastMonth = firstOfThisMonth.AddDays(-1);
|
||||
DateTime lookBackDate = firstOfThisMonth.AddMonths(-lookBack);
|
||||
|
||||
Console.WriteLine($"First of this Month: {firstOfThisMonth}");
|
||||
Console.WriteLine($"Last of Last Month: {lastOfLastMonth}");
|
||||
Console.WriteLine($"First of Lookback Month: {lookBackDate}");
|
||||
|
||||
List<Transaction> transactions = this.Transactions
|
||||
.Include(t => t.CreditEnvelope)
|
||||
.Include(t => t.DebitEnvelope)
|
||||
@ -292,63 +301,77 @@ public class DataContext : DbContext
|
||||
.Where(t => t.Date >= lookBackDate.ToUniversalTime() && t.Date <= lastOfLastMonth.ToUniversalTime())
|
||||
.ToList();
|
||||
|
||||
// Sum variables
|
||||
decimal sumDebit = 0;
|
||||
decimal sumCredit = 0;
|
||||
|
||||
decimal sumExpend = 0;
|
||||
decimal sumIncome = 0;
|
||||
decimal highExpend = 0;
|
||||
decimal lowExpend = 100000000;
|
||||
decimal highIncome = 0;
|
||||
decimal lowIncome = 100000000;
|
||||
// High variables
|
||||
decimal highDebit = 0;
|
||||
decimal highCredit = 0;
|
||||
|
||||
Dictionary<DateTime, decimal> statsExpend = new Dictionary<DateTime, decimal>();
|
||||
Dictionary<DateTime, decimal> statsIncome = new Dictionary<DateTime, decimal>();
|
||||
// Low variables
|
||||
decimal lowDebit = 100000000;
|
||||
decimal lowCredit = 100000000;
|
||||
|
||||
bool monthHasData = false;
|
||||
// Values variables
|
||||
Dictionary<DateTime, decimal> valuesDebit = new Dictionary<DateTime, decimal>();
|
||||
Dictionary<DateTime, decimal> valuesCredit = new Dictionary<DateTime, decimal>();
|
||||
|
||||
bool monthsHaveData = false;
|
||||
int monthsWithData = 0;
|
||||
|
||||
for (int i = 0; i < lookBack; i++)
|
||||
{
|
||||
DateTime currentLookBackMonth = lastOfLastMonth.AddMonths(-i);
|
||||
List<Transaction> monthTransactions = this.GetTransactionsFromMonth(currentLookBackMonth, transactions);
|
||||
|
||||
decimal monthlySumExpend = 0;
|
||||
decimal monthlySumIncome = 0;
|
||||
decimal monthlySumDebit = 0;
|
||||
decimal monthlySumCredit = 0;
|
||||
foreach (Transaction tran in monthTransactions)
|
||||
{
|
||||
monthHasData = true;
|
||||
monthsHaveData = true;
|
||||
|
||||
if (tran.CreditEnvelope != null && tran.CreditEnvelope.Id == id)
|
||||
monthlySumIncome += tran.Amount;
|
||||
monthlySumCredit += tran.Amount;
|
||||
else
|
||||
monthlySumExpend += tran.Amount;
|
||||
monthlySumDebit += tran.Amount;
|
||||
|
||||
if (tran.Amount != 0)
|
||||
monthsWithData = i + 1;
|
||||
}
|
||||
|
||||
sumExpend += monthlySumExpend;
|
||||
sumIncome += monthlySumIncome;
|
||||
if (monthsWithData == i + 1)
|
||||
{
|
||||
valuesDebit.Add(currentLookBackMonth, monthlySumDebit);
|
||||
valuesCredit.Add(currentLookBackMonth, monthlySumCredit);
|
||||
}
|
||||
|
||||
highExpend = i == 0 || monthlySumExpend > highExpend ? monthlySumExpend : highExpend;
|
||||
highIncome = i == 0 || monthlySumIncome > highIncome ? monthlySumIncome : highIncome;
|
||||
lowExpend = i == 0 || monthlySumExpend < lowExpend ? monthlySumExpend : lowExpend;
|
||||
lowIncome = i == 0 || monthlySumIncome < lowIncome ? monthlySumIncome : lowIncome;
|
||||
sumDebit += monthlySumDebit;
|
||||
sumCredit += monthlySumCredit;
|
||||
|
||||
statsExpend.Add(currentLookBackMonth, monthlySumExpend);
|
||||
statsIncome.Add(currentLookBackMonth, monthlySumIncome);
|
||||
highDebit = i == 0 || monthlySumDebit > highDebit ? monthlySumDebit : highDebit;
|
||||
highCredit = i == 0 || monthlySumCredit > highCredit ? monthlySumCredit : highCredit;
|
||||
lowDebit = i == 0 || monthlySumDebit < lowDebit ? monthlySumDebit : lowDebit;
|
||||
lowCredit = i == 0 || monthlySumCredit < lowCredit ? monthlySumCredit : lowCredit;
|
||||
}
|
||||
|
||||
if (monthHasData == false)
|
||||
if (monthsHaveData == false)
|
||||
return hist;
|
||||
|
||||
hist.Credit = new Statistic() {
|
||||
Median = HistoricalMedian(statsIncome),
|
||||
Mean = sumIncome / (decimal)lookBack,
|
||||
High = highIncome,
|
||||
Low = lowIncome,
|
||||
Median = HistoricalMedian(valuesCredit),
|
||||
Mean = sumCredit / (decimal)monthsWithData,
|
||||
High = highCredit,
|
||||
Low = lowCredit,
|
||||
Values = valuesCredit,
|
||||
};
|
||||
|
||||
hist.Debit = new Statistic() {
|
||||
Median = HistoricalMedian(statsExpend),
|
||||
Mean = sumExpend / (decimal)lookBack,
|
||||
High = highExpend,
|
||||
Low = lowExpend,
|
||||
Median = HistoricalMedian(valuesDebit),
|
||||
Mean = sumDebit / (decimal)monthsWithData,
|
||||
High = highDebit,
|
||||
Low = lowDebit,
|
||||
Values = valuesDebit,
|
||||
};
|
||||
|
||||
return hist;
|
||||
|
520
ActiveAllocator.API/Migrations/20240201041006_TransactionTags.Designer.cs
generated
Normal file
520
ActiveAllocator.API/Migrations/20240201041006_TransactionTags.Designer.cs
generated
Normal file
@ -0,0 +1,520 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ActiveAllocator.API.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ActiveAllocator.API.Migrations
|
||||
{
|
||||
[DbContext(typeof(DataContext))]
|
||||
[Migration("20240201041006_TransactionTags")]
|
||||
partial class TransactionTags
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "7.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.Account", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("Balance")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<DateTime>("CreatedOn")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<int>("CurrencyId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("ExternalAccountNumber")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<decimal>("InitialBalance")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<DateTime>("LastActivity")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int?>("UserId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<decimal>("VirtualBalance")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CurrencyId");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("Accounts");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.AutoclassChange", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int?>("AutoclassRuleId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("Field")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AutoclassRuleId");
|
||||
|
||||
b.ToTable("AutoclassChanges");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.AutoclassExpression", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int?>("AutoclassRuleId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("CompareOperator")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("TransactionField")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AutoclassRuleId");
|
||||
|
||||
b.ToTable("AutoclassExpressions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.AutoclassRule", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("AccountId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AccountId");
|
||||
|
||||
b.ToTable("AutoclassRules");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.CurrencyType", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Code")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int>("DecimalPlaces")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Symbol")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CurrencyTypes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.Envelope", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("AccountId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<decimal>("Balance")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<decimal>("InitialBalance")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<bool>("IsPersistant")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<DateTime?>("LastTriggeredOn")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<TimeSpan>("Period")
|
||||
.HasColumnType("interval");
|
||||
|
||||
b.Property<int>("Priority")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AccountId");
|
||||
|
||||
b.ToTable("Envelopes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.EnvelopeFundingMethod", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<int>("EnvelopeId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("Mode")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("Order")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("PeriodsToLookback")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Value")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("EnvelopeId");
|
||||
|
||||
b.ToTable("EnvelopeFundingMethods");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.Operation", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("AbsoluteValue")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<bool>("Enabled")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int>("HistoricLookbackDepth")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<TimeSpan>("HistoricPeriod")
|
||||
.HasColumnType("interval");
|
||||
|
||||
b.Property<int>("HistoricStatistic")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("Mode")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<bool>("Negative")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<int>("Order")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<decimal>("Percentage")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Operations");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.Transaction", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<decimal>("Amount")
|
||||
.HasColumnType("numeric");
|
||||
|
||||
b.Property<DateTime>("CreatedOn")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<int?>("CreditAccountId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int?>("CreditEnvelopeId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int>("CurrencyTypeId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<DateTime>("Date")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.Property<int?>("DebitAccountId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<int?>("DebitEnvelopeId")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Description")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("ExternalId")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<bool>("IsEnvelopeFundingTransaction")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<bool>("IsPending")
|
||||
.HasColumnType("boolean");
|
||||
|
||||
b.Property<string>("Notes")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<List<string>>("Tags")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.Property<DateTime>("UpdatedOn")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("CreditAccountId");
|
||||
|
||||
b.HasIndex("CreditEnvelopeId");
|
||||
|
||||
b.HasIndex("CurrencyTypeId");
|
||||
|
||||
b.HasIndex("DebitAccountId");
|
||||
|
||||
b.HasIndex("DebitEnvelopeId");
|
||||
|
||||
b.ToTable("Transactions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("integer");
|
||||
|
||||
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("FirstName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("LastName")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<int>("Role")
|
||||
.HasColumnType("integer");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.Account", b =>
|
||||
{
|
||||
b.HasOne("ActiveAllocator.API.Entities.CurrencyType", "Currency")
|
||||
.WithMany()
|
||||
.HasForeignKey("CurrencyId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("ActiveAllocator.API.Entities.User", null)
|
||||
.WithMany("Accounts")
|
||||
.HasForeignKey("UserId");
|
||||
|
||||
b.Navigation("Currency");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.AutoclassChange", b =>
|
||||
{
|
||||
b.HasOne("ActiveAllocator.API.Entities.AutoclassRule", null)
|
||||
.WithMany("Changes")
|
||||
.HasForeignKey("AutoclassRuleId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.AutoclassExpression", b =>
|
||||
{
|
||||
b.HasOne("ActiveAllocator.API.Entities.AutoclassRule", null)
|
||||
.WithMany("Expressions")
|
||||
.HasForeignKey("AutoclassRuleId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.AutoclassRule", b =>
|
||||
{
|
||||
b.HasOne("ActiveAllocator.API.Entities.Account", "Account")
|
||||
.WithMany()
|
||||
.HasForeignKey("AccountId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Account");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.Envelope", b =>
|
||||
{
|
||||
b.HasOne("ActiveAllocator.API.Entities.Account", "Account")
|
||||
.WithMany("Envelopes")
|
||||
.HasForeignKey("AccountId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Account");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.EnvelopeFundingMethod", b =>
|
||||
{
|
||||
b.HasOne("ActiveAllocator.API.Entities.Envelope", "Envelope")
|
||||
.WithMany("FundingMethods")
|
||||
.HasForeignKey("EnvelopeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Envelope");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.Transaction", b =>
|
||||
{
|
||||
b.HasOne("ActiveAllocator.API.Entities.Account", "CreditAccount")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreditAccountId");
|
||||
|
||||
b.HasOne("ActiveAllocator.API.Entities.Envelope", "CreditEnvelope")
|
||||
.WithMany()
|
||||
.HasForeignKey("CreditEnvelopeId");
|
||||
|
||||
b.HasOne("ActiveAllocator.API.Entities.CurrencyType", "CurrencyType")
|
||||
.WithMany()
|
||||
.HasForeignKey("CurrencyTypeId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("ActiveAllocator.API.Entities.Account", "DebitAccount")
|
||||
.WithMany()
|
||||
.HasForeignKey("DebitAccountId");
|
||||
|
||||
b.HasOne("ActiveAllocator.API.Entities.Envelope", "DebitEnvelope")
|
||||
.WithMany()
|
||||
.HasForeignKey("DebitEnvelopeId");
|
||||
|
||||
b.Navigation("CreditAccount");
|
||||
|
||||
b.Navigation("CreditEnvelope");
|
||||
|
||||
b.Navigation("CurrencyType");
|
||||
|
||||
b.Navigation("DebitAccount");
|
||||
|
||||
b.Navigation("DebitEnvelope");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.Account", b =>
|
||||
{
|
||||
b.Navigation("Envelopes");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.AutoclassRule", b =>
|
||||
{
|
||||
b.Navigation("Changes");
|
||||
|
||||
b.Navigation("Expressions");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.Envelope", b =>
|
||||
{
|
||||
b.Navigation("FundingMethods");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("ActiveAllocator.API.Entities.User", b =>
|
||||
{
|
||||
b.Navigation("Accounts");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace ActiveAllocator.API.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class TransactionTags : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<List<string>>(
|
||||
name: "Tags",
|
||||
table: "Transactions",
|
||||
type: "text[]",
|
||||
nullable: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Tags",
|
||||
table: "Transactions");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using ActiveAllocator.API.Helpers;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using ActiveAllocator.API.Helpers;
|
||||
|
||||
#nullable disable
|
||||
|
||||
@ -334,6 +335,10 @@ namespace ActiveAllocator.API.Migrations
|
||||
.IsRequired()
|
||||
.HasColumnType("text");
|
||||
|
||||
b.Property<List<string>>("Tags")
|
||||
.IsRequired()
|
||||
.HasColumnType("text[]");
|
||||
|
||||
b.Property<DateTime>("UpdatedOn")
|
||||
.HasColumnType("timestamp with time zone");
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using ActiveAllocator.API.Entities;
|
||||
|
||||
namespace ActiveAllocator.API.Models.Accounts;
|
||||
|
||||
@ -9,12 +10,7 @@ public class AccountHistoricalDTO
|
||||
//public int Id { get; set; }
|
||||
public int AccountId { get; set; }
|
||||
public int LookBack { get; set; }
|
||||
public decimal? MedianIncome { get; set; } = null;
|
||||
public decimal? MeanIncome { get; set; } = null;
|
||||
public decimal? HighIncome { get; set; } = null;
|
||||
public decimal? LowIncome { get; set; } = null;
|
||||
public decimal? MedianExpendeture { get; set; } = null;
|
||||
public decimal? MeanExpendeture { get; set; } = null;
|
||||
public decimal? HighExpendeture { get; set; } = null;
|
||||
public decimal? LowExpendeture { get; set; } = null;
|
||||
public Statistic? Credit { get; set; } = null;
|
||||
public Statistic? Debit { get; set; } = null;
|
||||
public Statistic? Income { get; set; } = null;
|
||||
}
|
@ -35,6 +35,8 @@ public class AutoclassFieldMetaDTO
|
||||
case AutoclassTransactionField.CREDIT_ENVELOPE:
|
||||
case AutoclassTransactionField.DEBIT_ENVELOPE:
|
||||
return "ENVELOPE";
|
||||
case AutoclassTransactionField.TAGS:
|
||||
return "STRING_ARRAY";
|
||||
default:
|
||||
return "ERROR";
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
using ActiveAllocator.API.Entities;
|
||||
|
||||
namespace ActiveAllocator.API.Models.Envelopes;
|
||||
|
||||
@ -10,12 +11,6 @@ public class EnvelopeHistoricalDTO
|
||||
public int EnvelopeId { get; set; }
|
||||
public int LookBack { get; set; }
|
||||
public decimal? EnvelopeFunding { get; set; } = null;
|
||||
public decimal? MedianIncome { get; set; } = null;
|
||||
public decimal? MeanIncome { get; set; } = null;
|
||||
public decimal? HighIncome { get; set; } = null;
|
||||
public decimal? LowIncome { get; set; } = null;
|
||||
public decimal? MedianExpendeture { get; set; } = null;
|
||||
public decimal? MeanExpendeture { get; set; } = null;
|
||||
public decimal? HighExpendeture { get; set; } = null;
|
||||
public decimal? LowExpendeture { get; set; } = null;
|
||||
public Statistic? Credit { get; set; } = null;
|
||||
public Statistic? Debit { get; set; } = null;
|
||||
}
|
@ -18,6 +18,7 @@ public class TransactionCreate
|
||||
public int CurrencyType { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public bool IsPending { get; set; }
|
||||
public List<string>? Tags { get; set; } = null;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -17,7 +17,8 @@ public class TransactionDto
|
||||
public int DebitEnvelopeId { get; set; }
|
||||
public int CreditEnvelopeId { get; set; }
|
||||
public decimal Amount { get; set; }
|
||||
public ActiveAllocator.API.Entities.CurrencyType CurrencyType { get; set; }
|
||||
public Entities.CurrencyType CurrencyType { get; set; }
|
||||
public string Notes { get; set; }
|
||||
public bool IsPending { get; set; }
|
||||
public List<string>? Tags { get; set; }
|
||||
}
|
@ -18,4 +18,5 @@ public class TransactionUpdateRequest
|
||||
public string? Notes { get; set; } = null;
|
||||
public bool? IsPending { get; set; } = null;
|
||||
public bool? TriggerAutoclassRules { get; set; } = false;
|
||||
public List<string>? Tags { get; set; } = null;
|
||||
}
|
@ -154,6 +154,7 @@ public class AutoclassService : IAutoclassService
|
||||
fields.Add(new AutoclassFieldMetaDTO(AutoclassTransactionField.DESCRIPTION));
|
||||
fields.Add(new AutoclassFieldMetaDTO(AutoclassTransactionField.EXTERNAL_ID));
|
||||
fields.Add(new AutoclassFieldMetaDTO(AutoclassTransactionField.IS_PENDING));
|
||||
fields.Add(new AutoclassFieldMetaDTO(AutoclassTransactionField.TAGS));
|
||||
|
||||
this.fieldMetaData = fields;
|
||||
}
|
||||
@ -233,6 +234,14 @@ public class AutoclassService : IAutoclassService
|
||||
}
|
||||
});
|
||||
|
||||
types.Add(new AutoclassTypeMetaDTO() {
|
||||
Type = AutoclassType.STRING_ARRAY,
|
||||
Operators = new List<AutoclassOperatorMetaDTO>() {
|
||||
new AutoclassOperatorMetaDTO(AutoclassCompareOperator.CONTAINS),
|
||||
new AutoclassOperatorMetaDTO(AutoclassCompareOperator.CONTAINS_INSENSITIVE),
|
||||
}
|
||||
});
|
||||
|
||||
this.typeMetaData = types;
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ using System.Linq;
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Internal;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
public interface ITransactionService
|
||||
{
|
||||
@ -116,9 +117,10 @@ public class TransactionService : ITransactionService
|
||||
CurrencyType = _context.CurrencyTypes.Find(model.CurrencyType),
|
||||
Notes = model.Notes,
|
||||
IsPending = model.IsPending,
|
||||
Tags = model.Tags,
|
||||
};
|
||||
|
||||
if (this.validateTransaction(transaction, errorOnFail) == false)
|
||||
if (this.ValidateTransaction(transaction, errorOnFail) == false)
|
||||
{
|
||||
_logger.LogInformation($"Aborted adding transaction '{transaction.Description}'.");
|
||||
return null;
|
||||
@ -191,7 +193,11 @@ public class TransactionService : ITransactionService
|
||||
if (model.IsPending.HasValue)
|
||||
transaction.IsPending = model.IsPending.Value;
|
||||
|
||||
this.validateTransaction(transaction);
|
||||
// Tags
|
||||
if (model.Tags != null)
|
||||
transaction.Tags = model.Tags;
|
||||
|
||||
this.ValidateTransaction(transaction);
|
||||
|
||||
if (model.TriggerAutoclassRules.HasValue && model.TriggerAutoclassRules == true)
|
||||
transaction = this.ApplyAutoclassRules(transaction);
|
||||
@ -204,12 +210,12 @@ public class TransactionService : ITransactionService
|
||||
this.UpdateAccountsAndEnvelopes(transaction);
|
||||
}
|
||||
|
||||
private bool validateTransaction(int transactionId)
|
||||
private bool ValidateTransaction(int transactionId)
|
||||
{
|
||||
return this.validateTransaction(getTransaction(transactionId));
|
||||
return this.ValidateTransaction(getTransaction(transactionId));
|
||||
}
|
||||
|
||||
private bool errorOrFalse(bool error, string errorMessage)
|
||||
private bool ErrorOrFalse(bool error, string errorMessage)
|
||||
{
|
||||
if (error)
|
||||
throw new AppException(errorMessage);
|
||||
@ -219,7 +225,7 @@ public class TransactionService : ITransactionService
|
||||
}
|
||||
|
||||
// FIX VALIDATETRANSACTION REFERENCES TO USE BOOL
|
||||
private bool validateTransaction(Transaction transaction, bool errorOnFail = true)
|
||||
private bool ValidateTransaction(Transaction transaction, bool errorOnFail = true)
|
||||
{
|
||||
// MUST!!! Classify intra-account transactions as NULL account ids, and only envelope Ids
|
||||
// MUST!!! Classify inter-account transactions as correct account ids, even with envelope ids
|
||||
@ -229,33 +235,33 @@ public class TransactionService : ITransactionService
|
||||
&& transaction.CreditAccount == null
|
||||
&& transaction.DebitEnvelope == null
|
||||
&& transaction.CreditEnvelope == null)
|
||||
return errorOrFalse(errorOnFail, "There must be an envelope or account chosen for a transaction.");
|
||||
return ErrorOrFalse(errorOnFail, "There must be an envelope or account chosen for a transaction.");
|
||||
|
||||
// Envelopes must have associated parent account entities
|
||||
if (transaction.CreditEnvelope != null && transaction.CreditEnvelope.Account == null)
|
||||
return errorOrFalse(errorOnFail, $"The parent account of envelope '{transaction.CreditEnvelope.Name}' with id '{transaction.CreditEnvelope.Id}' could not be found.");
|
||||
return ErrorOrFalse(errorOnFail, $"The parent account of envelope '{transaction.CreditEnvelope.Name}' with id '{transaction.CreditEnvelope.Id}' could not be found.");
|
||||
|
||||
if (transaction.DebitEnvelope != null && transaction.DebitEnvelope.Account == null)
|
||||
return errorOrFalse(errorOnFail, $"The parent account of envelope '{transaction.DebitEnvelope.Name}' with id '{transaction.DebitEnvelope.Id}' could not be found.");
|
||||
return ErrorOrFalse(errorOnFail, $"The parent account of envelope '{transaction.DebitEnvelope.Name}' with id '{transaction.DebitEnvelope.Id}' could not be found.");
|
||||
|
||||
// Accounts cannot be the same
|
||||
if (transaction.DebitAccount != null && transaction.CreditAccount != null &&
|
||||
transaction.DebitAccount.Id == transaction.CreditAccount.Id)
|
||||
return errorOrFalse(errorOnFail, "The debit and credit accounts of a transaction cannot be the same.");
|
||||
return ErrorOrFalse(errorOnFail, "The debit and credit accounts of a transaction cannot be the same.");
|
||||
|
||||
// Envelopes cannot be the same
|
||||
if (transaction.DebitEnvelope != null && transaction.CreditEnvelope != null &&
|
||||
transaction.DebitEnvelope.Id == transaction.CreditEnvelope.Id)
|
||||
return errorOrFalse(errorOnFail, "The debit and credit envelopes of a transaction cannot be the same.");
|
||||
return ErrorOrFalse(errorOnFail, "The debit and credit envelopes of a transaction cannot be the same.");
|
||||
|
||||
// Envelopes must be child of underlying parent account
|
||||
if (transaction.DebitEnvelope != null && transaction.DebitAccount != null &&
|
||||
transaction.DebitEnvelope.Account.Id != transaction.DebitAccount.Id)
|
||||
return errorOrFalse(errorOnFail, "The debit envelope of a transaction must be a child of the debit account.");
|
||||
return ErrorOrFalse(errorOnFail, "The debit envelope of a transaction must be a child of the debit account.");
|
||||
|
||||
if (transaction.CreditEnvelope != null && transaction.CreditAccount != null &&
|
||||
transaction.CreditEnvelope.Account.Id != transaction.CreditAccount.Id)
|
||||
return errorOrFalse(errorOnFail, "The credit envelope of a transaction must be a child of the credit account.");
|
||||
return ErrorOrFalse(errorOnFail, "The credit envelope of a transaction must be a child of the credit account.");
|
||||
|
||||
// If just envelopes are specified, they must belong to the same parent account, or add appropriate accounts
|
||||
if (transaction.CreditEnvelope != null
|
||||
@ -278,7 +284,7 @@ public class TransactionService : ITransactionService
|
||||
|
||||
// Transaction Duplication Check - External ID
|
||||
if (!string.IsNullOrWhiteSpace(transaction.ExternalId) && _context.Transactions.Any(x => x.ExternalId == transaction.ExternalId))
|
||||
return errorOrFalse(errorOnFail, "Transaction with the external ID '" + transaction.ExternalId + "' already exists");
|
||||
return ErrorOrFalse(errorOnFail, "Transaction with the external ID '" + transaction.ExternalId + "' already exists");
|
||||
|
||||
// Transaction Duplication Check - All other fields
|
||||
if (_context.Transactions.Any(x =>
|
||||
@ -290,7 +296,7 @@ public class TransactionService : ITransactionService
|
||||
&& x.CreditEnvelope == transaction.CreditEnvelope
|
||||
&& x.Amount == transaction.Amount))
|
||||
{
|
||||
return errorOrFalse(errorOnFail, "Transaction with the same fields already exists");
|
||||
return ErrorOrFalse(errorOnFail, "Transaction with the same fields already exists");
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -391,6 +397,10 @@ public class TransactionService : ITransactionService
|
||||
case AutoclassTransactionField.CURRENCY_TYPE:
|
||||
transaction.CurrencyType = _context.CurrencyTypes.Find(Convert.ToInt32(chg.Value));
|
||||
break;
|
||||
|
||||
case AutoclassTransactionField.TAGS:
|
||||
transaction = AddTag(transaction, chg.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -418,6 +428,35 @@ public class TransactionService : ITransactionService
|
||||
_context.AddAmountToEnvelope(transaction.CreditEnvelope.Id, creditAmount);
|
||||
}
|
||||
|
||||
public bool HasTag(Transaction transaction, string tag)
|
||||
{
|
||||
return transaction.Tags == null ? false : transaction.Tags.Any(t => t.ToUpper() == tag.ToUpper());
|
||||
}
|
||||
|
||||
private Transaction AddTag(Transaction transaction, string tag)
|
||||
{
|
||||
if (transaction.Tags == null)
|
||||
transaction.Tags = new List<string>() { tag };
|
||||
else if (transaction.Tags.Any(t => t.ToUpper() == tag.ToUpper()) == false)
|
||||
transaction.Tags.Add(tag);
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
private Transaction RemoveTag(Transaction transaction, string tag)
|
||||
{
|
||||
if (transaction.Tags != null)
|
||||
{
|
||||
string? actualTag = transaction.Tags
|
||||
.Where(t => t.ToUpper() == tag.ToUpper())
|
||||
.FirstOrDefault();
|
||||
|
||||
if (actualTag != null)
|
||||
transaction.Tags.Remove(actualTag);
|
||||
}
|
||||
|
||||
return transaction;
|
||||
}
|
||||
|
||||
public void Delete(int id)
|
||||
{
|
||||
|
3
Run.sh
Executable file
3
Run.sh
Executable file
@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
|
||||
dotnet run --project ActiveAllocator.API/ActiveAllocator.API.csproj
|
4
TestRun.sh
Executable file
4
TestRun.sh
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
dotnet test
|
||||
dotnet run --project ActiveAllocator.API/ActiveAllocator.API.csproj
|
Loading…
x
Reference in New Issue
Block a user