I have applied the advice suggested by @Quill and that helped clean up the code quite a bit, especially the last part where values are appended to the HTML document. The bit about putting the content to append into an array and just iterating over it made the code a lot more DRY!

I also applied @Hosch250's suggestions and extracted the date and number validation logic in two separate functions, `validateDates` and `validateNums`, and that also really helped clean up the code. It also allowed more flexibility in catching other invalid values, which in this case is very important since finances are involved. 

I added a small improvement suggested by @CanadianLuke as well. 

I applied @janos' idea of adding error messages to arrays, then checking for `array.length > 0` and print those values in an alert to the user, like so:

[![errors][1]][1]

**Improved code:**

 <!DOCTYPE html>
 <html>
 <head>
 <title>Prorated Refund Calculator</title>
 <style>
 body {
 font-family: Calibri, Arial, sans-serif;
 font-size: 1.0em;
 }
 h1 {
 font-size: 1.2em;
 }
 </style>
 </head>
 <body>
 <h1>Prorated Refund Calculator</h1>
 <p>Input into the following fields and press Calculate.</p>
 <p style="color: red;">Enter date format as MM/DD/YYYY</p>
 <form>
 <label>Product Purchase Date: <input type="text" id="productPurchaseDate" /> </label><br/>
 <label>Contract Purchase Date: <input type="text" id="contractPurchaseDate" /> </label><br/>
 <label>Purchase Price: <input type="text" id="purchasePrice" /> </label><br/>
 <label>Term (in years): <input type="text" id="termInYears" value="10" /> </label><br/>
 <label>Cancel Date: <input type="text" id="cancelDate" /> </label><br/>
 <label>Amount paid in claims: <input type="text" id="amtPaidInClaims" value="0" /> </label><br/>
 <label>Grace period (in days): <input type="text" id="gracePeriodInDays" value="60" /></label><br/>
 </form>
 <br/>
 <button onclick="calculateProratedRefund()">Calculate</button>
 
 <script type="text/javascript">
 
 
 /* Main function called by HTML form.
 * Validates input values, then performs calculations 
 * and adds the result into the HTML document to display to the user. */
 function calculateProratedRefund() {
 "use strict";
 
 var productPurchaseDate = new Date (document.getElementById("productPurchaseDate").value);
 var contractPurchaseDate = new Date (document.getElementById("contractPurchaseDate").value);
 var purchasePrice = parseFloat (document.getElementById("purchasePrice").value).toFixed(2);
 var termInYears = parseInt (document.getElementById("termInYears").value, 10);
 var cancelDate = new Date (document.getElementById("cancelDate").value);
 var amtPaidInClaims = parseFloat (document.getElementById("amtPaidInClaims").value).toFixed(2);
 var gracePeriodInDays = parseInt (document.getElementById("gracePeriodInDays").value, 10);
 
 /* Underwriting policies specify that a Year of coverage is exactly 365 Days, regardless of Leap Years.
 * Hence the following calculations: */
 var totalDays = termInYears * 365;
 var expirationDate = new Date(productPurchaseDate);
 expirationDate.setDate(productPurchaseDate.getDate() + (totalDays));
 
 /* Validation of user input. 
 * If any values are invalid, we return early and exit the function with error message to the user.
 * If all the input values are valid, we proceed to calculations.
 * NOTE: The two validation functions return an array of errors pushed from the called function. 
 * If the array's length is 0 (i.e., empty array) there are no errors. */
 var datesValid = validateDates(productPurchaseDate, contractPurchaseDate, cancelDate, expirationDate);
 var numsValid = validateNums(purchasePrice, termInYears, amtPaidInClaims, gracePeriodInDays);
 if (datesValid.length > 0 || numsValid.length > 0) {
 window.alert("Some values are invalid: \n"
 + "\n" + datesValid.join("\n")
 + "\n" + numsValid.join("\n")
 );
 return false;
 }
 
 /* All terms are calculated in Days, hence the following conversion from JavaScript's millisecond precision to Days.
 * (ms * secs * mins * hours) = 1 Day */
 var msPerDay = 1000 * 60 * 60 * 24; 
 var daysElapsed = Math.floor((Date.parse(cancelDate) - Date.parse(contractPurchaseDate)) / msPerDay);
 
 /* Policy holder is entitled to a full refund within the grace period.
 * Otherwise, if days elapsed exceed the grace period, the refund becomes prorated. */
 var termUsed = 0.0;
 if (daysElapsed > gracePeriodInDays) {
 termUsed = (daysElapsed / totalDays);
 }
 var termLeft = 1.0 - termUsed;
 
 /* Finally we calculate the refund amount */
 var proratedRefund = (purchasePrice * termLeft).toFixed(2);
 var finalRefund = (proratedRefund - amtPaidInClaims).toFixed(2);
 if (finalRefund < 0.0) {
 finalRefund = 0.0;
 }
 
 /* List of content to append into document. */
 var contentToAppend = [
 "Product Purchase date: " + formatDate(productPurchaseDate),
 "Contract Purchase date: " + formatDate(contractPurchaseDate),
 "Total days: " + totalDays + " (" + termInYears + " years)",
 "Expiration date: " + formatDate(expirationDate),
 "Cancel date: " + formatDate(cancelDate),
 "Grace period: " + gracePeriodInDays + " days",
 "Days elapsed: " + daysElapsed + " (" + parseFloat(daysElapsed / 365).toFixed(4) + " years)",
 "Refund percent: " + (termLeft * 100).toFixed(2) + " %",
 "Purchase price: $ " + purchasePrice,
 "Prorated refund: $ " + proratedRefund,
 "Paid in claims: ($ " + amtPaidInClaims + ")",
 "Final refund: $ " + finalRefund
 ];
 
 /* Append calculation results to HTML document. */
 var outputParagraph = document.createElement("p");
 
 contentToAppend.forEach(function(element) {
 outputParagraph.appendChild(document.createTextNode(element));
 outputParagraph.appendChild(document.createElement("br"));
 });
 
 document.body.appendChild(outputParagraph);
 return true;
 }
 
 
 /** Confirm that all dates are valid Date values and that they follow business rules.
 * @param {Date} productPurchaseDate Date of purchase of the product(s) covered by the contract.
 * @param {Date} contractPurchaseDate Date of purchase of the contract to be cancelled.
 * @param {Date} cancelDate Date on which the cancellation of the contract was requested.
 * @param {Date} expirationDate Date on which the contract expires and is no longer eligible for cancellation or claims payment. 
 * @return {Array} Array of Strings containing all applicable error messages. */
 function validateDates(productPurchaseDate, contractPurchaseDate, cancelDate, expirationDate) {
 "use strict";
 var dateErrors = new Array();
 if (!isValidDate(productPurchaseDate)) {
 dateErrors.push("Invalid Product Purchase Date: " + productPurchaseDate);
 } 
 if (!isValidDate(contractPurchaseDate)) {
 dateErrors.push("Invalid Contract Purchase Date: " + contractPurchaseDate);
 } 
 if (contractPurchaseDate < productPurchaseDate) {
 dateErrors.push("Contract cannot be purchased (" + formatDate(contractPurchaseDate) 
 + ") prior to the product (" + formatDate(productPurchaseDate) + ")");
 } 
 if (!isValidDate(cancelDate)) {
 dateErrors.push("Invalid Cancel Date: " + cancelDate);
 } 
 if (cancelDate < productPurchaseDate || cancelDate < contractPurchaseDate) {
 dateErrors.push("Cancel date (" + formatDate(cancelDate) 
 + ") cannot be prior to Product (" + formatDate(productPurchaseDate) 
 + ") or Contract purchase (" + formatDate(contractPurchaseDate) + ")");
 } 
 if (cancelDate > expirationDate) {
 dateErrors.push("Cancel date (" + formatDate(cancelDate) 
 + ") cannot be past Expiration date (" + formatDate(expirationDate) + ")");
 }
 return dateErrors;
 }
 
 /** Confirm that all numbers are valid numbers and that they follow business rules.
 * @param {number} purchasePrice The dollar amount purchase price of the contract.
 * @param {number} termInYears The duration term of the policy in 365-day years. Must be whole number. 
 * @param {number} amtPaidInClaims The dollar amount of claims paid against the contract prior to cancellation.
 * @param {number} gracePeriodInDays Grace period during which a contract holder can cancel with full refund/credit. Must be whole number.
 * @return {Array} Array of Strings containing all applicable error messages. */
 function validateNums (purchasePrice, termInYears, amtPaidInClaims, gracePeriodInDays) {
 "use strict";
 var numErrors = new Array();
 if (isNaN(purchasePrice) || purchasePrice < 0) {
 numErrors.push("Invalid purchase price: " + purchasePrice);
 } 
 if (isNaN(termInYears) || termInYears < 0) {
 numErrors.push("Invalid term period: " + termInYears);
 } 
 if (isNaN(amtPaidInClaims) || amtPaidInClaims < 0) {
 numErrors.push("Invalid paid claims amount: " + amtPaidInClaims);
 } 
 if (isNaN(gracePeriodInDays) || gracePeriodInDays < 0) {
 numErrors.push("Invalid grace period: " + gracePeriodInDays);
 }
 if (termInYears % 1 !== 0) {
 numErrors.push("Term " + termInYears + " is not a whole number.");
 }
 if (gracePeriodInDays % 1 !== 0) {
 numErrors.push("Grace period " + gracePeriodInDays + " is not a whole number.");
 }
 return numErrors;
 }
 
 /** Utility function to make sure an input is a correct Date format
 * @param {Date} date A date or date-time value.
 * @returns {boolean} Whether the input date is a valid date. */
 function isValidDate(date) {
 "use strict";
 if (isNaN(date.getTime())) {
 return false;
 } 
 return (Object.prototype.toString.call(date) === "[object Date]");
 }
 
 /** Utility function to convert a Date to MM/DD/YYYY formatted String.
 * @param {Date} date A date or date-time value.
 * @returns {string} A String formatted as MM/DD/YYYY if date is valid, otherwise a String with error message. */
 function formatDate(date) {
 "use strict";
 var inputDate = new Date(date);
 if (isValidDate(inputDate)) {
 var year = inputDate.getFullYear().toString();
 var month = (1 + inputDate.getMonth()).toString(); // months are 0-indexed hence the 1 + getMonth()
 var day = inputDate.getDate().toString();
 return(month + '/' + day + '/' + year);
 } 
 else {
 return("Invalid date: " + inputDate);
 }
 }
 
 </script>
 
 </body>
 </html>

<!-- end snippet -->


 [1]: https://i.sstatic.net/G19aB.png