diff --git a/cms-adapter/src/Rsbc.Dmf.CaseManagement.Service/Protos/cmsAdapter.proto b/cms-adapter/src/Rsbc.Dmf.CaseManagement.Service/Protos/cmsAdapter.proto index 6040e7097..1f5d2bf71 100644 --- a/cms-adapter/src/Rsbc.Dmf.CaseManagement.Service/Protos/cmsAdapter.proto +++ b/cms-adapter/src/Rsbc.Dmf.CaseManagement.Service/Protos/cmsAdapter.proto @@ -522,6 +522,9 @@ message CreateCaseRequest { string SubmittalStatus = 6; string CaseTypeCode = 7; string TriggerType = 8; + string DriverGivenName = 9; + string DriverSurname =10; + google.protobuf.Timestamp DriverDateOfBirth = 11; } message UpdateCaseRequest{ diff --git a/cms-adapter/src/Rsbc.Dmf.CaseManagement.Service/Services/CaseService.cs b/cms-adapter/src/Rsbc.Dmf.CaseManagement.Service/Services/CaseService.cs index 3ae86e507..b01662d98 100644 --- a/cms-adapter/src/Rsbc.Dmf.CaseManagement.Service/Services/CaseService.cs +++ b/cms-adapter/src/Rsbc.Dmf.CaseManagement.Service/Services/CaseService.cs @@ -8,7 +8,9 @@ using Microsoft.IdentityModel.Tokens; using Org.BouncyCastle.Asn1.Ocsp; using Pssg.SharedUtils; +using Rsbc.Dmf.CaseManagement.Dto; using Rsbc.Dmf.CaseManagement.Model; +using Serilog; using System; using System.Collections.Generic; using System.IdentityModel.Tokens.Jwt; @@ -1751,7 +1753,9 @@ public async override Task CreateCase(CreateCaseRequest reque CaseTypeCode = caseTypeCode, TriggerType = request.TriggerType, Owner = request.Owner, - + DriverSurname = request.DriverSurname, + DriverGivenName = request.DriverGivenName, + DriverDateOfBirth = request.DriverDateOfBirth?.ToDateTime(), }; Rsbc.Dmf.CaseManagement.CaseDetail activeRemedialCase = null; @@ -1790,15 +1794,23 @@ public async override Task CreateCase(CreateCaseRequest reque } var createDriver = await _caseManager.CreateCase(caseCreateRequest); - caseCreateRequest.CaseId = createDriver?.Id; - if (!string.IsNullOrEmpty(caseCreateRequest.TriggerType)) + if (createDriver.Success) { - await _caseManager.CreateRehabTrigger(caseCreateRequest); - await CreateRehabTriggerBringForward(caseCreateRequest.CaseId, caseCreateRequest.TriggerType); - } + caseCreateRequest.CaseId = createDriver?.Id; - reply.ResultStatus = ResultStatus.Success; + if (!string.IsNullOrEmpty(caseCreateRequest.TriggerType)) + { + await _caseManager.CreateRehabTrigger(caseCreateRequest); + await CreateRehabTriggerBringForward(caseCreateRequest.CaseId, caseCreateRequest.TriggerType); + } + + reply.ResultStatus = ResultStatus.Success; + } + else + { + reply.ResultStatus = ResultStatus.Fail; + } } catch(Exception e) diff --git a/cms-adapter/src/Rsbc.Dmf.CaseManagement/Manager/CaseManager.cs b/cms-adapter/src/Rsbc.Dmf.CaseManagement/Manager/CaseManager.cs index 027a0cd7b..cbd9e983b 100644 --- a/cms-adapter/src/Rsbc.Dmf.CaseManagement/Manager/CaseManager.cs +++ b/cms-adapter/src/Rsbc.Dmf.CaseManagement/Manager/CaseManager.cs @@ -28,7 +28,7 @@ public class CaseSearchRequest public class LegacyCandidateSearchRequest { - public string DriverLicenseNumber { get; set;} + public string DriverLicenseNumber { get; set; } public string Surname { get; set; } public int? SequenceNumber { get; set; } @@ -171,8 +171,8 @@ public class DmerCase : Case public IEnumerable Flags { get; set; } public IEnumerable Decisions { get; set; } public string ClinicId { get; set; } - public string ClinicName { get; set;} - public string DmerType { get; set;} + public string ClinicName { get; set; } + public string DmerType { get; set; } public int CaseSequence { get; set; } public IEnumerable MedicalConditions { get; set; } } @@ -204,7 +204,7 @@ public class Decision { public string Id { get; set; } public string Description { get; set; } - public DateTimeOffset CreatedOn { get; set;} + public DateTimeOffset CreatedOn { get; set; } public DecisionOutcome? Outcome { get; set; } } @@ -275,6 +275,10 @@ public class CreateCaseRequest public string TriggerType { get; set; } public string Owner { get; set; } + + public DateTime? DriverDateOfBirth { get; set; } + public string DriverGivenName { get; set; } + public string DriverSurname { get; set; } } @@ -444,7 +448,7 @@ private async Task LazyLoadProperties(incident @case) //{ // //load driver info // await dynamicsContext.LoadPropertyAsync(@case, nameof(incident.ownerid)); - + //} } @@ -603,7 +607,7 @@ public async Task> GetDriverLegacyComments(string dri int.TryParse(comment.dfp_caseidguid, out sequenceNumber); LegacyComment legacyComment = new LegacyComment - { + { CommentDate = comment.createdon.GetValueOrDefault(), CommentId = comment.dfp_commentid.ToString(), CommentText = comment.dfp_commentdetails, @@ -759,7 +763,7 @@ public IEnumerable GetDriverObjectsByIdAndSurCode(string licensenumb // First, get all drivers with the license number var driversWithLicense = dynamicsContext.dfp_drivers.Expand(x => x.dfp_PersonId) .Where(d => d.statuscode == 1 && d.dfp_licensenumber == licensenumber) - .ToList(); + .ToList(); if (string.IsNullOrEmpty(surCode)) { @@ -1134,7 +1138,7 @@ public async Task GetMostRecentCaseDetail(Guid driverId, string? pro var fetchedCase = fetchedCaseQuery.OrderByDescending(x => x.createdon).FirstOrDefault(); - if(fetchedCase != null) + if (fetchedCase != null) { result = await _caseMapper.Map(fetchedCase); } @@ -1866,7 +1870,7 @@ public async Task CreateICBCDocumentEnvelope(LegacyDocument r }; - if(request.FaxReceivedDate != null) + if (request.FaxReceivedDate != null) { documentEnvelope.FaxReceivedDate = request.FaxReceivedDate; } @@ -1983,7 +1987,7 @@ public async Task CreateDocumentOnDriver(LegacyDocument reque bcgovDocumentUrl = new bcgov_documenturl(); } - bcgovDocumentUrl.dfp_attachmentnumber = (int) request.DpsDocumentId; + bcgovDocumentUrl.dfp_attachmentnumber = (int)request.DpsDocumentId; bcgovDocumentUrl.dfp_batchid = request.BatchId; bcgovDocumentUrl.dfp_documentpages = request.DocumentPages.ToString(); @@ -1991,7 +1995,7 @@ public async Task CreateDocumentOnDriver(LegacyDocument reque bcgovDocumentUrl.bcgov_receiveddate = request.FaxReceivedDate; bcgovDocumentUrl.dfp_faxreceiveddate = request.FaxReceivedDate; - if (request.ImportDate != null && request.ImportDate.Value.Year > 1 ) + if (request.ImportDate != null && request.ImportDate.Value.Year > 1) { bcgovDocumentUrl.dfp_uploadeddate = request.ImportDate; bcgovDocumentUrl.dfp_dpsprocessingdate = request.ImportDate; @@ -3668,7 +3672,7 @@ private Guid CreateIncidentGuid(string driverLicenseNumber, int sequenceNumber) /// /// /// - public async Task CreateCase(CreateCaseRequest request ) + public async Task CreateCase(CreateCaseRequest request) { //return case Id in response ResultStatusReply result = new ResultStatusReply(); @@ -3681,138 +3685,143 @@ public async Task CreateCase(CreateCaseRequest request ) var driverQuery = dynamicsContext.dfp_drivers.Where(d => d.dfp_licensenumber == request.DriverLicenseNumber && d.statecode == 0).FirstOrDefault(); - - if(driverQuery != null) + if (driverQuery == null) { - await dynamicsContext.LoadPropertyAsync(driverQuery, nameof(dfp_driver.dfp_PersonId)); - - int sequenceNumber; - - if (request.SequenceNumber != null) - { - sequenceNumber = request.SequenceNumber.Value; - } - else - { - // get the number of cases that the driver has. + var createDriverRequest = new CreateDriverRequest { BirthDate = request.DriverDateOfBirth, DriverLicenseNumber = request.DriverLicenseNumber, GivenName = request.DriverGivenName, SequenceNumber = request.SequenceNumber, Surname = request.DriverSurname }; + await CreateDriver(createDriverRequest); + driverQuery = dynamicsContext.dfp_drivers.Where(d => d.dfp_licensenumber == request.DriverLicenseNumber && d.statecode == 0).FirstOrDefault(); - await dynamicsContext.LoadPropertyAsync(driverQuery, nameof(dfp_driver.dfp_driver_incident_DriverId)); + } - sequenceNumber = driverQuery.dfp_driver_incident_DriverId.Count + 1; + await dynamicsContext.LoadPropertyAsync(driverQuery, nameof(dfp_driver.dfp_PersonId)); - } + int sequenceNumber; - if (sequenceNumber == 0) - { - sequenceNumber = 1; - } + if (request.SequenceNumber != null) + { + sequenceNumber = request.SequenceNumber.Value; + } + else + { + // get the number of cases that the driver has. - Guid? ownerId = null; - if (request.Owner != null) - { - ownerId = dynamicsContext.teams.Where(x => x.name == request.Owner).FirstOrDefault()?.ownerid; - } + await dynamicsContext.LoadPropertyAsync(driverQuery, nameof(dfp_driver.dfp_driver_incident_DriverId)); + sequenceNumber = driverQuery.dfp_driver_incident_DriverId.Count + 1; - int? programArea = null; - if (string.Equals(request.CaseTypeCode, "REM", StringComparison.OrdinalIgnoreCase)) - { - programArea = TranslateProgramArea("Remedial"); - } - incident newIncident = new incident() - { - // Check the + } - customerid_contact = driverQuery.dfp_PersonId, - // set status to Open Pending for Submission - statuscode = 100000000, - // use dictionary to translate the codes - casetypecode = TranslateCaseType(request.CaseTypeCode ?? request.DocumentType), - dfp_progressstatus = 100000000, - dfp_dfcmscasesequencenumber = request.SequenceNumber, - _ownerid_value = ownerId, - dfp_programarea = programArea - }; + if (sequenceNumber == 0) + { + sequenceNumber = 1; + } - // Check sequence number on case + Guid? ownerId = null; + if (request.Owner != null) + { + ownerId = dynamicsContext.teams.Where(x => x.name == request.Owner).FirstOrDefault()?.ownerid; + } - newIncident.incidentid = CreateIncidentGuid(request.DriverLicenseNumber, sequenceNumber); - + int? programArea = null; + if (string.Equals(request.CaseTypeCode, "REM", StringComparison.OrdinalIgnoreCase)) + { + programArea = TranslateProgramArea("Remedial"); + } + incident newIncident = new incident() + { + // Check the - bool found = false; - int incidentLoop = 0; - while (IncidentExists(newIncident.incidentid.Value)) - { - sequenceNumber++; - newIncident.incidentid = CreateIncidentGuid(request.DriverLicenseNumber, sequenceNumber); + customerid_contact = driverQuery.dfp_PersonId, + // set status to Open Pending for Submission + statuscode = 100000000, + // use dictionary to translate the codes + casetypecode = TranslateCaseType(request.CaseTypeCode ?? request.DocumentType), + dfp_progressstatus = 100000000, + dfp_dfcmscasesequencenumber = request.SequenceNumber, + _ownerid_value = ownerId, + dfp_programarea = programArea + }; - incidentLoop++; + // Check sequence number on case - if (incidentLoop > 1000) - { - throw new Exception("IncidentLoop count exceeded"); - } - } - newIncident.dfp_dfcmscasesequencenumber = sequenceNumber; + newIncident.incidentid = CreateIncidentGuid(request.DriverLicenseNumber, sequenceNumber); - try - { - dynamicsContext.AddToincidents(newIncident); - if (driverQuery.dfp_PersonId != null && newIncident._customerid_value != driverQuery.dfp_PersonId.contactid) - { - dynamicsContext.SetLink(newIncident, nameof(incident.customerid_contact), driverQuery.dfp_PersonId); - } + bool found = false; + int incidentLoop = 0; + while (IncidentExists(newIncident.incidentid.Value)) + { + sequenceNumber++; + newIncident.incidentid = CreateIncidentGuid(request.DriverLicenseNumber, sequenceNumber); - var saveResult = await dynamicsContext.SaveChangesAsync(); + incidentLoop++; - var tempId = GetCreatedId(saveResult); - if (tempId != null) - { - dynamicsContext.Detach(newIncident); - newIncident = dynamicsContext.incidents.ByKey(tempId).GetValue(); - } + if (incidentLoop > 1000) + { + throw new Exception("IncidentLoop count exceeded"); + } + } + newIncident.dfp_dfcmscasesequencenumber = sequenceNumber; - result.Id = newIncident.incidentid.ToString(); - Log.Information($"Case has successfully Created : CreateCase {newIncident.incidentid} "); + try + { + dynamicsContext.AddToincidents(newIncident); - } - catch (Exception e) + if (driverQuery.dfp_PersonId != null && newIncident._customerid_value != driverQuery.dfp_PersonId.contactid) { - Log.Error(e, $"CandidateCreate ERROR CREATING INCIDENT - " + e.Message); + dynamicsContext.SetLink(newIncident, nameof(incident.customerid_contact), driverQuery.dfp_PersonId); } + var saveResult = await dynamicsContext.SaveChangesAsync(); - try + var tempId = GetCreatedId(saveResult); + + if (tempId != null) { - // first check to see that the driver is not already linked. + dynamicsContext.Detach(newIncident); + newIncident = dynamicsContext.incidents.ByKey(tempId).GetValue(); + } - //await dynamicsContext.LoadPropertyAsync(newIncident, nameof(incident.dfp_DriverId)); + result.Id = newIncident.incidentid.ToString(); + Log.Logger.Information($"Case has successfully Created : CreateCase {newIncident.incidentid} "); - if (newIncident._dfp_driverid_value == null || newIncident._dfp_driverid_value != driverQuery.dfp_driverid) - { - dynamicsContext.SetLink(newIncident, nameof(incident.dfp_DriverId), driverQuery); + } + catch (Exception e) + { + Log.Logger.Error(e, $"CandidateCreate ERROR CREATING INCIDENT - " + e.Message); + } - // add a link from driver to incident - // dynamicsContext.SetLink(driverQuery, nameof(dfp_driver.dfp_driver_incident_DriverId), newIncident); - await dynamicsContext.SaveChangesAsync(); - } + try + { + // first check to see that the driver is not already linked. - } - catch (Exception e) + //await dynamicsContext.LoadPropertyAsync(newIncident, nameof(incident.dfp_DriverId)); + + if (newIncident._dfp_driverid_value == null || newIncident._dfp_driverid_value != driverQuery.dfp_driverid) { - Log.Error(e, " Candidate Create {source} ERROR set link incident - driver " + e.Message); + dynamicsContext.SetLink(newIncident, nameof(incident.dfp_DriverId), driverQuery); + + // add a link from driver to incident + // dynamicsContext.SetLink(driverQuery, nameof(dfp_driver.dfp_driver_incident_DriverId), newIncident); + await dynamicsContext.SaveChangesAsync(); } - dynamicsContext.DetachAll(); + } + catch (Exception e) + { + Log.Logger.Error(e, " Candidate Create {source} ERROR set link incident - driver " + e.Message); } + dynamicsContext.DetachAll(); + + + return result; } @@ -3849,7 +3858,7 @@ public async Task CreateRehabTrigger(CreateCaseRequest caseCr } catch (Exception e) { - Log.Error(e, " Candidate Create {source} ERROR set link incident - driver " + e.Message); + Log.Logger.Error(e, " Candidate Create {source} ERROR set link incident - driver " + e.Message); } return result; @@ -3895,7 +3904,7 @@ public principal LookupTeam(string name, string validationPrevious) } catch (Exception e) { - Log.Error (e, $"LookupOwner {name}"); + Log.Error(e, $"LookupOwner {name}"); result = null; } @@ -3909,7 +3918,7 @@ public principal LookupTeam(string name, string validationPrevious) /// /// /// - private string TranslateStatus (int? statusCode) + private string TranslateStatus(int? statusCode) { var statusMap = new Dictionary() { @@ -4196,7 +4205,7 @@ private static async Task> SearchLegacyCandidate(DynamicsC if (!shouldSearchCases) return Array.Empty(); Guid? driverId = Guid.Empty; - var driverQuery = ctx.dfp_drivers.Expand(x => x.dfp_PersonId).Where(d => d.dfp_licensenumber == criteria.DriverLicenseNumber ).ToList(); + var driverQuery = ctx.dfp_drivers.Expand(x => x.dfp_PersonId).Where(d => d.dfp_licensenumber == criteria.DriverLicenseNumber).ToList(); dfp_driver driver = null; @@ -4565,7 +4574,7 @@ public DateTimeOffset GetDpsUploadedDate() Guid? eraResultsGuid = null; var tempQuery = dynamicsContext.dfp_submittaltypes.Where(x => x.dfp_name == "ERA Results").FirstOrDefault(); - if(tempQuery != null) + if (tempQuery != null) { eraResultsGuid = tempQuery.dfp_submittaltypeid.Value; } @@ -4586,7 +4595,7 @@ public DateTimeOffset GetDpsUploadedDate() && x.dfp_dpsclass.Contains("9 - General") // Check for 9 - General && x.dfp_DocumentTypeID.dfp_businessarea != 100000001 // Does not contain remedial && x._dfp_documenttypeid_value != eraResultsGuid - && x._dfp_documenttypeid_value != reExamResultsGuid )// Exclude ERA Results and Road Test - ICBC Re-exam docuemnt types + && x._dfp_documenttypeid_value != reExamResultsGuid)// Exclude ERA Results and Road Test - ICBC Re-exam docuemnt types .OrderBy(i => i.dfp_uploadeddate) // order by oldest uploaded date .Take(1) .FirstOrDefault(); @@ -4701,8 +4710,8 @@ public async Task ResolveCaseStatusUpdates() var resolveCases = dynamicsContext.incidents. - Where(x => x.statecode == 0 && (x.dfp_caseresolvedate <= currentDate || x.dfp_immediateclosure == true)) - .ToList() ; + Where(x => x.statecode == 0 && (x.dfp_caseresolvedate <= currentDate || x.dfp_immediateclosure == true)) + .ToList(); List ids = new List(); foreach (var item in resolveCases) @@ -4719,7 +4728,7 @@ public async Task ResolveCaseStatusUpdates() incidentid = id, }; - dynamicsContext.AttachTo("incidents",changedIncident); + dynamicsContext.AttachTo("incidents", changedIncident); changedIncident.dfp_resolvecase = true; dynamicsContext.UpdateObject(changedIncident); @@ -5110,14 +5119,14 @@ public async Task CreatePdfDocument(PdfDocument pdfDocumentRequest) } - Guid? GetCreatedId (DataServiceResponse saveResult) + Guid? GetCreatedId(DataServiceResponse saveResult) { Guid? result = null; try { string returnId = null; - if(saveResult.Count() > 0) + if (saveResult.Count() > 0) { var tempId = saveResult.First().Headers["OData-EntityId"]; @@ -5154,7 +5163,7 @@ public async Task UpdatePdfDocumentStatus(PdfDocument pdfDocum { dfp_pdfdocument pdfDocument = dynamicsContext.dfp_pdfdocuments.ByKey(Guid.Parse(pdfDocumentRequest.PdfDocumentId)).GetValue(); - if(pdfDocument != null) + if (pdfDocument != null) { // status to SEND or Failed TO Send @@ -5260,7 +5269,8 @@ public async Task UpdateDriver(Driver driver) ResultStatusReply result = new ResultStatusReply() { - Success = false, ErrorDetail = string.Empty + Success = false, + ErrorDetail = string.Empty }; var driverQuery = dynamicsContext.dfp_drivers.Expand(x => x.dfp_PersonId) .Where(x => x.dfp_licensenumber == driver.DriverLicenseNumber); @@ -5515,7 +5525,7 @@ public async Task MarkMedicalUpdateError(IcbcErrorRequest req catch (Exception ex) { result.Success = false; - Log.Logger.Error(ex,ex.Message); + Log.Logger.Error(ex, ex.Message); result.ErrorDetail = ex.Message; } } @@ -5670,7 +5680,7 @@ private string SanitizeLabel(string label) { if (label.Length > maxFieldLength) { - result = label.Substring(0,maxFieldLength); // Max 200 chars + result = label.Substring(0, maxFieldLength); // Max 200 chars } else { @@ -5839,7 +5849,7 @@ public async Task SetCasePractitionerClinic(string caseId, string practitionerId dynamicsContext.SetLink(dmerEntity, nameof(incident.dfp_MedicalPractitionerId), medicalpractitioner); } - if (! string.IsNullOrEmpty(clinicId)) + if (!string.IsNullOrEmpty(clinicId)) { // set the Clinic account clinic = dynamicsContext.accounts.ByKey(Guid.Parse(caseId)).GetValue(); diff --git a/cms-adapter/src/Rsbc.Dmf.CaseManagement/Model/Enum/RehabTriggerType.cs b/cms-adapter/src/Rsbc.Dmf.CaseManagement/Model/Enum/RehabTriggerType.cs index ceae9e7ab..282515cc3 100644 --- a/cms-adapter/src/Rsbc.Dmf.CaseManagement/Model/Enum/RehabTriggerType.cs +++ b/cms-adapter/src/Rsbc.Dmf.CaseManagement/Model/Enum/RehabTriggerType.cs @@ -3,7 +3,7 @@ public enum RehabTriggerType { CCC = 100000000, - ADM = 100000001, + ADMIN = 100000001, ILS = 100000002, SUPT = 100000003, REO = 100000004 diff --git a/document-storage-adapter/src/Pssg.DocumentStorageAdapter/Protos/documentStorageAdapter.proto b/document-storage-adapter/src/Pssg.DocumentStorageAdapter/Protos/documentStorageAdapter.proto index 7a7d2a3c5..4a201e154 100644 --- a/document-storage-adapter/src/Pssg.DocumentStorageAdapter/Protos/documentStorageAdapter.proto +++ b/document-storage-adapter/src/Pssg.DocumentStorageAdapter/Protos/documentStorageAdapter.proto @@ -83,6 +83,7 @@ message DownloadFileReply { ResultStatus resultStatus = 2; string serverRelativeUrl = 3; string errorDetail = 4; + string fileName = 5; } message DownloadFolderReply { diff --git a/icbc-adapter/src/Pssg.Dmf.IcbcAdapter/IcbcNotifactionsUtils.cs b/icbc-adapter/src/Pssg.Dmf.IcbcAdapter/IcbcNotifactionsUtils.cs index b8f78789a..4c0707767 100644 --- a/icbc-adapter/src/Pssg.Dmf.IcbcAdapter/IcbcNotifactionsUtils.cs +++ b/icbc-adapter/src/Pssg.Dmf.IcbcAdapter/IcbcNotifactionsUtils.cs @@ -66,12 +66,16 @@ internal async Task CreateOrUpdateCases(List cases) DriverLicenseNumber = dmf_case.LNUM, CaseTypeCode = "REM", TriggerType = dmf_case.CAND_CAUSE_CD, - Owner = "Remedial" + Owner = "Remedial", + DriverDateOfBirth = Timestamp.FromDateTime(DateTime.SpecifyKind(DateTime.Parse(dmf_case.BIRTH_DT), DateTimeKind.Utc)), + DriverSurname = dmf_case.SURNAME }; await _caseManagerClient.CreateCaseAsync(caseToCreate); } - Log.Logger.Information($"Successfully added {cases.Count} cases "); + + + Log.Logger.Information($"Successfully proccessed {cases.Count} cases see cms logs for more details"); } catch (Exception ex) { @@ -163,7 +167,8 @@ private async Task GetIcbcNotifications() result.NotificationFiles = new List(); var files = await _documentStorageAdapterClient.DownloadFolderAsync( new DownloadFolderRequest { BucketConfigName = "ICBC_NOTIFICATIONS_BUCKET" }); - Log.Logger.Information("Fetching ICBC Notifications dat file.."); + var fileNames = files.Files.Select(f => f.FileName).ToList(); + Log.Logger.Information("Fetching ICBC Notifications dat file(s):" + string.Join(",", fileNames)); if (files.ResultStatus == Pssg.DocumentStorageAdapter.ResultStatus.Success) { foreach (var fileBytes in files.Files)