Exemple #1
0
        /// <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());
        }
Exemple #2
0
        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);
                }
            });
        }
Exemple #3
0
        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);
                });
            }
        }
Exemple #4
0
        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);
        }
Exemple #6
0
        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
                    }
                }
            });
        }
Exemple #7
0
        /// <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);
            }
        }
Exemple #8
0
        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);
            }
        }
Exemple #9
0
        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);
                }
            });
        }
Exemple #11
0
        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"];
            }
        }