diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationCustomerRequest.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationCustomerRequest.cs index 0af274a..7d48cab 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationCustomerRequest.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationCustomerRequest.cs @@ -158,4 +158,5 @@ public class CustomerByCompanyCodeRequest [Required(ErrorMessage = "Company Code is required")] [StringLength(4, MinimumLength = 1, ErrorMessage = "Company Code must be between 1 and 4 characters")] public string CompanyCode { get; set; } = string.Empty; -} \ No newline at end of file +} + diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationInvoiceRequest.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationInvoiceRequest.cs index 31ef892..21bc87c 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationInvoiceRequest.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/Integrations/IntegrationInvoiceRequest.cs @@ -1,50 +1,87 @@ -using System; + +using DocumentFormat.OpenXml.Office2010.ExcelAc; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations; -public class IntegrationInvoiceRequest +public class IntegrationBillingDocumentRequest { - [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/Billing document number is required.")] + [StringLength(50, ErrorMessage = "Invoice/Billing document number cannot exceed 50 characters.")] + public string InvoiceBillingDocumentNumber { get; set; } = string.Empty; - [Required(ErrorMessage = "Invoice date is required.")] - public DateTime InvoiceDate { get; set; } + [Required(ErrorMessage = "Billing date is required.")] + [DataType(DataType.Date)] + public DateTime BillingDate { 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; } + [StringLength(50, ErrorMessage = "Sales order reference number cannot exceed 50 characters.")] + public string SalesOrderReferenceNumber { get; set; } = string.Empty; [Required(ErrorMessage = "Delivery reference number is required.")] - [StringLength(10, ErrorMessage = "Delivery reference number cannot exceed 10 characters.")] - public string DeliveryRefNo { get; set; } + [StringLength(50, ErrorMessage = "Delivery reference number cannot exceed 50 characters.")] + public string DeliveryReferenceNumber { get; set; } = string.Empty; - [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 IList Items { get; set; } = new List(); } -public class IntegrationInvoiceItemRequest +public class IntegrationBillingDocumentItemRequest { - [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 = "Item code is required.")] + [StringLength(100, ErrorMessage = "Item code cannot exceed 100 characters.")] + public string ItemCode { get; set; } = string.Empty; [Required(ErrorMessage = "Quantity is required.")] - [Range(typeof(decimal), "0.01", "999999999999.99", - ErrorMessage = "Quantity must be greater than 0.")] + [Range(0.000001, double.MaxValue, ErrorMessage = "Quantity must be greater than zero.")] 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; } + [Required(ErrorMessage = "Unit of Measure is required.")] + [StringLength(20, ErrorMessage = "Unit of Measure cannot exceed 20 characters.")] + public string UnitOfMeasure { get; set; } = string.Empty; + + [Required(ErrorMessage = "Billing amount is required.")] + [Range(0.01, double.MaxValue, ErrorMessage = "Billing amount must be greater than zero.")] + [DataType(DataType.Currency)] + public decimal BillingAmount { get; set; } } + + +public class IntegrationDeliveryDocumentRequest +{ + [Required(ErrorMessage = "Delivery Document number is required.")] + [StringLength(50, ErrorMessage = "Delivery Document number cannot exceed 50 characters.")] + public string DeliveryDocumentNo{ get; set; } = string.Empty; + + [Required(ErrorMessage = "Delivery date is required.")] + [DataType(DataType.Date)] + public DateTime DeliveryDate { get; set; } + + [Required(ErrorMessage = "Sales order reference number is required.")] + [StringLength(50, ErrorMessage = "Sales order reference number cannot exceed 50 characters.")] + public string SalesOrderReferenceNumber { get; set; } = string.Empty; + + [Required(ErrorMessage = "Delivery Status is required.")] + [StringLength(5, ErrorMessage = "Delivery Status cannot exceed 5 characters.")] + public string DeliveryStatus { get; set; } = string.Empty; + + public IList Items { get; set; } = new List(); +} + + +public class IntegrationDeliveryDocumentItemRequest +{ + [Required(ErrorMessage = "Item code is required.")] + [StringLength(100, ErrorMessage = "Item code cannot exceed 100 characters.")] + public string ItemCode { get; set; } = string.Empty; + + [Required(ErrorMessage = "Quantity is required.")] + [Range(0.000001, double.MaxValue, ErrorMessage = "Quantity must be greater than zero.")] + public decimal Quantity { get; set; } + + [Required(ErrorMessage = "Unit of Measure is required.")] + [StringLength(20, ErrorMessage = "Unit of Measure cannot exceed 20 characters.")] + public string UnitOfMeasure { get; set; } = string.Empty; +} \ No newline at end of file diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationInvoiceResponse.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationInvoiceResponse.cs index c1b9b75..18efeaf 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationInvoiceResponse.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/Integrations/IntegrationInvoiceResponse.cs @@ -1,13 +1,18 @@ using System; +using System.ComponentModel.DataAnnotations; namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations; -public class IntegrationInvoiceReqResponse : ResponseBase +public class IntegrationBillingReqResponse : 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; } + public string InvoiceBillingDocumentNumber { get; set; } = string.Empty; + public DateTime BillingDate { get; set; } +} + + +public class IntegrationDeliveryReqResponse : ResponseBase +{ + public string DeliveryDocumentNo{ get; set; } = string.Empty; + public DateTime DeliveryDate { get; set; } } diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Services/Contracts/Integrations/IIntegrationService.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Contracts/Integrations/IIntegrationService.cs index f50d871..e95150e 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI.Services/Contracts/Integrations/IIntegrationService.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Contracts/Integrations/IIntegrationService.cs @@ -33,5 +33,6 @@ public interface IIntegrationService Task GetPaymentTermsByFilterAsync(GetIntegrationPaymentTermRequest request); //Invoices - Task SaveInvoiceAsync(IntegrationInvoiceRequest request); + Task SaveBillingDocumentAsync(IntegrationBillingDocumentRequest request); + Task SaveDeliveryInvoiceDocumentAsync(IntegrationDeliveryDocumentRequest request); } diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/Integrations/IntegrationService.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/Integrations/IntegrationService.cs index 174f563..829c0c5 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/Integrations/IntegrationService.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/Integrations/IntegrationService.cs @@ -5,16 +5,13 @@ using Microsoft.Data.SqlClient; using Microsoft.Extensions.Options; using OnlineSalesAutoCrop.CoreAPI.Models; using OnlineSalesAutoCrop.CoreAPI.Models.Global; -using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems; using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations; using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Systems; using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations; using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations; using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems; using System; -using System.Collections.Generic; using System.Data; -using System.Text; using System.Threading.Tasks; namespace OnlineSalesAutoCrop.CoreAPI.Services.Services.Integrations; @@ -488,10 +485,6 @@ public class IntegrationService : IIntegrationService return response; } - public async Task SaveInvoiceAsync(IntegrationInvoiceRequest request) - { - throw new NotImplementedException(); - } #region Customer Private Functions @@ -1461,6 +1454,150 @@ public class IntegrationService : IIntegrationService return returnValue; } + #endregion + + #region Billing and Delivery Endpoints + + public async Task SaveBillingDocumentAsync(IntegrationBillingDocumentRequest request) + { + IntegrationBillingReqResponse response = new(); + try + { + using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true); + try + { + CreateBillingDocument(tc, request); + response.InvoiceBillingDocumentNumber = request.InvoiceBillingDocumentNumber; + response.BillingDate = request.BillingDate; + tc.End(); + } + catch (Exception ie) + { + tc?.HandleError(); + + throw DBCustomError.GenerateCustomError(ie); + } + } + catch (Exception ex) + { + throw; + } + + return response; + } + + public async Task SaveDeliveryInvoiceDocumentAsync(IntegrationDeliveryDocumentRequest request) + { + IntegrationDeliveryReqResponse response = new(); + try + { + using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true); + try + { + CreateDeliveryInovoiceDocument(tc, request); + response.DeliveryDocumentNo = request.DeliveryDocumentNo; + response.DeliveryDate = request.DeliveryDate; + tc.End(); + } + catch (Exception ie) + { + tc?.HandleError(); + + throw DBCustomError.GenerateCustomError(ie); + } + } + catch (Exception ex) + { + throw; + } + + return response; + } + + + private bool CreateBillingDocument(TransactionContext tc, IntegrationBillingDocumentRequest request) + { + bool returnValue = false; + + try + { + DataTable itemTable = new DataTable(); + itemTable.Columns.Add("MaterialCode", typeof(string)); + itemTable.Columns.Add("Quantity", typeof(decimal)); + itemTable.Columns.Add("UnitOfMeasure", typeof(string)); + itemTable.Columns.Add("BillingAmount", typeof(decimal)); + + foreach (var item in request.Items) + { + DataRow dr = itemTable.NewRow(); + dr["MaterialCode"] = item.ItemCode; + dr["Quantity"] = item.Quantity; + dr["UnitOfMeasure"] = item.UnitOfMeasure; + dr["BillingAmount"] = item.BillingAmount; + itemTable.Rows.Add(dr); + } + + SqlParameter[] p = + [ + SqlHelperExtension.CreateInParam("@BillingNumber", SqlDbType.NVarChar, request.InvoiceBillingDocumentNumber), + SqlHelperExtension.CreateInParam("@SalesOrderNo", SqlDbType.NVarChar, request.SalesOrderReferenceNumber), + SqlHelperExtension.CreateInParam("@BillingDate", SqlDbType.DateTime, request.BillingDate), + SqlHelperExtension.CreateInParam("@DeliveryNumber", SqlDbType.NVarChar, request.DeliveryReferenceNumber), + SqlHelperExtension.CreateInParam("@BillingItems", SqlDbType.Structured, itemTable) + ]; + + _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertBillingDocument", parameterValues: p); + + returnValue = true; + } + catch (Exception) + { + throw; + } + + return returnValue; + } + + private bool CreateDeliveryInovoiceDocument(TransactionContext tc, IntegrationDeliveryDocumentRequest request) + { + bool returnValue = false; + + try + { + DataTable itemTable = new DataTable(); + itemTable.Columns.Add("MaterialCode", typeof(string)); + itemTable.Columns.Add("Quantity", typeof(decimal)); + itemTable.Columns.Add("UnitOfMeasure", typeof(string)); + + foreach (var item in request.Items) + { + DataRow dr = itemTable.NewRow(); + dr["MaterialCode"] = item.ItemCode; + dr["Quantity"] = item.Quantity; + dr["UnitOfMeasure"] = item.UnitOfMeasure; + itemTable.Rows.Add(dr); + } + + SqlParameter[] p = + [ + SqlHelperExtension.CreateInParam("@DeliveryDocumentNo", SqlDbType.NVarChar, request.DeliveryDocumentNo), + SqlHelperExtension.CreateInParam("@SalesOrderReferenceNumber", SqlDbType.NVarChar, request.SalesOrderReferenceNumber ), + SqlHelperExtension.CreateInParam("@DeliveryDate", SqlDbType.DateTime, request.DeliveryDate), + SqlHelperExtension.CreateInParam("@DeliveryStatus", SqlDbType.NVarChar, request.DeliveryStatus), + SqlHelperExtension.CreateInParam("@InvoiceItems", SqlDbType.Structured, itemTable) + ]; + + _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertPrimarySalesInvoice", parameterValues: p); + + returnValue = true; + } + catch (Exception) + { + throw; + } + + return returnValue; + } #endregion } diff --git a/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Integretion/IntegrationController.cs b/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Integretion/IntegrationController.cs index c026c16..efa56d2 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Integretion/IntegrationController.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Integretion/IntegrationController.cs @@ -284,31 +284,64 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers } /// - /// Insert Invoices for SAP + /// Insert Deliveries for SAP /// /// /// /// /// if created return 201 or if updated return 200 true - [HttpPost("Invoices")] + [HttpPost("Deliveries")] [IgnoreAntiforgeryToken] - [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IntegrationInvoiceReqResponse))] - [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(IntegrationInvoiceReqResponse))] - public async Task SaveInvoices(IntegrationInvoiceRequest request) + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IntegrationDeliveryReqResponse))] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(IntegrationDeliveryReqResponse))] + public async Task SaveDeliveries(IntegrationDeliveryDocumentRequest request) { - IntegrationInvoiceReqResponse response = new IntegrationInvoiceReqResponse(); + IntegrationDeliveryReqResponse response = new IntegrationDeliveryReqResponse(); try { - response = await _integrationService.SaveInvoiceAsync(request); - response.ReturnMessage.Add($"Successfully Save the Invoices for InvoiceNo :{request.InvoiceDocumentNo} " + - $"And InvoiceDate : {request.InvoiceDate} "); + response = await _integrationService.SaveDeliveryInvoiceDocumentAsync(request); + response.ReturnMessage.Add($"Successfully Save the Deliveries for Delivery Documnet No :{request.DeliveryDocumentNo} " + + $"And DeliveryDate : {request.DeliveryDate} "); 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} " ; + string msg = $"Exception Occur in Deliveries for Delivery Documnet No :{request.DeliveryDocumentNo} " + + $"And DeliveryDate : {request.DeliveryDate} " ; + _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); + } + } + + /// + /// Insert Deliveries for SAP + /// + /// + /// + /// + /// if created return 201 or if updated return 200 true + [HttpPost("Billing")] + [IgnoreAntiforgeryToken] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IntegrationBillingReqResponse))] + [ProducesResponseType(StatusCodes.Status201Created, Type = typeof(IntegrationBillingReqResponse))] + public async Task SaveBilling(IntegrationBillingDocumentRequest request) + { + IntegrationBillingReqResponse response = new IntegrationBillingReqResponse(); + try + { + response = await _integrationService.SaveBillingDocumentAsync(request); + response.ReturnMessage.Add($"Successfully Save the Billing for Billing Documnet No :{request.InvoiceBillingDocumentNumber} " + + $"And BillingDate : {request.BillingDate} "); + response.ReturnStatus = StatusCodes.Status201Created; + return StatusCode(StatusCodes.Status201Created, response); + } + catch (Exception ex) + { + string msg = $"Exception Occur in Billing for Billing Documnet No :{request.InvoiceBillingDocumentNumber} " + + $"And BillingDate : {request.BillingDate} "; _logger.LogError(exception: ex, msg); response.ReturnStatus = StatusCodes.Status500InternalServerError; response.ReturnMessage.Add(ex.InnerException != null ? ex.InnerException.Message : ex.Message);