using System; using System.Collections; using System.Collections.Generic; using System.Linq; using NHibernate; using Tanshu.Accounts.Entities; using Tanshu.Common.Helpers; namespace Tanshu.Accounts.Repository { 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 list = _session.QueryOver().Where(x => x.Date >= startDate && x.Date <= finishDate && x.Void).List(); foreach (var item in list) { _session.Delete(item); foreach (var re in _session.QueryOver().Where(x => x.Voucher.VoucherID == item.VoucherID).List()) { _session.Delete(re); } } } public void DeleteStaff(DateTime startDate, DateTime finishDate) { var list = _session.QueryOver().Where(x => x.Date >= startDate && x.Date <= finishDate && x.VoucherType == VoucherType.Staff).List(); foreach (var item in list) { _session.Delete(item); foreach (var re in _session.QueryOver().Where(x => x.Voucher.VoucherID == item.VoucherID).List()) { _session.Delete(re); } } } public void SetPayments(DateTime startDate, DateTime finishDate) { var list = _session.QueryOver().Where(x => x.Date >= startDate && x.Date <= finishDate).List(); foreach (var voucher in list) { var settlementType = SettleOption.Cash; switch (voucher.VoucherType) { case VoucherType.NoCharge: settlementType = SettleOption.NoCharge; break; case VoucherType.Staff: settlementType = SettleOption.Staff; break; } var amount = -1 * voucher.Kots.Sum(x => x.Inventories.Sum(y => y.Amount)); var roundoff = Math.Round(amount) - amount; voucher.Settlements.Clear(); voucher.Settlements.Add(new VoucherSettlement() { Amount = amount, Settled = SettleOption.Amount }); voucher.Settlements.Add(new VoucherSettlement() { Amount = roundoff, Settled = SettleOption.RoundOff }); voucher.Settlements.Add(new VoucherSettlement() { Amount = -1 * (amount + roundoff), Settled = settlementType }); _session.Update(voucher); } } public void ClearModifiers(DateTime startDate, DateTime finishDate) { var list = _session.QueryOver().Where(x => x.Date >= startDate && x.Date <= finishDate).List(); foreach (var voucher in list) { foreach (var kot in voucher.Kots) { foreach (var inventory in kot.Inventories) { if (inventory.InventoryModifier.Count > 0) inventory.InventoryModifier.Clear(); } } _session.Update(voucher); } } public void CombineKots(DateTime startDate, DateTime finishDate) { var list = _session.QueryOver().Where(x => x.Date >= startDate && x.Date <= finishDate).List(); foreach (var voucher in list) { if (voucher.Kots.Count == 0) continue; var kots = voucher.Kots.OrderBy(x => x.Date); var kot = kots.First(); for (var kotIndex = kots.Count(); kotIndex > 1; kotIndex--) { var otherKot = kots.ElementAt(kotIndex - 1); for (var i = otherKot.Inventories.Count; i > 0; i--) { var inventory = otherKot.Inventories[i - 1]; var oldProduct = kot.Inventories.SingleOrDefault(x => x.Product.ProductID == inventory.Product.ProductID); if (oldProduct == null) { inventory.Kot = kot; } else { oldProduct.Quantity += inventory.Quantity; otherKot.Inventories.RemoveAt(i - 1); } } } _session.Update(voucher); } } public void RemoveBlankKots(DateTime startDate, DateTime finishDate) { var list = _session.QueryOver().Where(x => x.Date >= startDate && x.Date <= finishDate).List(); foreach (var voucher in list) { for (var kotIndex = voucher.Kots.Count; kotIndex > 0; kotIndex--) { var kot = voucher.Kots[kotIndex - 1]; if (kot.Inventories.Count == 0) voucher.Kots.RemoveAt(kotIndex - 1); } _session.Update(voucher); } } public void FinalSanction(DateTime startDate, DateTime finishDate) { var query = @" select v.BillID from Voucher v where v.Date < :startDate and v.Void = false and v.VoucherType not in (:nc, :staff) order by v.Date desc "; var lastBill = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("staff", VoucherType.Staff) .SetMaxResults(1) .UniqueResult(); var newID = lastBill == null ? 10001 : GetNewID((int)lastBill); var list = _session.QueryOver().Where(x => x.Date >= startDate && x.Date <= finishDate && x.VoucherType != VoucherType.NoCharge && x.VoucherType != VoucherType.Staff && x.Void == false).OrderBy(x => x.Date).Asc.List(); foreach (var voucher in list) { if (voucher.BillID != newID) { throw new NotImplementedException(); //voucher.BillID = newID; _session.Update(voucher); } 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) { throw new NotImplementedException(); //voucher.BillID = newID; _session.Update(voucher); } newID += 1; } } private static int GetNewID(int lastBill) { lastBill += 1; if (lastBill % 10000 == 0) lastBill += 1; return lastBill; } #endregion public void MoveNc(DateTime startDate, DateTime finishDate, decimal target) { const 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 in (.1575, .2625) 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.AddHours(7)) .SetParameter("finishDate", finishDate.AddDays(1).AddHours(7)) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("staff", VoucherType.Staff) .List(); var totalAmount = GetFood(.1575M, startDate, finishDate) + GetFood(.2625M, startDate, finishDate); var skip = false; for (int i = 0; i < list.Count / 20; i++) { if (target / totalAmount > .75M) break; skip = !skip; if (skip) continue; var item = (object[])list[i]; var voucherID = (Guid)item[0]; var amount = (decimal)item[1]; var voucher = _session.QueryOver().Where(x => x.VoucherID == voucherID).SingleOrDefault(); voucher.VoucherType = VoucherType.NoCharge; _session.Update(voucher); totalAmount -= amount; } } public Dictionary GetLiq(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.Vat = :vat and v.Void = false and v.VoucherType not in (:nc, :staff) "; var dict = new Dictionary(); for (var date = startDate; date <= finishDate; date = date.AddDays(1)) { var qty = _session .CreateQuery(query) .SetParameter("startDate", date.AddHours(7)) .SetParameter("finishDate", date.AddDays(1).AddHours(7)) .SetParameter("vat", vat) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("staff", VoucherType.Staff) .UniqueResult(); dict.Add(date, qty == null ? 0 : (decimal)qty); } return dict; } public Dictionary GetGrossSale(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)) * (1 + i.Vat) 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 dict = new Dictionary(); for (var date = startDate; date <= finishDate; date = date.AddDays(1)) { var qty = _session .CreateQuery(query) .SetParameter("startDate", date.AddHours(7)) .SetParameter("finishDate", date.AddDays(1).AddHours(7)) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("staff", VoucherType.Staff) .UniqueResult(); dict.Add(date, qty == null ? 0 : (decimal)qty); } return dict; } public decimal GetVat(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) * i.Vat) 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.Vat = :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 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.ServiceTax) 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 string GetFirstBill(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 not in (:nc, :staff) order by v.Date "; var qty = _session .CreateQuery(query) .SetParameter("startDate", date.AddHours(7)) .SetParameter("finishDate", date.AddDays(1).AddHours(7)) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("staff", VoucherType.Staff) .SetMaxResults(1) .UniqueResult(); return qty == null ? "" : (string)qty; } public string 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 not in (:nc, :staff) order by v.Date desc "; var qty = _session .CreateQuery(query) .SetParameter("startDate", date.AddHours(7)) .SetParameter("finishDate", date.AddDays(1).AddHours(7)) .SetParameter("nc", VoucherType.NoCharge) .SetParameter("staff", VoucherType.Staff) .SetMaxResults(1) .UniqueResult(); return qty == null ? "" : (string)qty; } public decimal GetFood(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.Vat = :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 decimal SetFood(decimal vat, decimal amount, DateTime startDate, DateTime finishDate) { var list = _session.QueryOver().Where(x => x.Date >= startDate && x.Date <= finishDate && x.Void == false && x.VoucherType != VoucherType.NoCharge && x.VoucherType != VoucherType.Staff).List(); list = Randomize(list); var left = GetFood(vat, startDate, finishDate) - amount; 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.VatRate == vat) { var inventoryAmount = inventory.Quantity * inventory.Price * (1 - inventory.Discount) * (1 + (inventory.IsScTaxable ? inventory.ServiceCharge : 0)); var i = _session.QueryOver().Where(x => x.InventoryID == inventory.InventoryID).SingleOrDefault(); if (inventoryAmount > left) { var newQuantity = inventory.Quantity * (inventoryAmount - left) / inventoryAmount; i.Quantity = newQuantity; _session.Update(i); left = 0; } else { left -= inventoryAmount; _session.Delete(i); } } } } } return GetFood(vat, startDate, finishDate); } public decimal SetLiq(decimal vat, decimal amount, DateTime startDate, DateTime finishDate) { var rand = new Random(); var list = _session.QueryOver().Where(x => x.Date >= startDate && x.Date <= finishDate && x.Void == false && x.VoucherType != VoucherType.NoCharge && x.VoucherType != VoucherType.Staff).List(); list = Randomize(list); var left = GetFood(vat, startDate, finishDate) - amount; 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.VatRate == vat) { var minimum = inventory.Discount == 0 ? 10 : Convert.ToInt32(inventory.Discount * 100); if (minimum >= 90) continue; var discount = Convert.ToDecimal(rand.Next(minimum, 90)) / 100; if (discount == inventory.Discount) continue; var reduction = inventory.Quantity * inventory.Price * (1 + (inventory.IsScTaxable ? inventory.ServiceCharge : 0)) * (discount - inventory.Discount); var i = _session.QueryOver().Where(x => x.InventoryID == inventory.InventoryID).SingleOrDefault(); if (reduction > left) { discount = inventory.Quantity * inventory.Price * (1 + (inventory.IsScTaxable ? inventory.ServiceCharge : 0)); discount = left / discount; i.Discount = discount; _session.Update(i); left = 0; } else { i.Discount = discount; _session.Update(i); left -= reduction; } } } } } return GetFood(vat, startDate, finishDate); } public decimal SetAmount(int vatID, decimal amount, DateTime startDate, DateTime finishDate) { throw new NotImplementedException(); //var random = new Random(); //var list = Randomize(new VoucherBI().List(x => x.Date >= startDate && x.Date <= finishDate && x.Void == false && x.VoucherType != VoucherType.NoCharge && x.VoucherType != VoucherType.Staff)); //var left = GetFood(vatID, startDate, finishDate) - amount; //foreach (var item in list) //{ // if (left <= 0) // break; // var discount = Convert.ToDecimal(random.Next(20, 70)); // discount -= discount % 5; // discount = discount / 100; // foreach (var kot in item.Kots) // { // if (left <= 0) // break; // foreach (var inventory in kot.Inventories) // { // if (left <= 0) // break; // if (inventory.Product.Vat.TaxID == vatID) // { // using (var bi = new InventoryBI()) // { // if (discount < inventory.Discount) // continue; // var inventoryAmount = inventory.Quantity * inventory.Price * (1 - inventory.Discount) * // (1 + (inventory.IsScTaxable ? inventory.ServiceCharge : 0)); // var reduction = inventory.Quantity * inventory.Price * (discount - inventory.Discount) * // (1 + (inventory.IsScTaxable ? inventory.ServiceCharge : 0)); // if (reduction > left) // { // var newDiscount = (1 - inventory.Discount) * left / inventoryAmount; // var i = bi.Get(x => x.InventoryID == inventory.InventoryID); // i.Discount = newDiscount; // bi.Update(i); // left = 0; // } // else // { // var i = bi.Get(x => x.InventoryID == inventory.InventoryID); // i.Discount = discount; // bi.Update(i); // left -= reduction; // } // } // } // } // } //} //return GetFood(vatID, startDate, finishDate); } public IList GetNcable(DateTime startDate, DateTime finishDate) { const string query = @" select v.VoucherID, sum(case when p.TaxID = 1 then i.ServiceCharge else 0 end) , 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 group by p.BaseCode order by p.BaseCode "; var list = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .List(); return list; } public IList GetMove(DateTime startDate, DateTime finishDate) { const string query = @" select p.BaseCode, 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 != 0 group by p.BaseCode order by p.BaseCode "; var list = _session .CreateQuery(query) .SetParameter("startDate", startDate) .SetParameter("finishDate", finishDate) .List(); return list; } #region Beer public decimal GetQuantity(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 SetQuantity(DateTime startDate, DateTime finishDate, decimal quantity) { var list = _session.QueryOver().Where(x => x.Date >= startDate && x.Date <= finishDate && x.Void == false).List(); list = Randomize(list); var left = GetQuantity(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.Quantity != 0) { var inventoryQuantity = inventory.Quantity * inventory.Product.Quantity; var i = _session.QueryOver().Where(x => x.InventoryID == inventory.InventoryID).SingleOrDefault(); if (inventoryQuantity > left) { var newQuantity = inventory.Quantity * (inventoryQuantity - left) / inventoryQuantity; i.Quantity = newQuantity; _session.Update(i); left = 0; } else { left -= inventoryQuantity; _session.Delete(i); } } } } } return GetQuantity(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 decimal GetQuantity(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 = GetQuantity(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 GetQuantity(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; } } }