2021-11-18 14:56:29 +01:00

514 lines
21 KiB
VB.net

Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Language
Imports DigitalData.Modules.Database
Imports MultiTool.Shared.Helpers
Imports System.Text.RegularExpressions
Namespace Winline
Public Class WinlineData
Inherits BaseClass
Private ReadOnly Database As MSSQLServer
Private ReadOnly Config As Config
Public Articles As New List(Of Article)
Public Accounts As New List(Of Account)
Public Mandators As New List(Of Mandator)
Public DocumentKinds As New List(Of DocumentKind)
Public Years As List(Of Integer)
Public Const ALL_MESOCOMP = "mesocomp"
Public Const V21_ARTICLENUMBER = "c002"
Public Const V21_ARTICLEDESCRIPTION = "c003"
Public Const V21_MAINARTICLENUMBER = "c011"
Public Const V21_REPLACEMENTARTICLENUMBER = "c123"
Public Const V21_EAN = "c075"
Public Const V50_ACCOUNTNUMBER = "c002"
Public Const V50_ACCOUNTNAME = "c003"
Public Const V50_STREETNAME = "c050"
Public Const V50_ZIPCODE = "c051"
Public Const V50_CITYNAME = "c052"
Public Const V50_GLN = "c260"
Public Const T45_KEY = "c000"
Public Const T45_NAME = "c001"
Public Const T45_CONTACTNUMBER = "c063"
Public Const V05_ACCOUNTID = "c002"
Public Const V05_ACCOUNTNAME = "c003"
Public Const T357_KINDID = "c030"
Public Const T357_KINDNAME = "c001"
Public Const T01_DATABASEINFO = "c004"
Public Const T01_MANDATORID = "c000"
Public Const T01_MANDATORNAME = "c003"
Public Sub New(pLogConfig As LogConfig, pDatabase As MSSQLServer, pConfig As Config)
MyBase.New(pLogConfig, pLogConfig.GetLogger())
Database = pDatabase
Config = pConfig
End Sub
<DebuggerStepThrough>
Public Function GetWinLineYear(pYear As Integer)
Return (pYear - 1900) * 12
End Function
<DebuggerStepThrough>
Public Function GetWinLineYear()
Return GetWinLineYear(Config.GetYear)
End Function
Public Async Function LoadArticles(pMandator As Mandator) As Task
Logger.Info("Loading Articles for Mandator [{0}]", pMandator)
Dim oYear = GetWinLineYear()
Try
Dim oSQL = $"
SELECT DISTINCT
[c002], -- Artikelnummer
[c003], -- Bezeichnung
[c075] -- EAN
FROM [{pMandator.Server}].[{pMandator.Database}].[dbo].[v021]
WHERE
mesocomp = '{pMandator.Id}'
AND mesoyear = {oYear}"
Dim oTable = Await Database.GetDatatableAsync(oSQL)
Dim oArticles As New List(Of Article)
For Each oRow As DataRow In oTable.Rows
Dim oArticleId As String = GetRowItem(oRow, V21_ARTICLENUMBER, String.Empty)
Dim oArticleDescription As String = GetRowItem(oRow, V21_ARTICLEDESCRIPTION, String.Empty)
Dim oEAN As String = GetRowItem(oRow, V21_EAN, String.Empty)
oArticles.Add(New Article With {
.Id = oArticleId,
.Name = oArticleDescription,
.EAN = oEAN,
.Mandator = pMandator
})
Next
Articles.AddRange(oArticles)
Logger.Info("[{0}] Articles loaded for Mandator [{1}]", oArticles.Count, pMandator)
Catch ex As Exception
Logger.Warn("Could not load Articles for Mandator [{0}]", pMandator)
Logger.Error(ex)
End Try
End Function
Public Async Function LoadAccounts(pMandator As Mandator) As Task
Logger.Info("Loading Accounts for Mandator [{0}]", pMandator)
Dim oYear = GetWinLineYear()
Try
Dim oSQL = $"
SELECT DISTINCT
[c002], -- Kundennummer
[c003], -- Kundenname
[c050], -- Straße
[c052], -- Ort
[c051], -- PLZ
[c260] -- GLN
FROM [{pMandator.Server}].[{pMandator.Database}].[dbo].[v050]
WHERE
c139 IS NULL
AND mesocomp = '{pMandator.Id}'
AND mesoyear = {oYear}"
Dim oTable = Await Database.GetDatatableAsync(oSQL)
Dim oAccounts As New List(Of Account)
For Each oRow As DataRow In oTable.Rows
Dim oAccountNumber As String = GetRowItem(oRow, V50_ACCOUNTNUMBER, String.Empty)
Dim oAccountName As String = GetRowItem(oRow, V50_ACCOUNTNAME, String.Empty)
Dim oStreetName As String = GetRowItem(oRow, V50_STREETNAME, String.Empty)
Dim oZipCode As String = GetRowItem(oRow, V50_ZIPCODE, String.Empty)
Dim oCityName As String = GetRowItem(oRow, V50_CITYNAME, String.Empty)
Dim oGLN As String = GetRowItem(oRow, V50_GLN, String.Empty)
oAccounts.Add(New Account With {
.Id = oAccountNumber,
.Name = oAccountName,
.StreetName = oStreetName,
.ZipCode = oZipCode,
.CityName = oCityName,
.GLN = oGLN,
.Mandator = pMandator
})
Next
Accounts.AddRange(oAccounts)
Logger.Info("[{0}] Accounts loaded for Mandator [{1}]", oAccounts.Count, pMandator)
Catch ex As Exception
Logger.Warn("Could not load Accounts for Mandator [{0}]", pMandator)
Logger.Error(ex)
End Try
End Function
Public Async Function LoadMandators() As Task
Try
Dim oSQL = "SELECT [c000], [c003], [c004] FROM [cwlsystem].[dbo].[T001SRV] (NOLOCK)"
Dim oTable = Await Database.GetDatatableAsync(oSQL)
Mandators.Clear()
For Each oRow As DataRow In oTable.Rows
Dim oDbInfo = SplitConnectionInfo(oRow)
Dim oMandator = New Mandator With {
.Id = GetRowItem(oRow, T01_MANDATORID, String.Empty),
.Name = GetRowItem(oRow, T01_MANDATORNAME, String.Empty),
.Database = oDbInfo.Item1,
.Server = oDbInfo.Item2
}
Dim oMandatorConfig As Config.MandatorConfig = Config.Mandators.
Where(Function(m) oMandator.Id = m.Name).
SingleOrDefault()
If oMandatorConfig IsNot Nothing Then
oMandator.IsWhitelisted = True
oMandator.Regex = oMandatorConfig.ArticleRegex
oMandator.Order = oMandatorConfig.Order
End If
Mandators.Add(oMandator)
Next
Logger.Info("[{0}] Mandators loaded", Mandators.Count)
Catch ex As Exception
Logger.Warn("Could not load Mandators")
Logger.Error(ex)
End Try
End Function
Public Sub LoadEconomicYears()
Dim oCurrentYear = Now.Year
Dim oRange As IEnumerable(Of Integer) = Enumerable.Range(oCurrentYear - 10, 12).ToList()
Years = oRange
End Sub
Public Async Function LoadDocumentKinds(pMandator As Mandator) As Task
Dim oYear As Integer = GetWinLineYear()
Try
' TODO: This is Schaum specific, maybe move to config later
Dim oSQL = $"
SELECT
[c030],
[c001],
[mesocomp]
FROM [{pMandator.Database}].[dbo].[t357] (NOLOCK)
WHERE (
[c001] LIKE 'Werk%(VK)' OR
[c001] LIKE 'Werk%(WK)'
)
AND [mesocomp] = '{pMandator.Id}' AND [mesoyear] = {oYear}"
Dim oTable As DataTable = Await Database.GetDatatableAsync(oSQL)
Dim oKinds As New List(Of DocumentKind)
For Each oRow As DataRow In oTable.Rows
oKinds.Add(New DocumentKind With {
.Id = GetRowItem(oRow, T357_KINDID, String.Empty),
.Name = GetRowItem(oRow, T357_KINDNAME, String.Empty),
.Mandator = pMandator
})
Next
DocumentKinds.AddRange(oKinds)
Logger.Info("[{0}] DocumentKinds loaded for [{1}]", Mandators.Count, pMandator)
Catch ex As Exception
Logger.Warn("Could not load DocumentKinds")
Logger.Error(ex)
End Try
End Function
Public Function TryGetAccount(pGLN As String, pMandator As Mandator) As Account
Try
If pGLN Is Nothing OrElse pGLN = String.Empty Then
Return Nothing
End If
Dim oYear As Integer = GetWinLineYear()
Dim oSQL = $"
SELECT
[c002], -- Kundennummer
[c003], -- Kundenname
[c050], -- Straße
[c052], -- Ort
[c051] -- PLZ
FROM [{pMandator.Database}].[dbo].[v050]
WHERE [c004] = 2 -- KontoTyp
AND [c260] = '{pGLN}'
AND [mesocomp] = '{pMandator.Id}' and [mesoyear] = {oYear}"
Dim oTable As DataTable = Database.GetDatatable(oSQL)
' GLN not found in this Mandator, continue to next one
If oTable.Rows.Count = 0 Then
Logger.Debug("GLN [{0}] was not found in Mandator: [{1}]", pGLN, pMandator.Id)
Return Nothing
End If
' Duplicate GLN, exit and do nothing about this number
If oTable.Rows.Count > 1 Then
Logger.Warn("GLN [{0}] was found more than once in Mandator: [{1}]", pGLN, pMandator.Id)
Return Nothing
End If
Dim oRow As DataRow = oTable.Rows.Item(0)
Dim oAccountNumber As String = GetRowItem(oRow, V50_ACCOUNTNUMBER, String.Empty)
Dim oAccountName As String = GetRowItem(oRow, V50_ACCOUNTNAME, String.Empty)
Dim oStreetName As String = GetRowItem(oRow, V50_STREETNAME, String.Empty)
Dim oZipCode As String = GetRowItem(oRow, V50_ZIPCODE, String.Empty)
Dim oCityName As String = GetRowItem(oRow, V50_CITYNAME, String.Empty)
Return New Account With {
.Id = oAccountNumber,
.Name = oAccountName,
.StreetName = oStreetName,
.CityName = oCityName,
.ZipCode = oZipCode,
.Mandator = pMandator
}
Catch ex As Exception
Logger.Warn("Error while trying to get account for GLN [{0}]", pGLN)
Logger.Error(ex)
Return Nothing
End Try
End Function
Public Function TryGetArticleNumber(pEAN As String, pMandator As Mandator) As String
Try
Dim oYear As Integer = GetWinLineYear()
Dim oSQL As String = $"
SELECT
[c011], -- Artikelnummer
[c003], -- Artikelbezeichnung
[c075], -- EAN-Nummer
[c123] -- Ersatzartikelnummer
FROM [{pMandator.Database}].[dbo].[v021]
WHERE [c075] = '{pEAN}'
AND [mesocomp] = '{pMandator.Id}' AND [mesoyear] = {oYear}"
Dim oTable As DataTable = Database.GetDatatable(oSQL)
' EAN not found in this Mandator, continue to next one
If oTable.Rows.Count = 0 Then
Logger.Debug("EAN [{0}] was not found in Mandator: [{1}]", pEAN, pMandator.Id)
Return Nothing
End If
' Duplicate EAN, exit and do nothing about this number
If oTable.Rows.Count > 1 Then
Logger.Warn("EAN [{0}] was found more than once", pEAN)
Return Nothing
End If
Dim oRow As DataRow = oTable.Rows.Item(0)
Dim oArticleNumber As String = GetRowItem(oRow, V21_MAINARTICLENUMBER, String.Empty)
Return oArticleNumber
Catch ex As Exception
Logger.Error(ex)
Return Nothing
End Try
End Function
Public Function GetContacts(pAccountNumber As String, pMandator As Mandator) As List(Of Contact)
Try
Dim oContacts As New List(Of Contact)
Dim oYear As Integer = GetWinLineYear()
Dim oSQL As String = $"
SELECT
[c000], -- Key
[c001], -- Name
[c063] -- Kontaktnummer
FROM [{pMandator.Database}].[dbo].[t045]
WHERE [c063] LIKE '{pAccountNumber}-%'
AND [mesocomp] = '{pMandator.Id}' AND [mesoyear] = {oYear}"
Dim oTable As DataTable = Database.GetDatatable(oSQL)
' Contact not found in this Mandator, continue to next one
If oTable.Rows.Count = 0 Then
Logger.Debug("Contact for Account [{0}] was not found in Mandator: [{1}]", pAccountNumber, pMandator.Id)
Return Nothing
End If
For Each oRow In oTable.Rows
oContacts.Add(New Contact With {
.Id = GetRowItem(Of String)(oRow, T45_KEY, Nothing),
.Name = GetRowItem(Of String)(oRow, T45_NAME, Nothing),
.Number = GetRowItem(Of String)(oRow, T45_CONTACTNUMBER, Nothing)
})
Next
Return oContacts
Catch ex As Exception
Logger.Error(ex)
Return Nothing
End Try
End Function
Public Function GetReplacementArticleNumber(pArticleNumber As String, pMandator As Mandator)
Try
Dim oYear As Integer = GetWinLineYear()
Dim oSQL As String = $"
SELECT
[c011], -- Artikelnummer
[c003], -- Artikelbezeichnung
[c075], -- EAN-Nummer
[c123] -- Ersatzartikelnummer
FROM [{pMandator.Database}].[dbo].[v021]
WHERE [c011] = '{pArticleNumber}'
AND [mesocomp] = '{pMandator.Id}' AND [mesoyear] = {oYear}"
Dim oTable As DataTable = Database.GetDatatable(oSQL)
' ArticleNumber not found in this Mandator, continue to next one
If oTable.Rows.Count = 0 Then
Logger.Debug("ArticleNumber [{0}] was not found in Mandator: [{1}]", pArticleNumber, pMandator.Id)
Return Nothing
End If
' Duplicate EAN, exit and do nothing about this number
If oTable.Rows.Count > 1 Then
Logger.Warn("ArticleNumber [{0}] was found more than once", pArticleNumber)
Return Nothing
End If
Dim oRow As DataRow = oTable.Rows.Item(0)
Dim oReplacementArticleNumber = GetRowItem(Of String)(oRow, V21_REPLACEMENTARTICLENUMBER, Nothing)
If oReplacementArticleNumber Is Nothing Then
Return pArticleNumber
End If
Return GetReplacementArticleNumber(oReplacementArticleNumber, pMandator)
Catch ex As Exception
Logger.Error(ex)
Return Nothing
End Try
End Function
Public Function FindMatchingMandatorFromOrder(pData As Documents.Document) As Mandator
Dim oPositions = pData.Rows.
Where(Function(r) r.Name.ToUpper.EndsWith("T026")).
ToList()
Dim oEANNumbers = oPositions.
Select(Function(p)
If p.Fields.ContainsKey("Artikelnummer") Then
Return p.Fields.Item("Artikelnummer").Original
Else
' TODO: Throw or ignore?
Throw New Exceptions.MissingAttributeException("Artikelnummer")
End If
End Function).
Distinct().
ToList()
Dim oYear = GetWinLineYear()
Dim oMandatorId As String = String.Empty
Dim oWhitelistedMandators = Mandators.
Where(Function(m) m.IsWhitelisted = True).
ToList()
For Each oEANNumber In oEANNumbers
For Each oMandator In oWhitelistedMandators
Dim oSQL As String = $"
SELECT
[c011], -- Artikelnummer
[c003], -- Artikelbezeichnung
[c075], -- EAN-Nummer
[c123] -- Ersatzartikelnummer
FROM [{oMandator.Database}].[dbo].[v021]
WHERE [c075] = '{oEANNumber}'
AND [mesocomp] = '{oMandator.Id}' AND [mesoyear] = {oYear}"
Dim oTable As DataTable = Database.GetDatatable(oSQL)
' EAN not found in this Mandator, continue to next one
If oTable.Rows.Count = 0 Then
Logger.Debug("EAN [{0}] was not found in Mandator: [{1}]", oEANNumber, oMandator.Id)
Continue For
End If
' Duplicate EAN, exit and do nothing about this manda
If oTable.Rows.Count > 1 Then
Logger.Warn("EAN [{0}] was found more than once. Skipping Mandator [{1}]", oEANNumber, oMandator.Id)
Exit For
End If
Dim oRow As DataRow = oTable.Rows.Item(0)
Dim oArticleNumber As String = GetRowItem(oRow, V21_MAINARTICLENUMBER, String.Empty)
' EAN was found, now we need to check it against the Regex of the current Mandantor, if one exists
If oMandator.Regex <> String.Empty Then
Try
Dim oRegex As New Regex(oMandator.Regex)
Dim oMatch = oRegex.Match(oArticleNumber)
' If ArticleNumber matches the regex, we assign it and exit
If oMatch.Success Then
oMandatorId = oMandator.Id
Exit For
Else
' If it does not match, continue to the next mandator
End If
Catch ex As Exception
Logger.Error(ex)
Logger.Warn("Regex [{0}] could not be parsed. Skipping.", oMandator.Regex)
End Try
Else
' If no regex was found, we assume the number matches
oMandatorId = oMandator.Id
End If
Next
Next
If oMandatorId = String.Empty Then
Return Nothing
Else
Return oWhitelistedMandators.
Where(Function(m) m.Id = oMandatorId).
Take(1).
SingleOrDefault()
End If
End Function
''' <summary>
''' Turns a database info like "SQLCWLDATEN on SERVER\INSTANCE" into a Tuple of two strings
''' </summary>
''' <param name="pRow"></param>
''' <returns></returns>
Private Function SplitConnectionInfo(pRow As DataRow) As Tuple(Of String, String)
Dim oDbInfo = pRow.Item(T01_DATABASEINFO).ToString()
Dim oSplittedInfo = SplitAtString(oDbInfo.ToUpper, "ON")
Dim oServer = oSplittedInfo.Item(1).Trim()
Dim oDatabase = oSplittedInfo.Item(0).Trim()
If oDatabase.StartsWith("SQL") Then
oDatabase = oDatabase.Remove(0, 3)
End If
Return New Tuple(Of String, String)(oDatabase, oServer)
End Function
Private Function SplitAtString(pStringToSplit As String, pDelimiter As String) As List(Of String)
Dim oDelimiter As String() = New String(0) {pDelimiter}
Return pStringToSplit.
Split(oDelimiter, StringSplitOptions.None).
ToList()
End Function
End Class
End Namespace