Save rating data to another database field
This maintains the old behavior while also writing rating result to another field in the database.master
commit
d2f9f5f18f
|
@ -341,14 +341,17 @@ If this is a concern,
|
||||||
in conjunction with ease.js'
|
in conjunction with ease.js'
|
||||||
@url{https://www.gnu.org/software/easejs/manual/easejs.html#Type-Checks-and-Polymorphism,@samp{Class.isA}}.
|
@url{https://www.gnu.org/software/easejs/manual/easejs.html#Type-Checks-and-Polymorphism,@samp{Class.isA}}.
|
||||||
|
|
||||||
Interfaces do not exist at runtime in TypeScript,
|
Often times you will need to reference a class or interface as a
|
||||||
but they do in easejs.
|
dependency before it has been migrated away from ease.js.
|
||||||
Consequently,
|
|
||||||
you can continue to export an ease.js interface while also exporting
|
|
||||||
a TypeScript interface.
|
|
||||||
To do this,
|
To do this,
|
||||||
continue to export using @samp{module.exports} rather than
|
create a corresponding @code{.d.ts} file in the same directory
|
||||||
TypeScript's @samp{export =}.
|
as the dependency.
|
||||||
|
For example,
|
||||||
|
if a class @code{Foo} is contained in @file{Foo.js},
|
||||||
|
create a sibling @file{Foo.d.ts} file.
|
||||||
|
For more information,
|
||||||
|
see @url{https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html,Declaration Files}
|
||||||
|
in the TypeScript handbook.
|
||||||
|
|
||||||
ease.js implements stackable Scala-like traits.
|
ease.js implements stackable Scala-like traits.
|
||||||
Traits are @emph{not} provided by TypeScript.
|
Traits are @emph{not} provided by TypeScript.
|
||||||
|
@ -446,7 +449,7 @@ This can be done using
|
||||||
@verbatim
|
@verbatim
|
||||||
type PositiveInteger = NominalType<number, 'PositiveInteger'>;
|
type PositiveInteger = NominalType<number, 'PositiveInteger'>;
|
||||||
|
|
||||||
const isPositiveInteger = ( x: number ): n is PositiveInteger => n > 0;
|
const isPositiveInteger = ( n: number ): n is PositiveInteger => n > 0;
|
||||||
|
|
||||||
const lookupIndex<T>( arr: T[], i: PositiveInteger ): T => arr[ i ];
|
const lookupIndex<T>( arr: T[], i: PositiveInteger ): T => arr[ i ];
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/**
|
||||||
|
* Representation of actions to be performed by the client
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action to be performed by the client
|
||||||
|
*
|
||||||
|
* TODO: More specific types
|
||||||
|
*/
|
||||||
|
export interface ClientAction
|
||||||
|
{
|
||||||
|
/** Action to be performed */
|
||||||
|
action: string;
|
||||||
|
|
||||||
|
/** Action arguments */
|
||||||
|
[P: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Set of actions */
|
||||||
|
export type ClientActions = ClientAction[];
|
|
@ -0,0 +1,43 @@
|
||||||
|
/**
|
||||||
|
* Numeric types
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
* TypeScript's type system does not support algebraic numeric domains. A
|
||||||
|
* compromise is to provide nominal types that allow developers to assume
|
||||||
|
* that some constraint has been met, and then ensure that the type is only
|
||||||
|
* ever asserted when that constraint is explicitly validated at
|
||||||
|
* runtime. This allows us to have compile-time checks on numeric values
|
||||||
|
* under the assumption that the runtime will enforce them.
|
||||||
|
*
|
||||||
|
* For this to work, _it is important to always use type predicates_;
|
||||||
|
* if you explicit cast to one of these numeric types, it circumvents the
|
||||||
|
* safety provided by the system and may introduce nasty bugs, since users
|
||||||
|
* of these types assume the provided data has already been validated.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any number ≥ 0
|
||||||
|
*
|
||||||
|
* This is useful for array indexing.
|
||||||
|
*/
|
||||||
|
export type PositiveInteger = NominalType<number, 'PositiveInteger'>;
|
||||||
|
|
||||||
|
|
||||||
|
/** Whether the given number is suitable as a PositiveInteger */
|
||||||
|
export const isPositiveInteger = ( n: number ): n is PositiveInteger => n >= 0;
|
|
@ -0,0 +1,27 @@
|
||||||
|
/**
|
||||||
|
* Contains Program base class
|
||||||
|
*
|
||||||
|
* 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 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 General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export declare abstract class Program
|
||||||
|
{
|
||||||
|
readonly ineligibleLockCount: number;
|
||||||
|
|
||||||
|
getId(): string;
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
/**
|
||||||
|
* Contains program Quote class
|
||||||
|
*
|
||||||
|
* 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 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 General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @todo Use ``document'' terminology in place of ``quote''
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Program } from "../program/Program";
|
||||||
|
import { Quote, QuoteId } from "./Quote";
|
||||||
|
|
||||||
|
|
||||||
|
export declare class BaseQuote implements Quote
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Retrieve Program associated with quote
|
||||||
|
*
|
||||||
|
* @return quote program
|
||||||
|
*/
|
||||||
|
getProgram(): Program;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the program id associated with the quote
|
||||||
|
*
|
||||||
|
* @return program id
|
||||||
|
*/
|
||||||
|
getProgramId(): string;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the quote id
|
||||||
|
*
|
||||||
|
* The quote id is immutable. A different quote id would represent a
|
||||||
|
* different quote, therefore a new object should be created with the
|
||||||
|
* desired quote id.
|
||||||
|
*
|
||||||
|
* @return quote id
|
||||||
|
*/
|
||||||
|
getId(): QuoteId;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the id of the current step
|
||||||
|
*
|
||||||
|
* @return id of current step
|
||||||
|
*/
|
||||||
|
getCurrentStepId(): number;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets an explicit lock, providing a reason for doing so
|
||||||
|
*
|
||||||
|
* @param reason - lock reason
|
||||||
|
* @param step - step that user may not navigate prior
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
setExplicitLock( reason: string, step: number ): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the date that the premium was calculated as a Unix timestamp
|
||||||
|
*
|
||||||
|
* @param timestamp - Unix timestamp representing premium date
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
setLastPremiumDate( timestamp: UnixTimestamp ): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the last time the premium was calculated
|
||||||
|
*
|
||||||
|
* @return last calculated time or 0
|
||||||
|
*/
|
||||||
|
getLastPremiumDate(): UnixTimestamp;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
* Generic interface to represent quotes
|
||||||
|
*
|
||||||
|
* 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 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 General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @todo Use ``document'' terminology in place of ``quote''
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Program } from "../program/Program";
|
||||||
|
import { QuoteId } from "../document/Document";
|
||||||
|
|
||||||
|
|
||||||
|
export declare interface Quote
|
||||||
|
{
|
||||||
|
// TODO: the easejs interface is empty; is this actually needed?
|
||||||
|
}
|
||||||
|
|
||||||
|
export { QuoteId };
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* General server actions
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ClientActions } from "../client/action/ClientAction";
|
||||||
|
import { ServerSideQuote } from "./quote/ServerSideQuote";
|
||||||
|
import { UserRequest } from "./request/UserRequest";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* General server actions
|
||||||
|
*/
|
||||||
|
export declare class Server
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Send response to user
|
||||||
|
*
|
||||||
|
* @param request - request to respond to
|
||||||
|
* @param quote - quote associated with request
|
||||||
|
* @param data - data with which to reply
|
||||||
|
* @param actions - optional client actions
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
sendResponse(
|
||||||
|
request: UserRequest,
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
data: Record<string, any>,
|
||||||
|
actions?: ClientActions,
|
||||||
|
): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send response to user
|
||||||
|
*
|
||||||
|
* @param request - request to respond to
|
||||||
|
* @param message - message to display to user
|
||||||
|
* @param actions - optional client actions
|
||||||
|
* @param btn_caption - optional caption for acknowledgement button
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
sendError(
|
||||||
|
request: UserRequest,
|
||||||
|
message: string,
|
||||||
|
actions?: ClientActions,
|
||||||
|
btn_caption?: string,
|
||||||
|
): this;
|
||||||
|
}
|
|
@ -28,6 +28,8 @@ const {
|
||||||
ReplSetServers: ReplSetServers,
|
ReplSetServers: ReplSetServers,
|
||||||
} = require( 'mongodb/lib/mongodb' );
|
} = require( 'mongodb/lib/mongodb' );
|
||||||
|
|
||||||
|
const easejs = require( 'easejs' );
|
||||||
|
|
||||||
const regex_base = /^\/quote\/([a-z0-9-]+)\/?(?:\/(\d+)\/?(?:\/(.*))?|\/(program.js))?$/;
|
const regex_base = /^\/quote\/([a-z0-9-]+)\/?(?:\/(\d+)\/?(?:\/(.*))?|\/(program.js))?$/;
|
||||||
const regex_step = /^step\/(\d+)\/?(?:\/(post|visit))?$/;
|
const regex_step = /^step\/(\d+)\/?(?:\/(post|visit))?$/;
|
||||||
|
|
||||||
|
@ -83,9 +85,8 @@ const {
|
||||||
ExportService,
|
ExportService,
|
||||||
},
|
},
|
||||||
|
|
||||||
RatingService,
|
RatingService: { RatingService },
|
||||||
RatingServicePublish,
|
RatingServicePublish,
|
||||||
RatingServiceSubmitNotify,
|
|
||||||
TokenedService,
|
TokenedService,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -137,7 +138,7 @@ exports.init = function( logger, enc_service, conf )
|
||||||
server.init( server_cache, exports.rater );
|
server.init( server_cache, exports.rater );
|
||||||
|
|
||||||
// TODO: temporary proof-of-concept
|
// TODO: temporary proof-of-concept
|
||||||
rating_service = RatingService.use(
|
rating_service = easejs( RatingService ).use(
|
||||||
RatingServicePublish( amqplib, exports.post_rate_publish, logger )
|
RatingServicePublish( amqplib, exports.post_rate_publish, logger )
|
||||||
)(
|
)(
|
||||||
logger, dao, server, exports.rater
|
logger, dao, server, exports.rater
|
||||||
|
@ -535,11 +536,9 @@ function doRoute( program, request, data, resolve, reject )
|
||||||
{
|
{
|
||||||
var response = UserResponse( request );
|
var response = UserResponse( request );
|
||||||
|
|
||||||
rating_service.request( request, response, quote, alias, function()
|
rating_service.request( request, response, quote, alias )
|
||||||
{
|
.catch( () => {} )
|
||||||
// we're done; free the lock
|
.then( () => free() );
|
||||||
free();
|
|
||||||
} );
|
|
||||||
} );
|
} );
|
||||||
}, true );
|
}, true );
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
/**
|
||||||
|
* Mongo DB DAO for program server
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ServerDao, Callback } from "./ServerDao";
|
||||||
|
|
||||||
|
import { ClassificationData, WorksheetData } from "../rater/Rater";
|
||||||
|
import { PositiveInteger } from "../../numeric";
|
||||||
|
import { QuoteId } from "../../document/Document";
|
||||||
|
import { ServerSideQuote } from "../quote/ServerSideQuote";
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MongoDB-backed data store
|
||||||
|
*/
|
||||||
|
export declare class MongoServerDao implements ServerDao
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Saves a quote to the database
|
||||||
|
*
|
||||||
|
* A full save will include all metadata.
|
||||||
|
*
|
||||||
|
* @param quote - the quote to save
|
||||||
|
* @param success - function to call on success
|
||||||
|
* @param failure - function to call if save fails
|
||||||
|
* @param save_data - quote data to save (optional)
|
||||||
|
*/
|
||||||
|
saveQuote(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
success: Callback,
|
||||||
|
failure: Callback,
|
||||||
|
save_data: Record<string, any>,
|
||||||
|
): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges bucket data with the existing bucket (rather than overwriting the
|
||||||
|
* entire bucket)
|
||||||
|
*
|
||||||
|
* @param quote - quote to save
|
||||||
|
* @param data - bucket data
|
||||||
|
* @param success - successful callback
|
||||||
|
* @param failure - failure callback
|
||||||
|
*/
|
||||||
|
mergeBucket(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
data: Record<string, any>,
|
||||||
|
success: Callback,
|
||||||
|
failure: Callback,
|
||||||
|
): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save quote classification data
|
||||||
|
*
|
||||||
|
* @param quote - quote to save
|
||||||
|
* @param classes - classification data
|
||||||
|
* @param success - successful callback
|
||||||
|
* @param failure - failure callback
|
||||||
|
*/
|
||||||
|
saveQuoteClasses(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
classes: ClassificationData,
|
||||||
|
success: Callback,
|
||||||
|
failure: Callback,
|
||||||
|
): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the quote state to the database
|
||||||
|
*
|
||||||
|
* The quote state includes the current step, the top visited step and the
|
||||||
|
* explicit lock message.
|
||||||
|
*
|
||||||
|
* @param quote - the quote to save
|
||||||
|
* @param success - function to call on success
|
||||||
|
* @param failure - function to call if save fails
|
||||||
|
*/
|
||||||
|
saveQuoteState(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
success: Callback,
|
||||||
|
failure: Callback,
|
||||||
|
): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the quote lock state to the database
|
||||||
|
*
|
||||||
|
* @param quote - the quote to save
|
||||||
|
* @param success - function to call on success
|
||||||
|
* @param failure - function to call if save fails
|
||||||
|
*/
|
||||||
|
saveQuoteLockState(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
success: Callback,
|
||||||
|
failure: Callback,
|
||||||
|
): this
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save worksheet data
|
||||||
|
*
|
||||||
|
* @param qid - quote identifier
|
||||||
|
* @param data - worksheet data
|
||||||
|
* @param callback - callback
|
||||||
|
*/
|
||||||
|
setWorksheets(
|
||||||
|
qid: QuoteId,
|
||||||
|
data: WorksheetData,
|
||||||
|
callback: NodeCallback<void>,
|
||||||
|
): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve worksheet data
|
||||||
|
*
|
||||||
|
* @param qid - quote identifier
|
||||||
|
* @param supplier - supplier id
|
||||||
|
* @param index - worksheet index
|
||||||
|
* @param callback - callback
|
||||||
|
*/
|
||||||
|
getWorksheet(
|
||||||
|
qid: QuoteId,
|
||||||
|
supplier: string,
|
||||||
|
index: PositiveInteger,
|
||||||
|
callback: ( data: WorksheetData | null ) => void,
|
||||||
|
): this;
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
/**
|
||||||
|
* General server database operations
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*
|
||||||
|
* This interface was created to satisfy MongoServerDao and may not be
|
||||||
|
* sufficiently general for other database abstractions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ClassificationData, WorksheetData } from "../rater/Rater";
|
||||||
|
import { PositiveInteger } from "../../numeric";
|
||||||
|
import { QuoteId } from "../../document/Document";
|
||||||
|
import { ServerSideQuote } from "../quote/ServerSideQuote";
|
||||||
|
|
||||||
|
/** Success or failure callback */
|
||||||
|
export type Callback = ( quote: ServerSideQuote ) => void;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Database abstraction
|
||||||
|
*/
|
||||||
|
export interface ServerDao
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Saves a quote to the database
|
||||||
|
*
|
||||||
|
* A full save will include all metadata.
|
||||||
|
*
|
||||||
|
* @param quote - the quote to save
|
||||||
|
* @param success - function to call on success
|
||||||
|
* @param failure - function to call if save fails
|
||||||
|
* @param save_data - quote data to save (optional)
|
||||||
|
*/
|
||||||
|
saveQuote(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
success: Callback,
|
||||||
|
failure: Callback,
|
||||||
|
save_data: Record<string, any>,
|
||||||
|
): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges bucket data with the existing bucket (rather than overwriting the
|
||||||
|
* entire bucket)
|
||||||
|
*
|
||||||
|
* @param quote - quote to save
|
||||||
|
* @param data - bucket data
|
||||||
|
* @param success - successful callback
|
||||||
|
* @param failure - failure callback
|
||||||
|
*/
|
||||||
|
mergeBucket(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
data: Record<string, any>,
|
||||||
|
success: Callback,
|
||||||
|
failure: Callback,
|
||||||
|
): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save quote classification data
|
||||||
|
*
|
||||||
|
* @param quote - quote to save
|
||||||
|
* @param classes - classification data
|
||||||
|
* @param success - successful callback
|
||||||
|
* @param failure - failure callback
|
||||||
|
*/
|
||||||
|
saveQuoteClasses(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
classes: ClassificationData,
|
||||||
|
success: Callback,
|
||||||
|
failure: Callback,
|
||||||
|
): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the quote state to the database
|
||||||
|
*
|
||||||
|
* The quote state includes the current step, the top visited step and the
|
||||||
|
* explicit lock message.
|
||||||
|
*
|
||||||
|
* @param quote - the quote to save
|
||||||
|
* @param success - function to call on success
|
||||||
|
* @param failure - function to call if save fails
|
||||||
|
*/
|
||||||
|
saveQuoteState(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
success: Callback,
|
||||||
|
failure: Callback,
|
||||||
|
): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves the quote lock state to the database
|
||||||
|
*
|
||||||
|
* @param quote - the quote to save
|
||||||
|
* @param success - function to call on success
|
||||||
|
* @param failure - function to call if save fails
|
||||||
|
*/
|
||||||
|
saveQuoteLockState(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
success: Callback,
|
||||||
|
failure: Callback,
|
||||||
|
): this
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save worksheet data
|
||||||
|
*
|
||||||
|
* @param qid - quote identifier
|
||||||
|
* @param data - worksheet data
|
||||||
|
* @param callback - callback
|
||||||
|
*/
|
||||||
|
setWorksheets(
|
||||||
|
qid: QuoteId,
|
||||||
|
data: WorksheetData,
|
||||||
|
callback: NodeCallback<void>,
|
||||||
|
): this;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve worksheet data
|
||||||
|
*
|
||||||
|
* @param qid - quote identifier
|
||||||
|
* @param supplier - supplier id
|
||||||
|
* @param index - worksheet index
|
||||||
|
* @param callback - callback
|
||||||
|
*/
|
||||||
|
getWorksheet(
|
||||||
|
qid: QuoteId,
|
||||||
|
supplier: string,
|
||||||
|
index: PositiveInteger,
|
||||||
|
callback: ( data: WorksheetData | null ) => void,
|
||||||
|
): this;
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* Priority log typescript type definitions
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export declare interface PriorityLog
|
||||||
|
{
|
||||||
|
readonly PRIORITY_ERROR: number;
|
||||||
|
readonly PRIORITY_IMPORTANT: number;
|
||||||
|
readonly PRIORITY_DB: number;
|
||||||
|
readonly PRIORITY_INFO: number;
|
||||||
|
readonly PRIORITY_SOCKET: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write to the log at the given priority
|
||||||
|
*
|
||||||
|
* If the priority is less than or equal to the set priority for this
|
||||||
|
* object, it will be logged. Otherwise, the message will be ignored.
|
||||||
|
*
|
||||||
|
* The first argument should be the priority. The remaining arguments should
|
||||||
|
* be provided in a sprintf()-style fashion
|
||||||
|
*
|
||||||
|
* @param priority - logging priority
|
||||||
|
* @param ...args - sprintf-style aruments
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
log( priority: number, ...args: Array<string|number> ): this;
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/**
|
||||||
|
* Augments a quote with additional data for use by the quote server
|
||||||
|
*
|
||||||
|
* 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 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 General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* @todo Use ``document'' terminology in place of ``quote''
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Program } from "../../program/Program";
|
||||||
|
import { BaseQuote } from "../../quote/BaseQuote";
|
||||||
|
|
||||||
|
|
||||||
|
export declare class ServerSideQuote extends BaseQuote
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Last rated date, if any
|
||||||
|
*
|
||||||
|
* @return last rated date
|
||||||
|
*/
|
||||||
|
getRatedDate(): UnixTimestamp;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the timestamp of the first time quote was rated
|
||||||
|
*
|
||||||
|
* @param timestamp - Unix timestamp representing first rated date
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
setRatedDate( timestamp: UnixTimestamp ): this;
|
||||||
|
}
|
|
@ -20,7 +20,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Class = require( 'easejs' ).Class,
|
var Class = require( 'easejs' ).Class,
|
||||||
Rater = require( './Rater' ),
|
|
||||||
EventEmitter = require( 'events' ).EventEmitter,
|
EventEmitter = require( 'events' ).EventEmitter,
|
||||||
|
|
||||||
DslRaterContext = require( './DslRaterContext' );
|
DslRaterContext = require( './DslRaterContext' );
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Class = require( 'easejs' ).Class,
|
var Class = require( 'easejs' ).Class,
|
||||||
Rater = require( './Rater' ),
|
|
||||||
EventEmitter = require( 'events' ).EventEmitter,
|
EventEmitter = require( 'events' ).EventEmitter,
|
||||||
Quote = require( '../../quote/Quote' );
|
Quote = require( '../../quote/Quote' );
|
||||||
|
|
||||||
|
|
|
@ -22,18 +22,14 @@
|
||||||
* "HttpRater"
|
* "HttpRater"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Class = require( 'easejs' ).Class,
|
var Class = require( 'easejs' ).Class;
|
||||||
Rater = require( './Rater' ),
|
var querystring = require( 'querystring' );
|
||||||
|
|
||||||
querystring = require( 'querystring' )
|
|
||||||
;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Rates using one of the PHP raters
|
* Rates using one of the PHP raters
|
||||||
*/
|
*/
|
||||||
module.exports = Class( 'HttpRater' )
|
module.exports = Class( 'HttpRater' )
|
||||||
.implement( Rater )
|
|
||||||
.extend(
|
.extend(
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
/**
|
||||||
|
* Rating process manager
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { Rater } from "./Rater";
|
||||||
|
|
||||||
|
|
||||||
|
export declare class ProcessManager
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Returns the rater associated with the given id
|
||||||
|
*
|
||||||
|
* @param id - rater id
|
||||||
|
*
|
||||||
|
* @return requested rater
|
||||||
|
*/
|
||||||
|
byId( id: string ): Rater;
|
||||||
|
}
|
|
@ -69,6 +69,9 @@ const _signum = {
|
||||||
*
|
*
|
||||||
* Handles formatting and sending requests to the rating process; and
|
* Handles formatting and sending requests to the rating process; and
|
||||||
* processing replies.
|
* processing replies.
|
||||||
|
*
|
||||||
|
* TODO: Rename this class and provide a more generic interface. The caller
|
||||||
|
* does not care that this sends data to another process for rating.
|
||||||
*/
|
*/
|
||||||
module.exports = Class( 'ProcessManager',
|
module.exports = Class( 'ProcessManager',
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
/**
|
||||||
|
* Contains Rater interface
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ClientActions } from "../../client/action/ClientAction";
|
||||||
|
import { ServerSideQuote } from "../quote/ServerSideQuote";
|
||||||
|
import { UserSession } from "../request/UserSession";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Result of rating */
|
||||||
|
export interface RateResult
|
||||||
|
{
|
||||||
|
/** Whether all suppliers were not able to provide rates */
|
||||||
|
_unavailable_all: '0' | '1';
|
||||||
|
|
||||||
|
/** Result data */
|
||||||
|
[P: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result of rating with an individual supplier
|
||||||
|
*
|
||||||
|
* This gets combined into a single RateResult prefixed with each supplier
|
||||||
|
* id and an underscore.
|
||||||
|
*/
|
||||||
|
export interface SupplierRateResult
|
||||||
|
{
|
||||||
|
/** Rating worksheet data */
|
||||||
|
__worksheet?: WorksheetData,
|
||||||
|
|
||||||
|
/** Classification system results */
|
||||||
|
__classes?: ClassificationData,
|
||||||
|
|
||||||
|
/** Basic profiling data */
|
||||||
|
__perf: PerformanceData,
|
||||||
|
|
||||||
|
/** Ineligible message, if any */
|
||||||
|
ineligible: string,
|
||||||
|
|
||||||
|
/** Submit message, if any */
|
||||||
|
submit: string,
|
||||||
|
|
||||||
|
/** Final premium */
|
||||||
|
premium: number,
|
||||||
|
|
||||||
|
/** Rating data */
|
||||||
|
[P: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Basic profiling data */
|
||||||
|
export interface PerformanceData
|
||||||
|
{
|
||||||
|
/** Timestamp of beginning of rating */
|
||||||
|
start: UnixTimestampMillis;
|
||||||
|
|
||||||
|
/** Timestamp of end of rating */
|
||||||
|
end: UnixTimestampMillis;
|
||||||
|
|
||||||
|
/** Total rating time */
|
||||||
|
total: Milliseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Worksheet data from rater
|
||||||
|
*
|
||||||
|
* These data come from the compiled raters.
|
||||||
|
*
|
||||||
|
* TODO: Fill in a schema here
|
||||||
|
*/
|
||||||
|
export type WorksheetData = Record<string, any>;
|
||||||
|
|
||||||
|
|
||||||
|
/** Classification results */
|
||||||
|
export type ClassificationData = Record<string, boolean>;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a rater that will generate a quote from a given set of values
|
||||||
|
*/
|
||||||
|
export interface Rater
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Asynchronously performs rating
|
||||||
|
*
|
||||||
|
* @param quote - quote to perform rating on
|
||||||
|
* @param session - user session
|
||||||
|
* @param indv - individual supplier to rate (otherwise empty)
|
||||||
|
* @param success - continuation when rating is successful
|
||||||
|
* @param failure - continuation when rating fails
|
||||||
|
*
|
||||||
|
* @return self
|
||||||
|
*/
|
||||||
|
rate(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
session: UserSession,
|
||||||
|
indv: string,
|
||||||
|
success: ( rate_data: RateResult, actions: ClientActions ) => void,
|
||||||
|
failure: ( message: string ) => void,
|
||||||
|
): this;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
* Contains Rater interface
|
* User request abstraction
|
||||||
*
|
*
|
||||||
* Copyright (C) 2010-2019 R-T Specialty, LLC.
|
* Copyright (C) 2010-2019 R-T Specialty, LLC.
|
||||||
*
|
*
|
||||||
|
@ -19,22 +19,18 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Interface = require( 'easejs' ).Interface;
|
import { UserSession } from "./UserSession";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a rater that will generate a quote from a given set of values
|
* Representation of request from user
|
||||||
*/
|
*/
|
||||||
module.exports = Interface( 'Rater',
|
export declare class UserRequest
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Asynchronously performs rating using the data from the given bucket
|
* Retrieve the current session
|
||||||
*
|
*
|
||||||
* @param {Quote} quote to rate
|
* @return current session
|
||||||
* @param {function()} callback function to call when complete
|
|
||||||
*
|
|
||||||
* @return {Rater} self
|
|
||||||
*/
|
*/
|
||||||
'public rate': [ 'quote', 'args', 'callback' ],
|
getSession(): UserSession;
|
||||||
} );
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* UserResponse class
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manipulates response to user request
|
||||||
|
*/
|
||||||
|
export declare class UserResponse
|
||||||
|
{
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/**
|
||||||
|
* UserSession class
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Session management
|
||||||
|
*/
|
||||||
|
export declare class UserSession
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Whether the user is logged in as an internal user
|
||||||
|
*
|
||||||
|
* @return true if internal user, otherwise false
|
||||||
|
*/
|
||||||
|
isInternal(): boolean;
|
||||||
|
}
|
|
@ -1,420 +0,0 @@
|
||||||
/**
|
|
||||||
* Rating service
|
|
||||||
*
|
|
||||||
* 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;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* XXX: Half-assed, quick refactoring to extract from Server class; this is not
|
|
||||||
* yet complete!
|
|
||||||
*
|
|
||||||
* TODO: Logging should be implemented by observers
|
|
||||||
*/
|
|
||||||
module.exports = Class( 'RatingService',
|
|
||||||
{
|
|
||||||
logger: null,
|
|
||||||
|
|
||||||
dao: null,
|
|
||||||
|
|
||||||
_server: null,
|
|
||||||
|
|
||||||
_raters: null,
|
|
||||||
|
|
||||||
|
|
||||||
__construct: function( logger, dao, server, raters )
|
|
||||||
{
|
|
||||||
this._logger = logger;
|
|
||||||
this._dao = dao;
|
|
||||||
this._server = server;
|
|
||||||
this._raters = raters;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sends rates to the client
|
|
||||||
*
|
|
||||||
* Note that the continuation will be called after all data saving is
|
|
||||||
* complete; the request will be sent back to the client before then.
|
|
||||||
*
|
|
||||||
* @param {UserRequest} request user request to satisfy
|
|
||||||
* @param {UserResponse} response pending response
|
|
||||||
* @param {Quote} quote quote to export
|
|
||||||
* @param {string} cmd applicable of command request
|
|
||||||
* @param {Function} callback continuation after saving is complete
|
|
||||||
*
|
|
||||||
* @return Server self to allow for method chaining
|
|
||||||
*/
|
|
||||||
'public request': function( request, response, quote, cmd, callback )
|
|
||||||
{
|
|
||||||
// cmd represents a request for a single rater
|
|
||||||
if ( !cmd && this._isQuoteValid( quote ) )
|
|
||||||
{
|
|
||||||
// send an empty reply (keeps what is currently in the bucket)
|
|
||||||
this._server.sendResponse( request, quote, {
|
|
||||||
data: {},
|
|
||||||
}, [] );
|
|
||||||
|
|
||||||
callback();
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
var program = quote.getProgram();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
this._performRating( request, program, quote, cmd, callback );
|
|
||||||
}
|
|
||||||
catch ( err )
|
|
||||||
{
|
|
||||||
this._sendRatingError( request, quote, program, err );
|
|
||||||
callback();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
_getProgramRater: function( program, quote )
|
|
||||||
{
|
|
||||||
var rater = this._raters.byId( program.getId() );
|
|
||||||
|
|
||||||
// if a rater could not be found, we can't do any rating
|
|
||||||
if ( rater === null )
|
|
||||||
{
|
|
||||||
this._logger.log( this._logger.PRIORITY_ERROR,
|
|
||||||
"Rating for quote %d (program %s) failed; missing module",
|
|
||||||
quote.getId(),
|
|
||||||
program.getId()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return rater;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
_isQuoteValid: function( quote )
|
|
||||||
{
|
|
||||||
// quotes are valid for 30 days
|
|
||||||
var re_date = Math.round( ( ( new Date() ).getTime() / 1000 ) -
|
|
||||||
( 60 * 60 * 24 * 30 )
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( quote.getLastPremiumDate() > re_date )
|
|
||||||
{
|
|
||||||
this._logger.log( this._logger.PRIORITY_INFO,
|
|
||||||
"Skipping '%s' rating for quote #%s; quote is still valid",
|
|
||||||
quote.getProgramId(),
|
|
||||||
quote.getId()
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
_performRating: function( request, program, quote, indv, c )
|
|
||||||
{
|
|
||||||
var _self = this;
|
|
||||||
|
|
||||||
var rater = this._getProgramRater( program );
|
|
||||||
if ( !rater )
|
|
||||||
{
|
|
||||||
this._server.sendError( request, 'Unable to perform rating.' );
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
|
|
||||||
this._logger.log( this._logger.PRIORITY_INFO,
|
|
||||||
"Performing '%s' rating for quote #%s",
|
|
||||||
quote.getProgramId(),
|
|
||||||
quote.getId()
|
|
||||||
);
|
|
||||||
|
|
||||||
rater.rate( quote, request.getSession(), indv,
|
|
||||||
function( rate_data, actions )
|
|
||||||
{
|
|
||||||
actions = actions || [];
|
|
||||||
|
|
||||||
_self.postProcessRaterData(
|
|
||||||
request, rate_data, actions, program, quote
|
|
||||||
);
|
|
||||||
|
|
||||||
const class_dest = {};
|
|
||||||
|
|
||||||
const cleaned = _self._cleanRateData(
|
|
||||||
rate_data,
|
|
||||||
class_dest
|
|
||||||
);
|
|
||||||
|
|
||||||
// TODO: move me during refactoring
|
|
||||||
_self._dao.saveQuoteClasses( quote, class_dest );
|
|
||||||
|
|
||||||
// save all data server-side (important: do after
|
|
||||||
// post-processing); async
|
|
||||||
_self._saveRatingData( quote, rate_data, indv, function()
|
|
||||||
{
|
|
||||||
// we're done
|
|
||||||
c();
|
|
||||||
} );
|
|
||||||
|
|
||||||
// no need to wait for the save; send the response
|
|
||||||
_self._server.sendResponse( request, quote, {
|
|
||||||
data: cleaned,
|
|
||||||
initialRatedDate: quote.getRatedDate(),
|
|
||||||
lastRatedDate: quote.getLastPremiumDate()
|
|
||||||
}, actions );
|
|
||||||
},
|
|
||||||
function( message )
|
|
||||||
{
|
|
||||||
_self._sendRatingError( request, quote, program,
|
|
||||||
Error( message )
|
|
||||||
);
|
|
||||||
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves rating data
|
|
||||||
*
|
|
||||||
* Data will be merged with existing bucket data and saved. The idea behind
|
|
||||||
* this is to allow us to reference the data (e.g. for reporting) even if
|
|
||||||
* the client does not save it.
|
|
||||||
*
|
|
||||||
* @param {Quote} quote quote to save data to
|
|
||||||
* @param {Object} data rating data
|
|
||||||
*
|
|
||||||
* @return {undefined}
|
|
||||||
*/
|
|
||||||
_saveRatingData: function( quote, data, indv, c )
|
|
||||||
{
|
|
||||||
// only update the last premium calc date on the initial request
|
|
||||||
if ( !indv )
|
|
||||||
{
|
|
||||||
var cur_date = Math.round(
|
|
||||||
( new Date() ).getTime() / 1000
|
|
||||||
);
|
|
||||||
|
|
||||||
quote.setLastPremiumDate( cur_date );
|
|
||||||
quote.setRatedDate( cur_date );
|
|
||||||
|
|
||||||
function done()
|
|
||||||
{
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
|
|
||||||
// save the last prem status (we pass an empty object as the save
|
|
||||||
// data argument to ensure that we do not save the actual bucket
|
|
||||||
// data, which may cause a race condition with the below merge call)
|
|
||||||
this._dao.saveQuote( quote, done, done, {} );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
c();
|
|
||||||
}
|
|
||||||
|
|
||||||
// we're not going to worry about whether or not this fails; if it does,
|
|
||||||
// an error will be automatically logged, but we still want to give the
|
|
||||||
// user a rate (if this save fails, it's likely we have bigger problems
|
|
||||||
// anyway); this can also be done concurrently with the above request
|
|
||||||
// since it only modifies a portion of the bucket
|
|
||||||
this._dao.mergeBucket( quote, data );
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Process rater data returned from a rater
|
|
||||||
*
|
|
||||||
* @param {UserRequest} request user request to satisfy
|
|
||||||
* @param {Object} data rating data returned
|
|
||||||
* @param {Array} actions actions to send to client
|
|
||||||
* @param {Program} program program used to perform rating
|
|
||||||
* @param {Quote} quote quote used for rating
|
|
||||||
*
|
|
||||||
* @return {undefined}
|
|
||||||
*/
|
|
||||||
'virtual protected postProcessRaterData': function(
|
|
||||||
request, data, actions, program, quote
|
|
||||||
)
|
|
||||||
{
|
|
||||||
var meta = data._cmpdata || {};
|
|
||||||
|
|
||||||
// the metadata will not be provided to the client
|
|
||||||
delete data._cmpdata;
|
|
||||||
|
|
||||||
// rating worksheets are returned as metadata
|
|
||||||
this._processWorksheetData( quote.getId(), data );
|
|
||||||
|
|
||||||
if ( ( program.ineligibleLockCount > 0 )
|
|
||||||
&& ( +meta.count_ineligible >= program.ineligibleLockCount )
|
|
||||||
)
|
|
||||||
{
|
|
||||||
// lock the quote client-side (we don't send them the reason; they
|
|
||||||
// don't need it) to the current step
|
|
||||||
actions.push( { action: 'lock' } );
|
|
||||||
|
|
||||||
var lock_reason = 'Supplier ineligibility restriction';
|
|
||||||
var lock_step = quote.getCurrentStepId();
|
|
||||||
|
|
||||||
// the next step is the step that displays the rating results
|
|
||||||
quote.setExplicitLock( lock_reason, ( lock_step + 1 ) );
|
|
||||||
|
|
||||||
// important: only save the lock state, not the step states, as we
|
|
||||||
// have a race condition with async. rating (the /visit request may
|
|
||||||
// be made while we're rating, and when we come back we would then
|
|
||||||
// update the step id with a prior, incorrect step)
|
|
||||||
this._dao.saveQuoteLockState( quote );
|
|
||||||
}
|
|
||||||
|
|
||||||
// if any have been deferred, instruct the client to request them
|
|
||||||
// individually
|
|
||||||
if ( Array.isArray( meta.deferred ) && ( meta.deferred.length > 0 ) )
|
|
||||||
{
|
|
||||||
var torate = [];
|
|
||||||
|
|
||||||
meta.deferred.forEach( function( alias )
|
|
||||||
{
|
|
||||||
actions.push( { action: 'indvRate', id: alias } );
|
|
||||||
torate.push( alias );
|
|
||||||
} );
|
|
||||||
|
|
||||||
// we log that we're performing rating, so we should also log when
|
|
||||||
// it is deferred (otherwise the logs will be rather confusing)
|
|
||||||
this._logger.log( this._logger.PRIORITY_INFO,
|
|
||||||
"'%s' rating deferred for quote #%s; will rate: %s",
|
|
||||||
quote.getProgramId(),
|
|
||||||
quote.getId(),
|
|
||||||
torate.join( ',' )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
_sendRatingError: function( request, quote, program, err )
|
|
||||||
{
|
|
||||||
// well that's no good
|
|
||||||
this._logger.log( this._logger.PRIORITY_ERROR,
|
|
||||||
"Rating for quote %d (program %s) failed: %s",
|
|
||||||
quote.getId(),
|
|
||||||
program.getId(),
|
|
||||||
err.message + '\n-!' + err.stack.replace( /\n/g, '\n-!' )
|
|
||||||
);
|
|
||||||
|
|
||||||
this._server.sendError( request,
|
|
||||||
'There was a problem during the rating process. Unable to ' +
|
|
||||||
'continue. Please contact our support team for assistance.' +
|
|
||||||
|
|
||||||
// show details for internal users
|
|
||||||
( ( request.getSession().isInternal() )
|
|
||||||
? '<br /><br />[Internal] ' + err.message + '<br /><br />' +
|
|
||||||
'<hr />' + err.stack.replace( /\n/g, '<br />' )
|
|
||||||
: ''
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
_processWorksheetData: function( qid, data )
|
|
||||||
{
|
|
||||||
// TODO: this should be done earlier on, so that this is not necessary
|
|
||||||
var wre = /^(.+)___worksheet$/,
|
|
||||||
worksheets = {};
|
|
||||||
|
|
||||||
// extract worksheets for each supplier
|
|
||||||
for ( var field in data )
|
|
||||||
{
|
|
||||||
var match;
|
|
||||||
if ( match = field.match( wre ) )
|
|
||||||
{
|
|
||||||
var name = match[ 1 ];
|
|
||||||
|
|
||||||
worksheets[ name ] = data[ field ];
|
|
||||||
delete data[ field ];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var _self = this;
|
|
||||||
this._dao.setWorksheets( qid, worksheets, function( err )
|
|
||||||
{
|
|
||||||
if ( err )
|
|
||||||
{
|
|
||||||
_self._logger.log( this._logger.PRIORITY_ERROR,
|
|
||||||
"Failed to save rating worksheets for quote %d",
|
|
||||||
quote.getId(),
|
|
||||||
err.message + '\n-!' + err.stack.replace( /\n/g, '\n-!' )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
serveWorksheet: function( request, quote, supplier, index )
|
|
||||||
{
|
|
||||||
var qid = quote.getId(),
|
|
||||||
_self = this;
|
|
||||||
|
|
||||||
this._dao.getWorksheet( qid, supplier, index, function( data )
|
|
||||||
{
|
|
||||||
_self._server.sendResponse( request, quote, {
|
|
||||||
data: data
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepares rate data to be sent back to the client
|
|
||||||
*
|
|
||||||
* There are certain data saved server-side that there is no use serving to
|
|
||||||
* the client.
|
|
||||||
*
|
|
||||||
* @param {Object} data rate data
|
|
||||||
*
|
|
||||||
* @return {Object} modified rate data
|
|
||||||
*/
|
|
||||||
'private _cleanRateData': function( data, classes )
|
|
||||||
{
|
|
||||||
classes = classes || {};
|
|
||||||
|
|
||||||
var result = {};
|
|
||||||
|
|
||||||
// clear class data
|
|
||||||
for ( var key in data )
|
|
||||||
{
|
|
||||||
var mdata;
|
|
||||||
|
|
||||||
// supplier___classes
|
|
||||||
if ( mdata = key.match( /^(.*)___classes$/ ) )
|
|
||||||
{
|
|
||||||
classes[ mdata[ 1 ] ] = data[ key ];
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result[ key ] = data[ key ];
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
},
|
|
||||||
} );
|
|
||||||
|
|
|
@ -0,0 +1,502 @@
|
||||||
|
/**
|
||||||
|
* Rating service
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ClassificationData, RateResult, WorksheetData } from "../rater/Rater";
|
||||||
|
import { ClientActions } from "../../client/action/ClientAction";
|
||||||
|
import { PositiveInteger } from "../../numeric";
|
||||||
|
import { PriorityLog } from "../log/PriorityLog";
|
||||||
|
import { ProcessManager } from "../rater/ProcessManager";
|
||||||
|
import { Program } from "../../program/Program";
|
||||||
|
import { QuoteId } from "../../quote/Quote";
|
||||||
|
import { Server } from "../Server";
|
||||||
|
import { ServerDao } from "../db/ServerDao";
|
||||||
|
import { ServerSideQuote } from "../quote/ServerSideQuote";
|
||||||
|
import { UserRequest } from "../request/UserRequest";
|
||||||
|
import { UserResponse } from "../request/UserResponse";
|
||||||
|
|
||||||
|
type RequestCallback = () => void;
|
||||||
|
|
||||||
|
/** Result of rating */
|
||||||
|
export type RateRequestResult = {
|
||||||
|
data: RateResult,
|
||||||
|
initialRatedDate: UnixTimestamp,
|
||||||
|
lastRatedDate: UnixTimestamp,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle rating requests
|
||||||
|
*
|
||||||
|
* XXX: This class was extracted from Server and needs additional
|
||||||
|
* refactoring, testing, and cleanup.
|
||||||
|
*
|
||||||
|
* TODO: Logging should be implemented by observers
|
||||||
|
*/
|
||||||
|
export class RatingService
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Initialize rating service
|
||||||
|
*
|
||||||
|
* @param _logger - logging system
|
||||||
|
* @param _dao - database connection
|
||||||
|
* @param _server - server actions
|
||||||
|
* @param _rater_manager - rating manager
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
private readonly _logger: PriorityLog,
|
||||||
|
private readonly _dao: ServerDao,
|
||||||
|
private readonly _server: Server,
|
||||||
|
private readonly _rater_manager: ProcessManager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TODO: Remove once traits subtypes are converted to TS
|
||||||
|
*
|
||||||
|
* This works around an easejs bug where prototype constructors are not
|
||||||
|
* properly invoked. Note that technically the constructor above is
|
||||||
|
* invoked twice by easejs: once with no arguments, and again when
|
||||||
|
* calling this method with the proper arguments.
|
||||||
|
*/
|
||||||
|
__construct()
|
||||||
|
{
|
||||||
|
(<any>RatingService ).apply( this, arguments );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends rates to the client
|
||||||
|
*
|
||||||
|
* Note that the promise will be resolved after all data saving is
|
||||||
|
* complete; the request will be sent back to the client before then.
|
||||||
|
*
|
||||||
|
* @param request - user request to satisfy
|
||||||
|
* @param _response - pending response
|
||||||
|
* @param quote - quote to export
|
||||||
|
* @param cmd - applicable of command request
|
||||||
|
*
|
||||||
|
* @return result promise
|
||||||
|
*/
|
||||||
|
request(
|
||||||
|
request: UserRequest,
|
||||||
|
_response: UserResponse,
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
cmd: string,
|
||||||
|
): Promise<RateRequestResult>
|
||||||
|
{
|
||||||
|
return new Promise<RateRequestResult>( resolve =>
|
||||||
|
{
|
||||||
|
// cmd represents a request for a single rater
|
||||||
|
if ( !cmd && this._isQuoteValid( quote ) )
|
||||||
|
{
|
||||||
|
// send an empty reply (keeps what is currently in the
|
||||||
|
// bucket)
|
||||||
|
this._server.sendResponse( request, quote, {
|
||||||
|
data: {},
|
||||||
|
}, [] );
|
||||||
|
|
||||||
|
// XXX: When this class is no longer responsible for
|
||||||
|
// sending the response to the server, this below data needs
|
||||||
|
// to represent the _current_ values, since as it is written
|
||||||
|
// now, it'll overwrite what is currently in the bucket
|
||||||
|
return resolve( {
|
||||||
|
data: { _unavailable_all: '0' },
|
||||||
|
initialRatedDate: <UnixTimestamp>0,
|
||||||
|
lastRatedDate: <UnixTimestamp>0,
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve( this._performRating( request, quote, cmd ) );
|
||||||
|
} )
|
||||||
|
.catch( err =>
|
||||||
|
{
|
||||||
|
this._sendRatingError( request, quote, err );
|
||||||
|
throw err;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether quote is still valid
|
||||||
|
*
|
||||||
|
* TODO: This class shouldn't be making this determination, and this
|
||||||
|
* method is nondeterministic.
|
||||||
|
*
|
||||||
|
* @param quote - quote to check
|
||||||
|
*
|
||||||
|
* @return whether quote is still valid
|
||||||
|
*/
|
||||||
|
private _isQuoteValid( quote: ServerSideQuote ): boolean
|
||||||
|
{
|
||||||
|
// quotes are valid for 30 days
|
||||||
|
var re_date = Math.round( ( ( new Date() ).getTime() / 1000 ) -
|
||||||
|
( 60 * 60 * 24 * 30 )
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( quote.getLastPremiumDate() > re_date )
|
||||||
|
{
|
||||||
|
this._logger.log( this._logger.PRIORITY_INFO,
|
||||||
|
"Skipping '%s' rating for quote #%s; quote is still valid",
|
||||||
|
quote.getProgramId(),
|
||||||
|
quote.getId()
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform rating and process result
|
||||||
|
*
|
||||||
|
* @param request - user request to satisfy
|
||||||
|
* @param quote - quote to process
|
||||||
|
* @param indv - individual supplier to rate (or empty)
|
||||||
|
*
|
||||||
|
* @return promise for results of rating
|
||||||
|
*/
|
||||||
|
private _performRating(
|
||||||
|
request: UserRequest,
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
indv: string,
|
||||||
|
): Promise<RateRequestResult>
|
||||||
|
{
|
||||||
|
return new Promise<RateRequestResult>( ( resolve, reject ) =>
|
||||||
|
{
|
||||||
|
const rater = this._rater_manager.byId( quote.getProgramId() );
|
||||||
|
|
||||||
|
this._logger.log( this._logger.PRIORITY_INFO,
|
||||||
|
"Performing '%s' rating for quote #%s",
|
||||||
|
quote.getProgramId(),
|
||||||
|
quote.getId()
|
||||||
|
);
|
||||||
|
|
||||||
|
rater.rate( quote, request.getSession(), indv,
|
||||||
|
( rate_data: RateResult, actions: ClientActions ) =>
|
||||||
|
{
|
||||||
|
actions = actions || [];
|
||||||
|
|
||||||
|
this.postProcessRaterData(
|
||||||
|
request, rate_data, actions, quote.getProgram(), quote
|
||||||
|
);
|
||||||
|
|
||||||
|
const class_dest = {};
|
||||||
|
|
||||||
|
const cleaned = this._cleanRateData(
|
||||||
|
rate_data,
|
||||||
|
class_dest
|
||||||
|
);
|
||||||
|
|
||||||
|
// TODO: move me during refactoring
|
||||||
|
this._dao.saveQuoteClasses(
|
||||||
|
quote, class_dest, () => {}, () => {}
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
data: cleaned,
|
||||||
|
initialRatedDate: quote.getRatedDate(),
|
||||||
|
lastRatedDate: quote.getLastPremiumDate()
|
||||||
|
};
|
||||||
|
|
||||||
|
// save all data server-side (important: do after
|
||||||
|
// post-processing); async
|
||||||
|
this._saveRatingData( quote, rate_data, indv, function()
|
||||||
|
{
|
||||||
|
// we're done
|
||||||
|
resolve( result );
|
||||||
|
} );
|
||||||
|
|
||||||
|
// no need to wait for the save; send the response
|
||||||
|
this._server.sendResponse( request, quote, result, actions );
|
||||||
|
},
|
||||||
|
( message: string ) =>
|
||||||
|
{
|
||||||
|
this._sendRatingError( request, quote,
|
||||||
|
Error( message )
|
||||||
|
);
|
||||||
|
|
||||||
|
reject( Error( message ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves rating data
|
||||||
|
*
|
||||||
|
* Data will be merged with existing bucket data and saved. The idea behind
|
||||||
|
* this is to allow us to reference the data (e.g. for reporting) even if
|
||||||
|
* the client does not save it.
|
||||||
|
*
|
||||||
|
* @param quote - quote to save data to
|
||||||
|
* @param data - rating data
|
||||||
|
* @param indv - individual supplier, or empty
|
||||||
|
* @param c - callback
|
||||||
|
*/
|
||||||
|
private _saveRatingData(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
data: RateResult,
|
||||||
|
indv: string,
|
||||||
|
c: RequestCallback
|
||||||
|
): void
|
||||||
|
{
|
||||||
|
// only update the last premium calc date on the initial request
|
||||||
|
if ( !indv )
|
||||||
|
{
|
||||||
|
var cur_date = <UnixTimestamp>Math.round(
|
||||||
|
( new Date() ).getTime() / 1000
|
||||||
|
);
|
||||||
|
|
||||||
|
quote.setLastPremiumDate( cur_date );
|
||||||
|
quote.setRatedDate( cur_date );
|
||||||
|
|
||||||
|
// save the last prem status (we pass an empty object as the save
|
||||||
|
// data argument to ensure that we do not save the actual bucket
|
||||||
|
// data, which may cause a race condition with the below merge call)
|
||||||
|
this._dao.saveQuote( quote, c, c, {
|
||||||
|
ratedata: data,
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c();
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're not going to worry about whether or not this fails; if it does,
|
||||||
|
// an error will be automatically logged, but we still want to give the
|
||||||
|
// user a rate (if this save fails, it's likely we have bigger problems
|
||||||
|
// anyway); this can also be done concurrently with the above request
|
||||||
|
// since it only modifies a portion of the bucket
|
||||||
|
this._dao.mergeBucket( quote, data, () => {}, () => {} );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process rater data returned from a rater
|
||||||
|
*
|
||||||
|
* @param _request - user request to satisfy
|
||||||
|
* @param data - rating data returned
|
||||||
|
* @param actions - actions to send to client
|
||||||
|
* @param program - program used to perform rating
|
||||||
|
* @param quote - quote used for rating
|
||||||
|
*/
|
||||||
|
protected postProcessRaterData(
|
||||||
|
_request: UserRequest,
|
||||||
|
data: RateResult,
|
||||||
|
actions: ClientActions,
|
||||||
|
program: Program,
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
): void
|
||||||
|
{
|
||||||
|
var meta = data._cmpdata || {};
|
||||||
|
|
||||||
|
// the metadata will not be provided to the client
|
||||||
|
delete data._cmpdata;
|
||||||
|
|
||||||
|
// rating worksheets are returned as metadata
|
||||||
|
this._processWorksheetData( quote.getId(), data );
|
||||||
|
|
||||||
|
if ( ( program.ineligibleLockCount > 0 )
|
||||||
|
&& ( +meta.count_ineligible >= program.ineligibleLockCount )
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// lock the quote client-side (we don't send them the reason; they
|
||||||
|
// don't need it) to the current step
|
||||||
|
actions.push( { action: 'lock' } );
|
||||||
|
|
||||||
|
var lock_reason = 'Supplier ineligibility restriction';
|
||||||
|
var lock_step = quote.getCurrentStepId();
|
||||||
|
|
||||||
|
// the next step is the step that displays the rating results
|
||||||
|
quote.setExplicitLock( lock_reason, ( lock_step + 1 ) );
|
||||||
|
|
||||||
|
// important: only save the lock state, not the step states, as we
|
||||||
|
// have a race condition with async. rating (the /visit request may
|
||||||
|
// be made while we're rating, and when we come back we would then
|
||||||
|
// update the step id with a prior, incorrect step)
|
||||||
|
this._dao.saveQuoteLockState( quote, () => {}, () => {} );
|
||||||
|
}
|
||||||
|
|
||||||
|
// if any have been deferred, instruct the client to request them
|
||||||
|
// individually
|
||||||
|
if ( Array.isArray( meta.deferred ) && ( meta.deferred.length > 0 ) )
|
||||||
|
{
|
||||||
|
var torate: string[] = [];
|
||||||
|
|
||||||
|
meta.deferred.forEach( ( alias: string ) =>
|
||||||
|
{
|
||||||
|
actions.push( { action: 'indvRate', after: alias } );
|
||||||
|
torate.push( alias );
|
||||||
|
} );
|
||||||
|
|
||||||
|
// we log that we're performing rating, so we should also log when
|
||||||
|
// it is deferred (otherwise the logs will be rather confusing)
|
||||||
|
this._logger.log( this._logger.PRIORITY_INFO,
|
||||||
|
"'%s' rating deferred for quote #%s; will rate: %s",
|
||||||
|
quote.getProgramId(),
|
||||||
|
quote.getId(),
|
||||||
|
torate.join( ',' )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send rating error to user and log
|
||||||
|
*
|
||||||
|
* @param request - user request to satisfy
|
||||||
|
* @param quote - problem quote
|
||||||
|
* @param err - error
|
||||||
|
*/
|
||||||
|
private _sendRatingError(
|
||||||
|
request: UserRequest,
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
err: Error,
|
||||||
|
): void
|
||||||
|
{
|
||||||
|
// well that's no good
|
||||||
|
this._logger.log( this._logger.PRIORITY_ERROR,
|
||||||
|
"Rating for quote %d (program %s) failed: %s",
|
||||||
|
quote.getId(),
|
||||||
|
quote.getProgramId(),
|
||||||
|
err.message + '\n-!' + ( err.stack || "" ).replace( /\n/g, '\n-!' )
|
||||||
|
);
|
||||||
|
|
||||||
|
this._server.sendError( request,
|
||||||
|
'There was a problem during the rating process. Unable to ' +
|
||||||
|
'continue. Please contact our support team for assistance.' +
|
||||||
|
|
||||||
|
// show details for internal users
|
||||||
|
( ( request.getSession().isInternal() )
|
||||||
|
? '<br /><br />[Internal] ' + err.message + '<br /><br />' +
|
||||||
|
'<hr />' + ( err.stack || "" ).replace( /\n/g, '<br />' )
|
||||||
|
: ''
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process and save worksheet data from rating results
|
||||||
|
*
|
||||||
|
* @param qid - quote id
|
||||||
|
* @param data - rating result
|
||||||
|
*/
|
||||||
|
private _processWorksheetData( qid: QuoteId, data: RateResult ): void
|
||||||
|
{
|
||||||
|
// TODO: this should be done earlier on, so that this is not necessary
|
||||||
|
const wre = /^(.+)___worksheet$/;
|
||||||
|
|
||||||
|
const worksheets: Record<string, WorksheetData> = {};
|
||||||
|
|
||||||
|
// extract worksheets for each supplier
|
||||||
|
for ( var field in data )
|
||||||
|
{
|
||||||
|
var match;
|
||||||
|
if ( match = field.match( wre ) )
|
||||||
|
{
|
||||||
|
var name = match[ 1 ];
|
||||||
|
|
||||||
|
worksheets[ name ] = data[ field ];
|
||||||
|
delete data[ field ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this._dao.setWorksheets( qid, worksheets, ( err: Error | null ) =>
|
||||||
|
{
|
||||||
|
if ( err )
|
||||||
|
{
|
||||||
|
this._logger.log( this._logger.PRIORITY_ERROR,
|
||||||
|
"Failed to save rating worksheets for quote %d",
|
||||||
|
qid,
|
||||||
|
err.message + '\n-!' + ( err.stack || "" ).replace( /\n/g, '\n-!' )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serve worksheet data to user
|
||||||
|
*
|
||||||
|
* @param request - user request to satisfy
|
||||||
|
* @param quote - quote from which to look up worksheet data
|
||||||
|
* @param supplier - supplier name
|
||||||
|
* @param index - worksheet index
|
||||||
|
*/
|
||||||
|
serveWorksheet(
|
||||||
|
request: UserRequest,
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
supplier: string,
|
||||||
|
index: PositiveInteger,
|
||||||
|
): void
|
||||||
|
{
|
||||||
|
var qid = quote.getId();
|
||||||
|
|
||||||
|
this._dao.getWorksheet( qid, supplier, index, data =>
|
||||||
|
{
|
||||||
|
this._server.sendResponse( request, quote, {
|
||||||
|
data: data
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prepares rate data to be sent back to the client
|
||||||
|
*
|
||||||
|
* There are certain data saved server-side that there is no use serving to
|
||||||
|
* the client.
|
||||||
|
*
|
||||||
|
* @param data - rate data
|
||||||
|
* @param classes - classification data
|
||||||
|
*
|
||||||
|
* @return modified rate data
|
||||||
|
*/
|
||||||
|
private _cleanRateData(
|
||||||
|
data: RateResult,
|
||||||
|
classes: ClassificationData
|
||||||
|
): RateResult
|
||||||
|
{
|
||||||
|
// forceful cast because the below loop will copy everything
|
||||||
|
const result = <RateResult>{};
|
||||||
|
|
||||||
|
// clear class data
|
||||||
|
for ( var key in data )
|
||||||
|
{
|
||||||
|
var mdata;
|
||||||
|
|
||||||
|
// supplier___classes
|
||||||
|
if ( mdata = key.match( /^(.*)___classes$/ ) )
|
||||||
|
{
|
||||||
|
classes[ mdata[ 1 ] ] = data[ key ];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
result[ key ] = data[ key ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,8 +21,8 @@
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { Trait } = require( 'easejs' );
|
const { Interface, Trait } = require( 'easejs' );
|
||||||
const RatingService = require( './RatingService' );
|
const { RatingService } = require( './RatingService' );
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,7 +51,8 @@ const RatingService = require( './RatingService' );
|
||||||
* See the body of `#_sendMessage' for their values.
|
* See the body of `#_sendMessage' for their values.
|
||||||
*/
|
*/
|
||||||
module.exports = Trait( 'RatingServicePublish' )
|
module.exports = Trait( 'RatingServicePublish' )
|
||||||
.extend( RatingService,
|
.implement( Interface( { 'postProcessRaterData': [] } ) )
|
||||||
|
.extend(
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* AMQP library (amqplib API)
|
* AMQP library (amqplib API)
|
||||||
|
@ -75,7 +76,7 @@ module.exports = Trait( 'RatingServicePublish' )
|
||||||
*
|
*
|
||||||
* @type {DebugLog}
|
* @type {DebugLog}
|
||||||
*/
|
*/
|
||||||
'private _logger': null,
|
'private _log': null,
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,7 +90,7 @@ module.exports = Trait( 'RatingServicePublish' )
|
||||||
{
|
{
|
||||||
this._amqp = amqp;
|
this._amqp = amqp;
|
||||||
this._conf = conf;
|
this._conf = conf;
|
||||||
this._logger = logger;
|
this._log = logger;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ module.exports = Trait( 'RatingServicePublish' )
|
||||||
*
|
*
|
||||||
* @return {undefined}
|
* @return {undefined}
|
||||||
*/
|
*/
|
||||||
'override protected postProcessRaterData'(
|
'abstract override postProcessRaterData'(
|
||||||
request, data, actions, program, quote
|
request, data, actions, program, quote
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -127,13 +128,13 @@ module.exports = Trait( 'RatingServicePublish' )
|
||||||
quote
|
quote
|
||||||
);
|
);
|
||||||
} )
|
} )
|
||||||
.then( () => this._logger.log(
|
.then( () => this._log.log(
|
||||||
this._logger.PRIORITY_INFO,
|
this._log.PRIORITY_INFO,
|
||||||
"Published quote " + quote.getId() +
|
"Published quote " + quote.getId() +
|
||||||
" to post-rate exchange '" + exchange + "'"
|
" to post-rate exchange '" + exchange + "'"
|
||||||
) )
|
) )
|
||||||
.catch( e => this._logger.log(
|
.catch( e => this._log.log(
|
||||||
this._logger.PRIORITY_ERROR,
|
this._log.PRIORITY_ERROR,
|
||||||
"Post-rate exchange publish failure for quote " +
|
"Post-rate exchange publish failure for quote " +
|
||||||
quote.getId() + ": " + e.message
|
quote.getId() + ": " + e.message
|
||||||
) );
|
) );
|
||||||
|
|
|
@ -1,163 +0,0 @@
|
||||||
/**
|
|
||||||
* Notification on all submit
|
|
||||||
*
|
|
||||||
* Copyright (C) 2010-2019 R-T Specialty, LLC.
|
|
||||||
*
|
|
||||||
* This file is part of liza.
|
|
||||||
*
|
|
||||||
* liza is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU 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 General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict';
|
|
||||||
|
|
||||||
const { Trait } = require( 'easejs' );
|
|
||||||
const DslRaterContext = require( '../rater/DslRaterContext' )
|
|
||||||
const RatingService = require( './RatingService' );
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers DataApi when no results are available
|
|
||||||
*
|
|
||||||
* This information is currently stored in `__prem_avail_count`. In the
|
|
||||||
* future, it may be worth accepting a parameter to configure this at
|
|
||||||
* runtime.
|
|
||||||
*
|
|
||||||
* Notification status will persist using the provided DAO. The next time
|
|
||||||
* such a notification is requested, it will only occur if the flag is not
|
|
||||||
* set. The flag is not set in the event of an error (determined by the
|
|
||||||
* DataApi; usually an HTTP error).
|
|
||||||
*/
|
|
||||||
module.exports = Trait( 'RatingServiceSubmitNotify' )
|
|
||||||
.extend( RatingService,
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Function returning DataApi to trigger
|
|
||||||
* @type {Function(UserSession):DataApi}
|
|
||||||
*/
|
|
||||||
'private _dapif': null,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data store for notification flag
|
|
||||||
* @type {ServerDao}
|
|
||||||
*/
|
|
||||||
'private _notifyDao': null,
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize mixin with DataApi to trigger
|
|
||||||
*
|
|
||||||
* @param {Function(UserSession):DataApi} dapif Function producing DataApi
|
|
||||||
* @param {ServerDao} dao store for notification flag
|
|
||||||
*/
|
|
||||||
__mixin( dapif, dao )
|
|
||||||
{
|
|
||||||
this._dapif = dapif;
|
|
||||||
this._notifyDao = dao;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger previously provided DataApi when no results are available
|
|
||||||
*
|
|
||||||
* Result count is determined by DATA.__prem_avail_count. If the
|
|
||||||
* notification is successful (determined by the DataApi), then a
|
|
||||||
* flag will be set preventing the request from being trigerred for
|
|
||||||
* subsequent rating data.
|
|
||||||
*
|
|
||||||
* @param {UserRequest} request user request
|
|
||||||
* @param {Object} data rating data returned
|
|
||||||
* @param {Array} actions actions to send to client
|
|
||||||
* @param {Program} program program used to perform rating
|
|
||||||
* @param {Quote} quote quote used for rating
|
|
||||||
*
|
|
||||||
* @return {undefined}
|
|
||||||
*/
|
|
||||||
'override protected postProcessRaterData'(
|
|
||||||
request, data, actions, program, quote
|
|
||||||
)
|
|
||||||
{
|
|
||||||
const quote_id = quote.getId();
|
|
||||||
const avail = ( data.__prem_avail_count || [ 0 ] )[ 0 ];
|
|
||||||
|
|
||||||
if ( avail === 0 )
|
|
||||||
{
|
|
||||||
this._maybeNotify( quote_id, request );
|
|
||||||
}
|
|
||||||
|
|
||||||
this.__super( request, data, actions, program, quote );
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform notification if flag has not been set
|
|
||||||
*
|
|
||||||
* See #postProcessRaterData for more information.
|
|
||||||
*
|
|
||||||
* @param {number} quote_id effective quote/document id
|
|
||||||
* @param {UserRequest} request user request
|
|
||||||
*
|
|
||||||
* @return {undefined}
|
|
||||||
*/
|
|
||||||
'private _maybeNotify'( quote_id, request )
|
|
||||||
{
|
|
||||||
this._getNotifyState( quote_id, notified =>
|
|
||||||
{
|
|
||||||
if ( notified === true )
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make the request, only setting the notification flag if
|
|
||||||
// it is successful
|
|
||||||
this._dapif( request )
|
|
||||||
.request( { quote_id: quote_id }, err =>
|
|
||||||
{
|
|
||||||
err || this._setNotified( quote_id );
|
|
||||||
} );
|
|
||||||
} );
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get value of notification flag
|
|
||||||
*
|
|
||||||
* @param {number} quote_id id of quote
|
|
||||||
* @param {function(boolean)} callback callback to call when complete
|
|
||||||
*
|
|
||||||
* @return {undefined}
|
|
||||||
*/
|
|
||||||
'private _getNotifyState'( quote_id, callback )
|
|
||||||
{
|
|
||||||
this._notifyDao.getDocumentField(
|
|
||||||
quote_id,
|
|
||||||
'submitNotified',
|
|
||||||
( err, value ) => callback( value )
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set notification flag
|
|
||||||
*
|
|
||||||
* @param {number} quote_id id of quote
|
|
||||||
*
|
|
||||||
* @return {undefined}
|
|
||||||
*/
|
|
||||||
'private _setNotified'( quote_id )
|
|
||||||
{
|
|
||||||
this._notifyDao.setDocumentField(
|
|
||||||
quote_id, 'submitNotified', true
|
|
||||||
);
|
|
||||||
},
|
|
||||||
} );
|
|
|
@ -1,92 +0,0 @@
|
||||||
/**
|
|
||||||
* Tests RatingService
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
|
|
||||||
exports.getStubs = function()
|
|
||||||
{
|
|
||||||
const program_id = 'foo';
|
|
||||||
const program = {
|
|
||||||
getId: () => program_id,
|
|
||||||
};
|
|
||||||
|
|
||||||
// rate reply
|
|
||||||
const stub_rate_data = {};
|
|
||||||
|
|
||||||
const rater = {
|
|
||||||
rate: ( quote, session, indv, callback ) => callback( stub_rate_data ),
|
|
||||||
};
|
|
||||||
|
|
||||||
const raters = {
|
|
||||||
byId: () => rater,
|
|
||||||
};
|
|
||||||
|
|
||||||
const logger = {
|
|
||||||
log: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
const server = {
|
|
||||||
sendResponse: () => {},
|
|
||||||
sendError: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
const dao = {
|
|
||||||
mergeBucket: () => {},
|
|
||||||
saveQuoteClasses: () => {},
|
|
||||||
setWorksheets: () => {},
|
|
||||||
saveQuote: () => {},
|
|
||||||
};
|
|
||||||
|
|
||||||
const session = {
|
|
||||||
isInternal: () => false,
|
|
||||||
};
|
|
||||||
|
|
||||||
const request = {
|
|
||||||
getSession: () => session,
|
|
||||||
getSessionIdName: () => {},
|
|
||||||
};
|
|
||||||
const response = {};
|
|
||||||
|
|
||||||
const quote = {
|
|
||||||
getProgramId: () => program_id,
|
|
||||||
getProgram: () => program,
|
|
||||||
getId: () => 0,
|
|
||||||
setLastPremiumDate: () => {},
|
|
||||||
setRatedDate: () => {},
|
|
||||||
getRatedDate: () => 0,
|
|
||||||
getLastPremiumDate: () => 0
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
program: program,
|
|
||||||
stub_rate_data: stub_rate_data,
|
|
||||||
rater: rater,
|
|
||||||
raters: raters,
|
|
||||||
logger: logger,
|
|
||||||
server: server,
|
|
||||||
dao: dao,
|
|
||||||
session: session,
|
|
||||||
request: request,
|
|
||||||
response: response,
|
|
||||||
quote: quote,
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -38,12 +38,24 @@
|
||||||
type NominalType<K, T> = K & { __nominal_type__: T };
|
type NominalType<K, T> = K & { __nominal_type__: T };
|
||||||
|
|
||||||
|
|
||||||
|
/** Unit of time in seconds */
|
||||||
|
type Seconds = NominalType<number, 'Seconds'>;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unix timestamp
|
* Unix timestamp
|
||||||
*
|
*
|
||||||
* Number of seconds since the Unix epoch (1970-01-01 UTC).
|
* Number of seconds since the Unix epoch (1970-01-01 UTC).
|
||||||
*/
|
*/
|
||||||
type UnixTimestamp = NominalType<number, 'UnixTimestamp'>;
|
type UnixTimestamp = NominalType<Seconds, 'UnixTimestamp'>;
|
||||||
|
|
||||||
|
|
||||||
|
/** Unit of time in milliseconds */
|
||||||
|
type Milliseconds = NominalType<number, 'Milliseconds'>;
|
||||||
|
|
||||||
|
|
||||||
|
/** Unix timestamp represented in milliseconds */
|
||||||
|
type UnixTimestampMillis = NominalType<Milliseconds, 'UnixTimestampMillis'>;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
/**
|
||||||
|
* Test numeric types
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { PositiveInteger, isPositiveInteger } from "../src/numeric";
|
||||||
|
|
||||||
|
|
||||||
|
describe( 'isPositiveInteger', () =>
|
||||||
|
{
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
5,
|
||||||
|
].forEach( value => it( `accepts positive integers (${value})`, () =>
|
||||||
|
{
|
||||||
|
expect( isPositiveInteger( value ) ).to.be.true;
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
|
||||||
|
[
|
||||||
|
-1,
|
||||||
|
-5,
|
||||||
|
].forEach( value => it( `rejects negative integers (${value})`, () =>
|
||||||
|
{
|
||||||
|
expect( isPositiveInteger( value ) ).to.be.false;
|
||||||
|
} ) );
|
||||||
|
|
||||||
|
|
||||||
|
it( "asserts type PositiveInteger", () =>
|
||||||
|
{
|
||||||
|
const n = 5;
|
||||||
|
|
||||||
|
if ( isPositiveInteger( n ) )
|
||||||
|
{
|
||||||
|
// TS should recognize as PositiveInteger within this block
|
||||||
|
checkPositiveInteger( n );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
const checkPositiveInteger = ( _n: PositiveInteger ): void => {};
|
|
@ -1,186 +0,0 @@
|
||||||
/**
|
|
||||||
* Tests RatingServiceSubmitNotify
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const { Class } = require( 'easejs' );
|
|
||||||
const { expect } = require( 'chai' );
|
|
||||||
|
|
||||||
|
|
||||||
const {
|
|
||||||
dapi: {
|
|
||||||
DataApi,
|
|
||||||
},
|
|
||||||
server: {
|
|
||||||
service: {
|
|
||||||
RatingServiceSubmitNotify: Sut,
|
|
||||||
RatingService,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
test: {
|
|
||||||
server: {
|
|
||||||
service: {
|
|
||||||
RatingServiceStub,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} = require( '../../../' );
|
|
||||||
|
|
||||||
|
|
||||||
describe( 'RatingServiceSubmitNotify', () =>
|
|
||||||
{
|
|
||||||
[
|
|
||||||
// not available; make successful request and save flag
|
|
||||||
{
|
|
||||||
prem_avail_count: [ 0 ],
|
|
||||||
prev_called: false,
|
|
||||||
expected_request: true,
|
|
||||||
request_err: null,
|
|
||||||
save: true,
|
|
||||||
},
|
|
||||||
// not available; make failing request, don't save flag
|
|
||||||
{
|
|
||||||
prem_avail_count: [ 0 ],
|
|
||||||
prev_called: false,
|
|
||||||
expected_request: true,
|
|
||||||
request_err: Error(),
|
|
||||||
save: false,
|
|
||||||
},
|
|
||||||
// available
|
|
||||||
{
|
|
||||||
prem_avail_count: [ 2 ],
|
|
||||||
prev_called: false,
|
|
||||||
expected_request: false,
|
|
||||||
request_err: null,
|
|
||||||
save: false,
|
|
||||||
},
|
|
||||||
// this shouldn't happen; ignore all but first index
|
|
||||||
{
|
|
||||||
prem_avail_count: [ 2, 2 ],
|
|
||||||
prev_called: false,
|
|
||||||
expected_request: false,
|
|
||||||
request_err: null,
|
|
||||||
save: false,
|
|
||||||
},
|
|
||||||
// save as above, but already saved
|
|
||||||
{
|
|
||||||
prem_avail_count: [ 0 ],
|
|
||||||
prev_called: true,
|
|
||||||
expected_request: false,
|
|
||||||
request_err: null,
|
|
||||||
save: false,
|
|
||||||
},
|
|
||||||
// available; don't make request
|
|
||||||
{
|
|
||||||
prem_avail_count: [ 2 ],
|
|
||||||
prev_called: true,
|
|
||||||
expected_request: false,
|
|
||||||
request_err: null,
|
|
||||||
save: false,
|
|
||||||
},
|
|
||||||
// this shouldn't happen; ignore all but first index
|
|
||||||
{
|
|
||||||
prem_avail_count: [ 2, 2 ],
|
|
||||||
prev_called: true,
|
|
||||||
expected_request: false,
|
|
||||||
request_err: null,
|
|
||||||
save: false,
|
|
||||||
},
|
|
||||||
].forEach( ( expected, i ) =>
|
|
||||||
it( `sends request on post process if no premiums (#${i})`, done =>
|
|
||||||
{
|
|
||||||
const {
|
|
||||||
dao,
|
|
||||||
logger,
|
|
||||||
quote,
|
|
||||||
raters,
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
server,
|
|
||||||
stub_rate_data,
|
|
||||||
} = RatingServiceStub.getStubs();
|
|
||||||
|
|
||||||
const quote_id = 1234;
|
|
||||||
let requested = false;
|
|
||||||
|
|
||||||
const dapif = given_request =>
|
|
||||||
Class.implement( DataApi ).extend(
|
|
||||||
{
|
|
||||||
// warning: if an expectation fails, because of how
|
|
||||||
// RatingService handles errors, it will cause the test to
|
|
||||||
// _hang_ rather than throw the assertion error
|
|
||||||
request( data, callback, id )
|
|
||||||
{
|
|
||||||
expect( given_request ).to.equal( request );
|
|
||||||
expect( data ).to.deep.equal( { quote_id: quote_id } );
|
|
||||||
|
|
||||||
requested = true;
|
|
||||||
|
|
||||||
callback( expected.request_err, null );
|
|
||||||
},
|
|
||||||
} )();
|
|
||||||
|
|
||||||
const sut = RatingService.use( Sut( dapif, dao ) )(
|
|
||||||
logger, dao, server, raters
|
|
||||||
);
|
|
||||||
|
|
||||||
quote.getId = () => quote_id;
|
|
||||||
|
|
||||||
// one of the methods that is called by the supertype
|
|
||||||
let save_called = false;
|
|
||||||
dao.setWorksheets = () => save_called = true;
|
|
||||||
|
|
||||||
// whether the notify flag is actually set
|
|
||||||
let notify_saved = false;
|
|
||||||
|
|
||||||
// request for notification status
|
|
||||||
dao.getDocumentField = ( qid, key, callback ) =>
|
|
||||||
{
|
|
||||||
expect( qid ).to.equal( quote_id );
|
|
||||||
expect( key ).to.equal( 'submitNotified' );
|
|
||||||
|
|
||||||
callback( expected.flag_error, expected.prev_called );
|
|
||||||
};
|
|
||||||
|
|
||||||
dao.setDocumentField = ( qid, key, value, callback ) =>
|
|
||||||
{
|
|
||||||
expect( qid ).to.equal( quote_id );
|
|
||||||
expect( key ).to.equal( 'submitNotified' );
|
|
||||||
expect( value ).to.equal( true );
|
|
||||||
|
|
||||||
notify_saved = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
stub_rate_data.__prem_avail_count = expected.prem_avail_count;
|
|
||||||
|
|
||||||
sut.request( request, response, quote, 'something', () =>
|
|
||||||
{
|
|
||||||
expect( requested ).to.equal( expected.expected_request );
|
|
||||||
expect( save_called ).to.be.true;
|
|
||||||
|
|
||||||
// only save notification status if we're notifying
|
|
||||||
expect( notify_saved ).to.equal( expected.save );
|
|
||||||
|
|
||||||
done();
|
|
||||||
} );
|
|
||||||
} )
|
|
||||||
);
|
|
||||||
} );
|
|
|
@ -1,105 +0,0 @@
|
||||||
/**
|
|
||||||
* Tests RatingService
|
|
||||||
*
|
|
||||||
* 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
const { expect } = require( 'chai' );
|
|
||||||
const Sut = require( '../../../' ).server.service.RatingService;
|
|
||||||
const RatingServiceStub = require( '../../../' ).test.server.service.RatingServiceStub;
|
|
||||||
|
|
||||||
describe( 'RatingService', () =>
|
|
||||||
{
|
|
||||||
describe( "protected API", () =>
|
|
||||||
{
|
|
||||||
it( "calls #postProcessRaterData after rating before save", done =>
|
|
||||||
{
|
|
||||||
let processed = false;
|
|
||||||
|
|
||||||
const {
|
|
||||||
logger,
|
|
||||||
server,
|
|
||||||
raters,
|
|
||||||
dao,
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
quote,
|
|
||||||
} = RatingServiceStub.getStubs();
|
|
||||||
|
|
||||||
dao.mergeBucket = () =>
|
|
||||||
{
|
|
||||||
expect( processed ).to.equal( true );
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
const sut = Sut.extend(
|
|
||||||
{
|
|
||||||
'override postProcessRaterData'(
|
|
||||||
request, data, actions, program, quote
|
|
||||||
)
|
|
||||||
{
|
|
||||||
processed = true;
|
|
||||||
}
|
|
||||||
} )( logger, dao, server, raters );
|
|
||||||
|
|
||||||
sut.request( request, response, quote, 'something', () => {} );
|
|
||||||
} );
|
|
||||||
|
|
||||||
it( "calls getLastPremiumDate during #_performRating", done =>
|
|
||||||
{
|
|
||||||
let getLastPremiumDateCallCount = 0;
|
|
||||||
|
|
||||||
const last_date = 1234;
|
|
||||||
const initial_date = 2345;
|
|
||||||
|
|
||||||
const {
|
|
||||||
logger,
|
|
||||||
server,
|
|
||||||
raters,
|
|
||||||
dao,
|
|
||||||
request,
|
|
||||||
response,
|
|
||||||
quote,
|
|
||||||
} = RatingServiceStub.getStubs();
|
|
||||||
|
|
||||||
quote.getLastPremiumDate = () =>
|
|
||||||
{
|
|
||||||
getLastPremiumDateCallCount++;
|
|
||||||
return last_date
|
|
||||||
};
|
|
||||||
|
|
||||||
quote.getRatedDate = () => initial_date;
|
|
||||||
|
|
||||||
const sut = Sut( logger, dao, server, raters );
|
|
||||||
|
|
||||||
server.sendResponse = ( request, quote, resp, actions ) =>
|
|
||||||
{
|
|
||||||
expect( getLastPremiumDateCallCount ).to.equal( 2 );
|
|
||||||
expect( resp.initialRatedDate ).to.equal( initial_date );
|
|
||||||
expect( resp.lastRatedDate ).to.equal( last_date );
|
|
||||||
|
|
||||||
done();
|
|
||||||
};
|
|
||||||
|
|
||||||
sut.request( request, response, quote, null, () => {} );
|
|
||||||
} );
|
|
||||||
|
|
||||||
} );
|
|
||||||
} );
|
|
|
@ -0,0 +1,411 @@
|
||||||
|
/**
|
||||||
|
* Tests RatingService
|
||||||
|
*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { RatingService as Sut } from "../../../src/server/service/RatingService";
|
||||||
|
|
||||||
|
import { ClientActions } from "../../../src/client/action/ClientAction";
|
||||||
|
import { PriorityLog } from "../../../src/server/log/PriorityLog";
|
||||||
|
import { ProcessManager } from "../../../src/server/rater/ProcessManager";
|
||||||
|
import { Program } from "../../../src/program/Program";
|
||||||
|
import { QuoteId } from "../../../src/quote/Quote";
|
||||||
|
import { Rater, RateResult } from "../../../src/server/rater/Rater";
|
||||||
|
import { Server } from "../../../src/server/Server";
|
||||||
|
import { ServerSideQuote } from "../../../src/server/quote/ServerSideQuote";
|
||||||
|
import { UserRequest } from "../../../src/server/request/UserRequest";
|
||||||
|
import { UserResponse } from "../../../src/server/request/UserResponse";
|
||||||
|
import { UserSession } from "../../../src/server/request/UserSession";
|
||||||
|
|
||||||
|
import {
|
||||||
|
ServerDao,
|
||||||
|
Callback as ServerDaoCallback
|
||||||
|
} from "../../../src/server/db/ServerDao";
|
||||||
|
|
||||||
|
import { expect, use as chai_use } from 'chai';
|
||||||
|
chai_use( require( 'chai-as-promised' ) );
|
||||||
|
|
||||||
|
|
||||||
|
describe( 'RatingService', () =>
|
||||||
|
{
|
||||||
|
it( "returns rating results", () =>
|
||||||
|
{
|
||||||
|
const {
|
||||||
|
logger,
|
||||||
|
server,
|
||||||
|
raters,
|
||||||
|
dao,
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
quote,
|
||||||
|
stub_rate_data,
|
||||||
|
} = getStubs();
|
||||||
|
|
||||||
|
const sut = new Sut( logger, dao, server, raters );
|
||||||
|
|
||||||
|
const expected = {
|
||||||
|
data: stub_rate_data,
|
||||||
|
initialRatedDate: quote.getRatedDate(),
|
||||||
|
lastRatedDate: quote.getLastPremiumDate(),
|
||||||
|
};
|
||||||
|
|
||||||
|
return expect( sut.request( request, response, quote, "" ) )
|
||||||
|
.to.eventually.deep.equal( expected );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( "saves rate data to own field", () =>
|
||||||
|
{
|
||||||
|
const {
|
||||||
|
logger,
|
||||||
|
server,
|
||||||
|
raters,
|
||||||
|
dao,
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
quote,
|
||||||
|
stub_rate_data,
|
||||||
|
} = getStubs();
|
||||||
|
|
||||||
|
let saved_rates = false;
|
||||||
|
|
||||||
|
dao.saveQuote = (
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
success: ServerDaoCallback,
|
||||||
|
_failure: ServerDaoCallback,
|
||||||
|
save_data: Record<string, any>,
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
expect( save_data ).to.deep.equal( {
|
||||||
|
ratedata: stub_rate_data,
|
||||||
|
} );
|
||||||
|
|
||||||
|
saved_rates = true;
|
||||||
|
success( quote );
|
||||||
|
|
||||||
|
return dao;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sut = new Sut( logger, dao, server, raters );
|
||||||
|
|
||||||
|
return sut.request( request, response, quote, "" )
|
||||||
|
.then( () =>
|
||||||
|
{
|
||||||
|
expect( saved_rates ).to.be.true;
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
it( "rejects and responds with error", () =>
|
||||||
|
{
|
||||||
|
const {
|
||||||
|
dao,
|
||||||
|
logger,
|
||||||
|
program,
|
||||||
|
quote,
|
||||||
|
rater,
|
||||||
|
raters,
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
server,
|
||||||
|
} = getStubs();
|
||||||
|
|
||||||
|
const expected_error = new Error( "expected error" );
|
||||||
|
|
||||||
|
rater.rate = () => { throw expected_error; };
|
||||||
|
|
||||||
|
const sut = new Sut( logger, dao, server, raters );
|
||||||
|
|
||||||
|
let logged = false;
|
||||||
|
|
||||||
|
logger.log = function(
|
||||||
|
priority: number,
|
||||||
|
_format: string,
|
||||||
|
qid: QuoteId,
|
||||||
|
program_id: string,
|
||||||
|
message: string,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if ( typeof message === 'string' )
|
||||||
|
{
|
||||||
|
expect( priority ).to.equal( logger.PRIORITY_ERROR );
|
||||||
|
expect( qid ).to.equal( quote.getId() );
|
||||||
|
expect( program_id ).to.equal( program.getId() );
|
||||||
|
expect( message ).to.contain( expected_error.message );
|
||||||
|
|
||||||
|
logged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return logger;
|
||||||
|
};
|
||||||
|
|
||||||
|
return expect( sut.request( request, response, quote, "" ) )
|
||||||
|
.to.eventually.rejectedWith( expected_error )
|
||||||
|
.then( () => expect( logged ).to.be.true );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
it( "returns error message from rater", () =>
|
||||||
|
{
|
||||||
|
const {
|
||||||
|
dao,
|
||||||
|
logger,
|
||||||
|
quote,
|
||||||
|
rater,
|
||||||
|
raters,
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
server,
|
||||||
|
} = getStubs();
|
||||||
|
|
||||||
|
const expected_message = 'expected foo';
|
||||||
|
|
||||||
|
const sut = new Sut( logger, dao, server, raters );
|
||||||
|
|
||||||
|
rater.rate = (
|
||||||
|
_quote: ServerSideQuote,
|
||||||
|
_session: UserSession,
|
||||||
|
_indv: string,
|
||||||
|
_success: ( data: RateResult, actions: ClientActions ) => void,
|
||||||
|
failure: ( message: string ) => void,
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
failure( expected_message );
|
||||||
|
return rater;
|
||||||
|
};
|
||||||
|
|
||||||
|
return expect( sut.request( request, response, quote, "" ) )
|
||||||
|
.to.eventually.rejectedWith( Error, expected_message );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
describe( "protected API", () =>
|
||||||
|
{
|
||||||
|
it( "calls #postProcessRaterData after rating before save", done =>
|
||||||
|
{
|
||||||
|
let processed = false;
|
||||||
|
|
||||||
|
const {
|
||||||
|
logger,
|
||||||
|
server,
|
||||||
|
raters,
|
||||||
|
dao,
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
quote,
|
||||||
|
} = getStubs();
|
||||||
|
|
||||||
|
dao.mergeBucket = () =>
|
||||||
|
{
|
||||||
|
expect( processed ).to.equal( true );
|
||||||
|
done();
|
||||||
|
|
||||||
|
return dao;
|
||||||
|
};
|
||||||
|
|
||||||
|
const sut = new class extends Sut
|
||||||
|
{
|
||||||
|
postProcessRaterData()
|
||||||
|
{
|
||||||
|
processed = true;
|
||||||
|
}
|
||||||
|
}( logger, dao, server, raters );
|
||||||
|
|
||||||
|
sut.request( request, response, quote, 'something' );
|
||||||
|
} );
|
||||||
|
|
||||||
|
it( "calls getLastPremiumDate during #_performRating", done =>
|
||||||
|
{
|
||||||
|
let getLastPremiumDateCallCount = 0;
|
||||||
|
|
||||||
|
const last_date = <UnixTimestamp>1234;
|
||||||
|
const initial_date = <UnixTimestamp>2345;
|
||||||
|
|
||||||
|
const {
|
||||||
|
logger,
|
||||||
|
server,
|
||||||
|
raters,
|
||||||
|
dao,
|
||||||
|
request,
|
||||||
|
response,
|
||||||
|
quote,
|
||||||
|
} = getStubs();
|
||||||
|
|
||||||
|
quote.getLastPremiumDate = () =>
|
||||||
|
{
|
||||||
|
getLastPremiumDateCallCount++;
|
||||||
|
return last_date
|
||||||
|
};
|
||||||
|
|
||||||
|
quote.getRatedDate = () => initial_date;
|
||||||
|
|
||||||
|
const sut = new Sut( logger, dao, server, raters );
|
||||||
|
|
||||||
|
server.sendResponse = ( _request: any, _quote: any, resp: any, _actions: any ) =>
|
||||||
|
{
|
||||||
|
expect( getLastPremiumDateCallCount ).to.equal( 2 );
|
||||||
|
expect( resp.initialRatedDate ).to.equal( initial_date );
|
||||||
|
expect( resp.lastRatedDate ).to.equal( last_date );
|
||||||
|
|
||||||
|
done();
|
||||||
|
|
||||||
|
return server;
|
||||||
|
};
|
||||||
|
|
||||||
|
sut.request( request, response, quote, "" );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
|
||||||
|
function getStubs()
|
||||||
|
{
|
||||||
|
const program_id = 'foo';
|
||||||
|
|
||||||
|
const program = <Program>{
|
||||||
|
getId: () => program_id,
|
||||||
|
ineligibleLockCount: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// rate reply
|
||||||
|
const stub_rate_data: RateResult = {
|
||||||
|
_unavailable_all: '0',
|
||||||
|
};
|
||||||
|
|
||||||
|
const rater = new class implements Rater
|
||||||
|
{
|
||||||
|
rate(
|
||||||
|
_quote: ServerSideQuote,
|
||||||
|
_session: UserSession,
|
||||||
|
_indv: string,
|
||||||
|
success: ( data: RateResult, actions: ClientActions ) => void,
|
||||||
|
_failure: ( message: string ) => void,
|
||||||
|
)
|
||||||
|
{
|
||||||
|
// force to be async so that the tests resemble how the code
|
||||||
|
// actually runs
|
||||||
|
process.nextTick( () => success( stub_rate_data, [] ) );
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const raters = <ProcessManager>{
|
||||||
|
byId: () => rater,
|
||||||
|
};
|
||||||
|
|
||||||
|
const logger = new class implements PriorityLog
|
||||||
|
{
|
||||||
|
readonly PRIORITY_ERROR: number = 0;
|
||||||
|
readonly PRIORITY_IMPORTANT: number = 1;
|
||||||
|
readonly PRIORITY_DB: number = 2;
|
||||||
|
readonly PRIORITY_INFO: number = 3;
|
||||||
|
readonly PRIORITY_SOCKET: number = 4;
|
||||||
|
|
||||||
|
log( _priority: number, ..._args: Array<string|number> ): this
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const server = <Server>{
|
||||||
|
sendResponse: () => server,
|
||||||
|
sendError: () => server,
|
||||||
|
};
|
||||||
|
|
||||||
|
const dao = new class implements ServerDao
|
||||||
|
{
|
||||||
|
saveQuote(
|
||||||
|
quote: ServerSideQuote,
|
||||||
|
success: ServerDaoCallback,
|
||||||
|
_failure: ServerDaoCallback,
|
||||||
|
_save_data: Record<string, any>,
|
||||||
|
): this
|
||||||
|
{
|
||||||
|
success( quote );
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeBucket(): this
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveQuoteClasses(): this
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
setWorksheets(): this
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveQuoteState(): this
|
||||||
|
{
|
||||||
|
throw new Error( "Unused method" );
|
||||||
|
}
|
||||||
|
|
||||||
|
saveQuoteLockState(): this
|
||||||
|
{
|
||||||
|
throw new Error( "Unused method" );
|
||||||
|
}
|
||||||
|
|
||||||
|
getWorksheet(): this
|
||||||
|
{
|
||||||
|
throw new Error( "Unused method" );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const session = <UserSession>{
|
||||||
|
isInternal: () => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = <UserRequest>{
|
||||||
|
getSession: () => session,
|
||||||
|
getSessionIdName: () => {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = <UserResponse>{};
|
||||||
|
|
||||||
|
const quote = <ServerSideQuote>{
|
||||||
|
getProgramId: () => program_id,
|
||||||
|
getProgram: () => program,
|
||||||
|
getId: () => <QuoteId>0,
|
||||||
|
setLastPremiumDate: () => quote,
|
||||||
|
setRatedDate: () => quote,
|
||||||
|
getRatedDate: () => <UnixTimestamp>0,
|
||||||
|
getLastPremiumDate: () => <UnixTimestamp>0,
|
||||||
|
getCurrentStepId: () => 0,
|
||||||
|
setExplicitLock: () => quote,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
program: program,
|
||||||
|
stub_rate_data: stub_rate_data,
|
||||||
|
rater: rater,
|
||||||
|
raters: raters,
|
||||||
|
logger: logger,
|
||||||
|
server: server,
|
||||||
|
dao: dao,
|
||||||
|
session: session,
|
||||||
|
request: request,
|
||||||
|
response: response,
|
||||||
|
quote: quote,
|
||||||
|
};
|
||||||
|
};
|
Loading…
Reference in New Issue