123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Windows;
- using System.Windows.Controls;
- using Comal.Classes;
- using InABox.Clients;
- using InABox.Core;
- using InABox.DynamicGrid;
- using InABox.Reports;
- using InABox.Reports.Common;
- using InABox.WPF;
- namespace PRSDesktop
- {
- public class CustomerInvoices : DynamicDataGrid<Invoice>, IPanel<Invoice>
- {
- private readonly List<Tuple<Guid, string, string>> emails = new();
- private bool Outstanding = true;
- public CustomerInvoices()
- {
- Options.AddRange(DynamicGridOption.RecordCount, DynamicGridOption.FilterRows, DynamicGridOption.SelectColumns,
- DynamicGridOption.MultiSelect);
- HiddenColumns.Add(x => x.Number);
- HiddenColumns.Add(x => x.IncTax);
- HiddenColumns.Add(x => x.CustomerLink.ID);
- HiddenColumns.Add(x => x.CustomerLink.Name);
- HiddenColumns.Add(x => x.CustomerLink.Contact);
- HiddenColumns.Add(x => x.CustomerLink.Email);
- HiddenColumns.Add(x => x.JobLink.ID);
- HiddenColumns.Add(x => x.JobLink.JobNumber);
- HiddenColumns.Add(x => x.JobLink.Name);
- HiddenColumns.Add(x => x.Balance);
- AddButton("Email", PRSDesktop.Resources.email.AsBitmapImage(), DoEmailInvoice);
- AddButton("Show All", PRSDesktop.Resources.view.AsBitmapImage(), ToggleView);
- }
- public bool IsReady { get; set; }
- public Dictionary<string, object[]> Selected()
- {
- return new Dictionary<string, object[]> { { typeof(Invoice).EntityName(), SelectedRows } };
- }
- public event DataModelUpdateEvent OnUpdateDataModel;
- public void CreateToolbarButtons(IPanelHost host)
- {
- //
- }
- public string SectionName => "Customer Invoices";
- public DataModel DataModel(Selection selection)
- {
- var ids = ExtractValues(x => x.ID, selection).ToArray();
- return new InvoiceDataModel(new Filter<Invoice>(x => x.ID).InList(ids));
- }
- public bool Focus()
- {
- return true;
- }
- public void Refresh()
- {
- Refresh(false, true);
- }
- public void Setup()
- {
- Refresh(true, false);
- }
- public void Shutdown()
- {
- }
- public void Heartbeat(TimeSpan time)
- {
- }
- private bool ToggleView(Button sender, CoreRow[] rows)
- {
- Outstanding = !Outstanding;
- UpdateButton(sender, PRSDesktop.Resources.view.AsBitmapImage(), Outstanding ? "Show All" : "Outstanding");
- return true;
- }
- private List<string> CreateInvoiceFiles(CoreRow[] rows)
- {
- Progress.SetMessage("Loading Invoice Template");
- emails.Clear();
- var section = SectionName;
- var dataModel = DataModel(Selection.None);
- var client = new Client<ReportTemplate>();
- var template = client.Load(
- new Filter<ReportTemplate>(x => x.DataModel).IsEqualTo(dataModel.Name)
- .And(x => x.Section).IsEqualTo(section)
- .And(x => x.Name).IsEqualTo("Invoice"),
- new SortOrder<ReportTemplate>(x => x.Name)
- ).FirstOrDefault();
- if (template == null)
- template = new ReportTemplate { DataModel = dataModel.Name, Section = section, Name = "Invoice" };
- var files = new List<string>();
- foreach (var row in rows)
- {
- var InvoiceNumber = row.Get<Invoice, int>(x => x.Number);
- Progress.SetMessage(string.Format("Processing Invoice #{0}", InvoiceNumber));
- var dm = new InvoiceDataModel(new Filter<Invoice>(x => x.ID).IsEqualTo(row.Get<Invoice, Guid>(x => x.ID)));
- var pdf = ReportUtils.ReportToPDF(template, dm);
- var filename = Path.Combine(Path.GetTempPath(), string.Format("Invoice {0}.pdf", InvoiceNumber));
- File.WriteAllBytes(filename, pdf);
- files.Add(filename);
- }
- return files;
- }
- private string GenerateTemplate(CoreRow[] rows, Employee me)
- {
- var table = new HTMLStyle
- {
- { "border", "1px solid black" },
- { "border-collapse", "collapse" }
- };
- var cell = new HTMLStyle
- {
- { "border", "1px solid black" }
- };
- var html = new HTMLBuilder();
- var salutation = "Dear ";
- for (var i = 0; i < emails.Count; i++)
- {
- if (i > 0)
- salutation = salutation + (i == emails.Count - 1 ? " and " : ", ");
- salutation = salutation + emails[i].Item2.Split(' ').First();
- }
- salutation = salutation + ",";
- html = html.StartParagraph().StartFont("Arial", "initial").AddContent(salutation).EndFont().EndParagraph();
- html = html.StartParagraph().StartFont("Arial", "initial").AddContent("Please find attached the following Invoices:").EndFont()
- .EndParagraph();
- html = html.StartTable(table).AddAttribute("cellpadding", "2px")
- .StartRow()
- .StartCell(cell).AddAttribute("width", "100px").AddAttribute("align", "center").AddAttribute("bgcolor", "#AAAAAA")
- .StartFont("Arial", "initial").AddContent("Date").EndFont().EndCell()
- .StartCell(cell).AddAttribute("width", "90px").AddAttribute("align", "center").AddAttribute("bgcolor", "#AAAAAA")
- .StartFont("Arial", "initial").AddContent("Job #").EndFont().EndCell()
- .StartCell(cell).AddAttribute("width", "90px").AddAttribute("align", "center").AddAttribute("bgcolor", "#AAAAAA")
- .StartFont("Arial", "initial").AddContent("Invoice #").EndFont().EndCell()
- .StartCell(cell).AddAttribute("width", "400px").AddAttribute("align", "left").AddAttribute("bgcolor", "#AAAAAA")
- .StartFont("Arial", "initial").AddContent("Description").EndFont().EndCell()
- .StartCell(cell).AddAttribute("width", "100px").AddAttribute("align", "center").AddAttribute("bgcolor", "#AAAAAA")
- .StartFont("Arial", "initial").AddContent("Inc GST $").EndFont().EndCell()
- .EndRow();
- foreach (var row in rows)
- html = html
- .StartRow()
- .StartCell(cell).AddAttribute("align", "center").StartFont("Arial", "initial")
- .AddContentFormat("{0:dd MMM yy}", row.Get<Invoice, DateTime>(x => x.Date)).EndFont().EndCell()
- .StartCell(cell).AddAttribute("align", "center").StartFont("Arial", "initial")
- .AddContent(row.Get<Invoice, string>(x => x.JobLink.JobNumber)).EndFont().EndCell()
- .StartCell(cell).AddAttribute("align", "center").StartFont("Arial", "initial")
- .AddContentFormat("{0}", row.Get<Invoice, int>(x => x.Number)).EndFont().EndCell()
- .StartCell(cell).AddAttribute("align", "left").StartFont("Arial", "initial")
- .AddContent(row.Get<Invoice, string>(x => x.Description))
- .EndFont().EndCell()
- .StartCell(cell).AddAttribute("align", "center").StartFont("Arial", "initial")
- .AddContentFormat("${0:N2}", row.Get<Invoice, double>(x => x.IncTax)).EndFont().EndCell()
- .EndRow();
- html = html.EndTable();
- html = html.StartParagraph().StartFont("Arial", "initial")
- .AddContent("If you have any queries, please do not hesitate to contact us at any time.").EndFont().EndParagraph();
- html = html.StartParagraph().StartFont("Arial", "initial").AddContent("Regards,").EndFont().EndParagraph();
- html = html.StartParagraph().StartFont("Arial", "initial").AddContent(me.Name).EndFont().EndParagraph();
- return html.ToString();
- }
- private bool DoEmailInvoice(Button sender, CoreRow[] rows)
- {
- return EmailInvoices(rows);
- }
- public bool EmailInvoices(CoreRow[] rows)
- {
- if (!rows.Any())
- {
- MessageBox.Show("Please select at least one row to process");
- return false;
- }
- Progress.Show("Loading Data");
- var ids = rows.Select(r => r.Get<Invoice, Guid>(c => c.ID)).ToArray();
- var model = new InvoiceDataModel(new Filter<Invoice>(x => x.ID).InList(ids));
- var sectionName = SectionName;
- model.LoadModel(null);
- //model.Populate();
- var myemail = model.ExtractValues<Employee, string>(x => x.UserLink.EmailAddress).Distinct().FirstOrDefault();
- if (string.IsNullOrEmpty(myemail))
- {
- Progress.Close();
- MessageBox.Show("Logged in User does not have a valid email address!");
- return false;
- }
- Progress.SetMessage("Connecting to Mail");
- var mailer = ClientFactory.CreateMailer();
- if (!mailer.Connect())
- {
- Progress.Close();
- MessageBox.Show("Unable to connect to Mail System!");
- return false;
- }
- Progress.SetMessage("Parsing Emails");
- var emails = new List<Tuple<Guid, string, string>>();
- var custids = rows.Select(r =>
- new Tuple<Guid, string, string>(
- r.Get<Invoice, Guid>(c => c.CustomerLink.ID),
- r.Get<Invoice, string>(c => c.CustomerLink.Email),
- r.Get<Invoice, string>(c => c.CustomerLink.Contact)
- )
- ).Distinct().Where(x => x.Item1 != default).ToArray();
- if (custids.Any())
- {
- var contacts = new Client<CustomerContact>().Query(
- new Filter<CustomerContact>(x => x.Customer.ID).InList(custids.Select(x => x.Item1).ToArray())
- .And(x => x.Contact.Email).IsNotEqualTo("")
- .And(x => x.Type.AccountsPayable).IsEqualTo(true),
- new Columns<CustomerContact>(x => x.Customer.ID, x => x.Contact.Email, x => x.Contact.Name)
- );
- foreach (var contact in contacts.Rows)
- {
- var custid = contact.Get<CustomerContact, Guid>(x => x.ID);
- var email = contact.Get<CustomerContact, string>(x => x.Contact.Email);
- var name = contact.Get<CustomerContact, string>(x => x.Contact.Name);
- if (!emails.Any(x => string.Equals(x.Item2, email) && string.Equals(x.Item3, name)))
- emails.Add(new Tuple<Guid, string, string>(custid, email, name));
- }
- foreach (var cust in custids.Where(x => !string.IsNullOrWhiteSpace(x.Item2)))
- if (!emails.Any(x => x.Item1.Equals(cust.Item1)))
- emails.Add(new Tuple<Guid, string, string>(cust.Item1, cust.Item2, cust.Item3));
- }
- Progress.SetMessage("Loading Report Template");
- var client = new Client<ReportTemplate>();
- var report = client.Load(
- new Filter<ReportTemplate>(x => x.DataModel).IsEqualTo(model.Name)
- .And(x => x.Section).IsEqualTo(sectionName)
- .And(x => x.Name).IsEqualTo("Invoice"),
- new SortOrder<ReportTemplate>(x => x.Name)
- ).FirstOrDefault();
- if (report == null)
- report = new ReportTemplate { DataModel = model.Name, Section = sectionName, Name = "Invoice" };
- var numbers = model.ExtractValues<Invoice, int>(x => x.Number);
- Progress.SetMessage("Processing Invoices");
- var pdf = ReportUtils.ReportToPDF(report, model, false);
- var filename = Path.Combine(Path.GetTempPath(), string.Format("INV {0}.pdf", string.Join(" ", numbers)));
- File.WriteAllBytes(filename, pdf);
- Progress.SetMessage("Preparing Email");
- var template = @"
- <p><font face=""Arial"" size=""initial"">Dear
- {{ for c in Customer }}
- {{ len = array.size Customer }}
- {{ sep = """" }}
- {{
- if for.index == len-2
- sep = "" and ""
- else
- sep = "", ""
- end
- }}
- {{ c.Contact | string.split "" "" | array.first | string.strip }}{{ sep }}
- {{ end }}
- </font></p>
- <p><font face=""Arial"" size=""initial"">Please find attached the following Invoices:</font></p>
- <table style=""border:1px solid black;border-collapse:collapse;"" cellpadding=""2px"">
- <tr>
- <td style=""border:1px solid black;"" valign=""middle"" width=""100px"" align=""center"" bgcolor=""#AAAAAA""><font face=""Arial"" size=""initial"">Date</font></td>
- <td style=""border:1px solid black;"" valign=""middle"" width=""90px"" align=""center"" bgcolor=""#AAAAAA""><font face=""Arial"" size=""initial"">Job #</font></td>
- <td style=""border:1px solid black;"" valign=""middle"" width=""90px"" align=""center"" bgcolor=""#AAAAAA""><font face=""Arial"" size=""initial"">Invoice #</font></td>
- <td style=""border:1px solid black;"" valign=""middle"" width=""400px"" align=""left"" bgcolor=""#AAAAAA""><font face=""Arial"" size=""initial"">Description</font></td>
- <td style=""border:1px solid black;"" valign=""middle"" width=""100px"" align=""center"" bgcolor=""#AAAAAA""><font face=""Arial"" size=""initial"">Inc GST $</font></td>
- </tr>
-
- {{ for i in Invoice }}
- <tr>
- <td style=""border:1px solid black;"" valign=""middle"" align=""center""><font face=""Arial"" size=""initial"">{{ i.Date }}</font></td>
- <td style=""border:1px solid black;"" valign=""middle"" align=""center""><font face=""Arial"" size=""initial"">{{ i.JobLink.JobNumber }}</font></td>
- <td style=""border:1px solid black;"" valign=""middle"" align=""center""><font face=""Arial"" size=""initial"">{{ i.Number }}</font></td>
- <td style=""border:1px solid black;"" valign=""middle"" align=""left""><font face=""Arial"" size=""initial"">{{ i.Description }}</font></td>
- <td style=""border:1px solid black;"" valign=""middle"" align=""center""><font face=""Arial"" size=""initial"">${{ i.IncTax | math.format ""F2"" }}</font></td>
- </tr>
- {{ end }}
-
- </table>
- <p><font face=""Arial"" size=""initial"">If you have any queries, please do not hesitate to contact us at any time.</font></p>
- <p><font face=""Arial"" size=""initial"">Regards,</font></p>
- <p><font face=""Arial"" size=""initial"">
- {{ Employee | array.map ""Name"" | array.first }}<br>
- {{ Employee | array.map ""Email"" | array.first }}
- </font></p>
- ";
- var templates =
- new Client<DataModelTemplate>().Query(new Filter<DataModelTemplate>(x => x.Model).IsEqualTo(model.Name).And(x => x.Default)
- .IsEqualTo(true));
- if (!templates.Rows.Any())
- {
- var newtemplate = new DataModelTemplate
- {
- Model = model.Name,
- Name = "Invoice",
- Default = true,
- Template = template
- };
- new Client<DataModelTemplate>().Save(newtemplate, "Auto-Generated Template");
- }
- else
- {
- template = templates.Rows.First().Get<DataModelTemplate, string>(x => x.Template);
- }
- try
- {
- template = DataModelUtils.ParseTemplate(model, template);
- }
- catch (Exception e)
- {
- template = string.Format("Unable to Process Email Template!\n\n" + e.Message);
- }
- var message = mailer.CreateMessage();
- message.Subject = string.Format("New Invoice{0} Available: (#{1})", rows.Length > 1 ? "s" : "", string.Join(", #", numbers));
- message.From = myemail; // THIS SHOULD BE USER.SMTP?
- message.To = emails.Select(x => x.Item2).ToArray();
- message.IsHTML = true;
- message.Body = template;
- var attach = new List<Tuple<string, byte[]>>();
- attach.Add(new Tuple<string, byte[]>(Path.GetFileName(filename), File.ReadAllBytes(filename)));
- message.Attachments = attach.ToArray();
- var form = new EmailForm(message, model) { Zoom = 100F };
- Progress.Close();
- if (form.ShowDialog() == true)
- mailer.SendMessage(message);
- return false;
- }
- protected override void Reload(Filters<Invoice> criteria, Columns<Invoice> columns, ref SortOrder<Invoice> sort,
- Action<CoreTable, Exception> action)
- {
- if (Outstanding)
- criteria.Add(new Filter<Invoice>(x => x.Balance).IsNotEqualTo(0.0F));
- base.Reload(criteria, columns, ref sort, action);
- }
- protected override bool FilterRecord(CoreRow row)
- {
- if (Outstanding)
- return Math.Abs(row.Get<Invoice, double>(x => x.Balance)) > 0.01F;
- return base.FilterRecord(row);
- }
- }
- }
|