Skip to content

Instantly share code, notes, and snippets.

@cscott530
Last active February 2, 2017 14:16
Show Gist options
  • Save cscott530/31e2afdbc8e9732a8f75b08a40fe8e3d to your computer and use it in GitHub Desktop.
Save cscott530/31e2afdbc8e9732a8f75b08a40fe8e3d to your computer and use it in GitHub Desktop.
Verifying & Fix Decimal Rounding Issues
public class PomodoDbContext : DbContext, IPomodoDbContext
{
static PomodoDbContext()
{
Database.SetInitializer<PomodoDbContext>(null);
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//this should just match whatever the DB column is
modelBuilder.Entity<Invoice>()
.Property(i => i.PretaxTotal).HasPrecision(18, 5);
modelBuilder.Entity<Invoice>()
.Property(i => i.TotalTax).HasPrecision(18, 5);
modelBuilder.Entity<Invoice>()
.Property(i => i.PosttaxTotal).HasPrecision(18, 5);
modelBuilder.Entity<InvoiceItem>()
.Property(i => i.Quantity).HasPrecision(18, 5);
modelBuilder.Entity<InvoiceItem>()
.Property(i => i.BasePrice).HasPrecision(18, 5);
modelBuilder.Entity<InvoiceItem>()
.Property(i => i.DiscountedPrice).HasPrecision(18, 5);
modelBuilder.Entity<InvoiceItem>()
.Property(i => i.Discount).HasPrecision(18, 5);
modelBuilder.Entity<InvoiceItem>()
.Property(i => i.TaxPaid).HasPrecision(18, 5);
modelBuilder.Entity<InvoiceItem>()
.Property(i => i.TotalPaid).HasPrecision(18, 5);
}
}
[TestClass]
public class InvoiceDecimalTruncationTest
{
[TestMethod]
public void TestTruncation()
{
using(var db = new PomodoDbContext())
{
//first create entity in db.
//be sure to use decimals that go beyond "2" precision
var retailer = db.Retailers.First();
var userId = db.AspNetUsers.First().Id;
var productId = db.Products.First().Id;
decimal taxAmt = 12.3456m;
decimal pretaxTotal = 33.44556m;
decimal discountedAmt = 29.9987m;
decimal target = taxAmt + pretaxTotal;
decimal quantity = 5.432m;
var invoice = new Invoice
{
TotalTax = taxAmt,
PretaxTotal = pretaxTotal,
PosttaxTotal = target,
RetailerId = retailer.Id,
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow,
InvoiceItems = new List<InvoiceItem>
{
new InvoiceItem
{
CreatedAt = DateTime.UtcNow,
UpdatedAt = DateTime.UtcNow,
ProductId = productId,
Quantity = quantity,
BasePrice = pretaxTotal,
DiscountedPrice = discountedAmt,
TaxPaid = taxAmt,
TotalPaid = target
}
}
};
Assert.AreEqual(taxAmt, invoice.TotalTax);
Assert.AreEqual(pretaxTotal, invoice.PretaxTotal);
Assert.AreEqual(target, invoice.PosttaxTotal);
Assert.AreEqual(quantity, invoice.InvoiceItems.First().Quantity);
Assert.AreEqual(pretaxTotal, invoice.InvoiceItems.First().BasePrice);
Assert.AreEqual(discountedAmt, invoice.InvoiceItems.First().DiscountedPrice);
Assert.AreEqual(taxAmt, invoice.InvoiceItems.First().TaxPaid);
Assert.AreEqual(target, invoice.InvoiceItems.First().TotalPaid);
db.Invoices.Add(invoice);
db.SaveChanges();
//need to detach and reload the item into memory to actually verify
//if we don't detach, .First() will just reuse the above invoice object.
var odb = ((IObjectContextAdapter)db).ObjectContext;
odb.Detach(invoice.InvoiceItems.First());
odb.Detach(invoice);
var dbInvoice = db.Invoices
.Include(i => i.InvoiceItems)
.First(i => i.Id == invoice.Id);
Assert.AreEqual(taxAmt, dbInvoice.TotalTax);
Assert.AreEqual(pretaxTotal, dbInvoice.PretaxTotal);
Assert.AreEqual(target, dbInvoice.PosttaxTotal);
Assert.AreEqual(quantity, dbInvoice.InvoiceItems.First().Quantity);
Assert.AreEqual(pretaxTotal, dbInvoice.InvoiceItems.First().BasePrice);
Assert.AreEqual(discountedAmt, dbInvoice.InvoiceItems.First().DiscountedPrice);
Assert.AreEqual(taxAmt, dbInvoice.InvoiceItems.First().TaxPaid);
Assert.AreEqual(target, dbInvoice.InvoiceItems.First().TotalPaid);
db.InvoiceItems.Remove(dbInvoice.InvoiceItems.First());
db.Invoices.Remove(dbInvoice);
db.SaveChanges();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment