341 lines
15 KiB
C#
341 lines
15 KiB
C#
using System.Text.Json;
|
|
using eSPJ.Models;
|
|
|
|
namespace eSPJ.Services
|
|
{
|
|
public class FileDetailPenjemputanStore : IDetailPenjemputanStore
|
|
{
|
|
private readonly string _storeFilePath;
|
|
private readonly ILogger<FileDetailPenjemputanStore> _logger;
|
|
private static readonly SemaphoreSlim _fileLock = new SemaphoreSlim(1, 1);
|
|
|
|
public FileDetailPenjemputanStore(
|
|
IWebHostEnvironment env,
|
|
ILogger<FileDetailPenjemputanStore> logger)
|
|
{
|
|
_logger = logger;
|
|
_storeFilePath = Path.Combine(env.ContentRootPath, "Data", "detail-penjemputan.json");
|
|
}
|
|
|
|
public async Task<List<TpsData>> GetAllAsync()
|
|
{
|
|
await _fileLock.WaitAsync();
|
|
try
|
|
{
|
|
return await ReadAllFromDiskAsync();
|
|
}
|
|
finally
|
|
{
|
|
_fileLock.Release();
|
|
}
|
|
}
|
|
|
|
private async Task<List<TpsData>> ReadAllFromDiskAsync()
|
|
{
|
|
try
|
|
{
|
|
if (!File.Exists(_storeFilePath))
|
|
{
|
|
return new List<TpsData>();
|
|
}
|
|
|
|
var json = await File.ReadAllTextAsync(_storeFilePath);
|
|
if (string.IsNullOrWhiteSpace(json))
|
|
{
|
|
return new List<TpsData>();
|
|
}
|
|
|
|
var data = JsonSerializer.Deserialize<List<TpsData>>(json, new JsonSerializerOptions
|
|
{
|
|
PropertyNameCaseInsensitive = true
|
|
});
|
|
|
|
return data?.Where(item => item != null).ToList() ?? new List<TpsData>();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error reading submitted penjemputan data");
|
|
return new List<TpsData>();
|
|
}
|
|
}
|
|
|
|
public async Task<List<TpsData>> GetByNomorSpjAsync(string nomorSpj)
|
|
{
|
|
var normalizedNomorSpj = (nomorSpj ?? string.Empty).Trim();
|
|
if (string.IsNullOrWhiteSpace(normalizedNomorSpj))
|
|
{
|
|
return new List<TpsData>();
|
|
}
|
|
|
|
var allData = await GetAllAsync();
|
|
return allData
|
|
.Where(item => string.Equals((item.NomorSpj ?? string.Empty).Trim(), normalizedNomorSpj, StringComparison.OrdinalIgnoreCase))
|
|
.OrderByDescending(item => item.UpdatedAt)
|
|
.GroupBy(GetRecordIdentity, StringComparer.OrdinalIgnoreCase)
|
|
.Select(group => group.First())
|
|
.OrderBy(item => item.Name)
|
|
.ToList();
|
|
}
|
|
|
|
public async Task<List<TpsData>> GetSubmittedAsync()
|
|
{
|
|
var allData = await GetAllAsync();
|
|
return allData
|
|
.Where(item => item.IsSubmit)
|
|
.OrderByDescending(item => item.UpdatedAt)
|
|
.GroupBy(GetRecordIdentity, StringComparer.OrdinalIgnoreCase)
|
|
.Select(group => group.First())
|
|
.ToList();
|
|
}
|
|
|
|
private static string GetRecordIdentity(TpsData item)
|
|
{
|
|
return string.Join("::", new[]
|
|
{
|
|
item.NomorSpj?.Trim() ?? string.Empty,
|
|
item.SpjDetailId?.Trim() ?? string.Empty,
|
|
item.LokasiAngkutId?.Trim() ?? string.Empty,
|
|
item.Name?.Trim() ?? string.Empty,
|
|
});
|
|
}
|
|
|
|
public async Task<TpsData?> GetSubmittedDetailAsync(string nomorSpj, string? spjDetailId = null, string? lokasiAngkutId = null, string? namaTps = null)
|
|
{
|
|
var normalizedNomorSpj = (nomorSpj ?? string.Empty).Trim();
|
|
var normalizedSpjDetailId = (spjDetailId ?? string.Empty).Trim();
|
|
var normalizedLokasiAngkutId = (lokasiAngkutId ?? string.Empty).Trim();
|
|
var normalizedNamaTps = (namaTps ?? string.Empty).Trim();
|
|
var allData = await GetSubmittedAsync();
|
|
return allData.FirstOrDefault(item =>
|
|
string.Equals((item.NomorSpj ?? string.Empty).Trim(), normalizedNomorSpj, StringComparison.OrdinalIgnoreCase) &&
|
|
(string.IsNullOrWhiteSpace(normalizedSpjDetailId) || string.Equals((item.SpjDetailId ?? string.Empty).Trim(), normalizedSpjDetailId, StringComparison.OrdinalIgnoreCase)) &&
|
|
(string.IsNullOrWhiteSpace(normalizedLokasiAngkutId) || string.Equals((item.LokasiAngkutId ?? string.Empty).Trim(), normalizedLokasiAngkutId, StringComparison.OrdinalIgnoreCase)) &&
|
|
(string.IsNullOrWhiteSpace(normalizedNamaTps) || string.Equals((item.Name ?? string.Empty).Trim(), normalizedNamaTps, StringComparison.OrdinalIgnoreCase)));
|
|
}
|
|
|
|
public async Task SaveSubmittedAsync(TpsData data)
|
|
{
|
|
await _fileLock.WaitAsync();
|
|
try
|
|
{
|
|
var allData = await ReadAllFromDiskAsync();
|
|
data.IsSubmit = true;
|
|
data.UpdatedAt = DateTime.Now;
|
|
if (!data.SubmittedAt.HasValue)
|
|
{
|
|
data.SubmittedAt = DateTime.Now;
|
|
}
|
|
|
|
var existingIndex = FindRecordIndex(allData, data.NomorSpj, data.SpjDetailId, data.LokasiAngkutId, data.Name);
|
|
|
|
if (existingIndex >= 0)
|
|
{
|
|
allData[existingIndex] = data;
|
|
}
|
|
else
|
|
{
|
|
allData.Add(data);
|
|
}
|
|
|
|
await WriteAllToDiskAsync(allData);
|
|
}
|
|
finally
|
|
{
|
|
_fileLock.Release();
|
|
}
|
|
}
|
|
|
|
public async Task SaveRecordAsync(RecordSaveRequest request)
|
|
{
|
|
await _fileLock.WaitAsync();
|
|
try
|
|
{
|
|
var allData = await ReadAllFromDiskAsync();
|
|
var mapped = MapRequestToRecord(request);
|
|
mapped.UpdatedAt = DateTime.Now;
|
|
|
|
var existingIndex = FindRecordIndex(allData, mapped.NomorSpj, mapped.SpjDetailId, mapped.LokasiAngkutId, mapped.Name);
|
|
if (existingIndex >= 0)
|
|
{
|
|
var existing = allData[existingIndex];
|
|
mapped.NomorSpj = string.IsNullOrWhiteSpace(mapped.NomorSpj) ? existing.NomorSpj : mapped.NomorSpj;
|
|
mapped.LokasiAngkutId = string.IsNullOrWhiteSpace(mapped.LokasiAngkutId) ? existing.LokasiAngkutId : mapped.LokasiAngkutId;
|
|
mapped.SpjDetailId = string.IsNullOrWhiteSpace(mapped.SpjDetailId) ? existing.SpjDetailId : mapped.SpjDetailId;
|
|
mapped.Name = string.IsNullOrWhiteSpace(mapped.Name) ? existing.Name : mapped.Name;
|
|
mapped.Latitude = string.IsNullOrWhiteSpace(mapped.Latitude) ? existing.Latitude : mapped.Latitude;
|
|
mapped.Longitude = string.IsNullOrWhiteSpace(mapped.Longitude) ? existing.Longitude : mapped.Longitude;
|
|
mapped.AlamatJalan = string.IsNullOrWhiteSpace(mapped.AlamatJalan) ? existing.AlamatJalan : mapped.AlamatJalan;
|
|
mapped.WaktuKedatangan = string.IsNullOrWhiteSpace(mapped.WaktuKedatangan) ? existing.WaktuKedatangan : mapped.WaktuKedatangan;
|
|
mapped.FotoKedatangan = mapped.FotoKedatangan.Count > 0 ? mapped.FotoKedatangan : (existing.FotoKedatangan ?? new List<string>());
|
|
mapped.FotoKedatanganUploaded = mapped.FotoKedatanganUploaded || existing.FotoKedatanganUploaded;
|
|
mapped.Timbangan = MergeTimbangan(existing.Timbangan, mapped.Timbangan);
|
|
mapped.TotalOrganik = mapped.TotalOrganik != 0 ? mapped.TotalOrganik : existing.TotalOrganik;
|
|
mapped.TotalAnorganik = mapped.TotalAnorganik != 0 ? mapped.TotalAnorganik : existing.TotalAnorganik;
|
|
mapped.TotalResidu = mapped.TotalResidu != 0 ? mapped.TotalResidu : existing.TotalResidu;
|
|
mapped.TotalTimbangan = mapped.TotalTimbangan != 0 ? mapped.TotalTimbangan : existing.TotalTimbangan;
|
|
mapped.FotoPetugas = mapped.FotoPetugas.Count > 0 ? mapped.FotoPetugas : (existing.FotoPetugas ?? new List<string>());
|
|
mapped.FotoPetugasUploaded = mapped.FotoPetugasUploaded || existing.FotoPetugasUploaded;
|
|
mapped.NamaPetugas = string.IsNullOrWhiteSpace(mapped.NamaPetugas) ? existing.NamaPetugas : mapped.NamaPetugas;
|
|
mapped.IsSubmit = existing.IsSubmit || mapped.IsSubmit;
|
|
mapped.SubmittedAt = existing.SubmittedAt;
|
|
allData[existingIndex] = mapped;
|
|
}
|
|
else
|
|
{
|
|
allData.Add(mapped);
|
|
}
|
|
|
|
await WriteAllToDiskAsync(allData);
|
|
}
|
|
finally
|
|
{
|
|
_fileLock.Release();
|
|
}
|
|
}
|
|
|
|
private static List<TimbanganItem> MergeTimbangan(List<TimbanganItem>? existingItems, List<TimbanganItem>? incomingItems)
|
|
{
|
|
var existing = existingItems ?? new List<TimbanganItem>();
|
|
var incoming = incomingItems ?? new List<TimbanganItem>();
|
|
|
|
if (incoming.Count == 0)
|
|
{
|
|
return existing;
|
|
}
|
|
|
|
var maxCount = Math.Max(existing.Count, incoming.Count);
|
|
var merged = new List<TimbanganItem>(maxCount);
|
|
|
|
for (var index = 0; index < maxCount; index++)
|
|
{
|
|
var existingItem = index < existing.Count ? existing[index] : null;
|
|
var incomingItem = index < incoming.Count ? incoming[index] : null;
|
|
|
|
if (existingItem == null && incomingItem == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (existingItem == null)
|
|
{
|
|
merged.Add(CloneTimbanganItem(incomingItem!));
|
|
continue;
|
|
}
|
|
|
|
if (incomingItem == null)
|
|
{
|
|
merged.Add(CloneTimbanganItem(existingItem));
|
|
continue;
|
|
}
|
|
|
|
merged.Add(new TimbanganItem
|
|
{
|
|
FotoFileName = string.IsNullOrWhiteSpace(incomingItem.FotoFileName)
|
|
? existingItem.FotoFileName
|
|
: incomingItem.FotoFileName,
|
|
Berat = incomingItem.Berat != null && incomingItem.Berat.Count > 0
|
|
? new List<decimal>(incomingItem.Berat)
|
|
: new List<decimal>(existingItem.Berat ?? new List<decimal>()),
|
|
LokasiAngkut = incomingItem.LokasiAngkut != null && incomingItem.LokasiAngkut.Count > 0
|
|
? new List<string>(incomingItem.LokasiAngkut)
|
|
: new List<string>(existingItem.LokasiAngkut ?? new List<string>()),
|
|
JenisSampah = incomingItem.JenisSampah != null && incomingItem.JenisSampah.Count > 0
|
|
? new List<JenisSampah>(incomingItem.JenisSampah)
|
|
: new List<JenisSampah>(existingItem.JenisSampah ?? new List<JenisSampah>()),
|
|
IsUploaded = existingItem.IsUploaded || incomingItem.IsUploaded,
|
|
WaktuUpload = incomingItem.WaktuUpload ?? existingItem.WaktuUpload,
|
|
});
|
|
}
|
|
|
|
return merged;
|
|
}
|
|
|
|
private static TimbanganItem CloneTimbanganItem(TimbanganItem source)
|
|
{
|
|
return new TimbanganItem
|
|
{
|
|
FotoFileName = source.FotoFileName,
|
|
Berat = new List<decimal>(source.Berat ?? new List<decimal>()),
|
|
LokasiAngkut = new List<string>(source.LokasiAngkut ?? new List<string>()),
|
|
JenisSampah = new List<JenisSampah>(source.JenisSampah ?? new List<JenisSampah>()),
|
|
IsUploaded = source.IsUploaded,
|
|
WaktuUpload = source.WaktuUpload,
|
|
};
|
|
}
|
|
|
|
private async Task WriteAllToDiskAsync(List<TpsData> data)
|
|
{
|
|
var directory = Path.GetDirectoryName(_storeFilePath);
|
|
if (!string.IsNullOrWhiteSpace(directory) && !Directory.Exists(directory))
|
|
{
|
|
Directory.CreateDirectory(directory);
|
|
}
|
|
|
|
data = data
|
|
.Where(item => item != null)
|
|
.OrderByDescending(item => item.UpdatedAt)
|
|
.GroupBy(GetRecordIdentity, StringComparer.OrdinalIgnoreCase)
|
|
.Select(group => group.First())
|
|
.OrderBy(item => item.Name)
|
|
.ToList();
|
|
|
|
var options = new JsonSerializerOptions { WriteIndented = true };
|
|
var json = JsonSerializer.Serialize(data, options);
|
|
var tempPath = _storeFilePath + ".tmp";
|
|
await File.WriteAllTextAsync(tempPath, json);
|
|
File.Move(tempPath, _storeFilePath, overwrite: true);
|
|
}
|
|
|
|
private static int FindRecordIndex(List<TpsData> allData, string? nomorSpj, string? spjDetailId, string? lokasiAngkutId, string? namaTps)
|
|
{
|
|
return allData.FindIndex(item =>
|
|
item != null &&
|
|
!string.IsNullOrWhiteSpace(nomorSpj) &&
|
|
string.Equals(item.NomorSpj, nomorSpj, StringComparison.OrdinalIgnoreCase) &&
|
|
string.Equals(item.SpjDetailId, spjDetailId ?? string.Empty, StringComparison.OrdinalIgnoreCase) &&
|
|
string.Equals(item.LokasiAngkutId, lokasiAngkutId ?? string.Empty, StringComparison.OrdinalIgnoreCase) &&
|
|
string.Equals(item.Name, namaTps ?? string.Empty, StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
private static TpsData MapRequestToRecord(RecordSaveRequest request)
|
|
{
|
|
return new TpsData
|
|
{
|
|
NomorSpj = request.NomorSpj,
|
|
LokasiAngkutId = request.LokasiAngkutId,
|
|
SpjDetailId = request.SpjDetailId,
|
|
Name = request.NamaTps,
|
|
Latitude = request.Latitude,
|
|
Longitude = request.Longitude,
|
|
AlamatJalan = request.AlamatJalan,
|
|
WaktuKedatangan = request.WaktuKedatangan,
|
|
FotoKedatangan = request.FotoKedatanganFileNames ?? new List<string>(),
|
|
FotoKedatanganUploaded = request.FotoKedatanganUploaded,
|
|
Timbangan = (request.Timbangan ?? new List<RecordTimbanganItem>())
|
|
.Where(item => item != null)
|
|
.Select(item => new TimbanganItem
|
|
{
|
|
FotoFileName = item.FotoFileName,
|
|
Berat = new List<decimal> { item.Berat },
|
|
LokasiAngkut = new List<string>(),
|
|
JenisSampah = Enum.TryParse<JenisSampah>(item.JenisSampah, out var parsedJenis)
|
|
? new List<JenisSampah> { parsedJenis }
|
|
: new List<JenisSampah> { JenisSampah.Residu },
|
|
IsUploaded = item.Uploaded,
|
|
WaktuUpload = DateTime.Now
|
|
}).ToList(),
|
|
TotalOrganik = request.TotalOrganik,
|
|
TotalAnorganik = request.TotalAnorganik,
|
|
TotalResidu = request.TotalResidu,
|
|
TotalTimbangan = request.TotalTimbangan,
|
|
FotoPetugas = request.FotoPetugasFileNames ?? new List<string>(),
|
|
FotoPetugasUploaded = request.FotoPetugasUploaded,
|
|
NamaPetugas = request.NamaPetugas,
|
|
IsSubmit = request.IsSubmit,
|
|
UpdatedAt = DateTime.Now,
|
|
SubmittedAt = request.IsSubmit ? DateTime.Now : null,
|
|
};
|
|
}
|
|
}
|
|
}
|