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
- Always use business objects for data modifications
- Respect SYSPRO transactions - don't bypass business logic
- Handle version differences gracefully
- Log all SYSPRO interactions for audit trail
- Validate against SYSPRO rules before posting
- Use SYSPRO session context for user information
- Follow SYSPRO naming conventions for custom objects
Common Pitfalls
- Direct table updates bypassing business logic
- Ignoring period controls when posting
- Not handling multi-company scenarios
- Missing security checks for operations
- Hardcoding SYSPRO configuration values
Related Documentation
- SYSPRO Data Models - Entity relationships
- SYSPRO Posting Patterns - Transaction posting
- SYSPRO Business Objects - API usage
- SYSPRO Customization - Extensions
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.