<commit_before>({
    /********************************************* View Modules *********************************************/

    /**
     * @description Returns the Batch Info View module.
     * @param component. Lightning Component reference.
     * @param model. The Model.
     * @return View of the Batch Info module.
     */
    BatchInfoView : function(component, model) {
        return (function (component, model) {

            // Subscribe to the model onInfoUpdated event.
            model.getBatchInfo().onInfoUpdated.subscribe(function() {
                var batchInfoView = component.get('v.batchInfo');
                var batchInfo = model.getBatchInfo();

                // record info
                batchInfoView.name = batchInfo.name;
                batchInfoView.id = batchInfo.id;
                batchInfoView.description = batchInfo.description;
                batchInfoView.expectedCount = batchInfo.expectedCount;
                batchInfoView.expectedTotal = batchInfo.expectedTotal;
                batchInfoView.recordCount = batchInfo.recordCount;

                // batch processing settings
                batchInfoView.requireTotalMatch = batchInfo.requireTotalMatch;
                batchInfoView.batchProcessSize = batchInfo.batchProcessSize;
                batchInfoView.runOpportunityRollupsWhileProcessing = batchInfo.runOpportunityRollupsWhileProcessing;
                batchInfoView.donationMatchingBehavior = batchInfo.donationMatchingBehavior;
                batchInfoView.donationMatchingClass = batchInfo.donationMatchingClass;
                batchInfoView.donationMatchingOptions = batchInfo.donationMatchingOptions;
                batchInfoView.donationMatchingRule = batchInfo.donationMatchingRule;
                batchInfoView.donationDateRange = batchInfo.donationDateRange;
                batchInfoView.noMatchOnDate = batchInfo.noMatchOnDate;
                batchInfoView.postProcessClass = batchInfo.postProcessClass;

                component.set('v.batchInfo', batchInfoView);
            });

            // BatchInfoView module public functions and properties
            return {
                name: '',
                id: '',
                description: '',
                expectedCount: 0,
                expectedTotal: 0,
                recordCount: 0,

                // batch processing settings
                requireTotalMatch: false,
                batchProcessSize: 0,
                runOpportunityRollupsWhileProcessing: false,
                donationMatchingBehavior: '',
                donationMatchingClass: '',
                donationMatchingOptions: [],
                donationMatchingRule: [],
                donationDateRange: '',
                noMatchOnDate: false,
                postProcessClass: ''
            };
        })(component, model);
    },

    /**
     * @description Returns the Batch Metadata View module.
     * @param component. Lightning Component reference.
     * @param model. The Model.
     * @return View of the Batch Metadata module.
     */
    BatchMetadataView : function(component, model) {
        return (function (component, model) {

            // Subscribe to the model onMetadataUpdated event.
            model.getBatchMetadata().onMetadataUpdated.subscribe(function() {
                var batchMetadataView = component.get('v.batchMetadata');
                var batchMetadata = model.getBatchMetadata();
                var headerChanged = Boolean(batchMetadataView.pageHeader !== batchMetadata.pageHeader);

                batchMetadataView.labels = batchMetadata.labels;
                batchMetadataView.mode = batchMetadata.mode;
                batchMetadataView.hasError = batchMetadata.hasError;
                batchMetadataView.errorMessage = batchMetadata.errorMessage;
                batchMetadataView.pageHeader = batchMetadata.pageHeader;
                batchMetadataView.pendingSave = batchMetadata.pendingSave;
                batchMetadataView.showAdvancedOptions = batchMetadata.showAdvancedOptions;

                if (!batchMetadataView.hasError) {
                    batchMetadataView.progressIndicatorStep = batchMetadata.progressIndicatorStep;
                    _sendMessage('setStep',batchMetadata.progressIndicatorStep);
                } else {
                    component.find('notifLib').showNotice({
                        'variant': 'error',
                        'header': $A.get('$Label.c.PageMessagesError'),
                        'message': batchMetadataView.errorMessage,
                        closeCallback: function() {
                            //callback action here
                        }
                    });
                }

                if (batchMetadataView.mode === 'view') {
                    component.set('v.isReadOnly', true);
                } else if (batchMetadataView.mode === 'create' || batchMetadataView.mode === 'edit') {
                    component.set('v.isReadOnly', false);
                }

                //update page header in modal if page header has changed and modal is used
                if (headerChanged) {
                    _sendMessage('setHeader', batchMetadataView.pageHeader);
                }

                //update footer in modal to keep save button appropriately enabled/disabled
                _sendMessage('pendingSave', batchMetadataView.pendingSave);

                // when in modal context, need to notify the modal footer component
                _sendMessage('setError', batchMetadataView.hasError);

                component.set('v.batchMetadata', batchMetadataView);
            });

            function _sendMessage(channel, message) {
                var sendMessage = $A.get('e.ltng:sendMessage');
                sendMessage.setParams({
                    'channel': channel,
                    'message': message
                });
                sendMessage.fire();
            }

            // BatchMetadataView module public functions and properties
            return {
                labels: {},
                mode: '',
                progressIndicatorStep: '',
                hasError: false,
                errorMessage: '',
                pendingSave: false,
                showAdvancedOptions: false
            };
        })(component, model);
    },

    /**
     * @description Returns the Batch Fields View module.
     * @param component. Lightning Component reference.
     * @param model. The Batch Fields Model.
     * @return View of the Batch Fields module.
     */
    BatchFieldsView : function(component, model) {
        return (function (component, model) {

            // Subscribe to the model onFieldsUpdated event.
            model.getAvailableFields().onFieldsUpdated.subscribe(function() {
                var availableFields = component.get('v.availableFields');
                availableFields.fieldGroups = [];

                var activeFieldsBySObject = model.getAvailableFields().getActivesBySObject();
                var allFieldsBySObject = model.getAvailableFields().getAllFieldsBySObject();

                Object.keys(allFieldsBySObject).forEach(function(sObjectName) {
                    var currentFieldGroup = {
                        sObjectName : sObjectName,
                        options: [],
                        requiredOptions: [],
                        values: []
                    };

                    allFieldsBySObject[sObjectName].forEach(function(currentField) {
                        currentFieldGroup.options.push(
                            {
                                label: currentField.label,
                                value: currentField.id
                            }
                        );
                        //special case so Amount object is always visible
                        if (currentField.id.includes('Donation_Amount__c')) {
                            currentFieldGroup.requiredOptions.push(currentField.id);
                        }
                    });

                    if (activeFieldsBySObject[sObjectName]) {
                        activeFieldsBySObject[sObjectName].forEach(function(currentField) {
                            currentFieldGroup.values.push(currentField.id);
                        });
                    }
                    availableFields.fieldGroups.push(currentFieldGroup);
                });

                component.set('v.availableFields', availableFields);
            });

            // BatchFieldsView module public functions and properties
            return {
                fieldGroups: []
            };
        })(component, model);
    },

    /**
     * @description Returns the Batch Field Options View module.
     * @param component. Lightning Component reference.
     * @param model. The Batch Fields Model.
     * @return View of the Batch Field Options module.
     */
    BatchFieldOptionsView : function(component, model) {
        return (function (component, model) {

            // Subscribe to the model onFieldsUpdated event.
            model.getAvailableFields().onFieldsUpdated.subscribe(function() {
                var batchFieldOptions = component.get('v.batchFieldOptions');
                batchFieldOptions.fieldGroups = [];
                var activeFieldsBySObject = model.getAvailableFields().getActivesBySObject();
                var availableFields = model.getAvailableFields();
                batchFieldOptions.errors = availableFields.errors;

                Object.keys(activeFieldsBySObject).forEach(function (sObjectName) {

                    var currentFieldGroup = {
                        sObjectName : sObjectName,
                        fields: []
                    };

                    activeFieldsBySObject[sObjectName].forEach(function (currentField) {

                        var fieldInfo = {
                            name: currentField.name,
                            sObjectName: currentField.sObjectName,
                            label: currentField.label,
                            defaultValue: currentField.defaultValue,
                            required: currentField.required,
                            hide: currentField.hide,
                            type: currentField.type,
                            formatter: currentField.formatter,
                            options: currentField.options
                        }

                        if (currentField.sObjectName === 'Opportunity' &&
                            (currentField.name == 'npsp__Donation_Amount__c' || currentField.name == 'Donation_Amount__c')) {
                            fieldInfo.systemRequired = true;
                        }

                        currentFieldGroup.fields.push(fieldInfo);

                    });

                    batchFieldOptions.fieldGroups.push(currentFieldGroup);

                });
                component.set('v.batchFieldOptions', batchFieldOptions);

            });

            // BatchFieldOptionsView module public functions and properties
            return {
                fieldGroups: []
            };

        })(component, model);
    },


    /*********************************************** Model Modules *********************************************/

    /**
     * @description Gets the Model module of Batch Details.
     * This is the main and only Model module for the Batch
     * Details components. Contains references to BatchFields
     * and BatchInfo sub-modules.
     * @return Model module of Batch Details.
     */
    DetailsModel : function() {
        return (function (availableFields, batchInfo, batchMetadata) {
            var _availableFields = availableFields;
            var _batchInfo = batchInfo;
            var _batchMetadata = batchMetadata;
            var _bgeBatchController;

            /* **********************************************************
             * @Description Gets the Batch Details and loads sub-modules.
             * @param component. Lightning Component reference.
             * @return void.
             ************************************************************/
            function init(component) {
                var recordId = _batchInfo.id ? _batchInfo.id : component.get('v.recordId');
                _bgeBatchController.getRecordDetails(recordId, {
                    success: function(response) {
                        _batchInfo.load(response);
                        _availableFields.load(response.availableFields, JSON.parse(response.activeFields));
                        _batchMetadata.load(response.labels, component);
                    },
                    error: function(error) {
                        _batchMetadatas.showError(error);
                        console.log(error);
                    }
                });
            }

            /**
             * @description Saves the model information to the backend.
             * @return void.
             */
            function save() {
                var batchDetailsData = {
                    //record info
                    name: _batchInfo.name,
                    id: _batchInfo.id,
                    description: _batchInfo.description,
                    expectedCount: _batchInfo.expectedCount,
                    expectedTotal: _batchInfo.expectedTotal,

                    // batch processing settings
                    requireTotalMatch: _batchInfo.requireTotalMatch,
                    batchProcessSize: _batchInfo.batchProcessSize,
                    runOpportunityRollupsWhileProcessing: _batchInfo.runOpportunityRollupsWhileProcessing,
                    donationMatchingBehavior: _batchInfo.donationMatchingBehavior,
                    donationMatchingClass: _batchInfo.donationMatchingClass,
                    donationMatchingRule: _batchInfo.donationMatchingRule,
                    donationDateRange: _batchInfo.donationDateRange,
                    postProcessClass: _batchInfo.postProcessClass
                };
                var activeFields = [];

                _availableFields.getActives().forEach(function(currentField) {
                    activeFields.push({
                        label: currentField.label,
                        name: currentField.name,
                        sObjectName: currentField.sObjectName,
                        defaultValue: currentField.defaultValue,
                        required: currentField.required,
                        hide: currentField.hide,
                        sortOrder: currentField.sortOrder,
                        type: currentField.type,
                        options: currentField.options
                    });
                });

                _bgeBatchController.saveRecord(batchDetailsData, activeFields, {
                    success: function(response) {
                        _batchMetadata.navigateToRecord(response.id);
                    },
                    error: function(error) {
                        console.log(error);
                        _batchMetadata.togglePendingSave();
                    }
                });
            }

            /**
             * @description Sets the Apex backend controller module.
             * @return void.
             */
            function setBackendController(bgeBatchController) {
                _bgeBatchController = bgeBatchController
            }

            /**
             * @description Gets the Batch Fields module.
             * @return Batch Fields module.
             */
            function getAvailableFields() {
                return _availableFields;
            }

            /**
             * @description Gets the Batch Info module.
             * @return Batch Info module.
             */
            function getBatchInfo() {
                return _batchInfo;
            }

            /**
             * @description Gets the Batch Metadata module.
             * @return Batch Metadata module.
             */
            function getBatchMetadata() {
                return _batchMetadata;
            }

            // DetailsModel module public functions and properties
            return {
                init: init,
                save: save,
                setBackendController: setBackendController,
                getAvailableFields: getAvailableFields,
                getBatchInfo: getBatchInfo,
                getBatchMetadata: getBatchMetadata
            }
        })(this.BatchFields(), this.BatchInfo(), this.BatchMetadata());
    },

    /**
     * @description Gets the Model module of the Batch Info.
     * @return Model module of the Batch Info.
     */
    BatchInfo : function() {
        return (function (Event) {
            var _onInfoUpdated = new Event(this);

            /**
             * @description Loads the Info, and notify all the
             * _onInfoUpdated listeners.
             * @return List of fields.
             */
            function load(info) {
                //record info
                this.name = info.name;
                this.description = info.description;
                this.id = info.id;
                this.expectedCount = (info.expectedCount === null || info.expectedCount === '') ? 0 : info.expectedCount;
                this.expectedTotal = (info.expectedTotal === null || info.expectedTotal === '') ? 0 : info.expectedTotal;
                this.recordCount = info.recordCount;

                //batch processing settings
                this.requireTotalMatch = info.requireTotalMatch;
                this.batchProcessSize = info.batchProcessSize;
                this.runOpportunityRollupsWhileProcessing = info.runOpportunityRollupsWhileProcessing;
                this.donationMatchingBehavior = info.donationMatchingBehavior;
                this.donationMatchingClass = info.donationMatchingClass;
                this.donationMatchingOptions = info.donationMatchingOptions;
                this.donationMatchingRule = info.donationMatchingRule;
                this.donationDateRange = info.donationDateRange;
                this.postProcessClass = info.postProcessClass;
                this.processUsingScheduledJob = info.processUsingScheduledJob;
                this.noMatchOnDate = info.donationMatchingRule.indexOf("donation_date__c") < 0;
                this.onInfoUpdated.notify();
            }

            /**
             * @description Validates the required batchInfo.
             * @return Boolean validity.
             */
            function isValid() {
                return this.name && this.description
            }

            // BatchInfo module public functions and properties
            return {
                // record info
                name: '',
                id: '',
                description: '',
                expectedCount: 0,
                expectedTotal: 0,
                recordCount: 0,

                // batch processing settings
                requireTotalMatch: false,
                batchProcessSize: 0,
                runOpportunityRollupsWhileProcessing: false,
                donationMatchingBehavior: '',
                donationMatchingClass: '',
                donationMatchingOptions: [],
                donationMatchingRule: [],
                donationDateRange: '',
                postProcessClass: '',
                processUsingScheduledJob: false,
                load: load,
                isValid: isValid,
                noMatchOnDate: false,
                onInfoUpdated: _onInfoUpdated
            }
        })(this.Event());
    },

    /**
     * @description Gets the Batch Fields module.
     * @return Model module of the Batch Fields.
     */
    BatchFields : function() {
        return (function (Event) {
            var _allFields = [];
            var _onFieldsUpdated = new Event(this);

            /* ******************PUBLIC FUNCTIONS*************************/

            /**
             * @description Load the fields and notify onFieldsUpdated listeners.<commit_msg>remove stale reference to scehduled job<commit_after>({
    /********************************************* View Modules *********************************************/

    /**
     * @description Returns the Batch Info View module.
     * @param component. Lightning Component reference.
     * @param model. The Model.
     * @return View of the Batch Info module.
     */
    BatchInfoView : function(component, model) {
        return (function (component, model) {

            // Subscribe to the model onInfoUpdated event.
            model.getBatchInfo().onInfoUpdated.subscribe(function() {
                var batchInfoView = component.get('v.batchInfo');
                var batchInfo = model.getBatchInfo();

                // record info
                batchInfoView.name = batchInfo.name;
                batchInfoView.id = batchInfo.id;
                batchInfoView.description = batchInfo.description;
                batchInfoView.expectedCount = batchInfo.expectedCount;
                batchInfoView.expectedTotal = batchInfo.expectedTotal;
                batchInfoView.recordCount = batchInfo.recordCount;

                // batch processing settings
                batchInfoView.requireTotalMatch = batchInfo.requireTotalMatch;
                batchInfoView.batchProcessSize = batchInfo.batchProcessSize;
                batchInfoView.runOpportunityRollupsWhileProcessing = batchInfo.runOpportunityRollupsWhileProcessing;
                batchInfoView.donationMatchingBehavior = batchInfo.donationMatchingBehavior;
                batchInfoView.donationMatchingClass = batchInfo.donationMatchingClass;
                batchInfoView.donationMatchingOptions = batchInfo.donationMatchingOptions;
                batchInfoView.donationMatchingRule = batchInfo.donationMatchingRule;
                batchInfoView.donationDateRange = batchInfo.donationDateRange;
                batchInfoView.noMatchOnDate = batchInfo.noMatchOnDate;
                batchInfoView.postProcessClass = batchInfo.postProcessClass;

                component.set('v.batchInfo', batchInfoView);
            });

            // BatchInfoView module public functions and properties
            return {
                name: '',
                id: '',
                description: '',
                expectedCount: 0,
                expectedTotal: 0,
                recordCount: 0,

                // batch processing settings
                requireTotalMatch: false,
                batchProcessSize: 0,
                runOpportunityRollupsWhileProcessing: false,
                donationMatchingBehavior: '',
                donationMatchingClass: '',
                donationMatchingOptions: [],
                donationMatchingRule: [],
                donationDateRange: '',
                noMatchOnDate: false,
                postProcessClass: ''
            };
        })(component, model);
    },

    /**
     * @description Returns the Batch Metadata View module.
     * @param component. Lightning Component reference.
     * @param model. The Model.
     * @return View of the Batch Metadata module.
     */
    BatchMetadataView : function(component, model) {
        return (function (component, model) {

            // Subscribe to the model onMetadataUpdated event.
            model.getBatchMetadata().onMetadataUpdated.subscribe(function() {
                var batchMetadataView = component.get('v.batchMetadata');
                var batchMetadata = model.getBatchMetadata();
                var headerChanged = Boolean(batchMetadataView.pageHeader !== batchMetadata.pageHeader);

                batchMetadataView.labels = batchMetadata.labels;
                batchMetadataView.mode = batchMetadata.mode;
                batchMetadataView.hasError = batchMetadata.hasError;
                batchMetadataView.errorMessage = batchMetadata.errorMessage;
                batchMetadataView.pageHeader = batchMetadata.pageHeader;
                batchMetadataView.pendingSave = batchMetadata.pendingSave;
                batchMetadataView.showAdvancedOptions = batchMetadata.showAdvancedOptions;

                if (!batchMetadataView.hasError) {
                    batchMetadataView.progressIndicatorStep = batchMetadata.progressIndicatorStep;
                    _sendMessage('setStep',batchMetadata.progressIndicatorStep);
                } else {
                    component.find('notifLib').showNotice({
                        'variant': 'error',
                        'header': $A.get('$Label.c.PageMessagesError'),
                        'message': batchMetadataView.errorMessage,
                        closeCallback: function() {
                            //callback action here
                        }
                    });
                }

                if (batchMetadataView.mode === 'view') {
                    component.set('v.isReadOnly', true);
                } else if (batchMetadataView.mode === 'create' || batchMetadataView.mode === 'edit') {
                    component.set('v.isReadOnly', false);
                }

                //update page header in modal if page header has changed and modal is used
                if (headerChanged) {
                    _sendMessage('setHeader', batchMetadataView.pageHeader);
                }

                //update footer in modal to keep save button appropriately enabled/disabled
                _sendMessage('pendingSave', batchMetadataView.pendingSave);

                // when in modal context, need to notify the modal footer component
                _sendMessage('setError', batchMetadataView.hasError);

                component.set('v.batchMetadata', batchMetadataView);
            });

            function _sendMessage(channel, message) {
                var sendMessage = $A.get('e.ltng:sendMessage');
                sendMessage.setParams({
                    'channel': channel,
                    'message': message
                });
                sendMessage.fire();
            }

            // BatchMetadataView module public functions and properties
            return {
                labels: {},
                mode: '',
                progressIndicatorStep: '',
                hasError: false,
                errorMessage: '',
                pendingSave: false,
                showAdvancedOptions: false
            };
        })(component, model);
    },

    /**
     * @description Returns the Batch Fields View module.
     * @param component. Lightning Component reference.
     * @param model. The Batch Fields Model.
     * @return View of the Batch Fields module.
     */
    BatchFieldsView : function(component, model) {
        return (function (component, model) {

            // Subscribe to the model onFieldsUpdated event.
            model.getAvailableFields().onFieldsUpdated.subscribe(function() {
                var availableFields = component.get('v.availableFields');
                availableFields.fieldGroups = [];

                var activeFieldsBySObject = model.getAvailableFields().getActivesBySObject();
                var allFieldsBySObject = model.getAvailableFields().getAllFieldsBySObject();

                Object.keys(allFieldsBySObject).forEach(function(sObjectName) {
                    var currentFieldGroup = {
                        sObjectName : sObjectName,
                        options: [],
                        requiredOptions: [],
                        values: []
                    };

                    allFieldsBySObject[sObjectName].forEach(function(currentField) {
                        currentFieldGroup.options.push(
                            {
                                label: currentField.label,
                                value: currentField.id
                            }
                        );
                        //special case so Amount object is always visible
                        if (currentField.id.includes('Donation_Amount__c')) {
                            currentFieldGroup.requiredOptions.push(currentField.id);
                        }
                    });

                    if (activeFieldsBySObject[sObjectName]) {
                        activeFieldsBySObject[sObjectName].forEach(function(currentField) {
                            currentFieldGroup.values.push(currentField.id);
                        });
                    }
                    availableFields.fieldGroups.push(currentFieldGroup);
                });

                component.set('v.availableFields', availableFields);
            });

            // BatchFieldsView module public functions and properties
            return {
                fieldGroups: []
            };
        })(component, model);
    },

    /**
     * @description Returns the Batch Field Options View module.
     * @param component. Lightning Component reference.
     * @param model. The Batch Fields Model.
     * @return View of the Batch Field Options module.
     */
    BatchFieldOptionsView : function(component, model) {
        return (function (component, model) {

            // Subscribe to the model onFieldsUpdated event.
            model.getAvailableFields().onFieldsUpdated.subscribe(function() {
                var batchFieldOptions = component.get('v.batchFieldOptions');
                batchFieldOptions.fieldGroups = [];
                var activeFieldsBySObject = model.getAvailableFields().getActivesBySObject();
                var availableFields = model.getAvailableFields();
                batchFieldOptions.errors = availableFields.errors;

                Object.keys(activeFieldsBySObject).forEach(function (sObjectName) {

                    var currentFieldGroup = {
                        sObjectName : sObjectName,
                        fields: []
                    };

                    activeFieldsBySObject[sObjectName].forEach(function (currentField) {

                        var fieldInfo = {
                            name: currentField.name,
                            sObjectName: currentField.sObjectName,
                            label: currentField.label,
                            defaultValue: currentField.defaultValue,
                            required: currentField.required,
                            hide: currentField.hide,
                            type: currentField.type,
                            formatter: currentField.formatter,
                            options: currentField.options
                        }

                        if (currentField.sObjectName === 'Opportunity' &&
                            (currentField.name == 'npsp__Donation_Amount__c' || currentField.name == 'Donation_Amount__c')) {
                            fieldInfo.systemRequired = true;
                        }

                        currentFieldGroup.fields.push(fieldInfo);

                    });

                    batchFieldOptions.fieldGroups.push(currentFieldGroup);

                });
                component.set('v.batchFieldOptions', batchFieldOptions);

            });

            // BatchFieldOptionsView module public functions and properties
            return {
                fieldGroups: []
            };

        })(component, model);
    },


    /*********************************************** Model Modules *********************************************/

    /**
     * @description Gets the Model module of Batch Details.
     * This is the main and only Model module for the Batch
     * Details components. Contains references to BatchFields
     * and BatchInfo sub-modules.
     * @return Model module of Batch Details.
     */
    DetailsModel : function() {
        return (function (availableFields, batchInfo, batchMetadata) {
            var _availableFields = availableFields;
            var _batchInfo = batchInfo;
            var _batchMetadata = batchMetadata;
            var _bgeBatchController;

            /* **********************************************************
             * @Description Gets the Batch Details and loads sub-modules.
             * @param component. Lightning Component reference.
             * @return void.
             ************************************************************/
            function init(component) {
                var recordId = _batchInfo.id ? _batchInfo.id : component.get('v.recordId');
                _bgeBatchController.getRecordDetails(recordId, {
                    success: function(response) {
                        _batchInfo.load(response);
                        _availableFields.load(response.availableFields, JSON.parse(response.activeFields));
                        _batchMetadata.load(response.labels, component);
                    },
                    error: function(error) {
                        _batchMetadatas.showError(error);
                        console.log(error);
                    }
                });
            }

            /**
             * @description Saves the model information to the backend.
             * @return void.
             */
            function save() {
                var batchDetailsData = {
                    //record info
                    name: _batchInfo.name,
                    id: _batchInfo.id,
                    description: _batchInfo.description,
                    expectedCount: _batchInfo.expectedCount,
                    expectedTotal: _batchInfo.expectedTotal,

                    // batch processing settings
                    requireTotalMatch: _batchInfo.requireTotalMatch,
                    batchProcessSize: _batchInfo.batchProcessSize,
                    runOpportunityRollupsWhileProcessing: _batchInfo.runOpportunityRollupsWhileProcessing,
                    donationMatchingBehavior: _batchInfo.donationMatchingBehavior,
                    donationMatchingClass: _batchInfo.donationMatchingClass,
                    donationMatchingRule: _batchInfo.donationMatchingRule,
                    donationDateRange: _batchInfo.donationDateRange,
                    postProcessClass: _batchInfo.postProcessClass
                };
                var activeFields = [];

                _availableFields.getActives().forEach(function(currentField) {
                    activeFields.push({
                        label: currentField.label,
                        name: currentField.name,
                        sObjectName: currentField.sObjectName,
                        defaultValue: currentField.defaultValue,
                        required: currentField.required,
                        hide: currentField.hide,
                        sortOrder: currentField.sortOrder,
                        type: currentField.type,
                        options: currentField.options
                    });
                });

                _bgeBatchController.saveRecord(batchDetailsData, activeFields, {
                    success: function(response) {
                        _batchMetadata.navigateToRecord(response.id);
                    },
                    error: function(error) {
                        console.log(error);
                        _batchMetadata.togglePendingSave();
                    }
                });
            }

            /**
             * @description Sets the Apex backend controller module.
             * @return void.
             */
            function setBackendController(bgeBatchController) {
                _bgeBatchController = bgeBatchController
            }

            /**
             * @description Gets the Batch Fields module.
             * @return Batch Fields module.
             */
            function getAvailableFields() {
                return _availableFields;
            }

            /**
             * @description Gets the Batch Info module.
             * @return Batch Info module.
             */
            function getBatchInfo() {
                return _batchInfo;
            }

            /**
             * @description Gets the Batch Metadata module.
             * @return Batch Metadata module.
             */
            function getBatchMetadata() {
                return _batchMetadata;
            }

            // DetailsModel module public functions and properties
            return {
                init: init,
                save: save,
                setBackendController: setBackendController,
                getAvailableFields: getAvailableFields,
                getBatchInfo: getBatchInfo,
                getBatchMetadata: getBatchMetadata
            }
        })(this.BatchFields(), this.BatchInfo(), this.BatchMetadata());
    },

    /**
     * @description Gets the Model module of the Batch Info.
     * @return Model module of the Batch Info.
     */
    BatchInfo : function() {
        return (function (Event) {
            var _onInfoUpdated = new Event(this);

            /**
             * @description Loads the Info, and notify all the
             * _onInfoUpdated listeners.
             * @return List of fields.
             */
            function load(info) {
                //record info
                this.name = info.name;
                this.description = info.description;
                this.id = info.id;
                this.expectedCount = (info.expectedCount === null || info.expectedCount === '') ? 0 : info.expectedCount;
                this.expectedTotal = (info.expectedTotal === null || info.expectedTotal === '') ? 0 : info.expectedTotal;
                this.recordCount = info.recordCount;

                //batch processing settings
                this.requireTotalMatch = info.requireTotalMatch;
                this.batchProcessSize = info.batchProcessSize;
                this.runOpportunityRollupsWhileProcessing = info.runOpportunityRollupsWhileProcessing;
                this.donationMatchingBehavior = info.donationMatchingBehavior;
                this.donationMatchingClass = info.donationMatchingClass;
                this.donationMatchingOptions = info.donationMatchingOptions;
                this.donationMatchingRule = info.donationMatchingRule;
                this.donationDateRange = info.donationDateRange;
                this.postProcessClass = info.postProcessClass;
                this.noMatchOnDate = info.donationMatchingRule.indexOf("donation_date__c") < 0;
                this.onInfoUpdated.notify();
            }

            /**
             * @description Validates the required batchInfo.
             * @return Boolean validity.
             */
            function isValid() {
                return this.name && this.description
            }

            // BatchInfo module public functions and properties
            return {
                // record info
                name: '',
                id: '',
                description: '',
                expectedCount: 0,
                expectedTotal: 0,
                recordCount: 0,

                // batch processing settings
                requireTotalMatch: false,
                batchProcessSize: 0,
                runOpportunityRollupsWhileProcessing: false,
                donationMatchingBehavior: '',
                donationMatchingClass: '',
                donationMatchingOptions: [],
                donationMatchingRule: [],
                donationDateRange: '',
                postProcessClass: '',
                load: load,
                isValid: isValid,
                noMatchOnDate: false,
                onInfoUpdated: _onInfoUpdated
            }
        })(this.Event());
    },

    /**
     * @description Gets the Batch Fields module.
     * @return Model module of the Batch Fields.
     */
    BatchFields : function() {
        return (function (Event) {
            var _allFields = [];
            var _onFieldsUpdated = new Event(this);

            /* ******************PUBLIC FUNCTIONS*************************/

            /**
             * @description Load the fields and notify onFieldsUpdated listeners.
{'fraction_non_alphanumeric': 0.09303250173938972, 'fraction_numerical': 0.0005466653414173541, 'mean_word_length': 1.5129566031845145, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '937639', 'n_tokens_mistral': 9090, 'n_tokens_neox': 8375, 'n_words': 1812}