Example #1
0
        private void AddExpenseClaims(Person person, Organization organization)
        {
            TaskGroup group = new TaskGroup(TaskGroupType.AttestExpenseClaims);

            // TODO: Loop over roles, get all open claims for roles where person can attest

            ExpenseClaims claims = ExpenseClaims.ForOrganization(organization);

            foreach (ExpenseClaim claim in claims)
            {
                try
                {
                    if (claim.Budget.OwnerPersonId == person.Identity && !claim.Attested)
                    {
                        group.Tasks.Add(new TaskExpenseClaim(claim));
                    }
                }
                catch (Exception)
                {
                    // ignore fn
                }
            }

            if (group.Tasks.Count > 0)
            {
                Add(group);
            }
        }
Example #2
0
    private void PopulateExpenses()
    {
        ExpenseClaims expenses = ExpenseClaims.ForOrganization(CurrentOrganization);

        foreach (ExpenseClaim expenseClaim in expenses)
        {
            if (this._attestationRights.ContainsKey(expenseClaim.BudgetId) ||
                expenseClaim.Budget.OwnerPersonId == Person.NobodyId)
            {
                Documents dox    = expenseClaim.Documents;
                bool      hasDox = (dox.Count > 0 ? true : false);

                AttestableItem item = new AttestableItem(
                    "E" + expenseClaim.Identity.ToString(CultureInfo.InvariantCulture),
                    expenseClaim.ClaimerCanonical, expenseClaim.AmountCents, expenseClaim.Budget,
                    expenseClaim.Description, "Financial_ExpenseClaim", hasDox, expenseClaim);

                if (expenseClaim.Attested)
                {
                    this._attestedItems.Add(item);
                }
                else
                {
                    this._items.Add(item);
                }
            }
        }
    }
Example #3
0
        private void AddReceiptValidations(Person person, Organization organization)
        {
            if (!person.HasAccess(new Access(organization, AccessAspect.Financials, AccessType.Write)))
            {
                return;
            }

            ExpenseClaims claims = ExpenseClaims.ForOrganization(organization);

            claims = claims.WhereUnvalidated;

            if (claims.Count == 0)
            {
                // nothing to add
                return;
            }

            DashboardTodo todo = new DashboardTodo();

            if (claims.Count > 1)
            {
                todo.Description = String.Format(App_GlobalResources.Logic_Swarm_DashboardTodos.Validate_Receipts_Many, Formatting.GenerateRangeString(claims.Identities));
            }
            else
            {
                todo.Description = String.Format(App_GlobalResources.Logic_Swarm_DashboardTodos.Validate_Receipts_One, claims[0].Identity);
            }

            todo.Icon = "/Images/PageIcons/iconshock-invoice-greentick-16px.png";
            todo.Url  = "/Pages/v5/Financial/ValidateReceipts.aspx";

            this.Add(todo);
        }
Example #4
0
        private void AddReceiptValidation(Person person)
        {
            TaskGroup group = new TaskGroup(TaskGroupType.ValidateExpenseClaims);

            // TODO: Loop over roles, get all open claims for roles where person can attest

            if (!person.GetAuthority().HasPermission(Permission.CanDoEconomyTransactions, Organization.PPSEid, Geography.RootIdentity, Authorization.Flag.AnyGeographyExactOrganization))
            {
                // no permission, no tasks
                return;
            }

            ExpenseClaims claims = ExpenseClaims.ForOrganization(Organization.PPSE);

            foreach (ExpenseClaim claim in claims)
            {
                if (!claim.Validated)
                {
                    group.Tasks.Add(new TaskReceiptValidation(claim));
                }
            }

            if (group.Tasks.Count > 0)
            {
                this.Add(group);
            }
        }
    private void PopulateGrid()
    {
        Dictionary <int, AdvanceDebt> debtLookup = new Dictionary <int, AdvanceDebt>();

        ExpenseClaims claims = ExpenseClaims.ForOrganization(Organization.PPSE);

        foreach (ExpenseClaim claim in claims)
        {
            // If ready for payout, add to list.

            if (claim.Open)
            {
                if (claim.Attested && claim.Validated && !claim.Repaid)
                {
                    // this should be added to the list. Check if we already have some open claims
                    // for this person:

                    if (debtLookup.ContainsKey(claim.ClaimingPersonId))
                    {
                        // Yes. Add claim to list.

                        debtLookup[claim.ClaimingPersonId].DebtCents -= claim.AmountCents;
                        debtLookup[claim.ClaimingPersonId].ClaimIds.Add(claim.Identity);
                    }
                    else
                    {
                        // No. Create a new debt for this person.

                        AdvanceDebt debt = new AdvanceDebt(claim.Claimer, -claim.AmountCents);
                        debt.ClaimIds.Add(claim.Identity);

                        debtLookup[claim.ClaimingPersonId] = debt;
                    }

                    if (debtLookup[claim.ClaimingPersonId].EarliestDate > claim.CreatedDateTime)
                    {
                        debtLookup[claim.ClaimingPersonId].EarliestDate = claim.CreatedDateTime;
                    }
                }
            }
        }

        // Now, we have grouped all ready but unsettled expenses per person. Let's add only those with a positive debt to the final list.

        List <AdvanceDebt> debtList = new List <AdvanceDebt>();

        foreach (int personId in debtLookup.Keys)
        {
            if (debtLookup[personId].DebtCents > 0)
            {
                debtList.Add(debtLookup[personId]);
            }
        }

        debtList.Sort(SortGridItems);

        this.GridDebts.DataSource = debtList;
    }
        private void PopulateExpenses()
        {
            ExpenseClaims expenses = ExpenseClaims.ForOrganization(this.CurrentOrganization).WhereUnvalidated;

            foreach (var expenseClaim in expenses)
            {
                AddDocuments(expenseClaim.Documents, "E" + expenseClaim.Identity.ToString(CultureInfo.InvariantCulture), String.Format(Resources.Global.Financial_ExpenseClaimSpecification + " - ", expenseClaim.Identity) + Resources.Global.Financial_ReceiptSpecification);
            }
        }
Example #7
0
        // TODO: Refactor the attest-X functions into one function with minimal differences


        private void AddExpenseClaimAttestations(Person person, Organization organization)
        {
            ExpenseClaims claims          = ExpenseClaims.ForOrganization(organization);
            List <int>    expenseClaimIds = new List <int>();

            bool isPersonOrgAdmin = false;

            if (person.Identity == 1)
            {
                isPersonOrgAdmin = true; // TODO: Make more advanced, obviously
            }

            foreach (ExpenseClaim claim in claims)
            {
                if (claim.Attested)
                {
                    continue;
                }

                bool attestable = false;

                if (claim.Budget.OwnerPersonId == 0 && isPersonOrgAdmin)
                {
                    attestable = true;
                }
                else if (claim.Budget.OwnerPersonId == person.Identity)
                {
                    attestable = true;
                }

                if (attestable)
                {
                    expenseClaimIds.Add(claim.Identity);
                }
            }

            if (expenseClaimIds.Count > 0)
            {
                DashboardTodo todo = new DashboardTodo();

                if (expenseClaimIds.Count > 1)
                {
                    todo.Description = String.Format(Logic_Swarm_DashboardTodos.Attest_ExpenseClaim_Many,
                                                     Formatting.GenerateRangeString(expenseClaimIds));
                }
                else
                {
                    todo.Description = String.Format(Logic_Swarm_DashboardTodos.Attest_ExpenseClaim_One,
                                                     expenseClaimIds[0]);
                }

                todo.Icon = "/Images/PageIcons/iconshock-stamped-paper-16px.png";
                todo.Url  = "/Pages/v5/Financial/AttestCosts.aspx";

                Add(todo);
            }
        }
Example #8
0
        private void PopulateExpenses()
        {
            ExpenseClaims expenses = ExpenseClaims.ForOrganization(this.CurrentOrganization).WhereUnattested;

            foreach (var expenseClaim in expenses)
            {
                if (_attestationRights.ContainsKey(expenseClaim.BudgetId) || expenseClaim.Budget.OwnerPersonId == Person.NobodyId)
                {
                    AddDocuments(expenseClaim.Documents, "E" + expenseClaim.Identity.ToString(CultureInfo.InvariantCulture), String.Format(Resources.Global.Financial_ExpenseClaimSpecificationWithClaimer + " - ", expenseClaim.Identity, expenseClaim.ClaimerCanonical) + Resources.Global.Financial_ReceiptSpecification);
                }
            }
        }
Example #9
0
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!CurrentUser.HasAccess(new Access(CurrentOrganization, AccessAspect.Financials, AccessType.Read)))
        {
            throw new UnauthorizedAccessException();
        }

        ExpenseClaims claims = ExpenseClaims.ForOrganization(CurrentOrganization);

        claims = claims.WhereUnvalidated;

        // Format as JSON and return

        Response.ContentType = "application/json";
        string json = FormatAsJson(claims);

        Response.Output.WriteLine(json);
        Response.End();
    }
    private void PopulateGrid()
    {
        ExpenseClaims allClaims = ExpenseClaims.ForOrganization(Organization.PPSE);

        ExpenseClaims unvalidatedClaims = new ExpenseClaims();

        // LINQ would be nice here. "Where Validated=0".

        foreach (ExpenseClaim claim in allClaims)
        {
            if (!claim.Validated)
            {
                unvalidatedClaims.Add(claim);
            }
        }

        unvalidatedClaims.Sort(SortGridItems);

        this.GridExpenseClaims.DataSource = unvalidatedClaims;
    }
Example #11
0
    private void PopulateExpenses()
    {
        ExpenseClaims expenses   = ExpenseClaims.ForOrganization(CurrentOrganization);
        bool          vatEnabled = CurrentOrganization.VatEnabled;

        foreach (ExpenseClaim expenseClaim in expenses)
        {
            if (this._approvalRights.ContainsKey(expenseClaim.BudgetId) ||
                expenseClaim.Budget.OwnerPersonId == Person.NobodyId)
            {
                Documents dox    = expenseClaim.Documents;
                bool      hasDox = (dox.Count > 0 ? true : false);

                ApprovableCost cost = null;

                if (vatEnabled)
                {
                    cost = new ApprovableCost(
                        "E" + expenseClaim.Identity.ToString(CultureInfo.InvariantCulture),
                        expenseClaim.ClaimerCanonical, expenseClaim.AmountCents - expenseClaim.VatCents, expenseClaim.Budget,
                        expenseClaim.Description, "Financial_ExpenseClaim", hasDox, expenseClaim);
                }
                else
                {
                    cost = new ApprovableCost(
                        "E" + expenseClaim.Identity.ToString(CultureInfo.InvariantCulture),
                        expenseClaim.ClaimerCanonical, expenseClaim.AmountCents, expenseClaim.Budget,
                        expenseClaim.Description, "Financial_ExpenseClaim", hasDox, expenseClaim);
                }

                if (expenseClaim.Attested)
                {
                    this._approvedCosts.Add(cost);
                }
                else
                {
                    this._approvableCosts.Add(cost);
                }
            }
        }
    }
Example #12
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);
        }