1
0
Fork 0
liza/src/server/rater/DslRaterContext.js

362 lines
8.6 KiB
JavaScript

/**
* Provides context-specific data to the DslRater
*
* Copyright (C) 2010-2019 R-T Specialty, LLC.
*
* This file is part of the Liza Data Collection Framework.
*
* liza is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var Class = require( 'easejs' ).Class,
EventEmitter = require( '../../events' ).EventEmitter,
Quote = require( '../../quote/Quote' );
module.exports = Class( 'DslRaterContext' )
.extend( EventEmitter,
{
/**
* TODO: Remove workaround for bug extending class across
* multiple easejs instances
*/
'public _events': {},
/**
* Hash of classes that will result in a global submit
* @type {Object}
*/
'private _global_submits': {},
/**
* Whether a particular global submit has been triggered
* @type {Object}
*/
'private _has_g_submit': {},
/**
* Rater corestrictions
* @type {Object}
*/
'private _restrict': {},
/**
* Quote data with which to rate
* @type {Object}
*/
'private _data': null,
/**
* Whether to immediately terminate on assertion failure
* @type {boolean}
*/
'private _can_term': true,
/**
* Result sets
* @type {Object}
*/
'private _results': [],
/**
* Number of available results
* @type {number}
*/
'private _avail_count': 0,
/**
* Total number of results
* @type {number}
*/
'private _total_count': 0,
__construct: function( data, can_term )
{
this._data = data;
this._can_term = ( can_term == undefined ) ? true : !!can_term;
this.init();
},
/** XXX: return to protected (see commit message) **/
'public getSourceData': function()
{
return this._data;
},
'public canTerm': function()
{
return this._can_term;
},
'virtual protected init': function()
{
// may be implemented by subtypes
},
'virtual public rate': function( name, meta, rate, complete )
{
rate( this._data );
},
'virtual public processResult': function( result, meta, context )
{
return result;
},
/**
* Add a completed ResultSet
*
* @param {string} name supplier/rater name
* @param {ResultSet} set completed rating result set
*
* @return {DslRaterContext} self
*/
'public addResultSet': function( name, set )
{
this._total_count += set.getResultCount();
this._avail_count += set.getAvailableCount();
this._checkGlobalSubmits( set );
this._results.push( set );
return this;
},
/**
* Checks each result in a set to determine if a global submit is to be
* triggered
*
* @param {ResultSet} set result set to scan
*
* @return {undefined}
*/
'private _checkGlobalSubmits': function( set )
{
var _self = this;
set.forEachResult( function( result, rcontext )
{
if ( !result.__classes )
{
return;
}
for ( var cname in _self._global_submits )
{
if ( result.__classes[ cname ] )
{
_self._has_g_submit[ cname ] = true;
}
}
} );
},
'public setGlobalSubmits': function( submits )
{
var i = submits.length;
while ( i-- )
{
this._global_submits[ submits[ i ] ] = true;
}
return this;
},
'public restrictSupplier': function( id, restricts )
{
this._restrict[ id ] = restricts;
return this;
},
'virtual public canSubmit': function( result, rcontext )
{
return true;
},
'public complete': function()
{
// allow context some time to manipulate the results mercilessly
this._avail_count = this.processCompleted(
this._results, this._avail_count
);
this._processGlobalSubmits();
this._emitResults();
},
/**
* Process result sets after rating is complete
*
* This is called before post-processing, which flattens into the final
* result; therefore, the ResultSet objects themselves can still be
* manipulated.
*
* If the availablity count is unchanged, COUNT should be returned.
*
* @param {Array.<ResultSet>} results result sets
* @param {number} count availaabilty count
*
* @return {number} availability count after processing
*/
'virtual protected processCompleted': function( results, count )
{
return this._processCorestrictions( results, count );
},
/**
* FIXME: I need to be cleaned up
*/
'private _processCorestrictions': function( results, count )
{
var _self = this;
if ( this._restrict.length === 0 )
{
return {};
}
// index results by id
var id_results = results.reduce( function( byid, result_set )
{
byid[ result_set.getId() ] = result_set;
return byid;
}, {} );
var rnames = Object.keys( this._restrict );
return rnames.reduce( function( count, name )
{
var result_set = id_results[ name ];
if ( !( result_set && result_set.getAvailableCount() > 0 ) )
{
return count;
}
// array of suppliers that we cannot be displayed with
var chk = _self._restrict[ name ];
for ( var chk_i in chk )
{
var chkname = chk[ chk_i ];
var chk_results;
if ( ( chk_results = id_results[ chk ] )
&& ( chk_results.getAvailableCount() > 0 )
)
{
var n = chk_results.getResultCount();
chk_results.forEachResult( function( result )
{
if ( +result._unavailable )
{
return;
}
result._unavailable = '1';
result.ineligible = 'Cannot display with ' +
'carrier ' + name;
count--;
} );
return count;
}
}
return count;
}, count );
},
/**
* Apply global submits to result sets
*
* If global submits have been found, they will be applied to each result
* individually, resulting in submits across the board.
*
* @return {undefined}
*/
'private _processGlobalSubmits': function()
{
for ( var cname in this._has_g_submit )
{
this._results.forEach( function( set )
{
set.forEachResult( function( result )
{
// TODO: class desc
result.submit += ( ( result.submit ) ? '; ' : '' ) +
cname;
result._unavailable = '1';
this._avail_count--;
} );
} );
}
},
'private _emitResults': function()
{
this.emit( 'complete',
this.postProcessResults( this._results )
);
},
'virtual public postProcessResults': function( results )
{
var ret = {};
results.forEach( function( set )
{
var id = set.getId(),
merged = set.getMergedResults();
// prefix each field with the result set id (TODO: this should
// really be part of a decorator, not this class)
for ( var field in merged )
{
if ( !field )
{
continue;
}
ret[ id + '_' + field ] = merged[ field ];
}
} );
ret.__prem_avail_count = [ this._avail_count ];
return ret;
}
} );