306 lines
15 KiB
C#
306 lines
15 KiB
C#
namespace LaaProduction.Services
|
|
{
|
|
using LaaPackages.SqlClient;
|
|
using LaaProduction.Services.Interfaces;
|
|
using LaaProduction.Services.Models;
|
|
using LaaProduction.Services.Models.Reports;
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
|
|
public class ProtocolService : IProtocolService
|
|
{
|
|
private const String PROTOCOL = "PROTOCOL";
|
|
|
|
private readonly SqlConnection sqlConnection;
|
|
|
|
public ProtocolService(SqlConnection sqlConnection)
|
|
=> this.sqlConnection = sqlConnection;
|
|
|
|
public Boolean DeleteFile(Int32 fileId)
|
|
=> this.sqlConnection
|
|
.CreateCommand($@"
|
|
DELETE FROM [File]
|
|
WHERE [FileId] = @{nameof(fileId)};
|
|
DELETE FROM [FilesOrders]
|
|
OUTPUT [Deleted].[FileId]
|
|
WHERE [FileId] = @{nameof(fileId)};")
|
|
.SetParameter(nameof(fileId), fileId)
|
|
.ExecuteScalar(x => x.GetValue<Int32>(0)) > 0;
|
|
|
|
public String FileContent(Int32? fileId)
|
|
{
|
|
var fileContent = this.sqlConnection
|
|
.CreateCommand($@"
|
|
SELECT [dbo].[File].[FileContent]
|
|
FROM [dbo].[File]
|
|
WHERE [dbo].[File].[FileId] = @{nameof(fileId)}")
|
|
.SetParameter(nameof(fileId), fileId)
|
|
.FirstOrDefault(reader => reader.GetValue<Byte[]>(0))
|
|
?? Array.Empty<Byte>();
|
|
|
|
return String.Format("data:application/pdf;base64,{0}", Convert.ToBase64String(fileContent));
|
|
}
|
|
|
|
public OrderClientModel FindOrder(Int32 orderId)
|
|
{
|
|
/// Für ungültige auftrag nummer einfach leere objekt zurück geben.
|
|
if (orderId <= 0)
|
|
{
|
|
return new OrderClientModel();
|
|
}
|
|
|
|
/// Abfragen der algemeinen auftrag daten
|
|
var model = this.sqlConnection
|
|
.CreateCommand($@"
|
|
SELECT [APG].[AuftragNr]
|
|
, [K].[KundenNr]
|
|
, [K].[Name]
|
|
FROM [AuftragPosition_Gesamt] AS [APG]
|
|
JOIN [Auftrag_Gesamt] AS [AG]
|
|
ON [AG].[AuftragNr] = [APG].[AuftragNr]
|
|
JOIN [IdentNr] AS [IN]
|
|
ON [IN].[IdentNr] = [APG].[Identnr]
|
|
AND [IN].[Typ] = 'GNS'
|
|
JOIN [Kunde] AS [K]
|
|
ON [K].[KundenNr] = [AG].[KundenNr]
|
|
WHERE [APG].[AuftragNr] = @{nameof(orderId)}")
|
|
.SetParameter(nameof(orderId), orderId)
|
|
.FirstOrDefault(reader => new OrderClientModel
|
|
{
|
|
OrderId = reader.GetValue<Int32>(0),
|
|
ClientId = reader.GetValue<Int32>(1),
|
|
ClientName = reader.GetValue<String>(2)
|
|
});
|
|
|
|
/// Wenn auftrag nicht gefunden ist einfach leere objekt zurück geben.
|
|
if (model is null)
|
|
{
|
|
return new OrderClientModel();
|
|
}
|
|
|
|
model.Results = this.LoadTestResults(orderId);
|
|
|
|
model.Positions = model
|
|
.Results
|
|
.GroupBy(x => x.PosNr)
|
|
.Where(x => x.Key > 0)
|
|
.OrderBy(x => x.Key)
|
|
.ToDictionary(x => x.Key, x => x.All(r => r.Succeeded));
|
|
|
|
/// Abfragen bestähende protokolle.
|
|
model.Files = this.sqlConnection
|
|
.CreateCommand($@"
|
|
SELECT COUNT([FileId])
|
|
FROM [FilesOrders]
|
|
WHERE [OrderId] = @{nameof(orderId)}
|
|
AND [Usage] = '{PROTOCOL}'")
|
|
.SetParameter(nameof(orderId), orderId)
|
|
.FirstOrDefault(x => x.GetValue<Int32>(0));
|
|
|
|
return model;
|
|
}
|
|
|
|
public IEnumerable<KeyValuePair<Int32, String>> FindOrdersById(Int32 orderno)
|
|
=> this.sqlConnection
|
|
.CreateCommand($@"
|
|
SELECT DISTINCT
|
|
[APG].[AuftragNr]
|
|
, [K].[Name]
|
|
FROM [AuftragPosition_Gesamt] AS [APG]
|
|
JOIN [Auftrag_Gesamt] AS [AG]
|
|
ON [AG].[AuftragNr] = [APG].[AuftragNr]
|
|
JOIN [IdentNr] AS [IN]
|
|
ON [IN].[IdentNr] = [APG].[Identnr]
|
|
AND [IN].[Typ] = 'GNS'
|
|
JOIN [Kunde] AS [K]
|
|
ON [K].[KundenNr] = [AG].[KundenNr]
|
|
WHERE [APG].[AuftragNr] LIKE @{nameof(orderno)}")
|
|
.SetParameter(nameof(orderno), $"%{orderno}%")
|
|
.ExecuteReader(reader => new KeyValuePair<Int32, String>(
|
|
key: reader.GetValue<Int32>(0),
|
|
value: reader.GetValue<String>(1)));
|
|
|
|
public IEnumerable<KeyValuePair<Int32, String>> FindOrdersByClient(String clientName)
|
|
=> this.sqlConnection
|
|
.CreateCommand($@"
|
|
SELECT DISTINCT
|
|
[APG].[AuftragNr]
|
|
, [K].[Name]
|
|
FROM [AuftragPosition_Gesamt] AS [APG]
|
|
JOIN [Auftrag_Gesamt] AS [AG]
|
|
ON [AG].[AuftragNr] = [APG].[AuftragNr]
|
|
JOIN [IdentNr] AS [IN]
|
|
ON [IN].[IdentNr] = [APG].[Identnr]
|
|
AND [IN].[Typ] = 'GNS'
|
|
JOIN [Kunde] AS [K]
|
|
ON [K].[KundenNr] = [AG].[KundenNr]
|
|
WHERE [K].[Name] LIKE @{nameof(clientName)}")
|
|
.SetParameter(nameof(clientName), $"%{clientName}%")
|
|
.ExecuteReader(reader => new KeyValuePair<Int32, String>(
|
|
key: reader.GetValue<Int32>(0),
|
|
value: reader.GetValue<String>(1)));
|
|
|
|
public IDictionary<Int32, String> GetFiles(Int32 orderId)
|
|
{
|
|
var files = this.sqlConnection
|
|
.CreateCommand($@"
|
|
SELECT [FileId]
|
|
, [FileContent]
|
|
FROM [File]
|
|
WHERE [FileId] IN (SELECT [FileId] FROM [FilesOrders] WHERE [OrderId] = @{nameof(orderId)})
|
|
ORDER BY [FileId] ASC")
|
|
.SetParameter(nameof(orderId), orderId)
|
|
.ExecuteReader(x => new
|
|
{
|
|
Key = x.GetValue<Int32>(0),
|
|
Value = String.Format("data:application/pdf;base64,{0}", Convert.ToBase64String(x.GetValue<Byte[]>(1)))
|
|
})
|
|
?.ToDictionary(x => x.Key, x => x.Value)
|
|
?? new Dictionary<Int32, String>();
|
|
|
|
return files;
|
|
}
|
|
|
|
public IEnumerable<TestStatus> LoadTestResults(Int32 orderId)
|
|
=> this.sqlConnection
|
|
.CreateCommand($@"
|
|
SELECT DISTINCT
|
|
[APS].[PositionNr] AS [PosNr] -- 0
|
|
, ISNULL([APS].[KundeneigeneSerienNr], [APS].[SerienNr]) AS [SerialNr] -- 1
|
|
, [CPT].[CordonelPressureTest_Valid] AS [3TightnessTest] -- 2
|
|
, [DP].[Dicht] AS [4PressureAndTightness] -- 3
|
|
, MAX([APS].[StatusFertigung]) AS [5Metrologicaltesting] -- 4
|
|
, [CRRH].[Result] AS [6ConfigComparisonAndRadiotest] -- 5
|
|
FROM [AuftragPositionSerienNr] AS [APS]
|
|
LEFT JOIN [Genesis_Meter] AS [GM] ON [GM].[Seriennummer] = [APS].[SerienNr]
|
|
LEFT JOIN [MapPcbIdToSerialNumber] AS [PCB] ON [PCB].[MapPcbIdToSerialNumber_SerialNumber] = [GM].[Seriennummer]
|
|
LEFT JOIN [Cordonel_Radio_RSSI_History] AS [CRRH] ON [CRRH].[RadioAdress] = [GM].[Adresse] - 10000000000
|
|
AND [CRRH].[IsLast] = 1
|
|
AND [CRRH].[Result] = 1
|
|
LEFT JOIN [Druckpruefung] AS [DP] ON [DP].[FabNr] = [PCB].[MapPcbIdToSerialNumber_PcbId]
|
|
AND [DP].[Dicht] = 1
|
|
LEFT JOIN [Cordonel_PressureTest] AS [CPT] ON [CPT].[CordonelPressureTest_PcbId] = [PCB].[MapPcbIdToSerialNumber_PcbId]
|
|
AND [CPT].[CordonelPressureTest_Valid] = 1
|
|
WHERE [APS].[AuftragNr] = @{nameof(orderId)}
|
|
GROUP BY [APS].[PositionNr]
|
|
, [APS].[SerienNr]
|
|
, [APS].[KundeneigeneSerienNr]
|
|
, [CPT].[CordonelPressureTest_Valid]
|
|
, [DP].[Dicht]
|
|
, [CRRH].[Result]
|
|
ORDER BY [APS].[PositionNr]
|
|
, ISNULL([APS].[KundeneigeneSerienNr], [APS].[SerienNr])")
|
|
.SetParameter(nameof(orderId), orderId)
|
|
.ExecuteReader(reader => new TestStatus
|
|
{
|
|
PosNr = reader.GetValue<Int16>(0),
|
|
SerialNr = reader.GetValue<String>(1),
|
|
HeliumTest = reader.GetValue<Boolean?>(2),
|
|
PressureTest = reader.GetValue<Boolean?>(3),
|
|
MetroTest = this.MetrologicalValue(reader.GetValue<Byte?>(4)),
|
|
RadioTest = reader.GetValue<Boolean?>(5),
|
|
})
|
|
.OrderBy(x => !x.Succeeded)
|
|
.ThenBy(x => x.PosNr);
|
|
|
|
public Boolean OrderCompleted(Int32 orderId)
|
|
{
|
|
var sumResults = this.sqlConnection
|
|
.CreateCommand($@"
|
|
SELECT CAST(CASE WHEN ISNULL([CPT].[CordonelPressureTest_Valid], 1) = 1 THEN 0 ELSE 1 END AS INT)
|
|
+ CAST(CASE WHEN ISNULL([DP].[Dicht], 1) = 1 THEN 0 ELSE 1 END AS INT)
|
|
+ ISNULL(MAX([APS].[StatusFertigung]) - 30, 0)
|
|
+ CAST(CASE WHEN ISNULL([CRRH].[Result], 1) = 1 THEN 0 ELSE 1 END AS INT)
|
|
FROM [AuftragPositionSerienNr] AS [APS]
|
|
LEFT JOIN [Genesis_Meter] AS [GM] ON [GM].[Seriennummer] = [APS].[SerienNr]
|
|
LEFT JOIN [MapPcbIdToSerialNumber] AS [PCB] ON [PCB].[MapPcbIdToSerialNumber_SerialNumber] = [GM].[Seriennummer]
|
|
LEFT JOIN [Cordonel_Radio_RSSI_History] AS [CRRH] ON [CRRH].[RadioAdress] = [GM].[Adresse] - 10000000000
|
|
AND [CRRH].[IsLast] = 1
|
|
AND [CRRH].[Result] = 1
|
|
LEFT JOIN [Druckpruefung] AS [DP] ON [DP].[FabNr] = [PCB].[MapPcbIdToSerialNumber_PcbId]
|
|
AND [DP].[Dicht] = 1
|
|
LEFT JOIN [Cordonel_PressureTest] AS [CPT] ON [CPT].[CordonelPressureTest_PcbId] = [PCB].[MapPcbIdToSerialNumber_PcbId]
|
|
AND [CPT].[CordonelPressureTest_Valid] = 1
|
|
WHERE [APS].[AuftragNr] = @{nameof(orderId)}
|
|
GROUP BY [APS].[PositionNr]
|
|
, [APS].[SerienNr]
|
|
, [APS].[KundeneigeneSerienNr]
|
|
, [CPT].[CordonelPressureTest_Valid]
|
|
, [DP].[Dicht]
|
|
, [CRRH].[Result]")
|
|
.SetParameter(nameof(orderId), orderId)
|
|
.ExecuteReader(reader => reader.GetValue<Int32>(0))
|
|
.Sum(x => x);
|
|
|
|
return sumResults == 0;
|
|
}
|
|
|
|
public Int32 SaveFile(Stream fileStream, Int32 clientId, Int32 orderId)
|
|
{
|
|
var fileName = $"{clientId}_{orderId}.pdf";
|
|
var fileContent = this.GetBuffer(fileStream);
|
|
var fileMD5Buffer = MD5.Create().ComputeHash(fileContent);
|
|
var fileMD5 = BitConverter
|
|
.ToString(fileMD5Buffer)
|
|
.Replace("-", String.Empty)
|
|
.ToLower();
|
|
var length = fileMD5?.Length;
|
|
var exists = this.sqlConnection
|
|
.CreateCommand($@"
|
|
SELECT COUNT(1)
|
|
FROM [FilesOrders]
|
|
WHERE [Hash] = @{nameof(fileMD5)}")
|
|
.SetParameter(nameof(fileMD5), fileMD5)
|
|
.FirstOrDefault(x => x.GetValue<Int32>(0)) > 0;
|
|
|
|
if (exists)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return this.sqlConnection
|
|
.CreateCommand($@"
|
|
INSERT INTO [dbo].[File] (
|
|
[FileName]
|
|
, [FileContent])
|
|
OUTPUT @{nameof(orderId)}, [Inserted].[FileId], '{PROTOCOL}', @{nameof(fileMD5)}
|
|
INTO [FilesOrders]([OrderId], [FileId], [Usage], [Hash])
|
|
OUTPUT [Inserted].[FileId]
|
|
VALUES (@{nameof(fileName)}
|
|
, @{nameof(fileContent)})")
|
|
.SetParameter(nameof(orderId), orderId)
|
|
.SetParameter(nameof(fileName), fileName)
|
|
.SetParameter(nameof(fileContent), fileContent)
|
|
.SetParameter(nameof(fileMD5), fileMD5)
|
|
.ExecuteScalar(x => x.GetValue<Int32>(0));
|
|
}
|
|
|
|
private Byte[] GetBuffer(Stream fileStream)
|
|
{
|
|
var fileContent = new Byte[fileStream.Length];
|
|
|
|
using (var memoryStream = new MemoryStream())
|
|
{
|
|
fileStream.CopyTo(memoryStream);
|
|
|
|
fileContent = memoryStream.ToArray();
|
|
}
|
|
|
|
return fileContent;
|
|
}
|
|
|
|
private Boolean? MetrologicalValue(Byte? value)
|
|
{
|
|
if (value is null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return value == 30;
|
|
}
|
|
}
|
|
} |