I have code which I need to refactor in order to use in many places. So I tried some solutions but always ending with repeated and messy code. So, I decided to ask what is possible best solutions.
This code is used for calculating sale price in e-commerce project. My goal is to put some code in method which will not change over time, or better to say, which will be managed only from one place. This part is considering of setting sale price based on some comparasion.
And problem occurs in this comparasion. I want also to do some formating of controls like Label based on this result, like setting currency code. The currency code will be sometimes in $, sometimes in USD. So, this mean I should somehow isolete this currency code also.
In short, I want to refactor this currency code and formating controls based on calculated sale price.
So, I created BasketHelper class with Product and Account properties and method SetBasketPayment that return properties I setted in this method. Basically, I use this approach to group properties of Product and Account classes and than return values.
Here is my code. Any further explanation, I will provide upon your request.
public class BasketHelper
{
public Product _product { get; set; }
public Account _account { get; set; }
public BasketHelper SetBasketPayment(Product product, Account account, HyperLink lblIconOnSale, Label lblSalePrice, Label lblListPrice, HyperLink lblIconCampaign)
{
decimal _brandAccountDiscountRate = default(decimal);
decimal _accountDiscount = default(decimal);
if (HttpContext.Current.Request.IsAuthenticated)
{
MembershipUser mUser = Membership.GetUser();
if (mUser != null)
{
account = Account.GetAccountByUserId((Guid)Membership.GetUser().ProviderUserKey);
try
{
_accountDiscount = account.DiscountRate;
}
catch (Exception ex) { }
BrandAccountDiscount brandAccountDiscount = BrandAccountDiscount.GetBrandAccountDiscountByUserAndBrandId(product.BrandId, mUser.ProviderUserKey.ToString());
if (brandAccountDiscount != null)
{
_brandAccountDiscountRate = brandAccountDiscount.DiscountRate;
}
}
}
decimal currencyMultiplier = Currency.GetCurrencyValue(product.CurrencyCode);
decimal _listPriceTL = product.ListPrice * currencyMultiplier;
decimal _productCampaignPrice = _listPriceTL * (1 - product.DiscountRate / 100);
decimal _accountPrice = _listPriceTL * (1 - _accountDiscount / 100);
decimal _brandPrice = _accountPrice * (1 - _brandAccountDiscountRate / 100);
lblListPrice.Text = product.ListPrice.ToString("N2") + " " + product.CurrencyCode;
if (product.DiscountRate > 0)
{
product.SalePrice = _productCampaignPrice;
lblSalePrice.Text = _productCampaignPrice.ToString("C2") + " + KDV";
lblListPrice.CssClass += " strike";
lblIconCampaign.Text = "+%" + product.DiscountRate.ToString("N0");
lblIconCampaign.Visible = true;
}
else
{
if (_accountPrice < _listPriceTL)
{
product.SalePrice = _accountPrice;
lblIconOnSale.Text = "%" + _accountDiscount.ToString();
lblIconOnSale.Visible = true;
}
if (_brandAccountDiscountRate > 0)
{
product.SalePrice = _brandPrice;
lblSalePrice.Text = _brandPrice.ToString("C2") + " +KDV";
}
}
return new BasketHelper
{
_product = product,
_account = account
};
}
}
Related
I have two columns in Datagridview, one for the price excluding Vat and another one for price including Vat, I want it to be dynamic, if I alter the price excluding vat it updates the column including Vat, and if I Update the including Vat column it updates the excluding VAT column vice-versa.
I would appreciate if anyone can help me with the right code for it in C#.
Here´s the code I´m using the calculation to one direction I need the code for the inverse.
private void dgv_Filho_CellEndEdit_1(object sender, DataGridViewCellEventArgs e)
{
bool Check = Convert.ToBoolean(dgv_Filho.CurrentRow.Cells["Check_Filho"].Value);
string Medida_1 = Convert.ToString(dgv_Filho.CurrentRow.Cells["Medida_1"].Value);
string Medida_2 = Convert.ToString(dgv_Filho.CurrentRow.Cells["Medida_2"].Value);
var Iva = Convert.ToDecimal(cb_Iva.Text);
if (Check)
{
if (!string.IsNullOrWhiteSpace(tb_CodigoArtigo.Text) || !string.IsNullOrWhiteSpace(tb_Descricao.Text))
{
dgv_Filho.CurrentRow.Cells["ArtigoPai"].Value = tb_CodigoArtigo.Text;
dgv_Filho.CurrentRow.Cells["Descricao_Pai"].Value = tb_Descricao.Text + " " + Medida_1 + Medida_2;
dgv_Filho.CurrentRow.Cells["CodigoArtigoFilho"].Value = tb_CodigoArtigo.Text + Medida_1 + Medida_2;
//dgv_Filho.CurrentRow.Cells["PrecoFilhoSemIva"].Value = tb_PVP1.Text;
decimal PrecoFilho = Convert.ToDecimal(dgv_Filho.CurrentRow.Cells["PrecoFilhoSemIva"].Value);
if (PrecoFilho > 0)
{
decimal PrecoFilhoComIva = PrecoFilho * Iva / 100 + PrecoFilho;
dgv_Filho.CurrentRow.Cells["PrecoFilhoComIva"].Value = PrecoFilhoComIva;
}
}
else
{
dgv_Filho.CurrentRow.Cells["ArtigoPai"].Value = string.Empty;
dgv_Filho.CurrentRow.Cells["Descricao_Pai"].Value = string.Empty;
}
}
}
This isn't too difficult using your existing code:
First of all, use the name of the edited column in if/else if statements to filter which conversion should take place, so that changing the VAT column doesn't get overwritten by the preVAT column. Then, use the opposite algebraic expression of the one you already have written to convert the postVAT price back to the preVAT
Here is what it will look like:
dgv_Filho.CurrentRow.Cells["ArtigoPai"].Value = tb_CodigoArtigo.Text;
dgv_Filho.CurrentRow.Cells["Descricao_Pai"].Value = tb_Descricao.Text + " " + Medida_1 + Medida_2;
dgv_Filho.CurrentRow.Cells["CodigoArtigoFilho"].Value = tb_CodigoArtigo.Text + Medida_1 + Medida_2;
decimal PrecoFilho = Convert.ToDecimal(dgv_Filho.CurrentRow.Cells["PrecoFilhoSemIva"].Value);
decimal PrecoFilhoComIva = Convert.ToDecimal(dgv_Filho.CurrentRow.Cells["PrecoFilhoComIva"].Value);
if (dgv_Filho.Columns[e.ColumnIndex].Name == "PrecoFilhoSemIva")
{
PrecoFilhoComIva = PrecoFilho * (Iva / 100) + PrecoFilho;
dgv_Filho.CurrentRow.Cells["PrecoFilhoComIva"].Value = PrecoFilhoComIva;
}
else if (dgv_Filho.Columns[e.ColumnIndex].Name == "PrecoFilhoComIva")
{
decimal PrecoFilhoSemIva = PrecoFilhoComIva - (PrecoFilhoComIva / (1 + (Iva / 100)) * (Iva / 100));
dgv_Filho.CurrentRow.Cells["PrecoFilhoSemIva"].Value = PrecoFilhoSemIva;
}
Using this code, editing the preVAT value will automatically update the postVAT value accordingly, and editing the postVAT value will automatically update the preVAT value accordingly
Rather than interact with the DataGridView directly (which can be complex) you could instead make a class that implements INotifyPropertyChanged and keeps all of its internal calculations up-to-date at all times (which is easier). Here is a simplified version of such a class that responds to changes of Descricao, Medida and PrecoFilhoSemIva.
Simplified class that represents a row of data
class Articulo : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
string _descricao = string.Empty;
public string Descricao
{
get => _descricao;
set
{
if (!Equals(_descricao, value))
{
_descricao = value;
OnPropertyChanged();
}
}
}
public string Descricao_Pai => $"{Descricao} {Medida_1}#{_precoFilhoSemIva.ToString("F2")}";
public decimal PrecoFilhoComIva => _precoFilhoSemIva * (1.0m + MainForm.Iva);
decimal _medida = 0;
public decimal Medida
{
get => _medida;
set
{
if (!Equals(_medida, value))
{
_medida = value;
OnPropertyChanged();
}
}
}
decimal _precoFilhoSemIva = 0;
public decimal PrecoFilhoSemIva
{
get => _precoFilhoSemIva;
set
{
if (!Equals(_precoFilhoSemIva, value))
{
_precoFilhoSemIva = value;
OnPropertyChanged();
}
}
}
string _codigoArtigo = System.Guid.NewGuid().ToString().Substring(0, 10).ToUpper();
public string CodigoArtigo
{
get => _codigoArtigo;
set
{
if (!Equals(_codigoArtigo, value))
{
_codigoArtigo = value;
OnPropertyChanged();
}
}
}
}
Instances of this class are placed in a BindingList which is assigned to the DataSource property of dgv_Filho and caused the DGV to update whenever the Refresh method is called.
Initializations
The only interaction that should be necessary with the DGV is to initialize the columns and bindings properly in the MainForm override for the Load event. This is also where we bind the combo box to a static value for Iva that can be used by the calculation for the row items.
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
initDataGridView();
initComboBox();
}
private void initDataGridView()
{
dgv_Filho.DataSource = DataSource;
DataSource.ListChanged += (sender, e) =>
{
if (e.ListChangedType == ListChangedType.ItemChanged)
{
dgv_Filho.Refresh();
}
};
// Add one or more items to autogenerate the columns.
Random randomPriceGen = new Random(1);
for (int i = 1; i <= 3; i++)
{
var preco = i == 1 ? 1.0m : (decimal)randomPriceGen.NextDouble() * 100;
DataSource.Add(new Articulo
{
Descricao = $"Articulo {(char)('A' + (i - 1))}",
Medida = i,
PrecoFilhoSemIva = preco,
});
}
// Do a little column formatting
foreach (DataGridViewColumn column in dgv_Filho.Columns)
{
switch (column.Name)
{
case nameof(Articulo.Descricao):
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
column.MinimumWidth = 120;
break;
case nameof(Articulo.Medida):
case nameof(Articulo.PrecoFilhoSemIva):
case nameof(Articulo.PrecoFilhoComIva):
column.DefaultCellStyle.Format = "F2";
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
break;
default:
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
break;
}
}
}
private void initComboBox()
{
cb_Iva.SelectedIndex = 0;
cb_Iva.SelectedIndexChanged += onIvaSelected;
cb_Iva.KeyDown += (sender, e) =>
{
if( e.KeyData == Keys.Enter)
{
e.Handled = e.SuppressKeyPress = true;
}
onIvaSelected(sender, e);
};
onIvaSelected(cb_Iva, EventArgs.Empty);
void onIvaSelected(object sender, EventArgs e)
{
if (decimal.TryParse(cb_Iva.Text.Replace("%", string.Empty), out decimal iva))
{
Iva = iva / 100m;
dgv_Filho.Refresh();
cb_Iva.BackColor = SystemColors.Window;
}
else cb_Iva.BackColor = Color.LightSalmon;
}
}
So I'm REALLY new to coding, so I'm learning as I go. I'm doing an assignment for a course, where I have to create a party booking program for a company. The idea is simple, just selected some different options, add them up, and calculate the costs. I have labels that will change and display the integer that the variable is set to, and they work perfectly which would tell me that the variables themselves are indeed getting changed.
However, once I try to add the variables together, it doesn't work.
public partial class AdultPayment : Form
{
public static int ConvertNumberAdult = Convert.ToInt32(Adult.numberAdult);
public static int MealCost = Adult.mealPrice*ConvertNumberAdult;
private static int PrivateRoomCost;
public static int TotalCost = MealCost + CalculateWine + PrivateRoomCost;
public static string DisplayNumberAdult = Convert.ToString(Adult.numberAdult);
private static int CalculateWine { get; set; } = ConvertNumberAdult / 6 * 15;
public AdultPayment()
{
InitializeComponent();
lblAdultConfirmName.Text = Adult.adultContactName;
lblAdultConfirmNumber.Text = Adult.adultContactNumber;
lblAdultConfirmDate.Text = Adult.adultDate;
lblAdultConfirmTime.Text = Adult.adultTime;
lblConfirmNumberOfAdult.Text = Adult.numberAdult.ToString();
lblMealCostTotal.Text = "£"+ MealCost.ToString();
lblCostTotal.Text = "£" + TotalCost.ToString();
if (Adult.adultPrivateRoom == true)
{
PrivateRoomCost = 40;
lblAdultConfirmPrivateRoom.Text = "Yes";
lblPrivateRoomTotal.Text = "£"+ PrivateRoomCost;
}
else
{
PrivateRoomCost = 0;
lblAdultConfirmPrivateRoom.Text = "No";
lblPrivateRoomTotal.Text = "N/A";
}
if(Adult.menuOption == true)
{
lblConfirmMenu.Text = "2 Courses for £15 each";
}
if(Adult.menuOption == false)
{
lblConfirmMenu.Text = "3 Courses for £18 each";
}
if (Adult.addWine == false)
{
CalculateWine = 0;
lblConfirmWineAdded.Text = "No";
lblWineTotal.Text = "N/A";
}
else
{
lblConfirmWineAdded.Text = "Yes";
lblWineTotal.Text = "£"+ CalculateWine.ToString();
}
lblCostTotal.Text = "£" + TotalCost.ToString();
}
}
I have a different form, that allows the users to select their preferences, which works just as I need it to.
The variable that is supposed to add the other variables together is
public static int TotalCost = MealCost + CalculateWine + PrivateRoomCost;
I genuinely am so confused now, and because I'm so new to this I don't know how else to word it in order to find anything on the internet
Any help would be great!
Thanks!
So I have an array, strArray, that stores the values of my text files which has 3 columns. I think this is called a two or three dimensional array, not sure. Or maybe one dimensional. I have a List<> called Inventory which adds the data to it.
I currently have three successful columns I just need the fourth. The fourth column is the second and third column multiplied together, which is a total price. The second column is an int, "Number of Items", the third is a decimal, "Price" and the fourth is a decimal, "Total Price" which is Number of Items * Price.
I'll go ahead and post my code, I am also using four list boxes for the data. Three columns (or three list boxes) work fine, but I just gotta get the fourth one figured out.
Sorry for the large amount of code, I figured if I copied all of it it'll make it easier to see if an error occurred earlier on. btnLoadInfo_Click is the event/method where the main issue is.
namespace TCSCapstone
{
public partial class frmInventory : Form
{
List<frmInventory> Inventory = new List<frmInventory>();
public frmInventory()
{
InitializeComponent();
}
public string ItemName { get; set; }
public int NumberOfItems { get; set; }
public decimal Price { get; set; }
public decimal TotalPrice { get; set; }
string selectedList = "";
private void cmbList_SelectedIndexChanged(object sender, EventArgs e)
{
selectedList = this.cmbList.GetItemText(this.cmbList.SelectedItem);
lstItemName.DataSource = null;
lstNumberOfItems.DataSource = null;
lstPrice.DataSource = null;
lstItemName.Items.Clear();
lstNumberOfItems.Items.Clear();
lstPrice.Items.Clear();
lstTotalPrices.Items.Clear();
if (selectedList == "Creative Construction")//if the selected combo box item equals the exact string selected
{
selectedList = "creative"; //then the string equals creative, which is creative.txt but I add the .txt in the btnLoadInfo method
} else if (selectedList == "Paradise Building")
{
selectedList = "paradise";//this is for paradise.txt
}
else if (selectedList == "Sitler Construction")
{
selectedList = "sitler";//this is for sitler.txt
}
else
{
MessageBox.Show("Please select one of the items.");
}
}`
private void btnLoadInfo_Click(object sender, EventArgs e)
{
Inventory.Clear(); //Clears the entire Inventory List
using (StreamReader invReader = new StreamReader(selectedList +
".txt"))
{
while (invReader.Peek() >= 0)
{
string str;
string[] strArray;
str = invReader.ReadLine();
strArray = str.Split(',');
frmInventory currentItem = new frmInventory();
currentItem.ItemName = strArray[0];
currentItem.NumberOfItems = int.Parse(strArray[1]);
currentItem.Price =
decimal.Parse(strArray[2]);
strArray[1].
currentItem.TotalPrice = decimal.Parse(strArray[1] *
strArray[2]);
Inventory.Add(currentItem);
}
}
displayLists(); //Calls the displayLists method to update list
//boxes at the end of the button click event
}//end of btnLoadInfo
void displayLists()
{
//Resets the listboxes datasources by setting them to null
lstItemName.DataSource = null;
lstNumberOfItems.DataSource = null;
lstPrice.DataSource = null;
lstItemName.Items.Clear();
lstNumberOfItems.Items.Clear();
lstPrice.Items.Clear();
lstTotalPrices.Items.Clear();
lstItemName.DisplayMember = "ItemName";
lstItemName.ValueMember = "";
lstItemName.DataSource = Inventory;
lstNumberOfItems.DisplayMember = "NumberOfItems";
lstNumberOfItems.ValueMember = "";
lstNumberOfItems.DataSource = Inventory;
lstPrice.DisplayMember = "Price";
lstPrice.ValueMember = "";
lstPrice.DataSource = Inventory;
}
Your TotalPrice property should be a mathematical equation, not something you set independently of the number of items and their prices.
Change the property to this:
public decimal TotalPrice{
get{ return NumberOfItems * Price; }
}
Delete the line that sets TotalPrice in your loop; it's no longer necessary because you've set the item price and the number of items; the total price inherently follows from these
You're trying to multiply two strings together. Instead, multiply the numeric values that you have already parsed:
currentItem.TotalPrice = currentItem.NumberOfItems * currentItem.Price;
Creating a new instance of Cost:
Cost newCost = new Cost();
newCost.TotalCost = 0;
newCost.Event = 1000;
newCost.personalEvent = 1500;
newCost.organisationalEvent = 1700;
then the if statement below it:
if (EventList.SelectedItem == "Event")
{
TotalCost = (Event + 100);
}
else if (EventList.SelectedItem == "Personal")
{
TotalCost = (personalEvent + 150);
}
else if (EventList.SelectedItem == "Organisational")
{
TotalCost = (organisationalEvent + 170);
}
else
{
txtTotalCost.Text = ("£" + TotalCost.ToString());
}
I also have a class named Cost, but i keep getting an error saying "The name 'TotalCost' does not exist in the current context".
Any help would be really appreciated.
My Cost class is as follows:
class Cost
{
public int TotalCost;
public int Event;
public int personalEvent;
public int organisationalEvent;
}
If you are trying to access the TotalCost field in your class, you need to provide an instance reference so that the computer knows from what object to read the value.
Replace TotalCost in the code with newCost.TotalCost.
if (EventList.SelectedItem == "Event")
{
newCost.TotalCost = (Event + 100);
}
else if (EventList.SelectedItem == "Personal")
{
newCost.TotalCost = (personalEvent + 150);
}
else if (EventList.SelectedItem == "Organisational")
{
newCost.TotalCost = (organisationalEvent + 170);
}
else
{
txtTotalCost.Text = ("£" + newCost.TotalCost.ToString());
}
By the way, it's not clear to me why you set txtTotalCost.Text only if you have not set the TotalCost field value. I would expect at a minimum that it's when you do set the TotalCost field value that you would want to update the txtTotalCost.Text property, and probably it makes sense to just always set it.
I have a WPF C# Application which is accessing data through a SQL-LINQ connection and putting it on a Datagrid. I have added a Running Pips column and have been trying to figure out how in to get this column populated correctly. I have found several methods through searching the web, but none of these are appropriate for my particular setup. Most of the time I end up in an endless loop. I would like the Running Pips column to be cumulative and the order of the calculation to start from the earliest 'Close Time'.
Close Time Profit Running Profit
10.09.11 $10 $10
10.10.11 $20 $30
10.11.11 $15 $45
Here is a summary of the code. I hope someone can suggest how to fix this code with any relevant information needed to aid me in implementing this:
public void RefreshClose() {
if (CloseTradeCollection == null) return;
var i = 0;
if (StaticTool.SelectedAccount == null) {
ExistCloseTrade = false;
CloseTradeCollection.Clear();
return;
}
Account = StaticTool.SelectedAccount;
foreach (var trade in GetClosedTradesFromDb()) {
if (CloseTradeCollection.Count <= i) {
ExistCloseTrade = true;
var tradeDetails = new Trade {
Id = trade.id,
Ticket = trade.ticket,
OpenTime = trade.opentime,
CloseTime = trade.closetime,
Symbol = trade.symbol,
OpenPrice = trade.openprice,
ClosePrice = trade.closeprice,
Profit = trade.profit,
Comment = trade.comment.Trim(),
};
tradeDetails.History = tradeDetails.CloseTime - tradeDetails.OpenTime;
CloseTradeCollection.Add(tradeDetails);
}
else {
var tradeDetails = CloseTradeCollection[i];
tradeDetails.Id = trade.id;
tradeDetails.Ticket = trade.ticket;
tradeDetails.OpenTime = trade.opentime;
tradeDetails.CloseTime = trade.closetime;
tradeDetails.Symbol = trade.symbol;
tradeDetails.OpenPrice = trade.openprice;
tradeDetails.ClosePrice = trade.closeprice;
tradeDetails.Profit = trade.profit;
tradeDetails.Comment = trade.comment.Trim();
tradeDetails.History = DateTime.Now - tradeDetails.OpenTime;
//tradeDetails.RunningProfit = ????????
}
i++;
}
}
You can create a local variable to keep track of running profit, making use of the fact that the assignment operation returns the value being assigned.
tradeDetails.RunningProfit = (runningProfit = runningProfit + trade.profit);
Here is a general idea - you should be able to adopt it to your needs:
class Trade {
public DateTime CloseTime { get; set; }
public decimal Profit { get; set; }
}
class TradeWithRunningProfit : Trade {
public decimal RunningProfit { get; set; }
}
class Program {
static IEnumerable<TradeWithRunningProfit> GetRunningProfits(IEnumerable<Trade> rows) {
decimal running_profit = 0;
return
from row in rows
select new TradeWithRunningProfit {
CloseTime = row.CloseTime,
Profit = row.Profit,
RunningProfit = (running_profit += row.Profit)
};
}
static void Main(string[] args) {
var rows = new[] {
new Trade { CloseTime = new DateTime(11,10,09), Profit = 10},
new Trade { CloseTime = new DateTime(11,10,10), Profit = 20},
new Trade { CloseTime = new DateTime(11,10,11), Profit = 15},
};
foreach (var row_with_running_profit in GetRunningProfits(rows)) {
Console.WriteLine(
"{0}\t{1}\t{2}",
row_with_running_profit.CloseTime,
row_with_running_profit.Profit,
row_with_running_profit.RunningProfit
);
}
}
}