complete order sending process using Hangfire

This commit is contained in:
dibakor 2026-07-21 13:10:16 +06:00
parent 2143a3761c
commit 8559e35086
6 changed files with 61 additions and 19 deletions

View File

@ -82,6 +82,7 @@ public class GetOrderSummaryRequest : PagedRequest
public class UpdateSapDetailsRequest public class UpdateSapDetailsRequest
{ {
public int OrderId { get; set; } public int OrderId { get; set; }
public string SapOrderNo { get; set; }
public SAPOrderStatusEnum Status { get; set; } public SAPOrderStatusEnum Status { get; set; }
public DateTime SentAt { get; set; } public DateTime SentAt { get; set; }
public int RetryCount { get; set; } public int RetryCount { get; set; }

View File

@ -1,6 +1,7 @@
 
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations; using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp; using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -15,7 +16,7 @@ public interface IIntegrationHttpService
Task<IList<IntegrationMaterialStockHttpResponse>> GetMaterialStockAsync(string plantCode, Task<IList<IntegrationMaterialStockHttpResponse>> GetMaterialStockAsync(string plantCode,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
Task<string> SendSAPOrdersAsync(GetOrderForSAPResponse request, Task<Tuple<string, string>> SendSAPOrdersAsync(GetOrderForSAPResponse request,
CancellationToken cancellationToken = default); CancellationToken cancellationToken = default);
} }

View File

@ -34,16 +34,34 @@ public class BackgroundJobService : IBackgroundJobService
foreach (var item in pendingOrderIds) foreach (var item in pendingOrderIds)
{ {
var orderDetails = await _orderService.GetOrderDetailsForSapByIdAsync(item); var orderDetails = await _orderService.GetOrderDetailsForSapByIdAsync(item);
string jsonResult = JsonConvert.SerializeObject(orderDetails); _logger.LogInformation("SendingOrder for Order No with: " + orderDetails.PurchaseOrderByCustomer);
string httpResponse = await _httpService.SendSAPOrdersAsync(orderDetails); var httpResponse = await _httpService.SendSAPOrdersAsync(orderDetails);
await _orderService.UpdateSendingSapDetailsAsync(new UpdateSapDetailsRequest if(string.IsNullOrEmpty( httpResponse.Item2))
{ {
OrderId = item, await _orderService.UpdateSendingSapDetailsAsync(new UpdateSapDetailsRequest
SentAt = DateTime.Now, {
RetryCount =1, OrderId = item,
ReturnMessage = httpResponse SapOrderNo = httpResponse.Item2,
}); SentAt = DateTime.Now,
Status = SAPOrderStatusEnum.Error,
RetryCount = 1,
LastError = httpResponse.Item1
});
}
else
{
await _orderService.UpdateSendingSapDetailsAsync(new UpdateSapDetailsRequest
{
OrderId = item,
SapOrderNo = httpResponse.Item2,
SentAt = DateTime.Now,
Status = SAPOrderStatusEnum.Sent,
RetryCount = 1,
ReturnMessage = httpResponse.Item1
});
}
_logger.LogInformation("Order Successfully sent to SAP,with Order No: " + orderDetails.PurchaseOrderByCustomer);
} }
} }
catch(Exception ex) catch(Exception ex)

View File

@ -8,6 +8,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net.Http; using System.Net.Http;
using System.Net.Http.Json; using System.Net.Http.Json;
using System.Text;
using System.Text.Json;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -73,24 +75,43 @@ public class IntegrationHttpService : IIntegrationHttpService
} }
} }
public async Task<string> SendSAPOrdersAsync(GetOrderForSAPResponse request, CancellationToken cancellationToken = default) public async Task<Tuple<string,string>> SendSAPOrdersAsync(GetOrderForSAPResponse request, CancellationToken cancellationToken = default)
{ {
try try
{ {
var requestUri = "http/sales_order"; var requestUri = "http/sales_order";
var response = await _httpClient.PostAsJsonAsync(requestUri,request,cancellationToken); var options = new JsonSerializerOptions
{
PropertyNamingPolicy = null
};
var json = JsonSerializer.Serialize(request, options);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(requestUri, content, cancellationToken);
if (!response.IsSuccessStatusCode) if (!response.IsSuccessStatusCode)
{ {
var body = await response.Content.ReadAsStringAsync(cancellationToken); var body = await response.Content.ReadAsStringAsync(cancellationToken);
_logger.LogError("Save Orders call failed: {StatusCode} — {Body}", response.StatusCode, body); _logger.LogError("Save Orders call failed: {StatusCode} — {Body}", response.StatusCode, body);
return body; return new Tuple<string, string>(body, string.Empty);
} }
var payload = await response.Content.ReadFromJsonAsync<SapODataResponse<IntegrationMaterialStockHttpResponse>>(cancellationToken: cancellationToken); var responseString = await response.Content.ReadAsStringAsync(cancellationToken);
return string.Empty ; using var document = JsonDocument.Parse(responseString);
var contentJson = document.RootElement
.GetProperty("content")
.GetRawText();
string salesOrder = document.RootElement
.GetProperty("content")
.GetProperty("properties")
.GetProperty("SalesOrder")
.GetString();
return new Tuple<string, string>(contentJson, salesOrder);
} }
catch (Exception) catch (Exception)
{ {

View File

@ -933,6 +933,7 @@ public class OrderService : IOrderService
SqlParameter[] p = SqlParameter[] p =
[ [
SqlHelperExtension.CreateInParam(pName: "@OrderId", pType: SqlDbType.Int, pValue: request.OrderId ), SqlHelperExtension.CreateInParam(pName: "@OrderId", pType: SqlDbType.Int, pValue: request.OrderId ),
SqlHelperExtension.CreateInParam(pName: "@OrderNo", pType: SqlDbType.NVarChar, pValue: request.SapOrderNo ),
SqlHelperExtension.CreateInParam(pName: "@Status", pType: SqlDbType.Int, pValue: request.Status ), SqlHelperExtension.CreateInParam(pName: "@Status", pType: SqlDbType.Int, pValue: request.Status ),
SqlHelperExtension.CreateInParam(pName: "@SentAt", pType: SqlDbType.DateTime, pValue: DateTime.Now ), SqlHelperExtension.CreateInParam(pName: "@SentAt", pType: SqlDbType.DateTime, pValue: DateTime.Now ),
SqlHelperExtension.CreateInParam(pName: "@RetryCount", pType: SqlDbType.Int, pValue: request.RetryCount ), SqlHelperExtension.CreateInParam(pName: "@RetryCount", pType: SqlDbType.Int, pValue: request.RetryCount ),
@ -940,7 +941,7 @@ public class OrderService : IOrderService
SqlHelperExtension.CreateInParam(pName: "@ReturnMessage", pType: SqlDbType.Int, pValue: request.ReturnMessage ), SqlHelperExtension.CreateInParam(pName: "@ReturnMessage", pType: SqlDbType.Int, pValue: request.ReturnMessage ),
]; ];
await tc.ExecuteNonQuerySpAsync("dbo.UpdateSendingSapDetails", parameterValues: p); tc.ExecuteNonQuerySp("dbo.UpdateSendingSapDetails", parameterValues: p);
tc.End(); tc.End();
} }

View File

@ -370,13 +370,13 @@ namespace OnlineSalesAutoCrop.CoreAPI
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); //client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
}) })
.AddStandardResilienceHandler(options => .AddStandardResilienceHandler(options =>
{ {
options.AttemptTimeout.Timeout = TimeSpan.FromSeconds(90); options.AttemptTimeout.Timeout = TimeSpan.FromSeconds(300);
options.CircuitBreaker.SamplingDuration = TimeSpan.FromSeconds(180); // must be >= 2x AttemptTimeout options.CircuitBreaker.SamplingDuration = TimeSpan.FromSeconds(600); // must be >= 2x AttemptTimeout
options.TotalRequestTimeout.Timeout = TimeSpan.FromSeconds(180); options.TotalRequestTimeout.Timeout = TimeSpan.FromSeconds(300);
options.Retry.MaxRetryAttempts = 1; // see note below options.Retry.MaxRetryAttempts = 1; // see note below
}); });