예제 #1
0
    private void PopulateDropPayouts()
    {
        int     orgId       = thisPayout.OrganizationId;
        Payouts openPayouts = Payouts.ForOrganization(Organization.FromIdentity(orgId));

        this.DropPayouts.Items.Clear();
        this.DropPayouts.Items.Add(new ListItem("-- Select a payout --", "0"));

        foreach (Payout payout in openPayouts)
        {
            if (payout.Identity != thisPayout.Identity)
            {
                this.DropPayouts.Items.Add(
                    new ListItem(
                        String.Format(new CultureInfo("sv-SE"), "#{0}, {1}, {2:N2}", payout.Identity,
                                      payout.Recipient, payout.Amount),
                        payout.Identity.ToString()));
            }
        }

        if (openPayouts.Count < 2)
        {
            this.DropPayouts.Items.Add(new ListItem("No other open payout.", "0"));
            this.RadioManualMerge.Enabled = false;
        }
    }
예제 #2
0
        protected void Page_Load(object sender, EventArgs e)
        {
            // Access required is change access to financials

            PageAccessRequired = new Access(CurrentOrganization, AccessAspect.Financials, AccessType.Write);

            // Get all payable items

            Payouts prototypePayouts = Payouts.Construct(CurrentOrganization);
            Payouts previousPayouts  = Payouts.ForOrganization(CurrentOrganization); // gets all currently open payouts - enabled for undoing

            // Format as JSON and return

            string prototypes = FormatPrototypesAsJson(prototypePayouts);
            string previous   = FormatPreviousAsJson(previousPayouts);

            string elements = (prototypes.Length > 0 && previous.Length > 0
                ? prototypes + "," + previous // if both have elements, add a comma between them
                : prototypes + previous);     // one or both strings are empty, so no comma

            Response.ContentType = "application/json";
            string json = "{\"rows\":[" + elements + "]}";

            Response.Output.WriteLine(json);
            Response.End();
        }
예제 #3
0
        private static DropdownOption[] GetOpenPayoutData(FinancialTransaction transaction)
        {
            DateTime transactionDateTime = transaction.DateTime;
            Int64    matchAmount         = transaction.Rows.AmountCentsTotal;

            DropdownOptions result = new DropdownOptions();

            List <DropdownOption> listExact    = new List <DropdownOption>();
            List <DropdownOption> listTolerant = new List <DropdownOption>();

            Payouts openPayouts = Payouts.ForOrganization(transaction.Organization);

            foreach (Payout payout in openPayouts)
            {
                if (payout.AmountCents > -matchAmount * 95 / 100 &&
                    payout.AmountCents < -matchAmount * 105 / 100)
                {
                    string description = String.Format(Resources.Pages.Ledgers.BalanceTransactions_PayoutMatch, payout.Identity,
                                                       payout.ExpectedTransactionDate, payout.Recipient, payout.Organization.Currency.DisplayCode, payout.AmountCents / 100.0,
                                                       payout.Specification);

                    if (payout.AmountCents == -matchAmount)
                    {
                        listExact.Add(new DropdownOption
                        {
                            id     = payout.Identity.ToString(CultureInfo.InvariantCulture),
                            @group = Resources.Pages.Ledgers.BalanceTransactions_ExactMatches,
                            text   = description
                        });
                    }
                    else
                    {
                        listTolerant.Add(new DropdownOption
                        {
                            id     = payout.Identity.ToString(CultureInfo.InvariantCulture),
                            @group = Resources.Pages.Ledgers.BalanceTransactions_FivePercentMatches,
                            text   = description
                        });
                    }
                }
            }

            List <DropdownOption> listCombined = new List <DropdownOption>();

            listCombined.AddRange(listExact);
            listCombined.AddRange(listTolerant);

            return(listCombined.ToArray());
        }
예제 #4
0
        protected void Page_Load(object sender, EventArgs e)
        {
            // Access required is change access to financials

            PageAccessRequired = new Access(CurrentOrganization, AccessAspect.Financials, AccessType.Write);

            // Get all payable items

            Payouts prototypePayouts = Payouts.Construct(CurrentOrganization);
            Payouts previousPayouts  = Payouts.ForOrganization(CurrentOrganization); // gets all currently open payouts - enabled for undoing

            // Format as JSON and return

            string elements = FormatPrototypesAsJson(prototypePayouts);

            Response.ContentType = "application/json";
            string json = "{\"rows\":[" + elements + "]}";

            Response.Output.WriteLine(json);
            Response.End();
        }
예제 #5
0
 private int GetOpenCount()
 {
     return(Payouts.ForOrganization(CurrentOrganization).Count);
 }
 protected void PopulatePayouts(int organizationId)
 {
     this.GridPayouts.DataSource = Payouts.ForOrganization(Organization.FromIdentity(organizationId));
 }
예제 #7
0
        private OutstandingAccounts GetOutstandingExpenseClaims(bool renderPresentTime, DateTime targetDateTime)
        {
            OutstandingAccounts outstandingAccounts = new OutstandingAccounts();

            if (renderPresentTime)
            {
                ExpenseClaims claims  = ExpenseClaims.ForOrganization(_authenticationData.CurrentOrganization);
                Payouts       payouts = Payouts.ForOrganization(_authenticationData.CurrentOrganization);

                foreach (ExpenseClaim claim in claims)
                {
                    outstandingAccounts.Add(OutstandingAccount.FromExpenseClaim(claim, DateTime.MinValue));
                }
                foreach (Payout payout in payouts)
                {
                    foreach (ExpenseClaim claim in payout.DependentExpenseClaims)
                    {
                        outstandingAccounts.Add(OutstandingAccount.FromExpenseClaim(claim,
                                                                                    payout.ExpectedTransactionDate));
                    }
                }
            }
            else
            {
                // This is a very expensive op. We need to load all expense claims and process them in logic, looking at their
                // payouts and end financial transactions, as the traceability was built to be efficient backwards (tracing money
                // paid out to its documentation), rather than forwards.

                // 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 ExpenseClaims and Payouts at the database level.

                // Load all (ALL) expense claims for org

                ExpenseClaims allClaims = ExpenseClaims.ForOrganization(_authenticationData.CurrentOrganization, true);
                // includes closed

                // For each claim, determine whether it was open or not at targetDateTime

                foreach (ExpenseClaim claim in allClaims)
                {
                    // if it wasn't opened until after target datetime, discard

                    if (claim.CreatedDateTime > targetDateTime)
                    {
                        continue;
                    }

                    // At this point, we are iterating over full set of expense claims opened before targetDateTime. We want the
                    // set of claims that were still open - as determined by the ledger account Expense Claims - on targetDateTime.
                    //
                    // For the expense claims that are still open, this is trivially true.
                    //
                    // However, for others, we need to look at the corresponding Payout and its FinancialTransaction to determine
                    // whetherthe transaction's date is on the other side of targetDateTime.

                    bool     includeThisClaim = false;
                    DateTime dateTimeClosed   = DateTime.MinValue;

                    if (claim.Open)
                    {
                        includeThisClaim = true;
                    }
                    else
                    {
                        // claim is closed. This is where we need to look first at payout then at financial transaction.

                        Payout payout = claim.Payout;

                        if (payout == null)
                        {
                            // TODO: Find outbound invoice item that depends on this expense claim
                            continue;
                            // some legacy from when Swarmops was primitive - earliest claims don't have payouts
                        }

                        if (payout.Open)
                        {
                            // Transaction is not yet closed. Include this claim, set closed to expected-closed.
                            includeThisClaim = true;
                            dateTimeClosed   = payout.ExpectedTransactionDate;
                        }
                        else
                        {
                            FinancialTransaction transaction = payout.FinancialTransaction;

                            if (transaction == null)
                            {
                                throw new InvalidOperationException(
                                          "This should not happen (transaction not found on closed payout)");
                            }

                            if (transaction.DateTime > targetDateTime)
                            {
                                // yes, the claim was opened before targetDateTime and closed after it. This should be included.
                                includeThisClaim = true;
                                dateTimeClosed   = transaction.DateTime;
                            }
                        }

                        // TODO: An expense claim can also be closed through an outbound invoice, in case there was a larger cash
                        // advance that wasn't fully covered, and where the two are added together. Check for this condition as well.
                        //
                        // OutboundInvoiceItem should have a dependency on the expense claim if this is the case.
                    }

                    if (includeThisClaim)
                    {
                        outstandingAccounts.Add(OutstandingAccount.FromExpenseClaim(claim, dateTimeClosed));
                    }
                }
            }

            return(outstandingAccounts);
        }
예제 #8
0
    private void PopulateDebugInfo()
    {
        debugLookup = new Dictionary <int, DebugInfoLine>();

        ExpenseClaims   expenseClaims   = ExpenseClaims.FromOrganization(Organization.PPSE);
        InboundInvoices inboundInvoices = InboundInvoices.ForOrganization(Organization.PPSE);
        Salaries        salaries        = Salaries.ForOrganization(Organization.PPSE);
        Payouts         payouts         = Payouts.ForOrganization(Organization.PPSE);

        debugLookup[Organization.PPSE.FinancialAccounts.DebtsExpenseClaims.Identity]   = new DebugInfoLine();
        debugLookup[Organization.PPSE.FinancialAccounts.DebtsInboundInvoices.Identity] = new DebugInfoLine();
        debugLookup[Organization.PPSE.FinancialAccounts.CostsAllocatedFunds.Identity]  = new DebugInfoLine();
        debugLookup[Organization.PPSE.FinancialAccounts.DebtsSalary.Identity]          = new DebugInfoLine();
        debugLookup[Organization.PPSE.FinancialAccounts.DebtsTax.Identity]             = new DebugInfoLine();

        foreach (Payout payout in payouts)
        {
            foreach (ExpenseClaim claim in payout.DependentExpenseClaims)
            {
                debugLookup[Organization.PPSE.FinancialAccounts.DebtsExpenseClaims.Identity].Payouts -= claim.Amount;
            }

            foreach (InboundInvoice invoice in payout.DependentInvoices)
            {
                debugLookup[Organization.PPSE.FinancialAccounts.DebtsInboundInvoices.Identity].Payouts -= (decimal)invoice.Amount;
            }

            foreach (Salary salary in payout.DependentSalariesNet)
            {
                debugLookup[Organization.PPSE.FinancialAccounts.DebtsSalary.Identity].Payouts -= salary.NetSalaryDecimal;
            }

            foreach (Salary salary in payout.DependentSalariesTax)
            {
                debugLookup[Organization.PPSE.FinancialAccounts.DebtsTax.Identity].Payouts -= salary.TaxTotalDecimal;
            }
        }


        foreach (ExpenseClaim claim in expenseClaims)
        {
            if (claim.Open)
            {
                AddExpenseToDebug(claim);
            }
        }

        foreach (InboundInvoice invoice in inboundInvoices)
        {
            AddInboundInvoiceToDebug(invoice);
        }

        foreach (Salary salary in salaries)
        {
            AddSalaryNetToDebug(salary);
            AddSalaryTaxToDebug(salary);
        }

        List <DebugInfoLine> debugInfoLines = new List <DebugInfoLine>();

        foreach (int accountId in debugLookup.Keys)
        {
            debugLookup[accountId].AccountId = accountId;
            debugLookup[accountId].Actual    = FinancialAccount.FromIdentity(accountId).GetDelta(new DateTime(2006, 1, 1), DateTime.Today.AddDays(2)); // two days to account for all possible time zones
        }

        foreach (DebugInfoLine line in debugLookup.Values)
        {
            debugInfoLines.Add(line);
        }

        this.GridDebug.DataSource = debugInfoLines;
    }