using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Xml;
using System.Linq;
using System.Collections.Generic;
using DataContracts;
using System.Text.RegularExpressions;

namespace Ato.EN.IntegrationServices.CodeGenerationPSS
{

    public partial class PSS2018Validator
    {
        /// <summary>
        /// The max parameter name length is restricted by the SBR1 and SBR2 schemas - the lowest common denominator of SBR 1 is used as the default
        /// </summary>
        private int _maxParameterNameLength;

        /// <summary>
        /// The max parameter value length is restricted by the SBR1 and SBR2 schemas
        /// </summary>
        private int _maxParameterValueLength;

        /// <summary>
        /// The SBR1 and ebms3 schemas do not allow parameter names or values to be the empty string
        /// </summary>
        private string _emptyParameterValue;

        /// <summary>
        /// Initializes a new instance of the <see cref="PSS2018Validator" /> class.
        /// </summary>
        /// <param name="maxParameterNameLength">Maximum length of the parameter name.</param>
        /// <param name="maxParameterValueLength">Maximum length of the parameter value.</param>
        /// <param name="emptyParameterValue">This value will be used in place of any parameter values that result in a null or empty value.</param>
        public PSS2018Validator(int maxParameterNameLength = 20, int maxParameterValueLength = 4096, string emptyParameterValue = "EMPTY")
        {
            _maxParameterNameLength = maxParameterNameLength;
            _maxParameterValueLength = maxParameterValueLength;
            _emptyParameterValue = emptyParameterValue;
        }

        #region Functions
        private static IEnumerable<string> Union(IEnumerable<string> list1, IEnumerable<string> list2)
        {
            IEnumerable<string> response;

            if (list1 == null && list2 == null)
            {
                response = null;
            }
            else if (list1 == null)
            {
                response = list2.Distinct();
            }
            else if (list2 == null)
            {
                response = list1.Distinct();
            }
            else
            {
                response = list1.Union(list2);
            }

            return response;
        }

        private static bool IsMatch(int? field, string expression, RegexOptions options = RegexOptions.None)
        {
            if (field == null)
                return false;
            else
                return Regex.IsMatch(Convert.ToString(field.Value), expression, options);
        }

        private static bool IsMatch(string field, string expression, RegexOptions options = RegexOptions.None)
        {
            if (field == null)
                return false;
            else
                return Regex.IsMatch(field, expression, options);
        }

        // This is just context and tuple counts where they are integer values - easier that changing the parsing logic to just return the value
        private static int Count(int count)
        {
            return count;
        }


        private static int Count<T>(IEnumerable<T> values)
        {
            return values == null ? 0 : values.Where(f => f != null).Count();
        }


        private static int Count<T>(ICollection<T> values)
        {
            return values == null ? 0 : values.Where(f => f != null).Count();
        }


        private static bool exists(bool value)
        {
            return value;
        }

        private static string GetValueOrEmpty(bool? val)
        {
            return (val.HasValue) ? val.ToString() : string.Empty;
        }

        private static string GetValueOrEmpty(DateTime? val)
        {
            return (val.HasValue) ? val.ToString() : string.Empty;
        }

         /// <summary>
         /// Get string value between [first] a and [last] b.
         /// </summary>
        public static string Between(string value, string a, string b)
        {
            int posA = value.IndexOf(a);
            int posB = value.LastIndexOf(b);
            if (posA == -1)
            {
                return "";
            }
            if (posB == -1)
            {
                return "";
            }
            int adjustedPosA = posA + a.Length;
            if (adjustedPosA >= posB)
            {
                return "";
            }
            return value.Substring(adjustedPosA, posB - adjustedPosA);
        }

         /// <summary>
         /// Get string value after [first] a.
         /// </summary>
        public static string Before(string value, string a)
        {
            int posA = value.IndexOf(a);
            if (posA == -1)
            {
                return "";
            }
            return value.Substring(0, posA);
        }

         /// <summary>
         /// Get string value after [last] a.
         /// </summary>
        public static string After(string value, string a)
        {
            int posA = value.LastIndexOf(a);
            if (posA == -1)
            {
                return "";
            }
            int adjustedPosA = posA + a.Length;
            if (adjustedPosA >= value.Length)
            {
                return "";
            }
            return value.Substring(adjustedPosA);
        }

        private static int Length(object field)
        {
            if (field == null)
            return 0;
            else
            return field.ToString().Trim().Length;
        }

        private static bool NotSameValues(IEnumerable<object> nodes)
        {
            if (nodes == null)
                return false;

            object[] nodesArray = nodes.Cast<object>().ToArray();
            return NotSameValues(nodesArray);
        }

        private static bool NotSameValues(params object[] nodes)
        {
            if (nodes == null)
                return false;

            return ((from x in nodes select x).Distinct().Count() == nodes.Count());
        }

        private static bool HasDuplicateValues(IEnumerable<object> nodes)
        {
            if (nodes == null)
                return false;

            object[] nodesArray = nodes.Cast<object>().ToArray();
            return HasDuplicateValues(nodesArray);
        }

        private static bool HasDuplicateValues(params object[] nodes)
        {
           if (nodes == null)
                return false;

            nodes = nodes.Where(x => x != null).ToArray();
            return !((from x in nodes select x).Distinct().Count() == nodes.Count());
        
        }

        private int DuplicateValueIndex(IEnumerable<object> values)
        {
            int response = 0;
            var hashset = new HashSet<object>();
            foreach (var value in values)
            {
                if (!hashset.Add(value))
                {
                    return response;
                }
                response++;
            }
            return response;
        }

        private int DuplicateValueIndex<T>(IEnumerable<T?> values) where T : struct
        {
            int response = 0;
            var hashset = new HashSet<T?>();
            foreach (var value in values)
            {
                if (!hashset.Add(value))
                {
                    return response;
                }
                response++;
            }
            return response;
        }

        private static bool IsDate(object value)
        {
            DateTime dateValue;
            return (value != null && DateTime.TryParse(value.ToString(), out dateValue));
        }

        public DateTime AsDate(string dateAsString)
        {
            DateTime response = DateTime.MinValue;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
            {
                response = date;
            }

            return response;
        }
				//The logic in After function expects "---" for day and "--" for month. 
				//Since hyphen was missing the date always returned null
        public DateTime? ConvertToDate(int day, int month, int year)
        {
					return ConvertToDate(day == 0 ? null : "---" + day.ToString(), month == 0 ? null : "--" + month.ToString(), year == 0 ? null : year.ToString());
        }

        public DateTime? ConvertToDate(string day, string month, string year)
        {
            DateTime? response;
            DateTime result;

            if (year == null || month == null || day == null)
            {
                return null;
            }
            string dateAsString = year + "-" + After(month, "--") + "-" + After(day, "---");
            if (DateTime.TryParse(dateAsString, out result))
            {
                response = result;
            }
            else
            {
                response = null;
            }
            return response;
        }


        public DateTime? ConvertToDate(string day, string month, int year)
        {
            DateTime? response;
            DateTime result;

            if (year == 0 || month == null || day == null)
            {
                return null;
            }
            string dateAsString = year.ToString() + "-" + After(month, "--") + "-" + After(day, "---");
            if (DateTime.TryParse(dateAsString, out result))
            {
                response = result;
            }
            else
            {
                response = null;
            }
            return response;
        }


        private static int Day(string dateAsString)
        {
            int response = 0;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
            {
                response = date.Day;
            }

            return response;
        }


        private static int Day(DateTime? date)
        {
            if (date == null)
                return 0;
            else
                return date.Value.Day;

        }


        private static string Month(string dateAsString)
        {
            string response = null;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
            {
                response = date.ToString("MMMM");
            }
            else
            {
                return "NotAMonth";
            }

            return response;
        }

        private static string Month(DateTime? date)
        {
            if (date == null)
                return "NotAMonth";
            else
                return date.Value.ToString("MMMM");
        }


        private static int MonthAsInt(string dateAsString)
        {
            int response = 0;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
            {
                response = date.Month;
            }

            return response;
        }

        private static int MonthAsInt(DateTime? date)
        {
            if (date == null)
            {
                return 0;
            }
            return date.Value.Month;
        }


        private static int Year(string dateAsString)
        {
            int response = 0;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
            {
                response = date.Year;
            }

            return response;
        }

        private static int Year(DateTime? date)
        {
            if (date == null)
                return 0;
            else
                return date.Value.Year;
        }


        private static int CurrentFinancialYear()
        {
            return DateToFinancialYear(DateTime.Now, 7);
        }

        private static int FinancialYear(string dateAsString)
        {
            return DateToFinancialYear(dateAsString, 7);
        }

        private static int FinancialYear(DateTime? date)
        {
            return DateToFinancialYear(date, 7);
        }

        private static int DateToFinancialYear(string dateAsString, int startingMonth)
        {
            int response = 0;
            DateTime date;
            if (DateTime.TryParse(dateAsString, out date))
            {
                response = DateToFinancialYear(date, startingMonth);
            }

            return response;
        }
        private static int DateToFinancialYear(DateTime? date, int startingMonth)
        {
            int response;
            if (date == null)
            {
                response = 0;
            }
            else
            {
                int year = date.Value.Year;
                int month = date.Value.Month;

                if (startingMonth > month)
                    response = year;
                else
                    response = year + 1;
            }
            return response;
        }


        private static int FBTYear(string dateAsString)
        {
            int response = 0;
            DateTime date;

            if (DateTime.TryParse(dateAsString, out date))
                response = FBTYear(date);
            return response;
        }

        private static int FBTYear(DateTime? date)
        {
            if (date == null)
            {
                return 0;
            }
            else
            {
                if (date.Value.Month > 3)
                    return date.Value.Year + 1;
                else
                    return date.Value.Year;
            }
        }

        private static DateTime? AddMonthsToDate(DateTime? dateTime, int months)
        {
            return dateTime == null ? null : (DateTime?)dateTime.Value.AddMonths(months);
        }

        private static bool IsNumeric(object value)
        {
            decimal numbervalue;
            return (value != null && decimal.TryParse(value.ToString(), out numbervalue));
        }

        private static bool NotMonetary(decimal? field, string sign, int digits, int decimals)
        {
            if (field == null)
            {
                return false;
            }
            else
            {
                string signExpression;
                string decimalExpression;
                int digitsToUse = digits - decimals;

                if (sign == "U")
                    signExpression = "^";
                else
                    signExpression = "^-?";

                if (decimals > 0)
                    decimalExpression = @"(\.\d{1," + decimals + "})?$";
                else
                    decimalExpression = @"$";

                return !(Regex.IsMatch(field.Value.ToString("0.#########################"), signExpression + @"\d{1," + digitsToUse + "}" + decimalExpression));
            }
        }

        private static bool NotNumeric(decimal? field, string sign, int digits, int decimals)
        {
            if (field == null)
            {
                return false;
            }
            else
            {
                string signExpression;
                string decimalExpression;
                int digitsToUse = digits - decimals;

                if (sign == "U")
                    signExpression = "^";
                else
                    signExpression = "^-?";

                if (decimals > 0)
                    decimalExpression = @"(\.\d{1," + decimals + "})?$";
                else
                    decimalExpression = @"$";

                return !(Regex.IsMatch(field.Value.ToString("0.#########################"), signExpression + @"\d{1," + digitsToUse + "}" + decimalExpression));
            }
        }

        private static bool NotNumeric(int? field, string sign, int digits, int decimals = 0)
        {
            if (field == null)
            {
                return false;
            }
            else
            {
                string signExpression;

                if (sign == "U")
                    signExpression = "^";
                else
                    signExpression = "^-?";

                return !(Regex.IsMatch(field.Value.ToString(), signExpression + @"\d{1," + digits + "}$"));
            }
        }

        private static bool NotNumeric(long? field, string sign, int digits, int decimals = 0)
        {
            if (field == null)
            {
                return false;
            }
            else
            {
                string signExpression;

                if (sign == "U")
                    signExpression = "^";
                else
                    signExpression = "^-?";

                return !(Regex.IsMatch(field.Value.ToString(), signExpression + @"\d{1," + digits + "}$"));
            }
        }


        private static bool OutsideRange(decimal field, decimal expression, int range)
        {
            bool response;

            response = (field < (expression - range)) || (field > (expression + range));

            return response;
        }


        private static bool FailsUSIAlgorithm(string usi, string abn)
        {
            bool response;
            if (usi == null || abn == null)
            {
                response = false;
            }
            else
            {
                usi = usi.Trim();
                abn = abn.Trim();
                if (usi.Length < 13 || abn.Length < 11)
                {
                    response = false;
                }
                else
                {
                    int numeric;
                    if (usi.Substring(0, 11) == abn && int.TryParse(usi.Substring(11, 2), out numeric))
                        response = false;
                    else if (Regex.IsMatch(usi, @"^[a-zA-Z]{3}\d{4}[a-zA-Z]{2}"))
                        response = false;
                    else
                        response = true;
                }
            }
            return response;
        }


        private static bool FailsTANAlgorithm(string tan)
        {
            bool response;
            decimal decimalTan;

            if (tan == null)
                return false;

            tan = tan.Trim();

            if (!decimal.TryParse(tan, out decimalTan))
                return true;

            if (tan.Length != 8)
                return true;

            decimal tanSum =
                7 * int.Parse(tan.Substring(0, 1)) +
                9 * int.Parse(tan.Substring(1, 1)) +
                8 * int.Parse(tan.Substring(2, 1)) +
                4 * int.Parse(tan.Substring(3, 1)) +
                6 * int.Parse(tan.Substring(4, 1)) +
                3 * int.Parse(tan.Substring(5, 1)) +
                5 * int.Parse(tan.Substring(6, 1)) +
                1 * int.Parse(tan.Substring(7, 1));

            if ((tanSum % 11) == 0)
                response = false;
            else
                response = true;

            return response;
        }


        private static bool FailsABNAlgorithm(string abn)
        {
            bool response;
            decimal decimalAbn;

            if (abn == null)
                return false;

            abn = abn.Trim();

            if (!decimal.TryParse(abn, out decimalAbn))
                return true;

            if (abn.Length != 11)
                return true;

            decimal abnSum =
                10 * (int.Parse(abn.Substring(0, 1)) - 1) +
                1 * int.Parse(abn.Substring(1, 1)) +
                3 * int.Parse(abn.Substring(2, 1)) +
                5 * int.Parse(abn.Substring(3, 1)) +
                7 * int.Parse(abn.Substring(4, 1)) +
                9 * int.Parse(abn.Substring(5, 1)) +
                11 * int.Parse(abn.Substring(6, 1)) +
                13 * int.Parse(abn.Substring(7, 1)) +
                15 * int.Parse(abn.Substring(8, 1)) +
                17 * int.Parse(abn.Substring(9, 1)) +
                19 * int.Parse(abn.Substring(10, 1));

            if ((abnSum % 89) == 0)
                response = false;
            else
                response = true;

            return response;
        }
        private static bool FailsACNAlgorithm(string acn)
        {
            bool response;
            decimal decimalAbn;
            if (acn == null)
                return false;

            acn = acn.Trim();

            if (!decimal.TryParse(acn, out decimalAbn))
                return true;

            if (acn.Length != 9)
                return true;

            decimal abnSum =
                8 * int.Parse(acn.Substring(0, 1)) +
                7 * int.Parse(acn.Substring(1, 1)) +
                6 * int.Parse(acn.Substring(2, 1)) +
                5 * int.Parse(acn.Substring(3, 1)) +
                4 * int.Parse(acn.Substring(4, 1)) +
                3 * int.Parse(acn.Substring(5, 1)) +
                2 * int.Parse(acn.Substring(6, 1)) +
                1 * int.Parse(acn.Substring(7, 1));

            decimal checkDigit = int.Parse(acn.Substring(8, 1));
            decimal acnRemainder = abnSum % 10;

            if (((10 - acnRemainder) % 10) == checkDigit)
                response = false;
            else
                response = true;

            return response;
        }


        private static bool FailsTFNAlgorithm(string tfn)
        {
            bool response;
            decimal decimalTfn;

            if (tfn == null)
                return false;

            tfn = tfn.Trim();
            tfn = Regex.Replace(tfn, "^0+", "");

            if (!decimal.TryParse(tfn, out decimalTfn))
                return true;

            if (tfn.Length < 8)
                return true;


            decimal tfn1To7Sum =
                1 * int.Parse(tfn.Substring(0, 1)) +
                4 * int.Parse(tfn.Substring(1, 1)) +
                3 * int.Parse(tfn.Substring(2, 1)) +
                7 * int.Parse(tfn.Substring(3, 1)) +
                5 * int.Parse(tfn.Substring(4, 1)) +
                8 * int.Parse(tfn.Substring(5, 1)) +
                6 * int.Parse(tfn.Substring(6, 1));

            decimal tfn8 = 9 * int.Parse(tfn.Substring(7, 1));

            if (tfn.Length == 8)
            {
                decimal tFNLg8WSum9 = 10 * int.Parse(tfn.Substring(7, 1));
                decimal tFNLg8WSum = tfn1To7Sum + tFNLg8WSum9;

                if ((tFNLg8WSum % 11) == 0)
                    response = false;
                else
                    response = true;
            }
            else if (tfn.Length == 9)
            {
                decimal tfn9 = 10 * int.Parse(tfn.Substring(8, 1));
                decimal tFNLg9WSum = tfn1To7Sum + tfn8 + tfn9;

                if ((tFNLg9WSum % 11) == 0)
                    response = false;
                else
                    response = true;
            }
            else
            {
                response = true;
            }

            return response;
        }


        private static decimal ConditionalValue(bool expression, decimal? trueVal, decimal? falseVal)
        {
             return expression ? trueVal.GetValueOrDefault() : falseVal.GetValueOrDefault();
        }

        private static decimal AsNumeric(string value)
        {
             decimal numberValue;
             decimal.TryParse(value, out numberValue);
             return numberValue;
        }

        private static bool RegexMatch(int? field, string expression, string flags="")
        {
            return IsMatch(field, expression, GetRegexOption(flags));
        }

        private static bool RegexMatch(string field, string expression, string flags="")
        {
            return IsMatch(field, expression, GetRegexOption(flags));
        }

        private static RegexOptions GetRegexOption(string flags)
        {
            RegexOptions options = RegexOptions.None;

            char[] characters = flags.ToCharArray();

            foreach (char character in characters)
            {
                switch (character)
                {
                    case 'i':                        
                        options = options | RegexOptions.IgnoreCase;                       
                        break;
                    case 'm':                        
                        options = options | RegexOptions.Multiline;                       
                        break;
                    case 's':                        
                            options = options | RegexOptions.Singleline;                       
                        break;
                    case 'n':                        
                            options = options | RegexOptions.ExplicitCapture;                       
                        break;
                    case 'x':                       
                            options = options | RegexOptions.IgnorePatternWhitespace;                       
                        break;
                }
            }

            return options;
        }

        /// <summary>
        /// Returns an occurrence index as [occurrenceIndex] of occurrenceIndex > 0, otherwise the empty string
        /// </summary>
        /// <param name="occurrenceIndex">Index of the occurrence.</param>
        /// <returns>Occurrence in XPath [#] format</returns>
        public string OccurrenceIndex(int occurrenceIndex)
        {
            return occurrenceIndex > 0 ? "[" + occurrenceIndex + "]" : "";
        }

        #endregion // Functions

        public PSS2018 ConsumedReport { get; private set; }

        private static Dictionary<string, ProcessMessageDocument> _processMessageDocuments = new Dictionary<string,ProcessMessageDocument>();

        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public List<ProcessMessageDocument> ValidateReport(PSS2018 report)
        {

            List<ProcessMessageDocument> response = new List<ProcessMessageDocument>();
            ProcessMessageDocument processMessage;
            ProcessMessageParameter parameter;
            bool assertion;

            this.ConsumedReport = report;

            // ------------------------------------------------------------------------------
            // Validations are now done in code.
            // This version supports full validation of a report - for those rules that have successfully parsed and could be generated.
            // Generated Validations include:
            //   - Validation logic in C#.
            //   - Production of errors in EBMS, SBR and SWS format.
            // 
            // The generation at this stage does not support the following - and has to be completed manually (later versions of the generation will do this for you)
            //   - Business Rules that did not parse.  The ESR team will help support you where this happens as an effort is being made to rectify these
            //   - You will get TODO tasks for those that the parser could not cope with
            // ------------------------------------------------------------------------------


            #region Repeating RPPayerPSSeqNumContext
            if (report.RPPayerPSSeqNumContextCollection != null)
            {
                int itemIndexContext1 = 0;
                foreach (PSS2018.RPPayerPSSeqNumContext rpPayerPSSeqNumContext in report.RPPayerPSSeqNumContextCollection)
                {
                    itemIndexContext1++;
            
                    #region VR.ATO.PSS.000002
            
                    /*  VR.ATO.PSS.000002
                    Payer's name - Family name has a maximum length of 38
    
                    Legacy Rule Format:
                    IF LENGTH([PSS29]) > 38
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    Length(^PSS29) > 38
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS29 = tns:PersonNameDetails.FamilyName.Text
                    */
                    assertion = (Length(rpPayerPSSeqNumContext.PSS29) > 38);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000002", Severity = ProcessMessageSeverity.Error,
                            Description = @"Payer's name - Family name must not exceed 38 characters",
                            LongDescription = @"For Payer's name - Family name, the maximum allowable characters for this form is 38",
                            Location = "/xbrli:xbrl/tns:PersonNameDetails.FamilyName.Text[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000002"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS29", Value = rpPayerPSSeqNumContext.PSS29 });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000002
            
                    #region VR.ATO.PSS.000003
            
                    /*  VR.ATO.PSS.000003
                    Payer's name - Given name has a maximum length of 38
    
                    Legacy Rule Format:
                    IF LENGTH([PSS27]) > 38
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    Length(^PSS27) > 38
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS27 = tns:PersonNameDetails.GivenName.Text
                    */
                    assertion = (Length(rpPayerPSSeqNumContext.PSS27) > 38);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000003", Severity = ProcessMessageSeverity.Error,
                            Description = @"Payer's name - Given name must not exceed 38 characters",
                            LongDescription = @"For Payer's name - Given name, the maximum allowable characters for this form is 38",
                            Location = "/xbrli:xbrl/tns:PersonNameDetails.GivenName.Text[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000003"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS27", Value = rpPayerPSSeqNumContext.PSS27 });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000003
            
                    #region VR.ATO.PSS.000004
            
                    /*  VR.ATO.PSS.000004
                    Payer's name - Other given names has a maximum length of 38
    
                    Legacy Rule Format:
                    IF LENGTH([PSS28]) > 38
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    Length(^PSS28) > 38
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS28 = tns:PersonNameDetails.OtherGivenName.Text
                    */
                    assertion = (Length(rpPayerPSSeqNumContext.PSS28) > 38);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000004", Severity = ProcessMessageSeverity.Error,
                            Description = @"Payer's name - Other given names must not exceed 38 characters",
                            LongDescription = @"For Payer's name - Other given names, the maximum allowable characters for this form is 38",
                            Location = "/xbrli:xbrl/tns:PersonNameDetails.OtherGivenName.Text[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000004"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS28", Value = rpPayerPSSeqNumContext.PSS28 });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000004
            
                    #region VR.ATO.PSS.000005
            
                    /*  VR.ATO.PSS.000005
                    Gross payment for foreign resident withholding has a maximum field length of 11
    
                    Legacy Rule Format:
                    IF [PSS18] <> MONETARY(U,11,0)
                         RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    NotMonetary(^PSS18, 'U', 11, 0)
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS18 = tns:Remuneration.PaymentToForeignResidentGross.Amount
                    */
                    assertion = NotMonetary(rpPayerPSSeqNumContext.PSS18, @"U", 11, 0);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000005", Severity = ProcessMessageSeverity.Error,
                            Description = @"Gross payment for foreign resident withholding is not in a valid monetary format",
                            LongDescription = @"Gross payment for foreign resident withholding must be unsigned, not exceed 11 digits and not contain a decimal point or any other characters",
                            Location = "/xbrli:xbrl/tns:Remuneration.PaymentToForeignResidentGross.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000005"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS18", Value = rpPayerPSSeqNumContext.PSS18.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000005
            
                    #region VR.ATO.PSS.000006
            
                    /*  VR.ATO.PSS.000006
                    Gross payment for withholding where ABN not quoted has a maximum field length of 11
    
                    Legacy Rule Format:
                    IF [PSS19] <> MONETARY(U,11,0)
                         RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    NotMonetary(^PSS19, 'U', 11, 0)
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS19 = tns:Remuneration.ABNNotQuotedPaymentGross.Amount
                    */
                    assertion = NotMonetary(rpPayerPSSeqNumContext.PSS19, @"U", 11, 0);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000006", Severity = ProcessMessageSeverity.Error,
                            Description = @"Gross payment for withholding where ABN not quoted is not in a valid monetary format",
                            LongDescription = @"Gross payment for withholding where ABN not quoted must be unsigned, not exceed 11 digits and not contain a decimal point or any other characters",
                            Location = "/xbrli:xbrl/tns:Remuneration.ABNNotQuotedPaymentGross.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000006"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS19", Value = rpPayerPSSeqNumContext.PSS19.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000006
            
                    #region VR.ATO.PSS.000007
            
                    /*  VR.ATO.PSS.000007
                    Gross payment for Voluntary agreement withholding has a maximum field length of 11
    
                    Legacy Rule Format:
                    IF [PSS20] <> MONETARY(U,11,0)
                         RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    NotMonetary(^PSS20, 'U', 11, 0)
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS20 = tns:Remuneration.VoluntaryAgreementGross.Amount
                    */
                    assertion = NotMonetary(rpPayerPSSeqNumContext.PSS20, @"U", 11, 0);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000007", Severity = ProcessMessageSeverity.Error,
                            Description = @"Gross payment for Voluntary agreement withholding is not in a valid monetary format",
                            LongDescription = @"Gross payment for Voluntary agreement withholding must be unsigned, not exceed 11 digits and not contain a decimal point or any other characters",
                            Location = "/xbrli:xbrl/tns:Remuneration.VoluntaryAgreementGross.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000007"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS20", Value = rpPayerPSSeqNumContext.PSS20.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000007
            
                    #region VR.ATO.PSS.000008
            
                    /*  VR.ATO.PSS.000008
                    Gross payment for Labour hire or other specified payments withholding has a maximum field length of 11
    
                    Legacy Rule Format:
                    IF [PSS21] <> MONETARY(U,11,0)
                         RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    NotMonetary(^PSS21, 'U', 11, 0)
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS21 = tns:Remuneration.LabourHireArrangementPaymentGross.Amount
                    */
                    assertion = NotMonetary(rpPayerPSSeqNumContext.PSS21, @"U", 11, 0);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000008", Severity = ProcessMessageSeverity.Error,
                            Description = @"Gross payment for Labour hire or other specified payments withholding is not in a valid monetary format",
                            LongDescription = @"Gross payment for Labour hire or other specified payments withholding must be unsigned, not exceed 11 digits and not contain a decimal point or any other characters",
                            Location = "/xbrli:xbrl/tns:Remuneration.LabourHireArrangementPaymentGross.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000008"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS21", Value = rpPayerPSSeqNumContext.PSS21.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000008
            
                    #region VR.ATO.PSS.000009
            
                    /*  VR.ATO.PSS.000009
                    Tax withheld for foreign resident withholding has a maximum field length of 11
    
                    Legacy Rule Format:
                    IF [PSS22] <> MONETARY(U,11,0)
                         RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    NotMonetary(^PSS22, 'U', 11, 0)
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS22 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessForeignResident.Amount
                    */
                    assertion = NotMonetary(rpPayerPSSeqNumContext.PSS22, @"U", 11, 0);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000009", Severity = ProcessMessageSeverity.Error,
                            Description = @"Tax withheld for foreign resident withholding is not in a valid monetary format",
                            LongDescription = @"Tax withheld for foreign resident withholding must be unsigned, not exceed 11 digits and not contain a decimal point or any other characters",
                            Location = "/xbrli:xbrl/tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessForeignResident.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000009"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS22", Value = rpPayerPSSeqNumContext.PSS22.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000009
            
                    #region VR.ATO.PSS.000010
            
                    /*  VR.ATO.PSS.000010
                    Tax withheld for withholding where ABN not quoted has a maximum field length of 11
    
                    Legacy Rule Format:
                    IF [PSS23] <> MONETARY(U,11,0)
                         RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    NotMonetary(^PSS23, 'U', 11, 0)
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS23 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessABNNotQuoted.Amount
                    */
                    assertion = NotMonetary(rpPayerPSSeqNumContext.PSS23, @"U", 11, 0);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000010", Severity = ProcessMessageSeverity.Error,
                            Description = @"Tax withheld for withholding where ABN not quoted is not in a valid monetary format",
                            LongDescription = @"Tax withheld for withholding where ABN not quoted must be unsigned, not exceed 11 digits and not contain a decimal point or any other characters",
                            Location = "/xbrli:xbrl/tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessABNNotQuoted.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000010"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS23", Value = rpPayerPSSeqNumContext.PSS23.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000010
            
                    #region VR.ATO.PSS.000011
            
                    /*  VR.ATO.PSS.000011
                    Tax withheld for Voluntary agreement withholding has a maximum field length of 11
    
                    Legacy Rule Format:
                    IF [PSS24] <> MONETARY(U,11,0)
                         RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    NotMonetary(^PSS24, 'U', 11, 0)
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS24 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessVoluntaryAgreement.Amount
                    */
                    assertion = NotMonetary(rpPayerPSSeqNumContext.PSS24, @"U", 11, 0);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000011", Severity = ProcessMessageSeverity.Error,
                            Description = @"Tax withheld for Voluntary agreement withholding is not in a valid monetary format",
                            LongDescription = @"Tax withheld for Voluntary agreement withholding must be unsigned, not exceed 11 digits and not contain a decimal point or any other characters",
                            Location = "/xbrli:xbrl/tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessVoluntaryAgreement.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000011"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS24", Value = rpPayerPSSeqNumContext.PSS24.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000011
            
                    #region VR.ATO.PSS.000012
            
                    /*  VR.ATO.PSS.000012
                    Tax withheld for labour hire or other specified payments withholding has a maximum field length of 11
    
                    Legacy Rule Format:
                    IF [PSS25] <> MONETARY(U,11,0)
                         RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    NotMonetary(^PSS25, 'U', 11, 0)
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS25 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessLabourHireOrOtherPayments.Amount
                    */
                    assertion = NotMonetary(rpPayerPSSeqNumContext.PSS25, @"U", 11, 0);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000012", Severity = ProcessMessageSeverity.Error,
                            Description = @"Tax withheld for labour hire or other specified payments withholding is not in a valid monetary format",
                            LongDescription = @"Tax withheld for labour hire or other specified payments withholding must be unsigned, not exceed 11 digits and not contain a decimal point or any other characters",
                            Location = "/xbrli:xbrl/tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessLabourHireOrOtherPayments.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000012"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS25", Value = rpPayerPSSeqNumContext.PSS25.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000012
            
                    #region VR.ATO.PSS.000013
            
                    /*  VR.ATO.PSS.000013
                    There is an occurrence of the Tax Amount withheld on the Payment Summary schedule being above 50% of the Gross Payment.
    
                    Legacy Rule Format:
                    WHERE IN CONTEXT(RP.Payer.{PSSeqNum})
                    IF ([PSS22] > 0 AND [PSS22] > [PSS18]*0.50 + 1) OR ([PSS23] > 0 AND [PSS23] > [PSS19]*0.50 + 1) OR ([PSS24] > 0 AND [PSS24] > [PSS20]*0.50 + 1) OR ([PSS25] > 0 AND [PSS25] > [PSS21]*0.50 + 1) OR ([PSS32] > 0 AND [PSS32] > [PSS31]*0.50 + 1)
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    (^PSS22 > 0 AND ^PSS22 > ^PSS18*0.50 + 1) OR (^PSS23 > 0 AND ^PSS23 > ^PSS19*0.50 + 1) OR (^PSS24 > 0 AND ^PSS24 > ^PSS20*0.50 + 1) OR (^PSS25 > 0 AND ^PSS25 > ^PSS21*0.50 + 1) OR (^PSS32 > 0 AND ^PSS32 > ^PSS31*0.50 + 1)
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS22 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessForeignResident.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS18 = tns:Remuneration.PaymentToForeignResidentGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS23 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessABNNotQuoted.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS19 = tns:Remuneration.ABNNotQuotedPaymentGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS24 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessVoluntaryAgreement.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS20 = tns:Remuneration.VoluntaryAgreementGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS25 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessLabourHireOrOtherPayments.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS21 = tns:Remuneration.LabourHireArrangementPaymentGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS32 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldPersonalServicesIncome.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS31 = tns:Remuneration.PersonalServicesIncome.AttributedGross.Amount
                    */
                    assertion = (rpPayerPSSeqNumContext.PSS22.GetValueOrDefault() > 0 && rpPayerPSSeqNumContext.PSS22.GetValueOrDefault() > rpPayerPSSeqNumContext.PSS18.GetValueOrDefault() * 0.50M + 1 || rpPayerPSSeqNumContext.PSS23.GetValueOrDefault() > 0 && rpPayerPSSeqNumContext.PSS23.GetValueOrDefault() > rpPayerPSSeqNumContext.PSS19.GetValueOrDefault() * 0.50M + 1 || rpPayerPSSeqNumContext.PSS24.GetValueOrDefault() > 0 && rpPayerPSSeqNumContext.PSS24.GetValueOrDefault() > rpPayerPSSeqNumContext.PSS20.GetValueOrDefault() * 0.50M + 1 || rpPayerPSSeqNumContext.PSS25.GetValueOrDefault() > 0 && rpPayerPSSeqNumContext.PSS25.GetValueOrDefault() > rpPayerPSSeqNumContext.PSS21.GetValueOrDefault() * 0.50M + 1 || rpPayerPSSeqNumContext.PSS32.GetValueOrDefault() > 0 && rpPayerPSSeqNumContext.PSS32.GetValueOrDefault() > rpPayerPSSeqNumContext.PSS31.GetValueOrDefault() * 0.50M + 1);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000013", Severity = ProcessMessageSeverity.Error,
                            Description = @"Tax Amount withheld is incorrect",
                            LongDescription = @"There is an occurrence of the Tax Amount withheld on the Payment Summary schedule for either foreign resident withholding, withholding where ABN not quoted, Voluntary agreement withholding, labour hire or other specified payments withholding or Attributed Personal Services Income payment being above 50% of the corresponding Gross Payment",
                            Location = "/xbrli:xbrl/tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessForeignResident.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000013"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS22", Value = rpPayerPSSeqNumContext.PSS22.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS18", Value = rpPayerPSSeqNumContext.PSS18.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS23", Value = rpPayerPSSeqNumContext.PSS23.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS19", Value = rpPayerPSSeqNumContext.PSS19.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS24", Value = rpPayerPSSeqNumContext.PSS24.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS20", Value = rpPayerPSSeqNumContext.PSS20.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS25", Value = rpPayerPSSeqNumContext.PSS25.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS21", Value = rpPayerPSSeqNumContext.PSS21.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS32", Value = rpPayerPSSeqNumContext.PSS32.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS31", Value = rpPayerPSSeqNumContext.PSS31.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000013
            
                    #region VR.ATO.PSS.000014
            
                    /*  VR.ATO.PSS.000014
                    Gross payment for Attributed Personal Services Income has a maximum field length of 11
    
                    Legacy Rule Format:
                    IF [PSS31] <> MONETARY(U,11,0)
                         RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    NotMonetary(^PSS31, 'U', 11, 0)
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS31 = tns:Remuneration.PersonalServicesIncome.AttributedGross.Amount
                    */
                    assertion = NotMonetary(rpPayerPSSeqNumContext.PSS31, @"U", 11, 0);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000014", Severity = ProcessMessageSeverity.Error,
                            Description = @"Gross payment for Attributed Personal Services Income is not in a valid monetary format",
                            LongDescription = @"Gross payment for Attributed Personal Services Income must be unsigned, not exceed 11 digits and not contain a decimal point or any other characters",
                            Location = "/xbrli:xbrl/tns:Remuneration.PersonalServicesIncome.AttributedGross.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000014"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS31", Value = rpPayerPSSeqNumContext.PSS31.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000014
            
                    #region VR.ATO.PSS.000015
            
                    /*  VR.ATO.PSS.000015
                    Tax withheld for Attributed Personal Services Income has a maximum field length of 11
    
                    Legacy Rule Format:
                    IF [PSS32] <> MONETARY(U,11,0)
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    NotMonetary(^PSS32, 'U', 11, 0)
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS32 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldPersonalServicesIncome.Amount
                    */
                    assertion = NotMonetary(rpPayerPSSeqNumContext.PSS32, @"U", 11, 0);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000015", Severity = ProcessMessageSeverity.Error,
                            Description = @"Tax withheld for Attributed Personal Services Income is not in a valid monetary format",
                            LongDescription = @"Tax withheld for Attributed Personal Services Income must be unsigned, not exceed 11 digits and not contain a decimal point or any other characters",
                            Location = "/xbrli:xbrl/tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldPersonalServicesIncome.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000015"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS32", Value = rpPayerPSSeqNumContext.PSS32.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000015
            
                    #region VR.ATO.PSS.000016
            
                    /*  VR.ATO.PSS.000016
                    Entity identifier scheme for Reporting Party Payer must be "http://www.ato.gov.au/tfn"
    
                    Legacy Rule Format:
                    IF (RP.Payer.{PSSeqNum}:entity.identifier.scheme <> “http://www.ato.gov.au/tfn”)
                        RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    ^IdentifierScheme <> 'http://www.ato.gov.au/tfn'
            
                    Data Elements:
            
                    ^IdentifierScheme = RP.Payer.{PSSeqNum}
                    */
                    assertion = (rpPayerPSSeqNumContext.IdentifierScheme != @"http://www.ato.gov.au/tfn");
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000016", Severity = ProcessMessageSeverity.Error,
                            Description = @"Entity identifier scheme for Reporting Party Payer must be ""http://www.ato.gov.au/tfn""",
                            Location = "/xbrli:xbrl/xbrli:context" + OccurrenceIndex(rpPayerPSSeqNumContext.OccurrenceIndex) + "/xbrli:entity/xbrli:identifier/@scheme",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000016"} },
                        };
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000016
            
                    #region VR.ATO.PSS.000017
            
                    /*  VR.ATO.PSS.000017
                    A text character must be one of the following: A to Z a to z 0 to 9 ! @ $ % & * ( ) - = [ ] ; : ' " , . ? / or a space character
    
                    Legacy Rule Format:
                    IF ([PSS26] <> NULLORBLANK) AND ([PSS26] CONTAINS SET("\", "{", "}", "_", "#"))
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    ContainsSet(^PSS26, '"\", "{", "}", "_", "#"')
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS26 = tns:OrganisationNameDetails.OrganisationalName.Text
                    */
                    assertion = IsMatch(rpPayerPSSeqNumContext.PSS26, @"\\|\{|\}|_|#",RegexOptions.IgnoreCase);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000017", Severity = ProcessMessageSeverity.Error,
                            Description = @"Payment Summary - Payer trading name contains invalid text",
                            LongDescription = @"A text character must be one of the following: A to Z a to z 0 to 9 ! @ $ % & * ( ) - = [ ] ; : ' "" , . ? / or a space character",
                            Location = "/xbrli:xbrl/tns:OrganisationNameDetails.OrganisationalName.Text[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000017"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS26", Value = rpPayerPSSeqNumContext.PSS26 });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000017
            
                    #region VR.ATO.PSS.000018
            
                    /*  VR.ATO.PSS.000018
                    A text character must be one of the following: A to Z a to z 0 to 9 @ $ % & * ( ) - = [ ] ; : ' " , . ? / or a space character
    
                    Legacy Rule Format:
                    IF ([PSS29] <> NULLORBLANK) AND ([PSS29] CONTAINS SET("\", "{", "}", "_", "#"))
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    ContainsSet(^PSS29, '"\", "{", "}", "_", "#"')
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS29 = tns:PersonNameDetails.FamilyName.Text
                    */
                    assertion = IsMatch(rpPayerPSSeqNumContext.PSS29, @"\\|\{|\}|_|#",RegexOptions.IgnoreCase);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000018", Severity = ProcessMessageSeverity.Error,
                            Description = @"Payer's name - Family name contains invalid text",
                            LongDescription = @"A text character must be one of the following: A to Z a to z 0 to 9 @ $ % & * ( ) - = [ ] ; : ' "" , . ? / or a space character",
                            Location = "/xbrli:xbrl/tns:PersonNameDetails.FamilyName.Text[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000018"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS29", Value = rpPayerPSSeqNumContext.PSS29 });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000018
            
                    #region VR.ATO.PSS.000019
            
                    /*  VR.ATO.PSS.000019
                    A text character must be one of the following: A to Z a to z 0 to 9 @ $ % & * ( ) - = [ ] ; : ' " , . ? / or a space character
    
                    Legacy Rule Format:
                    IF ([PSS27] <> NULLORBLANK) AND ([PSS27] CONTAINS SET("\", "{", "}", "_", "#"))
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    ContainsSet(^PSS27, '"\", "{", "}", "_", "#"')
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS27 = tns:PersonNameDetails.GivenName.Text
                    */
                    assertion = IsMatch(rpPayerPSSeqNumContext.PSS27, @"\\|\{|\}|_|#",RegexOptions.IgnoreCase);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000019", Severity = ProcessMessageSeverity.Error,
                            Description = @"Payer's name - Given name contains invalid text",
                            LongDescription = @"A text character must be one of the following: A to Z a to z 0 to 9 @ $ % & * ( ) - = [ ] ; : ' "" , . ? / or a space character",
                            Location = "/xbrli:xbrl/tns:PersonNameDetails.GivenName.Text[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000019"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS27", Value = rpPayerPSSeqNumContext.PSS27 });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000019
            
                    #region VR.ATO.PSS.000022
            
                    /*  VR.ATO.PSS.000022
                    A text character must be one of the following: A to Z a to z 0 to 9 @ $ % & * ( ) - = [ ] ; : ' " , . ? / or a space character
    
                    Legacy Rule Format:
                    IF ([PSS28] <> NULLORBLANK) AND ([PSS28] CONTAINS SET("\", "{", "}", "_", "#"))
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    ContainsSet(^PSS28, '"\", "{", "}", "_", "#"')
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS28 = tns:PersonNameDetails.OtherGivenName.Text
                    */
                    assertion = IsMatch(rpPayerPSSeqNumContext.PSS28, @"\\|\{|\}|_|#",RegexOptions.IgnoreCase);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000022", Severity = ProcessMessageSeverity.Error,
                            Description = @"Payer's name - Other given names contains invalid text",
                            LongDescription = @"A text character must be one of the following: A to Z a to z 0 to 9 @ $ % & * ( ) - = [ ] ; : ' "" , . ? / or a space character",
                            Location = "/xbrli:xbrl/tns:PersonNameDetails.OtherGivenName.Text[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000022"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS28", Value = rpPayerPSSeqNumContext.PSS28 });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000022
            
                    #region VR.ATO.PSS.000023
            
                    /*  VR.ATO.PSS.000023
                    Only one type of Tax withheld allowed in a single RP Payer context sequence number
    
                    Legacy Rule Format:
                    WHERE IN CONTEXT(RP.Payer.{PSSeqNum})
                    IF (([PSS22] <> NULL AND ([PSS23] <> NULL OR [PSS24] <> NULL OR [PSS25] <> NULL OR [PSS32] <> NULL)) OR ([PSS23] <> NULL AND ([PSS22] <> NULL OR [PSS24] <> NULL OR [PSS25] <> NULL OR [PSS32] <> NULL)) OR  ([PSS24] <> NULL AND ([PSS22] <> NULL OR [PSS23] <> NULL OR [PSS25] <> NULL OR [PSS32] <> NULL)) OR ([PSS25] <> NULL AND ([PSS22] <> NULL OR [PSS24] <> NULL OR [PSS23] <> NULL OR [PSS32] <> NULL)) OR ([PSS32] <> NULL AND ([PSS22] <> NULL OR [PSS24] <> NULL OR [PSS25] <> NULL OR [PSS23] <> NULL)))
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    ((^PSS22 <> NULL AND (^PSS23 <> NULL OR ^PSS24 <> NULL OR ^PSS25 <> NULL OR ^PSS32 <> NULL)) OR (^PSS23 <> NULL AND (^PSS22 <> NULL OR ^PSS24 <> NULL OR ^PSS25 <> NULL OR ^PSS32 <> NULL)) OR  (^PSS24 <> NULL AND (^PSS22 <> NULL OR ^PSS23 <> NULL OR ^PSS25 <> NULL OR ^PSS32 <> NULL)) OR (^PSS25 <> NULL AND (^PSS22 <> NULL OR ^PSS24 <> NULL OR ^PSS23 <> NULL OR ^PSS32 <> NULL)) OR (^PSS32 <> NULL AND (^PSS22 <> NULL OR ^PSS24 <> NULL OR ^PSS25 <> NULL OR ^PSS23 <> NULL)))
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS22 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessForeignResident.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS23 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessABNNotQuoted.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS24 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessVoluntaryAgreement.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS25 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessLabourHireOrOtherPayments.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS32 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldPersonalServicesIncome.Amount
                    */
                    assertion = (rpPayerPSSeqNumContext.PSS22 != null && (rpPayerPSSeqNumContext.PSS23 != null || rpPayerPSSeqNumContext.PSS24 != null || rpPayerPSSeqNumContext.PSS25 != null || rpPayerPSSeqNumContext.PSS32 != null) || rpPayerPSSeqNumContext.PSS23 != null && (rpPayerPSSeqNumContext.PSS22 != null || rpPayerPSSeqNumContext.PSS24 != null || rpPayerPSSeqNumContext.PSS25 != null || rpPayerPSSeqNumContext.PSS32 != null) || rpPayerPSSeqNumContext.PSS24 != null && (rpPayerPSSeqNumContext.PSS22 != null || rpPayerPSSeqNumContext.PSS23 != null || rpPayerPSSeqNumContext.PSS25 != null || rpPayerPSSeqNumContext.PSS32 != null) || rpPayerPSSeqNumContext.PSS25 != null && (rpPayerPSSeqNumContext.PSS22 != null || rpPayerPSSeqNumContext.PSS24 != null || rpPayerPSSeqNumContext.PSS23 != null || rpPayerPSSeqNumContext.PSS32 != null) || rpPayerPSSeqNumContext.PSS32 != null && (rpPayerPSSeqNumContext.PSS22 != null || rpPayerPSSeqNumContext.PSS24 != null || rpPayerPSSeqNumContext.PSS25 != null || rpPayerPSSeqNumContext.PSS23 != null));
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000023", Severity = ProcessMessageSeverity.Error,
                            Description = @"Tax withheld type is incorrect",
                            LongDescription = @"Only one type of Tax withheld allowed in a single RP Payer context sequence number",
                            Location = "/xbrli:xbrl/tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessForeignResident.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000023"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS22", Value = rpPayerPSSeqNumContext.PSS22.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS23", Value = rpPayerPSSeqNumContext.PSS23.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS24", Value = rpPayerPSSeqNumContext.PSS24.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS25", Value = rpPayerPSSeqNumContext.PSS25.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS32", Value = rpPayerPSSeqNumContext.PSS32.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000023
            
                    #region VR.ATO.PSS.000024
            
                    /*  VR.ATO.PSS.000024
                    Only one type of gross payment type is allowed in a single RP Payer context sequence number
    
                    Legacy Rule Format:
                    WHERE IN CONTEXT(RP.Payer.{PSSeqNum})
                    IF (([PSS18] <> NULL AND ([PSS19] <> NULL OR [PSS20] <> NULL OR [PSS21] <> NULL OR [PSS31] <> NULL)) OR ([PSS19] <> NULL AND ([PSS18] <> NULL OR [PSS20] <> NULL OR [PSS21] <> NULL OR [PSS31] <> NULL)) OR ([PSS20] <> NULL AND ([PSS19] <> NULL OR [PSS18] <> NULL OR [PSS21] <> NULL OR [PSS31] <> NULL)) OR ([PSS21] <> NULL AND ([PSS19] <> NULL OR [PSS20] <> NULL OR [PSS18] <> NULL OR [PSS31] <> NULL)) OR ([PSS31] <> NULL AND ([PSS19] <> NULL OR [PSS20] <> NULL OR [PSS21] <> NULL OR [PSS18] <> NULL)))
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    ((^PSS18 <> NULL AND (^PSS19 <> NULL OR ^PSS20 <> NULL OR ^PSS21 <> NULL OR ^PSS31 <> NULL)) OR (^PSS19 <> NULL AND (^PSS18 <> NULL OR ^PSS20 <> NULL OR ^PSS21 <> NULL OR ^PSS31 <> NULL)) OR (^PSS20 <> NULL AND (^PSS19 <> NULL OR ^PSS18 <> NULL OR ^PSS21 <> NULL OR ^PSS31 <> NULL)) OR (^PSS21 <> NULL AND (^PSS19 <> NULL OR ^PSS20 <> NULL OR ^PSS18 <> NULL OR ^PSS31 <> NULL)) OR (^PSS31 <> NULL AND (^PSS19 <> NULL OR ^PSS20 <> NULL OR ^PSS21 <> NULL OR ^PSS18 <> NULL)))
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS18 = tns:Remuneration.PaymentToForeignResidentGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS19 = tns:Remuneration.ABNNotQuotedPaymentGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS20 = tns:Remuneration.VoluntaryAgreementGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS21 = tns:Remuneration.LabourHireArrangementPaymentGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS31 = tns:Remuneration.PersonalServicesIncome.AttributedGross.Amount
                    */
                    assertion = (rpPayerPSSeqNumContext.PSS18 != null && (rpPayerPSSeqNumContext.PSS19 != null || rpPayerPSSeqNumContext.PSS20 != null || rpPayerPSSeqNumContext.PSS21 != null || rpPayerPSSeqNumContext.PSS31 != null) || rpPayerPSSeqNumContext.PSS19 != null && (rpPayerPSSeqNumContext.PSS18 != null || rpPayerPSSeqNumContext.PSS20 != null || rpPayerPSSeqNumContext.PSS21 != null || rpPayerPSSeqNumContext.PSS31 != null) || rpPayerPSSeqNumContext.PSS20 != null && (rpPayerPSSeqNumContext.PSS19 != null || rpPayerPSSeqNumContext.PSS18 != null || rpPayerPSSeqNumContext.PSS21 != null || rpPayerPSSeqNumContext.PSS31 != null) || rpPayerPSSeqNumContext.PSS21 != null && (rpPayerPSSeqNumContext.PSS19 != null || rpPayerPSSeqNumContext.PSS20 != null || rpPayerPSSeqNumContext.PSS18 != null || rpPayerPSSeqNumContext.PSS31 != null) || rpPayerPSSeqNumContext.PSS31 != null && (rpPayerPSSeqNumContext.PSS19 != null || rpPayerPSSeqNumContext.PSS20 != null || rpPayerPSSeqNumContext.PSS21 != null || rpPayerPSSeqNumContext.PSS18 != null));
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000024", Severity = ProcessMessageSeverity.Error,
                            Description = @"Gross payment type is incorrect",
                            LongDescription = @"Only one type of gross payment type is allowed in a single RP Payer context sequence number",
                            Location = "/xbrli:xbrl/tns:Remuneration.PaymentToForeignResidentGross.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000024"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS18", Value = rpPayerPSSeqNumContext.PSS18.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS19", Value = rpPayerPSSeqNumContext.PSS19.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS20", Value = rpPayerPSSeqNumContext.PSS20.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS21", Value = rpPayerPSSeqNumContext.PSS21.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS31", Value = rpPayerPSSeqNumContext.PSS31.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000024
            
                    #region VR.ATO.PSS.000025
            
                    /*  VR.ATO.PSS.000025
                    The Tax withholding and Gross payment must be of the same type
    
                    Legacy Rule Format:
                    WHERE IN CONTEXT(RP.Payer.{PSSeqNum})
                    IF (([PSS18] <> NULL AND [PSS22] = NULL) OR ([PSS19] <> NULL AND [PSS23] = NULL) OR ([PSS20] <> NULL AND [PSS24] = NULL) OR ([PSS21] <> NULL AND [PSS25] = NULL) OR ([PSS31] <> NULL AND [PSS32] = NULL))
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    ((^PSS18 <> NULL AND ^PSS22 = NULL) OR (^PSS19 <> NULL AND ^PSS23 = NULL) OR (^PSS20 <> NULL AND ^PSS24 = NULL) OR (^PSS21 <> NULL AND ^PSS25 = NULL) OR (^PSS31 <> NULL AND ^PSS32 = NULL))
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS18 = tns:Remuneration.PaymentToForeignResidentGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS22 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessForeignResident.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS19 = tns:Remuneration.ABNNotQuotedPaymentGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS23 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessABNNotQuoted.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS20 = tns:Remuneration.VoluntaryAgreementGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS24 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessVoluntaryAgreement.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS21 = tns:Remuneration.LabourHireArrangementPaymentGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS25 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldBusinessLabourHireOrOtherPayments.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS31 = tns:Remuneration.PersonalServicesIncome.AttributedGross.Amount
            
                    RP.Payer.{PSSeqNum}:^PSS32 = tns:IncomeTax.PayAsYouGoWithholding.CreditTaxWithheldPersonalServicesIncome.Amount
                    */
                    assertion = (rpPayerPSSeqNumContext.PSS18 != null && rpPayerPSSeqNumContext.PSS22 == null || rpPayerPSSeqNumContext.PSS19 != null && rpPayerPSSeqNumContext.PSS23 == null || rpPayerPSSeqNumContext.PSS20 != null && rpPayerPSSeqNumContext.PSS24 == null || rpPayerPSSeqNumContext.PSS21 != null && rpPayerPSSeqNumContext.PSS25 == null || rpPayerPSSeqNumContext.PSS31 != null && rpPayerPSSeqNumContext.PSS32 == null);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000025", Severity = ProcessMessageSeverity.Error,
                            Description = @"The Tax withheld or Gross payment type is invalid",
                            LongDescription = @"The Tax withholding and Gross payment must be of the same type",
                            Location = "/xbrli:xbrl/tns:Remuneration.PaymentToForeignResidentGross.Amount[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000025"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS18", Value = rpPayerPSSeqNumContext.PSS18.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS22", Value = rpPayerPSSeqNumContext.PSS22.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS19", Value = rpPayerPSSeqNumContext.PSS19.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS23", Value = rpPayerPSSeqNumContext.PSS23.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS20", Value = rpPayerPSSeqNumContext.PSS20.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS24", Value = rpPayerPSSeqNumContext.PSS24.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS21", Value = rpPayerPSSeqNumContext.PSS21.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS25", Value = rpPayerPSSeqNumContext.PSS25.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS31", Value = rpPayerPSSeqNumContext.PSS31.GetValueOrDefault().ToString() });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS32", Value = rpPayerPSSeqNumContext.PSS32.GetValueOrDefault().ToString() });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000025
            
                    #region VR.ATO.PSS.000026
            
                    /*  VR.ATO.PSS.000026
                    Withholding payer number must be valid
    
                    Legacy Rule Format:
                    IF ([PSS17] <> NULL AND WPNALGORITHM([PSS17]) = FALSE)
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    (^PSS17 <> NULL AND FailsWPNAlgorithm(^PSS17))
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS17 = tns:Identifiers.WithholdingPayerNumber.Identifier
                    */
                    assertion = (rpPayerPSSeqNumContext.PSS17 != null && FailsTFNAlgorithm(rpPayerPSSeqNumContext.PSS17));
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000026", Severity = ProcessMessageSeverity.Error,
                            Description = @"Withholding payer number is invalid",
                            LongDescription = @"Withholding payer number must be valid",
                            Location = "/xbrli:xbrl/tns:Identifiers.WithholdingPayerNumber.Identifier[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000026"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS17", Value = rpPayerPSSeqNumContext.PSS17 });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000026
            
                    #region VR.ATO.PSS.000030
            
                    /*  VR.ATO.PSS.000030
                    If Payer ABN is supplied then Payer WPN must be blank
    
                    Legacy Rule Format:
                    IF ([PSS16] <> NULL AND [PSS17] <> NULL)
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    ^PSS16 <> NULL AND ^PSS17 <> NULL
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS16 = tns:Identifiers.AustralianBusinessNumber.Identifier
            
                    RP.Payer.{PSSeqNum}:^PSS17 = tns:Identifiers.WithholdingPayerNumber.Identifier
                    */
                    assertion = (rpPayerPSSeqNumContext.PSS16 != null && rpPayerPSSeqNumContext.PSS17 != null);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000030", Severity = ProcessMessageSeverity.Error,
                            Description = @"Only a Payer ABN or Payer WPN may be supplied",
                            Location = "/xbrli:xbrl/tns:Identifiers.AustralianBusinessNumber.Identifier[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000030"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS16", Value = rpPayerPSSeqNumContext.PSS16 });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS17", Value = rpPayerPSSeqNumContext.PSS17 });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000030
            
                    #region VR.ATO.PSS.000032
            
                    /*  VR.ATO.PSS.000032
                    Trading name and the family name have both been provided. Only one is permitted.
    
                    Legacy Rule Format:
                    IF ([PSS26] <> NULLORBLANK AND [PSS29] <> NULLORBLANK)
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    ^PSS26 <> BLANK AND ^PSS29 <> BLANK
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS26 = tns:OrganisationNameDetails.OrganisationalName.Text
            
                    RP.Payer.{PSSeqNum}:^PSS29 = tns:PersonNameDetails.FamilyName.Text
                    */
                    assertion = (string.IsNullOrWhiteSpace(rpPayerPSSeqNumContext.PSS26) != true && string.IsNullOrWhiteSpace(rpPayerPSSeqNumContext.PSS29) != true);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000032", Severity = ProcessMessageSeverity.Error,
                            Description = @"Trading name and the family name have both been provided. Only one is permitted.",
                            Location = "/xbrli:xbrl/tns:OrganisationNameDetails.OrganisationalName.Text[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000032"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS26", Value = rpPayerPSSeqNumContext.PSS26 });
            
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS29", Value = rpPayerPSSeqNumContext.PSS29 });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000032
            
                    #region VR.ATO.PSS.000034
            
                    /*  VR.ATO.PSS.000034
                    The TFN has failed the algorithm check.
    
                    Legacy Rule Format:
                    IF (TFNALGORITHM (RP.Payer.{PSSeqNum}:entity.identifier.TFN) = FALSE)
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    (FailsTFNAlgorithm(^TFN))
            
                    Data Elements:
            
                    ^TFN = RP.Payer.{PSSeqNum}
                    */
                    assertion = FailsTFNAlgorithm(rpPayerPSSeqNumContext.IdentifierTFN);
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.PSS.000034", Severity = ProcessMessageSeverity.Error,
                            Description = @"Reporting Party Payer Tax File Number has failed the algorithm check",
                            Location = "/xbrli:xbrl/xbrli:context" + OccurrenceIndex(rpPayerPSSeqNumContext.OccurrenceIndex) + "/xbrli:entity/xbrli:identifier",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000034"} },
                        };
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000034
            
                    #region VR.ATO.PSS.000045
            
                    /*  VR.ATO.PSS.000045
                    The Australian Business Number (ABN) has failed the ABN algorithm check.
    
                    Legacy Rule Format:
                    IF ([PSS16] <> NULL) AND (ABNALGORITHM([PSS16]) = FALSE)
                       RETURN VALIDATION MESSAGE
                    ENDIF
        
                    Technical Business Rule Format:
                    (^PSS16 <> NULL) AND (FailsABNAlgorithm(^PSS16))
            
                    Data Elements:
            
                    RP.Payer.{PSSeqNum}:^PSS16 = tns:Identifiers.AustralianBusinessNumber.Identifier
                    */
                    assertion = (rpPayerPSSeqNumContext.PSS16 != null && FailsABNAlgorithm(rpPayerPSSeqNumContext.PSS16));
                    if (assertion)
                    {
                        processMessage = new ProcessMessageDocument()
                        {
                            Code = "CMN.ATO.GEN.000477", Severity = ProcessMessageSeverity.Error,
                            Description = @"ABN is invalid",
                            Location = "/xbrli:xbrl/tns:Identifiers.AustralianBusinessNumber.Identifier[@contextRef='" + rpPayerPSSeqNumContext.Id + "']",
                            Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000045"} },
                        };
                        processMessage.Parameters.Add(new ProcessMessageParameter
                            { Name = "PSS16", Value = rpPayerPSSeqNumContext.PSS16 });
            
                        response.Add(processMessage);
                    }
                    #endregion // VR.ATO.PSS.000045
                    }
                }
        
                #endregion // Foreach loop
    
            #region VR.ATO.PSS.000020
    
            /*  VR.ATO.PSS.000020
            The Sequence Number Container within the Payer Sequence Dimension context instance must not be duplicated
    
            Legacy Rule Format:
            IF ([PSS50] = ANY OTHER OCCURRENCE OF [PSS50])
                 RETURN VALIDATION MESSAGE
            ENDIF

            Technical Business Rule Format:
            HasDuplicateValues(^PSS50)
    
            Data Elements:
    
            RP.Payer.{PSSeqNum}:^PSS50 = tns:Report.ItemOrder.Number
            */
            assertion = HasDuplicateValues(report.RPPayerPSSeqNumContextCollection == null ? null : report.RPPayerPSSeqNumContextCollection.Select(f => f.PSS50).Cast<object>().ToArray());
            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.PSS.000044", Severity = ProcessMessageSeverity.Error,
                    Description = @"Sequence Number Container must not be duplicated",
                    LongDescription = @"The Sequence Number Container within the Payer Sequence Dimension context instance must not be duplicated",
                    Location = "/xbrli:xbrl/xbrli:context[@id='" + report.RPPayerPSSeqNumContextCollection[DuplicateValueIndex(report.RPPayerPSSeqNumContextCollection.Select(f => f.PSS50))].Id + "']",
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000020"} },
                };
                response.Add(processMessage);
            }
            #endregion // VR.ATO.PSS.000020
    
            #region VR.ATO.PSS.000042
    
            /*  VR.ATO.PSS.000042
            At least one Reporting Party Payer's information must be attached.
    
            Legacy Rule Format:
            IF COUNT(RP.Payer.{PSSeqNum}) = 0
               RETURN VALIDATION MESSAGE
            ENDIF

            Technical Business Rule Format:
            Count(^Context) = 0
    
            Data Elements:
    
            ^Context = RP.Payer.{PSSeqNum}
            */
            assertion = (Count(report.RPPayerPSSeqNumContextCollection) == 0);
            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.PSS.000042", Severity = ProcessMessageSeverity.Error,
                    Description = @"No Reporting Party Payer attached",
                    LongDescription = @"At least one beneficiary's Reporting Party Payer must be attached.",
                    Location = "/xbrli:xbrl/xbrli:context" + OccurrenceIndex(report.RPPayerPSSeqNumContextCollection == null ? 0 : (report.RPPayerPSSeqNumContextCollection.Count() == 0 ? 0 : report.RPPayerPSSeqNumContextCollection.Last().LastOccurrenceIndex)),
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000042"} },
                };
                response.Add(processMessage);
            }
            #endregion // VR.ATO.PSS.000042
    
            #region VR.ATO.PSS.000043
    
            /*  VR.ATO.PSS.000043
            Invalid context. The number of Reporting Party Payer contexts must not exceed 99.
    
            Legacy Rule Format:
            IF COUNT(RP.Payer.{PSSeqNum}) > 99
               RETURN VALIDATION MESSAGE
            ENDIF

            Technical Business Rule Format:
            Count(^Context) > 99
    
            Data Elements:
    
            ^Context = RP.Payer.{PSSeqNum}
            */
            assertion = (Count(report.RPPayerPSSeqNumContextCollection) > 99);
            if (assertion)
            {
                processMessage = new ProcessMessageDocument()
                {
                    Code = "CMN.ATO.PSS.000043", Severity = ProcessMessageSeverity.Error,
                    Description = @"Invalid context. The number of Reporting Party Payer contexts must not exceed 99.",
                    Location = "/xbrli:xbrl/xbrli:context" + OccurrenceIndex(report.RPPayerPSSeqNumContextCollection == null ? 0 : (report.RPPayerPSSeqNumContextCollection.Count() == 0 ? 0 : report.RPPayerPSSeqNumContextCollection.Last().LastOccurrenceIndex)),
                    Parameters = new ProcessMessageParameters() { new ProcessMessageParameter() {Name = "RuleIdentifier", Value = "VR.ATO.PSS.000043"} },
                };
                response.Add(processMessage);
            }
            #endregion // VR.ATO.PSS.000043

            foreach (ProcessMessageDocument currentProcessMessage in response)
            {
                if (currentProcessMessage.Parameters != null)
                {
                    foreach (ProcessMessageParameter currentParameter in currentProcessMessage.Parameters)
                    {
                        if (string.IsNullOrEmpty(currentParameter.Name))
                        {
                            currentParameter.Name = _emptyParameterValue;
                        }

                        if (currentParameter.Name.Length > _maxParameterNameLength)
                        {
                            currentParameter.Name = currentParameter.Name.Substring(0, _maxParameterNameLength - 1);
                        }

                        if (string.IsNullOrEmpty(currentParameter.Value))
                        {
                            currentParameter.Value = _emptyParameterValue;
                        }

                        if (currentParameter.Value.Length > _maxParameterValueLength)
                        {
                            currentParameter.Value = currentParameter.Value.Substring(0, _maxParameterValueLength - 1);
                        }
                    }
                }
            }

            return response;
        }


    }
} 
