Skip to main content

SYSPRO Integration Overview

Overview

The AR Payment Reversal dashboard integrates deeply with SYSPRO ERP version 7/8 through the MepDash module framework and ENet API. This document explains the overall SYSPRO integration architecture, the MepDash module integration patterns, SYSPRO-specific data models, and how the plugin interfaces with core SYSPRO functionality while maintaining version compatibility and respecting business constraints.

Key Concepts

  • MepDash Module Framework: SYSPRO plugin architecture for custom dashboards
  • ENet API Integration: COM-based API for SYSPRO business object interaction
  • SYSPRO Business Objects: Pre-built components for ERP operations
  • AR Module Integration: Accounts Receivable specific functionality
  • Version Compatibility: Support for SYSPRO 7 and 8
  • Session Management: SYSPRO authentication and context handling

Integration Architecture

MepDash Module Integration

The dashboard operates as a MepDash plugin within SYSPRO's architecture:

// MepApps.Dash.Ar.Maint.PaymentReversal/Views/MainView.xaml.cs (Lines 10-50)
namespace MepApps.Dash.Ar.Maint.PaymentReversal.Views
{
public partial class MainView : UserControl
{
// MepDash integration interfaces
private readonly IContainerEvents? _events;
private readonly IContainerNavigation? _navigation;
private readonly IMepPluginServiceHandler _mepPluginServiceHandler;
private readonly ISharedShellInterface _sharedShellInterface;

public MainView(
ISharedShellInterface sharedShellInterface,
IContainerEvents? events,
IContainerNavigation? navigation,
IMepPluginServiceHandler mepPluginServiceHandler)
{
try
{
// Initialize SYSPRO database context
System.Data.Entity.Database.SetInitializer<Db.PluginSysproDataContext>(null);

_dispatcher = Dispatcher.CurrentDispatcher;
_sharedShellInterface = sharedShellInterface;
_events = events;
_navigation = navigation;
_mepPluginServiceHandler = mepPluginServiceHandler;

// Initialize plugin services
InitializePluginServices();

// Connect to SYSPRO session
ConnectToSysproSession();
}
catch (Exception ex)
{
_logger.LogError(ex, "Failed to initialize SYSPRO plugin");
throw;
}
}
}
}

SYSPRO Session Architecture

Session Context Management

// MepApps.Dash.Ar.Maint.PaymentReversal/Services/SysproSessionManager.cs
public class SysproSessionManager
{
private readonly ISysproEnet _sysproEnet;
private readonly ISharedShellInterface _sharedShell;
private SysproSession _currentSession;

public SysproSession GetCurrentSession()
{
if (_currentSession == null || !_currentSession.IsValid)
{
_currentSession = EstablishSession();
}

return _currentSession;
}

private SysproSession EstablishSession()
{
// Get SYSPRO context from host
var sysproContext = _sharedShell.GetSysproContext();

return new SysproSession
{
UserId = sysproContext.UserId,
CompanyId = sysproContext.CompanyId,
CompanyName = sysproContext.CompanyName,
OperatorCode = sysproContext.OperatorCode,
OperatorGroup = sysproContext.OperatorGroup,
Language = sysproContext.Language,
SystemDate = sysproContext.SystemDate,
PeriodMonth = sysproContext.CurrentPeriod,
PeriodYear = sysproContext.CurrentYear,
SessionId = sysproContext.SessionGuid,
ServerName = sysproContext.ServerName,
DatabaseName = sysproContext.DatabaseName
};
}
}

SYSPRO Data Model Integration

The dashboard works with numerous SYSPRO tables and entities:

Core AR Tables

// MepApps.Dash.Ar.Maint.PaymentReversal/Db/PluginSysproDataContext.cs
public class PluginSysproDataContext : DbContext
{
// Accounts Receivable Tables
public DbSet<ArCustomer> ArCustomers { get; set; } // Customer master
public DbSet<ArInvoice> ArInvoices { get; set; } // Invoice header
public DbSet<ArInvoicePay> ArInvoicePays { get; set; } // Invoice payments
public DbSet<ArPayHistory> ArPayHistories { get; set; } // Payment history

// Cash Journal Tables
public DbSet<ArCshJnlCtl> ArCshJnlCtls { get; set; } // Journal control
public DbSet<ArCshJnlDet> ArCshJnlDets { get; set; } // Journal details
public DbSet<ArCshJnlPay> ArCshJnlPays { get; set; } // Journal payments

// Accounts Payable Tables (for bank integration)
public DbSet<ApBank> ApBanks { get; set; } // Bank master

// Custom Extension Tables
public DbSet<CG_ArReversePaymentQueueHeader> C_ArReversePaymentQueueHeader { get; set; }
public DbSet<CG_ArReversePaymentPostCompletionHistory> C_ArReversePaymentPostCompletionHistory { get; set; }
}

SYSPRO Business Object Usage

ARSTPY - AR Payment Entry

The dashboard primarily uses the ARSTPY business object for payment reversals:

// MepApps.Dash.Ar.Maint.PaymentReversal/Services/SysproPostService.cs (Lines 129-146)
public string PerformBusinessObjectPost(string inputXml, string paramXml)
{
string outputXml = string.Empty;
try
{
_dispatcher.Invoke(() =>
{
// ARSTPY - Accounts Receivable Payment Entry
outputXml = _sysproEnet.Transaction(
null, // Uses current SYSPRO session
"ARSTPY", // Business object code
paramXml, // Configuration parameters
inputXml // Transaction data
);
});

_logger.LogInformation("ARSTPY post completed successfully");
}
catch (Exception ex)
{
_logger.LogError(ex, "ARSTPY business object call failed");
throw;
}
return outputXml;
}

SYSPRO Version Compatibility

Version Detection and Adaptation

public class SysproVersionAdapter
{
private readonly ISharedShellInterface _sharedShell;
private SysproVersion _version;

public SysproVersion GetVersion()
{
if (_version == null)
{
var versionString = _sharedShell.GetSysproVersion();
_version = ParseVersion(versionString);
}
return _version;
}

public bool IsFeatureSupported(string feature)
{
return feature switch
{
"MultiCurrency" => _version.Major >= 7,
"ElectronicSignatures" => _version.Major >= 8,
"WorkflowIntegration" => _version.Major >= 8,
"AdvancedARFeatures" => _version.Major >= 7 && _version.Minor >= 2,
_ => false
};
}

public string AdaptXmlForVersion(string xml)
{
if (_version.Major < 8)
{
// Remove SYSPRO 8 specific elements
xml = RemoveUnsupportedElements(xml, new[]
{
"ElectronicSignature",
"WorkflowTrigger",
"AuditTrail"
});
}

return xml;
}
}

SYSPRO Module Dependencies

Required SYSPRO Modules

The dashboard requires specific SYSPRO modules to be licensed and configured:

public class SysproModuleValidator
{
private readonly ISharedShellInterface _sharedShell;

public ValidationResult ValidateRequiredModules()
{
var errors = new List<string>();

// Check AR module
if (!IsModuleLicensed("AR"))
{
errors.Add("Accounts Receivable module is not licensed");
}

// Check Cash Book integration
if (!IsModuleLicensed("CB"))
{
errors.Add("Cash Book module is required for payment processing");
}

// Check GL integration
if (!IsModuleLicensed("GL"))
{
errors.Add("General Ledger module is required for journal posting");
}

// Check AR sub-modules
if (!IsSubModuleEnabled("AR", "PaymentProcessing"))
{
errors.Add("AR Payment Processing sub-module must be enabled");
}

if (errors.Any())
{
return new ValidationResult
{
IsValid = false,
Errors = errors
};
}

return new ValidationResult { IsValid = true };
}

private bool IsModuleLicensed(string moduleCode)
{
var licensedModules = _sharedShell.GetLicensedModules();
return licensedModules.Contains(moduleCode);
}
}

SYSPRO Security Integration

Operator Permissions

public class SysproSecurityService
{
private readonly ISharedShellInterface _sharedShell;

public bool HasPermission(string activity)
{
var operatorCode = _sharedShell.GetOperatorCode();
var permissions = GetOperatorPermissions(operatorCode);

return activity switch
{
"PostPaymentReversal" => permissions.Contains("AR.PAYMENT.REVERSE"),
"ViewPaymentHistory" => permissions.Contains("AR.PAYMENT.VIEW"),
"ModifyQueue" => permissions.Contains("AR.PAYMENT.MODIFY"),
"ExportReports" => permissions.Contains("AR.REPORTS.EXPORT"),
_ => false
};
}

public void EnforcePermission(string activity)
{
if (!HasPermission(activity))
{
throw new SecurityException($"Operator lacks permission for: {activity}");
}
}
}

SYSPRO Configuration Requirements

System-Wide Settings

public class SysproConfigurationValidator
{
public ConfigurationValidationResult ValidateConfiguration()
{
var issues = new List<ConfigurationIssue>();

// Check AR Control settings
var arControl = GetArControlSettings();

if (!arControl.AllowPaymentReversal)
{
issues.Add(new ConfigurationIssue
{
Severity = "Error",
Message = "Payment reversals are disabled in AR Control"
});
}

if (arControl.RequireReasonCode && string.IsNullOrEmpty(arControl.DefaultReversalReason))
{
issues.Add(new ConfigurationIssue
{
Severity = "Warning",
Message = "No default reversal reason code configured"
});
}

// Check period settings
var periodControl = GetPeriodControl();

if (periodControl.CurrentPeriodStatus != "Open")
{
issues.Add(new ConfigurationIssue
{
Severity = "Error",
Message = "Current period is not open for posting"
});
}

// Check integration settings
if (!IsGLIntegrationEnabled())
{
issues.Add(new ConfigurationIssue
{
Severity = "Warning",
Message = "GL integration is disabled - journals will not post to GL"
});
}

return new ConfigurationValidationResult
{
IsValid = !issues.Any(i => i.Severity == "Error"),
Issues = issues
};
}
}

SYSPRO Database Connection

Connection String Management

public class SysproConnectionManager
{
private readonly ISharedShellInterface _sharedShell;

public string GetConnectionString()
{
var sysproContext = _sharedShell.GetSysproContext();

var builder = new SqlConnectionStringBuilder
{
DataSource = sysproContext.ServerName,
InitialCatalog = sysproContext.DatabaseName,
IntegratedSecurity = sysproContext.UseWindowsAuth,
ApplicationName = "AR Payment Reversal Dashboard",
ConnectTimeout = 30,
CommandTimeout = 60
};

if (!sysproContext.UseWindowsAuth)
{
builder.UserID = sysproContext.SqlUsername;
builder.Password = sysproContext.SqlPassword;
}

// Add SYSPRO-specific connection attributes
builder.Add("SYSPRO_COMPANY", sysproContext.CompanyId);
builder.Add("SYSPRO_OPERATOR", sysproContext.OperatorCode);

return builder.ConnectionString;
}
}

SYSPRO Event Integration

Responding to SYSPRO Events

public class SysproEventHandler
{
private readonly IContainerEvents _containerEvents;

public void RegisterEventHandlers()
{
// Period change event
_containerEvents.PeriodChanged += OnPeriodChanged;

// Company change event
_containerEvents.CompanyChanged += OnCompanyChanged;

// Operator change event
_containerEvents.OperatorChanged += OnOperatorChanged;

// System refresh event
_containerEvents.SystemRefresh += OnSystemRefresh;
}

private void OnPeriodChanged(object sender, PeriodChangedEventArgs e)
{
_logger.LogInformation("SYSPRO period changed to {Period}/{Year}",
e.NewPeriod, e.NewYear);

// Refresh posting period options
RefreshPostingPeriods();

// Validate queued payments for new period
ValidateQueuedPayments();
}

private void OnCompanyChanged(object sender, CompanyChangedEventArgs e)
{
_logger.LogInformation("SYSPRO company changed to {Company}",
e.NewCompanyId);

// Clear cached data
ClearAllCaches();

// Reload configuration
ReloadConfiguration();

// Refresh UI
RefreshUserInterface();
}
}

SYSPRO Constraints and Business Rules

Respecting SYSPRO Business Logic

public class SysproBusinessRuleValidator
{
public ValidationResult ValidatePaymentReversal(ArReversePaymentHeader payment)
{
var errors = new List<string>();

// SYSPRO Rule: Cannot reverse in closed period
if (IsPercodClosed(payment.TrnYear, payment.TrnMonth))
{
errors.Add("Cannot reverse payment in closed period");
}

// SYSPRO Rule: Cannot reverse if invoice is fully allocated
if (IsInvoiceFullyAllocated(payment.Invoice))
{
errors.Add("Cannot reverse - invoice is fully allocated");
}

// SYSPRO Rule: Check customer credit status
var creditStatus = GetCustomerCreditStatus(payment.Customer);
if (creditStatus == "Hold")
{
errors.Add("Customer is on credit hold");
}

// SYSPRO Rule: Validate against AR Control settings
var arControl = GetArControlSettings();
if (payment.CheckValue > arControl.MaxReversalAmount)
{
errors.Add($"Reversal amount exceeds maximum allowed: {arControl.MaxReversalAmount}");
}

// SYSPRO Rule: Check for sub-module integration
if (HasCashBookIntegration() && !IsBankAccountValid(payment.Bank))
{
errors.Add("Invalid bank account for Cash Book integration");
}

return new ValidationResult
{
IsValid = !errors.Any(),
Errors = errors
};
}
}

Integration Points

1. Authentication and Session Management

  • Single sign-on through SYSPRO operator login
  • Session context inheritance from host application
  • Automatic session refresh on timeout

2. Data Access

  • Direct database access for read operations
  • Business object API for write operations
  • Respect for SYSPRO table relationships and constraints

3. Business Logic

  • Validation against SYSPRO business rules
  • Integration with SYSPRO workflow engine (v8+)
  • Respect for SYSPRO security model

4. User Interface

  • Consistent with SYSPRO UI guidelines
  • Integration with SYSPRO theme engine
  • Support for SYSPRO keyboard shortcuts

Best Practices

  1. Always use business objects for data modifications
  2. Respect SYSPRO transactions - don't bypass business logic
  3. Handle version differences gracefully
  4. Log all SYSPRO interactions for audit trail
  5. Validate against SYSPRO rules before posting
  6. Use SYSPRO session context for user information
  7. Follow SYSPRO naming conventions for custom objects

Common Pitfalls

  1. Direct table updates bypassing business logic
  2. Ignoring period controls when posting
  3. Not handling multi-company scenarios
  4. Missing security checks for operations
  5. Hardcoding SYSPRO configuration values

Summary

The AR Payment Reversal dashboard achieves deep integration with SYSPRO through the MepDash framework, respecting all SYSPRO business rules, security models, and operational constraints. By leveraging SYSPRO's business objects and maintaining version compatibility, the dashboard provides a seamless extension to core SYSPRO functionality while ensuring data integrity and compliance with ERP best practices.