diff --git a/App.config b/App.config new file mode 100644 index 0000000..4a9f8d0 --- /dev/null +++ b/App.config @@ -0,0 +1,18 @@ + + + + +
+ + + + + + + + + + + + + \ No newline at end of file diff --git a/Form1.Designer.cs b/Form1.Designer.cs new file mode 100644 index 0000000..bf0f3ca --- /dev/null +++ b/Form1.Designer.cs @@ -0,0 +1,223 @@ +//------------------------------------------------------------------------------ +// +// Этот код создан программой. +// Исполняемая версия:4.0.30319.42000 +// +// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае +// повторной генерации кода. +// +//------------------------------------------------------------------------------ + +namespace OzonInternalLabelPrinter // Убедитесь, что это ваше пространство имен +{ + partial class Form1 + { + /// + /// Обязательная переменная конструктора. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Освободить все используемые ресурсы. + /// + /// истинно, если управляемый ресурс должен быть удален; иначе ложно. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + // Освобождаем ресурсы, созданные в коде Form1.cs + _httpClient?.Dispose(); + _printDocForSetup?.Dispose(); // Добавлено освобождение PrintDocument + } + base.Dispose(disposing); + } + + #region Код, автоматически созданный конструктором форм Windows + + /// + /// Требуемый метод для поддержки конструктора — не изменяйте + /// содержимое этого метода с помощью редактора кода. + /// + private void InitializeComponent() + { + this.label3 = new System.Windows.Forms.Label(); + this.txtOfferId = new System.Windows.Forms.TextBox(); + this.btnGetData = new System.Windows.Forms.Button(); + this.lblProductName = new System.Windows.Forms.Label(); + this.lblProductSku = new System.Windows.Forms.Label(); + this.lblProductBarcode = new System.Windows.Forms.Label(); + this.btnPrintLabel = new System.Windows.Forms.Button(); + this.lblStatus = new System.Windows.Forms.Label(); + this.cmbStores = new System.Windows.Forms.ComboBox(); + this.btnManageStores = new System.Windows.Forms.Button(); + this.labelStore = new System.Windows.Forms.Label(); + this.btnPageSetup = new System.Windows.Forms.Button(); // Объявление кнопки Настройки + this.pageSetupDialog1 = new System.Windows.Forms.PageSetupDialog(); // Объявление диалога Настройки + this.SuspendLayout(); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 94); // Скорректировано + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(51, 13); + this.label3.TabIndex = 4; + this.label3.Text = "Артикул:"; + // + // txtOfferId + // + this.txtOfferId.Enabled = false; + this.txtOfferId.Location = new System.Drawing.Point(88, 91); // Скорректировано + this.txtOfferId.Name = "txtOfferId"; + this.txtOfferId.Size = new System.Drawing.Size(176, 20); + this.txtOfferId.TabIndex = 3; // TabIndex изменен + this.txtOfferId.TextChanged += new System.EventHandler(this.txtOfferId_TextChanged); + // + // btnGetData + // + this.btnGetData.Enabled = false; + this.btnGetData.Location = new System.Drawing.Point(270, 89); // Скорректировано + this.btnGetData.Name = "btnGetData"; + this.btnGetData.Size = new System.Drawing.Size(118, 23); + this.btnGetData.TabIndex = 4; // TabIndex изменен + this.btnGetData.Text = "Получить данные"; + this.btnGetData.UseVisualStyleBackColor = true; + this.btnGetData.Click += new System.EventHandler(this.btnGetData_Click); + // + // lblProductName + // + this.lblProductName.AutoSize = true; + this.lblProductName.Location = new System.Drawing.Point(12, 133); // Скорректировано + this.lblProductName.Name = "lblProductName"; + this.lblProductName.Size = new System.Drawing.Size(60, 13); + this.lblProductName.TabIndex = 5; + this.lblProductName.Text = "Название:"; + // + // lblProductSku + // + this.lblProductSku.AutoSize = true; + this.lblProductSku.Location = new System.Drawing.Point(12, 156); // Скорректировано + this.lblProductSku.Name = "lblProductSku"; + this.lblProductSku.Size = new System.Drawing.Size(51, 13); + this.lblProductSku.TabIndex = 6; + this.lblProductSku.Text = "Артикул:"; + // + // lblProductBarcode + // + this.lblProductBarcode.AutoSize = true; + this.lblProductBarcode.Location = new System.Drawing.Point(12, 179); // Скорректировано + this.lblProductBarcode.Name = "lblProductBarcode"; + this.lblProductBarcode.Size = new System.Drawing.Size(59, 13); + this.lblProductBarcode.TabIndex = 7; + this.lblProductBarcode.Text = "Штрихкод:"; + // + // btnPrintLabel + // + this.btnPrintLabel.Enabled = false; + this.btnPrintLabel.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(204))); + this.btnPrintLabel.Location = new System.Drawing.Point(16, 214); // Скорректировано + this.btnPrintLabel.Name = "btnPrintLabel"; + this.btnPrintLabel.Size = new System.Drawing.Size(373, 33); + this.btnPrintLabel.TabIndex = 8; // TabIndex изменен + this.btnPrintLabel.Text = "Печать этикетки"; + this.btnPrintLabel.UseVisualStyleBackColor = true; + this.btnPrintLabel.Click += new System.EventHandler(this.btnPrintLabel_Click); + // + // lblStatus + // + this.lblStatus.AutoSize = true; + this.lblStatus.Location = new System.Drawing.Point(13, 260); // Скорректировано + this.lblStatus.Name = "lblStatus"; + this.lblStatus.Size = new System.Drawing.Size(44, 13); + this.lblStatus.TabIndex = 9; + this.lblStatus.Text = "Статус:"; + // + // cmbStores + // + this.cmbStores.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cmbStores.FormattingEnabled = true; + this.cmbStores.Location = new System.Drawing.Point(88, 24); + this.cmbStores.Name = "cmbStores"; + this.cmbStores.Size = new System.Drawing.Size(176, 21); + this.cmbStores.TabIndex = 0; + this.cmbStores.SelectedIndexChanged += new System.EventHandler(this.cmbStores_SelectedIndexChanged); + // + // btnManageStores + // + this.btnManageStores.Location = new System.Drawing.Point(270, 23); + this.btnManageStores.Name = "btnManageStores"; + this.btnManageStores.Size = new System.Drawing.Size(118, 23); + this.btnManageStores.TabIndex = 1; + this.btnManageStores.Text = "Упр. магазинами..."; + this.btnManageStores.UseVisualStyleBackColor = true; + this.btnManageStores.Click += new System.EventHandler(this.btnManageStores_Click); + // + // labelStore + // + this.labelStore.AutoSize = true; + this.labelStore.Location = new System.Drawing.Point(12, 27); + this.labelStore.Name = "labelStore"; + this.labelStore.Size = new System.Drawing.Size(54, 13); + this.labelStore.TabIndex = 15; + this.labelStore.Text = "Магазин:"; + // + // btnPageSetup + // *** Новая кнопка Настройки принтера *** + this.btnPageSetup.Location = new System.Drawing.Point(270, 53); + this.btnPageSetup.Name = "btnPageSetup"; + this.btnPageSetup.Size = new System.Drawing.Size(118, 23); + this.btnPageSetup.TabIndex = 2; // Изменен TabIndex + this.btnPageSetup.Text = "Настройка принтера"; + this.btnPageSetup.UseVisualStyleBackColor = true; + this.btnPageSetup.Click += new System.EventHandler(this.btnPageSetup_Click); + // + // pageSetupDialog1 + // *** Диалог настройки страницы *** + this.pageSetupDialog1 = new System.Windows.Forms.PageSetupDialog(); + this.pageSetupDialog1.EnableMetric = true; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(404, 288); // Скорректирован размер + this.Controls.Add(this.btnPageSetup); // Добавлена кнопка + this.Controls.Add(this.labelStore); + this.Controls.Add(this.btnManageStores); + this.Controls.Add(this.cmbStores); + this.Controls.Add(this.lblStatus); + this.Controls.Add(this.btnPrintLabel); + this.Controls.Add(this.lblProductBarcode); + this.Controls.Add(this.lblProductSku); + this.Controls.Add(this.lblProductName); + this.Controls.Add(this.btnGetData); + this.Controls.Add(this.txtOfferId); + this.Controls.Add(this.label3); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.Name = "Form1"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Генератор внутренних этикеток Ozon"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox txtOfferId; + private System.Windows.Forms.Button btnGetData; + private System.Windows.Forms.Label lblProductName; + private System.Windows.Forms.Label lblProductSku; + private System.Windows.Forms.Label lblProductBarcode; + private System.Windows.Forms.Button btnPrintLabel; + private System.Windows.Forms.Label lblStatus; + private System.Windows.Forms.ComboBox cmbStores; + private System.Windows.Forms.Button btnManageStores; + private System.Windows.Forms.Label labelStore; + private System.Windows.Forms.Button btnPageSetup; // Добавлено + private System.Windows.Forms.PageSetupDialog pageSetupDialog1; // Добавлено + } +} \ No newline at end of file diff --git a/Form1.cs b/Form1.cs new file mode 100644 index 0000000..0194b77 --- /dev/null +++ b/Form1.cs @@ -0,0 +1,500 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Printing; +using System.Linq; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Cryptography; // Для шифрования/дешифрования +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows.Forms; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using SKLADm.Properties; // Для доступа к Settings.Default +using SKLADm; +using ZXing; +using ZXing.Common; +using ZXing.Windows.Compatibility; + +namespace OzonInternalLabelPrinter // Убедитесь, что это ваше пространство имен +{ + public partial class Form1 : Form + { + private HttpClient _httpClient; + // Bitmap больше не нужен как поле класса + // private Bitmap _labelBitmap; + private string _currentProductName; + private string _currentSku; + private string _currentBarcode; + private List _availableStores; + // Поле для хранения экземпляра документа между настройкой и печатью + private PrintDocument _printDocForSetup; // Используем для PageSetup и Print + + // Конструктор формы + public Form1() + { + InitializeComponent(); // Инициализирует компоненты из ДИЗАЙНЕРА + InitializeHttpClient(); + // Инициализируем PrintDocument один раз + _printDocForSetup = new PrintDocument(); + // Устанавливаем обработчик печати один раз + _printDocForSetup.PrintPage += new PrintPageEventHandler(pd_PrintPage); + // Загружаем магазины при запуске ПОСЛЕ инициализации _printDocForSetup + LoadStoresToComboBox(); + } + + // Инициализация HTTP клиента + private void InitializeHttpClient() + { + _httpClient = new HttpClient + { + BaseAddress = new Uri("https://api-seller.ozon.ru/") + }; + _httpClient.DefaultRequestHeaders.Accept.Clear(); + _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); + } + + // --- Логика работы с магазинами и ключами --- + + private static readonly byte[] s_entropy = null; // Энтропия для шифрования + + // Дешифрование Api-Key + private string DecryptApiKey(string encryptedKeyBase64) + { + if (string.IsNullOrEmpty(encryptedKeyBase64)) return string.Empty; + try + { + byte[] encryptedBytes = Convert.FromBase64String(encryptedKeyBase64); + byte[] decryptedBytes = ProtectedData.Unprotect(encryptedBytes, s_entropy, DataProtectionScope.CurrentUser); + return Encoding.UTF8.GetString(decryptedBytes); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"Ошибка дешифрования ключа: {ex.Message}"); + MessageBox.Show($"Не удалось дешифровать Api-Key для магазина '{cmbStores.Text}'. Возможно, настройки повреждены или созданы под другим пользователем.\n\nОшибка: {ex.Message}", + "Ошибка ключа", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; + } + } + + // Загрузка магазинов из настроек в ComboBox + private void LoadStoresToComboBox() + { + string json = Settings.Default.SavedStoresJson; + _availableStores = new List(); + if (!string.IsNullOrEmpty(json)) + { + try + { + _availableStores = JsonConvert.DeserializeObject>(json) ?? new List(); + } + catch (Exception ex) + { + MessageBox.Show($"Ошибка загрузки списка магазинов: {ex.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning); + _availableStores = new List(); + } + } + + cmbStores.DataSource = null; + cmbStores.DataSource = _availableStores; + cmbStores.DisplayMember = "StoreName"; + + bool storesExist = _availableStores.Any(); + cmbStores.Enabled = storesExist; + txtOfferId.Enabled = storesExist; + btnPageSetup.Enabled = storesExist; // Включаем настройку, если есть магазины + // Кнопка GetData включится при вводе артикула + + if (storesExist) + { + cmbStores.SelectedIndex = 0; + // Установим принтер по умолчанию для _printDocForSetup, если возможно + TrySetDefaultPrinterForDocument(); + } + else + { + cmbStores.SelectedIndex = -1; + // Показываем сообщение, если нужно + // MessageBox.Show("Нет сохраненных магазинов...", "Внимание", MessageBoxButtons.OK, Information); + } + ResetProductData(); + // Обновляем состояние кнопки GetData после загрузки + txtOfferId_TextChanged(txtOfferId, EventArgs.Empty); + } + + // Попытка установить принтер по умолчанию для PrintDocument + private void TrySetDefaultPrinterForDocument() + { + string thermalPrinterName = "Xprinter XP-365B"; // Или другое имя по умолчанию + foreach (string printerName in PrinterSettings.InstalledPrinters) + { + if (printerName.Equals(thermalPrinterName, StringComparison.OrdinalIgnoreCase)) + { + try + { + _printDocForSetup.PrinterSettings.PrinterName = printerName; + System.Diagnostics.Debug.WriteLine($"Принтер по умолчанию '{printerName}' установлен для PrintDocument."); + } + catch (Exception ex) + { + System.Diagnostics.Debug.WriteLine($"Ошибка установки принтера по умолчанию '{printerName}': {ex.Message}"); + } + return; // Выходим после нахождения + } + } + System.Diagnostics.Debug.WriteLine($"Принтер по умолчанию '{thermalPrinterName}' не найден."); + } + + // --- Обработчики событий UI --- + + private void btnManageStores_Click(object sender, EventArgs e) + { + using (FormManageStores manageForm = new FormManageStores()) + { + manageForm.ShowDialog(this); + LoadStoresToComboBox(); // Перезагружаем список + } + } + + private void cmbStores_SelectedIndexChanged(object sender, EventArgs e) + { + ResetProductData(); + txtOfferId_TextChanged(txtOfferId, EventArgs.Empty); // Обновляем состояние кнопки GetData + // Можно попробовать обновить принтер по умолчанию для _printDocForSetup, + // если у разных магазинов могут быть разные принтеры (но это усложнит логику) + } + + private void txtOfferId_TextChanged(object sender, EventArgs e) + { + btnGetData.Enabled = cmbStores.SelectedItem != null && !string.IsNullOrEmpty(txtOfferId.Text.Trim()); + if (string.IsNullOrEmpty(txtOfferId.Text.Trim())) + { + ResetProductData(); + } + } + + // --- Кнопка "Настройка принтера" --- + private void btnPageSetup_Click(object sender, EventArgs e) + { + // Убедимся, что принтер в _printDocForSetup актуален (если не нашли Xprinter при запуске, + // или если у пользователя несколько принтеров) + if (!PrinterSettings.InstalledPrinters.Cast().Contains(_printDocForSetup.PrinterSettings.PrinterName)) + { + // Если текущий принтер недоступен, сбрасываем на принтер по умолчанию Windows + try + { + _printDocForSetup.PrinterSettings = new PrinterSettings(); // Сброс на настройки по умолчанию + System.Diagnostics.Debug.WriteLine("Текущий принтер в PrintDocument был недоступен, сброшен на принтер по умолчанию Windows."); + } + catch { } + } + + pageSetupDialog1.Document = _printDocForSetup; // Связываем диалог с нашим PrintDocument + pageSetupDialog1.MinMargins = new Margins(0, 0, 0, 0); // Минимальные поля + pageSetupDialog1.AllowMargins = true; // Разрешаем менять поля + pageSetupDialog1.AllowOrientation = false; // Запрещаем менять ориентацию + pageSetupDialog1.AllowPaper = true; // Разрешаем менять размер бумаги + pageSetupDialog1.AllowPrinter = true; // Разрешаем выбирать другой принтер + + if (pageSetupDialog1.ShowDialog(this) == DialogResult.OK) + { + // Настройки применились к _printDocForSetup + lblStatus.Text = "Настройки принтера применены."; + System.Diagnostics.Debug.WriteLine($"PageSetupDialog OK: New PaperSize={_printDocForSetup.DefaultPageSettings.PaperSize.PaperName}, Printer={_printDocForSetup.PrinterSettings.PrinterName}"); + } + else + { + lblStatus.Text = "Настройка принтера отменена."; + } + } + + // --- Получение данных из API --- + private async void btnGetData_Click(object sender, EventArgs e) + { + OzonStore selectedStore = cmbStores.SelectedItem as OzonStore; + if (selectedStore == null) { MessageBox.Show("Выберите магазин.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } + + string clientId = selectedStore.ClientId; + string apiKey = DecryptApiKey(selectedStore.EncryptedApiKey); + if (apiKey == null) { lblStatus.Text = "Ошибка ключа API."; return; } + + string rawOfferId = txtOfferId.Text.Trim(); + if (string.IsNullOrEmpty(rawOfferId)) { MessageBox.Show("Введите Артикул.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } + + string offerId = Regex.Replace(rawOfferId, @"[^a-zA-Zа-яА-Я0-9_-]", ""); + if (string.IsNullOrEmpty(offerId)) { MessageBox.Show("Артикул некорректен.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } + if (offerId != rawOfferId) { txtOfferId.Text = offerId; } + + ResetProductData(); + lblStatus.Text = "Запрос данных..."; + Application.DoEvents(); + + _httpClient.DefaultRequestHeaders.Remove("Client-Id"); + _httpClient.DefaultRequestHeaders.Remove("Api-Key"); + _httpClient.DefaultRequestHeaders.Add("Client-Id", clientId); + _httpClient.DefaultRequestHeaders.Add("Api-Key", apiKey); + + string responseBody = string.Empty; + try + { + var requestData = new { offer_id = new[] { offerId } }; + var jsonRequest = JsonConvert.SerializeObject(requestData); + var content = new StringContent(jsonRequest, Encoding.UTF8, "application/json"); + + HttpResponseMessage response = await _httpClient.PostAsync("/v3/product/info/list", content); + responseBody = await response.Content.ReadAsStringAsync(); + System.Diagnostics.Debug.WriteLine($"API Response ({response.StatusCode}): {responseBody}"); + + if (response.IsSuccessStatusCode) + { + JObject jsonResponse = JObject.Parse(responseBody); + JToken itemsArray = jsonResponse["items"]; + + if (itemsArray != null && itemsArray.Type == JTokenType.Array && itemsArray.HasValues) + { + JToken firstItem = itemsArray[0]; + if (firstItem != null) + { + _currentProductName = firstItem["name"]?.ToString() ?? "N/A"; + _currentSku = firstItem["offer_id"]?.ToString() ?? offerId; + _currentBarcode = firstItem["barcode"]?.ToString(); + if (string.IsNullOrEmpty(_currentBarcode)) + { + JToken barcodesToken = firstItem["barcodes"]; + if (barcodesToken != null && barcodesToken.Type == JTokenType.Array && barcodesToken.HasValues) + { _currentBarcode = barcodesToken.First?.ToString(); } + } + _currentBarcode = _currentBarcode ?? "N/A"; + + GenerateLabelPreview(); // Обновляем UI и включаем кнопку печати + } + else { HandleApiError("Нет данных о товаре в ответе.", responseBody); } + } + else { HandleApiError("Ответ API не содержит списка товаров.", responseBody); } + } + else { HandleApiError($"Ошибка API: {response.StatusCode}", responseBody); } + } + catch (JsonReaderException jsonEx) { MessageBox.Show($"Ошибка JSON: {jsonEx.Message}\n{responseBody}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); ResetProductData(); } + catch (HttpRequestException httpEx) { MessageBox.Show($"Ошибка сети: {httpEx.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); ResetProductData(); } + catch (Exception ex) { MessageBox.Show($"Ошибка: {ex.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); ResetProductData(); } + finally { apiKey = null; } + } + + // Обработка ошибок API + private void HandleApiError(string messagePrefix, string responseBody) + { + string errorMessage = $"{messagePrefix}"; + try + { + JObject errorJson = JObject.Parse(responseBody); + string ozonError = errorJson["message"]?.ToString() ?? errorJson["error"]?["message"]?.ToString(); + errorMessage = string.IsNullOrEmpty(ozonError) ? $"{messagePrefix}\n{responseBody}" : $"{messagePrefix}\n{ozonError}"; + } + catch { errorMessage = $"{messagePrefix}\n{responseBody}"; } + + MessageBox.Show(errorMessage, "Ошибка API Ozon", MessageBoxButtons.OK, MessageBoxIcon.Error); + lblStatus.Text = "Ошибка API."; + ResetProductData(); + } + + // Сброс данных о товаре и состояния UI + private void ResetProductData() + { + _currentProductName = null; + _currentSku = null; + _currentBarcode = null; + lblProductName.Text = "Название:"; + lblProductSku.Text = "Артикул:"; + lblProductBarcode.Text = "Штрихкод:"; + // Очищаем превью, если оно есть + if (this.Controls.ContainsKey("picLabelPreview")) + (this.Controls["picLabelPreview"] as PictureBox).Image = null; + btnPrintLabel.Enabled = false; + // lblStatus.Text = "Статус:"; + } + + // Генерация (только обновление UI) + private void GenerateLabelPreview() + { + bool dataAvailable = !string.IsNullOrEmpty(_currentSku) && + !string.IsNullOrEmpty(_currentProductName) && + !string.IsNullOrEmpty(_currentBarcode) && + _currentBarcode != "N/A"; + if (!dataAvailable) { ResetProductData(); return; } + + lblProductName.Text = $"Название: {_currentProductName}"; + lblProductSku.Text = $"Артикул: {_currentSku}"; + lblProductBarcode.Text = $"Штрихкод: {_currentBarcode}"; + + // Очистка превью, если оно есть + if (this.Controls.ContainsKey("picLabelPreview")) + (this.Controls["picLabelPreview"] as PictureBox).Image = null; + + btnPrintLabel.Enabled = true; + lblStatus.Text = "Данные получены, готово к печати."; + } + + + // --- Печать --- + + // Кнопка "Печать этикетки" + private void btnPrintLabel_Click(object sender, EventArgs e) + { + if (string.IsNullOrEmpty(_currentSku) || string.IsNullOrEmpty(_currentProductName) || string.IsNullOrEmpty(_currentBarcode) || _currentBarcode == "N/A") + { + MessageBox.Show("Нет данных для печати.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + PrintDialog printDialog = new PrintDialog(); + printDialog.Document = _printDocForSetup; // Используем настроенный документ + printDialog.AllowSomePages = false; + printDialog.AllowSelection = false; + printDialog.UseEXDialog = true; + + if (printDialog.ShowDialog(this) == DialogResult.OK) + { + // _printDocForSetup уже содержит принтер и настройки страницы, выбранные в PrintDialog или PageSetupDialog + // Переустанавливаем поля на случай, если PrintDialog их сбросил + _printDocForSetup.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0); + _printDocForSetup.OriginAtMargins = false; + + try + { + lblStatus.Text = $"Печать на {_printDocForSetup.PrinterSettings.PrinterName}..."; + _printDocForSetup.Print(); // Печатаем с текущими настройками + lblStatus.Text = "Отправлено на печать."; + } + catch (InvalidPrinterException) + { + MessageBox.Show($"Ошибка: Принтер '{_printDocForSetup.PrinterSettings.PrinterName}' недоступен или не найден.\nПроверьте подключение или выберите другой принтер в настройках.", "Ошибка принтера", MessageBoxButtons.OK, MessageBoxIcon.Error); + lblStatus.Text = "Ошибка принтера."; + } + + catch (Exception ex) + { + MessageBox.Show($"Ошибка печати: {ex.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); + lblStatus.Text = "Ошибка печати."; + } + } + else { lblStatus.Text = "Печать отменена."; } + + printDialog.Dispose(); + } + + // Метод отрисовки страницы для печати (динамический) + private void pd_PrintPage(object sender, PrintPageEventArgs e) + { + // Проверка данных + if (string.IsNullOrEmpty(_currentSku) || string.IsNullOrEmpty(_currentProductName) || string.IsNullOrEmpty(_currentBarcode) || _currentBarcode == "N/A") + { System.Diagnostics.Debug.WriteLine("PrintPage ABORTED - Missing data!"); e.Cancel = true; return; } + + Graphics g = e.Graphics; + // Получаем РЕАЛЬНЫЕ границы печатаемой области в единицах Graphics (обычно сотые дюйма) + // Не PageBounds, а PrintableArea! PageBounds - это физический размер листа. + RectangleF printArea = e.PageSettings.PrintableArea; + + // Отступы от КРАЕВ ПЕЧАТАЕМОЙ ОБЛАСТИ (в единицах Graphics) + // Подбирайте эти значения, чтобы получить рамку внутри печатаемой зоны + float marginX = 5 * g.DpiX / 100f; // Пример: 5/100 дюйма -> в единицах Graphics + float marginY = 3 * g.DpiY / 100f; // Пример: 3/100 дюйма -> в единицах Graphics + + // Область для рисования контента внутри отступов + float drawableX = printArea.Left + marginX; + float drawableY = printArea.Top + marginY; + float drawableWidth = printArea.Width - (marginX * 2); + float drawableHeight = printArea.Height - (marginY * 2); + float currentY = drawableY; // Текущая позиция по Y + + // Проверка на валидность области + if (drawableWidth <= 0 || drawableHeight <= 0) { System.Diagnostics.Debug.WriteLine("PrintPage ABORTED - Invalid drawable area!"); e.Cancel = true; return; } + + System.Diagnostics.Debug.WriteLine("--- Printing Page (Dynamic) ---"); + System.Diagnostics.Debug.WriteLine($"Paper: {e.PageSettings.PaperSize.PaperName} ({e.PageSettings.PaperSize.Width}x{e.PageSettings.PaperSize.Height}) hund.inch"); + System.Diagnostics.Debug.WriteLine($"PrintableArea ({g.PageUnit}): X={printArea.X:F2}, Y={printArea.Y:F2}, W={printArea.Width:F2}, H={printArea.Height:F2}"); + System.Diagnostics.Debug.WriteLine($"Drawable Area ({g.PageUnit}): X={drawableX:F2}, Y={drawableY:F2}, W={drawableWidth:F2}, H={drawableHeight:F2}"); + + // Шрифты (размер в пунктах) + float baseFontSizePoints = 6f; // Базовый размер, можно менять + Font titleFont = new Font("Arial", baseFontSizePoints + 1, FontStyle.Bold); + Font regularFont = new Font("Arial", baseFontSizePoints); + Font barcodeTextFont = new Font("Arial", baseFontSizePoints - 1); + + try + { + // --- Рисуем Название --- + string productName = _currentProductName ?? "N/A"; + SizeF titleSize = g.MeasureString(productName, titleFont, (int)drawableWidth); + // Ограничиваем высоту, чтобы поместилось остальное + float maxTitleHeight = drawableHeight * 0.3f; + float actualTitleHeight = Math.Min(titleSize.Height, maxTitleHeight); + g.DrawString(productName, titleFont, Brushes.Black, new RectangleF(drawableX, currentY, drawableWidth, actualTitleHeight)); + currentY += actualTitleHeight + (2 * g.DpiY / 72f); // Отступ 2 пункта + + // --- Рисуем Артикул --- + string skuText = $"Артикул: {_currentSku ?? "N/A"}"; + SizeF skuSize = g.MeasureString(skuText, regularFont, (int)drawableWidth); + if (currentY + skuSize.Height < printArea.Bottom - marginY - 15 * 100f / g.DpiY) // Оставляем ~15px под ШК + текст + { + g.DrawString(skuText, regularFont, Brushes.Black, drawableX, currentY); + currentY += skuSize.Height + (3 * g.DpiY / 72f); // Отступ 3 пункта + } + + // --- Рисуем Штрихкод --- + float remainingHeight = (printArea.Bottom - marginY) - currentY; // Оставшаяся высота + if (remainingHeight > 15 * 100f / g.DpiY) // Если осталось хотя бы ~15px + { + try + { + // --- Расчет размеров ШК --- + float barcodeTextHeight = g.MeasureString(_currentBarcode, barcodeTextFont).Height; + float barcodePrintHeight = Math.Max(10 * 100f / g.DpiY, remainingHeight - barcodeTextHeight - (2 * g.DpiY / 72f)); // Вычитаем текст и отступ + float barcodePrintWidth = drawableWidth * 0.98f; + + int barcodePixelHeight = (int)(barcodePrintHeight * g.DpiY / 100f); + int barcodePixelWidth = (int)(barcodePrintWidth * g.DpiX / 100f); + if (barcodePixelHeight < 10 || barcodePixelWidth < 40) throw new Exception("Слишком мало места для ШК."); + + BarcodeFormat barcodeFormat = BarcodeFormat.CODE_128; + // ... (определение barcodeFormat) ... + if (_currentBarcode.Length == 13 && long.TryParse(_currentBarcode, out _)) barcodeFormat = BarcodeFormat.EAN_13; + else if (_currentBarcode.Length == 8 && long.TryParse(_currentBarcode, out _)) barcodeFormat = BarcodeFormat.EAN_8; + + var barcodeWriter = new ZXing.Windows.Compatibility.BarcodeWriter { Format = barcodeFormat, Options = new EncodingOptions { Height = barcodePixelHeight, Width = barcodePixelWidth, PureBarcode = true, Margin = 1 } }; + + using (var barcodeBitmap = barcodeWriter.Write(_currentBarcode)) + { + float barcodeX = drawableX + (drawableWidth - barcodePrintWidth) / 2.0f; // Центрируем + g.DrawImage(barcodeBitmap, barcodeX, currentY, barcodePrintWidth, barcodePrintHeight); + currentY += barcodePrintHeight + (1 * g.DpiY / 72f); // Отступ 1 пункт + } + + // --- Рисуем текст ШК --- + SizeF barcodeTextSize = g.MeasureString(_currentBarcode, barcodeTextFont); + if (currentY + barcodeTextSize.Height <= printArea.Bottom - marginY) + { + float textX = drawableX + (drawableWidth - barcodeTextSize.Width) / 2.0f; // Центрируем + g.DrawString(_currentBarcode, barcodeTextFont, Brushes.Black, textX, currentY); + } + else { System.Diagnostics.Debug.WriteLine("SKIPPING Barcode text - no space"); } + + } + catch (Exception exBarcode) + { + System.Diagnostics.Debug.WriteLine($"Error drawing barcode: {exBarcode.Message}"); + g.DrawString("Ошибка ШК", regularFont, Brushes.Red, drawableX, currentY); // Рисуем ошибку вместо ШК + } + } + else { System.Diagnostics.Debug.WriteLine("SKIPPING Barcode - not enough vertical space"); } + + } + catch (Exception exDraw) { System.Diagnostics.Debug.WriteLine($"Error drawing page: {exDraw}"); } + finally { titleFont.Dispose(); regularFont.Dispose(); barcodeTextFont.Dispose(); } + + e.HasMorePages = false; + } + + } // Конец класса Form1 +} // Конец namespace \ No newline at end of file diff --git a/Form1.resx b/Form1.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/Form1.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/FormManageStores.Designer.cs b/FormManageStores.Designer.cs new file mode 100644 index 0000000..09e93fd --- /dev/null +++ b/FormManageStores.Designer.cs @@ -0,0 +1,201 @@ +namespace SKLADm +{ + partial class FormManageStores + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lstStores = new System.Windows.Forms.ListBox(); + this.label1 = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.btnAddStore = new System.Windows.Forms.Button(); + this.txtEditApiKey = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.txtEditClientId = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.txtStoreName = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.btnDeleteStore = new System.Windows.Forms.Button(); + this.btnClose = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // lstStores + // + this.lstStores.FormattingEnabled = true; + this.lstStores.Location = new System.Drawing.Point(12, 25); + this.lstStores.Name = "lstStores"; + this.lstStores.Size = new System.Drawing.Size(188, 199); // Adjust height as needed + this.lstStores.TabIndex = 0; + // Add event handler if you want to display details on selection: + // this.lstStores.SelectedIndexChanged += new System.EventHandler(this.lstStores_SelectedIndexChanged); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(121, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Сохраненные магазины:"; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.btnAddStore); + this.groupBox1.Controls.Add(this.txtEditApiKey); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.txtEditClientId); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.txtStoreName); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Location = new System.Drawing.Point(219, 25); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(303, 155); // Adjust size as needed + this.groupBox1.TabIndex = 2; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Добавить новый магазин"; + // + // btnAddStore + // + this.btnAddStore.Location = new System.Drawing.Point(196, 118); + this.btnAddStore.Name = "btnAddStore"; + this.btnAddStore.Size = new System.Drawing.Size(97, 23); + this.btnAddStore.TabIndex = 6; + this.btnAddStore.Text = "Добавить"; + this.btnAddStore.UseVisualStyleBackColor = true; + this.btnAddStore.Click += new System.EventHandler(this.btnAddStore_Click); + // + // txtEditApiKey + // + this.txtEditApiKey.Location = new System.Drawing.Point(74, 86); + this.txtEditApiKey.Name = "txtEditApiKey"; + this.txtEditApiKey.PasswordChar = '*'; + this.txtEditApiKey.Size = new System.Drawing.Size(219, 20); + this.txtEditApiKey.TabIndex = 5; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(16, 89); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(48, 13); + this.label4.TabIndex = 4; + this.label4.Text = "Api-Key:"; + // + // txtEditClientId + // + this.txtEditClientId.Location = new System.Drawing.Point(74, 57); + this.txtEditClientId.Name = "txtEditClientId"; + this.txtEditClientId.Size = new System.Drawing.Size(219, 20); + this.txtEditClientId.TabIndex = 3; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(16, 60); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(50, 13); + this.label3.TabIndex = 2; + this.label3.Text = "Client ID:"; + // + // txtStoreName + // + this.txtStoreName.Location = new System.Drawing.Point(74, 28); + this.txtStoreName.Name = "txtStoreName"; + this.txtStoreName.Size = new System.Drawing.Size(219, 20); + this.txtStoreName.TabIndex = 1; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(16, 31); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(60, 13); + this.label2.TabIndex = 0; + this.label2.Text = "Название:"; + // + // btnDeleteStore + // + this.btnDeleteStore.Location = new System.Drawing.Point(12, 230); // Position below listbox + this.btnDeleteStore.Name = "btnDeleteStore"; + this.btnDeleteStore.Size = new System.Drawing.Size(188, 23); + this.btnDeleteStore.TabIndex = 3; + this.btnDeleteStore.Text = "Удалить выбранный"; + this.btnDeleteStore.UseVisualStyleBackColor = true; + this.btnDeleteStore.Click += new System.EventHandler(this.btnDeleteStore_Click); + // + // btnClose + // + this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel; // Makes Esc close the form + this.btnClose.Location = new System.Drawing.Point(447, 230); // Position bottom right + this.btnClose.Name = "btnClose"; + this.btnClose.Size = new System.Drawing.Size(75, 23); + this.btnClose.TabIndex = 4; + this.btnClose.Text = "Закрыть"; + this.btnClose.UseVisualStyleBackColor = true; + this.btnClose.Click += new System.EventHandler(this.btnClose_Click); + // + // FormManageStores + // + this.AcceptButton = this.btnAddStore; // Enter in groupbox adds store + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnClose; // Esc closes form + this.ClientSize = new System.Drawing.Size(534, 267); // Adjust size as needed + this.Controls.Add(this.btnClose); + this.Controls.Add(this.btnDeleteStore); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.label1); + this.Controls.Add(this.lstStores); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; // Prevent resizing + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "FormManageStores"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; // Center over Form1 + this.Text = "Управление магазинами Ozon"; + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.ListBox lstStores; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.Button btnAddStore; + private System.Windows.Forms.TextBox txtEditApiKey; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.TextBox txtEditClientId; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.TextBox txtStoreName; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.Button btnDeleteStore; + private System.Windows.Forms.Button btnClose; + } +} diff --git a/FormManageStores.cs b/FormManageStores.cs new file mode 100644 index 0000000..41df99e --- /dev/null +++ b/FormManageStores.cs @@ -0,0 +1,150 @@ +using Newtonsoft.Json; +using OzonInternalLabelPrinter; // Добавляем пространство имен для OzonStore +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; // Для ProtectedData +using System.Text; +using System.Windows.Forms; + +namespace SKLADm +{ + public partial class FormManageStores : Form + { + private List _stores; + // Энтропия для шифрования (можно оставить null или использовать свой секрет) + private static readonly byte[] s_entropy = null; // Или Encoding.UTF8.GetBytes("MyOptionalEntropy"); + + public FormManageStores() + { + InitializeComponent(); + LoadStoresToListBox(); + } + + // --- Шифрование Api-Key --- + private string EncryptApiKey(string apiKey) + { + if (string.IsNullOrEmpty(apiKey)) return string.Empty; + try + { + byte[] apiKeyBytes = Encoding.UTF8.GetBytes(apiKey); + byte[] encryptedBytes = ProtectedData.Protect(apiKeyBytes, s_entropy, DataProtectionScope.CurrentUser); + return Convert.ToBase64String(encryptedBytes); + } + catch (Exception ex) + { + MessageBox.Show($"Ошибка шифрования ключа: {ex.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); + return null; // Возвращаем null при ошибке + } + } + + // --- Загрузка магазинов из настроек --- + private void LoadStoresToListBox() + { + string json = Properties.Settings.Default.SavedStoresJson; + _stores = new List(); + if (!string.IsNullOrEmpty(json)) + { + try + { + _stores = JsonConvert.DeserializeObject>(json) ?? new List(); + } + catch (Exception ex) + { + MessageBox.Show($"Ошибка загрузки списка магазинов: {ex.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning); + _stores = new List(); // Создаем пустой список при ошибке + } + } + UpdateListBox(); + } + + // --- Сохранение магазинов в настройки --- + private void SaveStores() + { + try + { + string json = JsonConvert.SerializeObject(_stores, Formatting.Indented); + Properties.Settings.Default.SavedStoresJson = json; + Properties.Settings.Default.Save(); + } + catch (Exception ex) + { + MessageBox.Show($"Ошибка сохранения списка магазинов: {ex.Message}", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + // --- Обновление ListBox --- + private void UpdateListBox() + { + lstStores.DataSource = null; // Сначала отвязываем источник + lstStores.DataSource = _stores; // Привязываем обновленный список + lstStores.DisplayMember = "StoreName"; // Отображаем имя + } + + // --- Кнопка "Добавить магазин" --- + private void btnAddStore_Click(object sender, EventArgs e) + { + string storeName = txtStoreName.Text.Trim(); + string clientId = txtEditClientId.Text.Trim(); + string apiKey = txtEditApiKey.Text.Trim(); // Берем ключ как есть + + if (string.IsNullOrEmpty(storeName) || string.IsNullOrEmpty(clientId) || string.IsNullOrEmpty(apiKey)) + { + MessageBox.Show("Пожалуйста, заполните все поля: Название, Client ID, Api-Key.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + // Проверяем, нет ли уже магазина с таким именем + if (_stores.Any(s => s.StoreName.Equals(storeName, StringComparison.OrdinalIgnoreCase))) + { + MessageBox.Show("Магазин с таким названием уже существует.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Warning); + return; + } + + // Шифруем ключ + string encryptedKey = EncryptApiKey(apiKey); + if (encryptedKey == null) // Если шифрование не удалось + { + return; + } + + // Создаем и добавляем магазин + OzonStore newStore = new OzonStore(storeName, clientId, encryptedKey); + _stores.Add(newStore); + + // Сохраняем и обновляем список + SaveStores(); + UpdateListBox(); + + // Очищаем поля ввода + txtStoreName.Clear(); + txtEditClientId.Clear(); + txtEditApiKey.Clear(); + } + + // --- Кнопка "Удалить выбранный" (Опционально) --- + private void btnDeleteStore_Click(object sender, EventArgs e) + { + if (lstStores.SelectedItem is OzonStore selectedStore) + { + if (MessageBox.Show($"Вы уверены, что хотите удалить магазин '{selectedStore.StoreName}'?", "Подтверждение", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) + { + _stores.Remove(selectedStore); + SaveStores(); + UpdateListBox(); + } + } + else + { + MessageBox.Show("Выберите магазин для удаления.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + } + + // --- Кнопка "Закрыть" --- + private void btnClose_Click(object sender, EventArgs e) + { + this.DialogResult = DialogResult.OK; // Указываем, что форма закрыта штатно + this.Close(); + } + } +} diff --git a/FormManageStores.resx b/FormManageStores.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/FormManageStores.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/OzonStore.cs b/OzonStore.cs new file mode 100644 index 0000000..54b28ee --- /dev/null +++ b/OzonStore.cs @@ -0,0 +1,28 @@ +using System; + +namespace OzonInternalLabelPrinter +{ + [Serializable] // Важно для возможной сериализации в будущем, хотя с JSON необязательно + public class OzonStore + { + public string StoreName { get; set; } // Имя, которое видит пользователь + public string ClientId { get; set; } + public string EncryptedApiKey { get; set; } // Храним ЗАШИФРОВАННЫЙ ключ + + // Конструктор для удобства + public OzonStore(string name, string clientId, string encryptedKey) + { + StoreName = name; + ClientId = clientId; + EncryptedApiKey = encryptedKey; + } + + public OzonStore() { } // Пустой конструктор для сериализации + + // Переопределяем ToString, чтобы в ComboBox отображалось имя + public override string ToString() + { + return StoreName ?? "Без имени"; + } + } +} \ No newline at end of file diff --git a/Program.cs b/Program.cs new file mode 100644 index 0000000..93fa4e4 --- /dev/null +++ b/Program.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using System.Windows.Forms; +using OzonInternalLabelPrinter; // Добавляем директиву using для пространства имен с Form1 + +namespace SKLADm +{ + internal static class Program + { + /// + /// Главная точка входа для приложения. + /// + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..d9343ab --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,33 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Общие сведения об этой сборке предоставляются следующим набором +// набора атрибутов. Измените значения этих атрибутов для изменения сведений, +// связанных со сборкой. +[assembly: AssemblyTitle("SKLADm")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("SKLADm")] +[assembly: AssemblyCopyright("Copyright © 2025")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Установка значения False для параметра ComVisible делает типы в этой сборке невидимыми +// для компонентов COM. Если необходимо обратиться к типу в этой сборке через +// COM, следует установить атрибут ComVisible в TRUE для этого типа. +[assembly: ComVisible(false)] + +// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM +[assembly: Guid("17f6818e-f645-43c4-a25a-eab41e5e1be6")] + +// Сведения о версии сборки состоят из указанных ниже четырех значений: +// +// Основной номер версии +// Дополнительный номер версии +// Номер сборки +// Редакция +// +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs new file mode 100644 index 0000000..6630341 --- /dev/null +++ b/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// Этот код создан программным средством. +// Версия среды выполнения: 4.0.30319.42000 +// +// Изменения в этом файле могут привести к неправильному поведению и будут утрачены, если +// код создан повторно. +// +//------------------------------------------------------------------------------ + +namespace SKLADm.Properties +{ + + + /// + /// Класс ресурсов со строгим типом для поиска локализованных строк и пр. + /// + // Этот класс был автоматически создан при помощи StronglyTypedResourceBuilder + // класс с помощью таких средств, как ResGen или Visual Studio. + // Для добавления или удаления члена измените файл .ResX, а затем перезапустите ResGen + // с параметром /str или заново постройте свой VS-проект. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Возврат кэшированного экземпляра ResourceManager, используемого этим классом. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("SKLADm.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Переопределяет свойство CurrentUICulture текущего потока для всех + /// подстановки ресурсов с помощью этого класса ресурсов со строгим типом. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/Properties/Resources.resx b/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs new file mode 100644 index 0000000..0c10770 --- /dev/null +++ b/Properties/Settings.Designer.cs @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------------ +// +// Этот код создан программой. +// Исполняемая версия:4.0.30319.42000 +// +// Изменения в этом файле могут привести к неправильной работе и будут потеряны в случае +// повторной генерации кода. +// +//------------------------------------------------------------------------------ + +namespace SKLADm.Properties { + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.13.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default { + get { + return defaultInstance; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("")] + public string SavedStoresJson { + get { + return ((string)(this["SavedStoresJson"])); + } + set { + this["SavedStoresJson"] = value; + } + } + } +} diff --git a/Properties/Settings.settings b/Properties/Settings.settings new file mode 100644 index 0000000..da36574 --- /dev/null +++ b/Properties/Settings.settings @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/SKLADm.csproj b/SKLADm.csproj new file mode 100644 index 0000000..502966b --- /dev/null +++ b/SKLADm.csproj @@ -0,0 +1,122 @@ + + + + + Debug + AnyCPU + {17F6818E-F645-43C4-A25A-EAB41E5E1BE6} + WinExe + SKLADm + SKLADm + v4.6.2 + 512 + true + true + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + + + packages\System.Drawing.Common.8.0.12\lib\net462\System.Drawing.Common.dll + + + + packages\System.Security.Cryptography.ProtectedData.9.0.4\lib\net462\System.Security.Cryptography.ProtectedData.dll + + + + + + + + + + + + packages\ZXing.Net.0.16.10\lib\net461\zxing.dll + + + packages\ZXing.Net.0.16.10\lib\net461\zxing.presentation.dll + + + packages\ZXing.Net.Bindings.Windows.Compatibility.0.16.13\lib\netstandard2.0\ZXing.Windows.Compatibility.dll + + + + + Form + + + Form1.cs + + + Form + + + FormManageStores.cs + + + + + + Form1.cs + + + FormManageStores.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + Designer + + + True + Resources.resx + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + True + Settings.settings + True + + + + + + + + + + Данный проект ссылается на пакеты NuGet, отсутствующие на этом компьютере. Используйте восстановление пакетов NuGet, чтобы скачать их. Дополнительную информацию см. по адресу: http://go.microsoft.com/fwlink/?LinkID=322105. Отсутствует следующий файл: {0}. + + + + \ No newline at end of file diff --git a/SKLADm.sln b/SKLADm.sln new file mode 100644 index 0000000..e5a9478 --- /dev/null +++ b/SKLADm.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.13.35913.81 d17.13 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SKLADm", "SKLADm.csproj", "{17F6818E-F645-43C4-A25A-EAB41E5E1BE6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {17F6818E-F645-43C4-A25A-EAB41E5E1BE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {17F6818E-F645-43C4-A25A-EAB41E5E1BE6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {17F6818E-F645-43C4-A25A-EAB41E5E1BE6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {17F6818E-F645-43C4-A25A-EAB41E5E1BE6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {58FC063D-E3B8-421B-BCB0-0349A0C4DCDB} + EndGlobalSection +EndGlobal diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..c09cfa3 --- /dev/null +++ b/packages.config @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file