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(); 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; } } } }