diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Enums.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Enums.cs index 515a230..a1732c0 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Enums.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Enums.cs @@ -725,8 +725,8 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models AppUser =2, } - public enum UserRoleTypeEnum - { + public enum UserRoleTypeEnum : short + { [Description("Order Collector")] OrderCollector = 1, [Description("OrderValidator")] @@ -737,4 +737,21 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models SapUser = 4 , } + public enum OrderStatusEnum : short + { + [Description("Draft")] + Draft = 1, + [Description("Order Sent to Validator")] + InOrderValidation = 2, + [Description("Cancelled by Validator")] + CancelledByValidator = 3, + [Description("Order Sent to Approver")] + InOrderApproval = 4, + [Description("Cancelled by Approver")] + CancelledByApprover = 5, + [Description("Approved")] + Approved = 6, + [Description("Sent To SAP")] + SentToSAP = 7 + } } \ No newline at end of file diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/MobileApp/OrderRequest.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/MobileApp/OrderRequest.cs new file mode 100644 index 0000000..158b2a2 --- /dev/null +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Requests/MobileApp/OrderRequest.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; + +namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp; + +public class SaveOrderRequest +{ + public SaveOrderRequest() + { + Items = new List(); + } + + public int? OrderId { get; set; } + public string? OrderNo { get; set; } + public DateTime? OrderDate { get; set; } + public DateTime? ExpectedDeliveryDate { get; set; } + public string UUID { get; set; } + public string SalesOrgCode { get; set; } + public string CustomerCode { get; set; } + public string CustomerName { get; set; } + public int? EmployeeId { get; set; } + public string EmployeeCode { get; set; } + public string? ReferenceTxtNo { get; set; } + public string PaymentTermCode { get; set; } + public string DiscountCode { get; set; } + public string FocCode { get; set; } + public decimal DiscountValue { get; set; } + public decimal GrossValue { get; set; } + public decimal NetValue { get; set; } + public OrderStatusEnum OrderStatus { get; set; } + public IList Items { get; set; } +} + +public class SaveOrderItemRequest +{ + public string MaterialCode { get; set; } + public string MaterialName { get; set; } + public decimal UnitPrice { get; set; } + public string SalesUnit { get; set; } + public decimal OrderQuantity { get; set; } + public decimal ValidatedQuantity { get; set; } + public decimal ApprovedQuantity { get; set; } + public decimal DiscountPercentage { get; set; } + public decimal DiscountAmount { get; set; } + public bool IsFocItem { get; set; } + public decimal LineTotalValue { get; set; } +} + +public class SaveOrderPromotionRequest +{ + public int OrderId { get; set; } + public int MaterialId { get; set; } + public string PromotionCode { get; set; } + public decimal DiscountPercentage { get; set; } + public decimal DiscountValue { get; set; } + public decimal ForQuantity { get; set; } + public decimal OrderFocQty { get; set; } + public decimal ValidatedFocQty { get; set; } + public decimal ApprovedFocQty { get; set; } + public int PromotionType { get; set; } +} \ No newline at end of file diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/MobileApp/OrderResponse.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/MobileApp/OrderResponse.cs new file mode 100644 index 0000000..8208d23 --- /dev/null +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Models/Responses/MobileApp/OrderResponse.cs @@ -0,0 +1,76 @@ +using System; +using System.Collections.Generic; + +namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp; + +public class SaveOrderResponse +{ + public int OrderId { get; set; } + public string OrderNo { get; set; } + public string UUID { get; set; } + public DateTime OrderDate { get; set; } + public bool IsNewOrder { get; set; } +} + +public class GetOrderByUUIDResponse +{ + public int OrderId { get; set; } + public string OrderNo { get; set; } + public DateTime OrderDate { get; set; } + public DateTime? ExpectedSalesDate { get; set; } + public Guid UUID { get; set; } + public string SalesOrgCode { get; set; } + public int CustomerId { get; set; } + public string CustomerCode { get; set; } + public string CustomerName { get; set; } + public int EmployeeId { get; set; } + public string EmployeeCode { get; set; } + public string EmployeeName { get; set; } + public string PaymentTermCode { get; set; } + public string? ReferenceTxtNo { get; set; } + public decimal GrossValue { get; set; } + public decimal DiscountValue { get; set; } + public decimal FOCValue { get; set; } + public decimal NetValue { get; set; } + public string OrderStatus { get; set; } + public string SAPReferenceOrderNo { get; set; } + + public List Items { get; set; } = new(); + public List Promotions { get; set; } = new(); +} + +public class GetOrderItemResponse +{ + public int ItemId { get; set; } + public int OrderID { get; set; } + public int MaterialId { get; set; } + public string MaterialCode { get; set; } + public string MaterialName { get; set; } + public decimal UnitPrice { get; set; } + public string SalesUnit { get; set; } + public decimal OrderQuantity { get; set; } + public decimal ValidatedQuantity { get; set; } + public decimal ApprovedQuantity { get; set; } + public decimal DiscountPercentage { get; set; } + public decimal DiscountValue { get; set; } + public bool IsFOCItem { get; set; } + public decimal OrderFocQuantity { get; set; } + public decimal ValidatedFocQuantity { get; set; } + public decimal ApprovedFocQuantity { get; set; } + public decimal LineTotalValue { get; set; } +} + +public class GetOrderPromotionResponse +{ + public int ItemId { get; set; } + public int OrderID { get; set; } + public int MaterialId { get; set; } + public string PromotionCode { get; set; } + public decimal DiscountPercentage { get; set; } + public decimal DiscountValue { get; set; } + public decimal ForQuantity { get; set; } + public decimal OrderFocQuantity { get; set; } + public decimal ValidatedFocQuantity { get; set; } + public decimal ApprovedFocQuantity { get; set; } + public int PromotionType { get; set; } +} \ No newline at end of file diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Services/Contracts/MobileApp/IOrderService.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Contracts/MobileApp/IOrderService.cs new file mode 100644 index 0000000..beb0c58 --- /dev/null +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Contracts/MobileApp/IOrderService.cs @@ -0,0 +1,11 @@ + +using OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp; +using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp; +using System.Threading.Tasks; + +namespace OnlineSalesAutoCrop.CoreAPI.Services.Contracts.MobileApp; + +public interface IOrderService +{ + Task SaveOrderAsync(SaveOrderRequest request); +} diff --git a/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/MobileApp/OrderService.cs b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/MobileApp/OrderService.cs new file mode 100644 index 0000000..eab4ca1 --- /dev/null +++ b/Api/OnlineSalesAutoCrop.CoreAPI.Services/Services/MobileApp/OrderService.cs @@ -0,0 +1,167 @@ +using Ease.NetCore.DataAccess; +using Ease.NetCore.DataAccess.SQL; +using Microsoft.Data.SqlClient; +using Microsoft.Extensions.Options; +using OnlineSalesAutoCrop.CoreAPI.Models.Global; +using OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp; +using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp; +using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.MobileApp; +using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems; +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Threading.Tasks; + +namespace OnlineSalesAutoCrop.CoreAPI.Services.Services.MobileApp; + +public class OrderService : IOrderService +{ + private readonly AppSettings _settings; + private readonly IUserService _userService; + private readonly IMobileMasterDataService _masterService; + + public OrderService(IOptions options, IUserService userService, IMobileMasterDataService masterService) + { + _settings = options.Value; + _userService = userService; + _masterService = masterService; + } + + public async Task SaveOrderAsync(SaveOrderRequest request) + { + SaveOrderResponse response = new(); + try + { + using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode,true); + + + GetOrderByUUIDResponse order= await GetOrderByUUIDAsync(tc, request.UUID); + + + tc.End(); + + } + catch(Exception) + { + throw; + } + + return new SaveOrderResponse() + { + OrderId = 12345, + OrderDate = DateTime.Now, + OrderNo = "Ord-000001-" + DateTime.Now.ToString("HH-mm-ss"), + UUID = request.UUID, + IsNewOrder =true + }; + } + + private async Task GetOrderByUUIDAsync(TransactionContext tc, string uuid) + { + GetOrderByUUIDResponse response = null; + + try + { + SqlParameter[] p = + [ + SqlHelperExtension.CreateInParam(pName: "@UUID", pType: SqlDbType.UniqueIdentifier, pValue: uuid) + ]; + + using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetOrderDetailsByUUID", parameterValues: p)) + { + // Result Set 1: Order Header + if (dr.Read()) + { + response = new GetOrderByUUIDResponse + { + OrderId = dr.GetInt32(0), + OrderNo = dr.GetString(1), + OrderDate = dr.GetDateTime(2), + ExpectedSalesDate = dr.IsDBNull(3) ? null : dr.GetDateTime(3), + UUID = dr.GetGuid(4), + SalesOrgCode = dr.GetString(5), + CustomerId = dr.GetInt32(6), + CustomerCode = dr.GetString(7), + CustomerName = dr.GetString(8), + EmployeeId = dr.GetInt32(9), + EmployeeCode = dr.GetString(10), + EmployeeName = dr.GetString(11), + PaymentTermCode = dr.GetString(12), + ReferenceTxtNo = dr.IsDBNull(13) ? null : dr.GetString(13), + GrossValue = dr.GetDecimal(14), + DiscountValue = dr.GetDecimal(15), + FOCValue = dr.GetDecimal(16), + NetValue = dr.GetDecimal(17), + OrderStatus = dr.GetString(18), + SAPReferenceOrderNo = dr.IsDBNull(19) ? null : dr.GetString(19) + }; + } + + if (response != null && dr.NextResult()) + { + while (dr.Read()) + { + GetOrderItemResponse item = new() + { + ItemId = dr.GetInt32(0), + OrderID = dr.GetInt32(1), + MaterialId = dr.GetInt32(2), + MaterialCode = dr.GetString(3), + MaterialName = dr.GetString(4), + UnitPrice = dr.GetDecimal(5), + SalesUnit = dr.GetString(6), + OrderQuantity = dr.GetDecimal(7), + ValidatedQuantity = dr.GetDecimal(8), + ApprovedQuantity = dr.GetDecimal(9), + DiscountPercentage = dr.GetDecimal(10), + DiscountValue = dr.GetDecimal(11), + IsFOCItem = dr.GetBoolean(12), + OrderFocQuantity = dr.GetDecimal(13), + ValidatedFocQuantity = dr.GetDecimal(14), + ApprovedFocQuantity = dr.GetDecimal(15), + LineTotalValue = dr.GetDecimal(16), + }; + + response.Items.Add(item); + } + } + + // Result Set 3: Promotions (attach to matching item) + if (response != null && dr.NextResult()) + { + while (dr.Read()) + { + GetOrderPromotionResponse promotion = new() + { + ItemId = dr.GetInt32(0), + OrderID = dr.GetInt32(1), + MaterialId = dr.GetInt32(2), + PromotionCode = dr.GetString(3), + DiscountPercentage = dr.GetDecimal(4), + DiscountValue = dr.GetDecimal(5), + ForQuantity = dr.GetDecimal(6), + OrderFocQuantity = dr.GetDecimal(7), + ValidatedFocQuantity = dr.GetDecimal(8), + ApprovedFocQuantity = dr.GetDecimal(9), + PromotionType = dr.GetInt32(10), + }; + + response.Promotions.Add(promotion); + } + } + + dr.Close(); + } + + tc.End(); + } + catch (Exception) + { + throw; + } + + return response; + } + +} diff --git a/Api/OnlineSalesAutoCrop.CoreAPI/Configurations/DI/ServiceCollectionExtensions.cs b/Api/OnlineSalesAutoCrop.CoreAPI/Configurations/DI/ServiceCollectionExtensions.cs index eaeb5ca..dd16f20 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI/Configurations/DI/ServiceCollectionExtensions.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI/Configurations/DI/ServiceCollectionExtensions.cs @@ -34,6 +34,7 @@ namespace OnlineSalesAutoCrop.CoreAPI.Configuration.DI services.AddTransient(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); } } } diff --git a/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Mobile/MobileAuthController.cs b/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Mobile/MobileAuthController.cs index 3f121f9..6b096f4 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Mobile/MobileAuthController.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Mobile/MobileAuthController.cs @@ -8,20 +8,15 @@ using Microsoft.IdentityModel.Tokens; using OnlineSalesAutoCrop.CoreAPI; using OnlineSalesAutoCrop.CoreAPI.Models; using OnlineSalesAutoCrop.CoreAPI.Models.Global; -using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems; -using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Common; using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations; using OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp; using OnlineSalesAutoCrop.CoreAPI.Models.Responses; using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations; using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp; -using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Systems; using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Auth; using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems; using System; -using System.DirectoryServices; using System.IdentityModel.Tokens.Jwt; -using System.Runtime.Versioning; using System.Security.Claims; using System.Text; using System.Threading.Tasks; @@ -44,7 +39,7 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers [ApiVersion("1.0")] [ValidateAntiForgeryToken] [Route("api/mobile/v{version:apiVersion}/auth")] - public class MobileAuthController(IUserService service, IOptions appSettings, IEaseCache cache, ILogger logger, + public class MobileAuthController(IUserService service, IOptions appSettings, IEaseCache cache, ILogger logger, IRefreshTokenService refreshTokenService) : ControllerBase { private readonly ILogger _logger = logger; diff --git a/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Mobile/MobileMasterDataController.cs b/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Mobile/MobileMasterDataController.cs index eb2c859..79f98e0 100644 --- a/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Mobile/MobileMasterDataController.cs +++ b/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Mobile/MobileMasterDataController.cs @@ -32,7 +32,7 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers [ApiVersion("1.0")] [ValidateAntiForgeryToken] [Route("api/mobile/v{version:apiVersion}/masterdata")] - public class MobileMasterDataController(IMobileMasterDataService service, IOptions appSettings, IEaseCache cache, ILogger logger) : ControllerBase + public class MobileMasterDataController(IMobileMasterDataService service, IOptions appSettings, IEaseCache cache, ILogger logger) : ControllerBase { private readonly ILogger _logger = logger; private readonly IEaseCache _cache = cache; diff --git a/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Mobile/OrdersController.cs b/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Mobile/OrdersController.cs new file mode 100644 index 0000000..f9b6ecb --- /dev/null +++ b/Api/OnlineSalesAutoCrop.CoreAPI/Controllers/Mobile/OrdersController.cs @@ -0,0 +1,68 @@ +using Asp.Versioning; +using Google.Api; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using OnlineSalesAutoCrop.CoreAPI.Models.Global; +using OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp; +using OnlineSalesAutoCrop.CoreAPI.Models.Responses; +using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp; +using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.MobileApp; +using System; +using System.Threading.Tasks; + +namespace OnlineSalesAutoCrop.CoreAPI.Controllers.Mobile; + +/// +/// +/// +/// +/// +/// +/// +/// +/// +/// +[Authorize] +[ApiController] +[ApiVersion("1.0")] +[ValidateAntiForgeryToken] +[Route("api/mobile/v{version:apiVersion}/orders")] +public class OrdersController(IOrderService service, IOptions appSettings, IEaseCache cache, ILogger logger) : ControllerBase +{ + private readonly ILogger _logger = logger; + private readonly IEaseCache _cache = cache; + private readonly IOrderService _service = service; + private readonly AppSettings _appSettings = appSettings?.Value; + private readonly DateTimeOffset _options = Helper.CreateEaseCacheOptions(); + + + /// + /// Login using your credential data retrieve from SqlServer + /// + /// + /// + /// + /// If login successful Return Attendance List + [HttpPost("SaveOrder")] + [IgnoreAntiforgeryToken] + [ProducesResponseType(StatusCodes.Status200OK, Type = typeof(SaveOrderResponse))] + public async Task UpsertAttendance([FromBody] SaveOrderRequest request) + { + SaveOrderResponse response = new(); + try + { + response = await _service.SaveOrderAsync(request); + return Ok(MobileResponseBase.Success(response)); + } + catch (Exception ex) + { + string msg = $"Exception occur on Save Orders endpoint with Order UUID request - {request?.UUID}"; + _logger.LogError(exception: ex, message: msg); + return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError)); + } + } +} +