Jelajahi Sumber

Added Customer MYOB poster

Kenric Nugteren 1 tahun lalu
induk
melakukan
557de82656

+ 3 - 1
prs.server/Engines/WebEngine/WebListener.cs

@@ -57,7 +57,9 @@ namespace PRSServer
 
         public IResponseBuilder? Response { get; private set; }
 
-        public IEnumerable<System.Data.DataTable> DefaultTables => throw new NotImplementedException();
+        public IEnumerable<System.Data.DataTable> DefaultTables => _dataModel.DefaultTables;
+
+        public IEnumerable<KeyValuePair<string, DataModel.DataModelTable>> ModelTables => _dataModel.ModelTables;
 
         public IResponseBuilder Respond()
         {

+ 98 - 36
prs.shared/Posters/MYOB/CustomerMYOBPoster.cs

@@ -1,6 +1,7 @@
 using Comal.Classes;
 using FastReport.Data;
 using InABox.Core;
+using InABox.Core.Postable;
 using InABox.Poster.MYOB;
 using MYOB.AccountRight.SDK.Services;
 using MYOB.AccountRight.SDK.Services.Contact;
@@ -13,12 +14,19 @@ using System.Threading.Tasks;
 using Customer = Comal.Classes.Customer;
 using MYOBCustomer = MYOB.AccountRight.SDK.Contracts.Version2.Contact.Customer;
 using MYOBAddress = MYOB.AccountRight.SDK.Contracts.Version2.Contact.Address;
+using MYOB.AccountRight.SDK.Contracts.Version2.Sale;
 
 namespace PRS.Shared.Posters.MYOB;
 
-public class CustomerMYOBPoster : IMYOBPoster<Customer>
+public class CustomerMYOBPosterSettings : MYOBPosterSettings
 {
-    public MYOBPosterSettings Settings { get; set; }
+    [TextBoxEditor(ToolTip = "The MYOB tax code which should be used when posting customers")]
+    public string DefaultTaxCode { get; set; }
+}
+
+public class CustomerMYOBPoster : IMYOBPoster<Customer, CustomerMYOBPosterSettings>
+{
+    public CustomerMYOBPosterSettings Settings { get; set; }
     public MYOBGlobalPosterSettings GlobalSettings { get; set; }
 
     public MYOBConnectionData ConnectionData { get; set; }
@@ -29,36 +37,38 @@ public class CustomerMYOBPoster : IMYOBPoster<Customer>
         firstName = names.Length > 0 ? names[0] : "";
         lastName = names.Length > 1 ? names[1] : "";
     }
-    private static string TruncateString(string value, int maxLength)
-    {
-        if(value.Length > maxLength)
-        {
-            return value[..maxLength];
-        }
-        else
-        {
-            return value;
-        }
-    }
 
     private MYOBAddress ConvertAddress(Address address, int location, IContact contact)
     {
         return new MYOBAddress
         {
             Location = location,
-            Street = address.Street,
-            City = address.City,
-            State = address.State,
-            PostCode = address.PostCode,
-            Phone1 = contact.Mobile,
-            Phone2 = contact.Telephone,
-            Email = contact.Email,
-            ContactName = contact.Name
+            Street = address.Street.Truncate(255),
+            City = address.City.Truncate(255),
+            State = address.State.Truncate(255),
+            PostCode = address.PostCode.Truncate(11),
+            Phone1 = contact.Mobile.Truncate(21),
+            Phone2 = contact.Telephone.Truncate(21),
+            Email = contact.Email.Truncate(255),
+            ContactName = contact.Name.Truncate(25)
         };
     }
 
+    public bool BeforePost(IDataModel<Customer> model)
+    {
+        foreach (var (_, table) in model.ModelTables)
+        {
+            table.IsDefault = false;
+        }
+        model.SetIsDefault<Customer>(true);
+
+        return true;
+    }
+
     public IPostResult<Customer> Process(IDataModel<Customer> model)
     {
+        // Documentation: https://developer.myob.com/api/myob-business-api/v2/contact/customer/
+
         var results = new PostResult<Customer>();
 
         var service = new CustomerService(ConnectionData.Configuration, null, ConnectionData.AuthKey);
@@ -69,17 +79,37 @@ public class CustomerMYOBPoster : IMYOBPoster<Customer>
         {
             try
             {
-                Guid.TryParse(customer.PostedReference, out var myobID);
+                bool isNew;
+                MYOBCustomer myobCustomer;
+                if(Guid.TryParse(customer.PostedReference, out var myobID))
+                {
+                    if(!service.Get(ConnectionData, myobID).Get(out var newCustomer, out var error))
+                    {
+                        CoreUtils.LogException("", error, $"Failed to find Customer in MYOB with id {myobID}");
+                        results.AddFailed(customer, $"Failed to find Customer in MYOB with id {myobID}: {error.Message}");
+                        continue;
+                    }
+                    else
+                    {
+                        myobCustomer = newCustomer;
+                        isNew = false;
+                    }
+                }
+                else
+                {
+                    myobCustomer = new MYOBCustomer();
+                    isNew = true;
+                }
+
                 SplitName(customer.DefaultContact.Name, out var firstName, out var lastName);
 
-                var myobCustomer = new MYOBCustomer
+                myobCustomer = new MYOBCustomer
                 {
-                    UID = myobID,
-                    CompanyName = customer.Name,
-                    FirstName = firstName,
-                    LastName = lastName,
+                    CompanyName = customer.Name.Truncate(50),
+                    FirstName = firstName.Truncate(30),
+                    LastName = lastName.Truncate(20),
                     IsIndividual = false,
-                    DisplayID = TruncateString(customer.Code, 15),
+                    DisplayID = customer.Code.Truncate(15),
                     IsActive = customer.CustomerStatus.Active,
                     Addresses =
                     [
@@ -87,15 +117,12 @@ public class CustomerMYOBPoster : IMYOBPoster<Customer>
                         ConvertAddress(customer.Postal, 2, customer.DefaultContact)
                     ],
                     // Notes = 
-                    CurrentBalance = (decimal)customer.Balance,
-                    // PaymentDetails = 
                     // PhotoURI =
                     // RowVersion = 
                 };
-                // myobCustomer.SellingDetails.SaleLayout = 
+                myobCustomer.SellingDetails.SaleLayout = InvoiceLayoutType.NoDefault;
                 // myobCustomer.SellingDetails.PrintedFOrm = 
-                // myobCustomer.SellingDetails.InvoiceDelivery = 
-                // myobCustomer.SellingDetails.ItemPriceLevel = 
+                myobCustomer.SellingDetails.InvoiceDelivery = DocumentAction.PrintAndEmail;
                 // myobCustomer.SellingDetails.IncomeAccount = 
                 // myobCustomer.SellingDetails.ReceiptMemo = 
                 // myobCustomer.SellingDetails.SalesPerson = 
@@ -103,14 +130,47 @@ public class CustomerMYOBPoster : IMYOBPoster<Customer>
                 // myobCustomer.SellingDetails.ShippingMethod = 
                 // myobCustomer.SellingDetails.HourlyBillRate = 
                 // myobCustomer.SellingDetails.ABNBranch = 
-                myobCustomer.SellingDetails.ABN = customer.ABN;
-                // myobCustomer.SellingDetails.TaxCode = 
-                // myobCustomer.SellingDetails.FreightTaxCode = 
+                myobCustomer.SellingDetails.ABN = customer.ABN.Truncate(14);
+
+                if (isNew)
+                {
+                    if (Settings.DefaultTaxCode.IsNullOrWhiteSpace())
+                    {
+                        throw new PostFailedMessageException("Default tax code has not been set up.");
+                    }
+                    else if(ConnectionData.GetMYOBTaxCodeUID(Settings.DefaultTaxCode).Get(out var taxID, out var error))
+                    {
+                        if (taxID.HasValue)
+                        {
+                            myobCustomer.SellingDetails.TaxCode.UID = taxID.Value;
+                            myobCustomer.SellingDetails.FreightTaxCode.UID = taxID.Value;
+                        }
+                        else
+                        {
+                            results.AddFailed(customer, $"Failed to find TaxCode in MYOB with code {Settings.DefaultTaxCode}");
+                            continue;
+                        }
+                    }
+                    else
+                    {
+                        CoreUtils.LogException("", error, $"Failed to find TaxCode in MYOB with code {Settings.DefaultTaxCode}");
+                        results.AddFailed(customer, $"Failed to find TaxCode in MYOB with code {Settings.DefaultTaxCode}: {error.Message}");
+                        continue;
+                    }
+                }
+
                 // myobCustomer.SellingDetails.UseCustomerTaxCode = 
                 // myobCustomer.SellingDetails.Terms = 
                 // myobCustomer.SellingDetails.Credit = 
                 // myobCustomer.SellingDetails.TaxIdNumber = 
                 // myobCustomer.SellingDetails.Memo = 
+                // myboCustomer.PaymentDetails.Method = 
+                // myboCustomer.PaymentDetails.CardNumber = 
+                // myboCustomer.PaymentDetails.NameOnCard = 
+                // myboCustomer.PaymentDetails.BSBNumber = 
+                // myboCustomer.PaymentDetails.BankAccountNumber = 
+                // myboCustomer.PaymentDetails.BankAccountName = 
+                // myboCustomer.PaymentDetails.Notes = 
 
                 var result = service.Update(ConnectionData.CompanyFile, myobCustomer, ConnectionData.CompanyFileCredentials);
                 results.AddSuccess(customer);
@@ -125,3 +185,5 @@ public class CustomerMYOBPoster : IMYOBPoster<Customer>
         return results;
     }
 }
+
+public class CustomerMYOBPosterEngine : MYOBPosterEngine<Customer, CustomerMYOBPosterSettings> { }

+ 118 - 0
prs.shared/Posters/MYOB/PRSMYOBPosterUtils.cs

@@ -0,0 +1,118 @@
+using Comal.Classes;
+using InABox.Core;
+using InABox.Poster.MYOB;
+using MYOB.AccountRight.SDK.Contracts.Version2;
+using MYOB.AccountRight.SDK.Services;
+using MYOB.AccountRight.SDK.Services.GeneralLedger;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MYOBBaseEntity = MYOB.AccountRight.SDK.Contracts.Version2.BaseEntity;
+using MYOBTaxCode = MYOB.AccountRight.SDK.Contracts.Version2.GeneralLedger.TaxCode;
+
+namespace PRS.Shared.Posters.MYOB;
+
+public static class PRSMYOBPosterUtils
+{
+    public class QueryResult<T> : Result<PagedCollection<T>, Exception>
+    {
+        public QueryResult(PagedCollection<T> value) : base(value)
+        {
+        }
+
+        public QueryResult(Exception error) : base(error)
+        {
+        }
+
+        public static QueryResult<T> Ok(PagedCollection<T> collection) => new QueryResult<T>(collection);
+
+        public static QueryResult<T> Error(Exception e) => new QueryResult<T>(e);
+    }
+
+    public class GetResult<T> : Result<T, Exception>
+    {
+        public GetResult(T value) : base(value)
+        {
+        }
+
+        public GetResult(Exception error) : base(error)
+        {
+        }
+
+        public static GetResult<T> Ok(T value) => new GetResult<T>(value);
+
+        public static GetResult<T> Error(Exception e) => new GetResult<T>(e);
+    }
+
+    public static Result<PagedCollection<T>, Exception> Query<T>(
+        this MutableService<T> service, MYOBConnectionData data,
+        Filter<T>? filter,
+        int? top = null, int? skip = null
+    )
+        where T : MYOBBaseEntity
+    {
+        var queries = new List<string>();
+        if(filter is not null)
+        {
+            queries.Add($"$filter={Uri.EscapeDataString(filter.AsOData())}");
+        }
+        if (top.HasValue)
+        {
+            queries.Add($"$top={top.Value}");
+        }
+        if (skip.HasValue)
+        {
+            queries.Add($"$skip={skip.Value}");
+        }
+
+        try
+        {
+            var values = service.GetRange(data.CompanyFile, string.Join('&', queries), data.CompanyFileCredentials);
+            return QueryResult<T>.Ok(values);
+        }
+        catch(Exception e)
+        {
+            return QueryResult<T>.Error(e);
+        }
+    }
+
+    public static GetResult<T> Get<T>(this MutableService<T> service, MYOBConnectionData data, Guid id)
+        where T : MYOBBaseEntity
+    {
+        try
+        {
+            var value = service.Get(data.CompanyFile, id, data.CompanyFileCredentials);
+            return GetResult<T>.Ok(value);
+        }
+        catch(Exception e)
+        {
+            return GetResult<T>.Error(e);
+        }
+    }
+
+    public static Result<Guid?, Exception> GetMYOBTaxCodeUID(this MYOBConnectionData data, string code)
+    {
+        var service = new TaxCodeService(data.Configuration, null, data.AuthKey);
+        var result = service.Query(data, new Filter<MYOBTaxCode>(x => x.Code).IsEqualTo(code), top: 1);
+        if(!result.Get(out var myobCodes, out var error))
+        {
+            return Result.Error<Guid?, Exception>(error);
+        }
+        if(myobCodes.Count == 0)
+        {
+            return Result.Ok<Guid?, Exception>(Guid.Empty);
+        }
+        return Result.Ok<Guid?, Exception>(myobCodes.Items[0].UID);
+    }
+
+    public static Result<Guid?, Exception> GetMYOBTaxCodeUID(this MYOBConnectionData data, ITaxCode code)
+    {
+        if(Guid.TryParse(code.PostedReference, out var id))
+        {
+            return Result.Ok<Guid?, Exception>(id);
+        }
+        return GetMYOBTaxCodeUID(data, code.Code);
+    }
+}

+ 6 - 4
prs.shared/Posters/Timberline/BillTimberlinePoster.cs

@@ -279,9 +279,12 @@ public class Module
 
         public bool BeforePost(IDataModel<Bill> model)
         {
-            model.SetIsDefault<Document>(false, alias: "CompanyLogo");
-            model.SetIsDefault<CoreTable>(false, alias: "CompanyInformation");
-            model.SetIsDefault<Employee>(false);
+            foreach(var (name, table) in model.ModelTables)
+            {
+                table.IsDefault = false;
+            }
+            model.SetIsDefault<Bill>(true);
+            model.SetIsDefault<BillLine>(true, "Bill_BillLine");
 
             model.SetColumns(Columns.None<Bill>().Add(x => x.ID)
                 .Add(x => x.SupplierLink.Code)
@@ -305,7 +308,6 @@ public class Module
                 .Add(x => x.Job.JobNumber),
                 alias: "Bill_BillLine");
 
-            model.SetIsDefault<BillLine>(true, "Bill_BillLine");
             model.AddChildTable<BillLine, PurchaseOrderItem>(x => x.OrderItem.ID, x => x.ID, isdefault: true,
                 parentalias: "Bill_BillLine", childalias: "POItem",
                 columns: Columns.None<PurchaseOrderItem>().Add(x => x.ID)