diff --git a/Apps.XtrfCustomerPortal/Actions/InvoiceActions.cs b/Apps.XtrfCustomerPortal/Actions/InvoiceActions.cs index 92134fc..c7619bf 100644 --- a/Apps.XtrfCustomerPortal/Actions/InvoiceActions.cs +++ b/Apps.XtrfCustomerPortal/Actions/InvoiceActions.cs @@ -31,19 +31,12 @@ public async Task SearchInvoices([ActionParameter] SearchIn endpoint = endpoint.AddQueryParameter("search", request.Search); } - if (request.InvoiceDateFrom.HasValue) - { - var invoiceDateFromMilliseconds = new DateTimeOffset(request.InvoiceDateFrom.Value).ToUnixTimeMilliseconds(); - endpoint = endpoint.AddQueryParameter("invoiceDateFrom", invoiceDateFromMilliseconds.ToString()); - } - - if (request.InvoiceDateTo.HasValue) - { - var invoiceDateToMilliseconds = new DateTimeOffset(request.InvoiceDateTo.Value).ToUnixTimeMilliseconds(); - endpoint = endpoint.AddQueryParameter("invoiceDateTo", invoiceDateToMilliseconds.ToString()); - } - var invoices = await FetchInvoicesWithPagination(endpoint); + invoices.Invoices = invoices.Invoices + .Where(i => request.InvoiceDateFrom == null || i.ExpectedFullyPaidDate >= request.InvoiceDateFrom) + .Where(i => request.InvoiceDateTo == null || i.ExpectedFullyPaidDate <= request.InvoiceDateTo) + .ToList(); + return invoices; } diff --git a/Apps.XtrfCustomerPortal/Actions/ProjectActions.cs b/Apps.XtrfCustomerPortal/Actions/ProjectActions.cs index 74c5368..20f143e 100644 --- a/Apps.XtrfCustomerPortal/Actions/ProjectActions.cs +++ b/Apps.XtrfCustomerPortal/Actions/ProjectActions.cs @@ -44,37 +44,17 @@ public async Task SearchProjects([ActionParameter] SearchPr { endpoint = endpoint.AddQueryParameter("customerProjectNumber", searchProjectsRequest.CustomerProjectNumber); } - - if (searchProjectsRequest.CreatedOnFrom.HasValue) - { - var createdOnFromMilliseconds = - new DateTimeOffset(searchProjectsRequest.CreatedOnFrom.Value).ToUnixTimeMilliseconds(); - endpoint = endpoint.AddQueryParameter("startDateFrom", createdOnFromMilliseconds.ToString()); - } - - if (searchProjectsRequest.CreatedOnTo.HasValue) - { - var createdOnToMilliseconds = - new DateTimeOffset(searchProjectsRequest.CreatedOnTo.Value).ToUnixTimeMilliseconds(); - endpoint = endpoint.AddQueryParameter("startDateTo", createdOnToMilliseconds.ToString()); - } - - if (searchProjectsRequest.ExpirationFrom.HasValue) - { - var expirationFromMilliseconds = - new DateTimeOffset(searchProjectsRequest.ExpirationFrom.Value).ToUnixTimeMilliseconds(); - endpoint = endpoint.AddQueryParameter("deadlineFrom", expirationFromMilliseconds.ToString()); - } - - if (searchProjectsRequest.ExpirationTo.HasValue) - { - var expirationToMilliseconds = - new DateTimeOffset(searchProjectsRequest.ExpirationTo.Value).ToUnixTimeMilliseconds(); - endpoint = endpoint.AddQueryParameter("deadlineTo", expirationToMilliseconds.ToString()); - } - + var projects = await FetchProjectsWithPagination(endpoint); - return new GetProjectsResponse(projects); + var response = new GetProjectsResponse(projects); + response.Projects = response.Projects + .Where(x => searchProjectsRequest.CreatedOnFrom == null || x.StartDate >= searchProjectsRequest.CreatedOnFrom) + .Where(x => searchProjectsRequest.CreatedOnTo == null || x.StartDate <= searchProjectsRequest.CreatedOnTo) + .Where(x => searchProjectsRequest.ExpirationFrom == null || x.Deadline >= searchProjectsRequest.ExpirationFrom) + .Where(x => searchProjectsRequest.ExpirationTo == null || x.Deadline <= searchProjectsRequest.ExpirationTo) + .ToList(); + + return response; } [Action("Get project", Description = "Get project based on project ID")] @@ -84,7 +64,7 @@ public async Task GetProject([ActionParameter] ProjectIdentifie await Client.ExecuteRequestAsync($"/projects/{projectIdentifier.ProjectId}", Method.Get, null); return new ProjectResponse(projectDto); } - + [Action("Create project", Description = "Create a new project")] public async Task CreateProject([ActionParameter] CreateProjectRequest request) { @@ -98,24 +78,24 @@ public async Task CreateProject([ActionParameter] CreateProject specializationId = int.Parse(request.SpecializationId), deliveryDate = new { - time = request.DeliveryDate.HasValue - ? new DateTimeOffset(request.DeliveryDate.Value).ToUnixTimeMilliseconds() + time = request.DeliveryDate.HasValue + ? new DateTimeOffset(request.DeliveryDate.Value).ToUnixTimeMilliseconds() : DateTime.Now.AddDays(7).ToUnixTimeMilliseconds() }, - notes = request.Note ?? string.Empty, + notes = string.Empty, priceProfileId = int.Parse(request.PriceProfileId), personId = int.Parse(request.PersonId), sendBackToId = request.SendBackToId == null ? int.Parse(request.PersonId) : int.Parse(request.SendBackToId), - additionalPersonIds = request.AdditionalPersonIds == null - ? new List() + additionalPersonIds = request.AdditionalPersonIds == null + ? new List() : request.AdditionalPersonIds.Select(int.Parse).ToList(), files = await UploadFilesAsync(request.Files, fileManagementClient), - referenceFiles = request.ReferenceFiles == null - ? new List() + referenceFiles = request.ReferenceFiles == null + ? new List() : await UploadFilesAsync(request.ReferenceFiles, fileManagementClient), customFields = new List(), - officeId = request.OfficeId != null - ? int.Parse(request.OfficeId) + officeId = request.OfficeId != null + ? int.Parse(request.OfficeId) : (await GetDefaultOffice()).Id, budgetCode = request.BudgetCode ?? string.Empty, catToolType = request.CatToolType ?? "TRADOS" @@ -124,32 +104,36 @@ public async Task CreateProject([ActionParameter] CreateProject var projectDto = await Client.ExecuteRequestAsync("/v2/projects", Method.Post, obj); return new ProjectResponse(projectDto); } - - [Action("Download project files", Description = "Download project translation files")] - public async Task DownloadProjectFiles([ActionParameter] ProjectIdentifier projectIdentifier) + + [Action("Download project translated files", Description = "Download project translation files")] + public async Task DownloadProjectFiles( + [ActionParameter] ProjectIdentifier projectIdentifier) { - var taskFilesDto = await Client.ExecuteRequestAsync($"/projects/{projectIdentifier.ProjectId}/files", Method.Get, null); + var taskFilesDto = + await Client.ExecuteRequestAsync($"/projects/{projectIdentifier.ProjectId}/files", Method.Get, + null); var files = taskFilesDto.TasksFiles.SelectMany(x => x.Output?.Files ?? new List()).ToList(); var fileReferences = new List(); foreach (var file in files) { - var invoicePdf = await Client.ExecuteRequestAsync($"/projects/files/{file.Id}", Method.Get, null, "application/octet-stream"); + var invoicePdf = await Client.ExecuteRequestAsync($"/projects/files/{file.Id}", Method.Get, null, + "application/octet-stream"); var rawBytes = invoicePdf.RawBytes!; - + var stream = new MemoryStream(rawBytes); stream.Position = 0; - + var fileReference = await fileManagementClient.UploadAsync(stream, "application/octet-stream", file.Name); fileReferences.Add(fileReference); } - + return new DownloadProjectFilesResponse { Files = fileReferences }; } - + private async Task> FetchProjectsWithPagination(string endpoint) { var allProjects = new List(); diff --git a/Apps.XtrfCustomerPortal/Actions/QuoteActions.cs b/Apps.XtrfCustomerPortal/Actions/QuoteActions.cs index 611b601..1e6cce5 100644 --- a/Apps.XtrfCustomerPortal/Actions/QuoteActions.cs +++ b/Apps.XtrfCustomerPortal/Actions/QuoteActions.cs @@ -30,31 +30,15 @@ public async Task SearchQuotes([ActionParameter] SearchQuotes endpoint = endpoint.AddQueryParameter("search", searchQuotesRequest.Search); } - if (searchQuotesRequest.CreatedOnFrom.HasValue) - { - var createdOnFromMilliseconds = new DateTimeOffset(searchQuotesRequest.CreatedOnFrom.Value).ToUnixTimeMilliseconds(); - endpoint = endpoint.AddQueryParameter("createdOnFrom", createdOnFromMilliseconds.ToString()); - } - - if (searchQuotesRequest.CreatedOnTo.HasValue) - { - var createdOnToMilliseconds = new DateTimeOffset(searchQuotesRequest.CreatedOnTo.Value).ToUnixTimeMilliseconds(); - endpoint = endpoint.AddQueryParameter("createdOnTo", createdOnToMilliseconds.ToString()); - } - - if (searchQuotesRequest.ExpirationFrom.HasValue) - { - var expirationFromMilliseconds = new DateTimeOffset(searchQuotesRequest.ExpirationFrom.Value).ToUnixTimeMilliseconds(); - endpoint = endpoint.AddQueryParameter("expirationDateFrom", expirationFromMilliseconds.ToString()); - } + var quotes = await FetchQuotesWithPagination(endpoint); - if (searchQuotesRequest.ExpirationTo.HasValue) - { - var expirationToMilliseconds = new DateTimeOffset(searchQuotesRequest.ExpirationTo.Value).ToUnixTimeMilliseconds(); - endpoint = endpoint.AddQueryParameter("expirationDateTo", expirationToMilliseconds.ToString()); - } + quotes.Quotes = quotes.Quotes + .Where(x => searchQuotesRequest.CreatedOnFrom == null || x.StartDate >= searchQuotesRequest.CreatedOnFrom) + .Where(x => searchQuotesRequest.CreatedOnTo == null || x.StartDate <= searchQuotesRequest.CreatedOnTo) + .Where(x => searchQuotesRequest.ExpirationFrom == null || x.Deadline >= searchQuotesRequest.ExpirationFrom) + .Where(x => searchQuotesRequest.ExpirationTo == null || x.Deadline <= searchQuotesRequest.ExpirationTo) + .ToList(); - var quotes = await FetchQuotesWithPagination(endpoint); return quotes; } @@ -84,7 +68,7 @@ public async Task CreateQuote([ActionParameter] QuoteCreateReques ? new DateTimeOffset(request.DeliveryDate.Value).ToUnixTimeMilliseconds() : DateTime.Now.AddDays(7).ToUnixTimeMilliseconds() }, - notes = request.Note ?? string.Empty, + notes = string.Empty, priceProfileId = int.Parse(request.PriceProfileId), personId = int.Parse(request.PersonId), sendBackToId = request.SendBackToId == null ? int.Parse(request.PersonId) : int.Parse(request.SendBackToId), diff --git a/Apps.XtrfCustomerPortal/Api/ApiClient.cs b/Apps.XtrfCustomerPortal/Api/ApiClient.cs index 30defad..18bb946 100644 --- a/Apps.XtrfCustomerPortal/Api/ApiClient.cs +++ b/Apps.XtrfCustomerPortal/Api/ApiClient.cs @@ -30,8 +30,7 @@ public async Task ExecuteRequestAsync(string endpoint, Method method, obje request.WithJsonBody(bodyObj); } - var response = await ExecuteWithErrorHandling(request); - return response; + return await ExecuteWithErrorHandling(request); } public async Task ExecuteRequestAsync(string endpoint, Method method, object? bodyObj, string? acceptHeader = null) @@ -95,6 +94,29 @@ private async Task GetTokenAsync() protected override Exception ConfigureErrorException(RestResponse response) { - return new Exception($"Error message: {response.Content}; StatusCode: {response.StatusCode}"); + try + { + var xmlSerializer = new XmlSerializer(typeof(XmlErrorDto)); + using var xmlReader = new StringReader(response.Content!); + + var xmlErrorDto = (XmlErrorDto)xmlSerializer.Deserialize(xmlReader)!; + return new Exception($"Error message: {xmlErrorDto.Body}; Status code: {response.StatusCode}"); + } + catch (InvalidOperationException) + { + try + { + var jsonErrorDto = JsonConvert.DeserializeObject(response.Content!)!; + return new Exception($"Error message: {jsonErrorDto.ErrorMessage}; Status code: {response.StatusCode}"); + } + catch (JsonException) + { + return new Exception($"Error message: {response.Content}; Status code: {response.StatusCode}"); + } + } + catch (Exception ex) + { + return new Exception($"Unexpected error during error deserialization: {ex.Message}; Error body: {response.Content!} ; Status code: {response.StatusCode}"); + } } } \ No newline at end of file diff --git a/Apps.XtrfCustomerPortal/Apps.XtrfCustomerPortal.csproj b/Apps.XtrfCustomerPortal/Apps.XtrfCustomerPortal.csproj index 940e35e..46fb7a7 100644 --- a/Apps.XtrfCustomerPortal/Apps.XtrfCustomerPortal.csproj +++ b/Apps.XtrfCustomerPortal/Apps.XtrfCustomerPortal.csproj @@ -6,7 +6,7 @@ enable XTRF Customer portal The XTRF Customer Portal is a private website restricted to authorized use for business purposes. It allows clients to access and manage translation project details. Within the portal, clients can view and edit information such as contact details, account manager, pricing, language combinations, and CAT tools used. - 1.0.0 + 1.0.1 Apps.XtrfCustomerPortal Apps.XtrfCustomerPortal diff --git a/Apps.XtrfCustomerPortal/DataSources/Static/ProjectStatusDataSource.cs b/Apps.XtrfCustomerPortal/DataSources/Static/ProjectStatusDataSource.cs index dec6429..26b9f0f 100644 --- a/Apps.XtrfCustomerPortal/DataSources/Static/ProjectStatusDataSource.cs +++ b/Apps.XtrfCustomerPortal/DataSources/Static/ProjectStatusDataSource.cs @@ -11,7 +11,8 @@ public Dictionary GetData() { "OPENED", "Opened" }, { "CLOSED", "Closed" }, { "CLAIM", "Claim" }, - { "CANCELLED", "Cancelled" } + { "CANCELLED", "Cancelled" }, + { "REQUESTED_PROJECT", "Requested"} }; } } \ No newline at end of file diff --git a/Apps.XtrfCustomerPortal/DataSources/Static/ViewDataSource.cs b/Apps.XtrfCustomerPortal/DataSources/Static/ViewDataSource.cs new file mode 100644 index 0000000..0ee22a1 --- /dev/null +++ b/Apps.XtrfCustomerPortal/DataSources/Static/ViewDataSource.cs @@ -0,0 +1,18 @@ +using Blackbird.Applications.Sdk.Common.Dictionaries; + +namespace Apps.XtrfCustomerPortal.DataSources.Static; + +public class ViewDataSource : IStaticDataSourceHandler +{ + public Dictionary GetData() + { + return new() + { + {"UNPAID", "Unpaid"}, + {"OVERDUE", "Overdue"}, + {"EARLY_UNPAID", "Early unpaid"}, + {"PAID", "Paid"}, + {"ALL", "All"} + }; + } +} \ No newline at end of file diff --git a/Apps.XtrfCustomerPortal/Models/Dtos/JsonErrorDto.cs b/Apps.XtrfCustomerPortal/Models/Dtos/JsonErrorDto.cs new file mode 100644 index 0000000..5da4e9a --- /dev/null +++ b/Apps.XtrfCustomerPortal/Models/Dtos/JsonErrorDto.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Apps.XtrfCustomerPortal.Models.Dtos; + +public class JsonErrorDto +{ + [JsonProperty("status")] + public string Status { get; set; } + + [JsonProperty("errorMessage")] + public string ErrorMessage { get; set; } + + [JsonProperty("detailedMessage")] + public string DetailedMessage { get; set; } +} \ No newline at end of file diff --git a/Apps.XtrfCustomerPortal/Models/Dtos/TaskFilesDto.cs b/Apps.XtrfCustomerPortal/Models/Dtos/TaskFilesDto.cs index f3525e3..bd5c1e3 100644 --- a/Apps.XtrfCustomerPortal/Models/Dtos/TaskFilesDto.cs +++ b/Apps.XtrfCustomerPortal/Models/Dtos/TaskFilesDto.cs @@ -3,13 +3,15 @@ namespace Apps.XtrfCustomerPortal.Models.Dtos; public class TaskFilesDto { public int Id { get; set; } + public string IdNumber { get; set; } public List TasksFiles { get; set; } + public bool OutputFilesAsZipDownloadable { get; set; } public class TaskFile { - public int Id { get; set; } + public string Id { get; set; } public string IdNumber { get; set; } public LanguageCombination LanguageCombination { get; set; } public FileGroup InputWorkfiles { get; set; } @@ -26,7 +28,7 @@ public class LanguageCombination public class Language { - public int Id { get; set; } + public string Id { get; set; } public string Symbol { get; set; } public string Name { get; set; } public string DisplayName { get; set; } @@ -49,7 +51,7 @@ public class Directory public class File { public string Name { get; set; } - public int Id { get; set; } + public string Id { get; set; } public bool Downloadable { get; set; } public string Category { get; set; } public bool Zip { get; set; } diff --git a/Apps.XtrfCustomerPortal/Models/Dtos/XmlErrorDto.cs b/Apps.XtrfCustomerPortal/Models/Dtos/XmlErrorDto.cs new file mode 100644 index 0000000..071a95d --- /dev/null +++ b/Apps.XtrfCustomerPortal/Models/Dtos/XmlErrorDto.cs @@ -0,0 +1,19 @@ +using System.Xml.Serialization; + +namespace Apps.XtrfCustomerPortal.Models.Dtos; + +[XmlRoot("html")] +public class XmlErrorDto +{ + [XmlElement("head")] + public Head Head { get; set; } + + [XmlElement("body")] + public string Body { get; set; } +} + +public class Head +{ + [XmlElement("title")] + public string Title { get; set; } +} \ No newline at end of file diff --git a/Apps.XtrfCustomerPortal/Models/Requests/CreateProjectRequest.cs b/Apps.XtrfCustomerPortal/Models/Requests/CreateProjectRequest.cs index 68dfb6c..92c95d8 100644 --- a/Apps.XtrfCustomerPortal/Models/Requests/CreateProjectRequest.cs +++ b/Apps.XtrfCustomerPortal/Models/Requests/CreateProjectRequest.cs @@ -32,13 +32,10 @@ public class CreateProjectRequest [Display("Delivery date", Description = "By default, the delivery date is set to the current date + 7 days.")] public DateTime? DeliveryDate { get; set; } - [Display("Note")] - public string? Note { get; set; } - [Display("Price profile ID"), DataSource(typeof(PriceProfileDataSource))] public string PriceProfileId { get; set; } - [Display("Person ID"), DataSource(typeof(PersonDataSource))] + [Display("Contact person ID"), DataSource(typeof(PersonDataSource))] public string PersonId { get; set; } [Display("Send back to ID"), DataSource(typeof(PersonDataSource))] @@ -47,7 +44,7 @@ public class CreateProjectRequest [Display("Additional person IDs"), DataSource(typeof(PersonDataSource))] public IEnumerable? AdditionalPersonIds { get; set; } - [Display("Additional email addresses")] + [Display("Reference files")] public IEnumerable? ReferenceFiles { get; set; } [Display("Office ID"), DataSource(typeof(OfficeDataSource))] @@ -56,6 +53,6 @@ public class CreateProjectRequest [Display("Budget code")] public string? BudgetCode { get; set; } - [Display("Cat tool type", Description = "By default, the value is set to 'Trados'."), StaticDataSource(typeof(CatToolTypeDataSource))] + [Display("CAT tool type", Description = "By default, the value is set to 'Trados'."), StaticDataSource(typeof(CatToolTypeDataSource))] public string? CatToolType { get; set; } } \ No newline at end of file diff --git a/Apps.XtrfCustomerPortal/Models/Requests/QuoteCreateRequest.cs b/Apps.XtrfCustomerPortal/Models/Requests/QuoteCreateRequest.cs index a35f0a9..e55e7f7 100644 --- a/Apps.XtrfCustomerPortal/Models/Requests/QuoteCreateRequest.cs +++ b/Apps.XtrfCustomerPortal/Models/Requests/QuoteCreateRequest.cs @@ -24,7 +24,7 @@ public class QuoteCreateRequest public string SourceLanguageId { get; set; } [Display("Target language IDs"), DataSource(typeof(LanguageDataSource))] - public IEnumerable? TargetLanguageIds { get; set; } + public IEnumerable TargetLanguageIds { get; set; } [Display("Specialization ID"), DataSource(typeof(SpecializationDataSource))] public string SpecializationId { get; set; } @@ -32,13 +32,10 @@ public class QuoteCreateRequest [Display("Delivery date", Description = "By default, the delivery date is set to the current date + 7 days.")] public DateTime? DeliveryDate { get; set; } - [Display("Note")] - public string? Note { get; set; } - [Display("Price profile ID"), DataSource(typeof(PriceProfileDataSource))] public string PriceProfileId { get; set; } - [Display("Person ID"), DataSource(typeof(PersonDataSource))] + [Display("Contact person ID"), DataSource(typeof(PersonDataSource))] public string PersonId { get; set; } [Display("Send back to ID"), DataSource(typeof(PersonDataSource))] @@ -56,6 +53,6 @@ public class QuoteCreateRequest [Display("Budget code")] public string? BudgetCode { get; set; } - [Display("Cat tool type", Description = "By default, the value is set to 'Trados'."), StaticDataSource(typeof(CatToolTypeDataSource))] + [Display("CAT tool type", Description = "By default, the value is set to 'Trados'."), StaticDataSource(typeof(CatToolTypeDataSource))] public string? CatToolType { get; set; } } \ No newline at end of file diff --git a/Apps.XtrfCustomerPortal/Models/Requests/SearchInvoicesRequest.cs b/Apps.XtrfCustomerPortal/Models/Requests/SearchInvoicesRequest.cs index 5467d84..2270275 100644 --- a/Apps.XtrfCustomerPortal/Models/Requests/SearchInvoicesRequest.cs +++ b/Apps.XtrfCustomerPortal/Models/Requests/SearchInvoicesRequest.cs @@ -1,9 +1,12 @@ +using Apps.XtrfCustomerPortal.DataSources.Static; using Blackbird.Applications.Sdk.Common; +using Blackbird.Applications.Sdk.Common.Dictionaries; namespace Apps.XtrfCustomerPortal.Models.Requests; public class SearchInvoicesRequest { + [StaticDataSource(typeof(ViewDataSource))] public string? View { get; set; } [Display("Search (Final number, draft number or accountancy person)")] diff --git a/Apps.XtrfCustomerPortal/Models/Requests/SearchProjectsRequest.cs b/Apps.XtrfCustomerPortal/Models/Requests/SearchProjectsRequest.cs index d2996a4..b864a7b 100644 --- a/Apps.XtrfCustomerPortal/Models/Requests/SearchProjectsRequest.cs +++ b/Apps.XtrfCustomerPortal/Models/Requests/SearchProjectsRequest.cs @@ -9,7 +9,7 @@ public class SearchProjectsRequest [StaticDataSource(typeof(ProjectStatusDataSource))] public IEnumerable? Statuses { get; set; } - [StaticDataSource(typeof(SurveyStatusDataSource))] + [Display("Survey status"), StaticDataSource(typeof(SurveyStatusDataSource))] public string? SurveyStatus { get; set; } [Display("Search (Project ID, ID number, reference number, or project name)")] diff --git a/Apps.XtrfCustomerPortal/Models/Responses/Invoices/InvoiceResponse.cs b/Apps.XtrfCustomerPortal/Models/Responses/Invoices/InvoiceResponse.cs index 8af642a..6da072a 100644 --- a/Apps.XtrfCustomerPortal/Models/Responses/Invoices/InvoiceResponse.cs +++ b/Apps.XtrfCustomerPortal/Models/Responses/Invoices/InvoiceResponse.cs @@ -3,48 +3,6 @@ namespace Apps.XtrfCustomerPortal.Models.Responses.Invoices; -/* - * [ - { - "id": 5, - "draftNumber": null, - "finalNumber": "2024/1", - "creditNoteNumber": null, - "currency": "€", - "totalBrutto": 0, - "totalNetto": 0, - "formattedTotalBrutto": "€0.00", - "formattedTotalNetto": "€0.00", - "charges": [ - { - "value": 0, - "paidValue": 0, - "dueDate": { - "formatted": "2024-07-02", - "millisGMT": 1719914400000 - } - } - ], - "expectedFullyPaidDate": { - "formatted": "2024-07-02", - "millisGMT": 1719914400000 - }, - "paymentState": "Fully Paid", - "overdue": false, - "notPaid": false, - "documents": [ - { - "id": 820, - "name": "Built-in-Client Invoice (PDF) (en)", - "format": "pdf" - } - ], - "office": { - "name": "Vitalii" - } - } -] - */ public class InvoiceResponse { [Display("Invoice ID")] diff --git a/Apps.XtrfCustomerPortal/Models/Responses/Projects/ProjectResponse.cs b/Apps.XtrfCustomerPortal/Models/Responses/Projects/ProjectResponse.cs index e2a300f..6554db2 100644 --- a/Apps.XtrfCustomerPortal/Models/Responses/Projects/ProjectResponse.cs +++ b/Apps.XtrfCustomerPortal/Models/Responses/Projects/ProjectResponse.cs @@ -1,7 +1,7 @@ -using System.Globalization; using Apps.XtrfCustomerPortal.Models.Dtos; using Apps.XtrfCustomerPortal.Models.Responses.Quotes; using Blackbird.Applications.Sdk.Common; +using Apps.XtrfCustomerPortal.Utilities.Extensions; namespace Apps.XtrfCustomerPortal.Models.Responses.Projects; @@ -42,8 +42,6 @@ public class ProjectResponse public DateTime Deadline { get; set; } - public string Note { get; set; } - public string Status { get; set; } [Display("Is project")] @@ -75,29 +73,12 @@ public ProjectResponse(ProjectDto dto) SourceLanguage = lc.SourceLanguage.Symbol, TargetLanguage = lc.TargetLanguage.Symbol }).ToList(); - StartDate = ParseDate(dto.StartDate?.Formatted); - Deadline = ParseDate(dto.Deadline?.Formatted); - Note = dto.CustomerNotes; + StartDate = dto.StartDate?.Formatted.ParseDate() ?? DateTime.MinValue; + Deadline = dto.Deadline?.Formatted.ParseDate() ?? DateTime.MinValue; Status = dto.Status; IsProject = dto.IsProject; BudgetCode = dto.BudgetCode; HasOutputFiles = dto.HasOutputFiles; AwaitingCustomerReview = dto.AwaitingCustomerReview; } - - private DateTime ParseDate(string? dateString) - { - if (string.IsNullOrEmpty(dateString)) - { - return DateTime.MinValue; - } - - const string format = "yyyy-MM-dd HH:mm 'CET'"; - if (DateTime.TryParseExact(dateString, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime parsedDate)) - { - return parsedDate; - } - - return DateTime.MinValue; - } } \ No newline at end of file diff --git a/Apps.XtrfCustomerPortal/Models/Responses/Quotes/QuoteResponse.cs b/Apps.XtrfCustomerPortal/Models/Responses/Quotes/QuoteResponse.cs index ae41a76..6918b7d 100644 --- a/Apps.XtrfCustomerPortal/Models/Responses/Quotes/QuoteResponse.cs +++ b/Apps.XtrfCustomerPortal/Models/Responses/Quotes/QuoteResponse.cs @@ -1,5 +1,5 @@ -using System.Globalization; using Apps.XtrfCustomerPortal.Models.Dtos; +using Apps.XtrfCustomerPortal.Utilities.Extensions; using Blackbird.Applications.Sdk.Common; namespace Apps.XtrfCustomerPortal.Models.Responses.Quotes; @@ -34,8 +34,6 @@ public class QuoteResponse [Display("Office")] public string Office { get; set; } - [Display("Customer notes")] public string CustomerNotes { get; set; } - [Display("Status")] public string Status { get; set; } [Display("Sales person ID")] public string SalesPersonId { get; set; } @@ -59,31 +57,13 @@ public QuoteResponse(QuoteDto quoteDtoDto) SourceLanguage = lc.SourceLanguage.Symbol, TargetLanguage = lc.TargetLanguage.Symbol }).ToList(); - StartDate = ParseDate(quoteDtoDto.StartDate?.Formatted); - Deadline = ParseDate(quoteDtoDto.Deadline?.Formatted); + StartDate = quoteDtoDto.StartDate?.Formatted.ParseDate() ?? DateTime.MinValue; + Deadline = quoteDtoDto.Deadline?.Formatted.ParseDate() ?? DateTime.MinValue; Office = quoteDtoDto.Office.Name; - CustomerNotes = quoteDtoDto.CustomerNotes; Status = quoteDtoDto.Status; SalesPersonId = quoteDtoDto.SalesPerson?.Id.ToString() ?? string.Empty; SalesPersonName = quoteDtoDto.SalesPerson?.Name ?? string.Empty; } - - // Example: 2023-12-20 08:30 CET - private DateTime ParseDate(string? dateString) - { - if (string.IsNullOrEmpty(dateString)) - { - return DateTime.MinValue; - } - - const string format = "yyyy-MM-dd HH:mm 'CET'"; - if (DateTime.TryParseExact(dateString, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime parsedDate)) - { - return parsedDate; - } - - return DateTime.MinValue; - } } public class LanguageCombinationResponse diff --git a/Apps.XtrfCustomerPortal/Utilities/Extensions/DateTimeExtensions.cs b/Apps.XtrfCustomerPortal/Utilities/Extensions/DateTimeExtensions.cs index 93d2c08..44f03f9 100644 --- a/Apps.XtrfCustomerPortal/Utilities/Extensions/DateTimeExtensions.cs +++ b/Apps.XtrfCustomerPortal/Utilities/Extensions/DateTimeExtensions.cs @@ -1,3 +1,5 @@ +using System.Globalization; + namespace Apps.XtrfCustomerPortal.Utilities.Extensions; public static class DateTimeExtensions @@ -6,4 +8,22 @@ public static long ToUnixTimeMilliseconds(this DateTime dateTime) { return new DateTimeOffset(dateTime).ToUnixTimeMilliseconds(); } + + public static DateTime ParseDate(this string? dateString) + { + if (string.IsNullOrEmpty(dateString)) + { + return DateTime.MinValue; + } + + const string format = "yyyy-MM-dd HH:mm zzz"; + dateString = dateString.Replace("CEST", "+02:00").Replace("CET", "+01:00"); + + if (DateTimeOffset.TryParseExact(dateString, format, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTimeOffset parsedDate)) + { + return parsedDate.DateTime; + } + + return DateTime.MinValue; + } } \ No newline at end of file