Enable Получить накладную for sent orders, build local invoices without refusals, and stop the tab close menu from covering dedicated grid menus. Also fix price-list Backspace search and refresh the Release dist binaries. Co-authored-by: Cursor <cursoragent@cursor.com>
341 lines
11 KiB
C#
341 lines
11 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Data.SQLite;
|
||
using System.Globalization;
|
||
|
||
namespace Электронная_Фармация.Classes
|
||
{
|
||
public sealed class InvoiceRequestService
|
||
{
|
||
public string CreateOrUpdateFromOrder(string orderId)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(orderId))
|
||
{
|
||
throw new ArgumentException("Не указан заказ для формирования накладной.", nameof(orderId));
|
||
}
|
||
|
||
using (var con = new SQLiteConnection(AppConfig.SqliteConnectionString))
|
||
{
|
||
con.Open();
|
||
|
||
string orderNumber;
|
||
string supplierName;
|
||
string consigneeName;
|
||
string orderState;
|
||
|
||
using (var cmd = new SQLiteCommand(@"
|
||
select
|
||
o.[OrderNumber],
|
||
o.[SupplierName],
|
||
ifnull(o.[ConsigneeName], '') as [ConsigneeName],
|
||
ifnull(o.[OrderState], '') as [OrderState]
|
||
from [Orders] o
|
||
where o.[Id_Order] = @orderId;", con))
|
||
{
|
||
cmd.Parameters.AddWithValue("@orderId", orderId);
|
||
using (var reader = cmd.ExecuteReader())
|
||
{
|
||
if (!reader.Read())
|
||
{
|
||
throw new InvalidOperationException("Выбранный заказ не найден.");
|
||
}
|
||
|
||
orderNumber = reader["OrderNumber"]?.ToString() ?? string.Empty;
|
||
supplierName = reader["SupplierName"]?.ToString() ?? string.Empty;
|
||
consigneeName = reader["ConsigneeName"]?.ToString() ?? string.Empty;
|
||
orderState = reader["OrderState"]?.ToString() ?? string.Empty;
|
||
}
|
||
}
|
||
|
||
if (!string.Equals(orderState, "ОТПРАВЛЕН", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
throw new InvalidOperationException("Получить накладную можно только для заказа со статусом ОТПРАВЛЕН.");
|
||
}
|
||
|
||
var items = new List<InvoiceOrderItem>();
|
||
using (var cmd = new SQLiteCommand(@"
|
||
select
|
||
ifnull([es_code], 0) as [GoodCode],
|
||
[DrugName],
|
||
[Price],
|
||
ifnull([Zakaz], 0) as [Zakaz],
|
||
ifnull([RefuseItemsCount], 0) as [RefuseItemsCount],
|
||
ifnull([ExpiryPeriod], '') as [ExpiryPeriod]
|
||
from [OrderItems]
|
||
where [Id_Order] = @orderId
|
||
order by [DrugName];", con))
|
||
{
|
||
cmd.Parameters.AddWithValue("@orderId", orderId);
|
||
using (var reader = cmd.ExecuteReader())
|
||
{
|
||
while (reader.Read())
|
||
{
|
||
int orderedQty = SafeInt(reader["Zakaz"]);
|
||
int refusedQty = SafeInt(reader["RefuseItemsCount"]);
|
||
int arrivedQty = Math.Max(orderedQty - refusedQty, 0);
|
||
if (arrivedQty <= 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
var price = SafeDecimal(reader["Price"]);
|
||
items.Add(new InvoiceOrderItem
|
||
{
|
||
GoodCode = SafeInt(reader["GoodCode"]),
|
||
GoodName = reader["DrugName"]?.ToString() ?? string.Empty,
|
||
Price = price,
|
||
ArrivedQty = arrivedQty,
|
||
ExpiryPeriod = reader["ExpiryPeriod"]?.ToString() ?? string.Empty
|
||
});
|
||
}
|
||
}
|
||
}
|
||
|
||
if (items.Count == 0)
|
||
{
|
||
throw new InvalidOperationException("Для этого заказа нет фактически пришедших позиций.");
|
||
}
|
||
|
||
int invoiceId;
|
||
string invoiceNumber;
|
||
using (var findCmd = new SQLiteCommand(@"
|
||
select [idInvoice], [InvoiceNumber]
|
||
from [Invoice]
|
||
where [SourceOrderId] = @orderId
|
||
limit 1;", con))
|
||
{
|
||
findCmd.Parameters.AddWithValue("@orderId", orderId);
|
||
using (var reader = findCmd.ExecuteReader())
|
||
{
|
||
if (reader.Read())
|
||
{
|
||
invoiceId = Convert.ToInt32(reader["idInvoice"]);
|
||
invoiceNumber = reader["InvoiceNumber"]?.ToString() ?? string.Empty;
|
||
}
|
||
else
|
||
{
|
||
invoiceId = 0;
|
||
invoiceNumber = $"НКЛ-{orderNumber}";
|
||
}
|
||
}
|
||
}
|
||
|
||
var invoiceDate = DateTime.Now.ToString("yyyy-MM-dd");
|
||
var invoiceSum = 0m;
|
||
foreach (var item in items)
|
||
{
|
||
invoiceSum += item.Price * item.ArrivedQty;
|
||
}
|
||
|
||
if (invoiceId == 0)
|
||
{
|
||
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,
|
||
@invoiceSum,
|
||
0,
|
||
@sourceOrderId,
|
||
@sourceOrderNumber,
|
||
1
|
||
);
|
||
select last_insert_rowid();", con))
|
||
{
|
||
insertCmd.Parameters.AddWithValue("@number", invoiceNumber);
|
||
insertCmd.Parameters.AddWithValue("@date", invoiceDate);
|
||
insertCmd.Parameters.AddWithValue("@sum", invoiceSum);
|
||
insertCmd.Parameters.AddWithValue("@supplier", supplierName);
|
||
insertCmd.Parameters.AddWithValue("@consignee", consigneeName);
|
||
insertCmd.Parameters.AddWithValue("@invoiceSum", invoiceSum);
|
||
insertCmd.Parameters.AddWithValue("@sourceOrderId", orderId);
|
||
insertCmd.Parameters.AddWithValue("@sourceOrderNumber", orderNumber);
|
||
invoiceId = Convert.ToInt32(insertCmd.ExecuteScalar());
|
||
}
|
||
}
|
||
else
|
||
{
|
||
using (var updateCmd = new SQLiteCommand(@"
|
||
update [Invoice]
|
||
set
|
||
[InvoiceDate] = @date,
|
||
[SumWithoutNDS] = @sum,
|
||
[SumWithNDS] = @sum,
|
||
[SumNDS] = 0,
|
||
[SupplierName] = @supplier,
|
||
[ConsigneesName] = @consignee,
|
||
[InvoiceSum] = @invoiceSum,
|
||
[RefuseSum] = 0,
|
||
[SourceOrderNumber] = @sourceOrderNumber,
|
||
[IsRequestedInvoice] = 1
|
||
where [idInvoice] = @invoiceId;", con))
|
||
{
|
||
updateCmd.Parameters.AddWithValue("@date", invoiceDate);
|
||
updateCmd.Parameters.AddWithValue("@sum", invoiceSum);
|
||
updateCmd.Parameters.AddWithValue("@supplier", supplierName);
|
||
updateCmd.Parameters.AddWithValue("@consignee", consigneeName);
|
||
updateCmd.Parameters.AddWithValue("@invoiceSum", invoiceSum);
|
||
updateCmd.Parameters.AddWithValue("@sourceOrderNumber", orderNumber);
|
||
updateCmd.Parameters.AddWithValue("@invoiceId", invoiceId);
|
||
updateCmd.ExecuteNonQuery();
|
||
}
|
||
|
||
using (var deleteItemsCmd = new SQLiteCommand("delete from [InvoiceItem] where [idInvoice] = @invoiceId;", con))
|
||
{
|
||
deleteItemsCmd.Parameters.AddWithValue("@invoiceId", invoiceId);
|
||
deleteItemsCmd.ExecuteNonQuery();
|
||
}
|
||
}
|
||
|
||
foreach (var item in items)
|
||
{
|
||
decimal lineSum = item.Price * item.ArrivedQty;
|
||
using (var itemCmd = 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,
|
||
'',
|
||
@bestBefore,
|
||
'',
|
||
0,
|
||
''
|
||
);", con))
|
||
{
|
||
itemCmd.Parameters.AddWithValue("@goodCode", item.GoodCode);
|
||
itemCmd.Parameters.AddWithValue("@good", item.GoodName);
|
||
itemCmd.Parameters.AddWithValue("@invoiceId", invoiceId);
|
||
itemCmd.Parameters.AddWithValue("@qty", item.ArrivedQty);
|
||
itemCmd.Parameters.AddWithValue("@price", item.Price);
|
||
itemCmd.Parameters.AddWithValue("@sum", lineSum);
|
||
itemCmd.Parameters.AddWithValue("@bestBefore", item.ExpiryPeriod);
|
||
itemCmd.ExecuteNonQuery();
|
||
}
|
||
}
|
||
|
||
return orderId;
|
||
}
|
||
}
|
||
|
||
private static int SafeInt(object value)
|
||
{
|
||
if (value == null || value == DBNull.Value)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
int result;
|
||
return int.TryParse(value.ToString(), NumberStyles.Integer, CultureInfo.InvariantCulture, out result)
|
||
|| int.TryParse(value.ToString(), NumberStyles.Integer, CultureInfo.CurrentCulture, out result)
|
||
? result
|
||
: 0;
|
||
}
|
||
|
||
private static decimal SafeDecimal(object value)
|
||
{
|
||
if (value == null || value == DBNull.Value)
|
||
{
|
||
return 0m;
|
||
}
|
||
|
||
var text = value.ToString()?.Trim();
|
||
if (string.IsNullOrWhiteSpace(text))
|
||
{
|
||
return 0m;
|
||
}
|
||
|
||
decimal result;
|
||
if (decimal.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out result))
|
||
{
|
||
return result;
|
||
}
|
||
|
||
text = text.Replace(',', '.');
|
||
if (decimal.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out result))
|
||
{
|
||
return result;
|
||
}
|
||
|
||
if (decimal.TryParse(text, NumberStyles.Number, CultureInfo.CurrentCulture, out result))
|
||
{
|
||
return result;
|
||
}
|
||
|
||
return 0m;
|
||
}
|
||
|
||
private sealed class InvoiceOrderItem
|
||
{
|
||
public int GoodCode { get; set; }
|
||
public string GoodName { get; set; }
|
||
public decimal Price { get; set; }
|
||
public int ArrivedQty { get; set; }
|
||
public string ExpiryPeriod { get; set; }
|
||
}
|
||
}
|
||
}
|