private void AddInboundInvoiceEvent(int parentId, InboundInvoice invoice) { int newId = transactionEvents.Count + 1; transactionEvents.Add(new TransactionEvent(newId, parentId, "Invoice #" + invoice.Identity.ToString())); transactionEvents.Add( new TransactionEvent(newId + 1, newId, "Supplier: " + invoice.Supplier)); transactionEvents.Add( new TransactionEvent(newId + 2, newId, "Received: " + invoice.CreatedDateTime.ToString("yyyy-MM-dd HH:mm"))); transactionEvents.Add( new TransactionEvent(newId + 3, newId, "Budget: " + invoice.Budget.Name)); AddValidations(newId, invoice); foreach (Document document in invoice.Documents) { AddDocumentEvent(newId, document); } }
protected void GridInvoices_ItemCreated(object sender, GridItemEventArgs e) { if (e.Item is GridDataItem) { InboundInvoice invoice = (InboundInvoice)e.Item.DataItem; if (invoice == null) { return; } Label labelBudgetYear = (Label)e.Item.FindControl("LabelBudgetYear"); if (invoice.BudgetId == 0) { labelBudgetYear.Text = "UNBUDGETED!"; } else { labelBudgetYear.Text = invoice.Budget.Name + ", " + invoice.CreatedDateTime.Year.ToString(); } Controls_v4_DocumentList docList = (Controls_v4_DocumentList)e.Item.FindControl("DocListInvoice"); docList.Documents = invoice.Documents; HyperLink editLink = (HyperLink)e.Item.FindControl("LinkEdit"); editLink.Attributes["href"] = "#"; editLink.Attributes["onclick"] = String.Format("return ShowInboundInvoiceForm('{0}','{1}');", invoice.Identity, e.Item.ItemIndex); } }
protected void Page_Load(object sender, EventArgs e) { _invoice = InboundInvoice.FromIdentity(Int32.Parse(Request.QueryString["InboundInvoiceId"])); // TODO: Verify authority (economy assistant or budget owner) if (!Page.IsPostBack) { this.LabelInvoiceFrom.Text = _invoice.Supplier; this.LabelInvoiceReceivedDate.Text = _invoice.CreatedDateTime.ToString("yyyy-MM-dd"); this.LabelAttested.Text = _invoice.Attested ? "Yes." : "No."; this.DropAccounts.Populate(_invoice.Organization, FinancialAccountType.Cost); if (_invoice.BudgetId != 0) { this.DropAccounts.SelectedFinancialAccount = _invoice.Budget; } this.DateInvoiceDue.SelectedDate = _invoice.DueDate; this.TextAmount.Text = _invoice.Amount.ToString("N2", new CultureInfo("sv-SE")); } // The DocumentList control does not hold state - yet - so must be initialized always this.DocumentList.Documents = Documents.ForObject(_invoice); }
public TaskInboundInvoice(InboundInvoice invoice) : base( invoice.Identity, "Inbound Invoice #" + invoice.Identity, invoice.CreatedDateTime, invoice.DueDate.AddDays(-7)) { // empty ctor }
private static string GetObjectDetails(IHasIdentity identifiableObject) { switch (identifiableObject.GetType().Name) { case "ExpenseClaim": ExpenseClaim claim = (ExpenseClaim)identifiableObject; return("<strong>" + String.Format(Global.Financial_ExpenseClaimLongSpecification, claim.Identity) + ":</strong> " + claim.Organization.Currency.Code + " " + (claim.AmountCents / 100.0).ToString("N2") + ". " + HttpUtility.HtmlEncode(GetValidationDetails(claim.Validations)) + " " + GetDocumentDetails(claim.Documents, claim)); case "CashAdvance": CashAdvance advance = (CashAdvance)identifiableObject; return("<strong>" + String.Format(Global.Financial_CashAdvanceSpecification, advance.Identity) + ":</strong> " + advance.Organization.Currency.Code + " " + (advance.AmountCents / 100.0).ToString("N2") + ". " + HttpUtility.HtmlEncode(GetValidationDetails(advance.Validations))); case "InboundInvoice": InboundInvoice invoice = (InboundInvoice)identifiableObject; return("<strong>" + String.Format(Global.Financial_InboundInvoiceSpecification, invoice.Identity) + ":</strong> " + invoice.Organization.Currency.Code + " " + (invoice.AmountCents / 100.0).ToString("N2") + ". " + GetValidationDetails(invoice.Validations) + " " + GetDocumentDetails(invoice.Documents, invoice)); case "Salary": Salary salary = (Salary)identifiableObject; return("<strong>" + String.Format(Global.Financial_SalaryIdentity, salary.Identity) + ":</strong> " + String.Format(Resources.Pages.Ledgers.InspectLedgers_TxDetail_SalaryDetail, salary.PayrollItem.Organization.Currency.Code, salary.BaseSalaryCents / 100.0, // base salary (salary.GrossSalaryCents - salary.BaseSalaryCents) / 100.0, // before-tax adjustments salary.GrossSalaryCents / 100.0, // before-tax adjusted salary salary.SubtractiveTaxCents / 100.0, // tax deduction (salary.NetSalaryCents + salary.SubtractiveTaxCents - salary.GrossSalaryCents) / 100.0, // after-tax adjustments salary.NetSalaryCents / 100.0) + // actual payout amount " " + GetValidationDetails(salary.Validations)); default: throw new NotImplementedException("Unhandled object type in GetObjectDetails: " + identifiableObject.GetType().Name); } }
protected void GridInvoices_ItemCreated(object sender, GridItemEventArgs e) { // Set the images for the status indicators. const string imageUrlTodo = "~/Images/Public/Fugue/icons-shadowless/minus-small.png"; const string imageUrlTick = "~/Images/Public/Fugue/icons-shadowless/tick.png"; const string imageUrlFail = "~/Images/Public/Fugue/icons-shadowless/cross-circle-frame.png"; if (e.Item is GridDataItem) { InboundInvoice invoice = (InboundInvoice)e.Item.DataItem; if (invoice == null) { return; } Controls_v4_DocumentList docList = (Controls_v4_DocumentList)e.Item.FindControl("DocumentList"); if (docList != null) { docList.Documents = Documents.ForObject(invoice); } Image imageAttested = (Image)e.Item.FindControl("ImageAttested"); Image imagePaid = (Image)e.Item.FindControl("ImageClosedPaid"); imageAttested.ImageUrl = invoice.Attested ? imageUrlTick : imageUrlTodo; if (invoice.Open == false) { imagePaid.ImageUrl = invoice.Attested ? imageUrlTick : imageUrlFail; } else { imagePaid.ImageUrl = imageUrlTodo; } HyperLink editLink = (HyperLink)e.Item.FindControl("LinkEdit"); editLink.Attributes["href"] = "#"; if (invoice.Open) { editLink.Attributes["onclick"] = String.Format("return ShowInboundInvoiceForm('{0}','{1}');", invoice.Identity, e.Item.ItemIndex); } else { editLink.Visible = false; } } }
static protected IPayable PayableFromRecordId(string recordId) { char recordType = recordId[0]; int itemId = Int32.Parse(recordId.Substring(1)); switch (recordType) { case 'E': // Expense claim return(ExpenseClaim.FromIdentity(itemId)); case 'A': // Cash advance return(CashAdvance.FromIdentity(itemId)); case 'I': // Inbound invoice return(InboundInvoice.FromIdentity(itemId)); default: throw new NotImplementedException("Unknown record type"); } }
private void AddInboundInvoiceToDebug(InboundInvoice invoice) { debugLookup[Organization.PPSE.FinancialAccounts.DebtsInboundInvoices.Identity].Invoices -= invoice.Amount; }
static public object FromBasic(IHasIdentity basic) { string argumentType = basic.GetType().ToString(); switch (argumentType) { // ----- Is there any way to make self-writing code here through replication or similar, so // ----- that every case doesn't need to be listed? // ------------ COMMUNICATION CLASSES ------------ case "Swarmops.Basic.Types.BasicCommunicationTurnaround": return(CommunicationTurnaround.FromBasic((BasicCommunicationTurnaround)basic)); case "Swarmops.Basic.Types.Communications.BasicOutboundComm": return(OutboundComm.FromBasic((BasicOutboundComm)basic)); case "Swarmops.Basic.Types.Communications.BasicOutboundCommRecipient": return(OutboundCommRecipient.FromBasic((BasicOutboundCommRecipient)basic)); // ----------- FINANCIAL CLASSES ---------- case "Swarmops.Basic.Types.BasicExpenseClaim": return(ExpenseClaim.FromBasic((BasicExpenseClaim)basic)); case "Swarmops.Basic.Types.Financial.BasicCashAdvance": return(CashAdvance.FromBasic((BasicCashAdvance)basic)); case "Swarmops.Basic.Types.BasicInboundInvoice": return(InboundInvoice.FromBasic((BasicInboundInvoice)basic)); case "Swarmops.Basic.Types.Financial.BasicFinancialAccount": return(FinancialAccount.FromBasic((BasicFinancialAccount)basic)); case "Swarmops.Basic.Types.Financial.BasicFinancialTransaction": return(FinancialTransaction.FromBasic((BasicFinancialTransaction)basic)); case "Swarmops.Basic.Types.BasicFinancialValidation": return(FinancialValidation.FromBasic((BasicFinancialValidation)basic)); case "Swarmops.Basic.Types.BasicOutboundInvoice": return(OutboundInvoice.FromBasic((BasicOutboundInvoice)basic)); case "Swarmops.Basic.Types.BasicOutboundInvoiceItem": return(OutboundInvoiceItem.FromBasic((BasicOutboundInvoiceItem)basic)); case "Swarmops.Basic.Types.BasicPayment": return(Payment.FromBasic((BasicPayment)basic)); case "Swarmops.Basic.Types.BasicPaymentGroup": return(PaymentGroup.FromBasic((BasicPaymentGroup)basic)); case "Swarmops.Basic.Types.BasicPayout": return(Payout.FromBasic((BasicPayout)basic)); case "Swarmops.Basic.Types.BasicPayrollAdjustment": return(PayrollAdjustment.FromBasic((BasicPayrollAdjustment)basic)); case "Swarmops.Basic.Types.BasicPayrollItem": return(PayrollItem.FromBasic((BasicPayrollItem)basic)); case "Swarmops.Basic.Types.BasicSalary": return(Salary.FromBasic((BasicSalary)basic)); case "Swarmops.Basic.Types.Financial.BasicFinancialTransactionTagSet": return(FinancialTransactionTagSet.FromBasic((BasicFinancialTransactionTagSet)basic)); case "Swarmops.Basic.Types.Financial.BasicFinancialTransactionTagType": return(FinancialTransactionTagType.FromBasic((BasicFinancialTransactionTagType)basic)); // ------------ GOVERNANCE CLASSES ------------ case "Swarmops.Basic.Types.BasicBallot": return(Ballot.FromBasic((BasicBallot)basic)); case "Swarmops.Basic.Types.BasicMeetingElectionCandidate": return(MeetingElectionCandidate.FromBasic((BasicInternalPollCandidate)basic)); case "Swarmops.Basic.Types.BasicMeetingElection": return(MeetingElection.FromBasic((BasicInternalPoll)basic)); case "Swarmops.Basic.Types.BasicMeetingElectionVote": return(MeetingElectionVote.FromBasic((BasicInternalPollVote)basic)); case "Swarmops.Basic.Types.Governance.BasicMotion": return(Motion.FromBasic((BasicMotion)basic)); case "Swarmops.Basic.Types.Governance.BasicMotionAmendment": return(MotionAmendment.FromBasic((BasicMotionAmendment)basic)); // ------------ PARLEY/ACTIVISM CLASSES ------------ case "Swarmops.Basic.Types.BasicExternalActivity": return(ExternalActivity.FromBasic((BasicExternalActivity)basic)); case "Swarmops.Basic.Types.BasicParley": return(Parley.FromBasic((BasicParley)basic)); case "Swarmops.Basic.Types.BasicParleyAttendee": return(ParleyAttendee.FromBasic((BasicParleyAttendee)basic)); case "Swarmops.Basic.Types.BasicParleyOption": return(ParleyOption.FromBasic((BasicParleyOption)basic)); case "Swarmops.Basic.Types.BasicPerson": return(Person.FromBasic((BasicPerson)basic)); // ------------------ FAIL ---------------- default: throw new NotImplementedException("Unimplemented argument type: " + argumentType); } }
protected void Page_Load(object sender, EventArgs e) { string documentIdString = Request.QueryString["DocId"]; int documentId = Int32.Parse(documentIdString); string documentDownloadName = Request.QueryString["DocName"]; documentDownloadName = documentDownloadName.Replace("\"", "'"); Document document = Document.FromIdentity(documentId); //Orgid is needed to safely verify permission int orgId = 0; // initialize to invalid bool hasPermission = false; string serverFileName = document.ServerFileName; if (document.UploadedByPersonId == this.CurrentAuthority.Person.Identity) { hasPermission = true; // can always view documents you yourself uploaded } if (CurrentOrganization.HasOpenLedgers) { hasPermission = true; } if (!hasPermission) { switch (document.DocumentType) { case DocumentType.FinancialTransaction: { /* * //TODO: Get the orgId from foreign object * if (this.CurrentAuthority.HasPermission(Permission.CanSeeEconomyDetails, orgId, -1, Authorization.Flag.ExactOrganization)) * { * hasPermission = true; * }*/ } break; case DocumentType.ExpenseClaim: case DocumentType.InboundInvoice: case DocumentType.OutboundInvoice: { int budgetId = 0; if (document.DocumentType == DocumentType.ExpenseClaim) { ExpenseClaim claim = (ExpenseClaim)document.ForeignObject; orgId = claim.Budget.OrganizationId; budgetId = claim.BudgetId; } else if (document.DocumentType == DocumentType.InboundInvoice) { InboundInvoice invoice = (InboundInvoice)document.ForeignObject; orgId = invoice.Budget.OrganizationId; budgetId = invoice.BudgetId; } else { OutboundInvoice invoice = (OutboundInvoice)document.ForeignObject; orgId = invoice.OrganizationId; budgetId = invoice.BudgetId; } FinancialAccount budget = FinancialAccount.FromIdentity(budgetId); if (budget.OwnerPersonId == CurrentUser.Identity || budget.OwnerPersonId == 0) { hasPermission = true; break; } // TODO: Security leak - check CurrentOrganization against Document's org if ( CurrentAuthority.HasAccess(new Access(CurrentOrganization, AccessAspect.Financials, AccessType.Write))) { hasPermission = true; } /* * if (this.CurrentAuthority.HasPermission(Permission.CanSeeEconomyDetails, orgId, -1, Authorization.Flag.ExactOrganization)) * { * hasPermission = true; * break; * }*/ break; } case DocumentType.PaperLetter: { PaperLetter letter = (PaperLetter)document.ForeignObject; if (letter.Recipient.Identity == CurrentUser.Identity) { hasPermission = true; // A letter to the viewer } /* * // Otherwise, are there overriding permissions, if not addressed to him/her? * * else if (!letter.Personal) * { * // Unpersonal paper letter, like a rally permit. Note that bank statements should * // be considered personal as they contain donors' information in the transaction info. * * if (this.CurrentAuthority.HasPermission(Permission.CanSeeInsensitivePaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) * { * hasPermission = true; * } * } * else if (letter.ToPersonId == 0) * { * // Addressed to the organization, not to a specific person, but still personal. * // Typical examples include political inquiries from private citizens written on * // paper. * * if (this.CurrentAuthority.HasPermission(Permission.CanSeeSensitivePaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) * { * hasPermission = true; * } * } * else * { * // Addressed to a specific individual that is not the viewer, and it's personal. * // INVOCATION OF THIS CODE IS A BREACH OF THE POSTAL SECRET and should ONLY EVER * // be done for technical, not operational, reasons and preferably NEVER. * * if (this.CurrentAuthority.HasPermission(Permission.CanBreachPostalSecretPaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) * { * hasPermission = true; * } * }*/ } break; case DocumentType.PersonPhoto: case DocumentType.Logo: case DocumentType.Artwork: { // These are public hasPermission = true; } break; } } if (!hasPermission) { throw new Exception("Access is not allowed"); } string contentType = string.Empty; string clientFileNameLower = document.ClientFileName.ToLowerInvariant().Trim(); string serverFileNameLower = document.ServerFileName.ToLowerInvariant().Trim(); // The "Filename.Contains" here instead of "Filename.EndsWith" is because page counts are added to file names if (serverFileNameLower.EndsWith(".png") && clientFileNameLower.Contains(".pdf")) { // Converted PDF, so cut filename to raw GUID length serverFileName = serverFileName.Substring(0, serverFileName.Length - "-0001.png".Length); documentDownloadName += ".pdf"; contentType = MediaTypeNames.Application.Pdf; } else if (clientFileNameLower.EndsWith(".png")) { contentType = "image/png"; // why isn't this in MediaTypeNames? documentDownloadName += ".png"; } else if (clientFileNameLower.EndsWith(".jpg") || clientFileNameLower.EndsWith(".jpeg")) { contentType = MediaTypeNames.Image.Jpeg; documentDownloadName += ".jpg"; } else { int lastDot = clientFileNameLower.LastIndexOf('.'); if (lastDot > 0) { documentDownloadName += clientFileNameLower.Substring(lastDot); // Adds original client extension } } if (documentDownloadName.EndsWith(" 2_1") || documentDownloadName.EndsWith(" 2/1")) { // Mystery bug documentDownloadName = documentDownloadName.Substring(0, documentDownloadName.Length - 4); } string legacyMarker = string.Empty; if (!File.Exists(Document.StorageRoot + serverFileName)) { legacyMarker = "legacy/"; // for some legacy installations, all older files are placed here } // TODO: If still doesn't exist, perhaps return a friendly error image instead? if (!File.Exists(Document.StorageRoot + legacyMarker + serverFileName)) { if (!Debugger.IsAttached) // if running live; ignore FNF errors when debugging { throw new FileNotFoundException(Document.StorageRoot + legacyMarker + serverFileName); } else { Response.StatusCode = 404; Response.End(); return; } } Response.ContentType = contentType; Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + documentDownloadName + "\""); Response.TransmitFile(Document.StorageRoot + legacyMarker + serverFileName); }
private void AddAttestableItem(AttestableItems items, InboundInvoice invoice) { items.Add(new AttestableItem("I" + invoice.Identity.ToString(), invoice.Supplier, (decimal)invoice.Amount, invoice.Budget, "See scans:", "Inbound Invoice #" + invoice.Identity, invoice)); }
private static int SortInvoicesByDueDateReverse(InboundInvoice a, InboundInvoice b) { return(DateTime.Compare(b.DueDate, a.DueDate)); }
public TaskAttestationLate(InboundInvoice invoice) : base(invoice.Identity, "Invoice #" + invoice.Identity, invoice.CreatedDateTime, invoice.DueDate) { }
private static string GetTrackingDetails(object someObject) { string objectType = someObject.GetType().Name; switch (objectType) { case "Payout": Payout payout = (Payout)someObject; string result = String.Format(Resources.Pages.Ledgers.InspectLedgers_TxDetail_ThisIsPayoutX, payout.Identity) + " "; List <string> subValidations = new List <string>(); List <string> subResults = new List <string>(); if (payout.DependentExpenseClaims.Count > 0) { if (payout.DependentExpenseClaims.Count == 1) { subResults.Add("<strong>" + String.Format(Global.Financial_ExpenseClaimSpecificationWithClaimer, payout.DependentExpenseClaims[0].Identity, HttpUtility.HtmlEncode(payout.DependentExpenseClaims[0].Claimer.Name)) + ".</strong>"); } else { subResults.Add("<strong>" + String.Format(Global.Financial_ExpenseClaimsSpecificationWithClaimer, Formatting.GenerateRangeString(payout.DependentExpenseClaims.Identities), HttpUtility.HtmlEncode(payout.DependentExpenseClaims[0].Claimer.Name)) + ".</strong>"); } foreach (ExpenseClaim claim in payout.DependentExpenseClaims) { subValidations.Add(GetObjectDetails(claim)); } } if (payout.DependentCashAdvancesPayback.Count > 0) { if (payout.DependentCashAdvancesPayback.Count == 1) { subResults.Add("<strong>" + String.Format(Global.Financial_CashAdvancePaybackSpecification, payout.DependentCashAdvancesPayback[0].Identity) + ".</strong>"); } else { subResults.Add("<strong>" + String.Format(Global.Financial_CashAdvancePaybacksSpecification, Formatting.GenerateRangeString(payout.DependentExpenseClaims.Identities)) + ".</strong>"); } } if (payout.DependentCashAdvancesPayout.Count > 0) { CashAdvance advance0 = payout.DependentCashAdvancesPayout[0]; if (payout.DependentCashAdvancesPayout.Count == 1) { subResults.Add("<strong>" + String.Format(Global.Financial_CashAdvanceLongSpecificationWithRecipient, advance0.Identity, advance0.Person.Name) + ".</strong>"); } else { subResults.Add("<strong>" + String.Format(Global.Financial_CashAdvancesLongSpecificationWithRecipient, Formatting.GenerateRangeString(payout.DependentExpenseClaims.Identities), advance0.Person.Name) + ".</strong>"); } foreach (CashAdvance advance in payout.DependentCashAdvancesPayout) { subValidations.Add(GetObjectDetails(advance)); } } if (payout.DependentInvoices.Count > 0) { // Assume _one_ invoice InboundInvoice invoice = payout.DependentInvoices[0]; subResults.Add("<strong>" + String.Format( Global.Financial_InboundInvoiceSpecificationWithSender, invoice.Identity, invoice.Supplier) + "</strong>"); subValidations.Add(GetObjectDetails(invoice)); } if (payout.DependentSalariesNet.Count > 0) { // Assume one salary Salary salary = payout.DependentSalariesNet[0]; subResults.Add("<strong>" + String.Format(Global.Financial_SalaryDualSpecificationWithRecipient, salary.Identity, salary.PayoutDate, HttpUtility.HtmlEncode(salary.PayrollItem.PersonCanonical)) + "</strong>"); subValidations.Add(GetObjectDetails(salary)); } if (payout.DependentSalariesTax.Count > 0) { Salary salary0 = payout.DependentSalariesTax[0]; if (payout.DependentSalariesTax.Count == 1) { subResults.Add("<strong>" + String.Format(Global.Financial_SalaryTaxDualSpecification, salary0.Identity, salary0.PayoutDate) + "</strong>"); } else { subResults.Add("<strong>" + String.Format(Global.Financial_SalariesTaxSpecification, salary0.PayoutDate) + "</strong>"); } } result += String.Join(" " + Resources.Pages.Ledgers.InspectLedgers_TxDetail_CombinedWith + " ", subResults) + ". " + String.Format(Resources.Pages.Ledgers.InspectLedgers_TxDetail_PaidOutBy, payout.CreatedByPerson.Canonical); return("<p>" + result + "</p><p>" + String.Join("</p><p>", subValidations) + "</p>"); case "ExpenseClaim": case "CashAdvance": case "InboundInvoice": case "Salary": return("<p>" + GetObjectDetails((IHasIdentity)someObject) + "</p>"); default: return("Unimplemented dependency type: " + objectType); } }
protected void ButtonCreate_Click(object sender, EventArgs e) // TODO { // The data has been validated client-side already. We'll throw unfriendly exceptions if invalid data is passed here. // People who choose to disable JavaScript and then submit bad input almost deserve to be hurt. double amount = Double.Parse(this.TextAmount.Text, NumberStyles.Number); // parses in current culture - intentional Int64 amountCents = (Int64)amount * 100; string description = this.TextPurpose.Text; DateTime dueDate = DateTime.Parse(this.TextDueDate.Text); FinancialAccount budget = FinancialAccount.FromIdentity(Int32.Parse(this.Request.Form["DropBudgets"])); // sanity check if (budget.Organization.Identity != CurrentOrganization.Identity) { throw new InvalidOperationException("Budget-organization mismatch; won't file expense claim"); } // Get documents; check that documents have been uploaded Documents documents = Documents.RecentFromDescription(this.FileUpload.GuidString); if (documents.Count == 0) { throw new InvalidOperationException("No documents uploaded"); } InboundInvoice invoice = InboundInvoice.Create(CurrentOrganization, dueDate, amountCents, budget, this.TextSupplier.Text, this.TextPurpose.Text, this.TextAccount.Text, string.Empty, this.TextReference.Text, CurrentUser); foreach (int tagSetId in _tagSetIds) { string selectedTagString = this.Request.Form["DropTags" + tagSetId.ToString(CultureInfo.InvariantCulture)]; if (!String.IsNullOrEmpty(selectedTagString)) { int selectedTagType = Int32.Parse(selectedTagString); if (selectedTagType != 0) { invoice.FinancialTransaction.CreateTag( FinancialTransactionTagType.FromIdentity(selectedTagType), CurrentUser); } } } documents.SetForeignObjectForAll(invoice); // Display success message this.LiteralSuccess.Text = HttpUtility.UrlEncode(String.Format(Resources.Pages.Financial.CreateInboundInvoice_SuccessMessage, invoice.Identity)).Replace("+", "%20"); // Reset all fields for next invoice this.FileUpload.Reset(); this.TextSupplier.Text = String.Empty; this.TextAccount.Text = String.Empty; this.TextPurpose.Text = String.Empty; this.TextReference.Text = String.Empty; this.TextAmount.Text = 0.ToString("N2"); this.TextDueDate.Text = DateTime.Today.AddDays(30).ToShortDateString(); // Use current culture // the easyUI combo fields should reset automatically on form submission unless we explicitly reconstruct this.TextSupplier.Focus(); }
public static PaymentTransferInfoResult GetPaymentTransferInfo(string prototypeId) { AuthenticationData authData = GetAuthenticationDataAndCulture(); // TODO: Authentication check string[] payoutComponents = prototypeId.Split('|'); if (payoutComponents.Length < 1) { throw new InvalidOperationException("Prototype ID can't be empty"); } PaymentTransferInfo info = new PaymentTransferInfo(); // Some payouts are composites of multiple objects, but all these will share the same // payout data, so we can safely use just the first object to determine payment // target information // // with one exception -- we need to determine the amount by adding all the objects // together, if applicable DateTime paymentDueBy = Constants.DateTimeLow; switch (Char.ToUpperInvariant(payoutComponents[0][0])) { case 'C': // expense claim info = PaymentTransferInfo.FromObject( ExpenseClaim.FromIdentity(Int32.Parse(payoutComponents[0].Substring(1))), new Money(GetSumCentsTotal(prototypeId), authData.CurrentOrganization.Currency)); break; case 'A': // cash advance (payout or payback, same logic either way) info = PaymentTransferInfo.FromObject( CashAdvance.FromIdentity(Int32.Parse(payoutComponents[0].Substring(1))), new Money(GetSumCentsTotal(prototypeId), authData.CurrentOrganization.Currency)); break; case 'S': // salary Salary salary = Salary.FromIdentity(Int32.Parse(payoutComponents[0].Substring(1))); info = PaymentTransferInfo.FromObject(salary); paymentDueBy = salary.PayoutDate; break; case 'I': // inbound invoice InboundInvoice invoice = InboundInvoice.FromIdentity(Int32.Parse(payoutComponents[0].Substring(1))); info = PaymentTransferInfo.FromObject(invoice); paymentDueBy = invoice.DueDate; break; default: throw new NotImplementedException("Unrecognized payment type"); } PaymentTransferInfoResult result = new PaymentTransferInfoResult { Success = true, CurrencyAmount = info.CurrencyAmount, DisplayMessage = string.Empty, Recipient = info.Recipient, Reference = info.Reference, TransferMethod = info.LocalizedPaymentMethodName }; if (paymentDueBy < Constants.DateTimeLowThreshold) { result.DueBy = Resources.Global.Global_ASAP; } else { DateTime nowUtc = DateTime.UtcNow; if (paymentDueBy.Year != nowUtc.Year || paymentDueBy < nowUtc.AddMonths(-3)) { result.DueBy = paymentDueBy.ToString(Resources.Global.Global_DateFormatLongSansWeekday); } else { result.DueBy = paymentDueBy.ToString(Resources.Global.Global_DateFormatLongDateMonth); } if (paymentDueBy < nowUtc.AddDays(-1)) { result.DueBy += " - " + Resources.Pages.Financial.PayOutMoney_PaymentLate; } } List <string> listTransferMethodLabels = new List <string>(); List <string> listTransferMethodData = new List <string>(); foreach (string label in info.LocalizedPaymentInformation.Keys) { listTransferMethodLabels.Add(HttpUtility.HtmlEncode(label)); listTransferMethodData.Add(HttpUtility.HtmlEncode(info.LocalizedPaymentInformation [label])); } result.TransferMethodLabels = listTransferMethodLabels.ToArray(); result.TransferMethodData = listTransferMethodData.ToArray(); result.OcrData = info.OcrData; // can be null and that's ok return(result); }
protected void ButtonSubmitClaim_Click(object sender, EventArgs e) { // First, if there's an upload that the user hasn't processed, process it first. if (this.Upload.UploadedFiles.Count > 0) { ProcessUpload(); } // If args were invalid, abort if (!Page.IsValid) { return; } // Read the form data string supplier = this.TextSupplier.Text; string bankAccount = this.TextAccount.Text; int temporaryId = Int32.Parse(this.TemporaryDocumentIdentity.Text); int organizationId = Int32.Parse(this.DropOrganizations.SelectedValue); Organization org = Organization.FromIdentity(organizationId); Int64 amountCents = (Int64)(Double.Parse(this.TextAmount.Text, new CultureInfo("sv-SE")) * 100); FinancialAccount budget = this.DropBudgets.SelectedFinancialAccount; DateTime dueDate = (DateTime)this.DatePicker.SelectedDate; string ocr = string.Empty; string invoiceNumber = string.Empty; if (this.DropReferenceType.SelectedValue == "OCR") { ocr = this.TextReference.Text; } else { invoiceNumber = this.TextReference.Text; } // Create the invoice record InboundInvoice newInvoice = InboundInvoice.Create(org, dueDate, amountCents, budget, supplier, bankAccount, ocr, invoiceNumber, _currentUser); // Move documents to the new invoice Documents.ForObject(new TemporaryIdentity(temporaryId)).SetForeignObjectForAll(newInvoice); // Create the event for PirateBot-Mono to send off mails Activizr.Logic.Support.PWEvents.CreateEvent(EventSource.PirateWeb, EventType.InboundInvoiceReceived, _currentUser.Identity, organizationId, 1, _currentUser.Identity, newInvoice.Identity, string.Empty); Page.ClientScript.RegisterStartupScript(typeof(Page), "OkMessage", @"alert ('The invoice was registered.');", true); // Clear the text fields this.TextSupplier.Text = string.Empty; this.TextAccount.Text = string.Empty; this.TextReference.Text = string.Empty; this.DropReferenceType.SelectedIndex = 0; this.TemporaryDocumentIdentity.Text = "0"; this.TextAmount.Text = "0,00"; // TODO: LOCALIZE BY CULTURE // PopulateGrid(); }
protected void Page_Load(object sender, EventArgs e) { string documentIdString = Request.QueryString["DocId"]; int documentId = Int32.Parse(documentIdString); Document document = Document.FromIdentity(documentId); //Orgid is needed to safely verify permission int orgId = 0; // initialize to invalid bool hasPermission = false; switch (document.DocumentType) { case DocumentType.FinancialTransaction: { /* * //TODO: Get the orgId from foreign object * if (this.CurrentAuthority.HasPermission(Permission.CanSeeEconomyDetails, orgId, -1, Authorization.Flag.ExactOrganization)) * { * hasPermission = true; * }*/ } break; case DocumentType.ExpenseClaim: case DocumentType.InboundInvoice: { int budgetId = 0; if (document.DocumentType == DocumentType.ExpenseClaim) { ExpenseClaim claim = (ExpenseClaim)document.ForeignObject; orgId = claim.Budget.OrganizationId; budgetId = claim.BudgetId; } else { InboundInvoice invoice = (InboundInvoice)document.ForeignObject; orgId = invoice.Budget.OrganizationId; budgetId = invoice.BudgetId; } FinancialAccount budget = FinancialAccount.FromIdentity(budgetId); if (budget.OwnerPersonId == this.CurrentUser.Identity || budget.OwnerPersonId == 0) { hasPermission = true; break; } // TODO: Security leak - check CurrentOrganization against Document's org if (this.CurrentUser.HasAccess(new Access(CurrentOrganization, AccessAspect.Financials, AccessType.Write))) { hasPermission = true; break; } /* * if (this.CurrentAuthority.HasPermission(Permission.CanSeeEconomyDetails, orgId, -1, Authorization.Flag.ExactOrganization)) * { * hasPermission = true; * break; * }*/ break; } case DocumentType.PaperLetter: { PaperLetter letter = (PaperLetter)document.ForeignObject; if (letter.Recipient.Identity == this.CurrentUser.Identity) { hasPermission = true; // A letter to the viewer } /* * // Otherwise, are there overriding permissions, if not addressed to him/her? * * else if (!letter.Personal) * { * // Unpersonal paper letter, like a rally permit. Note that bank statements should * // be considered personal as they contain donors' information in the transaction info. * * if (this.CurrentAuthority.HasPermission(Permission.CanSeeInsensitivePaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) * { * hasPermission = true; * } * } * else if (letter.ToPersonId == 0) * { * // Addressed to the organization, not to a specific person, but still personal. * // Typical examples include political inquiries from private citizens written on * // paper. * * if (this.CurrentAuthority.HasPermission(Permission.CanSeeSensitivePaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) * { * hasPermission = true; * } * } * else * { * // Addressed to a specific individual that is not the viewer, and it's personal. * // INVOCATION OF THIS CODE IS A BREACH OF THE POSTAL SECRET and should ONLY EVER * // be done for technical, not operational, reasons and preferably NEVER. * * if (this.CurrentAuthority.HasPermission(Permission.CanBreachPostalSecretPaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) * { * hasPermission = true; * } * }*/ } break; case DocumentType.PersonPhoto: { // These are public hasPermission = true; } break; } if (!hasPermission) { throw new Exception("Access is not allowed"); } string contentType = string.Empty; string fileNameLower = document.ClientFileName.ToLowerInvariant(); if (fileNameLower.EndsWith(".pdf")) { contentType = MediaTypeNames.Application.Pdf; } else if (fileNameLower.EndsWith(".png")) { contentType = "image/png"; // why isn't this in MediaTypeNames? } else if (fileNameLower.EndsWith(".jpg")) { contentType = MediaTypeNames.Image.Jpeg; } string legacyMarker = string.Empty; if (!File.Exists(StorageRoot + document.ServerFileName)) { legacyMarker = "legacy/"; // for some legacy installations, all older files are placed here } // TODO: If still doesn't exist, perhaps return a friendly error image instead? if (!File.Exists(StorageRoot + legacyMarker + document.ServerFileName)) { throw new FileNotFoundException(StorageRoot + legacyMarker + document.ServerFileName); } Response.ContentType = contentType + "; filename=" + document.ClientFileName; Response.TransmitFile(StorageRoot + legacyMarker + document.ServerFileName); }
protected void ButtonAttest_Click(object sender, EventArgs e) { List <string> identityStrings = new List <string>(); foreach (string indexString in this.GridAttestables.SelectedIndexes) { int index = Int32.Parse(indexString); string itemIdentityString = (string)this.GridAttestables.MasterTableView.DataKeyValues[index]["Identity"]; int itemIdentity = Int32.Parse(itemIdentityString.Substring(1)); // Mark items as attested switch (itemIdentityString[0]) { case 'E': ExpenseClaim claim = ExpenseClaim.FromIdentity(itemIdentity); if (attestationRights.ContainsKey(claim.BudgetId)) { claim.Attest(_currentUser); Activizr.Logic.Support.PWEvents.CreateEvent( EventSource.PirateWeb, EventType.ExpenseAttested, _currentUser.Identity, claim.OrganizationId, 0, claim.ClaimingPersonId, claim.Identity, string.Empty); } break; case 'I': InboundInvoice invoice = InboundInvoice.FromIdentity(itemIdentity); if (attestationRights.ContainsKey(invoice.BudgetId)) { invoice.Attest(_currentUser); Activizr.Logic.Support.PWEvents.CreateEvent( EventSource.PirateWeb, EventType.InboundInvoiceAttested, _currentUser.Identity, invoice.OrganizationId, 0, 0, invoice.Identity, string.Empty); } break; case 'S': Salary salary = Salary.FromIdentity(itemIdentity); // Mark as attested bool mayAttest = false; if (attestationRights.ContainsKey(salary.PayrollItem.BudgetId) && salary.PayrollItem.PersonId != _currentUser.Identity) { mayAttest = true; } if (salary.PayrollItem.ReportsToPersonId == _currentUser.Identity) { mayAttest = true; } if (mayAttest) { salary.Attest(_currentUser); Activizr.Logic.Support.PWEvents.CreateEvent( EventSource.PirateWeb, EventType.SalaryAttested, _currentUser.Identity, salary.PayrollItem.OrganizationId, 0, 0, salary.Identity, string.Empty); } break; case 'P': Parley parley = Parley.FromIdentity(itemIdentity); if (attestationRights.ContainsKey(parley.BudgetId)) { parley.Attest(_currentUser); } break; } } this.GridAttestables.Rebind(); }
private static int SortGridInvoices(InboundInvoice invoice1, InboundInvoice invoice2) { return(DateTime.Compare(invoice1.CreatedDateTime, invoice2.CreatedDateTime)); }
protected void Page_Load(object sender, EventArgs e) { string documentIdString = Request.QueryString["DocumentId"]; int documentId = Int32.Parse(documentIdString); Document document = Document.FromIdentity(documentId); //Orgid is needed to safely verify permission int orgId = Organization.PPSEid; bool hasPermission = false; switch (document.DocumentType) { case DocumentType.FinancialTransaction: { //TODO: Get the orgId from foreign object if (_authority.HasPermission(Permission.CanSeeEconomyDetails, orgId, -1, Authorization.Flag.ExactOrganization)) { hasPermission = true; } } break; case DocumentType.ExpenseClaim: case DocumentType.InboundInvoice: { int budgetId = 0; if (document.DocumentType == DocumentType.ExpenseClaim) { ExpenseClaim claim = (ExpenseClaim)document.ForeignObject; orgId = claim.Budget.OrganizationId; budgetId = claim.BudgetId; } else { InboundInvoice invoice = (InboundInvoice)document.ForeignObject; orgId = invoice.Budget.OrganizationId; budgetId = invoice.BudgetId; } if (_authority.HasPermission(Permission.CanSeeEconomyDetails, orgId, -1, Authorization.Flag.ExactOrganization)) { hasPermission = true; break; } if (FinancialAccount.FromIdentity(budgetId).OwnerPersonId == _currentUser.Identity) { hasPermission = true; } break; } case DocumentType.PaperLetter: { PaperLetter letter = (PaperLetter)document.ForeignObject; if (letter.Recipient.Identity == _currentUser.Identity) { hasPermission = true; // A letter to the viewer } // Otherwise, are there overriding permissions, if not addressed to him/her? else if (!letter.Personal) { // Unpersonal paper letter, like a rally permit. Note that bank statements should // be considered personal as they contain donors' information in the transaction info. if (_authority.HasPermission(Permission.CanSeeInsensitivePaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) { hasPermission = true; } } else if (letter.ToPersonId == 0) { // Addressed to the organization, not to a specific person, but still personal. // Typical examples include political inquiries from private citizens written on // paper. if (_authority.HasPermission(Permission.CanSeeSensitivePaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) { hasPermission = true; } } else { // Addressed to a specific individual that is not the viewer, and it's personal. // INVOCATION OF THIS CODE IS A BREACH OF THE POSTAL SECRET and should ONLY EVER // be done for technical, not operational, reasons and preferably NEVER. if (_authority.HasPermission(Permission.CanBreachPostalSecretPaperLetters, letter.OrganizationId, -1, Authorization.Flag.Default)) { hasPermission = true; } } } break; case DocumentType.PersonPhoto: { // These are public hasPermission = true; } break; } if (!hasPermission) { throw new Exception("Access is not allowed"); } string serverPath = @"C:\Data\Uploads\PirateWeb"; // TODO: Read from web.config string contentType = string.Empty; if (document.ServerFileName.EndsWith(".pdf")) { contentType = MediaTypeNames.Application.Pdf; } else if (document.ServerFileName.EndsWith(".png")) { contentType = "image/png"; // why isn't this in MediaTypeNames? } else if (document.ServerFileName.EndsWith(".jpg")) { contentType = MediaTypeNames.Image.Jpeg; } Response.ContentType = contentType + "; filename=" + document.ClientFileName; Response.TransmitFile(serverPath + Path.DirectorySeparatorChar + document.ServerFileName); }
protected void GridAttestables_ItemCreated(object sender, GridItemEventArgs e) { if (e.Item is GridDataItem) { AttestableItem item = (AttestableItem)e.Item.DataItem; if (item == null) { return; } // Set Description field Label description = (Label)e.Item.FindControl("LabelDescription"); description.Text = item.Description; if (item.Item is InboundInvoice) { InboundInvoice invoice = item.Item as InboundInvoice; Controls_v4_DocumentList docList = (Controls_v4_DocumentList)e.Item.FindControl("DocList"); docList.Documents = invoice.Documents; docList.Visible = true; description.Visible = false; HyperLink editLink = (HyperLink)e.Item.FindControl("LinkEdit"); editLink.Attributes["href"] = "#"; editLink.Attributes["onclick"] = String.Format("return ShowInboundInvoiceForm('{0}','{1}');", invoice.Identity, e.Item.ItemIndex); } else if (item.Item is ExpenseClaim) { ExpenseClaim claim = item.Item as ExpenseClaim; HyperLink editLink = (HyperLink)e.Item.FindControl("LinkEdit"); editLink.Attributes["href"] = "#"; editLink.Attributes["onclick"] = String.Format("return ShowExpenseClaimForm('{0}','{1}');", claim.Identity, e.Item.ItemIndex); } // Calculate or retrieve remaining budget if (!budgetsRemainingLookup.ContainsKey(item.Budget.Identity)) { int year = DateTime.Today.Year; // HACK: Should be item's date Int64 budgetCents = (Int64)item.Budget.GetBudget(year) * 100; Int64 centsUsed = item.Budget.GetDeltaCents(new DateTime(year, 1, 1), new DateTime(year + 1, 1, 1)); decimal budgetRemaining = (-budgetCents - centsUsed) / 100.0m; budgetsRemainingLookup[item.Budget.Identity] = budgetRemaining; } Label labelBudgetRemaining = (Label)e.Item.FindControl("LabelBudgetRemaining"); labelBudgetRemaining.Text = String.Format("{0:N2}", budgetsRemainingLookup[item.Budget.Identity]); } // Set the images for the status indicators. return; // fix later if (e.Item is GridDataItem) { ExpenseClaim claim = (ExpenseClaim)e.Item.DataItem; if (claim == null) { return; } Label labelBudgetYear = (Label)e.Item.FindControl("LabelBudgetYear"); if (claim.BudgetId == 0) { labelBudgetYear.Text = "UNBUDGETED!"; } else { labelBudgetYear.Text = claim.Budget.Name + ", " + claim.BudgetYear.ToString(); } HyperLink editLink = (HyperLink)e.Item.FindControl("LinkEdit"); editLink.Attributes["href"] = "#"; editLink.Attributes["onclick"] = String.Format("return ShowExpenseClaimForm('{0}','{1}');", claim.Identity, e.Item.ItemIndex); } }
protected void ButtonCreate_Click(object sender, EventArgs e) // TODO { // The data has been validated client-side already. We'll throw unfriendly exceptions if invalid data is passed here. // People who choose to disable JavaScript and then submit bad input almost deserve to be hurt. Int64 amountCents = this.CurrencyAmount.Cents; Int64 amountVatCents = this.CurrencyVat.Cents; string description = this.TextPurpose.Text; DateTime dueDate = DateTime.Parse(this.TextDueDate.Text); FinancialAccount budget = this.ComboBudgets.SelectedAccount; // sanity check if (budget.Organization.Identity != CurrentOrganization.Identity) { throw new InvalidOperationException("Budget-organization mismatch; won't file expense claim"); } // Get documents; check that documents have been uploaded Documents documents = Documents.RecentFromDescription(this.FileUpload.GuidString); if (documents.Count == 0) { throw new InvalidOperationException("No documents uploaded"); } InboundInvoice invoice = InboundInvoice.Create(CurrentOrganization, dueDate, amountCents, amountVatCents, budget, this.TextSupplier.Text, this.TextPurpose.Text, this.TextAccount.Text, string.Empty, this.TextReference.Text, CurrentUser); foreach (int tagSetId in this._tagSetIds) { string selectedTagString = Request.Form["DropTags" + tagSetId.ToString(CultureInfo.InvariantCulture)]; if (!String.IsNullOrEmpty(selectedTagString)) { int selectedTagType = Int32.Parse(selectedTagString); if (selectedTagType != 0) { invoice.FinancialTransaction.CreateTag( FinancialTransactionTagType.FromIdentity(selectedTagType), CurrentUser); } } } documents.SetForeignObjectForAll(invoice); // If amounts were in a different currency, record the native values for proper payment if (this.CurrencyAmount.NonPresentationCurrencyUsed) { Money currencyEntered = this.CurrencyAmount.NonPresentationCurrencyAmount; invoice.NativeCurrencyAmount = currencyEntered; } // Display success message this._invoiceId = invoice.OrganizationSequenceId; // a property returns the localized string // Reset all fields for next invoice this.FileUpload.Reset(); this.TextSupplier.Text = String.Empty; this.TextAccount.Text = String.Empty; this.TextPurpose.Text = String.Empty; this.TextReference.Text = String.Empty; this.CurrencyAmount.Cents = 0; this.CurrencyVat.Cents = 0; this.TextDueDate.Text = DateTime.Today.AddDays(30).ToShortDateString(); // Use current culture // the easyUI combo fields should reset automatically on form submission unless we explicitly reconstruct this.TextSupplier.Focus(); }
private static AjaxCallResult HandleAttestationDeattestation(string identifier, AttestationMode mode) { AuthenticationData authData = GetAuthenticationDataAndCulture(); IApprovable approvableItem; string attestedTemplate; string deattestedTemplate; char costType = identifier[0]; int itemId = Int32.Parse(identifier.Substring(1)); Int64 amountCents; string beneficiary; string result; // Find the item we are attesting or deattesting switch (costType) { case 'A': // Case advance CashAdvance advance = CashAdvance.FromIdentity(itemId); if (advance.OrganizationId != authData.CurrentOrganization.Identity) { throw new InvalidOperationException("Called to attest out-of-org line item"); } if (advance.Budget.OwnerPersonId != authData.CurrentUser.Identity && advance.Budget.OwnerPersonId != Person.NobodyId) { throw new SecurityException("Called without attestation privileges"); } approvableItem = advance; attestedTemplate = Resources.Pages.Financial.AttestCosts_AdvanceAttested; deattestedTemplate = Resources.Pages.Financial.AttestCosts_AdvanceDeattested; beneficiary = advance.Person.Name; amountCents = advance.AmountCents; break; case 'E': // Expense claim ExpenseClaim expense = ExpenseClaim.FromIdentity(itemId); if (expense.OrganizationId != authData.CurrentOrganization.Identity) { throw new InvalidOperationException("Called to attest out-of-org line item"); } if (expense.Budget.OwnerPersonId != authData.CurrentUser.Identity && expense.Budget.OwnerPersonId != Person.NobodyId) { throw new SecurityException("Called without attestation privileges"); } approvableItem = expense; attestedTemplate = Resources.Pages.Financial.AttestCosts_ExpenseAttested; deattestedTemplate = Resources.Pages.Financial.AttestCosts_ExpenseDeattested; beneficiary = expense.Claimer.Name; amountCents = expense.AmountCents; break; case 'I': // Inbound invoice InboundInvoice invoice = InboundInvoice.FromIdentity(itemId); if (invoice.OrganizationId != authData.CurrentOrganization.Identity) { throw new InvalidOperationException("Called to attest out-of-org line item"); } if (invoice.Budget.OwnerPersonId != authData.CurrentUser.Identity && invoice.Budget.OwnerPersonId != Person.NobodyId) { throw new SecurityException("Called without attestation privileges"); } approvableItem = invoice; attestedTemplate = Resources.Pages.Financial.AttestCosts_InvoiceAttested; deattestedTemplate = Resources.Pages.Financial.AttestCosts_InvoiceDeattested; beneficiary = invoice.Supplier; amountCents = invoice.AmountCents; break; case 'S': // Salary payout Salary salary = Salary.FromIdentity(itemId); if (salary.PayrollItem.OrganizationId != authData.CurrentOrganization.Identity) { throw new InvalidOperationException("Called to attest out-of-org line item"); } if (salary.PayrollItem.Budget.OwnerPersonId != authData.CurrentUser.Identity && salary.PayrollItem.Budget.OwnerPersonId != Person.NobodyId) { throw new SecurityException("Called without attestation privileges"); } approvableItem = salary; attestedTemplate = Resources.Pages.Financial.AttestCosts_SalaryAttested; deattestedTemplate = Resources.Pages.Financial.AttestCosts_SalaryDeattested; beneficiary = salary.PayrollItem.PersonCanonical; amountCents = salary.GrossSalaryCents + salary.AdditiveTaxCents; break; case 'P': // Parley, aka Conference Parley parley = Parley.FromIdentity(itemId); if (parley.OrganizationId != authData.CurrentOrganization.Identity) { throw new InvalidOperationException("Called to attest out-of-org line item"); } if (parley.Budget.OwnerPersonId != authData.CurrentUser.Identity && parley.Budget.OwnerPersonId != Person.NobodyId) { throw new SecurityException("Called without attestation privileges"); } approvableItem = parley; attestedTemplate = Resources.Pages.Financial.AttestCosts_ParleyAttested; deattestedTemplate = Resources.Pages.Financial.AttestCosts_ParleyDeattested; beneficiary = parley.Person.Name; amountCents = parley.BudgetCents; break; default: throw new InvalidOperationException("Unknown Cost Type in HandleAttestationDeattestation: \"" + identifier + "\""); } // Finally, attest or deattest if (mode == AttestationMode.Attestation) { Int64 budgetRemaining = approvableItem.Budget.GetBudgetCentsRemaining(); result = string.Empty; if (amountCents > -budgetRemaining) { if ( authData.Authority.HasAccess(new Access(authData.CurrentOrganization, AccessAspect.Administration))) { // Admin rights, so allow (forced) overdraft // Unless budget was nonzero and allocated, set protest message if (approvableItem.Budget.Owner != null || approvableItem.Budget.GetBudgetCents() != 0) { result = Resources.Pages.Financial.AttestCosts_Overdrafted + " "; } } else { // Do not allow overdraft return(new AjaxCallResult { DisplayMessage = Resources.Pages.Financial.AttestCosts_OutOfBudget, Success = false }); } } approvableItem.Approve(authData.CurrentUser); result += string.Format(attestedTemplate, itemId, beneficiary, authData.CurrentOrganization.Currency.Code, amountCents / 100.0); } else if (mode == AttestationMode.Deattestation) { approvableItem.RetractApproval(authData.CurrentUser); result = string.Format(deattestedTemplate, itemId, beneficiary, authData.CurrentOrganization.Currency.Code, amountCents / 100.0); } else { throw new InvalidOperationException("Unknown Approval Mode: " + mode); } FinancialAccount.ClearApprovalAdjustmentsCache(authData.CurrentOrganization); return(new AjaxCallResult { DisplayMessage = result, Success = true }); }
private static string HandleAttestationDeattestation(string identifier, AttestationMode mode) { AuthenticationData authData = GetAuthenticationDataAndCulture(); IAttestable attestableItem = null; string attestedTemplate = string.Empty; string deattestedTemplate = string.Empty; char costType = identifier[0]; int itemId = Int32.Parse(identifier.Substring(1)); Int64 amountCents; string beneficiary = string.Empty; string result = string.Empty; // Find the item we are attesting or deattesting switch (costType) { case 'A': // Case advance CashAdvance advance = CashAdvance.FromIdentity(itemId); if (advance.OrganizationId != authData.CurrentOrganization.Identity) { throw new InvalidOperationException("Called to attest out-of-org line item"); } if (advance.Budget.OwnerPersonId != authData.CurrentUser.Identity && advance.Budget.OwnerPersonId != Person.NobodyId) { throw new SecurityAccessDeniedException("Called without attestation privileges"); } attestableItem = advance; attestedTemplate = Resources.Pages.Financial.AttestCosts_AdvanceAttested; deattestedTemplate = Resources.Pages.Financial.AttestCosts_AdvanceDeattested; beneficiary = advance.Person.Name; amountCents = advance.AmountCents; break; case 'E': // Expense claim ExpenseClaim expense = ExpenseClaim.FromIdentity(itemId); if (expense.OrganizationId != authData.CurrentOrganization.Identity) { throw new InvalidOperationException("Called to attest out-of-org line item"); } if (expense.Budget.OwnerPersonId != authData.CurrentUser.Identity && expense.Budget.OwnerPersonId != Person.NobodyId) { throw new SecurityAccessDeniedException("Called without attestation privileges"); } attestableItem = expense; attestedTemplate = Resources.Pages.Financial.AttestCosts_ExpenseAttested; deattestedTemplate = Resources.Pages.Financial.AttestCosts_ExpenseDeattested; beneficiary = expense.Claimer.Name; amountCents = expense.AmountCents; break; case 'I': // Inbound invoice InboundInvoice invoice = InboundInvoice.FromIdentity(itemId); if (invoice.OrganizationId != authData.CurrentOrganization.Identity) { throw new InvalidOperationException("Called to attest out-of-org line item"); } if (invoice.Budget.OwnerPersonId != authData.CurrentUser.Identity && invoice.Budget.OwnerPersonId != Person.NobodyId) { throw new SecurityAccessDeniedException("Called without attestation privileges"); } attestableItem = invoice; attestedTemplate = Resources.Pages.Financial.AttestCosts_InvoiceAttested; deattestedTemplate = Resources.Pages.Financial.AttestCosts_InvoiceDeattested; beneficiary = invoice.Supplier; amountCents = invoice.AmountCents; break; case 'S': // Salary payout Salary salary = Salary.FromIdentity(itemId); if (salary.PayrollItem.OrganizationId != authData.CurrentOrganization.Identity) { throw new InvalidOperationException("Called to attest out-of-org line item"); } if (salary.PayrollItem.Budget.OwnerPersonId != authData.CurrentUser.Identity && salary.PayrollItem.Budget.OwnerPersonId != Person.NobodyId) { throw new SecurityAccessDeniedException("Called without attestation privileges"); } attestableItem = salary; attestedTemplate = Resources.Pages.Financial.AttestCosts_SalaryAttested; deattestedTemplate = Resources.Pages.Financial.AttestCosts_SalaryDeattested; beneficiary = salary.PayrollItem.PersonCanonical; amountCents = salary.GrossSalaryCents; break; case 'P': // Parley, aka Conference Parley parley = Parley.FromIdentity(itemId); if (parley.OrganizationId != authData.CurrentOrganization.Identity) { throw new InvalidOperationException("Called to attest out-of-org line item"); } if (parley.Budget.OwnerPersonId != authData.CurrentUser.Identity && parley.Budget.OwnerPersonId != Person.NobodyId) { throw new SecurityAccessDeniedException("Called without attestation privileges"); } attestableItem = parley; attestedTemplate = Resources.Pages.Financial.AttestCosts_ParleyAttested; deattestedTemplate = Resources.Pages.Financial.AttestCosts_ParleyDeattested; beneficiary = parley.Person.Name; amountCents = parley.BudgetCents; break; default: throw new InvalidOperationException("Unknown Cost Type in HandleAttestationDeattestation: \"" + identifier + "\""); } // Finally, attest or deattest if (mode == AttestationMode.Attestation) { attestableItem.Attest(authData.CurrentUser); result = string.Format(attestedTemplate, itemId, beneficiary, authData.CurrentOrganization.Currency.Code, amountCents / 100.0); } else if (mode == AttestationMode.Deattestation) { attestableItem.Deattest(authData.CurrentUser); result = string.Format(deattestedTemplate, itemId, beneficiary, authData.CurrentOrganization.Currency.Code, amountCents / 100.0); } else { throw new InvalidOperationException("Unknown Attestation Mode: " + mode); } return(result); }
private string GetProgressTicks(InboundInvoice invoice) { StringBuilder ticks = new StringBuilder(512); // The first tick is whether the invoice was even received yet, in anticipation of Purchase Orders // For now, it is always filled ticks.Append(_greenTick); // The second tick is whether the invoice has been attested if (invoice.Attested) { ticks.Append(_greenTick); // Is it also paid? if (invoice.PaidOut) { ticks.Append(_greenTick); // Is the payout closed, that is, registered closed with the bank? try { if (Payout.FromDependency(invoice).Open) { ticks.Append(_emptyTick); } else { ticks.Append(_greenTick); } } catch (ArgumentException) { // There was no payout; the invoice was closed another way. ticks.Append(_redCross); } } else { // attested but not paid yet ticks.Append(_emptyTick + _emptyTick); } } else // not attested { // Is the invoice closed? If so, it was denied entirely if (invoice.Open) { ticks.Append(_emptyTick + _emptyTick + _emptyTick); } else { // Closed, and therefore it was denied attestation ticks.Append(_redCross + _filler + _filler); } } return(ticks.ToString()); }