public static TransactionMatchabilityData GetTransactionMatchability(int transactionId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails))) { throw new UnauthorizedAccessException(); } FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); if (transaction.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException(); } TransactionMatchabilityData result = new TransactionMatchabilityData(); result.TransactionDate = transaction.DateTime.ToString("yyyy-MMM-dd HH:mm"); result.DifferingAmount = String.Format("{0} {1:+#,#.00;−#,#.00;0}", // this is a UNICODE MINUS (U+2212), not the hyphen on the keyboard authData.CurrentOrganization.Currency.DisplayCode, transaction.Rows.AmountCentsTotal / 100.0); result.OpenPayoutData = GetOpenPayoutData(transaction); return(result); }
protected void ButtonExecute_Click(object sender, EventArgs e) { if (!_authority.HasPermission(Permission.CanDoEconomyTransactions, thisPayout.OrganizationId, -1, Authorization.Flag.ExactOrganization)) { throw new UnauthorizedAccessException("Access Denied"); } if (this.RadioManualMap.Checked) { int transactionId = Int32.Parse(this.DropTransactions.SelectedValue); FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); thisPayout.BindToTransactionAndClose(transaction, _currentUser); } else if (this.RadioManualMerge.Checked) { int otherPayoutId = Int32.Parse(this.DropPayouts.SelectedValue); Payout otherPayout = Payout.FromIdentity(otherPayoutId); otherPayout.MigrateDependenciesTo(thisPayout); otherPayout.Open = false; thisPayout.Reference = GetDependencyString(thisPayout); } else if (this.RadioUndoPayout.Checked) { thisPayout.UndoPayout(); } ClientScript.RegisterStartupScript(Page.GetType(), "mykey", "CloseAndRebind();", true); }
protected void ButtonExecute_Click(object sender, EventArgs e) { if (!_authority.HasPermission(Permission.CanDoEconomyTransactions, thisInvoice.OrganizationId, -1, Authorization.Flag.ExactOrganization)) { throw new UnauthorizedAccessException("Access Denied"); } if (this.RadioManualMap.Checked) { int transactionId = Int32.Parse(this.DropTransactions.SelectedValue); FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); Payment payment = Payment.CreateSingle(thisInvoice.Organization, transaction.DateTime, thisInvoice.Currency, thisInvoice.AmountCents, thisInvoice, _currentUser); payment.AddInformation(PaymentInformationType.Freeform, "Mapped manually in PirateWeb"); transaction.AddRow(thisInvoice.Organization.FinancialAccounts.AssetsOutboundInvoices, -thisInvoice.AmountCents, _currentUser); transaction.Dependency = payment.Group; } else if (this.RadioCreditInvoice.Checked) { thisInvoice.Credit(_currentUser); } ClientScript.RegisterStartupScript(Page.GetType(), "mykey", "CloseAndRebind();", true); }
public static void BalanceTransactionManually(int transactionId, int accountId) { if (transactionId == 0 || accountId == 0) { return; } AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails))) { throw new UnauthorizedAccessException(); } FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); FinancialAccount account = FinancialAccount.FromIdentity(accountId); if (transaction.OrganizationId != authData.CurrentOrganization.Identity || account.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException(); } transaction.AddRow(account, -transaction.Rows.AmountCentsTotal, authData.CurrentUser); }
public static void MatchTransactionOpenPayout(int transactionId, int payoutId) { if (transactionId == 0 || payoutId == 0) { return; } AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails))) { throw new UnauthorizedAccessException(); } FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); Payout payout = Payout.FromIdentity(payoutId); if (transaction.OrganizationId != authData.CurrentOrganization.Identity || payout.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException(); } if (transaction.Rows.AmountCentsTotal != -payout.AmountCents) { throw new InvalidOperationException(); } payout.BindToTransactionAndClose(transaction, authData.CurrentUser); }
private FinancialTransaction GetTransaction() { int transactionId = Int32.Parse(Request.QueryString["TransactionId"]); FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); return(transaction); }
public static void MatchTransactionOpenPayout(int transactionId, int payoutId) { if (transactionId == 0 || payoutId == 0) { return; } AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails))) { throw new UnauthorizedAccessException(); } FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); Payout payout = Payout.FromIdentity(payoutId); if (transaction.OrganizationId != authData.CurrentOrganization.Identity || payout.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException(); } Int64 transactionCents = transaction.Rows.AmountCentsTotal; Int64 payoutCents = payout.AmountCents; FinancialAccount forexSpillAccount = authData.CurrentOrganization.FinancialAccounts.IncomeCurrencyFluctuations; if (forexSpillAccount == null && payoutCents != -transactionCents) // the tx-negative is because it's a payout { throw new InvalidOperationException("Need forex gain/loss accounts for this operation"); // TODO: Autocreate? } if ((-transactionCents) > payoutCents) // the tx-negative is because it's a payout { // This is a forex loss, not a gain which is the default forexSpillAccount = authData.CurrentOrganization.FinancialAccounts.CostsCurrencyFluctuations; } if (-transactionCents != payoutCents) { // Forex adjust transaction.AddRow(forexSpillAccount, -(payoutCents + transactionCents), // plus because transactionCents is negative authData.CurrentUser); // Adds the forex adjustment so we can bind payout to tx and close } // The amounts should match now if (transaction.Rows.AmountCentsTotal != -payout.AmountCents) { throw new InvalidOperationException(); } payout.BindToTransactionAndClose(transaction, authData.CurrentUser); }
public static string GetTransactionDisplayIdentity(int transactionId) { GetAuthenticationDataAndCulture(); // Sets culture FinancialTransaction tx = FinancialTransaction.FromIdentity(transactionId); return(tx.OrganizationSequenceId.ToString("N0")); }
public static void MatchTransactionOpenPayoutForeign(int transactionId, int payoutId) { // This is like the non-foreign version except this one chalks up the difference to forex gain/loss accounts if (transactionId == 0 || payoutId == 0) { return; } AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails))) { throw new UnauthorizedAccessException(); } FinancialAccount forexSpillAccount = authData.CurrentOrganization.FinancialAccounts.IncomeCurrencyFluctuations; if (forexSpillAccount == null) { throw new InvalidOperationException("Need forex gain/loss accounts for this operation"); // TODO: Autocreate? } FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); Payout payout = Payout.FromIdentity(payoutId); if (transaction.OrganizationId != authData.CurrentOrganization.Identity || payout.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException(); } if (-transaction.Rows.AmountCentsTotal > payout.AmountCents) { // This is a forex loss, not a gain which is the default forexSpillAccount = authData.CurrentOrganization.FinancialAccounts.CostsCurrencyFluctuations; } transaction.AddRow(forexSpillAccount, -(payout.AmountCents + transaction.Rows.AmountCentsTotal), // plus because AmountCentsTotal is negative authData.CurrentUser); // Adds the forex adjustment so we can bind payout to tx and close if (transaction.Rows.AmountCentsTotal != -payout.AmountCents) { throw new InvalidOperationException(); } payout.BindToTransactionAndClose(transaction, authData.CurrentUser); }
public static void MatchTransactionOpenVatReport(int transactionId, int vatReportId) { if (transactionId == 0 || vatReportId == 0) { return; } AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails))) { throw new UnauthorizedAccessException(); } FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); VatReport vatReport = VatReport.FromIdentity(vatReportId); if (authData.CurrentOrganization.Identity != transaction.OrganizationId || authData.CurrentOrganization.Identity != vatReport.OrganizationId) { throw new InvalidOperationException("Organization mismatch"); } Int64 diffCents = vatReport.VatInboundCents - vatReport.VatOutboundCents; if (transaction.Rows.AmountCentsTotal != diffCents) { throw new InvalidOperationException("Amount mismatch"); } // Go ahead and close vatReport.CloseTransaction = transaction; // throws if already closed vatReport.Open = false; if (diffCents > 0) { // Positive amount - asset account transaction.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsVatInboundReported, -diffCents, null); } else { // Negative amount - liability account transaction.AddRow(authData.CurrentOrganization.FinancialAccounts.DebtsVatOutboundReported, -diffCents, null); } }
public static string GetUnbalancedAmount(int txId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.Bookkeeping, AccessType.Read))) { return(string.Empty); // leave no clue to an attacker why the call failed } FinancialTransaction transaction = FinancialTransaction.FromIdentity(txId); return((-transaction.Rows.AmountCentsTotal / 100.0).ToString("N2")); }
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"; }
public static TransactionMatchabilityData GetTransactionMatchability(int transactionId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails))) { throw new UnauthorizedAccessException(); } FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); if (transaction.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException(); } TransactionMatchabilityData result = new TransactionMatchabilityData(); Int64 transactionCents = transaction.Rows.AmountCentsTotal; result.TransactionDate = transaction.DateTime.ToString("yyyy-MMM-dd HH:mm"); result.TransactionDescription = transaction.Description; result.AmountAsPurchase = ((-transactionCents) / 100.0).ToString("N2"); result.DifferingAmount = String.Format("{0} {1:+#,#.00;−#,#.00;0}", // this is a UNICODE MINUS (U+2212), not the hyphen on the keyboard authData.CurrentOrganization.Currency.DisplayCode, transactionCents / 100.0); if (transaction.Rows.AmountCentsTotal > 0) { result.OpenOutboundInvoiceData = GetOpenOutboundInvoiceData(transaction); result.AmountSign = 1; } else { // Negative difference result.AmountSign = -1; result.OpenPayoutData = GetOpenPayoutData(transaction); } result.OpenVatReportData = GetOpenVatReportData(transaction); return(result); }
private void UpdateExecute() { bool valid = false; string message = string.Empty; Dictionary <double, List <int> > transactionDeltas = new Dictionary <double, List <int> >(); this.ButtonExecute.Enabled = false; if (this.RadioManualMap.Checked) { int transactionId = Int32.Parse(this.DropTransactions.SelectedValue); if (transactionId > 0) { FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); this.LabelActionDescription.Text = String.Format( "Outbound Invoice #{0} to {1}, supposed date {2:yyyy-MM-dd}, will be mapped to Transaction #{3} on date {4:yyyy-MM-dd}. Transaction #{3} will be balanced, documented, and tied to a new payment group with a single payment referring to Outbound Invoice #{0}. Outbound Invoice #{0} will be closed.", thisInvoice.Identity, thisInvoice.CustomerName, thisInvoice.DueDate, transaction.Identity, transaction.DateTime); valid = true; this.ButtonExecute.Text = "Execute MAP"; this.ButtonExecute.Enabled = true; } } if (this.RadioCreditInvoice.Checked) { this.LabelActionDescription.Text = String.Format("A credit invoice for the same amount as Outbound Invoice #{0}, {1} {2:N2}, will be issued to {3} and closed immediately together with Outbound Invoice #{0}.", thisInvoice.Identity, thisInvoice.Currency.Code, thisInvoice.Amount, thisInvoice.CustomerName); valid = true; this.ButtonExecute.Text = "Execute CREDIT"; this.ButtonExecute.Enabled = true; } if (!valid) { this.ButtonExecute.Enabled = false; this.ButtonExecute.Text = "Execute Nothing"; this.LabelActionDescription.Text = "Nothing."; } }
public static string GetTransactionTracking(int txId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails, AccessType.Read))) { return(string.Empty); // leave no clue to an attacker why the call failed } FinancialTransaction transaction = FinancialTransaction.FromIdentity(txId); IHasIdentity dependency = transaction.Dependency; if (dependency == null) { return(string.Empty); } return(GetTrackingDetails(dependency)); }
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); }
protected void Page_Load(object sender, EventArgs e) { Response.ContentType = "application/json"; string transactionIdString = Request.QueryString["TxId"]; string emptyResponse = "[{\"id\":\"-\",\"accountName\":\"" + JsonSanitize(Resources.Pages.Ledgers.InspectLedgers_EmptyTransaction) + "\"}]"; if (string.IsNullOrEmpty(transactionIdString) || transactionIdString == "undefined") { Response.Output.WriteLine(emptyResponse); Response.End(); } int transactionId = Int32.Parse(transactionIdString); DateTime dawnOfMankind = new DateTime(1901, 1, 1); // no org will ever import bookkeeping from before this date if (transactionId <= 0) { Response.Output.WriteLine(emptyResponse); Response.End(); } FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); if (transaction.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"); } FinancialTransactionRows rows = transaction.Rows; StringBuilder result = new StringBuilder(16384); foreach (FinancialTransactionRow row in rows) { string creditString = string.Empty; string debitString = string.Empty; if (row.AmountCents < 0) { creditString = String.Format("{0:N2}", row.AmountCents / 100.0); } else if (row.AmountCents > 0) { debitString = String.Format("{0:N2}", row.AmountCents / 100.0); } result.Append("{" + String.Format( "\"id\":\"{0}\",\"dateTime\":\"{1:yyyy-MMM-dd HH:mm}\",\"accountName\":\"{2}\"," + "\"deltaPos\":\"{3}\",\"deltaNeg\":\"{4}\",\"initials\":\"{5}\"", row.FinancialTransactionId, row.CreatedDateTime, JsonSanitize(row.AccountName), debitString, creditString, row.CreatedByPerson != null? row.CreatedByPerson.Initials: Resources.Global.Global_System) + "},"); } Int64 amountCentsTotal = transaction.Rows.AmountCentsTotal; if (amountCentsTotal != 0) { // If the transaction is unbalanced, make a huge deal about it result.Append("{\"accountName\":\"<img src='/Images/Icons/iconshock-warning-24px.png' height='16px' width='16px' class='elementFloatFar' />" + JsonSanitize(Resources.Pages.Ledgers.InspectLedgers_UnbalancedTransaction) + "\","); if (amountCentsTotal < 0) { result.AppendFormat("\"deltaPos\":\"<span class='spanAnnoyingBlink'>{0:N2}</span>\"", -amountCentsTotal / 100.0); } else if (amountCentsTotal > 0) { result.AppendFormat("\"deltaNeg\":\"<span class='spanAnnoyingBlink'>{0:N2}</span>\"", -amountCentsTotal / 100.0); } result.Append("},"); // the comma isn't really necessary here but will be stripped later and is kept for cut&paste consistency of this code block } Response.Output.WriteLine("[" + result.ToString().TrimEnd(',') + "]"); Response.End(); }
private void UpdateExecute() { bool valid = false; string message = string.Empty; Dictionary <decimal, List <int> > transactionDeltas = new Dictionary <decimal, List <int> >(); FinancialTransactions transactions = FinancialTransactions.GetUnbalanced(thisPayout.Organization); this.ButtonExecute.Enabled = false; foreach (FinancialTransaction transaction in transactions) { decimal diff = transaction.Rows.AmountTotal; if (!transactionDeltas.ContainsKey(-diff)) { transactionDeltas[-diff] = new List <int>(); } transactionDeltas[-diff].Add(transaction.Identity); } if (this.RadioManualMap.Checked) { int transactionId = Int32.Parse(this.DropTransactions.SelectedValue); if (transactionId > 0) { FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); this.LabelActionDescription.Text = String.Format( "Payout #{0}, supposed date {1:yyyy-MM-dd}, will be mapped to Transaction #{2} on date {3:yyyy-MM-dd}. Transaction #{2} will be balanced and documented and tied to {4}. Payout #{0} will be closed.", thisPayout.Identity, thisPayout.ExpectedTransactionDate, transaction.Identity, transaction.DateTime, GetDependencyString(thisPayout)); valid = true; this.ButtonExecute.Text = "Execute MAP"; this.ButtonExecute.Enabled = true; } } if (this.RadioManualMerge.Checked) { int payoutId = Int32.Parse(this.DropPayouts.SelectedValue); if (payoutId > 0) { Payout payout = Payout.FromIdentity(payoutId); decimal newAmount = (decimal)(payout.Amount + thisPayout.Amount); this.LabelActionDescription.Text = String.Format( "Payout #{0} will be zeroed and closed. Payout #{1} will take over the dependencies of Payout #{0}. It will cover {2} and have an amount of {3:N2}.", payout.Identity, thisPayout.Identity, GetDependencyString(thisPayout, payout), newAmount); if (transactionDeltas.ContainsKey(newAmount)) { this.LabelActionDescription.Text += " This matches Transaction " + Formatting.GenerateRangeString(transactionDeltas[newAmount]) + "."; } valid = true; this.ButtonExecute.Text = "Execute MERGE"; this.ButtonExecute.Enabled = true; } } if (this.RadioUndoPayout.Checked) { this.LabelActionDescription.Text = String.Format("Payout #{0} will be zeroed and closed. {1} will be re-opened and ready for payout.", thisPayout.Identity, GetDependencyString(thisPayout)); valid = true; this.ButtonExecute.Text = "Execute UNDO"; this.ButtonExecute.Enabled = true; } if (!valid) { this.ButtonExecute.Enabled = false; this.ButtonExecute.Text = "Execute Nothing"; this.LabelActionDescription.Text = "Nothing."; } }
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 void MatchTransactionOpenOutboundInvoice(int transactionId, int invoiceId) { if (transactionId == 0 || invoiceId == 0) { return; } AuthenticationData authData = GetAuthenticationDataAndCulture(); if ( !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.BookkeepingDetails))) { throw new UnauthorizedAccessException(); } FinancialTransaction transaction = FinancialTransaction.FromIdentity(transactionId); OutboundInvoice outboundInvoice = OutboundInvoice.FromIdentity(invoiceId); if (transaction.OrganizationId != authData.CurrentOrganization.Identity || outboundInvoice.OrganizationId != authData.CurrentOrganization.Identity) { throw new UnauthorizedAccessException(); } Int64 transactionCents = transaction.Rows.AmountCentsTotal; Int64 invoiceCents = outboundInvoice.AmountCents; FinancialAccount forexSpillAccount = authData.CurrentOrganization.FinancialAccounts.IncomeCurrencyFluctuations; if (forexSpillAccount == null && invoiceCents != transactionCents) { throw new InvalidOperationException("Need forex gain/loss accounts for this operation"); // TODO: Autocreate? } if (transaction.Rows.AmountCentsTotal < outboundInvoice.AmountCents) { // This is a forex loss, not a gain which is the default forexSpillAccount = authData.CurrentOrganization.FinancialAccounts.CostsCurrencyFluctuations; } // Close invoice Payment payment = Payment.CreateSingle(authData.CurrentOrganization, transaction.DateTime, authData.CurrentOrganization.Currency, outboundInvoice.AmountCents, outboundInvoice, authData.CurrentUser); // TODO: Notify? // TODO: Log? // Close transaction if (transactionCents != invoiceCents) { transaction.AddRow(forexSpillAccount, invoiceCents - transactionCents, authData.CurrentUser); // Adds the forex adjustment so we can bind payout to tx and close } transaction.AddRow(authData.CurrentOrganization.FinancialAccounts.AssetsOutboundInvoices, -outboundInvoice.AmountCents, authData.CurrentUser); }
protected void GridTransactions_ItemCreated(object sender, GridItemEventArgs e) { const string imageUrlNone = "~/Images/Public/Fugue/icons-shadowless/minus-small.png"; const string imageUrlDoc = "~/Images/Public/Fugue/icons-shadowless/report.png"; const string imageUrlDoc2 = "~/Images/Public/Fugue/icons-shadowless/reports.png"; const string imageUrlDoc3 = "~/Images/Public/Fugue/icons-shadowless/reports-stack.png"; const string imageUrlLink = "~/Images/Public/Fugue/icons-shadowless/chain.png"; if (e.Item is GridDataItem) { LedgerRow row = (LedgerRow)e.Item.DataItem; if (row == null) { return; } decimal delta = row.Amount; decimal balance = row.Balance; if (_simplifiedView) { delta = -delta; balance = -balance; // Change accountant's worldview (costs are positive) to normal people's (expenses are negative) } string field = "LabelDebit"; if (row.Amount < 0.0m) { field = "LabelCredit"; } Label labelDelta = (Label)e.Item.FindControl(field); labelDelta.Text = delta.ToString("+#,##0.00;-#,##0.00", new CultureInfo("sv-SE")); Label labelAccountName = (Label)e.Item.FindControl("LabelAccountName"); labelAccountName.Text = _accountNames[row.FinancialAccountId]; Label labelLedgered = (Label)e.Item.FindControl("LabelLedgered"); if (!_peopleInitials.ContainsKey(row.RowCreatedByPersonId)) { if (row.RowCreatedByPersonId > 0) { _peopleInitials[row.RowCreatedByPersonId] = Person.FromIdentity(row.RowCreatedByPersonId).Initials; } else { _peopleInitials[0] = "bot"; } } labelLedgered.Text = String.Format("{0:yyMMdd}/{1}", row.RowDateTime, _peopleInitials[row.RowCreatedByPersonId]); Label labelBalance = (Label)e.Item.FindControl("LabelBalance"); labelBalance.Text = balance.ToString("N2", new CultureInfo("sv-SE")); Image imageDoxored = (Image)e.Item.FindControl("ImageDocumented"); Image imageLinked = (Image)e.Item.FindControl("ImageLinked"); FinancialTransaction transaction = FinancialTransaction.FromIdentity(row.FinancialTransactionId); int docCount = Documents.ForObject(transaction).Count; bool hasDependency = transaction.Dependency == null ? false : true; if (hasDependency) { imageLinked.ImageUrl = imageUrlLink; imageDoxored.ImageUrl = imageUrlDoc; } else { imageLinked.ImageUrl = imageUrlNone; if (docCount == 0) { imageDoxored.ImageUrl = imageUrlNone; } else if (docCount == 1) { imageDoxored.ImageUrl = imageUrlDoc; } else if (docCount == 2) { imageDoxored.ImageUrl = imageUrlDoc2; } else { imageDoxored.ImageUrl = imageUrlDoc3; } } HyperLink editLink = (HyperLink)e.Item.FindControl("LinkManage"); editLink.Attributes["href"] = "#"; editLink.Attributes["onclick"] = String.Format("return ShowTransactionForm('{0}','{1}');", row.FinancialTransactionId, e.Item.ItemIndex); } }