diff --git a/dist/Электронная-Фармация/Elfisa.UI.dll b/dist/Электронная-Фармация/Elfisa.UI.dll index 061485b..cb04318 100644 Binary files a/dist/Электронная-Фармация/Elfisa.UI.dll and b/dist/Электронная-Фармация/Elfisa.UI.dll differ diff --git a/dist/Электронная-Фармация/Elfisa.UI.pdb b/dist/Электронная-Фармация/Elfisa.UI.pdb index ee64690..af1bdf3 100644 Binary files a/dist/Электронная-Фармация/Elfisa.UI.pdb and b/dist/Электронная-Фармация/Elfisa.UI.pdb differ diff --git a/dist/Электронная-Фармация/README.md b/dist/Электронная-Фармация/README.md index cd24f32..74f8982 100644 --- a/dist/Электронная-Фармация/README.md +++ b/dist/Электронная-Фармация/README.md @@ -3,5 +3,6 @@ 1. Распакуйте архив РІ любую папку. 2. Запустите `Электронная Фармация.exe`. 3. РџСЂРё первом запуске выполните авторизацию (меню АВТОРИЗАЦИЯ). +4. Укажите Location ID точки РІ настройках авторизации. -База данных: `efClient.db` (СЂСЏРґРѕРј СЃ exe). +База данных: `Data\efClient.db` (или `efClient.db` СЂСЏРґРѕРј СЃ exe). diff --git a/dist/Электронная-Фармация/Электронная Фармация.exe b/dist/Электронная-Фармация/Электронная Фармация.exe index 5752129..77e7afe 100644 Binary files a/dist/Электронная-Фармация/Электронная Фармация.exe and b/dist/Электронная-Фармация/Электронная Фармация.exe differ diff --git a/dist/Электронная-Фармация/Электронная Фармация.pdb b/dist/Электронная-Фармация/Электронная Фармация.pdb index 7414a35..6616477 100644 Binary files a/dist/Электронная-Фармация/Электронная Фармация.pdb and b/dist/Электронная-Фармация/Электронная Фармация.pdb differ diff --git a/src/ElectronicPharmacy/Form1.cs b/src/ElectronicPharmacy/Form1.cs index 93323d3..da97301 100644 --- a/src/ElectronicPharmacy/Form1.cs +++ b/src/ElectronicPharmacy/Form1.cs @@ -210,17 +210,27 @@ namespace Электронная_Фармация HF_DownloadDataFromServer hF_DownloadDataFromServer = new HF_DownloadDataFromServer(); UiThemeHelper.ApplyToControlTree(hF_DownloadDataFromServer); + DialogResult downloadResult = DialogResult.Cancel; if (countDataTempOrder > 0) { DialogResult drShowDataDownload = UiDialogs.ConfirmYesNoCancel("В корзине найдены товары. При обновлении прайса она будет очищена.\nПродолжить?", "ТОВАРЫ В КОРЗИНЕ", this); if(drShowDataDownload == DialogResult.Yes) { - hF_DownloadDataFromServer.ShowDialog(); + downloadResult = hF_DownloadDataFromServer.ShowDialog(); } } else { - hF_DownloadDataFromServer.ShowDialog(); + downloadResult = hF_DownloadDataFromServer.ShowDialog(); + } + + if (downloadResult == DialogResult.OK) + { + RefreshOpenPriceLists(); + } + else if (!HasDocumentTabs()) + { + loadDefaultPriceList(); } } diff --git a/src/ElectronicPharmacy/UserControls/UCPriceList.cs b/src/ElectronicPharmacy/UserControls/UCPriceList.cs index c6d4092..4a7b5b4 100644 --- a/src/ElectronicPharmacy/UserControls/UCPriceList.cs +++ b/src/ElectronicPharmacy/UserControls/UCPriceList.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; +using System.Globalization; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -35,6 +36,7 @@ namespace Электронная_Фармация.UserControls decimal _percentageAsDefault; string _selectedSupplierFilter = string.Empty; bool _suppressSupplierFilterEvents; + bool _suppressPriceListSelectionEvents; int _committedSupplierFilterIndex; string connectionStringToLocalDB = AppConfig.SqliteConnectionString; @@ -275,41 +277,53 @@ namespace Электронная_Фармация.UserControls tablePrice.Columns[10].ColumnName = "Сумма"; tablePrice.Columns[12].ColumnName = "ИДПрайсЛистАйтем"; - bsPriceList.DataSource = tablePrice; - dgvPriceList.DataSource = bsPriceList; - dgvPriceList.AutoGenerateColumns = true; - dgvPriceList.Font = new Font("Segoe UI", 13, FontStyle.Regular); + try + { + _suppressPriceListSelectionEvents = true; + bsPriceList.DataSource = tablePrice; + dgvPriceList.DataSource = bsPriceList; + dgvPriceList.AutoGenerateColumns = true; + dgvPriceList.Font = new Font("Segoe UI", 13, FontStyle.Regular); - dgvPriceList.Columns[0].Visible = false; - dgvPriceList.Columns[1].Visible = false; - dgvPriceList.Columns[2].Visible = false; - dgvPriceList.Columns[7].Visible = true; - dgvPriceList.Columns[8].Visible = false; - dgvPriceList.Columns[11].Visible = false; - dgvPriceList.Columns[12].Visible = false; + dgvPriceList.Columns[0].Visible = false; + dgvPriceList.Columns[1].Visible = false; + dgvPriceList.Columns[2].Visible = false; + dgvPriceList.Columns[7].Visible = true; + dgvPriceList.Columns[8].Visible = false; + dgvPriceList.Columns[11].Visible = false; + dgvPriceList.Columns[12].Visible = false; - dgvPriceList.Columns[3].Width = 760; - dgvPriceList.Columns[4].Width = 150; - dgvPriceList.Columns[5].Width = 120; - dgvPriceList.Columns[6].Width = 100; - dgvPriceList.Columns[7].Width = 140; - dgvPriceList.Columns[9].Width = 100; - dgvPriceList.Columns[10].Width = 100; + dgvPriceList.Columns[3].Width = 760; + dgvPriceList.Columns[4].Width = 150; + dgvPriceList.Columns[5].Width = 120; + dgvPriceList.Columns[6].Width = 100; + dgvPriceList.Columns[7].Width = 140; + dgvPriceList.Columns[9].Width = 100; + dgvPriceList.Columns[10].Width = 100; + + if (dgvPriceList.Rows.Count > 0) + { + dgvPriceList.ClearSelection(); + } + } + finally + { + _suppressPriceListSelectionEvents = false; + ShowMePriceWithMarkupPercentForSelectedGood(); + } } void loadInfoAboutDefaultMarkup() { - decimal percentageMarkupDefault = Convert.ToDecimal(Properties.Settings.Default.IntDefaultPercentMarkup); - - if (percentageMarkupDefault == 0) + var percentageMarkupDefault = Properties.Settings.Default.IntDefaultPercentMarkup; + if (percentageMarkupDefault <= 0) { percentageMarkupDefault = 30; } _percentageAsDefault = percentageMarkupDefault; - numericPercent.Value = Convert.ToDecimal(Properties.Settings.Default.IntDefaultPercentMarkup); - + numericPercent.Value = Math.Max(numericPercent.Minimum, Math.Min(numericPercent.Maximum, percentageMarkupDefault)); } public void loadSupplierTabs(string SupplierName) @@ -865,30 +879,42 @@ and tempOrder.GoodName = PriceList.GoodName (e.KeyChar >= (Char)Keys.NumPad1 && e.KeyChar <= (Char)Keys.NumPad9) || (e.KeyChar == (Char)Keys.D0 && dgvPriceList.Rows[RowIndex].Cells[10].Value.ToString().Length > 1) || (e.KeyChar == (Char)Keys.NumPad0 && dgvPriceList.Rows[RowIndex].Cells[10].Value.ToString().Length > 1)) { - int QuantityForSale = Convert.ToInt32(dgvPriceList.Rows[RowIndex].Cells[6].Value.ToString()); + if (!TryReadInt32(dgvPriceList.Rows[RowIndex].Cells[6].Value, out var quantityForSale)) + { + return; + } stringIWantBuy = dgvPriceList.Rows[RowIndex].Cells[9].Value.ToString() + e.KeyChar.ToString(); - int IWantBuy = Convert.ToInt32(stringIWantBuy); - - if (IWantBuy <= QuantityForSale) + if (!TryReadInt32(stringIWantBuy, out var iWantBuy)) { - dgvPriceList.Rows[RowIndex].Cells[9].Value = IWantBuy.ToString(); - - decimal PriceForOne = Convert.ToDecimal(dgvPriceList.Rows[RowIndex].Cells[5].Value.ToString()); - decimal sumOrder = IWantBuy * PriceForOne; - dgvPriceList.Rows[RowIndex].Cells[10].Value = sumOrder.ToString(); + return; } - else if (IWantBuy > QuantityForSale) + + if (iWantBuy <= quantityForSale) { - DialogResult drIWantBuyAll = UiDialogs.ConfirmYesNoCancel($"Для заказа доступно только {QuantityForSale.ToString()}. Заказать доступное количество?", "Заказ", FindForm()); + dgvPriceList.Rows[RowIndex].Cells[9].Value = iWantBuy.ToString(); + + if (!TryReadDecimal(dgvPriceList.Rows[RowIndex].Cells[5].Value, out var priceForOne)) + { + return; + } + + dgvPriceList.Rows[RowIndex].Cells[10].Value = (iWantBuy * priceForOne).ToString(); + } + else if (iWantBuy > quantityForSale) + { + DialogResult drIWantBuyAll = UiDialogs.ConfirmYesNoCancel($"Для заказа доступно только {quantityForSale.ToString()}. Заказать доступное количество?", "Заказ", FindForm()); if (drIWantBuyAll == DialogResult.Yes) { - dgvPriceList.Rows[RowIndex].Cells[9].Value = QuantityForSale.ToString(); + dgvPriceList.Rows[RowIndex].Cells[9].Value = quantityForSale.ToString(); - decimal PriceForOne = Convert.ToDecimal(dgvPriceList.Rows[RowIndex].Cells[5].Value.ToString()); - decimal sumOrder = QuantityForSale * PriceForOne; - dgvPriceList.Rows[RowIndex].Cells[10].Value = sumOrder.ToString(); + if (!TryReadDecimal(dgvPriceList.Rows[RowIndex].Cells[5].Value, out var priceForOne)) + { + return; + } + + dgvPriceList.Rows[RowIndex].Cells[10].Value = (quantityForSale * priceForOne).ToString(); } } } @@ -908,9 +934,13 @@ and tempOrder.GoodName = PriceList.GoodName dgvPriceList.Rows[RowIndex].Cells[9].Value = result; - decimal PriceForOne = Convert.ToDecimal(dgvPriceList.Rows[RowIndex].Cells[5].Value.ToString()); - decimal sumOrder = Convert.ToDecimal(result) * PriceForOne; - dgvPriceList.Rows[RowIndex].Cells[10].Value = sumOrder.ToString(); + if (!TryReadDecimal(dgvPriceList.Rows[RowIndex].Cells[5].Value, out var priceForOne) || + !TryReadInt32(result, out var count)) + { + return; + } + + dgvPriceList.Rows[RowIndex].Cells[10].Value = (count * priceForOne).ToString(); } } else if (e.KeyChar == (Char)Keys.Delete) @@ -928,7 +958,7 @@ and tempOrder.GoodName = PriceList.GoodName foreach (DataGridViewRow row in dgvPriceList.Rows) { - if (Convert.ToInt32(row.Cells[9].Value) == 0) + if (TryReadInt32(row.Cells[9].Value, out var orderedCount) && orderedCount == 0) { int rowIndex = row.Index; deleteGood(rowIndex, idPriceListItem); @@ -1197,30 +1227,229 @@ and SumOrderedItems = '{SumOrder}'"; void ShowMePriceWithMarkupPercentForSelectedGood() { - if(dgvPriceList.RowCount > 0) + try { - lblSelectedGoodName.Text = dgvPriceList.CurrentRow.Cells[3].Value.ToString(); + var currentRow = dgvPriceList.CurrentRow; + if (currentRow == null || currentRow.IsNewRow) + { + lblSelectedGoodName.Text = string.Empty; + lblPriceForGood.Text = string.Empty; + return; + } + var nameCell = currentRow.Cells[3].Value; + lblSelectedGoodName.Text = nameCell == null || nameCell == DBNull.Value + ? string.Empty + : nameCell.ToString(); - double priceForGood = Convert.ToDouble(dgvPriceList.CurrentRow.Cells[5].Value.ToString()); - double MarkupPercentage = Convert.ToDouble(numericPercent.Value); + if (!TryReadDouble(currentRow.Cells[5].Value, out var priceForGood)) + { + lblPriceForGood.Text = string.Empty; + return; + } - double priceWithPercentage = priceForGood + (priceForGood / 100 * MarkupPercentage); - lblPriceForGood.Text = $"= {priceWithPercentage.ToString()} руб"; + var markupPercentage = (double)numericPercent.Value; + var priceWithPercentage = priceForGood + (priceForGood / 100 * markupPercentage); + lblPriceForGood.Text = $"= {priceWithPercentage} руб"; } + catch + { + lblSelectedGoodName.Text = string.Empty; + lblPriceForGood.Text = string.Empty; + } + } + + private static bool TryReadDouble(object value, out double result) + { + return TryReadNumber(value, out result); + } + + private static bool TryReadDecimal(object value, out decimal result) + { + return TryReadNumber(value, out result); + } + + private static bool TryReadInt32(object value, out int result) + { + return TryReadNumber(value, out result); + } + + private static bool TryReadNumber(object value, out T result) where T : struct + { + result = default; + + if (value == null || value == DBNull.Value) + { + return false; + } + + if (value is T typedValue) + { + result = typedValue; + return true; + } + + if (value is decimal decimalValue && typeof(T) == typeof(double)) + { + result = (T)(object)(double)decimalValue; + return true; + } + + if (value is double doubleValue && typeof(T) == typeof(decimal)) + { + result = (T)(object)(decimal)doubleValue; + return true; + } + + if (value is float floatValue && typeof(T) == typeof(double)) + { + result = (T)(object)(double)floatValue; + return true; + } + + if (value is float floatValueDecimal && typeof(T) == typeof(decimal)) + { + result = (T)(object)(decimal)floatValueDecimal; + return true; + } + + var text = NormalizeNumberText(value.ToString()); + if (string.IsNullOrEmpty(text)) + { + return false; + } + + if (typeof(T) == typeof(double)) + { + if (double.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out var invariantDouble)) + { + result = (T)(object)invariantDouble; + return true; + } + + if (double.TryParse(text, NumberStyles.Number, CultureInfo.CurrentCulture, out var currentDouble)) + { + result = (T)(object)currentDouble; + return true; + } + + if (double.TryParse(text.Replace(',', '.'), NumberStyles.Number, CultureInfo.InvariantCulture, out var normalizedDouble)) + { + result = (T)(object)normalizedDouble; + return true; + } + + return false; + } + + if (typeof(T) == typeof(decimal)) + { + if (decimal.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out var invariantDecimal)) + { + result = (T)(object)invariantDecimal; + return true; + } + + if (decimal.TryParse(text, NumberStyles.Number, CultureInfo.CurrentCulture, out var currentDecimal)) + { + result = (T)(object)currentDecimal; + return true; + } + + if (decimal.TryParse(text.Replace(',', '.'), NumberStyles.Number, CultureInfo.InvariantCulture, out var normalizedDecimal)) + { + result = (T)(object)normalizedDecimal; + return true; + } + + return false; + } + + if (typeof(T) == typeof(int)) + { + if (int.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var invariantInt)) + { + result = (T)(object)invariantInt; + return true; + } + + if (int.TryParse(text, NumberStyles.Integer, CultureInfo.CurrentCulture, out var currentInt)) + { + result = (T)(object)currentInt; + return true; + } + } + + return false; + } + + private static string NormalizeNumberText(string text) + { + if (string.IsNullOrWhiteSpace(text)) + { + return string.Empty; + } + + text = text.Trim().Replace('\u00A0', ' ').Replace(" ", string.Empty).Replace(',', '.'); + var builder = new StringBuilder(); + var started = false; + var hasDecimalSeparator = false; + + foreach (var ch in text) + { + if (char.IsDigit(ch)) + { + builder.Append(ch); + started = true; + continue; + } + + if (ch == '.' && started && !hasDecimalSeparator) + { + builder.Append(ch); + hasDecimalSeparator = true; + continue; + } + + if (ch == '-' && !started) + { + builder.Append(ch); + continue; + } + + if (started) + { + break; + } + } + + return builder.ToString(); } private void dgvPriceList_SelectionChanged(object sender, EventArgs e) { - SumIWantBuy = string.Empty; - - if (timerForResetSearch.Enabled == true) + if (_suppressPriceListSelectionEvents) { - timerForResetSearch.Enabled = false; - timerForResetSearch.Stop(); + return; } - ShowMePriceWithMarkupPercentForSelectedGood(); + try + { + SumIWantBuy = string.Empty; + + if (timerForResetSearch.Enabled == true) + { + timerForResetSearch.Enabled = false; + timerForResetSearch.Stop(); + } + + ShowMePriceWithMarkupPercentForSelectedGood(); + } + catch + { + lblSelectedGoodName.Text = string.Empty; + lblPriceForGood.Text = string.Empty; + } } diff --git a/src/Elfisa.UI/Controls/ModernDataGridView.cs b/src/Elfisa.UI/Controls/ModernDataGridView.cs index b7c4361..7320f8d 100644 --- a/src/Elfisa.UI/Controls/ModernDataGridView.cs +++ b/src/Elfisa.UI/Controls/ModernDataGridView.cs @@ -22,7 +22,9 @@ namespace Elfisa.UI.Controls AllowUserToResizeRows = false; AllowUserToResizeColumns = true; AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None; + AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None; ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing; + RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing; ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.None; DoubleBuffered = true; SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw, true); @@ -30,6 +32,42 @@ namespace Elfisa.UI.Controls ApplyTheme(ThemeManager.Colors); } + public new DataGridViewAutoSizeRowsMode AutoSizeRowsMode + { + get => base.AutoSizeRowsMode; + set => base.AutoSizeRowsMode = NormalizeAutoSizeRowsMode(value); + } + + public new DataGridViewRowHeadersWidthSizeMode RowHeadersWidthSizeMode + { + get => base.RowHeadersWidthSizeMode; + set => base.RowHeadersWidthSizeMode = NormalizeRowHeadersWidthSizeMode(value); + } + + private DataGridViewAutoSizeRowsMode NormalizeAutoSizeRowsMode(DataGridViewAutoSizeRowsMode value) + { + if (!RowHeadersVisible && + (value == DataGridViewAutoSizeRowsMode.DisplayedHeaders || + value == DataGridViewAutoSizeRowsMode.AllHeaders)) + { + return DataGridViewAutoSizeRowsMode.None; + } + + return value; + } + + private DataGridViewRowHeadersWidthSizeMode NormalizeRowHeadersWidthSizeMode( + DataGridViewRowHeadersWidthSizeMode value) + { + if (!RowHeadersVisible && + value == DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders) + { + return DataGridViewRowHeadersWidthSizeMode.DisableResizing; + } + + return value; + } + private void ApplyBorderStyles(ThemeColors theme) { GridColor = theme.GridBorder;