/// <summary> /// Creates a Splitwise transaction with specified, or random values. /// </summary> /// <param name="context">The database context.</param> /// <param name="id">The identifier.</param> /// <param name="description">The description.</param> /// <param name="date">The date.</param> /// <param name="isDeleted">A value indicating if the expense is deleted.</param> /// <param name="updatedAt">The updated at timestamp.</param> /// <param name="paidAmount">The paid amount.</param> /// <param name="personalAmount">The personal amount.</param> /// <param name="imported">The imported value.</param> /// <param name="splits">The splits.</param> /// <returns>The created expense.</returns> public static SplitwiseTransactionEntity GenerateSplitwiseTransaction( this Context context, int id = 0, string description = null, LocalDate?date = null, bool isDeleted = false, DateTime?updatedAt = null, decimal paidAmount = 10, decimal personalAmount = 5, bool imported = false, List <SplitDetailEntity> splits = null) { var expense = new SplitwiseTransactionEntity { Id = id, Description = description ?? GetRandomString(), Date = date ?? DateTime.Today.ToLocalDate(), IsDeleted = isDeleted, UpdatedAt = updatedAt ?? DateTime.Now, PaidAmount = paidAmount, PersonalAmount = personalAmount, Imported = imported, SplitDetails = splits ?? new List <SplitDetailEntity>(), }; context.SplitwiseTransactions.Add(expense); return(expense); }
/// <summary> /// Converts a Splitwise transaction to a transfer transaction. Creates a transaction with the correct type. /// Also marks the Splitwise transaction as imported. /// </summary> /// <param name="entity">The Splitwise transaction.</param> /// <param name="splitwiseAccount">The Spltiwise account.</param> /// <param name="internalAccount">The receiving/sending account.</param> /// <returns>The created transaction.</returns> public static TransactionEntity ToTransaction( this SplitwiseTransactionEntity entity, AccountEntity splitwiseAccount, AccountEntity internalAccount) { entity.Imported = true; var transaction = new TransactionEntity { Description = entity.Description, Date = entity.Date, SplitwiseTransactionId = entity.Id, SplitwiseTransaction = entity, PaymentRequests = new List <PaymentRequestEntity>(), SplitDetails = entity.SplitDetails, Type = TransactionType.Transfer, }; if (entity.PaidAmount > 0) { transaction.Account = internalAccount; transaction.AccountId = internalAccount.Id; transaction.ReceivingAccount = splitwiseAccount; transaction.ReceivingAccountId = splitwiseAccount.Id; transaction.Amount = entity.PaidAmount; } else { transaction.Account = splitwiseAccount; transaction.AccountId = splitwiseAccount.Id; transaction.ReceivingAccount = internalAccount; transaction.ReceivingAccountId = internalAccount.Id; transaction.Amount = entity.PersonalAmount; } return(transaction); }
/// <summary> /// Converts a Splitwise transaction to a normal transaction. Creates a transaction with the correct type. /// Also marks the Splitwise transaction as imported. /// </summary> /// <param name="entity">The Splitwise transaction.</param> /// <param name="account">The account to be linked to the transaction.</param> /// <param name="category">The category to be linked to the transaction.</param> /// <returns>The created transaction.</returns> public static TransactionEntity ToTransaction( this SplitwiseTransactionEntity entity, AccountEntity account, CategoryEntity category) { entity.Imported = true; var transaction = new TransactionEntity { Description = entity.Description, Date = entity.Date, AccountId = account.Id, Account = account, CategoryId = category.Id, Category = category, SplitwiseTransactionId = entity.Id, SplitwiseTransaction = entity, PaymentRequests = new List <PaymentRequestEntity>(), SplitDetails = entity.SplitDetails, }; if (entity.PaidAmount > 0 && account.Type == AccountType.Splitwise) { transaction.Type = TransactionType.Income; transaction.Amount = entity.PaidAmount - entity.PersonalAmount; } else { transaction.Type = TransactionType.Expense; transaction.Amount = -entity.PaidAmount; } return(transaction); }
/// <summary> /// Updates the values of a Splitwise transaction with the values from an expense. /// </summary> /// <param name="entity">The Splitwise transaction entity to be updated.</param> /// <param name="expense">The expense.</param> public static void UpdateValues(this SplitwiseTransactionEntity entity, SW.Expense expense) { entity.Id = expense.Id; entity.Date = expense.Date; entity.Description = expense.Description; entity.IsDeleted = expense.IsDeleted; entity.UpdatedAt = expense.UpdatedAt; entity.PaidAmount = expense.PaidAmount; entity.PersonalAmount = expense.PersonalAmount; entity.Imported = false; }
/// <summary> /// Converts the entity to a data transfer object. /// </summary> /// <param name="entity">The entity.</param> /// <returns>The data transfer object.</returns> public static SplitwiseTransaction AsSplitwiseTransaction(this SplitwiseTransactionEntity entity) { return(new SplitwiseTransaction { Id = entity.Id, Description = entity.Description, Date = entity.Date, IsDeleted = entity.IsDeleted, Imported = entity.Imported, PaidAmount = entity.PaidAmount, PersonalAmount = entity.PersonalAmount, }); }
/// <summary> /// Verifies that a Splitwise transaction is processable. This is the case when the transaction has been /// imported and is not deleted. /// </summary> /// <param name="transaction">The entity to verify.</param> public static void VerifyProcessable(this SplitwiseTransactionEntity transaction) { if (!transaction.Imported) { throw new InvalidOperationException( "This Splitwise transaction is not imported and should therefore not be processed."); } if (transaction.IsDeleted) { throw new InvalidOperationException( "This Splitwise transaction is marked deleted and should therefore not be processed."); } }
/// <summary> /// Reverses the processing of a Splitwise transaction. Meaning that the Splitwise account balances are updated /// if needed. /// </summary> /// <param name="transaction">The Splitwise transaction.</param> private void Revert(SplitwiseTransactionEntity transaction) { transaction.VerifyProcessable(); var splitwiseAccount = this.Context.Accounts.GetSplitwiseEntity(); var(historicalEntriesToEdit, _) = this.GetBalanceEntriesToEdit(splitwiseAccount.Id, transaction.Date); var mutationAmount = transaction.GetSplitwiseAccountDifference(); foreach (var entry in historicalEntriesToEdit) { entry.Balance -= mutationAmount; } }
/// <summary> /// Creates a transaction with specified, or random values. /// </summary> /// <param name="context">The database context.</param> /// <param name="account">The account.</param> /// <param name="type">The type of the transaction.</param> /// <param name="description">The description of the transaction.</param> /// <param name="date">The date of the transaction.</param> /// <param name="amount">The amount.</param> /// <param name="category">The category.</param> /// <param name="receivingAccount">The receiving account.</param> /// <param name="recurringTransaction">The recurring transaction from which this is an instance.</param> /// <param name="splitwiseTransaction">The Splitwise transaction which is linked to this transaction.</param> /// <param name="paymentRequests">The payment requests that are linked to this transaction.</param> /// <param name="splitDetails">The split details which are linked to this transaction.</param> /// <param name="needsConfirmation">A value indicating if the transaction has to be confirmed.</param> /// <returns>The created transaction.</returns> public static TransactionEntity GenerateTransaction( this Context context, AccountEntity account, TransactionType type = TransactionType.Expense, string description = null, LocalDate?date = null, decimal?amount = null, CategoryEntity category = null, AccountEntity receivingAccount = null, RecurringTransactionEntity recurringTransaction = null, SplitwiseTransactionEntity splitwiseTransaction = null, List <PaymentRequestEntity> paymentRequests = null, List <SplitDetailEntity> splitDetails = null, bool needsConfirmation = false) { if ((type == TransactionType.Expense || type == TransactionType.Income) && category == null) { throw new Exception("Specify a category for an income or expense transaction."); } if (type == TransactionType.Transfer && receivingAccount == null) { throw new Exception("Specify a receiving account for a transfer transaction."); } return(context.Transactions.Add(new TransactionEntity { Account = account, Amount = amount ?? (type == TransactionType.Expense ? -50 : 50), Description = description ?? GetRandomString(), Date = date ?? DateTime.Now.ToLocalDate(), Category = category, ReceivingAccount = receivingAccount, NeedsConfirmation = needsConfirmation, PaymentRequests = paymentRequests ?? new List <PaymentRequestEntity>(), SplitDetails = splitDetails ?? new List <SplitDetailEntity>(), Processed = false, IsConfirmed = !needsConfirmation, Type = type, RecurringTransaction = recurringTransaction, SplitwiseTransaction = splitwiseTransaction, }).Entity); }
/// <summary> /// Processes a Splitwise transaction. Meaning that the Splitwise account balances are updated if needed. /// </summary> /// <param name="transaction">The Splitwise transaction.</param> /// <param name="addedDailyBalances">The daily balances that were already added. This is needed since the /// context does not contain already added entities, resulting in possible double daily balances which results /// in an error.</param> private void Process( SplitwiseTransactionEntity transaction, List <DailyBalanceEntity> addedDailyBalances, TransactionType type) { transaction.VerifyProcessable(); var splitwiseAccount = this.Context.Accounts.GetSplitwiseEntity(); var(historicalEntriesToEdit, newHistoricalEntry) = this.GetBalanceEntriesToEdit(splitwiseAccount.Id, transaction.Date, addedDailyBalances); if (newHistoricalEntry.IsSome) { addedDailyBalances.Add(newHistoricalEntry.Value); } var mutationAmount = transaction.GetSplitwiseAccountDifference(); foreach (var entry in historicalEntriesToEdit) { entry.Balance += mutationAmount; } }
/// <summary> /// Gets the amount with which the Splitwise account should be updated. This can either be negative /// (in the case that something is owed to others) positive (when someone else owes something to me). /// </summary> /// <param name="entity">The transaction entity.</param> /// <returns>The mutation for the Splitwise account.</returns> public static decimal GetSplitwiseAccountDifference(this SplitwiseTransactionEntity entity) { return(-entity.OwedToOthers + entity.OwedByOthers); }