using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; using NHibernate; using Tanshu.Accounts.Entities; namespace Tanshu.Accounts.Repository { public class SaleInfo { public int StartBill { get; set; } public int FinishBill { get; set; } public decimal Rate { get; set; } public decimal Net { get; set; } public decimal Vat { get; set; } } public class ExcelInfo { public DateTime Date { get; set; } public string StartBill { get; set; } public string FinishBill { get; set; } public IDictionary SaleAndVat { get; set; } public decimal ServiceTax { get; set; } } public class SaleJson { IFormatProvider culture = new CultureInfo("en-US", true); private DateTime? dateStart; private DateTime? dateFinish; public string _startDate { get; set; } public string _finishDate { get; set; } public IList Sale { get; set; } public DateTime StartDate { get { if (!dateStart.HasValue) { DateTime tDate; if (!DateTime.TryParseExact(_startDate, "dd-MMM-yyyy", culture, DateTimeStyles.NoCurrentDateDefault, out tDate)) throw new ArgumentException(); dateStart = tDate; } return dateStart.Value; } } public DateTime FinishDate { get { if (!dateFinish.HasValue) { DateTime tDate; if (!DateTime.TryParseExact(_finishDate, "dd-MMM-yyyy", culture, DateTimeStyles.NoCurrentDateDefault, out tDate)) throw new ArgumentException(); dateFinish = tDate; } return dateFinish.Value; } } } public class SaleDetailJson { public decimal Rate { get; set; } public bool IsLiq { get; set; } public decimal Amount { get; set; } } public class BeerJson { IFormatProvider culture = new CultureInfo("en-US", true); private DateTime? date; public string _date { get; set; } public IList Beers { get; set; } public DateTime Date { get { if (!date.HasValue) { DateTime tDate; if (!DateTime.TryParseExact(_date, "dd-MMM-yyyy", culture, DateTimeStyles.NoCurrentDateDefault, out tDate)) throw new ArgumentException(); date = tDate; } return date.Value; } } public decimal Quantity { get { decimal amount = 0; foreach (var item in Beers) { amount += item.Quantity; } return amount; } } } public class BeerDetailJson { public string Name { get; set; } public decimal Quantity { get; set; } } public class CreditJson { IFormatProvider culture = new CultureInfo("en-US", true); private DateTime? date; public string _date { get; set; } public decimal Amount { get; set; } public DateTime Date { get { if (!date.HasValue) { DateTime tDate; if (!DateTime.TryParseExact(_date, "dd-MMM-yyyy", culture, DateTimeStyles.NoCurrentDateDefault, out tDate)) throw new ArgumentException(); date = tDate; } return date.Value; } } } public class ManagementBI : IUnitOfWork { protected readonly ISession _session; private ITransaction _transaction; public ManagementBI() { _session = SessionManager.Session; _transaction = _session.BeginTransaction(); } #region Cleanup public void DeleteVoid(DateTime startDate, DateTime finishDate) { var query = @"delete from Reprint r where r.Voucher in ( select v from Voucher v where v.Date >= :startDate and v.Date <= :finishDate and v.Void = :void )"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("void", true) .ExecuteUpdate(); query = @"delete from VoucherSettlement vs where vs.Voucher in ( select v from Voucher v where v.Date >= :startDate and v.Date <= :finishDate and v.Void = :void )"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("void", true) .ExecuteUpdate(); query = @"delete from InventoryModifier im where im.Inventory in ( select i from Inventory i where i.Kot in ( select k from Kot k where k.Voucher in ( select v from Voucher v where v.Date >= :startDate and v.Date <= :finishDate and v.Void = :void )))"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("void", true) .ExecuteUpdate(); query = @"delete from Inventory i where i.Kot in ( select k from Kot k where k.Voucher in ( select v from Voucher v where v.Date >= :startDate and v.Date <= :finishDate and v.Void = :void ))"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("void", true) .ExecuteUpdate(); query = @"delete from Kot k where k.Voucher in ( select v from Voucher v where v.Date >= :startDate and v.Date <= :finishDate and v.Void = :void )"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("void", true) .ExecuteUpdate(); query = @"delete from Voucher v where v.Date >= :startDate and v.Date <= :finishDate and v.Void = :void"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("void", true) .ExecuteUpdate(); } public void MoveStaffToNc(DateTime startDate, DateTime finishDate) { var query = @"update Voucher set VoucherType = :nc where VoucherType = :staff and Date >= :startDate and Date <= :finishDate"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("staff", VoucherType.Staff) .ExecuteUpdate(); } public void ClearModifiers(DateTime startDate, DateTime finishDate) { var query = @"delete from InventoryModifier im where im.Inventory in ( select i from Inventory i where i.Kot in ( select k from Kot k where k.Voucher in ( select v from Voucher v where v.Date >= :startDate and v.Date <= :finishDate )))"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .ExecuteUpdate(); } public void CombineKots(DateTime startDate, DateTime finishDate) { var query = @" select v.VoucherID, k.KotID, i.InventoryID, i.Product.ProductID, i.Quantity from Voucher v inner join v.Kots k inner join k.Inventories i where v.Date >= :startDate and v.Date <= :finishDate order by v.Date, k.Date"; var list = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .List(); Dictionary>> vouchers = new Dictionary>>(); foreach (var item in list) { var voucherID = (Guid)item[0]; var kotID = (Guid)item[1]; var inventoryID = (Guid)item[2]; var productID = (Guid)item[3]; var quantity = (decimal)item[4]; if (!vouchers.ContainsKey(voucherID)) vouchers.Add(voucherID, new Dictionary>()); if (!vouchers[voucherID].ContainsKey(kotID)) vouchers[voucherID].Add(kotID, new List()); vouchers[voucherID][kotID].Add(new object[] { inventoryID, productID, quantity }); } foreach (var voucher in vouchers) { var kots = voucher.Value; if (kots.Count <= 1) continue; Dictionary kotInventories = new Dictionary(); foreach (var item in kots.ElementAt(0).Value) { Guid inventoryID = (Guid)item[0]; Guid productID = (Guid)item[1]; kotInventories.Add(productID, inventoryID); } for (var i = kots.Count; i > 1; i--) { foreach (var item in kots.ElementAt(i - 1).Value) { Guid inventoryID = (Guid)item[0]; Guid productID = (Guid)item[1]; decimal quantity = (decimal)item[2]; if (kotInventories.ContainsKey(productID)) { query = @"update Inventory set Quantity = Quantity + :quantity where InventoryID = :inventoryID"; _session.CreateQuery(query).SetParameter("quantity", quantity).SetParameter("inventoryID", kotInventories[productID]).ExecuteUpdate(); query = @"delete from Inventory where InventoryID = :inventoryID"; _session.CreateQuery(query).SetParameter("inventoryID", inventoryID).ExecuteUpdate(); } else { kotInventories.Add(productID, inventoryID); query = @"update Inventory set Kot.KotID = :kotID where InventoryID = :inventoryID"; _session.CreateQuery(query).SetParameter("kotID", kots.ElementAt(0).Key).SetParameter("inventoryID", inventoryID).ExecuteUpdate(); } } query = @"delete from Kot where KotID = :kotID"; _session.CreateQuery(query).SetParameter("kotID", kots.ElementAt(i - 1).Key).ExecuteUpdate(); } } } public void RemoveBlankKots(DateTime startDate, DateTime finishDate) { var query = @"delete from Kot k where k.Voucher in (select v from Voucher v where v.Date >= :startDate and v.Date <= :finishDate) and k not in (select distinct i.Kot from Inventory i)"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .ExecuteUpdate(); query = @"delete from VoucherSettlement vs where vs.Voucher in (select v from Voucher v where v.Date >= :startDate and v.Date <= :finishDate and v not in (select distinct k.Voucher from Kot k))"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .ExecuteUpdate(); query = @"delete from Reprint r where r.Voucher in (select v from Voucher v where v.Date >= :startDate and v.Date <= :finishDate and v not in (select distinct k.Voucher from Kot k))"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .ExecuteUpdate(); query = @"delete from Voucher v where v.Date >= :startDate and v.Date <= :finishDate and v not in (select distinct k.Voucher from Kot k)"; _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .ExecuteUpdate(); } public void SetPayments(DateTime startDate, DateTime finishDate) { var query = @"select v.VoucherID, v.VoucherType, sum(i.Amount) from Voucher v inner join v.Kots k inner join k.Inventories i where v.Date >= :startDate and v.Date <= :finishDate group by v.VoucherID, v.VoucherType"; var list = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .List(); Dictionary vouchers = new Dictionary(); foreach (var item in list) { var voucherType = (int)item[1] == 1 || (int)item[1] == 3 ? VoucherType.Regular : (int)item[1] == 2 ? VoucherType.NoCharge : VoucherType.Staff; vouchers.Add((Guid)item[0], new object[] { voucherType, Math.Round((decimal)item[2], 5) }); } foreach (var item in vouchers) { SettleOption settlementType; switch ((VoucherType)item.Value[0]) { case VoucherType.NoCharge: settlementType = SettleOption.NoCharge; break; case VoucherType.Staff: settlementType = SettleOption.Staff; break; default: settlementType = SettleOption.Cash; break; } var amount = -1 * (decimal)item.Value[1]; var roundoff = Math.Round(amount) - amount; query = @"select count(*) from VoucherSettlement vs where vs.Voucher.VoucherID = :voucherID and ( (vs.Amount = :amount and vs.Settled = :soAmount) or (vs.Amount = :roundOff and vs.Settled = :soRoundOff) or (vs.Amount = :paid and vs.Settled = :so))"; var existing = _session.CreateQuery(query) .SetParameter("voucherID", item.Key) .SetParameter("amount", amount) .SetParameter("roundOff", roundoff) .SetParameter("paid", -1 * (amount + roundoff)) .SetParameter("soAmount", SettleOption.Amount) .SetParameter("soRoundOff", SettleOption.RoundOff) .SetParameter("so", settlementType) .UniqueResult(); if (existing == 3) continue; query = @"delete from VoucherSettlement vs where vs.Voucher.VoucherID = :voucherID"; _session .CreateQuery(query) .SetParameter("voucherID", item.Key) .ExecuteUpdate(); _session.Save(new VoucherSettlement() { Voucher = new Voucher() { VoucherID = item.Key }, Amount = amount, Settled = SettleOption.Amount }); _session.Save(new VoucherSettlement() { Voucher = new Voucher() { VoucherID = item.Key }, Amount = roundoff, Settled = SettleOption.RoundOff }); _session.Save(new VoucherSettlement() { Voucher = new Voucher() { VoucherID = item.Key }, Amount = -1 * (amount + roundoff), Settled = settlementType }); } } public void UpdateBillID(DateTime startDate, DateTime finishDate) { var query = @" select MAX(v.BillID) from Voucher v where v.Date < :startDate and v.Void = false and v.VoucherType in (:regular, :takeAway) "; var lastBill = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("regular", VoucherType.Regular) .SetParameter("takeAway", VoucherType.TakeAway) .UniqueResult(); var newID = lastBill == null ? 1 : GetNewID((int)lastBill); var list = _session.QueryOver() .Where(x => x.Date >= startDate && x.Date <= finishDate && x.Void == false && (x.VoucherType == VoucherType.Regular || x.VoucherType == VoucherType.TakeAway)) .OrderBy(x => x.Date).Asc .List(); var count = " of" + list.Count.ToString(); var i = 0; foreach (var voucher in list) { i++; if (i % 20 == 0) Console.WriteLine("Loop " + i.ToString() + count); if (voucher.BillID != newID) { var update = _session.CreateSQLQuery("exec UpdateBillID ?,?"); update.SetParameter(0, voucher.VoucherID); update.SetParameter(1, newID); update.ExecuteUpdate(); } newID = GetNewID(newID); } query = @" select coalesce(v.BillID + 1, 1) from Voucher v where v.Date < :startDate and v.Void = false and v.VoucherType = :nc order by v.Date desc "; lastBill = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("nc", VoucherType.NoCharge) .SetMaxResults(1) .UniqueResult(); newID = (int)lastBill; list = _session.QueryOver() .Where(x => x.Date >= startDate && x.Date <= finishDate && x.VoucherType == VoucherType.NoCharge && x.Void == false) .OrderBy(x => x.Date).Asc .List(); foreach (var voucher in list) { if (voucher.BillID != newID) { var update = _session.CreateSQLQuery("exec UpdateBillID ?,?"); update.SetParameter(0, voucher.VoucherID); update.SetParameter(1, newID); update.ExecuteUpdate(); } newID += 1; } } private static int GetNewID(int lastBill) { lastBill += 1; if (lastBill % 10000 == 0) lastBill += 1; return lastBill; } #endregion public void MoveToNc(DateTime startDate, DateTime finishDate, decimal target) { string query = @" select v.VoucherID, sum(i.Amount) from Voucher v inner join v.Kots k inner join k.Inventories i where v.Date >= :startDate and v.Date <= :finishDate and i.Vat.TaxID = :vatLiquor and v.Void = false and v.VoucherType not in (:nc, :staff) group by v.VoucherID order by sum(i.Amount) desc "; var list = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("staff", VoucherType.Staff) .SetParameter("vatLiquor", new Guid("2C8AD8EC-E09A-4194-B348-01243474CF26")) .List(); var totalAmount = GetSaleAmount(.1575M, startDate, finishDate) + GetSaleAmount(.2625M, startDate, finishDate); for (int i = 0; i < list.Count / 20; i += 2) // Skip every alternate bill { if (totalAmount <= target) break; var item = (object[])list[i]; var voucherID = (Guid)item[0]; var amount = (decimal)item[1]; query = @"update Voucher set VoucherType = :nc where VoucherID = :voucherID"; _session .CreateQuery(query) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("voucherID", voucherID) .ExecuteUpdate(); totalAmount -= amount; } } public IList GetSaleAndVat(DateTime startDate, DateTime finishDate) { const string query = @" select i.VatRate as Rate, sum(i.Quantity * i.Price * (1 - i.Discount) * (1 + case when i.IsScTaxable then i.ServiceCharge else 0 end)) as Net, sum(i.Quantity * i.Price * (1 - i.Discount) * (1 + case when i.IsScTaxable then i.ServiceCharge else 0 end) * i.VatRate) as Vat from Voucher v inner join v.Kots k inner join k.Inventories i where v.Date >= :startDate and v.Date <= :finishDate and v.Void = false and v.VoucherType in (:regular, :takeAway) group by i.VatRate order by i.VatRate "; var list = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("regular", VoucherType.Regular) .SetParameter("takeAway", VoucherType.TakeAway) .List(); var info = new List(); foreach (var item in list) { info.Add(new SaleInfo() { Rate = (decimal)item[0], Net = (decimal)item[1], Vat = (decimal)item[2] }); } return info; } public decimal GetServiceTax(DateTime startDate, DateTime finishDate) { const string query = @" select sum(i.Quantity * i.Price * (1 - i.Discount) * (1 + case when i.IsScTaxable then i.ServiceCharge else 0 end) * i.ServiceTaxRate) as Amount from Voucher v inner join v.Kots k inner join k.Inventories i where v.Date >= :startDate and v.Date <= :finishDate and v.Void = false and v.VoucherType not in (:nc, :staff) "; var qty = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("staff", VoucherType.Staff) .UniqueResult(); return qty == null ? 0 : (decimal)qty; } public SaleInfo GetMinMaxBills(DateTime startDate, DateTime finishDate) { const string query = @" select MIN(v.BillID) as StartBill, MAX(v.BillID) as FinishBill from Voucher v where v.Date >= :startDate and v.Date <= :finishDate and v.Void = false and v.VoucherType in (:regular, :takeAway) "; var item = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("regular", VoucherType.Regular) .SetParameter("takeAway", VoucherType.TakeAway) .UniqueResult(); if (item[0] == null || item[1] == null) return null; return new SaleInfo() { StartBill = (int)item[0], FinishBill = (int)item[1] }; } public int? GetLastBill(DateTime date) { const string query = @" select v.BillID from Voucher v where v.Date >= :startDate and v.Date <= :finishDate and v.Void = false and v.VoucherType in (:regular, :takeAway) order by v.Date desc "; var qty = _session .CreateQuery(query) .SetParameter("startDate", date.AddHours(7)) .SetParameter("finishDate", date.AddDays(1).AddHours(7)) .SetParameter("regular", VoucherType.Regular) .SetParameter("takeAway", VoucherType.TakeAway) .SetMaxResults(1) .UniqueResult(); if (qty == null) return null; return (int)qty; } private decimal GetSaleAmount(decimal vat, DateTime startDate, DateTime finishDate) { const string query = @" select sum(i.Quantity * i.Price * (1 - i.Discount) * (1 + case when i.IsScTaxable then i.ServiceCharge else 0 end)) as Amount from Voucher v inner join v.Kots k inner join k.Inventories i where v.Date >= :startDate and v.Date <= :finishDate and i.VatRate = :vat and v.Void = false and v.VoucherType not in (:nc, :staff) "; var qty = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .SetParameter("vat", vat) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("staff", VoucherType.Staff) .UniqueResult(); return qty == null ? 0 : (decimal)qty; } public class DateVatSale { public DateTime Date { get; set; } public decimal VatRate { get; set; } public decimal Net { get; set; } public decimal Gross { get; set; } } public List GetSaleAmount(DateTime startDate, DateTime finishDate) { var list = new List(); const string query = @" select i.VatRate, sum(i.Quantity * i.Price * (1 - i.Discount) * (1 + case when i.IsScTaxable then i.ServiceCharge else 0 end)), sum(i.Amount) from Voucher v inner join v.Kots k inner join k.Inventories i where v.Date >= :startDate and v.Date <= :finishDate and v.Void = false and v.VoucherType not in (:nc, :staff) group by i.VatRate "; IList q; for (var date = startDate.Date; date <= finishDate.Date; date = date.AddDays(1)) { q = _session .CreateQuery(query) .SetParameter("startDate", date.AddHours(7)) .SetParameter("finishDate", date.AddDays(1).AddHours(7)) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("staff", VoucherType.Staff) .List(); foreach (var item in q) { list.Add(new DateVatSale() { Date = date, VatRate = (decimal)item[0], Net = (decimal)item[1], Gross = (decimal)item[2] }); } } return list; } private class InvDate : Inventory { public DateTime Date { get; set; } public decimal Net { get { if (IsScTaxable) return Quantity * Price * (1 - Discount) * (1 + ServiceCharge); return Quantity * Price * (1 - Discount); } } } public void SetQuantityAndDiscount(IList sale, IList credit, DateTime startDate, DateTime finishDate) { var rand = new Random(); var query = @" select v.Date, i.InventoryID, i.Quantity, i.Price, i.Discount, i.ServiceCharge, i.IsScTaxable, i.ServiceTaxRate, i.VatRate from Voucher v inner join v.Kots k inner join k.Inventories i where v.Date >= :startDate and v.Date <= :finishDate and v.VoucherType in (:regular, :takeAway)"; var list = _session .CreateQuery(query) .SetParameter("startDate", startDate.AddHours(7)) .SetParameter("finishDate", finishDate.AddDays(1).AddHours(7)) .SetParameter("regular", VoucherType.Regular) .SetParameter("takeAway", VoucherType.TakeAway) .List(); List inventories = new List(); foreach (var item in Randomize(list)) { inventories.Add(new InvDate() { Date = ((DateTime)item[0]).AddHours(-7).Date, InventoryID = (Guid)item[1], Quantity = (decimal)item[2], Price = (decimal)item[3], Discount = (decimal)item[4], ServiceCharge = (decimal)item[5], IsScTaxable = (bool)item[6], ServiceTaxRate = (decimal)item[7], VatRate = (decimal)item[8] }); } var sales = GetSaleAmount(startDate, finishDate); List continueDates = new List(); List continueVat = new List(); var creditSale = credit.Sum(x => x.Amount); //this is approx, but more than actual as the formula does not take into account service tax var creditLiqSale = creditSale - sale.Where(x => x.IsLiq == false).Sum(x => x.Amount * (1 + x.Rate)); var actualLiqSale = sales.Where(x => sale.Where(y => y.IsLiq == true).Select(y => y.Rate).Contains(x.VatRate)).Sum(x => x.Gross); var max = 1 - (creditLiqSale / actualLiqSale); max = Math.Min(.90M, Math.Round(max, 2) * 2); max = Math.Max(.10M, max); int run = 0; while (continueVat.Intersect(sale.Select(x => x.Rate)).Count() != continueVat.Union(sale.Select(x => x.Rate)).Count() && continueDates.Intersect(credit.Select(x => x.Date)).Count() != continueDates.Union(credit.Select(x => x.Date)).Count() && ++run <= 10) { foreach (var inv in inventories) { if (sale.Count(x => x.Rate == inv.VatRate) == 0) throw new ArgumentException("Unknown type of vat rate encountered"); var creditForDay = credit.SingleOrDefault(x => x.Date == inv.Date).Amount; var grossSaleForDay = sales.Where(x => x.Date == inv.Date).Sum(x => x.Gross); if (creditForDay >= grossSaleForDay && !continueDates.Contains(inv.Date)) continueDates.Add(inv.Date); var targetVatAmountForPeriod = sale.SingleOrDefault(x => x.Rate == inv.VatRate).Amount; var vatRemainingForPeriod = sales.Where(x => x.VatRate == inv.VatRate).Sum(x => x.Net); if (vatRemainingForPeriod <= targetVatAmountForPeriod && !continueVat.Contains(inv.VatRate)) continueVat.Add(inv.VatRate); if (continueDates.Contains(inv.Date) || continueVat.Contains(inv.VatRate)) continue; var vatLeft = vatRemainingForPeriod - targetVatAmountForPeriod; var creditLeft = grossSaleForDay - creditForDay; var left = Math.Min(vatLeft, creditLeft); //Net Gross conversion var isLiq = sale.SingleOrDefault(x => x.Rate == inv.VatRate).IsLiq; if (isLiq) { if (inv.Discount >= max || inv.Price == 0) continue; var minimum = inv.Discount == 0 ? 10 : Convert.ToInt32(inv.Discount * 100) + 1; var discount = Convert.ToDecimal(rand.Next(minimum, Convert.ToInt32(max * 100))) / 100; if (inv.Net * (discount - inv.Discount) > left) { discount = Math.Round(left * (1 - inv.Discount) / inv.Net, 2); } query = @"update Inventory set Discount = :discount where InventoryID = :inventoryID"; _session.CreateQuery(query).SetParameter("discount", discount).SetParameter("inventoryID", inv.InventoryID).ExecuteUpdate(); // reduce from daily var saleItem = sales.Single(x => x.Date == inv.Date && x.VatRate == inv.VatRate); inv.Discount += 1 - discount; saleItem.Net -= Math.Round(inv.Net); saleItem.Gross -= Math.Round(inv.Amount); } else { if (inv.Net > left) { var ratio = (inv.Net - left) / inv.Net; query = @"update Inventory set Quantity = Quantity * :ratio where InventoryID = :inventoryID"; _session.CreateQuery(query).SetParameter("ratio", ratio).SetParameter("inventoryID", inv.InventoryID).ExecuteUpdate(); // reduce from daily var saleItem = sales.Single(x => x.Date == inv.Date && x.VatRate == inv.VatRate); inv.Quantity -= inv.Quantity * ratio; saleItem.Net -= Math.Round(inv.Net); saleItem.Gross -= Math.Round(inv.Amount); } else { query = @"delete from Inventory where InventoryID = :inventoryID"; _session.CreateQuery(query).SetParameter("inventoryID", inv.InventoryID).ExecuteUpdate(); // reduce from daily var saleItem = sales.Single(x => x.Date == inv.Date && x.VatRate == inv.VatRate); saleItem.Net -= inv.Net; saleItem.Gross -= inv.Amount; } } } } } #region Beer public decimal GetBeer(DateTime startDate, DateTime finishDate) { const string query = @" select sum(i.Quantity * p.Quantity) as Quantity from Voucher v inner join v.Kots k inner join k.Inventories i inner join i.Product p where v.Date >= :startDate and v.Date <= :finishDate and v.Void = false and p.Quantity != 0 "; var qty = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .UniqueResult(); return qty == null ? 0 : (decimal)qty; } public decimal SetBeer(DateTime startDate, DateTime finishDate, decimal quantity) { var query = @" select i.InventoryID, i.Product.ProductID, i.Quantity, p.Quantity from Voucher v inner join v.Kots k inner join k.Inventories i inner join i.Product p where v.Date >= :startDate and v.Date <= :finishDate and p.Quantity != 0"; var list = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .List(); list = Randomize(list); Dictionary inventories = new Dictionary(); foreach (var item in list) { var inventoryID = (Guid)item[0]; var productID = (Guid)item[1]; var inventoryQuantity = (decimal)item[2]; var productQuantity = (decimal)item[3]; inventories.Add(inventoryID, new object[] { productID, inventoryQuantity, productQuantity }); } var left = GetBeer(startDate, finishDate) - quantity; foreach (var item in inventories) { if (left <= 0) break; var productID = (Guid)item.Value[0]; var inventoryQuantity = (decimal)item.Value[1]; var productQuantity = (decimal)item.Value[2]; var q = inventoryQuantity * productQuantity; if (q > left) { var newQuantity = inventoryQuantity * (q - left) / q; query = @"update Inventory set Quantity = :quantity where InventoryID = :inventoryID"; _session.CreateQuery(query).SetParameter("quantity", newQuantity).SetParameter("inventoryID", item.Key).ExecuteUpdate(); left = 0; } else { query = @"delete from Inventory where InventoryID = :inventoryID"; _session.CreateQuery(query).SetParameter("inventoryID", item.Key).ExecuteUpdate(); left -= q; } } return GetBeer(startDate, finishDate); } #endregion #region Helper and Comments private static IList Randomize(IEnumerable list) { var tList = list.ToArray(); var rand = new Random(); for (var i = tList.Length - 1; i > 0; i--) { var swapIndex = rand.Next(i + 1); var tmp = tList[i]; tList[i] = tList[swapIndex]; tList[swapIndex] = tmp; } return tList.ToList(); } public string FullBillID(int billID, VoucherType voucherType) { switch (voucherType) { case VoucherType.NoCharge: return "NC-" + billID.ToString(); case VoucherType.Staff: return "ST-" + billID.ToString(); case VoucherType.TakeAway: case VoucherType.Regular: default: return (billID / 10000).ToString() + "-" + (billID % 10000).ToString(); } } // public decimal GetBeer(int baseCode, DateTime startDate, DateTime finishDate) // { // const string query = @" //select sum(i.Quantity * p.Quantity) as Quantity //from Voucher v //inner join v.Kots k //inner join k.Inventories i //inner join i.Product p //where v.Date >= :startDate and v.Date <= :finishDate and v.Void = false and p.BaseCode = :baseCode // "; // var qty = Session // .CreateQuery(query) // .SetParameter("startDate", startDate) // .SetParameter("finishDate", finishDate) // .SetParameter("baseCode", baseCode) // .UniqueResult(); // return qty == null ? 0 : (decimal)qty; // } // public decimal SetQuantity(int baseCode, decimal quantity, DateTime startDate, DateTime finishDate) // { // var list = Randomize(new VoucherBI().List(x => x.Date >= startDate && x.Date <= finishDate && x.Void == false)); // var left = GetBeer(baseCode, startDate, finishDate) - quantity; // foreach (var item in list) // { // if (left <= 0) // break; // foreach (var kot in item.Kots) // { // if (left <= 0) // break; // foreach (var inventory in kot.Inventories) // { // if (left <= 0) // break; // if (inventory.Product.BaseCode == baseCode) // { // using (var bi = new InventoryBI()) // { // var inventoryQuantity = inventory.Quantity * inventory.Product.Quantity; // if (inventoryQuantity > left) // { // var newQuantity = inventory.Quantity * (inventoryQuantity - left) / inventoryQuantity; // var i = bi.Get(x => x.InventoryID == inventory.InventoryID); // i.Quantity = newQuantity; // bi.Update(i); // left = 0; // } // else // { // left -= inventoryQuantity; // bi.Delete(x => x.InventoryID == inventory.InventoryID); // } // } // } // } // } // } // return GetBeer(baseCode, startDate, finishDate); // } //private static int GetNewID(int code, int toBaseCode) //{ // // Name Mug, Pit, H H // // Dark 301, 305, 384 // BaseCode = 1 // // Wheat 300, 304, 383 // BaseCode = 2 // // Premium 299, 303, 382 // BaseCode = 3 // // Light 297, 302, 363 // BaseCode = 4 // // Dragon 677, 679, 678 // BaseCode = 5 // // Festivals 762 764, 752 // BaseCode = 6 // // Festivals 751, 753, 763 // BaseCode = 6 // // Festivals 734, 736, 587 // BaseCode = 6 // // Festivals 408, 409, 735 // BaseCode = 6 // // Strong 697, 708, 707 // BaseCode = 7 // var list = new List { 301, 300, 299, 297, 677, 762, 751, 734, 408, 697 }; // if (list.Contains(code)) // { // if (toBaseCode == 1) // return 301; // if (toBaseCode == 2) // return 300; // if (toBaseCode == 3) // return 299; // if (toBaseCode == 4) // return 297; // if (toBaseCode == 5) // return 677; // if (toBaseCode == 6) // return code; // if (toBaseCode == 7) // return 697; // } // list = new List { 305, 304, 303, 302, 679, 764, 753, 736, 409, 708 }; // if (list.Contains(code)) // { // if (toBaseCode == 1) // return 305; // if (toBaseCode == 2) // return 304; // if (toBaseCode == 3) // return 303; // if (toBaseCode == 4) // return 302; // if (toBaseCode == 5) // return 679; // if (toBaseCode == 6) // return code; // if (toBaseCode == 7) // return 708; // } // list = new List { 384, 383, 382, 363, 678, 752, 763, 587, 735, 707 }; // if (list.Contains(code)) // { // if (toBaseCode == 1) // return 384; // if (toBaseCode == 2) // return 383; // if (toBaseCode == 3) // return 382; // if (toBaseCode == 4) // return 363; // if (toBaseCode == 5) // return 678; // if (toBaseCode == 6) // return code; // if (toBaseCode == 7) // return 707; // } // return code; //} //public void SetMove(int fromBaseCode, int toBaseCode, DateTime startDate, DateTime finishDate) //{ // var list = new VoucherBI().List(x => x.Date >= startDate && x.Date <= finishDate); // using (var bi = new InventoryBI()) // { // using (var pbi = new ProductBI()) // { // foreach (var item in list) // { // foreach (var kot in item.Kots) // { // foreach (var inventory in kot.Inventories) // { // if (inventory.Product.BaseCode == fromBaseCode) // { // var i = bi.Get(x => x.InventoryID == inventory.InventoryID); // i.Product = pbi.Get(x => x.ProductID == GetNewID(i.Product.ProductID, toBaseCode)); // GetNewID(i.InventoryID, toBaseCode); // bi.Update(i); // } // } // } // } // } // } //} #endregion public void Dispose() { if (_transaction != null) _transaction.Rollback(); } public void SaveChanges() { if (_transaction == null) throw new InvalidOperationException("UnitOfWork have already been saved."); _transaction.Commit(); _transaction = null; } } }