/// <summary> /// Get Receivable Account /// </summary> /// <param name="db"></param> /// <returns></returns> public static List <string> GetCashAccounts(NancyBlackDatabase db) { var siteSettings = AdminModule.ReadSiteSettings(); if (siteSettings.accounting == null) { return(db.QueryAsDynamic("SELECT DISTINCT IncreaseAccount AS Name FROM AccountingEntry", new { Name = "" }) .AsEnumerable() .Select(item => (string)item.Name) .ToList()); } var accountSettings = (from dynamic item in siteSettings.accounting.accounts as JArray select new { Name = (string)item.Name, Type = (string)item.Type }).ToLookup(i => i.Name, i => i.Type); return(db.QueryAsDynamic("SELECT DISTINCT IncreaseAccount AS Name FROM AccountingEntry", new { Name = "" }) .AsEnumerable() .Select(item => (string)item.Name) .Where(s => string.IsNullOrEmpty(s) == false && accountSettings[s].FirstOrDefault() == "Cash") .ToList()); }
internal static void ProcessReceiptCreation(NancyBlackDatabase db, Receipt obj) { // When payment receipt is created, create accounting entry db.Transaction(() => { var saleorder = db.GetById <SaleOrder>(obj.SaleOrderId); var paymentlog = db.GetById <PaymentLog>(obj.PaymentLogId); if (saleorder == null || paymentlog == null) { // bogus receipt throw new InvalidOperationException("Invalid Receipt was created"); } // Ensures all sale order logic has been ran // if the sale order was created before new system change if (saleorder.__createdAt < TaxSystemEpoch) { saleorder.UpdateSaleOrder(AdminModule.ReadSiteSettings(), db, false); } // Receipt will create 2 entries // 1) PaymentSource account increases, with total amount // TODO: Mapping from PaymentSource to Account AccountingEntry entry1 = new AccountingEntry(); entry1.TransactionDate = paymentlog.__createdAt; entry1.TransactionType = "income"; entry1.DebtorLoanerName = "Customer"; entry1.IncreaseAccount = paymentlog.PaymentSource; entry1.IncreaseAmount = saleorder.TotalAmount; entry1.SaleOrderId = saleorder.Id; db.UpsertRecord(entry1); if (saleorder.TotalTax > 0) { // 2) paid tax is decreased // (ภาษีขาย ทำให้ภาษีซื้อลดลง, ภาษีซื้อ บันทึกไว้ตอน InventoryInbound) AccountingEntry entry2 = new AccountingEntry(); entry2.TransactionDate = paymentlog.__createdAt; entry2.TransactionType = "expense"; entry2.DebtorLoanerName = "Tax"; entry2.DecreaseAccount = "Paid Tax"; entry2.DecreaseAmount = saleorder.TotalTax * -1; entry2.SaleOrderId = saleorder.Id; db.UpsertRecord(entry2); } }); }
private static void NancyBlackDatabase_ObjectCreated(NancyBlackDatabase db, string table, dynamic row) { if (table == "NcbMailingListSubscription") { var settings = AdminModule.ReadSiteSettings(); var listId = settings.commerce.mailchimp.listid; var key = settings.commerce.mailchimp.apikey; Task.Run(() => { MailingListModule.AddToMailChimp(key, listId, row); }); } }
private dynamic SyncMailchimp(dynamic arg) { var errors = new List <string>(); string key = AdminModule.ReadSiteSettings().commerce.mailchimp.apikey; string memberListId = this.CurrentSite.commerce.mailchimp.listid; string customerListId = this.CurrentSite.commerce.mailchimp.customerlistid; var all = this.SiteDatabase.Query <NcbMailingListSubscription>().OrderByDescending(u => u.Id).ToList(); foreach (var item in all) { MailingListModule.AddToMailChimp(key, memberListId, item); } var allCustomers = this.SiteDatabase.Query <SaleOrder>() .Where(so => so.PaymentStatus == PaymentStatus.PaymentReceived) .OrderByDescending(so => so.Id) .ToList(); foreach (var item in allCustomers) { if (item.Customer == null) { continue; } MailingListModule.AddToMailChimp(key, customerListId, new NcbMailingListSubscription() { FirstName = item.Customer.FirstName, LastName = item.Customer.LastName, Email = item.Customer.Email }); } if (errors.Count > 0) { return(errors); } return("OK"); }
/// <summary> /// When Saleorder is set to waiting for order, generate InventoryItem for each item in the sale order /// TransformInventoryRequest event is called to finalize the list of items. /// </summary> /// <param name="db"></param> /// <param name="saleOrder"></param> internal static void ProcessSaleOrderUpdate(NancyBlackDatabase db, SaleOrder saleOrder, bool forceUpdate, DateTime now) { if (forceUpdate == false) { now = DateTime.Now; // fulfill the requests of this sale order // (No longer used) //InventoryItemModule.ProcessFulfillSaleOrder(db, saleOrder); // only do when status is waiting for order if (saleOrder.Status != SaleOrderStatus.WaitingForOrder) { return; } // if previous status is already waiting for order - do nothing if (db.GetOlderVersions(saleOrder).Any(s => s.Status == SaleOrderStatus.WaitingForOrder)) { return; } } if (saleOrder.Status == SaleOrderStatus.Cancel) { db.Transaction(() => { var relatedRequest = db.Query <InventoryItem>().Where(ivt => ivt.SaleOrderId == saleOrder.Id).ToList(); foreach (var item in relatedRequest) { // remove the usage from purchase var relatedPurchase = db.Query <InventoryPurchase>().Where(ip => ip.InventoryItemId == item.Id).ToList(); foreach (var p in relatedPurchase) { p.InventoryItemId = 0; db.UpsertRecord(p); } // remove the request from database db.DeleteRecord(item); } }); return; } if (saleOrder.PaymentStatus == PaymentStatus.PaymentReceived || saleOrder.PaymentStatus == PaymentStatus.Deposit || saleOrder.PaymentStatus == PaymentStatus.Credit) { } else { return; } var totalDiscount = 0M; var items = new List <InventoryItem>(); foreach (var item in saleOrder.ItemsDetail) { if (item.CurrentPrice < 0) // dont take negative prices (coupon) { totalDiscount += item.CurrentPrice * -1; // record the discount continue; } if (item.Url == "/dummy/dummy" && item.CurrentPrice == 0) { continue; } // For each items in sale order, create an inventory item for (int i = 0; i < (int)item.Attributes.Qty; i++) { // virtual products does not need inventory inbound if (item.Attributes.IsVirtual == 1) { continue; } var ivitm = new InventoryItem() { SaleOrderId = saleOrder.Id, ProductId = item.Id, RequestedDate = now, IsFullfilled = false, QuotedPrice = item.CurrentPrice, SellingPrice = item.CurrentPrice, }; items.Add(ivitm); if (item.CurrentPrice != item.Price) { totalDiscount += item.Price - item.CurrentPrice; } } } // distribute discount into items which has actual sell price var totalTrueItems = items.Where(item => item.QuotedPrice > 0).Count(); var discountRemaining = totalDiscount; while (discountRemaining > 0) { foreach (var item in items) { if (item.SellingPrice > 0) { // discount by 1% var discount = item.SellingPrice * 0.01M; if (discountRemaining - discount < 0) { discount = discountRemaining; } discountRemaining -= discount; item.SellingPrice = item.SellingPrice - discount; if (discountRemaining == 0) { break; } } } } var currentSite = AdminModule.ReadSiteSettings(); foreach (var item in items) { item.__updatedAt = DateTime.Now; item.__createdAt = DateTime.Now; if (item.SellingPrice > 0) { if (currentSite.commerce.billing.vattype == "addvat") { item.SellingTax = item.SellingPrice * (100 + (int)currentSite.commerce.billing.vatpercent) / 100; } if (currentSite.commerce.billing.vattype == "includevat") { var priceWithoutTax = item.SellingPrice * 100 / (100 + (int)currentSite.commerce.billing.vatpercent); item.SellingTax = item.SellingPrice - priceWithoutTax; item.SellingPrice = priceWithoutTax; } } } InventoryItemModule.TransformInventoryRequest(db, saleOrder, items); // NOTE: sometimes we give free, so price can be 0 items = (from item in items where item.SellingPrice >= 0 select item).ToList(); // attempt to merge the old list and new list using product id // by seeing if there is any item that was already fulfilled - if // there is any - copy the information into new list var existing = db.Query <InventoryItem>().Where(ivt => ivt.SaleOrderId == saleOrder.Id).ToLookup(ivt => ivt.ProductId); var newList = items.ToLookup(ivt => ivt.ProductId); foreach (var group in existing) { var existingGroup = existing[group.Key].ToList(); var newGroup = newList[group.Key].ToList(); for (int i = 0; i < existingGroup.Count; i++) { if (i >= newGroup.Count) { // old list has more items - keep them if it is already fulfilled if (existingGroup[i].IsFullfilled) { existingGroup[i].Note = "This sale order have less items, this is an orphaned row"; db.Connection.Update(existingGroup[i]); } else { // otherwise, just deletes them db.Connection.Delete <InventoryItem>(existingGroup[i].Id); } continue; } if (existingGroup[i].IsFullfilled) { // copy information from the existing one // for some reason not yet understand - i cant just remove newGroup[i] from items // and add existingGroup[i] into it instead! newGroup[i].IsFullfilled = true; newGroup[i].SerialNumber = existingGroup[i].SerialNumber; newGroup[i].FulfilledDate = existingGroup[i].FulfilledDate; newGroup[i].BuyingCost = existingGroup[i].BuyingCost; newGroup[i].BuyingTax = existingGroup[i].BuyingTax; newGroup[i].InventoryPurchaseId = existingGroup[i].InventoryPurchaseId; newGroup[i].Note = existingGroup[i].Note; } db.Connection.Delete <InventoryItem>(existingGroup[i].Id); } } db.Connection.InsertAll(items); }
internal static void ProcessReceiptCreation(NancyBlackDatabase db, Receipt obj) { // When payment receipt is created, create accounting entry db.Transaction(() => { var saleorder = db.GetById <SaleOrder>(obj.SaleOrderId); var paymentlog = db.GetById <PaymentLog>(obj.PaymentLogId); if (paymentlog.Amount <= 0) { return; // perhaps it is an error } if (saleorder == null || paymentlog == null) { // bogus receipt throw new InvalidOperationException("Invalid Receipt was created"); } var currentSite = saleorder.SiteSettings; if (currentSite == null) { currentSite = AdminModule.ReadSiteSettings(); } // Ensures all sale order logic has been ran // if the sale order was created before new system change if (saleorder.__createdAt < TaxSystemEpoch) { saleorder.UpdateSaleOrder(currentSite, db, false); } // Receipt will create 4 entries // 1) PaymentSource account increases, with amount paid // TODO: Mapping from PaymentSource to Account AccountingEntry entry1 = new AccountingEntry(); entry1.TransactionDate = paymentlog.__createdAt; entry1.TransactionType = "income"; entry1.DebtorLoanerName = "Customer"; entry1.IncreaseAccount = paymentlog.PaymentSource; entry1.IncreaseAmount = paymentlog.Amount; entry1.SaleOrderId = saleorder.Id; db.UpsertRecord(entry1); // 2) Sales Tax Calculation { AccountingEntry taxExtry = new AccountingEntry(); taxExtry.TransactionDate = paymentlog.__createdAt; taxExtry.TransactionType = "taxcredit"; taxExtry.DebtorLoanerName = "Tax"; taxExtry.DecreaseAccount = "Tax Credit"; taxExtry.SaleOrderId = saleorder.Id; if (currentSite.commerce.billing.vattype == "addvat") { var tax = paymentlog.Amount * ((100 + (Decimal)currentSite.commerce.billing.vatpercent) / 100); taxExtry.DecreaseAmount = tax * -1; } if (currentSite.commerce.billing.vattype == "includevat") { var tax = paymentlog.Amount * ((Decimal)currentSite.commerce.billing.vatpercent / 100); taxExtry.DecreaseAmount = tax * -1; } db.UpsertRecord(taxExtry); } // 3) Payment Fee if (paymentlog.Fee > 0) { AccountingEntry feeEntry = new AccountingEntry(); feeEntry.TransactionDate = paymentlog.__createdAt; feeEntry.TransactionType = "buy"; feeEntry.DebtorLoanerName = paymentlog.PaymentSource; feeEntry.IncreaseAccount = "Payment Fee - " + paymentlog.PaymentSource; feeEntry.IncreaseAmount = paymentlog.Fee; feeEntry.SaleOrderId = saleorder.Id; db.UpsertRecord(feeEntry); } // 4) Receivable from the Sale Order { // existing receivable of this sale order var existingReceivable = db.Query <AccountingEntry>().Where(e => e.SaleOrderId == saleorder.Id && e.IncreaseAccount == "Receivable").ToList(); // see if we have any receivable of this sale order // if we had, we have to deduct it if (existingReceivable.Count > 0) { AccountingEntry deductReceivableEntry = new AccountingEntry(); deductReceivableEntry.TransactionDate = paymentlog.__createdAt; deductReceivableEntry.TransactionType = "arpayment"; deductReceivableEntry.DebtorLoanerName = "Receivable From Sales"; deductReceivableEntry.DecreaseAccount = "Receivable"; deductReceivableEntry.DecreaseAmount = paymentlog.Amount; deductReceivableEntry.SaleOrderId = saleorder.Id; db.UpsertRecord(deductReceivableEntry); } else { // this maybe the first payment, see if all amount has been paid // see all payment log of this sale order // we only query payments up to currently processing payment log // so that when we re var payments = db.Query <PaymentLog>().Where(l => l.SaleOrderId == saleorder.Id && l.Id <= paymentlog.Id).ToList(); var remaining = saleorder.TotalAmount - payments.Sum(p => p.Amount); if (remaining > 0) { // this is partial payment - create new receivable AccountingEntry receivableEntry = new AccountingEntry(); receivableEntry.TransactionDate = paymentlog.__createdAt; receivableEntry.TransactionType = "newaccount"; receivableEntry.DebtorLoanerName = "Receivable From Sales"; receivableEntry.IncreaseAccount = "Receivable"; receivableEntry.IncreaseAmount = remaining; receivableEntry.SaleOrderId = saleorder.Id; db.UpsertRecord(receivableEntry); } // this is full payment in one go, no need for receivable } } }); }
/// <summary> /// Performs Machine translation using Microsoft Translator API /// </summary> /// <param name="input"></param> /// <param name="primaryLanguage"></param> /// <param name="translatedLanguage"></param> /// <param name=""></param> /// <returns></returns> public string MachineTranslate(string input, string translatedLanguage, string primaryLanguage = null) { TranslateHelper.Initialize(); if (input.Length > 10000) { throw new InvalidOperationException("Input is too long for machine translation"); } if (string.IsNullOrEmpty(input.Trim())) { return(string.Empty); } var key = translatedLanguage + "-" + input.Trim(); string translated; if (_Translations.TryGetValue(key, out translated)) { return(translated); } lock (BaseModule.GetLockObject("Translate-" + key)) { // when other threads unlocked - we have to check again if (_Translations.ContainsKey(key)) { return(_Translations[key]); } var siteSettings = AdminModule.ReadSiteSettings(); var translate = siteSettings.translate; if (translate == null || translate.key == null) { throw new InvalidOperationException("Machine Translation require 'key' in translate object of site settings"); } RestClient client = new RestClient("https://api.microsofttranslator.com"); RestRequest req = new RestRequest("/v2/Http.svc/Translate"); req.Method = Method.GET; req.AddHeader("Ocp-Apim-Subscription-Key", (string)translate.key); req.AddQueryParameter("text", input); req.AddQueryParameter("to", translatedLanguage); if (string.IsNullOrEmpty(primaryLanguage) == false) { req.AddQueryParameter("from", primaryLanguage); } var result = client.Execute(req); var element = System.Xml.Linq.XElement.Parse(result.Content); translated = element.Value; _Translations[key] = translated; _Database.UpsertRecord <TranslateEntry>(new TranslateEntry() { Primary = input, Language = translatedLanguage, Translated = translated }); return(translated); } }
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) { BootStrapper.RootPath = this.RootPathProvider.GetRootPath(); // create App_Data Directory.CreateDirectory(Path.Combine(BootStrapper.RootPath, "App_Data")); ModuleResource.ReadSystemsAndResources(BootStrapper.RootPath); this.Conventions.ViewLocationConventions.Clear(); #region Localized View Conventions // Site's View Folder has most priority // Mobile View Overrides this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } string u = context.Context.Request.Headers.UserAgent.ToLowerInvariant(); if (u.Contains("mobile/")) { return("Site/Views/Mobile/" + viewName + "_" + context.Context.Items["Language"]); } return(string.Empty); // not mobile browser }); // Desktop View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return("Site/Views/Desktop/" + viewName + "_" + context.Context.Items["Language"]); }); // Generic View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return("Site/Views/" + viewName + "_" + context.Context.Items["Language"]); }); // Theme view location (views/_theme) can override _theme of the Theme folder this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { var theme = context.Context.GetSiteSettings().Theme; if (theme == null) { return(string.Empty); } if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return("Themes/" + theme + "/" + viewName + "_" + context.Context.Items["Language"]); }); // NancyBlack's View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return("NancyBlack/Content/Views/" + viewName + "_" + context.Context.Items["Language"]); }); // then try Views in Systems (AdminSystem, ContentSystem etc...) foreach (var system in ModuleResource.Systems) { this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return(string.Concat("NancyBlack/Modules/", viewName, "_", context.Context.Items["Language"])); }); this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return(string.Concat("NancyBlack/Modules/", system, "/Views/", viewName, "_", context.Context.Items["Language"])); }); } #endregion #region Sub Website View Conventions // Generic View for SubWebsite Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { string subSiteName = (string)context.Context.Items[ContextItems.SubSite]; if (!string.IsNullOrEmpty(subSiteName)) { return("Site/SubSites/" + subSiteName + "/Views/" + viewName); } return(string.Empty); }); #endregion #region View Conventions // Site's View Folder has most priority // Mobile View Overrides this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { string u = context.Context.Request.Headers.UserAgent.ToLowerInvariant(); if (u.Contains("mobile/")) { return("Site/Views/Mobile/" + viewName); } return(string.Empty); // not mobile browser }); // Desktop View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return("Site/Views/Desktop/" + viewName); }); // Generic View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return("Site/Views/" + viewName); }); // Theme view location (views/_theme) can override _theme of the Theme folder this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { var theme = context.Context.GetSiteSettings().Theme; if (theme == null) { return(string.Empty); } return("Themes/" + theme + "/" + viewName); }); // NancyBlack's View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return("NancyBlack/Content/Views/" + viewName); }); // then try Views in Systems (AdminSystem, ContentSystem etc...) foreach (var system in ModuleResource.Systems) { this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return(string.Concat("NancyBlack/Modules/", viewName)); }); this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return(string.Concat("NancyBlack/Modules/", system, "/Views/", viewName)); }); } this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return(viewName); // fully qualify names }); this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return(viewName.Substring(1)); // fully qualify names, remove forward slash at first }); #endregion var formsAuthConfiguration = new FormsAuthenticationConfiguration { RedirectUrl = "~/__membership/login", UserMapper = container.Resolve <IUserMapper>(), }; FormsAuthentication.Enable(pipelines, formsAuthConfiguration); pipelines.BeforeRequest.AddItemToStartOfPipeline((ctx) => { // Get Subsite Name if in main site will get null string folder = Path.Combine(BootStrapper.RootPath, "Site", "SubSites"); if (Directory.Exists(folder)) { var subSiteNames = from subDirectories in Directory.GetDirectories(folder) select Path.GetFileName(subDirectories); var matchSubSiteName = (from subSite in subSiteNames where ctx.Request.Url.HostName.Contains(subSite) select subSite).FirstOrDefault(); ctx.Items[ContextItems.SubSite] = matchSubSiteName; } else { ctx.Items[ContextItems.SubSite] = null; } var db = NancyBlackDatabase.GetSiteDatabase(this.RootPathProvider.GetRootPath()); GlobalVar.Default.Load(db); ctx.Items["SiteDatabase"] = db; ctx.Items["CurrentSite"] = AdminModule.ReadSiteSettings(); ctx.Items["SiteSettings"] = AdminModule.ReadSiteSettings(); ctx.Items["RootPath"] = BootStrapper.RootPath; if (ctx.Request.Cookies.ContainsKey("userid") == false) { ctx.Request.Cookies.Add("userid", Guid.NewGuid().ToString()); } return(null); }); pipelines.AfterRequest.AddItemToEndOfPipeline((ctx) => { if (ctx.Request.Cookies.ContainsKey("userid")) { ctx.Response.Cookies.Add( new NancyCookie("userid", ctx.Request.Cookies["userid"], DateTime.Now.AddYears(10))); } GlobalVar.Default.Persist(ctx.Items["SiteDatabase"] as NancyBlackDatabase); }); foreach (var item in container.ResolveAll <IPipelineHook>()) { item.Hook(pipelines); } }
protected override void ApplicationStartup(TinyIoCContainer container, IPipelines pipelines) { BootStrapper.RootPath = this.RootPathProvider.GetRootPath(); // create App_Data Directory.CreateDirectory(Path.Combine(BootStrapper.RootPath, "App_Data")); ModuleResource.ReadSystemsAndResources(BootStrapper.RootPath); this.Conventions.ViewLocationConventions.Clear(); #region Localized View Conventions // Site's View Folder has most priority // Mobile View Overrides this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } string u = context.Context.Request.Headers.UserAgent.ToLowerInvariant(); if (u.Contains("mobile/")) { return("Site/Views/Mobile/" + viewName + "_" + context.Context.Items["Language"]); } return(string.Empty); // not mobile browser }); // Desktop View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return("Site/Views/Desktop/" + viewName + "_" + context.Context.Items["Language"]); }); // Generic View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return("Site/Views/" + viewName + "_" + context.Context.Items["Language"]); }); // Theme view location (views/_theme) can override _theme of the Theme folder this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { var theme = context.Context.GetSiteSettings().Theme; if (theme == null) { return(string.Empty); } if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return("Themes/" + theme + "/" + viewName + "_" + context.Context.Items["Language"]); }); // NancyBlack's View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return("NancyBlack/Content/Views/" + viewName + "_" + context.Context.Items["Language"]); }); // then try Views in Systems (AdminSystem, ContentSystem etc...) foreach (var system in ModuleResource.Systems) { this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return(string.Concat("NancyBlack/Modules/", viewName, "_", context.Context.Items["Language"])); }); this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { if (context.Context.Items.ContainsKey("Language") == false) { return(string.Empty); } return(string.Concat("NancyBlack/Modules/", system, "/Views/", viewName, "_", context.Context.Items["Language"])); }); } #endregion #region View Conventions // Site's View Folder has most priority // Mobile View Overrides this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { string u = context.Context.Request.Headers.UserAgent.ToLowerInvariant(); if (u.Contains("mobile/")) { return("Site/Views/Mobile/" + viewName); } return(string.Empty); // not mobile browser }); // Desktop View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return("Site/Views/Desktop/" + viewName); }); // Generic View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return("Site/Views/" + viewName); }); // Theme view location (views/_theme) can override _theme of the Theme folder this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { var theme = context.Context.GetSiteSettings().Theme; if (theme == null) { return(string.Empty); } return("Themes/" + theme + "/" + viewName); }); // NancyBlack's View Location this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return("NancyBlack/Content/Views/" + viewName); }); // then try Views in Systems (AdminSystem, ContentSystem etc...) foreach (var system in ModuleResource.Systems) { this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return(string.Concat("NancyBlack/Modules/", viewName)); }); this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return(string.Concat("NancyBlack/Modules/", system, "/Views/", viewName)); }); } this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return(viewName); // fully qualify names }); this.Conventions.ViewLocationConventions.Add((viewName, model, context) => { return(viewName.Substring(1)); // fully qualify names, remove forward slash at first }); #endregion var formsAuthConfiguration = new FormsAuthenticationConfiguration { RedirectUrl = "~/__membership/login", UserMapper = container.Resolve <IUserMapper>(), }; FormsAuthentication.Enable(pipelines, formsAuthConfiguration); pipelines.BeforeRequest.AddItemToStartOfPipeline((ctx) => { ctx.Items["SiteDatabase"] = NancyBlackDatabase.GetSiteDatabase(this.RootPathProvider.GetRootPath()); ctx.Items["CurrentSite"] = AdminModule.ReadSiteSettings(); ctx.Items["SiteSettings"] = AdminModule.ReadSiteSettings(); ctx.Items["RootPath"] = BootStrapper.RootPath; if (ctx.CurrentUser == null) { ctx.CurrentUser = NcbUser.Anonymous; if (ctx.Request.Url.HostName == "localhost") { ctx.CurrentUser = NcbUser.LocalHostAdmin; } } return(null); }); foreach (var item in container.ResolveAll <IPipelineHook>()) { item.Hook(pipelines); } }
/// <summary> /// When Saleorder is set to waiting for order, generate InventoryItem for each item in the sale order /// TransformInventoryRequest event is called to finalize the list of items. /// </summary> /// <param name="db"></param> /// <param name="saleOrder"></param> internal static void ProcessSaleOrderUpdate(NancyBlackDatabase db, SaleOrder saleOrder, bool replay, DateTime now) { if (replay == false) { now = DateTime.Now; // only do when status is waiting for order if (saleOrder.Status != SaleOrderStatus.WaitingForOrder) { return; } // if previous status is already waiting for order - do nothing if (db.GetOlderVersions(saleOrder).First().Status == SaleOrderStatus.WaitingForOrder) { return; } } var currentSite = AdminModule.ReadSiteSettings(); // NOTE: We can't run it again since it can alter the amount // it is possible that admin may change amount in database //// ensures that all logic of sale order has been ran //saleOrder.UpdateSaleOrder(currentSite, db, false); // ensure that no inventory inbound can be run var totalDiscount = 0M; var items = new List <InventoryItem>(); foreach (var item in saleOrder.ItemsDetail) { if (item.CurrentPrice < 0) // dont take negative prices (coupon) { totalDiscount += item.CurrentPrice * -1; // record the discount continue; } // For each items in sale order, create an inventory item for (int i = 0; i < (int)item.Attributes.Qty; i++) { var ivitm = new InventoryItem() { SaleOrderId = saleOrder.Id, ProductId = item.Id, RequestedDate = now, IsFullfilled = false, SellingPrice = item.CurrentPrice }; items.Add(ivitm); if (item.CurrentPrice != item.Price) { totalDiscount += item.Price - item.CurrentPrice; } } } // distribute discount into items which has actual sell price var discountToDistribute = totalDiscount / items.Where(item => item.SellingPrice > 0).Count(); // discount is too great for some item, add it to the most expensive one if (items.Where(item => discountToDistribute > item.SellingPrice).Count() > 0) { var item = items.OrderByDescending(i => i.SellingPrice).First(); item.SellingPrice -= totalDiscount; if (currentSite.commerce.billing.vattype == "addvat") { item.SellingTax = item.SellingPrice * (100 + (int)currentSite.commerce.billing.vatpercent) / 100; } if (currentSite.commerce.billing.vattype == "includevat") { var priceWithoutTax = item.SellingPrice * 100 / (100 + (int)currentSite.commerce.billing.vatpercent); item.SellingTax = item.SellingPrice - priceWithoutTax; item.SellingPrice = priceWithoutTax; } } else // distribute it to items { foreach (var item in items) { if (item.SellingPrice > 0) { item.SellingPrice -= discountToDistribute; if (currentSite.commerce.billing.vattype == "addvat") { item.SellingTax = item.SellingPrice * (100 + (int)currentSite.commerce.billing.vatpercent) / 100; } if (currentSite.commerce.billing.vattype == "includevat") { var priceWithoutTax = item.SellingPrice * 100 / (100 + (int)currentSite.commerce.billing.vatpercent); item.SellingTax = item.SellingPrice - priceWithoutTax; item.SellingPrice = priceWithoutTax; } } } } InventoryAdminModule.TransformInventoryRequest(db, saleOrder, items); db.Transaction(() => { // before inserting... // if the inventory item for this sale order already fullfilled // it will remain in inventory but sale order removed // we will always create new inventory item for this sale order // and clear out old ones foreach (var item in db.Query <InventoryItem>().Where(ivt => ivt.SaleOrderId == saleOrder.Id).ToList()) { if (item.IsFullfilled) { item.Note = "Sale Order Id was removed because sale order which created this item has status set to WaitingForOrder Again"; item.SaleOrderId = 0; item.IsFullfilled = false; db.UpsertRecord(item); continue; // item already fullfilled, we leave it but remove sale order id } db.DeleteRecord(item); } foreach (var item in items) { db.UpsertRecord(item); } }); }
public void Initialize(IPipelines piepeLinse, NancyContext ctx) { if (ctx.Request.Headers.UserAgent.Contains("facebookexternalhit/1.1")) { ctx.Request.Headers.Accept = new List <Tuple <string, decimal> >() { new Tuple <string, decimal>("text/html", 1) }; ctx.Items["FBBot"] = true; } ctx.Items["Webp"] = ctx.Request.Headers.Accept.Any(a => a.Item1 == "image/webp"); ctx.Items["CurrentSite"] = AdminModule.ReadSiteSettings(); ctx.Items["SiteSettings"] = AdminModule.ReadSiteSettings(); ctx.Items["RootPath"] = BootStrapper.RootPath; ctx.Items["IsAdmin"] = null; NancyBlackDatabase db = null; if (_FirstRun == true) { lock (BaseModule.GetLockObject("Request-FirstRun")) { // check again, other thread might done it if (_FirstRun == false) { goto Skip; } _FirstRun = false; // this will ensure DataType Factory only run once db = NancyBlackDatabase.GetSiteDatabase(BootStrapper.RootPath, ctx); GlobalVar.Default.Load(db); ctx.Items["SiteDatabase"] = db; // other modules expected this foreach (var item in _GlobalInitializes) { item.GlobalInitialize(ctx); } Skip: ; } } if (db == null) { db = NancyBlackDatabase.GetSiteDatabase(BootStrapper.RootPath, ctx); ctx.Items["SiteDatabase"] = db; } // Get Subsite Name if in main site will get null string folder = Path.Combine(BootStrapper.RootPath, "Site", "SubSites"); if (Directory.Exists(folder)) { var subSiteNames = from subDirectories in Directory.GetDirectories(folder) select Path.GetFileName(subDirectories); var matchSubSiteName = (from subSite in subSiteNames where ctx.Request.Url.HostName.Contains(subSite) select subSite).FirstOrDefault(); ctx.Items[ContextItems.SubSite] = matchSubSiteName; } else { ctx.Items[ContextItems.SubSite] = null; } if (ctx.Request.Cookies.ContainsKey("userid") == false) { ctx.Items["userid"] = Guid.NewGuid().ToString(); } else { ctx.Items["userid"] = ctx.Request.Cookies["userid"]; } }