private void PopulateCashAdvances() { CashAdvances advances = CashAdvances.ForOrganization(CurrentOrganization); foreach (CashAdvance advance in advances) { if (this._attestationRights.ContainsKey(advance.BudgetId) || advance.Budget.OwnerPersonId == Person.NobodyId) { AttestableItem item = new AttestableItem( "A" + advance.Identity.ToString(CultureInfo.InvariantCulture), advance.Person.Name, advance.AmountCents, advance.Budget, advance.Description, "Financial_CashAdvance", false, advance); if (advance.Attested) { this._attestedItems.Add(item); } else { this._items.Add(item); } } } }
private void PopulateCashAdvances() { CashAdvances advances = CashAdvances.ForOrganization(CurrentOrganization); foreach (CashAdvance advance in advances) { if (this._approvalRights.ContainsKey(advance.BudgetId) || advance.Budget.OwnerPersonId == Person.NobodyId) { ApprovableCost cost = new ApprovableCost( "A" + advance.Identity.ToString(CultureInfo.InvariantCulture), advance.Person.Name, advance.AmountCents, advance.Budget, advance.Description, "Financial_CashAdvance", false, advance); if (!advance.Attested) // if not attested { this._approvableCosts.Add(cost); } else if (!advance.PaidOut) // if attested, but still reversible { this._approvedCosts.Add(cost); } } } }
private void AddCashAdvanceAttestations(Person person, Organization organization) { CashAdvances advances = CashAdvances.ForOrganization(organization); List <int> cashAdvanceIds = new List <int>(); bool isPersonOrgAdmin = false; if (person.Identity == 1) { isPersonOrgAdmin = true; // TODO: Make more advanced, obviously } foreach (CashAdvance advance in advances) { if (advance.Attested) { continue; } bool attestable = false; if (advance.Budget.OwnerPersonId == 0 && isPersonOrgAdmin) { attestable = true; } else if (advance.Budget.OwnerPersonId == person.Identity) { attestable = true; } if (attestable) { cashAdvanceIds.Add(advance.Identity); } } if (cashAdvanceIds.Count > 0) { DashboardTodo todo = new DashboardTodo(); if (cashAdvanceIds.Count > 1) { todo.Description = String.Format(Logic_Swarm_DashboardTodos.Attest_CashAdvance_Many, Formatting.GenerateRangeString(cashAdvanceIds)); } else { todo.Description = String.Format(Logic_Swarm_DashboardTodos.Attest_CashAdvance_One, cashAdvanceIds[0]); } todo.Icon = "/Images/PageIcons/iconshock-stamped-paper-16px.png"; todo.Url = "/Pages/v5/Financial/AttestCosts.aspx"; Add(todo); } }
private void LoadDependencies() { DependentExpenseClaims = new ExpenseClaims(); DependentInvoices = new InboundInvoices(); DependentSalariesNet = new Salaries(); DependentSalariesTax = new Salaries(); DependentCashAdvancesPayout = new CashAdvances(); DependentCashAdvancesPayback = new CashAdvances(); BasicFinancialDependency[] dependencies = SwarmDb.GetDatabaseForReading().GetPayoutDependencies(this.Identity); foreach (BasicFinancialDependency dependency in dependencies) { switch (dependency.DependencyType) { case FinancialDependencyType.ExpenseClaim: DependentExpenseClaims.Add(ExpenseClaim.FromIdentity(dependency.ForeignId)); break; case FinancialDependencyType.InboundInvoice: DependentInvoices.Add(InboundInvoice.FromIdentity(dependency.ForeignId)); break; case FinancialDependencyType.Salary: Salary salary = Salary.FromIdentity(dependency.ForeignId); if (salary.NetSalaryCents == this.AmountCents) // HACK: Assumes that tax total is not identical { DependentSalariesNet.Add(salary); } else { DependentSalariesTax.Add(salary); } break; case FinancialDependencyType.CashAdvance: DependentCashAdvancesPayout.Add(CashAdvance.FromIdentity(dependency.ForeignId)); break; case FinancialDependencyType.CashAdvancePayback: DependentCashAdvancesPayback.Add(CashAdvance.FromIdentity(dependency.ForeignId)); break; default: throw new NotImplementedException("Unknown financial dependency type in Payout.LoadDependencies(): " + dependency.ToString()); } } }
public List <PaymentHistoryLineItem> GetAmountsOwed() { List <PaymentHistoryLineItem> items = new List <PaymentHistoryLineItem>(); // Expense claims ExpenseClaims expenses = ExpenseClaims.FromClaimingPersonAndOrganization(_person, _authenticationData.CurrentOrganization); foreach (ExpenseClaim claim in expenses) { if (claim.Open || claim.PaidOut) // if both these are false, the claim was denied and shouldn't be listed { PaymentHistoryLineItem newItem = new PaymentHistoryLineItem(); newItem.Id = "E" + claim.Identity.ToString(CultureInfo.InvariantCulture); newItem.Name = String.Format(Resources.Global.Financial_ExpenseClaimLongSpecification, claim.Identity); newItem.Description = claim.Description; newItem.OpenedDate = claim.CreatedDateTime; newItem.OwedToPerson = claim.AmountCents; Payout payout = claim.Payout; if (payout != null && payout.Open == false) { _payoutLookup[payout.Identity] = payout; newItem.ClosedDate = payout.FinancialTransaction.DateTime; } items.Add(newItem); } } // Salaries Salaries salaries = Salaries.ForPersonAndOrganization(_person, _authenticationData.CurrentOrganization, true); foreach (Salary salary in salaries) { if (salary.Open || salary.NetPaid) // either of these must be open for the salary to be valid { PaymentHistoryLineItem newItem = new PaymentHistoryLineItem(); newItem.Id = "S" + salary.Identity.ToString(CultureInfo.InvariantCulture); newItem.Name = Resources.Global.Financial_Salary; newItem.Description = String.Format(Resources.Global.Financial_SalaryDualSpecification, salary.Identity, salary.PayoutDate); newItem.OwedToPerson = salary.NetSalaryCents; FinancialTransaction openTx = FinancialTransaction.FromDependency(salary); if (openTx != null) { newItem.OpenedDate = openTx.DateTime; } Payout payout = Payout.FromDependency(salary, FinancialDependencyType.Salary); if (payout != null && payout.Open == false) { _payoutLookup[payout.Identity] = payout; newItem.ClosedDate = payout.FinancialTransaction.DateTime; } items.Add(newItem); } } // Cash advances CashAdvances advances = CashAdvances.ForPersonAndOrganization(_person, _authenticationData.CurrentOrganization, true); foreach (CashAdvance advance in advances) { if (advance.Open || advance.PaidOut) { Payout payout = advance.PayoutOut; if (payout != null) { _payoutLookup[payout.Identity] = payout; _payoutDescriptionOverride[payout.Identity] = String.Format(Resources.Global.Financial_CashAdvanceSpecification, advance.Identity.ToString("N0")); } } } return(items); }
private OutstandingAccounts GetOutstandingCashAdvances(bool renderPresentTime, DateTime targetDateTime) { OutstandingAccounts outstandingAccounts = new OutstandingAccounts(); // This is a very expensive op. We need to load ALL the cash advances, and determine the opening date from its associated // payout. Then, we need to determine when it was paid pack through another associated payout (or invoice payment) which // I don't know how to find at the time of writing this comment, and if the target date is in between those two, then the // cash advance was outstanding on the target date (or is outstanding now) // A possible optimization could be to load the payouts into a hash table initially instead of looking them up // with two dbroundtrips per expense claim. It should be more efficient to have three dbroundtrips to load expenses, // payouts, and the relevant transactions, then stuff it all into hash tables keyed by identity and process it // in-memory. // A future optimization involves adding "ClosedDateTime" to some tables. // Load all (ALL) cash advances for org CashAdvances allCashAdvances = CashAdvances.ForOrganization(_authenticationData.CurrentOrganization, true); // includes closed // For each advance, determine whether it was open or not at targetDateTime foreach (CashAdvance cashAdvance in allCashAdvances) { // if it wasn't opened until after target datetime, discard (optimization) if (cashAdvance.CreatedDateTime > targetDateTime) { continue; } // At this point, we are iterating over full set of cash advances opened before targetDateTime, but not necessarily // paid out before targetDateTime. We want the set of advances that had been paid out, and had not been paid back, // as determined by the ledger account Cash Advances - on targetDateTime. bool includeThisAdvance = false; DateTime dateTimePaidBack = DateTime.MinValue; DateTime dateTimePaidOut = DateTime.MaxValue; if (!cashAdvance.PaidOut) { // This cash advance hasn't entered the ledger yet continue; } Payout payoutOut = cashAdvance.PayoutOut; Payout payoutBack = cashAdvance.PayoutBack; if (payoutOut == null) { continue; // This cash advance has not been paid out yet } try { dateTimePaidOut = payoutOut.FinancialTransaction.DateTime; } catch (ArgumentException) { // It's possible the payout exists, but hasn't found its transaction yet. If so, this will throw // an ArgumentException here. In either case, it's not in the ledger, so don't include it. continue; } if (dateTimePaidOut > targetDateTime) { // This cash advance falls outside the scope of our window, so ignore continue; } if (payoutBack != null) { try { dateTimePaidBack = payoutBack.FinancialTransaction.DateTime; } catch (ArgumentException) { // as above continue; } if (dateTimePaidBack > targetDateTime) { includeThisAdvance = true; } } else { // As there is no payback, this advance is paid out and still open. includeThisAdvance = true; // TODO: If there is no payout where the cash advance is deducted, it may be // invoiced to close it. // TODO: Find OutboundInvoiceItem that depends on this CashAdvance. Look at the invoice date. That's our PaidBack datetime. } if (includeThisAdvance) { outstandingAccounts.Add(OutstandingAccount.FromCashAdvance(cashAdvance, dateTimePaidOut)); } } return(outstandingAccounts); }