From 43efe235876dadf3b1573906a486bdd43885095b Mon Sep 17 00:00:00 2001 From: dibakor Date: Tue, 30 Jun 2026 18:57:11 +0600 Subject: [PATCH] add salesinvoice api --- .../Integrations/IntegrationInvoiceRequest.cs | 50 +++++++++++++++++++ .../IntegrationMaterialRequest.cs | 10 +++- .../IntegrationInvoiceResponse.cs | 13 +++++ .../IntegrationMaterialResponse.cs | 2 + .../Integrations/IIntegrationService.cs | 3 ++ .../Integrations/IntegrationService.cs | 25 +++++++--- .../IntegretionApi/IntegrationController.cs | 34 +++++++++++++ 7 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationInvoiceRequest.cs create mode 100644 Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationInvoiceResponse.cs diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationInvoiceRequest.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationInvoiceRequest.cs new file mode 100644 index 0000000..31ef892 --- /dev/null +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationInvoiceRequest.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations; + +public class IntegrationInvoiceRequest +{ + [Required(ErrorMessage = "Invoice document number is required.")] + [StringLength(10, ErrorMessage = "Invoice document number cannot exceed 10 characters.")] + public string InvoiceDocumentNo { get; set; } + + [Required(ErrorMessage = "Invoice date is required.")] + public DateTime InvoiceDate { get; set; } + + [Required(ErrorMessage = "Sales order reference number is required.")] + [StringLength(13, ErrorMessage = "Sales order reference number cannot exceed 13 characters.")] + public string SalesOrderRefNo { get; set; } + + [Required(ErrorMessage = "Delivery reference number is required.")] + [StringLength(10, ErrorMessage = "Delivery reference number cannot exceed 10 characters.")] + public string DeliveryRefNo { get; set; } + + [Required(ErrorMessage = "Invoice amount is required.")] + [Range(typeof(decimal), "0.01", "999999999999.99", + ErrorMessage = "Invoice amount must be greater than 0.")] + public decimal InvoiceAmount { get; set; } + + [Required(ErrorMessage = "Invoice items are required.")] + [MinLength(1, ErrorMessage = "At least one invoice item is required.")] + public List Items { get; set; } = new(); +} + + +public class IntegrationInvoiceItemRequest +{ + [Required(ErrorMessage = "Material code is required.")] + [RegularExpression(@".*\S.*", ErrorMessage = "Material code cannot be empty or whitespace.")] + [StringLength(10, ErrorMessage = "Material code cannot exceed 10 characters.")] + public string MaterialCode { get; set; } + + [Required(ErrorMessage = "Quantity is required.")] + [Range(typeof(decimal), "0.01", "999999999999.99", + ErrorMessage = "Quantity must be greater than 0.")] + public decimal Quantity { get; set; } + + [Required(ErrorMessage = "Unit of measurement is required.")] + [StringLength(10, ErrorMessage = "Unit of measurement cannot exceed 10 characters.")] + public string UnitOfMeasurement { get; set; } +} diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationMaterialRequest.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationMaterialRequest.cs index 3df8c51..f186a75 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationMaterialRequest.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationMaterialRequest.cs @@ -18,7 +18,15 @@ public class IntegrationMaterialRequest [Required(ErrorMessage = "Material description is required.")] [StringLength(40, ErrorMessage = "Material description cannot exceed 40 characters.")] - public string MaterialDescription { get; set; } + public string MaterialDescription { get; set; } + + [Required(ErrorMessage = "BrandCode is required.")] + [StringLength(3, ErrorMessage = "BrandCode cannot exceed 3 characters.")] + public string BrandCode { get; set; } + + [Required(ErrorMessage = "BrandName is required.")] + [StringLength(20, ErrorMessage = "BrandName cannot exceed 20 characters.")] + public string BrandName { get; set; } [Required(ErrorMessage = "Material group code is required.")] [StringLength(9, ErrorMessage = "Material group code cannot exceed 9 characters.")] diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationInvoiceResponse.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationInvoiceResponse.cs new file mode 100644 index 0000000..c1b9b75 --- /dev/null +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationInvoiceResponse.cs @@ -0,0 +1,13 @@ +using System; + +namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations; + +public class IntegrationInvoiceReqResponse : ResponseBase +{ + public string SalesOrderRefNo { get; set; } + public string InvoiceDocumnentNo { get; set; } + public DateTime InvoiceDate { get; set; } + public string DeliveryRefNo { get; set; } + public int NumberOfMaterial { get; set; } +} + diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationMaterialResponse.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationMaterialResponse.cs index be08672..34be9aa 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationMaterialResponse.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationMaterialResponse.cs @@ -20,6 +20,8 @@ public class IntegrationMaterialResponse : ResponseBase public string StorageLocationDescription { get; set; } public string SalesOrganization { get; set; } public string SalesOrganizationDescription { get; set; } + public string BrandCode { get; set; } + public string BrandName { get; set; } } public class MaterialIntegrationReqResponse : ResponseBase diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Services/Contracts/Integrations/IIntegrationService.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Contracts/Integrations/IIntegrationService.cs index e865bff..f50d871 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI.Services/Contracts/Integrations/IIntegrationService.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Contracts/Integrations/IIntegrationService.cs @@ -31,4 +31,7 @@ public interface IIntegrationService //Payment Terms Task UpsertPaymentTermsAsync(IntegrationPaymentTermRequest request); Task GetPaymentTermsByFilterAsync(GetIntegrationPaymentTermRequest request); + + //Invoices + Task SaveInvoiceAsync(IntegrationInvoiceRequest request); } diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/Integrations/IntegrationService.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/Integrations/IntegrationService.cs index 4f9607e..d61f6d4 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/Integrations/IntegrationService.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/Integrations/IntegrationService.cs @@ -434,6 +434,12 @@ public class IntegrationService : IIntegrationService return response; } + public async Task SaveInvoiceAsync(IntegrationInvoiceRequest request) + { + throw new NotImplementedException(); + } + + #region Customer Private Functions private async Task GetCustomerByCompanyCodeAsync(TransactionContext tc, CustomerByCompanyCodeRequest request) @@ -863,6 +869,8 @@ public class IntegrationService : IIntegrationService StorageLocationDescription = dr.GetString(13), SalesOrganization = dr.GetString(14), SalesOrganizationDescription = dr.GetString(15), + BrandCode = dr.GetString(16), + BrandName = dr.GetString(17) }; } dr.Close(); @@ -904,8 +912,11 @@ public class IntegrationService : IIntegrationService SqlHelperExtension.CreateInParam("@StorageLocationCode", SqlDbType.NVarChar, request.StorageLocationCode), SqlHelperExtension.CreateInParam("@StorageLocationDescription", SqlDbType.NVarChar, request.StorageLocationDescription), - SqlHelperExtension.CreateInParam("@SalesOrganization", SqlDbType.NVarChar, request.SalesOrganization), - SqlHelperExtension.CreateInParam("@SalesOrganizationDescription", SqlDbType.NVarChar, request.SalesOrganizationDescription) + SqlHelperExtension.CreateInParam("@SalesOrganization", SqlDbType.NVarChar, request.SalesOrganization), + SqlHelperExtension.CreateInParam("@SalesOrganizationDescription", SqlDbType.NVarChar, request.SalesOrganizationDescription), + + SqlHelperExtension.CreateInParam("@BrandCode", SqlDbType.NVarChar, request.BrandCode), + SqlHelperExtension.CreateInParam("@BrandName", SqlDbType.NVarChar, request.BrandName) ]; _ = tc.ExecuteNonQuerySp(spName: "dbo.CreateMaterial", parameterValues: p); @@ -948,8 +959,11 @@ public class IntegrationService : IIntegrationService SqlHelperExtension.CreateInParam("@StorageLocationCode", SqlDbType.NVarChar, request.StorageLocationCode), SqlHelperExtension.CreateInParam("@StorageLocationDescription", SqlDbType.NVarChar, request.StorageLocationDescription), - SqlHelperExtension.CreateInParam("@SalesOrganization", SqlDbType.NVarChar, request.SalesOrganization), - SqlHelperExtension.CreateInParam("@SalesOrganizationDescription", SqlDbType.NVarChar, request.SalesOrganizationDescription) + SqlHelperExtension.CreateInParam("@SalesOrganization", SqlDbType.NVarChar, request.SalesOrganization), + SqlHelperExtension.CreateInParam("@SalesOrganizationDescription", SqlDbType.NVarChar, request.SalesOrganizationDescription), + + SqlHelperExtension.CreateInParam("@BrandCode", SqlDbType.NVarChar, request.BrandCode), + SqlHelperExtension.CreateInParam("@BrandName", SqlDbType.NVarChar, request.BrandName) ]; _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateMaterial", parameterValues: p); @@ -1213,7 +1227,7 @@ public class IntegrationService : IIntegrationService #endregion - #region Credit Code Private Functions + #region Payment Terms Private Functions private async Task GetPaymentTermByFilterAsync(TransactionContext tc, GetIntegrationPaymentTermRequest request) @@ -1307,6 +1321,5 @@ public class IntegrationService : IIntegrationService return returnValue; } - #endregion } diff --git a/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/IntegretionApi/IntegrationController.cs b/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/IntegretionApi/IntegrationController.cs index 1d3cd68..1e03b03 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/IntegretionApi/IntegrationController.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/IntegretionApi/IntegrationController.cs @@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; +using OnlineSalesAutoCrop.CoreAPI; using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations; using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations; using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations; @@ -281,5 +282,38 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers.IntegretionApi return StatusCode(StatusCodes.Status500InternalServerError, response); } } + + /// + /// Insert Invoices for SAP + /// + /// + /// + /// + /// if created return 201 or if updated return 200 true + [HttpPost("Invoices")] + [IgnoreAntiforgeryToken] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IntegrationInvoiceReqResponse))] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(IntegrationInvoiceReqResponse))] + public async Task SaveInvoices(IntegrationInvoiceRequest request) + { + IntegrationInvoiceReqResponse response = new IntegrationInvoiceReqResponse(); + try + { + response = await _integrationService.SaveInvoiceAsync(request); + response.ReturnMessage.Add($"Successfully Save the Invoices for InvoiceNo :{request.InvoiceDocumentNo} " + + $"And InvoiceDate : {request.InvoiceDate} "); + response.ReturnStatus = StatusCodes.Status201Created; + return StatusCode(StatusCodes.Status201Created, response); + } + catch (Exception ex) + { + string msg = $"Exception Occur in Invoices for InvoiceNo :{request.InvoiceDocumentNo} " + + $"And InvoiceDate : {request.InvoiceDate} " ; + _logger.LogError(exception: ex, msg); + response.ReturnStatus = StatusCodes.Status500InternalServerError; + response.ReturnMessage.Add(ex.InnerException != null ? ex.InnerException.Message : ex.Message); + return StatusCode(StatusCodes.Status500InternalServerError, response); + } + } } } \ No newline at end of file