# Thu, 20 Aug 2026 13:11:52 GMT
---
version: 23
data:


- type: ModificationMethod
  attributes:
    displayName: Canadian social insurance number
    description: |
          Generates a Canadian social insurance number (SIN) based on the specified seed value. The generated SIN is returned as a string. Leading zeroes are preserved.
    scriptLanguage: "GROOVY"
    legacyScript: false
    inputType: "COLUMN"
    mappingTableContainers: []
    mappingTableAccessMode: READ
    code: |
        /*
         * *****************************************************************************
         * Canadian Social Insurance Number
         * *****************************************************************************
         *
         * The following variables are available in this script:
         * =====================================================
         * ctx             : A context object that offers a number of methods.
         *                   The method indexOf() can be used to get the index of a
         *                   specific column within the data.
         * data       : The data array. This array contains the contents of all
         *                   columns of the current row of the table that is being
         *                   masked by this method.
         *
         * Additionally for column based modification methods the following two
         * variables are available:
         * columnName      : The name of the column that matched the pattern.
         * columnIndex     : The position of the column that matched the pattern within
         *                   the data array. This value is zero-based.
         * *****************************************************************************
         */
        
        import de.ubs.xdm3.batch.modification.HashUtils
        
        /*
         * This function is called once before the processing starts. The method
         * is called once per table.
         */
        def init() {
        
        }
        
        /*
         * This function should modify the row that is provided by the data. The
         * method is called for each single row of the table.
         */
        def apply() {
        
            def seedValue = modificationMethod.seed
        
            def value = seedValue.toString().trim()
            if (value.length() == 11) {
                def c1 = value.charAt(3)
                def c2 = value.charAt(7)
                if ((c1 == c2) && (c1 == '-' || c1 == ' ' || c1 == '/' || c1 == '.')) {
                    value = value.substring(0, 3) + value.substring(4, 7) + value.substring(8, 11)
                }
            }
            def x = HashUtils.hashStringLikeInt(value)
            x = HashUtils.hashInt(x) % 1000000000
            def r = HashUtils.luhn(x)
            def sin = r.toString()
            while (sin.length() < 9) {
                sin = "0" + sin
            }
            if (modificationMethod.delimiter != null && modificationMethod.delimiter != "") {
                sin = sin.substring(0, 3) + modificationMethod.delimiter + sin.substring(3, 6) + modificationMethod.delimiter + sin.substring(6, 9)
            }
            data[columnIndex] = sin
            return true
        }
        
        
        /*
         * This function is executed once after the modification of a table is complete. The method
         * is called once per table.
         */
        def close() {
        }
    parameters:
    - displayName: Seed
      description: |
          Specify a value that is used to calculate the hash.
      variableName: seed
      dataType: STRING
    - displayName: Delimiter
      description: |
          The delimiter character used to separate the groups of digits. May be empty.
      variableName: delimiter
      dataType: STRING
