/// <summary> /// Validates CA for usage submittal. Assumes current reporting year. /// </summary> /// <param name="ca"></param> /// <param name="errors"></param> /// <returns></returns> protected bool ValidateContiguousAcres(JsonContiguousAcres ca, out List<string> errors) { errors = new List<string>(); /* MWinckler.20130202: This set of validation is written as CA-specific, but it is * attempting to validate meter-specific conditions. This validation needs to be * rewritten to validate meter readings, and also not rely on calculated boolean * values sent from the (untrustworthy) client. Rely on the actual submitted meter * readings and user inputs - we have them all here. if (ca.isFakingValidReadings) { if(!ca.userRevisedVolume) errors.Add("The end reading for one of the meters is not in the valid reporting range of December 15 to January 15."); } if (ca.notEnoughReadingsForAllMeters) // This also allows user override { if (!ca.userRevisedVolume) errors.Add("One of the meters does not have enough valid readings for volume calculation."); } if (!ca.hasValidBeginReadings) // This also allows user override { if (!ca.userRevisedVolume) errors.Add("One of the meters does not have valid begin readings for volume calculation."); } */ foreach (var mr in ca.meterReadings) { // If this is an annual reading or if the user supplied a revised volume, this validation doesn't matter. if (!mr.Value.readings.Any(x => x.isAnnualTotalReading) && mr.Value.userRevisedVolume.GetValueOrDefault(0) <= 0) { if (mr.Value.readings.Length < 2) { // Too few readings. errors.Add("One of the meters does not have enough valid readings for volume calculation."); } else if (!mr.Value.readings.Any(x => x.isValidBeginReading)) { // Need both a valid begin and a valid end reading. // Note that the above check is not good - it depends on a value // sent by the client. // TODO: Refactor this to not rely on .isValidBeginReading; get // the values needed to validate meter reading against the database // using the methods in ReportingDalc. errors.Add("One of the meters does not have valid begin readings for volume calculation."); } else if (!mr.Value.readings.Any(x => x.isValidEndReading)) { // TODO: See above comment regarding trusting vlient values. errors.Add("One of the meters does not have valid ending readings for volume calculation."); } } } // Ensure the CA actually exists in the database. if (!new GisDalc().ContiguousAcresExists(ca.number)) { errors.Add("The specified contiguous area (ID: " + ca.number + ") does not exist."); } else { // (the remainder of validation is only useful if the CA actually exists) // Verify that the user is actually associated with the CA if (!new GisDalc().OwnsContiguousAcres(ActualUser, ca.number)) { errors.Add("Records show that you do not own the specified contiguous acres. You may not record banked water for this area."); return false; } // Ensure the CA is for the current reporting year. if (ca.year != CurrentReportingYear) { errors.Add("You cannot submit usage reports for previous operating years."); } // Check to see if the CA has already been submitted. if (new ReportingDalc().IsSubmitted(ca.number, CurrentReportingYear)) { errors.Add("The usage report has already been submitted for this contiguous area in this reporting year."); } if (ca.annualUsageSummary.contiguousArea <= 0) { errors.Add("The contiguous area has no acreage defined!"); } foreach (var mr in ca.meterReadings) { if (mr.Value.acceptCalculation) { if (mr.Value.calculatedVolumeGallons < 0) { errors.Add("Meter ID " + mr.Key.ToString() + " has an invalid volume."); } } else { if (mr.Value.userRevisedVolume <= 0) { errors.Add("Meter ID " + mr.Key.ToString() + " has an invalid user-revised volume."); } } } if (ca.annualUsageSummary.desiredBankInches < 0) { errors.Add("Desired water bank value cannot be negative."); } // Retrieve allowable application rate for this year // It's also on the submitted CA JSON, but we cannot // trust the client here! var rdalc = new ReportingDalc(); var allowableRate = rdalc.GetAllowableProductionRate(CurrentReportingYear); if (ca.annualUsageSummary.desiredBankInches > allowableRate) { errors.Add(string.Format("You cannot bank more than {0} inches for this reporting year.", allowableRate)); } // Check all associated wells foreach (var well in ca.wells) { if (well.meterInstallationIds.Length == 0) { // Check to see if there's already been a user error response if (!rdalc.IsWellErrorResponseRecorded(well.id, ActualUser.ActingAsUserId ?? ActualUser.Id)) { errors.Add("Well #" + well.permitNumber + " has no associated meters."); } } } // Retrieve previous banked water values for the CA. // (These are on the ca object, but we can't trust the client.) var bankHistory = new ReportingDalc().GetHistoricalBankedWater(ca.number); double prevBank = bankHistory.Where(x => x.year == CurrentReportingYear - 1).Select(x => x.bankedInches).DefaultIfEmpty(0).First();//mjia: round banked water to the 10ths. int avgAppRate = (int)(ca.annualUsageSummary.annualVolume / ca.annualUsageSummary.contiguousArea); int surplusSubtotal = ca.annualUsageSummary.allowableApplicationRate - avgAppRate; var surplusTotal = prevBank + surplusSubtotal; if (ca.annualUsageSummary.desiredBankInches > 0 && ca.annualUsageSummary.desiredBankInches > surplusTotal) { errors.Add("You cannot bank more water than your cumulative available total (previous year's banked inches plus this year's surplus/deficit)."); } } return errors.Count == 0; }