public static void RebudgetItem(string recordId, int newAccountId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); IPayable payable = PayableFromRecordId(recordId); FinancialAccount newAccount = FinancialAccount.FromIdentity(newAccountId); if (payable.Budget.OrganizationId != authData.CurrentOrganization.Identity || payable.Budget.OwnerPersonId != authData.CurrentUser.Identity || newAccount.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException(); } payable.SetBudget(newAccount, authData.CurrentUser); }
protected void ButtonAutoBalance_Click(object sender, EventArgs e) { Person currentUser = Person.FromIdentity(Int32.Parse(HttpContext.Current.User.Identity.Name)); Authority authority = currentUser.GetAuthority(); if (!authority.HasPermission(Permission.CanDoEconomyTransactions, Int32.Parse(this.DropOrganizations.SelectedValue), -1, Authorization.Flag.ExactOrganization)) { ScriptManager.RegisterStartupScript(this, Page.GetType(), "validationfailed", "alert ('You do not have access to changing financial records.');", true); return; } if (this.DropAutoBalanceAccount.SelectedValue == "0") { ScriptManager.RegisterStartupScript(this, Page.GetType(), "validationfailed", "alert ('Please select an account to auto-balance against.');", true); return; } FinancialAccount autoBalanceAccount = FinancialAccount.FromIdentity(Int32.Parse(this.DropAutoBalanceAccount.SelectedValue)); if (this.GridTransactions.SelectedIndexes.Count == 0) { ScriptManager.RegisterStartupScript(this, Page.GetType(), "validationfailed", "alert ('Please select one or more transactions to auto-balance.');", true); return; } foreach (string indexString in this.GridTransactions.SelectedIndexes) { int index = Int32.Parse(indexString); int transactionId = (int)this.GridTransactions.MasterTableView.DataKeyValues[index]["Identity"]; FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); transaction.AddRow(autoBalanceAccount, -transaction.Rows.AmountCentsTotal, currentUser); } PopulateGrid(); this.GridTransactions.Rebind(); this.DropAutoBalanceAccount.SelectedValue = "0"; }
private static ExpensifyOutputRecord[] FormatExpensifyOutputRecords(List <ExpensifyRecord> recordList) { List <ExpensifyOutputRecord> outputRecords = new List <ExpensifyOutputRecord>(); const string doxString = "<img src='/Images/Icons/iconshock-search-256px.png' onmouseover=\"this.src='/Images/Icons/iconshock-search-hot-256px.png';\" onmouseout=\"this.src='/Images/Icons/iconshock-search-256px.png';\" firstDocId='{0}' class='LocalIconViewDoc' style='cursor:pointer' height='20' width='20' />"; const string editString = "<img src='/Images/Icons/iconshock-wrench-128x96px-centered.png' height='18' width='24' class='LocalEditExpenseClaim' data-guid='{0}' />"; foreach (ExpensifyRecord record in recordList) { ExpensifyOutputRecord newRecord = new ExpensifyOutputRecord { Description = record.CategoryCustom + " / " + record.Description, CreatedDateTime = record.Timestamp.ToString("MMM dd"), Amount = (record.AmountCents / 100.0).ToString("N2"), AmountVat = (record.VatCents / 100.0).ToString("N2"), Actions = String.Format(doxString, "D" + record.Documents[0].Identity.ToString(CultureInfo.InvariantCulture)) + String.Format(editString, record.Guid), Guid = record.Guid }; if (record.BudgetId != 0) { FinancialAccount account = FinancialAccount.FromIdentity(record.BudgetId); newRecord.BudgetText = account.Name; if (account.ParentIdentity != 0) { newRecord.BudgetText = account.Parent.Name + " » " + account.Name; } } else { newRecord.BudgetText = "<span class='LocalEditExpenseClaim' data-guid='" + record.Guid + "'>" + Resources.Global.Global_DropInits_SelectFinancialAccount + "</span>"; } outputRecords.Add(newRecord); } return(outputRecords.ToArray()); }
protected void DropBudgets_SelectedIndexChanged(object sender, EventArgs e) { if (this.DropBudgets.SelectedValue != "0") { FinancialAccount selectedBudget = FinancialAccount.FromIdentity(Int32.Parse(this.DropBudgets.SelectedValue)); if (selectedBudget.GetTree().Count > 1) { this.DropSubBudget.Populate(selectedBudget); this.DropMethod.Items[4].Enabled = true; } else { this.DropMethod.Items[4].Enabled = false; } } }
private string ProcessTransferSubBudget() { int year = DateTime.Today.Year; FinancialAccount fromAccount = FinancialAccount.FromIdentity(Int32.Parse(this.DropBudgets.SelectedValue)); FinancialAccount toAccount = this.DropSubBudget.SelectedFinancialAccount; double amount = Double.Parse(this.TextAmount.Text, NumberStyles.Float, new CultureInfo("sv-SE")); string description = this.TextDescription.Text; // Transfer the budget fromAccount.SetBudget(year, fromAccount.GetBudget(year) + amount); // budgets are negative -- this decreases the budget toAccount.SetBudget(year, toAccount.GetBudget(year) - amount); // budgets are negative -- this increases the budget // Set result return(amount.ToString("N2") + " was transferred from " + fromAccount.Name + " to " + toAccount.Name + "."); }
public static ChangeAccountDataResult SetAccountBudget(int accountId, string budget) { AuthenticationData authData = GetAuthenticationDataAndCulture(); FinancialAccount account = FinancialAccount.FromIdentity(accountId); if (!PrepareAccountChange(account, authData, false)) { return(new ChangeAccountDataResult { Result = ChangeAccountDataOperationsResult.NoPermission }); } Int64 newTreeBudget; budget = budget.Replace("%A0", "%20"); // some very weird browser space-to-otherspace translation weirds out number parsing budget = HttpContext.Current.Server.UrlDecode(budget); if (budget.Trim().Length > 0 && Int64.TryParse(budget, NumberStyles.Currency, CultureInfo.CurrentCulture, out newTreeBudget)) { newTreeBudget *= 100; // convert to cents int year = DateTime.Today.Year; FinancialAccounts accountTree = account.GetTree(); Int64 currentTreeBudget = accountTree.GetBudgetSumCents(year); Int64 currentSingleBudget = account.GetBudgetCents(year); Int64 suballocatedBudget = currentTreeBudget - currentSingleBudget; Int64 newSingleBudget = newTreeBudget - suballocatedBudget; account.SetBudgetCents(DateTime.Today.Year, newSingleBudget); return(new ChangeAccountDataResult { Result = ChangeAccountDataOperationsResult.Changed, NewData = (newTreeBudget / 100).ToString("N0", CultureInfo.CurrentCulture) }); } else { return(new ChangeAccountDataResult { Result = ChangeAccountDataOperationsResult.Invalid }); } }
private string ProcessExpenseClaim() { int year = DateTime.Today.Year; FinancialAccount account = FinancialAccount.FromIdentity(Int32.Parse(this.DropBudgets.SelectedValue)); string expenseName = this.TextDescription.Text; Person claimer = this.ComboClaimPerson.SelectedPerson; Int64 amountCents = (Int64)(Double.Parse(this.TextAmount.Text, NumberStyles.Float, new CultureInfo("sv-SE")) * 100); // Create the expense claim record ExpenseClaim newClaim = ExpenseClaim.Create(claimer, Organization.PPSE, account, DateTime.Today, expenseName, amountCents); newClaim.Claimed = false; newClaim.Attest(_currentUser); return("The claim was created and pre-attested. " + claimer.Canonical + " has it in the list of approved expenses."); }
public static JsonAccountData GetAccountData(int accountId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); FinancialAccount account = FinancialAccount.FromIdentity(accountId); if (account.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException("A million nopes"); } FinancialAccounts accountTree = account.GetTree(); int year = DateTime.Today.Year; JsonAccountData result = new JsonAccountData(); result.AccountName = account.Name; result.ParentAccountId = account.ParentIdentity; result.ParentAccountName = account.ParentFinancialAccountId == 0 ? Resources.Global.ResourceManager.GetString("Financial_" + account.AccountType.ToString()) : account.Parent.Name; result.Expensable = account.Expensable; result.Administrative = account.Administrative; result.Active = account.Active; result.Open = account.Open; result.AccountOwnerName = account.OwnerPersonId != 0 ? account.Owner.Name : Resources.Global.Global_NoOwner; result.AccountOwnerAvatarUrl = account.OwnerPersonId != 0 ? account.Owner.GetSecureAvatarLink(24) : "/Images/Icons/iconshock-warning-24px.png"; result.Budget = (accountTree.GetBudgetSumCents(year) / 100L).ToString("N0", CultureInfo.CurrentCulture); if (account.AccountType == FinancialAccountType.Asset || account.AccountType == FinancialAccountType.Debt) { result.Balance = (accountTree.GetDeltaCents(new DateTime(1900, 1, 1), new DateTime(year + 1, 1, 1)) / 100L).ToString("N0"); } else { result.Balance = (-accountTree.GetDeltaCents(new DateTime(year, 1, 1), new DateTime(year + 1, 1, 1)) / 100L).ToString("N0"); } result.CurrencyCode = account.Organization.Currency.Code; return(result); }
private void RedrawForNewAccount() { if (!_authority.HasPermission(Permission.CanDoEconomyTransactions, _organizationId, -1, Authorization.Flag.ExactOrganization)) { CreateTransactionPanel.Visible = false; ScriptManager.RegisterStartupScript(this, Page.GetType(), "getlost", "alert ('You do not have access to financial records.');", true); return; } int accountId = Int32.Parse(this.DropAccounts.SelectedValue); if (this.DateStart.SelectedDate > this.DateEnd.SelectedDate) { DateTime largerDate = (DateTime)this.DateStart.SelectedDate; this.DateStart.SelectedDate = this.DateEnd.SelectedDate; this.DateEnd.SelectedDate = largerDate; } PopulateGrid(accountId, (DateTime)this.DateStart.SelectedDate, (DateTime)this.DateEnd.SelectedDate); this.GridTransactions.Rebind(); if (accountId != 0) { FinancialAccount account = FinancialAccount.FromIdentity(accountId); this.LabelTransactionsTitle.Text = "Transactions in account '" + account.Name + "'"; // Hide the accounts dropdown in "Create Transaction" and replace it with a static account name this.DropAccountsCreate.Visible = false; this.LabelAccountCreate.Visible = true; this.DropAccountsCreate.SelectedValue = accountId.ToString(); this.LabelAccountCreate.Text = account.Name; } else { this.LabelTransactionsTitle.Text = "No account selected."; this.DropAccountsCreate.Visible = true; this.LabelAccountCreate.Visible = false; this.LabelAccountCreate.Text = ""; } }
public static bool SetAccountName(int accountId, string name) { AuthenticationData authData = GetAuthenticationDataAndCulture(); FinancialAccount account = FinancialAccount.FromIdentity(accountId); if (account.Name == name) { // no change return(true); } if (!PrepareAccountChange(account, authData, true)) { return(false); } account.Name = name; return(true); }
protected void ButtonSelectBudget_Click(object sender, EventArgs e) { ViewState[this.ClientID + "_BudgetId"] = this.DropBudgets.SelectedValue; this.HiddenInitBudgetId.Value = this.DropBudgets.SelectedValue; ViewState[this.ClientID + "_Year"] = this.DropYears.SelectedValue; this.HiddenInitYear.Value = this.DropYears.SelectedValue; _account = FinancialAccount.FromIdentity(Int32.Parse(this.DropBudgets.SelectedValue)); _year = Int32.Parse(this.DropYears.SelectedValue); PopulateBudgetData(); bool enableChanges = Int32.Parse(this.DropYears.SelectedValue) >= DateTime.Today.Year; this.ButtonReallocate.Enabled = enableChanges; this.ButtonSavePredict.Enabled = enableChanges; RebindTooltips(); }
protected void Page_Load(object sender, EventArgs e) { attestationRights = GetAttestationRights(); this.ComboClaimPerson.Authority = _currentUser.GetAuthority(); this.ComboBudgetPerson.Authority = _currentUser.GetAuthority(); if (!Page.IsPostBack) { this.DropMethod.Style [HtmlTextWriterStyle.Width] = "300px"; // Populate foreach (int budgetId in attestationRights.Keys) { this.DropBudgets.Items.Add(new ListItem(FinancialAccount.FromIdentity(budgetId).Name, budgetId.ToString())); } this.LabelForTheItem.Text = "for the expense claim, purchase order, budget, or transfer order"; } }
protected void DropOrganizations_SelectedIndexChanged(object sender, EventArgs e) { int organizationId = Int32.Parse(this.DropOrganizations.SelectedValue); Organization organization = Organization.FromIdentity(organizationId); // TODO: Security parsing this.DropAssetAccount.Items.Clear(); this.DropAutoDeposits.Items.Clear(); this.DropAutoWithdrawals.Items.Clear(); if (organizationId == PPOrgId && _authority.HasPermission(Permission.CanDoEconomyTransactions, PPOrgId, -1, Authorization.Flag.ExactOrganization)) { // TODO: Populate from a database table instead FinancialAccount assetAccount = organization.FinancialAccounts.AssetsBankAccountMain; FinancialAccount incomeAccount = organization.FinancialAccounts.IncomeDonations; FinancialAccount costAccount = organization.FinancialAccounts.CostsBankFees; this.DropAssetAccount.Items.Add(new ListItem(assetAccount.Name, assetAccount.Identity.ToString())); this.DropAssetAccount.Items.Add(new ListItem("Paypal", organization.FinancialAccounts.AssetsPaypal.Identity.ToString())); this.DropAutoDeposits.Items.Add(new ListItem(incomeAccount.Name, incomeAccount.Identity.ToString())); this.DropAutoWithdrawals.Items.Add(new ListItem(costAccount.Name, costAccount.Identity.ToString())); this.TextDepositLimit.Text = "1000"; this.TextWithdrawalLimit.Text = "0"; } else if (organizationId == 55) { // Rick's sandbox. Please leave in code for the time being. FinancialAccount assetAccount = FinancialAccount.FromIdentity(60); FinancialAccount incomeAccount = FinancialAccount.FromIdentity(63); FinancialAccount costAccount = FinancialAccount.FromIdentity(65); this.DropAssetAccount.Items.Add(new ListItem(assetAccount.Name, assetAccount.Identity.ToString())); this.DropAutoDeposits.Items.Add(new ListItem(incomeAccount.Name, incomeAccount.Identity.ToString())); this.DropAutoWithdrawals.Items.Add(new ListItem(costAccount.Name, costAccount.Identity.ToString())); this.TextDepositLimit.Text = "7500"; this.TextWithdrawalLimit.Text = "0"; } }
protected void Page_Init(object sender, EventArgs e) { // In case we're in a postback, we need to recreate the suballocation controls in order for the viewstate to be recaptured. // But we don't have the viewstate in Init, yet. Still, we must have it here to recapture ViewState. // // The solution is to use hidden fields with the information we need to recreate the controls and then read them directly // from the Request object. string accountIdString = Request["ctl00$BodyContent$HiddenInitBudgetId"]; string yearString = Request["ctl00$BodyContent$HiddenInitYear"]; if (!string.IsNullOrEmpty(accountIdString)) { _account = FinancialAccount.FromIdentity(Int32.Parse(accountIdString)); _year = Int32.Parse(yearString); InitSuballocation(false); } // If these are not present in the Request objects, the suballocation controls will be created in Page_Load without postback values. }
public static bool SetAccountOwner(int accountId, int newOwnerId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); FinancialAccount account = FinancialAccount.FromIdentity(accountId); if (!PrepareAccountChange(account, authData, false)) { return(false); } Person newOwner = Person.FromIdentity(newOwnerId); // Verify that authdata.AuthenticatedPerson can see personId, or this can be exploited to enumerate all people if (!authData.Authority.CanSeePerson(newOwner)) { throw new ArgumentException("No such person identity"); } account.Owner = newOwner; return(true); }
private string ProcessCreateSubBudget() { int year = DateTime.Today.Year; FinancialAccount parentAccount = FinancialAccount.FromIdentity(Int32.Parse(this.DropBudgets.SelectedValue)); string budgetName = this.TextDescription.Text; Person owner = this.ComboBudgetPerson.SelectedPerson; double currentBudget = parentAccount.GetBudget(year); double amount = Double.Parse(this.TextAmount.Text, NumberStyles.Float, new CultureInfo("sv-SE")); FinancialAccount account = FinancialAccount.Create(Organization.PPSEid, budgetName, FinancialAccountType.Cost, parentAccount.Identity); account.Owner = owner; account.SetBudget(year, -amount); // cost accounts have a negative budget parentAccount.SetBudget(year, currentBudget + amount); // cost accounts have a negative budget -- this will LOWER the budget return("The budget " + budgetName + " was created, owned by " + owner.Canonical + " and with an initial budget for " + year.ToString() + " of " + amount.ToString("N2") + ". Do not forget to instruct " + (owner.IsFemale? "her" : "him") + " on the duties associated, such as attesting expenses, etc."); }
public static AjaxCallAutomationDataResult SetAccountAutomationProfile(int accountId, int profileId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); FinancialAccount account = FinancialAccount.FromIdentity(accountId); if (account.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException("A million nopes"); } if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails, AccessType.Write))) { throw new UnauthorizedAccessException("No"); } account.AutomationProfileId = profileId; AjaxCallAutomationDataResult result = new AjaxCallAutomationDataResult(); result.Success = true; result.Data = GetAccountAutomationData(profileId); result.Data.NonPresentationCurrency = (result.Data.Profile.CurrencyId != authData.CurrentOrganization.Currency.Identity); if (result.Data.NonPresentationCurrency) { account.ForeignCurrency = Currency.FromCode(result.Data.AutomationCurrencyCode); } else { account.ForeignCurrency = null; } return(result); }
public static bool AddTransactionRow(int txId, int accountId, string amountString) { AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.Bookkeeping, AccessType.Write))) { return(false); // fail } FinancialTransaction transaction = FinancialTransaction.FromIdentity(txId); if (authData.CurrentOrganization.Parameters.FiscalBooksClosedUntilYear >= transaction.DateTime.Year) { return(false); // can't edit closed books } FinancialAccount account = FinancialAccount.FromIdentity(accountId); Double amountFloat = Double.Parse(amountString); Int64 amountCents = (Int64)(amountFloat * 100.0); if (account.OrganizationId != authData.CurrentOrganization.Identity) { throw new InvalidOperationException("Account/Organization mismatch"); } if (amountCents == 0) { return(false); } transaction.AddRow(account, amountCents, authData.CurrentUser); return(true); }
public static void InitializeProcessing(string guid, string accountIdString) { // Start an async thread that does all the work, then return AuthenticationData authData = GetAuthenticationDataAndCulture(); int accountId = Int32.Parse(accountIdString); FinancialAccount account = FinancialAccount.FromIdentity(accountId); if (account.Organization.Identity != authData.CurrentOrganization.Identity || !authData.CurrentUser.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.Bookkeeping, AccessType.Write))) { throw new UnauthorizedAccessException(); } Thread initThread = new Thread(ProcessUploadThread); ProcessThreadArguments args = new ProcessThreadArguments { Guid = guid, Organization = authData.CurrentOrganization, Account = account }; initThread.Start(args); }
protected void ButtonRequest_Click(object sender, EventArgs e) { // The data has been validated client-side already. We'll throw unfriendly exceptions if invalid data is passed here. // People who choose to disable JavaScript and then submit bad input almost deserve to be hurt. Int64 amountCents = (Int64)(this.CurrencyAmount.Value * 100.0); string description = this.TextPurpose.Text; FinancialAccount budget = FinancialAccount.FromIdentity(Int32.Parse(Request.Form["DropBudgets"])); // sanity check if (budget.Organization.Identity != CurrentOrganization.Identity) { throw new InvalidOperationException("Budget-organization mismatch; won't file expense claim"); } // Store bank details for current user CurrentUser.BankName = this.TextBank.Text; CurrentUser.BankClearing = this.TextClearing.Text; CurrentUser.BankAccount = this.TextAccount.Text; // Get documents; check that documents have been uploaded Documents documents = Documents.RecentFromDescription(this.FileUpload.GuidString); if (documents.Count == 0) { throw new InvalidOperationException("No documents uploaded"); } ExpenseClaim claim = ExpenseClaim.Create(CurrentUser, CurrentOrganization, budget, DateTime.UtcNow, description, amountCents); foreach (int tagSetId in this._tagSetIds) { string selectedTagString = Request.Form["DropTags" + tagSetId.ToString(CultureInfo.InvariantCulture)]; if (!String.IsNullOrEmpty(selectedTagString)) { int selectedTagType = Int32.Parse(selectedTagString); if (selectedTagType != 0) { claim.FinancialTransaction.CreateTag( FinancialTransactionTagType.FromIdentity(selectedTagType), CurrentUser); } } } documents.SetForeignObjectForAll(claim); string successMessage = string.Format(Resources.Pages.Financial.FileExpenseClaim_SuccessMessagePartOne, CurrentOrganization.Currency.Code, amountCents / 100.0, budget.Name); if (budget.OwnerPersonId != CurrentUser.Identity) { successMessage += "<br/><br/>" + Resources.Pages.Financial.FileExpenseClaim_SuccessMessagePartTwo + "<br/>"; } else { successMessage += "<br/><br/>" + Resources.Pages.Financial.FileExpenseClaim_SuccessMessagePartTwoOwnBudget + "<br/>"; claim.Attest(CurrentUser); } Response.AppendCookie(new HttpCookie("DashboardMessage", HttpUtility.UrlEncode(successMessage))); // Redirect to dashboard Response.Redirect("/", true); }
protected void Page_Load(object sender, EventArgs e) { FinancialAccount bankAccount = FinancialAccount.FromIdentity(29); Organization euroPirates = Organization.FromIdentity(7); FinancialTransactions unbalancedTransactions = FinancialTransactions.GetUnbalanced(euroPirates); // assume all in bank account foreach (FinancialTransaction transaction in unbalancedTransactions) { if (transaction.Description[0] == 'H' && Char.IsDigit(transaction.Description[1]) && transaction.Rows.BalanceCentsDelta > 0) { // outbound intl invoice. Add an untracked intl invoice 10 days prior, map it to this OutboundInvoice newInvoice = OutboundInvoice.Create(euroPirates, transaction.DateTime, euroPirates.FinancialAccounts.IncomeSales, "Untracked", "*****@*****.**", string.Empty, euroPirates.Currency, false, string.Empty, Person.FromIdentity(1)); newInvoice.AddItem("Untracked item", transaction.Rows.BalanceCentsDelta); // Doesn't close // Add transaction // Create the financial transaction with rows FinancialTransaction invoiceTransaction = FinancialTransaction.Create(euroPirates.Identity, transaction.DateTime.AddDays(-10), "Outbound Invoice #" + newInvoice.Identity); invoiceTransaction.AddRow(euroPirates.FinancialAccounts.AssetsOutboundInvoices, newInvoice.AmountCents, null); invoiceTransaction.AddRow(euroPirates.FinancialAccounts.IncomeSales, -newInvoice.AmountCents, null); invoiceTransaction.Dependency = newInvoice; transaction.AddRow(euroPirates.FinancialAccounts.AssetsOutboundInvoices, -newInvoice.AmountCents, null); Payment payment = Payment.CreateSingle(euroPirates, transaction.DateTime, euroPirates.Currency, newInvoice.AmountCents, newInvoice, null); transaction.Dependency = payment.Group; payment.Group.Open = false; } if ((transaction.Description == "Kostnad" || transaction.Description == "Bank charges") && transaction.Rows.BalanceCentsDelta < 0 && transaction.Rows.BalanceCentsDelta > -125000) { // Bank fee. transaction.AddRow(euroPirates.FinancialAccounts.CostsBankFees, -transaction.Rows.BalanceCentsDelta, null); } if (transaction.Description.StartsWith("Paypal ")) { // Bank fee. transaction.AddRow(euroPirates.FinancialAccounts.CostsBankFees, -transaction.Rows.BalanceCentsDelta, null); } } Payouts.AutomatchAgainstUnbalancedTransactions(euroPirates); }
protected static ImportStats ProcessImportedData(ImportResult import, Organization organization, Person importingPerson) { FinancialAccount paysonAccount = FinancialAccount.FromIdentity(99); // HACK -- need something more sophisticated long run that allows different accounts for different orgs FinancialAccount bankFees = organization.FinancialAccounts.CostsBankFees; FinancialAccount donations = organization.FinancialAccounts.IncomeDonations; int autoDepositLimit = 1000; // TODO: Get from organization parameters int autoWithdrawalLimit = 0; ImportStats result = new ImportStats(); foreach (ImportedRow row in import.Rows) { // Each row is at least a stub, probably more. // If too old, ignore. if (row.DateTime < new DateTime(2010, 4, 1)) { continue; } string importKey = row.SuppliedTransactionId; // If importKey is empty, construct a hash from the data fields. if (string.IsNullOrEmpty(importKey)) { string hashKey = row.HashBase + row.Comment + (row.AmountCentsNet / 100.0).ToString(CultureInfo.InvariantCulture) + row.CurrentBalance.ToString(CultureInfo.InvariantCulture) + row.DateTime.ToString("yyyy-MM-dd-hh-mm-ss"); importKey = SHA1.Hash(hashKey).Replace(" ", ""); } if (importKey.Length > 30) { importKey = importKey.Substring(0, 30); } Int64 amountCents = row.AmountCentsNet; if (amountCents == 0) { amountCents = row.AmountCentsGross; } Dictionary <int, long> nominalTransaction = new Dictionary <int, long>(); FinancialTransaction transaction = null; try { transaction = FinancialTransaction.FromImportKey(organization, importKey); } catch (Exception) { // if we get here, that means the transaction did not yet exist transaction = FinancialTransaction.ImportWithStub(organization.Identity, row.DateTime, paysonAccount.Identity, amountCents, row.Comment, importKey, importingPerson.Identity); result.ImportedTransactionCount++; if (transaction == null) { // No transaction was created. This is an error condition as it should have been created if it didn't // exist, and the "exist" case is handled in the FromImportKey attempt above. Abort with error. // Throw new exception? continue; } } result.ProcessedTransactionCount++; nominalTransaction[paysonAccount.Identity] = amountCents; // The transaction was created. Examine if the autobook criteria are true. if (amountCents < 0) { if ((-amountCents) < autoWithdrawalLimit * 100) { // Book against autoWithdrawal account. nominalTransaction[bankFees.Identity] = -amountCents; } } else if (amountCents > 0) { if (row.FeeCents < 0) { // This is always an autodeposit, if there is a fee (which is never > 0.0) nominalTransaction[bankFees.Identity] = -row.FeeCents; nominalTransaction[donations.Identity] = -row.AmountCentsGross; } else if (amountCents < autoDepositLimit * 100) { // Book against autoDeposit account. nominalTransaction[donations.Identity] = -amountCents; } } if (transaction.Rows.AmountCentsTotal != 0) // If transaction is unbalanced, balance it { if (transaction.RecalculateTransaction(nominalTransaction, importingPerson)) { result.ModifiedTransactionCount++; } } } return(result); }
protected void Page_Load(object sender, EventArgs e) { Response.ContentType = "application/json"; string accountIdString = Request.QueryString["AccountId"]; string yearString = Request.QueryString["Year"]; string monthString = Request.QueryString["Month"]; string emptyResponse = "[{\"id\":\"-\",\"description\":\"" + JsonSanitize(Resources.Pages.Ledgers.InspectLedgers_PleaseSelectAccount) + "\"}]"; if (string.IsNullOrEmpty(accountIdString) || string.IsNullOrEmpty(yearString) || string.IsNullOrEmpty(monthString) || accountIdString == "undefined") { Response.Output.WriteLine(emptyResponse); Response.End(); } int accountId = Int32.Parse(accountIdString); int year = Int32.Parse(yearString); int month = Int32.Parse(monthString); DateTime dawnOfMankind = new DateTime(1901, 1, 1); // no org will ever import bookkeeping from before this date if (accountId <= 0) { Response.Output.WriteLine(emptyResponse); Response.End(); } FinancialAccount account = FinancialAccount.FromIdentity(accountId); if (account.OrganizationId != CurrentOrganization.Identity) { throw new UnauthorizedAccessException("All the nopes in the world"); } if (!CurrentAuthority.HasAccess(new Access(CurrentOrganization, AccessAspect.Bookkeeping, AccessType.Read))) { throw new UnauthorizedAccessException("Access denied because security tokens say so"); } DateTime periodStart, periodEnd; DateTime balanceStart = dawnOfMankind; bool zeroStart = false; bool zeroEnd = false; bool displayDescription = CurrentAuthority.HasAccess(new Access(CurrentOrganization, AccessAspect.BookkeepingDetails, AccessType.Read)); bool canSeeAudit = CurrentAuthority.HasAccess(new Access(CurrentOrganization, AccessAspect.Auditing, AccessType.Read)); if (month > 0 && month <= 12) { periodStart = new DateTime(year, month, 1); periodEnd = periodStart.AddMonths(1); if (account.AccountType == FinancialAccountType.Income || account.AccountType == FinancialAccountType.Cost) { balanceStart = new DateTime(year, 1, 1); if (month == 1) { zeroStart = true; } if (month == 12) { zeroEnd = true; } } } else if (month > 20 && month < 25) // quarters 1..4 are coded as months 21..24 { periodStart = new DateTime(year, (month - 21) * 3 + 1, 1); periodEnd = periodStart.AddMonths(3); if (account.AccountType == FinancialAccountType.Income || account.AccountType == FinancialAccountType.Cost) { balanceStart = new DateTime(year, 1, 1); if (month == 21) { zeroStart = true; } if (month == 24) { zeroEnd = true; } } } else if (month == 31) // "whole year" is coded as month 31 { periodStart = new DateTime(year, 1, 1); periodEnd = new DateTime(year + 1, 1, 1); if (account.AccountType == FinancialAccountType.Income || account.AccountType == FinancialAccountType.Cost) { zeroStart = true; zeroEnd = true; } } else { throw new ArgumentException("Invalid month supplied: " + month.ToString(CultureInfo.InvariantCulture)); } FinancialAccountRows rows = account.GetRows(periodStart, periodEnd); StringBuilder result = new StringBuilder(16384); Int64 runningBalance = 0L; string startString = Resources.Pages.Ledgers.InspectLedgers_InboundBalanceZero; string endString = Resources.Pages.Ledgers.InspectLedgers_OutboundBalanceZero; if (!zeroStart) { runningBalance = account.GetDeltaCents(balanceStart, periodStart); startString = Resources.Pages.Ledgers.InspectLedgers_InboundBalance; } if (!zeroEnd) { endString = Resources.Pages.Ledgers.InspectLedgers_OutboundBalance; } else if (periodEnd > DateTime.Now) { // account is zeroed at end of this period, but we're not yet at end of period, so add a "to date" disclaimer endString = Resources.Pages.Ledgers.InspectLedgers_OutboundBalanceZeroToDate; } result.Append("{" + String.Format("\"description\":\"{0}\",\"balance\":\"{1:N0}\"", JsonSanitize(startString), runningBalance / 100.0) + "},"); foreach (FinancialAccountRow row in rows) { string creditString = string.Empty; string debitString = string.Empty; string description = row.Description; if (!displayDescription) { description = Resources.Pages.Ledgers.InspectLedgers_TxDetail_DescriptionWithheld; } if (row.AmountCents < 0) { creditString = String.Format("{0:N0}", row.AmountCents / 100.0); } else if (row.AmountCents > 0) { debitString = String.Format("{0:N0}", row.AmountCents / 100.0); } runningBalance += row.AmountCents; string actionHtml = String.Format( "<img src=\"/Images/Icons/iconshock-magnifyingglass-16px.png\" class=\"LocalIconInspect\" txId=\"{0}\" />", row.FinancialTransactionId.ToString(CultureInfo.InvariantCulture)); if (canSeeAudit) { actionHtml += String.Format( " <img src=\"/Images/Icons/iconshock-flag-white-16px.png\" class=\"LocalIconFlag\" txId=\"{0}\" />", row.FinancialTransactionId.ToString(CultureInfo.InvariantCulture)); } result.Append("{" + String.Format( "\"id\":\"{0:N0}\",\"datetime\":\"{1:MMM-dd HH:mm}\",\"description\":\"{2}\"," + "\"deltaPos\":\"{3}\",\"deltaNeg\":\"{4}\",\"balance\":\"{5:N0}\",\"action\":\"{6}\"", row.FinancialTransactionId, row.TransactionDateTime, JsonSanitize(description), debitString, creditString, runningBalance / 100.0, JsonSanitize(actionHtml)) + "},"); } if (rows.Count == 0) { // If there are no transactions in this time period, say so result.Append("{\"description\":\"" + JsonSanitize(Resources.Pages.Ledgers.InspectLedgers_NoTransactions) + "\"},"); } result.Append("{" + String.Format("\"description\":\"{0}\",\"balance\":\"{1:N0}\"", JsonSanitize(endString), runningBalance / 100.0) + "},"); Response.Output.WriteLine("[" + result.ToString().TrimEnd(',') + "]"); Response.End(); }
protected void Page_Load(object sender, EventArgs e) { string documentIdString = Request.QueryString["DocumentId"]; int documentId = Int32.Parse(documentIdString); Document document = Document.FromIdentity(documentId); //Orgid is needed to safely verify permission int orgId = Organization.PPSEid; bool hasPermission = false; switch (document.DocumentType) { case DocumentType.FinancialTransaction: { //TODO: Get the orgId from foreign object if (_authority.HasPermission(Permission.CanSeeEconomyDetails, orgId, -1, Authorization.Flag.ExactOrganization)) { hasPermission = true; } } break; case DocumentType.ExpenseClaim: case DocumentType.InboundInvoice: { int budgetId = 0; if (document.DocumentType == DocumentType.ExpenseClaim) { ExpenseClaim claim = (ExpenseClaim)document.ForeignObject; orgId = claim.Budget.OrganizationId; budgetId = claim.BudgetId; } else { InboundInvoice invoice = (InboundInvoice)document.ForeignObject; orgId = invoice.Budget.OrganizationId; budgetId = invoice.BudgetId; } if (_authority.HasPermission(Permission.CanSeeEconomyDetails, orgId, -1, Authorization.Flag.ExactOrganization)) { hasPermission = true; break; } if (FinancialAccount.FromIdentity(budgetId).OwnerPersonId == _currentUser.Identity) { hasPermission = true; } break; } case DocumentType.PaperLetter: { PaperLetter letter = (PaperLetter)document.ForeignObject; if (letter.Recipient.Identity == _currentUser.Identity) { hasPermission = true; // A letter to the viewer } // Otherwise, are there overriding permissions, if not addressed to him/her? else if (!letter.Personal) { // Unpersonal paper letter, like a rally permit. Note that bank statements should // be considered personal as they contain donors' information in the transaction info. if (_authority.HasPermission(Permission.CanSeeInsensitivePaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) { hasPermission = true; } } else if (letter.ToPersonId == 0) { // Addressed to the organization, not to a specific person, but still personal. // Typical examples include political inquiries from private citizens written on // paper. if (_authority.HasPermission(Permission.CanSeeSensitivePaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) { hasPermission = true; } } else { // Addressed to a specific individual that is not the viewer, and it's personal. // INVOCATION OF THIS CODE IS A BREACH OF THE POSTAL SECRET and should ONLY EVER // be done for technical, not operational, reasons and preferably NEVER. if (_authority.HasPermission(Permission.CanBreachPostalSecretPaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) { hasPermission = true; } } } break; case DocumentType.PersonPhoto: { // These are public hasPermission = true; } break; } if (!hasPermission) { throw new Exception("Access is not allowed"); } string serverPath = @"C:\Data\Uploads\PirateWeb"; // TODO: Read from web.config string contentType = string.Empty; if (document.ServerFileName.EndsWith(".pdf")) { contentType = MediaTypeNames.Application.Pdf; } else if (document.ServerFileName.EndsWith(".png")) { contentType = "image/png"; // why isn't this in MediaTypeNames? } else if (document.ServerFileName.EndsWith(".jpg")) { contentType = MediaTypeNames.Image.Jpeg; } Response.ContentType = contentType + "; filename=" + document.ClientFileName; Response.TransmitFile(serverPath + Path.DirectorySeparatorChar + document.ServerFileName); }
protected void Page_Load(object sender, EventArgs e) { string documentIdString = Request.QueryString["DocId"]; int documentId = Int32.Parse(documentIdString); string documentDownloadName = Request.QueryString["DocName"]; documentDownloadName = documentDownloadName.Replace("\"", "'"); Document document = Document.FromIdentity(documentId); //Orgid is needed to safely verify permission int orgId = 0; // initialize to invalid bool hasPermission = false; string serverFileName = document.ServerFileName; if (document.UploadedByPersonId == this.CurrentAuthority.Person.Identity) { hasPermission = true; // can always view documents you yourself uploaded } if (CurrentOrganization.HasOpenLedgers) { hasPermission = true; } if (!hasPermission) { switch (document.DocumentType) { case DocumentType.FinancialTransaction: { /* * //TODO: Get the orgId from foreign object * if (this.CurrentAuthority.HasPermission(Permission.CanSeeEconomyDetails, orgId, -1, Authorization.Flag.ExactOrganization)) * { * hasPermission = true; * }*/ } break; case DocumentType.ExpenseClaim: case DocumentType.InboundInvoice: case DocumentType.OutboundInvoice: { int budgetId = 0; if (document.DocumentType == DocumentType.ExpenseClaim) { ExpenseClaim claim = (ExpenseClaim)document.ForeignObject; orgId = claim.Budget.OrganizationId; budgetId = claim.BudgetId; } else if (document.DocumentType == DocumentType.InboundInvoice) { InboundInvoice invoice = (InboundInvoice)document.ForeignObject; orgId = invoice.Budget.OrganizationId; budgetId = invoice.BudgetId; } else { OutboundInvoice invoice = (OutboundInvoice)document.ForeignObject; orgId = invoice.OrganizationId; budgetId = invoice.BudgetId; } FinancialAccount budget = FinancialAccount.FromIdentity(budgetId); if (budget.OwnerPersonId == CurrentUser.Identity || budget.OwnerPersonId == 0) { hasPermission = true; break; } // TODO: Security leak - check CurrentOrganization against Document's org if ( CurrentAuthority.HasAccess(new Access(CurrentOrganization, AccessAspect.Financials, AccessType.Write))) { hasPermission = true; } /* * if (this.CurrentAuthority.HasPermission(Permission.CanSeeEconomyDetails, orgId, -1, Authorization.Flag.ExactOrganization)) * { * hasPermission = true; * break; * }*/ break; } case DocumentType.PaperLetter: { PaperLetter letter = (PaperLetter)document.ForeignObject; if (letter.Recipient.Identity == CurrentUser.Identity) { hasPermission = true; // A letter to the viewer } /* * // Otherwise, are there overriding permissions, if not addressed to him/her? * * else if (!letter.Personal) * { * // Unpersonal paper letter, like a rally permit. Note that bank statements should * // be considered personal as they contain donors' information in the transaction info. * * if (this.CurrentAuthority.HasPermission(Permission.CanSeeInsensitivePaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) * { * hasPermission = true; * } * } * else if (letter.ToPersonId == 0) * { * // Addressed to the organization, not to a specific person, but still personal. * // Typical examples include political inquiries from private citizens written on * // paper. * * if (this.CurrentAuthority.HasPermission(Permission.CanSeeSensitivePaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) * { * hasPermission = true; * } * } * else * { * // Addressed to a specific individual that is not the viewer, and it's personal. * // INVOCATION OF THIS CODE IS A BREACH OF THE POSTAL SECRET and should ONLY EVER * // be done for technical, not operational, reasons and preferably NEVER. * * if (this.CurrentAuthority.HasPermission(Permission.CanBreachPostalSecretPaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) * { * hasPermission = true; * } * }*/ } break; case DocumentType.PersonPhoto: case DocumentType.Logo: case DocumentType.Artwork: { // These are public hasPermission = true; } break; } } if (!hasPermission) { throw new Exception("Access is not allowed"); } string contentType = string.Empty; string clientFileNameLower = document.ClientFileName.ToLowerInvariant().Trim(); string serverFileNameLower = document.ServerFileName.ToLowerInvariant().Trim(); // The "Filename.Contains" here instead of "Filename.EndsWith" is because page counts are added to file names if (serverFileNameLower.EndsWith(".png") && clientFileNameLower.Contains(".pdf")) { // Converted PDF, so cut filename to raw GUID length serverFileName = serverFileName.Substring(0, serverFileName.Length - "-0001.png".Length); documentDownloadName += ".pdf"; contentType = MediaTypeNames.Application.Pdf; } else if (clientFileNameLower.EndsWith(".png")) { contentType = "image/png"; // why isn't this in MediaTypeNames? documentDownloadName += ".png"; } else if (clientFileNameLower.EndsWith(".jpg") || clientFileNameLower.EndsWith(".jpeg")) { contentType = MediaTypeNames.Image.Jpeg; documentDownloadName += ".jpg"; } else { int lastDot = clientFileNameLower.LastIndexOf('.'); if (lastDot > 0) { documentDownloadName += clientFileNameLower.Substring(lastDot); // Adds original client extension } } if (documentDownloadName.EndsWith(" 2_1") || documentDownloadName.EndsWith(" 2/1")) { // Mystery bug documentDownloadName = documentDownloadName.Substring(0, documentDownloadName.Length - 4); } string legacyMarker = string.Empty; if (!File.Exists(Document.StorageRoot + serverFileName)) { legacyMarker = "legacy/"; // for some legacy installations, all older files are placed here } // TODO: If still doesn't exist, perhaps return a friendly error image instead? if (!File.Exists(Document.StorageRoot + legacyMarker + serverFileName)) { if (!Debugger.IsAttached) // if running live; ignore FNF errors when debugging { throw new FileNotFoundException(Document.StorageRoot + legacyMarker + serverFileName); } else { Response.StatusCode = 404; Response.End(); return; } } Response.ContentType = contentType; Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + documentDownloadName + "\""); Response.TransmitFile(Document.StorageRoot + legacyMarker + serverFileName); }
public static ChangeAccountDataResult SetAccountBudget(int accountId, string budget) { try { AuthenticationData authData = GetAuthenticationDataAndCulture(); FinancialAccount account = FinancialAccount.FromIdentity(accountId); if (!PrepareAccountChange(account, authData, false)) { return(new ChangeAccountDataResult { Result = ChangeAccountDataOperationsResult.NoPermission }); } Int64 newTreeBudget; budget = budget.Replace("%A0", "%20"); // some very weird browser space-to-otherspace translation weirds out number parsing budget = HttpContext.Current.Server.UrlDecode(budget); if (budget.Trim().Length > 0 && Int64.TryParse(budget, NumberStyles.Currency, CultureInfo.CurrentCulture, out newTreeBudget)) { newTreeBudget *= 100; // convert to cents int year = DateTime.Today.Year; FinancialAccounts accountTree = account.ThisAndBelow(); Int64 currentTreeBudget = accountTree.GetBudgetSumCents(year); Int64 currentSingleBudget = account.GetBudgetCents(year); Int64 suballocatedBudget = currentTreeBudget - currentSingleBudget; Int64 newSingleBudget = newTreeBudget - suballocatedBudget; account.SetBudgetCents(DateTime.Today.Year, newSingleBudget); // Once we've set the budget, also update the "yearly result" budget. // The "yearly result" budget isn't shown in the account plan, but is // abstracted to "projected loss" or "projected gain" pseudobudgets. int thisYear = DateTime.UtcNow.Year; FinancialAccounts allProfitLossAccounts = FinancialAccounts.ForOrganization(authData.CurrentOrganization); Int64 newProfitLossProjection = allProfitLossAccounts.Where(queryAccount => queryAccount.Identity != authData.CurrentOrganization.FinancialAccounts.CostsYearlyResult.Identity).Sum(queryAccount => queryAccount.GetBudgetCents(thisYear)); authData.CurrentOrganization.FinancialAccounts.CostsYearlyResult.SetBudgetCents(thisYear, -newProfitLossProjection); return(new ChangeAccountDataResult { Result = ChangeAccountDataOperationsResult.Changed, NewData = (newTreeBudget / 100).ToString("N0", CultureInfo.CurrentCulture) }); } return(new ChangeAccountDataResult { Result = ChangeAccountDataOperationsResult.Invalid }); } catch (Exception weirdException) { // Exceptions are happening here in deployment ONLY. We're logging it to find which one and why. // TODO: This really needs to be in Logic. DO NOT DO NOT DO NOT call Database layer directly from Site layer. SwarmDb.GetDatabaseForWriting() .CreateExceptionLogEntry(DateTime.UtcNow, "AccountPlan-SetBudget", weirdException); throw; } }
public static ChangeAccountDataResult SetAccountInitialBalance(int accountId, string newInitialBalanceString) { try { AuthenticationData authData = GetAuthenticationDataAndCulture(); FinancialAccount account = FinancialAccount.FromIdentity(accountId); if (!PrepareAccountChange(account, authData, false) || authData.CurrentOrganization.Parameters.FiscalBooksClosedUntilYear >= authData.CurrentOrganization.FirstFiscalYear) { return(new ChangeAccountDataResult { Result = ChangeAccountDataOperationsResult.NoPermission }); } Int64 desiredInitialBalanceCents = (Int64) (Double.Parse(newInitialBalanceString, NumberStyles.AllowThousands | NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint, CultureInfo.CurrentCulture) * 100.0); Int64 currentInitialBalanceCents = account.GetDeltaCents(new DateTime(1900, 1, 1), new DateTime(authData.CurrentOrganization.FirstFiscalYear, 1, 1)); Int64 deltaCents = desiredInitialBalanceCents - currentInitialBalanceCents; // Find or create "Initial Balances" transaction FinancialAccountRows testRows = FinancialAccountRows.ForOrganization(authData.CurrentOrganization, new DateTime(1900, 1, 1), new DateTime(authData.CurrentOrganization.FirstFiscalYear, 1, 1)); FinancialTransaction initialBalancesTransaction = null; foreach (FinancialAccountRow row in testRows) { if (row.Transaction.Description == "Initial Balances") { initialBalancesTransaction = row.Transaction; break; } } if (initialBalancesTransaction == null) { // create transaction initialBalancesTransaction = FinancialTransaction.Create(authData.CurrentOrganization.Identity, new DateTime(authData.CurrentOrganization.FirstFiscalYear - 1, 12, 31), "Initial Balances"); } Dictionary <int, Int64> recalcBase = initialBalancesTransaction.GetRecalculationBase(); int equityAccountId = authData.CurrentOrganization.FinancialAccounts.DebtsEquity.Identity; if (!recalcBase.ContainsKey(accountId)) { recalcBase[accountId] = 0; } if (!recalcBase.ContainsKey(equityAccountId)) { recalcBase[equityAccountId] = 0; } recalcBase[accountId] += deltaCents; recalcBase[equityAccountId] -= deltaCents; initialBalancesTransaction.RecalculateTransaction(recalcBase, authData.CurrentUser); return(new ChangeAccountDataResult { Result = ChangeAccountDataOperationsResult.Changed, NewData = (desiredInitialBalanceCents / 100.0).ToString("N2", CultureInfo.CurrentCulture) }); } catch (Exception weirdException) { SwarmDb.GetDatabaseForWriting() .CreateExceptionLogEntry(DateTime.UtcNow, "AccountPlan-SetInitBalance", weirdException); throw; } }
public static JsonAccountData GetAccountData(int accountId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); FinancialAccount account = FinancialAccount.FromIdentity(accountId); if (account.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException("A million nopes"); } FinancialAccounts accountTree = account.ThisAndBelow(); int year = DateTime.Today.Year; JsonAccountData result = new JsonAccountData(); if (account.ParentIdentity == 0) { // if this is a root account, put it under the category root node, which has negative the type id result.ParentAccountId = -(int)account.AccountType; } else { result.ParentAccountId = account.ParentIdentity; } result.AccountName = account.Name; result.ParentAccountName = account.ParentFinancialAccountId == 0 ? Global.ResourceManager.GetString("Financial_" + account.AccountType) : account.Parent.Name; result.Expensable = account.Expensable; result.Administrative = account.Administrative; result.Active = account.Active; result.Open = account.Open; result.AccountOwnerName = account.OwnerPersonId != 0 ? account.Owner.Name : Global.Global_NoOwner; result.AccountOwnerAvatarUrl = account.OwnerPersonId != 0 ? account.Owner.GetSecureAvatarLink(24) : "/Images/Icons/iconshock-warning-24px.png"; result.Budget = (accountTree.GetBudgetSumCents(year) / 100L).ToString("N0", CultureInfo.CurrentCulture); if (account.AccountType == FinancialAccountType.Asset || account.AccountType == FinancialAccountType.Debt) { result.Balance = (accountTree.GetDeltaCents(new DateTime(1900, 1, 1), new DateTime(year + 1, 1, 1)) / 100L).ToString ( "N0"); result.InitialBalance = ((accountTree.GetDeltaCents(new DateTime(1900, 1, 1), new DateTime(authData.CurrentOrganization.FirstFiscalYear, 1, 1)) / 100.0).ToString("N2")); } else { result.Balance = (-accountTree.GetDeltaCents(new DateTime(year, 1, 1), new DateTime(year + 1, 1, 1)) / 100L) .ToString( "N0"); result.InitialBalance = "N/A"; // unused } result.CurrencyCode = account.Organization.Currency.DisplayCode; return(result); }
public static AjaxCallResult MarkDirectPurchase(int transactionId, int budgetId, string vatAmountString, string newDescription, string guid) { if (transactionId == 0 | budgetId == 0) { return(new AjaxCallResult { Success = false }); } AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails))) { throw new UnauthorizedAccessException(); } FinancialAccount budget = FinancialAccount.FromIdentity(budgetId); if (authData.CurrentOrganization.Identity != budget.Organization.Identity) { throw new UnauthorizedAccessException(); } newDescription = newDescription.Trim(); if (newDescription.Length < 1) { return(new AjaxCallResult { Success = false, DisplayMessage = Resources.Pages.Ledgers.BalanceTransactions_Error_NeedDescription }); } Documents docs = Documents.RecentFromDescription(guid).WhereNotAssociated; if (docs.Count < 1) { return(new AjaxCallResult { Success = false, DisplayMessage = Resources.Pages.Ledgers.BalanceTransactions_Error_NeedDocumentation }); } Int64 vatCents = 0; bool vatEnabled = authData.CurrentOrganization.VatEnabled; if (vatEnabled) { try { vatCents = Swarmops.Logic.Support.Formatting.ParseDoubleStringAsCents(vatAmountString); } catch (ArgumentException) { return(new AjaxCallResult { Success = false, DisplayMessage = Resources.Pages.Ledgers.BalanceTransactions_Error_VatAmountParseError }); throw; } } // We're FINALLY ready to update the transaction FinancialTransaction tx = FinancialTransaction.FromIdentity(transactionId); tx.Description = newDescription; docs.SetForeignObjectForAll(tx); Int64 centsDiff = tx.Rows.AmountCentsTotal; if (vatEnabled) { tx.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsVatInboundUnreported, vatCents, authData.CurrentUser); tx.AddRow(budget, (-centsDiff) - vatCents, authData.CurrentUser); } else { tx.AddRow(budget, -centsDiff, authData.CurrentUser); } return(new AjaxCallResult { Success = true }); }
public static AjaxUploadCallResult UploadBankTransactionData(string guid, string itemId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); if (!authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails))) { throw new UnauthorizedAccessException(); } string[] parts = itemId.Split('-'); FinancialAccount account = FinancialAccount.FromIdentity(Int32.Parse(parts[1])); if (account.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException(); } Documents documents = Documents.RecentFromDescription(guid); // Safeguard 2019-Dec-23: Abort if more than one document (code below needs hardening against concurrent-threads race conditions) if (documents.Count != 1) { throw new NotImplementedException(); } // Load documents and process them as loaded strings, one by one foreach (Document document in documents) { string documentData = document.GetReader().ReadToEnd(); ExternalBankDataProfile profile = account.ExternalBankDataProfile; ExternalBankData loadedData = new ExternalBankData(); loadedData.Profile = profile; try { loadedData.LoadData(documentData, authData.CurrentOrganization, account.Currency); } catch (Exception) { return(new AjaxUploadCallResult { Success = false, DisplayMessage = "ERROR_FILEDATAFORMAT" }); } // Start async thread to import the data to the SQL database; the caller must // check the status of the import string identifier = guid + "-" + itemId + "-" + Guid.NewGuid().ToString(); /* Thread processThread = new Thread((ThreadStart) AsyncProcesses.ImportExternalTransactionDataThreadStart); * processThread.Start(new AsyncProcesses.ImportExternalTransactionDataArgs {}); */ return(new AjaxUploadCallResult { Success = true, StillProcessing = true, Identifier = identifier }); } return(new AjaxUploadCallResult { Success = true, StillProcessing = true }); }