<commit_before>/*
 * Copyright 2005-2012 The Kuali Foundation
 *
 * Licensed under the Educational Community License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.opensource.org/licenses/ecl2.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// global vars
var $dialog = null;
var jq = jQuery.noConflict();

//clear out blockUI css, using css class overrides
jQuery.blockUI.defaults.css = {};
jQuery.blockUI.defaults.overlayCSS = {};

// validation init
var pageValidatorReady = false;

//sets up the validator with the necessary default settings and methods
//note the use of onClick and onFocusout for on the fly validation client side
function setupValidator(){
	jq('#kualiForm').dirty_form({changedClass: 'dirty'});

	//Make sure form doesn't have any unsaved data when user clicks on any other portal links, closes browser or presses fwd/back browser button
	jq(window).bind('beforeunload', function(evt){
		var validateDirty = jq("[name='validateDirty']").val();
		if (validateDirty == "true")
		{
			var dirty = jq(".uif-field").find("input.dirty");
			//methodToCall check is needed to skip from normal way of unloading (cancel,save,close)
			var methodToCall = jq("[name='methodToCall']").val();
			if (dirty.length > 0 && methodToCall == null)
			{
				return "Form has unsaved data. Do you want to leave anyway?";
			}
		}
	});

	jq('#kualiForm').validate(
	{
		onsubmit: false,
		ignore: ".ignoreValid",
		onclick: function(element) {
            if(element.type != "select-one") {
			    var valid = jq(element).valid();
			    dependsOnCheck(element, new Array());
            }
		},
		onfocusout: function(element) {
			var valid = jq(element).valid();
			dependsOnCheck(element, new Array());
			if((element.type == "select-one" || element.type == "select-multiple") && jq(element).hasClass("valid")){
				applyErrorColors(getAttributeId(element.id, element.type) + "_errors_div", 0, 0, 0, true);
				showFieldIcon(getAttributeId(element.id, element.type) + "_errors_div", 0);
			}
		},
		wrapper: "li",
		highlight: function(element, errorClass, validClass) {
			jq(element).addClass(errorClass).removeClass(validClass);
            jq(element).attr("aria-invalid", "true");
			applyErrorColors(getAttributeId(element.id, element.type) + "_errors_div", 1, 0, 0, true);
			showFieldIcon(getAttributeId(element.id, element.type) + "_errors_div", 1);
		},
		unhighlight: function(element, errorClass, validClass) {
			jq(element).removeClass(errorClass).addClass(validClass);
            jq(element).attr("aria-invalid", "false");
			applyErrorColors(getAttributeId(element.id, element.type) + "_errors_div", 0, 0, 0, true);
			showFieldIcon(getAttributeId(element.id, element.type) + "_errors_div", 0);
		},
		errorPlacement: function(error, element) {
			var id = getAttributeId(element.attr('id'), element[0].type);
			//check to see if the option to use labels is on
			if (!jq("#" + id + "_errors_div").hasClass("noLabels")) {
				var label = getLabel(id);
				label = jq.trim(label);
				if (label) {
					if (label.charAt(label.length - 1) == ":") {
						label = label.slice(0, -1);
					}
					error.find("label").before(label + " - ");
				}
			}
			jq("#" + id + "_errors_div").show();
			jq("#" + id + "_errors_errorMessages").show();
			var errorList = jq("#" + id + "_errors_errorMessages ul");
			error.appendTo(errorList);
		}
	});

    jq(".required").each(function(){
        jq(this).attr("aria-required", "true");
    });

	jq(document).trigger('validationSetup');
	pageValidatorReady = true;

	jq.watermark.showAll();
}

jQuery.validator.addMethod("minExclusive", function(value, element, param){
	if (param.length == 1 || param[1]()) {
		return this.optional(element) || value > param[0];
	}
	else{
		return true;
	}
});
jQuery.validator.addMethod("maxInclusive", function(value, element, param){
	if (param.length == 1 || param[1]()) {
		return this.optional(element) || value <= param[0];
	}
	else{
		return true;
	}
});
jQuery.validator.addMethod("minLengthConditional", function(value, element, param){
	if (param.length == 1 || param[1]()) {
		return this.optional(element) || this.getLength(jq.trim(value), element) >= param[0];
	}
	else{
		return true;
	}
});
jQuery.validator.addMethod("maxLengthConditional", function(value, element, param){
	if (param.length == 1 || param[1]()) {
		return this.optional(element) || this.getLength(jq.trim(value), element) <= param[0];
	}
	else{
		return true;
	}
});

// data table initialize default sorting
jQuery.fn.dataTableExt.oSort['kuali_date-asc']  = function(a,b) {
	var date1 = a.split('/');
	var date2 = b.split('/');
	var x = (date1[2] + date1[0] + date1[1]) * 1;
	var y = (date2[2] + date2[0] + date2[1]) * 1;
	return ((x < y) ? -1 : ((x > y) ?  1 : 0));
};

jQuery.fn.dataTableExt.oSort['kuali_date-desc'] = function(a,b) {
	var date1 = a.split('/');
	var date2 = b.split('/');
	var x = (date1[2] + date1[0] + date1[1]) * 1;
	var y = (date2[2] + date2[0] + date2[1]) * 1;
	return ((x < y) ? 1 : ((x > y) ?  -1 : 0));
};

jQuery.fn.dataTableExt.oSort['kuali_percent-asc'] = function(a,b) {
	var num1 = a.replace(/[^0-9]/g, '');
	var num2 = b.replace(/[^0-9]/g, '');
	num1 = (num1 == "-" || num1 === "" || isNaN(num1)) ? 0 : num1*1;
	num2 = (num2 == "-" || num2 === "" || isNaN(num2)) ? 0 : num2*1;
	return num1 - num2;
};

jQuery.fn.dataTableExt.oSort['kuali_percent-desc'] = function(a,b) {
	var num1 = a.replace(/[^0-9]/g, '');
	var num2 = b.replace(/[^0-9]/g, '');
	num1 = (num1 == "-" || num1 === "" || isNaN(num1)) ? 0 : num1*1;
	num2 = (num2 == "-" || num2 === "" || isNaN(num2)) ? 0 : num2*1;
	return num2 - num1;
};

jQuery.fn.dataTableExt.oSort['kuali_currency-asc'] = function(a,b) {
	/* Remove any commas (assumes that if present all strings will have a fixed number of d.p) */
	var x = a == "-" ? 0 : a.replace( /,/g, "" );
	var y = b == "-" ? 0 : b.replace( /,/g, "" );
	/* Remove the currency sign */
	x = x.substring( 1 );
	y = y.substring( 1 );
	/* Parse and return */
	x = parseFloat( x );
	y = parseFloat( y );

	x = isNaN(x) ? 0 : x*1;
	y = isNaN(y) ? 0 : y*1;

	return x - y;
};

jQuery.fn.dataTableExt.oSort['kuali_currency-desc'] = function(a,b) {
	/* Remove any commas (assumes that if present all strings will have a fixed number of d.p) */
	var x = a == "-" ? 0 : a.replace( /,/g, "" );
	var y = b == "-" ? 0 : b.replace( /,/g, "" );
	/* Remove the currency sign */
	x = x.substring( 1 );
	y = y.substring( 1 );
	/* Parse and return */
	x = parseFloat( x );
	y = parseFloat( y );

	x = isNaN(x) ? 0 : x;
	y = isNaN(y) ? 0 : y;

	return y - x;
};

jQuery.fn.dataTableExt.afnSortData['dom-text'] = function  ( oSettings, iColumn )
{
	var aData = [];
	jq( 'td:eq('+iColumn+')', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
		var input = jq(this).find('input:text');
		if(input.length != 0){
			aData.push( input.val() );
		}else{
            // match DataField or InputField CSS classes - respectively
			var input1 = jq(this).find('.uif-field');
			if(input1.length != 0){
				aData.push(jq.trim(input1.find("span:first").text()));
			}else{
				aData.push("");
			}
		}

	} );
	return aData;
}

/* Create an array with the values of all the select options in a column */
jQuery.fn.dataTableExt.afnSortData['dom-select'] = function  ( oSettings, iColumn )
{
	var aData = [];
	jq( 'td:eq('+iColumn+')', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
		var selected = jq(this).find('select option:selected:first');
		if(selected.length != 0){
			aData.push( selected.text() );
		}else{
			var input1 = jq(this).find('.uif-inputField');
			if(input1.length != 0){
				aData.push(jq.trim(input1.text()));
			}else{
				aData.push( "");
			}
		}

	} );
	return aData;
}

/* Create an array with the values of all the checkboxes in a column */
jQuery.fn.dataTableExt.afnSortData['dom-checkbox'] = function  ( oSettings, iColumn )
{
	var aData = [];
	jq( 'td:eq('+iColumn+')', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
		var checkboxes = jq(this).find('input:checkbox');
		if(checkboxes.length != 0){
			var str = "";
			for(i=0; i < checkboxes.length; i++){
				var check = checkboxes[i];
				if (check.checked == true && check.value.length > 0){
					str += check.value + " ";
				}
			}
			aData.push( str );
		}else{
			var input1 = jq(this).find('.uif-inputField');
			if(input1.length != 0){
				aData.push(jq.trim(input1.text()));
			}else{
				aData.push( "");
			}
		}

	} );
	return aData;

}

jQuery.fn.dataTableExt.afnSortData['dom-radio'] = function  ( oSettings, iColumn )
{
	var aData = [];
	jq( 'td:eq('+iColumn+')', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
		var radioButtons = jq(this).find('input:radio');
		if(radioButtons.length != 0){
			var value = "";
			for(i=0; i < radioButtons.length; i++){
				var radio = radioButtons[i];
				if (radio.checked == true){
					value = radio.value;
					break;
				}
			}
			aData.push( value );
		}else{
			var input1 = jq(this).find('.uif-inputField');
			if(input1.length != 0){
				aData.push(jq.trim(input1.text()));
			}else{
				aData.push( "");
			}
		}

	} );
	return aData;

}

// setup window javascript error handler
window.onerror = errorHandler;

function errorHandler(msg,url,lno)
{
  jq("#view_div").show();
  jq("#viewpage_div").show();
  var context = getContext();
  context.unblockUI();
  showGrowl(msg + '
' + url + '
' + lno, 'Javascript Error', 'errorGrowl');
  return false;
}

// common event registering done here through JQuery ready event
jq(document).ready(function() {
	setPageBreadcrumb();

	// buttons
	jq("input:submit").button();
	jq("input:button").button();
    jq("a.button").button();

    // common ajax setup
	jq.ajaxSetup({
		  beforeSend: function() {
		     createLoading(true);
		  },
		  complete: function(){
			 createLoading(false);
		  },
		  error: function(jqXHR, textStatus, errorThrown){
			 createLoading(false);
			 showGrowl('Status: ' + textStatus + '
' + errorThrown, 'Server Response Error', 'errorGrowl');
		  }
	});

	runHiddenScripts("");
    jq("#view_div").show();
    createLoading(false);
});

<commit_msg>KULRICE-6658 -  ajax progress display screen continues to show even when the page is replaced<commit_after>/*
 * Copyright 2005-2012 The Kuali Foundation
 *
 * Licensed under the Educational Community License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.opensource.org/licenses/ecl2.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
// global vars
var $dialog = null;
var jq = jQuery.noConflict();

//clear out blockUI css, using css class overrides
jQuery.blockUI.defaults.css = {};
jQuery.blockUI.defaults.overlayCSS = {};

// validation init
var pageValidatorReady = false;

//sets up the validator with the necessary default settings and methods
//note the use of onClick and onFocusout for on the fly validation client side
function setupValidator(){
	jq('#kualiForm').dirty_form({changedClass: 'dirty'});

	//Make sure form doesn't have any unsaved data when user clicks on any other portal links, closes browser or presses fwd/back browser button
	jq(window).bind('beforeunload', function(evt){
		var validateDirty = jq("[name='validateDirty']").val();
		if (validateDirty == "true")
		{
			var dirty = jq(".uif-field").find("input.dirty");
			//methodToCall check is needed to skip from normal way of unloading (cancel,save,close)
			var methodToCall = jq("[name='methodToCall']").val();
			if (dirty.length > 0 && methodToCall == null)
			{
				return "Form has unsaved data. Do you want to leave anyway?";
			}
		}
	});

	jq('#kualiForm').validate(
	{
		onsubmit: false,
		ignore: ".ignoreValid",
		onclick: function(element) {
            if(element.type != "select-one") {
			    var valid = jq(element).valid();
			    dependsOnCheck(element, new Array());
            }
		},
		onfocusout: function(element) {
			var valid = jq(element).valid();
			dependsOnCheck(element, new Array());
			if((element.type == "select-one" || element.type == "select-multiple") && jq(element).hasClass("valid")){
				applyErrorColors(getAttributeId(element.id, element.type) + "_errors_div", 0, 0, 0, true);
				showFieldIcon(getAttributeId(element.id, element.type) + "_errors_div", 0);
			}
		},
		wrapper: "li",
		highlight: function(element, errorClass, validClass) {
			jq(element).addClass(errorClass).removeClass(validClass);
            jq(element).attr("aria-invalid", "true");
			applyErrorColors(getAttributeId(element.id, element.type) + "_errors_div", 1, 0, 0, true);
			showFieldIcon(getAttributeId(element.id, element.type) + "_errors_div", 1);
		},
		unhighlight: function(element, errorClass, validClass) {
			jq(element).removeClass(errorClass).addClass(validClass);
            jq(element).attr("aria-invalid", "false");
			applyErrorColors(getAttributeId(element.id, element.type) + "_errors_div", 0, 0, 0, true);
			showFieldIcon(getAttributeId(element.id, element.type) + "_errors_div", 0);
		},
		errorPlacement: function(error, element) {
			var id = getAttributeId(element.attr('id'), element[0].type);
			//check to see if the option to use labels is on
			if (!jq("#" + id + "_errors_div").hasClass("noLabels")) {
				var label = getLabel(id);
				label = jq.trim(label);
				if (label) {
					if (label.charAt(label.length - 1) == ":") {
						label = label.slice(0, -1);
					}
					error.find("label").before(label + " - ");
				}
			}
			jq("#" + id + "_errors_div").show();
			jq("#" + id + "_errors_errorMessages").show();
			var errorList = jq("#" + id + "_errors_errorMessages ul");
			error.appendTo(errorList);
		}
	});

    jq(".required").each(function(){
        jq(this).attr("aria-required", "true");
    });

	jq(document).trigger('validationSetup');
	pageValidatorReady = true;

	jq.watermark.showAll();
}

jQuery.validator.addMethod("minExclusive", function(value, element, param){
	if (param.length == 1 || param[1]()) {
		return this.optional(element) || value > param[0];
	}
	else{
		return true;
	}
});
jQuery.validator.addMethod("maxInclusive", function(value, element, param){
	if (param.length == 1 || param[1]()) {
		return this.optional(element) || value <= param[0];
	}
	else{
		return true;
	}
});
jQuery.validator.addMethod("minLengthConditional", function(value, element, param){
	if (param.length == 1 || param[1]()) {
		return this.optional(element) || this.getLength(jq.trim(value), element) >= param[0];
	}
	else{
		return true;
	}
});
jQuery.validator.addMethod("maxLengthConditional", function(value, element, param){
	if (param.length == 1 || param[1]()) {
		return this.optional(element) || this.getLength(jq.trim(value), element) <= param[0];
	}
	else{
		return true;
	}
});

// data table initialize default sorting
jQuery.fn.dataTableExt.oSort['kuali_date-asc']  = function(a,b) {
	var date1 = a.split('/');
	var date2 = b.split('/');
	var x = (date1[2] + date1[0] + date1[1]) * 1;
	var y = (date2[2] + date2[0] + date2[1]) * 1;
	return ((x < y) ? -1 : ((x > y) ?  1 : 0));
};

jQuery.fn.dataTableExt.oSort['kuali_date-desc'] = function(a,b) {
	var date1 = a.split('/');
	var date2 = b.split('/');
	var x = (date1[2] + date1[0] + date1[1]) * 1;
	var y = (date2[2] + date2[0] + date2[1]) * 1;
	return ((x < y) ? 1 : ((x > y) ?  -1 : 0));
};

jQuery.fn.dataTableExt.oSort['kuali_percent-asc'] = function(a,b) {
	var num1 = a.replace(/[^0-9]/g, '');
	var num2 = b.replace(/[^0-9]/g, '');
	num1 = (num1 == "-" || num1 === "" || isNaN(num1)) ? 0 : num1*1;
	num2 = (num2 == "-" || num2 === "" || isNaN(num2)) ? 0 : num2*1;
	return num1 - num2;
};

jQuery.fn.dataTableExt.oSort['kuali_percent-desc'] = function(a,b) {
	var num1 = a.replace(/[^0-9]/g, '');
	var num2 = b.replace(/[^0-9]/g, '');
	num1 = (num1 == "-" || num1 === "" || isNaN(num1)) ? 0 : num1*1;
	num2 = (num2 == "-" || num2 === "" || isNaN(num2)) ? 0 : num2*1;
	return num2 - num1;
};

jQuery.fn.dataTableExt.oSort['kuali_currency-asc'] = function(a,b) {
	/* Remove any commas (assumes that if present all strings will have a fixed number of d.p) */
	var x = a == "-" ? 0 : a.replace( /,/g, "" );
	var y = b == "-" ? 0 : b.replace( /,/g, "" );
	/* Remove the currency sign */
	x = x.substring( 1 );
	y = y.substring( 1 );
	/* Parse and return */
	x = parseFloat( x );
	y = parseFloat( y );

	x = isNaN(x) ? 0 : x*1;
	y = isNaN(y) ? 0 : y*1;

	return x - y;
};

jQuery.fn.dataTableExt.oSort['kuali_currency-desc'] = function(a,b) {
	/* Remove any commas (assumes that if present all strings will have a fixed number of d.p) */
	var x = a == "-" ? 0 : a.replace( /,/g, "" );
	var y = b == "-" ? 0 : b.replace( /,/g, "" );
	/* Remove the currency sign */
	x = x.substring( 1 );
	y = y.substring( 1 );
	/* Parse and return */
	x = parseFloat( x );
	y = parseFloat( y );

	x = isNaN(x) ? 0 : x;
	y = isNaN(y) ? 0 : y;

	return y - x;
};

jQuery.fn.dataTableExt.afnSortData['dom-text'] = function  ( oSettings, iColumn )
{
	var aData = [];
	jq( 'td:eq('+iColumn+')', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
		var input = jq(this).find('input:text');
		if(input.length != 0){
			aData.push( input.val() );
		}else{
            // match DataField or InputField CSS classes - respectively
			var input1 = jq(this).find('.uif-field');
			if(input1.length != 0){
				aData.push(jq.trim(input1.find("span:first").text()));
			}else{
				aData.push("");
			}
		}

	} );
	return aData;
}

/* Create an array with the values of all the select options in a column */
jQuery.fn.dataTableExt.afnSortData['dom-select'] = function  ( oSettings, iColumn )
{
	var aData = [];
	jq( 'td:eq('+iColumn+')', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
		var selected = jq(this).find('select option:selected:first');
		if(selected.length != 0){
			aData.push( selected.text() );
		}else{
			var input1 = jq(this).find('.uif-inputField');
			if(input1.length != 0){
				aData.push(jq.trim(input1.text()));
			}else{
				aData.push( "");
			}
		}

	} );
	return aData;
}

/* Create an array with the values of all the checkboxes in a column */
jQuery.fn.dataTableExt.afnSortData['dom-checkbox'] = function  ( oSettings, iColumn )
{
	var aData = [];
	jq( 'td:eq('+iColumn+')', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
		var checkboxes = jq(this).find('input:checkbox');
		if(checkboxes.length != 0){
			var str = "";
			for(i=0; i < checkboxes.length; i++){
				var check = checkboxes[i];
				if (check.checked == true && check.value.length > 0){
					str += check.value + " ";
				}
			}
			aData.push( str );
		}else{
			var input1 = jq(this).find('.uif-inputField');
			if(input1.length != 0){
				aData.push(jq.trim(input1.text()));
			}else{
				aData.push( "");
			}
		}

	} );
	return aData;

}

jQuery.fn.dataTableExt.afnSortData['dom-radio'] = function  ( oSettings, iColumn )
{
	var aData = [];
	jq( 'td:eq('+iColumn+')', oSettings.oApi._fnGetTrNodes(oSettings) ).each( function () {
		var radioButtons = jq(this).find('input:radio');
		if(radioButtons.length != 0){
			var value = "";
			for(i=0; i < radioButtons.length; i++){
				var radio = radioButtons[i];
				if (radio.checked == true){
					value = radio.value;
					break;
				}
			}
			aData.push( value );
		}else{
			var input1 = jq(this).find('.uif-inputField');
			if(input1.length != 0){
				aData.push(jq.trim(input1.text()));
			}else{
				aData.push( "");
			}
		}

	} );
	return aData;

}

// setup window javascript error handler
window.onerror = errorHandler;

function errorHandler(msg,url,lno)
{
  jq("#view_div").show();
  jq("#viewpage_div").show();
  var context = getContext();
  context.unblockUI();
  showGrowl(msg + '
' + url + '
' + lno, 'Javascript Error', 'errorGrowl');
  return false;
}

// common event registering done here through JQuery ready event
jq(document).ready(function() {
	setPageBreadcrumb();

	// buttons
	jq("input:submit").button();
	jq("input:button").button();
    jq("a.button").button();

    // common ajax setup
	jq.ajaxSetup({
		  beforeSend: function() {
		     createLoading(true);
		  },
		  complete: function(){
			 createLoading(false);
		  },
		  error: function(jqXHR, textStatus, errorThrown){
			 createLoading(false);
			 showGrowl('Status: ' + textStatus + '
' + errorThrown, 'Server Response Error', 'errorGrowl');
		  }
	});

	runHiddenScripts("");
    jq("#view_div").show();
    createLoading(false);

    // hide the ajax progress display screen if the page is replaced e.g. by a login page when the session expires
    jq(window).unload(function() {
        createLoading(false);
    });
});

<|endoftext|>


<commit_before>        var width = 222,
        height = 200;

	    var cluster = d3.layout.cluster()
	        .size([height, width - 160]);

	    var diagonal = d3.svg.diagonal()
	        .projection(function(d) { return [d.y, d.x]; });

	    var orientation_left = { // right to left
	        size: [height, width],
	        x: function(d) { return width/2 - d.y * 100 / width; },
	        y: function(d) { return d.x; }
	    };

	    var orientation_right = { // left to right
	   	    size: [height, width],
	   	    x: function(d) { return d.y * 100 / width; },
	 	    y: function(d) { return d.x; }
	    };

	    d3.select("#parentChild").style("width", width*2 + "px");
	    d3.select("#childDiv").style("width", width + "px");
	    d3.select("#parentDiv").style("width", width + "px");

 var svgP;

	    d3.json("../mpTree/json/" + mp_id + "?type=parents", function(error, root) {

	    	svgP = d3.select("#parentDiv").append("svg")
		        .attr("width", width)
		        .attr("height", height)
		        .append("g")
		        .attr("transform", "translate(120,0)");

		     var diagonalP = d3.svg.diagonal()
	        	.projection(function(d) { return [d.y, d.x]; });

		     if (error){
		    	  console.log(error);
		    	  throw error;
		     }

		     if (root.children.length == 0){
		    		hasParents = false;
		    		d3.select("#parentDiv").remove();
		    		d3.selectAll("#childDiv")
		    		  .classed("half", false);
		  	 }

		     var nodes = cluster.nodes(root),
		          links = cluster.links(nodes);

		     var link = svgP.selectAll(".link")
		          .data(links)
		          .enter().append("path")
		          .attr("class", "link")
		          .attr("d", d3.svg.diagonal().projection(function(d) { return [orientation_left.x(d), orientation_left.y(d)]; }));

		     var node = svgP.selectAll(".node")
		          .data(nodes)
		          .enter().append("g")
		          .attr("class", "node")
		          .attr("transform", function(d) { return "translate(" +  orientation_left.x(d) + "," + orientation_left.y(d) + ")"; })

		     node.append("circle")
		          .attr("r", 4.5)
		          .style("fill", function(d) { return d.children ? "lightsteelblue" : "#fff"; })
		          .on('click', function(d, i) {
		        	  window.location.href = "../phenotypes/"  + d.id;
			 });

		     node.append("text")
		          .attr("x", function(d) { return d.children ?  8 : -8; })
		          .attr("y", 3)
		          .attr("class", "treeLabel")
		          .style("text-anchor", function(d) { return d.children ? "start" : "end"; })
		          .text(function(d) { return d.children ? "current page" : d.name; })
		          .attr("transform", function(d) {return d.children ? "rotate(270)" : ""})
	  		      .style("width", "150px")
	  		      .on('click', function(d, i) {
					  window.location.href = "../phenotypes/"  + d.id;
	  		  }) ; // width of the node labels;
	    });

	    d3.json("../mpTree/json/" + mp_id + "?type=children", function(error, root) {

		    var svg = d3.select("#childDiv").append("svg")
		        .attr("width", width)
		        .attr("height", height)
		        .append("g")
		        .attr("transform", "translate(5,0)");

		     if (error){
		    	  console.log(error);
		    	  throw error;
		   	 }

		     if (root.children.length == 0){
		    		hasParents = false;
		    		d3.select("#childDiv").remove();
		    		d3.selectAll("#parentDiv")
		    		  .classed("half", false);

			        svgP.attr("transform", "translate(100,0)");
		  	 }

		     var nodes = cluster.nodes(root),
		          links = cluster.links(nodes);

		     var link = svg.selectAll(".link")
		          .data(links)
		          .enter().append("path")
		          .attr("class", "link")
		          .attr("d", d3.svg.diagonal().projection(function(d) { return [orientation_right.x(d), orientation_right.y(d)]; }));

		     var node = svg.selectAll(".node")
		          .data(nodes)
		          .enter().append("g")
		          .attr("class", "node")
		          .attr("transform", function(d) { return "translate(" +  orientation_right.x(d) + "," + orientation_right.y(d) + ")"; })

		     node.append("circle")
		          .attr("r", 4.5)
		          .style("fill", function(d) { return d.children ? "lightsteelblue" : "#fff"; })
		          .on('click', function(d, i) {
					  window.location.href = "../phenotypes/"  + d.id;
				   });

		     node.append("text")
		          .attr("x", function(d) { return d.children ? -8 : 8; })
		          .attr("y", 3)
		          .attr("class", "treeLabel")
		          .style("text-anchor", function(d) { return d.children ? "start" : "start"; })
		          .attr("transform", function(d) {return d.children ? "rotate(270) translate (15,0)" : ""})
		          .text(function(d) { return d.children ? "current page" : d.name; })
	   		      .style("width", "150px")
	   		      .on('click', function(d, i) {
					  window.location.href = "../phenotypes/"  + d.id;
				   }); // width of the node labels;
	    });

	    d3.select(self.frameElement).style("height", height + "px");
	    <commit_msg>Shortening long labels, parent-child display.<commit_after>        var width = 222,
        height = 200;

	    var cluster = d3.layout.cluster()
	        .size([height, width - 160]);

	    var diagonal = d3.svg.diagonal()
	        .projection(function(d) { return [d.y, d.x]; });

	    var orientation_left = { // right to left
	        size: [height, width],
	        x: function(d) { return width/2 - d.y * 100 / width; },
	        y: function(d) { return d.x; }
	    };

	    var orientation_right = { // left to right
	   	    size: [height, width],
	   	    x: function(d) { return d.y * 100 / width; },
	 	    y: function(d) { return d.x; }
	    };

	    d3.select("#parentChild").style("width", width*2 + "px");
	    d3.select("#childDiv").style("width", width + "px");
	    d3.select("#parentDiv").style("width", width + "px");

	    var svgP;

	    function shortenLabel(label){
	    	if (label.length > 33){
	    		return label.substring(0,27) + "...";
	    	} else {
	    		return  label;
	    	}
	    }

	    d3.json("../mpTree/json/" + mp_id + "?type=parents", function(error, root) {

	    	svgP = d3.select("#parentDiv").append("svg")
		        .attr("width", width)
		        .attr("height", height)
		        .append("g")
		        .attr("transform", "translate(120,0)");

		     var diagonalP = d3.svg.diagonal()
	        	.projection(function(d) { return [d.y, d.x]; });

		     if (error){
		    	  console.log(error);
		    	  throw error;
		     }

		     if (root.children.length == 0){
		    		hasParents = false;
		    		d3.select("#parentDiv").remove();
		    		d3.selectAll("#childDiv")
		    		  .classed("half", false);
		  	 }

		     var nodes = cluster.nodes(root),
		          links = cluster.links(nodes);

		     var link = svgP.selectAll(".link")
		          .data(links)
		          .enter().append("path")
		          .attr("class", "link")
		          .attr("d", d3.svg.diagonal().projection(function(d) { return [orientation_left.x(d), orientation_left.y(d)]; }));

		     var node = svgP.selectAll(".node")
		          .data(nodes)
		          .enter().append("g")
		          .attr("class", "node")
		          .attr("transform", function(d) { return "translate(" +  orientation_left.x(d) + "," + orientation_left.y(d) + ")"; })

		     node.append("circle")
		          .attr("r", 4.5)
		          .style("fill", function(d) { return d.children ? "lightsteelblue" : "#fff"; })
		          .on('click', function(d, i) {
		        	  window.location.href = "../phenotypes/"  + d.id;
			 });

		     node.append("text")
		          .attr("x", function(d) { return d.children ?  8 : -8; })
		          .attr("y", 3)
		          .attr("class", "treeLabel")
		          .style("text-anchor", function(d) { return d.children ? "start" : "end"; })
		          .text(function(d) { return d.children ? "current page" : shortenLabel(d.name); })
		          .attr("transform", function(d) {return d.children ? "rotate(270)" : ""})
	  		      .style("width", "150px")
	  		      .on('click', function(d, i) {
					  window.location.href = "../phenotypes/"  + d.id;
	  		  }) ; // width of the node labels;
	    });

	    d3.json("../mpTree/json/" + mp_id + "?type=children", function(error, root) {

		    var svg = d3.select("#childDiv").append("svg")
		        .attr("width", width)
		        .attr("height", height)
		        .append("g")
		        .attr("transform", "translate(5,0)");

		     if (error){
		    	  console.log(error);
		    	  throw error;
		   	 }

		     if (root.children.length == 0){
		    		hasParents = false;
		    		d3.select("#childDiv").remove();
		    		d3.selectAll("#parentDiv")
		    		  .classed("half", false);

			        svgP.attr("transform", "translate(100,0)");
		  	 }

		     var nodes = cluster.nodes(root),
		          links = cluster.links(nodes);

		     var link = svg.selectAll(".link")
		          .data(links)
		          .enter().append("path")
		          .attr("class", "link")
		          .attr("d", d3.svg.diagonal().projection(function(d) { return [orientation_right.x(d), orientation_right.y(d)]; }));

		     var node = svg.selectAll(".node")
		          .data(nodes)
		          .enter().append("g")
		          .attr("class", "node")
		          .attr("transform", function(d) { return "translate(" +  orientation_right.x(d) + "," + orientation_right.y(d) + ")"; })

		     node.append("circle")
		          .attr("r", 4.5)
		          .style("fill", function(d) { return d.children ? "lightsteelblue" : "#fff"; })
		          .on('click', function(d, i) {
					  window.location.href = "../phenotypes/"  + d.id;
				   });

		     node.append("text")
		          .attr("x", function(d) { return d.children ? -8 : 8; })
		          .attr("y", 3)
		          .attr("class", "treeLabel")
		          .style("text-anchor", function(d) { return d.children ? "start" : "start"; })
		          .attr("transform", function(d) {return d.children ? "rotate(270) translate (15,0)" : ""})
		          .text(function(d) { return d.children ? "current page" : shortenLabel(d.name); })
	   		      .style("width", "150px")
	   		      .on('click', function(d, i) {
					  window.location.href = "../phenotypes/"  + d.id;
				   }); // width of the node labels;
	    });

	    d3.select(self.frameElement).style("height", height + "px");
	    <|endoftext|>


<commit_before>/*
 * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
 */

define([
    'underscore',
    'contrail-view'
], function (_, ContrailView) {
    var DiskGridView = ContrailView.extend({
        el: $(contentContainer),

        render: function () {
            var self = this,
                viewConfig = this.attributes.viewConfig,
                storageNodeName = viewConfig['storageNode'],
                pagerOptions = viewConfig['pagerOptions'];

            var diskRemoteConfig = {
                url: storageNodeName != null ? swc.get(swc.URL_STORAGENODE_DISKS, storageNodeName) : swc.URL_DISKS_SUMMARY,
                type: 'GET'
            };

            var ucid = storageNodeName != null ? (swc.UCID_PREFIX_MS_LISTS + storageNodeName + ":disks") : swc.UCID_ALL_DISK_LIST;

            self.renderView4Config(self.$el, self.model, getDisksGridViewConfig(diskRemoteConfig, ucid, pagerOptions));

        }
    });

    function getDisksGridViewConfig(diskRemoteConfig, ucid, pagerOptions) {
        return {
            elementId: cowu.formatElementId([swl.MONITOR_DISK_LIST_VIEW_ID]),
            view: "SectionView",
            viewConfig: {
                rows: [
                    {
                        columns: [
                            {
                                elementId: swl.MONITOR_DISK_GRID_ID,
                                title: swl.TITLE_DISKS,
                                view: "GridView",
                                viewConfig: {
                                    elementConfig: getDisksGridConfig(diskRemoteConfig, ucid, pagerOptions)
                                }
                            }
                        ]
                    }
                ]
            }
        }
    };

    var getDisksGridConfig = function (diskRemoteConfig, fetchedDiskList, ucid, pagerOptions) {
        var gridElementConfig = {
            header: {
                title: {
                    text: swl.TITLE_DISK_SUMMARY
                },
                defaultControls: {
                    collapseable: false,
                    exportable: true,
                    refreshable: true,
                    searchable: true
                }
            },
            body: {
                options: {
                    autoRefresh: false,
                    checkboxSelectable: false,
                    detail: {
                        template: cowu.generateDetailTemplateHTML(getDiskDetailsTemplateConfig(), cowc.APP_CONTRAIL_STORAGE, 'rawData')
                    },
                    fixedRowHeight: 30
                },
                dataSource: {
                    remote: {
                        ajaxConfig: diskRemoteConfig,
                        onAllRequestsCompleteCB : function(diskListModel) {
                            var fetchContrailListModel = new ContrailListModel({
                                remote : {
                                    ajaxConfig : {
                                       url: ucid != null ? swc.get(swc.URL_STORAGENODE_DISKS, ucid) : swc.URL_DISKS_SUMMARY + '?forceRefresh',
                                    },
                                    onAllRequestsCompleteCB: function(fetchedDiskListModel) {
                                        var data = fetchedDiskListModel.getItems();
                                        diskListModel.setData(data);
                                    },
                                    dataParser: swp.disksDataParser
                                },
                            });
                        },
                        dataParser: swp.disksDataParser
                    },
                    cacheConfig: {
                        ucid: ucid
                    }
                }
            },
            columnHeader: {
                columns: swgc.disksColumns
            },
            footer: {
                pager: contrail.handleIfNull(pagerOptions, {options: {pageSize: 5, pageSizeSelect: [5, 10, 50, 100]}})
            }
        };
        return gridElementConfig;
    };

    function getDiskDetailsTemplateConfig() {
        //TODO: Complete
        return {
            templateGenerator: 'RowSectionTemplateGenerator',
            templateGeneratorConfig: {
                rows: [
                    {
                        templateGenerator: 'ColumnSectionTemplateGenerator',
                        templateGeneratorConfig: {
                            columns: [
                                {
                                    class: 'span6',
                                    rows: [
                                        {
                                            title: swl.TITLE_DISK_DETAILS,
                                            templateGenerator: 'BlockListTemplateGenerator',
                                            templateGeneratorConfig: [
                                                {
                                                    key: 'id',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'name',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'host',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'status_tmpl',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'cluster_status_tmpl',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'public_addr',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'state',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'uuid',
                                                    templateGenerator: 'TextGenerator'
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    class: 'span6',
                                    rows: [
                                        {
                                            title: swl.TITLE_DISK_USAGE,
                                            templateGenerator: 'BlockListTemplateGenerator',
                                            templateGeneratorConfig: [
                                                {
                                                    key: 'used',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'total',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'available',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'apply_latency',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'commit_latency',
                                                    templateGenerator: 'TextGenerator'
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    }
                ]
            }
        };
    };

    return DiskGridView;
});
<commit_msg>Fixed broken Test Case<commit_after>
/*
 * Copyright (c) 2014 Juniper Networks, Inc. All rights reserved.
 */

define([
    'underscore',
    'contrail-view'
], function (_, ContrailView) {
    var DiskGridView = ContrailView.extend({
        el: $(contentContainer),

        render: function () {
            var self = this,
                viewConfig = this.attributes.viewConfig,
                storageNodeName = viewConfig['storageNode'],
                pagerOptions = viewConfig['pagerOptions'];

            var diskRemoteConfig = {
                url: storageNodeName != null ? swc.get(swc.URL_STORAGENODE_DISKS, storageNodeName) : swc.URL_DISKS_SUMMARY,
                type: 'GET'
            };

            var ucid = storageNodeName != null ? (swc.UCID_PREFIX_MS_LISTS + storageNodeName + ":disks") : swc.UCID_ALL_DISK_LIST;

            self.renderView4Config(self.$el, self.model, getDisksGridViewConfig(diskRemoteConfig, ucid, pagerOptions));

        }
    });

    function getDisksGridViewConfig(diskRemoteConfig, ucid, pagerOptions) {
        return {
            elementId: cowu.formatElementId([swl.MONITOR_DISK_LIST_VIEW_ID]),
            view: "SectionView",
            viewConfig: {
                rows: [
                    {
                        columns: [
                            {
                                elementId: swl.MONITOR_DISK_GRID_ID,
                                title: swl.TITLE_DISKS,
                                view: "GridView",
                                viewConfig: {
                                    elementConfig: getDisksGridConfig(diskRemoteConfig, ucid, pagerOptions)
                                }
                            }
                        ]
                    }
                ]
            }
        }
    };

    var getDisksGridConfig = function (diskRemoteConfig, ucid, pagerOptions) {

        var gridElementConfig = {
            header: {
                title: {
                    text: swl.TITLE_DISK_SUMMARY
                },
                defaultControls: {
                    collapseable: false,
                    exportable: true,
                    refreshable: true,
                    searchable: true
                }
            },
            body: {
                options: {
                    autoRefresh: false,
                    checkboxSelectable: false,
                    detail: {
                        template: cowu.generateDetailTemplateHTML(getDiskDetailsTemplateConfig(), cowc.APP_CONTRAIL_STORAGE, 'rawData')
                    },
                    fixedRowHeight: 30
                },
                dataSource: {
                    remote: {
                        ajaxConfig: diskRemoteConfig,
                        dataParser: swp.disksDataParser
                    },
                    cacheConfig: {
                        ucid: ucid
                    }
                }
            },
            columnHeader: {
                columns: swgc.disksColumns
            },
            footer: {
                pager: contrail.handleIfNull(pagerOptions, {options: {pageSize: 5, pageSizeSelect: [5, 10, 50, 100]}})
            }
        };
        return gridElementConfig;
    };

    function getDiskDetailsTemplateConfig() {
        //TODO: Complete
        return {
            templateGenerator: 'RowSectionTemplateGenerator',
            templateGeneratorConfig: {
                rows: [
                    {
                        templateGenerator: 'ColumnSectionTemplateGenerator',
                        templateGeneratorConfig: {
                            columns: [
                                {
                                    class: 'span6',
                                    rows: [
                                        {
                                            title: swl.TITLE_DISK_DETAILS,
                                            templateGenerator: 'BlockListTemplateGenerator',
                                            templateGeneratorConfig: [
                                                {
                                                    key: 'id',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'name',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'host',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'status_tmpl',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'cluster_status_tmpl',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'public_addr',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'state',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'uuid',
                                                    templateGenerator: 'TextGenerator'
                                                }
                                            ]
                                        }
                                    ]
                                },
                                {
                                    class: 'span6',
                                    rows: [
                                        {
                                            title: swl.TITLE_DISK_USAGE,
                                            templateGenerator: 'BlockListTemplateGenerator',
                                            templateGeneratorConfig: [
                                                {
                                                    key: 'used',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'total',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'available',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'apply_latency',
                                                    templateGenerator: 'TextGenerator'
                                                },
                                                {
                                                    key: 'commit_latency',
                                                    templateGenerator: 'TextGenerator'
                                                }
                                            ]
                                        }
                                    ]
                                }
                            ]
                        }
                    }
                ]
            }
        };
    };

    return DiskGridView;
});

<|endoftext|>


<commit_before>/* global moment */
import { push } from 'react-router-redux';
import { fromJS } from 'immutable';
import { getEntityModule } from './entity-module';
import StoreFactory from '../store/store-factory';
import enquiryModule from './enquiries';
import cashFlowModule from './cash-flows';

const ENTITY_URL = 'purchaseOrders';
const ENTITY_LABEL = 'Purchase Orders';

const INITIAL_STATE = fromJS({
  entityConfig: {
    apiUrl: ENTITY_URL,
    label: ENTITY_LABEL,
    url: ENTITY_URL,
    identity: '_id',
    fields: [
      { label: '_id', name: '_id', type: 'hidden' },
      { label: 'enquiryId', name: 'enquiryId', type: 'hidden' },
      { label: 'Sign Date', name: 'signDate', type: 'date', defaultValue: () =>
        new Date().toISOString().substring(0, 10) },
      { label: 'PO#', name: 'poNum', type: 'text' },
      { label: 'Purchase', name: 'purchase', type: 'choice', choices: [
        '', 'Eva', 'Lucy', 'Dawson', 'Penny', 'Matthew'
      ] },
      { label: 'Sales', name: 'sales', type: 'choice', choices: [
        '', 'Dawson', 'Penny', 'Matthew'
      ] },
      { label: 'Company Name', name: 'companyName', type: 'text' },
      { label: 'Contact Person', name: 'contactPerson', type: 'text' },
      { label: 'Tel(s)', name: 'tels', type: 'text' },
      { label: 'Email(s)', name: 'emails', type: 'text' },
      { label: 'Delivery Address', name: 'deliveryAddress', type: 'textarea' },
      { label: 'Description', name: 'description', type: 'textarea' },
      { label: '廠', name: 'factory', type: 'text' },
      { label: '成本 (RMB)', name: 'cost', type: 'number', defaultValue: 0 },
      { label: '單價', name: 'price', type: 'number', defaultValue: 0 },
      { label: '數量', name: 'amount', type: 'number', defaultValue: 0 },
      { label: '備品', name: 'spareAmount', type: 'number', defaultValue: 0 },
      { label: '其他成本 (RMB)', name: 'otherCost', type: 'number', defaultValue: 0 },
      { label: '預計物流成本 (RMB)', name: 'logisticsCost', type: 'number', defaultValue: 0 },
      { label: '預計出樣板日', name: 'sampleDate', type: 'date' },
      { label: '預計出貨日', name: 'deliveryDate', type: 'date' },
      { label: '預計收尾數日', name: 'deadline', type: 'date', validations: { required: true } },
      { label: '狀態', name: 'status', type: 'choice', choices: [
        'New', 'Sample', 'Manufacturing', 'Delivering', 'Done', 'Closed'
      ], defaultValue: 'New' },
      { label: 'Finish Date', name: 'finishDate', type: 'date' },
      { label: 'Remarks', name: 'remarks', type: 'textarea' },
      { label: 'G.P. %', name: 'gpPercentage', transform: (value, entity) =>
        calculateGpPercentage(entity.toJS()), notEditable: true },
      { label: 'Est. Profit (HKD)', name: 'estimateProfit', transform: (value, entity) =>
        calculateGp(entity.toJS()), notEditable: true },
      { label: '已收客訂金', name: 'paidDeposit', type: 'bool' },
      { label: '已收客尾數', name: 'paidRemaining', type: 'bool' },
      { label: '已付廠訂金', name: 'paidFactoryDeposit', type: 'bool' },
      { label: '已付廠尾數', name: 'paidFactoryRemaining', type: 'bool' }
    ],
    iconClass: 'grid'
  },
  listView: {
    ui: {
      title: `All ${ENTITY_LABEL}`,
      loading: false,
      error: null,
      order: [[0, 'desc']],
      page: 0,
      search: '',
      filters: [
        { name: 'purchase' },
        { name: 'sales' },
        { name: 'status' }
      ],
      cssClass: entity => `tr-${entity.get('status')}`,
      actions: ['export', 'toggle'],
      listActions: ['edit', 'delete'],
      displayClosedDone: false,
      displayContextMenu: false,
      contextMenuLeft: 0,
      contextMenuTop: 0
    },
    data: {
      entities: [],
      contextMenuEntity: null
    }
  },
  newView: {
    ui: {
      title: `New ${ENTITY_LABEL}`,
      loading: false,
      error: null
    },
    data: {
      entity: null
    }
  },
  editView: {
    ui: {
      title: `Edit ${ENTITY_LABEL}`,
      loading: false,
      error: null
    },
    data: {
      entity: null
    }
  }
});

function calculateGp(purchaseOrder) {
  // TODO: move this to settings
  const EX_HKD_RMB = 0.843;
  const totalPrice = purchaseOrder.price * purchaseOrder.amount;
  const totalCost = purchaseOrder.cost *
    (purchaseOrder.amount + (purchaseOrder.spareAmount || 0)) +
    (purchaseOrder.otherCost || 0) + (purchaseOrder.logisticsCost || 0);
  const gp = totalPrice - totalCost / EX_HKD_RMB;

  // Invariant Violation, can be fixed using toString?
  return Math.round(gp || 0).toString();
}

function calculateGpPercentage(purchaseOrder) {
  const totalPrice = purchaseOrder.price * purchaseOrder.amount;

  if (totalPrice === 0) return '';

  const gp = calculateGp(purchaseOrder);
  const gpPercentage = gp / totalPrice;

  return `${((gpPercentage || 0) * 100).toFixed(1)}%`;
}

const originalEntityModule = getEntityModule(ENTITY_URL, INITIAL_STATE);

export default Object.assign({}, originalEntityModule, (() => {
  // Override create
  const START_CREATE = `${ENTITY_URL}/START_CREATE`;
  const CREATE_SUCCESS = `${ENTITY_URL}/CREATE_SUCCESS`;
  const CREATE_FAILURE = `${ENTITY_URL}/CREATE_FAILURE`;

  // Fetch related enquiry
  const START_FETCH_ENQUIRY_FOR_NEW_VIEW = `${ENTITY_URL}/START_FETCH_ENQUIRY_FOR_NEW_VIEW`;
  const FETCH_ENQUIRY_FOR_NEW_VIEW_SUCCESS = `${ENTITY_URL}/FETCH_ENQUIRY_FOR_NEW_VIEW_SUCCESS`;
  const FETCH_ENQUIRY_FOR_NEW_VIEW_FAILURE = `${ENTITY_URL}/FETCH_ENQUIRY_FOR_NEW_VIEW_FAILURE`;

  // Fetch purchase orders for the same enquiryId to calculate poNum
  const START_FETCH_DUPLICATES_FOR_NEW_VIEW =
    `${ENTITY_URL}/START_FETCH_DUPLICATES_FOR_NEW_VIEW`;
  const FETCH_DUPLICATES_FOR_NEW_VIEW_SUCCESS =
    `${ENTITY_URL}/FETCH_DUPLICATES_FOR_NEW_VIEW_SUCCESS`;
  const FETCH_DUPLICATES_FOR_NEW_VIEW_FAILURE =
    `${ENTITY_URL}/FETCH_DUPLICATES_FOR_NEW_VIEW_FAILURE`;

  // Create cash flow records
  const START_CREATE_CASH_FLOWS = `${ENTITY_URL}/START_CREATE_CASH_FLOWS`;

  return {

    // Extends the original reducer
    reducer: (originalState, action) => {
      // Run the original reducer first
      const state = originalEntityModule.reducer(originalState, action);

      // Chain with new reducer
      switch (action.type) {
        case START_CREATE:
          // set loading
          return state.setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], true);
        case CREATE_SUCCESS:
          // set responded data and cancel loading
          return state.setIn(['newView', 'data', 'created'], fromJS(action.payload))
            .setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], false);
        case CREATE_FAILURE:
          // set error and cancel loading
          return state.setIn(['newView', 'ui', 'error'], action.payload)
            .setIn(['newView', 'ui', 'loading'], false);
        case START_FETCH_ENQUIRY_FOR_NEW_VIEW:
          // set loading
          return state.setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], true);
        case FETCH_ENQUIRY_FOR_NEW_VIEW_SUCCESS:
          // set responded data and cancel loading
          return state.setIn(['newView', 'data', 'enquiry'], fromJS(action.payload))
            .setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], false);
        case FETCH_ENQUIRY_FOR_NEW_VIEW_FAILURE:
          // set error and cancel loading
          return state.setIn(['newView', 'ui', 'error'], action.payload)
            .setIn(['newView', 'ui', 'loading'], false);
        case START_FETCH_DUPLICATES_FOR_NEW_VIEW:
          // set loading
          return state.setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], true);
        case FETCH_DUPLICATES_FOR_NEW_VIEW_SUCCESS:
          // set responded data and cancel loading
          return state.setIn(['newView', 'data', 'duplicates'], fromJS(action.payload))
            .setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], false);
        case FETCH_DUPLICATES_FOR_NEW_VIEW_FAILURE:
          // set error and cancel loading
          return state.setIn(['newView', 'ui', 'error'], action.payload)
            .setIn(['newView', 'ui', 'loading'], false);
        case START_CREATE_CASH_FLOWS:
          // no state change
          // TODO: any ui logics for create cash flow records?
          return state;
        default:
          return state;
      }
    },

    // Override to create cash flows
    // FIXME: duplicate code with entity-module.js
    create: (fields, redirectUrl) => (dispatch, getState) => {
      const user = getState().users.getIn(['data', 'user']);
      const mergedFields = Object.assign(fields, {
        username: user && user.get('username'),
        createdAt: moment().format('YYYY-MM-DD')
      });

      dispatch(startCreate(mergedFields, redirectUrl));

      const apiUrl = getState()[ENTITY_URL].getIn(['entityConfig', 'apiUrl']);

      StoreFactory.getInstance().insert(apiUrl, mergedFields, (error, _id) => {
        if (error) {
          dispatch(createFailure(error));
        } else {
          const createdEntity = Object.assign({}, mergedFields, { _id });
          dispatch(createSuccess(createdEntity));

          if (redirectUrl) {
            dispatch(push(redirectUrl));
          }

          // Create cash flow records
          dispatch(createCashFlowsAction(_id));
        }
      });
    },

    fetchEnquiryForNewView: enquiryId => (dispatch, getState) => {
      dispatch(startFetchEnquiryForNewView(enquiryId));

      const apiUrl = getState()[enquiryModule.entityUrl].getIn(['entityConfig', 'apiUrl']);

      StoreFactory.getInstance().retrieveOne(apiUrl, enquiryId, enquiry => {
        if (!enquiry) {
          dispatch(fetchEnquiryForNewViewFailure('related enquiry not found'));
        } else {
          dispatch(fetchEnquiryForNewViewSuccess(enquiry));
        }
      });
    },

    fetchDuplicatesForNewView: enquiryId => (dispatch, getState) => {
      dispatch(startFetchDuplicatesForNewView(enquiryId));

      const apiUrl = getState()[ENTITY_URL].getIn(['entityConfig', 'apiUrl']);

      StoreFactory.getInstance().retrieveBy(apiUrl, 'enquiryId', enquiryId, duplicates => {
        if (!duplicates) {
          dispatch(fetchDuplicatesForNewViewFailure('not found'));
        } else {
          dispatch(fetchDuplicatesForNewViewSuccess(duplicates));
        }
      });
    },

    createCashFlows: createCashFlowsAction

  };

  function createCashFlowsAction(_id) {
    return (dispatch, getState) => {
      dispatch(startCreateCashFlows(_id));

      const apiUrl = getState()[ENTITY_URL].getIn(['entityConfig', 'apiUrl']);

      StoreFactory.getInstance().retrieveOne(apiUrl, _id, purchaseOrder => {
        const startDate = purchaseOrder.sampleDate || purchaseOrder.signDate;
        // deadline is required
        const deadline = purchaseOrder.deadline;
        // set deliveryDate to deadline if not provided
        const deliveryDate = purchaseOrder.deliveryDate || deadline;

        const totalCost = purchaseOrder.cost * (purchaseOrder.amount + purchaseOrder.spareAmount);
        const totalPrice = purchaseOrder.price * purchaseOrder.amount;

        if (totalCost !== 0) {
          // [1/4] Factory deposit
          dispatch(cashFlowModule.create({
            purchaseOrderId: purchaseOrder._id,
            sales: purchaseOrder.sales,
            type: 2,
            title: `${purchaseOrder.poNum}廠訂金 (${purchaseOrder.companyName})`,
            date: startDate,
            amount: totalCost * 0.3,
            done: false
          }));

          // [2/4] Factory remaining
          dispatch(cashFlowModule.create({
            purchaseOrderId: purchaseOrder._id,
            sales: purchaseOrder.sales,
            type: 3,
            title: `${purchaseOrder.poNum}廠尾數 (${purchaseOrder.companyName})`,
            date: deliveryDate,
            amount: totalCost * 0.7,
            done: false
          }));
        }

        if (totalPrice !== 0) {
          // [3/4] Client deposit
          dispatch(cashFlowModule.create({
            purchaseOrderId: purchaseOrder._id,
            sales: purchaseOrder.sales,
            type: 0,
            title: `${purchaseOrder.poNum}客訂金 (${purchaseOrder.companyName})`,
            date: startDate,
            amount: totalPrice * 0.5,
            done: false
          }));

          // [4/4] Client remaining
          dispatch(cashFlowModule.create({
            purchaseOrderId: purchaseOrder._id,
            sales: purchaseOrder.sales,
            type: 1,
            title: `${purchaseOrder.poNum}客尾數 (${purchaseOrder.companyName})`,
            date: deadline,
            amount: totalPrice * 0.5,
            done: false
          }));
        }
      });
    };
  }

  /**
   * Dispatch this when start a create process
   */
  function startCreate(mergedFields, redirectUrl) {
    return {
      type: START_CREATE,
      payload: { mergedFields, redirectUrl }
    };
  }

  /**
   * Dispatch this when get a successful response
   */
  function createSuccess(entity) {
    return {
      type: CREATE_SUCCESS,
      payload: entity
    };
  }

  /**
   * Dispatch this when get a failed response
   */
  function createFailure(error) {
    return {
      type: CREATE_FAILURE,
      payload: error
    };
  }

  /**
   * Dispatch this when start a fetch process
   */
  function startFetchEnquiryForNewView(enquiryId) {
    return {
      type: START_FETCH_ENQUIRY_FOR_NEW_VIEW,
      payload: enquiryId
    };
  }

  /**
   * Dispatch this when get a successful response
   */
  function fetchEnquiryForNewViewSuccess(enquiry) {
    return {
      type: FETCH_ENQUIRY_FOR_NEW_VIEW_SUCCESS,
      payload: enquiry
    };
  }

  /**
   * Dispatch this when get a failed response
   */
  function fetchEnquiryForNewViewFailure(error) {
    return {
      type: FETCH_ENQUIRY_FOR_NEW_VIEW_FAILURE,
      payload: error
    };
  }

  /**
   * Dispatch this when start a fetch process
   */
  function startFetchDuplicatesForNewView(enquiryId) {
    return {
      type: START_FETCH_DUPLICATES_FOR_NEW_VIEW,
      payload: enquiryId
    };
  }

  /**
   * Dispatch this when get a successful response
   */
  function fetchDuplicatesForNewViewSuccess(duplicates) {
    return {
      type: FETCH_DUPLICATES_FOR_NEW_VIEW_SUCCESS,
      payload: duplicates
    };
  }

  /**
   * Dispatch this when get a failed response
   */
  function fetchDuplicatesForNewViewFailure(error) {
    return {
      type: FETCH_DUPLICATES_FOR_NEW_VIEW_FAILURE,
      payload: error
    };
  }

  /**
   * Dispatch this when start a create process
   */
  function startCreateCashFlows(_id) {
    return {
      type: START_CREATE_CASH_FLOWS,
      payload: _id
    };
  }
})());
<commit_msg>fix float precision problem when creating cash flows from purchase order<commit_after>/* global moment */
import { push } from 'react-router-redux';
import { fromJS } from 'immutable';
import { getEntityModule } from './entity-module';
import StoreFactory from '../store/store-factory';
import enquiryModule from './enquiries';
import cashFlowModule from './cash-flows';

const ENTITY_URL = 'purchaseOrders';
const ENTITY_LABEL = 'Purchase Orders';

const INITIAL_STATE = fromJS({
  entityConfig: {
    apiUrl: ENTITY_URL,
    label: ENTITY_LABEL,
    url: ENTITY_URL,
    identity: '_id',
    fields: [
      { label: '_id', name: '_id', type: 'hidden' },
      { label: 'enquiryId', name: 'enquiryId', type: 'hidden' },
      { label: 'Sign Date', name: 'signDate', type: 'date', defaultValue: () =>
        new Date().toISOString().substring(0, 10) },
      { label: 'PO#', name: 'poNum', type: 'text' },
      { label: 'Purchase', name: 'purchase', type: 'choice', choices: [
        '', 'Eva', 'Lucy', 'Dawson', 'Penny', 'Matthew'
      ] },
      { label: 'Sales', name: 'sales', type: 'choice', choices: [
        '', 'Dawson', 'Penny', 'Matthew'
      ] },
      { label: 'Company Name', name: 'companyName', type: 'text' },
      { label: 'Contact Person', name: 'contactPerson', type: 'text' },
      { label: 'Tel(s)', name: 'tels', type: 'text' },
      { label: 'Email(s)', name: 'emails', type: 'text' },
      { label: 'Delivery Address', name: 'deliveryAddress', type: 'textarea' },
      { label: 'Description', name: 'description', type: 'textarea' },
      { label: '廠', name: 'factory', type: 'text' },
      { label: '成本 (RMB)', name: 'cost', type: 'number', defaultValue: 0 },
      { label: '單價', name: 'price', type: 'number', defaultValue: 0 },
      { label: '數量', name: 'amount', type: 'number', defaultValue: 0 },
      { label: '備品', name: 'spareAmount', type: 'number', defaultValue: 0 },
      { label: '其他成本 (RMB)', name: 'otherCost', type: 'number', defaultValue: 0 },
      { label: '預計物流成本 (RMB)', name: 'logisticsCost', type: 'number', defaultValue: 0 },
      { label: '預計出樣板日', name: 'sampleDate', type: 'date' },
      { label: '預計出貨日', name: 'deliveryDate', type: 'date' },
      { label: '預計收尾數日', name: 'deadline', type: 'date', validations: { required: true } },
      { label: '狀態', name: 'status', type: 'choice', choices: [
        'New', 'Sample', 'Manufacturing', 'Delivering', 'Done', 'Closed'
      ], defaultValue: 'New' },
      { label: 'Finish Date', name: 'finishDate', type: 'date' },
      { label: 'Remarks', name: 'remarks', type: 'textarea' },
      { label: 'G.P. %', name: 'gpPercentage', transform: (value, entity) =>
        calculateGpPercentage(entity.toJS()), notEditable: true },
      { label: 'Est. Profit (HKD)', name: 'estimateProfit', transform: (value, entity) =>
        calculateGp(entity.toJS()), notEditable: true },
      { label: '已收客訂金', name: 'paidDeposit', type: 'bool' },
      { label: '已收客尾數', name: 'paidRemaining', type: 'bool' },
      { label: '已付廠訂金', name: 'paidFactoryDeposit', type: 'bool' },
      { label: '已付廠尾數', name: 'paidFactoryRemaining', type: 'bool' }
    ],
    iconClass: 'grid'
  },
  listView: {
    ui: {
      title: `All ${ENTITY_LABEL}`,
      loading: false,
      error: null,
      order: [[0, 'desc']],
      page: 0,
      search: '',
      filters: [
        { name: 'purchase' },
        { name: 'sales' },
        { name: 'status' }
      ],
      cssClass: entity => `tr-${entity.get('status')}`,
      actions: ['export', 'toggle'],
      listActions: ['edit', 'delete'],
      displayClosedDone: false,
      displayContextMenu: false,
      contextMenuLeft: 0,
      contextMenuTop: 0
    },
    data: {
      entities: [],
      contextMenuEntity: null
    }
  },
  newView: {
    ui: {
      title: `New ${ENTITY_LABEL}`,
      loading: false,
      error: null
    },
    data: {
      entity: null
    }
  },
  editView: {
    ui: {
      title: `Edit ${ENTITY_LABEL}`,
      loading: false,
      error: null
    },
    data: {
      entity: null
    }
  }
});

function calculateGp(purchaseOrder) {
  // TODO: move this to settings
  const EX_HKD_RMB = 0.843;
  const totalPrice = purchaseOrder.price * purchaseOrder.amount;
  const totalCost = purchaseOrder.cost *
    (purchaseOrder.amount + (purchaseOrder.spareAmount || 0)) +
    (purchaseOrder.otherCost || 0) + (purchaseOrder.logisticsCost || 0);
  const gp = totalPrice - totalCost / EX_HKD_RMB;

  // Invariant Violation, can be fixed using toString?
  return Math.round(gp || 0).toString();
}

function calculateGpPercentage(purchaseOrder) {
  const totalPrice = purchaseOrder.price * purchaseOrder.amount;

  if (totalPrice === 0) return '';

  const gp = calculateGp(purchaseOrder);
  const gpPercentage = gp / totalPrice;

  return `${((gpPercentage || 0) * 100).toFixed(1)}%`;
}

const originalEntityModule = getEntityModule(ENTITY_URL, INITIAL_STATE);

export default Object.assign({}, originalEntityModule, (() => {
  // Override create
  const START_CREATE = `${ENTITY_URL}/START_CREATE`;
  const CREATE_SUCCESS = `${ENTITY_URL}/CREATE_SUCCESS`;
  const CREATE_FAILURE = `${ENTITY_URL}/CREATE_FAILURE`;

  // Fetch related enquiry
  const START_FETCH_ENQUIRY_FOR_NEW_VIEW = `${ENTITY_URL}/START_FETCH_ENQUIRY_FOR_NEW_VIEW`;
  const FETCH_ENQUIRY_FOR_NEW_VIEW_SUCCESS = `${ENTITY_URL}/FETCH_ENQUIRY_FOR_NEW_VIEW_SUCCESS`;
  const FETCH_ENQUIRY_FOR_NEW_VIEW_FAILURE = `${ENTITY_URL}/FETCH_ENQUIRY_FOR_NEW_VIEW_FAILURE`;

  // Fetch purchase orders for the same enquiryId to calculate poNum
  const START_FETCH_DUPLICATES_FOR_NEW_VIEW =
    `${ENTITY_URL}/START_FETCH_DUPLICATES_FOR_NEW_VIEW`;
  const FETCH_DUPLICATES_FOR_NEW_VIEW_SUCCESS =
    `${ENTITY_URL}/FETCH_DUPLICATES_FOR_NEW_VIEW_SUCCESS`;
  const FETCH_DUPLICATES_FOR_NEW_VIEW_FAILURE =
    `${ENTITY_URL}/FETCH_DUPLICATES_FOR_NEW_VIEW_FAILURE`;

  // Create cash flow records
  const START_CREATE_CASH_FLOWS = `${ENTITY_URL}/START_CREATE_CASH_FLOWS`;

  return {

    // Extends the original reducer
    reducer: (originalState, action) => {
      // Run the original reducer first
      const state = originalEntityModule.reducer(originalState, action);

      // Chain with new reducer
      switch (action.type) {
        case START_CREATE:
          // set loading
          return state.setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], true);
        case CREATE_SUCCESS:
          // set responded data and cancel loading
          return state.setIn(['newView', 'data', 'created'], fromJS(action.payload))
            .setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], false);
        case CREATE_FAILURE:
          // set error and cancel loading
          return state.setIn(['newView', 'ui', 'error'], action.payload)
            .setIn(['newView', 'ui', 'loading'], false);
        case START_FETCH_ENQUIRY_FOR_NEW_VIEW:
          // set loading
          return state.setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], true);
        case FETCH_ENQUIRY_FOR_NEW_VIEW_SUCCESS:
          // set responded data and cancel loading
          return state.setIn(['newView', 'data', 'enquiry'], fromJS(action.payload))
            .setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], false);
        case FETCH_ENQUIRY_FOR_NEW_VIEW_FAILURE:
          // set error and cancel loading
          return state.setIn(['newView', 'ui', 'error'], action.payload)
            .setIn(['newView', 'ui', 'loading'], false);
        case START_FETCH_DUPLICATES_FOR_NEW_VIEW:
          // set loading
          return state.setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], true);
        case FETCH_DUPLICATES_FOR_NEW_VIEW_SUCCESS:
          // set responded data and cancel loading
          return state.setIn(['newView', 'data', 'duplicates'], fromJS(action.payload))
            .setIn(['newView', 'ui', 'error'], null)
            .setIn(['newView', 'ui', 'loading'], false);
        case FETCH_DUPLICATES_FOR_NEW_VIEW_FAILURE:
          // set error and cancel loading
          return state.setIn(['newView', 'ui', 'error'], action.payload)
            .setIn(['newView', 'ui', 'loading'], false);
        case START_CREATE_CASH_FLOWS:
          // no state change
          // TODO: any ui logics for create cash flow records?
          return state;
        default:
          return state;
      }
    },

    // Override to create cash flows
    // FIXME: duplicate code with entity-module.js
    create: (fields, redirectUrl) => (dispatch, getState) => {
      const user = getState().users.getIn(['data', 'user']);
      const mergedFields = Object.assign(fields, {
        username: user && user.get('username'),
        createdAt: moment().format('YYYY-MM-DD')
      });

      dispatch(startCreate(mergedFields, redirectUrl));

      const apiUrl = getState()[ENTITY_URL].getIn(['entityConfig', 'apiUrl']);

      StoreFactory.getInstance().insert(apiUrl, mergedFields, (error, _id) => {
        if (error) {
          dispatch(createFailure(error));
        } else {
          const createdEntity = Object.assign({}, mergedFields, { _id });
          dispatch(createSuccess(createdEntity));

          if (redirectUrl) {
            dispatch(push(redirectUrl));
          }

          // Create cash flow records
          dispatch(createCashFlowsAction(_id));
        }
      });
    },

    fetchEnquiryForNewView: enquiryId => (dispatch, getState) => {
      dispatch(startFetchEnquiryForNewView(enquiryId));

      const apiUrl = getState()[enquiryModule.entityUrl].getIn(['entityConfig', 'apiUrl']);

      StoreFactory.getInstance().retrieveOne(apiUrl, enquiryId, enquiry => {
        if (!enquiry) {
          dispatch(fetchEnquiryForNewViewFailure('related enquiry not found'));
        } else {
          dispatch(fetchEnquiryForNewViewSuccess(enquiry));
        }
      });
    },

    fetchDuplicatesForNewView: enquiryId => (dispatch, getState) => {
      dispatch(startFetchDuplicatesForNewView(enquiryId));

      const apiUrl = getState()[ENTITY_URL].getIn(['entityConfig', 'apiUrl']);

      StoreFactory.getInstance().retrieveBy(apiUrl, 'enquiryId', enquiryId, duplicates => {
        if (!duplicates) {
          dispatch(fetchDuplicatesForNewViewFailure('not found'));
        } else {
          dispatch(fetchDuplicatesForNewViewSuccess(duplicates));
        }
      });
    },

    createCashFlows: createCashFlowsAction

  };

  function createCashFlowsAction(_id) {
    return (dispatch, getState) => {
      dispatch(startCreateCashFlows(_id));

      const apiUrl = getState()[ENTITY_URL].getIn(['entityConfig', 'apiUrl']);

      StoreFactory.getInstance().retrieveOne(apiUrl, _id, purchaseOrder => {
        const startDate = purchaseOrder.sampleDate || purchaseOrder.signDate;
        // deadline is required
        const deadline = purchaseOrder.deadline;
        // set deliveryDate to deadline if not provided
        const deliveryDate = purchaseOrder.deliveryDate || deadline;

        const totalCost = purchaseOrder.cost * (purchaseOrder.amount + purchaseOrder.spareAmount);
        const totalPrice = purchaseOrder.price * purchaseOrder.amount;

        if (totalCost !== 0) {
          // [1/4] Factory deposit
          dispatch(cashFlowModule.create({
            purchaseOrderId: purchaseOrder._id,
            sales: purchaseOrder.sales,
            type: 2,
            title: `${purchaseOrder.poNum}廠訂金 (${purchaseOrder.companyName})`,
            date: startDate,
            amount: +(totalCost * 0.3).toFixed(2),
            done: false
          }));

          // [2/4] Factory remaining
          dispatch(cashFlowModule.create({
            purchaseOrderId: purchaseOrder._id,
            sales: purchaseOrder.sales,
            type: 3,
            title: `${purchaseOrder.poNum}廠尾數 (${purchaseOrder.companyName})`,
            date: deliveryDate,
            amount: +(totalCost * 0.7).toFixed(2),
            done: false
          }));
        }

        if (totalPrice !== 0) {
          // [3/4] Client deposit
          dispatch(cashFlowModule.create({
            purchaseOrderId: purchaseOrder._id,
            sales: purchaseOrder.sales,
            type: 0,
            title: `${purchaseOrder.poNum}客訂金 (${purchaseOrder.companyName})`,
            date: startDate,
            amount: +(totalPrice * 0.5).toFixed(2),
            done: false
          }));

          // [4/4] Client remaining
          dispatch(cashFlowModule.create({
            purchaseOrderId: purchaseOrder._id,
            sales: purchaseOrder.sales,
            type: 1,
            title: `${purchaseOrder.poNum}客尾數 (${purchaseOrder.companyName})`,
            date: deadline,
            amount: +(totalPrice * 0.5).toFixed(2),
            done: false
          }));
        }
      });
    };
  }

  /**
   * Dispatch this when start a create process
   */
  function startCreate(mergedFields, redirectUrl) {
    return {
      type: START_CREATE,
      payload: { mergedFields, redirectUrl }
    };
  }

  /**
   * Dispatch this when get a successful response
   */
  function createSuccess(entity) {
    return {
      type: CREATE_SUCCESS,
      payload: entity
    };
  }

  /**
   * Dispatch this when get a failed response
   */
  function createFailure(error) {
    return {
      type: CREATE_FAILURE,
      payload: error
    };
  }

  /**
   * Dispatch this when start a fetch process
   */
  function startFetchEnquiryForNewView(enquiryId) {
    return {
      type: START_FETCH_ENQUIRY_FOR_NEW_VIEW,
      payload: enquiryId
    };
  }

  /**
   * Dispatch this when get a successful response
   */
  function fetchEnquiryForNewViewSuccess(enquiry) {
    return {
      type: FETCH_ENQUIRY_FOR_NEW_VIEW_SUCCESS,
      payload: enquiry
    };
  }

  /**
   * Dispatch this when get a failed response
   */
  function fetchEnquiryForNewViewFailure(error) {
    return {
      type: FETCH_ENQUIRY_FOR_NEW_VIEW_FAILURE,
      payload: error
    };
  }

  /**
   * Dispatch this when start a fetch process
   */
  function startFetchDuplicatesForNewView(enquiryId) {
    return {
      type: START_FETCH_DUPLICATES_FOR_NEW_VIEW,
      payload: enquiryId
    };
  }

  /**
   * Dispatch this when get a successful response
   */
  function fetchDuplicatesForNewViewSuccess(duplicates) {
    return {
      type: FETCH_DUPLICATES_FOR_NEW_VIEW_SUCCESS,
      payload: duplicates
    };
  }

  /**
   * Dispatch this when get a failed response
   */
  function fetchDuplicatesForNewViewFailure(error) {
    return {
      type: FETCH_DUPLICATES_FOR_NEW_VIEW_FAILURE,
      payload: error
    };
  }

  /**
   * Dispatch this when start a create process
   */
  function startCreateCashFlows(_id) {
    return {
      type: START_CREATE_CASH_FLOWS,
      payload: _id
    };
  }
})());
<|endoftext|>