public void Close (Salary salary) { if (!Open) { throw new InvalidOperationException("Payroll adjustment #" + this.Identity.ToString() + " cannot be closed; is already closed"); } SwarmDb.GetDatabaseForWriting().ClosePayrollAdjustment(this.Identity, salary.Identity); base.Open = false; base.SalaryId = salary.Identity; }
/// <summary> /// Processes all payroll for all organizations system-wide. Should run on the 1st of every month. /// </summary> public static void ProcessMonthly() { DateTime today = DateTime.UtcNow; string lastRun = Persistence.Key["LastSalaryRun"]; string expectedLastRun = today.ToString("yyyyMM", CultureInfo.InvariantCulture); if (lastRun != null && String.Compare(lastRun, expectedLastRun, CultureInfo.InvariantCulture, CompareOptions.IgnoreCase) >= 0) { // nothing to do, return return; } Persistence.Key["LastSalaryRun"] = expectedLastRun; // Process the payroll for all organizations. Assume payday is 25th. // TODO: Different payday per organization? Payroll payroll = GetAll(); DateTime payday = new DateTime(today.Year, today.Month, 25); foreach (PayrollItem payrollItem in payroll) { Salary salary = Salary.Create(payrollItem, payday); SwarmopsLog.CreateEntry(payrollItem.Person, new SalaryCreatedLogEntry(salary)); // TODO: CREATE SALARY SPECIFICATION, SEND TO PERSON } // If this is January, also send the annual statements for last year if (today.Month == 1) { Salaries.CreateAnnualStatements(today.Year - 1); } }
private static void AddUnpaidSalaries(Payouts payoutList, Organization organization) { Int64 taxTotalCents = 0; Salaries salaries = Salaries.ForOrganization(organization); List <int> identityList = new List <int>(); DateTime payDay = Constants.DateTimeHigh; foreach (Salary salary in salaries) { if (!salary.Attested) { continue; } if (!salary.NetPaid) { PayrollItem payrollItem = salary.PayrollItem; Person employee = payrollItem.Person; BasicPayout basicPayout = new BasicPayout(0, organization.Identity, employee.BankName, employee.BankClearing + " / " + employee.BankAccount, "[Loc]Financial_SalarySpecification|[Date]" + salary.PayoutDate.ToString(CultureInfo.InvariantCulture), salary.NetSalaryCents, salary.PayoutDate, false, DateTime.Now, 0); Payout payout = Payout.FromBasic(basicPayout); payout.RecipientPerson = employee; payout.DependentSalariesNet.Add(salary); payoutList.Add(payout); if (payDay > salary.PayoutDate) { payDay = salary.PayoutDate; } } if (!salary.TaxPaid) { taxTotalCents += salary.TaxTotalCents; identityList.Add(salary.Identity); if (payDay > salary.PayoutDate) { payDay = salary.PayoutDate; } } } if (taxTotalCents > 0) { // Add the summarized tax line, too BasicPayout basicPayout = new BasicPayout(0, organization.Identity, "[Loc]Financial_TheTaxMan", "SEBG 5050-1055", // HACK: Get tax account from something organization.TaxPaymentOcr, taxTotalCents, payDay, false, DateTime.Now, 0); Payout payout = Payout.FromBasic(basicPayout); foreach (int salaryId in identityList) { payout.DependentSalariesTax.Add(Salary.FromIdentity(salaryId)); } payoutList.Add(payout); } }
public static Salary Create(PayrollItem payrollItem, DateTime payoutDate) { // Load the existing adjustments. PayrollAdjustments adjustments = PayrollAdjustments.ForPayrollItem(payrollItem); Int64 payCents = payrollItem.BaseSalaryCents; // Apply all before-tax adjustments foreach (PayrollAdjustment adjustment in adjustments) { if (adjustment.Type == PayrollAdjustmentType.GrossAdjustment) { payCents += adjustment.AmountCents; } } // calculate tax double subtractiveTax = TaxLevels.GetTax(payrollItem.Country, payrollItem.SubtractiveTaxLevelId, payCents / 100.0); if (subtractiveTax < 1.0) { // this is a percentage and not an absolute number subtractiveTax = payCents * subtractiveTax; } Int64 subtractiveTaxCents = (Int64)(subtractiveTax * 100); Int64 additiveTaxCents = (Int64)(payCents * payrollItem.AdditiveTaxLevel); payCents -= subtractiveTaxCents; // Apply all after-tax adjustments foreach (PayrollAdjustment adjustment in adjustments) { if (adjustment.Type == PayrollAdjustmentType.NetAdjustment) { payCents += adjustment.AmountCents; } } // Create salary, close adjustments Salary salary = Create(payrollItem, payoutDate, payCents, subtractiveTaxCents, additiveTaxCents); // For each adjustment, close and bind to salary foreach (PayrollAdjustment adjustment in adjustments) { adjustment.Close(salary); } // If net is negative, create rollover adjustment if (payCents < 0) { PayrollAdjustment rollover1 = PayrollAdjustment.Create(payrollItem, PayrollAdjustmentType.NetAdjustment, -payCents, "Deficit rolls over to next salary"); rollover1.Close(salary); PayrollAdjustment rollover2 = PayrollAdjustment.Create(payrollItem, PayrollAdjustmentType.NetAdjustment, payCents, "Deficit rolled over from " + payoutDate.ToString("yyyy-MM-dd")); // keep rollover2 open, so the deficit from this salary is carried to the next salary.NetSalaryCents = 0; } // Add the financial transaction FinancialTransaction transaction = FinancialTransaction.Create(payrollItem.OrganizationId, DateTime.Now, "Salary #" + salary.Identity + ": " + payrollItem.PersonCanonical + " " + salary.PayoutDate.ToString("yyyy-MMM", CultureInfo.InvariantCulture)); transaction.AddRow(payrollItem.Budget, salary.CostTotalCents, null); transaction.AddRow(payrollItem.Organization.FinancialAccounts.DebtsSalary, -salary.NetSalaryCents, null); transaction.AddRow(payrollItem.Organization.FinancialAccounts.DebtsTax, -salary.TaxTotalCents, null); transaction.Dependency = salary; // Finally, check if net and/or tax are zero, and if so, mark them as already-paid (i.e. not due for payment) if (salary.NetSalaryCents == 0) { salary.NetPaid = true; } if (salary.TaxTotalCents == 0) { salary.TaxPaid = true; } return(salary); }
private static void AddUnpaidSalaries(Payouts payoutList, int organizationId) { Int64 taxTotalCents = 0; Salaries salaries = Salaries.ForOrganization(Organization.FromIdentity(organizationId)); List <int> identityList = new List <int>(); DateTime payDay = DateTime.MaxValue; foreach (Salary salary in salaries) { if (!salary.Attested) { continue; } if (!salary.NetPaid) { PayrollItem payrollItem = salary.PayrollItem; Person employee = payrollItem.Person; BasicPayout basicPayout = new BasicPayout(0, organizationId, employee.BankName, employee.BankClearing + " / " + employee.BankAccount, "[Loc]Financial_SalarySpecification|[Date]" + salary.PayoutDate.ToString(CultureInfo.InvariantCulture), salary.NetSalaryCents, salary.PayoutDate, false, DateTime.Now, 0); Payout payout = Payout.FromBasic(basicPayout); payout.DependentSalariesNet.Add(salary); payoutList.Add(payout); if (payDay > salary.PayoutDate) { payDay = salary.PayoutDate; } } if (!salary.TaxPaid) { taxTotalCents += salary.TaxTotalCents; identityList.Add(salary.Identity); if (payDay > salary.PayoutDate) { payDay = salary.PayoutDate; } } } if (taxTotalCents > 0) { // Add the summarized tax line, too string referenceString = string.Empty; if (identityList.Count == 1) { referenceString = "[Loc]Financial_TaxSpecification|" + identityList[0].ToString(); } else { identityList.Sort(); referenceString = "[Loc]Financial_TaxesSpecification|" + Formatting.GenerateRangeString(identityList); } BasicPayout basicPayout = new BasicPayout(0, organizationId, "[Loc]Financial_TheTaxMan", string.Empty, referenceString, taxTotalCents, payDay, false, DateTime.Now, 0); Payout payout = Payout.FromBasic(basicPayout); foreach (int salaryId in identityList) { payout.DependentSalariesTax.Add(Salary.FromIdentity(salaryId)); } payoutList.Add(payout); } }
public static PayrollAdjustments ForSalary(Salary salary) { return(FromArray(SwarmDb.GetDatabaseForReading().GetPayrollAdjustments(salary))); }
private void LoadDependencies() { if (this.DependentCashAdvancesPayback != null && Identity == 0) { return; // if inited and identity zero, return } this.DependentExpenseClaims = new ExpenseClaims(); this.DependentInvoices = new InboundInvoices(); this.DependentSalariesNet = new Salaries(); this.DependentSalariesTax = new Salaries(); this.DependentCashAdvancesPayout = new CashAdvances(); this.DependentCashAdvancesPayback = new CashAdvances(); if (Identity == 0) { return; // never progress past here if identity zero } BasicFinancialDependency[] dependencies = SwarmDb.GetDatabaseForReading().GetPayoutDependencies(Identity); foreach (BasicFinancialDependency dependency in dependencies) { switch (dependency.DependencyType) { case FinancialDependencyType.ExpenseClaim: this.DependentExpenseClaims.Add(ExpenseClaim.FromIdentity(dependency.ForeignId)); break; case FinancialDependencyType.InboundInvoice: this.DependentInvoices.Add(InboundInvoice.FromIdentity(dependency.ForeignId)); break; case FinancialDependencyType.Salary: Salary salary = Salary.FromIdentity(dependency.ForeignId); if (salary.NetSalaryCents == AmountCents || this.CreatedDateTime > new DateTime(2015, 11, 1)) { this.DependentSalariesNet.Add(salary); } else // LEGACY { this.DependentSalariesTax.Add(salary); } break; case FinancialDependencyType.SalaryTax: Salary salaryTax = Salary.FromIdentity(dependency.ForeignId); this.DependentSalariesTax.Add(salaryTax); break; case FinancialDependencyType.CashAdvance: this.DependentCashAdvancesPayout.Add(CashAdvance.FromIdentity(dependency.ForeignId)); break; case FinancialDependencyType.CashAdvancePayback: this.DependentCashAdvancesPayback.Add(CashAdvance.FromIdentity(dependency.ForeignId)); break; default: throw new NotImplementedException( "Unknown financial dependency type in Payout.LoadDependencies(): " + dependency); } } }
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 TaskSalary (Salary salary): base (salary.Identity, salary.PayoutDate.ToString("yyyy-MMM") + " salary for " + salary.PayrollItem.PersonCanonical, salary.PayoutDate.AddDays(-(salary.PayoutDate.Day-1)), salary.PayoutDate.AddDays(-7)) { // empty ctor }
public static Salary Create(PayrollItem payrollItem, DateTime payoutDate) { // Load the existing adjustments. PayrollAdjustments adjustments = PayrollAdjustments.ForPayrollItem(payrollItem); Int64 payCents = payrollItem.BaseSalaryCents; // Apply all before-tax adjustments foreach (PayrollAdjustment adjustment in adjustments) { if (adjustment.Type == PayrollAdjustmentType.GrossAdjustment) { payCents += adjustment.AmountCents; } } Int64 subtractiveTaxCents = 0; Int64 additiveTaxCents = 0; if (!payrollItem.IsContractor) { // calculate tax Money grossInOrgCurrency = new Money { Cents = payCents, Currency = payrollItem.Organization.Currency, ValuationDateTime = DateTime.UtcNow }; Money grossInTaxCurrency = grossInOrgCurrency.ToCurrency(payrollItem.Country.Currency); Money subtractiveTax = TaxLevels.GetTax(payrollItem.Country, payrollItem.SubtractiveTaxLevelId, grossInTaxCurrency); Money subtractiveTaxInOrgCurrency = subtractiveTax.ToCurrency(payrollItem.Organization.Currency); subtractiveTaxCents = (Int64)(subtractiveTaxInOrgCurrency.Cents); additiveTaxCents = (Int64)(payCents * payrollItem.AdditiveTaxLevel); payCents -= subtractiveTaxCents; } // Apply all after-tax adjustments foreach (PayrollAdjustment adjustment in adjustments) { if (adjustment.Type == PayrollAdjustmentType.NetAdjustment) { payCents += adjustment.AmountCents; } } // If net is negative, create rollover adjustment PayrollAdjustment rolloverAdjustment = null; if (payCents < 0) { rolloverAdjustment = PayrollAdjustment.Create(payrollItem, PayrollAdjustmentType.NetAdjustment, -payCents, "Deficit rolls over to next salary"); PayrollAdjustment.Create(payrollItem, PayrollAdjustmentType.NetAdjustment, payCents, "Deficit rolled over from " + payoutDate.ToString("yyyy-MM-dd")); // keep second rollover open, so the deficit from this salary is carried to the next payCents = 0; } // Create salary, close adjustments Salary salary = Create(payrollItem, payoutDate, payCents, subtractiveTaxCents, additiveTaxCents); // For each adjustment, close and bind to salary foreach (PayrollAdjustment adjustment in adjustments) { adjustment.Close(salary); } if (rolloverAdjustment != null) { rolloverAdjustment.Close(salary); } // Add the financial transaction FinancialTransaction transaction = FinancialTransaction.Create(payrollItem.OrganizationId, DateTime.Now, "Salary #" + salary.Identity + ": " + payrollItem.PersonCanonical + " " + salary.PayoutDate.ToString("yyyy-MMM", CultureInfo.InvariantCulture)); transaction.AddRow(payrollItem.Budget, salary.CostTotalCents, null); transaction.AddRow(payrollItem.Organization.FinancialAccounts.DebtsSalary, -salary.NetSalaryCents, null); if (salary.TaxTotalCents != 0) { transaction.AddRow(payrollItem.Organization.FinancialAccounts.DebtsTax, -salary.TaxTotalCents, null); } transaction.Dependency = salary; // Finally, check if net and/or tax are zero, and if so, mark them as already-paid (i.e. not due for payment) if (salary.NetSalaryCents == 0) { salary.NetPaid = true; } if (salary.TaxTotalCents == 0) { salary.TaxPaid = true; } // Clear a cache FinancialAccount.ClearAttestationAdjustmentsCache(payrollItem.Organization); return(salary); }
public static PaymentTransferInfo FromObject(IHasIdentity financialObject, Money amountToPay = null) { if (financialObject is ExpenseClaim) { ExpenseClaim claim = financialObject as ExpenseClaim; if (amountToPay == null) { return(FromObject(claim.Claimer, new Money(claim.AmountCents, claim.Organization.Currency))); } else { return(FromObject(claim.Claimer, amountToPay)); } } if (financialObject is CashAdvance) { CashAdvance advance = financialObject as CashAdvance; if (amountToPay == null) { return(FromObject(advance.Person, new Money(advance.AmountCents, advance.Organization.Currency))); } else { return(FromObject(advance.Person, amountToPay)); } } if (financialObject is Salary) { Salary salary = financialObject as Salary; return(FromObject(salary.PayrollItem.Person, new Money(salary.NetSalaryCents, salary.PayrollItem.Organization.Currency))); } if (financialObject is InboundInvoice) { // TODO: Create Supplier object, read from that instead InboundInvoice invoice = financialObject as InboundInvoice; PaymentTransferInfo result = new PaymentTransferInfo(); // For now, do a switch on the pay-to-account string, before the payment targets are implemented // on invoices and expense claims: result.LocalizedPaymentInformation = new Dictionary <string, string>(); if (invoice.PayToAccount.StartsWith("IBAN")) { result.TargetType = PaymentTargetType.InternationalBankTransfer; result.LocalizedPaymentInformation[ Logic_Financial_PaymentTransferInfo.PaymentTargetField_Iban] = invoice.PayToAccount.Substring(5); // this should have bic too but we don't have that information before payment targets // are properly implemented } else if (invoice.PayToAccount.StartsWith("SEBG")) { result.TargetType = PaymentTargetType.DomesticBankGiro; // for now result.LocalizedPaymentInformation[ Logic_Financial_PaymentTransferInfo.PaymentTargetField_GiroNumber] = invoice.PayToAccount.Substring(5); // Check for SEBG OCR availability if (invoice.InvoiceReference.Length > 2 && Formatting.CheckLuhnChecksum(invoice.InvoiceReference) && Formatting.CheckLuhnChecksum(invoice.PayToAccount)) { result.OcrAvailable = true; result.OcrData = new string[3]; result.OcrData[0] = invoice.InvoiceReference + " #"; result.OcrData[1] = string.Format("{0} {1:00} {2} >", // three spaces between the cents and the checksum invoice.AmountCents / 100, invoice.AmountCents % 100, Formatting.GetLuhnChecksum(invoice.AmountCents.ToString(CultureInfo.InvariantCulture))); result.OcrData[2] = Formatting.CleanNumber(invoice.PayToAccount) + "#41#"; } } else { // Assume domestic giro in lack of other information result.TargetType = PaymentTargetType.DomesticBankGiro; result.LocalizedPaymentInformation[ Logic_Financial_PaymentTransferInfo.PaymentTargetField_GiroNumber] = invoice.PayToAccount; // the whole string, as opposed to case above } result.LocalizedPaymentMethodName = Logic_Financial_PaymentTransferInfo.ResourceManager.GetString("PaymentTargetType_" + result.TargetType.ToString()); if (invoice.HasNativeCurrency) { result.Currency = invoice.NativeCurrencyAmount.Currency; result.CurrencyAmount = result.Currency.Code + " " + (invoice.NativeCurrencyAmount.Cents / 100.0).ToString("N2"); } else { result.Currency = invoice.Organization.Currency; result.CurrencyAmount = result.Currency.Code + " " + (invoice.AmountCents / 100.0).ToString("N2"); } result.Country = null; // TODO: Set to Supplier's PaymentTarget country result.Recipient = invoice.Supplier; return(result); } if (financialObject is Person) { Person person = financialObject as Person; // For now, assume the bank/clearing/account triplet // TODO: Implement payment targets on teh Person object PaymentTransferInfo result = new PaymentTransferInfo(); result.TargetType = PaymentTargetType.DomesticBankTransfer; // We must know the amount at this point if (amountToPay == null) { throw new ArgumentNullException("amountToPay", @"Cannot determine payment transfer information without knowing origin currency"); } if (string.IsNullOrEmpty(person.BankName) || string.IsNullOrEmpty(person.BankClearing) || string.IsNullOrEmpty(person.BankAccount)) { throw new NotImplementedException("Cannot provide payment transfer information for Person #" + person.Identity.ToString()); } result.TargetType = PaymentTargetType.DomesticBankTransfer; result.Country = person.CountryId == 0? null: person.Country; result.Currency = amountToPay.Currency; // TODO: The currency will need to come from the payment method instead result.CurrencyAmount = result.Currency.Code + " " + (amountToPay.ToCurrency(result.Currency).Cents / 100.0).ToString("N2"); result.LocalizedPaymentMethodName = Logic_Financial_PaymentTransferInfo.ResourceManager.GetString("PaymentTargetType_" + result.TargetType.ToString()); result.Recipient = person.Canonical; result.LocalizedPaymentInformation = new Dictionary <string, string>(); result.LocalizedPaymentInformation[ Logic_Financial_PaymentTransferInfo.PaymentTargetField_ClearingCode] = person.BankName + " " + person.BankClearing; result.LocalizedPaymentInformation[ Logic_Financial_PaymentTransferInfo.PaymentTargetField_AccountNumber] = person.BankAccount; return(result); } throw new NotImplementedException("Unknown payment information"); }