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); }
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); }
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 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)); }
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)); }
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); }