public OrderData(Order anOrder) { orderId = anOrder.Id; using (citylifedb8_blContext db = new citylifedb8_blContext()) { Guest theGuest = db.Guest.Find(anOrder.GuestId); name = theGuest?.Name; phone = theGuest?.Phone; email = theGuest?.Email; Country guestCountry = theGuest?.CountryCodeNavigation; country = guestCountry?.Name; Apartment theApartment = db.Apartment.Find(anOrder.ApartmentId); apartmentNumber = theApartment?.Number ?? 0; //if an apartment was not found - put 0 (although not expected) } adults = anOrder.AdultCount; children = anOrder.ChildrenCount; checkin = anOrder.CheckinDate; checkout = anOrder.CheckoutDate; nights = anOrder.nights; Money priceM = anOrder.priceAsMoney(); Money paidM = anOrder.amountPaidAsMoney(); Money unpaidM = priceM - paidM; price = priceM.toMoneyString(); paid = paidM.toMoneyString(); unpaid = unpaidM.toMoneyString(); expectedArrival = anOrder.ExpectedArrival; comments = anOrder.SpecialRequest; bookedBy = anOrder.BookedBy; confirmationNumber = anOrder.ConfirmationNumber; status = (OrderStatus)anOrder.Status; orderColor = (Color)anOrder.OrderColor; staffComments = anOrder.StaffComments; }
/// <summary> /// converts the money object to string representation /// </summary> /// <param name="showCents">when true will show cents as 123.45 When false will round to the closest integral value</param> /// <param name="showCurrency">when true will show the currency symbol to the left of the value.</param> /// <returns>$1,234.56 orf $1235 bsaed on the showCents param</returns> public string toMoneyString(bool showCents = false, bool showCurrency = false, bool showComma = true) { string currencySymbol = ""; if (showCurrency) { citylifedb8_blContext db = new citylifedb8_blContext(); var theCurrency = db.Currency.SingleOrDefault(aCurrency => aCurrency.CurrencyCode == this.currencyCode); if (theCurrency == null) { throw new AppException(102, null, "such currency does not exist in DB:" + this.currencyCode); } currencySymbol = theCurrency.Symbol; } //At this point currency symbol contains either the currency symbol or empty string, if show currency is false string comma = ""; if (showComma) { comma = ","; } string moneyString; if (showCents) { moneyString = string.Format("{0}{1:#" + comma + "##0.00}", currencySymbol, this.amount); } else { moneyString = string.Format("{0}{1:#" + comma + "##0}", currencySymbol, decimal.Round(this.amount)); } return(moneyString); }
/// <summary> /// Converts the amount of money from currency to currency based on currency exchange records in the DB. /// </summary> /// <param name="newCurrencyCode">target currency to which we need to convert</param> /// <param name="atDate">the date for which we would like to convert. The method will look for latest currency /// exchange record which is still before or at that date. </param> /// <param name="rounded">When set to true - rounds the converted result to integral value</param> /// <returns>a Money object converted to the new currency.</returns> /// <exception cref="101">no suitable currency exchange record found in the DB. (Either the currency code was illegal, or no /// such record exists)</exception> public Money converTo(string newCurrencyCode, DateTime?atDate = null, bool rounded = false) { if (currencyCode == newCurrencyCode) { //current and target currencies are the same - no conversion needed. return(new Money(this)); } else { //Look for all exchange rates records that match the "to currency" and "from currency". //Note that in the DB we do not keep both conversion rates: EUR->USD and USD->EUR - since one is the reciprocal //of the other. We only keep the pair where the "from" curency code is alphabetically lower than the "to" //So we keep EUR->USD, UAH->USD, etc. citylifedb8_blContext db = new citylifedb8_blContext(); if (atDate == null) { atDate = FakeDateTime.Now; } string lowerCurrencyCode; string upperCurrencyCOde; if (this.currencyCode.CompareTo(newCurrencyCode) < 0) { lowerCurrencyCode = this.currencyCode; upperCurrencyCOde = newCurrencyCode; } else { lowerCurrencyCode = newCurrencyCode; upperCurrencyCOde = this.currencyCode; } var exchangeRates = from anExchangeRate in db.CurrencyExchange where anExchangeRate.FromCurrencyCurrencyCode == lowerCurrencyCode && anExchangeRate.ToCurrencyCurrencyCode == upperCurrencyCOde && anExchangeRate.Date <= atDate orderby anExchangeRate.Date descending select anExchangeRate; if (exchangeRates.Count() == 0) { //no suitable exchange rate was found throw new AppException(101, null, this.currencyCode, newCurrencyCode, atDate, this.amount); } var theExchangeRate = exchangeRates.First(); //take the latest record which is still before or at the requested date decimal result; if (theExchangeRate.FromCurrencyCurrencyCode == this.currencyCode) { result = this.amount * theExchangeRate.ConversionRate; } else { result = this.amount / theExchangeRate.ConversionRate; } if (rounded) { result = decimal.Round(result); } return(new Money(result, newCurrencyCode)); } }
public OrderData s22OrderDetails(int orderId) { //Session["lastOrderDetails"] = orderId; //Keep the data so we know which order to highlight using (citylifedb8_blContext db = new citylifedb8_blContext()) { var theOrder = db.Order.Find(orderId); OrderData theOrderData = new OrderData(theOrder); return(theOrderData); } }
public static void writeException(int code, Exception innerException, string stackTrace, params object[] parameters) { citylifedb8_blContext db = new citylifedb8_blContext(); ErrorCode theErrorCode = db.ErrorCode.SingleOrDefault(aRecord => aRecord.Code == code); if (theErrorCode != null) { //This error code already exists in the DB. theErrorCode.LastOccurenceDate = DateTime.Now; theErrorCode.OccurenceCount++; } else { //The error code does not exist - create it theErrorCode = new ErrorCode() { Code = code, Message = ErrorCodeCollection.message(code), LastOccurenceDate = DateTime.Now, OccurenceCount = 1 }; db.ErrorCode.Add(theErrorCode); } db.SaveChanges(); //check if the same error message exists in the error message table string formattedMessage = AppException.formatMessage(code, parameters); ErrorMessage theErrorMessage = (from anErrorMessage in theErrorCode.ErrorMessages where anErrorMessage.FormattedMessage == formattedMessage && anErrorMessage.StackTrace == stackTrace select anErrorMessage).FirstOrDefault(); //actually we expect only a single record to be found if (theErrorMessage != null) { //Such an exact error message already exists - increment the counter theErrorMessage.LastOccurenceDate = DateTime.Now; theErrorMessage.OccurenceCount++; } else { //such exact error message does not exist - add it theErrorMessage = new ErrorMessage() { ErrorCodeCode = theErrorCode.Code, FormattedMessage = formattedMessage, LastOccurenceDate = DateTime.Now, OccurenceCount = 1, StackTrace = stackTrace, }; db.ErrorMessage.Add(theErrorMessage); } db.SaveChanges(); }
public Employee UserLoggedin(string userName, string password) { using (var db = new citylifedb8_blContext()) { Employee theEmployee = db.Employee.SingleOrDefault(anEmp => anEmp.UserName == userName); if (theEmployee != null && theEmployee.PasswordHash == password) { LoggedinUser = theEmployee; } else { theEmployee = null; } return(theEmployee); //(or null if no user is logged in) } }
/// <summary> /// The constructor gets a string containing: $1,234.56. If currencyCode exists - uses it as the currency, regardless if thre is a currency symbol /// or not. If not - creates the currency based on the symbol. If symbol does not exist, or it is an unknown symbol - aborts /// Note that empty string will be converted to 0 /// </summary> /// <param name="moneyString"></param> /// <param name="currencyCode"></param> public Money(string moneyString, string currencyCode = null) { if (moneyString == "" || moneyString == null) { this.amount = 0; this.currencyCode = currencyCode; return; } //The string is not empty char firstChar = moneyString[0]; if (firstChar < '0' || firstChar > '9') { //The amount start with a non-digit character - assuming it is a currency symbol citylifedb8_blContext db = new citylifedb8_blContext(); string firstCharAsString = firstChar.ToString(); Currency theCurrency = db.Currency.SingleOrDefault(a => a.Symbol == firstCharAsString); if (theCurrency == null) { //Such currency does not exist in our DB - raise an exception throw new AppException(117, null, moneyString); } this.currencyCode = theCurrency.CurrencyCode; string amountSt = moneyString.Substring(1); //Take out the currency symbol - assuming this is a clean number if (!decimal.TryParse(amountSt, out this.amount)) { //The conversion did not succeed - raise an exception throw new AppException(118, null, moneyString); } } else { //Assume that the number does not contain a currency symbol - convert it to decimal if (!decimal.TryParse(moneyString, out this.amount)) { //The conversion did not succeed - raise an exception throw new AppException(118, null, moneyString); } this.currencyCode = currencyCode; } }
/// <summary> /// This is the horizontal version of the dashboard. It shows the orders of all apartments for 31 days, since the date entered by the user, /// or since today. (the default) /// </summary> /// <param name="fromDate">Date entered in the date picker, or null</param> /// <param name="wideDashboard">When "on" means that the user wants to get the wide version of the dashboard. /// In this mode, each column is wider (about 4 normal columns), we show only 3 days, and we put more data into\ /// each order element.</param> /// <returns></returns> //public void s21Dashboard(DateTime startDate, string wideDashboard = "off") //{ // this.FromDate = startDate; // //Currntly for both normal mode and wide mode we dislay 31 days. The number of days can be set here. // //We display one month. The calculation is: the number of days displayed are equal to the month length of the starting month. // //In most cases this will yield an end date which is one less that the starting date. The only exception is January 30 and 31, which will // //end at 1 or 2 of March. // //For example: start date end date // // 10/11/2019 9/12/2019 // // 31/12/2019 30/1/2020 // // 30/1/2019 1/3/2019 (except for leap year, where it will be 29/2/2020) // // 1/11/2019 30/11/2019 // // 1/12/2019 31/12/2019 // // 1/2/2020 29/2/2020 (2020 is leap year) // int dashboardDays = FakeDateTime.monthLength(startDate); // List<Money> revenuePerDay = null; // List<Money> expensePerDay = null; // List<string> expenseTypes = null; // EmployeeWorkDay[] empWorkDaysArray = null; // List<Employee> maidList = null; // List<Money> revenuePerApartment = null; // List<double> aveargeDaysPerApartment = null; // List<int> percentOccupancyPerApartment = null; // var apartmentDayBlocks = s21dashboardPreparation( // startDate, // dashboardDays, // ref revenuePerDay, // ref expensePerDay, // ref expenseTypes, // ref revenuePerApartment, // ref aveargeDaysPerApartment, // ref percentOccupancyPerApartment, // ref empWorkDaysArray, // ref maidList); // if (Session["lastOrderDetails"] != null) // { // ViewBag.highlightOrderId = (int)Session["lastOrderDetails"]; // } // else // { // ViewBag.highlightOrderId = 0; // } // return View("s21Dashboard"); //} /// <summary> /// The function reads the orders for all apartments starting from the date set by the user and for a full month (30 or 31 days, /// and for February 28 or 29 days) /// </summary> ///<param name="fromDate">starting date of the dashboard</param> ///<param name="days">the number of days we wish to display.(depends on the starting month)</param> ///<param name="revenuePerDay">An output parameter - will contain the list of revenues per day</param> ///<param name="expensePerDay">total expenses for each day</param> ///<param name="percentOccupancyPerApartment">Number of days the apartment is occupied divided by total number of days (rounded to ///whole percent)</param> ///<param name="revenuePerApartment">Total revenue per apartment for that month</param> ///<param name="averageDaysPerApartment">contains the average number of days per rent for each apartment. We include in this average ///only rents that have started in the displayed month. IF a rent started in that month and spans to the next month ///the average takes into account the total time for that rent - not only the portion will falls in this month</param> ///<param name="empWorkDaysArray">An array containing an employeeWorkDay record for each day in the month. ///Days for which no record found - will be null. Days for which more than one recrod found - will contain ///the last record. </param> ///<param name="maidList">A list of maids (employees of role="maid") - ouitput parameter</param> /// <returns>List of apartment orders. For each apartment: /// list of DayBlocks. /// A dayBlock is either a single free day, or an order which can span 1 or more days. Note that a day block may not /// be identical to the corresponding order because the order may start before the "fromDate" or end after the "fromDate+31". /// Note that the list contains first all real apartments, then "waiting" apartments</returns> public List <List <DayBlock> > s21dashboardPreparation(DateTime fromDate, int days, ref List <Money> revenuePerDay, ref List <Money> expensePerDay, ref List <string> expenseTypes, ref List <Money> revenuePerApartment, ref List <double> averageDaysPerApartment, ref List <int> percentOccupancyPerApartment, ref EmployeeWorkDay[] empWorkDaysArray, ref List <Employee> maidList) { //for each apartment //for each day from from_date to from_date+3 //lastOrderId = 0; //orderLength = 0; //apartmentDay = read apartmentDay record for apartment and day //if record does not exist or record status == free - this is a free day - add a free block //order = apartmentDay->order //if order.isFirstDay - create a new busy block //add the day to the busy block //if order.isLastDay - write busy block //write last busy block //a 2 dimensional array - a list of apartments, and for each apartment - a list of day blocks //where each day block is either a free day or an order. using (citylifedb8_blContext db = new citylifedb8_blContext()) { var apartmentDayBlocks = new List <List <DayBlock> >(); revenuePerDay = new List <Money>(); expensePerDay = new List <Money>(); for (int i = 0; i < days; i++) { revenuePerDay.Add(new Money(0m, "UAH")); } var lastDate = fromDate.AddDays(days - 1); revenuePerApartment = new List <Money>(); averageDaysPerApartment = new List <double>(); percentOccupancyPerApartment = new List <int>(); //Calculate the expenses for each date in the range for (DateTime aDate = fromDate; aDate <= lastDate; aDate = aDate.AddDays(1)) { //Read all expenses for the date and sum them var expenseListCentsForDate = (from expense in db.Expense where expense.Date == aDate select expense.Amount).ToList(); //The expenses are kept as cents in the DB int expensesCentsForDate = 0; if (expenseListCentsForDate.Count() > 0) { expensesCentsForDate = expenseListCentsForDate.Sum(); } Money expensesForDate = new Money(expensesCentsForDate, "UAH"); expensePerDay.Add(expensesForDate); } //Sort apartments by type (first all "normal" apartments then the "waiting" apartments), then by their number var sortedApartments = (from anApartment in db.Apartment orderby anApartment.Type, anApartment.Number select anApartment).ToList(); Order anOrder = new Order() //create a fictitious order with id = 0 { Id = 0 }; foreach (var anApartment in sortedApartments) { var dayBlocks = new List <DayBlock>(); DayBlock aDayBlock = null; int dayNumber = 0; Money apartmentRevenue = new Money(0m, "UAH"); double apartmentOccupiedDays = 0; //Use float for the percentage calculation later double totalRents = 0.0; //Counter for how many orders are during the month for that apartment. //We keep it as double in order to calculate the average (which should be in float) int totalRentDays = 0; //the total amount of rented days for that apartment in that month. We take into account only rents that started //in the displayed month. //Get all apartment days of the current apartment for the desired month var apartmentDaysForMonth = (from theApartmentDay in db.ApartmentDay where theApartmentDay.Apartment.Id == anApartment.Id && theApartmentDay.Date >= fromDate && theApartmentDay.Date <= lastDate orderby theApartmentDay.Date select theApartmentDay).ToList(); int apartmentDaysI = 0; ApartmentDay anApartmentDay; int apartmentDaysCount = apartmentDaysForMonth.Count(); for (var aDate = fromDate; aDate <= lastDate; aDate = aDate.AddDays(1)) { if (apartmentDaysCount > apartmentDaysI && apartmentDaysForMonth[apartmentDaysI].Date == aDate) { //The current apartmentDays record matches the on-hand date - an apartmentDay exists anApartmentDay = apartmentDaysForMonth[apartmentDaysI]; apartmentDaysI++; } else { //An apartment day does not exist - it will be null anApartmentDay = null; } if (anApartmentDay == null || anApartmentDay.Status == (int)ApartOccuStatus.Free) { //This is a free day if (aDayBlock != null) { //Although this should not occur (assuming that the apartmentDays table matches the orders checkin and checkout dates) //But anyway - we will write the dayBlock to the list dayBlocks.Add(aDayBlock); } aDayBlock = new DayBlock() { apartmentNumber = anApartment.Number, status = OrderStatus.Free, firstDate = aDate.ToString("yyyy-MM-dd") }; //"Free" status denotes a free day dayBlocks.Add(aDayBlock); aDayBlock = null; } else { //this is a busy day. Read the order record if (anOrder.Id != anApartmentDay.OrderId) { //We did not read this order yet - read it anOrder = db.Order.Find(anApartmentDay.OrderId); // anOrder = db.Order.Single(record => record.Id == anApartmentDay.Order.Id); //Check if this order started today if (anOrder.CheckinDate == aDate) { //take this order into account for calculation of average days per rent totalRents++; totalRentDays += anOrder.DayCount; } else { //This is a new order but it started before the first day of the dispalyed month - do not take it into consideration //for calculating average rent days. } } else { //the order is for more than one day. We have already read this order in the previous cycle in the date loop } //At this point anOrder contains the order pointed by the on-hand apartmentDay record //Add the revenue of that day to the total revenu per day revenuePerDay[dayNumber] += anApartmentDay.revenueAsMoney(); apartmentRevenue += anApartmentDay.revenueAsMoney(); apartmentOccupiedDays++; if (aDayBlock == null) { //This is the first time we see this order - open a new DayBlock object. Note that if the report starts from //1/12/2019 and we have an order that started on 39/11/2019 and continued to 4/12/2019 - then the first time we //encounted this order is not in the checkin date of it. aDayBlock = new DayBlock(anOrder) { days = 1, firstDate = aDate.ToString("yyyy-MM-dd"), }; } else { //This is a continuation of the order - increment the number of days aDayBlock.days++; } if (anOrder.isLastDay(aDate)) { //This is the last day of the order - write the day block dayBlocks.Add(aDayBlock); aDayBlock = null; } } dayNumber++; } //At this point we finished going on all dates for a specific apartment. It is possible that the last DayBlock was not yet written //if its checkout date is beyond the last day of the report (our report is from 1/12/2019 till 31/12/2019, but the checkout date //of the last order is 2/1/2020) if (aDayBlock != null) { dayBlocks.Add(aDayBlock); aDayBlock = null; } //Add the dayBlocks list into the apartmentDayBlocks. Check if it is a "waiting" apartment. apartmentDayBlocks.Add(dayBlocks); //Add the apartment revenue and apartment occupacy percentage - only for "normal" apartments revenuePerApartment.Add(apartmentRevenue); double apartmentOccupancyPercent = apartmentOccupiedDays / days * 100.0; int apartmentOccupancyPercentRounded = (int)Math.Round(apartmentOccupancyPercent); percentOccupancyPerApartment.Add(apartmentOccupancyPercentRounded); //calculate the average rent days per apartment double averageRentDays = 0.0; if (totalRents > 0) { averageRentDays = totalRentDays / totalRents; } averageDaysPerApartment.Add(averageRentDays); } //At this point the apartmentDayBlocks variable contaiins a list of list of day blocks //Calculate the list of employee work days. The list contains a single record for each day (or null, if no employee is assigned //for that day). If 2 employees are assigned for the same day - only one is taken (the last one) //empWorkDaysList = new List<EmployeeWorkDay>(); empWorkDaysArray = new EmployeeWorkDay[days]; var empWorkDays = from anEmpWorkDay in db.EmployeeWorkDay where anEmpWorkDay.DateAndTime >= fromDate && anEmpWorkDay.DateAndTime <= lastDate orderby anEmpWorkDay.DateAndTime select anEmpWorkDay; foreach (var anEmpWorkDays in empWorkDays) { int dayNumber = (int)Math.Round((anEmpWorkDays.DateAndTime.Date - fromDate).TotalDays, 0); empWorkDaysArray[dayNumber] = anEmpWorkDays; } maidList = db.Employee.Where(emp => emp.Role == "maid").ToList(); //Add all maids to the maid list expenseTypes = (from expenseType in db.ExpenseType select expenseType.NameKey).ToList(); return(apartmentDayBlocks); } }
/// <summary> /// The function checks the booking data for validity. There is a difference if the booking was made by a guest or by admin. /// If by guest - there will be more checks then if done by admin. /// </summary> /// <returns></returns> public override bool isValid() { this.errorMessage.Clear(); if (this.name == null || this.name == "") { this.errorMessage.Add("name", "Please enter name"); } if (this.country == "" && this.bookedBy == "Guest") { //A guest must specify country this.errorMessage.Add("country", "Please select country"); } else if (this.country == "") { //Booking was done by admin and not by a guest - it is OK not to have country } else { //Cuntry is not empty - check that it exists in our DB citylifedb8_blContext db = new citylifedb8_blContext(); Country theCountry = db.Country.SingleOrDefault(a => a.Name == this.country); if (theCountry == null) { //Although we do not expect such a case, as our country list contains all countries, and the user can only choose from the list this.errorMessage.Add("country", "This country does not exist in our country list"); } } if (this.bookedBy == "Guest" && !OrderData.IsValidEmail(this.email)) //Email is mandatory for a guest, but not for admin { this.errorMessage.Add("email", "Please enter a valid email address"); } //When a guest enters a phone number - it should be between 10 to 13 digits. no special characters allowed in the number. //THIS IS AN INTERIM SOLUTION - WE SHOULD LOOK FOR A SUITABLE LIBRARY TO VALIDATE PHONE NUMBER if (this.bookedBy == "Guest" && !Regex.Match(this.phone, @"^(\+?[0-9]{10,13})$").Success) { this.errorMessage.Add("phone", "Please enter a valid phone number"); } if (adults < 1) { this.errorMessage.Add("adults", "Number of adults must be at least 1"); } if (children < 0) { this.errorMessage.Add("children", "number of children cannot be negative"); } if (checkout <= checkin) { this.errorMessage.Add("checkin", "Checkout date cannot be before or equal to checkin date"); } try { Money priceM = new Money(this.price); } catch (AppException) { //The price amount could not be converted to Money - it is not legal as money (either the currency does not exist or non numeric this.errorMessage.Add("price", "Invalid price"); } try { Money paidM = new Money(this.paid); } catch (AppException) { //The paid amount could not be converted to Money - it is not legal as money (either the currency does not exist or non numeric this.errorMessage.Add("paid", "Invalid amount"); } return(errorMessage.Count() == 0); }
/// <summary> /// perform a translation operation to the target languagewhich was defined in the constructor. If the translation key does not exist /// creates a record in the translation key table, and also a record in the translation table for the English text. So default English /// translation will be created immediately. This translation can later be changed. /// </summary> /// <param name="translationKey">the translation key which needs to be translated</param> /// <param name="lineNumber">the line number in the code where the translate method was last called. Note that /// if the same key is requested in more than one place in the code - the DB will only save the last call</param> /// <param name="filePath">the file path where the method was last called</param> /// <returns>the translation in the required language. If translation was not found in the required language - /// will try to return the translation in the default language. Otherwise will return the trnaslation key /// itself. If "show asterisks" is set - then will reutnr the translation key with surounded with asterisks</returns> public string translate(string translationKey, [CallerLineNumber] int lineNumber = 0, [CallerFilePath] string filePath = null) { if (translationKey == null) { AppException.writeException(120, null, Environment.StackTrace); return(""); } using (citylifedb8_blContext db = new citylifedb8_blContext()) { TranslationKey theTranslationKey = db.TranslationKey.SingleOrDefault(record => record.TransKey == translationKey); if (theTranslationKey == null) { //the translation key does not exist. Add it to the translation key table and add the //same text to the translation text as English text theTranslationKey = new TranslationKey() { TransKey = translationKey, IsUsed = true, FilePath = filePath, LineNumber = lineNumber }; db.TranslationKey.Add(theTranslationKey); db.SaveChanges(); Language english = db.Language.Single(a => a.LanguageCode == "EN"); Translation theEnglishTranslation = new Translation() { LanguageLanguageCode = english.LanguageCode, TranslationKey = theTranslationKey, Message = translationKey }; db.Translation.Add(theEnglishTranslation); db.SaveChanges(); if (_noTranslation == "showAsterisks") { //return the translation key surrounded by asterisks for QA string translated = '*' + translationKey + '*'; return(translated); } else { //assuming "defaultLanguage" - but since there is no translation at all for this key - return the key without asterisks return(translationKey); } } else { //The translation key exists - if (theTranslationKey.LineNumber != lineNumber || theTranslationKey.FilePath != filePath) { //The file path or the line number where the call was performed has changed. Assuming it is because we added some lines of //code, or refactored the code - update the file path tne line number theTranslationKey.LineNumber = lineNumber; theTranslationKey.FilePath = filePath; db.SaveChanges(); } //check if we have translation in the desired language Translation theTranslation = db.Translation.SingleOrDefault(record => record.TranslationKey.Id == theTranslationKey.Id && record.LanguageLanguageCode == _targetLanguageCode); if (theTranslation != null) { //the translation exists in the target language - return it return(theTranslation.Message); } else { //The translation does not exist in the target language if (_noTranslation == "showAsterisks") { //In this case we need to return the translation key with asterisks return('*' + translationKey + '*'); } else { //assuming _noTranslation is "defaultLanguage" - look for translation in the default language theTranslation = db.Translation.SingleOrDefault(record => record.TranslationKey.Id == theTranslationKey.Id && record.LanguageLanguageCode == _defaultLanguageCode); if (theTranslation != null) { //translation exists - return it return(theTranslation.Message); } else { //no translation exists even in the default language - return the translation key (without asterisks) return(translationKey); } } } } } }