// Copyright (c) 2017- schick Informatik // Description: Display dialog for customs XML data upload app // using bsmd.database.EasyPeasy; using ENI2.Util; using Microsoft.Win32; using System; using System.Collections.ObjectModel; using System.Globalization; using System.IO; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Xml; using System.Xml.Serialization; namespace ENI2.Controls { /// /// Interaction logic for EasyPeasyControl.xaml /// public partial class EasyPeasyControl : UserControl { private ProofRequest _vm; public EasyPeasyControl() { InitializeComponent(); } public void SaveState() { try { EasyPeasyState.Save(_vm); } catch { } } #region button event handler private void buttonClear_Click(object sender, RoutedEventArgs e) { this._vm = EasyPeasyState.CreateDefault(); if (_vm.ProofInformationT2LT2LF?.GoodsShipmentForT2LT2LF?.GoodsItemsForT2LT2LF == null) _vm.ProofInformationT2LT2LF.GoodsShipmentForT2LT2LF.GoodsItemsForT2LT2LF = new ObservableCollection(); this.DataContext = this._vm; } private void buttonExport_Click(object sender, RoutedEventArgs e) { var dlg = new SaveFileDialog { FileName = "proofRequest.xml", Filter = "XML file|*.xml", OverwritePrompt = true }; if (dlg.ShowDialog() == true) { try { var ser = new XmlSerializer(typeof(ProofRequest)); // Namespaces (if needed) // var ns = new XmlSerializerNamespaces(); // ns.Add("xsd", "http://www.w3.org/2001/XMLSchema"); // ns.Add("xsi", "http://www.w3.org/2001/XMLSchema-instance"); var settings = new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true }; using (var fs = File.Create(dlg.FileName)) using (var xw = XmlWriter.Create(fs, settings)) { ser.Serialize(xw, _vm); //, ns); } MessageBox.Show("Exported successfully.", "easy-peasy", MessageBoxButton.OK, MessageBoxImage.Information); } catch (Exception ex) { MessageBox.Show("Export failed:\n" + ex.Message, "easy-peasy", MessageBoxButton.OK, MessageBoxImage.Error); } } } private void buttonImport_Click(object sender, RoutedEventArgs e) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Filter = "XML file|*.xml"; ofd.RestoreDirectory = true; ofd.Multiselect = false; if (ofd.ShowDialog() == true) { using (var fs = File.OpenRead(ofd.FileName)) { var ser = new XmlSerializer(typeof(ProofRequest)); _vm = (ProofRequest)ser.Deserialize(fs); // after loading/creating _vm if (_vm.ProofInformationT2LT2LF?.GoodsShipmentForT2LT2LF?.GoodsItemsForT2LT2LF == null) _vm.ProofInformationT2LT2LF.GoodsShipmentForT2LT2LF.GoodsItemsForT2LT2LF = new ObservableCollection(); this.DataContext = _vm; } } } #endregion #region loaded/unloaded event handler private void UserControl_Loaded(object sender, RoutedEventArgs e) { _vm = EasyPeasyState.LoadOrCreate(); if (_vm.ProofInformationT2LT2LF == null) _vm.ProofInformationT2LT2LF = new ProofInformationT2LT2LF(); if (_vm.ProofInformationT2LT2LF.GoodsShipmentForT2LT2LF == null) _vm.ProofInformationT2LT2LF.GoodsShipmentForT2LT2LF = new GoodsShipmentForT2LT2LF { LocationOfGoods = new LocationOfGoods(), TransportDocuments = new TransportDocuments() }; this.DataContext = _vm; } private void UserControl_Unloaded(object sender, RoutedEventArgs e) { try { EasyPeasyState.Save(_vm); } catch { } } #endregion #region cut & paste logic private void DataGrid_PreviewKeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.V && (Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) { if (Clipboard.ContainsText()) { var text = Clipboard.GetText(); if(!TryPaste_EspHsPkgsGross(text)) PasteGoodsItems(text); e.Handled = true; } } } private void PasteGoodsItems(string text) { if (_vm?.ProofInformationT2LT2LF?.GoodsShipmentForT2LT2LF == null) return; var lines = text.Replace("\r\n", "\n").Replace('\r', '\n') .Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (var line in lines) { // Split by tab first; if only one column, try CSV var cells = line.Split('\t'); if (cells.Length == 1) cells = SplitCsv(line); // Expected order: HS, Item#, Description, Gross, Net, Pkgs, Type, Marks var item = new GoodsItemForT2LT2LF(); if (cells.Length > 0) item.Commodity.HarmonizedSystemSubHeadingCode = cells[0].Trim(); if (cells.Length > 1 && int.TryParse(cells[1], out var n)) item.GoodsItemNumber = n; if (cells.Length > 2) item.DescriptionOfGoods = cells[2].Trim(); if (cells.Length > 3 && decimal.TryParse(cells[3], out var gross)) item.GoodsMeasure.GrossMass = gross; if (cells.Length > 4 && decimal.TryParse(cells[4], out var net)) item.GoodsMeasure.NetMass = net; if (cells.Length > 5 && int.TryParse(cells[5], out var pkgs)) item.Packaging.NumberOfPackages = pkgs; if (cells.Length > 6) item.Packaging.TypeOfPackages = cells[6].Trim(); if (cells.Length > 7) item.Packaging.ShippingMarks = cells[7].Trim(); _vm.ProofInformationT2LT2LF.GoodsShipmentForT2LT2LF.GoodsItemsForT2LT2LF.Add(item); } } // Very small CSV splitter (handles quotes) private static string[] SplitCsv(string line) { var res = new System.Collections.Generic.List(); var sb = new StringBuilder(); bool inQuotes = false; for (int i = 0; i < line.Length; i++) { char c = line[i]; if (c == '\"') { if (inQuotes && i + 1 < line.Length && line[i + 1] == '\"') { sb.Append('\"'); i++; } else { inQuotes = !inQuotes; } } else if (c == ',' && !inQuotes) { res.Add(sb.ToString()); sb.Clear(); } else { sb.Append(c); } } res.Add(sb.ToString()); return res.ToArray(); } private bool TryPaste_EspHsPkgsGross(string text) { if (_vm?.ProofInformationT2LT2LF?.GoodsShipmentForT2LT2LF == null) return false; // Normalize and split lines var lines = text.Replace("\r\n", "\n").Replace('\r', '\n') .Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); if (lines.Length == 0) return false; // Determine next item number var list = _vm.ProofInformationT2LT2LF.GoodsShipmentForT2LT2LF.GoodsItemsForT2LT2LF; int nextItemNo = list.Any() ? list.Max(x => x.GoodsItemNumber) + 1 : 1; bool anyAdded = false; bool countrySeen = false; foreach (var raw in lines) { var line = raw; // do not Trim() entirely; keep leading tab as empty first cell var cells = line.Split('\t'); // keeps empty entries // Expected: // - 4 cells: [ESP or ""], [HS], [Pkgs], [Gross] // - 3 cells: [HS], [Pkgs], [Gross] string hs = null, pkgs = null, gross = null; if (cells.Length >= 4) { string c0 = cells[0]?.Trim(); // Optionally capture the first token like "ESP" (country tag), // only once and only if alphabetic (won't throw if numeric) if (!countrySeen && !string.IsNullOrWhiteSpace(c0) && c0.All(ch => char.IsLetter(ch))) { // If you decide later this should set a field, uncomment: // if (string.IsNullOrWhiteSpace(_vm.Country)) _vm.Country = c0; countrySeen = true; } hs = (cells.Length > 1 ? cells[1] : null); pkgs = (cells.Length > 2 ? cells[2] : null); gross = (cells.Length > 3 ? cells[3] : null); } else if (cells.Length == 3) { hs = cells[0]; pkgs = cells[1]; gross = cells[2]; } else { // Not enough data for this format; skip the row continue; } if (string.IsNullOrWhiteSpace(hs)) continue; var item = new GoodsItemForT2LT2LF { GoodsItemNumber = nextItemNo++, DescriptionOfGoods = "" // per spec }; item.Commodity.HarmonizedSystemSubHeadingCode = hs.Trim(); if (TryParseIntFlexible(pkgs, out var pk)) item.Packaging.NumberOfPackages = pk; if (TryParseDecimalFlexible(gross, out var g)) { item.GoodsMeasure.GrossMass = g; var net = g - 1m; if (net < 0m) net = 0m; item.GoodsMeasure.NetMass = net; } list.Add(item); anyAdded = true; } return anyAdded; } #endregion #region static utils // this will go somewhere else later // Try parse decimal with current culture, invariant, and comma/dot flip private static bool TryParseDecimalFlexible(string s, out decimal value) { s = (s ?? "").Trim(); // 1) current culture if (decimal.TryParse(s, NumberStyles.Number, CultureInfo.CurrentCulture, out value)) return true; // 2) invariant if (decimal.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out value)) return true; // 3) flip comma/dot and retry (helps when clipboard mixes locales) string flipped = s.Contains(",") ? s.Replace(",", ".") : s.Replace(".", ","); if (decimal.TryParse(flipped, NumberStyles.Number, CultureInfo.CurrentCulture, out value)) return true; if (decimal.TryParse(flipped, NumberStyles.Number, CultureInfo.InvariantCulture, out value)) return true; value = 0m; return false; } private static bool TryParseIntFlexible(string s, out int value) { s = (s ?? "").Trim(); // Extract leading integer if something like "12 pcs" var digits = new string(s.TakeWhile(ch => char.IsDigit(ch) || ch == '-' || ch == '+').ToArray()); if (string.IsNullOrEmpty(digits)) digits = s; return int.TryParse(digits, NumberStyles.Integer, CultureInfo.CurrentCulture, out value) || int.TryParse(digits, NumberStyles.Integer, CultureInfo.InvariantCulture, out value); } #endregion } }