Working on a C# application for Payroll. As a warning, I'm very new to all this, just been chucked in to it and enjoying it but it's a lot to absorb in a short amount of time. I'm currently learning about LINQ and classes. I'm grabbing invoice lines out of our account SQL server and paying personnel based on sales and some situations that can be determined from the data. See the sample below:
Ord_Inv_No Delivery_Date Trmnl_Key TrmnlGrp_Key
INV-00059754 2016-05-02 07:00:00 23 3
INV-00059839 2016-05-02 16:01:00 56 3
This is a very small portion of the data but it gives the gist of what I want to analyze. I have a class as shown below:
class SalesItem
{
public string DriverName { get; set; }
public DriverData DriverData { get; set; }
public int TerminalKey { get; set; }
public int TerminalGroupKey { get; set; }
public string DeliveryDate { get; set; }
public string CustomerLocation { get; set; }
public int? CustomerLocationKey { get; set; }
public bool? IsCredited { get; set; }
public string InvoiceNumber { get; set; }
public string TermianlGroupDesc { get; set; }
public SalesItem(string driverName, int terminalKey, int terminalGroupKey, string deliveryDate,
string customerLocation, int? customerLocationKey, bool? isCredited, string invoiceNumber, string terminalGroupDesc)
{
this.DriverName = driverName;
this.TerminalKey = terminalKey;
this.TerminalGroupKey = terminalGroupKey;
this.DeliveryDate = deliveryDate;
this.CustomerLocation = customerLocation;
this.CustomerLocationKey = customerLocationKey;
this.IsCredited = isCredited;
this.InvoiceNumber = invoiceNumber;
this.TermianlGroupDesc = terminalGroupDesc;
}
I'm trying to implement a way I can 1. store each SalesItem (each row) as a Collection for lack of a better word. I want to iterate through the collection of SalesItem and find out a few things, like when an Invoice row shows up twice with a different Trmnl_Key and two different Ord_Inv_No that have the exact same Date as one another and return the greatest rate of pay for the two. I had written some logic for this that was manipulating a DataTable that I was grabbing through SQLConnection/Command/Reader/Etc but all of this was very slow and cumbersome when dealing with a week of data and I couldn't get the comparison to work reliably. Further down the line, these rows would be flagged in a DataGrid in WPF for human verification of their pay in case of something funky coming in from the accounting software.
Right now, I'm trying to save the collection as shown below (which is just the current iteration, I have several days worth of trying that's failed.)
private void GetInformation(object sender, SelectionChangedEventArgs e)
{
ComboBox currentItem = sender as ComboBox;
int driverKey = Convert.ToInt32(currentItem.SelectedValue);
DriverData driver = new DriverData();
driver.SetDriverData(driverKey);
int years = driver.ServiceYears;
List<SalesItem> items = (from o in transportationDb._Payroll_Orders
where o.Ord_Driver_Key == driverKey &&
o.Delivery_Date >= new DateTime(2016, 5, 2) && o.Delivery_Date <= new DateTime(2016, 5, 8)
select new SalesItem(
o.Driver_Name,
o.Trmnl_Key,
o.TrmnlGrp_Key,
o.Delivery_Date.ToString(),
o.CustLoc_Description,
o.Ord_CustLoc_Key,
o.Credits, o.Ord_Inv_No, o.TrmnlGrp_Description )).ToList();
dataGrid.ItemsSource = items;
}
Any wisdom or direction would be much appreciated
Granted, this isn't much different than what you had, but try this and see if it works for you:
private void GetInformation(object sender, SelectionChangedEventArgs e)
{
ComboBox currentItem = sender as ComboBox;
int driverKey = Convert.ToInt32(currentItem.SelectedValue);
DriverData driver = new DriverData(); //What's this for?
driver.SetDriverData(driverKey); //What's this for?
int years = driver.ServiceYears; //What's this for?
var startDate=new DateTime(2016, 5, 2);
var endDate=new DateTime(2016, 5, 8);
var items = transportationDb._Payroll_Orders
.Where(o=>o.Ord_Driver_Key == driverKey)
.Where(o=>o.Delivery_Date >= startDate && o.Delivery_Date <= endDate)
.Select(o=>new SalesItem {
DriverName=o.Driver_Name,
...
});
dataGrid.ItemsSource = items;
}
If your Orders table has an index on Ord_Driver_key and Delivery_Date, then this query should be pretty quick.
I hope this helps in some way. I'm not too sure of what you're trying to achieve. A save function could look something like the following, but I don't know exactly what kind of connection you're using. Note that I'm checking to make sure the record doesn't exist already.
private void Save(SalesItem item)
{
if(!transportationDb._Payroll_Orders.Any(p => p.Ord_Inv_No == item.InvoiceNumber))
{
transportationDb._Payroll_Orders.Add(item.PayrollOrder);
transportationDb.SaveChanges();
}
else
{
// Already exists
}
}
Update your class to however you'd like, but I'd do it this way from the limited knowledge of what your object is suppose to look like.
class SalesItem
{
public SalesItem(_Payroll_Orders po == null, DriverData dd == null)
{
this._Payroll_Order = po != null ? po : new _Payroll_Orders();
this.DriverData = dd != null ? dd : new DriverData();
}
private _Payroll_Orders _Payroll_Order { get; set; }
public _Payroll_Orders PayrollOrder
{
get { return _Payroll_Order; }
set { _Payroll_Order = value; }
}
public string DriverName
{
get { return _Payroll_Order.Driver_Name; }
set { _Payroll_Order.Driver_Name= value; }
}
public DriverData DriverData { get; set; }
public int TerminalKey
{
get { return _Payroll_Order.Trmnl_Key; }
set { _Payroll_Order.Trmnl_Key= value; }
}
public int TerminalGroupKey
{
get { return _Payroll_Order.TrmnlGrp_Key; }
set { _Payroll_Order.TrmnlGrp_Key= value; }
}
public DateTime DeliveryDate
{
get { return _Payroll_Order.Delivery_Date; }
set { _Payroll_Order.Delivery_Date= value; }
}
public string CustomerLocation
{
get { return _Payroll_Order.CustLoc_Description; }
set { _Payroll_Order.CustLoc_Description = value; }
}
public int? CustomerLocationKey
{
get { return _Payroll_Order.Ord_CustLoc_Key; }
set { _Payroll_Order.Ord_CustLoc_Key = value; }
}
public bool? IsCredited
{
get { return _Payroll_Order.Credits; }
set { _Payroll_Order.Credits = value; }
}
public string InvoiceNumber
{
get { return _Payroll_Order.Ord_Inv_No; }
set { _Payroll_Order.Ord_Inv_No = value; }
}
public string TermianlGroupDesc
{
get { return _Payroll_Order.TrmnlGrp_Description; }
set { _Payroll_Order.TrmnlGrp_Description = value; }
}
}
then you can change your function here so you only have to select 'new SalesItem(o, driver)':
private void GetInformation(object sender, SelectionChangedEventArgs e)
{
ComboBox currentItem = sender as ComboBox;
int driverKey = Convert.ToInt32(currentItem.SelectedValue);
DriverData driver = new DriverData();
driver.SetDriverData(driverKey);
int years = driver.ServiceYears;
List<SalesItem> items = (from o in transportationDb._Payroll_Orders
where o.Ord_Driver_Key == driverKey &&
o.Delivery_Date >= new DateTime(2016, 5, 2) &&
o.Delivery_Date <= new DateTime(2016, 5, 8)
select new SalesItem(o, driver)).ToList();
dataGrid.ItemsSource = items;
}
Related
What Im trying to achieve is a Budget Calculator. I have am using SQLite so all my database work needed to be in string format. below is my Save routine to show you guys...
void AddToBudget_Clicked(object sender, System.EventArgs e)
{
Budget Budget = new Budget()
{
OutgoingProductName = OProductName.Text,
OutgoingMonthlyCostS = OMonthlyCost.Text
};
using (SQLiteConnection conn = new SQLiteConnection(App.FilePath))
{
conn.CreateTable<Budget>();
int rowsAdded = conn.Insert(Budget);
}
DisplayAlert("Added!", "Your Monthly Item has been Added to Budget!", "OK");
BindingContext = new Budget();
OnAppearing();
}
I want all OutgoingMonthlyCostS items to add up before I subtract on an entry box in which the user would enter their Monthly Salary in to. Below is the code for my OutgoingMonthlyCost & OutgoingMonthlyCostS...
private decimal outgoingMonthlyCost { get; set; }
public decimal OutgoingMonthlyCost
{
get => outgoingMonthlyCost;
set
{
outgoingMonthlyCost = value;
OnPropertyChanged("OutgoingMonthlyCost");
}
}
private string outgoingMonthlyCostS { get; set; }
public string OutgoingMonthlyCostS
{
get => outgoingMonthlyCostS;
set
{
outgoingMonthlyCostS = value;
OnPropertyChanged("OutgoingMonthlyCostS");
}
}
public void outgoingMonthlyCostFin()
{
outgoingMonthlyCostS = outgoingMonthlyCost.ToString();
TotalBudget();
}
This is currently how I have it laid out but something isnt right as my app keeps crashing...
private decimal totalMonthlyCost { get; set; }
public decimal TotalMonthlyCost
{
get => totalMonthlyCost;
set
{
totalMonthlyCost = value;
OnPropertyChanged("totalMonthlyCost");
TotalBudget();
}
}
private string totalMonthlyCostFin { get; set; }
public string TotalMonthlyCostFin
{
get => totalMonthlyCostFin;
set
{
totalMonthlyCostFin = value;
OnPropertyChanged("totalMonthlyCostFin");
}
}
public void TotalBudget()
{
var Conversion = default(decimal);
if (OutgoingMonthlyCost != 0)
{
Conversion += decimal.Round((Convert.ToDecimal(OutgoingMonthlyCostS)), 2, MidpointRounding.AwayFromZero);
TotalMonthlyCostFin = "£" + (TotalMonthlyCost - Conversion).ToString();
}
else
{
TotalMonthlyCostFin = "£0";
}
}
I am currently creating an Attendance application but I am having a hard time matching a schedule where there is no logs to mark it as absent.
As of the moment this is how my table looks like
Current Table
As of the moment, the table will only show which schedule has attendance logs on it. So I can't see if there is a schedule which the employee hasn't shown up which s/he is absent.
I have tried matching it with null, but it ends up not showing anything.
This is my code to populate the table
public void Main()
{
// works but not the midnight cross stuff
var final = (from a1 in EmployeeAttendanceLogs
join a2 in EmployeeAttendanceLogs on a1.ID equals a2.ID
join t1 in EmployeeScheduleList on a1.ID equals t1.ID
join t2 in EmployeeScheduleList on a2.ID equals t2.ID
join d1 in EmployeeDetails on t1.ID equals d1.EmployeeID
where ((a1.LogStatus == 0 && t1.In == t2.In) && (((((a1.ActualLog - t1.In ).Ticks) > TimeSpan.FromHours(1).Ticks) || t1.In.Date == a1.ActualLog.Date) && t1.In.Date == a1.ActualLog.Date )) && (a2.LogStatus == 1 && t1.Out == t2.Out && (t2.Out.Date == a2.ActualLog.Date) )
select new
{
User_ID = t1.ID,
Name = d1.EmployeeName,
Scheduled_In = t1.In,
Actual_Login = a1.ActualLog,
Scheduled_Out = t2.Out,
Actual_Out = a2.ActualLog
}).Distinct(). ToList();
tbContainer = StaticClasses.ToDataTable(final);
dgvAttendance.ItemsSource = emp.CalculateEmployeeAttendance(tbContainer);
}
And these are my sources of data
Employee Schedule File
Employee Attendance Logs File
As based from the logs Employee 5 has no record and this is the output to the grid
So it doesn't show, but I have also tried to set my class to have a logic
Employee Schedule Class
public class EmployeeSchedule
{
public int ID { get; set; }
private string _name;
public string Name
{ get
{
if (_name == null)
{
_name = "";
}
return _name;
}
set { _name = value; }
}
public string scheduleeIn { get; set; }
private string _actualIn;
public string actualIn
{
get
{
if (_actualIn == null)
{
_actualIn = "Absent";
}
return _actualIn;
}
set { _actualIn = value; }
}
public string scheduleOut { get; set; }
public string _actualOut;
public string actualOut
{
get
{
if (_actualOut == null)
{
_actualOut = "Absent";
}
return _actualOut;
}
set { _actualOut = value; }
}
private string _tardiness;
public string tardiness
{
get
{
if (_tardiness == null)
{
_tardiness = "Absent";
}
return _tardiness;
}
set { _tardiness = value; }
}
private string _workHours;
public string workHours
{
get
{
if (_workHours == null)
{
_workHours = "Absent";
}
return _workHours;
}
set { _workHours = value; }
}
}
It's been a day already I have tried figuring it out but it doesn't seem to show up or to mark the schedule as absent.
Any ideas or suggestion would be of great help. Thanks
Edit : Sources of Data
Here is the source of data for my Attendance Logs
Attendance Logs
public class Actual
{
public int ID { get; set; }
public DateTime ActualLog { get; set; }
public int LogStatus { get; set; }
public DateTime date { get; set; }
}
Employee Schedule
public class Emp1
{
public int ID { get; set; }
public DateTime In { get; set; }
public DateTime Out { get; set; }
}
So I'm trying to append values to a list (in Json []), that's empty or has items in it. So I check wether the list in the object has items in it or not, if the item doesn't exist, then it creates a new item, if it exists, it rewrites it's value. Here is the code:
if (e.Key == Key.Enter)
{
// When the user pressed enter, do action
Team selected_team = teams.Where(t => t.team_number == Convert.ToInt32(inp_team_number.Text)).FirstOrDefault();
if (selected_team != null)
{
// when the team number is given, go try and find the data of them
Results team_results = results.Where(r => r.team_number == Convert.ToInt32(inp_team_number.Text)).FirstOrDefault();
int index = (Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1);
// Check if the item in the list exists
if (index < team_results.results[inp_tour_part.SelectedIndex].gtks.Length && team_results.results[inp_tour_part.SelectedIndex].gtks[index] != null)
{
if (regexColon.Match(gtk_input.Text).Success == true)
{
team_results.results[inp_tour_part.SelectedIndex].gtks[(Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1)] = gtk_input.Text; // Give the new value
}
else
{
MessageBox.Show("Wrong value.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
team_results.results[inp_tour_part.SelectedIndex].gtks[(Convert.ToInt32(gtk_input.Name.Substring(gtk_input.Name.Length - 1)) - 1)] = "00:00"; // Give the default value
}
}
else
{
if (regexColon.Match(gtk_input.Text).Success == true)
{
team_results.results[inp_tour_part.SelectedIndex].gtks.Append(gtk_input.Text); // Give the new value
}
else
{
MessageBox.Show("Wrong value.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
team_results.results[inp_tour_part.SelectedIndex].gtks.Append("00:00"); // Give the default value
}
}
SaveResults(results);
// Move to the next UI element
MoveToNextUIElement(e);
}
else
{
MessageBox.Show("Something went somewhere wrong.", "An error occured", MessageBoxButton.OK, MessageBoxImage.Warning);
}
}
Now, it works fine to rewrite the items, but when the list is empty (default) or when the item doesn't exist, and it needs to add/append the new value, it doesn't crahs and doesn't throw any error... Also it doesn't add the value to my json, now when I initialize the new object for this, it looks like the following:
team_results = new Results()
{
team_number = selected_team.team_number,
results = new Result[2] { new Result{ }, new Result { } } // Fixed length of array for the results. TODO: Needs fix.
};
And the model looks like this:
namespace RittensportRekenSoftware.Models
{
public class Results
{
public int team_number { get; set; }
public Result[] results { get; set; }
}
public class Result
{
public string given_start_time { get; set; }
public string connection_to_start { get; set; }
public string start_kp { get; set; }
public string stop_kp { get; set; }
public int missed_controls { get; set; }
public float km { get; set; }
public string[] gtks { get; set; }
}
}
Now I just need a list of strings in my json, but I don't have any clue on how to achieve this...
If you MUST, you can resize an array using Array.Resize() method. Please see documentation here.
int[] array = new int[] { 1, 2, 3 };
Array.Resize(ref array, 5);
array[3] = 4;
array[4] = 5;
But it is strongly advised the use of List<T> instead of arrays. After all List<T> uses arrays behind the scenes so you get all the functionality of an array minus most of the cons.
You can use List instead. Thus you don't need to know the array size when instantiating the list.
Why not alter your models so they implement List instead of array. In the constructor of each model just initialize the empty list (or other action depending on your situation)
namespace RittensportRekenSoftware.Models
{
public class Results
{
public int team_number { get; set; }
public List<Result> results { get; set; }
public Results() {
results = new List<Result>();
}
}
public class Result
{
public string given_start_time { get; set; }
public string connection_to_start { get; set; }
public string start_kp { get; set; }
public string stop_kp { get; set; }
public int missed_controls { get; set; }
public float km { get; set; }
public List<string> gtks { get; set; }
public Result() {
gtks = new List<string>();
}
}
}
Then when you have your models you can add to each list like the following:
Results r = new Results();
r.results.Add(new Result()); // or other `result` object here
Result r = new Result();
r.gtks.Add("My String"); // or other `string` here
I think you can implement a method which would create a new array based on original one. Then, you would be able to override that original array with the resulted one (returned by that new method).
The example code would be the following:
var test = new string[1] { "Test string 1" };
test = AddItemToArray(test, "Test string 2");
private static string[] AddItemToArray(string[] original, string item)
{
var result = new string[original.Length + 1];
for (int i = 0; i < original.Length; i++)
{
result[i] = original[i];
}
result[result.Length - 1] = item;
return result;
}
I am trying to bind a List of a custom class to a Listbox and cannot get anything to display. The List is a subset of another List. I can bind the parent List and see the items, but not the child List. How can I get the subset List to bind to the Listbox? I have tried changing the order of the ListBox's DisplayMember, ValueMember, and DataSource properties. In debugging I can see that the DataSource has the correct values, but I can't get them to display. Relevant code below:
public class DimZone
{
public int Zone_Key { get; set; }
public int Zone_ID { get; set; }
public int Facility_Key { get; set; }
public string Zone_Name { get; set; }
public string Zone_Type { get; set; }
}
GlobalVariables Class containing global List collection:
public static List<DimZone>[] zoneCollection = new List<DimZone>[maxServerCount];
Form using global List collection and subset List:
List<DimZone> zoneCollectionAppended = new List<DimZone>();
private void StaffStatusReportForm_Load(object sender, EventArgs e)
{
facilityComboBox.DataSource = GlobalVariables.facilityCollection;
GetFacilityIndex();
CreateZoneAppendedList();
PopulateUI();
}
private void CreateZoneAppendedList()
{
foreach (var zone in GlobalVariables.zoneCollection[currentFacilityIndex])
{
if (zone.Zone_Name != "All")
{
zoneCollectionAppended.Add(zone);
}
}
}
private void PopulateUI()
{
if (zoneCollectionAppended != null)
{
zoneListBox.DisplayMember = "Zone_Name";
zoneListBox.ValueMember = "Zone_ID";
zoneListBox.DataSource = zoneCollectionAppended;
}
}
Your code contains various unclear parts. In any case, the best proceeding in these situations is setting up a properly-working simpler code and modifying it until reaching the stage you want. I can provide this properly-working first step. Sample code:
private void Form1_Load(object sender, EventArgs e)
{
List<DimZone> source = new List<DimZone>();
DimZone curZone = new DimZone() { Zone_Key = 1, Zone_ID = 11, Facility_Key = 111, Zone_Name = "1111", Zone_Type = "11111" };
source.Add(curZone);
curZone = new DimZone() { Zone_Key = 2, Zone_ID = 22, Facility_Key = 222, Zone_Name = "2222", Zone_Type = "22222" };
source.Add(curZone);
zoneListBox.DisplayMember = "Facility_Key";
zoneListBox.DataSource = source;
}
public class DimZone
{
public int Zone_Key { get; set; }
public int Zone_ID { get; set; }
public int Facility_Key { get; set; }
public string Zone_Name { get; set; }
public string Zone_Type { get; set; }
}
Try this code and confirm that the changes in zoneListBox.DisplayMember (e.g., "Zone_Key", "Zone_ID", etc.) are immediately reflected in the values being displayed by zoneListBox.
The problem was I was changing zoneListBox.DataSource from one source to another on load, which caused the error. In order for the DataSource to update properly, I had to set zoneListBox.DataSource = null before updating to a new DataSource. I don't know why I have to set it to null first, but it solved my problem. So my updated code is as follows:
private void PopulateUI()
{
if (zoneCollectionAppended != null)
{
zoneListBox.DisplayMember = "Zone_Name";
zoneListBox.ValueMember = "Zone_ID";
//DataSource had to be reset to null before updating to new DataSource
zoneListBox.DataSource = null;
zoneListBox.DataSource = zoneCollectionAppended;
}
}
Our users will have a List<EmailRecords> collection, and only one of which will be marked (bool)IsPrimary = true.
I'd like to write Entity Framework code to update this.
Something like this:
UPDATE dbo.EmailRecords
SET IsPrimary = 1
WHERE EmailRecordId = #RecordId
UPDATE dbo.EmailRecords
SET IsPrimary = 0
WHERE EmailRecordId != #RecordId
AND ParentRecordId = #ParentRecordId
My object is:
public class EmailRecords
{
public int EmailRecordId { get; set; }
public int ParentRecordId { get; set; }
public string EmailAddress { get; set; }
public bool IsPrimary { get; set; }
}
How can I do this with Entity Framework?
I was thinking about doing something like this:
foreach (var thisRecord in profile.EmailRecords)
{
if (thisRecord.EmailRecordId == thisId)
{
thisRecord.IsPrimary = true;
}
else
{
thisRecord.IsPrimary = false;
}
}
db.SaveChanges();
Is there a cleaner way to do this?
Are you looking for C# code, something along these lines?
foreach(var record in profile.EmailRecords)
{
record.IsPrimary = record.EmailRecordId == recordId;
}
Using this example model you've given.
public class EmailRecords
{
public int EmailRecordId { get; set; }
public int ParentRecordId { get; set; }
public string EmailAddress { get; set; }
public bool IsPrimary { get; set; }
}
You can unset this primary behavior using this combination of LINQ and code.
// Change this Int32 to match your #RecordId and #ParentRecordId. Possibly parameterize this entire code snippet into a method.
Int32 recordIdToChange = 1;
Int32 parentRecordIdToChange = 1;
// Set the new primary.
EmailRecords emailRecordToSetToPrimary = profile.EmailRecords.Where(cs => cs.EmailRecordId == recordIdToChange).FirstOrDefault();
if (emailRecordToSetToPrimary != null){
emailRecordToSetToPrimary.IsPrimary = true;
}
// Only unset those records whose id does not match the new primary AND is currently set as a primary.
List<EmailRecords> emailRecordsToUnsetFromPrimary = profile.EmailRecords.Where(cs => cs.EmailRecordId != recordIdToChange && cs.IsPrimary == true && cs.ParentRecordId == parentRecordIdToChange).ToList();
foreach (EmailRecords emailRecordToUnsetFromPrimary in emailRecordsToUnsetFromPrimary){
emailRecordToUnsetFromPrimary.IsPrimary = false;
}
// Perform your save on the emailRecords list collection.