using CAPI.Custom.Data; using CAPI.Custom.Entities; using System; using System.Collections.Generic; using System.Linq; using System.Text; using CAPI.Custom.Entities.publ.PurchaseOrders; using CAPI.Custom.Domain.PurchaseOrders; using framework_library; using System.Reflection; using System.Collections; using framework_business; using System.Web; using System.Configuration; using AutoMapper; using CAPI.Custom.Domain.PurchaseOrders.Invoices; using CAPI.Custom.Domain.PurchaseOrders.PickingSlip; using CAPI.Custom.Domain.Quotes; using framework_business.objects.custom; namespace CAPI.Custom.Services { public class PurchaseOrderService { private QuotesContext db = new QuotesContext(); private readonly SupplierService supplierService = new SupplierService(); private readonly QuoteService quoteService = new QuoteService(); public readonly TemplateService templateService = new TemplateService(); public readonly InventoryService inventoryService = new InventoryService(); //TODO: consider moving to web.config or maybe some constants class (may be better) private readonly string CEPInventoryCode = "CEP-INV"; private readonly string CEPInventoryTradingName = "CEP Inventory"; //TODO: this should go to web.config private readonly string LocalSupplierType = "local"; private readonly string LocalCurrency = "ZAR"; private readonly decimal LocalVATPercentage = 15; //TODO: Create enum for PurchaseOrder doc types private readonly string DocTypeStockPick = "SP"; private readonly string DocStatusSent = "Sent"; private readonly string POEmailTemplateName = "Purchase Order E-mail Template"; #region public methods public bool ProcessOrder(int quoteId) { var types = db.PurchaseOrderTypes.ToList(); var docTypes = db.PurchaseOrderDocumentTypes.ToList(); var statuses = db.PurchaseOrderStatuses.ToList(); var docStatus = db.PurchaseOrderDocumentStatuses.ToList(); var currencies = db.Currencies.ToList(); vQuote quote = db.vQuotes.FirstOrDefault(p => p.itemID == quoteId); string quoteNumber = quote.QuoteInformation_QuoteNumber; int nextPONumber = BusinessUtils.GetNextPurchaseOrderNumber(); var customerSetup = db.Setup; Dictionary> quoteItemsFinal = db.QuoteItemsFinal_GetByQuote(quoteId); foreach (KeyValuePair> pair in quoteItemsFinal) { PurchaseOrder purchaseOrder = new PurchaseOrder(); purchaseOrder.DateChanged = DateTime.Now; purchaseOrder.DeliveryCity = customerSetup.physicalCity; purchaseOrder.DeliveryCountry = customerSetup.physicalCountry; purchaseOrder.DeliveryPostalCode = customerSetup.physicalCode; purchaseOrder.DeliveryState = customerSetup.physicalProvinceState; purchaseOrder.DeliveryStreet = customerSetup.physicalStreet; purchaseOrder.DeliverySuburb = customerSetup.physicalSuburb; purchaseOrder.DeliveryTelephone = customerSetup.tel; purchaseOrder.QuoteItemsFinal = new List(); List poqifTemp = new List(); List psqifTemp = new List(); purchaseOrder.QuoteId = quoteId; purchaseOrder.QuoteNumber = quoteNumber; PurchaseOrderDocumentType purchaseOrderDocType = null; Supplier supplier = supplierService.Supplier_GetByTradingName(pair.Key); decimal forexAmount = 0, exclAmount = 0, inclAmount = 0; PurchaseOrderType purchaseOrderType = DetermineOrderType(ref supplier, types); // Need to ignore CEP Inventory because Purchase Order should not be created for them // TODO: check with Doroteja if new changes are correct if (purchaseOrderType == null) continue; purchaseOrder.Type = purchaseOrderType; purchaseOrder.Date = DateTime.Now; foreach (QuoteItemsFinal finalItem in pair.Value) { //Depending on Doc type process QIF if (supplier != null) { poqifTemp.Add(ProcessPOQuoteItemsFinal(finalItem, ref forexAmount, ref exclAmount)); } else { psqifTemp.Add(ProcessSPQuoteItemsFinal(finalItem, ref forexAmount, ref exclAmount)); } } if (supplier != null) { purchaseOrderDocType = docTypes.Where(dt => dt.ShortName.EqualsIgnoreCase("PO")).FirstOrDefault(); purchaseOrder.Status = statuses.Where(s => s.Name.EqualsIgnoreCase("Draft")).FirstOrDefault(); purchaseOrder.SupplierId = supplier.itemID; var currency = currencies.Where(c => c.Code.EqualsIgnoreCase(supplier.Currency)).FirstOrDefault(); purchaseOrder.CurrencyId = currency.itemID; purchaseOrder.Currency = currency.Code; purchaseOrder.SupplierTradingName = supplier.TradingName; if (!supplier.SupplierType.EqualsIgnoreCase(LocalSupplierType)) { purchaseOrder.ForexAmount = forexAmount; purchaseOrder.ExclAmountZAR = exclAmount; // Foreign: Excl. Amount ZAR = Incl. Amount ZAR purchaseOrder.InclAmountZAR = exclAmount; } else { //Local: Excl. Amount ZAR x 15% VAT = Incl. Amount ZAR inclAmount = exclAmount + exclAmount * (LocalVATPercentage / 100); purchaseOrder.ExclAmountZAR = exclAmount; purchaseOrder.InclAmountZAR = inclAmount; } } else { purchaseOrder.Status = statuses.Where(s => s.Name.EqualsIgnoreCase("Awaiting Picking")).FirstOrDefault(); purchaseOrderDocType = docTypes.Where(dt => dt.ShortName.EqualsIgnoreCase("SP")).FirstOrDefault(); } purchaseOrder.DocumentType = purchaseOrderDocType; //TODO: Discuss with Dylan how Generate Code (i.e. by reading next number for next PurchaseOrder like for quotes/sales) //purchaseOrder.Code = $"{purchaseOrderDocType.ShortName}" + DateTime.Now.Ticks.ToString().Substring(10); //TODO: Is this correct? purchaseOrder.Code = $"{purchaseOrderDocType.ShortName}{nextPONumber++}"; purchaseOrder = db.PurchaseOrders.Add(purchaseOrder); foreach (PurchaseOrderQuoteItemFinal item in poqifTemp) { item.PurchaseOrderId = purchaseOrder.Id; db.PurchaseOrderQuoteItemFinalProxy.Add(item); } foreach (PurchaseOrderPickingSlipQuoteItemFinal item in psqifTemp) { item.PurchaseOrderId = purchaseOrder.Id; db.PurchaseOrderPickingSlipQuoteItemFinalProxy.Add(item); } db.SaveChanges(); } return true; } public IList GetAll() { return SearchPurchases(new SearchModel()); } public IList SearchPurchases(SearchModel searchInfo) { var posQuery = db.PurchaseOrders.AsQueryable(); if (searchInfo.DocumentTypeIds != null) { posQuery = posQuery.Where(po => searchInfo.DocumentTypeIds.Contains(po.DocumentTypeID)); } if (searchInfo.StatusId.HasValue) { posQuery = posQuery.Where(po => po.StatusID == searchInfo.StatusId); } if (searchInfo.SupplierId.HasValue) { posQuery = posQuery.Where(po => po.SupplierId == searchInfo.SupplierId); } // searchInfo.Keyword will at least be string.Empty so this is fine var keyword = searchInfo.Keyword.ToUpper().Trim(); if (!string.IsNullOrEmpty(keyword)) { posQuery = posQuery.Where(po => po.DocumentType.Name.ToUpper().Contains(keyword) || po.Code.ToUpper().Contains(keyword) || po.QuoteId.ToString().ToUpper().Contains(keyword) || po.QuoteNumber.ToUpper().Contains(keyword) || (string.IsNullOrEmpty(po.SupplierTradingName) ? false : po.SupplierTradingName.ToUpper().Contains(keyword))); // TODO: this seems redundant since quote number is added to child po, but older po's need this in query posQuery = posQuery.Where(po => po.PurchaseOrderParent == null ? true : po.PurchaseOrderParent.QuoteNumber.ToUpper().Contains(keyword)); } posQuery = posQuery.OrderByDescending(x => x.Date); return Mapper.Map(posQuery.ToList(), new List()); } public IList GetAllDocumentTypesModel() { return Mapper.Map(GetAllDocumentTypes(), new List()); } public PurchaseOrderDocumentType GetDocumentTypeByShortName(string shortName) { return GetAllDocumentTypes().FirstOrDefault(t => t.ShortName.Equals(shortName, StringComparison.Ordinal)); } public PurchaseOrderStatusModel GetStatusByNameModel(string name) { return Mapper.Map(GetStatusByName(name), new PurchaseOrderStatusModel()); } public IList GetAllStatusesModel() { return Mapper.Map(GetAllStatuses(), new List()); } public bool PrintPurchaseOrder(int purchaseOrderId, string webAddress, ref string statementPath, ref string statementFile) { try { bool result = false; PurchaseOrder purchaseOrder = db.PurchaseOrder_GetById(purchaseOrderId); if (purchaseOrder == null) { throw new Exception("Purchase Order with ID = " + purchaseOrderId + " not found!"); } Supplier supplier = null; if (purchaseOrder.SupplierId != 0) { supplier = supplierService.Supplier_GetByItemId(purchaseOrder.SupplierId); if (supplier == null) { throw new Exception("Supplier with ID = " + purchaseOrder.SupplierId + " not found!"); } } Quote quote = quoteService.GetByItemId(purchaseOrder.QuoteId); if (quote == null) { throw new Exception("Quote with ID = " + purchaseOrder.QuoteId + " not found!"); } oSetup setup = (oSetup)(xData.GetTypedByCriteriaSpecific("recId", typeof(oSetup), "isActive", "1")[0]); string headerData = String.Empty; string bodyData = String.Empty; pNums.TemplateType templateType = pNums.TemplateType.PurchaseOrder; if (purchaseOrder.DocumentType.ShortName.EqualsIgnoreCase(DocTypeStockPick)) { templateType = pNums.TemplateType.StockPick; } //get templates foreach (oTemplate template in xData.GetTypedByCriteriaSpecific("recId", typeof(oTemplate), "templateTypeId", templateType.GetHashCode().ToString(), "templateName")) { if (template.templateName.ToLower().Contains("header")) { headerData = template.templateContent; } else if (template.templateName.ToLower().Contains("body")) { bodyData = template.templateContent; } } switch (templateType) { case pNums.TemplateType.PurchaseOrder: headerData = SetPurchaseOrderHeaderParamsForPrint(headerData, setup, purchaseOrder, supplier, quote); break; case pNums.TemplateType.StockPick: headerData = SetStockPickHeaderParamsForPrint(headerData, purchaseOrder, quote); break; } headerData = headerData.Replace("{WebAddress}", ""); //cater for image paths headerData = headerData.Replace("/images/", webAddress + "/images/"); headerData = headerData.Replace("/upload/image/", webAddress + "/upload/image/"); //CVH 2016-09-15 If no logo uploaded, build company name in box string companyName = setup.customer; if (setup.logoUploaded == String.Empty) headerData = headerData.Replace("{logo}", "

" + companyName + "

"); else headerData = headerData.Replace("{logo}", ""); //Reusing the method for generating QuoteItemsFinal table switch (templateType) { case pNums.TemplateType.PurchaseOrder: IList purchaseOrderQuoteItemsFinalList = db.PurcaseOrderQuotesFinalItem_GetByPurchaseOrderId(purchaseOrderId); ArrayList oQuoteItemsFinalList = ConvertToQuoteItemList(purchaseOrderQuoteItemsFinalList, typeof(oQuoteItemsFinal)); ArrayList quoteItemsFinalList = ConvertToQuoteItemList(purchaseOrderQuoteItemsFinalList, typeof(QuoteItemsFinal)); bodyData = SetPurchaseOrderBodyParamsForPrint(bodyData, setup, purchaseOrder, supplier, quoteItemsFinalList, oQuoteItemsFinalList); break; case pNums.TemplateType.StockPick: IList purchaseOrderPickingSlipQuoteItemFinalList = purchaseOrder.PickingSlipQuoteItemFinal.ToList(); ArrayList oPickingSlipQuoteItemsFinalList = ConvertPirckingSlipToQuoteItemList(purchaseOrderPickingSlipQuoteItemFinalList, typeof(oQuoteItemsFinal)); ArrayList pickingSlipQuoteItemsFinalList = ConvertPirckingSlipToQuoteItemList(purchaseOrderPickingSlipQuoteItemFinalList, typeof(QuoteItemsFinal)); ArrayList oPurchaseOrderPickingSlipQuoteItemFinalList = new ArrayList(); foreach (var oPickingSlipQuoteItemFinal in oPickingSlipQuoteItemsFinalList) { var pickingSlipItem = purchaseOrder.PickingSlipQuoteItemFinal.FirstOrDefault(x => x.QuoteItemFinalId == ((oQuoteItemsFinal)oPickingSlipQuoteItemFinal).itemID); var oPickingSlipItem = Mapper.Map(oPickingSlipQuoteItemFinal, new oPurchaseOrderPickingSlipQuoteItemFinal()); oPickingSlipItem.Available = pickingSlipItem.Available; oPickingSlipItem.Picked = pickingSlipItem.Picked; oPickingSlipItem.Outstanding = pickingSlipItem.Outstanding; oPickingSlipItem.LocationBin = pickingSlipItem.LocationBin; oPurchaseOrderPickingSlipQuoteItemFinalList.Add(oPickingSlipItem); } bodyData = SetStockPickBodyParamsForPrint(bodyData, setup, pickingSlipQuoteItemsFinalList, oPurchaseOrderPickingSlipQuoteItemFinalList); break; } statementFile = purchaseOrder.Code + "_" + purchaseOrder.Date.ToString("yyyy-MM-dd") + ".pdf"; statementPath = HttpContext.Current.Server.MapPath("~/upload/documents/"); utils.validateFolder(statementPath); string columnHeaders = GetColumnHeaders(supplier); result = utils.ConvertHTMLToPDFFile(bodyData, statementPath + statementFile, true, headerData, "", true, "", columnHeaders); return result; } catch (Exception ex) { throw new Exception(MethodBase.GetCurrentMethod().Name + ":" + ex.Message); } } public string GetTemplateForPOEmail() { return templateService.GetTemplateByName(POEmailTemplateName); } public PurchaseOrderModel GetByIdModel(int purchaseOrderId) { var purchaseOrder = GetById(purchaseOrderId); var purchaseOrderModel = Mapper.Map(purchaseOrder, new PurchaseOrderModel()); switch (purchaseOrder.DocumentType.ShortName) { case "PO": break; case "SP": purchaseOrderModel.PickingSlipQuoteItemsFinal = GetStockPickQuoteItemModelList(purchaseOrder.PickingSlipQuoteItemFinal); break; case "INV": purchaseOrderModel.InvoiceQuoteItemsFinal = GetInvoiceQuoteItemModelList(purchaseOrder.InvoiceQuoteItemsFinal); break; } return purchaseOrderModel; } public IList GetQuoteItemsFinals(int purchaseOrderId) { var purchaseOrder = GetById(purchaseOrderId); List finalItemsList = ConvertToQuoteItemList(purchaseOrder.QuoteItemsFinal.ToList(), typeof(QuoteItemsFinal)).Cast().ToList(); var retVal = Mapper.Map(finalItemsList, new List()); foreach(var item in retVal) { item.Currency = purchaseOrder.Currency; } return retVal; } public decimal CalculateTotalWeightFromModel(IEnumerable finalItems) { return CalculateTotalWeight(Mapper.Map(finalItems, new List())); } public PurchaseOrderModel UpdatePurchaseOrder(PurchaseOrderModel po) { PurchaseOrder poLoaded = db.PurchaseOrders.Find(po.Id); poLoaded.DateChanged = DateTime.Now; db.Entry(poLoaded).OriginalValues["RowVersion"] = po.RowVersion; switch (poLoaded.DocumentType.ShortName) { case "PO": poLoaded.DeliveryAttention = po.DeliveryAttention; poLoaded.DeliveryStreet = po.DeliveryStreet; poLoaded.DeliverySuburb = po.DeliverySuburb; poLoaded.DeliveryCity = po.DeliveryCity; poLoaded.DeliveryState = po.DeliveryState; poLoaded.DeliveryPostalCode = po.DeliveryPostalCode; poLoaded.DeliveryCountry = po.DeliveryCountry; poLoaded.DeliveryInstructions = po.DeliveryInstructions; poLoaded.StatusID = po.StatusID; poLoaded.DeliveryDate = po.DeliveryDate; break; case "SP": poLoaded.Notes = po.Notes; poLoaded.CancelReason = po.CancelReason; var outstandingItems = new List(); foreach (var item in po.PickingSlipQuoteItemsFinal) { PurchaseOrderPickingSlipQuoteItemFinal itemInDb = poLoaded.PickingSlipQuoteItemFinal.FirstOrDefault(x => x.QuoteItemFinalId == item.itemID); itemInDb.Available -= item.Picked; itemInDb.TotallyPicked += item.Picked; itemInDb.Picked = item.Picked; itemInDb.Outstanding = itemInDb.Available; if(itemInDb.Outstanding != 0) { outstandingItems.Add(itemInDb); } itemInDb.LocationBin = item.LocationBin; } if(outstandingItems.Count == 0) { poLoaded.Status = GetStatusByName("Picked"); } else { poLoaded.Status = GetStatusByName("Partially Picked"); } break; } try { db.SaveChanges(); } catch (Exception ex) { // TODO: update services to use context per request (somehow) db = new QuotesContext(); throw ex; } if (poLoaded.DocumentType.ShortName.Equals("SP")) { inventoryService.InventoryAutomationUpdate(poLoaded.QuoteId, pNums.InventoryAutomationType.StockPick_Picked); } var returnModel = Mapper.Map(poLoaded, new PurchaseOrderModel()); returnModel.PickingSlipQuoteItemsFinal = GetStockPickQuoteItemModelList(poLoaded.PickingSlipQuoteItemFinal); return returnModel; } public bool EmailPurchaseOrder(PurchaseOrderEmailModel emailModel) { bool success = SendPurchaseOrderEmail(emailModel); if (success) { PurchaseOrder purchaseOrder = AutoMapper.Mapper.Map(GetById(emailModel.PurchaseOrderId.Value), new PurchaseOrder()); int newStatusId = GetDocumentStatusByName(DocStatusSent).Id; purchaseOrder.DocumentStatusID = newStatusId; db.SaveChanges(); return true; } return false; } public void CreateInvoice(PurchaseOrderModel model) { var parentPurchaseOrder = GetById(model.PurchaseOrderParentId.Value); var statuses = db.PurchaseOrderStatuses.ToList(); var docTypes = db.PurchaseOrderDocumentTypes.ToList(); var newSupplierInvoice = new PurchaseOrder(); newSupplierInvoice.PurchaseOrderParentId = parentPurchaseOrder.Id; newSupplierInvoice.QuoteId = parentPurchaseOrder.QuoteId; newSupplierInvoice.QuoteNumber = parentPurchaseOrder.QuoteNumber; newSupplierInvoice.SupplierId = parentPurchaseOrder.SupplierId; newSupplierInvoice.CurrencyId = parentPurchaseOrder.CurrencyId; newSupplierInvoice.Currency = parentPurchaseOrder.Currency; var supplier = supplierService.Supplier_GetByItemId(parentPurchaseOrder.SupplierId); if (!supplier.SupplierType.EqualsIgnoreCase(LocalSupplierType)) { newSupplierInvoice.ForexAmount = model.InvoiceTotal + model.FreightCost + model.DutiesCost; newSupplierInvoice.ExclAmountZAR = newSupplierInvoice.ForexAmount * model.ExchangeRate; newSupplierInvoice.InclAmountZAR = newSupplierInvoice.ExclAmountZAR; } else { newSupplierInvoice.ForexAmount = 0; newSupplierInvoice.ExclAmountZAR = model.InvoiceTotal + model.FreightCost; newSupplierInvoice.InclAmountZAR = newSupplierInvoice.ExclAmountZAR * ((100 + LocalVATPercentage) / 100); } newSupplierInvoice.SupplierTradingName = parentPurchaseOrder.SupplierTradingName; newSupplierInvoice.Code = model.Code; newSupplierInvoice.Date = model.Date; newSupplierInvoice.DueDate = model.DueDate; newSupplierInvoice.ExchangeRate = model.ExchangeRate; newSupplierInvoice.FreightCost = model.FreightCost; newSupplierInvoice.DutiesCost = model.DutiesCost; newSupplierInvoice.WaybillNumber = model.WaybillNumber; newSupplierInvoice.InvoiceTotal = model.InvoiceTotal; newSupplierInvoice.Status = statuses.Where(s => s.Name.EqualsIgnoreCase("Allocated")).FirstOrDefault(); newSupplierInvoice.DocumentType = docTypes.Where(dt => dt.ShortName.EqualsIgnoreCase("INV")).FirstOrDefault(); newSupplierInvoice.TypeID = parentPurchaseOrder.TypeID; newSupplierInvoice = db.PurchaseOrders.Add(newSupplierInvoice); foreach (var item in model.InvoiceQuoteItemsFinal) { var newItem = new PurchaseOrderInvoiceQuoteItemFinal() { QuoteItemFinalId = item.itemID, InvoicePrice = item.InvoicePrice, LocationBin = item.LocationBin, PurchaseOrderId = newSupplierInvoice.Id, Received = item.Received }; db.PurchaseOrderInvoiceQuoteItemFinalProxy.Add(newItem); } db.SaveChanges(); } public void UpdateInvoice(PurchaseOrderModel model) { var updateSupplierInvoice = GetById(model.Id); updateSupplierInvoice.DateChanged = DateTime.Now; db.Entry(updateSupplierInvoice).OriginalValues["RowVersion"] = model.RowVersion; updateSupplierInvoice.Code = model.Code; updateSupplierInvoice.Date = model.Date; updateSupplierInvoice.DueDate = model.DueDate; updateSupplierInvoice.ExchangeRate = model.ExchangeRate; updateSupplierInvoice.FreightCost = model.FreightCost; updateSupplierInvoice.DutiesCost = model.DutiesCost; updateSupplierInvoice.WaybillNumber = model.WaybillNumber; updateSupplierInvoice.InvoiceTotal = model.InvoiceTotal; updateSupplierInvoice.StatusID = model.StatusID; var supplier = supplierService.Supplier_GetByItemId(updateSupplierInvoice.PurchaseOrderParent.SupplierId); if (!supplier.SupplierType.EqualsIgnoreCase(LocalSupplierType)) { updateSupplierInvoice.ForexAmount = model.InvoiceTotal + model.FreightCost + model.DutiesCost; updateSupplierInvoice.ExclAmountZAR = updateSupplierInvoice.ForexAmount * model.ExchangeRate; updateSupplierInvoice.InclAmountZAR = updateSupplierInvoice.ExclAmountZAR; } else { updateSupplierInvoice.ForexAmount = 0; updateSupplierInvoice.ExclAmountZAR = model.InvoiceTotal + model.FreightCost; updateSupplierInvoice.InclAmountZAR = updateSupplierInvoice.ExclAmountZAR * ((100 + LocalVATPercentage) / 100); } foreach (var item in model.InvoiceQuoteItemsFinal) { var itemInDb = updateSupplierInvoice.InvoiceQuoteItemsFinal.FirstOrDefault(x => x.QuoteItemFinalId == item.itemID); itemInDb.QuoteItemFinalId = item.itemID; itemInDb.InvoicePrice = item.InvoicePrice; itemInDb.LocationBin = item.LocationBin; itemInDb.PurchaseOrderId = updateSupplierInvoice.Id; itemInDb.Received = item.Received; } try { db.SaveChanges(); } catch (Exception ex) { // TODO: update services to use context per request (somehow) db = new QuotesContext(); throw ex; } } #endregion #region private methods private PurchaseOrderType DetermineOrderType(ref Supplier supplier, List types) { string type = string.Empty; if (supplier != null) { if (supplier.Code.EqualsIgnoreCase(CEPInventoryCode) && supplier.TradingName.EqualsIgnoreCase(CEPInventoryTradingName)) { supplier = null; type = "S"; } else if (supplier.SupplierType.EqualsIgnoreCase(LocalSupplierType)) { type = "LB"; } else { type = "OB"; } } else { supplier = null; type = "S"; } return types.Where(t => t.ShortName.EqualsIgnoreCase(type)).FirstOrDefault(); } private PurchaseOrderQuoteItemFinal ProcessPOQuoteItemsFinal(QuoteItemsFinal finalItem, ref decimal forexAmount, ref decimal exclAmount) { PurchaseOrderQuoteItemFinal newItem = new PurchaseOrderQuoteItemFinal(); newItem.QuoteItemFinalId = finalItem.itemID; newItem.Available = finalItem.QuantityAvailable.Value; forexAmount += calculateForexAmount(finalItem); exclAmount += calculateCostPrice(finalItem); return newItem; } private PurchaseOrderPickingSlipQuoteItemFinal ProcessSPQuoteItemsFinal(QuoteItemsFinal finalItem, ref decimal forexAmount, ref decimal exclAmount) { PurchaseOrderPickingSlipQuoteItemFinal newItem = new PurchaseOrderPickingSlipQuoteItemFinal(); newItem.QuoteItemFinalId = finalItem.itemID; newItem.Available = finalItem.QuantityAvailable.Value; newItem.Picked = 0; newItem.Outstanding = finalItem.QuantityAvailable.Value; newItem.LocationBin = string.Empty; forexAmount += calculateForexAmount(finalItem); exclAmount += calculateCostPrice(finalItem); return newItem; } private decimal calculateForexAmount(QuoteItemsFinal finalItem) { if (!finalItem.CostPriceFOREX.HasValue) { finalItem.CostPriceFOREX = 0; } return finalItem.CostPriceFOREX.Value * finalItem.QuantityAvailable.Value; ; } private decimal calculateCostPrice(QuoteItemsFinal finalItem) { if (!finalItem.CostPriceZAR.HasValue) { finalItem.CostPriceZAR = 0; } return finalItem.CostPriceZAR.Value * finalItem.QuantityAvailable.Value; } private ArrayList ConvertToQuoteItemList(IList purchaseOrderQuoteFinalItems, Type type) { ArrayList retVal = null; IEnumerable ids = from PurchaseOrderQuoteItemFinal item in purchaseOrderQuoteFinalItems select item.QuoteItemFinalId; if (type.Equals(typeof(oQuoteItemsFinal))) { retVal = xData.GetTypedByCriteriaSpecific("recId", type, "itemID", String.Join(",", ids), "itemID", "publ_"); } else { retVal = new ArrayList(db.QuoteItemsFinal.Where(i => ids.Contains(i.itemID)).ToList()); } return retVal; } private ArrayList ConvertPirckingSlipToQuoteItemList(IList list, Type type) { ArrayList retVal = null; IEnumerable ids = from PurchaseOrderPickingSlipQuoteItemFinal item in list select item.QuoteItemFinalId; if (type.Equals(typeof(oQuoteItemsFinal))) { retVal = xData.GetTypedByCriteriaSpecific("recId", type, "itemID", String.Join(",", ids), "itemID", "publ_"); } else { retVal = new ArrayList(db.QuoteItemsFinal.Where(i => ids.Contains(i.itemID)).ToList()); } return retVal; } private string BuildSalesTotals(oSetup setup, Supplier supplier, ArrayList quoteItemsFinalList) { StringBuilder totalsBuilder = new StringBuilder("
"); if (supplier != null) { decimal VatRate = 0; string currency = LocalCurrency; if (supplier.VATRegistered != null) { if (supplier.VATRate == "") { supplier.VATRate = "0%"; } VatRate = Convert.ToDecimal(supplier.VATRate.Replace('%', ' ').Trim()); currency = supplier.Currency; } else if (setup.vatRegistered && setup.vatRate > 0) { VatRate = setup.vatRate; } decimal subtotal = CalculateSubTotal(quoteItemsFinalList.Cast().ToList(), supplier.SupplierType.EqualsIgnoreCase(LocalSupplierType)); decimal VatAmount = subtotal * (VatRate / 100); decimal total = subtotal + VatAmount; totalsBuilder.AppendLine(""); totalsBuilder.AppendLine(""); totalsBuilder.AppendLine(""); totalsBuilder.AppendLine(""); totalsBuilder.AppendLine(""); totalsBuilder.AppendLine(""); totalsBuilder.AppendLine(""); totalsBuilder.AppendLine(""); totalsBuilder.AppendLine(""); totalsBuilder.AppendLine(""); } decimal totalWeight = CalculateTotalWeight(quoteItemsFinalList.Cast().ToList()); totalsBuilder.AppendLine(""); totalsBuilder.AppendLine(""); totalsBuilder.AppendLine(""); totalsBuilder.AppendLine("
 "); totalsBuilder.AppendLine("Subtotal"); totalsBuilder.AppendLine($"{subtotal:N2}"); totalsBuilder.AppendLine("
 "); totalsBuilder.AppendLine("VAT @ " + VatRate + "%"); totalsBuilder.AppendLine($"{VatAmount:N2}"); totalsBuilder.AppendLine("
 "); totalsBuilder.AppendLine("Total Amount " + currency + ""); totalsBuilder.AppendLine($"{total:N2}"); totalsBuilder.AppendLine("
 
 "); totalsBuilder.AppendLine("Total Weight"); totalsBuilder.AppendLine($"{totalWeight:N2} kg"); totalsBuilder.AppendLine("
"); return totalsBuilder.ToString(); } private decimal CalculateSubTotal(IEnumerable finalItems, bool isLocalSupplier) { return finalItems.Sum(i => CalculateSubtotalForItem(i, isLocalSupplier)); } private decimal CalculateSubtotalForItem(QuoteItemsFinal finalItem, bool isLocalSupplier) { if (!isLocalSupplier) { if (finalItem.CostPriceFOREX == null) finalItem.CostPriceFOREX = 0; return finalItem.CostPriceFOREX.Value * finalItem.QuantityAvailable.Value; } else { if (finalItem.CostPriceZAR == null) finalItem.CostPriceZAR = 0; return finalItem.CostPriceZAR.Value * finalItem.QuantityAvailable.Value; } } private string SetPurchaseOrderHeaderParamsForPrint(string headerData, oSetup setup, PurchaseOrder purchaseOrder, Supplier supplier, Quote quote) { headerData = headerData.Replace("{To}", "To"); headerData = headerData.Replace("{From}", "From"); //JR 2019-04-27 Contact Details StringBuilder sbContactDetails = new StringBuilder(); sbContactDetails.Append("Contact Details
"); sbContactDetails.Append(setup.tel + "
"); sbContactDetails.Append(setup.email + "
"); headerData = headerData.Replace("{contactDetails}", sbContactDetails.ToString()); headerData = headerData.Replace("{DocNum}", "Purchase Order Number:
" + purchaseOrder.Code + "
"); string deliveryDate = ""; if (purchaseOrder.DeliveryDate != null) { purchaseOrder.DeliveryDate.Value.ToString("yyyy/MM/dd"); } headerData = headerData.Replace("{DocDate}", "Purchase Order Date:
" + purchaseOrder.Date.ToString("yyyy/MM/dd") + "

Delivery Date:
" + deliveryDate + "
"); headerData = headerData.Replace("{AccountNumber}", "Account Number:
" + supplier.Code + "
"); headerData = headerData.Replace("{Reference}", "Reference:
" + quote.Number + "
"); headerData = headerData.Replace("{Attention}", ""); supplier.PostalAddress = supplier.PostalAddress.Replace(",", "
"); /* CVH 2016-09-13 Add trading as name to company name */ string companyName = setup.customer; if (setup.tradingAs != String.Empty && !companyName.Contains(" t/a ")) companyName += " t/a " + setup.tradingAs; headerData = headerData.Replace("{FromName}", companyName); headerData = headerData.Replace("{FromAddress}", setup.postalStreet + "
" + setup.postalSuburb + "
" + setup.postalCity + "
" + setup.postalProvinceState + "
" + setup.postalCountry + "
" + setup.postalCode); if (setup.vatRegistered) { headerData = headerData.Replace("{FromTaxDisplayname}", "VAT Number:"); headerData = headerData.Replace("{FromTaxDisplayNumber}", setup.vatRegistrationNumber); } else { headerData = headerData.Replace("{FromTaxDisplayNumber}", ""); headerData = headerData.Replace("{FromTaxDisplayname}", ""); } if (supplier.VATRegistered != string.Empty && supplier.VATRegistered != "No") { headerData = headerData.Replace("{ToTaxDisplayname}", "VAT Number:"); headerData = headerData.Replace("{ToTaxNumber}", supplier.VATRegistered); } else { headerData = headerData.Replace("{ToTaxDisplayname}", ""); headerData = headerData.Replace("{ToTaxNumber}", ""); } headerData = headerData.Replace("{oSales.name}", supplier.TradingName); utils.MergeHTMData(ref headerData, utils.BuildFieldCodeList(setup, true)); utils.MergeHTMData(ref headerData, utils.BuildFieldCodeList(purchaseOrder, true)); headerData = headerData.Replace("{heading}", purchaseOrder.DocumentType.Name + " Order"); headerData = headerData.Replace("{oSales.postalAddress}", supplier.PostalAddress.Replace(",", "
")); return headerData; } private string SetPurchaseOrderBodyParamsForPrint(string bodyData, oSetup setup, PurchaseOrder purchaseOrder, Supplier supplier, ArrayList quoteItemsFinalList, ArrayList oQuoteItemsFinalList) { bodyData = bodyData.Replace("{AccountLines}", xSales.BuildSalesInvoiceLines(oQuoteItemsFinalList, pNums.TemplateType.PurchaseOrder, supplier.SupplierType.EqualsIgnoreCase(LocalSupplierType), supplier.Currency, pNums.DocumentType.Quote)); bodyData = bodyData.Replace("{Totals}", BuildSalesTotals(setup, supplier, quoteItemsFinalList)); bodyData = bodyData.Replace("{DeliveryAddress}", $"{purchaseOrder.DeliveryStreet }
{purchaseOrder.DeliverySuburb }
{purchaseOrder.DeliveryCity }
{purchaseOrder.DeliveryPostalCode }
{purchaseOrder.DeliveryCountry }"); bodyData = bodyData.Replace("{DeliveryAttention}", purchaseOrder.DeliveryAttention == null ? "" : purchaseOrder.DeliveryAttention); bodyData = bodyData.Replace("{DeliveryTelephone}", purchaseOrder.DeliveryTelephone); bodyData = bodyData.Replace("{DeliveryInstructions}", purchaseOrder.DeliveryInstructions == null ? "" : purchaseOrder.DeliveryInstructions); return bodyData; } private string SetStockPickHeaderParamsForPrint(string headerData, PurchaseOrder purchaseOrder, Quote quote) { headerData = headerData.Replace("{CustomerName}", quote.CustomerTradingName); headerData = headerData.Replace("{PurchaseOrderNumber}", quote.DeliveryPONumber); string deliveryEstimatedDate = ""; if (quote.DeliveryEstimatedDate != null) deliveryEstimatedDate = quote.DeliveryEstimatedDate.Value.ToString("yyyy/MM/dd"); headerData = headerData.Replace("{EstimatedDeliveryDate}", deliveryEstimatedDate); headerData = headerData.Replace("{AccountNumber}", quote.CustomerCode); headerData = headerData.Replace("{PickingSlipNumber}", purchaseOrder.Code); headerData = headerData.Replace("{Date}", purchaseOrder.Date.ToString("yyyy/MM/dd")); headerData = headerData.Replace("{Reference}", quote.Number); headerData = headerData.Replace("{oSales.postalAddress}", quote.CustomerPostalAddress.Replace(",", "
")); return headerData; } private string SetStockPickBodyParamsForPrint(string bodyData, oSetup setup, ArrayList quoteItemsFinalList, ArrayList oQuoteItemsFinalList) { bodyData = bodyData.Replace("{AccountLines}", xSales.BuildSalesInvoiceLines(oQuoteItemsFinalList, pNums.TemplateType.StockPick, true, LocalCurrency, pNums.DocumentType.Quote)); return bodyData.Replace("{Totals}", BuildSalesTotals(setup, null, quoteItemsFinalList)); } private string GetColumnHeaders(Supplier supplier) { if (supplier != null) return @"" + xSales.GetColumnHeaders(pNums.TemplateType.PurchaseOrder, supplier.SupplierType.EqualsIgnoreCase(LocalSupplierType), supplier.Currency) + ""; else return @"" + xSales.GetColumnHeaders(pNums.TemplateType.StockPick, true, LocalCurrency) + ""; } private PurchaseOrderDocumentStatus GetDocumentStatusByName(string name) { return db.PurchaseOrderDocumentStatuses.FirstOrDefault(s => s.Name.Equals(name, StringComparison.Ordinal)); } private bool SendPurchaseOrderEmail(PurchaseOrderEmailModel emailModel) { try { string file = String.Empty; string path = string.Empty; if (PrintPurchaseOrder(emailModel.PurchaseOrderId.Value, ConfigurationManager.AppSettings["WebAddy"], ref path, ref file)) { /* CVH 2016-09-02 Use template from calling method, user allowed to edit before send. All {placeholder}'s have already been replaced before showing in modal */ string emailTemplate = emailModel.EmailBody; oEmail mail = new oEmail(); mail.Body = emailTemplate; mail.Attachments.Add(path + file); mail.Subject = emailModel.Subject; mail.fromAddress = emailModel.From; mail.toAddress = emailModel.To; mail.ccAddress = emailModel.Cc; mail.bccAddress = emailModel.Bcc; if (communication.SendAnEmail(mail)) { //Add note with statement as attachment xSales.AddCreateStatementNote(emailModel.PurchaseOrderId.Value, mail.Subject, mail.Body, path, file, emailModel.userId.Value, string.Empty); return true; } else { return false; } } else return false; } catch (Exception ex) { throw new Exception(MethodBase.GetCurrentMethod().Name + ":" + ex.Message); } } private PurchaseOrder GetById(int purchaseOrderId) { return db.PurchaseOrders.Find(purchaseOrderId); } private PurchaseOrderStatus GetStatusByName(string name) { return GetAllStatuses().FirstOrDefault(s => s.Name.Equals(name, StringComparison.Ordinal)); } private IList GetAllDocumentTypes() { return db.PurchaseOrderDocumentTypes.OrderBy(s => s.Name).ToList(); } private IList GetAllStatuses() { return db.PurchaseOrderStatuses.OrderBy(s => s.Name).ToList(); } private decimal CalculateTotalWeight(IEnumerable finalItems) { return finalItems.Sum(i => i.WeightKG.Value * i.QuantityAvailable.Value); } private List GetInvoiceQuoteItemModelList( ICollection purchaseOrderInvoiceQuoteFinalItems) { List retVal = new List(); IEnumerable ids = from PurchaseOrderInvoiceQuoteItemFinal item in purchaseOrderInvoiceQuoteFinalItems select item.QuoteItemFinalId; List quotes = db.QuoteItemsFinal.Where(i => ids.Contains(i.itemID)).ToList(); foreach (var quote in quotes) { var invoiceQuote = Mapper.Map(quote, new InvoiceQuoteItemsFinalModel()); var invoiceQuoteItemFinal = purchaseOrderInvoiceQuoteFinalItems.FirstOrDefault(x => x.QuoteItemFinalId == quote.itemID); invoiceQuote.Received = invoiceQuoteItemFinal.Received; invoiceQuote.InvoicePrice = invoiceQuoteItemFinal.InvoicePrice; invoiceQuote.LocationBin = invoiceQuoteItemFinal.LocationBin; retVal.Add(invoiceQuote); } return retVal; } private List GetStockPickQuoteItemModelList( ICollection purchaseOrderStockPickQuoteFinalItems) { List retVal = new List(); IEnumerable ids = from PurchaseOrderPickingSlipQuoteItemFinal item in purchaseOrderStockPickQuoteFinalItems select item.QuoteItemFinalId; List quotes = db.QuoteItemsFinal.Where(i => ids.Contains(i.itemID)).ToList(); foreach (var quote in quotes) { var stockPickQuote = Mapper.Map(quote, new PickingSlipQuoteItemsFinalModel()); var stockPickQuoteItemFinal = purchaseOrderStockPickQuoteFinalItems.FirstOrDefault(x => x.QuoteItemFinalId == quote.itemID); stockPickQuote.QuantityAvailable = quote.QuantityAvailable; stockPickQuote.Available = stockPickQuoteItemFinal.Available; stockPickQuote.TotallyPicked = stockPickQuoteItemFinal.TotallyPicked; stockPickQuote.Picked = 0; stockPickQuote.Outstanding = stockPickQuoteItemFinal.Available; stockPickQuote.LocationBin = stockPickQuoteItemFinal.LocationBin; retVal.Add(stockPickQuote); } retVal = retVal.OrderBy(x => x.WarehouseLocation).ThenBy(x => x.Location).ToList(); return retVal; } #endregion } }