Beispiel #1
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);
        }
Beispiel #2
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);
        }
Beispiel #3
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);
        }
Beispiel #4
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));
        }
Beispiel #5
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));
        }
Beispiel #6
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);
        }