Example #1
0
        public static ExpenseClaim Create(Person claimer, Organization organization, FinancialAccount budget,
                                          DateTime expenseDate, string description, Int64 amountCents)
        {
            ExpenseClaim newClaim = FromIdentityAggressive(SwarmDb.GetDatabaseForWriting().CreateExpenseClaim(claimer.Identity, organization.Identity,
                                                                                                              budget.Identity, expenseDate, description, amountCents));
            // Create the financial transaction with rows

            string transactionDescription = "Expense #" + newClaim.Identity + ": " + description;  // TODO: Localize

            if (transactionDescription.Length > 64)
            {
                transactionDescription = transactionDescription.Substring(0, 61) + "...";
            }

            FinancialTransaction transaction =
                FinancialTransaction.Create(organization.Identity, DateTime.Now,
                                            transactionDescription);

            transaction.AddRow(organization.FinancialAccounts.DebtsExpenseClaims, -amountCents, claimer);
            transaction.AddRow(budget, amountCents, claimer);

            // Make the transaction dependent on the expense claim

            transaction.Dependency = newClaim;

            // Create notifications

            OutboundComm.CreateNotificationAttestationNeeded(budget, claimer, string.Empty, (double)amountCents / 100.0, description, NotificationResource.ExpenseClaim_Created); // Slightly misplaced logic, but failsafer here
            OutboundComm.CreateNotificationFinancialValidationNeeded(organization, (double)amountCents / 100.0,
                                                                     NotificationResource.Receipts_Filed);
            SwarmopsLogEntry.Create(claimer,
                                    new ExpenseClaimFiledLogEntry(claimer /*filing person*/, claimer /*beneficiary*/, (double)amountCents / 100.0, budget, description), newClaim);

            return(newClaim);
        }
Example #2
0
        public static InboundInvoice Create(Organization organization, DateTime dueDate, Int64 amountCents,
                                            FinancialAccount budget, string supplier, string description, string payToAccount, string ocr,
                                            string invoiceReference, Person creatingPerson)
        {
            InboundInvoice newInvoice = FromIdentity(SwarmDb.GetDatabaseForWriting().
                                                     CreateInboundInvoice(organization.Identity, dueDate, budget.Identity,
                                                                          supplier, payToAccount, ocr,
                                                                          invoiceReference, amountCents, creatingPerson.Identity));

            newInvoice.Description = description; // Not in original schema; not cause for schema update

            // Create a corresponding financial transaction with rows

            FinancialTransaction transaction =
                FinancialTransaction.Create(organization.Identity, DateTime.Now,
                                            "Invoice #" + newInvoice.Identity + " from " + supplier);

            transaction.AddRow(organization.FinancialAccounts.DebtsInboundInvoices, -amountCents, creatingPerson);
            transaction.AddRow(budget, amountCents, creatingPerson);

            // Make the transaction dependent on the inbound invoice

            transaction.Dependency = newInvoice;

            // Create notification (slightly misplaced logic, but this is failsafest place)

            OutboundComm.CreateNotificationAttestationNeeded(budget, creatingPerson, supplier, amountCents / 100.0,
                                                             description, NotificationResource.InboundInvoice_Created);
            // Slightly misplaced logic, but failsafer here
            SwarmopsLogEntry.Create(creatingPerson,
                                    new InboundInvoiceCreatedLogEntry(creatingPerson, supplier, description, amountCents / 100.0, budget),
                                    newInvoice);

            return(newInvoice);
        }
Example #3
0
        protected void ButtonSubmit_Click(object sender, EventArgs e)
        {
            DateTime dateOfBirth = new DateTime(1800, 1, 1);  // null equivalent

            if (this.TextDateOfBirth.Text.Length > 0)
            {
                dateOfBirth = DateTime.Parse(this.TextDateOfBirth.Text);
            }

            string street = this.TextStreet1.Text;

            if (!string.IsNullOrEmpty(this.TextStreet2.Text))
            {
                street += "|" + this.TextStreet2.Text;
            }

            Person newPerson = Person.Create(this.TextName.Text, this.TextMail.Text, string.Empty, this.TextPhone.Text,
                                             street, this.TextPostal.Text, this.TextCity.Text, this.DropCountries.SelectedValue, dateOfBirth,
                                             (PersonGender)Enum.Parse(typeof(PersonGender), this.DropGenders.SelectedValue));

            DateTime            participationExpiry = Constants.DateTimeHigh;
            ParticipantMailType welcomeMailType     = ParticipantMailType.ParticipantAddedWelcome_NoExpiry;

            int participationDurationMonths = Int32.Parse(CurrentOrganization.Parameters.ParticipationDuration);

            if (participationDurationMonths < 1000)
            {
                participationExpiry = DateTime.Today.AddMonths(participationDurationMonths);
                welcomeMailType     = ParticipantMailType.ParticipantAddedWelcome;
            }

            Participation newParticipation = Participation.Create(newPerson, CurrentOrganization, participationExpiry);

            OutboundComm.CreateParticipantMail(welcomeMailType, newParticipation, CurrentUser);

            newPerson.LastLogonOrganizationId = CurrentOrganization.Identity;

            SwarmopsLogEntry logEntry = SwarmopsLog.CreateEntry(newPerson,
                                                                new Swarmops.Logic.Support.LogEntries.PersonAddedLogEntry(newParticipation, CurrentUser));

            logEntry.CreateAffectedObject(newParticipation);
            logEntry.CreateAffectedObject(CurrentUser);

            // Clear form and make way for next person

            this.TextName.Text             = string.Empty;
            this.TextStreet1.Text          = string.Empty;
            this.TextStreet2.Text          = string.Empty;
            this.TextMail.Text             = string.Empty;
            this.TextPhone.Text            = string.Empty;
            this.TextPostal.Text           = string.Empty;
            this.TextCity.Text             = string.Empty;
            this.TextDateOfBirth.Text      = string.Empty;
            this.DropGenders.SelectedValue = "Unknown";

            this.TextName.Focus();
            this.LiteralLoadAlert.Text = Resources.Pages.Swarm.AddPerson_PersonSuccessfullyRegistered;
        }
Example #4
0
        public static CashAdvance Create(Organization organization, Person forPerson, Person createdByPerson, Int64 amountCents, FinancialAccount budget, string description)
        {
            CashAdvance newAdvance = FromIdentityAggressive(SwarmDb.GetDatabaseForWriting().CreateCashAdvance(forPerson.Identity,
                                                                                                              createdByPerson.Identity,
                                                                                                              organization.Identity,
                                                                                                              budget.Identity, amountCents,
                                                                                                              description));

            OutboundComm.CreateNotificationAttestationNeeded(budget, forPerson, string.Empty, (double)amountCents / 100.0, description, NotificationResource.CashAdvance_Requested); // Slightly misplaced logic, but failsafer here
            SwarmopsLogEntry.Create(forPerson,
                                    new CashAdvanceRequestedLogEntry(createdByPerson, forPerson, (double)amountCents / 100.0, budget, description),
                                    newAdvance);

            return(newAdvance);
        }
        public static AjaxCallResult Commence(int personId)
        {
            AuthenticationData authData = GetAuthenticationDataAndCulture();

            if (!authData.Authority.HasSystemAccess())
            {
                // Restrict impersonation to system-level access for now: it's a debugging tool

                return(new AjaxCallResult
                {
                    Success = false,
                    DisplayMessage = CommonV5.JavascriptEscape(Resources.Pages.Admin.CommenceImpersonation_Failed)
                });
            }

            // BEGIN IMPERSONATION

            Person impersonatedPerson = Person.FromIdentity(personId);

            SwarmopsLogEntry newEntry = SwarmopsLog.CreateEntry(impersonatedPerson,
                                                                new ImpersonationLogEntry {
                ImpersonatorPersonId = authData.CurrentUser.PersonId, Started = true
            });

            newEntry.CreateAffectedObject(authData.CurrentUser); // link impersonator to log entry for searchability

            // Someone who has system level access can always impersonate => no further access control at this time

            // SECURITY CONSIDERATIONS: If somebody replaces/fires a superior? Trivially undoable at the database level

            DateTime  utcNow = DateTime.UtcNow;
            Authority impersonatingAuthority = Authority.FromLogin(impersonatedPerson, authData.CurrentOrganization);

            impersonatingAuthority.Impersonation = new Impersonation
            {
                ImpersonatedByPersonId = authData.CurrentUser.PersonId,
                ImpersonationStarted   = utcNow
            };

            FormsAuthentication.SetAuthCookie(impersonatingAuthority.ToEncryptedXml(), false);
            HttpContext.Current.Response.AppendCookie(new HttpCookie("DashboardMessage", CommonV5.JavascriptEscape(String.Format(Resources.Pages.Admin.CommenceImpersonation_Success, utcNow))));
            return(new AjaxCallResult {
                Success = true
            });
        }
Example #6
0
        protected void ButtonSubmit_Click(object sender, EventArgs e)
        {
            DateTime dateOfBirth = new DateTime(1800, 1, 1);  // null equivalent

            if (this.TextDateOfBirth.Text.Length > 0)
            {
                dateOfBirth = DateTime.Parse(this.TextDateOfBirth.Text);
            }

            string street = this.TextStreet1.Text;

            if (!string.IsNullOrEmpty(this.TextStreet2.Text))
            {
                street += "|" + this.TextStreet2.Text;
            }

            Person newPerson = Person.Create(this.TextName.Text, this.TextMail.Text, string.Empty, this.TextPhone.Text,
                                             street, this.TextPostal.Text, this.TextCity.Text, this.DropCountries.SelectedValue, dateOfBirth,
                                             (PersonGender)Enum.Parse(typeof(PersonGender), this.DropGenders.SelectedValue));

            Membership newMembership = Membership.Create(newPerson, CurrentOrganization, DateTime.Today.AddYears(1));

            OutboundComm.CreateMembershipLetter(ParticipantMailType.MemberAddedWelcome, newMembership, CurrentUser);

            SwarmopsLogEntry logEntry = SwarmopsLog.CreateEntry(newPerson,
                                                                new Swarmops.Logic.Support.LogEntries.PersonAddedLogEntry(newMembership, CurrentUser));

            logEntry.CreateAffectedObject(newMembership);
            logEntry.CreateAffectedObject(CurrentUser);

            // Clear form and make way for next person

            this.TextName.Text             = string.Empty;
            this.TextStreet1.Text          = string.Empty;
            this.TextStreet2.Text          = string.Empty;
            this.TextMail.Text             = string.Empty;
            this.TextPhone.Text            = string.Empty;
            this.TextPostal.Text           = string.Empty;
            this.TextCity.Text             = string.Empty;
            this.TextDateOfBirth.Text      = string.Empty;
            this.DropGenders.SelectedValue = "Unknown";

            this.TextName.Focus();
            this.LiteralLoadAlert.Text = Resources.Pages.Swarm.AddPerson_PersonSuccessfullyRegistered;
        }
Example #7
0
        public static AjaxCallResult TerminateImpersonation()
        {
            AuthenticationData authData = GetAuthenticationDataAndCulture();

            if (!authData.Authority.ImpersonationActive)
            {
                return(new AjaxCallResult {
                    Success = false
                });                                          // no impersonation active. Race condition?
            }

            int    realUserPersonId = authData.Authority.Impersonation.ImpersonatedByPersonId;
            Person impersonator     = Person.FromIdentity(realUserPersonId);

            // Terminate impersonation and set new authority cookie from the impersonator data.
            // VERY SECURITY SENSITIVE: The identity as impersonator will be the new user.

            // TODO: LOG LOG LOG LOG

            SwarmopsLogEntry logEntry = SwarmopsLog.CreateEntry(authData.CurrentUser,
                                                                new ImpersonationLogEntry
            {
                ImpersonatorPersonId = impersonator.Identity,
                Started = false
            });

            logEntry.CreateAffectedObject(impersonator); // link impersonator to log entry for searchability

            DateTime utcNow = DateTime.UtcNow;

            Authority authority =
                Authority.FromLogin(impersonator, authData.CurrentOrganization);

            FormsAuthentication.SetAuthCookie(authority.ToEncryptedXml(), false);
            HttpContext.Current.Response.AppendCookie(new HttpCookie("DashboardMessage", CommonV5.JavascriptEscape(String.Format(Resources.Pages.Admin.CommenceImpersonation_Ended, utcNow))));

            // returning Success will force a reload, resetting dashboard to original user

            return(new AjaxCallResult {
                Success = true
            });
        }
Example #8
0
        public static Payout CreateFromProtoIdentity(Person creator, string protoIdentity)
        {
            string[] components = protoIdentity.Split('|');
            int      payoutId   = 0;

            // The components can EITHER be a series of expense claims OR a single invoice.

            if (components.Length == 0)
            {
                // nothing to construct. Exception or return null?

                return(null);
            }
            if (components[0][0] == 'A')
            {
                // Cash advance(s) to be paid out.

                string     bank           = string.Empty;
                string     account        = string.Empty;
                List <int> identityList   = new List <int>();
                Int64      amountCents    = 0;
                int        organizationId = 0;

                foreach (string component in components)
                {
                    int         advanceId = Int32.Parse(component.Substring(1));
                    CashAdvance advance   = CashAdvance.FromIdentity(advanceId);
                    identityList.Add(advanceId);
                    organizationId = advance.OrganizationId;
                    Organization organization = Organization.FromIdentity(advance.OrganizationId);

                    if (bank.Length < 1)
                    {
                        Person asker = advance.Person;
                        bank    = asker.BankName;
                        account = asker.BankAccount;
                    }

                    amountCents += advance.AmountCents;

                    advance.PaidOut = true;
                    // advance.Open remains true until the advance is repaid

                    SwarmopsLogEntry.Create(creator,
                                            new PayoutCreatedLogEntry(creator, advance.Person, organization,
                                                                      organization.Currency, amountCents / 100.0,
                                                                      "Cash Advance Paid Out"),
                                            advance.Person, advance);


                    OutboundComm.CreateNotificationOfFinancialValidation(advance.Budget, advance.Person,
                                                                         advance.AmountCents / 100.0, advance.Description, NotificationResource.CashAdvance_PaidOut);
                }

                string referenceString = string.Empty;

                if (identityList.Count == 1)
                {
                    referenceString = "Cash Advance #" + identityList[0].ToString(CultureInfo.InvariantCulture);
                }
                else
                {
                    identityList.Sort();
                    referenceString = "Cash Advances " + Formatting.GenerateRangeString(identityList);
                }

                payoutId = SwarmDb.GetDatabaseForWriting().CreatePayout(organizationId, bank, account,
                                                                        referenceString, amountCents, DateTime.Today.AddDays(1),
                                                                        creator.Identity);

                foreach (int advanceId in identityList)
                {
                    SwarmDb.GetDatabaseForWriting()
                    .CreatePayoutDependency(payoutId, FinancialDependencyType.CashAdvance,
                                            advanceId);
                }
            }
            else if (components[0][0] == 'C')
            {
                // Expense claims, possibly followed up by cash advance paybacks

                Person       beneficiaryPerson = null;
                Organization organization      = null;
                string       bank                       = string.Empty;
                string       account                    = string.Empty;
                List <int>   claimIdentityList          = new List <int>();
                List <int>   advancePaybackIdentityList = new List <int>();
                Int64        amountCents                = 0;
                int          organizationId             = 0;

                foreach (string component in components)
                {
                    int foreignId = Int32.Parse(component.Substring(1));

                    if (component[0] == 'C')
                    {
                        ExpenseClaim claim = ExpenseClaim.FromIdentity(foreignId);
                        claimIdentityList.Add(foreignId);

                        if (bank.Length < 1)
                        {
                            Person claimer = claim.Claimer;
                            bank           = claimer.BankName;
                            account        = claimer.BankAccount;
                            organizationId = claim.OrganizationId;
                        }

                        beneficiaryPerson = claim.Claimer;
                        organization      = claim.Organization;
                        amountCents      += claim.AmountCents;

                        claim.Repaid = true;
                        claim.Close();

                        OutboundComm.CreateNotificationOfFinancialValidation(claim.Budget, claim.Claimer,
                                                                             claim.AmountCents / 100.0, claim.Description, NotificationResource.ExpenseClaim_PaidOut);
                    }
                    else if (component[0] == 'a')
                    {
                        CashAdvance advancePayback = CashAdvance.FromIdentity(foreignId);
                        advancePaybackIdentityList.Add(foreignId);

                        amountCents        -= advancePayback.AmountCents;
                        advancePayback.Open = false;
                    }
                }

                string referenceString = string.Empty;

                if (claimIdentityList.Count == 1)
                {
                    referenceString = "Expense Claim #" + claimIdentityList[0].ToString(CultureInfo.InvariantCulture);
                }
                else
                {
                    claimIdentityList.Sort();
                    referenceString = "Expense Claims " + Formatting.GenerateRangeString(claimIdentityList);
                }

                SwarmopsLogEntry.Create(creator,
                                        new PayoutCreatedLogEntry(creator, beneficiaryPerson, organization,
                                                                  organization.Currency, amountCents / 100.0,
                                                                  referenceString),
                                        beneficiaryPerson);

                payoutId = SwarmDb.GetDatabaseForWriting().CreatePayout(organizationId, bank, account,
                                                                        referenceString, amountCents, DateTime.Today.AddDays(1),
                                                                        creator.Identity);

                foreach (int claimId in claimIdentityList)
                {
                    SwarmDb.GetDatabaseForWriting()
                    .CreatePayoutDependency(payoutId, FinancialDependencyType.ExpenseClaim,
                                            claimId);
                }

                foreach (int advancePaybackId in advancePaybackIdentityList)
                {
                    SwarmDb.GetDatabaseForWriting()
                    .CreatePayoutDependency(payoutId, FinancialDependencyType.CashAdvancePayback,
                                            advancePaybackId);
                }
            }
            else if (components[0][0] == 'I')
            {
                // There is just one invoice per payout

                InboundInvoice invoice = InboundInvoice.FromIdentity(Int32.Parse(components[0].Substring(1)));

                DateTime expectedPayment = invoice.DueDate;

                if (expectedPayment < DateTime.Today)
                {
                    expectedPayment = DateTime.Today;
                }

                payoutId = SwarmDb.GetDatabaseForWriting()
                           .CreatePayout(invoice.OrganizationId, string.Empty, invoice.PayToAccount,
                                         invoice.Ocr.Length > 0 ? "OCR " + invoice.Ocr : "Ref# " + invoice.InvoiceReference,
                                         invoice.AmountCents, expectedPayment,
                                         creator.Identity);

                SwarmDb.GetDatabaseForWriting()
                .CreatePayoutDependency(payoutId, FinancialDependencyType.InboundInvoice,
                                        invoice.Identity);

                invoice.Open = false;
            }
            else if (components[0][0] == 'S')
            {
                // Salary, net payment

                Salary salary = Salary.FromIdentity(Int32.Parse(components[0].Substring(1)));

                payoutId = SwarmDb.GetDatabaseForWriting()
                           .CreatePayout(salary.PayrollItem.OrganizationId, salary.PayrollItem.Person.BankName,
                                         salary.PayrollItem.Person.BankAccount,
                                         "Salary " + salary.PayoutDate.ToString("yyyy-MMM"),
                                         salary.NetSalaryCents, salary.PayoutDate,
                                         creator.Identity);

                SwarmDb.GetDatabaseForWriting().CreatePayoutDependency(payoutId, FinancialDependencyType.Salary,
                                                                       salary.Identity);

                salary.NetPaid = true;
            }
            else if (components[0][0] == 'T')
            {
                // Tax payment for multiple salaries.

                List <int> identityList   = new List <int>();
                Int64      amountCents    = 0;
                int        organizationId = 0;
                DateTime   payDay         = DateTime.Today.AddDays(1);

                foreach (string component in components)
                {
                    int    salaryId = Int32.Parse(component.Substring(1));
                    Salary salary   = Salary.FromIdentity(salaryId);
                    identityList.Add(salaryId);

                    if (organizationId == 0)
                    {
                        organizationId = salary.PayrollItem.OrganizationId;
                        payDay         = salary.PayoutDate;
                    }

                    amountCents += salary.TaxTotalCents;

                    salary.TaxPaid = true;
                }


                Organization organization = Organization.FromIdentity(organizationId);
                identityList.Sort();

                payoutId = SwarmDb.GetDatabaseForWriting()
                           .CreatePayout(organization.Identity, "The Tax Man", organization.Parameters.TaxAccount,
                                         organization.Parameters.TaxOcr,
                                         amountCents, payDay, creator.Identity);

                foreach (int salaryId in identityList)
                {
                    SwarmDb.GetDatabaseForWriting().CreatePayoutDependency(payoutId, FinancialDependencyType.SalaryTax,
                                                                           salaryId);
                }
            }
            else
            {
                throw new NotImplementedException();
            }

            return(FromIdentity(payoutId));
        }
Example #9
0
        public static Payout CreateBitcoinPayoutFromPrototype(Organization organization, Payout prototype, string transactionHash)
        {
            string[] components = prototype.ProtoIdentity.Split('|');
            int      payoutId   = 0;

            // This function is made for complex bitcoin payouts and will typically take many different types of payouts to many people at once.

            if (components.Length == 0)
            {
                // nothing to construct. Exception or return null?

                return(null);
            }

            payoutId = SwarmDb.GetDatabaseForWriting().CreatePayout(organization.Identity, "Bitcoin network", "Multiple",
                                                                    transactionHash, prototype.AmountCents, DateTime.UtcNow, 0);

            foreach (string component in components)
            {
                int foreignId = Int32.Parse(component.Substring(1));

                switch (component[0])
                {
                case 'A':
                    // Cash advance
                    CashAdvance advance = CashAdvance.FromIdentity(foreignId);
                    advance.PaidOut = true;

                    SwarmopsLogEntry.Create(null,
                                            new PayoutCreatedLogEntry(null, advance.Person, organization,
                                                                      organization.Currency, advance.AmountCents / 100.0,
                                                                      "Cash Advance Paid Out"),
                                            advance.Person, advance);

                    OutboundComm.CreateNotificationOfFinancialValidation(advance.Budget, advance.Person,
                                                                         advance.AmountCents / 100.0, advance.Description, NotificationResource.CashAdvance_PaidOut);
                    SwarmDb.GetDatabaseForWriting()
                    .CreatePayoutDependency(payoutId, FinancialDependencyType.CashAdvance,
                                            foreignId);
                    break;

                case 'a':
                    // This is a negative record - payback of cash advance
                    CashAdvance advancePayback = CashAdvance.FromIdentity(foreignId);
                    advancePayback.Open = false;

                    SwarmDb.GetDatabaseForWriting()
                    .CreatePayoutDependency(payoutId, FinancialDependencyType.CashAdvancePayback,
                                            foreignId);

                    break;

                case 'C':
                    // Expense claim
                    ExpenseClaim claim = ExpenseClaim.FromIdentity(foreignId);
                    claim.Repaid = true;
                    claim.Close();

                    OutboundComm.CreateNotificationOfFinancialValidation(claim.Budget, claim.Claimer,
                                                                         claim.AmountCents / 100.0, claim.Description, NotificationResource.ExpenseClaim_PaidOut);
                    SwarmDb.GetDatabaseForWriting()
                    .CreatePayoutDependency(payoutId, FinancialDependencyType.ExpenseClaim,
                                            foreignId);

                    break;

                case 'I':
                    // Invoice
                    InboundInvoice invoice         = InboundInvoice.FromIdentity(foreignId);
                    DateTime       expectedPayment = invoice.DueDate;

                    if (expectedPayment < DateTime.Today)
                    {
                        expectedPayment = DateTime.Today;
                    }

                    SwarmDb.GetDatabaseForWriting()
                    .CreatePayoutDependency(payoutId, FinancialDependencyType.InboundInvoice,
                                            invoice.Identity);

                    // TODO: NOTIFY PAID?

                    invoice.Open = false;
                    break;

                case 'S':
                    // Salary net

                    Salary salaryNet = Salary.FromIdentity(foreignId);
                    SwarmDb.GetDatabaseForWriting().CreatePayoutDependency(payoutId, FinancialDependencyType.Salary,
                                                                           salaryNet.Identity);
                    salaryNet.NetPaid = true;
                    break;

                case 'T':
                    // Tax payout, typically for multiple salaries

                    Salary salaryTax = Salary.FromIdentity(foreignId);
                    SwarmDb.GetDatabaseForWriting().CreatePayoutDependency(payoutId, FinancialDependencyType.SalaryTax,
                                                                           salaryTax.Identity);
                    salaryTax.TaxPaid = true;

                    break;

                default:
                    throw new NotImplementedException();
                }
            }

            // Return the new object by reloading it from database

            return(Payout.FromIdentity(payoutId));
        }
Example #10
0
        public static ExpenseClaim Create(Person claimer, Organization organization, FinancialAccount budget,
                                          DateTime expenseDate, string description, Int64 amountCents, Int64 vatCents, ExpenseClaimGroup group = null)
        {
            ExpenseClaim newClaim =
                FromIdentityAggressive(SwarmDb.GetDatabaseForWriting()
                                       .CreateExpenseClaim(claimer.Identity, organization?.Identity ?? 0,
                                                           budget?.Identity ?? 0, expenseDate, description, amountCents)); // budget can be 0 initially if created with a group

            if (vatCents > 0)
            {
                newClaim.VatCents = vatCents;
            }

            if (group != null)
            {
                newClaim.Group = group;
            }

            if (budget != null && organization != null)
            {
                // Create the financial transaction with rows

                string transactionDescription = "Expense #" + newClaim.OrganizationSequenceId + ": " + description;
                // TODO: Localize

                if (transactionDescription.Length > 64)
                {
                    transactionDescription = transactionDescription.Substring(0, 61) + "...";
                }


                DateTime expenseTxDate      = expenseDate;
                int      ledgersClosedUntil = organization.Parameters.FiscalBooksClosedUntilYear;

                if (ledgersClosedUntil >= expenseDate.Year)
                {
                    expenseTxDate = DateTime.UtcNow; // If ledgers are closed for the actual expense time, account now
                }

                FinancialTransaction transaction =
                    FinancialTransaction.Create(organization.Identity, expenseTxDate,
                                                transactionDescription);

                transaction.AddRow(organization.FinancialAccounts.DebtsExpenseClaims, -amountCents, claimer);
                if (vatCents > 0)
                {
                    transaction.AddRow(budget, amountCents - vatCents, claimer);
                    transaction.AddRow(organization.FinancialAccounts.AssetsVatInboundUnreported, vatCents, claimer);
                }
                else
                {
                    transaction.AddRow(budget, amountCents, claimer);
                }

                // Make the transaction dependent on the expense claim

                transaction.Dependency = newClaim;

                // Create notifications

                OutboundComm.CreateNotificationAttestationNeeded(budget, claimer, string.Empty,
                                                                 newClaim.BudgetAmountCents / 100.0,
                                                                 description, NotificationResource.ExpenseClaim_Created);
                // Slightly misplaced logic, but failsafer here
                OutboundComm.CreateNotificationFinancialValidationNeeded(organization, newClaim.AmountCents / 100.0,
                                                                         NotificationResource.Receipts_Filed);
                SwarmopsLogEntry.Create(claimer,
                                        new ExpenseClaimFiledLogEntry(claimer /*filing person*/, claimer /*beneficiary*/,
                                                                      newClaim.BudgetAmountCents / 100.0,
                                                                      vatCents / 100.0, budget, description), newClaim);

                // Clear a cache
                FinancialAccount.ClearAttestationAdjustmentsCache(organization);
            }

            return(newClaim);
        }
Example #11
0
        public static AjaxInputCallResult SetPersonEditorData(int personId, string field, string newValue)
        {
            if (newValue == null || field == null)
            {
                throw new ArgumentNullException();
            }

            AuthenticationData authData = GetAuthenticationDataAndCulture();
            bool self = false;

            // Are we modifying ourselves?

            if (personId == 0)   // request self record
            {
                self     = true; // may make use of this later
                personId = authData.CurrentUser.Identity;
            }

            // Preliminary input validation

            if (string.IsNullOrEmpty(newValue))
            {
                if (field != "TwitterId") // These fields may be set to empty; default is disallow
                {
                    return(new AjaxInputCallResult
                    {
                        Success = false,
                        ObjectIdentity = personId,
                        DisplayMessage = Resources.Global.Global_FieldCannotBeEmpty,
                        FailReason = AjaxInputCallResult.ErrorInvalidFormat,
                        NewValue = GetPersonValue(personId, field)
                    });
                }
            }

            // Verify authority to see and change personal data

            Person affectedPerson = Person.FromIdentity(personId);

            if (!self)
            {
                if (!authData.Authority.CanSeePerson(affectedPerson) ||
                    !authData.Authority.HasAccess(new Access(authData.CurrentOrganization, affectedPerson.Geography,
                                                             AccessAspect.PersonalData)))
                {
                    throw new UnauthorizedAccessException();
                }
            }

            string oldValue;
            string displayMessage = string.Empty;

            while (newValue.Contains("  "))
            {
                newValue = newValue.Trim().Replace("  ", " ");  // double, triple, quadruple spaces reduced to one
            }

            switch (field)
            {
            case "Name":
                oldValue            = affectedPerson.Name;
                affectedPerson.Name = newValue;
                break;

            case "Mail":
                oldValue            = affectedPerson.Mail;
                affectedPerson.Mail = newValue;
                break;

            case "Phone":
                oldValue             = affectedPerson.Phone;
                affectedPerson.Phone = newValue;
                if (!Regex.IsMatch(newValue, @"^[0-9 \(\)\-\+]+$"))
                {
                    // using characters not typically seen in a phone number? Warn
                    displayMessage = Resources.Global.Master_EditPersonWarning_Phone;
                }
                break;

            case "TwitterId":
                if (newValue.StartsWith("@"))
                {
                    newValue = newValue.Substring(1);
                }
                oldValue = affectedPerson.TwitterId;
                affectedPerson.TwitterId = newValue;
                break;

            default:
                throw new ArgumentException("Unrecognized field in /Automation/SwarmFunctions.SetPersonEditorData");
            }

            SwarmopsLogEntry logEntry = SwarmopsLog.CreateEntry(affectedPerson, new PersonalDataChangedLogEntry
            {
                ActingPersonId   = authData.CurrentUser.PersonId,
                AffectedPersonId = affectedPerson.PersonId,
                Field            = field,
                IpAddress        = SupportFunctions.GetMostLikelyRemoteIPAddress(),
                OldValue         = oldValue,
                NewValue         = newValue
            });

            if (!self)
            {
                logEntry.CreateAffectedObject(authData.CurrentUser);
            }

            return(new AjaxInputCallResult
            {
                ObjectIdentity = personId,
                Success = true,
                NewValue = newValue,
                DisplayMessage = displayMessage
            });
        }