v1.0.4: адаптация desktop к текущему buyer API

Перевести desktop-клиент на работу с текущими buyer orders и локальным SQLite-кешем, чтобы отправка заказов и синхронизация документов работали с уже развернутым сервером без старых MSSQL-зависимостей.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Exest 2026-07-28 11:41:00 +03:00
parent 4b3b2c8ca8
commit e35e67849f
9 changed files with 570 additions and 103 deletions

View File

@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Электроннаяармация.Classes
{
@ -155,20 +158,101 @@ namespace Электронная_Фармация.Classes
}
public async Task<List<InvoiceApiItem>> GetInvoicesAsync()
{
var orders = await GetBuyerOrdersAsync(status: "Placed", limit: 200);
var result = new List<InvoiceApiItem>();
foreach (var order in orders)
{
var detail = await GetBuyerOrderByIdAsync(order.OrderID);
if (detail == null)
{
continue;
}
result.Add(InvoiceApiItem.FromBuyerOrder(detail));
}
AppDebugLog.Info("ApiClient", $"Накладные (через buyer/orders) получены: {result.Count} шт.");
return result;
}
public async Task<List<BuyerOrderListItemDto>> GetBuyerOrdersAsync(string status = null, int limit = 200, int offset = 0)
{
EnsureAuthenticated();
var responseBody = await SendAuthorizedGetAsync("/api/buyer/invoices", "загрузку накладных");
var query = new List<string>();
if (!string.IsNullOrWhiteSpace(status))
{
query.Add($"status={Uri.EscapeDataString(status)}");
}
if (limit > 0)
{
query.Add($"limit={limit}");
}
if (offset > 0)
{
query.Add($"offset={offset}");
}
var path = "/api/buyer/orders";
if (query.Count > 0)
{
path += "?" + string.Join("&", query);
}
var responseBody = await SendAuthorizedGetAsync(path, "загрузку заказов");
try
{
var items = JsonSerializer.Deserialize<List<InvoiceApiItem>>(responseBody, JsonOptions) ?? new List<InvoiceApiItem>();
AppDebugLog.Info("ApiClient", $"Накладные получены: {items.Count} шт.");
return items;
var response = JsonSerializer.Deserialize<BuyerOrdersResponse>(responseBody, JsonOptions);
return response?.Orders ?? new List<BuyerOrderListItemDto>();
}
catch (Exception ex)
{
AppDebugLog.Error("ApiClient", "Не удалось разобрать ответ накладных", ex);
throw new HttpRequestException($"Некорректный ответ сервера при загрузке накладных: {ex.Message}", ex);
AppDebugLog.Error("ApiClient", "Не удалось разобрать список заказов", ex);
throw new HttpRequestException($"Некорректный ответ сервера при загрузке заказов: {ex.Message}", ex);
}
}
public async Task<BuyerOrderDetailDto> GetBuyerOrderByIdAsync(string orderId)
{
EnsureAuthenticated();
if (string.IsNullOrWhiteSpace(orderId))
{
throw new ArgumentException("Не указан ID заказа.", nameof(orderId));
}
var responseBody = await SendAuthorizedGetAsync($"/api/buyer/orders/{Uri.EscapeDataString(orderId)}", "загрузку заказа");
try
{
return JsonSerializer.Deserialize<BuyerOrderDetailDto>(responseBody, JsonOptions);
}
catch (Exception ex)
{
AppDebugLog.Error("ApiClient", $"Не удалось разобрать заказ {orderId}", ex);
throw new HttpRequestException($"Некорректный ответ сервера при загрузке заказа: {ex.Message}", ex);
}
}
public async Task<BuyerOrderDetailDto> PlaceBuyerOrderAsync(string orderId)
{
EnsureAuthenticated();
if (string.IsNullOrWhiteSpace(orderId))
{
throw new ArgumentException("Не указан ID заказа.", nameof(orderId));
}
var responseBody = await SendAuthorizedPostAsync($"/api/buyer/orders/{Uri.EscapeDataString(orderId)}/place", string.Empty, "оформление заказа");
try
{
return JsonSerializer.Deserialize<BuyerOrderDetailDto>(responseBody, JsonOptions);
}
catch (Exception ex)
{
AppDebugLog.Error("ApiClient", $"Не удалось разобрать ответ оформления заказа {orderId}", ex);
throw new HttpRequestException($"Некорректный ответ сервера при оформлении заказа: {ex.Message}", ex);
}
}
@ -187,6 +271,63 @@ namespace Электронная_Фармация.Classes
return await SendAuthorizedGetWithProgressAsync(path, operationName, null);
}
private async Task<string> SendAuthorizedPostAsync(string path, string requestBody, string operationName)
{
var fullUrl = BuildFullUrl(path);
var stopwatch = Stopwatch.StartNew();
AppDebugLog.ApiRequest("POST", fullUrl, requestBody, $"token={AppDebugLog.MaskToken(_token)}");
try
{
using (var httpRequest = new HttpRequestMessage(HttpMethod.Post, fullUrl))
{
httpRequest.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _token);
httpRequest.Content = new StringContent(requestBody ?? string.Empty, Encoding.UTF8, "application/json");
var response = await _httpClient.SendAsync(httpRequest);
var responseBody = await response.Content.ReadAsStringAsync();
stopwatch.Stop();
AppDebugLog.ApiResponse("POST", fullUrl, (int)response.StatusCode, stopwatch.ElapsedMilliseconds, responseBody);
if (response.IsSuccessStatusCode)
{
return responseBody;
}
if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized)
{
_token = null;
var error = TryDeserializeError(responseBody);
var message = $"Сессия истекла: {error?.Error ?? "Необходимо войти заново"}";
AppDebugLog.ApiHttpError("POST", fullUrl, (int)response.StatusCode, responseBody, operationName);
throw new UnauthorizedAccessException(message);
}
var httpError = TryDeserializeError(responseBody);
var httpMessage = $"Ошибка HTTP {response.StatusCode}: {httpError?.Error ?? responseBody}";
AppDebugLog.ApiHttpError("POST", fullUrl, (int)response.StatusCode, responseBody, operationName);
throw new HttpRequestException(httpMessage);
}
}
catch (UnauthorizedAccessException)
{
throw;
}
catch (HttpRequestException ex) when (!ex.Message.StartsWith("Ошибка HTTP"))
{
stopwatch.Stop();
AppDebugLog.ApiFailure("POST", fullUrl, stopwatch.ElapsedMilliseconds, ex);
throw WrapNetworkError(ex, operationName);
}
catch (TaskCanceledException ex)
{
stopwatch.Stop();
AppDebugLog.ApiFailure("POST", fullUrl, stopwatch.ElapsedMilliseconds, ex);
throw WrapNetworkError(ex, operationName);
}
}
private async Task<string> SendAuthorizedGetWithProgressAsync(
string path,
string operationName,
@ -372,6 +513,127 @@ namespace Электронная_Фармация.Classes
public string ConsigneeName { get; set; }
public string InvoiceSum { get; set; }
public string RefuseSum { get; set; }
public string SourceOrderId { get; set; }
public List<InvoiceApiOrderItem> Items { get; set; } = new List<InvoiceApiOrderItem>();
public static InvoiceApiItem FromBuyerOrder(BuyerOrderDetailDto detail)
{
var supplierNames = detail.Items == null
? string.Empty
: string.Join(", ", detail.Items
.Select(i => i.Supplier)
.Where(s => !string.IsNullOrWhiteSpace(s))
.Distinct());
var invoiceDate = detail.PlacedAt ?? detail.CreatedAt;
var invoice = new InvoiceApiItem
{
InvoiceNumber = string.IsNullOrWhiteSpace(detail.LocalOrderNumber)
? detail.OrderID
: detail.LocalOrderNumber,
InvoiceDate = invoiceDate?.ToString("yyyy-MM-dd") ?? string.Empty,
SupplierName = supplierNames,
ConsigneeName = detail.LocationAddress ?? string.Empty,
InvoiceSum = (detail.TotalAmount ?? 0m).ToString(System.Globalization.CultureInfo.InvariantCulture),
RefuseSum = "0",
SourceOrderId = detail.OrderID
};
if (detail.Items != null)
{
foreach (var item in detail.Items)
{
invoice.Items.Add(new InvoiceApiOrderItem
{
GoodCode = item.ItemCode ?? string.Empty,
GoodName = item.Name ?? string.Empty,
SupplierName = item.Supplier ?? string.Empty,
Qty = item.Qty,
Price = item.UnitPrice,
Total = item.Total
});
}
}
return invoice;
}
}
public sealed class InvoiceApiOrderItem
{
public string GoodCode { get; set; }
public string GoodName { get; set; }
public string SupplierName { get; set; }
public decimal Qty { get; set; }
public decimal Price { get; set; }
public decimal Total { get; set; }
}
public sealed class BuyerOrdersResponse
{
[JsonPropertyName("orders")]
public List<BuyerOrderListItemDto> Orders { get; set; }
}
public sealed class BuyerOrderListItemDto
{
[JsonPropertyName("order_id")]
public string OrderID { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
}
public sealed class BuyerOrderDetailDto
{
[JsonPropertyName("order_id")]
public string OrderID { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
[JsonPropertyName("total_amount")]
public decimal? TotalAmount { get; set; }
[JsonPropertyName("created_at")]
public DateTime? CreatedAt { get; set; }
[JsonPropertyName("placed_at")]
public DateTime? PlacedAt { get; set; }
[JsonPropertyName("comment")]
public string Comment { get; set; }
[JsonPropertyName("location_address")]
public string LocationAddress { get; set; }
[JsonPropertyName("items")]
public List<BuyerOrderItemDetailDto> Items { get; set; }
[JsonIgnore]
public string LocalOrderNumber { get; set; }
}
public sealed class BuyerOrderItemDetailDto
{
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("supplier")]
public string Supplier { get; set; }
[JsonPropertyName("qty")]
public decimal Qty { get; set; }
[JsonPropertyName("unit_price")]
public decimal UnitPrice { get; set; }
[JsonPropertyName("total")]
public decimal Total { get; set; }
[JsonPropertyName("item_code")]
public string ItemCode { get; set; }
}
public sealed class HttpTransferProgress

View File

@ -272,7 +272,13 @@ WHERE Orders.OrderState = 'НОВЫЙ'
return false;
}
MarkOrderSent(order.LocalOrderId);
var createdOrder = JsonSerializer.Deserialize<BuyerOrderCreateResult>(responseString, options);
if (createdOrder == null || string.IsNullOrWhiteSpace(createdOrder.OrderID))
{
throw new InvalidOperationException("Сервер не вернул order_id созданного заказа.");
}
MarkOrderSent(order.LocalOrderId, createdOrder.OrderID, createdOrder.Status);
AppDebugLog.Info("DataSender", $"Заказ {order.LocalOrderId} отправлен");
return true;
}
@ -286,7 +292,7 @@ WHERE Orders.OrderState = 'НОВЫЙ'
}
}
private static void MarkOrderSent(string localOrderId)
private static void MarkOrderSent(string localOrderId, string remoteOrderId, string remoteStatus)
{
if (string.IsNullOrWhiteSpace(localOrderId))
{
@ -297,9 +303,14 @@ WHERE Orders.OrderState = 'НОВЫЙ'
{
con.Open();
using (var cmd = new SQLiteCommand(
"UPDATE [Orders] SET [OrderState] = 'ОТПРАВЛЕН' WHERE [Id_Order] = @id AND [OrderState] = 'НОВЫЙ'",
@"UPDATE [Orders]
SET [OrderState] = @state,
[RemoteOrderId] = @remoteOrderId
WHERE [Id_Order] = @id AND [OrderState] = 'НОВЫЙ'",
con))
{
cmd.Parameters.AddWithValue("@state", "ОТПРАВЛЕН");
cmd.Parameters.AddWithValue("@remoteOrderId", remoteOrderId ?? string.Empty);
cmd.Parameters.AddWithValue("@id", localOrderId);
cmd.ExecuteNonQuery();
}
@ -357,4 +368,13 @@ WHERE Orders.OrderState = 'НОВЫЙ'
[JsonPropertyName("item_code")]
public string ItemCode { get; set; }
}
public sealed class BuyerOrderCreateResult
{
[JsonPropertyName("order_id")]
public string OrderID { get; set; }
[JsonPropertyName("status")]
public string Status { get; set; }
}
}

View File

@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using Электроннаяармация.Properties;
@ -26,7 +28,29 @@ namespace Электронная_Фармация.Classes
var client = new ApiClient();
client.SetToken(token);
AppDebugLog.Info("InvoiceSync", $"Старт синхронизации накладных. Сервер={client.BaseUrl}");
var items = await client.GetInvoicesAsync();
var orders = await client.GetBuyerOrdersAsync(limit: 200);
var items = new List<InvoiceApiItem>();
using (var con = new SQLiteConnection(AppConfig.SqliteConnectionString))
{
con.Open();
foreach (var order in orders)
{
if (string.Equals(order.Status, "Cancelled", StringComparison.OrdinalIgnoreCase))
{
continue;
}
var detail = await client.GetBuyerOrderByIdAsync(order.OrderID);
if (detail == null)
{
continue;
}
detail.LocalOrderNumber = TryGetLocalOrderNumber(con, detail.OrderID);
items.Add(InvoiceApiItem.FromBuyerOrder(detail));
}
}
var saved = SaveInvoices(items);
AppDebugLog.Info("InvoiceSync", $"Накладные сохранены локально: {saved} шт.");
return saved;
@ -40,30 +64,32 @@ namespace Электронная_Фармация.Classes
private static int SaveInvoices(IReadOnlyList<InvoiceApiItem> items)
{
if (items.Count == 0)
{
return 0;
}
using (var con = new SQLiteConnection(AppConfig.SqliteConnectionString))
{
con.Open();
using (var tx = con.BeginTransaction())
{
using (var cleanupItems = new SQLiteCommand(@"
DELETE FROM InvoiceItem
WHERE idInvoice IN (
SELECT idInvoice FROM Invoice WHERE ifnull(IsRequestedInvoice, 0) = 0
);", con, tx))
{
cleanupItems.ExecuteNonQuery();
}
using (var cleanupInvoices = new SQLiteCommand(
"DELETE FROM Invoice WHERE ifnull(IsRequestedInvoice, 0) = 0;",
con,
tx))
{
cleanupInvoices.ExecuteNonQuery();
}
foreach (var item in items)
{
using (var cmd = new SQLiteCommand(@"
INSERT OR REPLACE INTO Invoice (InvoiceNumber, invoiceDate, SupplierName, ConsigneesName, InvoiceSum, RefuseSum)
VALUES (@number, @date, @supplier, @consignee, @sum, @refuseSum)", con, tx))
{
cmd.Parameters.AddWithValue("@number", item.InvoiceNumber ?? string.Empty);
cmd.Parameters.AddWithValue("@date", item.InvoiceDate ?? string.Empty);
cmd.Parameters.AddWithValue("@supplier", item.SupplierName ?? string.Empty);
cmd.Parameters.AddWithValue("@consignee", item.ConsigneeName ?? string.Empty);
cmd.Parameters.AddWithValue("@sum", item.InvoiceSum ?? string.Empty);
cmd.Parameters.AddWithValue("@refuseSum", item.RefuseSum ?? string.Empty);
cmd.ExecuteNonQuery();
}
var invoiceId = UpsertInvoice(con, tx, item);
SaveInvoiceItems(con, tx, invoiceId, item);
}
tx.Commit();
@ -72,5 +98,192 @@ VALUES (@number, @date, @supplier, @consignee, @sum, @refuseSum)", con, tx))
return items.Count;
}
private static int UpsertInvoice(SQLiteConnection con, SQLiteTransaction tx, InvoiceApiItem item)
{
using (var findCmd = new SQLiteCommand(@"
SELECT [idInvoice]
FROM [Invoice]
WHERE cast([SourceOrderId] as text) = @sourceOrderId
LIMIT 1;", con, tx))
{
findCmd.Parameters.AddWithValue("@sourceOrderId", item.SourceOrderId ?? string.Empty);
var existing = findCmd.ExecuteScalar();
if (existing != null && existing != DBNull.Value)
{
var invoiceId = Convert.ToInt32(existing, CultureInfo.InvariantCulture);
using (var updateCmd = new SQLiteCommand(@"
UPDATE [Invoice]
SET [InvoiceNumber] = @number,
[InvoiceDate] = @date,
[SupplierName] = @supplier,
[ConsigneesName] = @consignee,
[InvoiceSum] = @sum,
[RefuseSum] = @refuseSum,
[SourceOrderNumber] = @sourceOrderNumber,
[IsRequestedInvoice] = 0
WHERE [idInvoice] = @invoiceId;", con, tx))
{
updateCmd.Parameters.AddWithValue("@number", item.InvoiceNumber ?? string.Empty);
updateCmd.Parameters.AddWithValue("@date", item.InvoiceDate ?? string.Empty);
updateCmd.Parameters.AddWithValue("@supplier", item.SupplierName ?? string.Empty);
updateCmd.Parameters.AddWithValue("@consignee", item.ConsigneeName ?? string.Empty);
updateCmd.Parameters.AddWithValue("@sum", item.InvoiceSum ?? "0");
updateCmd.Parameters.AddWithValue("@refuseSum", item.RefuseSum ?? "0");
updateCmd.Parameters.AddWithValue("@sourceOrderNumber", item.InvoiceNumber ?? string.Empty);
updateCmd.Parameters.AddWithValue("@invoiceId", invoiceId);
updateCmd.ExecuteNonQuery();
}
using (var deleteItems = new SQLiteCommand("DELETE FROM [InvoiceItem] WHERE [idInvoice] = @invoiceId;", con, tx))
{
deleteItems.Parameters.AddWithValue("@invoiceId", invoiceId);
deleteItems.ExecuteNonQuery();
}
return invoiceId;
}
}
using (var insertCmd = new SQLiteCommand(@"
INSERT INTO [Invoice]
(
[InvoiceNumber],
[InvoiceDate],
[CodeSupplier],
[CodeConsignees],
[SumWithoutNDS],
[SumWithNDS],
[SumNDS],
[SupplierName],
[ConsigneesName],
[InvoiceSum],
[RefuseSum],
[SourceOrderId],
[SourceOrderNumber],
[IsRequestedInvoice]
)
VALUES
(
@number,
@date,
0,
0,
@sum,
@sum,
0,
@supplier,
@consignee,
@sum,
@refuseSum,
@sourceOrderId,
@sourceOrderNumber,
0
);
SELECT last_insert_rowid();", con, tx))
{
insertCmd.Parameters.AddWithValue("@number", item.InvoiceNumber ?? string.Empty);
insertCmd.Parameters.AddWithValue("@date", item.InvoiceDate ?? string.Empty);
insertCmd.Parameters.AddWithValue("@sum", item.InvoiceSum ?? "0");
insertCmd.Parameters.AddWithValue("@supplier", item.SupplierName ?? string.Empty);
insertCmd.Parameters.AddWithValue("@consignee", item.ConsigneeName ?? string.Empty);
insertCmd.Parameters.AddWithValue("@refuseSum", item.RefuseSum ?? "0");
insertCmd.Parameters.AddWithValue("@sourceOrderId", item.SourceOrderId ?? string.Empty);
insertCmd.Parameters.AddWithValue("@sourceOrderNumber", item.InvoiceNumber ?? string.Empty);
return Convert.ToInt32(insertCmd.ExecuteScalar(), CultureInfo.InvariantCulture);
}
}
private static void SaveInvoiceItems(SQLiteConnection con, SQLiteTransaction tx, int invoiceId, InvoiceApiItem item)
{
foreach (var invoiceItem in item.Items ?? Enumerable.Empty<InvoiceApiOrderItem>())
{
using (var cmd = new SQLiteCommand(@"
INSERT INTO [InvoiceItem]
(
[idGood],
[GoodCode],
[Good],
[ProducerName],
[CountryName],
[idInvoice],
[GoodsGount],
[PriceSupplierWithoutNDS],
[PriceSupplierWithNDS],
[PriceProducerWithoutNDS],
[PriceProducerWithNDS],
[NDS],
[JNVLS],
[PriceReestr],
[SumWithoutNDS],
[SumWithNDS],
[SumNDS],
[Serial],
[BestBefore],
[Sertificate],
[Marked],
[GTIN]
)
VALUES
(
null,
@goodCode,
@good,
'',
'',
@invoiceId,
@qty,
@price,
@price,
null,
null,
0,
0,
null,
@sum,
@sum,
0,
'',
'',
'',
0,
''
)", con, tx))
{
cmd.Parameters.AddWithValue("@goodCode", ParseGoodCode(invoiceItem.GoodCode));
cmd.Parameters.AddWithValue("@good", invoiceItem.GoodName ?? string.Empty);
cmd.Parameters.AddWithValue("@invoiceId", invoiceId);
cmd.Parameters.AddWithValue("@qty", invoiceItem.Qty);
cmd.Parameters.AddWithValue("@price", invoiceItem.Price);
cmd.Parameters.AddWithValue("@sum", invoiceItem.Total);
cmd.ExecuteNonQuery();
}
}
}
private static int ParseGoodCode(string value)
{
int parsed;
return int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out parsed) ? parsed : 0;
}
private static string TryGetLocalOrderNumber(SQLiteConnection con, string remoteOrderId)
{
if (string.IsNullOrWhiteSpace(remoteOrderId))
{
return null;
}
using (var cmd = new SQLiteCommand(@"
SELECT [OrderNumber]
FROM [Orders]
WHERE [RemoteOrderId] = @remoteOrderId
LIMIT 1;", con))
{
cmd.Parameters.AddWithValue("@remoteOrderId", remoteOrderId);
var value = cmd.ExecuteScalar();
return value == null || value == DBNull.Value ? null : value.ToString();
}
}
}
}

View File

@ -301,9 +301,6 @@
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<Content Include="Data\efClient.db">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<None Include="Resources\JVMarkOfGood.jpg" />

View File

@ -250,7 +250,8 @@ create table if not exists [Orders] (
[SummaZakaza] nvarchar(32),
[OrderState] nvarchar(32),
[Comment] nvarchar(1024),
[ConsigneeName] nvarchar(128)
[ConsigneeName] nvarchar(128),
[RemoteOrderId] nvarchar(36)
)
";
@ -400,6 +401,7 @@ create table if not exists [OrderItems] (
TryAddColumn(conForCheckTables, "Invoice", "SourceOrderId", "integer");
TryAddColumn(conForCheckTables, "Invoice", "SourceOrderNumber", "nvarchar(36)");
TryAddColumn(conForCheckTables, "Invoice", "IsRequestedInvoice", "int(1)");
TryAddColumn(conForCheckTables, "Orders", "RemoteOrderId", "nvarchar(36)");
TryAddColumn(conForCheckTables, "PriceList", "TradeName", "nvarchar(256)");
TryAddColumn(conForCheckTables, "PriceList", "Dosage", "nvarchar(128)");
TryAddColumn(conForCheckTables, "PriceList", "MarkupPercent", "real");

View File

@ -43,22 +43,25 @@ using Электронная_Фармация.Classes;
using (SQLiteConnection conAddComment = new SQLiteConnection(connectionStringToLocalDB))
{
string qShowMeStatusOrder = $"select OrderState from Orders where Id_Order = '{_idOrder}'";
string qAddComment = $"update Orders set Comment = '{rtxtComment.Text}' where Id_Order = '{_idOrder}'";
try
{
conAddComment.Open();
SQLiteCommand cmdShowMeOrderStatus = new SQLiteCommand(qShowMeStatusOrder, conAddComment);
string OrderState = cmdShowMeOrderStatus.ExecuteScalar().ToString();
if (OrderState == "НОВЫЙ")
string orderState;
using (var cmdShowMeOrderStatus = new SQLiteCommand("select OrderState from Orders where Id_Order = @id", conAddComment))
{
SQLiteCommand cmdAddComment = new SQLiteCommand(qAddComment, conAddComment);
cmdAddComment.ExecuteNonQuery();
cmdShowMeOrderStatus.Parameters.AddWithValue("@id", _idOrder);
orderState = Convert.ToString(cmdShowMeOrderStatus.ExecuteScalar()) ?? string.Empty;
}
if (orderState == "НОВЫЙ")
{
using (var cmdAddComment = new SQLiteCommand("update Orders set Comment = @comment where Id_Order = @id", conAddComment))
{
cmdAddComment.Parameters.AddWithValue("@comment", rtxtComment.Text);
cmdAddComment.Parameters.AddWithValue("@id", _idOrder);
cmdAddComment.ExecuteNonQuery();
}
}
else
{

View File

@ -394,9 +394,9 @@ namespace Электронная_Фармация.UserControls
try
{
var service = new InvoiceRequestService();
service.CreateOrUpdateFromOrder(orderId);
ToastNotification.ShowSuccess("Накладная добавлена в раздел \"Накладные\".");
var service = new InvoiceSyncService();
service.SyncFromServerAsync().GetAwaiter().GetResult();
ToastNotification.ShowSuccess("Накладные обновлены с сервера.");
var shell = FindForm() as ElectroPharmacy;
shell?.OpenInvoicesTab(orderId);
@ -508,7 +508,11 @@ and OrderDate <= '{dateTo}'
void loadConsignees()
{
string connectionStringToLocalDB = AppConfig.SqliteConnectionString;
string qShowMeConsigneesList = "select ConsigneesName from Consignees order by [ConsigneesUseAsDefault] desc";
string qShowMeConsigneesList = @"
select distinct ConsigneeName
from Orders
where trim(ifnull(ConsigneeName, '')) <> ''
order by ConsigneeName";
using (SQLiteConnection conConsignees = new SQLiteConnection(connectionStringToLocalDB))
{
@ -527,7 +531,7 @@ and OrderDate <= '{dateTo}'
var items = new List<string> { "Грузополучатель" };
items.AddRange(tableConsignees.Rows.Cast<DataRow>()
.Select(r => r["ConsigneesName"]?.ToString())
.Select(r => r["ConsigneeName"]?.ToString())
.Where(n => !string.IsNullOrWhiteSpace(n)));
_comboConsignees.DataSource = items;
_comboConsignees.SelectedIndex = 0;
@ -547,7 +551,11 @@ and OrderDate <= '{dateTo}'
{
string connectionStringToLocalDB = AppConfig.SqliteConnectionString;
string qShowMeSuppliersList = "select SuppliersName from suppliers order by [SuppliersName] asc";
string qShowMeSuppliersList = @"
select distinct SupplierName
from Orders
where trim(ifnull(SupplierName, '')) <> ''
order by SupplierName asc";
using (SQLiteConnection conSuppliers = new SQLiteConnection(connectionStringToLocalDB))
{
@ -559,7 +567,7 @@ and OrderDate <= '{dateTo}'
DataTable tableSuppliers = new DataTable();
daSuppliersList.Fill(tableSuppliers);
comboSuppliers.DataSource = tableSuppliers;
comboSuppliers.DisplayMember = "SuppliersName";
comboSuppliers.DisplayMember = "SupplierName";
comboSuppliers.Text = "Поставщик";
}
catch (Exception ex)

View File

@ -57,7 +57,11 @@ namespace Электронная_Фармация.UserControls
{
string connectionStringToLocalDB = AppConfig.SqliteConnectionString;
string qShowMeSuppliersList = "select SuppliersName from suppliers order by [SuppliersName] asc";
string qShowMeSuppliersList = @"
select distinct SupplierName
from Invoice
where trim(ifnull(SupplierName, '')) <> ''
order by SupplierName asc";
using (SQLiteConnection conSuppliers = new SQLiteConnection(connectionStringToLocalDB))
{
@ -69,7 +73,7 @@ namespace Электронная_Фармация.UserControls
DataTable tableSuppliers = new DataTable();
daSuppliersList.Fill(tableSuppliers);
comboSuppliers.DataSource = tableSuppliers;
comboSuppliers.DisplayMember = "SuppliersName";
comboSuppliers.DisplayMember = "SupplierName";
comboSuppliers.Text = "Поставщик";
}
catch(Exception ex)
@ -87,7 +91,11 @@ namespace Электронная_Фармация.UserControls
{
string connectionStringToLocalDB = AppConfig.SqliteConnectionString;
string qShowMeConsigneesList = "select ConsigneesName from Consignees order by [ConsigneesUseAsDefault] desc";
string qShowMeConsigneesList = @"
select distinct ConsigneesName
from Invoice
where trim(ifnull(ConsigneesName, '')) <> ''
order by ConsigneesName asc";
using (SQLiteConnection conConsignees = new SQLiteConnection(connectionStringToLocalDB))
{
@ -127,8 +135,8 @@ select
i.[idInvoice] as [ИД накладной],
i.[InvoiceNumber] as [Номер],
i.[InvoiceDate] as [Дата],
coalesce(nullif(i.[SupplierName], ''), (select s.[SuppliersName] from [Suppliers] s where s.[codeSuppliers] = i.[CodeSupplier])) as [Поставщик],
coalesce(nullif(i.[ConsigneesName], ''), (select c.[ConsigneesName] from [Consignees] c where c.[codeConsignees] = i.[CodeConsignees])) as [Грузополучатель],
ifnull(i.[SupplierName], '') as [Поставщик],
ifnull(i.[ConsigneesName], '') as [Грузополучатель],
i.[SourceOrderNumber] as [Номер заказа],
coalesce(i.[InvoiceSum], i.[SumWithNDS], i.[SumWithoutNDS], 0) as [Сумма],
coalesce(i.[RefuseSum], 0) as [Сумма отказа]
@ -142,12 +150,12 @@ where date(i.[InvoiceDate]) between date(@dateFrom) and date(@dateTo)";
if (comboSuppliers.Text != "" && comboSuppliers.Text != "Поставщик")
{
sql += " and coalesce(nullif(i.[SupplierName], ''), (select s.[SuppliersName] from [Suppliers] s where s.[codeSuppliers] = i.[CodeSupplier])) like @supplierName";
sql += " and ifnull(i.[SupplierName], '') like @supplierName";
}
if (comboConsignees.Text != "" && comboConsignees.Text != "Грузополучатель")
{
sql += " and coalesce(nullif(i.[ConsigneesName], ''), (select c.[ConsigneesName] from [Consignees] c where c.[codeConsignees] = i.[CodeConsignees])) like @consigneeName";
sql += " and ifnull(i.[ConsigneesName], '') like @consigneeName";
}
if (!string.IsNullOrWhiteSpace(_initialSourceOrderId))

View File

@ -124,12 +124,7 @@ namespace Электронная_Фармация.UserControls
using (var con = new SQLiteConnection(AppConfig.SqliteConnectionString))
{
con.Open();
var orderColumns = GetColumns(con, "Orders");
var usesNewSchema = orderColumns.Contains("Id_Order") && orderColumns.Contains("OrderedCountItems");
var q = usesNewSchema ? GetQueryForNewSchema() : GetQueryForOldSchema();
using (var cmd = new SQLiteCommand(q, con))
using (var cmd = new SQLiteCommand(GetQueryForNewSchema(), con))
using (var da = new SQLiteDataAdapter(cmd))
{
var table = new DataTable();
@ -186,26 +181,6 @@ order by oi.[DrugName]", con))
}
}
}
private static HashSet<string> GetColumns(SQLiteConnection con, string tableName)
{
var columns = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
using (var cmd = new SQLiteCommand($"pragma table_info([{tableName}]);", con))
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
var name = reader["name"] as string;
if (!string.IsNullOrWhiteSpace(name))
{
columns.Add(name);
}
}
}
return columns;
}
private static string GetQueryForNewSchema()
{
return @"
@ -237,26 +212,5 @@ group by
having sum(ifnull(oi.[RefuseItemsCount], 0)) > 0
order by o.[OrderDate] desc;";
}
private static string GetQueryForOldSchema()
{
return @"
select
o.[OrderNumber] as [Номер заказа],
o.[OrderDate] as [Дата],
supp.[SuppliersName] as [Поставщик],
consign.[ConsigneesName] as [Грузополучатель],
o.[OrderedItemsCount] as [К-во товара в заказе],
o.[OrderSum] as [Сумма заказа],
o.[RefuseItemsCount] as [К-во отказанного товара],
o.[RefuseSum] as [Сумма отказа],
o.[Comment] as [Комментарий],
o.[OrderState] as [Статус]
from Orders as o
inner join Consignees consign on consign.codeConsignees = o.codeConsignees
inner join Suppliers supp on supp.codeSuppliers = o.codeSuppliers
where ifnull(o.[RefuseItemsCount], 0) > 0 or ifnull(o.[RefuseSum], 0) > 0
order by [OrderDate] desc;";
}
}
}