public void MigrateDependenciesTo(Payout migrationTarget) { if (Identity > 0 && migrationTarget.Identity > 0) { // Persisted payout migration SwarmDb.GetDatabaseForWriting().MovePayoutDependencies(Identity, migrationTarget.Identity); } else { // In-memory migration: this payout isn't in database yet this.DependentCashAdvancesPayback.ForEach(item => migrationTarget.DependentCashAdvancesPayback.Add(item)); this.DependentCashAdvancesPayout.ForEach(item => migrationTarget.DependentCashAdvancesPayout.Add(item)); this.DependentExpenseClaims.ForEach(item => migrationTarget.DependentExpenseClaims.Add(item)); this.DependentInvoices.ForEach(item => migrationTarget.DependentInvoices.Add(item)); this.DependentSalariesNet.ForEach(item => migrationTarget.DependentSalariesNet.Add(item)); this.DependentSalariesTax.ForEach(item => migrationTarget.DependentSalariesTax.Add(item)); this.DependentCashAdvancesPayback = new CashAdvances(); this.DependentCashAdvancesPayout = new CashAdvances(); this.DependentExpenseClaims = new ExpenseClaims(); this.DependentInvoices = new InboundInvoices(); this.DependentSalariesNet = new Salaries(); this.DependentSalariesTax = new Salaries(); } migrationTarget.RecalculateAmount(); RecalculateAmount(); }
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 static Dictionary <int, Int64> GetBudgetAttestationSpaceAdjustments(Organization organization) { // This function returns a dictionary for the cents that are either accounted for but not attested, // or attested but accounted for, to be used to understand how much is really left in budget // Positive adjustment means more [cost] budget available, negative less [cost] budget available if (_organizationBudgetAttestationSpaceLookup.ContainsKey(organization.Identity)) { return(_organizationBudgetAttestationSpaceLookup [organization.Identity]); } // TODO: This is expensive research, we should cache this result and clear cache on any attestation or create op Dictionary <int, Int64> result = new Dictionary <int, long>(); // Cash advances are accounted for when paid out. Make sure they count toward the budget when attested. CashAdvances advances = CashAdvances.ForOrganization(organization); foreach (CashAdvance advance in advances) { if (!result.ContainsKey(advance.BudgetId)) { result[advance.BudgetId] = 0; } if (advance.Attested) { result[advance.BudgetId] -= advance.AmountCents; } } // Expense claims, Inbound invoices, and Salaries are accounted for when filed. Make sure they DON'T // count toward the budget while they are NOT attested. ExpenseClaims claims = ExpenseClaims.ForOrganization(organization); // gets all open claims foreach (ExpenseClaim claim in claims) { if (!result.ContainsKey(claim.BudgetId)) { result[claim.BudgetId] = 0; } if (!claim.Attested) { result[claim.BudgetId] += claim.AmountCents; } } InboundInvoices invoices = InboundInvoices.ForOrganization(organization); foreach (InboundInvoice invoice in invoices) { if (!result.ContainsKey(invoice.BudgetId)) { result[invoice.BudgetId] = 0; } if (!invoice.Attested) { result[invoice.BudgetId] += invoice.AmountCents; } } Salaries salaries = Salaries.ForOrganization(organization); foreach (Salary salary in salaries) { if (!result.ContainsKey(salary.PayrollItem.BudgetId)) { result[salary.PayrollItem.BudgetId] = 0; } if (!salary.Attested) { result[salary.PayrollItem.BudgetId] += (salary.GrossSalaryCents + salary.AdditiveTaxCents); } } _organizationBudgetAttestationSpaceLookup[organization.Identity] = result; return(result); }
private static void AddUnpaidExpenseClaims(Payouts payoutList, Organization organization) { ExpenseClaims claims = ExpenseClaims.FromOrganization(organization); Dictionary <int, Payout> payoutLookup = new Dictionary <int, Payout>(); foreach (ExpenseClaim claim in claims) { // If ready for payout, add to list. if (claim.Open) { if (claim.Attested && claim.Validated && !claim.Repaid && !claim.KeepSeparate) { // this should be added to the list. Check if we already have pending payouts // for this person: if (payoutLookup.ContainsKey(claim.ClaimingPersonId)) { // Yes. Add claim to list. payoutLookup[claim.ClaimingPersonId].DependentExpenseClaims.Add(claim); } else { // No. Create a new payout for this person. BasicPayout basicPayout = new BasicPayout(0, organization.Identity, claim.Claimer.BankName, claim.Claimer.BankClearing + " / " + claim.Claimer.BankAccount, string.Empty, 0, Constants.DateTimeLow, false, DateTime.Now, 0); Payout payout = Payout.FromBasic(basicPayout); payout.RecipientPerson = claim.Claimer; payout.DependentExpenseClaims.Add(claim); payoutLookup[claim.ClaimingPersonId] = payout; } } } } // At this point, all the expense claims have been added - but we need to add the open // cash advances and deduct them. CashAdvances cashAdvances = CashAdvances.ForOrganization(organization); cashAdvances = cashAdvances.WherePaid; // At this point, only open and paid cash advances are in the list: they're debts to the org foreach (CashAdvance cashAdvance in cashAdvances) { if (payoutLookup.ContainsKey(cashAdvance.PersonId)) { // there's a payout prepared to this person - we need to deduct the cash advance from it. payoutLookup[cashAdvance.PersonId].DependentCashAdvancesPayback.Add(cashAdvance); } } // We now have the list of payouts and the associated claims, but the amounts aren't set on the // payouts. This will be the next step, as we assemble the list. foreach (Payout payout in payoutLookup.Values) { Int64 newAmountCents = 0; List <int> claimIds = new List <int>(); foreach (ExpenseClaim claim in payout.DependentExpenseClaims) { newAmountCents += claim.AmountCents; claimIds.Add(claim.Identity); } foreach (CashAdvance previousAdvance in payout.DependentCashAdvancesPayback) { newAmountCents -= previousAdvance.AmountCents; } string lessAdvancesIndicator = payout.DependentCashAdvancesPayback.Count > 0 ? "LessAdvances" : string.Empty; payout.AmountCents = newAmountCents; if (claimIds.Count == 1) { payout.Reference = "[Loc]Financial_ExpenseClaimSpecification" + lessAdvancesIndicator + "|" + claimIds[0].ToString(CultureInfo.InvariantCulture); } else { claimIds.Sort(); payout.Reference = "[Loc]Financial_ExpenseClaimsSpecification" + lessAdvancesIndicator + "|" + Formatting.GenerateRangeString(claimIds); } if (newAmountCents > 0) { payoutList.Add(payout); } } }
private static void AddUnpaidCashAdvances(Payouts payoutList, Organization organization) { CashAdvances advances = CashAdvances.ForOrganization(organization); advances = advances.WhereAttested; advances = advances.WhereUnpaid; Dictionary <int, Payout> payoutLookup = new Dictionary <int, Payout>(); foreach (CashAdvance advance in advances) { // If ready for payout, add to list. if (!advance.Open || !advance.Attested || advance.PaidOut) { throw new InvalidOperationException( "Got into loop with closed/unattested/paid-out cash advances - this is not a possible state"); } if (payoutLookup.ContainsKey(advance.PersonId)) { // Yes. Add claim to list. payoutLookup[advance.PersonId].DependentCashAdvancesPayout.Add(advance); } else { // No. Create a new payout for this person. BasicPayout basicPayout = new BasicPayout(0, organization.Identity, advance.Person.BankName, advance.Person.BankClearing + " / " + advance.Person.BankAccount, string.Empty, 0, Constants.DateTimeLow, false, DateTime.Now, 0); Payout payout = Payout.FromBasic(basicPayout); payout.RecipientPerson = advance.Person; payout.DependentCashAdvancesPayout.Add(advance); payoutLookup[advance.PersonId] = payout; } } // We now have the list of payouts and the associated claims, but the amounts aren't set on the // payouts. This will be the next step, as we assemble the list. foreach (Payout payout in payoutLookup.Values) { Int64 newAmountCents = 0; List <int> advanceIds = new List <int>(); foreach (CashAdvance advance in payout.DependentCashAdvancesPayout) { newAmountCents += advance.AmountCents; advanceIds.Add(advance.Identity); } payout.AmountCents = newAmountCents; if (advanceIds.Count == 1) { payout.Reference = "[Loc]Financial_CashAdvanceSpecification|" + advanceIds[0].ToString(CultureInfo.InvariantCulture); } else { advanceIds.Sort(); payout.Reference = "[Loc]Financial_CashAdvancesSpecification|" + Formatting.GenerateRangeString(advanceIds); } if (newAmountCents > 0) { payoutList.Add(payout); } } }