elfisa-pharmacy/src/ElectronicPharmacy/Forms/FConsignees.cs
Magomed fd5bd18c66 Add per-pharmacy carts and client-side summed discount pricing.
Apply available buyer/price-list/region discounts to summary.price on download, keep consignee carts separate, and harden SQLite startup/migrations.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-30 14:07:47 +03:00

264 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Data;
using System.Data.SQLite;
using System.Windows.Forms;
using Электроннаяармация.Classes;
namespace Электроннаяармация.Forms
{
public partial class FConsignees : Form
{
public string SelectedConsigneeNameAfterSave { get; private set; } = string.Empty;
public FConsignees()
{
InitializeComponent();
}
private void FConsignees_Load(object sender, EventArgs e)
{
UiThemeHelper.ApplyToControlTree(this);
showMeContentFromConsigneesTable();
}
void showMeContentFromConsigneesTable()
{
using (SQLiteConnection conConsignees = new SQLiteConnection(AppConfig.SqliteConnectionString))
{
string selectFromConsignees = @"
select [idConsignees] as [Id],
[codeConsignees] as [Код],
[ConsigneesName] as [Наименование],
[ConsigneesAddress] as [Адрес],
ifnull([LocationId], '') as [Location ID],
[ConsigneesUseAsDefault] as [По умолчанию]
from [Consignees]
order by [ConsigneesUseAsDefault] desc, [ConsigneesName]";
try
{
conConsignees.Open();
SQLiteCommand cmdShowConsigneesList = new SQLiteCommand(selectFromConsignees, conConsignees);
DataTable tableConsignees = new DataTable();
SQLiteDataAdapter daConsigneeList = new SQLiteDataAdapter(cmdShowConsigneesList);
daConsigneeList.Fill(tableConsignees);
dgvConsignees.DataSource = tableConsignees;
if (dgvConsignees.Columns.Contains("Id"))
{
dgvConsignees.Columns["Id"].Visible = false;
}
foreach (DataGridViewColumn column in dgvConsignees.Columns)
{
column.ReadOnly = column.Name != "Location ID" && column.Name != "Адрес";
}
}
catch (Exception ex)
{
MessageBox.Show($"Возникла ошибка при заполнении данных о грузополучателях.\nТекст ошибки:\n{ex}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
private void txtInteractiveShowMeConsignees_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
if (dgvConsignees.Rows.Count > 0 && dgvConsignees.DataSource is DataTable table)
{
table.DefaultView.RowFilter = $"[Наименование] like '%{txtInteractiveShowMeConsignees.Text.Replace("'", "''")}%'";
if (dgvConsignees.Rows.Count == 0)
{
showMeContentFromConsigneesTable();
}
}
else
{
showMeContentFromConsigneesTable();
}
txtInteractiveShowMeConsignees.Text = string.Empty;
}
}
private void btnSave_Click(object sender, EventArgs e)
{
if (!(dgvConsignees.DataSource is DataTable table))
{
return;
}
dgvConsignees.EndEdit();
// Кто должен стать активной аптекой после сохранения.
// По вашему ТЗ: "аптека выбранная в этом окне" => текущая выделенная строка.
var selectedName = dgvConsignees.CurrentRow?.Cells["Наименование"]?.Value?.ToString()?.Trim()
?? string.Empty;
SelectedConsigneeNameAfterSave = selectedName;
using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString))
{
connection.Open();
using (var tx = connection.BeginTransaction())
{
foreach (DataRow row in table.Rows)
{
if (row.RowState == DataRowState.Unchanged)
{
continue;
}
using (var cmd = new SQLiteCommand(
@"UPDATE Consignees
SET ConsigneesAddress = @address,
LocationId = @locationId
WHERE idConsignees = @id",
connection,
tx))
{
cmd.Parameters.AddWithValue("@address", row["Адрес"]?.ToString() ?? string.Empty);
cmd.Parameters.AddWithValue("@locationId", row["Location ID"]?.ToString()?.Trim() ?? string.Empty);
cmd.Parameters.AddWithValue("@id", Convert.ToInt64(row["Id"]));
cmd.ExecuteNonQuery();
}
}
tx.Commit();
}
}
table.AcceptChanges();
ToastNotification.ShowSuccess("Грузополучатели сохранены");
if (!string.IsNullOrWhiteSpace(selectedName))
{
ConsigneeHelper.SetActiveConsignee(selectedName);
}
DialogResult = DialogResult.OK;
Close();
}
private void btnAdd_Click(object sender, EventArgs e)
{
using (var dialog = new Form())
{
dialog.Text = "Новая аптека";
dialog.FormBorderStyle = FormBorderStyle.FixedDialog;
dialog.StartPosition = FormStartPosition.CenterParent;
// Немного увеличиваем высоту/ширину на случай DPI/шрифтов.
dialog.ClientSize = new System.Drawing.Size(480, 310);
dialog.MaximizeBox = false;
dialog.MinimizeBox = false;
dialog.ShowInTaskbar = false;
var lblName = new Label { Text = "Наименование", Left = 16, Top = 16, AutoSize = true };
var txtName = new TextBox { Left = 16, Top = 42, Width = 440, Height = 28 };
var lblAddress = new Label { Text = "Адрес", Left = 16, Top = 82, AutoSize = true };
var txtAddress = new TextBox { Left = 16, Top = 108, Width = 440, Height = 28 };
var lblLocation = new Label { Text = "Location ID", Left = 16, Top = 148, AutoSize = true };
var txtLocation = new TextBox { Left = 16, Top = 174, Width = 440, Height = 28 };
var btnOk = new Elfisa.UI.Controls.ModernButton
{
Text = "Добавить",
DialogResult = DialogResult.OK
};
var btnCancel = new Elfisa.UI.Controls.ModernButton
{
Text = "Отмена",
DialogResult = DialogResult.Cancel
};
dialog.Controls.AddRange(new Control[]
{
lblName, txtName, lblAddress, txtAddress, lblLocation, txtLocation, btnOk, btnCancel
});
dialog.AcceptButton = btnOk;
dialog.CancelButton = btnCancel;
UiThemeHelper.ApplyToControlTree(dialog);
btnOk.Padding = new Padding(12, 4, 12, 4);
btnCancel.Padding = new Padding(12, 4, 12, 4);
Elfisa.UI.Controls.ModernButtonStyles.FitToText(btnOk, 36);
Elfisa.UI.Controls.ModernButtonStyles.FitToText(btnCancel, 36);
btnOk.Height = 36;
btnCancel.Height = 36;
const int padding = 16;
const int gap = 10;
// Минимально гарантируем ширину, чтобы обе кнопки поместились.
var requiredWidth = btnOk.Width + btnCancel.Width + gap + padding * 2;
if (dialog.ClientSize.Width < requiredWidth)
{
dialog.ClientSize = new System.Drawing.Size(requiredWidth, dialog.ClientSize.Height);
}
// Всегда зажимаем в границы формы после вычисления ширины ModernButton'ов.
btnCancel.Left = Math.Max(padding, dialog.ClientSize.Width - btnCancel.Width - padding);
btnCancel.Top = dialog.ClientSize.Height - btnCancel.Height - padding;
btnOk.Left = Math.Max(padding, btnCancel.Left - btnOk.Width - gap);
btnOk.Top = btnCancel.Top;
if (dialog.ShowDialog(this) != DialogResult.OK)
{
return;
}
var name = (txtName.Text ?? string.Empty).Trim();
var address = (txtAddress.Text ?? string.Empty).Trim();
var locationId = (txtLocation.Text ?? string.Empty).Trim();
if (string.IsNullOrWhiteSpace(name))
{
UiDialogs.ShowError("Укажите наименование аптеки.", "Грузополучатели", this);
return;
}
using (var connection = new SQLiteConnection(AppConfig.SqliteConnectionString))
{
connection.Open();
int nextCode = 1;
using (var codeCmd = new SQLiteCommand("SELECT ifnull(MAX(codeConsignees), 0) + 1 FROM Consignees", connection))
{
nextCode = Convert.ToInt32(codeCmd.ExecuteScalar());
}
using (var insert = new SQLiteCommand(
@"INSERT INTO Consignees (codeConsignees, ConsigneesName, ConsigneesAddress, ConsigneesUseAsDefault, LocationId)
VALUES (@code, @name, @address, 0, @locationId)",
connection))
{
insert.Parameters.AddWithValue("@code", nextCode);
insert.Parameters.AddWithValue("@name", name);
insert.Parameters.AddWithValue("@address", address);
insert.Parameters.AddWithValue("@locationId", locationId);
insert.ExecuteNonQuery();
}
}
ToastNotification.ShowSuccess("Аптека добавлена");
showMeContentFromConsigneesTable();
}
}
private void btnSetDefault_Click(object sender, EventArgs e)
{
if (dgvConsignees.CurrentRow == null)
{
UiDialogs.ShowInfo("Выберите аптеку в списке.", "Грузополучатели", this);
return;
}
var name = dgvConsignees.CurrentRow.Cells["Наименование"]?.Value?.ToString();
if (string.IsNullOrWhiteSpace(name))
{
return;
}
ConsigneeHelper.SetActiveConsignee(name);
ToastNotification.ShowSuccess($"Аптека по умолчанию: {name}");
showMeContentFromConsigneesTable();
}
}
}