Beispiel #1
0
        public static StatementSpecification GetStatementSpecification(CMSDataContext db, string name)
        {
            var standardheader = db.ContentHtml("StatementHeader", Resource1.ContributionStatementHeader);
            var standardnotice = db.ContentHtml("StatementNotice", Resource1.ContributionStatementNotice);

            if (name == null || name == "all")
            {
                return(new StatementSpecification()
                {
                    Description = "All Statements",
                    Notice = standardnotice,
                    Header = standardheader,
                    Funds = null
                });
            }
            var standardsetlabel = db.Setting("StandardFundSetName", "Standard Statements");

            if (name == standardsetlabel)
            {
                var funds = APIContributionSearchModel.GetCustomStatementsList(db, name);
                return(new StatementSpecification()
                {
                    Description = standardsetlabel,
                    Notice = standardnotice,
                    Header = standardheader,
                    Funds = funds
                });
            }
            var xd  = XDocument.Parse(Util.PickFirst(db.ContentOfTypeText("CustomStatements"), "<CustomStatement/>"));
            var ele = xd.XPathSelectElement($"//Statement[@description='{name}']");

            if (ele == null)
            {
                return(null);
            }

            var desc = ele.Attribute("description")?.Value;
            var cs   = new StatementSpecification
            {
                Description = desc
            };
            var headerele = ele.Element("Header");

            cs.Header = headerele != null
                ? string.Concat(headerele.Nodes().Select(x => x.ToString()).ToArray())
                : standardheader;

            var noticeele = ele.Element("Notice");

            cs.Notice = noticeele != null
                ? string.Concat(noticeele.Nodes().Select(x => x.ToString()).ToArray())
                : standardnotice;

            cs.Funds = APIContributionSearchModel.GetCustomStatementsList(db, desc);
            return(cs);
        }
Beispiel #2
0
        private void EmailExistingPerson()
        {
            var message = db.ContentHtml("ExistingUserConfirmation", Resource1.CreateAccount_ExistingUser);

            message = message
                      .Replace("{name}", FoundPerson.Name)
                      .Replace("{host}", db.CmsHost);
            db.Email(DbUtil.AdminMail, FoundPerson, "Account information for " + db.Host, message);
            User = FoundPerson.Users.OrderByDescending(uu => uu.LastActivityDate).FirstOrDefault()
                   ?? MembershipService.CreateUser(db, FoundPerson.PeopleId);
            Result = "found existing person";
        }
Beispiel #3
0
        private void NotifyAboutExistingAccount(Person p)
        {
            var message = db.ContentHtml("ExistingUserConfirmation", Resource1.CreateAccount_ExistingUser);

            message = message
                      .Replace("{name}", p.Name)
                      .Replace("{host}", db.CmsHost);
            db.Email(DbUtil.AdminMail, p, "Account information for " + db.Host, message);
            User = p.Users.OrderByDescending(uu => uu.LastActivityDate).FirstOrDefault()
                   ?? MembershipService.CreateUser(db, p.PeopleId);
            Result = ResultCode.FoundPersonWithSameEmail;
        }
        public static StatementSpecification GetStatementSpecification(CMSDataContext db, string name)
        {
            string nameOfChurch   = db.Setting("NameOfChurch", "Name of Church");
            string startAddress   = db.Setting("StartAddress", "Start Address");
            string churchPhone    = db.Setting("ChurchPhone", "(000) 000-0000");
            var    standardheader = db.ContentHtml("StatementHeader", string.Format(Resource1.ContributionStatementHeader, nameOfChurch, startAddress, churchPhone));
            var    standardnotice = db.ContentHtml("StatementNotice", string.Format(Resource1.ContributionStatementNotice, nameOfChurch));

            if (name == null || name == "all")
            {
                return(new StatementSpecification()
                {
                    Notice = standardnotice,
                    Header = standardheader,
                    Funds = null
                });
            }
            var standardsetlabel = db.Setting("StandardFundSetName", "Standard Statements");

            if (name == standardsetlabel)
            {
                var funds = APIContributionSearchModel.GetCustomStatementsList(db, name);
                return(new StatementSpecification()
                {
                    Description = standardsetlabel,
                    Notice = standardnotice,
                    Header = standardheader,
                    Funds = funds
                });
            }
            var xd            = XDocument.Parse(Util.PickFirst(db.ContentOfTypeText("CustomStatements"), "<CustomStatement/>"));
            var statementSpec = xd.XPathSelectElement($"//Statement[@description='{name}']");

            if (statementSpec == null)
            {
                return(null);
            }

            var desc = statementSpec.Attribute("description")?.Value;
            var cs   = new StatementSpecification
            {
                Description = desc
            };

            cs.Funds        = APIContributionSearchModel.GetCustomStatementsList(db, desc);
            cs.Header       = GetSectionHTML(db, "Header", statementSpec, standardheader);
            cs.Notice       = GetSectionHTML(db, "Notice", statementSpec, standardnotice);
            cs.Template     = GetSectionHTML(db, "Template", statementSpec);
            cs.TemplateBody = GetSectionHTML(db, "TemplateBody", statementSpec);
            cs.Footer       = GetSectionHTML(db, "Footer", statementSpec);

            return(cs);
        }
Beispiel #5
0
        public void ComposeMessage()
        {
            var dt = DateTime.Now;

            ticks = dt.Ticks;
            var yeslink = $@"<a href=""http://volsublink"" aid=""{attend.AttendId}"" pid=""{person.PeopleId}"" ticks=""{ticks}"" ans=""yes"">
Yes, I can sub for you.</a>";
            var nolink  = $@"<a href=""http://volsublink"" aid=""{attend.AttendId}"" pid=""{person.PeopleId}"" ticks=""{ticks}"" ans=""no"">
Sorry, I cannot sub for you.</a>";

            subject = $"Volunteer substitute request for {org.OrganizationName}";
            message = Db.ContentHtml("VolunteerSubRequest", Resource1.VolSubModel_ComposeMessage_Body);
            message = message.Replace("{org}", org.OrganizationName)
                      .Replace("{meetingdate}", attend.MeetingDate.ToString("dddd, MMM d"))
                      .Replace("{meetingtime}", attend.MeetingDate.ToString("h:mm tt"))
                      .Replace("{yeslink}", yeslink)
                      .Replace("{nolink}", nolink)
                      .Replace("{sendername}", person.Name);
        }
Beispiel #6
0
        public void sendDeepLink()
        {
            if (db.People.Any(p => p.EmailAddress == email || p.EmailAddress2 == email))
            {
                string code     = createQuickSignInCode(device, instance, key, email);
                string deepLink = db.Setting("MobileDeepLinkURL", "");

                if (string.IsNullOrEmpty(code))
                {
                    results = Results.CommonCodeCreationFailed;

                    return;
                }

                if (string.IsNullOrEmpty(deepLink))
                {
                    results = Results.CommonInvalidDeepLink;

                    return;
                }

                List <MailAddress> mailAddresses = new List <MailAddress>();
                mailAddresses.Add(new MailAddress(email));

                string link    = $"{deepLink}/signin/quick/{code}";
                string message = $"<a href='{link}'>Click here to sign in</a>";

                string body = db.ContentHtml("NewMobileUserDeepLink", message);
                body = body.Replace("{link}", link);

                db.SendEmail(new MailAddress(DbUtil.AdminMail, DbUtil.AdminMailName), db.Setting("MobileQuickSignInSubject", "Quick Sign In Link"), body, mailAddresses);

                results = Results.CommonEmailSent;
            }
            else
            {
                results = Results.DeepLinkNoPeopleFound;
            }
        }
Beispiel #7
0
        public static void SendNewUserEmail(CMSDataContext db, string username)
        {
            var user = db.Users.First(u => u.Username == username);
            var body = db.ContentHtml("NewUserWelcome", Resource1.AccountModel_NewUserWelcome);

            body = body.Replace("{first}", user.Person.PreferredName);
            body = body.Replace("{name}", user.Person.Name);
            body = body.Replace("{cmshost}", db.Setting("DefaultHost", db.Host));
            body = body.Replace("{username}", user.Username);
            user.ResetPasswordCode    = Guid.NewGuid();
            user.ResetPasswordExpires = DateTime.Now.AddHours(db.Setting("ResetPasswordExpiresHours", "24").ToInt());
            var link = db.ServerLink("/Account/SetPassword/" + user.ResetPasswordCode);

            body = body.Replace("{link}", link);
            db.SubmitChanges();
            db.EmailRedacted(DbUtil.AdminMail, user.Person, "New user welcome", body);
        }
Beispiel #8
0
        public static string GetResults(CMSDataContext db, int pid, int oid)
        {
            var host = db.Host;

            try
            {
                var si       = new SummaryInfo(db, pid, oid);
                var content  = db.ContentHtml("OnlineRegSummaryHtml", Properties.Resources.Details2);
                var template = si.hbContext.Compile(content);
                var ret      = template(si);
                return(ret);
            }
            catch (Exception ex)
            {
                throw new Exception($@"
message: {ex.Message}
host: {host}
oid: {oid}
pid: {pid}
", ex);
            }
        }
        public void Run(Stream stream, CMSDataContext Db, IEnumerable <ContributorInfo> q, int set = 0)
        {
            pageEvents.set = set;
            IEnumerable <ContributorInfo> contributors = q;
            var toDate = ToDate.Date.AddHours(24).AddSeconds(-1);

            PdfContentByte dc;
            var            font     = FontFactory.GetFont(FontFactory.HELVETICA, 11);
            var            boldfont = FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 11);

            var doc = new Document(PageSize.LETTER);

            doc.SetMargins(36f, 30f, 24f, 36f);
            var w = PdfWriter.GetInstance(doc, stream);

            w.PageEvent = pageEvents;
            doc.Open();
            dc = w.DirectContent;

            int prevfid       = 0;
            var runningtotals = Db.ContributionsRuns.OrderByDescending(mm => mm.Id).FirstOrDefault();

            runningtotals.Processed = 0;
            Db.SubmitChanges();
            var count = 0;

            foreach (var ci in contributors)
            {
                if (set > 0 && pageEvents.FamilySet[ci.PeopleId] != set)
                {
                    continue;
                }

                var contributions = APIContribution.contributions(Db, ci, FromDate, toDate).ToList();
                var pledges       = APIContribution.pledges(Db, ci, toDate).ToList();
                var giftsinkind   = APIContribution.GiftsInKind(Db, ci, FromDate, toDate).ToList();
                var nontaxitems   = Db.Setting("DisplayNonTaxOnStatement", "false").ToBool()
                    ? APIContribution.NonTaxItems(Db, ci, FromDate, toDate).ToList()
                    : new List <ContributionInfo>();

                if ((contributions.Count + pledges.Count + giftsinkind.Count + nontaxitems.Count) == 0)
                {
                    runningtotals.Processed += 1;
                    runningtotals.CurrSet    = set;
                    Db.SubmitChanges();
                    if (set == 0)
                    {
                        pageEvents.FamilySet[ci.PeopleId] = 0;
                    }
                    continue;
                }

                doc.NewPage();
                if (prevfid != ci.FamilyId)
                {
                    prevfid = ci.FamilyId;
                    pageEvents.EndPageSet();
                }
                if (set == 0)
                {
                    pageEvents.FamilySet[ci.PeopleId] = 0;
                }
                count++;

                var css = @"
<style>
h1 { font-size: 24px; font-weight:normal; margin-bottom:0; }
h2 { font-size: 11px; font-weight:normal; margin-top: 0; }
p { font-size: 11px; }
</style>
";
                //----Church Name

                var t1 = new PdfPTable(1);
                t1.TotalWidth         = 72f * 5f;
                t1.DefaultCell.Border = Rectangle.NO_BORDER;
                string html1 = Db.ContentHtml("StatementHeader", Resource1.ContributionStatementHeader);
                string html2 = Db.ContentHtml("StatementNotice", Resource1.ContributionStatementNotice);

                var mh = new MyHandler();
                using (var sr = new StringReader(css + html1))
                    XMLWorkerHelper.GetInstance().ParseXHtml(mh, sr);

                var cell = new PdfPCell(t1.DefaultCell);
                foreach (var e in mh.elements)
                {
                    if (e.Chunks.Count > 0)
                    {
                        cell.AddElement(e);
                    }
                }
                //cell.FixedHeight = 72f * 1.25f;
                t1.AddCell(cell);
                t1.AddCell("\n");

                var t1a = new PdfPTable(1);
                t1a.TotalWidth         = 72f * 5f;
                t1a.DefaultCell.Border = Rectangle.NO_BORDER;

                var ae = new PdfPTable(1);
                ae.DefaultCell.Border = Rectangle.NO_BORDER;
                ae.WidthPercentage    = 100;

                var a = new PdfPTable(1);
                a.DefaultCell.Indent = 25f;
                a.DefaultCell.Border = Rectangle.NO_BORDER;
                a.AddCell(new Phrase(ci.Name, font));
                foreach (var line in ci.MailingAddress.SplitLines())
                {
                    a.AddCell(new Phrase(line, font));
                }
                cell = new PdfPCell(a)
                {
                    Border = Rectangle.NO_BORDER
                };
                //cell.FixedHeight = 72f * 1.0625f;
                ae.AddCell(cell);

                cell = new PdfPCell(t1a.DefaultCell);
                cell.AddElement(ae);
                t1a.AddCell(ae);

                //-----Notice

                var t2 = new PdfPTable(1);
                t2.TotalWidth         = 72f * 3f;
                t2.DefaultCell.Border = Rectangle.NO_BORDER;
                t2.AddCell(new Phrase($"\nPrint Date: {DateTime.Now:d}   (id:{ci.PeopleId} {ci.CampusId})", font));
                t2.AddCell("");
                var mh2 = new MyHandler();
                using (var sr = new StringReader(css + html2))
                    XMLWorkerHelper.GetInstance().ParseXHtml(mh2, sr);
                cell = new PdfPCell(t1.DefaultCell);
                foreach (var e in mh2.elements)
                {
                    if (e.Chunks.Count > 0)
                    {
                        cell.AddElement(e);
                    }
                }
                t2.AddCell(cell);

                // POSITIONING OF ADDRESSES
                //----Header

                var yp = doc.BottomMargin +
                         Db.Setting("StatementRetAddrPos", "10.125").ToFloat() * 72f;
                t1.WriteSelectedRows(0, -1,
                                     doc.LeftMargin - 0.1875f * 72f, yp, dc);

                yp = doc.BottomMargin +
                     Db.Setting("StatementAddrPos", "8.3375").ToFloat() * 72f;
                t1a.WriteSelectedRows(0, -1, doc.LeftMargin, yp, dc);

                yp = doc.BottomMargin + 10.125f * 72f;
                t2.WriteSelectedRows(0, -1, doc.LeftMargin + 72f * 4.4f, yp, dc);

                //----Contributions

                doc.Add(new Paragraph(" "));
                doc.Add(new Paragraph(" ")
                {
                    SpacingBefore = 72f * 2.125f
                });

                doc.Add(new Phrase($"\n  Period: {FromDate:d} - {toDate:d}", boldfont));

                var pos = w.GetVerticalPosition(true);

                var   ct       = new ColumnText(dc);
                float gutter   = 20f;
                float colwidth = (doc.Right - doc.Left - gutter) / 2;

                var t = new PdfPTable(new[] { 10f, 24f, 10f });
                t.WidthPercentage    = 100;
                t.DefaultCell.Border = Rectangle.NO_BORDER;
                t.HeaderRows         = 2;

                cell         = new PdfPCell(t.DefaultCell);
                cell.Colspan = 3;
                cell.Phrase  = new Phrase("Contributions\n", boldfont);
                t.AddCell(cell);

                t.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
                t.AddCell(new Phrase("Date", boldfont));
                t.AddCell(new Phrase("Description", boldfont));
                cell = new PdfPCell(t.DefaultCell);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                cell.Phrase = new Phrase("Amount", boldfont);
                t.AddCell(cell);

                t.DefaultCell.Border = Rectangle.NO_BORDER;

                var total = 0m;
                foreach (var c in contributions)
                {
                    t.AddCell(new Phrase(c.ContributionDate.ToShortDateString(), font));
                    t.AddCell(new Phrase(c.Fund, font));
                    cell = new PdfPCell(t.DefaultCell);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    cell.Phrase = new Phrase(c.ContributionAmount.ToString("N2"), font);
                    t.AddCell(cell);
                    total += (c.ContributionAmount);
                }
                t.DefaultCell.Border = Rectangle.TOP_BORDER;
                cell         = new PdfPCell(t.DefaultCell);
                cell.Colspan = 2;
                cell.Phrase  = new Phrase("Total Contributions for period", boldfont);
                t.AddCell(cell);
                cell = new PdfPCell(t.DefaultCell);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                cell.Phrase = new Phrase(total.ToString("N2"), font);
                t.AddCell(cell);

                ct.AddElement(t);

                //------Pledges

                if (pledges.Count > 0)
                {
                    t = new PdfPTable(new float[] { 16f, 12f, 12f });
                    t.WidthPercentage    = 100;
                    t.DefaultCell.Border = Rectangle.NO_BORDER;
                    t.HeaderRows         = 2;

                    cell         = new PdfPCell(t.DefaultCell);
                    cell.Colspan = 3;
                    cell.Phrase  = new Phrase("\n\nPledges\n", boldfont);
                    t.AddCell(cell);

                    t.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
                    t.AddCell(new Phrase("Fund", boldfont));
                    cell = new PdfPCell(t.DefaultCell);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    cell.Phrase = new Phrase("Pledge", boldfont);
                    t.AddCell(cell);
                    cell = new PdfPCell(t.DefaultCell);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    cell.Phrase = new Phrase("Given", boldfont);
                    t.AddCell(cell);

                    t.DefaultCell.Border = Rectangle.NO_BORDER;

                    foreach (var c in pledges)
                    {
                        t.AddCell(new Phrase(c.Fund, font));
                        cell = new PdfPCell(t.DefaultCell);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        cell.Phrase = new Phrase(c.PledgeAmount.ToString2("N2"), font);
                        t.AddCell(cell);
                        cell = new PdfPCell(t.DefaultCell);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        cell.Phrase = new Phrase(c.ContributionAmount.ToString2("N2"), font);
                        t.AddCell(cell);
                    }
                    ct.AddElement(t);
                }

                //------Gifts In Kind

                if (giftsinkind.Count > 0)
                {
                    t = new PdfPTable(new float[] { 12f, 18f, 20f });
                    t.WidthPercentage    = 100;
                    t.DefaultCell.Border = Rectangle.NO_BORDER;
                    t.HeaderRows         = 2;

                    cell         = new PdfPCell(t.DefaultCell);
                    cell.Colspan = 3;
                    cell.Phrase  = new Phrase("\n\nGifts in Kind\n", boldfont);
                    t.AddCell(cell);

                    t.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
                    t.AddCell(new Phrase("Date", boldfont));
                    cell        = new PdfPCell(t.DefaultCell);
                    cell.Phrase = new Phrase("Fund", boldfont);
                    t.AddCell(cell);
                    cell        = new PdfPCell(t.DefaultCell);
                    cell.Phrase = new Phrase("Description", boldfont);
                    t.AddCell(cell);

                    t.DefaultCell.Border = Rectangle.NO_BORDER;

                    foreach (var c in giftsinkind)
                    {
                        t.AddCell(new Phrase(c.ContributionDate.ToShortDateString(), font));
                        cell        = new PdfPCell(t.DefaultCell);
                        cell.Phrase = new Phrase(c.Fund, font);
                        t.AddCell(cell);
                        cell        = new PdfPCell(t.DefaultCell);
                        cell.Phrase = new Phrase(c.Description, font);
                        t.AddCell(cell);
                    }
                    ct.AddElement(t);
                }

                //-----Summary

                t = new PdfPTable(new float[] { 29f, 9f });
                t.WidthPercentage    = 100;
                t.DefaultCell.Border = Rectangle.NO_BORDER;
                t.HeaderRows         = 2;

                cell         = new PdfPCell(t.DefaultCell);
                cell.Colspan = 2;
                cell.Phrase  = new Phrase("\n\nPeriod Summary\n", boldfont);
                t.AddCell(cell);

                t.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
                t.AddCell(new Phrase("Fund", boldfont));
                cell = new PdfPCell(t.DefaultCell);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                cell.Phrase = new Phrase("Amount", boldfont);
                t.AddCell(cell);

                t.DefaultCell.Border = Rectangle.NO_BORDER;
                foreach (var c in APIContribution.quarterlySummary(Db, ci, FromDate, toDate))
                {
                    t.AddCell(new Phrase(c.Fund, font));
                    cell = new PdfPCell(t.DefaultCell);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    cell.Phrase = new Phrase(c.ContributionAmount.ToString("N2"), font);
                    t.AddCell(cell);
                }
                t.DefaultCell.Border = Rectangle.TOP_BORDER;
                t.AddCell(new Phrase("Total contributions for period", boldfont));
                cell = new PdfPCell(t.DefaultCell);
                cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                cell.Phrase = new Phrase(total.ToString("N2"), font);
                t.AddCell(cell);
                ct.AddElement(t);

                //------NonTax

                if (nontaxitems.Count > 0)
                {
                    t = new PdfPTable(new float[] { 10f, 24f, 10f });
                    t.WidthPercentage    = 100;
                    t.DefaultCell.Border = Rectangle.NO_BORDER;
                    t.HeaderRows         = 2;

                    cell         = new PdfPCell(t.DefaultCell);
                    cell.Colspan = 3;
                    cell.Phrase  = new Phrase("\n\nNon Tax-Deductible Items\n", boldfont);
                    t.AddCell(cell);

                    t.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
                    t.AddCell(new Phrase("Date", boldfont));
                    t.AddCell(new Phrase("Description", boldfont));
                    cell = new PdfPCell(t.DefaultCell);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    cell.Phrase = new Phrase("Amount", boldfont);
                    t.AddCell(cell);

                    t.DefaultCell.Border = Rectangle.NO_BORDER;

                    var ntotal = 0m;
                    foreach (var c in nontaxitems)
                    {
                        t.AddCell(new Phrase(c.ContributionDate.ToShortDateString(), font));
                        t.AddCell(new Phrase(c.Fund, font));
                        cell = new PdfPCell(t.DefaultCell);
                        cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                        cell.Phrase = new Phrase(c.ContributionAmount.ToString("N2"), font);
                        t.AddCell(cell);
                        ntotal += (c.ContributionAmount);
                    }
                    t.DefaultCell.Border = Rectangle.TOP_BORDER;
                    cell         = new PdfPCell(t.DefaultCell);
                    cell.Colspan = 2;
                    cell.Phrase  = new Phrase("Total Non Tax-Deductible Items for period", boldfont);
                    t.AddCell(cell);
                    cell = new PdfPCell(t.DefaultCell);
                    cell.HorizontalAlignment = Element.ALIGN_RIGHT;
                    cell.Phrase = new Phrase(ntotal.ToString("N2"), font);
                    t.AddCell(cell);

                    ct.AddElement(t);
                }

                var col    = 0;
                var status = 0;
                while (ColumnText.HasMoreText(status))
                {
                    if (col == 0)
                    {
                        ct.SetSimpleColumn(doc.Left, doc.Bottom, doc.Left + colwidth, pos);
                    }
                    else if (col == 1)
                    {
                        ct.SetSimpleColumn(doc.Right - colwidth, doc.Bottom, doc.Right, pos);
                    }
                    status = ct.Go();
                    ++col;
                    if (col > 1)
                    {
                        col = 0;
                        pos = doc.Top;
                        doc.NewPage();
                    }
                }

                runningtotals.Processed += 1;
                runningtotals.CurrSet    = set;
                Db.SubmitChanges();
            }

            if (count == 0)
            {
                doc.NewPage();
                doc.Add(new Paragraph("no data"));
                var a = new Anchor("see this help document docs.touchpointsoftware.com/Finance/ContributionStatements.html")
                {
                    Reference = "http://docs.touchpointsoftware.com/Finance/ContributionStatements.html#troubleshooting"
                };
                doc.Add(a);
            }
            doc.Close();

            if (set == LastSet())
            {
                runningtotals.Completed = DateTime.Now;
            }
            Db.SubmitChanges();
        }
Beispiel #10
0
        public void StandardMethod(Stream stream, CMSDataContext db, IEnumerable <ContributorInfo> q, StatementSpecification cs, int set = 0)
        {
            pageEvents.set      = set;
            pageEvents.PeopleId = 0;
            var contributors = q;
            var toDate       = ToDate.Date.AddHours(24).AddSeconds(-1);

            var font     = FontFactory.GetFont(FontFactory.HELVETICA, 11);
            var boldfont = FontFactory.GetFont(FontFactory.HELVETICA_BOLD, 11);

            var doc = new Document(PageSize.LETTER);

            doc.SetMargins(36f, 30f, 24f, 36f);
            var w = PdfWriter.GetInstance(doc, stream);

            w.PageEvent = pageEvents;
            doc.Open();
            var dc = w.DirectContent;

            var prevfid       = 0;
            var runningtotals = UUId.HasValue ? db.ContributionsRuns.Where(mm => mm.UUId == UUId).SingleOrDefault() : null;

            if (runningtotals != null)
            {
                runningtotals.Processed = 0;
                db.SubmitChanges();
            }
            var count = 0;

            foreach (var ci in contributors)
            {
                if (set > 0 && pageEvents.FamilySet[ci.PeopleId] != set)
                {
                    continue;
                }

                var contributions = APIContribution.Contributions(db, ci, FromDate, toDate, cs.Funds).ToList();
                var pledges       = APIContribution.Pledges(db, ci, toDate, cs.Funds).ToList();
                var giftsinkind   = APIContribution.GiftsInKind(db, ci, FromDate, toDate, cs.Funds).ToList();
                var nontaxitems   = db.Setting("DisplayNonTaxOnStatement", "false").ToBool()
                    ? APIContribution.NonTaxItems(db, ci, FromDate, toDate, cs.Funds).ToList()
                    : new List <NonTaxContribution>();

                if ((contributions.Count + pledges.Count + giftsinkind.Count + nontaxitems.Count) == 0)
                {
                    if (runningtotals != null)
                    {
                        runningtotals.Processed += 1;
                        runningtotals.CurrSet    = set;
                        db.SubmitChanges();
                    }
                    if (set == 0)
                    {
                        pageEvents.FamilySet[ci.PeopleId] = 0;
                    }

                    continue;
                }

                pageEvents.NextPeopleId = ci.PeopleId;
                doc.NewPage();
                if (prevfid != ci.FamilyId)
                {
                    prevfid = ci.FamilyId;
                    pageEvents.EndPageSet();
                    pageEvents.PeopleId = ci.PeopleId;
                }

                if (set == 0)
                {
                    pageEvents.FamilySet[ci.PeopleId] = 0;
                }

                count++;

                var css = @"
<style>
h1 { font-size: 24px; font-weight:normal; margin-bottom:0; }
h2 { font-size: 11px; font-weight:normal; margin-top: 0; }
p { font-size: 11px; }
</style>
";
                //----Church Name

                var t1 = new PdfPTable(1)
                {
                    TotalWidth = 72f * 5f
                };
                t1.DefaultCell.Border = Rectangle.NO_BORDER;
                string nameOfChurch = db.Setting("NameOfChurch", "Name of Church");
                string startAddress = db.Setting("StartAddress", "Start Address");
                string churchPhone  = db.Setting("ChurchPhone", "(000) 000-0000");
                var    html1        = cs.Header ?? db.ContentHtml("StatementHeader", string.Format(Resource1.ContributionStatementHeader, nameOfChurch, startAddress, churchPhone));
                var    html2        = cs.Notice ?? db.ContentHtml("StatementNotice", string.Format(Resource1.ContributionStatementNotice, nameOfChurch));

                var mh = new MyHandler();
                using (var sr = new StringReader(css + html1))
                {
                    XMLWorkerHelper.GetInstance().ParseXHtml(mh, sr);
                }

                var cell = new PdfPCell(t1.DefaultCell);
                foreach (var e in mh.elements)
                {
                    if (e.Chunks.Count > 0)
                    {
                        cell.AddElement(e);
                    }
                }

                t1.AddCell(cell);
                t1.AddCell("\n");

                var t1a = new PdfPTable(1)
                {
                    TotalWidth = 72f * 5f
                };
                t1a.DefaultCell.Border = Rectangle.NO_BORDER;

                var ae = new PdfPTable(1);
                ae.DefaultCell.Border = Rectangle.NO_BORDER;
                ae.WidthPercentage    = 100;

                var a = new PdfPTable(1);
                a.DefaultCell.Indent = 25f;
                a.DefaultCell.Border = Rectangle.NO_BORDER;
                a.AddCell(new Phrase(ci.Name, font));
                foreach (var line in ci.MailingAddress.SplitLines())
                {
                    a.AddCell(new Phrase(line, font));
                }

                cell = new PdfPCell(a)
                {
                    Border = Rectangle.NO_BORDER
                };
                ae.AddCell(cell);

                cell = new PdfPCell(t1a.DefaultCell);
                cell.AddElement(ae);
                t1a.AddCell(ae);

                //-----Notice

                var t2 = new PdfPTable(1)
                {
                    TotalWidth = 72f * 3f
                };
                t2.DefaultCell.Border = Rectangle.NO_BORDER;

                var envno = "";
                if (db.Setting("PrintEnvelopeNumberOnStatement"))
                {
                    var ev = Person.GetExtraValue(db, ci.PeopleId, "EnvelopeNumber");
                    var s  = Util.PickFirst(ev.Data, ev.IntValue.ToString(), ev.StrValue);
                    if (s.HasValue())
                    {
                        envno = $"env: {s}";
                    }
                }

                t2.AddCell(db.Setting("NoPrintDateOnStatement")
                    ? new Phrase($"\nid:{ci.PeopleId}{envno} {ci.CampusId}", font)
                    : new Phrase($"\nprinted: {DateTime.Now:d} id:{ci.PeopleId}{envno} {ci.CampusId}", font));

                t2.AddCell("");
                var mh2 = new MyHandler();
                using (var sr = new StringReader(css + html2))
                {
                    XMLWorkerHelper.GetInstance().ParseXHtml(mh2, sr);
                }

                cell = new PdfPCell(t1.DefaultCell);
                foreach (var e in mh2.elements)
                {
                    if (e.Chunks.Count > 0)
                    {
                        cell.AddElement(e);
                    }
                }

                t2.AddCell(cell);

                // POSITIONING OF ADDRESSES
                //----Header

                var yp = doc.BottomMargin + db.Setting("StatementRetAddrPos", "10.125").ToFloat() * 72f;
                t1.WriteSelectedRows(0, -1, doc.LeftMargin - 0.1875f * 72f, yp, dc);

                yp = doc.BottomMargin + db.Setting("StatementAddrPos", "8.3375").ToFloat() * 72f;
                t1a.WriteSelectedRows(0, -1, doc.LeftMargin, yp, dc);

                yp = doc.BottomMargin + 10.125f * 72f;
                t2.WriteSelectedRows(0, -1, doc.LeftMargin + 72f * 4.4f, yp, dc);

                //----Contributions

                doc.Add(new Paragraph(" "));
                doc.Add(new Paragraph(" ")
                {
                    SpacingBefore = 72f * 2.125f
                });

                doc.Add(new Phrase($"\n  Period: {FromDate:d} - {toDate:d}", boldfont));

                var pos = w.GetVerticalPosition(true);

                var ct     = new ColumnText(dc);
                var gutter = 20f;
                if (NumberOfColumns == 1)
                {
                    gutter = 0;
                }
                var colwidth = (doc.Right - doc.Left - gutter) / NumberOfColumns;

                var t = (NumberOfColumns == 2)
                ? new PdfPTable(new[] { 18f, 24f, 15f })
                : new PdfPTable(new[] { 18f, 25f, 15f, 15f, 30f })
                {
                    WidthPercentage = 100
                };
                t.DefaultCell.Border = Rectangle.NO_BORDER;
                t.HeaderRows         = 2;

                cell = new PdfPCell(t.DefaultCell)
                {
                    Colspan = (NumberOfColumns == 2) ? 3 : 5,
                    Phrase  = new Phrase("Contributions\n", boldfont)
                };
                t.AddCell(cell);

                t.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
                t.AddCell(new Phrase("Date", boldfont));
                t.AddCell(new Phrase("Description", boldfont));

                cell = new PdfPCell(t.DefaultCell)
                {
                    HorizontalAlignment = Element.ALIGN_RIGHT,
                    Phrase = new Phrase("Amount", boldfont)
                };
                t.AddCell(cell);

                if (NumberOfColumns == 1)
                {
                    cell = new PdfPCell(t.DefaultCell)
                    {
                        HorizontalAlignment = Element.ALIGN_CENTER,
                        Phrase = ShowCheckNo ? new Phrase("Check No", boldfont) : new Phrase("", boldfont)
                    };

                    t.AddCell(cell);

                    t.AddCell(ShowNotes ? new Phrase("Notes", boldfont) : new Phrase("", boldfont));
                }

                t.DefaultCell.Border = Rectangle.NO_BORDER;

                var total = 0m;
                foreach (var c in contributions)
                {
                    t.AddCell(new Phrase(c.ContributionDate.ToString2("d"), font));
                    t.AddCell(new Phrase(GetFundDisplayText(db, () => c.FundName, () => c.FundDescription), font));

                    cell = new PdfPCell(t.DefaultCell)
                    {
                        HorizontalAlignment = Element.ALIGN_RIGHT,
                        Phrase = new Phrase(c.ContributionAmount.ToString2("N2"), font)
                    };
                    t.AddCell(cell);
                    if (NumberOfColumns == 1)
                    {
                        cell = new PdfPCell(t.DefaultCell)
                        {
                            HorizontalAlignment = Element.ALIGN_CENTER,
                            Phrase = ShowCheckNo ? new Phrase(c.CheckNo, font) : new Phrase("", font)
                        };

                        t.AddCell(cell);

                        t.AddCell(ShowNotes ? new Phrase(c.Description?.Trim() ?? "", font) : new Phrase("", font));
                    }
                    total += (c.ContributionAmount ?? 0);
                }

                t.DefaultCell.Border = Rectangle.TOP_BORDER;

                cell = new PdfPCell(t.DefaultCell)
                {
                    Colspan = 2,
                    Phrase  = new Phrase("Total Contributions for period", boldfont)
                };
                t.AddCell(cell);

                cell = new PdfPCell(t.DefaultCell)
                {
                    HorizontalAlignment = Element.ALIGN_RIGHT,
                    Phrase = new Phrase(total.ToString("N2"), font)
                };
                t.AddCell(cell);
                if (NumberOfColumns == 1)
                {
                    cell = new PdfPCell(t.DefaultCell)
                    {
                        Colspan = 2,
                        Phrase  = new Phrase("")
                    };
                    t.AddCell(cell);
                }

                ct.AddElement(t);

                //------Pledges

                if (pledges.Count > 0)
                {
                    t = new PdfPTable((NumberOfColumns == 1)
                        ? new[] { 25f, 15f, 15f, 15f, 30f }
                        : new[] { 16f, 12f, 12f })
                    {
                        WidthPercentage = 100,
                        HeaderRows      = 2,
                    };
                    t.DefaultCell.Border = Rectangle.NO_BORDER;

                    cell = new PdfPCell(t.DefaultCell)
                    {
                        Colspan = (NumberOfColumns == 1) ? 5 : 3,
                        Phrase  = new Phrase("\n\nPledges\n", boldfont)
                    };
                    t.AddCell(cell);

                    t.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
                    t.AddCell(new Phrase("Fund", boldfont));

                    cell = new PdfPCell(t.DefaultCell)
                    {
                        HorizontalAlignment = Element.ALIGN_RIGHT,
                        Phrase = new Phrase("Pledge", boldfont)
                    };
                    t.AddCell(cell);

                    cell = new PdfPCell(t.DefaultCell)
                    {
                        HorizontalAlignment = Element.ALIGN_RIGHT,
                        Phrase = new Phrase("Given", boldfont)
                    };
                    t.AddCell(cell);

                    t.DefaultCell.Border = Rectangle.NO_BORDER;
                    if (NumberOfColumns == 1)
                    {
                        t.AddCell(new Phrase("", boldfont));
                        t.AddCell(new Phrase("", boldfont));
                    }

                    foreach (var c in pledges)
                    {
                        t.AddCell(new Phrase(GetFundDisplayText(db, () => c.FundName, () => c.FundDescription), font));

                        cell = new PdfPCell(t.DefaultCell)
                        {
                            HorizontalAlignment = Element.ALIGN_RIGHT,
                            Phrase = new Phrase(c.Pledged.ToString2("N2"), font)
                        };
                        t.AddCell(cell);

                        cell = new PdfPCell(t.DefaultCell)
                        {
                            HorizontalAlignment = Element.ALIGN_RIGHT,
                            Phrase = new Phrase(c.Given.ToString2("N2"), font)
                        };
                        t.AddCell(cell);

                        if (NumberOfColumns == 1)
                        {
                            t.AddCell(new Phrase("", boldfont));
                            t.AddCell(new Phrase("", boldfont));
                        }
                    }

                    ct.AddElement(t);
                }

                //------Gifts In Kind

                if (giftsinkind.Count > 0)
                {
                    t = new PdfPTable((NumberOfColumns == 1)
                        ? new[] { 18f, 25f, 15f, 15f, 30f }
                        : new[] { 12f, 18f, 20f });

                    t.WidthPercentage    = 100;
                    t.DefaultCell.Border = Rectangle.NO_BORDER;
                    t.HeaderRows         = 2;

                    // Headers
                    cell = new PdfPCell(t.DefaultCell)
                    {
                        Colspan = (NumberOfColumns == 1) ? 5 : 3,
                        Phrase  = new Phrase("\n\nGifts in Kind\n", boldfont)
                    };
                    t.AddCell(cell);

                    t.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
                    t.AddCell(new Phrase("Date", boldfont));
                    cell = new PdfPCell(t.DefaultCell)
                    {
                        Phrase = new Phrase("Fund", boldfont)
                    };
                    t.AddCell(cell);
                    cell = new PdfPCell(t.DefaultCell)
                    {
                        Phrase = new Phrase("Description", boldfont)
                    };
                    t.AddCell(cell);

                    if (NumberOfColumns == 1)
                    {
                        t.AddCell(new Phrase("", boldfont));
                        t.AddCell(new Phrase("", boldfont));
                    }

                    t.DefaultCell.Border = Rectangle.NO_BORDER;

                    foreach (var c in giftsinkind)
                    {
                        t.AddCell(new Phrase(c.ContributionDate.ToString2("d"), font));
                        cell = new PdfPCell(t.DefaultCell)
                        {
                            Phrase = new Phrase(GetFundDisplayText(db, () => c.FundName, () => c.FundDescription), font)
                        };
                        t.AddCell(cell);

                        cell = new PdfPCell(t.DefaultCell)
                        {
                            Colspan = (NumberOfColumns == 1) ? 3 : 1,
                            Phrase  = new Phrase(c.Description, font)
                        };
                        t.AddCell(cell);
                    }

                    ct.AddElement(t);
                }

                //-----Summary

                t = new PdfPTable((NumberOfColumns == 1)
                    ? new[] { 40f, 15f, 45f }
                    : new[] { 29f, 9f });

                t.WidthPercentage    = 100;
                t.DefaultCell.Border = Rectangle.NO_BORDER;
                t.HeaderRows         = 2;

                cell = new PdfPCell(t.DefaultCell)
                {
                    Colspan = (NumberOfColumns == 1) ? 3 : 2,
                    Phrase  = new Phrase("\n\nPeriod Summary\n", boldfont)
                };
                t.AddCell(cell);

                t.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
                t.AddCell(new Phrase("Fund", boldfont));

                cell = new PdfPCell(t.DefaultCell)
                {
                    HorizontalAlignment = Element.ALIGN_RIGHT,
                    Phrase = new Phrase("Amount", boldfont)
                };
                t.AddCell(cell);

                t.DefaultCell.Border = Rectangle.NO_BORDER;
                if (NumberOfColumns == 1)
                {
                    t.AddCell(new Phrase("", boldfont));
                }

                foreach (var c in APIContribution.GiftSummary(db, ci, FromDate, toDate, cs.Funds))
                {
                    t.AddCell(new Phrase(GetFundDisplayText(db, () => c.FundName, () => c.FundDescription), font));

                    cell = new PdfPCell(t.DefaultCell)
                    {
                        HorizontalAlignment = Element.ALIGN_RIGHT,
                        Phrase = new Phrase(c.Total.ToString2("N2"), font)
                    };
                    t.AddCell(cell);

                    if (NumberOfColumns == 1)
                    {
                        t.AddCell(new Phrase("", boldfont));
                    }
                }

                t.DefaultCell.Border = Rectangle.TOP_BORDER;
                t.AddCell(new Phrase("Total contributions for period", boldfont));

                cell = new PdfPCell(t.DefaultCell)
                {
                    HorizontalAlignment = Element.ALIGN_RIGHT,
                    Phrase = new Phrase(total.ToString("N2"), font)
                };
                t.AddCell(cell);

                if (NumberOfColumns == 1)
                {
                    cell = new PdfPCell(t.DefaultCell)
                    {
                        Phrase = new Phrase("")
                    };
                    t.AddCell(cell);
                }
                ct.AddElement(t);

                //------NonTax

                if (nontaxitems.Count > 0)
                {
                    t = new PdfPTable((NumberOfColumns == 1)
                        ? new[] { 18f, 25f, 15f, 15f, 30f }
                        : new[] { 18f, 24f, 15f });

                    t.WidthPercentage    = 100;
                    t.DefaultCell.Border = Rectangle.NO_BORDER;
                    t.HeaderRows         = 2;

                    cell = new PdfPCell(t.DefaultCell)
                    {
                        Colspan = (NumberOfColumns == 1) ? 5 : 3,
                        Phrase  = new Phrase("\n\nNon Tax-Deductible Items\n", boldfont)
                    };
                    t.AddCell(cell);

                    t.DefaultCell.Border = Rectangle.BOTTOM_BORDER;
                    t.AddCell(new Phrase("Date", boldfont));
                    t.AddCell(new Phrase("Description", boldfont));
                    cell = new PdfPCell(t.DefaultCell)
                    {
                        HorizontalAlignment = Element.ALIGN_RIGHT,
                        Phrase = new Phrase("Amount", boldfont)
                    };
                    t.AddCell(cell);
                    if (NumberOfColumns == 1)
                    {
                        t.AddCell(new Phrase("", boldfont));
                        t.AddCell(new Phrase("", boldfont));
                    }

                    t.DefaultCell.Border = Rectangle.NO_BORDER;

                    var ntotal = 0m;
                    foreach (var c in nontaxitems)
                    {
                        t.AddCell(new Phrase(c.ContributionDate.ToString2("d"), font));
                        t.AddCell(new Phrase(GetFundDisplayText(db, () => c.FundName, () => c.FundDescription), font));
                        cell = new PdfPCell(t.DefaultCell)
                        {
                            HorizontalAlignment = Element.ALIGN_RIGHT,
                            Phrase = new Phrase(c.ContributionAmount.ToString2("N2"), font)
                        };
                        t.AddCell(cell);
                        if (NumberOfColumns == 1)
                        {
                            t.AddCell(new Phrase("", boldfont));
                            t.AddCell(ShowNotes ? new Phrase(c.Description, font) : new Phrase("", font));
                        }
                        ntotal += (c.ContributionAmount ?? 0);
                    }

                    t.DefaultCell.Border = Rectangle.TOP_BORDER;
                    cell = new PdfPCell(t.DefaultCell)
                    {
                        Colspan = 2,
                        Phrase  = new Phrase("Total Non Tax-Deductible Items for period", boldfont)
                    };
                    t.AddCell(cell);
                    cell = new PdfPCell(t.DefaultCell)
                    {
                        HorizontalAlignment = Element.ALIGN_RIGHT,
                        Phrase = new Phrase(ntotal.ToString("N2"), font)
                    };
                    t.AddCell(cell);
                    if (NumberOfColumns == 1)
                    {
                        t.AddCell(new Phrase("", boldfont));
                        t.AddCell(new Phrase("", boldfont));
                    }

                    ct.AddElement(t);
                }

                var col    = 0;
                var status = 0;
                while (ColumnText.HasMoreText(status))
                {
                    switch (col)
                    {
                    case 0:
                        ct.SetSimpleColumn(doc.Left, doc.Bottom, doc.Left + colwidth, pos);
                        break;

                    case 1:
                        ct.SetSimpleColumn(doc.Right - colwidth, doc.Bottom, doc.Right, pos);
                        break;
                    }

                    status = ct.Go();
                    if (NumberOfColumns == 2)
                    {
                        ++col;
                        if (col <= 1)
                        {
                            continue;
                        }
                        col = 0;
                    }
                    pos = doc.Top;
                    doc.NewPage();
                }
                if (runningtotals != null)
                {
                    runningtotals.Processed += 1;
                    runningtotals.CurrSet    = set;
                    db.SubmitChanges();
                }
            }

            if (count == 0)
            {
                doc.NewPage();
                doc.Add(new Paragraph("no data"));
                var a = new Anchor("see this help document docs.touchpointsoftware.com/Finance/ContributionStatements.html")
                {
                    Reference = "https://docs.touchpointsoftware.com/Finance/ContributionStatements.html#troubleshooting"
                };
                doc.Add(a);
            }
            doc.Close();

            if (set == LastSet() && runningtotals != null)
            {
                runningtotals.Completed = DateTime.Now;
            }

            db.SubmitChanges();
        }
Beispiel #11
0
        public static void ForgotPassword(CMSDataContext db, string username)
        {
            // first find a user with the email address or username
            string msg  = null;
            var    path = new StringBuilder();

            username = username.Trim();
            var q = db.Users.Where(uu =>
                                   uu.Username == username ||
                                   uu.Person.EmailAddress == username ||
                                   uu.Person.EmailAddress2 == username
                                   );

            if (!q.Any())
            {
                path.Append("u0");
                // could not find a user to match
                // so we look for a person without an account, to match the email address

                var minage = db.Setting("MinimumUserAge", "16").ToInt();
                var q2     = from uu in db.People
                             where uu.EmailAddress == username || uu.EmailAddress2 == username
                             where uu.Age == null || uu.Age >= minage
                             select uu;
                if (q2.Any())
                {
                    path.Append("p+");
                    // we found person(s), not a user
                    // we will compose an email for each of them to create an account
                    foreach (var p in q2)
                    {
                        var ot = new OneTimeLink
                        {
                            Id          = Guid.NewGuid(),
                            Querystring = p.PeopleId.ToString()
                        };
                        db.OneTimeLinks.InsertOnSubmit(ot);
                        db.SubmitChanges();
                        var url = db.ServerLink($"/Account/CreateAccount/{ot.Id.ToCode()}");
                        msg = db.ContentHtml("ForgotPasswordReset", Resource1.AccountModel_ForgotPasswordReset);
                        msg = msg.Replace("{name}", p.Name);
                        msg = msg.Replace("{first}", p.PreferredName);
                        msg = msg.Replace("{email}", username);
                        msg = msg.Replace("{resetlink}", url);
                        db.SendEmail(Util.FirstAddress(DbUtil.AdminMail),
                                     "touchpointsoftware new password link", msg, Util.ToMailAddressList(p.EmailAddress ?? p.EmailAddress2));
                    }
                    DbUtil.LogActivity($"ForgotPassword ('{username}', {path})");
                    return;
                }
                path.Append("p0");
                if (!Util.ValidEmail(username))
                {
                    DbUtil.LogActivity($"ForgotPassword ('{username}', {path})");
                    return;
                }
                path.Append("n0");

                msg = db.ContentHtml("ForgotPasswordBadEmail", Resource1.AccountModel_ForgotPasswordBadEmail);
                msg = msg.Replace("{email}", username);
                db.SendEmail(Util.FirstAddress(DbUtil.AdminMail),
                             "Forgot password request for " + db.Setting("NameOfChurch", "bvcms"),
                             msg, Util.ToMailAddressList(username));
                DbUtil.LogActivity($"ForgotPassword ('{username}', {path})");
                return;
            }
            path.Append("u+");

            // we found users who match,
            // so now we send the users who match the username or email a set of links to all their usernames

            var sb       = new StringBuilder();
            var addrlist = new List <MailAddress>();

            foreach (var user in q)
            {
                Util.AddGoodAddress(addrlist, user.EmailAddress);
                user.ResetPasswordCode    = Guid.NewGuid();
                user.ResetPasswordExpires = DateTime.Now.AddHours(db.Setting("ResetPasswordExpiresHours", "24").ToInt());
                var link = db.ServerLink($"/Account/SetPassword/{user.ResetPasswordCode}");
                sb.Append($@"{user.Name}, <a href=""{link}"">{user.Username}</a><br>");
                db.SubmitChanges();
            }
            msg = db.ContentHtml("ForgotPasswordReset2", Resource1.AccountModel_ForgotPasswordReset2);
            msg = msg.Replace("{email}", username);
            msg = msg.Replace("{resetlink}", sb.ToString());
            db.SendEmail(Util.FirstAddress(DbUtil.AdminMail),
                         "TouchPoint password reset link", msg, addrlist);
            DbUtil.LogActivity($"ForgotPassword ('{username}', {path})");
        }