From 3357a8a5643b80243d6d5a969509883225ea3594 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Fri, 17 Jan 2020 11:03:11 -0800 Subject: [PATCH] Added base decoding logic + notification logic. --- BodyshopUploader/BodyshopUploader.csproj | 12 + BodyshopUploader/Models/DTO_QueueItem.cs | 7 + .../Utils/Decoder/EstimateDecoder.cs | 249 ++++++++++++++++++ .../Utils/Growls/GrowlNotification.xaml | 178 +++++++++++++ .../Utils/Growls/GrowlNotification.xaml.cs | 91 +++++++ BodyshopUploader/Utils/Growls/Notification.cs | 102 +++++++ BodyshopUploader/Utils/JobProcessingQueue.cs | 5 +- .../ViewModels/MainViewModel.commands.cs | 2 +- BodyshopUploader/ViewModels/MainViewModel.cs | 15 +- .../ViewModels/MainViewModel.props.cs | 8 +- BodyshopUploader/packages.config | 1 + 11 files changed, 659 insertions(+), 11 deletions(-) create mode 100644 BodyshopUploader/Utils/Decoder/EstimateDecoder.cs create mode 100644 BodyshopUploader/Utils/Growls/GrowlNotification.xaml create mode 100644 BodyshopUploader/Utils/Growls/GrowlNotification.xaml.cs create mode 100644 BodyshopUploader/Utils/Growls/Notification.cs diff --git a/BodyshopUploader/BodyshopUploader.csproj b/BodyshopUploader/BodyshopUploader.csproj index a34dea5..e70a0f0 100644 --- a/BodyshopUploader/BodyshopUploader.csproj +++ b/BodyshopUploader/BodyshopUploader.csproj @@ -55,6 +55,9 @@ favicon.ico + + ..\packages\DotNetDBF.6.0.0.3\lib\net35\DotNetDBF.dll + ..\packages\FirebaseAuthentication.net.3.4.0\lib\netstandard1.1\Firebase.Auth.dll @@ -267,7 +270,12 @@ Component + + + GrowlNotification.xaml + + @@ -288,6 +296,10 @@ Main.xaml + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/BodyshopUploader/Models/DTO_QueueItem.cs b/BodyshopUploader/Models/DTO_QueueItem.cs index abf959e..a4e08bd 100644 --- a/BodyshopUploader/Models/DTO_QueueItem.cs +++ b/BodyshopUploader/Models/DTO_QueueItem.cs @@ -13,6 +13,13 @@ namespace BodyshopUploader.Models } + private dynamic _job; + public dynamic Job + { + get { return _job; } + set { SetProperty(ref _job, value); } + } + private string _filePath; public string FilePath { diff --git a/BodyshopUploader/Utils/Decoder/EstimateDecoder.cs b/BodyshopUploader/Utils/Decoder/EstimateDecoder.cs new file mode 100644 index 0000000..62b5e35 --- /dev/null +++ b/BodyshopUploader/Utils/Decoder/EstimateDecoder.cs @@ -0,0 +1,249 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using DotNetDBF; +using Newtonsoft.Json.Linq; + +namespace BodyshopUploader.Utils.Decoder +{ + class EstimateDecoder + { + public static class CIECAEstimateImport + { + private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); + + /// + /// Decode the set of estimate files based on the creation of an envelope file. + /// + /// Full path to the envelope file that was created/updated. + /// + public static dynamic DecodeEstimate(string FilePath) + { + //Sleep the thread so that all files can finish writing. + Thread.Sleep(1000); + dynamic ret = new JObject(); + + ret.CiecaId = Path.GetFileNameWithoutExtension(FilePath); + + string _dir = Path.GetDirectoryName(FilePath) + @"\"; + + ParseAd1File(ref ret, _dir); + ParseVehFile(ref ret, _dir); + ParseStlFile(ref ret, _dir); + ParseTtlFile(ref ret, _dir); + ParseLinFile(ref ret, _dir); + + return ret; + } + + public static void ParseAd1File(ref dynamic j, string RootFilePath) + { + if (string.IsNullOrWhiteSpace(j.CiecaId.Value)) + { + return; + } + logger.Trace(@"Parsing AD1 at: {0}{1}", RootFilePath, j.CiecaId.Value); + + int retryNumber = 0; + while (retryNumber < 11) + { + try + { + using (Stream fis = File.Open(RootFilePath + j.CiecaId.Value + "A.ad1", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + var reader = new DBFReader(fis); + reader.SetSelectFields(new string[] { "INS_CO_NM", "CLM_NO", "OWNR_LN", "OWNR_FN", "OWNR_EA", "OWNR_PH1" }); + var readValues = reader.NextRecord(); + j.Claim_Source = readValues[0].ToString(); + j.Claim_Number = readValues[1].ToString(); + j.Owner_Ln = readValues[2].ToString(); + j.Owner_Fn = readValues[3].ToString(); + j.Owner_Email = readValues[4].ToString(); + j.Owner_Phone = readValues[5].ToString(); + return; + } + } + catch (IOException ex) + { + logger.Trace(ex, "Unable to open AD1 file. Retrying. "); + retryNumber++; + Thread.Sleep(3000); + } + } + + + } + + public static void ParseVehFile(ref dynamic j, string RootFilePath) + { + if (string.IsNullOrWhiteSpace(j.CiecaId.Value)) { return; } + + logger.Trace(@"Parsing Veh at: {0}{1}", RootFilePath, j.CiecaId.Value); + + int retryNumber = 0; + while (retryNumber < 11) + { + try + { + using (Stream fis = File.Open(RootFilePath + j.CiecaId.Value + "v.veh", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + var reader = new DBFReader(fis); + reader.SetSelectFields(new string[] { "V_MODEL_YR", "V_MAKEDESC", "V_MODEL", "V_COLOR", "PLATE_NO", "V_VIN" }); + var readValues = reader.NextRecord(); + j.V_Model_Yr = readValues[0].ToString(); + j.V_Make_Desc = readValues[1].ToString(); + j.V_Model = readValues[2].ToString(); + j.V_Color = readValues[3].ToString(); + j.Lic_Plate = readValues[4].ToString(); + j.V_Vin = readValues[5].ToString(); + + } + return; + } + catch (IOException ex) + { + logger.Trace(ex, "Unable to open VEH file. Retrying. "); + retryNumber++; + Thread.Sleep(3000); + } + } + } + + public static void ParseTtlFile(ref dynamic j, string RootFilePath) + { + if (string.IsNullOrWhiteSpace(j.CiecaId.Value)) { return; } + + logger.Trace(@"Parsing Ttl at: {0}{1}", RootFilePath, j.CiecaId.Value); + + + + int retryNumber = 0; + while (retryNumber < 11) + { + try + { + using (Stream fis = File.Open(RootFilePath + j.CiecaId.Value + ".ttl", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + var reader = new DBFReader(fis); + reader.SetSelectFields(new string[] { "G_TTL_AMT" }); + var readValues = reader.NextRecord(); + j.Claim_Total = Convert.ToDecimal(readValues[0].ToString()); + } + return; + } + catch (IOException ex) + { + logger.Trace(ex, "Unable to open TTL file. Retrying. "); + retryNumber++; + Thread.Sleep(3000); + } + } + } + + public static void ParseStlFile(ref dynamic j, string RootFilePath) + { + if (string.IsNullOrWhiteSpace(j.CiecaId.Value)) { return; } + + logger.Trace(@"Parsing Ttl at: {0}{1}", RootFilePath, j.CiecaId.Value); + + + + int retryNumber = 0; + while (retryNumber < 11) + { + try + { + using (Stream fis = File.Open(RootFilePath + j.CiecaId.Value + ".stl", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + var reader = new DBFReader(fis); + reader.SetSelectFields(new string[] { "TTL_TYPECD", "T_HRS" }); + var _rc = reader.RecordCount; + for (var i = 0; i < _rc; i++) + { + var readValues = reader.NextRecord(); + switch (readValues[0]) + { + + //Labor Code + case "LAB": + j.BodyHrs = Convert.ToDecimal(readValues[1]); + break; + case "LAR": + j.RefHrs = Convert.ToDecimal(readValues[1]); + break; + } + } + } + return; + } + catch (IOException ex) + { + logger.Trace(ex, "Unable to open STL file. Retrying. "); + retryNumber++; + Thread.Sleep(3000); + } + } + } + + + public static void ParseLinFile(ref dynamic j, string RootFilePath) + { + if (string.IsNullOrWhiteSpace(j.CiecaId.Value)) { return; } + + logger.Trace(@"Parsing Ttl at: {0}{1}", RootFilePath, j.CiecaId.Value); + //j.JobSublets = new List(); + + string _maxSupp = ""; + + int retryNumber = 0; + while (retryNumber < 11) + { + try + { + using (Stream fis = File.Open(RootFilePath + j.CiecaId.Value + ".lin", FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + var reader = new DBFReader(fis); + reader.SetSelectFields(new string[] { "PART_TYPE", "LINE_DESC", "UNQ_SEQ", "LINE_IND" }); + var _rc = reader.RecordCount; + for (var i = 0; i < _rc; i++) + { + var readValues = reader.NextRecord(); + //Find Max Supplement Number + if (string.Compare(_maxSupp, readValues[3].ToString()) < 0) + { + _maxSupp = readValues[3].ToString(); + } + + switch (readValues[3]) + { + + //Labor Code + case "PAS": + case "PASL": + //j.JobSublets.Add(new JobSublet() + //{ + // SubletDesc = readValues[1].ToString(), + // Unq_Seq = Convert.ToInt32(readValues[2]) + //}); + break; + } + } + } + j.MaxSupplement = _maxSupp; + return; + } + catch (IOException ex) + { + logger.Trace(ex, "Unable to open LIN file. Retrying. "); + retryNumber++; + Thread.Sleep(3000); + } + } + } + } + } +} diff --git a/BodyshopUploader/Utils/Growls/GrowlNotification.xaml b/BodyshopUploader/Utils/Growls/GrowlNotification.xaml new file mode 100644 index 0000000..42dd3ea --- /dev/null +++ b/BodyshopUploader/Utils/Growls/GrowlNotification.xaml @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyshopUploader/Utils/Growls/GrowlNotification.xaml.cs b/BodyshopUploader/Utils/Growls/GrowlNotification.xaml.cs new file mode 100644 index 0000000..6820078 --- /dev/null +++ b/BodyshopUploader/Utils/Growls/GrowlNotification.xaml.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Shapes; + + +namespace BodyshopUploader.Utils.Growls +{ + public partial class GrowlNotification + { + private const byte MAX_NOTIFICATIONS = 4; + private int count; + public Notifications Notifications = new Notifications(); + private readonly Notifications buffer = new Notifications(); + public ViewModels.MainViewModel ShellVm; + public GrowlNotification(ViewModels.MainViewModel shellViewModel) + { + InitializeComponent(); + ShellVm = shellViewModel; + NotificationsControl.DataContext = Notifications; + var desktopWorkingArea = System.Windows.SystemParameters.WorkArea; + this.Left = desktopWorkingArea.Right - 425; + //this.Top = desktopWorkingArea.Bottom - 425; + this.Top = 50; + } + + public void AddNotification(Notification notification) + { + notification.Id = count++; + if (Notifications.Count + 1 > MAX_NOTIFICATIONS) + buffer.Add(notification); + else + Notifications.Add(notification); + //Show window if there're notifications + if (Notifications.Count > 0 && !IsActive) + Show(); + } + public void RemoveNotification(Notification notification) + { + if (Notifications.Contains(notification)) + Notifications.Remove(notification); + if (buffer.Count > 0) + { + Notifications.Add(buffer[0]); + buffer.RemoveAt(0); + } + //Close window if there's nothing to show + if (Notifications.Count < 1) + Hide(); + } + private void NotificationWindowSizeChanged(object sender, SizeChangedEventArgs e) + { + if (e.NewSize.Height != 0.0) + return; + var element = sender as Grid; + RemoveNotification(Notifications.First( + n => n.Id == Int32.Parse(element.Tag.ToString()))); + } + + private void NotificationWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) + { + Notification n = (Notification)((Grid)sender).DataContext; + BringWindowToFront(); + RemoveNotification(n); + } + + static void BringWindowToFront() + { + var currentProcess = Process.GetCurrentProcess(); + var processes = Process.GetProcessesByName(currentProcess.ProcessName); + var process = processes.FirstOrDefault(p => p.Id == currentProcess.Id); + if (process == null) return; + + SetForegroundWindow(process.MainWindowHandle); + } + + [DllImport("user32.dll")] + static extern bool SetForegroundWindow(IntPtr hWnd); + } +} diff --git a/BodyshopUploader/Utils/Growls/Notification.cs b/BodyshopUploader/Utils/Growls/Notification.cs new file mode 100644 index 0000000..de38944 --- /dev/null +++ b/BodyshopUploader/Utils/Growls/Notification.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BodyshopUploader.Utils.Growls +{ + public class Notification : INotifyPropertyChanged + { + private string message; + public string Message + { + get { return message; } + + set + { + if (message == value) return; + message = value; + OnPropertyChanged("Message"); + } + } + + private int id; + public int Id + { + get { return id; } + + set + { + if (id == value) return; + id = value; + OnPropertyChanged("Id"); + } + } + + private int threadid; + public int ThreadId + { + get { return threadid; } + + set + { + if (threadid == value) return; + threadid = value; + OnPropertyChanged("ThreadId"); + } + } + + private string imageUrl; + public string ImageUrl + { + get { return imageUrl; } + + set + { + if (imageUrl == value) return; + imageUrl = value; + OnPropertyChanged("ImageUrl"); + } + } + + + private string title; + public string Title + { + get { return title; } + + set + { + if (title == value) return; + title = value; + OnPropertyChanged("Title"); + } + } + + private string subtitle; + public string Subtitle + { + get { return subtitle; } + + set + { + if (subtitle == value) return; + subtitle = value; + OnPropertyChanged("Subtitle"); + } + } + + protected virtual void OnPropertyChanged(string propertyName) + { + var handler = PropertyChanged; + if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); + } + + public event PropertyChangedEventHandler PropertyChanged; + } + + public class Notifications : ObservableCollection { } +} diff --git a/BodyshopUploader/Utils/JobProcessingQueue.cs b/BodyshopUploader/Utils/JobProcessingQueue.cs index 14cb41f..3646e86 100644 --- a/BodyshopUploader/Utils/JobProcessingQueue.cs +++ b/BodyshopUploader/Utils/JobProcessingQueue.cs @@ -57,9 +57,7 @@ namespace BodyshopUploader.Utils try { Thread.Sleep(1000);//Allow a small amount of time to pass before processing the queue item so that any writes can finish. - DecodeQueueItemJob(item); - UpsertQueueItem(item); } catch @@ -74,12 +72,13 @@ namespace BodyshopUploader.Utils { //Process the job. logger.Info("Should process the job here. {0}", item.FilePath); + item.Job = Utils.Decoder.EstimateDecoder.CIECAEstimateImport.DecodeEstimate(item.FilePath); } private static void UpsertQueueItem(DTO_QueueItem item) { //Save the job to the DB. - logger.Info("Should upsert the job graphqlly here. {0}", item.FilePath); + logger.Info("Should upsert the job graphqlly here. {0}", item.Job); _jobs.Dequeue(); } diff --git a/BodyshopUploader/ViewModels/MainViewModel.commands.cs b/BodyshopUploader/ViewModels/MainViewModel.commands.cs index 9598ebe..d538ebc 100644 --- a/BodyshopUploader/ViewModels/MainViewModel.commands.cs +++ b/BodyshopUploader/ViewModels/MainViewModel.commands.cs @@ -63,7 +63,7 @@ namespace BodyshopUploader.ViewModels if (_removeMonitoringPathCommand == null) { _removeMonitoringPathCommand = new RelayCommand( - p => true, + p => FolderMonitors.Count == 0, p => RemoveFolderMonitoringPath(p as string) ); } diff --git a/BodyshopUploader/ViewModels/MainViewModel.cs b/BodyshopUploader/ViewModels/MainViewModel.cs index 88b87c7..28eefe9 100644 --- a/BodyshopUploader/ViewModels/MainViewModel.cs +++ b/BodyshopUploader/ViewModels/MainViewModel.cs @@ -1,4 +1,5 @@ -using GraphQL.Client; +using BodyshopUploader.Utils.Growls; +using GraphQL.Client; using GraphQL.Common.Request; using System; using System.Collections.Generic; @@ -17,6 +18,7 @@ namespace BodyshopUploader.ViewModels public MainViewModel() { logger.Trace("Main VM Created."); + Growler = new GrowlNotification(this); //Create Variables if (MonitoringPaths == null) MonitoringPaths = new ObservableCollection(); @@ -75,6 +77,17 @@ namespace BodyshopUploader.ViewModels public async Task TestGql() { + Notification _n = new Notification() + { + Id = 123, + ThreadId = 123, + Title = "This is a title", + Subtitle = "Subtitle", + Message = "Somethin" + }; + Growler.AddNotification(_n); + + var r = new GraphQLRequest { Query = @" diff --git a/BodyshopUploader/ViewModels/MainViewModel.props.cs b/BodyshopUploader/ViewModels/MainViewModel.props.cs index 363a33d..34370e8 100644 --- a/BodyshopUploader/ViewModels/MainViewModel.props.cs +++ b/BodyshopUploader/ViewModels/MainViewModel.props.cs @@ -4,17 +4,13 @@ using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; +using BodyshopUploader.Utils.Growls; namespace BodyshopUploader.ViewModels { public partial class MainViewModel : BaseViewModel { - private int _progress = 5; - public int Progress - { - get { return _progress; } - set { SetProperty(ref _progress, value); } - } + public GrowlNotification Growler; private ObservableCollection _folderMonitors = new ObservableCollection() ; public ObservableCollection FolderMonitors diff --git a/BodyshopUploader/packages.config b/BodyshopUploader/packages.config index e5b3837..7986984 100644 --- a/BodyshopUploader/packages.config +++ b/BodyshopUploader/packages.config @@ -1,5 +1,6 @@  +