瀏覽代碼

Added supplier MYOB puller; fixed some problems with pullers. Improved interface of pulling screen by using images instead of text.

Kenric Nugteren 11 月之前
父節點
當前提交
296718eb8a
共有 3 個文件被更改,包括 274 次插入24 次删除
  1. 79 5
      prs.desktop/Utils/PostUtils.cs
  2. 48 18
      prs.shared/Posters/MYOB/CustomerMYOBPoster.cs
  3. 147 1
      prs.shared/Posters/MYOB/SupplierMYOBPoster.cs

+ 79 - 5
prs.desktop/Utils/PostUtils.cs

@@ -5,6 +5,7 @@ using InABox.Core.Postable;
 using InABox.DynamicGrid;
 using InABox.Wpf;
 using InABox.WPF;
+using Syncfusion.UI.Xaml.Diagram;
 using System;
 using System.Collections.Generic;
 using System.Diagnostics.CodeAnalysis;
@@ -22,7 +23,9 @@ namespace PRSDesktop;
 public class PullResultGrid<T> : DynamicItemsListGrid<T>
     where T : BaseObject, IPostable, new()
 {
-    private static BitmapImage tick = InABox.Wpf.Resources.tick.AsBitmapImage();
+    private static readonly BitmapImage tick = InABox.Wpf.Resources.tick.AsBitmapImage();
+    private static readonly BitmapImage link = PRSDesktop.Resources.link.AsBitmapImage();
+    private static readonly BitmapImage refresh = PRSDesktop.Resources.refresh.AsBitmapImage();
 
     private class ResultItem(PullResultItem<T> item, bool selected)
     {
@@ -72,12 +75,59 @@ public class PullResultGrid<T> : DynamicItemsListGrid<T>
         base.Init();
 
         ActionColumns.Add(new DynamicImageColumn(Selected_Image, Selected_Click) { Position = DynamicActionColumnPosition.Start });
-        ActionColumns.Add(new DynamicTextColumn(row => GetItem(row)?.Item.Type.ToString() ?? "Action")
+        ActionColumns.Add(new DynamicImageColumn(Action_Image)
         {
-            Position = DynamicActionColumnPosition.Start
+            Position = DynamicActionColumnPosition.Start,
+            ToolTip = Action_ToolTip
         });
     }
 
+    private FrameworkElement? Action_ToolTip(DynamicActionColumn column, CoreRow? row)
+    {
+        var item = GetItem(row);
+        if(item is null)
+        {
+            return column.TextToolTip("Item Import Action");
+        }
+        else if(item.Item.Type == PullResultType.Linked)
+        {
+            return column.TextToolTip("Existing PRS item linked to external item.");
+        }
+        else if(item.Item.Type == PullResultType.Updated)
+        {
+            return column.TextToolTip("Existing PRS item updated to external item.");
+        }
+        else if(item.Item.Type == PullResultType.New)
+        {
+            return column.TextToolTip("New item imported.");
+        }
+        else
+        {
+            return null;
+        }
+    }
+
+    private BitmapImage? Action_Image(CoreRow? row)
+    {
+        var item = GetItem(row);
+        if(item is null)
+        {
+            return null;
+        }
+        else if(item.Item.Type == PullResultType.Linked)
+        {
+            return link;
+        }
+        else if(item.Item.Type == PullResultType.Updated)
+        {
+            return refresh;
+        }
+        else
+        {
+            return null;
+        }
+    }
+
     private BitmapImage? Selected_Image(CoreRow? row)
     {
         var item = GetItem(row);
@@ -93,9 +143,33 @@ public class PullResultGrid<T> : DynamicItemsListGrid<T>
         {
             item.Selected = !item.Selected;
             DoChanged();
-            return true;
+            InvalidateRow(row!);
+            return false;
+        }
+        else
+        {
+            var menu = new ContextMenu();
+            menu.AddItem("Select All", null, () =>
+            {
+                foreach (var item in _items)
+                {
+                    item.Selected = true;
+                }
+                DoChanged();
+                InvalidateGrid();
+            });
+            menu.AddItem("Deselect All", null, () =>
+            {
+                foreach (var item in _items)
+                {
+                    item.Selected = false;
+                }
+                DoChanged();
+                InvalidateGrid();
+            });
+            menu.IsOpen = true;
+            return false;
         }
-        return false;
     }
 
     protected override void DoReconfigure(DynamicGridOptions options)

+ 48 - 18
prs.shared/Posters/MYOB/CustomerMYOBPoster.cs

@@ -293,6 +293,11 @@ public class CustomerMYOBPoster :
         }).Flatten();
     }
 
+    private static bool IsBlankCode(string code)
+    {
+        return code.IsNullOrWhiteSpace() || code.Equals("*None");
+    }
+
     public IPullResult<Customer> Pull()
     {
         var result = new PullResult<Customer>();
@@ -316,8 +321,8 @@ public class CustomerMYOBPoster :
             }
 
             var myobIDs = myobCustomers.Items.ToArray(x => x.UID.ToString());
-            var myobCodes = myobCustomers.Items.Select(x => x.DisplayID).Where(x => !x.IsNullOrWhiteSpace()).ToArray();
-            var myobNames = myobCustomers.Items.Where(x => x.DisplayID.IsNullOrWhiteSpace() && !x.CompanyName.IsNullOrWhiteSpace())
+            var myobCodes = myobCustomers.Items.Select(x => x.DisplayID).Where(x => !IsBlankCode(x)).ToArray();
+            var myobNames = myobCustomers.Items.Where(x => IsBlankCode(x.DisplayID) && !x.CompanyName.IsNullOrWhiteSpace())
                 .Select(x => x.CompanyName).ToArray();
 
             var customers = Client.Query(
@@ -328,6 +333,7 @@ public class CustomerMYOBPoster :
                 .ToArray<Customer>();
             var customerDict = customers.Where(x => !x.PostedReference.IsNullOrWhiteSpace())
                 .ToDictionary(x => x.PostedReference);
+            var blankCustomers = customers.Where(x => x.PostedReference.IsNullOrWhiteSpace()).ToArray();
 
             var needCodes = new Dictionary<string, (string prefix, int i, Customer customer)>();
 
@@ -338,9 +344,9 @@ public class CustomerMYOBPoster :
                     // Skipping existing customers at this point.
                     continue;
                 }
-                customer = !myobCustomer.DisplayID.IsNullOrWhiteSpace()
-                    ? customers.FirstOrDefault(x => string.Equals(x.Code, myobCustomer.DisplayID))
-                    : customers.FirstOrDefault(x => string.Equals(x.Name, myobCustomer.CompanyName));
+                customer = !IsBlankCode(myobCustomer.DisplayID)
+                    ? blankCustomers.FirstOrDefault(x => string.Equals(x.Code, myobCustomer.DisplayID))
+                    : blankCustomers.FirstOrDefault(x => string.Equals(x.Name, myobCustomer.CompanyName));
                 if(customer is not null)
                 {
                     customer.PostedReference = myobCustomer.UID.ToString();
@@ -351,7 +357,7 @@ public class CustomerMYOBPoster :
                 customer = new Customer();
 
                 string code;
-                if (!myobCustomer.DisplayID.IsNullOrWhiteSpace())
+                if (!IsBlankCode(myobCustomer.DisplayID))
                 {
                     code = myobCustomer.DisplayID.ToString();
                 }
@@ -375,17 +381,20 @@ public class CustomerMYOBPoster :
                 customer.Name = myobCustomer.CompanyName;
                 customer.ABN = myobCustomer.SellingDetails.ABN;
 
-                var delivery = myobCustomer.Addresses.FirstOrDefault(x => x.Location == 2);
-                if(delivery is not null)
+                if(myobCustomer.Addresses is not null)
                 {
-                    customer.Delivery.CopyFrom(ContactMYOBUtils.ConvertAddress(delivery));
-                }
-                var postal = myobCustomer.Addresses.FirstOrDefault(x => x.Location == 1);
-                if(postal is not null)
-                {
-                    customer.Postal.CopyFrom(ContactMYOBUtils.ConvertAddress(postal));
+                    var delivery = myobCustomer.Addresses.FirstOrDefault(x => x.Location == 2);
+                    if(delivery is not null)
+                    {
+                        customer.Delivery.CopyFrom(ContactMYOBUtils.ConvertAddress(delivery));
+                    }
+                    var postal = myobCustomer.Addresses.FirstOrDefault(x => x.Location == 1);
+                    if(postal is not null)
+                    {
+                        customer.Postal.CopyFrom(ContactMYOBUtils.ConvertAddress(postal));
+                    }
+                    customer.Email = delivery?.Email ?? postal?.Email ?? "";
                 }
-                customer.Email = delivery?.Email ?? postal?.Email ?? "";
 
                 customer.PostedReference = myobCustomer.UID.ToString();
                 result.AddEntity(PullResultType.New, customer);
@@ -407,7 +416,7 @@ public class CustomerMYOBPoster :
                         int i = needed.i;
                         do
                         {
-                            needed.customer.Code = $"{needed.prefix}{needed.i:d3}";
+                            needed.customer.Code = $"{needed.prefix}{i:d3}";
                             ++i;
                         } while (customerCodes.Contains(needed.customer.Code));
                         customerCodes.Add(needed.customer.Code);
@@ -465,10 +474,31 @@ public class CustomerMYOBPoster :
                         myobCustomer = myobCustomers.Items[0];
                         isNew = false;
                     }
+                    else if(service.Query(
+                        ConnectionData,
+                        new Filter<MYOBCustomer>(x => x.CompanyName).IsEqualTo(customer.Name)
+                            .And(new Filter<MYOBCustomer>(x => x.DisplayID).IsEqualTo(null)
+                                .Or(x => x.DisplayID).IsEqualTo("")
+                                .Or(x => x.DisplayID).IsEqualTo("*None")),
+                        top: 1).Get(out myobCustomers, out error))
+                    {
+                        if(myobCustomers.Items.Length > 0)
+                        {
+                            myobCustomer = myobCustomers.Items[0];
+                            myobCustomer.DisplayID = customer.Code;
+                            isNew = false;
+                        }
+                        else
+                        {
+                            myobCustomer = new MYOBCustomer();
+                            isNew = true;
+                        }
+                    }
                     else
                     {
-                        myobCustomer = new MYOBCustomer();
-                        isNew = true;
+                        CoreUtils.LogException("", error);
+                        results.AddFailed(customer, error.Message);
+                        continue;
                     }
                 }
                 else

+ 147 - 1
prs.shared/Posters/MYOB/SupplierMYOBPoster.cs

@@ -245,6 +245,145 @@ public class SupplierMYOBPoster : IMYOBPoster<Supplier, SupplierMYOBPosterSettin
         }).Flatten();
     }
 
+    private static bool IsBlankCode(string code)
+    {
+        return code.IsNullOrWhiteSpace() || code.Equals("*None");
+    }
+
+    public IPullResult<Supplier> Pull()
+    {
+        var result = new PullResult<Supplier>();
+
+        var top = 400;
+        var skip = 0;
+
+        var supplierCodes = new HashSet<string>();
+
+        var service = new SupplierService(ConnectionData.Configuration, null, ConnectionData.AuthKey);
+        while (true)
+        {
+            if(!service.Query(ConnectionData, null, top: top, skip: skip).Get(out var myobSuppliers, out var error))
+            {
+                CoreUtils.LogException("", error);
+                throw new PullFailedMessageException(error.Message);
+            }
+            if(myobSuppliers.Items.Length == 0)
+            {
+                break;
+            }
+
+            var myobIDs = myobSuppliers.Items.ToArray(x => x.UID.ToString());
+            var myobCodes = myobSuppliers.Items.Select(x => x.DisplayID).Where(x => !IsBlankCode(x)).ToArray();
+            var myobNames = myobSuppliers.Items.Where(x => IsBlankCode(x.DisplayID) && !x.CompanyName.IsNullOrWhiteSpace())
+                .Select(x => x.CompanyName).ToArray();
+
+            var suppliers = Client.Query(
+                new Filter<Supplier>(x => x.PostedReference).InList(myobIDs)
+                    .Or(x => x.Code).InList(myobCodes)
+                    .Or(x => x.Name).InList(myobNames),
+                Columns.None<Supplier>().Add(x => x.ID).Add(x => x.PostedReference).Add(x => x.Code).Add(x => x.Name))
+                .ToArray<Supplier>();
+            var supplierDict = suppliers.Where(x => !x.PostedReference.IsNullOrWhiteSpace())
+                .ToDictionary(x => x.PostedReference);
+            var blankSuppliers = suppliers.Where(x => x.PostedReference.IsNullOrWhiteSpace()).ToArray();
+
+            var needCodes = new Dictionary<string, (string prefix, int i, Supplier supplier)>();
+
+            foreach(var myobSupplier in myobSuppliers.Items)
+            {
+                if (supplierDict.TryGetValue(myobSupplier.UID.ToString(), out var supplier))
+                {
+                    // Skipping existing suppliers at this point.
+                    continue;
+                }
+                supplier = !IsBlankCode(myobSupplier.DisplayID)
+                    ? blankSuppliers.FirstOrDefault(x => string.Equals(x.Code, myobSupplier.DisplayID))
+                    : blankSuppliers.FirstOrDefault(x => string.Equals(x.Name, myobSupplier.CompanyName));
+                if(supplier is not null)
+                {
+                    supplier.PostedReference = myobSupplier.UID.ToString();
+                    result.AddEntity(PullResultType.Linked, supplier);
+                    continue;
+                }
+
+                supplier = new Supplier();
+
+                string code;
+                if (!IsBlankCode(myobSupplier.DisplayID))
+                {
+                    code = myobSupplier.DisplayID.ToString();
+                }
+                else if (!myobSupplier.CompanyName.IsNullOrWhiteSpace())
+                {
+                    code = myobSupplier.CompanyName[..Math.Min(3, myobSupplier.CompanyName.Length)].ToUpper();
+                }
+                else
+                {
+                    code = "SUP";
+                }
+                int i = 1;
+                supplier.Code = code;
+                while (supplierCodes.Contains(supplier.Code))
+                {
+                    supplier.Code = $"{code}{i:d3}";
+                    ++i;
+                }
+                supplierCodes.Add(supplier.Code);
+
+                supplier.Name = myobSupplier.CompanyName;
+                supplier.ABN = myobSupplier.BuyingDetails.ABN;
+
+                if(myobSupplier.Addresses is not null)
+                {
+                    var delivery = myobSupplier.Addresses.FirstOrDefault(x => x.Location == 2);
+                    if(delivery is not null)
+                    {
+                        supplier.Delivery.CopyFrom(ContactMYOBUtils.ConvertAddress(delivery));
+                    }
+                    var postal = myobSupplier.Addresses.FirstOrDefault(x => x.Location == 1);
+                    if(postal is not null)
+                    {
+                        supplier.Postal.CopyFrom(ContactMYOBUtils.ConvertAddress(postal));
+                    }
+                    supplier.Email = delivery?.Email ?? postal?.Email ?? "";
+                }
+
+                supplier.PostedReference = myobSupplier.UID.ToString();
+                result.AddEntity(PullResultType.New, supplier);
+                needCodes.Add(supplier.Code, (code, i, supplier));
+            }
+
+            // Do code clash checking
+            while(needCodes.Count > 0)
+            {
+                var codes = Client.Query(
+                    new Filter<Supplier>(x => x.Code).InList(needCodes.Values.Select(x => x.supplier.Code).ToArray()),
+                    Columns.None<Supplier>().Add(x => x.Code));
+                var newNeedCodes = new Dictionary<string, (string prefix, int i, Supplier supplier)>();
+                foreach(var row in codes.Rows)
+                {
+                    var code = row.Get<Supplier, string>(x => x.Code);
+                    if(needCodes.Remove(code, out var needed))
+                    {
+                        int i = needed.i;
+                        do
+                        {
+                            needed.supplier.Code = $"{needed.prefix}{i:d3}";
+                            ++i;
+                        } while (supplierCodes.Contains(needed.supplier.Code));
+                        supplierCodes.Add(needed.supplier.Code);
+                        newNeedCodes.Add(needed.supplier.Code, (needed.prefix, i, needed.supplier));
+                    }
+                }
+                needCodes = newNeedCodes;
+            }
+
+            skip += top;
+        }
+
+        return result;
+    }
+
     public IPostResult<Supplier> Process(IDataModel<Supplier> model)
     {
         var results = new PostResult<Supplier>();
@@ -340,4 +479,11 @@ public class SupplierMYOBPoster : IMYOBPoster<Supplier, SupplierMYOBPosterSettin
         return results;
     }
 }
-public class SupplierMYOBPosterEngine<T> : MYOBPosterEngine<Supplier, SupplierMYOBPoster, SupplierMYOBPosterSettings> { }
+public class SupplierMYOBPosterEngine<T> : MYOBPosterEngine<Supplier, SupplierMYOBPoster, SupplierMYOBPosterSettings>, IPullerEngine<Supplier, SupplierMYOBPoster>
+{
+    public IPullResult<Supplier> DoPull()
+    {
+        LoadConnectionData();
+        return Poster.Pull();
+    }
+}