Step 11: Creating the Configuration Form

For a user to specify the basic settings of the connection with the external system, you need to create a custom form in MYOB Acumatica. You have the following options for the creation of the form:
  • You can create a custom form from scratch. For details about the creation of custom forms, see To Develop a Custom Form in the Customization Guide, or review the T200 Maintenance Forms training course.
  • You can use the configuration forms that are available for existing BigCommerce and Shopify connectors as a template and adjust these forms. In this step, you will use this approach.

1. Creating the Configuration Form

  1. Open the solution of your extension library, which consists of two projects: the project with the code of the extension library, and the website project.
  2. In the Pages folder of the website project, create a folder (such as WO) that will contain the custom form for configuration of the connector.
  3. Copy the BC201000.aspx file from the BC folder to the folder you have created in the previous step, and rename it so that the file name has a prefix that is specific for your connector (for example, WO201000.aspx has the WO prefix).
  4. Review the BigCommerce Stores (BC201000) form, and identify which elements of the form you need to use for the configuration of your connector. In this example, the configuration form has only the following tabs: Connection Settings, Entity Settings, and Customer Settings.
  5. In the project of the extension library, add the graph for the configuration form, such as the graph shown in the following code.
    Tip:
    You can see this code on GitHub.
    using PX.Commerce.Core;
    using PX.Commerce.Objects;
    using PX.Data;
    using System;
    using System.Collections;
    using PX.Data.BQL.Fluent;
    
    namespace WooCommerceTest
    {
        public class WooCommerceStoreMaint : BCStoreMaint
        {
    
            public SelectFrom<BCBindingWooCommerce>.
                Where<BCBindingWooCommerce.bindingID.
                    IsEqual<BCBinding.bindingID.FromCurrent>>.View 
                        CurrentBindingWooCommerce;
    
            public WooCommerceStoreMaint()
            {
                base.Bindings.WhereAnd<Where<BCBinding.connectorType.
                    IsEqual<WooCommerceConnector.WCConnectorType>>>();
            }
    
            #region Actions
            public PXAction<BCBinding> TestConnection;
            [PXButton]
            [PXUIField(DisplayName = "Test Connection", Enabled = false)]
            protected virtual IEnumerable testConnection(PXAdapter adapter)
            {
                Actions.PressSave();
    
                BCBinding binding = Bindings.Current;
                BCBindingWooCommerce bindingWooCommerce = 
                    CurrentBindingWooCommerce.Current ?? 
                    CurrentBindingWooCommerce.Select();
                if (binding == null || bindingWooCommerce == null || 
                    bindingWooCommerce.StoreBaseUrl == null)
                {
                    throw new PXException(BCMessages.TestConnectionFailedParameters);
                }
    
                PXLongOperation.StartOperation(this, delegate
                {
                    SystemStatusProvider restClient = new SystemStatusProvider(
                        WooCommerceConnector.GetRestClient(bindingWooCommerce));
                    WooCommerceStoreMaint graph = 
                        PXGraph.CreateInstance<WooCommerceStoreMaint>();
                    graph.Bindings.Current = binding;
                    graph.CurrentBindingWooCommerce.Current = bindingWooCommerce;
                    try
                    {
                        var systemStatus = restClient.Get();
    
                        CurrentBindingWooCommerce.Current.WooCommerceDefaultCurrency = 
                            systemStatus.Settings.Currency;
                        CurrentBindingWooCommerce.Current.WooCommerceStoreTimeZone = 
                            systemStatus.Environment.DefaultTimezone;
                        Actions.PressSave();
    
                        if (systemStatus == null) 
                            throw new PXException(Messages.TestConnectionStoreNotFound);
    
                        graph.CurrentBindingWooCommerce.Cache.SetValueExt(
                            binding, nameof(BCBindingWooCommerce.
                            wooCommerceDefaultCurrency), 
                            systemStatus.Settings.Currency);
                        graph.CurrentBindingWooCommerce.Cache.SetValueExt(binding, 
                            nameof(BCBindingWooCommerce.wooCommerceStoreTimeZone), 
                            systemStatus.Environment.DefaultTimezone);
                        graph.CurrentBindingWooCommerce.Cache.IsDirty = true;
                        graph.CurrentBindingWooCommerce.Cache.Update(
                            bindingWooCommerce);
    
                        graph.Persist();
                    }
                    catch (Exception ex)
                    {
                        throw new PXException(ex, 
                            BCMessages.TestConnectionFailedGeneral, ex.Message);
                    }
                });
    
                return adapter.Get();
            }
            #endregion
    
            protected virtual void _(Events.RowPersisting<BCBindingWooCommerce> e)
            {
                BCBindingWooCommerce row = e.Row as BCBindingWooCommerce;
                if (row == null || string.IsNullOrEmpty(row.StoreBaseUrl) || 
                    string.IsNullOrWhiteSpace(row.StoreXAuthClient) || 
                    string.IsNullOrWhiteSpace(row.StoreXAuthToken))
                    return;
    
                SystemStatusProvider restClient = new SystemStatusProvider(
                    WooCommerceConnector.GetRestClient(row));
                try
                {
                    var store = restClient.Get();
    
                    CurrentBindingWooCommerce.Cache.SetValueExt(row, 
                        nameof(row.WooCommerceDefaultCurrency), 
                        store.Settings?.Currency);
                    CurrentBindingWooCommerce.Cache.SetValueExt(row, 
                        nameof(row.WooCommerceStoreTimeZone), 
                        store.Environment?.DefaultTimezone);
                    CurrentBindingWooCommerce.Cache.IsDirty = true;
                    CurrentBindingWooCommerce.Cache.Update(row);
                }
                catch (Exception) { }
            }
    
            //Set the default connector type. This type will be displayed
            //in the Connector box on the configuration form.
            [PXMergeAttributes(Method = MergeMethod.Append)]
            [PXCustomizeBaseAttribute(typeof(BCConnectorsAttribute), 
                "DefaultConnector", WooCommerceConnector.TYPE)]
            public virtual void _(Events.CacheAttached<BCBinding.connectorType> e) { }
    
            public override void _(Events.RowSelected<BCBinding> e)
            {
                base._(e);
    
                BCBinding row = e.Row as BCBinding;
                if (row == null) return;
    
                //Actions
                TestConnection.SetEnabled(row.BindingID > 0 && 
                    row.ConnectorType == WooCommerceConnector.TYPE);
            }
    
            public override void _(Events.RowInserted<BCBinding> e)
            {
                base._(e);
    
                bool dirty = CurrentBindingWooCommerce.Cache.IsDirty;
                CurrentBindingWooCommerce.Insert();
                CurrentBindingWooCommerce.Cache.IsDirty = dirty;
            }
    
            public override void _(Events.RowSelected<BCBindingExt> e)
            {
                base._(e);
    
                BCBindingExt row = e.Row as BCBindingExt;
                if (row == null) return;
                PXDefaultAttribute.SetPersistingCheck<BCBindingExt.refundAmountItemID>(
                    e.Cache, row, PXPersistingCheck.Nothing);
            }
    
        }
    }
  6. Add the messages that you are using in the actions and events of the graph to a class with the PXLocalizable attribute, as shown in the following code.
    Tip:
    You can see this code on GitHub.
    using PX.Common;
    
    namespace WooCommerceTest
    {
        [PXLocalizable]
        class Messages
        {
            public const string TestConnectionStoreNotFound = 
                "The store data cannot be retrieved through the WooCommerce REST API. Check that the store URL is correct.";
        }
    }
  7. In the WO201000.aspx file, change the properties of the PXDataSource control as follows:
    • TypeName: Assign the name of the graph that you have just created, such as WooCommerceTest.WooCommerceStoreMaint.
    • PrimaryView: Assign the name of the primary view of the graph, such as Bindings.
    See the following code example.
    Tip:
    You can find the complete WO201000.aspx file on GitHub.
    <asp:Content ID="cont1" ContentPlaceHolderID="phDS" runat="Server">
        <px:PXDataSource PageLoadBehavior="GoFirstRecord" ID="ds" runat="server" Visible="True" Width="100%"
            TypeName="WooCommerceTest.WooCommerceStoreMaint"
            PrimaryView="Bindings">
            <CallbackCommands>
            </CallbackCommands>
        </px:PXDataSource>
    </asp:Content>
  8. Change the DataMember property of the PXFormView control to the name of the primary view of the graph, such as Bindings. See the following code example.
    <asp:Content ID="cont2" ContentPlaceHolderID="phF" runat="Server">
        <px:PXFormView ID="form" runat="server" DataSourceID="ds" DataMember="Bindings" Width="100%" Height="100px" AllowAutoHide="false">
            <Template>
                <px:PXLayoutRule ID="PXLayoutRule1" runat="server" StartRow="True"></px:PXLayoutRule>
                <px:PXDropDown runat="server" ID="CstPXDropDown10" DataField="ConnectorType" />
                <px:PXSelector runat="server" ID="CstPXSelector9" DataField="BindingName" />
                <px:PXLayoutRule runat="server" ID="CstPXLayoutRule13" StartColumn="True" />
                <px:PXCheckBox runat="server" ID="CstPXCheckBox11" DataField="IsActive" />
                <px:PXCheckBox runat="server" ID="CstPXCheckBox12" DataField="IsDefault" />
            </Template>
        </px:PXFormView>
    </asp:Content>
  9. Adjust the DataMember property and the list of fields of the PXTabItem control that corresponds to the Connection Settings tab, as shown in the following code.
    <px:PXTabItem Text="Connection Settings">
        <Template>
            <px:PXLayoutRule runat="server" ID="CstLayoutRule26" StartColumn="True"></px:PXLayoutRule>
            <px:PXFormView runat="server" ID="CstFormView14" DataMember="CurrentBindingWooCommerce">
                <Template>
                    <px:PXLayoutRule runat="server" ID="CstLayoutRule23" ColumnWidth="XL" LabelsWidth="SM" StartRow="True" StartColumn="True"></px:PXLayoutRule>
                    <px:PXTextEdit runat="server" ID="CstPXTextEdit15" DataField="StoreAdminUrl"></px:PXTextEdit>
                    <px:PXLayoutRule GroupCaption="REST Settings" ColumnWidth="XL" LabelsWidth="SM" StartGroup="True" runat="server" ID="CstLayoutRule24"></px:PXLayoutRule>
                    <px:PXTextEdit runat="server" ID="CstPXTextEdit16" DataField="StoreBaseUrl"></px:PXTextEdit>
                    <px:PXTextEdit runat="server" ID="CstPXTextEdit17" DataField="StoreXAuthClient"></px:PXTextEdit>
                    <px:PXTextEdit runat="server" ID="CstPXTextEdit18" DataField="StoreXAuthToken"></px:PXTextEdit>
                    <px:PXLayoutRule runat="server" ID="CstLayoutRule25"></px:PXLayoutRule>
                </Template>
            </px:PXFormView>
            <px:PXLayoutRule GroupCaption="Store Properties" runat="server" ID="CstPXLayoutRule29" StartRow="True"></px:PXLayoutRule>
            <px:PXFormView runat="server" ID="CstFormView30" DataMember="CurrentBindingWooCommerce" RenderStyle="Simple">
                <Template>
                    <px:PXTextEdit runat="server" ID="CstPXTextEdit31" DataField="WooCommerceDefaultCurrency"></px:PXTextEdit>
                    <px:PXTextEdit runat="server" ID="CstPXTextEdit32" DataField="WooCommerceStoreTimeZone"></px:PXTextEdit>
                </Template>
            </px:PXFormView>
        </Template>
    </px:PXTabItem>
  10. Remove unnecessary elements from the PXTabItem control that corresponds to the Customer Settings tab, as shown in the following code.
    <px:PXTabItem Text="Customer Settings">
    	<Template>
    		<px:PXLayoutRule runat="server" StartGroup="False" ControlSize="M" LabelsWidth="M" StartColumn="True">
    		</px:PXLayoutRule>
    		<px:PXLayoutRule GroupCaption="Customer" runat="server" ID="CstPXLayoutRule79" StartGroup="True"></px:PXLayoutRule>
    		<px:PXSelector AllowEdit="True" ID="edCustomerClassID" runat="server" DataField="CustomerClassID" CommitChanges="True">
    		</px:PXSelector>
    		<px:PXSelector runat="server" ID="CstPXSelector27" DataField="CustomerNumberingID" AllowEdit="True"></px:PXSelector>
    	</Template>
    	<ContentLayout ControlSize="XM" LabelsWidth="M"></ContentLayout>
    </px:PXTabItem>
  11. Remove the PXTabItem controls for the tabs that you do not need to use.

2. Adding the Form to the Customization Project

For the WO201000.aspx and WO201000.aspx.cs files, do the following:

  1. Open the customization project in the Customization Project Editor. (See To Open a Project for details.)
  2. Click Files in the navigation pane to open the Custom Files page.
  3. On the page toolbar, click Add New Record.
  4. In the Add Files dialog box, which opens, find the file in the table and select the check box in the Selected column for it.
    Note:
    • You can select multiple custom files to add them to the project at the same time.
    • For any files other than the ones placed in the Bin folder, you can click Refresh on the toolbar of the Add Files dialog box to make the system update the list of files in the table. If you have changed files in the Bin folder of the website, you should refresh the page in the browser.
  5. In the dialog box, click Save to save each selected file to the customization project as a File item.

3. Adding the Form to the Site Map

  1. Publish the customization project.
  2. On the Enable/Disable Features (CS100000) form, enable the Retail Commerce feature which is listed under Third Party Integrations.
  3. In the navigation pane of the Customization Project Editor, click Site Map. The Site Map page opens.
  4. On the page toolbar, click Manage Site Map.

    The Site Map (SM200520) form opens.

  5. On the form toolbar, click Add Row, and specify the site map position of the configuration form. For the WooCommerce connector, you can specify the following settings:
    • Screen ID: WO201000
    • Title: WooCommerce Stores
    • URL: ~/Pages/WO/WO201000.aspx
    • Workspaces: Commerce
    • Category: Configuration
  6. Save your changes and close the form.

    The new site map item has been created.

  7. Open the Commerce workspace. Notice that the WooCommerce Stores link is now available in the workspace under Configuration.

4. Adding the Site Map Item to the Customization Project

  1. Open the customization project in the Customization Project Editor. (See To Open a Project for details.)
  2. Click Site Map in the navigation pane to open the Site Map page.
  3. On the page toolbar, click Add New Record.
  4. In the list of site map nodes in the Add Site Map dialog box, which opens, select the check box for each screen that you want to include in the project.
    Note:
    The Add Site Map dialog box displays all the custom site map nodes that have been created in the site map of MYOB Acumatica and the nodes that have been modified in the site map. You can select multiple custom site map nodes to add them to the project simultaneously.
  5. In the dialog box, click Save to add each selected site map node to the customization project.

5. Adding the Form to the Screen Editor

You can edit a form created in Visual Studio both in Visual Studio and in the Screen Editor. To be able to edit the form in the Screen Editor, you should add it to the Screen Editor by doing the following:

  1. Open the customization project in the Customization Project Editor.
  2. In the navigation pane, click Screens. The Customized Screens page opens.
  3. On the page toolbar, click Customize Existing Screen.
  4. In the Customize Existing Screen dialog box, which opens, select the configuration form.
  5. Click OK.