change material price endpoint request

This commit is contained in:
dibakor 2026-08-10 17:35:41 +06:00
parent cf1a8e74a6
commit 45f95b3184
12 changed files with 301 additions and 35 deletions

View File

@ -55,6 +55,7 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models.Global
public bool JwtValidateAudience { get; set; }
public int RefreshTokenDuration { get; set; }
public int AccessTokenDuration { get; set; }
public int IsLogRequest { get; set; } = 0;
/// <summary>
/// Folder management

View File

@ -26,7 +26,7 @@ public class IntegrationMaterialFreeGoodsRequest
[StringLength(2, MinimumLength = 1, ErrorMessage = "CustomerPriceGroup must be between 1 and 2 characters.")]
public string? CustomerPriceGroup { get; set; }
[StringLength(10, MinimumLength = 1, ErrorMessage = "MaterialCode must be between 1 and 10 characters.")]
[StringLength(18, MinimumLength = 1, ErrorMessage = "MaterialCode must be between 1 and 18 characters.")]
public string? MaterialCode { get; set; }
public IList<IntegrationMaterialFreeGoodItemRequest> Slabs { get; set; }
}

View File

@ -27,7 +27,7 @@ public class IntegrationMaterialPriceRequest
[StringLength(10, ErrorMessage = "Customer Group Code cannot exceed 10 characters.")]
public string? CustomerGroupCode { get; set; }
[StringLength(10, ErrorMessage = "Material Code cannot exceed 10 characters.")]
[StringLength(18, ErrorMessage = "Material Code cannot exceed 18 characters.")]
public string? MaterialCode { get; set; }
[Required(ErrorMessage = "Condition Type is required.")]
@ -43,12 +43,28 @@ public class IntegrationMaterialPriceRequest
[StringLength(3, ErrorMessage = "Unit Of Measure cannot exceed 3 characters.")]
public string? UnitOfMeasure { get; set; }
public decimal? ScaleValue { get; set; }
[Required(ErrorMessage = "Valid From is Required")]
public DateTime ValidFrom { get; set; }
[Required(ErrorMessage = "Valid To is Required")]
public DateTime ValidTo { get; set; }
[StringLength(1, ErrorMessage = "Status cannot exceed 1 character.")]
[RegularExpression(@"^$|^X$", ErrorMessage = "Status must be blank (Active) or 'X' (Inactive).")]
public string Status { get; set; }
[Required(ErrorMessage = "Condition Value is required.")]
[Range(typeof(decimal), "0", "999999999999999999.99", ErrorMessage = "Condition Value must be greater than or equal to 0.")]
public decimal ConditionValue { get; set; }
public IList<IntegrationMaterialPriceItemRequest> Slabs { get; set; }
}
public class IntegrationMaterialPriceItemRequest
{
[Range(typeof(decimal), "0", "999999999999999999.99", ErrorMessage = "Scale Value must be greater than or equal to 0.")]
public decimal? ScaleValue { get; set; }
[Required(ErrorMessage ="Valid From is Required")]
@ -73,7 +89,7 @@ public class GetMaterialPriceByCodeRequest
public string SalesOrg { get; set; }
[Required(ErrorMessage = "Material Code is required.")]
[StringLength(10, ErrorMessage = "Material Code cannot exceed 10 characters.")]
[StringLength(18, ErrorMessage = "Material Code cannot exceed 18 characters.")]
public string MaterialCode { get; set; }
[Required(ErrorMessage = "Condition Type is required.")]

View File

@ -13,7 +13,7 @@ public class IntegrationMaterialRequest
public string MaterialTypeDescription { get; set; }
[Required(ErrorMessage = "Material code is required.")]
[StringLength(10, ErrorMessage = "Material code cannot exceed 10 characters.")]
[StringLength(18, ErrorMessage = "Material code cannot exceed 18 characters.")]
public string MaterialCode { get; set; }
[Required(ErrorMessage = "Material description is required.")]

View File

@ -135,7 +135,7 @@ public class IntegrationService : IIntegrationService
try
{
IntegrationEmployeeResponse employee = await GetEmployeeBySalesOrgAsync(tc,
new EmployeeIntegrationByComapanyRequest() { EmployeeVendorCode = request.EmployeeVendorCode, CompanyCode = request.CompanyCode });
new EmployeeIntegrationByComapanyRequest() { EmployeeVendorCode = request.EmployeeVendorCode, CompanyCode = request.SalesOrg });
if (employee != null && employee.EmployeeId > 0)
@ -1305,6 +1305,8 @@ public class IntegrationService : IIntegrationService
bool response = false;
try
{
if(request.Slabs!= null && request.Slabs.Count > 0)
{
foreach (var item in request.Slabs)
{
@ -1329,6 +1331,32 @@ public class IntegrationService : IIntegrationService
_ = tc.ExecuteNonQuerySp(spName: "dbo.InsertIntegrationMaterialPrice", parameterValues: p);
}
}
else
{
SqlParameter[] p =
[
SqlHelperExtension.CreateInParam("@SalesOrg", SqlDbType.NVarChar, request.SalesOrg),
SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
SqlHelperExtension.CreateInParam("@CustomerNumber", SqlDbType.NVarChar, request.CustomerNumber),
SqlHelperExtension.CreateInParam("@CustomerGroupCode", SqlDbType.NVarChar, request.CustomerGroupCode),
SqlHelperExtension.CreateInParam("@MaterialCode", SqlDbType.NVarChar, request.MaterialCode),
SqlHelperExtension.CreateInParam("@ConditionType", SqlDbType.NVarChar, request.ConditionType),
SqlHelperExtension.CreateInParam("@CalculationType", SqlDbType.NVarChar, request.CalculationType),
SqlHelperExtension.CreateInParam("@PricingUnit", SqlDbType.NVarChar, request.PricingUnit),
SqlHelperExtension.CreateInParam("@UnitOfMeasure", SqlDbType.NVarChar, request.UnitOfMeasure),
SqlHelperExtension.CreateInParam("@ScaleValue", SqlDbType.NVarChar, Convert.ToDecimal(request.PricingUnit ?? "0")),
SqlHelperExtension.CreateInParam("@ValidFrom", SqlDbType.DateTime, request.ValidFrom),
SqlHelperExtension.CreateInParam("@ValidTo", SqlDbType.DateTime, request.ValidTo),
SqlHelperExtension.CreateInParam("@Status", SqlDbType.NVarChar, request.Status),
SqlHelperExtension.CreateInParam("@ConditionValue", SqlDbType.Decimal, request.ConditionValue) ,
SqlHelperExtension.CreateInParam("@ConditionRecNo", SqlDbType.Int, request.ConditionRecNo) ,
];
_ = tc.ExecuteNonQuerySp(spName: "dbo.InsertIntegrationMaterialPrice", parameterValues: p);
}
response = true;
}
catch (Exception)
@ -1948,12 +1976,6 @@ public class IntegrationService : IIntegrationService
break;
}
if (request.Slabs == null || !request.Slabs.Any())
{
errors.Add("At least one slab is required.");
return errors;
}
return errors;
}

View File

@ -0,0 +1,16 @@
{
"timestamp": "2026-08-10T06:07:01.1034033+00:00",
"request": {
"method": "GET",
"scheme": "http",
"host": "localhost:4204",
"path": "/",
"query": "",
"ipAddress": "127.0.0.1",
"body": ""
},
"response": {
"statusCode": 200,
"body": "\u003Cb\u003EEase Taskforce Api is Running\u003C/b\u003E"
}
}

View File

@ -0,0 +1,16 @@
{
"timestamp": "2026-08-10T06:07:22.2388472+00:00",
"request": {
"method": "POST",
"scheme": "http",
"host": "localhost:4204",
"path": "/api/v1/IntegrationAuth/login",
"query": "",
"ipAddress": "::1",
"body": "{\r\n \u0022loginId\u0022 : \u0022SAPUser\u0022,\r\n \u0022password\u0022 : \u0022SapUser@#1213@%!\u0022\r\n}"
},
"response": {
"statusCode": 200,
"body": "{\u0022loginId\u0022:\u0022SAPUser\u0022,\u0022accessToken\u0022:\u0022eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJMb2dpbklkIjoiU0FQVXNlciIsIkVtYWlsIjoiIiwiQXV0aEtleSI6IiIsIkhhc2hLZXkiOiJmOWE5ODgxNC1mYjgxLTRkYjctYjNkZi04OGM5MzVjNjgyYTYiLCJuYmYiOjE3ODYzNDIwNDIsImV4cCI6MTc4NjM4NTI0MiwiaWF0IjoxNzg2MzQyMDQyfQ.VhHYVb58-iXAe6uJfK-JddsssTO3pGzoMj0zeSrOjv290uWj6X7VbquntXHmKUBcrMabRBtjwPT7YdQZn0njwQ\u0022,\u0022refreshToken\u0022:\u0022VsChwEpKHMb7eFC2ZVK/o8uRbZ/0ochGgsAFR1lKpH4=\u0022,\u0022loginStatus\u0022:0,\u0022accessTokenExpiry\u0022:\u00222026-08-10T12:09:22.1883677\u002B06:00\u0022,\u0022returnStatus\u0022:200,\u0022returnMessage\u0022:[]}"
}
}

View File

@ -0,0 +1,24 @@
{
"timestamp": "2026-08-10T06:22:54.3731022+00:00",
"request": {
"method": "POST",
"scheme": "http",
"host": "localhost:4204",
"path": "/api/v1/IntegrationAuth/login",
"query": "",
"ipAddress": "::1",
"body": "{\r\n \u0022loginId\u0022 : \u0022SAPUser\u0022,\r\n \u0022password\u0022 : \u0022SapUser@#1213@%!\u0022\r\n}"
},
"response": {
"statusCode": 200,
"body": {
"loginId": "SAPUser",
"accessToken": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJMb2dpbklkIjoiU0FQVXNlciIsIkVtYWlsIjoiIiwiQXV0aEtleSI6IiIsIkhhc2hLZXkiOiJmYjE5OWZlMi0zMGVlLTQ2YjItOWYzNC1lNjI4ZTY5NTkzN2QiLCJuYmYiOjE3ODYzNDI5NzQsImV4cCI6MTc4NjM4NjE3MywiaWF0IjoxNzg2MzQyOTc0fQ.NQH786tBsAdB-oToocQzbV4t_esZwR3t2gszdZCFnD5xanE4So-PnXmOtZKjfIIgP6AEcIek5_FqMz8fVwWkXg",
"refreshToken": "jolD3tih1hLRiGNi/4WvLJDCTyNUJKuRJHEWoTDk7X4=",
"loginStatus": 0,
"accessTokenExpiry": "2026-08-10T12:24:54.3150635\u002B06:00",
"returnStatus": 200,
"returnMessage": []
}
}
}

View File

@ -0,0 +1,27 @@
{
"timestamp": "2026-08-10T06:23:57.8920082+00:00",
"request": {
"method": "POST",
"scheme": "http",
"host": "localhost:4204",
"path": "/api/v1/IntegrationAuth/login",
"query": "",
"ipAddress": "::1",
"body": {
"loginId": "SAPUser",
"password": "SapUser@#1213@%!"
}
},
"response": {
"statusCode": 200,
"body": {
"loginId": "SAPUser",
"accessToken": "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJMb2dpbklkIjoiU0FQVXNlciIsIkVtYWlsIjoiIiwiQXV0aEtleSI6IiIsIkhhc2hLZXkiOiJhYTQ0NjAwZC0wM2VmLTQxN2QtOTM0Mi1lNmVhNDZhYWFkMzEiLCJuYmYiOjE3ODYzNDMwMzcsImV4cCI6MTc4NjM4NjIzNywiaWF0IjoxNzg2MzQzMDM3fQ.ML8boRFCmpgRiXOOjBLPihcJ4lTfqQnRJru9z66uc2Ovp2U3sbs4VHGTaVA0dOXW809humaicRBlspWptOKCfg",
"refreshToken": "nZfBF\u002BkjKgl9ObZXLHvaNb69d07e3jOubNRXdA3D8BQ=",
"loginStatus": 0,
"accessTokenExpiry": "2026-08-10T12:25:57.7816164\u002B06:00",
"returnStatus": 200,
"returnMessage": []
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace OnlineSalesAutoCrop.CoreAPI.Converter;
public class NullableDecimalConverter : JsonConverter<decimal?>
{
public override decimal? Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.Null)
return null;
if (reader.TokenType == JsonTokenType.Number)
{
var value = reader.GetInt32();
return value == 0 ? null : value;
}
if (reader.TokenType == JsonTokenType.String)
{
var value = reader.GetString();
if (string.IsNullOrWhiteSpace(value) || value == "0")
return null;
if (int.TryParse(value, out var result))
return result;
throw new JsonException($"Invalid ScaleValue: {value}");
}
throw new JsonException("ScaleValue must be a number, string, or null.");
}
public override void Write(
Utf8JsonWriter writer,
decimal? value,
JsonSerializerOptions options)
{
if (value is null)
writer.WriteNullValue();
else
writer.WriteNumberValue(value.Value);
}
}

View File

@ -36,6 +36,7 @@ using System.Net;
using System.Net.Http.Headers;
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.RateLimiting;
using System.Threading.Tasks;
@ -91,6 +92,9 @@ namespace OnlineSalesAutoCrop.CoreAPI
{
options.JsonSerializerOptions.Converters.Add(
new CoreAPI.Converter.EmptyStringToNullConverter());
options.JsonSerializerOptions.Converters.Add(
new CoreAPI.Converter.NullableDecimalConverter());
});
services.Configure<ApiBehaviorOptions>(options =>
@ -517,6 +521,95 @@ namespace OnlineSalesAutoCrop.CoreAPI
#endregion
#region Log Request and Response
if (_appSettings.IsLogRequest > 0)
{
app.Use(async (context, next) =>
{
var logDirectory = Path.Combine(
env.ContentRootPath,
"ApiLogs"
);
context.Request.EnableBuffering();
string requestBody = "";
if (context.Request.ContentLength > 0)
{
using var reader = new StreamReader(
context.Request.Body,
Encoding.UTF8,
leaveOpen: true);
requestBody = await reader.ReadToEndAsync();
context.Request.Body.Position = 0;
}
var originalResponseBody = context.Response.Body;
await using var responseBody = new MemoryStream();
context.Response.Body = responseBody;
try
{
await next();
responseBody.Position = 0;
var responseText =
await new StreamReader(responseBody).ReadToEndAsync();
responseBody.Position = 0;
await responseBody.CopyToAsync(originalResponseBody);
var log = new
{
timestamp = DateTimeOffset.UtcNow,
request = new
{
method = context.Request.Method,
scheme = context.Request.Scheme,
host = context.Request.Host.ToString(),
path = context.Request.Path.ToString(),
query = context.Request.QueryString.ToString(),
ipAddress = context.Connection.RemoteIpAddress?.ToString(),
body = JsonDocument.Parse(requestBody).RootElement
},
response = new
{
statusCode = context.Response.StatusCode,
body = JsonDocument.Parse(responseText).RootElement
}
};
var json = System.Text.Json.JsonSerializer.Serialize(
log,
new JsonSerializerOptions
{
WriteIndented = true
});
var fileName =
$"{DateTime.Now:yyyy-MM-dd_HH-mm-ss-fff}.json";
var filePath = Path.Combine(logDirectory, fileName);
await File.WriteAllTextAsync(filePath, json);
}
finally
{
context.Response.Body = originalResponseBody;
}
});
}
#endregion
#region Controllers and SignalR
app.UseEndpoints(endpoints =>

View File

@ -86,6 +86,7 @@
"WaSenderId": "+8801326755660",
"RefreshTokenDuration": "2",
"AccessTokenDuration": "1",
"IsLogRequest": 0,
"AutoCropSAPApi": {
"BaseUrl": "https://accl-test-pad-l06vsvh7.it-cpi004-rt.cfapps.ap11.hana.ondemand.com/",
"UserName": "sb-1635ae0e-9941-4998-962f-e23f592d29b5!b45657|it-rt-accl-test-pad-l06vsvh7!b68",