Forráskód Böngészése

Added initial MYOB poster code

Kenric Nugteren 1 éve
szülő
commit
930352bac1

+ 16 - 0
InABox.Poster.MYOB/IMYOBPoster.cs

@@ -0,0 +1,16 @@
+using InABox.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace InABox.Poster.MYOB;
+
+public interface IMYOBPoster<TPostable> : IPoster<TPostable, MYOBPosterSettings>, IGlobalSettingsPoster<MYOBGlobalPosterSettings>
+    where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
+{
+    public MYOBConnectionData ConnectionData { get; set; }
+
+    IPostResult<TPostable> Process(IDataModel<TPostable> model);
+}

+ 18 - 0
InABox.Poster.MYOB/InABox.Poster.MYOB.csproj

@@ -0,0 +1,18 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFramework>net8.0-windows</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+	  <UseWpf>true</UseWpf>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <PackageReference Include="MYOB.AccountRight.API.SDK" Version="2024.4.591" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\InABox.Core\InABox.Core.csproj" />
+  </ItemGroup>
+
+</Project>

+ 17 - 0
InABox.Poster.MYOB/MYOBGlobalPosterSettings.cs

@@ -0,0 +1,17 @@
+using InABox.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace InABox.Poster.MYOB;
+
+public class MYOBGlobalPosterSettings : GlobalPosterSettings
+{
+    public Guid CompanyFileID { get; set; }
+
+    public string CompanyFileUserID { get; set; }
+
+    public string CompanyFilePassword { get; set; }
+}

+ 155 - 0
InABox.Poster.MYOB/MYOBPosterEngine.cs

@@ -0,0 +1,155 @@
+using InABox.Core;
+using InABox.Core.Postable;
+using MYOB.AccountRight.SDK;
+using MYOB.AccountRight.SDK.Contracts;
+using MYOB.AccountRight.SDK.Services;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using System.Threading.Tasks;
+using System.Web;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace InABox.Poster.MYOB;
+
+public class MYOBConnectionData(ApiConfiguration configuration, CompanyFileService cfService)
+{
+    public ApiConfiguration Configuration { get; set; } = configuration;
+
+    public CompanyFileService CompanyFileService { get; set; } = cfService;
+
+    public CompanyFile? CompanyFile { get; set; }
+
+    public CompanyFileCredentials? CompanyFileCredentials { get; set; }
+
+    public CompanyFileWithResources? ActiveCompanyFile { get; set; }
+}
+
+public partial class MYOBPosterEngine<TPostable> :
+    PosterEngine<TPostable, IMYOBPoster<TPostable>, MYOBPosterSettings>,
+    IGlobalSettingsPosterEngine<IMYOBPoster<TPostable>, MYOBGlobalPosterSettings>
+
+    where TPostable : Entity, IPostable, IRemotable, IPersistent, new()
+{
+    internal static readonly string DEV_KEY = "f3b27f88-2ef9-4d8e-95c1-d0a045d0afee";
+    internal static readonly string SECRET_KEY = "ksm0e8yo6oumcPb63A8cduaN";
+    internal const string AUTH_URL = "https://secure.myob.com/oauth2/account/authorize";
+    internal const string AUTH_SCOPE = "CompanyFile";
+    internal const string REDIRECT_URL = "http://desktop";
+
+    private static MYOBConnectionData? _connectionData;
+
+    private MYOBGlobalPosterSettings GetGlobalSettings() => (this as IGlobalSettingsPosterEngine<IMYOBPoster<TPostable>, MYOBGlobalPosterSettings>).GetGlobalSettings();
+
+    public override bool BeforePost(IDataModel<TPostable> model)
+    {
+        return true;
+    }
+
+    public static bool GetAuthorisationCode(IApiConfiguration config, out string? code)
+    {
+        var url = $"{AUTH_URL}?client_id={config.ClientId}&redirect_uri={HttpUtility.UrlEncode(config.RedirectUrl)}&scope={AUTH_SCOPE}&response_type=code";
+
+        var window = new Window
+        {
+            Width = 800,
+            Height = 600
+        };
+
+        string? resultCode = null;
+        var browser = new WebBrowser();
+        browser.Navigated += (o, e) =>
+        {
+            dynamic doc = browser.Document;
+            var htmlText = doc.documentElement.InnerHtml as string;
+            if(htmlText is not null)
+            {
+                var match = CodeRegex().Match(htmlText);
+                if (match.Success)
+                {
+                    resultCode = match.Groups[1].Value;
+                    window.Close();
+                }
+            }
+        };
+        browser.Navigate(url);
+        window.Content = browser;
+        if(window.ShowDialog() == true)
+        {
+            code = resultCode;
+            return true;
+        }
+        else
+        {
+            code = null;
+            return false;
+        }
+    }
+
+    private static MYOBConnectionData GetConnectionData()
+    {
+        if(_connectionData is MYOBConnectionData data)
+        {
+            return data;
+        }
+
+        var configuration = new ApiConfiguration(DEV_KEY, SECRET_KEY, REDIRECT_URL);
+        var authService = new OAuthService(configuration);
+
+        if(!GetAuthorisationCode(configuration, out var code))
+        {
+            throw new PostCancelledException();
+        }
+        if(code is null)
+        {
+            throw new PostFailedMessageException("No authorisation code was received.");
+        }
+
+        var keystore = new SimpleOAuthKeyService
+        {
+            OAuthResponse = authService.GetTokens(code)
+        };
+
+        var cfService = new CompanyFileService(configuration, null, keystore);
+
+        _connectionData = new MYOBConnectionData(configuration, cfService);
+
+        return _connectionData;
+    }
+    
+    protected override IPostResult<TPostable> DoProcess(IDataModel<TPostable> model)
+    {
+        var data = GetConnectionData();
+
+        var globalSettings = GetGlobalSettings();
+        if(data.CompanyFile is null || data.CompanyFile.Id != globalSettings.CompanyFileID)
+        {
+            if(globalSettings.CompanyFileID == Guid.Empty)
+            {
+                throw new PostFailedMessageException("No CompanyFileID has been set.");
+            }
+            else if(globalSettings.CompanyFileUserID.IsNullOrWhiteSpace() || globalSettings.CompanyFilePassword.IsNullOrWhiteSpace())
+            {
+                throw new PostFailedMessageException("CompanyFile credentials have not been set.");
+            }
+            var companyFile = data.CompanyFileService.GetRange().FirstOrDefault(x => x.Id == globalSettings.CompanyFileID);
+            var fileCredentials = new CompanyFileCredentials(globalSettings.CompanyFileUserID, globalSettings.CompanyFilePassword);
+            data.CompanyFile = companyFile;
+            data.CompanyFileCredentials = fileCredentials;
+            data.ActiveCompanyFile = data.CompanyFileService.Get(companyFile, fileCredentials);
+        }
+        Poster.ConnectionData = data;
+
+        return Poster.Process(model);
+    }
+
+    public override void AfterPost(IDataModel<TPostable> model, IPostResult<TPostable> result)
+    {
+    }
+
+    [GeneratedRegex("code=(.*)<")]
+    private static partial Regex CodeRegex();
+}

+ 16 - 0
InABox.Poster.MYOB/MYOBPosterSettings.cs

@@ -0,0 +1,16 @@
+using InABox.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace InABox.Poster.MYOB;
+
+public class MYOBPosterSettings : PosterSettings
+{
+    public override string DefaultScript(Type TPostable)
+    {
+        return "";
+    }
+}