From 8e140a7131e9ffbcedf620c402c1e5bc565ffef9 Mon Sep 17 00:00:00 2001 From: Garritt McCune Date: Tue, 8 Nov 2016 02:24:58 -0600 Subject: [PATCH] Set up Invoice DataGridView event handlers to validate user input and provide basic formatting for the contents of the cells. Updated the week ending masked text box to get a parsed DateTime value, just to make it look pretty. --- .../AdvertisingProfitControlTableHelper.cs | 12 + AdvertsingProfitControl/NewAddRecord.cs | 258 +++++++++++++++--- .../bin/Debug/APCDatabase.accdb | Bin 2932736 -> 2932736 bytes .../Debug/AdvertsingProfitControl.application | 2 +- .../AdvertsingProfitControl.exe.manifest | 4 +- ...AdvertsingProfitControl.vshost.application | 2 +- ...dvertsingProfitControl.vshost.exe.manifest | 4 +- .../Debug/AdvertsingProfitControl.application | 2 +- .../AdvertsingProfitControl.exe.manifest | 4 +- 9 files changed, 243 insertions(+), 45 deletions(-) diff --git a/AdvertsingProfitControl/AdvertisingProfitControlTableHelper.cs b/AdvertsingProfitControl/AdvertisingProfitControlTableHelper.cs index 99d8e3d..b5dfdd2 100644 --- a/AdvertsingProfitControl/AdvertisingProfitControlTableHelper.cs +++ b/AdvertsingProfitControl/AdvertisingProfitControlTableHelper.cs @@ -288,6 +288,18 @@ namespace AdvertsingProfitControl IsInDatabase = 11 } + public enum InvoiceTableColumns + { + Id = 0, + InvoiceDate = 1, + Supplier = 2, + InvoiceNumber = 3, + InvoiceNetAmountAtCost = 4, + InvoiceNetAmount = 5, + InvoiceNote = 6, + IsDirty = 7 + } + public enum TrimmingOperationResult { FailedToTrim = 0, diff --git a/AdvertsingProfitControl/NewAddRecord.cs b/AdvertsingProfitControl/NewAddRecord.cs index 7a5f789..7b20a0c 100644 --- a/AdvertsingProfitControl/NewAddRecord.cs +++ b/AdvertsingProfitControl/NewAddRecord.cs @@ -14,14 +14,13 @@ namespace AdvertsingProfitControl { private static readonly FrmLogConsole LogConsole = FrmLogConsole.GetStaticInstance; //Create an array that contains all the ad items from the database. - //private read only Dictionary _adItemCollectionDictionary; private readonly List _adItemCollection; //This object contains all the unused ad items. private AutoCompleteStringCollection _trimmedAdItemCollection = new AutoCompleteStringCollection(); //Contains all the ad specials that are in the database (i.e. "Daily Coupons"). private readonly AutoCompleteStringCollection _adSpecialList; //This object contains all the suppliers that were found in the database. - private AutoCompleteStringCollection _supplierCollection; + private readonly AutoCompleteStringCollection _supplierCollection; //This array keeps track of the number of times an Ad Item is used, if used once then it may only be used AFTER an AdSpecialRow and only once after that. //Once an item has been used twice, it will not appear again in the AutoCompleteSuggestions. //The structure of the used ad item list is as follows: @@ -32,8 +31,6 @@ namespace AdvertsingProfitControl private string _beginningCellValue = ""; //Flag showing whether or not the AdSpecialRow has been made in this session. private int _adSpecialIndex = -1; - //Set the starting value for temporary IDs for ad items that have yet to be added to the database. - //private int _temporaryKey; private readonly AdvertisingProfitControlTableHelper _tableHelperFunctions = new AdvertisingProfitControlTableHelper(); //Set flags to indicate whether or not a DataGridView needs to be painted. private bool _projectionsRequirePainting; @@ -97,9 +94,193 @@ namespace AdvertsingProfitControl mainTabControl.SelectedIndexChanged += PaintDataGridViewOnTabPageChange; //After all events have been set, construct the DataGridVeiws for use. ConstructApcDataGridViews(); + //Set-up events for the Invoice table. + invoicesDataGridView.CellEnter += StoreBeginningCellValue; + //Validate that the row the user is trying to leave is legal (has at least an ad item entered) and prevent the user from leaving the row is its not. + invoicesDataGridView.RowValidating += ValidateInvoiceRow; + //Validate, clean and format the contents of the cell that fires the cell validating event. + invoicesDataGridView.CellValidating += ValidateInvoicesCellContents; + //Grab the underlying text box object in the ad item cell, and build an auto complete list for the user. + invoicesDataGridView.EditingControlShowing += DisplaySupplierAutoComleteOnEditingShadowControl; + //Finally build the last DataGridView for the form. ConstructInvoicesDataGridView();//No weekly sales table is nice. } + #region Invoice Table Events + + /// + /// Event Used: RowValidating + /// Validates that the row has required information, namely an invoice date, number and supplier. + /// + /// + /// + private void ValidateInvoiceRow(object sender, DataGridViewCellCancelEventArgs e) + { + var dataGridView = (DataGridView) sender; + if (dataGridView.Rows[e.RowIndex].IsNewRow) return; + //Check to make sure the Invoice Date, Invoice Number and the Supplier values are set. + if (dataGridView.Rows[e.RowIndex].Cells[(int) InvoiceTableColumns.InvoiceDate].EditedFormattedValue.ToString() == "") + { + MessageBox.Show(@"An invoice date must be specified.", @"Invalid Invoice Date", MessageBoxButtons.OK, MessageBoxIcon.Error); + e.Cancel = true; + dataGridView.CurrentCell = dataGridView.Rows[e.RowIndex].Cells[(int)InvoiceTableColumns.InvoiceDate]; + return; + } + + if (dataGridView.Rows[e.RowIndex].Cells[(int)InvoiceTableColumns.Supplier].EditedFormattedValue.ToString() == "") + { + MessageBox.Show(@"A supplier must be specified.", @"Invalid Supplier", MessageBoxButtons.OK, MessageBoxIcon.Error); + e.Cancel = true; + dataGridView.CurrentCell = dataGridView.Rows[e.RowIndex].Cells[(int) InvoiceTableColumns.Supplier]; + return; + } + + if (dataGridView.Rows[e.RowIndex].Cells[(int) InvoiceTableColumns.InvoiceNumber].EditedFormattedValue.ToString() == "") + { + MessageBox.Show(@"An invoice number must be specified.", @"Invalid Invoice Number", MessageBoxButtons.OK, MessageBoxIcon.Error); + dataGridView.CurrentCell = dataGridView.Rows[e.RowIndex].Cells[(int)InvoiceTableColumns.InvoiceNumber]; + e.Cancel = true; + } + } + + /// + /// Event Used: CellValidating + /// Verifies the contents of the invoice table's cells. Also applies formating where needed. + /// + /// + /// + private void ValidateInvoicesCellContents(object sender, DataGridViewCellValidatingEventArgs e) + { + //Grab the DataGirdView that fired the event and make it into a local variable. + var dataGridView = (DataGridView)sender; + var userInput = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString().Trim(); + var textInfo = new CultureInfo("en-US", false).TextInfo; + //Check for isNewRow if it is, return no need to check it for anything. + if (dataGridView.Rows[e.RowIndex].IsNewRow) + { + return; + } + //Mark the row as dirty assuming the user made changes + if (userInput != _beginningCellValue) + { + dataGridView.Rows[e.RowIndex].Cells[(int) InvoiceTableColumns.IsDirty].Value = true; + } + else + { + return; + } + //Check to see if we're in the invoice date column make sure the date is valid. + switch (e.ColumnIndex) + { + case (int) InvoiceTableColumns.InvoiceDate: + //Clear any error text a cell has for this column. + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = ""; + if (userInput != "") + { + DateTime date; + //Try parsing the date to make sure its valid, otherwise clear it from the cell and inform the user. + if (DateTime.TryParse(userInput, out date)) + { + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = date.ToString("MM/dd/yyyy"); + } + else + { + MessageBox.Show(@"The date '" + userInput + @"' is not a valid date.", @"Invalid Date", MessageBoxButtons.OK, MessageBoxIcon.Error); + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "Invoice Date Must be in a Valid Format"; + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = ""; + } + } + else + { + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = ""; + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "An Invoice Date is Required"; + } + break; + case (int) InvoiceTableColumns.InvoiceNumber: + //Clear any error text a cell has for this column. + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = ""; + if (userInput != "") + { + long parsedNumber; + if (long.TryParse(userInput, out parsedNumber)) + { + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = parsedNumber; + } + else + { + MessageBox.Show(@"The invoice number must be a numeric value.", @"Non Numeric Invoice Number", MessageBoxButtons.OK, MessageBoxIcon.Error); + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = ""; + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "Invoice Number Must be Numeric"; + } + } + else + { + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = ""; + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "An Invoice Number is Required"; + } + break; + case (int) InvoiceTableColumns.Supplier: + //Clear any error text a cell has for this column. + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = ""; + if (userInput != "") + { + //TODO: Create a custom engine to do this. + //Pretty up the entered text since there is something here. + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = textInfo.ToTitleCase(userInput); + } + else + { + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = ""; + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "A Supplier is Required"; + } + break; + default: + //Should only process the InvoiceNetAmountAtCost and InvoiceNetAmount columns. + if (e.ColumnIndex != (int) InvoiceTableColumns.Id && + e.ColumnIndex < (int) InvoiceTableColumns.InvoiceNote) + { + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = ""; + //Now check to make sure the user input isn't null + //Math.Round(parsedNumber, 2).ToString("N", new CultureInfo("en-US")); + if (userInput != "") + { + double parsedNumber; + if (double.TryParse(userInput, out parsedNumber)) + { + //Since the input is a number format it to show the cents and display it. + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = Math.Round(parsedNumber, 2).ToString("N", new CultureInfo("en-US")); + } + else + { + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = ""; + dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "Only Numeric Values Allowed."; + } + } + } + break; + } + dataGridView.RefreshEdit(); + } + + /// + /// Event Used: EditingShadowControlShowing + /// Adds an auto-complete list of suppliers to the Suppliers cell. + /// + /// + /// + private void DisplaySupplierAutoComleteOnEditingShadowControl(object sender, DataGridViewEditingControlShowingEventArgs e) + { + var dataGridView = (DataGridView) sender; + var autoText = e.Control as TextBox; + if (autoText == null) return; + if (!(e.Control is DataGridViewTextBoxEditingControl) || dataGridView.CurrentCell.ColumnIndex != (int) InvoiceTableColumns.Supplier) return; + autoText.AutoCompleteMode = AutoCompleteMode.Suggest; + autoText.AutoCompleteSource = AutoCompleteSource.CustomSource; + autoText.AutoCompleteCustomSource = _supplierCollection; + } + + #endregion + private void PaintDataGridViewOnTabPageChange(object sender, EventArgs e) { var helper = new AdvertisingProfitControlTableHelper(); @@ -398,7 +579,7 @@ namespace AdvertsingProfitControl private void ValidateSalesDataGridViewCellContents(object sender, DataGridViewCellValidatingEventArgs e) { //Grab the DataGirdView that fired the event and make it into a local variable. - var dataGridView = ((DataGridView)sender); + var dataGridView = (DataGridView)sender; var userInput = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString(); //TODO: Write a custom parsing engine for detecting when bins are entered. var textInfo = new CultureInfo("en-US", false).TextInfo; @@ -1455,24 +1636,37 @@ namespace AdvertsingProfitControl /// private void ConstructInvoicesDataGridView() { - string[] invoicesColumnNames = { "InvoiceDate", "Supplier", "InvoiceNumber", "InvoiceNetAmountAtCost", "InvoiceNetAmount", "InvoiceNote", "IsDirty", "IsInDatabase"}; + string[] invoicesColumnNames = { "ID", "InvoiceDate", "Supplier", "InvoiceNumber", "InvoiceNetAmountAtCost", "InvoiceNetAmount", "InvoiceNote", "IsDirty"}; foreach (var name in invoicesColumnNames) { - var column = new DataGridViewColumn { Name = name }; if (!name.StartsWith("Is")) { - column.HeaderText = TextFormat.AddSpacesToSentence(name, false); - column.ValueType = typeof(string); + var column = new DataGridViewTextBoxColumn + { + Name = name, + HeaderText = TextFormat.AddSpacesToSentence(name, false), + ValueType = typeof(string), + SortMode = DataGridViewColumnSortMode.NotSortable, + MaxInputLength = 20 + }; + if (name.Contains("ID")) + { + //column.Visible = false; + } + invoicesDataGridView.Columns.Add(column); } else { - column.HeaderText = TextFormat.AddSpacesToSentence(name, false); - column.Visible = false; - column.ValueType = typeof(bool); - } - column.CellTemplate = new DataGridViewTextBoxCell(); - invoicesDataGridView.Columns.Add(column); + var column = new DataGridViewCheckBoxColumn + { + Name = name, + ValueType = typeof(bool), + //Visible = false, + SortMode = DataGridViewColumnSortMode.NotSortable + }; + invoicesDataGridView.Columns.Add(column); + } } } @@ -1530,30 +1724,22 @@ namespace AdvertsingProfitControl private void UpdateCalendarOnFocusLost(object sender, EventArgs e) { //Replace any white space with zeros to pad out the mask. - weekEndingMaskedTextBox.Text = weekEndingMaskedTextBox.Text.Replace(' ', '0'); - //Check to see if the mask is completed, otherwise clear it. - if (weekEndingMaskedTextBox.MaskCompleted) + weekEndingMaskedTextBox.Text = weekEndingMaskedTextBox.Text.Replace("/", ""); + DateTime date; + //Try parsing the contents of the masked text box to see if the date is valid. + if (DateTime.TryParse(weekEndingMaskedTextBox.Text, out date)) { - DateTime date; - //Try parsing the contents of the masked text box to see if the date is valid. - if (DateTime.TryParse(weekEndingMaskedTextBox.Text, out date)) - { - //If it is update the calendar with the manually entered date. - weekEndingMonthCalendar.SelectionStart = date; - } - else - { - //Otherwise throw an error to day that the date isn't valid and clear the text box. - MessageBox.Show(@"The date entered appears to be invalid", @"Invalid Date", MessageBoxButtons.OK, - MessageBoxIcon.Error); - weekEndingMaskedTextBox.Text = ""; - } + //Update the text box's text with a nicely formatted date. + weekEndingMaskedTextBox.Text = date.ToString("MM/dd/yyyy"); + //If it is update the calendar with the manually entered date. + weekEndingMonthCalendar.SelectionStart = date; } else { + //Otherwise throw an error to day that the date isn't valid and clear the text box. + MessageBox.Show(@"The date entered appears to be invalid.", @"Invalid Date", MessageBoxButtons.OK, MessageBoxIcon.Error); weekEndingMaskedTextBox.Text = ""; } - } #endregion @@ -1652,9 +1838,9 @@ namespace AdvertsingProfitControl } //Run the row parsing engine on all the APC tables. //Create the cleaned table objects that will be sent to the database. - var trimmed = new DataTable(); - var update = new DataTable(); - var trimmedProjectionsTable = ConstructCleanedProjectionsTable(dateId, out trimmed, out update); + //var trimmed = new DataTable(); + //var update = new DataTable(); + //var trimmedProjectionsTable = ConstructCleanedProjectionsTable(dateId, out trimmed, out update); //var trimmedInventoryTable = ConstructCleanedInventoryTable(dateId); //var trimmedActualSalesTable = ConstructCleanedActualSalesTable(dateId); //Create the transaction scope. diff --git a/AdvertsingProfitControl/bin/Debug/APCDatabase.accdb b/AdvertsingProfitControl/bin/Debug/APCDatabase.accdb index 9fe8d250f64569ab1baf5bd01b3441e2ee5d0367..661ffc5c722bf30ccca1f913658c3603be662324 100644 GIT binary patch delta 404 zcmZo@*vtsR8<_Yw*<^MyF)=bSGHw>+d(Svofsd_8piO|WO@OIQfO(q$3zGo19d9uM z1V~QjRbVmR?xet?&dbNZz{=nY5ob`?)LyE~vb|K7wfB?!8@^PiFc-u1{zKsm zo4?|G48P}jMSi}`f&y>(w)5$;F)6a{Vqjo6HeED;O^@-=^Z)}6h3Pd8oTA$+1K6hD zXO(1NVDOtRYQV0?=m(Ni-JWT{K2x9hGjH+4h2q;~6gW>XPJfcfuFLAnz~CglT`Y+d(Svofsd_8piO|WO@OIQfO(q$3zGo1I&U!p z1V~NiRbVk@%-o(>%sQWE;)YHhRtA5F6vKh*?WMXb+e>v>dp{{2=SzhOb2D7;KXiWc z`6cJO`76%H@Oz$D+YAF#P}LmXlwUn4{oZnp>=3qTrdA zoRL~A!@$PC$iTdvPoIrRk##o%1H|uW{fM-Ch~MHvK-U6axc; z|8!9Uc0ERakfiGNOau0r`pmC*izhA=XJumH5Kx%@ah_Dw#tp8F(;p37K7FC2ro?oa0`|+3PcQhm{Xrr70yfs;3=BzJ?X4B;?X49Y?X4A@?X49c zK6iU-1y6fx1#f$61z&q>1%G>Mg+P02gZXog-CmAg=l+gg;;xQg?M{w zg+zO6g=Bkcg;aZMg>-vsg-m;Eg=~9kgrjqg-UyC kg=%|ig<5-Sg?f8yg+_a8g=Tweg;slOh4%K=3Y}_q0OB>3tN;K2 diff --git a/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.application b/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.application index e0d94e7..d1418b9 100644 --- a/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.application +++ b/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.application @@ -14,7 +14,7 @@ - a9nSyX771UnNpCxSLQTrqyr+/1DNpDIEZBXaQAVLi88= + LsVCFrHqz9eC+Xb4h5OB0HAtYPeUrflbVosVWeS6Y6M= diff --git a/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.exe.manifest b/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.exe.manifest index 07db5d4..50bd7bc 100644 --- a/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.exe.manifest +++ b/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.exe.manifest @@ -43,14 +43,14 @@ - + - EvD+c0PqPuyMPwSjcVOB4gfL+Q/3iQ2v/e+IKDLio0Y= + iKpPfS5yNYsJ6mqWS0c0RqAtEX1hyz5JzaK7T5nObHU= diff --git a/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.vshost.application b/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.vshost.application index e0d94e7..d1418b9 100644 --- a/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.vshost.application +++ b/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.vshost.application @@ -14,7 +14,7 @@ - a9nSyX771UnNpCxSLQTrqyr+/1DNpDIEZBXaQAVLi88= + LsVCFrHqz9eC+Xb4h5OB0HAtYPeUrflbVosVWeS6Y6M= diff --git a/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.vshost.exe.manifest b/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.vshost.exe.manifest index 07db5d4..50bd7bc 100644 --- a/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.vshost.exe.manifest +++ b/AdvertsingProfitControl/bin/Debug/AdvertsingProfitControl.vshost.exe.manifest @@ -43,14 +43,14 @@ - + - EvD+c0PqPuyMPwSjcVOB4gfL+Q/3iQ2v/e+IKDLio0Y= + iKpPfS5yNYsJ6mqWS0c0RqAtEX1hyz5JzaK7T5nObHU= diff --git a/AdvertsingProfitControl/obj/Debug/AdvertsingProfitControl.application b/AdvertsingProfitControl/obj/Debug/AdvertsingProfitControl.application index e0d94e7..d1418b9 100644 --- a/AdvertsingProfitControl/obj/Debug/AdvertsingProfitControl.application +++ b/AdvertsingProfitControl/obj/Debug/AdvertsingProfitControl.application @@ -14,7 +14,7 @@ - a9nSyX771UnNpCxSLQTrqyr+/1DNpDIEZBXaQAVLi88= + LsVCFrHqz9eC+Xb4h5OB0HAtYPeUrflbVosVWeS6Y6M= diff --git a/AdvertsingProfitControl/obj/Debug/AdvertsingProfitControl.exe.manifest b/AdvertsingProfitControl/obj/Debug/AdvertsingProfitControl.exe.manifest index 07db5d4..50bd7bc 100644 --- a/AdvertsingProfitControl/obj/Debug/AdvertsingProfitControl.exe.manifest +++ b/AdvertsingProfitControl/obj/Debug/AdvertsingProfitControl.exe.manifest @@ -43,14 +43,14 @@ - + - EvD+c0PqPuyMPwSjcVOB4gfL+Q/3iQ2v/e+IKDLio0Y= + iKpPfS5yNYsJ6mqWS0c0RqAtEX1hyz5JzaK7T5nObHU=