Update model data for river and marine ftp to centralize with mms 1.0 setup

This commit is contained in:
ALim Aidrus 2025-11-25 09:42:32 +08:00
parent 033391b770
commit b97aa7ddf9
8 changed files with 210 additions and 174 deletions

View File

@ -101,7 +101,7 @@ class _HomePageState extends State<HomePage> {
); );
}, },
), ),
title: const Text("MMS Version 3.12.01"), title: const Text("MMS Version 3.12.03"),
actions: [ actions: [
IconButton( IconButton(
icon: const Icon(Icons.person), icon: const Icon(Icons.person),

View File

@ -308,99 +308,117 @@ class InSituSamplingData {
}; };
} }
/// Creates a single JSON object with all submission data, mimicking 'db.json'
/// Creates a single JSON object with all submission data, mimicking 'db.json' /// Creates a single JSON object with all submission data, mimicking 'db.json'
String toDbJson() { String toDbJson() {
// This is a direct conversion of the model's properties to a map,
// with keys matching the expected 'db.json' file format.
final data = { final data = {
'battery_cap': batteryVoltage == -999.0 ? null : batteryVoltage, // --- Sorted exactly according to your Marine db.json sample ---
'device_name': sondeId, 'battery_cap': batteryVoltage ?? -999.0,
'sampling_type': samplingType, 'device_name': sondeId ?? "",
'report_id': reportId, 'sampling_type': samplingType ?? "",
'sampler_2ndname': secondSampler?['first_name'], 'report_id': reportId ?? "",
'sample_state': selectedStateName, 'sampler_2ndname': secondSampler?['first_name'] ?? "",
'station_id': selectedStation?['man_station_code'], 'sample_state': selectedStateName ?? "",
'tech_id': firstSamplerUserId, 'station_id': selectedStation?['man_station_code'] ?? "",
'tech_phonenum': null, // This field was not in the model 'tech_id': firstSamplerUserId ?? -999, // Default to -999 for int
'tech_name': firstSamplerName, 'tech_phonenum': "", // Not in model, default to empty string
'latitude': stationLatitude, 'tech_name': firstSamplerName ?? "",
'longitude': stationLongitude, 'latitude': stationLatitude ?? "",
'record_dt': '$samplingDate $samplingTime', 'longitude': stationLongitude ?? "",
'do_mgl': oxygenConcentration == -999.0 ? null : oxygenConcentration, 'record_dt': (samplingDate != null && samplingTime != null)
'do_sat': oxygenSaturation == -999.0 ? null : oxygenSaturation, ? '$samplingDate $samplingTime'
'ph': ph == -999.0 ? null : ph, : "",
'salinity': salinity == -999.0 ? null : salinity,
'tss': tss == -999.0 ? null : tss, // --- Sensor Readings ---
'temperature': temperature == -999.0 ? null : temperature, 'do_mgl': oxygenConcentration ?? -999.0,
'turbidity': turbidity == -999.0 ? null : turbidity, 'do_sat': oxygenSaturation ?? -999.0,
'tds': tds == -999.0 ? null : tds, 'ph': ph ?? -999.0,
'electric_conductivity': electricalConductivity == -999.0 ? null : electricalConductivity, 'salinity': salinity ?? -999.0,
'sample_id': sampleIdCode, 'tss': tss ?? -999.0,
'tarball': "", // <-- MODIFIED: Hardcoded to "N/A" 'temperature': temperature ?? -999.0,
'weather': weather, 'turbidity': turbidity ?? -999.0,
'tide_lvl': tideLevel, 'tds': tds ?? -999.0,
'sea_cond': seaCondition, 'electric_conductivity': electricalConductivity ?? -999.0,
'remarks_event': eventRemarks,
'remarks_lab': labRemarks, // --- Manual/Observations ---
'sample_id': sampleIdCode ?? "",
'tarball': "No", // Field removed from model logic, default to empty
'weather': weather ?? "",
'tide_lvl': tideLevel ?? "",
'sea_cond': seaCondition ?? "",
'remarks_event': eventRemarks ?? "",
'remarks_lab': labRemarks ?? "",
}; };
// Remove null values before encoding
// DO NOT UNCOMMENT. Keeps all keys even if values are null/default.
// data.removeWhere((key, value) => value == null); // data.removeWhere((key, value) => value == null);
return jsonEncode(data); return jsonEncode(data);
} }
/// Creates a JSON object for basic form info, mimicking 'marine_insitu_basic_form.json'. /// Creates a JSON object for basic form info, mimicking 'marine_insitu_basic_form.json'.
String toBasicFormJson() { String toBasicFormJson() {
final data = { final data = {
'tech_name': firstSamplerName, // --- Sorted exactly according to your Marine sample ---
'sampler_2ndname': secondSampler?['first_name'], // Assuming 'first_name' key 'tech_name': firstSamplerName ?? "",
'sample_date': samplingDate, 'sampler_2ndname': secondSampler?['first_name'] ?? "",
'sample_time': samplingTime, 'sample_date': samplingDate ?? "",
'sampling_type': samplingType, 'sample_time': samplingTime ?? "",
'sample_state': selectedStateName, 'sampling_type': samplingType ?? "",
'station_id': selectedStation?['man_station_code'], // Marine-specific key 'sample_state': selectedStateName ?? "",
'station_latitude': stationLatitude, 'sample_category': selectedCategoryName ?? "", // Added to match sample
'station_longitude': stationLongitude, 'station_id': selectedStation?['man_station_code'] ?? "",
'latitude': currentLatitude, 'station_latitude': stationLatitude ?? "",
'longitude': currentLongitude, 'station_longitude': stationLongitude ?? "",
'sample_id': sampleIdCode, 'latitude': currentLatitude ?? "",
'longitude': currentLongitude ?? "",
'sample_id': sampleIdCode ?? "",
}; };
// Remove null values before encoding
data.removeWhere((key, value) => value == null); // DO NOT UNCOMMENT
// data.removeWhere((key, value) => value == null);
return jsonEncode(data); return jsonEncode(data);
} }
/// Creates a JSON object for sensor readings, mimicking 'marine_sampling_reading.json'. /// Creates a JSON object for sensor readings, mimicking 'marine_sampling_reading.json'.
String toReadingJson() { String toReadingJson() {
final data = { final data = {
'do_mgl': oxygenConcentration == -999.0 ? null : oxygenConcentration, // --- Sorted exactly according to your Marine sample ---
'do_sat': oxygenSaturation == -999.0 ? null : oxygenSaturation, 'do_mgl': oxygenConcentration ?? -999.0,
'ph': ph == -999.0 ? null : ph, 'do_sat': oxygenSaturation ?? -999.0,
'salinity': salinity == -999.0 ? null : salinity, 'ph': ph ?? -999.0,
'tds': tds == -999.0 ? null : tds, 'salinity': salinity ?? -999.0,
'tss': tss == -999.0 ? null : tss, 'tds': tds ?? -999.0,
'temperature': temperature == -999.0 ? null : temperature, 'tss': tss ?? -999.0,
'turbidity': turbidity == -999.0 ? null : turbidity, 'temperature': temperature ?? -999.0,
'electric_conductivity': electricalConductivity == -999.0 ? null : electricalConductivity, 'turbidity': turbidity ?? -999.0,
'date_sampling_reading': dataCaptureDate, 'electric_conductivity': electricalConductivity ?? -999.0,
'time_sampling_reading': dataCaptureTime, 'date_sampling_reading': dataCaptureDate ?? "",
'time_sampling_reading': dataCaptureTime ?? "",
}; };
// Remove null values before encoding
data.removeWhere((key, value) => value == null); // DO NOT UNCOMMENT
// data.removeWhere((key, value) => value == null);
return jsonEncode(data); return jsonEncode(data);
} }
/// Creates a JSON object for manual info, mimicking 'marine_manual_info.json'. /// Creates a JSON object for manual info, mimicking 'marine_manual_info.json'.
String toManualInfoJson() { String toManualInfoJson() {
final data = { final data = {
'tarball': "", // <-- MODIFIED: Hardcoded to "N/A" // --- Sorted exactly according to your Marine sample ---
'weather': weather, 'tarball': "", // Field removed from model logic, default to empty
'tide_lvl': tideLevel, 'weather': weather ?? "",
'sea_cond': seaCondition, 'tide_lvl': tideLevel ?? "",
'remarks_event': eventRemarks, 'sea_cond': seaCondition ?? "",
'remarks_lab': labRemarks, 'remarks_event': eventRemarks ?? "",
'remarks_lab': labRemarks ?? "",
}; };
// Remove null values before encoding
data.removeWhere((key, value) => value == null); // DO NOT UNCOMMENT
// data.removeWhere((key, value) => value == null);
return jsonEncode(data); return jsonEncode(data);
} }

View File

@ -316,91 +316,99 @@ class RiverInSituSamplingData {
}; };
} }
/// Creates a single JSON object with all submission data, mimicking 'db.json' /// Creates a single JSON object with all submission data, mimicking 'db.json'
String toDbJson() { String toDbJson() {
// This is a direct conversion of the model's properties to a map,
// with keys matching the expected JSON file format.
final data = { final data = {
// --- START FIX: Map model properties to correct db.json keys --- // --- Sorted exactly according to your sample ---
'battery_cap': batteryVoltage == -999.0 ? null : batteryVoltage, // Handle -999 'battery_cap': batteryVoltage ?? -999.0,
'device_name': sondeId, 'device_name': sondeId ?? "",
'sampling_type': samplingType, 'sampling_type': samplingType ?? "",
'report_id': reportId, 'report_id': reportId ?? "",
'sampler_2ndname': secondSampler?['first_name'], // Use first_name as likely user name 'sampler_2ndname': secondSampler?['first_name'] ?? "",
'sample_state': selectedStateName, 'sample_state': selectedStateName ?? "",
'station_id': selectedStation?['sampling_station_code'], 'station_id': selectedStation?['sampling_station_code'] ?? "",
'tech_id': firstSamplerUserId, 'tech_id': firstSamplerUserId ?? -999, // Default to -999 if no ID
'tech_name': firstSamplerName, 'tech_phonenum': "", // Field present in sample but not in model, defaults to empty
'latitude': stationLatitude, // Assuming station lat/lon is intended here 'tech_name': firstSamplerName ?? "",
'longitude': stationLongitude, // Assuming station lat/lon is intended here 'latitude': stationLatitude ?? "",
'record_dt': '$samplingDate $samplingTime', 'longitude': stationLongitude ?? "",
'do_mgl': oxygenConcentration == -999.0 ? null : oxygenConcentration, 'record_dt': (samplingDate != null && samplingTime != null)
'do_sat': oxygenSaturation == -999.0 ? null : oxygenSaturation, ? '$samplingDate $samplingTime'
'ph': ph == -999.0 ? null : ph, : "",
'salinity': salinity == -999.0 ? null : salinity,
'temperature': temperature == -999.0 ? null : temperature, // --- Sensor Readings ---
'turbidity': turbidity == -999.0 ? null : turbidity, 'do_mgl': oxygenConcentration ?? -999.0,
'tds': tds == -999.0 ? null : tds, 'do_sat': oxygenSaturation ?? -999.0,
'electric_conductivity': electricalConductivity == -999.0 ? null : electricalConductivity, 'ph': ph ?? -999.0,
'ammonia': ammonia == -999.0 ? null : ammonia, 'salinity': salinity ?? -999.0,
'flowrate': flowrateValue, 'temperature': temperature ?? -999.0,
'odour': '', // Not collected 'turbidity': turbidity ?? -999.0,
'floatable': '', // Not collected 'tds': tds ?? -999.0,
'sample_id': sampleIdCode, 'electric_conductivity': electricalConductivity ?? -999.0,
'weather': weather, 'flowrate': flowrateValue ?? -999.0,
'remarks_event': eventRemarks,
'remarks_lab': labRemarks, // --- Manual/Observations ---
// --- END FIX --- 'odour': "", // Default empty
'floatable': "", // Default empty
'sample_id': sampleIdCode ?? "",
'weather': weather ?? "",
'remarks_event': eventRemarks ?? "",
'remarks_lab': labRemarks ?? "",
}; };
// Remove null values before encoding
// DO NOT UNCOMMENT. We want to keep all keys even if values are default.
// data.removeWhere((key, value) => value == null); // data.removeWhere((key, value) => value == null);
return jsonEncode(data); return jsonEncode(data);
} }
/// Creates a JSON object for basic form info, mimicking 'river_insitu_basic_form.json'. /// Creates a JSON object for basic form info, mimicking 'river_insitu_basic_form.json'.
String toBasicFormJson() { String toBasicFormJson() {
final data = { final data = {
// --- START FIX: Map model properties to correct form keys --- // --- Sorted sequence: tech_name -> sampler_2ndname -> date/time -> type -> state -> station info -> location -> sample_id
'tech_name': firstSamplerName, 'tech_name': firstSamplerName ?? "",
'sampler_2ndname': secondSampler?['first_name'], 'sampler_2ndname': secondSampler?['first_name'] ?? "",
'sample_date': samplingDate, 'sample_date': samplingDate ?? "",
'sample_time': samplingTime, 'sample_time': samplingTime ?? "",
'sampling_type': samplingType, 'sampling_type': samplingType ?? "",
'sample_state': selectedStateName, 'sample_state': selectedStateName ?? "",
'station_id': selectedStation?['sampling_station_code'], 'station_id': selectedStation?['sampling_station_code'] ?? "",
'station_latitude': stationLatitude, 'station_latitude': stationLatitude ?? "",
'station_longitude': stationLongitude, 'station_longitude': stationLongitude ?? "",
'latitude': currentLatitude, // Current location lat 'latitude': currentLatitude ?? "", // Current user location lat
'longitude': currentLongitude, // Current location lon 'longitude': currentLongitude ?? "", // Current user location lon
'sample_id': sampleIdCode, 'sample_id': sampleIdCode ?? "",
// --- END FIX ---
}; };
// Remove null values before encoding
data.removeWhere((key, value) => value == null); // REMOVE or COMMENT OUT this line so no keys are deleted
// data.removeWhere((key, value) => value == null);
return jsonEncode(data); return jsonEncode(data);
} }
/// Creates a JSON object for sensor readings, mimicking 'river_sampling_reading.json'.
/// Creates a JSON object for sensor readings, mimicking 'river_sampling_reading.json'. /// Creates a JSON object for sensor readings, mimicking 'river_sampling_reading.json'.
String toReadingJson() { String toReadingJson() {
final data = { final data = {
// --- START FIX: Map model properties to correct reading keys --- // --- Sorted exactly according to your sample ---
'do_mgl': oxygenConcentration == -999.0 ? null : oxygenConcentration, 'do_mgl': oxygenConcentration ?? -999.0,
'do_sat': oxygenSaturation == -999.0 ? null : oxygenSaturation, 'do_sat': oxygenSaturation ?? -999.0,
'ph': ph == -999.0 ? null : ph, 'ph': ph ?? -999.0,
'salinity': salinity == -999.0 ? null : salinity, 'salinity': salinity ?? -999.0,
'temperature': temperature == -999.0 ? null : temperature, 'temperature': temperature ?? -999.0,
'turbidity': turbidity == -999.0 ? null : turbidity, 'turbidity': turbidity ?? -999.0,
'tds': tds == -999.0 ? null : tds, 'tds': tds ?? -999.0,
'electric_conductivity': electricalConductivity == -999.0 ? null : electricalConductivity, 'electric_conductivity': electricalConductivity ?? -999.0,
'ammonia': ammonia == -999.0 ? null : ammonia, 'flowrate': flowrateValue ?? -999.0,
'flowrate': flowrateValue,
'date_sampling_reading': dataCaptureDate, // Use data capture date/time // --- Date and Time ---
'time_sampling_reading': dataCaptureTime, // Use data capture date/time 'date_sampling_reading': dataCaptureDate ?? "",
// --- END FIX --- 'time_sampling_reading': dataCaptureTime ?? "",
}; };
// Remove null values before encoding
data.removeWhere((key, value) => value == null); // REMOVE or COMMENT OUT this line to ensure no keys are skipped/removed
// data.removeWhere((key, value) => value == null);
return jsonEncode(data); return jsonEncode(data);
} }

View File

@ -446,7 +446,7 @@ class RiverInvesManualSamplingData {
'tds': tds == -999.0 ? null : tds, 'tds': tds == -999.0 ? null : tds,
'electric_conductivity': electricalConductivity == -999.0 ? null : electricalConductivity, 'electric_conductivity': electricalConductivity == -999.0 ? null : electricalConductivity,
'ammonia': ammonia == -999.0 ? null : ammonia, 'ammonia': ammonia == -999.0 ? null : ammonia,
'flowrate': flowrateValue, 'flowrate': flowrateValue ?? -999.0,
'odour': '', // Not collected 'odour': '', // Not collected
'floatable': '', // Not collected 'floatable': '', // Not collected
'sample_id': sampleIdCode, 'sample_id': sampleIdCode,

View File

@ -322,7 +322,7 @@ class RiverManualTriennialSamplingData {
'turbidity': turbidity == -999.0 ? null : turbidity, 'turbidity': turbidity == -999.0 ? null : turbidity,
'tds': tds == -999.0 ? null : tds, 'tds': tds == -999.0 ? null : tds,
'electric_conductivity': electricalConductivity == -999.0 ? null : electricalConductivity, 'electric_conductivity': electricalConductivity == -999.0 ? null : electricalConductivity,
'ammonia': ammonia == -999.0 ? null : ammonia, //'ammonia': ammonia == -999.0 ? null : ammonia,
'flowrate': flowrateValue, 'flowrate': flowrateValue,
'odour': '', // Not collected 'odour': '', // Not collected
'floatable': '', // Not collected 'floatable': '', // Not collected
@ -335,47 +335,57 @@ class RiverManualTriennialSamplingData {
return jsonEncode(data); return jsonEncode(data);
} }
/// Creates a JSON object for basic form info, mimicking 'river_triennial_basic_form.json'. /// Creates a JSON object for basic form info, mimicking 'river_insitu_basic_form.json'.
String toBasicFormJson() { String toBasicFormJson() {
final data = { final data = {
// --- START FIX: Map model properties to correct form keys --- // Keys sorted exactly according to the provided sample
'tech_name': firstSamplerName, 'tech_name': firstSamplerName ?? "",
'sampler_2ndname': secondSampler?['first_name'], 'sampler_2ndname': secondSampler?['first_name'] ?? "",
'sample_date': samplingDate, 'sample_date': samplingDate ?? "",
'sample_time': samplingTime, 'sample_time': samplingTime ?? "",
'sampling_type': samplingType, 'sampling_type': samplingType ?? "",
'sample_state': selectedStateName, 'sample_state': selectedStateName ?? "",
'station_id': selectedStation?['sampling_station_code'], 'station_id': selectedStation?['sampling_station_code'] ?? "",
'station_latitude': stationLatitude, 'station_latitude': stationLatitude ?? "",
'station_longitude': stationLongitude, 'station_longitude': stationLongitude ?? "",
'latitude': currentLatitude, // Current location lat 'latitude': currentLatitude ?? "", // Current user location lat
'longitude': currentLongitude, // Current location lon 'longitude': currentLongitude ?? "", // Current user location lon
'sample_id': sampleIdCode, 'sample_id': sampleIdCode ?? "",
// --- END FIX ---
}; };
data.removeWhere((key, value) => value == null);
// REMOVE or COMMENT OUT this line so no keys are deleted
// data.removeWhere((key, value) => value == null);
return jsonEncode(data); return jsonEncode(data);
} }
/// Creates a JSON object for sensor readings, mimicking 'river_sampling_reading.json'. /// Creates a JSON object for sensor readings, mimicking 'river_sampling_reading.json'.
String toReadingJson() { String toReadingJson() {
final data = { final data = {
// --- START FIX: Map model properties to correct reading keys --- // Use ?? operator to default to -999.0 if null
'do_mgl': oxygenConcentration == -999.0 ? null : oxygenConcentration, 'do_mgl': oxygenConcentration ?? -999.0,
'do_sat': oxygenSaturation == -999.0 ? null : oxygenSaturation, 'do_sat': oxygenSaturation ?? -999.0,
'ph': ph == -999.0 ? null : ph, 'ph': ph ?? -999.0,
'salinity': salinity == -999.0 ? null : salinity, 'salinity': salinity ?? -999.0,
'temperature': temperature == -999.0 ? null : temperature, 'temperature': temperature ?? -999.0,
'turbidity': turbidity == -999.0 ? null : turbidity, 'turbidity': turbidity ?? -999.0,
'tds': tds == -999.0 ? null : tds, 'tds': tds ?? -999.0,
'electric_conductivity': electricalConductivity == -999.0 ? null : electricalConductivity, 'electric_conductivity': electricalConductivity ?? -999.0,
'ammonia': ammonia == -999.0 ? null : ammonia,
'flowrate': flowrateValue, // Keep 'ammonia' commented out if it's not used in Triennial,
'date_sampling_reading': dataCaptureDate, // Use data capture date/time // otherwise uncomment and use: 'ammonia': ammonia ?? -999.0,
'time_sampling_reading': dataCaptureTime, // Use data capture date/time
// --- END FIX --- // Flowrate defaults to -999.0 (as requested in previous turn)
'flowrate': flowrateValue ?? -999.0,
// Date and Time default to empty string "" if null
'date_sampling_reading': dataCaptureDate ?? "",
'time_sampling_reading': dataCaptureTime ?? "",
}; };
data.removeWhere((key, value) => value == null);
// REMOVE or COMMENT OUT this line so keys are NEVER deleted
// data.removeWhere((key, value) => value == null);
return jsonEncode(data); return jsonEncode(data);
} }

View File

@ -221,7 +221,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
ListTile( ListTile(
leading: const Icon(Icons.info_outline), leading: const Icon(Icons.info_outline),
title: const Text('App Version'), title: const Text('App Version'),
subtitle: const Text('MMS Version 3.12.01'), subtitle: const Text('MMS Version 3.12.03'),
dense: true, dense: true,
), ),
ListTile( ListTile(

View File

@ -603,7 +603,7 @@ class RiverInSituSamplingService {
mapImage(data.backgroundStationImage, 'background'); mapImage(data.backgroundStationImage, 'background');
mapImage(data.upstreamRiverImage, 'upstream'); mapImage(data.upstreamRiverImage, 'upstream');
mapImage(data.downstreamRiverImage, 'downstream'); mapImage(data.downstreamRiverImage, 'downstream');
mapImage(data.sampleTurbidityImage, 'sample_turbidity'); mapImage(data.sampleTurbidityImage, 'turbidity');
mapImage(data.optionalImage1, 'optional_1'); mapImage(data.optionalImage1, 'optional_1');
mapImage(data.optionalImage2, 'optional_2'); mapImage(data.optionalImage2, 'optional_2');
mapImage(data.optionalImage3, 'optional_3'); mapImage(data.optionalImage3, 'optional_3');

View File

@ -607,9 +607,9 @@ class RiverManualTriennialSamplingService {
// --- START FIX: Include all four JSON files --- // --- START FIX: Include all four JSON files ---
jsonDataMap: { jsonDataMap: {
'db.json': data.toDbJson(), 'db.json': data.toDbJson(),
'river_triennial_basic_form.json': data.toBasicFormJson(), // ADDED 'river_insitu_basic_form.json': data.toBasicFormJson(), // ADDED
'river_triennial_reading.json': data.toReadingJson(), // ADDED 'river_sampling_reading.json': data.toReadingJson(), // ADDED
'river_triennial_manual_info.json': data.toManualInfoJson(), // ADDED 'river_manual_info.json': data.toManualInfoJson(), // ADDED
}, },
// --- END FIX --- // --- END FIX ---
baseFileName: baseFileName, baseFileName: baseFileName,