private static void WriteData(ApplicationDbContext db, bool removeCycles, Person[] people) { const string outDir = @"C:\Users\AustinWise\Dropbox\DKP"; List <Debt> netMoney = null; using (Stream fs = removeCycles ? new FileStream(Path.Combine(outDir, "Info.txt"), FileMode.Create, FileAccess.Write) : Stream.Null) { using (var infoOutput = new StreamWriter(fs)) { netMoney = DebtGraph.CalculateDebts(db, people, removeCycles, infoOutput ?? Console.Out); } } Console.WriteLine("{0:c}", netMoney.Sum(m => m.Amount) / 100d); const string gvPath = @"c:\temp\graph\test.gv"; using (var fs = new FileStream(gvPath, FileMode.Create, FileAccess.Write)) { using (var sw = new StreamWriter(fs)) { DebtGraph.WriteGraph(netMoney, sw); } } DebtGraph.RenderGraphAsPng(gvPath, Path.Combine(outDir, removeCycles ? "current.png" : "nocycles.png")); if (removeCycles) { DebtGraph.RenderGraphAsPng(gvPath, Path.Combine(outDir, DateTime.Now.ToString("yyyy-MM-dd") + ".png")); } }
public async Task Send(int creditorId) { bool actuallySend = false; Console.Write("Type 'true' to actually send emails: "); bool.TryParse(Console.ReadLine(), out actuallySend); var person = mDb.Person .Where(p => p.Id == creditorId) .Include(p => p.PaymentIdentity).ThenInclude(p => p.PaymentMeth) .Single(); var transactions = mDb.Transaction .Where(t => t.CreditorId != t.DebtorId && (t.CreditorId == person.Id || t.DebtorId == person.Id) && (!t.Creditor.IsDeleted && !t.Debtor.IsDeleted)); foreach (var dontUse in PEOPLE_TO_EXCLUDE) { var p = dontUse; transactions = transactions.Where(t => t.DebtorId != p && t.CreditorId != p); } var netMoney = DebtGraph.CalculateDebts(mDb, transactions, true, TextWriter.Null); var swGraph = new StringWriter(); DebtGraph.WriteGraph(netMoney, swGraph); var bytes = DebtGraph.RenderGraphAsPng(swGraph.ToString()); var debtors = DebtGraph.GreatestDebtor(netMoney); var myDebt = debtors.Where(d => d.Item1.Id == person.Id).SingleOrDefault(); if (myDebt != null) { debtors.Remove(myDebt); } debtors = debtors.Where(tup => tup.Item2 > 1000 && !string.IsNullOrEmpty(tup.Item1.Email)).ToList(); int sentSoFar = 0; foreach (var tup in debtors) { var fields = ProcessOnePerson(person, tup.Item1, tup.Item2); if (actuallySend) { await mEmail.SendHtmlEmailAsync(tup.Item1.FullName, tup.Item1.Email, "DKP Invoice", fields.BODY); } Console.WriteLine(actuallySend ? "Sent {0,2}/{1,2} ({2} {3})" : "Would send: {2} {3}", ++sentSoFar, debtors.Count, tup.Item1.FirstName, tup.Item1.LastName); } Console.WriteLine(); Console.WriteLine("Done! Press enter to exit."); Console.ReadLine(); }
public ActionResult Display(int[] peopleIds) { var people = peopleIds .Select(i => dc.Person.Where(p => p.Id == i).Single()) .ToArray(); var swLog = new StringWriter(); var netMoney = DebtGraph.CalculateDebts(dc, people, true, swLog); var swGraph = new StringWriter(); DebtGraph.WriteGraph(netMoney, swGraph); var svg = DebtGraph.RenderGraphAsSvg(swGraph.ToString()); var mod = new AnalyseModel(); mod.LogOutput = swLog.ToString(); mod.ImageSvg = svg; mod.Debtors = DebtGraph.GreatestDebtor(netMoney); return(View(mod)); }
// // GET: /MyDebt/Details/5 public ActionResult Details(int id) { var person = mData.Person.Where(p => p.Id == id).Single(); var transactions = mData.Transaction.Include(t => t.Creditor).Include(t => t.Debtor) .Where(t => t.CreditorId != t.DebtorId && !t.Creditor.IsDeleted && !t.Debtor.IsDeleted && (t.CreditorId == person.Id || t.DebtorId == person.Id)) .ToList(); var netMoney = DebtGraph.CalculateDebts(mData, transactions, true, TextWriter.Null); var swGraph = new StringWriter(); DebtGraph.WriteGraph(netMoney, swGraph); var svg = DebtGraph.RenderGraphAsSvg(swGraph.ToString()); var creditors = DebtGraph.GreatestDebtor(netMoney); var myDebt = creditors.Where(d => d.Item1.Id == person.Id).SingleOrDefault(); if (myDebt != null) { creditors.Remove(myDebt); } //change the list of debtors in to creditors creditors = creditors.Select(c => new Tuple <Person, int>(c.Item1, -c.Item2)) .Reverse() .ToList(); var mod = new MyDebtModel(); mod.Person = person; mod.ImageSvg = svg; mod.Creditors = creditors; mod.OverallDebt = (myDebt == null) ? 0 : myDebt.Item2; return(View(mod)); }
private static void DebtTransfer(ApplicationDbContext db, Person debtor, Person oldCreditor, Person newCreditor, DateTime when) { var netMoney = DebtGraph.CalculateDebts(db, new[] { debtor, oldCreditor }, false, null); if (netMoney.Count != 1) { throw new Exception("No debt to transfer."); } var theDebt = netMoney[0]; if (theDebt.Debtor.Id != debtor.Id || theDebt.Creditor.Id != oldCreditor.Id) { throw new Exception("Debt does not go in the expected direction."); } var msg = Transaction.CreateDebtTransferString(debtor, oldCreditor, newCreditor); var bs = new BillSplit(); bs.Name = msg; db.BillSplit.Add(bs); var cancelTrans = new Transaction() { Id = Guid.NewGuid(), DebtorId = oldCreditor.Id, //owes money CreditorId = debtor.Id, //owed money Amount = theDebt.Amount, Bill = bs, Description = msg, Created = when }; db.Transaction.Add(cancelTrans); var makeCreditorWholeTransaction = new Transaction() { Id = Guid.NewGuid(), DebtorId = newCreditor.Id, //owes money CreditorId = oldCreditor.Id, //owed money Amount = theDebt.Amount, Bill = bs, Description = msg, Created = when }; db.Transaction.Add(makeCreditorWholeTransaction); var makeDebtorOweNewPartyTrans = new Transaction() { Id = Guid.NewGuid(), DebtorId = debtor.Id, //owes money CreditorId = newCreditor.Id, //owed money Amount = theDebt.Amount, Bill = bs, Description = msg, Created = when }; db.Transaction.Add(makeDebtorOweNewPartyTrans); db.SaveChanges(); }
MyRecord ProcessOnePerson(Person creditor, Person debtor, int amount) { var q = from t in mDb.Transaction where (t.CreditorId == debtor.Id && t.DebtorId == creditor.Id) || (t.CreditorId == creditor.Id && t.DebtorId == debtor.Id) orderby t.Created select t; var allTrans = q.ToList(); foreach (var t in allTrans) { t.SetPrettyDescription(mPersonMap); } var souceTrans = new List <Transaction>(); Debt debt = null; while (allTrans.Count != 0) { debt = DebtGraph.CalculateDebts(mDb, allTrans, false, TextWriter.Null).SingleOrDefault(); if (debt == null) { break; //this indicates that there is no debt between the two people } if (debt.Debtor.Id == creditor.Id) { break; //this indicates that there is a debt owed in the opisite direction } souceTrans.Add(allTrans[allTrans.Count - 1]); allTrans.RemoveAt(allTrans.Count - 1); } //TODO: grenerate a pretty table, maybe //It seems like a duplication of effort to try to create a subset of the website's debt table here. double amountInDollars = Math.Round(amount / 100d, 2); var sb = new StringBuilder(); sb.AppendFormat("Hi {0},", debtor.FirstName); sb.AppendLine("<br/>"); sb.Append("This is a friendly, automated reminder that you currently owe a balence to me in DKP. "); sb.Append("Including "); sb.Append(souceTrans[0].Description); sb.Append(", our most recent time together, you owe "); sb.AppendFormat("{0:c}.", amountInDollars); sb.AppendLine("<br/>"); sb.Append("For more information about the transaction history see <a href=\"http://dkp.awise.us/MyDebt/DebtHistory?"); sb.AppendFormat("debtorId={0}&creditorId={1}", debtor.Id, creditor.Id); sb.Append("\">this table</a>. Let me know if you have any questions or concerns."); sb.AppendLine("<br/>"); sb.AppendLine("Here are some handy links to send payment:<ul>"); foreach (var payId in creditor.PaymentIdentity) { if (!payId.PaymentMeth.HasPayLink) { continue; } sb.AppendFormat("<li><a href=\"{0}\">{1}</a></li>", payId.CreatePayLink(amount), payId.PaymentMeth.Name.Trim()); } sb.Append("</ul>"); sb.AppendLine("<br/>"); sb.Append("Thanks,"); sb.AppendLine("<br/>"); sb.Append(creditor.FirstName); var ret = new MyRecord(); ret.EmailAddress = debtor.Email; ret.BODY = sb.ToString(); return(ret); }