PageRenderTime 8ms CodeModel.GetById 19ms app.highlight 81ms RepoModel.GetById 2ms app.codeStats 0ms

/CmsData/Person.cs

https://bitbucket.org/mahalowe/bvcms
C# | 1188 lines | 1125 code | 25 blank | 38 comment | 371 complexity | febd0f15229b05f3f0445a5883123e87 MD5 | raw file
   1/* Author: David Carroll
   2 * Copyright (c) 2008, 2009 Bellevue Baptist Church 
   3 * Licensed under the GNU General Public License (GPL v2)
   4 * you may not use this code except in compliance with the License.
   5 * You may obtain a copy of the License at http://bvcms.codeplex.com/license 
   6 */
   7using System;
   8using System.Linq;
   9using UtilityExtensions;
  10using System.Text;
  11using System.Data.Linq;
  12using System.Data.Linq.Mapping;
  13using System.Data;
  14using System.Collections.Generic;
  15using System.Reflection;
  16using System.Linq.Expressions;
  17using System.ComponentModel;
  18using System.Transactions;
  19using System.Text.RegularExpressions;
  20using System.Threading;
  21using System.Data.Linq.SqlClient;
  22using System.Web;
  23using CmsData.Codes;
  24
  25namespace CmsData
  26{
  27
  28	public partial class Person
  29	{
  30		public static int[] DiscClassStatusCompletedCodes = new int[] 
  31        { 
  32            NewMemberClassStatusCode.AdminApproval, 
  33            NewMemberClassStatusCode.Attended, 
  34            NewMemberClassStatusCode.ExemptedChild 
  35        };
  36		public static int[] DropCodesThatDrop = new int[] 
  37        { 
  38            DropTypeCode.Administrative,
  39            DropTypeCode.AnotherDenomination,
  40            DropTypeCode.LetteredOut,
  41            DropTypeCode.Requested,
  42            DropTypeCode.Other,
  43        };
  44		public DateTime Now()
  45		{
  46			return Util.Now;
  47		}
  48		/* Origins
  49		10		Visit						Worship or BFClass Visit
  50		30		Referral					see Request
  51		40		Request						Task, use this for Referral too
  52		50		Deacon Telephone			Contact, type = phoned in
  53		60		Survey (EE)					Contact, EE
  54		70		Enrollment					Member of org
  55		80		Membership Decision			Contact, Type=Worship Visit
  56		90		Contribution				-1 peopleid in Excel with Name?
  57		98		Other						Task, use task description
  58		*/
  59		public string CityStateZip
  60		{
  61			get { return Util.FormatCSZ4(PrimaryCity, PrimaryState, PrimaryZip); }
  62		}
  63		public string CityStateZip5
  64		{
  65			get { return Util.FormatCSZ(PrimaryCity, PrimaryState, PrimaryZip); }
  66		}
  67		public string AddrCityStateZip
  68		{
  69			get { return PrimaryAddress + " " + CityStateZip; }
  70		}
  71		public string Addr2CityStateZip
  72		{
  73			get { return PrimaryAddress2 + " " + CityStateZip; }
  74		}
  75		public string FullAddress
  76		{
  77			get
  78			{
  79				var sb = new StringBuilder(PrimaryAddress + "\n");
  80				if (PrimaryAddress2.HasValue())
  81					sb.AppendLine(PrimaryAddress2);
  82				sb.Append(CityStateZip);
  83				return sb.ToString();
  84			}
  85		}
  86		public string SpouseName(CMSDataContext Db)
  87		{
  88			if (SpouseId.HasValue)
  89			{
  90				var q = from p in Db.People
  91						where p.PeopleId == SpouseId
  92						select p.Name;
  93				return q.SingleOrDefault();
  94			}
  95			return "";
  96		}
  97		public DateTime? BirthDate
  98		{
  99			get
 100			{
 101				DateTime dt;
 102				if (DateTime.TryParse(DOB, out dt))
 103					return dt;
 104				return null;
 105			}
 106		}
 107		public string DOB
 108		{
 109			get
 110			{ return Util.FormatBirthday(BirthYear, BirthMonth, BirthDay); }
 111			set
 112			{
 113				// reset all values before replacing b/c replacement may be partial
 114				BirthDay = null;
 115				BirthMonth = null;
 116				BirthYear = null;
 117				DateTime dt;
 118				if (DateTime.TryParse(value, out dt))
 119				{
 120					BirthDay = dt.Day;
 121					BirthMonth = dt.Month;
 122					if (Regex.IsMatch(value, @"\d+/\d+/\d+"))
 123						BirthYear = dt.Year;
 124				}
 125				else
 126				{
 127					int n;
 128					if (int.TryParse(value, out n))
 129						if (n >= 1 && n <= 12)
 130							BirthMonth = n;
 131						else
 132							BirthYear = n;
 133				}
 134			}
 135		}
 136		public DateTime? GetBirthdate()
 137		{
 138			DateTime dt;
 139			if (DateTime.TryParse(DOB, out dt))
 140				return dt;
 141			return null;
 142		}
 143		public int GetAge()
 144		{
 145			int years;
 146			var dt0 = GetBirthdate();
 147			if (!dt0.HasValue)
 148				return -1;
 149			var dt = dt0.Value;
 150			years = Util.Now.Year - dt.Year;
 151			if (Util.Now.Month < dt.Month || (Util.Now.Month == dt.Month && Util.Now.Day < dt.Day))
 152				years--;
 153			return years;
 154		}
 155		public void MovePersonStuff(CMSDataContext Db, int otherid)
 156		{
 157			var toperson = Db.People.Single(p => p.PeopleId == otherid);
 158			foreach (var om in this.OrganizationMembers)
 159			{
 160				var om2 = OrganizationMember.InsertOrgMembers(Db, om.OrganizationId, otherid, om.MemberTypeId, om.EnrollmentDate.Value, om.InactiveDate, om.Pending ?? false);
 161				Db.UpdateMainFellowship(om.OrganizationId);
 162				om2.CreatedBy = om.CreatedBy;
 163				om2.CreatedDate = om.CreatedDate;
 164				om2.AttendPct = om.AttendPct;
 165				om2.AttendStr = om.AttendStr;
 166				om2.LastAttended = om.LastAttended;
 167				om2.Request = om.Request;
 168				om2.Grade = om.Grade;
 169				om2.Amount = om.Amount;
 170				om2.RegisterEmail = om.RegisterEmail;
 171				om2.ShirtSize = om.ShirtSize;
 172				om2.Tickets = om.Tickets;
 173				om2.UserData = om.UserData;
 174				Db.SubmitChanges();
 175				foreach (var m in om.OrgMemMemTags)
 176					if (!om2.OrgMemMemTags.Any(mm => mm.MemberTagId == m.MemberTagId))
 177						om2.OrgMemMemTags.Add(new OrgMemMemTag { MemberTagId = m.MemberTagId });
 178				Db.SubmitChanges();
 179				Db.OrgMemMemTags.DeleteAllOnSubmit(om.OrgMemMemTags);
 180				Db.SubmitChanges();
 181			}
 182			Db.OrganizationMembers.DeleteAllOnSubmit(this.OrganizationMembers);
 183			Db.SubmitChanges();
 184
 185			foreach (var et in this.EnrollmentTransactions)
 186				et.PeopleId = otherid;
 187			Db.SubmitChanges();
 188
 189			var q = from a in Db.Attends
 190					where a.PeopleId == this.PeopleId
 191					let oa = Db.Attends.SingleOrDefault(a2 => a2.MeetingId == a.MeetingId && a2.PeopleId == otherid)
 192					where oa == null
 193					select a;
 194			var list = q.ToList();
 195			foreach (var a in list)
 196			{
 197				a.PeopleId = otherid;
 198				Db.SubmitChanges();
 199			}
 200
 201			foreach (var c in this.Contributions)
 202				c.PeopleId = otherid;
 203			foreach (var u in this.Users)
 204				u.PeopleId = otherid;
 205			if (this.Volunteers.Any() && !toperson.Volunteers.Any())
 206				foreach (var v in this.Volunteers)
 207				{
 208					var vv = new Volunteer
 209					{
 210						PeopleId = otherid,
 211						Children = v.Children,
 212						Comments = v.Comments,
 213						Leader = v.Leader,
 214						ProcessedDate = v.ProcessedDate,
 215						Standard = v.Standard,
 216						StatusId = v.StatusId,
 217					};
 218					Db.Volunteers.InsertOnSubmit(vv);
 219				}
 220			foreach (var v in this.VolunteerForms)
 221				v.PeopleId = otherid;
 222			foreach (var c in this.contactsMade)
 223			{
 224				var cp = Db.Contactors.SingleOrDefault(c2 => c2.PeopleId == otherid && c.ContactId == c2.ContactId);
 225				if (cp == null)
 226					c.contact.contactsMakers.Add(new Contactor { PeopleId = otherid });
 227				Db.Contactors.DeleteOnSubmit(c);
 228			}
 229			foreach (var c in this.contactsHad)
 230			{
 231				var cp = Db.Contactees.SingleOrDefault(c2 => c2.PeopleId == otherid && c.ContactId == c2.ContactId);
 232				if (cp == null)
 233					c.contact.contactees.Add(new Contactee { PeopleId = otherid });
 234				Db.Contactees.DeleteOnSubmit(c);
 235			}
 236			foreach (var e in this.PeopleExtras)
 237			{
 238				var cp = Db.PeopleExtras.FirstOrDefault(c2 => c2.PeopleId == otherid && c2.Field == e.Field);
 239				var e2 = new PeopleExtra
 240				{
 241					PeopleId = otherid,
 242					Field = e.Field,
 243					Data = e.Data,
 244					StrValue = e.StrValue,
 245					DateValue = e.DateValue,
 246					IntValue = e.IntValue,
 247					IntValue2 = e.IntValue2,
 248					TransactionTime = e.TransactionTime
 249				};
 250				if (cp != null)
 251					e2.Field = e.Field + "_mv";
 252				Db.PeopleExtras.InsertOnSubmit(e2);
 253				Db.PeopleExtras.DeleteOnSubmit(e);
 254			}
 255
 256			var torecreg = toperson.RecRegs.SingleOrDefault();
 257			var frrecreg = RecRegs.SingleOrDefault();
 258			if (torecreg == null && frrecreg != null)
 259				frrecreg.PeopleId = otherid;
 260			if (torecreg != null && frrecreg != null)
 261			{
 262				torecreg.Comments = frrecreg.Comments + "\n" + torecreg.Comments;
 263				if (frrecreg.ShirtSize.HasValue())
 264					torecreg.ShirtSize = frrecreg.ShirtSize;
 265				if (frrecreg.MedicalDescription.HasValue())
 266					torecreg.MedicalDescription = frrecreg.MedicalDescription;
 267				if (frrecreg.Doctor.HasValue())
 268					torecreg.Doctor = frrecreg.Doctor;
 269				if (frrecreg.Docphone.HasValue())
 270					torecreg.Docphone = frrecreg.Docphone;
 271				if (frrecreg.MedAllergy.HasValue)
 272					torecreg.MedAllergy = frrecreg.MedAllergy;
 273				if (frrecreg.Tylenol.HasValue)
 274					torecreg.Tylenol = frrecreg.Tylenol;
 275				if (frrecreg.Robitussin.HasValue)
 276					torecreg.Robitussin = frrecreg.Robitussin;
 277				if (frrecreg.Advil.HasValue)
 278					torecreg.Advil = frrecreg.Advil;
 279				if (frrecreg.Maalox.HasValue)
 280					torecreg.Maalox = frrecreg.Maalox;
 281				if (frrecreg.Insurance.HasValue())
 282					torecreg.Insurance = frrecreg.Insurance;
 283				if (frrecreg.Policy.HasValue())
 284					torecreg.Policy = frrecreg.Policy;
 285				if (frrecreg.Mname.HasValue())
 286					torecreg.Mname = frrecreg.Mname;
 287				if (frrecreg.Fname.HasValue())
 288					torecreg.Fname = frrecreg.Fname;
 289				if (frrecreg.Emcontact.HasValue())
 290					torecreg.Emcontact = frrecreg.Emcontact;
 291				if (frrecreg.Emphone.HasValue())
 292					torecreg.Emphone = frrecreg.Emphone;
 293				if (frrecreg.ActiveInAnotherChurch.HasValue)
 294					torecreg.ActiveInAnotherChurch = frrecreg.ActiveInAnotherChurch;
 295			}
 296			var mg = Db.ManagedGivings.FirstOrDefault(mm => mm.PeopleId == otherid);
 297			if (mg != null)
 298				foreach (var v in this.ManagedGivings)
 299				{
 300					var qq = from ra in Db.RecurringAmounts
 301							 where ra.PeopleId == PeopleId
 302							 select ra;
 303					foreach (var ra in qq)
 304						ra.PeopleId = otherid;
 305					v.PeopleId = otherid;
 306				}
 307			var pi = Db.PaymentInfos.FirstOrDefault(mm => mm.PeopleId == otherid);
 308			if (pi != null)
 309				foreach (var i in PaymentInfos)
 310					i.PeopleId = otherid;
 311
 312			Db.SubmitChanges();
 313		}
 314		public bool PurgePerson(CMSDataContext Db)
 315		{
 316			try
 317			{
 318				Db.PurgePerson(PeopleId);
 319			}
 320			catch
 321			{
 322				return false;
 323			}
 324			return true;
 325
 326		}
 327		public bool Deceased
 328		{
 329			get { return DeceasedDate.HasValue; }
 330		}
 331		public string FromEmail
 332		{
 333			get { return Util.FullEmail(EmailAddress, Name); }
 334		}
 335		public string FromEmail2
 336		{
 337			get { return Util.FullEmail(EmailAddress2, Name); }
 338		}
 339		public static void NameSplit(string name, out string First, out string Last)
 340		{
 341			First = "";
 342			Last = "";
 343			if (!name.HasValue())
 344				return;
 345			var a = name.Trim().Split(' ');
 346			if (a.Length > 1)
 347			{
 348				First = a[0];
 349				Last = a[1];
 350			}
 351			else
 352				Last = a[0];
 353
 354		}
 355		public static Person Add(Family fam, int position, Tag tag, string name, string dob, bool Married, int gender, int originId, int? EntryPointId)
 356		{
 357			string First, Last;
 358			NameSplit(name, out First, out Last);
 359			if (!First.HasValue() || Married)
 360				switch (gender)
 361				{
 362					case 0: First = "A"; break;
 363					case 1: if (!First.HasValue()) First = "Husbander"; break;
 364					case 2: First = "Wifey"; break;
 365				}
 366			return Add(fam, position, tag, First, null, Last, dob, Married, gender, originId, EntryPointId);
 367		}
 368		public static Person Add(Family fam,
 369			int position,
 370			Tag tag,
 371			string firstname,
 372			string nickname,
 373			string lastname,
 374			string dob,
 375			int MarriedCode,
 376			int gender,
 377			int originId,
 378			int? EntryPointId)
 379		{
 380			return Person.Add(DbUtil.Db, true, fam, position, tag, firstname, nickname, lastname, dob, MarriedCode, gender, originId, EntryPointId);
 381		}
 382		public static Person Add(CMSDataContext Db, Family fam, string firstname, string nickname, string lastname, DateTime? dob)
 383		{
 384			return Person.Add(Db, false, fam, 20, null, firstname, nickname, lastname, dob.FormatDate(), 0, 0, 0, 0);
 385		}
 386
 387		public static Person Add(CMSDataContext Db, bool SendNotices, Family fam, int position, Tag tag, string firstname, string nickname, string lastname, string dob, int MarriedCode, int gender, int originId, int? EntryPointId, bool testing = false)
 388		{
 389			var p = new Person();
 390			p.CreatedDate = Util.Now;
 391			p.CreatedBy = Util.UserId;
 392			Db.People.InsertOnSubmit(p);
 393			p.PositionInFamilyId = position;
 394			p.AddressTypeId = 10;
 395
 396			if (firstname.HasValue())
 397				p.FirstName = firstname.Trim().ToProper().Truncate(25);
 398			else
 399				p.FirstName = "";
 400
 401			if (nickname.HasValue())
 402				p.NickName = nickname.Trim().ToProper().Truncate(15);
 403
 404			if (lastname.HasValue())
 405				p.LastName = lastname.Trim().ToProper().Truncate(30);
 406			else
 407				p.LastName = "?";
 408
 409			p.GenderId = gender;
 410			if (p.GenderId == 99)
 411				p.GenderId = 0;
 412			p.MaritalStatusId = MarriedCode;
 413
 414			DateTime dt;
 415			if (Util.DateValid(dob, out dt))
 416			{
 417				while (dt.Year < 1900)
 418					dt = dt.AddYears(100);
 419				if (dt > Util.Now)
 420					dt = dt.AddYears(-100);
 421				p.BirthDay = dt.Day;
 422				p.BirthMonth = dt.Month;
 423				p.BirthYear = dt.Year;
 424				if (p.GetAge() < 18 && MarriedCode == 0)
 425					p.MaritalStatusId = MaritalStatusCode.Single;
 426			}
 427			else if (DateTime.TryParse(dob, out dt))
 428			{
 429				p.BirthDay = dt.Day;
 430				p.BirthMonth = dt.Month;
 431				if (Regex.IsMatch(dob, @"\d+[-/]\d+[-/]\d+"))
 432				{
 433					p.BirthYear = dt.Year;
 434					while (p.BirthYear < 1900)
 435						p.BirthYear += 100;
 436					if (p.GetAge() < 18 && MarriedCode == 0)
 437						p.MaritalStatusId = MaritalStatusCode.Single;
 438				}
 439			}
 440
 441			p.MemberStatusId = MemberStatusCode.JustAdded;
 442			if (fam == null)
 443			{
 444				fam = new Family();
 445				Db.Families.InsertOnSubmit(fam);
 446				p.Family = fam;
 447			}
 448			else
 449				fam.People.Add(p);
 450
 451			var PrimaryCount = fam.People.Where(c => c.PositionInFamilyId == PositionInFamily.PrimaryAdult).Count();
 452			if (PrimaryCount > 2 && p.PositionInFamilyId == PositionInFamily.PrimaryAdult)
 453				p.PositionInFamilyId = PositionInFamily.SecondaryAdult;
 454
 455			if (tag != null)
 456				tag.PersonTags.Add(new TagPerson { Person = p });
 457
 458			p.OriginId = originId;
 459			p.EntryPointId = EntryPointId;
 460			p.FixTitle();
 461			if (!testing)
 462				Db.SubmitChanges();
 463			if (SendNotices)
 464			{
 465				if (Util.UserPeopleId.HasValue
 466						&& Util.UserPeopleId.Value != Db.NewPeopleManagerId
 467						&& !HttpContext.Current.User.IsInRole("OrgMembersOnly")
 468						&& HttpContext.Current.User.IsInRole("Access"))
 469					Task.AddNewPerson(p.PeopleId);
 470				else
 471					Db.Email(Util.SysFromEmail, Db.GetNewPeopleManagers(),
 472							"Just Added Person on " + Db.Host, "{0} ({1})".Fmt(p.Name, p.PeopleId));
 473			}
 474			return p;
 475		}
 476		public static Person Add(Family fam, int position, Tag tag, string firstname, string nickname, string lastname, string dob, bool Married, int gender, int originId, int? EntryPointId)
 477		{
 478			return Add(fam, position, tag, firstname, nickname, lastname, dob, Married ? 20 : 10, gender, originId, EntryPointId);
 479		}
 480		public List<Duplicate> PossibleDuplicates()
 481		{
 482			var fone = Util.GetDigits(Util.PickFirst(CellPhone, HomePhone));
 483			using (var ctx = new CMSDataContext(Util.ConnectionString))
 484			{
 485				ctx.SetNoLock();
 486				string street = GetStreet(ctx) ?? "--";
 487				var nick = NickName ?? "--";
 488				var maid = MaidenName ?? "--";
 489				var em = EmailAddress ?? "--";
 490				if (!em.HasValue())
 491					em = "--";
 492				var bd = BirthDay ?? -1;
 493				var bm = BirthMonth ?? -1;
 494				var byr = BirthYear ?? -1;
 495				var q = from p in ctx.People
 496						let firstmatch = p.FirstName == FirstName || (p.NickName ?? "") == FirstName || (p.MiddleName ?? "") == FirstName
 497									|| p.FirstName == nick || (p.NickName ?? "") == nick || (p.MiddleName ?? "") == nick
 498						let lastmatch = p.LastName == LastName || (p.MaidenName ?? "") == LastName
 499									|| (p.MaidenName ?? "") == maid || p.LastName == maid
 500						let nobday = (p.BirthMonth == null && p.BirthYear == null && p.BirthDay == null)
 501									|| (BirthMonth == null && BirthYear == null && BirthDay == null)
 502						let bdmatch = (p.BirthDay ?? -2) == bd && (p.BirthMonth ?? -2) == bm && (p.BirthYear ?? -2) == byr
 503						let bdmatchpart = (p.BirthDay ?? -2) == bd && (p.BirthMonth ?? -2) == bm
 504						let emailmatch = p.EmailAddress != null && p.EmailAddress == em
 505						let addrmatch = (p.AddressLineOne ?? "").Contains(street) || (p.Family.AddressLineOne ?? "").Contains(street)
 506						let phonematch = (p.CellPhoneLU == CellPhoneLU
 507											|| p.CellPhoneLU == Family.HomePhoneLU
 508											|| p.CellPhone == WorkPhoneLU
 509											|| p.Family.HomePhoneLU == CellPhoneLU
 510											|| p.Family.HomePhoneLU == Family.HomePhoneLU
 511											|| p.Family.HomePhoneLU == WorkPhoneLU
 512											|| p.WorkPhoneLU == CellPhoneLU
 513											|| p.WorkPhoneLU == Family.HomePhoneLU
 514											|| p.WorkPhoneLU == WorkPhoneLU)
 515						let samefamily = p.FamilyId == FamilyId
 516						let nmatches = samefamily ? 0 :
 517										(firstmatch ? 1 : 0)
 518										+ (bdmatch ? 1 : 0)
 519										+ (emailmatch ? 1 : 0)
 520										+ (phonematch ? 1 : 0)
 521										+ (addrmatch ? 1 : 0)
 522						where (lastmatch && nmatches >= 3)
 523								|| ((firstmatch && lastmatch && bdmatchpart) && p.PeopleId != PeopleId)
 524						select new Duplicate
 525												{
 526													PeopleId = p.PeopleId,
 527													First = p.FirstName,
 528													Last = p.LastName,
 529													Nick = p.NickName,
 530													Middle = p.MiddleName,
 531													BMon = p.BirthMonth,
 532													BDay = p.BirthDay,
 533													BYear = p.BirthYear,
 534													Email = p.EmailAddress,
 535													FamAddr = p.Family.AddressLineOne,
 536													PerAddr = p.AddressLineOne,
 537													Member = p.MemberStatus.Description
 538												};
 539				var list = q.ToList();
 540				return list;
 541			}
 542		}
 543		public class Duplicate
 544		{
 545			public bool s0 { get; set; }
 546			public bool s1 { get; set; }
 547			public bool s2 { get; set; }
 548			public bool s3 { get; set; }
 549			public bool s4 { get; set; }
 550			public bool s5 { get; set; }
 551			public bool s6 { get; set; }
 552			public int PeopleId { get; set; }
 553			public string First { get; set; }
 554			public string Last { get; set; }
 555			public string Nick { get; set; }
 556			public string Middle { get; set; }
 557			public string Maiden { get; set; }
 558			public int? BMon { get; set; }
 559			public int? BDay { get; set; }
 560			public int? BYear { get; set; }
 561			public string Email { get; set; }
 562			public string FamAddr { get; set; }
 563			public string PerAddr { get; set; }
 564			public string Member { get; set; }
 565		}
 566		public List<Duplicate> PossibleDuplicates2()
 567		{
 568			using (var ctx = new CMSDataContext(Util.ConnectionString))
 569			{
 570				ctx.SetNoLock();
 571				string street = GetStreet(ctx) ?? "--";
 572				var nick = NickName ?? "--";
 573				var maid = MaidenName ?? "--";
 574				var em = EmailAddress ?? "--";
 575				if (!em.HasValue())
 576					em = "--";
 577				var bd = BirthDay ?? -1;
 578				var bm = BirthMonth ?? -1;
 579				var byr = BirthYear ?? -1;
 580				var q = from p in ctx.People
 581						let firstmatch = p.FirstName == FirstName || (p.NickName ?? "") == FirstName || (p.MiddleName ?? "") == FirstName
 582									|| p.FirstName == nick || (p.NickName ?? "") == nick || (p.MiddleName ?? "") == nick
 583						let lastmatch = p.LastName == LastName || (p.MaidenName ?? "") == LastName
 584									|| (p.MaidenName ?? "") == maid || p.LastName == maid
 585						let nobday = (p.BirthMonth == null && p.BirthYear == null && p.BirthDay == null)
 586									|| (BirthMonth == null && BirthYear == null && BirthDay == null)
 587						let bdmatch = (p.BirthDay ?? -2) == bd && (p.BirthMonth ?? -2) == bm && (p.BirthYear ?? -2) == byr
 588						let bdmatchpart = (p.BirthDay ?? -2) == bd && (p.BirthMonth ?? -2) == bm
 589						let emailmatch = p.EmailAddress != null && p.EmailAddress == em
 590						let addrmatch = (p.AddressLineOne ?? "").Contains(street) || (p.Family.AddressLineOne ?? "").Contains(street)
 591						let s1 = firstmatch && bdmatchpart
 592						let s2 = firstmatch && bdmatch
 593						let s3 = firstmatch && lastmatch && nobday
 594						let s4 = firstmatch && addrmatch
 595						let s5 = firstmatch && emailmatch
 596						let s6 = lastmatch && bdmatch
 597						where p.FamilyId != FamilyId && (s1 || s2 || s3 || s4 || s5 || s6)
 598						select new Duplicate
 599						{
 600							s1 = s1,
 601							s2 = s2,
 602							s3 = s3,
 603							s4 = s4,
 604							s5 = s5,
 605							s6 = s6,
 606							PeopleId = p.PeopleId,
 607							First = p.FirstName,
 608							Last = p.LastName,
 609							Nick = p.NickName,
 610							Middle = p.MiddleName,
 611							BMon = p.BirthMonth,
 612							BDay = p.BirthDay,
 613							BYear = p.BirthYear,
 614							Email = p.EmailAddress,
 615							FamAddr = p.Family.AddressLineOne,
 616							PerAddr = p.AddressLineOne,
 617							Member = p.MemberStatus.Description
 618						};
 619				try
 620				{
 621					var list = q.ToList();
 622					var t = new Duplicate
 623					{
 624						s0 = true,
 625						PeopleId = PeopleId,
 626						First = FirstName,
 627						Last = LastName,
 628						Nick = NickName,
 629						Middle = MiddleName,
 630						BMon = BirthMonth,
 631						BDay = BirthDay,
 632						BYear = BirthYear,
 633						Email = EmailAddress,
 634						FamAddr = Family.AddressLineOne,
 635						PerAddr = AddressLineOne,
 636						Member = MemberStatus.Description
 637					};
 638					list.Insert(0, t);
 639
 640					return list;
 641				}
 642				catch (Exception)
 643				{
 644					throw;
 645				}
 646			}
 647		}
 648		private string GetStreet(CMSDataContext db)
 649		{
 650			if (!PrimaryAddress.HasValue())
 651				return null;
 652			try
 653			{
 654				var s = PrimaryAddress.Replace(".", "");
 655				var a = s.SplitStr(" ");
 656				var la = a.ToList();
 657				if (la[0].AllDigits())
 658					la.RemoveAt(0);
 659				var quadrants = new string[] { "N", "NORTH", "S", "SOUTH", "E", "EAST", "W", "WEST", "NE", "NORTHEAST", "NW", "NORTHWEST", "SE", "SOUTHEAST", "SW", "SOUTHWEST" };
 660				if (quadrants.Contains(a[0].ToUpper()))
 661					la.RemoveAt(0);
 662				la.Reverse();
 663				if (la[0].AllDigits())
 664					la.RemoveAt(0);
 665				if (la[0].StartsWith("#"))
 666					la.RemoveAt(0);
 667				var apt = new string[] { "APARTMENT", "APT", "BUILDING", "BLDG", "DEPARTMENT", "DEPT", "FLOOR", "FL", "HANGAR", "HNGR", "LOT", "LOT", "PIER", "PIER", "ROOM", "RM", "SLIP", "SLIP", "SPACE", "SPC", "STOP", "STOP", "SUITE", "STE", "TRAILER", "TRLR", "UNIT", "UNIT", "UPPER", "UPPR",
 668        	                    "BASEMENT","BSMT", "FRONT","FRNT", "LOBBY","LBBY", "LOWER","LOWR", "OFFICE","OFC", "PENTHOUSE","PH", "REAR", "SIDE" };
 669				if (apt.Contains(la[0].ToUpper()))
 670					la.RemoveAt(0);
 671				if (db.StreetTypes.Any(t => t.Type == la[0]))
 672					la.RemoveAt(0);
 673				la.Reverse();
 674				var street = string.Join(" ", la);
 675				return street;
 676			}
 677			catch (Exception)
 678			{
 679				return null;
 680			}
 681		}
 682		public void FixTitle()
 683		{
 684			if (GenderId == 1)
 685				TitleCode = "Mr.";
 686			else if (GenderId == 2)
 687				if (MaritalStatusId == 20 || MaritalStatusId == 50)
 688					TitleCode = "Mrs.";
 689				else
 690					TitleCode = "Ms.";
 691		}
 692		public string OptOutKey(string FromEmail)
 693		{
 694			return Util.EncryptForUrl("{0}|{1}".Fmt(PeopleId, FromEmail));
 695		}
 696
 697		public static bool ToggleTag(int PeopleId, string TagName, int? OwnerId, int TagTypeId)
 698		{
 699			var Db = DbUtil.Db;
 700			var tag = Db.FetchOrCreateTag(TagName, OwnerId, TagTypeId);
 701			if (tag == null)
 702				throw new Exception("ToggleTag, tag '{0}' not found");
 703			var tp = Db.TagPeople.SingleOrDefault(t => t.Id == tag.Id && t.PeopleId == PeopleId);
 704			if (tp == null)
 705			{
 706				tag.PersonTags.Add(new TagPerson { PeopleId = PeopleId });
 707				return true;
 708			}
 709			Db.TagPeople.DeleteOnSubmit(tp);
 710			return false;
 711		}
 712		public static void Tag(CMSDataContext Db, int PeopleId, string TagName, int? OwnerId, int TagTypeId)
 713		{
 714			var tag = Db.FetchOrCreateTag(TagName, OwnerId, TagTypeId);
 715			var tp = Db.TagPeople.SingleOrDefault(t => t.Id == tag.Id && t.PeopleId == PeopleId);
 716			var isperson = Db.People.Count(p => p.PeopleId == PeopleId) > 0;
 717			if (tp == null && isperson)
 718				tag.PersonTags.Add(new TagPerson { PeopleId = PeopleId });
 719		}
 720		public static void UnTag(int PeopleId, string TagName, int? OwnerId, int TagTypeId)
 721		{
 722			var Db = DbUtil.Db;
 723			var tag = Db.FetchOrCreateTag(TagName, OwnerId, TagTypeId);
 724			var tp = Db.TagPeople.SingleOrDefault(t => t.Id == tag.Id && t.PeopleId == PeopleId);
 725			if (tp != null)
 726				Db.TagPeople.DeleteOnSubmit(tp);
 727		}
 728		partial void OnNickNameChanged()
 729		{
 730			if (NickName != null && NickName.Trim() == String.Empty)
 731				NickName = null;
 732		}
 733		private bool _DecisionTypeIdChanged;
 734		public bool DecisionTypeIdChanged
 735		{
 736			get { return _DecisionTypeIdChanged; }
 737		}
 738		partial void OnDecisionTypeIdChanged()
 739		{
 740			_DecisionTypeIdChanged = true;
 741		}
 742		private bool _NewMemberClassStatusIdChanged;
 743		public bool NewMemberClassStatusIdChanged
 744		{
 745			get { return _NewMemberClassStatusIdChanged; }
 746		}
 747		partial void OnNewMemberClassStatusIdChanged()
 748		{
 749			_NewMemberClassStatusIdChanged = true;
 750		}
 751		private bool _BaptismStatusIdChanged;
 752		public bool BaptismStatusIdChanged
 753		{
 754			get { return _BaptismStatusIdChanged; }
 755		}
 756		partial void OnBaptismStatusIdChanged()
 757		{
 758			_BaptismStatusIdChanged = true;
 759		}
 760		private bool _DeceasedDateChanged;
 761		public bool DeceasedDateChanged
 762		{
 763			get { return _DeceasedDateChanged; }
 764		}
 765		partial void OnDeceasedDateChanged()
 766		{
 767			_DeceasedDateChanged = true;
 768		}
 769		private bool _DropCodeIdChanged;
 770		public bool DropCodeIdChanged
 771		{
 772			get { return _DropCodeIdChanged; }
 773		}
 774		partial void OnDropCodeIdChanged()
 775		{
 776			_DropCodeIdChanged = true;
 777		}
 778		//internal static int FindResCode(string zipcode)
 779		//{
 780		//    if (zipcode.HasValue() && zipcode.Length >= 5)
 781		//    {
 782		//        var z5 = zipcode.Substring(0, 5);
 783		//        var z = DbUtil.Db.Zips.SingleOrDefault(zip => z5 == zip.ZipCode);
 784		//        if (z == null)
 785		//            return 30;
 786		//        return z.MetroMarginalCode ?? 30;
 787		//    }
 788		//    return 30;
 789		//}
 790		private bool? _CanUserEditAll;
 791		public bool CanUserEditAll
 792		{
 793			get
 794			{
 795				if (!_CanUserEditAll.HasValue)
 796					_CanUserEditAll = HttpContext.Current.User.IsInRole("Edit");
 797				return _CanUserEditAll.Value;
 798			}
 799		}
 800		private bool? _CanUserEditFamilyAddress;
 801		public bool CanUserEditFamilyAddress
 802		{
 803			get
 804			{
 805				if (!_CanUserEditFamilyAddress.HasValue)
 806					_CanUserEditFamilyAddress = CanUserEditAll
 807						|| Util.UserPeopleId == Family.HeadOfHouseholdId
 808						|| Util.UserPeopleId == Family.HeadOfHouseholdSpouseId;
 809				return _CanUserEditFamilyAddress.Value;
 810			}
 811		}
 812		private bool? _CanUserEditBasic;
 813		public bool CanUserEditBasic
 814		{
 815			get
 816			{
 817				if (!_CanUserEditBasic.HasValue)
 818					_CanUserEditBasic = CanUserEditFamilyAddress
 819						|| Util.UserPeopleId == PeopleId;
 820				return _CanUserEditBasic.Value;
 821			}
 822		}
 823		private bool? _CanUserSee;
 824		public bool CanUserSee
 825		{
 826			get
 827			{
 828				if (!_CanUserSee.HasValue)
 829					_CanUserSee = CanUserEditBasic
 830						|| Family.People.Any(m => m.PeopleId == Util.UserPeopleId);
 831				return _CanUserSee.Value;
 832			}
 833		}
 834
 835		//partial void OnZipCodeChanged()
 836		//{
 837		//    ResCodeId = FindResCode(Db, ZipCode);
 838		//}
 839		//partial void OnAltZipCodeChanged()
 840		//{
 841		//    AltResCodeId = FindResCode(Db, AltZipCode);
 842		//}
 843		public RecReg GetRecReg()
 844		{
 845			var rr = RecRegs.SingleOrDefault();
 846			if (rr == null)
 847				return new RecReg();
 848			return rr;
 849		}
 850		public RecReg SetRecReg()
 851		{
 852			var rr = RecRegs.SingleOrDefault();
 853			if (rr == null)
 854			{
 855				rr = new RecReg();
 856				RecRegs.Add(rr);
 857			}
 858			return rr;
 859		}
 860		public Contact AddContactReceived(CMSDataContext Db, DateTime dt, int type, int reason, string notes)
 861		{
 862			var c = new Contact
 863			{
 864				CreatedDate = Util.Now,
 865				CreatedBy = Util.UserId1,
 866				ContactDate = dt,
 867				ContactTypeId = type,
 868				ContactReasonId = reason,
 869				Comments = notes
 870			};
 871			Db.Contacts.InsertOnSubmit(c);
 872			c.contactees.Add(new Contactee { PeopleId = PeopleId });
 873			Db.SubmitChanges();
 874			return c;
 875		}
 876
 877		private StringBuilder psbDefault;
 878		public void UpdateValue(string field, object value)
 879		{
 880			if (psbDefault == null)
 881				psbDefault = new StringBuilder();
 882			UpdateValue(psbDefault, field, value);
 883		}
 884		public void UpdateValue(StringBuilder psb, string field, object value)
 885		{
 886			if (value is string)
 887				value = ((string)value).TrimEnd();
 888			var o = Util.GetProperty(this, field);
 889			if (o is string)
 890				o = ((string)o).TrimEnd();
 891			if (o == null && value == null)
 892				return;
 893			if (o != null && o.Equals(value))
 894				return;
 895			if (o == null && value is string && !((string)value).HasValue())
 896				return;
 897			if (value == null && o is string && !((string)o).HasValue())
 898				return;
 899			psb.AppendFormat("<tr><td>{0}</td><td>{1}</td><td>{2}</td></tr>\n", field, o, value ?? "(null)");
 900			Util.SetProperty(this, field, value);
 901		}
 902		public void UpdateValueFromText(StringBuilder psb, string field, string value)
 903		{
 904			value = value.TrimEnd();
 905			var o = Util.GetProperty(this, field);
 906			if (o is string)
 907				o = ((string)o).TrimEnd();
 908			if (o == null && value == null)
 909				return;
 910			if (o != null && o.Equals(value))
 911				return;
 912			if (o == null && value is string && !((string)value).HasValue())
 913				return;
 914			if (value == null && o is string && !((string)o).HasValue())
 915				return;
 916			psb.AppendFormat("<tr><td>{0}</td><td>{1}</td><td>{2}</td></tr>\n", field, o, value ?? "(null)");
 917			Util.SetPropertyFromText(this, field, value);
 918		}
 919		public void LogChanges(CMSDataContext Db, int UserPeopleId)
 920		{
 921			if (psbDefault != null)
 922				LogChanges(Db, psbDefault, UserPeopleId);
 923		}
 924		public void LogChanges(CMSDataContext Db, StringBuilder psb, int UserPeopleId)
 925		{
 926			if (psb.Length > 0)
 927			{
 928				var c = new ChangeLog
 929				{
 930					UserPeopleId = UserPeopleId,
 931					PeopleId = PeopleId,
 932					Field = "Basic Info",
 933					Data = "<table>\n" + psb.ToString() + "</table>",
 934					Created = Util.Now
 935				};
 936				Db.ChangeLogs.InsertOnSubmit(c);
 937			}
 938		}
 939		public void LogPictureUpload(CMSDataContext Db, int UserPeopleId)
 940		{
 941			var c = new ChangeLog
 942			{
 943				UserPeopleId = UserPeopleId,
 944				PeopleId = PeopleId,
 945				Field = "Basic Info",
 946				Data = "<table>\n<tr><td>Picture</td><td></td><td>(new upload)</td></tr>\n</table>",
 947				Created = Util.Now
 948			};
 949			Db.ChangeLogs.InsertOnSubmit(c);
 950		}
 951		public override string ToString()
 952		{
 953			return Name + "(" + PeopleId + ")";
 954		}
 955		public void SetExtra(string field, string value)
 956		{
 957			var e = PeopleExtras.FirstOrDefault(ee => ee.Field == field);
 958			if (e == null)
 959			{
 960				e = new PeopleExtra { Field = field, PeopleId = PeopleId, TransactionTime = DateTime.Now };
 961				this.PeopleExtras.Add(e);
 962			}
 963			e.StrValue = value;
 964		}
 965		public string GetExtra(string field)
 966		{
 967			var e = PeopleExtras.SingleOrDefault(ee => ee.Field == field);
 968			if (e == null)
 969				return "";
 970			if (e.StrValue.HasValue())
 971				return e.StrValue;
 972			if (e.Data.HasValue())
 973				return e.Data;
 974			if (e.DateValue.HasValue)
 975				return e.DateValue.FormatDate();
 976			if (e.IntValue.HasValue)
 977				return e.IntValue.ToString();
 978			return e.BitValue.ToString();
 979		}
 980		public PeopleExtra GetExtraValue(string field)
 981		{
 982			if (!field.HasValue())
 983				field = "blank";
 984			field = field.Replace(",", "_");
 985			var ev = PeopleExtras.AsEnumerable().FirstOrDefault(ee => string.Compare(ee.Field, field, ignoreCase: true) == 0);
 986			if (ev == null)
 987			{
 988				ev = new PeopleExtra
 989				{
 990					Field = field,
 991					TransactionTime = DateTime.Now
 992				};
 993				PeopleExtras.Add(ev);
 994			}
 995			return ev;
 996		}
 997		public void RemoveExtraValue(CMSDataContext Db, string field)
 998		{
 999			var ev = PeopleExtras.AsEnumerable().FirstOrDefault(ee => string.Compare(ee.Field, field, ignoreCase: true) == 0);
1000			if (ev != null)
1001				Db.PeopleExtras.DeleteOnSubmit(ev);
1002		}
1003		public void AddEditExtraValue(string field, string value)
1004		{
1005			if (!field.HasValue())
1006				return;
1007			if (!value.HasValue())
1008				return;
1009			var ev = GetExtraValue(field);
1010			ev.StrValue = value;
1011		}
1012		public void AddEditExtraDate(string field, DateTime? value)
1013		{
1014			if (!value.HasValue)
1015				return;
1016			var ev = GetExtraValue(field);
1017			ev.DateValue = value;
1018		}
1019		public void AddEditExtraData(string field, string value)
1020		{
1021			if (!value.HasValue())
1022				return;
1023			var ev = GetExtraValue(field);
1024			ev.Data = value;
1025		}
1026		public void AddToExtraData(string field, string value)
1027		{
1028			if (!value.HasValue())
1029				return;
1030			var ev = GetExtraValue(field);
1031			if (ev.Data.HasValue())
1032				ev.Data = value + "\n" + ev.Data;
1033			else
1034				ev.Data = value;
1035		}
1036		public void AddEditExtraInt(string field, int value)
1037		{
1038			var ev = GetExtraValue(field);
1039			ev.IntValue = value;
1040		}
1041		public void AddEditExtraBool(string field, bool tf)
1042		{
1043			if (!field.HasValue())
1044				return;
1045			var ev = GetExtraValue(field);
1046			ev.BitValue = tf;
1047		}
1048		public void AddEditExtraInts(string field, int value, int value2)
1049		{
1050			var ev = GetExtraValue(field);
1051			ev.IntValue = value;
1052			ev.IntValue2 = value2;
1053		}
1054		public ManagedGiving ManagedGiving()
1055		{
1056			var mg = ManagedGivings.SingleOrDefault();
1057			return mg;
1058		}
1059		public PaymentInfo PaymentInfo()
1060		{
1061			var pi = PaymentInfos.SingleOrDefault();
1062			return pi;
1063		}
1064		public Contribution PostUnattendedContribution(CMSDataContext Db, decimal Amt, int? Fund, string Description, bool pledge = false)
1065		{
1066			var typecode = BundleTypeCode.Online;
1067			if (pledge)
1068				typecode = BundleTypeCode.OnlinePledge;
1069
1070			var d = Util.Now.Date;
1071			d = d.AddDays(-(int)d.DayOfWeek); // prev sunday
1072			var q = from b in Db.BundleHeaders
1073					where b.BundleHeaderTypeId == typecode
1074					where b.BundleStatusId == BundleStatusCode.Open
1075					where b.ContributionDate >= d
1076					where b.ContributionDate < Util.Now
1077					orderby b.ContributionDate descending
1078					select b;
1079			var bundle = q.FirstOrDefault();
1080			if (bundle == null)
1081			{
1082				bundle = new BundleHeader
1083				{
1084					BundleHeaderTypeId = typecode,
1085					BundleStatusId = BundleStatusCode.Open,
1086					CreatedBy = Util.UserId1,
1087					ContributionDate = d,
1088					CreatedDate = DateTime.Now,
1089					DepositDate = DateTime.Now,
1090					FundId = Db.Setting("DefaultFundId", "1").ToInt(),
1091					RecordStatus = false,
1092					TotalCash = 0,
1093					TotalChecks = 0,
1094					TotalEnvelopes = 0,
1095					BundleTotal = 0
1096				};
1097				Db.BundleHeaders.InsertOnSubmit(bundle);
1098			}
1099			if (!Fund.HasValue)
1100				Fund = (from f in Db.ContributionFunds
1101						where f.FundStatusId == 1
1102						orderby f.FundId
1103						select f.FundId).First();
1104
1105			var FinanceManagerId = Db.Setting("FinanceManagerId", "").ToInt2();
1106			if (!FinanceManagerId.HasValue)
1107			{
1108				var qu = from u in Db.Users
1109						 where u.UserRoles.Any(ur => ur.Role.RoleName == "Finance")
1110						 orderby u.Person.LastName
1111						 select u.UserId;
1112				FinanceManagerId = qu.FirstOrDefault();
1113				if (!FinanceManagerId.HasValue)
1114					FinanceManagerId = 1;
1115			}
1116			var bd = new CmsData.BundleDetail
1117			{
1118				BundleHeaderId = bundle.BundleHeaderId,
1119				CreatedBy = FinanceManagerId.Value,
1120				CreatedDate = DateTime.Now,
1121			};
1122			var typid = ContributionTypeCode.CheckCash;
1123			if (pledge)
1124				typid = ContributionTypeCode.Pledge;
1125			bd.Contribution = new Contribution
1126			{
1127				CreatedBy = FinanceManagerId.Value,
1128				CreatedDate = bd.CreatedDate,
1129				FundId = Fund.Value,
1130				PeopleId = PeopleId,
1131				ContributionDate = bd.CreatedDate,
1132				ContributionAmount = Amt,
1133				ContributionStatusId = 0,
1134				ContributionTypeId = typid,
1135				ContributionDesc = Description,
1136			};
1137			bundle.BundleDetails.Add(bd);
1138			Db.SubmitChanges();
1139			return bd.Contribution;
1140		}
1141		public static int FetchOrCreateMemberStatus(CMSDataContext Db, string type)
1142		{
1143			var ms = Db.MemberStatuses.SingleOrDefault(m => m.Description == type);
1144			if (ms == null)
1145			{
1146				var max = Db.MemberStatuses.Max(mm => mm.Id) + 1;
1147				ms = new MemberStatus() { Id = max, Code = "M" + max, Description = type };
1148				Db.MemberStatuses.InsertOnSubmit(ms);
1149				Db.SubmitChanges();
1150			}
1151			return ms.Id;
1152		}
1153		public static Campu FetchOrCreateCampus(CMSDataContext Db, string campus)
1154		{
1155			if (!campus.HasValue())
1156				return null;
1157			var cam = Db.Campus.SingleOrDefault(pp => pp.Description == campus);
1158			if (cam == null)
1159			{
1160				int max = 10;
1161				if (Db.Campus.Any())
1162					max = Db.Campus.Max(mm => mm.Id) + 10;
1163				cam = new Campu() { Id = max, Description = campus, Code = campus.Truncate(20) };
1164				Db.Campus.InsertOnSubmit(cam);
1165				Db.SubmitChanges();
1166			}
1167			else if (!cam.Code.HasValue())
1168			{
1169				cam.Code = campus.Truncate(20);
1170				Db.SubmitChanges();
1171			}
1172			return cam;
1173		}
1174		public Task AddTaskAbout(CMSDataContext Db, int AssignTo, string description)
1175		{
1176			var t = new Task
1177			{
1178				OwnerId = AssignTo,
1179				Description = description,
1180				ForceCompleteWContact = true,
1181				ListId = Task.GetRequiredTaskList("InBox", AssignTo).Id,
1182				StatusId = TaskStatusCode.Active,
1183			};
1184			TasksAboutPerson.Add(t);
1185			return t;
1186		}
1187	}
1188}