Add name/MG browse flow in price list and harden grid hover.

Show names on the left and dosages on the right after selection, then open supplier offers for the chosen pair. Persist TradeName/Dosage on download and avoid crashes when rebinding or pressing Escape.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Magomed 2026-07-16 14:42:30 +03:00
parent c447048b66
commit 74390c4918
4 changed files with 730 additions and 55 deletions

View File

@ -400,6 +400,8 @@ create table if not exists [OrderItems] (
TryAddColumn(conForCheckTables, "Invoice", "SourceOrderId", "integer"); TryAddColumn(conForCheckTables, "Invoice", "SourceOrderId", "integer");
TryAddColumn(conForCheckTables, "Invoice", "SourceOrderNumber", "nvarchar(36)"); TryAddColumn(conForCheckTables, "Invoice", "SourceOrderNumber", "nvarchar(36)");
TryAddColumn(conForCheckTables, "Invoice", "IsRequestedInvoice", "int(1)"); TryAddColumn(conForCheckTables, "Invoice", "IsRequestedInvoice", "int(1)");
TryAddColumn(conForCheckTables, "PriceList", "TradeName", "nvarchar(256)");
TryAddColumn(conForCheckTables, "PriceList", "Dosage", "nvarchar(128)");
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -144,6 +144,18 @@ namespace Электронная_Фармация.HelpForms
}); });
tablePrice.Columns.Add("Zakaz"); tablePrice.Columns.Add("Zakaz");
tablePrice.Columns.Add("SummaZakaza"); tablePrice.Columns.Add("SummaZakaza");
tablePrice.Columns.Add(new DataColumn
{
ColumnName = "TradeName",
DataType = typeof(string),
AllowDBNull = true
});
tablePrice.Columns.Add(new DataColumn
{
ColumnName = "Dosage",
DataType = typeof(string),
AllowDBNull = true
});
if (allSuppliersSummary?.Summary == null) if (allSuppliersSummary?.Summary == null)
{ {
@ -153,18 +165,20 @@ namespace Электронная_Фармация.HelpForms
foreach (var item in allSuppliersSummary.Summary) foreach (var item in allSuppliersSummary.Summary)
{ {
var row = tablePrice.NewRow(); var row = tablePrice.NewRow();
row["supplier_price_id"] = item.SupplierPriceID.ToString(); row["supplier_price_id"] = item.SupplierPriceID ?? string.Empty;
row["guid_es"] = item.GuidEs.ToString(); row["guid_es"] = item.GuidEs ?? string.Empty;
row["es_code"] = item.EsCode.ToString(); row["es_code"] = item.EsCode?.ToString() ?? "0";
row["supplier_id"] = item.SupplierId.ToString(); row["supplier_id"] = item.SupplierId ?? string.Empty;
row["DrugName"] = item.DrugName.ToString(); row["DrugName"] = item.DrugName ?? string.Empty;
row["SupplierName"] = item.SupplierName.ToString(); row["SupplierName"] = item.SupplierName ?? string.Empty;
row["Price"] = item.Price.ToString(); row["Price"] = item.Price?.ToString() ?? string.Empty;
row["Quantity"] = item.Quantity.ToString(); row["Quantity"] = item.Quantity?.ToString() ?? string.Empty;
row["ExpiryPeriod"] = item.ExpiryPeriod == null ? (object)DBNull.Value : item.ExpiryPeriod.ToString(); row["ExpiryPeriod"] = item.ExpiryPeriod == null ? (object)DBNull.Value : item.ExpiryPeriod;
row["Description"] = item.Description == null ? (object)DBNull.Value : item.Description.ToString(); row["Description"] = item.Description == null ? (object)DBNull.Value : item.Description;
row["Zakaz"] = string.Empty; row["Zakaz"] = string.Empty;
row["SummaZakaza"] = string.Empty; row["SummaZakaza"] = string.Empty;
row["TradeName"] = string.IsNullOrWhiteSpace(item.TradeName) ? (object)DBNull.Value : item.TradeName.Trim();
row["Dosage"] = string.IsNullOrWhiteSpace(item.Dosage) ? (object)DBNull.Value : item.Dosage.Trim();
tablePrice.Rows.Add(row); tablePrice.Rows.Add(row);
} }
@ -187,7 +201,9 @@ namespace Электронная_Фармация.HelpForms
[Description], [Description],
[Zakaz], [Zakaz],
[SummaZakaza], [SummaZakaza],
[supplier_price_id] [supplier_price_id],
[TradeName],
[Dosage]
) )
VALUES VALUES
( (
@ -202,7 +218,9 @@ VALUES
@Description, @Description,
@Zakaz, @Zakaz,
@SummaZakaza, @SummaZakaza,
@supplier_price_id @supplier_price_id,
@TradeName,
@Dosage
)"; )";
using (var sqliteCon = new SQLiteConnection(_connectionStringToLocalDb)) using (var sqliteCon = new SQLiteConnection(_connectionStringToLocalDb))
@ -234,6 +252,8 @@ VALUES
cmd.Parameters.AddWithValue("@Zakaz", row["Zakaz"]); cmd.Parameters.AddWithValue("@Zakaz", row["Zakaz"]);
cmd.Parameters.AddWithValue("@SummaZakaza", row["SummaZakaza"]); cmd.Parameters.AddWithValue("@SummaZakaza", row["SummaZakaza"]);
cmd.Parameters.AddWithValue("@supplier_price_id", row["supplier_price_id"]); cmd.Parameters.AddWithValue("@supplier_price_id", row["supplier_price_id"]);
cmd.Parameters.AddWithValue("@TradeName", row.Table.Columns.Contains("TradeName") ? row["TradeName"] : DBNull.Value);
cmd.Parameters.AddWithValue("@Dosage", row.Table.Columns.Contains("Dosage") ? row["Dosage"] : DBNull.Value);
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
} }

View File

@ -6,6 +6,7 @@ using System.Drawing;
using System.Globalization; using System.Globalization;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Windows.Forms; using System.Windows.Forms;
using System.Data.SQLite; using System.Data.SQLite;
@ -37,7 +38,26 @@ namespace Электронная_Фармация.UserControls
string _selectedSupplierFilter = string.Empty; string _selectedSupplierFilter = string.Empty;
bool _suppressSupplierFilterEvents; bool _suppressSupplierFilterEvents;
bool _suppressPriceListSelectionEvents; bool _suppressPriceListSelectionEvents;
bool _suppressBrowseEvents;
int _committedSupplierFilterIndex; int _committedSupplierFilterIndex;
DataTable _fullPriceTable;
PriceBrowseMode _browseMode = PriceBrowseMode.Browse;
string _selectedBaseName = string.Empty;
string _selectedMg = string.Empty;
int _browseSplitterDistance = 0;
ModernSplitContainer splitNameMgBrowse;
ModernDataGridView dgvBrowseNames;
ModernDataGridView dgvBrowseMg;
static readonly Regex DosageRegex = new Regex(
@"(\d+(?:[.,]\d+)?\s*(?:мг|мкг|г|мл|МЕ|ме)\b)",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
const string EmptyMgDisplay = "(без МГ)";
private enum PriceBrowseMode
{
Browse,
Offers
}
string connectionStringToLocalDB = AppConfig.SqliteConnectionString; string connectionStringToLocalDB = AppConfig.SqliteConnectionString;
@ -51,6 +71,7 @@ namespace Электронная_Фармация.UserControls
private void UCPriceList_Load(object sender, EventArgs e) private void UCPriceList_Load(object sender, EventArgs e)
{ {
EnsureBrowseSplit();
UiThemeHelper.ApplyToControlTree(this); UiThemeHelper.ApplyToControlTree(this);
Tag = "chrome-child"; Tag = "chrome-child";
@ -71,6 +92,64 @@ namespace Электронная_Фармация.UserControls
txtSearchGoodNameInPriceList.Focus(); txtSearchGoodNameInPriceList.Focus();
} }
private void EnsureBrowseSplit()
{
if (splitNameMgBrowse != null)
{
return;
}
dgvBrowseNames = CreateBrowseGrid("dgvBrowseNames");
dgvBrowseMg = CreateBrowseGrid("dgvBrowseMg");
splitNameMgBrowse = new ModernSplitContainer
{
Name = "splitNameMgBrowse",
Dock = DockStyle.Fill,
Orientation = Orientation.Vertical,
SplitterWidth = 4,
Visible = false
};
splitNameMgBrowse.Panel1.Controls.Add(dgvBrowseNames);
splitNameMgBrowse.Panel2.Controls.Add(dgvBrowseMg);
TLPPriceList.Controls.Add(splitNameMgBrowse, 0, 0);
splitNameMgBrowse.BringToFront();
dgvBrowseNames.SelectionChanged += dgvBrowseNames_SelectionChanged;
dgvBrowseMg.CellClick += dgvBrowseMg_CellClick;
dgvBrowseNames.KeyPress += dgvPriceList_KeyPress;
dgvBrowseMg.KeyPress += dgvPriceList_KeyPress;
splitNameMgBrowse.SplitterMoved += (_, __) =>
{
if (splitNameMgBrowse.SplitterDistance > 80)
{
_browseSplitterDistance = splitNameMgBrowse.SplitterDistance;
}
};
}
private static ModernDataGridView CreateBrowseGrid(string name)
{
var grid = new ModernDataGridView
{
Name = name,
Dock = DockStyle.Fill,
AllowUserToAddRows = false,
AllowUserToDeleteRows = false,
AllowUserToResizeRows = false,
AllowUserToResizeColumns = true,
MultiSelect = false,
ReadOnly = true,
RowHeadersVisible = false,
SelectionMode = DataGridViewSelectionMode.FullRowSelect,
AutoGenerateColumns = true,
Font = new Font("Segoe UI", 13F, FontStyle.Regular),
TabStop = true
};
return grid;
}
private void AlignSearchRow() private void AlignSearchRow()
{ {
const int searchY = 9; const int searchY = 9;
@ -167,6 +246,26 @@ namespace Электронная_Фармация.UserControls
private void ApplyPriceListFilters() private void ApplyPriceListFilters()
{ {
if (_browseMode == PriceBrowseMode.Browse)
{
ShowBrowseView();
return;
}
if (_fullPriceTable == null)
{
return;
}
// Фильтр по базовому имени/МГ применим только к полной таблице прайса.
if (!ReferenceEquals(bsPriceList.DataSource, _fullPriceTable)
|| !_fullPriceTable.Columns.Contains("Базовое наименование")
|| !_fullPriceTable.Columns.Contains("МГ"))
{
ShowOffersView(_selectedBaseName, string.IsNullOrEmpty(_selectedMg) ? EmptyMgDisplay : _selectedMg);
return;
}
var parts = new List<string>(); var parts = new List<string>();
if (!string.IsNullOrWhiteSpace(_selectedSupplierFilter)) if (!string.IsNullOrWhiteSpace(_selectedSupplierFilter))
@ -175,13 +274,27 @@ namespace Электронная_Фармация.UserControls
parts.Add($"[Поставщик] = '{escapedSupplier}'"); parts.Add($"[Поставщик] = '{escapedSupplier}'");
} }
if (!string.IsNullOrWhiteSpace(GoodsFilter)) if (!string.IsNullOrWhiteSpace(_selectedBaseName))
{
var escapedName = _selectedBaseName.Replace("'", "''");
var escapedMg = (_selectedMg ?? string.Empty).Replace("'", "''");
parts.Add($"[Базовое наименование] = '{escapedName}'");
parts.Add($"[МГ] = '{escapedMg}'");
}
else if (!string.IsNullOrWhiteSpace(GoodsFilter))
{ {
var escaped = GoodsFilter.Replace("'", "''"); var escaped = GoodsFilter.Replace("'", "''");
parts.Add($"[Наименование] like '%{escaped}%'"); parts.Add($"[Наименование] like '%{escaped}%'");
} }
bsPriceList.Filter = parts.Count == 0 ? null : string.Join(" AND ", parts); try
{
bsPriceList.Filter = parts.Count == 0 ? string.Empty : string.Join(" AND ", parts);
}
catch (EvaluateException)
{
ShowOffersView(_selectedBaseName, string.IsNullOrEmpty(_selectedMg) ? EmptyMgDisplay : _selectedMg);
}
} }
private void comboSupplierFilter_SelectionChangeCommitted(object sender, EventArgs e) private void comboSupplierFilter_SelectionChangeCommitted(object sender, EventArgs e)
@ -277,30 +390,377 @@ namespace Электронная_Фармация.UserControls
tablePrice.Columns[10].ColumnName = "Сумма"; tablePrice.Columns[10].ColumnName = "Сумма";
tablePrice.Columns[12].ColumnName = "ИДПрайсЛистАйтем"; tablePrice.Columns[12].ColumnName = "ИДПрайсЛистАйтем";
if (tablePrice.Columns.Contains("TradeName"))
{
tablePrice.Columns["TradeName"].ColumnName = "Торговое название";
}
if (tablePrice.Columns.Contains("Dosage"))
{
tablePrice.Columns["Dosage"].ColumnName = "Дозировка";
}
EnsureDerivedBrowseColumns(tablePrice);
_fullPriceTable = tablePrice;
_selectedBaseName = string.Empty;
_selectedMg = string.Empty;
ShowBrowseView();
}
private void HideOptionalColumn(string columnName)
{
if (dgvPriceList.Columns.Contains(columnName))
{
dgvPriceList.Columns[columnName].Visible = false;
}
}
private void EnsureDerivedBrowseColumns(DataTable tablePrice)
{
if (!tablePrice.Columns.Contains("Базовое наименование"))
{
tablePrice.Columns.Add("Базовое наименование", typeof(string));
}
if (!tablePrice.Columns.Contains("МГ"))
{
tablePrice.Columns.Add("МГ", typeof(string));
}
foreach (DataRow row in tablePrice.Rows)
{
var drugName = row["Наименование"]?.ToString() ?? string.Empty;
var tradeName = tablePrice.Columns.Contains("Торговое название")
? row["Торговое название"]?.ToString()
: null;
var dosage = tablePrice.Columns.Contains("Дозировка")
? row["Дозировка"]?.ToString()
: null;
if (string.IsNullOrWhiteSpace(dosage))
{
dosage = ExtractDosageFromName(drugName);
}
dosage = (dosage ?? string.Empty).Trim();
row["МГ"] = dosage;
row["Базовое наименование"] = BuildBaseName(drugName, tradeName, dosage);
}
}
private static string ExtractDosageFromName(string drugName)
{
if (string.IsNullOrWhiteSpace(drugName))
{
return string.Empty;
}
var match = DosageRegex.Match(drugName);
return match.Success ? match.Value.Trim() : string.Empty;
}
private static string BuildBaseName(string drugName, string tradeName, string dosage)
{
if (!string.IsNullOrWhiteSpace(tradeName))
{
return tradeName.Trim();
}
var name = drugName ?? string.Empty;
if (!string.IsNullOrWhiteSpace(dosage))
{
var idx = name.IndexOf(dosage, StringComparison.OrdinalIgnoreCase);
if (idx >= 0)
{
name = name.Remove(idx, dosage.Length);
}
}
name = Regex.Replace(name, @"\s{2,}", " ").Trim(' ', ',', '-', '.', ';');
return string.IsNullOrWhiteSpace(name) ? (drugName ?? string.Empty).Trim() : name;
}
private void ShowBrowseView()
{
if (_fullPriceTable == null)
{
return;
}
EnsureBrowseSplit();
_browseMode = PriceBrowseMode.Browse;
_selectedMg = string.Empty;
try try
{ {
bsPriceList.RemoveFilter();
}
catch
{
bsPriceList.Filter = string.Empty;
}
var search = (GoodsFilter ?? string.Empty).Trim();
var namesTable = new DataTable();
namesTable.Columns.Add("Наименование", typeof(string));
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (DataRow row in _fullPriceTable.Rows)
{
var baseName = row["Базовое наименование"]?.ToString() ?? string.Empty;
if (string.IsNullOrWhiteSpace(baseName) || !seen.Add(baseName))
{
continue;
}
if (!string.IsNullOrWhiteSpace(search))
{
var keep = false;
foreach (DataRow candidate in _fullPriceTable.Rows)
{
if (!string.Equals(candidate["Базовое наименование"]?.ToString(), baseName, StringComparison.OrdinalIgnoreCase))
{
continue;
}
var drugName = candidate["Наименование"]?.ToString() ?? string.Empty;
var mgText = candidate["МГ"]?.ToString() ?? string.Empty;
if (baseName.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0
|| drugName.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0
|| mgText.IndexOf(search, StringComparison.OrdinalIgnoreCase) >= 0)
{
keep = true;
break;
}
}
if (!keep)
{
continue;
}
}
namesTable.Rows.Add(baseName);
}
namesTable.DefaultView.Sort = "Наименование ASC";
var sortedNames = namesTable.DefaultView.ToTable();
try
{
_suppressBrowseEvents = true;
dgvBrowseNames.DataSource = sortedNames;
ConfigureSingleColumnGrid(dgvBrowseNames, "Наименование");
ClearMgPanel();
if (!string.IsNullOrWhiteSpace(_selectedBaseName))
{
SelectBrowseName(_selectedBaseName);
}
else
{
dgvBrowseNames.ClearSelection();
}
}
finally
{
_suppressBrowseEvents = false;
}
ShowBrowsePanels(true);
if (!string.IsNullOrWhiteSpace(_selectedBaseName) && dgvBrowseNames.SelectedRows.Count > 0)
{
FillMgPanelForName(_selectedBaseName);
}
ShowMePriceWithMarkupPercentForSelectedGood();
}
private void ClearMgPanel()
{
var empty = new DataTable();
empty.Columns.Add("МГ", typeof(string));
dgvBrowseMg.DataSource = empty;
ConfigureSingleColumnGrid(dgvBrowseMg, "МГ");
dgvBrowseMg.ClearSelection();
}
private void FillMgPanelForName(string baseName)
{
var mgTable = new DataTable();
mgTable.Columns.Add("МГ", typeof(string));
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (DataRow row in _fullPriceTable.Rows)
{
if (!string.Equals(row["Базовое наименование"]?.ToString(), baseName, StringComparison.OrdinalIgnoreCase))
{
continue;
}
var dosage = row["МГ"]?.ToString() ?? string.Empty;
if (!seen.Add(dosage))
{
continue;
}
mgTable.Rows.Add(string.IsNullOrEmpty(dosage) ? EmptyMgDisplay : dosage);
}
mgTable.DefaultView.Sort = "МГ ASC";
try
{
_suppressBrowseEvents = true;
dgvBrowseMg.DataSource = mgTable.DefaultView.ToTable();
ConfigureSingleColumnGrid(dgvBrowseMg, "МГ");
dgvBrowseMg.ClearSelection();
}
finally
{
_suppressBrowseEvents = false;
}
}
private void ConfigureSingleColumnGrid(ModernDataGridView grid, string columnName)
{
grid.AutoGenerateColumns = true;
grid.AllowUserToResizeColumns = true;
grid.Font = new Font("Segoe UI", 13F, FontStyle.Regular);
foreach (DataGridViewColumn column in grid.Columns)
{
var match = string.Equals(column.Name, columnName, StringComparison.Ordinal)
|| string.Equals(column.HeaderText, columnName, StringComparison.Ordinal);
column.Visible = match;
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
column.Resizable = DataGridViewTriState.True;
column.MinimumWidth = 80;
}
}
private void SelectBrowseName(string baseName)
{
for (var i = 0; i < dgvBrowseNames.Rows.Count; i++)
{
var value = dgvBrowseNames.Rows[i].Cells["Наименование"]?.Value?.ToString();
if (string.Equals(value, baseName, StringComparison.OrdinalIgnoreCase))
{
dgvBrowseNames.ClearSelection();
dgvBrowseNames.Rows[i].Selected = true;
if (dgvBrowseNames.Columns.Contains("Наименование"))
{
dgvBrowseNames.CurrentCell = dgvBrowseNames.Rows[i].Cells["Наименование"];
}
dgvBrowseNames.FirstDisplayedScrollingRowIndex = Math.Max(0, i);
return;
}
}
}
private void ShowBrowsePanels(bool browseVisible)
{
EnsureBrowseSplit();
if (browseVisible)
{
dgvPriceList.Visible = false;
splitNameMgBrowse.Visible = true;
splitNameMgBrowse.BringToFront();
var width = Math.Max(200, splitNameMgBrowse.Width);
var preferred = _browseSplitterDistance > 80
? _browseSplitterDistance
: Math.Max(180, width / 2);
preferred = Math.Min(preferred, Math.Max(120, width - 120));
try
{
splitNameMgBrowse.SplitterDistance = preferred;
}
catch
{
// splitter not ready yet
}
}
else
{
if (splitNameMgBrowse.SplitterDistance > 80)
{
_browseSplitterDistance = splitNameMgBrowse.SplitterDistance;
}
splitNameMgBrowse.Visible = false;
dgvPriceList.Visible = true;
dgvPriceList.BringToFront();
}
}
private void ShowOffersView(string baseName, string mgDisplay)
{
if (_fullPriceTable == null || string.IsNullOrWhiteSpace(baseName))
{
return;
}
if (splitNameMgBrowse != null && splitNameMgBrowse.SplitterDistance > 80)
{
_browseSplitterDistance = splitNameMgBrowse.SplitterDistance;
}
_selectedBaseName = baseName;
_selectedMg = string.Equals(mgDisplay, EmptyMgDisplay, StringComparison.Ordinal)
? string.Empty
: (mgDisplay ?? string.Empty);
_suppressSupplierFilterEvents = true;
if (comboSupplierFilter.Items.Count > 0)
{
comboSupplierFilter.SelectedIndex = 0;
}
_suppressSupplierFilterEvents = false;
_committedSupplierFilterIndex = comboSupplierFilter.SelectedIndex;
_selectedSupplierFilter = string.Empty;
btnClearSupplierFilter.Visible = false;
BindOffersTable();
ApplyOffersColumns();
ShowBrowsePanels(false);
var escapedName = _selectedBaseName.Replace("'", "''");
var escapedMg = _selectedMg.Replace("'", "''");
try
{
bsPriceList.Filter = $"[Базовое наименование] = '{escapedName}' AND [МГ] = '{escapedMg}'";
}
catch (EvaluateException ex)
{
AppDebugLog.Error("PriceList", "Не удалось применить фильтр наименование+МГ", ex);
bsPriceList.RemoveFilter();
}
}
private void BindOffersTable()
{
try
{
_suppressBrowseEvents = true;
_suppressPriceListSelectionEvents = true; _suppressPriceListSelectionEvents = true;
bsPriceList.DataSource = tablePrice; _browseMode = PriceBrowseMode.Offers;
try
{
bsPriceList.RemoveFilter();
}
catch
{
bsPriceList.Filter = string.Empty;
}
bsPriceList.DataSource = _fullPriceTable;
dgvPriceList.DataSource = bsPriceList; dgvPriceList.DataSource = bsPriceList;
dgvPriceList.AutoGenerateColumns = true; dgvPriceList.AutoGenerateColumns = true;
dgvPriceList.Font = new Font("Segoe UI", 13, FontStyle.Regular); dgvPriceList.Font = new Font("Segoe UI", 13, FontStyle.Regular);
dgvPriceList.AllowUserToResizeColumns = true;
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;
if (dgvPriceList.Rows.Count > 0) if (dgvPriceList.Rows.Count > 0)
{ {
dgvPriceList.ClearSelection(); dgvPriceList.ClearSelection();
@ -309,10 +769,107 @@ namespace Электронная_Фармация.UserControls
finally finally
{ {
_suppressPriceListSelectionEvents = false; _suppressPriceListSelectionEvents = false;
_suppressBrowseEvents = false;
ShowMePriceWithMarkupPercentForSelectedGood(); ShowMePriceWithMarkupPercentForSelectedGood();
} }
} }
private void ApplyOffersColumns()
{
if (dgvPriceList.Columns.Count == 0)
{
return;
}
foreach (DataGridViewColumn column in dgvPriceList.Columns)
{
column.Visible = true;
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
column.Resizable = DataGridViewTriState.True;
}
if (dgvPriceList.Columns.Count > 0) dgvPriceList.Columns[0].Visible = false;
if (dgvPriceList.Columns.Count > 1) dgvPriceList.Columns[1].Visible = false;
if (dgvPriceList.Columns.Count > 2) dgvPriceList.Columns[2].Visible = false;
if (dgvPriceList.Columns.Count > 7) dgvPriceList.Columns[7].Visible = true;
if (dgvPriceList.Columns.Count > 8) dgvPriceList.Columns[8].Visible = false;
if (dgvPriceList.Columns.Count > 11) dgvPriceList.Columns[11].Visible = false;
if (dgvPriceList.Columns.Count > 12) dgvPriceList.Columns[12].Visible = false;
HideOptionalColumn("Торговое название");
HideOptionalColumn("Дозировка");
HideOptionalColumn("Базовое наименование");
HideOptionalColumn("МГ");
if (dgvPriceList.Columns.Count > 3) dgvPriceList.Columns[3].Width = 760;
if (dgvPriceList.Columns.Count > 4) dgvPriceList.Columns[4].Width = 150;
if (dgvPriceList.Columns.Count > 5) dgvPriceList.Columns[5].Width = 120;
if (dgvPriceList.Columns.Count > 6) dgvPriceList.Columns[6].Width = 100;
if (dgvPriceList.Columns.Count > 7) dgvPriceList.Columns[7].Width = 140;
if (dgvPriceList.Columns.Count > 9) dgvPriceList.Columns[9].Width = 100;
if (dgvPriceList.Columns.Count > 10) dgvPriceList.Columns[10].Width = 100;
}
private void dgvBrowseNames_SelectionChanged(object sender, EventArgs e)
{
if (_suppressBrowseEvents || _browseMode != PriceBrowseMode.Browse)
{
return;
}
if (dgvBrowseNames.SelectedRows.Count == 0)
{
_selectedBaseName = string.Empty;
ClearMgPanel();
return;
}
var name = dgvBrowseNames.SelectedRows[0].Cells["Наименование"]?.Value?.ToString() ?? string.Empty;
_selectedBaseName = name;
_selectedMg = string.Empty;
if (string.IsNullOrWhiteSpace(name))
{
ClearMgPanel();
return;
}
FillMgPanelForName(name);
ShowMePriceWithMarkupPercentForSelectedGood();
}
private void dgvBrowseMg_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (_suppressBrowseEvents || e.RowIndex < 0 || e.RowIndex >= dgvBrowseMg.Rows.Count)
{
return;
}
if (_browseMode != PriceBrowseMode.Browse || string.IsNullOrWhiteSpace(_selectedBaseName))
{
return;
}
var mg = dgvBrowseMg.Rows[e.RowIndex].Cells["МГ"]?.Value?.ToString() ?? string.Empty;
ShowOffersView(_selectedBaseName, mg);
}
private void NavigateBrowseBack()
{
if (_browseMode == PriceBrowseMode.Offers)
{
// Оставляем выбранное наименование, справа снова покажем его МГ.
_selectedMg = string.Empty;
ShowBrowseView();
}
}
private void ResetBrowseToNames()
{
_selectedBaseName = string.Empty;
_selectedMg = string.Empty;
ShowBrowseView();
}
void loadInfoAboutDefaultMarkup() void loadInfoAboutDefaultMarkup()
{ {
@ -762,7 +1319,7 @@ select strftime('%Y-%m-%d','{OrderDate}'),
{ {
txtSearchGoodNameInPriceList.Text = string.Empty; txtSearchGoodNameInPriceList.Text = string.Empty;
GoodsFilter = string.Empty; GoodsFilter = string.Empty;
ApplyPriceListFilters(); ResetBrowseToNames();
//loadPriceList(string.Empty); //loadPriceList(string.Empty);
} }
@ -824,23 +1381,85 @@ and tempOrder.GoodName = PriceList.GoodName
private void dgvPriceList_KeyPress(object sender, KeyPressEventArgs e) private void dgvPriceList_KeyPress(object sender, KeyPressEventArgs e)
{ {
if (e.KeyChar == (Char)Keys.Escape)
{
if (_browseMode != PriceBrowseMode.Browse)
{
NavigateBrowseBack();
}
else
{
txtSearchGoodNameInPriceList.Text = string.Empty;
GoodsFilter = string.Empty;
ResetBrowseToNames();
}
return;
}
int RowIndex = -1; int RowIndex = -1;
string idPriceListItem = string.Empty; string idPriceListItem = string.Empty;
if (dgvPriceList.SelectedRows.Count > 0) if (_browseMode == PriceBrowseMode.Offers && dgvPriceList.SelectedRows.Count > 0)
{ {
RowIndex = dgvPriceList.SelectedRows[0].Index; RowIndex = dgvPriceList.SelectedRows[0].Index;
if (RowIndex >= 0 && RowIndex < dgvPriceList.Rows.Count) if (RowIndex >= 0
&& RowIndex < dgvPriceList.Rows.Count
&& dgvPriceList.Rows[RowIndex].Cells.Count > 11)
{ {
idPriceListItem = dgvPriceList.Rows[RowIndex].Cells[11].Value?.ToString() ?? string.Empty; idPriceListItem = dgvPriceList.Rows[RowIndex].Cells[11].Value?.ToString() ?? string.Empty;
} }
} }
if (_browseMode != PriceBrowseMode.Offers)
{
if (e.KeyChar == (Char)Keys.Back && GoodsFilter.Length > 0)
{
GoodsFilter = GoodsFilter.Substring(0, GoodsFilter.Length - 1);
txtSearchGoodNameInPriceList.Text = GoodsFilter;
ResetBrowseToNames();
if (GoodsFilter.Length == 0)
{
timerForResetSearch.Enabled = false;
timerForResetSearch.Stop();
}
else
{
timerForResetSearch.Enabled = true;
timerForResetSearch.Start();
}
return;
}
if ((e.KeyChar >= 'A' && e.KeyChar <= 'Z')
|| (e.KeyChar >= 'a' && e.KeyChar <= 'z')
|| (e.KeyChar >= 'А' && e.KeyChar <= 'Я')
|| (e.KeyChar >= 'а' && e.KeyChar <= 'я')
|| (e.KeyChar == (Char)Keys.Subtract))
{
dgvPriceList.ClearSelection();
GoodsFilter += e.KeyChar.ToString();
txtSearchGoodNameInPriceList.Text = GoodsFilter;
ResetBrowseToNames();
if (dgvPriceList.Rows.Count == 0)
{
UiDialogs.ShowInfo("Подходящий товар не найден.", "Поиск", FindForm());
GoodsFilter = string.Empty;
txtSearchGoodNameInPriceList.Text = string.Empty;
ResetBrowseToNames();
}
}
return;
}
if (e.KeyChar == (Char)Keys.Back && GoodsFilter.Length > 0) if (e.KeyChar == (Char)Keys.Back && GoodsFilter.Length > 0)
{ {
GoodsFilter = GoodsFilter.Substring(0, GoodsFilter.Length - 1); GoodsFilter = GoodsFilter.Substring(0, GoodsFilter.Length - 1);
txtSearchGoodNameInPriceList.Text = GoodsFilter; txtSearchGoodNameInPriceList.Text = GoodsFilter;
ApplyPriceListFilters(); ResetBrowseToNames();
if (GoodsFilter.Length == 0) if (GoodsFilter.Length == 0)
{ {
@ -893,14 +1512,14 @@ and tempOrder.GoodName = PriceList.GoodName
#region старый способ поиска с фильтрацией данных #region старый способ поиска с фильтрацией данных
if (!string.IsNullOrEmpty(GoodsFilter)) if (!string.IsNullOrEmpty(GoodsFilter))
{ {
ApplyPriceListFilters(); ResetBrowseToNames();
if (dgvPriceList.Rows.Count == 0) if (dgvPriceList.Rows.Count == 0)
{ {
UiDialogs.ShowInfo("Подходящий товар не найден.", "Поиск", FindForm()); UiDialogs.ShowInfo("Подходящий товар не найден.", "Поиск", FindForm());
GoodsFilter = string.Empty; GoodsFilter = string.Empty;
txtSearchGoodNameInPriceList.Text = string.Empty; txtSearchGoodNameInPriceList.Text = string.Empty;
ApplyPriceListFilters(); ResetBrowseToNames();
} }
} }
#endregion #endregion
@ -908,8 +1527,12 @@ and tempOrder.GoodName = PriceList.GoodName
return; return;
} }
else if ((e.KeyChar >= (Char)Keys.D1 && e.KeyChar <= (Char)Keys.D9) || else if ((e.KeyChar >= (Char)Keys.D1 && e.KeyChar <= (Char)Keys.D9) ||
(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)) (e.KeyChar >= (Char)Keys.NumPad1 && e.KeyChar <= (Char)Keys.NumPad9) || (RowIndex >= 0 && e.KeyChar == (Char)Keys.D0 && dgvPriceList.Rows[RowIndex].Cells[10].Value.ToString().Length > 1) || (RowIndex >= 0 && e.KeyChar == (Char)Keys.NumPad0 && dgvPriceList.Rows[RowIndex].Cells[10].Value.ToString().Length > 1))
{ {
if (RowIndex < 0)
{
return;
}
if (!TryReadInt32(dgvPriceList.Rows[RowIndex].Cells[6].Value, out var quantityForSale)) if (!TryReadInt32(dgvPriceList.Rows[RowIndex].Cells[6].Value, out var quantityForSale))
{ {
@ -950,13 +1573,6 @@ and tempOrder.GoodName = PriceList.GoodName
} }
} }
} }
else if (e.KeyChar == (Char)Keys.Escape)
{
txtSearchGoodNameInPriceList.Text = string.Empty;
GoodsFilter = string.Empty;
ApplyPriceListFilters();
return;
}
else if (e.KeyChar == (Char)Keys.Back) else if (e.KeyChar == (Char)Keys.Back)
{ {
if (RowIndex < 0) return; if (RowIndex < 0) return;
@ -1267,6 +1883,25 @@ and SumOrderedItems = '{SumOrder}'";
{ {
try try
{ {
if (_browseMode != PriceBrowseMode.Offers)
{
if (!string.IsNullOrWhiteSpace(_selectedBaseName))
{
lblSelectedGoodName.Text = _selectedBaseName;
}
else if (dgvBrowseNames?.SelectedRows.Count > 0 && dgvBrowseNames.Columns.Contains("Наименование"))
{
lblSelectedGoodName.Text = dgvBrowseNames.SelectedRows[0].Cells["Наименование"]?.Value?.ToString() ?? string.Empty;
}
else
{
lblSelectedGoodName.Text = string.Empty;
}
lblPriceForGood.Text = string.Empty;
return;
}
var currentRow = dgvPriceList.CurrentRow; var currentRow = dgvPriceList.CurrentRow;
if (currentRow == null || currentRow.IsNewRow) if (currentRow == null || currentRow.IsNewRow)
{ {
@ -1701,7 +2336,7 @@ and SumOrderedItems = '{SumOrder}'";
{ {
txtSearchGoodNameInPriceList.Text = string.Empty; txtSearchGoodNameInPriceList.Text = string.Empty;
GoodsFilter = string.Empty; GoodsFilter = string.Empty;
ApplyPriceListFilters(); ResetBrowseToNames();
timerForResetSearch.Enabled = false; timerForResetSearch.Enabled = false;
timerForResetSearch.Stop(); timerForResetSearch.Stop();
} }

View File

@ -178,6 +178,12 @@ namespace Elfisa.UI.Controls
e.CellStyle.Font = theme.FontRegular13; e.CellStyle.Font = theme.FontRegular13;
} }
protected override void OnDataSourceChanged(EventArgs e)
{
_hoverRowIndex = null;
base.OnDataSourceChanged(e);
}
protected override void OnCellMouseEnter(DataGridViewCellEventArgs e) protected override void OnCellMouseEnter(DataGridViewCellEventArgs e)
{ {
base.OnCellMouseEnter(e); base.OnCellMouseEnter(e);
@ -188,12 +194,8 @@ namespace Elfisa.UI.Controls
var previous = _hoverRowIndex; var previous = _hoverRowIndex;
_hoverRowIndex = e.RowIndex; _hoverRowIndex = e.RowIndex;
if (previous.HasValue) InvalidateRowSafe(previous);
{ InvalidateRowSafe(e.RowIndex);
InvalidateRow(previous.Value);
}
InvalidateRow(e.RowIndex);
} }
protected override void OnCellMouseLeave(DataGridViewCellEventArgs e) protected override void OnCellMouseLeave(DataGridViewCellEventArgs e)
@ -205,7 +207,23 @@ namespace Elfisa.UI.Controls
} }
_hoverRowIndex = null; _hoverRowIndex = null;
InvalidateRow(e.RowIndex); InvalidateRowSafe(e.RowIndex);
}
private void InvalidateRowSafe(int? rowIndex)
{
if (!rowIndex.HasValue)
{
return;
}
var index = rowIndex.Value;
if (index < 0 || index >= Rows.Count)
{
return;
}
InvalidateRow(index);
} }
} }
} }