Fix price list parsing crashes and invoice grid initialization.
Harden UCPriceList number parsing and selection handling after download, guard ModernDataGridView row header autosize, and refresh price list from menu load action. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
5cc202dea7
commit
0c73d7e40b
Binary file not shown.
Binary file not shown.
@ -3,5 +3,6 @@
|
||||
1. Распакуйте архив в любую папку.
|
||||
2. Запустите `Рлектронная Фармация.exe`.
|
||||
3. РџСЂРё первом запуске выполните авторизацию (меню РђР’РўРћР РР—РђР¦РРЇ).
|
||||
4. Укажите Location ID точки в настройках авторизации.
|
||||
|
||||
База данных: `efClient.db` (рядом с exe).
|
||||
База данных: `Data\efClient.db` (или `efClient.db` рядом с exe).
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<T>(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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user