Compare commits
71 Commits
main
...
Dev_Integr
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ef4818b42 | |||
| 458b7b6976 | |||
| 4d9a467558 | |||
| 0529139358 | |||
| 68cf33d5a6 | |||
| b93734f888 | |||
| 45f95b3184 | |||
| cf1a8e74a6 | |||
| 83f92ea6c8 | |||
| 17bd6a7727 | |||
| 311a9d5faa | |||
| 8290cc1c46 | |||
| 11c2e86888 | |||
| 177ee7d57f | |||
| 472cdf9409 | |||
| 874611cd18 | |||
| 7763c5278d | |||
| 4f3a990c60 | |||
| 93be7ab99c | |||
| 769e973f48 | |||
| 6f82ff2ae9 | |||
| 2b938d35b2 | |||
| 8b5af20539 | |||
| 240cb8ba2a | |||
| 5b35e0b044 | |||
| 399590a904 | |||
| e9500278cd | |||
| edf51b4271 | |||
| c75c96d0fd | |||
| c4ad3e53c7 | |||
| 3aea7dee2c | |||
| 13b1739ab1 | |||
| 16dcf2351f | |||
| 1a264523a0 | |||
| 6cd0f8f82f | |||
| 4990ac7a4a | |||
| 827795661a | |||
| 8559e35086 | |||
| 2143a3761c | |||
| 4f89ed32a7 | |||
| 23f07386ba | |||
| f02504d76d | |||
| 777aff085e | |||
| 3ae6fa0882 | |||
| 56bbcdfa04 | |||
| 794086917b | |||
|
|
38e557fbfd | ||
| 97a07bd216 | |||
| 7acf518892 | |||
| 1aed28659e | |||
| 376af6828e | |||
| b094c7ca75 | |||
| 8bf59da423 | |||
| a7467fbb39 | |||
| 66e52442df | |||
| 0250908261 | |||
| 5778ee9203 | |||
| cbd94a76ac | |||
| a64aa85d33 | |||
| bdcda8c1fb | |||
| 8c6df3cd19 | |||
| 18891cd584 | |||
| ad9694f85d | |||
| 89ef87fb18 | |||
| 5d6228aba2 | |||
| 1b738897d2 | |||
| 43efe23587 | |||
| 70a4a757f2 | |||
| a8f7cd51ce | |||
| e55821737f | |||
| 7ae8591ce6 |
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -20,3 +20,5 @@ obj
|
|||
/OnlineSalesAutoCrop/App/ClientApp/node_modules
|
||||
/App/ClientApp/node_modules
|
||||
/Api/OnlineSalesAutoCrop.CoreAPI/.config/dotnet-tools.json
|
||||
/App/ClientApp/.angular/cache/21.2.13/OnlineSalesAutoCropApp
|
||||
/Deployment/App/browser
|
||||
|
|
|
|||
|
|
@ -700,4 +700,89 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models
|
|||
[Description("From Others")]
|
||||
FromOthers = 3,
|
||||
}
|
||||
|
||||
public enum IntegrationMaterialCalCulationType : short
|
||||
{
|
||||
[Description("Percentage")]
|
||||
A = 1,
|
||||
[Description("Fixed value ")]
|
||||
B = 2,
|
||||
}
|
||||
|
||||
public enum IntegrationMaterialPriceType: short
|
||||
{
|
||||
[Description("Base Price")]
|
||||
PR00 = 1 ,
|
||||
[Description("Amount Based Discount")]
|
||||
ZDS1 = 2 ,
|
||||
[Description("Percentage Based Discount")]
|
||||
ZDS2 = 3
|
||||
}
|
||||
|
||||
public enum UserTypeEnum : short
|
||||
{
|
||||
SuperAdmin = 1,
|
||||
Admin = 2,
|
||||
SalesAppOfficer = 3
|
||||
}
|
||||
|
||||
public enum MaterialPriceTypeEnum : short
|
||||
{
|
||||
BasePrice = 1,
|
||||
Discount = 2,
|
||||
VatPrice = 3,
|
||||
SlabBasedDiscount = 4,
|
||||
}
|
||||
|
||||
public enum UserPlatFormType : short
|
||||
{
|
||||
SAP=1,
|
||||
AppUser =2,
|
||||
}
|
||||
|
||||
public enum UserRoleTypeEnum : short
|
||||
{
|
||||
[Description("Order Collector")]
|
||||
OrderCollector = 1,
|
||||
[Description("OrderValidator")]
|
||||
OrderValidator = 2,
|
||||
[Description("OrderApprover")]
|
||||
OrderApprover = 3 ,
|
||||
[Description("ApproverWithoutValidate")]
|
||||
OrderApproverWithoutValidated = 4,
|
||||
[Description("SAP User")]
|
||||
SapUser = 5 ,
|
||||
}
|
||||
|
||||
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("Delivered in SAP")]
|
||||
Delivered = 7,
|
||||
|
||||
}
|
||||
|
||||
public enum SAPOrderStatusEnum : short
|
||||
{
|
||||
Pending = 0,
|
||||
Sent = 1,
|
||||
Error = 2
|
||||
}
|
||||
|
||||
public enum DiscountTypeEnum : short
|
||||
{
|
||||
ItemType = 1,
|
||||
InvoiceValueType =2
|
||||
}
|
||||
}
|
||||
|
|
@ -54,7 +54,9 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models.Global
|
|||
public bool JwtValidateIssuer { get; set; }
|
||||
public bool JwtValidateAudience { get; set; }
|
||||
public int RefreshTokenDuration { get; set; }
|
||||
|
||||
public int AccessTokenDuration { get; set; }
|
||||
public int IsLogRequest { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Folder management
|
||||
/// </summary>
|
||||
|
|
@ -126,22 +128,23 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models.Global
|
|||
public string LoggerPath { get; set; }
|
||||
public int LoggerMinLevel { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Database connection Hangfire
|
||||
/// </summary>
|
||||
private string _hangfireDb;
|
||||
public string HangfireDb
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_hangfireDb) || string.IsNullOrEmpty(PwdSecretKey))
|
||||
return string.Empty;
|
||||
/// <summary>
|
||||
/// Database connection Hangfire
|
||||
/// </summary>
|
||||
public string HangfireDb { get; set; }
|
||||
//private string _hangfireDb;
|
||||
//public string HangfireDb
|
||||
//{
|
||||
// get
|
||||
// {
|
||||
// if (string.IsNullOrEmpty(_hangfireDb) || string.IsNullOrEmpty(PwdSecretKey))
|
||||
// return string.Empty;
|
||||
|
||||
string secretKey = GlobalFunctions.ConvertFromBase64String(PwdSecretKey);
|
||||
return Ease.NetCore.Utility.Global.CipherFunctions.DecryptByAES(privateKey: secretKey, publicKey: secretKey, data: _hangfireDb, input: 2);
|
||||
}
|
||||
set { _hangfireDb = value; }
|
||||
}
|
||||
// string secretKey = GlobalFunctions.ConvertFromBase64String(PwdSecretKey);
|
||||
// return Ease.NetCore.Utility.Global.CipherFunctions.DecryptByAES(privateKey: secretKey, publicKey: secretKey, data: _hangfireDb, input: 2);
|
||||
// }
|
||||
// set { _hangfireDb = value; }
|
||||
//}
|
||||
|
||||
|
||||
|
||||
|
|
@ -265,11 +268,13 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models.Global
|
|||
/// </summary>
|
||||
[Required]
|
||||
public ApiSettings API { get; set; }
|
||||
|
||||
public AutoCropSAPApi AutoCropSAPApi { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Swagger Setting
|
||||
/// </summary>
|
||||
[Required]
|
||||
/// <summary>
|
||||
/// Swagger Setting
|
||||
/// </summary>
|
||||
[Required]
|
||||
public Swagger Swagger { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -345,10 +350,20 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models.Global
|
|||
public string Url { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ApiLicense
|
||||
/// <summary>
|
||||
/// AutoCrop Integration API Details
|
||||
/// </summary>
|
||||
public class AutoCropSAPApi
|
||||
{
|
||||
public string BaseUrl { get; set; }
|
||||
public string UserName { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class ApiLicense
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Url { get; set; }
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Objects.Integrations;
|
||||
|
||||
public class CustomerIntegration
|
||||
public class IntegrationCustomer
|
||||
{
|
||||
public string CustomerNumber { get; set; }
|
||||
public string CustomerName { get; set; }
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Objects.Integrations;
|
||||
|
||||
public class EmployeeIntegration
|
||||
public class IntegrationEmployee
|
||||
{
|
||||
public string EmployeeVendorCode { get; set; }
|
||||
public string EmployeeVendorName { get; set; }
|
||||
|
|
@ -3,7 +3,7 @@ using System.ComponentModel.DataAnnotations;
|
|||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Objects.Integrations;
|
||||
|
||||
public class MaterialIntegration
|
||||
public class IntegrationMaterial
|
||||
{
|
||||
public int MeterialId { get; set; }
|
||||
public string MaterialType { get; set; }
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Objects.Integrations;
|
||||
|
||||
public class IntegrationMaterialFreeGood
|
||||
{
|
||||
public int FreeGoodsId { get; set; } // required for Update
|
||||
public string SalesOrg { get; set; }
|
||||
public string DistributionChannel { get; set; }
|
||||
public int? CustomerId { get; set; } // nullable
|
||||
public string CustomerPriceGroup { get; set; }
|
||||
public int MaterialId{ get; set; }
|
||||
public decimal MinOrderQuantity { get; set; }
|
||||
public decimal ForQuantity { get; set; }
|
||||
public string UnitOfMeasure { get; set; }
|
||||
public decimal FreeQuantity { get; set; }
|
||||
public string FocUnitOfMeasure { get; set; }
|
||||
public DateTime ValidFrom { get; set; }
|
||||
public DateTime ValidTo { get; set; }
|
||||
public string? Status { get; set; } // NULL = Active, X = Inactive
|
||||
public DateTime CreatedDate { get; set; }
|
||||
public DateTime ModifiedDate { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Objects.Integrations;
|
||||
|
||||
public class IntegrationMaterialPrice
|
||||
{
|
||||
public int MaterialPriceId { get; set; }
|
||||
public string SalesOrg { get; set; }
|
||||
public string DistributionChannel { get; set; }
|
||||
public string CustomerNumber { get; set; }
|
||||
public string CustomerGroupCode { get; set; }
|
||||
public string MaterialCode { get; set; }
|
||||
public string ConditionType { get; set; }
|
||||
public string CalculationType { get; set; }
|
||||
public string PricingUnit { get; set; }
|
||||
public string UnitOfMeasure { get; set; }
|
||||
public DateTime ValidFrom { get; set; }
|
||||
public DateTime ValidTo { get; set; }
|
||||
public string Status { get; set; }
|
||||
public decimal ConditionValue { get; set; }
|
||||
public DateTime CreatedDate { get; set; }
|
||||
public DateTime ModifiedDate { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
using System;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Objects.Integrations;
|
||||
|
||||
internal class IntegrationPaymentTerm
|
||||
{
|
||||
public int CreditCodeId { get; set; }
|
||||
public string CreditCode { get; set; }
|
||||
public string Description { get; set; }
|
||||
public DateTime ValidFrom { get; set; }
|
||||
public DateTime ValidTo { get; set; }
|
||||
public string SalesOrg { get; set; }
|
||||
public DateTime CreatedDate { get; set; }
|
||||
public DateTime? ModifiedDate { get; set; }
|
||||
}
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
using System;
|
||||
using DocumentFormat.OpenXml.Office2010.ExcelAc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems
|
||||
{
|
||||
|
|
@ -26,9 +28,18 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems
|
|||
public string SchemeName { get; set; }
|
||||
public string MenuLayout { get; set; }
|
||||
public bool IsLocked { get; set; }
|
||||
public EnumLoginStatus LoginStatus { get; set; }
|
||||
public DateTime? NextLoginTime { get; set; }
|
||||
|
||||
public UserPlatFormType? UserPlatFormType { get; set; }
|
||||
public UserRoleTypeEnum? UserRoleType { get; set; }
|
||||
public string? EmployeeNumber { get; set; }
|
||||
public string? DesignationCode { get; set; }
|
||||
public string? DesignationName { get; set; }
|
||||
public EnumLoginStatus LoginStatus { get; set; }
|
||||
public DateTime? NextLoginTime { get; set; }
|
||||
public int NotificationCount { get; set; }
|
||||
|
||||
public List<string> ModuleIds { get; set; } = new List<string>();
|
||||
public List<int> TeamSpaceIds { get; set; } = new List<int>();
|
||||
}
|
||||
|
||||
public class LoginHistory
|
||||
|
|
|
|||
|
|
@ -27,4 +27,13 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests
|
|||
{
|
||||
public string AuthenticationId { get; set; }
|
||||
}
|
||||
|
||||
public abstract class PagedRequest
|
||||
{
|
||||
[Range(1, int.MaxValue, ErrorMessage = "PageNumber must be at least 1.")]
|
||||
public int PageNumber { get; set; } = 1;
|
||||
|
||||
[Range(1, 1000, ErrorMessage = "PageSize must be between 1 and 1000.")]
|
||||
public int PageSize { get; set; } = 1000;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Common;
|
||||
|
||||
public class AuthLoginRequest
|
||||
{
|
||||
[Required, NotNull, StringLength(maximumLength: 15, MinimumLength = 3, ErrorMessage = "Login Id must be between 3 and 15 characters.")]
|
||||
public string LoginId { get; set; }
|
||||
|
||||
[Required, NotNull, StringLength(maximumLength: 20, MinimumLength = 5, ErrorMessage = "Password must be between 5 and 20 characters.")]
|
||||
public string Password { get; set; }
|
||||
}
|
||||
|
|
@ -1,41 +1,41 @@
|
|||
using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Common;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
|
||||
public class IntegrationLoginRequest
|
||||
public class IntegrationLoginRequest : AuthLoginRequest
|
||||
{
|
||||
[Required, NotNull, StringLength(maximumLength: 150, MinimumLength = 3, ErrorMessage = "Login Id must be between 4 and 30 characters.")]
|
||||
public string LoginId { get; set; }
|
||||
|
||||
[Required, NotNull, StringLength(maximumLength: 150, MinimumLength = 5, ErrorMessage = "Password must be between 1 and 30 characters.")]
|
||||
public string Password { get; set; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
public class IntegrationRefreshTokenRequest
|
||||
{
|
||||
public string RefreshToken { get; set; }
|
||||
[Required]
|
||||
public string RefreshToken { get; set; }
|
||||
}
|
||||
|
||||
public class InsertRefreshTokenRequest : RefreshToken
|
||||
{
|
||||
[Required]
|
||||
public string RefreshToken { get; set; }
|
||||
}
|
||||
|
||||
public class RevokedRefreshTokenRequest
|
||||
public class RevokedRefreshTokenRequest
|
||||
{
|
||||
[Required]
|
||||
public string RefreshToken { get; set; }
|
||||
[Required]
|
||||
public int UserId { get; set; }
|
||||
}
|
||||
|
||||
public class GenerateRefreshTokenRequest
|
||||
{
|
||||
[Required]
|
||||
public int UserId { get; set; }
|
||||
[Required]
|
||||
public string IpAddress { get; set; }
|
||||
[Required]
|
||||
public string RawRefreshToken { get; set; }
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ using System.Text;
|
|||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
|
||||
public class CustomerIntegrationRequest
|
||||
public class IntegrationCustomerRequest
|
||||
{
|
||||
[Required(ErrorMessage = "Customer number is required.")]
|
||||
[StringLength(10, ErrorMessage = "Customer number cannot exceed 10 characters.")]
|
||||
|
|
@ -16,7 +16,7 @@ public class CustomerIntegrationRequest
|
|||
public string CustomerName { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Account group is required.")]
|
||||
[StringLength(4, ErrorMessage = "Account group cannot exceed 3 characters.")]
|
||||
[StringLength(4, ErrorMessage = "Account group cannot exceed 4 characters.")]
|
||||
public string AccountGroup { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Account group description is required.")]
|
||||
|
|
@ -60,57 +60,45 @@ public class CustomerIntegrationRequest
|
|||
[Phone(ErrorMessage = "Mobile number is not a valid phone number.")]
|
||||
public string MobileNumber { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Email address is required.")]
|
||||
[StringLength(241, ErrorMessage = "Email address cannot exceed 241 characters.")]
|
||||
[EmailAddress(ErrorMessage = "Email address is not valid.")]
|
||||
public string EmailAddress { get; set; }
|
||||
public string? EmailAddress { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Business/Tax number is required.")]
|
||||
[StringLength(16, ErrorMessage = "Business/Tax number cannot exceed 16 characters.")]
|
||||
public string BusinessTaxNumber { get; set; }
|
||||
public string? BusinessTaxNumber { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Credit limit is required.")]
|
||||
[Range(0, 9999999999999.99, ErrorMessage = "Credit limit must be between 0 and 9,999,999,999,999.99.")]
|
||||
public decimal CreditLimit { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Sales group is required.")]
|
||||
[StringLength(3, ErrorMessage = "Sales group cannot exceed 3 characters.")]
|
||||
public string SalesGroup { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Sales group description is required.")]
|
||||
[StringLength(20, ErrorMessage = "Sales group description cannot exceed 20 characters.")]
|
||||
public string SalesGroupDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Customer group is required.")]
|
||||
[StringLength(2, ErrorMessage = "Customer group cannot exceed 2 characters.")]
|
||||
public string CustomerGroup { get; set; }
|
||||
public string? CustomerGroup { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Customer group description is required.")]
|
||||
[StringLength(20, ErrorMessage = "Customer group description cannot exceed 20 characters.")]
|
||||
public string CustomerGroupDescription { get; set; }
|
||||
public string? CustomerGroupDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Customer price group is required.")]
|
||||
[StringLength(2, ErrorMessage = "Customer price group cannot exceed 2 characters.")]
|
||||
public string CustomerPriceGroup { get; set; }
|
||||
public string? CustomerPriceGroup { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Customer price group description is required.")]
|
||||
[StringLength(20, ErrorMessage = "Customer price group description cannot exceed 20 characters.")]
|
||||
public string CustomerPriceGroupDescription { get; set; }
|
||||
public string? CustomerPriceGroupDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Status code is required.")]
|
||||
[StringLength(1, ErrorMessage = "Status code cannot exceed 1 character.")]
|
||||
public string StatusCode { get; set; }
|
||||
public string? StatusCode { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Status description is required.")]
|
||||
[StringLength(30, ErrorMessage = "Status description cannot exceed 30 characters.")]
|
||||
public string StatusDescription { get; set; }
|
||||
public string? StatusDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Payment terms is required.")]
|
||||
[StringLength(4, ErrorMessage = "Payment terms cannot exceed 4 characters.")]
|
||||
public string PaymentTerms { get; set; }
|
||||
public string? PaymentTerms { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Payment terms description is required.")]
|
||||
public string PaymentTermsDescription { get; set; }
|
||||
public string? PaymentTermsDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Search term is required.")]
|
||||
[StringLength(20, ErrorMessage = "Search term cannot exceed 20 characters.")]
|
||||
|
|
@ -150,7 +138,6 @@ public class CustomerIntegrationRequest
|
|||
}
|
||||
|
||||
|
||||
|
||||
public class CustomerByCompanyCodeRequest
|
||||
{
|
||||
[Required(ErrorMessage = "Customer Number is required")]
|
||||
|
|
@ -161,4 +148,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
|
||||
public class EmployeeIntegrationRequest
|
||||
public class IntegrationEmployeeRequest
|
||||
{
|
||||
[Required(ErrorMessage = "Employee vendor code is required.")]
|
||||
[StringLength(10, ErrorMessage = "Employee vendor code cannot exceed 10 characters.")]
|
||||
|
|
@ -25,7 +25,6 @@ public class EmployeeIntegrationRequest
|
|||
[Phone(ErrorMessage = "Mobile number is not a valid phone number.")]
|
||||
public string MobileNo { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Email address is required.")]
|
||||
[StringLength(241, ErrorMessage = "Email address cannot exceed 241 characters.")]
|
||||
[EmailAddress(ErrorMessage = "Email address is not valid.")]
|
||||
public string Mail { get; set; }
|
||||
|
|
@ -46,21 +45,17 @@ public class EmployeeIntegrationRequest
|
|||
[StringLength(40, ErrorMessage = "Sales org description cannot exceed 40 characters.")]
|
||||
public string SalesOrgDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Distribution channel is required.")]
|
||||
[StringLength(2, ErrorMessage = "Distribution channel cannot exceed 2 characters.")]
|
||||
public string DistChannel { get; set; }
|
||||
public string? DistChannel { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Distribution channel description is required.")]
|
||||
[StringLength(20, ErrorMessage = "Distribution channel description cannot exceed 20 characters.")]
|
||||
public string DistChannelDescription { get; set; }
|
||||
public string? DistChannelDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Division is required.")]
|
||||
[StringLength(2, ErrorMessage = "Division cannot exceed 2 characters.")]
|
||||
public string Division { get; set; }
|
||||
public string? Division { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Division description is required.")]
|
||||
[StringLength(20, ErrorMessage = "Division description cannot exceed 20 characters.")]
|
||||
public string DivisionDescription { get; set; }
|
||||
public string? DivisionDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Region/Area code is required.")]
|
||||
[StringLength(3, ErrorMessage = "Region/Area code cannot exceed 3 characters.")]
|
||||
|
|
@ -70,37 +65,29 @@ public class EmployeeIntegrationRequest
|
|||
[StringLength(40, ErrorMessage = "Region/Area description cannot exceed 40 characters.")]
|
||||
public string RegionAreaDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Area-AV/Sales unit code is required.")]
|
||||
[StringLength(10, ErrorMessage = "Area-AV/Sales unit code cannot exceed 10 characters.")]
|
||||
public string AreaAVSalesUnitCode { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Area-AV/Sales unit description is required.")]
|
||||
[StringLength(40, ErrorMessage = "Area-AV/Sales unit description cannot exceed 40 characters.")]
|
||||
public string AreaAVSalesUnitDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Territory is required.")]
|
||||
[StringLength(3, ErrorMessage = "Territory cannot exceed 3 characters.")]
|
||||
public string Territory { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Territory description is required.")]
|
||||
[StringLength(20, ErrorMessage = "Territory description cannot exceed 20 characters.")]
|
||||
public string TerritoryDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Plant is required.")]
|
||||
[StringLength(4, ErrorMessage = "Plant cannot exceed 4 characters.")]
|
||||
public string Plant { get; set; }
|
||||
public string? Plant { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Plant description is required.")]
|
||||
[StringLength(30, ErrorMessage = "Plant description cannot exceed 30 characters.")]
|
||||
public string PlantDescription { get; set; }
|
||||
public string? PlantDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Status is required.")]
|
||||
[StringLength(1, ErrorMessage = "Status cannot exceed 1 character.")]
|
||||
public string Status { get; set; }
|
||||
public string? Status { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Status description is required.")]
|
||||
[StringLength(30, ErrorMessage = "Status description cannot exceed 30 characters.")]
|
||||
public string StatusDescription { get; set; }
|
||||
public string? StatusDescription { get; set; }
|
||||
}
|
||||
|
||||
public class EmployeeIntegrationByComapanyRequest
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
|
||||
using DocumentFormat.OpenXml.Office2010.ExcelAc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
|
||||
public class IntegrationBillingDocumentRequest
|
||||
{
|
||||
[Required(ErrorMessage = "Invoice/Billing document number is required.")]
|
||||
[StringLength(50, ErrorMessage = "Invoice/Billing document number cannot exceed 50 characters.")]
|
||||
public string BillingDocumentNumber { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "Billing date is required.")]
|
||||
[DataType(DataType.Date)]
|
||||
public DateTime BillingDate { 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 reference number is required.")]
|
||||
[StringLength(50, ErrorMessage = "Delivery reference number cannot exceed 50 characters.")]
|
||||
public string DeliveryReferenceNumber { get; set; } = string.Empty;
|
||||
|
||||
public IList<IntegrationBillingDocumentItemRequest> Items { get; set; } = new List<IntegrationBillingDocumentItemRequest>();
|
||||
}
|
||||
|
||||
|
||||
public class IntegrationBillingDocumentItemRequest
|
||||
{
|
||||
[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;
|
||||
|
||||
[Required(ErrorMessage = "Billing amount is required.")]
|
||||
[Range(0, 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<IntegrationDeliveryDocumentItemRequest> Items { get; set; } = new List<IntegrationDeliveryDocumentItemRequest>();
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
@ -0,0 +1,86 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
|
||||
public class IntegrationMaterialFreeGoodsRequest
|
||||
{
|
||||
public IntegrationMaterialFreeGoodsRequest()
|
||||
{
|
||||
Slabs = new List<IntegrationMaterialFreeGoodItemRequest>();
|
||||
}
|
||||
|
||||
[Required(ErrorMessage = "Condition Record No is Required")]
|
||||
public int ConditionRecNo { get; set; }
|
||||
|
||||
[StringLength(10, MinimumLength = 1, ErrorMessage = "SalesOrg must be between 1 and 10 characters.")]
|
||||
public string SalesOrg { get; set; }
|
||||
|
||||
[StringLength(5, MinimumLength = 1, ErrorMessage = "DistributionChannel must be between 1 and 5 characters.")]
|
||||
public string DistributionChannel { get; set; }
|
||||
|
||||
[StringLength(13, MinimumLength = 1, ErrorMessage = "CustomerNumber must be between 1 and 13 characters.")]
|
||||
public string? CustomerNumber { get; set; } // nullable
|
||||
|
||||
[Required(ErrorMessage = "CustomerPriceGroup Is Required")]
|
||||
[StringLength(2, MinimumLength = 1, ErrorMessage = "CustomerPriceGroup must be between 1 and 2 characters.")]
|
||||
public string? CustomerPriceGroup { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "MaterialCode Is Required")]
|
||||
|
||||
[StringLength(18, MinimumLength = 1, ErrorMessage = "MaterialCode must be between 1 and 18 characters.")]
|
||||
public string? MaterialCode { get; set; }
|
||||
public IList<IntegrationMaterialFreeGoodItemRequest> Slabs { get; set; }
|
||||
}
|
||||
|
||||
public class IntegrationMaterialFreeGoodItemRequest
|
||||
{
|
||||
[Range(0.001, 9999999999999.999, ErrorMessage = "MinOrderQuantity must be greater than 0.")]
|
||||
public decimal? MinOrderQuantity { get; set; }
|
||||
|
||||
[Range(0.001, 9999999999999.999, ErrorMessage = "ForQuantity must be greater than 0.")]
|
||||
public decimal? ForQuantity { get; set; }
|
||||
|
||||
[StringLength(3, MinimumLength = 1, ErrorMessage = "UnitOfMeasure must be between 1 and 3 characters.")]
|
||||
public string? UnitOfMeasure { get; set; }
|
||||
|
||||
[Range(0.001, 9999999999999.999, ErrorMessage = "FreeQuantity must be greater than 0.")]
|
||||
public decimal? FreeQuantity { get; set; }
|
||||
|
||||
[StringLength(3, MinimumLength = 1, ErrorMessage = "FocUnitOfMeasure must be between 1 and 3 characters.")]
|
||||
public string? FocUnitOfMeasure { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "ValidFrom is required.")]
|
||||
public DateTime ValidFrom { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "ValidTo is required.")]
|
||||
public DateTime ValidTo { get; set; }
|
||||
|
||||
[StringLength(1, MinimumLength = 1, ErrorMessage = "Status must be 1 character.")]
|
||||
public string? Status { get; set; } // NULL = Active, X = Inactive
|
||||
}
|
||||
|
||||
public class GetMaterialFreeGoodsByFilterRequest
|
||||
{
|
||||
[Required(ErrorMessage = "SalesOrg is required.")]
|
||||
[StringLength(4, MinimumLength = 1, ErrorMessage = "SalesOrg must be between 1 and 4 characters.")]
|
||||
public string SalesOrg { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "DistributionChannel is required.")]
|
||||
[StringLength(2, MinimumLength = 1, ErrorMessage = "DistributionChannel must be between 1 and 2 characters.")]
|
||||
public string DistributionChannel { get; set; }
|
||||
|
||||
[StringLength(13, MinimumLength = 1, ErrorMessage = "CustomerNumber must be between 1 and 13 characters.")]
|
||||
public string? CustomerNumber { get; set; } // nullable
|
||||
|
||||
[StringLength(2, MinimumLength = 1, ErrorMessage = "CustomerPriceGroup must be between 1 and 2 characters.")]
|
||||
public string? CustomerPriceGroup { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "MaterialCode is required.")]
|
||||
[StringLength(10, MinimumLength = 1, ErrorMessage = "MaterialCode must be between 1 and 10 characters.")]
|
||||
public string MaterialCode { get; set; }
|
||||
|
||||
public DateTime? ValidFrom { get; set; }
|
||||
public DateTime? ValidTo { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,110 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
|
||||
public class IntegrationMaterialPriceRequest
|
||||
{
|
||||
public IntegrationMaterialPriceRequest()
|
||||
{
|
||||
Slabs = new List<IntegrationMaterialPriceItemRequest>();
|
||||
}
|
||||
|
||||
[Required(ErrorMessage = "Condition Record No is required.")]
|
||||
public int ConditionRecNo { get; set; }
|
||||
|
||||
[StringLength(4, ErrorMessage = "Sales Org cannot exceed 4 characters.")]
|
||||
public string? SalesOrg { get; set; }
|
||||
|
||||
[StringLength(2, ErrorMessage = "Distribution Channel cannot exceed 2 characters.")]
|
||||
public string? DistributionChannel { get; set; }
|
||||
|
||||
[StringLength(13, ErrorMessage = "Customer Number cannot exceed 13 characters.")]
|
||||
public string? CustomerNumber { get; set; }
|
||||
|
||||
[StringLength(10, ErrorMessage = "Customer Group Code cannot exceed 10 characters.")]
|
||||
public string? CustomerGroupCode { get; set; }
|
||||
|
||||
[StringLength(18, ErrorMessage = "Material Code cannot exceed 18 characters.")]
|
||||
public string? MaterialCode { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Condition Type is required.")]
|
||||
[StringLength(4, ErrorMessage = "Condition Type cannot exceed 4 characters.")]
|
||||
public string ConditionType { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Calculation Type is required.")]
|
||||
[StringLength(1, ErrorMessage = "Calculation Type cannot exceed 1 character.")]
|
||||
public string CalculationType { get; set; }
|
||||
|
||||
[StringLength(1, ErrorMessage = "Pricing Unit cannot exceed 1 character.")]
|
||||
public string? PricingUnit { get; set; }
|
||||
|
||||
[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
|
||||
{
|
||||
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 class GetMaterialPriceByCodeRequest
|
||||
{
|
||||
[Required(ErrorMessage = "Sales Org is required.")]
|
||||
[StringLength(4, ErrorMessage = "Sales Org cannot exceed 4 characters.")]
|
||||
public string SalesOrg { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Material Code is required.")]
|
||||
[StringLength(18, ErrorMessage = "Material Code cannot exceed 18 characters.")]
|
||||
public string MaterialCode { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Condition Type is required.")]
|
||||
[StringLength(4, ErrorMessage = "Condition Type cannot exceed 4 characters.")]
|
||||
public string ConditionType { get; set; }
|
||||
|
||||
[StringLength(13, ErrorMessage = "Customer Number cannot exceed 13 characters.")]
|
||||
public string? CustomerNumber { get; set; }
|
||||
|
||||
[StringLength(10, ErrorMessage = "Customer Group Code cannot exceed 10 characters.")]
|
||||
public string? CustomerGroupCode { get; set; }
|
||||
|
||||
[StringLength(10, ErrorMessage = "Distributor Channel Code cannot exceed 10 characters.")]
|
||||
public string? DistributorChannelCode { get; set; }
|
||||
|
||||
public DateTime? ValidFrom { get; set; }
|
||||
public DateTime? ValidTo { get; set; }
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
|
||||
public class MaterialIntegrationRequest
|
||||
public class IntegrationMaterialRequest
|
||||
{
|
||||
[Required(ErrorMessage = "Material type is required.")]
|
||||
[StringLength(4, ErrorMessage = "Material type cannot exceed 4 characters.")]
|
||||
|
|
@ -13,12 +13,20 @@ public class MaterialIntegrationRequest
|
|||
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.")]
|
||||
[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.")]
|
||||
|
|
@ -40,28 +48,21 @@ public class MaterialIntegrationRequest
|
|||
[Range(0.001, 999.999, ErrorMessage = "Unit conversion must be between 0.001 and 999.999.")]
|
||||
public decimal UnitConversionWithBaseUoM { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Plant code is required.")]
|
||||
[StringLength(4, ErrorMessage = "Plant code cannot exceed 4 characters.")]
|
||||
public string PlantCode { get; set; }
|
||||
[StringLength(10, ErrorMessage = "Plant code cannot exceed 10 characters.")]
|
||||
public string? PlantCode { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Plant description is required.")]
|
||||
[StringLength(30, ErrorMessage = "Plant description cannot exceed 30 characters.")]
|
||||
public string PlantDescription { get; set; }
|
||||
public string? PlantDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Storage location code is required.")]
|
||||
[StringLength(4, ErrorMessage = "Storage location code cannot exceed 4 characters.")]
|
||||
public string StorageLocationCode { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Storage location description is required.")]
|
||||
[StringLength(16, ErrorMessage = "Storage location description cannot exceed 16 characters.")]
|
||||
public string StorageLocationDescription { get; set; }
|
||||
public string? StorageLocationCode { get; set; }
|
||||
public string? StorageLocationDescription { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Sales Organization code is required.")]
|
||||
[StringLength(4, ErrorMessage = "Sales Organization code cannot exceed 4 characters.")]
|
||||
public string SalesOrganization { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Sales Organization Description is required.")]
|
||||
[StringLength(16, ErrorMessage = "Sales Organization Description cannot exceed 16 characters.")]
|
||||
[StringLength( 40, MinimumLength =1, ErrorMessage = "Sales Organization Description cannot exceed 40 characters.")]
|
||||
public string SalesOrganizationDescription { get; set; }
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
|
||||
|
||||
public class IntegrationPaymentTermRequest
|
||||
{
|
||||
|
||||
[Required(ErrorMessage = "CreditCode is required.")]
|
||||
[StringLength(4, MinimumLength = 1, ErrorMessage = "CreditCode must be between 1 and 4 characters.")]
|
||||
public string CreditCode { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Description is required.")]
|
||||
[StringLength(30, MinimumLength = 1, ErrorMessage = "Description must be between 1 and 30 characters.")]
|
||||
public string Description { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "ValidFrom is required.")]
|
||||
public DateTime ValidFrom { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "ValidTo is required.")]
|
||||
public DateTime ValidTo { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "SalesOrg is required.")]
|
||||
[StringLength(4, MinimumLength = 1, ErrorMessage = "SalesOrg must be between 1 and 4 characters.")]
|
||||
public string SalesOrg { get; set; }
|
||||
}
|
||||
|
||||
public class GetIntegrationPaymentTermRequest
|
||||
{
|
||||
[Required(ErrorMessage = "CreditCode is required.")]
|
||||
[StringLength(4, MinimumLength = 1, ErrorMessage = "CreditCode must be between 1 and 4 characters.")]
|
||||
public string CreditCode { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "SalesOrg is required.")]
|
||||
[StringLength(4, MinimumLength = 1, ErrorMessage = "SalesOrg must be between 1 and 4 characters.")]
|
||||
public string SalesOrg { get; set; }
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp;
|
||||
|
||||
public class MobileAppAuthRequest : AuthLoginRequest
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class AuthLogoutRequest
|
||||
{
|
||||
[Required, NotNull, StringLength(maximumLength: 10, MinimumLength = 3, ErrorMessage = "Login Id must be between 3 and 10 characters.")]
|
||||
public string LoginId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class AppUserChangePasswordRequest
|
||||
{
|
||||
[Required, NotNull, StringLength(maximumLength: 10, MinimumLength = 3, ErrorMessage = "Login Id must be between 3 and 10 characters.")]
|
||||
public string LoginId { get; set; }
|
||||
|
||||
[Required, NotNull, StringLength(maximumLength: 20, MinimumLength = 5, ErrorMessage = "Password must be between 5 and 20 characters.")]
|
||||
public string Password { get; set; }
|
||||
|
||||
[Required, NotNull, StringLength(maximumLength: 20, MinimumLength = 5, ErrorMessage = "Password must be between 5 and 20 characters.")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[Required, NotNull, StringLength(maximumLength: 20, MinimumLength = 5, ErrorMessage = "Password must be between 5 and 20 characters.")]
|
||||
[Compare("NewPassword", ErrorMessage = "Password and Confirm Password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(NewPassword) &&
|
||||
!string.IsNullOrWhiteSpace(ConfirmPassword) &&
|
||||
Password != ConfirmPassword)
|
||||
{
|
||||
yield return new ValidationResult(
|
||||
"Password and Confirm Password do not match.",
|
||||
[nameof(NewPassword), nameof(ConfirmPassword)]
|
||||
);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(LoginId) &&
|
||||
!string.IsNullOrWhiteSpace(NewPassword) &&
|
||||
Password.Equals(LoginId, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
yield return new ValidationResult(
|
||||
"Password must not be the same as your Login ID.",
|
||||
[nameof(NewPassword)]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,185 @@
|
|||
|
||||
using DocumentFormat.OpenXml.Wordprocessing;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp;
|
||||
|
||||
public class GetMarketHeirarchyByEmpRequest
|
||||
{
|
||||
[Required, NotNull, StringLength(maximumLength: 12, MinimumLength = 3, ErrorMessage = "EmployeeNumber must be between 3 and 12 characters.")]
|
||||
public string EmployeeNumber { get; set; }
|
||||
}
|
||||
|
||||
public class GetBrandsRequest : PagedRequest
|
||||
{
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Brand code must be between 1 and 15 characters.")]
|
||||
public string? BrandCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Sales organization code must be between 1 and 15 characters.")]
|
||||
public string? SalesOrgCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Employee number must be between 1 and 15 characters.")]
|
||||
public string? EmployeeNumber { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class GetMaterialsRequest : PagedRequest
|
||||
{
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Sales organization code must be between 1 and 15 characters.")]
|
||||
public string SalesOrgCode { get; set; }
|
||||
|
||||
[StringLength(6, MinimumLength = 1, ErrorMessage = "Brand code must be between 1 and 6 characters.")]
|
||||
public string? BrandCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Material Code must be between 1 and 15 characters.")]
|
||||
public string? MaterialCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Employee number must be between 1 and 15 characters.")]
|
||||
public string? EmployeeNumber { get; set; }
|
||||
}
|
||||
|
||||
public class GetMaterialStockRequest : PagedRequest
|
||||
{
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Plant Code must be between 1 and 15 characters.")]
|
||||
public string PlantCode { get; set; }
|
||||
}
|
||||
|
||||
public class GetMaterialPriceRequest : PagedRequest
|
||||
{
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Sales organization code must be between 1 and 15 characters.")]
|
||||
public string SalesOrgCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Brand code must be between 1 and 15 characters.")]
|
||||
public string? BrandCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Material Code must be between 1 and 15 characters.")]
|
||||
public string? MaterialCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Employee number must be between 1 and 15 characters.")]
|
||||
public string? EmployeeNumber { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class GetCustomersRequest : PagedRequest
|
||||
{
|
||||
[StringLength(15, MinimumLength = 3, ErrorMessage = "Sales organization code must be between 1 and 15 characters.")]
|
||||
public string SalesOrgCode { get; set; }
|
||||
|
||||
[StringLength(5, MinimumLength = 3, ErrorMessage = "Teritory Code must be between 1 and 5 characters.")]
|
||||
public string? TeritoryCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 5, ErrorMessage = "Customer Code must be between 1 and 15 characters.")]
|
||||
public string? CustomerCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 5, ErrorMessage = "Employee number must be between 1 and 15 characters.")]
|
||||
public string? EmployeeNumber { get; set; }
|
||||
}
|
||||
|
||||
public class GetAttendanceByEmpRequest
|
||||
{
|
||||
[Required, NotNull, StringLength(maximumLength: 15, MinimumLength = 3, ErrorMessage = "EmployeeNumber must be between 3 and 15 characters.")]
|
||||
public string EmployeeNumber { get; set; }
|
||||
public DateTime? AttendanceDate { get; set; }
|
||||
}
|
||||
|
||||
public class UpsertAttendanceByEmpRequest
|
||||
{
|
||||
[Required, NotNull, StringLength(maximumLength: 15, MinimumLength = 3, ErrorMessage = "EmployeeNumber must be between 3 and 15 characters.")]
|
||||
public string EmployeeNumber { get; set; }
|
||||
public TimeSpan? CheckInTime { get; set; }
|
||||
public string? CheckInLatitude { get; set; }
|
||||
public string? CheckInLongitude { get; set; }
|
||||
public string? CheckInLocationName { get; set; }
|
||||
public TimeSpan? CheckOutTime { get; set; }
|
||||
public string? CheckOutLatitude { get; set; }
|
||||
public string? CheckOutLongitude { get; set; }
|
||||
public string? CheckOutLocationName { get; set; }
|
||||
public bool IsCheckIn => CheckInTime.HasValue ? true : false;
|
||||
public bool IsCheckOut => CheckOutTime.HasValue ? true : false;
|
||||
}
|
||||
|
||||
public class GetDiscountRequest : PagedRequest
|
||||
{
|
||||
[StringLength(15, MinimumLength = 3, ErrorMessage = "Sales organization code must be between 1 and 15 characters.")]
|
||||
public string SalesOrgCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 5, ErrorMessage = "Customer Code must be between 1 and 15 characters.")]
|
||||
public string? CustomerCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 5, ErrorMessage = "Employee number must be between 1 and 15 characters.")]
|
||||
public string? EmployeeNumber { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 3, ErrorMessage = "Material Code must be between 1 and 15 characters.")]
|
||||
public string? MaterialCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Discount Code must be between 1 and 15 characters.")]
|
||||
public string? DiscountCode { get; set; }
|
||||
}
|
||||
|
||||
public class GetDiscountMaterialRequest : PagedRequest
|
||||
{
|
||||
[StringLength(15, MinimumLength = 3, ErrorMessage = "Sales organization code must be between 1 and 15 characters.")]
|
||||
public string SalesOrgCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 5, ErrorMessage = "Customer Code must be between 1 and 15 characters.")]
|
||||
public string? CustomerCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 5, ErrorMessage = "Employee number must be between 1 and 15 characters.")]
|
||||
public string? EmployeeNumber { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 3, ErrorMessage = "Material Code must be between 1 and 15 characters.")]
|
||||
public string? MaterialCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Discount Code must be between 1 and 15 characters.")]
|
||||
public string? DiscountCode { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class GetFOCRequest : PagedRequest
|
||||
{
|
||||
[StringLength(15, MinimumLength = 3, ErrorMessage = "Sales organization code must be between 1 and 15 characters.")]
|
||||
public string SalesOrgCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 5, ErrorMessage = "Customer Code must be between 1 and 15 characters.")]
|
||||
public string? CustomerCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 5, ErrorMessage = "Employee number must be between 1 and 15 characters.")]
|
||||
public string? EmployeeNumber { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 3, ErrorMessage = "Material Code must be between 1 and 15 characters.")]
|
||||
public string? MaterialCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Discount Code must be between 1 and 15 characters.")]
|
||||
public string? FOCCode { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class GetFOCMaterialRequest : PagedRequest
|
||||
{
|
||||
[StringLength(15, MinimumLength = 3, ErrorMessage = "Sales organization code must be between 1 and 15 characters.")]
|
||||
public string SalesOrgCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 5, ErrorMessage = "Customer Code must be between 1 and 15 characters.")]
|
||||
public string? CustomerCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 5, ErrorMessage = "Employee number must be between 1 and 15 characters.")]
|
||||
public string? EmployeeNumber { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 3, ErrorMessage = "Material Code must be between 1 and 15 characters.")]
|
||||
public string? MaterialCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 1, ErrorMessage = "Discount Code must be between 1 and 15 characters.")]
|
||||
public string? FOCCode { get; set; }
|
||||
}
|
||||
|
||||
public class GetPaymentTermRequest : PagedRequest
|
||||
{
|
||||
[StringLength(15, MinimumLength = 3, ErrorMessage = "Sales organization code must be between 1 and 15 characters.")]
|
||||
public string SalesOrgCode { get; set; }
|
||||
|
||||
[StringLength(15, MinimumLength = 3, ErrorMessage = "PayementTerm Code must be between 3 and 15 characters.")]
|
||||
public string? PaymentTermCode { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp;
|
||||
|
||||
public class SaveOrderRequest
|
||||
{
|
||||
public SaveOrderRequest()
|
||||
{
|
||||
Items = new List<SaveOrderItemRequest>();
|
||||
}
|
||||
|
||||
public int? OrderId { get; set; }
|
||||
public string? OrderNo { get; set; }
|
||||
public DateTime? OrderDate { get; set; }
|
||||
public DateTime? ExpectedDeliveryDate { 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 string PlantCode { 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 FocValue { get; set; }
|
||||
public decimal DiscountValue { get; set; }
|
||||
public decimal? TotalVatValue { get; set; }
|
||||
public decimal GrossValue { get; set; }
|
||||
public decimal NetValue { get; set; }
|
||||
public OrderStatusEnum OrderStatus { get; set; }
|
||||
public IList<SaveOrderItemRequest> Items { get; set; }
|
||||
}
|
||||
|
||||
public class SaveOrderItemRequest
|
||||
{
|
||||
public int? OrderId { get; set; }
|
||||
public int? ItemId { 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 PromoQuantity { 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 decimal? VatValue { get; set; }
|
||||
}
|
||||
|
||||
public class SaveOrderPromotionRequest
|
||||
{
|
||||
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 OrderFocQty { get; set; }
|
||||
public decimal ValidatedFocQty { get; set; }
|
||||
public decimal ApprovedFocQty { get; set; }
|
||||
public int PromotionType { get; set; }
|
||||
}
|
||||
|
||||
public class GetOrderSummaryRequest : PagedRequest
|
||||
{
|
||||
public string? SalesOrgCode { get; set; }
|
||||
public string? EmployeeCode { get; set; }
|
||||
public string? OrderNo { get; set; }
|
||||
public string? UUID { get; set; }
|
||||
public string? CustomerCode { get; set; }
|
||||
public DateTime? StartDate { get; set; }
|
||||
public DateTime? EndDate { get; set; }
|
||||
public OrderStatusEnum? OrderStatus { get; set; }
|
||||
}
|
||||
|
||||
public class UpdateSapDetailsRequest
|
||||
{
|
||||
public int OrderId { get; set; }
|
||||
public string SapOrderNo { get; set; }
|
||||
public SAPOrderStatusEnum Status { get; set; }
|
||||
public DateTime SentAt { get; set; }
|
||||
public int RetryCount { get; set; }
|
||||
public string LastError { get; set; }
|
||||
public string ReturnMessage { get; set; }
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
using System;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Setups;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Requests.Systems;
|
||||
|
|
@ -70,6 +72,14 @@ public class ResetPasswordRequest : ByUserIdRequest
|
|||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
|
||||
public class BulkPasswordUploadRequest : FileUploadRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// When true, uploaded users are forced to change their password at next login.
|
||||
/// </summary>
|
||||
public bool ForcePasswordChange { get; set; }
|
||||
}
|
||||
|
||||
public class PasswordChangeRequest : ResetPasswordRequest
|
||||
{
|
||||
[Required, NotNull, StringLength(maximumLength: 30, MinimumLength = 1, ErrorMessage = "Old Password must be between 1 and 30 characters.")]
|
||||
|
|
@ -219,3 +229,43 @@ public class PayslipRequest
|
|||
[Required, NotNull]
|
||||
public DateTime YearMonth { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class AppUserCreateRequest
|
||||
{
|
||||
[Required(ErrorMessage = "Login ID is required.")]
|
||||
[MaxLength(100, ErrorMessage = "Login ID cannot exceed 100 characters.")]
|
||||
public string LoginId { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "Username is required.")]
|
||||
[MaxLength(150, ErrorMessage = "Username cannot exceed 150 characters.")]
|
||||
public string UserName { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
public int Status { get; set; }
|
||||
|
||||
[Required]
|
||||
public int AccessStatus { get; set; }
|
||||
|
||||
[Phone(ErrorMessage = "Invalid mobile number format.")]
|
||||
[MaxLength(20, ErrorMessage = "Mobile number cannot exceed 20 characters.")]
|
||||
public string? MobileNo { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Email address is required.")]
|
||||
[EmailAddress(ErrorMessage = "Invalid email address format.")]
|
||||
[MaxLength(200, ErrorMessage = "Email address cannot exceed 200 characters.")]
|
||||
public string EmailAddress { get; set; } = string.Empty;
|
||||
|
||||
public int IsLocked { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "Password is required.")]
|
||||
[MaxLength(500, ErrorMessage = "Password hash length cannot exceed 500 characters.")]
|
||||
public string Password { get; set; } = string.Empty;
|
||||
|
||||
public int? UserPlatformId { get; set; }
|
||||
|
||||
public int? UserRoleType { get; set; }
|
||||
|
||||
[MaxLength(10,ErrorMessage = "EmployeeNumber hash length cannot exceed 10 characters")]
|
||||
public string? EmployeeNumber { get; set; }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,4 @@
|
|||
using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
|
||||
|
|
@ -14,16 +11,22 @@ public class IntegrationLoginResponse : ResponseBase
|
|||
public DateTime AccessTokenExpiry { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class IntegrationRrefreshTokenResponse : ResponseBase
|
||||
{
|
||||
public string AccessToken { get; set; } = string.Empty;
|
||||
public string RefreshToken { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
public class RefreshTokenResponse : ResponseBase
|
||||
public class MobileRrefreshTokenResponse
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public string AccessToken { get; set; } = string.Empty;
|
||||
public string RefreshToken { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class RefreshTokenResponse : ResponseBase
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public string TokenHash { get; set; }
|
||||
public string IpAddress { get; set; }
|
||||
public DateTime ExpiredAt { get; set; }
|
||||
|
|
@ -35,14 +38,14 @@ public class RefreshTokenResponse : ResponseBase
|
|||
public class GenerateRefreshTokenResponse : ResponseBase
|
||||
{
|
||||
public string RefreshToken { get; set; }
|
||||
public DateTime ExpireTime { get; set; }
|
||||
public DateTime ExpireTime { get; set; }
|
||||
}
|
||||
|
||||
public class UserByRefreshTokenResponse : ResponseBase
|
||||
public class UserByRefreshTokenResponse : ResponseBase
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public string LoginId { get; set; }
|
||||
public string EmailAddress { get; set; }
|
||||
public string AuthKey { get; set; }
|
||||
public bool IsActive { set; get; }
|
||||
public string EmailAddress { get; set; }
|
||||
public string AuthKey { get; set; }
|
||||
public bool IsActive { set; get; }
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
|
||||
public class CustomerIntegrationResponse : ResponseBase
|
||||
public class IntegrationCustomerResponse : ResponseBase
|
||||
{
|
||||
public string CustomerNumber { get; set; }
|
||||
public string CompanyCode { get; set; }
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
|
||||
public class EmployeeIntegrationResponse : ResponseBase
|
||||
public class IntegrationEmployeeResponse : ResponseBase
|
||||
{
|
||||
public int EmployeeId { get; set; }
|
||||
public string EmployeeVendorCode { get; set; }
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
|
||||
public sealed class SapODataResponse<T>
|
||||
{
|
||||
[JsonPropertyName("d")]
|
||||
public SapODataResult<T> D { get; set; } = default!;
|
||||
}
|
||||
|
||||
public sealed class SapODataResult<T>
|
||||
{
|
||||
[JsonPropertyName("results")]
|
||||
public List<T> Results { get; set; } = new();
|
||||
}
|
||||
|
||||
public sealed class IntegrationCustLedgerHttpResponse
|
||||
{
|
||||
[JsonPropertyName("company")]
|
||||
public string Company { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("customer_no")]
|
||||
public string CustomerNo { get; set; } = string.Empty; // stays string — SAP customer numbers can carry leading zeros
|
||||
|
||||
[JsonPropertyName("current_balance")]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
|
||||
public decimal CurrentBalance { get; set; }
|
||||
|
||||
[JsonPropertyName("overdue_amount")]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
|
||||
public decimal OverdueAmount { get; set; }
|
||||
|
||||
[JsonPropertyName("currency")]
|
||||
public string Currency { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("overdue_date")]
|
||||
[JsonConverter(typeof(SapODataDateConverter))]
|
||||
public DateTime OverdueDate { get; set; }
|
||||
}
|
||||
|
||||
public sealed class IntegrationMaterialStockHttpResponse
|
||||
{
|
||||
[JsonPropertyName("plant")]
|
||||
public string PlantCode { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("material")]
|
||||
public string MaterialCode { get; set; } = string.Empty; // stays string — SAP customer numbers can carry leading zeros
|
||||
|
||||
[JsonPropertyName("available_stock")]
|
||||
[JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)]
|
||||
public decimal AvailableStock { get; set; }
|
||||
|
||||
[JsonPropertyName("uom")]
|
||||
public string UOM { get; set; } = string.Empty;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public sealed class SapODataDateConverter : JsonConverter<DateTime>
|
||||
{
|
||||
// Matches "/Date(1783641600000)/" and the rarer offset form "/Date(1783641600000+0600)/"
|
||||
private static readonly Regex Pattern = new(@"/Date\((-?\d+)(?:[+-]\d{4})?\)/", RegexOptions.Compiled);
|
||||
|
||||
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
var raw = reader.GetString();
|
||||
if (string.IsNullOrEmpty(raw))
|
||||
return default;
|
||||
|
||||
var match = Pattern.Match(raw);
|
||||
if (!match.Success)
|
||||
throw new JsonException($"Unexpected SAP OData date format: '{raw}'");
|
||||
|
||||
var ms = long.Parse(match.Groups[1].Value);
|
||||
return DateTimeOffset.FromUnixTimeMilliseconds(ms).UtcDateTime;
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
|
||||
{
|
||||
var ms = new DateTimeOffset(value, TimeSpan.Zero).ToUnixTimeMilliseconds();
|
||||
writer.WriteStringValue($"/Date({ms})/");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
|
||||
public class IntegrationBillingReqResponse : ResponseBase
|
||||
{
|
||||
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; }
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
using System;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
|
||||
public class IntegrationMaterialFreeGoodsResponse : ResponseBase
|
||||
{
|
||||
public int FreeGoodsId { get; set; } // required for Update
|
||||
public string SalesOrg { get; set; }
|
||||
public string DistributionChannel { get; set; }
|
||||
public string? CustomerNumber { get; set; } // nullable
|
||||
public string? CustomerPriceGroup { get; set; }
|
||||
public string? MaterialCode { get; set; }
|
||||
public decimal? MinOrderQuantity { get; set; }
|
||||
public decimal? ForQuantity { get; set; }
|
||||
public string? UnitOfMeasure { get; set; }
|
||||
public decimal? FreeQuantity { get; set; }
|
||||
public string? FocUnitOfMeasure { get; set; }
|
||||
public DateTime? ValidFrom { get; set; }
|
||||
public DateTime? ValidTo { get; set; }
|
||||
public string? Status { get; set; }
|
||||
}
|
||||
|
||||
public class MaterialFreeGoodsByReqResponse : ResponseBase
|
||||
{
|
||||
public string SalesOrg { get; set; }
|
||||
public string DistributionChannel { get; set; }
|
||||
public string CustomerNumber { get; set; }
|
||||
public string CustomerPriceGroup { get; set; }
|
||||
public string MaterialCode { get; set; }
|
||||
public bool IsUpdated { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
using System;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
|
||||
public class IntegrationMaterialPriceResponse : ResponseBase
|
||||
{
|
||||
public int MaterialPriceId { get; set; }
|
||||
public string? SalesOrg { get; set; }
|
||||
public string? DistributionChannel { get; set; }
|
||||
public string? CustomerNumber { get; set; }
|
||||
public string? CustomerGroupCode { get; set; }
|
||||
public string MaterialCode { get; set; }
|
||||
public string ConditionType { get; set; }
|
||||
public string CalculationType { get; set; }
|
||||
public string PricingUnit { get; set; }
|
||||
public string UnitOfMeasure { get; set; }
|
||||
public DateTime ValidFrom { get; set; }
|
||||
public DateTime ValidTo { get; set; }
|
||||
public string Status { get; set; }
|
||||
public decimal ConditionValue { get; set; }
|
||||
}
|
||||
|
||||
public class MaterialIntegrationPriceReqResponse : ResponseBase
|
||||
{
|
||||
public string MaterialCode { get; set; }
|
||||
public string ConditionType { get; set; }
|
||||
public string? CustomerNumber { get; set; }
|
||||
public string? CustomerGroupCode { get; set; }
|
||||
public bool IsUpdated { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class MaterialPriceTypeResponse
|
||||
{
|
||||
public int PriceTypeId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Code { get; set; }
|
||||
public MaterialPriceTypeEnum PriceType { get; set; }
|
||||
}
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
|
||||
public class MaterialIntegrationResponse : ResponseBase
|
||||
public class IntegrationMaterialResponse : ResponseBase
|
||||
{
|
||||
public int MeterialId { get; set; }
|
||||
public string MaterialType { get; set; }
|
||||
|
|
@ -20,6 +20,8 @@ public class MaterialIntegrationResponse : 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
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
using System;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
|
||||
public class IntegrationPaymentTermResponse : ResponseBase
|
||||
{
|
||||
public int CreditCodeId { get; set; }
|
||||
public string CreditCode { get; set; }
|
||||
public string Description { get; set; }
|
||||
public DateTime ValidFrom { get; set; }
|
||||
public DateTime ValidTo { get; set; }
|
||||
public string SalesOrg { get; set; }
|
||||
}
|
||||
|
||||
public class IntegrationPaymentTermReqResponse : ResponseBase
|
||||
{
|
||||
public string CreditCode { get; set; }
|
||||
public string SalesOrg { get; set; }
|
||||
public bool IsUpdated { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
|
||||
using System;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp;
|
||||
|
||||
public class AppAuthUserResponse
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public string LoginId { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string? Email { get; set; }
|
||||
public string? MobileNumber { get; set; }
|
||||
public string EmployeeNumber { get; set; }
|
||||
public string DesignationCode { get; set; }
|
||||
public string DesignationName { get; set; }
|
||||
public bool IsLocked { get; set; }
|
||||
public UserRoleTypeEnum UserRole { get; set; }
|
||||
public string AccessToken { get; set; }
|
||||
public DateTime AccessTokenExpiryTime { get; set; }
|
||||
public string RefreshToken { get; set; }
|
||||
public DateTime RefreshTokenExpiryTime { get; set; }
|
||||
public EnumLoginStatus LoginStatus { get; set; }
|
||||
public bool IsAuthorized { get; set; }
|
||||
public bool IsInitialPassword { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class AuthLogoutResponse
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public string LoginId { get; set; }
|
||||
public bool IsSuccess { get; set; }
|
||||
}
|
||||
|
||||
public class AppChangePasswordResponse
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public string LoginId { get; set; }
|
||||
public bool IsSuccess { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
using Microsoft.AspNetCore.Mvc.Formatters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp;
|
||||
|
||||
public class MarketHeirarchyByEmpResponse
|
||||
{
|
||||
public MarketHeirarchyByEmpResponse()
|
||||
{
|
||||
Companies = new List<EmpCompanyResponse>();
|
||||
SalesOrgs = new List<SalesOrgResponse>();
|
||||
DistributionChannels = new List<DistibutionChannleResponse>();
|
||||
Regions = new List<RegionResponse>();
|
||||
Areas = new List<AreaResponse>();
|
||||
Teritories = new List<TeritoryResponse>();
|
||||
Plants = new List<PlantResponse>();
|
||||
}
|
||||
|
||||
public IList<EmpCompanyResponse> Companies { get; set; }
|
||||
public IList<SalesOrgResponse> SalesOrgs { get; set; }
|
||||
public IList<DistibutionChannleResponse> DistributionChannels { get; set; }
|
||||
public IList<RegionResponse> Regions { get; set; }
|
||||
public IList<AreaResponse> Areas { get; set; }
|
||||
public IList<TeritoryResponse> Teritories { get; set; }
|
||||
public IList<PlantResponse> Plants { get; set; }
|
||||
}
|
||||
|
||||
public class EmpCompanyResponse
|
||||
{
|
||||
public string CompanyCode { get; set; }
|
||||
public string CompanyName { get; set; }
|
||||
}
|
||||
|
||||
public class SalesOrgResponse
|
||||
{
|
||||
public string CompanyCode { get; set; }
|
||||
public string SalesOrgCode { get; set; }
|
||||
public string SalesOrgName { get; set; }
|
||||
}
|
||||
|
||||
public class DistibutionChannleResponse
|
||||
{
|
||||
public string CompanyCode { get; set; }
|
||||
public string SalesOrgCode { get; set; }
|
||||
public string DistributorChannelCode { get; set; }
|
||||
public string DistributorChannelName { get; set; }
|
||||
}
|
||||
|
||||
public class RegionResponse
|
||||
{
|
||||
public string CompanyCode { get; set; }
|
||||
public string SalesOrgCode { get; set; }
|
||||
public string RegionCode { get; set; }
|
||||
public string RegionName { get; set; }
|
||||
}
|
||||
|
||||
public class AreaResponse
|
||||
{
|
||||
public string CompanyCode { get; set; }
|
||||
public string SalesOrgCode { get; set; }
|
||||
public string RegionCode { get; set; }
|
||||
public string AreaCode { get; set; }
|
||||
public string AreaName { get; set; }
|
||||
}
|
||||
|
||||
public class TeritoryResponse
|
||||
{
|
||||
public string CompanyCode { get; set; }
|
||||
public string SalesOrgCode { get; set; }
|
||||
public string RegionCode { get; set; }
|
||||
public string AreaCode { get; set; }
|
||||
public string TeritoryCode { get; set; }
|
||||
public string TeritoryName { get; set; }
|
||||
}
|
||||
|
||||
public class PlantResponse
|
||||
{
|
||||
public string CompanyCode { get; set; }
|
||||
public string SalesOrgCode { get; set; }
|
||||
public string PlantCode { get; set; }
|
||||
public string PlantName { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
public class GetBrandResponse
|
||||
{
|
||||
public string BrandCode { get; set; } = string.Empty;
|
||||
public string BrandName { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
|
||||
public class GetMaterialResponse
|
||||
{
|
||||
public string MaterialName { get; set; }
|
||||
public string MaterialCode { get; set; }
|
||||
public string TypeCode { get; set; }
|
||||
public string TypeName { get; set; }
|
||||
public string GroupCode { get; set; }
|
||||
public string GroupName { get; set; }
|
||||
public string BaseUnitMeasurement { get; set; }
|
||||
public string SalesUnitMeasurement { get; set; }
|
||||
public decimal UnitConversionValue { get; set; }
|
||||
public string BrandCode { get; set; }
|
||||
public string BrandName { get; set; }
|
||||
public string SalesOrg { get; set; }
|
||||
public bool IsSealable { get; set; } = true;
|
||||
}
|
||||
|
||||
public class GetMaterialPriceResponse
|
||||
{
|
||||
public string SalesOrgCode { get; set; }
|
||||
public string CustomerCode { get; set; }
|
||||
public string MaterialCode { get; set; }
|
||||
public decimal BasePrice { get; set; }
|
||||
public decimal? VatValue { get; set; }
|
||||
public string? VatCalculationType { get; set; }
|
||||
}
|
||||
|
||||
public class GetCustomerResponse
|
||||
{
|
||||
public string CustomerCode { get; set; }
|
||||
public string CustomerName { get; set; }
|
||||
public string AccountGroupCode { get; set; }
|
||||
public string AccountGroupDescription { get; set; }
|
||||
public string DistributionChannelCode { get; set; }
|
||||
public string DistributionChannelName { get; set; }
|
||||
public string DivisionCode { get; set; }
|
||||
public string DivisionName { get; set; }
|
||||
public string MobileNumber { get; set; }
|
||||
public string EmailAddress { get; set; }
|
||||
public string TaxNumber { get; set; }
|
||||
public string? SalesGroupCode { get; set; }
|
||||
public string? SalesGroupName { get; set; }
|
||||
public string? CustomerGroupCode { get; set; }
|
||||
public string? CustomerGroupName { get; set; }
|
||||
public string? CustomerPriceGroupCode { get; set; }
|
||||
public string? CustomerPriceGroupName { get; set; }
|
||||
public string? PaymentTermCode { get; set; }
|
||||
public string SalesOrgCode { get; set; }
|
||||
public string TeritoryCode { get; set; }
|
||||
public string PlantCode { get; set; }
|
||||
public bool IsCreditCustomer { get; set; }
|
||||
public decimal CreditLimit { get; set; }
|
||||
public decimal CreditBalance { get; set; }
|
||||
public decimal CreditAvailable => CreditLimit - CreditBalance;
|
||||
public decimal CreditOverdue { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class GetAttendanceByEmpResponse
|
||||
{
|
||||
public DateTime? AttendanceDate { get; set; }
|
||||
public string EmployeeNumber { get; set; }
|
||||
public TimeSpan? CheckInTime { get; set; }
|
||||
public string? CheckInLatitude { get; set; }
|
||||
public string? CheckInLongitude { get; set; }
|
||||
public string? CheckInLocationName { get; set; }
|
||||
public TimeSpan? CheckOutTime { get; set; }
|
||||
public string? CheckOutLatitude { get; set; }
|
||||
public string? CheckOutLongitude { get; set; }
|
||||
public string? CheckOutLocationName { get; set; }
|
||||
public bool? IsCheckIn => CheckInTime.HasValue ? true : false;
|
||||
public bool? IsCheckOut => CheckOutTime.HasValue ? true : false;
|
||||
}
|
||||
|
||||
public class GetDiscountResponse
|
||||
{
|
||||
public string? SalesOrgCode { get; set; }
|
||||
public string DiscountCode { get; set; }
|
||||
public string DiscountName { get; set; }
|
||||
public string? DistributorChannelCode { get; set; }
|
||||
public string? DistributorChannelName { get; set; }
|
||||
public DiscountTypeEnum DiscountType { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class GetDiscountMaterialResponse
|
||||
{
|
||||
public string DiscountCode { get; set; }
|
||||
public string CustomerCode { get; set; }
|
||||
public string SalesOrgCode { get; set; }
|
||||
public string TeritoryCode { get; set; }
|
||||
public string? MaterialCode { get; set; }
|
||||
public string UnitOfMeasurement { get; set; }
|
||||
public string CalculationType { get; set; }
|
||||
public decimal Threshold { get; set; }
|
||||
public decimal DiscountValue { get; set; }
|
||||
public DateTime StartDate { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
}
|
||||
|
||||
public class GetFOCResponse
|
||||
{
|
||||
public string? SalesOrgcCode { get; set; }
|
||||
public string FOCCode { get; set; }
|
||||
public string FOCName { get; set; }
|
||||
public string? DistributorChannelCode { get; set; }
|
||||
public string? DistributorChannelName { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class GetFOCMaterialResponse
|
||||
{
|
||||
public string FOCCode { get; set; }
|
||||
public string CustomerCode { get; set; }
|
||||
public string SalesOrgCode { get; set; }
|
||||
public string TeritoryCode { get; set; }
|
||||
public string MaterialCode { get; set; }
|
||||
public string? UnitOfMeasurement { get; set; }
|
||||
public decimal? MinimumOrderQty { get; set; }
|
||||
public decimal? ForQuantity { get; set; }
|
||||
public decimal? FreeQty { get; set; }
|
||||
public string? FOCUnitOfMeasurement { get; set; }
|
||||
public DateTime StartDate { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
}
|
||||
|
||||
|
||||
public class GetPaymentTermResponse
|
||||
{
|
||||
public int PaymentTermId { get; set; }
|
||||
public string PaymentTermCode { get; set; }
|
||||
public string PaymentTermDescription { get; set; }
|
||||
public string SalesOrgCode { get; set; }
|
||||
public DateTime StartDate { get; set; }
|
||||
public DateTime EndDate { get; set; }
|
||||
public string PaymentTermType { get; set; }
|
||||
}
|
||||
|
||||
public class GetMaterialStockReponse
|
||||
{
|
||||
public string PlantCode { get;set; }
|
||||
public string MaterialCode { get; set; }
|
||||
public decimal AvailableStock { get; set; }
|
||||
}
|
||||
|
||||
public class GetPasswordPolicyResponse
|
||||
{
|
||||
public int? MinLength { get; set; }
|
||||
public int? MaxLength { get; set; }
|
||||
public bool IsUppercase { get; set; }
|
||||
public bool IsLowercase { get; set; }
|
||||
public bool IsNumber { get; set; }
|
||||
public bool IsSpecialCharacter { get; set; }
|
||||
public int? PasswordLife { get; set; }
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
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 DateTime OrderDate { get; set; }
|
||||
public Guid UUID { get; set; }
|
||||
public bool IsNewOrder { get; set; }
|
||||
}
|
||||
|
||||
public class OrderBasicResponse
|
||||
{
|
||||
public int OrderId { get; set; }
|
||||
public string OrderNo { get; set; }
|
||||
public DateTime OrderDate { get; set; }
|
||||
public Guid UUID { get; set; }
|
||||
public OrderStatusEnum OrderStatus { get; set; }
|
||||
}
|
||||
|
||||
public class GetSalesOrderResponse
|
||||
{
|
||||
public int OrderId { get; set; }
|
||||
public Guid Uuid { get; set; }
|
||||
public string OrderNo { get; set; }
|
||||
public DateTime OrderDate { get; set; }
|
||||
public string SalesOrgCode { get; set; }
|
||||
public string CustomerCode { get; set; }
|
||||
public string CustomerName { get; set; }
|
||||
public string? ReferenceTxtNo { get; set; }
|
||||
public string EmployeeCode { get; set; }
|
||||
public DateTime? ExpectedDeliveryDate { 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? TotalVatValue { get; set; }
|
||||
public decimal NetValue { get; set; }
|
||||
public int OrderStatus { get; set; }
|
||||
public string BillingNumber { get; set; }
|
||||
public DateTime? BillingDate { get; set; }
|
||||
|
||||
public List<GetSalesOrderItemResponse> Items { get; set; } = new();
|
||||
}
|
||||
|
||||
public class GetSalesOrderItemResponse
|
||||
{
|
||||
public int OrderId { get; set; }
|
||||
public Guid UUID { get;set; }
|
||||
public string MaterialCode { get; set; }
|
||||
public string MaterialName { get; set; }
|
||||
public decimal UnitPrice { get; set; }
|
||||
public string SalesUnit { get; set; }
|
||||
public decimal? PromoQuantity { 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 decimal? VatValue { get; set; }
|
||||
public bool IsFocItem { 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; }
|
||||
}
|
||||
|
||||
|
||||
public sealed class UserRoleDto
|
||||
{
|
||||
public int UserId { get; set; }
|
||||
public UserRoleTypeEnum RoleId { get; set; }
|
||||
}
|
||||
|
||||
public sealed class CustomerLookupDto
|
||||
{
|
||||
public int CustomerId { get; set; }
|
||||
public string CustomerCode { get; set; } = string.Empty;
|
||||
public string CustomerName { get; set; } = string.Empty;
|
||||
public bool IsCreditCustomer { get; set; } = false;
|
||||
public string CompanyCode { get; set; }
|
||||
public decimal CreditLimit { get; set; }
|
||||
}
|
||||
|
||||
public sealed class PaymentTermLookupDto
|
||||
{
|
||||
public int PaymentTermId { get; set; }
|
||||
public string PaymentTermCode { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public sealed class DiscountLookupDto
|
||||
{
|
||||
public int DiscountId { get; set; }
|
||||
public string DiscountCode { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public sealed class MaterialLookupDto
|
||||
{
|
||||
public int MaterialId { get; set; }
|
||||
public string MaterialCode { get; set; } = string.Empty;
|
||||
public string MaterialName { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public sealed class FreeGoodsRuleDto
|
||||
{
|
||||
public int FreeGoodsId { get; set; }
|
||||
public int MaterialId { get; set; }
|
||||
public decimal MinOrderQuantity { get; set; }
|
||||
public decimal ForQuantity { get; set; }
|
||||
public decimal FreeQuantity { get; set; }
|
||||
public string UnitOfMeasure { get; set; } = string.Empty;
|
||||
public string FocUnitOfMeasure { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class GetOrderForSAPResponse
|
||||
{
|
||||
public GetOrderForSAPResponse()
|
||||
{
|
||||
to_Item = new List<GetOrderItemForSAPResponse>();
|
||||
}
|
||||
|
||||
public string SalesOrderType { get; set; }
|
||||
public string SalesOrganization { get; set; }
|
||||
public string DistributionChannel { get; set; }
|
||||
public string OrganizationDivision { get; set; }
|
||||
public string SoldToParty { get; set; }
|
||||
public string PurchaseOrderByCustomer { get; set; }
|
||||
public string CustomerPurchaseOrderDate { get; set; }
|
||||
public string PurchaseOrderByShipToParty { get; set; }
|
||||
public string CustomerPaymentTerms { get; set; }
|
||||
public string? CustomerGroup { get; set; }
|
||||
public string? CustomerPriceGroup { get; set; }
|
||||
public IList<GetOrderItemForSAPResponse> to_Item { get; set; }
|
||||
}
|
||||
|
||||
public class GetOrderItemForSAPResponse
|
||||
{
|
||||
public string Material { get; set; }
|
||||
public string RequestedQuantity { get; set; }
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
using OnlineSalesAutoCrop.CoreAPI.Models.Global;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Objects;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses
|
||||
{
|
||||
|
|
@ -12,7 +14,21 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses
|
|||
public List<string> ReturnMessage { get; set; } = [];
|
||||
}
|
||||
|
||||
public abstract class TotalRowsResponseBase : ResponseBase
|
||||
public class MobileResponseBase<T>
|
||||
{
|
||||
public int ReturnStatus { get; set; }
|
||||
public List<string> ReturnMessage { get; set; } = [];
|
||||
public T? Data { get; set; }
|
||||
|
||||
public static MobileResponseBase<T> Success(T data, string message = "Success") =>
|
||||
new() { ReturnStatus = 200, ReturnMessage = [message], Data = data };
|
||||
|
||||
public static MobileResponseBase<T> Failure(string message, int status = 400 ) =>
|
||||
new() { ReturnStatus = status, ReturnMessage = [message], Data = default };
|
||||
}
|
||||
|
||||
|
||||
public abstract class TotalRowsResponseBase : ResponseBase
|
||||
{
|
||||
public int TotalRows { get; set; }
|
||||
}
|
||||
|
|
@ -50,4 +66,15 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses
|
|||
{
|
||||
public List<FoundKeywordItem> FoundKeywords { get; set; }
|
||||
}
|
||||
|
||||
public class PagedResult<T>
|
||||
{
|
||||
public IList<T> Items { get; set; } = [];
|
||||
public int TotalCount { get; set; }
|
||||
public int PageNumber { get; set; } = 1;
|
||||
public int PageSize { get; set; } = 10000;
|
||||
public int TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize);
|
||||
public bool HasNextPage => PageNumber < TotalPages;
|
||||
public bool HasPreviousPage => PageNumber > 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -27,46 +27,28 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Systems
|
|||
public DateTime? Expires { get; set; }
|
||||
public DateTime SystemDate { get; set; }
|
||||
public string LoginTime { get; set; }
|
||||
public int LogId { get; set; }
|
||||
public DateTime? LogoutTime { get; private set; }
|
||||
public string MenuLayout { get; set; }
|
||||
public string ThemeName { get; set; }
|
||||
public string SchemeName { get; set; }
|
||||
public bool DbOnStartup { get; set; }
|
||||
public bool ViewOwnTaskOnly { get; private set; }
|
||||
public int? EmployeeId { get; private set; }
|
||||
public int NotificationCount { get; private set; }
|
||||
public int IdleTime { get; set; }
|
||||
public int PingTime { get; set; }
|
||||
public int TimeoutTime { get; set; }
|
||||
public bool BatchEnabled { get; private set; }
|
||||
public int BmProcessId { get; private set; }
|
||||
public int PrProcessId { get; private set; }
|
||||
public string IdsValue { get; set; }
|
||||
|
||||
//public List<string> ModuleIds { get; set; } = [];
|
||||
public List<string> ModuleIds { get; set; } = [];
|
||||
|
||||
public void Map(User source)
|
||||
public string RefreshToken { get;set; }
|
||||
public UserPlatFormType? UserPlatFormType { get; set; }
|
||||
public UserRoleTypeEnum? UserRoleType { get; set; }
|
||||
public string? EmployeeNumber { get; set; }
|
||||
|
||||
public void Map(User source)
|
||||
{
|
||||
Id = source.UserId;
|
||||
LoginId = source.LoginId;
|
||||
UserName = source.UserName;
|
||||
ThemeName = source.ThemeName;
|
||||
//ModuleIds = source.ModuleIds;
|
||||
ModuleIds = source.ModuleIds;
|
||||
LogoutTime = source.LogoutTime;
|
||||
SchemeName = source.SchemeName;
|
||||
MenuLayout = source.MenuLayout;
|
||||
LoginStatus = source.LoginStatus;
|
||||
//DbOnStartup = source.DbOnStartup;
|
||||
//TimeoutTime = source.TimeoutTime;
|
||||
//BmProcessId = source.BmProcessId;
|
||||
//PrProcessId = source.PrProcessId;
|
||||
//BatchEnabled = source.BatchEnabled;
|
||||
//ViewOwnTaskOnly = source.ViewOwnTaskOnly;
|
||||
//NotificationCount = source.NotificationCount;
|
||||
//AuthRequiredAtLogin = source.AuthRequiredAtLogin;
|
||||
//IdsValue = Newtonsoft.Json.JsonConvert.SerializeObject(source.ModuleIds);
|
||||
}
|
||||
UserPlatFormType = source.UserPlatFormType;
|
||||
UserRoleType = source.UserRoleType;
|
||||
EmployeeNumber = source.EmployeeNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public class MenuResponse
|
||||
|
|
@ -142,4 +124,22 @@ namespace OnlineSalesAutoCrop.CoreAPI.Models.Responses.Systems
|
|||
public string LoginId { get; set; }
|
||||
public decimal Value { get; set; }
|
||||
}
|
||||
|
||||
public class BulkPasswordUploadItem
|
||||
{
|
||||
public int RowNo { get; set; }
|
||||
public int UserId { get; set; }
|
||||
public string EmployeeCode { get; set; }
|
||||
public string LoginId { get; set; }
|
||||
public bool Updated { get; set; }
|
||||
public string Message { get; set; }
|
||||
}
|
||||
|
||||
public class BulkPasswordUploadResponse : ResponseBase
|
||||
{
|
||||
public int TotalRows { get; set; }
|
||||
public int SuccessCount { get; set; }
|
||||
public int FailedCount { get; set; }
|
||||
public List<BulkPasswordUploadItem> Items { get; set; } = [];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
using Ease.NetCore.DataAccess;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -9,4 +10,5 @@ public interface IRefreshTokenService
|
|||
Task<GenerateRefreshTokenResponse> GenerateRefreshTokenByUserAsync(GenerateRefreshTokenRequest request);
|
||||
Task<string> GenerateRefreshTokenAsync(string refreshToken, string ipAddress);
|
||||
Task<UserByRefreshTokenResponse> GetUserByRefreshTokenAsync(string refreshToken);
|
||||
Task<bool> InvalidRefreshTokenAsync(TransactionContext tc, int userId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
using Hangfire;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Services.Contracts.BackgroupJobs;
|
||||
|
||||
public interface IBackgroundJobService
|
||||
{
|
||||
[Queue("sap_order_send")]
|
||||
[DisableConcurrentExecution(timeoutInSeconds: 40 * 60)]
|
||||
Task ExecuteSendingOrderAsync(CancellationToken cancellationToken);
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations;
|
||||
|
||||
public interface IIntegrationHttpService
|
||||
{
|
||||
Task<IntegrationCustLedgerHttpResponse?> GetCustomerLedgerAsync(string customerNumber, string companyCode,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<IList<IntegrationMaterialStockHttpResponse>> GetMaterialStockAsync(string plantCode,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
Task<Tuple<string, string>> SendSAPOrdersAsync(GetOrderForSAPResponse request,
|
||||
CancellationToken cancellationToken = default);
|
||||
|
||||
}
|
||||
|
|
@ -8,14 +8,31 @@ namespace OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations;
|
|||
public interface IIntegrationService
|
||||
{
|
||||
//Customer
|
||||
Task<CustomerIntegrationResponse> UpsertCustomerAsync(CustomerIntegrationRequest request);
|
||||
Task<IntegrationCustomerResponse> UpsertCustomerAsync(IntegrationCustomerRequest request);
|
||||
Task<CustomerByCompanyCodeResponse> GetCustomerByCompanyCodeAsync(CustomerByCompanyCodeRequest request);
|
||||
|
||||
//Employee
|
||||
Task<EmployeeIntegrationReqResponse> UpsertEmployeeAsync(EmployeeIntegrationRequest request);
|
||||
Task<EmployeeIntegrationResponse> GetEmployeeBySalesOrgAsync(EmployeeIntegrationByComapanyRequest request);
|
||||
Task<EmployeeIntegrationReqResponse> UpsertEmployeeAsync(IntegrationEmployeeRequest request);
|
||||
Task<IntegrationEmployeeResponse> GetEmployeeBySalesOrgAsync(EmployeeIntegrationByComapanyRequest request);
|
||||
|
||||
//Meterial
|
||||
Task<MaterialIntegrationReqResponse > UpsertMaterialAsync(MaterialIntegrationRequest request);
|
||||
Task<MaterialIntegrationResponse> GetMaterialByCodeAsync(GetMaterialByCodeRequest request);
|
||||
//Material
|
||||
Task<MaterialIntegrationReqResponse > UpsertMaterialAsync(IntegrationMaterialRequest request);
|
||||
Task<IntegrationMaterialResponse> GetMaterialByCodeAsync(GetMaterialByCodeRequest request);
|
||||
|
||||
|
||||
//Material Price
|
||||
Task<MaterialIntegrationPriceReqResponse> UpsertMaterialPriceAsync(IntegrationMaterialPriceRequest request);
|
||||
Task<IntegrationMaterialPriceResponse> GetMaterialPriceByCodeAsync( GetMaterialPriceByCodeRequest request);
|
||||
|
||||
//Material Free Goods
|
||||
Task<MaterialFreeGoodsByReqResponse> UpsertMaterialFreeGoodsAsync(IntegrationMaterialFreeGoodsRequest request);
|
||||
Task<IntegrationMaterialFreeGoodsResponse> GetMaterialFreeGoodseByFilterAsync(GetMaterialFreeGoodsByFilterRequest request);
|
||||
|
||||
//Payment Terms
|
||||
Task<IntegrationPaymentTermReqResponse> UpsertPaymentTermsAsync(IntegrationPaymentTermRequest request);
|
||||
Task<IntegrationPaymentTermResponse> GetPaymentTermsByFilterAsync(GetIntegrationPaymentTermRequest request);
|
||||
|
||||
//Invoices
|
||||
Task<IntegrationBillingReqResponse> SaveBillingDocumentAsync(IntegrationBillingDocumentRequest request);
|
||||
Task<IntegrationDeliveryReqResponse> SaveDeliveryInvoiceDocumentAsync(IntegrationDeliveryDocumentRequest request);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Services.Contracts.MobileApp;
|
||||
|
||||
public interface IMobileMasterDataService
|
||||
{
|
||||
Task<MarketHeirarchyByEmpResponse> GetMarketHeirarchiesByEmpAsync(GetMarketHeirarchyByEmpRequest request);
|
||||
Task<PagedResult<GetBrandResponse>> GetBrandsAsync(GetBrandsRequest request);
|
||||
Task<PagedResult<GetMaterialResponse>> GetMaterialsAsync(GetMaterialsRequest request);
|
||||
Task<PagedResult<GetMaterialStockReponse>> GetMaterialsStockAsync(GetMaterialStockRequest request);
|
||||
Task<PagedResult<GetMaterialPriceResponse>> GetMaterialPricesAsync(GetMaterialPriceRequest request);
|
||||
Task<PagedResult<GetCustomerResponse>> GetCustomersAsync(GetCustomersRequest request);
|
||||
Task<GetAttendanceByEmpResponse> GetAttendanceByEmpAsync(GetAttendanceByEmpRequest request);
|
||||
Task<GetAttendanceByEmpResponse> UpsertAttendanceByEmpAsync(UpsertAttendanceByEmpRequest request);
|
||||
Task<PagedResult<GetDiscountResponse>> GetDiscountAsync(GetDiscountRequest request);
|
||||
Task<PagedResult<GetDiscountMaterialResponse>> GetDiscountMaterialsAsync(GetDiscountMaterialRequest request);
|
||||
Task<PagedResult<GetFOCResponse>> GetFOCsAsync(GetFOCRequest request);
|
||||
Task<PagedResult<GetFOCMaterialResponse>> GetFOCMaterialsAsync(GetFOCMaterialRequest request);
|
||||
Task<PagedResult<GetPaymentTermResponse>> GetPaymentTermsAsync(GetPaymentTermRequest request);
|
||||
Task<GetPasswordPolicyResponse> GetPasswordPolicyAsync();
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
using OnlineSalesAutoCrop.CoreAPI.Models;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Services.Contracts.MobileApp;
|
||||
|
||||
public interface IOrderService
|
||||
{
|
||||
Task<SaveOrderResponse> SaveOrderAsync(SaveOrderRequest request, int userId);
|
||||
Task<PagedResult<GetSalesOrderResponse>> GetSalesOrdersSummary(GetOrderSummaryRequest request, int userId);
|
||||
Task<IList<int>> GetAvailableOrderIdsForSAPAsync(SAPOrderStatusEnum orderStaus, CancellationToken cancellationToken = default);
|
||||
Task<GetOrderForSAPResponse?> GetOrderDetailsForSapByIdAsync(int orderId, CancellationToken cancellationToken = default);
|
||||
Task<bool> UpdateSendingSapDetailsAsync(UpdateSapDetailsRequest request, CancellationToken cancellationToken = default);
|
||||
|
||||
}
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Setups;
|
||||
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.Requests.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Systems;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
|
@ -13,10 +16,14 @@ namespace OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems
|
|||
{
|
||||
Task<bool> ValidateAuthValueAsync(string authValue, int userId);
|
||||
Task<User> LoginAsync(LoginRequest request, string ipAddress, bool checkPwd);
|
||||
Task<AppAuthUserResponse> LoginAsync(MobileAppAuthRequest request, string ipAddress);
|
||||
Task<User> IntegrationLoginAsync(IntegrationLoginRequest request, string ipAddress, bool checkPwd);
|
||||
|
||||
Task<bool> LogoutAsync(string ipAddress, int userId, int logId, bool attendanceLogout, string loginId, string localIp, string macAddress, string hostName, string logoutRemarks);
|
||||
|
||||
Task<AuthLogoutResponse> LogoutAsync(AuthLogoutRequest request, string ipAddress);
|
||||
Task<AppChangePasswordResponse> ChangePasswordAsync(AppUserChangePasswordRequest request, string ipAddress);
|
||||
|
||||
Task<bool> DeleteUserAsync(int userId, int deletedBy);
|
||||
Task<bool> ForceLogoutNowAsync(List<int> userIds, string ipAddress);
|
||||
Task<bool> UnlockUserAsync(int userId, string loginId, int unlockedBy);
|
||||
|
|
@ -25,6 +32,7 @@ namespace OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems
|
|||
Task<bool> AddUserAsync(NewUserRequest user, string ipAddress, int createdBy);
|
||||
Task<bool> UpdateMyInfoAsync(string address, string contactNo, int modifiedBy, int emplyeeId);
|
||||
Task<bool> ResetPasswordAsync(int userId, string newPassword, string ipAddress, int changedBy);
|
||||
Task<BulkPasswordUploadResponse> UpdatePasswordsFromExcelAsync(string fileSpec, string ipAddress, int changedBy, bool forcePasswordChange);
|
||||
Task<bool> UpdateMyThemeAsync(int userId, string menuLayout, string themeName, string schemeName);
|
||||
Task<bool> SaveAuthorizeLimitAsync(decimal maxAuthLimit, int userId, string ipAddress, string savedBy);
|
||||
Task<bool> UploadDocumentAsync(int userId, int id, int documentOf, string orgFileName, string fileName);
|
||||
|
|
|
|||
|
|
@ -96,6 +96,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ease.NetCore" Version="2.1.4" />
|
||||
<PackageReference Include="Hangfire.Core" Version="1.8.24" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.0.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="10.0.8" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.9.1" />
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using Ease.NetCore.DataAccess.SQL;
|
|||
using Microsoft.Data.SqlClient;
|
||||
using Microsoft.Extensions.Options;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Global;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Auth;
|
||||
|
|
@ -116,6 +117,22 @@ public class RefreshTokenService : IRefreshTokenService
|
|||
return refreshTokenResponse;
|
||||
}
|
||||
|
||||
public async Task<bool> InvalidRefreshTokenAsync( TransactionContext tc, int userId)
|
||||
{
|
||||
bool response = false;
|
||||
try
|
||||
{
|
||||
RevokeRefreshTokenByUserIdAsync(tc, userId);
|
||||
response = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidOperationException(e.Message, e);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
#region Private Methods
|
||||
// ----- private helpers -----
|
||||
|
||||
|
|
@ -145,7 +162,7 @@ public class RefreshTokenService : IRefreshTokenService
|
|||
SqlHelperExtension.CreateInParam(pName: "@TokenHash", pType: SqlDbType.VarChar, pValue: refreshToken.TokenHash),
|
||||
SqlHelperExtension.CreateInParam(pName: "@IpAddress", pType: SqlDbType.VarChar, pValue: refreshToken.IpAddress),
|
||||
SqlHelperExtension.CreateInParam(pName: "@CreatedAt", pType: SqlDbType.DateTime, pValue: DateTime.Now),
|
||||
SqlHelperExtension.CreateInParam(pName: "@ExpiredAt", pType: SqlDbType.DateTime, pValue: DateTime.Now.AddMinutes(_settings.RefreshTokenDuration)),
|
||||
SqlHelperExtension.CreateInParam(pName: "@ExpiredAt", pType: SqlDbType.DateTime, pValue: refreshToken.ExpiresAt),
|
||||
];
|
||||
_ = tc.ExecuteNonQuerySp(spName: "dbo.InsertRefreshToken", parameterValues: p);
|
||||
|
||||
|
|
@ -250,8 +267,8 @@ public class RefreshTokenService : IRefreshTokenService
|
|||
UserId = userId,
|
||||
TokenHash = tokenHash,
|
||||
IpAddress = ipAddress,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
ExpiresAt = DateTime.UtcNow.AddDays(_settings.RefreshTokenDuration)
|
||||
CreatedAt = DateTime.Now,
|
||||
ExpiresAt = DateTime.Now.AddMinutes(_settings.RefreshTokenDuration)
|
||||
};
|
||||
|
||||
AddAsync(tc,refreshToken);
|
||||
|
|
@ -259,7 +276,7 @@ public class RefreshTokenService : IRefreshTokenService
|
|||
return new GenerateRefreshTokenResponse
|
||||
{
|
||||
RefreshToken = tokenHash,
|
||||
ExpireTime = DateTime.UtcNow.AddMinutes(_settings.RefreshTokenDuration)
|
||||
ExpireTime = DateTime.Now.AddMinutes(_settings.RefreshTokenDuration)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -277,5 +294,7 @@ public class RefreshTokenService : IRefreshTokenService
|
|||
return Convert.ToBase64String(bytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,75 @@
|
|||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.MobileApp;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.BackgroupJobs;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.MobileApp;
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Services.Services.BackgroupJobs;
|
||||
|
||||
public class BackgroundJobService : IBackgroundJobService
|
||||
{
|
||||
private readonly IIntegrationHttpService _httpService;
|
||||
private readonly IOrderService _orderService;
|
||||
private readonly ILogger<BackgroundJobService> _logger;
|
||||
|
||||
public BackgroundJobService(IIntegrationHttpService httpService, IOrderService orderService, ILogger<BackgroundJobService> logger)
|
||||
{
|
||||
_httpService = httpService;
|
||||
_orderService = orderService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task ExecuteSendingOrderAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_logger.LogInformation("SendingOrder Job successfully run at: " + DateTime.Now.ToString());
|
||||
try
|
||||
{
|
||||
var pendingOrderIds = await _orderService.GetAvailableOrderIdsForSAPAsync(SAPOrderStatusEnum.Pending);
|
||||
foreach (var item in pendingOrderIds)
|
||||
{
|
||||
var orderDetails = await _orderService.GetOrderDetailsForSapByIdAsync(item);
|
||||
_logger.LogInformation("SendingOrder for Order No with: " + orderDetails.PurchaseOrderByCustomer);
|
||||
|
||||
var httpResponse = await _httpService.SendSAPOrdersAsync(orderDetails);
|
||||
if(string.IsNullOrEmpty( httpResponse.Item2))
|
||||
{
|
||||
await _orderService.UpdateSendingSapDetailsAsync(new UpdateSapDetailsRequest
|
||||
{
|
||||
OrderId = item,
|
||||
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)
|
||||
{
|
||||
_logger.LogError("Exception Occur in ExecuteSendingOrder "+ ex.Message);
|
||||
throw;
|
||||
}
|
||||
|
||||
_logger.LogInformation("SendingOrder Job successfully finished at: " + DateTime.Now.ToString());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.MobileApp;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Services.Services.Integrations;
|
||||
|
||||
public class IntegrationHttpService : IIntegrationHttpService
|
||||
{
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILogger<IntegrationHttpService> _logger;
|
||||
|
||||
public IntegrationHttpService(HttpClient httpClient, ILogger<IntegrationHttpService> logger)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task<IntegrationCustLedgerHttpResponse> GetCustomerLedgerAsync(string customerNumber, string companyCode, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var requestUri = $"http/get_customer_ledger?customer={Uri.EscapeDataString(customerNumber)}&company={Uri.EscapeDataString(companyCode)}";
|
||||
|
||||
var response = await _httpClient.GetAsync(requestUri, cancellationToken);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var body = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
_logger.LogError("Customer ledger call failed: {StatusCode} — {Body}", response.StatusCode, body);
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
var payload= await response.Content.ReadFromJsonAsync< SapODataResponse<IntegrationCustLedgerHttpResponse>>(cancellationToken: cancellationToken);
|
||||
|
||||
return payload?.D.Results.FirstOrDefault();
|
||||
}
|
||||
catch(Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<IList<IntegrationMaterialStockHttpResponse>> GetMaterialStockAsync(string plantCode, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var requestUri = $"http/get_plantwise_available_stocks?plant={Uri.EscapeDataString(plantCode)}";
|
||||
|
||||
var response = await _httpClient.GetAsync(requestUri, cancellationToken);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
var body = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
_logger.LogError("Material Stock call failed: {StatusCode} — {Body}", response.StatusCode, body);
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
|
||||
var payload = await response.Content.ReadFromJsonAsync<SapODataResponse<IntegrationMaterialStockHttpResponse>>(cancellationToken: cancellationToken);
|
||||
|
||||
return payload?.D.Results;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<Tuple<string,string>> SendSAPOrdersAsync(GetOrderForSAPResponse request, CancellationToken cancellationToken = default)
|
||||
{
|
||||
try
|
||||
{
|
||||
var requestUri = "http/sales_order";
|
||||
|
||||
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)
|
||||
{
|
||||
var body = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
_logger.LogError("Save Orders call failed: {StatusCode} — {Body}", response.StatusCode, body);
|
||||
return new Tuple<string, string>(body, string.Empty);
|
||||
}
|
||||
|
||||
var responseString = await response.Content.ReadAsStringAsync(cancellationToken);
|
||||
|
||||
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)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,10 +1,15 @@
|
|||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Hangfire;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Auth;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.BackgroupJobs;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.MobileApp;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Setups;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Services.Auth;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Services.BackgroupJobs;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Services.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Services.MobileApp;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Services.Setups;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Services.Systems;
|
||||
|
||||
|
|
@ -23,14 +28,16 @@ namespace OnlineSalesAutoCrop.CoreAPI.Configuration.DI
|
|||
{
|
||||
if (services == null)
|
||||
return;
|
||||
|
||||
services.AddSingleton<IEaseCache, EaseCache>();
|
||||
services.AddSingleton<IEaseCache, EaseCache>();
|
||||
services.AddTransient<IUserService, UserService>();
|
||||
services.AddTransient<IParamTypeService, ParamTypeService>();
|
||||
services.AddTransient<IThisSystemService, ThisSystemService>();
|
||||
services.AddTransient<IAuthModulesService, AuthModulesService>();
|
||||
services.AddTransient<IRefreshTokenService, RefreshTokenService>();
|
||||
services.AddScoped<IIntegrationService, IntegrationService>();
|
||||
services.AddScoped<IMobileMasterDataService, MobileMasterDataService>();
|
||||
services.AddScoped<IBackgroundJobService, BackgroundJobService>();
|
||||
services.AddScoped<IOrderService, OrderService>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.DirectoryServices;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.IO;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
|
|
@ -230,7 +231,7 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers
|
|||
loginReponse.AccessToken = userToken;
|
||||
loginReponse.RefreshToken = refreshToken.RefreshToken;
|
||||
loginReponse.AccessTokenExpiry = refreshToken.ExpireTime;
|
||||
return StatusCode(StatusCodes.Status431RequestHeaderFieldsTooLarge, loginReponse);
|
||||
return StatusCode(StatusCodes.Status200OK, loginReponse);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -295,7 +296,7 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers
|
|||
response.AccessToken = userToken;
|
||||
response.RefreshToken = refreshToken;
|
||||
|
||||
return StatusCode(StatusCodes.Status431RequestHeaderFieldsTooLarge, response);
|
||||
return StatusCode(StatusCodes.Status200OK, response);
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
|
@ -309,6 +310,25 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers
|
|||
return Ok();
|
||||
}
|
||||
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpGet("download")]
|
||||
public IActionResult Download()
|
||||
{
|
||||
string fileName = "AutoCropCare.apk";
|
||||
var filePath = Path.Combine(@"D:\Local", fileName);
|
||||
|
||||
if (!System.IO.File.Exists(filePath))
|
||||
return NotFound();
|
||||
|
||||
return PhysicalFile(
|
||||
filePath,
|
||||
"application/octet-stream",
|
||||
fileName,
|
||||
enableRangeProcessing: true
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
|
@ -0,0 +1,358 @@
|
|||
using Asp.Versioning;
|
||||
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;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="integrationService"></param>
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[Route("api/v{version:apiVersion}/Integration")]
|
||||
public class IntegrationController(ILogger<IntegrationAuthController> logger, IIntegrationService integrationService) : ControllerBase
|
||||
{
|
||||
|
||||
private readonly ILogger _logger = logger;
|
||||
private readonly IIntegrationService _integrationService = integrationService;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Insert or Update Customers for SAP
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>if created return 201 or if updated return 200 true</returns>
|
||||
[HttpPost("Customers")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IntegrationLoginResponse))]
|
||||
public async Task<IActionResult> UpsertCustomers(IntegrationCustomerRequest request)
|
||||
{
|
||||
IntegrationCustomerResponse response = new IntegrationCustomerResponse();
|
||||
try
|
||||
{
|
||||
response = await _integrationService.UpsertCustomerAsync(request);
|
||||
if (!response.IsUpdated)
|
||||
{
|
||||
response.ReturnMessage.Add($"Customer Created Successfully for CustomerNumber :{request.CustomerNumber} & CompanyCode:{request.CompanyCode}");
|
||||
response.ReturnStatus = StatusCodes.Status201Created;
|
||||
return StatusCode(StatusCodes.Status201Created, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ReturnMessage.Add($"Customer Updated Successfully for CustomerNumber :{request.CustomerNumber} & CompanyCode:{request.CompanyCode}");
|
||||
response.ReturnStatus = StatusCodes.Status200OK;
|
||||
return StatusCode(StatusCodes.Status200OK, response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception Occur in Customer Operation {request?.CustomerName}~{request?.CompanyCode}";
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert or Update Employees for SAP
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>if created return 201 or if updated return 200 true</returns>
|
||||
[HttpPost("Employees")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(EmployeeIntegrationReqResponse))]
|
||||
public async Task<IActionResult> UpsertEmployee(IntegrationEmployeeRequest request)
|
||||
{
|
||||
EmployeeIntegrationReqResponse response = new EmployeeIntegrationReqResponse();
|
||||
try
|
||||
{
|
||||
response = await _integrationService.UpsertEmployeeAsync(request);
|
||||
if (!response.IsUpdated)
|
||||
{
|
||||
response.ReturnMessage.Add($"Employee Created Successfully for EmployeeVendorName :{request.EmployeeVendorName} & SalesOrgCode:{request.CompanyCode}");
|
||||
response.ReturnStatus = StatusCodes.Status201Created;
|
||||
return StatusCode(StatusCodes.Status201Created, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ReturnMessage.Add($"Employee Updated Successfully for EmployeeVendorName :{request.EmployeeVendorName} & SalesOrgCode:{request.CompanyCode}");
|
||||
response.ReturnStatus = StatusCodes.Status200OK;
|
||||
return StatusCode(StatusCodes.Status200OK, response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception Occur in Employee Operation {request?.EmployeeVendorName}~{request?.CompanyCode}";
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Insert or Update Material for SAP
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>if created return 201 or if updated return 200 true</returns>
|
||||
[HttpPost("Materials")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(MaterialIntegrationReqResponse))]
|
||||
[ProducesResponseType(StatusCodes.Status201Created, Type = typeof(MaterialIntegrationReqResponse))]
|
||||
public async Task<IActionResult> UpsertMeterial(IntegrationMaterialRequest request)
|
||||
{
|
||||
MaterialIntegrationReqResponse response = new MaterialIntegrationReqResponse();
|
||||
try
|
||||
{
|
||||
response = await _integrationService.UpsertMaterialAsync(request);
|
||||
if (!response.IsUpdated)
|
||||
{
|
||||
response.ReturnMessage.Add($"Material Created Successfully for MaterialCode :{request.MaterialCode} ");
|
||||
response.ReturnStatus = StatusCodes.Status201Created;
|
||||
return StatusCode(StatusCodes.Status201Created, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ReturnMessage.Add($"Material Updated Successfully for MaterialCode :{request.MaterialCode} ");
|
||||
response.ReturnStatus = StatusCodes.Status200OK;
|
||||
return StatusCode(StatusCodes.Status200OK, response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception Occur in Material Operation {request?.MaterialCode}";
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert or Update Material Prices for SAP
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>if created return 201 or if updated return 200 true</returns>
|
||||
[HttpPost("MaterialPrices")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(MaterialIntegrationPriceReqResponse))]
|
||||
[ProducesResponseType(StatusCodes.Status201Created, Type = typeof(MaterialIntegrationPriceReqResponse))]
|
||||
public async Task<IActionResult> UpsertMeterialPrices(IntegrationMaterialPriceRequest request)
|
||||
{
|
||||
MaterialIntegrationPriceReqResponse response = new MaterialIntegrationPriceReqResponse();
|
||||
try
|
||||
{
|
||||
response = await _integrationService.UpsertMaterialPriceAsync(request);
|
||||
if (!response.IsUpdated)
|
||||
{
|
||||
response.ReturnMessage.Add($"Material Price Created Successfully for MaterialCode :{request.MaterialCode} And ConditionType : {request.ConditionType}" +
|
||||
$"And Customer Number : {request.CustomerNumber} And Customer Group Code : {request.CustomerGroupCode} ");
|
||||
response.ReturnStatus = StatusCodes.Status201Created;
|
||||
return StatusCode(StatusCodes.Status201Created, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ReturnMessage.Add($"Material Price Updated Successfully for MaterialCode :{request.MaterialCode} And ConditionType : {request.ConditionType}" +
|
||||
$"And Customer Number : {request.CustomerNumber} And Customer Group Code : {request.CustomerGroupCode} ");
|
||||
response.ReturnStatus = StatusCodes.Status200OK;
|
||||
return StatusCode(StatusCodes.Status200OK, response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception Occur in Material Price Operation MaterialCode :{request.MaterialCode} And ConditionType : {request.ConditionType}" +
|
||||
$"And Customer Number : {request.CustomerNumber} And Customer Group Code : {request.CustomerGroupCode} ";
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert or Update Material Prices for SAP
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>if created return 201 or if updated return 200 true</returns>
|
||||
[HttpPost("MaterialFreeGoods")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(MaterialFreeGoodsByReqResponse))]
|
||||
[ProducesResponseType(StatusCodes.Status201Created, Type = typeof(MaterialFreeGoodsByReqResponse))]
|
||||
public async Task<IActionResult> UpsertMaterialFreeGoods(IntegrationMaterialFreeGoodsRequest request)
|
||||
{
|
||||
MaterialFreeGoodsByReqResponse response = new MaterialFreeGoodsByReqResponse();
|
||||
try
|
||||
{
|
||||
if(request.Slabs == null || request.Slabs?.Count==0)
|
||||
{
|
||||
response.ReturnMessage.Add($"At least one slab must be sent.");
|
||||
response.ReturnStatus = StatusCodes.Status400BadRequest;
|
||||
return StatusCode(StatusCodes.Status400BadRequest, response);
|
||||
}
|
||||
response = await _integrationService.UpsertMaterialFreeGoodsAsync(request);
|
||||
if (!response.IsUpdated)
|
||||
{
|
||||
response.ReturnMessage.Add($"Material Free Goods Created Successfully for SalesOrg :{request.SalesOrg} " +
|
||||
$"And CustomerPriceGroup : {request.CustomerPriceGroup} And MaterialCode : {request.MaterialCode} And DistributorChannel : {request.DistributionChannel}" +
|
||||
$" And Customer Number :{request.CustomerNumber} And Customer Price Group : {request.CustomerPriceGroup}");
|
||||
response.ReturnStatus = StatusCodes.Status201Created;
|
||||
return StatusCode(StatusCodes.Status201Created, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ReturnMessage.Add($"Material Free Goods Updated Successfully for SalesOrg :{request.SalesOrg} " +
|
||||
$"And CustomerPriceGroup : {request.CustomerPriceGroup} And MaterialCode : {request.MaterialCode} And DistributorChannel : {request.DistributionChannel}" +
|
||||
$" And Customer Number :{request.CustomerNumber} And Customer Price Group : {request.CustomerPriceGroup}");
|
||||
response.ReturnStatus = StatusCodes.Status200OK;
|
||||
return StatusCode(StatusCodes.Status200OK, response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception Occur in Material Free Goods Operation SalesOrg :{request.SalesOrg} " +
|
||||
$" And CustomerPriceGroup : {request.CustomerPriceGroup} And MaterialCode : {request.MaterialCode} And DistributorChannel : {request.DistributionChannel}" +
|
||||
$" And Customer Number :{request.CustomerNumber} And Customer Price Group : {request.CustomerPriceGroup}";
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert or Update Payment Terms for SAP
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>if created return 201 or if updated return 200 true</returns>
|
||||
[HttpPost("PaymentTerms")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IntegrationPaymentTermReqResponse))]
|
||||
[ProducesResponseType(StatusCodes.Status201Created, Type = typeof(IntegrationPaymentTermReqResponse))]
|
||||
public async Task<IActionResult> UpsertPaymentTerms(IntegrationPaymentTermRequest request)
|
||||
{
|
||||
IntegrationPaymentTermReqResponse response = new IntegrationPaymentTermReqResponse();
|
||||
try
|
||||
{
|
||||
response = await _integrationService.UpsertPaymentTermsAsync(request);
|
||||
if (!response.IsUpdated)
|
||||
{
|
||||
response.ReturnMessage.Add($"Payment Terms Created Successfully for SalesOrg :{request.SalesOrg} " +
|
||||
$"And CreditCode : {request.CreditCode} ");
|
||||
response.ReturnStatus = StatusCodes.Status201Created;
|
||||
return StatusCode(StatusCodes.Status201Created, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ReturnMessage.Add($"Payment Terms Updated Successfully for SalesOrg :{request.SalesOrg} " +
|
||||
$"And CreditCode : {request.CreditCode} ");
|
||||
response.ReturnStatus = StatusCodes.Status200OK;
|
||||
return StatusCode(StatusCodes.Status200OK, response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception Occur in Payment Terms for SalesOrg :{request.SalesOrg} " +
|
||||
$"And CreditCode : {request.CreditCode} ";
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert Deliveries for SAP
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>if created return 201 or if updated return 200 true</returns>
|
||||
[HttpPost("Deliveries")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IntegrationDeliveryReqResponse))]
|
||||
[ProducesResponseType(StatusCodes.Status201Created, Type = typeof(IntegrationDeliveryReqResponse))]
|
||||
public async Task<IActionResult> SaveDeliveries(IntegrationDeliveryDocumentRequest request)
|
||||
{
|
||||
IntegrationDeliveryReqResponse response = new IntegrationDeliveryReqResponse();
|
||||
try
|
||||
{
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert Deliveries for SAP
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>if created return 201 or if updated return 200 true</returns>
|
||||
[HttpPost("Billing")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IntegrationBillingReqResponse))]
|
||||
[ProducesResponseType(StatusCodes.Status201Created, Type = typeof(IntegrationBillingReqResponse))]
|
||||
public async Task<IActionResult> 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.BillingDocumentNumber} " +
|
||||
$"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.BillingDocumentNumber} " +
|
||||
$"And BillingDate : {request.BillingDate} ";
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,153 +0,0 @@
|
|||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Controllers.IntegretionApi
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="integrationService"></param>
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[Route("api/v{version:apiVersion}/Integration")]
|
||||
public class IntegrationController(ILogger<IntegrationAuthController> logger, IIntegrationService integrationService) : ControllerBase
|
||||
{
|
||||
|
||||
private readonly ILogger _logger = logger;
|
||||
private readonly IIntegrationService _integrationService = integrationService;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Insert or Update Customers for SAP
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>if created return 201 or if updated return 200 true</returns>
|
||||
[HttpPost("Customers")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(IntegrationLoginResponse))]
|
||||
public async Task<IActionResult> UpsertCustomers(CustomerIntegrationRequest request)
|
||||
{
|
||||
CustomerIntegrationResponse response = new CustomerIntegrationResponse();
|
||||
try
|
||||
{
|
||||
response = await _integrationService.UpsertCustomerAsync(request);
|
||||
if (!response.IsUpdated)
|
||||
{
|
||||
response.ReturnMessage.Add($"Customer Created Successfully for CustomerNumber :{request.CustomerNumber} & CompanyCode:{request.CompanyCode}");
|
||||
response.ReturnStatus = StatusCodes.Status201Created;
|
||||
return StatusCode(StatusCodes.Status201Created, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ReturnMessage.Add($"Customer Updated Successfully for CustomerNumber :{request.CustomerNumber} & CompanyCode:{request.CompanyCode}");
|
||||
response.ReturnStatus = StatusCodes.Status200OK;
|
||||
return StatusCode(StatusCodes.Status200OK, response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception Occur in Customer Operation {request?.CustomerName}~{request?.CompanyCode}";
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert or Update Employees for SAP
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>if created return 201 or if updated return 200 true</returns>
|
||||
[HttpPost("Employees")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(EmployeeIntegrationReqResponse))]
|
||||
public async Task<IActionResult> UpsertEmployee(EmployeeIntegrationRequest request)
|
||||
{
|
||||
EmployeeIntegrationReqResponse response = new EmployeeIntegrationReqResponse();
|
||||
try
|
||||
{
|
||||
response = await _integrationService.UpsertEmployeeAsync(request);
|
||||
if (!response.IsUpdated)
|
||||
{
|
||||
response.ReturnMessage.Add($"Employee Created Successfully for EmployeeVendorName :{request.EmployeeVendorName} & SalesOrgCode:{request.CompanyCode}");
|
||||
response.ReturnStatus = StatusCodes.Status201Created;
|
||||
return StatusCode(StatusCodes.Status201Created, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ReturnMessage.Add($"Employee Updated Successfully for EmployeeVendorName :{request.EmployeeVendorName} & SalesOrgCode:{request.CompanyCode}");
|
||||
response.ReturnStatus = StatusCodes.Status200OK;
|
||||
return StatusCode(StatusCodes.Status200OK, response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception Occur in Employee Operation {request?.EmployeeVendorName}~{request?.CompanyCode}";
|
||||
_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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Insert or Update Material for SAP
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>if created return 201 or if updated return 200 true</returns>
|
||||
[HttpPost("Materials")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(MaterialIntegrationReqResponse))]
|
||||
[ProducesResponseType(StatusCodes.Status201Created, Type = typeof(MaterialIntegrationReqResponse))]
|
||||
public async Task<IActionResult> UpsertMeterial(MaterialIntegrationRequest request)
|
||||
{
|
||||
MaterialIntegrationReqResponse response = new MaterialIntegrationReqResponse();
|
||||
try
|
||||
{
|
||||
response = await _integrationService.UpsertMaterialAsync(request);
|
||||
if (!response.IsUpdated)
|
||||
{
|
||||
response.ReturnMessage.Add($"Material Created Successfully for MaterialCode :{request.MaterialCode} ");
|
||||
response.ReturnStatus = StatusCodes.Status201Created;
|
||||
return StatusCode(StatusCodes.Status201Created, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ReturnMessage.Add($"Material Updated Successfully for MaterialCode :{request.MaterialCode} ");
|
||||
response.ReturnStatus = StatusCodes.Status200OK;
|
||||
return StatusCode(StatusCodes.Status200OK, response);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception Occur in Material Operation {request?.MaterialCode}";
|
||||
_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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,354 @@
|
|||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using OnlineSalesAutoCrop.CoreAPI;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Global;
|
||||
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.MobileApp;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems;
|
||||
using System;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="service"></param>
|
||||
/// <param name="appSettings"></param>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="refreshTokenService"></param>
|
||||
/// <param name="masterService"></param>
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[Route("api/mobile/v{version:apiVersion}/auth")]
|
||||
public class MobileAuthController(IUserService service, IOptions<AppSettings> appSettings, IEaseCache cache, ILogger<MobileAuthController> logger,
|
||||
IRefreshTokenService refreshTokenService, IMobileMasterDataService masterService) : ControllerBase
|
||||
{
|
||||
private readonly ILogger _logger = logger;
|
||||
private readonly IEaseCache _cache = cache;
|
||||
private readonly IUserService _service = service;
|
||||
private readonly IRefreshTokenService _refreshTokenService = refreshTokenService;
|
||||
private readonly AppSettings _appSettings = appSettings?.Value;
|
||||
private readonly DateTimeOffset _options = Helper.CreateEaseCacheOptions();
|
||||
private readonly IMobileMasterDataService _masterService = masterService;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>If login successful ValidUser: true</returns>
|
||||
/// <response code="200">If login successful Return ValidUser: true and UserName: not empty</response>
|
||||
[HttpPost("Login")]
|
||||
[AllowAnonymous]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(MobileAppAuthRequest))]
|
||||
public async Task<IActionResult> Login([FromBody] MobileAppAuthRequest request)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
AppAuthUserResponse loginReponse = new();
|
||||
|
||||
if (string.IsNullOrEmpty(request.LoginId))
|
||||
{
|
||||
string message = "Login ID is required.";
|
||||
return BadRequest(MobileResponseBase<AppAuthUserResponse>.Failure(message, StatusCodes.Status400BadRequest));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(request.Password))
|
||||
{
|
||||
string message = "Password is required.";
|
||||
return BadRequest(MobileResponseBase<AppAuthUserResponse>.Failure(message, StatusCodes.Status400BadRequest));
|
||||
}
|
||||
|
||||
|
||||
string ipAddress = string.Empty;
|
||||
try
|
||||
{
|
||||
#region Decrypt LoginID
|
||||
|
||||
string cipherSecretKey = GlobalFunctions.ConvertFromBase64String(_appSettings.CipherSecretKey);
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
bool checkPwd = true;
|
||||
|
||||
ipAddress = Request.HttpContext.GetIpAddress();
|
||||
loginReponse = await _service.LoginAsync(request: request, ipAddress: ipAddress);
|
||||
|
||||
if (loginReponse.LoginStatus == EnumLoginStatus.Unsuccessful)
|
||||
{
|
||||
string message = checkPwd ? $"Password is invalid for {request.LoginId}." : "You are not Authorized to login into the System";
|
||||
return Unauthorized(MobileResponseBase<AppAuthUserResponse>.Failure(message, StatusCodes.Status401Unauthorized));
|
||||
}
|
||||
|
||||
if (loginReponse == null || loginReponse.UserId == 0 || loginReponse.IsAuthorized ==false)
|
||||
{
|
||||
string message = "Login ID is invalid.\" : \"You are not Authorized to login into the System.";
|
||||
return Unauthorized(MobileResponseBase<AppAuthUserResponse>.Failure(message, StatusCodes.Status401Unauthorized));
|
||||
}
|
||||
|
||||
if (loginReponse.IsLocked)
|
||||
{
|
||||
string message =$"Your Account is locked . Please try again after few minutes";
|
||||
return Unauthorized(MobileResponseBase<AppAuthUserResponse>.Failure(message, StatusCodes.Status401Unauthorized));
|
||||
}
|
||||
|
||||
if (!loginReponse.IsAuthorized )
|
||||
{
|
||||
string message = $"You are not Authorized to Login into the System, Please contact with System Administrator.";
|
||||
return Unauthorized(MobileResponseBase<AppAuthUserResponse>.Failure(message, StatusCodes.Status401Unauthorized));
|
||||
}
|
||||
|
||||
string pwdSecretKey = GlobalFunctions.ConvertFromBase64String(_appSettings.PwdSecretKey);
|
||||
string userPwd = Ease.NetCore.Utility.Global.CipherFunctions.EncryptByAES(privateKey: pwdSecretKey, publicKey: pwdSecretKey, data: request.Password);
|
||||
byte[] key = Encoding.ASCII.GetBytes(_appSettings.JwtCryptoKey);
|
||||
JwtSecurityTokenHandler tokenHandler = new();
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Subject = new ClaimsIdentity(
|
||||
[
|
||||
Helper.CreateClaim("LoginId", loginReponse.LoginId),
|
||||
Helper.CreateClaim("Email", loginReponse.Email),
|
||||
Helper.CreateClaim("UserId", $"{loginReponse.UserId}"),
|
||||
Helper.CreateClaim("HashKey", Guid.NewGuid().ToString())
|
||||
]),
|
||||
Expires = DateTime.UtcNow.AddMinutes(_appSettings.AccessTokenDuration),
|
||||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)
|
||||
};
|
||||
|
||||
SecurityToken token = tokenHandler.CreateToken(tokenDescriptor);
|
||||
string userToken = tokenHandler.WriteToken(token);
|
||||
GenerateRefreshTokenRequest refreshTokenRequest = new GenerateRefreshTokenRequest()
|
||||
{
|
||||
UserId = loginReponse.UserId,
|
||||
IpAddress = ipAddress,
|
||||
RawRefreshToken = string.Empty
|
||||
};
|
||||
|
||||
var refreshToken = await _refreshTokenService.GenerateRefreshTokenByUserAsync(refreshTokenRequest);
|
||||
|
||||
//If token length is greater than or equal to 4096 (4KB) then return error
|
||||
//because cookie can not store more than 4KB data and we are storing this token in cookie for authentication
|
||||
if (userToken.Length >= 4096) //4Kb
|
||||
{
|
||||
string message = $"Authentication Token is too large for cookie.";
|
||||
return StatusCode(StatusCodes.Status431RequestHeaderFieldsTooLarge, MobileResponseBase<AppAuthUserResponse>.Failure(message, StatusCodes.Status431RequestHeaderFieldsTooLarge));
|
||||
}
|
||||
|
||||
|
||||
loginReponse.LoginId = loginReponse.LoginId;
|
||||
loginReponse.AccessToken = userToken;
|
||||
loginReponse.RefreshToken = refreshToken.RefreshToken;
|
||||
loginReponse.AccessTokenExpiryTime = DateTime.Now.AddMinutes(_appSettings.AccessTokenDuration);
|
||||
loginReponse.RefreshTokenExpiryTime = refreshToken.ExpireTime;
|
||||
|
||||
return Ok(MobileResponseBase<AppAuthUserResponse>.Success(loginReponse));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"{request?.LoginId}~{ipAddress}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
string mesgae= ex.InnerException != null ? ex.InnerException.Message : ex.Message;
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(mesgae, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>If login successful ValidUser: true</returns>
|
||||
/// <response code="200">If login successful Return ValidUser: true and UserName: not empty</response>
|
||||
[HttpPost("RefreshToken")]
|
||||
[AllowAnonymous]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(MobileRrefreshTokenResponse))]
|
||||
public async Task<IActionResult> GetRefreshToken([FromBody] IntegrationRefreshTokenRequest request)
|
||||
{
|
||||
MobileRrefreshTokenResponse response = new();
|
||||
try
|
||||
{
|
||||
var userRefreshToken = await _refreshTokenService.GetUserByRefreshTokenAsync(request.RefreshToken);
|
||||
if (!userRefreshToken.IsActive)
|
||||
{
|
||||
string msg = $"Refresh Token is not active: {request?.RefreshToken}";
|
||||
_logger.LogError(message: msg);
|
||||
return Unauthorized( MobileResponseBase<AppAuthUserResponse>.Failure(msg, StatusCodes.Status401Unauthorized));
|
||||
}
|
||||
|
||||
byte[] key = Encoding.ASCII.GetBytes(_appSettings.JwtCryptoKey);
|
||||
JwtSecurityTokenHandler tokenHandler = new();
|
||||
var tokenDescriptor = new SecurityTokenDescriptor
|
||||
{
|
||||
Subject = new ClaimsIdentity(
|
||||
[
|
||||
Helper.CreateClaim("LoginId", userRefreshToken.LoginId),
|
||||
Helper.CreateClaim("Email", userRefreshToken.EmailAddress),
|
||||
Helper.CreateClaim("UserId", $"{userRefreshToken.UserId}"),
|
||||
Helper.CreateClaim("HashKey", Guid.NewGuid().ToString())
|
||||
]),
|
||||
Expires = DateTime.UtcNow.AddMinutes(_appSettings.AccessTokenDuration),
|
||||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)
|
||||
};
|
||||
|
||||
SecurityToken token = tokenHandler.CreateToken(tokenDescriptor);
|
||||
string userToken = tokenHandler.WriteToken(token);
|
||||
|
||||
string ipAddress = Request.HttpContext.GetIpAddress();
|
||||
var refreshToken = await _refreshTokenService.GenerateRefreshTokenAsync(request.RefreshToken, ipAddress);
|
||||
|
||||
response.AccessToken = userToken;
|
||||
response.RefreshToken = refreshToken;
|
||||
|
||||
return Ok(MobileResponseBase<MobileRrefreshTokenResponse>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"{request?.RefreshToken}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>If login successful ValidUser: true</returns>
|
||||
/// <response code="200">If login successful Return ValidUser: true and UserName: not empty</response>
|
||||
[HttpPost("Logout")]
|
||||
[Authorize]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AuthLogoutResponse))]
|
||||
public async Task<IActionResult> Logout([FromBody] AuthLogoutRequest request)
|
||||
{
|
||||
AuthLogoutResponse response = new();
|
||||
try
|
||||
{
|
||||
string ipAddress = Request.HttpContext.GetIpAddress();
|
||||
response = await _service.LogoutAsync(request, ipAddress);
|
||||
return Ok(MobileResponseBase<AuthLogoutResponse>.Success(response, "Successfully Logout"));
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on logout {request?.LoginId}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <returns>If login successful ValidUser: true</returns>
|
||||
/// <response code="200">If login successful Return ValidUser: true and UserName: not empty</response>
|
||||
[HttpPost("ChangePassword")]
|
||||
[Authorize]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(AppChangePasswordResponse))]
|
||||
public async Task<IActionResult> ChangePassword([FromBody] AppUserChangePasswordRequest request)
|
||||
{
|
||||
AppChangePasswordResponse response = new();
|
||||
try
|
||||
{
|
||||
|
||||
if (request.Password.Equals(request.ConfirmPassword))
|
||||
{
|
||||
string msg = $"You can't use your old password as your new password.";
|
||||
_logger.LogError(message: msg);
|
||||
return BadRequest(MobileResponseBase<AppAuthUserResponse>.Failure(msg, StatusCodes.Status400BadRequest));
|
||||
}
|
||||
GetPasswordPolicyResponse passwordPolicy = await _masterService.GetPasswordPolicyAsync();
|
||||
|
||||
string passValidationResponse = ValidatePassword(request.ConfirmPassword, passwordPolicy);
|
||||
|
||||
if(!string.IsNullOrEmpty(passValidationResponse))
|
||||
{
|
||||
string msg = passValidationResponse;
|
||||
_logger.LogError(message: msg);
|
||||
return BadRequest(MobileResponseBase<AppAuthUserResponse>.Failure(msg, StatusCodes.Status400BadRequest));
|
||||
}
|
||||
|
||||
string ipAddress = Request.HttpContext.GetIpAddress();
|
||||
response = await _service.ChangePasswordAsync(request, ipAddress);
|
||||
return Ok(MobileResponseBase<AppChangePasswordResponse>.Success(response, "Successfully Changed the Password"));
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on logout {request?.LoginId}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
private string ValidatePassword(string password, GetPasswordPolicyResponse policy)
|
||||
{
|
||||
if (policy == null)
|
||||
throw new ArgumentNullException(nameof(policy));
|
||||
|
||||
if (string.IsNullOrEmpty(password))
|
||||
{
|
||||
return "Password cannot be empty.";
|
||||
}
|
||||
|
||||
if (policy.MinLength.HasValue && password.Length < policy.MinLength.Value)
|
||||
return $"Password must be at least {policy.MinLength.Value} characters long.";
|
||||
|
||||
if (policy.MaxLength.HasValue && password.Length > policy.MaxLength.Value)
|
||||
return $"Password must not exceed {policy.MaxLength.Value} characters.";
|
||||
|
||||
if (policy.IsUppercase && !password.Any(char.IsUpper))
|
||||
return "Password must contain at least one uppercase letter.";
|
||||
|
||||
if (policy.IsLowercase && !password.Any(char.IsLower))
|
||||
return "Password must contain at least one lowercase letter.";
|
||||
|
||||
if (policy.IsNumber && !password.Any(char.IsDigit))
|
||||
return "Password must contain at least one digit.";
|
||||
|
||||
if (policy.IsSpecialCharacter && !password.Any(c => !char.IsLetterOrDigit(c)))
|
||||
return "Password must contain at least one special character.";
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,415 @@
|
|||
using Asp.Versioning;
|
||||
using DocumentFormat.OpenXml.Office2010.ExcelAc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using OnlineSalesAutoCrop.CoreAPI;
|
||||
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.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="service"></param>
|
||||
/// <param name="appSettings"></param>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="logger"></param>
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[Route("api/mobile/v{version:apiVersion}/masterdata")]
|
||||
public class MobileMasterDataController(IMobileMasterDataService service, IOptions<AppSettings> appSettings, IEaseCache cache, ILogger<MobileMasterDataController> logger) : ControllerBase
|
||||
{
|
||||
private readonly ILogger _logger = logger;
|
||||
private readonly IEaseCache _cache = cache;
|
||||
private readonly IMobileMasterDataService _service = service;
|
||||
private readonly AppSettings _appSettings = appSettings?.Value;
|
||||
private readonly DateTimeOffset _options = Helper.CreateEaseCacheOptions();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return MarketHierarchies List</response>
|
||||
[HttpGet("MarketHierarchies")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(MarketHeirarchyByEmpResponse))]
|
||||
public async Task<IActionResult> EmployeeMarketHierarchies([FromQuery] GetMarketHeirarchyByEmpRequest request)
|
||||
{
|
||||
MarketHeirarchyByEmpResponse response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetMarketHeirarchiesByEmpAsync(request);
|
||||
return Ok(MobileResponseBase<MarketHeirarchyByEmpResponse>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on MarketHeirarchys endpoint with employee request - {request?.EmployeeNumber}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Brands List</response>
|
||||
[HttpGet("Brands")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(MarketHeirarchyByEmpResponse))]
|
||||
public async Task<IActionResult> Brands([FromQuery] GetBrandsRequest request)
|
||||
{
|
||||
PagedResult<GetBrandResponse> response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetBrandsAsync(request);
|
||||
return Ok(MobileResponseBase<PagedResult<GetBrandResponse>>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on brands endpoint with employee request - {request?.BrandCode}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Material List</response>
|
||||
[HttpGet("Materials")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetMaterialResponse))]
|
||||
public async Task<IActionResult> Materials([FromQuery] GetMaterialsRequest request)
|
||||
{
|
||||
PagedResult<GetMaterialResponse> response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetMaterialsAsync(request);
|
||||
return Ok(MobileResponseBase<PagedResult<GetMaterialResponse>>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on Materials endpoint with employee request - {request?.BrandCode} -{request?.MaterialCode}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Material List</response>
|
||||
[HttpGet("MaterialsStock")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetMaterialStockReponse))]
|
||||
public async Task<IActionResult> GetMaterialsStock([FromQuery] GetMaterialStockRequest request)
|
||||
{
|
||||
PagedResult<GetMaterialStockReponse> response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetMaterialsStockAsync(request);
|
||||
return Ok(MobileResponseBase<PagedResult<GetMaterialStockReponse>>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on MaterialsStock endpoint with plant request - {request?.PlantCode} ";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Material List</response>
|
||||
[HttpGet("CustomerWiseMaterialPrices")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetMaterialPriceResponse))]
|
||||
public async Task<IActionResult> GetCustomerWiseMaterialPrices([FromQuery] GetMaterialPriceRequest request)
|
||||
{
|
||||
PagedResult<GetMaterialPriceResponse> response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetMaterialPricesAsync(request);
|
||||
return Ok(MobileResponseBase<PagedResult<GetMaterialPriceResponse>>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on Materials prices endpoint with employee request - {request?.MaterialCode} -{request?.EmployeeNumber}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Material List</response>
|
||||
[HttpGet("Customers")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetCustomerResponse))]
|
||||
public async Task<IActionResult> Customers([FromQuery] GetCustomersRequest request)
|
||||
{
|
||||
PagedResult<GetCustomerResponse> response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetCustomersAsync(request);
|
||||
return Ok(MobileResponseBase<PagedResult<GetCustomerResponse>>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on Materials endpoint with employee request - {request?.TeritoryCode} -{request?.CustomerCode}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Attendance List</response>
|
||||
[HttpGet("Attendance")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetAttendanceByEmpResponse))]
|
||||
public async Task<IActionResult> GetAttendance([FromQuery] GetAttendanceByEmpRequest request)
|
||||
{
|
||||
GetAttendanceByEmpResponse response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetAttendanceByEmpAsync(request);
|
||||
return Ok(MobileResponseBase<GetAttendanceByEmpResponse>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on Get Attendance endpoint with employee request - {request?.EmployeeNumber} -{request?.AttendanceDate}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Attendance List</response>
|
||||
[HttpPost("SaveAttendance")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetAttendanceByEmpResponse))]
|
||||
public async Task<IActionResult> UpsertAttendance([FromBody] UpsertAttendanceByEmpRequest request)
|
||||
{
|
||||
GetAttendanceByEmpResponse response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.UpsertAttendanceByEmpAsync(request);
|
||||
return Ok(MobileResponseBase<GetAttendanceByEmpResponse>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on Save Attendance endpoint with employee request - {request?.EmployeeNumber}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Attendance List</response>
|
||||
[HttpGet("Discounts")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetDiscountResponse))]
|
||||
public async Task<IActionResult> GetDiscounts([FromQuery] GetDiscountRequest request)
|
||||
{
|
||||
PagedResult<GetDiscountResponse> response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetDiscountAsync(request);
|
||||
return Ok(MobileResponseBase<PagedResult<GetDiscountResponse>>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on Get Discounts endpoint with request - {request?.EmployeeNumber} -{request?.DiscountCode}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Attendance List</response>
|
||||
[HttpGet("DiscountMaterials")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetDiscountMaterialResponse))]
|
||||
public async Task<IActionResult> GetDiscountMaterials([FromQuery] GetDiscountMaterialRequest request)
|
||||
{
|
||||
PagedResult<GetDiscountMaterialResponse> response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetDiscountMaterialsAsync(request);
|
||||
return Ok(MobileResponseBase<PagedResult<GetDiscountMaterialResponse>>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on Get DiscountMaterials endpoint with request - {request?.MaterialCode} -{request?.DiscountCode}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Attendance List</response>
|
||||
[HttpGet("FOCs")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetFOCResponse))]
|
||||
public async Task<IActionResult> GetMaterialFOCs([FromQuery] GetFOCRequest request)
|
||||
{
|
||||
PagedResult<GetFOCResponse> response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetFOCsAsync(request);
|
||||
return Ok(MobileResponseBase<PagedResult<GetFOCResponse>>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on Get MaterialFOCs endpoint with request - {request?.EmployeeNumber} -{request?.FOCCode}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Attendance List</response>
|
||||
[HttpGet("FOCsMaterials")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetFOCMaterialResponse))]
|
||||
public async Task<IActionResult> GetFOCsMaterials([FromQuery] GetFOCMaterialRequest request)
|
||||
{
|
||||
PagedResult<GetFOCMaterialResponse> response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetFOCMaterialsAsync(request);
|
||||
return Ok(MobileResponseBase<PagedResult<GetFOCMaterialResponse>>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on Get FOCsMaterials endpoint with request - {request?.MaterialCode} -{request?.FOCCode}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Attendance List</response>
|
||||
[HttpGet("PaymentTerms")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetPaymentTermResponse))]
|
||||
public async Task<IActionResult> GetPaymentTerms([FromQuery] GetPaymentTermRequest request)
|
||||
{
|
||||
PagedResult<GetPaymentTermResponse> response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetPaymentTermsAsync(request);
|
||||
return Ok(MobileResponseBase<PagedResult<GetPaymentTermResponse>>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on Get PaymentTerms endpoint with request - {request?.SalesOrgCode} -{request?.PaymentTermCode}";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// For PasswordPolicy
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <response code="200">If login successful Return Attendance List</response>
|
||||
[HttpGet("PasswordPolicy")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetPasswordPolicyResponse))]
|
||||
public async Task<IActionResult> GetPasswordPolicy()
|
||||
{
|
||||
GetPasswordPolicyResponse response = new();
|
||||
try
|
||||
{
|
||||
response = await _service.GetPasswordPolicyAsync();
|
||||
return Ok(MobileResponseBase<GetPasswordPolicyResponse>.Success(response));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string msg = $"Exception occur on Get PasswordPolicy endpoint ";
|
||||
_logger.LogError(exception: ex, message: msg);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, MobileResponseBase<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
using Asp.Versioning;
|
||||
using Google.Api;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models;
|
||||
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;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
///
|
||||
/// </remarks>
|
||||
/// <param name="service"></param>
|
||||
/// <param name="appSettings"></param>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="logger"></param>
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[Route("api/mobile/v{version:apiVersion}/orders")]
|
||||
public class OrdersController(IOrderService service, IOptions<AppSettings> appSettings, IEaseCache cache, ILogger<OrdersController> 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();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Order List</response>
|
||||
[HttpPost("SaveOrder")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(SaveOrderResponse))]
|
||||
public async Task<IActionResult> SaveOrders([FromBody] SaveOrderRequest request)
|
||||
{
|
||||
SaveOrderResponse response = new();
|
||||
try
|
||||
{
|
||||
int userId = HttpContext.User.GetClaimValue<int>(Constants.UserId);
|
||||
response = await _service.SaveOrderAsync(request, userId);
|
||||
return Ok(MobileResponseBase<SaveOrderResponse>.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<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// </remarks>
|
||||
/// <param name="request"></param>
|
||||
/// <response code="200">If login successful Return Attendance List</response>
|
||||
[HttpGet("OrderSummary")]
|
||||
[IgnoreAntiforgeryToken]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(GetSalesOrderResponse))]
|
||||
public async Task<IActionResult> GetOrderSummaries([FromQuery] GetOrderSummaryRequest request)
|
||||
{
|
||||
PagedResult<GetSalesOrderResponse> response = new();
|
||||
try
|
||||
{
|
||||
int userId = HttpContext.User.GetClaimValue<int>(Constants.UserId);
|
||||
response = await _service.GetSalesOrdersSummary(request, userId);
|
||||
return Ok(MobileResponseBase<PagedResult<GetSalesOrderResponse>>.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<AppAuthUserResponse>.Failure(ex.InnerException != null ? ex.InnerException.Message : ex.Message, StatusCodes.Status500InternalServerError));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ using Microsoft.Extensions.Logging;
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Controllers.V1
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Controllers.Web
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
|
|
@ -13,7 +13,7 @@ using Microsoft.Extensions.Logging;
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Controllers.V1
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Controllers.Web
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
|
|
@ -1,16 +1,5 @@
|
|||
using Asp.Versioning;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Configurations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Global;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Objects;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Setups;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.SignalRHub;
|
||||
using Google.Apis.Auth.OAuth2.Requests;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
|
@ -18,6 +7,20 @@ using Microsoft.AspNetCore.SignalR;
|
|||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Configurations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Global;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Objects;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Setups;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Auth;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.SignalRHub;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.DirectoryServices;
|
||||
|
|
@ -29,7 +32,7 @@ using System.Security.Claims;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Controllers.V1
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Controllers.Web
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
|
|
@ -45,11 +48,11 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers.V1
|
|||
[Authorize]
|
||||
[ApiController]
|
||||
[ApiVersion("1.0")]
|
||||
[Route("api/users")]
|
||||
[ValidateAntiForgeryToken]
|
||||
[Route("api/v{version:apiVersion}/users")]
|
||||
|
||||
public class UserController(IUserService service, IOptions<AppSettings> appSettings, IEaseCache cache, ILogger<IntegrationAuthController> logger, IHubContext<NotificationHub, INotificationHub> hub) : ControllerBase
|
||||
public class UserController(IUserService service, IOptions<AppSettings> appSettings, IEaseCache cache, ILogger<IntegrationAuthController> logger,
|
||||
IHubContext<NotificationHub, INotificationHub> hub, IRefreshTokenService refreshTokenService) : ControllerBase
|
||||
{
|
||||
private readonly ILogger _logger = logger;
|
||||
private readonly IEaseCache _cache = cache;
|
||||
|
|
@ -57,6 +60,7 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers.V1
|
|||
private readonly AppSettings _appSettings = appSettings?.Value;
|
||||
private readonly DateTimeOffset _options = Helper.CreateEaseCacheOptions();
|
||||
private readonly IHubContext<NotificationHub, INotificationHub> _hub = hub;
|
||||
private readonly IRefreshTokenService _refreshTokenService= refreshTokenService;
|
||||
|
||||
/// <summary>
|
||||
/// Login using your credential data retrieve from SqlServer
|
||||
|
|
@ -215,17 +219,15 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers.V1
|
|||
{
|
||||
Subject = new ClaimsIdentity(
|
||||
[
|
||||
//Helper.CreateClaim("UserId", $"{user.Id}"),
|
||||
//Helper.CreateClaim("LoginId", user.LoginId),
|
||||
//Helper.CreateClaim("UserPwd", userPwd),
|
||||
//Helper.CreateClaim("AuthKey", $"{user.AuthKey}"),
|
||||
//Helper.CreateClaim("TeamSpaceIds", $"{string.Join(',',user.TeamSpaceIds)}"),
|
||||
//Helper.CreateClaim("BatchEnabled", user.BatchEnabled ? "1" : "0"),
|
||||
//Helper.CreateClaim("BmProcessId", $"{user.BmProcessId}"),
|
||||
//Helper.CreateClaim("PrProcessId", $"{user.PrProcessId}"),
|
||||
//Helper.CreateClaim("EmployeeId", $"{user.EmployeeCode}")
|
||||
Helper.CreateClaim("UserId", $"{user.UserId}"),
|
||||
Helper.CreateClaim("LoginId", user.LoginId),
|
||||
Helper.CreateClaim("AuthKey", $"{user.AuthKey}"),
|
||||
Helper.CreateClaim("TeamSpaceIds", $"{string.Join(',',user.TeamSpaceIds)}"),
|
||||
Helper.CreateClaim("UserPlatformId", ((int)user.UserPlatFormType).ToString()),
|
||||
Helper.CreateClaim("UserRoleType", $"{user.UserRoleType}"),
|
||||
Helper.CreateClaim("EmployeeCode", $"{user.EmployeeNumber}")
|
||||
]),
|
||||
Expires = DateTime.UtcNow.AddHours(12),
|
||||
Expires = DateTime.UtcNow.AddMinutes(_appSettings.AccessTokenDuration),
|
||||
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha512Signature)
|
||||
};
|
||||
|
||||
|
|
@ -246,37 +248,17 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers.V1
|
|||
response.AuthenticationToken = userToken;
|
||||
response.LoginTime = $"{DateTime.Now:dd-MM-yy H:mm:ss}";
|
||||
|
||||
//await HttpContext.Session.SetModulesToSession(key: userToken, value: user.ModuleIds);
|
||||
//if (user.LoginStatus == EnumLoginStatus.Success)
|
||||
//{
|
||||
// if (user.AuthMethod == EnumAuthenticationMethod.Email && !string.IsNullOrEmpty(user.EmailAddress) && !string.IsNullOrWhiteSpace(user.EmailAddress) && !string.IsNullOrWhiteSpace(user.AuthValue))
|
||||
// {
|
||||
// List<string> to = [.. user.EmailAddress.Split(separator: ';', options: StringSplitOptions.RemoveEmptyEntries)];
|
||||
// await MailHelper.SendMailMessageAsync(settings: _appSettings, to: to,
|
||||
// cc: null, bcc: null, attachments: null, embeddedImages: null, isHtmlBody: false, priority: System.Net.Mail.MailPriority.Normal,
|
||||
// subject: "Your OTP", messageBody: string.Format("Your OTP: {0} and is valid for 5 minutes only", user.AuthValue));
|
||||
// }
|
||||
// else if (user.AuthMethod == EnumAuthenticationMethod.MobileSMS && !string.IsNullOrEmpty(user.MobileNo) && !string.IsNullOrWhiteSpace(user.MobileNo) && !string.IsNullOrWhiteSpace(user.AuthValue))
|
||||
// {
|
||||
// MailHelper.SendSMSOrWhatsAppMessage(settings: _appSettings, whatsAppMsg: false, msg: string.Format("Your OTP: {0} and is valid for 5 minutes only", user.AuthValue), mobileNumber: user.MobileNo);
|
||||
// }
|
||||
//}
|
||||
GenerateRefreshTokenRequest refreshTokenRequest = new GenerateRefreshTokenRequest()
|
||||
{
|
||||
UserId = user.UserId,
|
||||
IpAddress = ipAddress,
|
||||
RawRefreshToken = string.Empty
|
||||
};
|
||||
|
||||
//if (user.DisallowMultiLogin)
|
||||
//{
|
||||
// await _hub.Clients.All.NotifySubscriber(userId: user.Id, msgType: 1, itemId: 0, ipAddress: ipAddress);
|
||||
// if (request.AttendanceLogin)
|
||||
// await _hub.Clients.All.NotifySubscriber(userId: user.Id, msgType: 6, itemId: 0, ipAddress: ipAddress);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// await _hub.Clients.All.NotifySubscriber(userId: user.Id, msgType: 2, itemId: 0, ipAddress: ipAddress);
|
||||
// if (request.AttendanceLogin)
|
||||
// await _hub.Clients.All.NotifySubscriber(userId: user.Id, msgType: 6, itemId: 0, ipAddress: ipAddress);
|
||||
//}
|
||||
//response.IdsValue = Ease.NetCore.Utility.Global.CipherFunctions.EncryptByAES(data: Newtonsoft.Json.JsonConvert.SerializeObject(user.ModuleIds), privateKey: cipherSecretKey, publicKey: cipherSecretKey, output: 2);
|
||||
var refreshToken = await _refreshTokenService.GenerateRefreshTokenByUserAsync(refreshTokenRequest);
|
||||
|
||||
return Ok(response);
|
||||
response.RefreshToken = refreshToken.RefreshToken;
|
||||
return Ok(response);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -623,7 +605,96 @@ namespace OnlineSalesAutoCrop.CoreAPI.Controllers.V1
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// Updates password of multiple users from an excel file having EmployeeCode and Password columns.
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
[ValidateSession]
|
||||
[HttpPost("uploadPasswords")]
|
||||
[AllowAnonymous]
|
||||
[ProducesResponseType(StatusCodes.Status200OK, Type = typeof(BulkPasswordUploadResponse))]
|
||||
public async Task<IActionResult> UploadPasswords([FromForm] BulkPasswordUploadRequest request)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
BulkPasswordUploadResponse response = new() { ReturnStatus = StatusCodes.Status200OK };
|
||||
if (string.IsNullOrEmpty(request.FileName))
|
||||
{
|
||||
response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
|
||||
response.ReturnMessage.Add("There is no valid file to process.");
|
||||
return StatusCode(StatusCodes.Status417ExpectationFailed, response);
|
||||
}
|
||||
|
||||
if (request.FileData == null || request.FileData.Length <= 0)
|
||||
{
|
||||
response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
|
||||
response.ReturnMessage.Add("There is no valid data to process.");
|
||||
return StatusCode(StatusCodes.Status417ExpectationFailed, response);
|
||||
}
|
||||
|
||||
string[] allowedExtensions = [".xlsx", ".xls"];
|
||||
string fileExtension = Path.GetExtension(request.FileName).ToLowerInvariant();
|
||||
if (!allowedExtensions.Contains(fileExtension))
|
||||
{
|
||||
response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
|
||||
response.ReturnMessage.Add("Only excel file is allowed to process.");
|
||||
return BadRequest(response);
|
||||
}
|
||||
|
||||
Result result = fileExtension.Equals(".xls") ? ExcelFileValidator.Validate(request.FileData) : ExcelxFileValidator.Validate(request.FileData);
|
||||
if (!result.Acceptable)
|
||||
{
|
||||
response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
|
||||
response.ReturnMessage.Add("This is not a valid Excel file.");
|
||||
return BadRequest(response);
|
||||
}
|
||||
|
||||
long maxSz = 10 * 1024 * 1024;
|
||||
if (request.FileData.Length > maxSz)
|
||||
{
|
||||
response.ReturnStatus = StatusCodes.Status417ExpectationFailed;
|
||||
response.ReturnMessage.Add("Maximum allowable size is 10 MB");
|
||||
return StatusCode(StatusCodes.Status417ExpectationFailed, response);
|
||||
}
|
||||
|
||||
bool permitted = await HttpContext.IsPermitted("ELIT.1.2.5_2");
|
||||
if (!permitted)
|
||||
{
|
||||
response.ReturnStatus = StatusCodes.Status403Forbidden;
|
||||
response.ReturnMessage.Add("You are not authorize to Reset Password.");
|
||||
return StatusCode(StatusCodes.Status417ExpectationFailed, response);
|
||||
}
|
||||
|
||||
string fileSpec = Path.Combine(_appSettings.UploadFolder, $"PWD_{DateTime.Now:yyyyMMddHHmmssfff}{fileExtension}");
|
||||
try
|
||||
{
|
||||
using (var stream = new FileStream(fileSpec, FileMode.Create))
|
||||
{
|
||||
await request.FileData.CopyToAsync(stream);
|
||||
}
|
||||
|
||||
string ipAddress = Request.HttpContext.GetIpAddress();
|
||||
int changedBy = HttpContext.User.GetClaimValue<int>(Constants.UserId);
|
||||
response = await _service.UpdatePasswordsFromExcelAsync(fileSpec: fileSpec, ipAddress: ipAddress, changedBy: changedBy, forcePasswordChange: request.ForcePasswordChange);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex);
|
||||
response.ReturnStatus = StatusCodes.Status500InternalServerError;
|
||||
response.ReturnMessage.Add(ex.InnerException != null ? ex.InnerException.Message : ex.Message);
|
||||
return StatusCode(StatusCodes.Status500InternalServerError, response);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (System.IO.File.Exists(fileSpec))
|
||||
System.IO.File.Delete(fileSpec);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace OnlineSalesAutoCrop.CoreAPI.Converter;
|
||||
|
||||
public class EmptyStringToNullConverter : JsonConverter<string>
|
||||
{
|
||||
public override string? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.Null)
|
||||
return null;
|
||||
|
||||
var value = reader.GetString();
|
||||
|
||||
return string.IsNullOrWhiteSpace(value) ? null : value;
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, string? value, JsonSerializerOptions options)
|
||||
{
|
||||
writer.WriteStringValue(value);
|
||||
}
|
||||
}
|
||||
|
|
@ -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.GetDecimal();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -167,10 +167,13 @@
|
|||
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="10.0.0" />
|
||||
<PackageReference Include="Ease.NetCore" Version="2.1.4" />
|
||||
<PackageReference Include="Google.Cloud.Speech.V1" Version="3.9.0" />
|
||||
<PackageReference Include="Hangfire" Version="1.8.23" />
|
||||
<PackageReference Include="Hangfire.AspNetCore" Version="1.8.24" />
|
||||
<PackageReference Include="Hangfire.SqlServer" Version="1.8.24" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="10.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.SqlServer" Version="10.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="10.0.8" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="10.0.10" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http.Resilience" Version="10.8.0" />
|
||||
<PackageReference Include="OpenAI" Version="2.10.0" />
|
||||
<PackageReference Include="RabbitMQ.Client" Version="7.2.1" />
|
||||
<PackageReference Include="ReportViewerCore.NETCore" Version="15.1.33" />
|
||||
|
|
|
|||
|
|
@ -1,12 +1,5 @@
|
|||
using Asp.Versioning;
|
||||
using Asp.Versioning.ApiExplorer;
|
||||
using OnlineSalesAutoCrop.CoreAPI.API.Swagger;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Configuration.DI;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Configurations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Global;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems;
|
||||
using OnlineSalesAutoCrop.CoreAPI.SignalRHub;
|
||||
using Hangfire;
|
||||
using Hangfire.SqlServer;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
|
|
@ -19,17 +12,33 @@ using Microsoft.AspNetCore.HttpOverrides;
|
|||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Newtonsoft.Json;
|
||||
using OnlineSalesAutoCrop.CoreAPI.API.Swagger;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Configuration.DI;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Configurations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Global;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Models.Responses;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.BackgroupJobs;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.Services.Services.Integrations;
|
||||
using OnlineSalesAutoCrop.CoreAPI.SignalRHub;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
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;
|
||||
|
||||
|
|
@ -47,11 +56,11 @@ namespace OnlineSalesAutoCrop.CoreAPI
|
|||
/// </summary>
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Startup class using the specified configuration settings.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration settings used to initialize the application. Cannot be null.</param>
|
||||
public Startup(IConfiguration configuration)
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Startup class using the specified configuration settings.
|
||||
/// </summary>
|
||||
/// <param name="configuration">The configuration settings used to initialize the application. Cannot be null.</param>
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
_appSettings = Configuration.GetSection("AppSettings").Get<AppSettings>();
|
||||
|
|
@ -73,20 +82,52 @@ namespace OnlineSalesAutoCrop.CoreAPI
|
|||
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
|
||||
services.Configure<MenuSettings>(Configuration.GetSection("MenuSettings"));
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Controllers
|
||||
#region Controllers
|
||||
|
||||
services.AddControllers(options =>
|
||||
services.AddControllers(options =>
|
||||
{
|
||||
options.Filters.Add(new ProducesAttribute("application/json"));
|
||||
}).AddJsonOptions(options =>
|
||||
{
|
||||
options.Filters.Add(new ProducesAttribute("application/json"));
|
||||
options.JsonSerializerOptions.Converters.Add(
|
||||
new CoreAPI.Converter.EmptyStringToNullConverter());
|
||||
options.JsonSerializerOptions.Converters.Add(
|
||||
new CoreAPI.Converter.NullableDecimalConverter());
|
||||
|
||||
});
|
||||
|
||||
#endregion
|
||||
services.Configure<ApiBehaviorOptions>(options =>
|
||||
{
|
||||
options.InvalidModelStateResponseFactory = context =>
|
||||
{
|
||||
var logger = context.HttpContext.RequestServices
|
||||
.GetRequiredService<ILogger<Startup>>();
|
||||
|
||||
#region API versioning
|
||||
var errors = context.ModelState
|
||||
.Where(kvp => kvp.Value?.Errors.Count > 0)
|
||||
.SelectMany(kvp => kvp.Value!.Errors.Select(e => e.ErrorMessage))
|
||||
.ToList();
|
||||
|
||||
services.AddApiVersioning(options =>
|
||||
var response = new MobileResponseBase<object>
|
||||
{
|
||||
ReturnStatus = StatusCodes.Status400BadRequest,
|
||||
ReturnMessage =new List<string>() { errors.Count > 0 ? errors[0] : string.Empty },
|
||||
Data = null
|
||||
};
|
||||
|
||||
logger.LogError("Validation Failed. Request: {@Errors}", errors);
|
||||
|
||||
return new BadRequestObjectResult(response);
|
||||
};
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
#region API versioning
|
||||
|
||||
services.AddApiVersioning(options =>
|
||||
{
|
||||
options.ReportApiVersions = true;
|
||||
options.DefaultApiVersion = new ApiVersion(1, 0);
|
||||
|
|
@ -286,6 +327,10 @@ namespace OnlineSalesAutoCrop.CoreAPI
|
|||
services.AddHangfire(config =>
|
||||
{
|
||||
config.UseFilter(new TimeRestrictionServerFilter(startHour: 1, endHour: 7));
|
||||
config.SetDataCompatibilityLevel(CompatibilityLevel.Version_180);
|
||||
config.UseSimpleAssemblyNameTypeSerializer();
|
||||
config.UseRecommendedSerializerSettings();
|
||||
|
||||
config.UseSqlServerStorage(_appSettings.HangfireDb, new SqlServerStorageOptions
|
||||
{
|
||||
DisableGlobalLocks = true,
|
||||
|
|
@ -295,14 +340,18 @@ namespace OnlineSalesAutoCrop.CoreAPI
|
|||
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5)
|
||||
});
|
||||
});
|
||||
services.AddHangfireServer();
|
||||
services.AddHangfireServer(options =>
|
||||
{
|
||||
options.Queues = new[] { "sap_order_send", "default" }; // merge with any queues you already have
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region SWAGGER
|
||||
#endregion
|
||||
|
||||
if (_appSettings.Swagger.Enabled)
|
||||
#region SWAGGER
|
||||
|
||||
if (_appSettings.Swagger.Enabled)
|
||||
{
|
||||
services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>();
|
||||
services.AddSwaggerGen(options =>
|
||||
|
|
@ -318,9 +367,35 @@ namespace OnlineSalesAutoCrop.CoreAPI
|
|||
|
||||
services.ConfigureBusinessServices();
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region AutoCrop Integration Service
|
||||
|
||||
services.AddHttpClient<IIntegrationHttpService, IntegrationHttpService>((sp, client) =>
|
||||
{
|
||||
var opt = _appSettings.AutoCropSAPApi;
|
||||
|
||||
client.BaseAddress = new Uri(opt.BaseUrl);
|
||||
|
||||
var basicAuth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{opt.UserName}:{opt.Password}"));
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", basicAuth);
|
||||
|
||||
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
|
||||
//client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
|
||||
})
|
||||
.AddStandardResilienceHandler(options =>
|
||||
{
|
||||
options.AttemptTimeout.Timeout = TimeSpan.FromSeconds(300);
|
||||
options.CircuitBreaker.SamplingDuration = TimeSpan.FromSeconds(600); // must be >= 2x AttemptTimeout
|
||||
options.TotalRequestTimeout.Timeout = TimeSpan.FromSeconds(300);
|
||||
options.Retry.MaxRetryAttempts = 1; // see note below
|
||||
});
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Nothimg to do here as we are handling all exceptions in Configure method using global exception handler
|
||||
|
|
@ -388,11 +463,11 @@ namespace OnlineSalesAutoCrop.CoreAPI
|
|||
|
||||
app.UseStaticFiles();
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Routing
|
||||
#region Routing
|
||||
|
||||
app.UseRouting();
|
||||
app.UseRouting();
|
||||
|
||||
#endregion
|
||||
|
||||
|
|
@ -445,11 +520,114 @@ namespace OnlineSalesAutoCrop.CoreAPI
|
|||
loggerFactory.AddFile(pathFormat: $@"{_appSettings.LoggerPath}\Log.txt", minimumLevel: (LogLevel)_appSettings.LoggerMinLevel);
|
||||
}
|
||||
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
#region Controllers and SignalR
|
||||
#region Log Request and Response
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
if (_appSettings.IsLogRequest > 0)
|
||||
{
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
var logDirectory = Path.Combine(
|
||||
env.ContentRootPath,
|
||||
"ApiLogs"
|
||||
);
|
||||
|
||||
var logErrorDirectory = Path.Combine(
|
||||
env.ContentRootPath,
|
||||
"ApiErrorLogs"
|
||||
);
|
||||
|
||||
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 =
|
||||
$"{ context.Request.Path.ToString().Split('/').Last() }-{ DateTime.Now:yyyy-MM-dd_HH-mm-ss-fff}.json";
|
||||
|
||||
string filePath = string.Empty;
|
||||
|
||||
if(context.Response.StatusCode ==200 || context.Response.StatusCode == 201)
|
||||
{
|
||||
filePath = Path.Combine(logDirectory, fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
filePath = Path.Combine(logErrorDirectory, fileName);
|
||||
}
|
||||
|
||||
await File.WriteAllTextAsync(filePath, json);
|
||||
}
|
||||
finally
|
||||
{
|
||||
context.Response.Body = originalResponseBody;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
#region Controllers and SignalR
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_appSettings.RLName))
|
||||
{
|
||||
|
|
@ -483,6 +661,11 @@ namespace OnlineSalesAutoCrop.CoreAPI
|
|||
app.UseHangfireDashboard();
|
||||
|
||||
RecurringJobOptions options = new() { TimeZone = TimeZoneInfo.Local, MisfireHandling = MisfireHandlingMode.Relaxed };
|
||||
|
||||
RecurringJob.AddOrUpdate<IBackgroundJobService>(
|
||||
"send-sap-orders",
|
||||
service => service.ExecuteSendingOrderAsync(CancellationToken.None),
|
||||
"*/1 * * * *");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
"EmailUseDefaultCredentials": false,
|
||||
"EPMaxLevel": 2,
|
||||
"FileProcessFolder": "D:\\Local\\EaseBilling\\Api\\OnlineSalesAutoCrop.CoreAPI\\FileProcessFolder",
|
||||
"HangfireDb": "9oXGnVl0H8yqF5I2MjHeXGNp5367ljjQjnsatcKsW/KFPlA8iwEVdaY7ZMBnU+AtKZIaKjwWoHZvDLmNn0K8Ke96pS3Sj4tD+mJejgSfJLhaB+UERm6M+xqVC30kk25TsVBQezB7AsmS8PXLfgWAboe4YmyQ3pXMrDx7WCfiuJA=",
|
||||
"HangfireDb": "Data Source=210.4.65.222,3341;Initial Catalog=AutoCropDB;User ID=dmsuser;Password=dMsu@er;Encrypt=false",
|
||||
"JwtAudience": "www.celdevbd.com",
|
||||
"JwtCryptoKey": "Computer ease limited, dhaka, bangladesh BDComputer ease limited",
|
||||
"JwtIssuer": "https://www.celdevbd.com",
|
||||
|
|
@ -84,7 +84,14 @@
|
|||
"WaAuthToken": "024a6897584671d9f9fa588d7c94aa96",
|
||||
"WaMsgSvcSid": "MG8401d33a9a3b2aea95619bda3e5757b5",
|
||||
"WaSenderId": "+8801326755660",
|
||||
"RefreshTokenDuration": "15"
|
||||
"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",
|
||||
"Password": "01b3f9b9-8dee-4aed-9cb9-bbefeffc1db8$eB6J_oUJZDGuJnpzAzLUxI9lAha_hljim2cfH1niJa8="
|
||||
}
|
||||
},
|
||||
|
||||
"MenuSettings": {
|
||||
|
|
|
|||
13
Api/OnlineSalesAutoCrop.CoreAPI/dotnet-tools.json
Normal file
13
Api/OnlineSalesAutoCrop.CoreAPI/dotnet-tools.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "10.0.9",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
],
|
||||
"rollForward": false
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
313
App/ClientApp/package-lock.json
generated
313
App/ClientApp/package-lock.json
generated
|
|
@ -76,7 +76,7 @@
|
|||
"@angular-eslint/eslint-plugin-template": "21.4.0",
|
||||
"@angular-eslint/schematics": "21.4.0",
|
||||
"@angular-eslint/template-parser": "21.4.0",
|
||||
"@angular/cli": "21.2.13",
|
||||
"@angular/cli": "^21.2.19",
|
||||
"@angular/compiler-cli": "21.2.15",
|
||||
"@angular/language-service": "21.2.15",
|
||||
"@types/crypto-js": "4.2.2",
|
||||
|
|
@ -581,12 +581,11 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@angular-devkit/schematics": {
|
||||
"version": "21.2.13",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.13.tgz",
|
||||
"integrity": "sha512-gifpOcMNiAy49lQmQKhzpxoSfS3qJQSEdJSF5m7RVFkAcmllfcCD76GPN4dhho3wdAnbZ3qr54LtDqrGY4xNjw==",
|
||||
"license": "MIT",
|
||||
"version": "21.2.19",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.19.tgz",
|
||||
"integrity": "sha512-AG3Fzh9wJCmKBfxUQOUWaEHMj5Gq2O+Msf1z52aDSxbVhs5/iSQcXGPv/DLdAXu7d4xmQhLouNe9Glaq2omDyw==",
|
||||
"dependencies": {
|
||||
"@angular-devkit/core": "21.2.13",
|
||||
"@angular-devkit/core": "21.2.19",
|
||||
"jsonc-parser": "3.3.1",
|
||||
"magic-string": "0.30.21",
|
||||
"ora": "9.3.0",
|
||||
|
|
@ -598,6 +597,32 @@
|
|||
"yarn": ">= 1.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": {
|
||||
"version": "21.2.19",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.19.tgz",
|
||||
"integrity": "sha512-dtpJMQBz5nhkcIogPmXP/aT2Ak8m/wLRPOSTI/g4vSJSuGiI53PgtWq4/wfQga6E6wdM2XWsblAE89d8w5heQQ==",
|
||||
"dependencies": {
|
||||
"ajv": "8.18.0",
|
||||
"ajv-formats": "3.0.1",
|
||||
"jsonc-parser": "3.3.1",
|
||||
"picomatch": "4.0.4",
|
||||
"rxjs": "7.8.2",
|
||||
"source-map": "0.7.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
|
||||
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
||||
"yarn": ">= 1.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"chokidar": "^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"chokidar": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@angular-eslint/builder": {
|
||||
"version": "21.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-21.4.0.tgz",
|
||||
|
|
@ -823,26 +848,26 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@angular/cli": {
|
||||
"version": "21.2.13",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.13.tgz",
|
||||
"integrity": "sha512-j1kOV/f0og/3xCwG7Y8RyPd6V7uYfX2NuvXbvN1mzgxLLN2mu6CTsvPg5l/9Pu9SJI3KOPRgDxWyuP3k8KuzMg==",
|
||||
"version": "21.2.19",
|
||||
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.19.tgz",
|
||||
"integrity": "sha512-i78NzvoNonAY17QgzSmqrYnXHmEfraLv4wZ/o/m3efxuz61ZJ+5X/PsCeAhbwBvQfRrPRQaJV2tK9vGjHa+U6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@angular-devkit/architect": "0.2102.13",
|
||||
"@angular-devkit/core": "21.2.13",
|
||||
"@angular-devkit/schematics": "21.2.13",
|
||||
"@angular-devkit/architect": "0.2102.19",
|
||||
"@angular-devkit/core": "21.2.19",
|
||||
"@angular-devkit/schematics": "21.2.19",
|
||||
"@inquirer/prompts": "7.10.1",
|
||||
"@listr2/prompt-adapter-inquirer": "3.0.5",
|
||||
"@modelcontextprotocol/sdk": "1.26.0",
|
||||
"@schematics/angular": "21.2.13",
|
||||
"@schematics/angular": "21.2.19",
|
||||
"@yarnpkg/lockfile": "1.1.0",
|
||||
"algoliasearch": "5.48.1",
|
||||
"ini": "6.0.0",
|
||||
"jsonc-parser": "3.3.1",
|
||||
"listr2": "9.0.5",
|
||||
"npm-package-arg": "13.0.2",
|
||||
"pacote": "21.3.1",
|
||||
"pacote": "21.5.1",
|
||||
"parse5-html-rewriting-stream": "8.0.0",
|
||||
"semver": "7.7.4",
|
||||
"yargs": "18.0.0",
|
||||
|
|
@ -857,6 +882,51 @@
|
|||
"yarn": ">= 1.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cli/node_modules/@angular-devkit/architect": {
|
||||
"version": "0.2102.19",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.19.tgz",
|
||||
"integrity": "sha512-cj4tzUMiloLTg5rNf17E8MsvIxCWYoBiBsaj7ns6dgXqT9XCeG+J0TA2t1M+N9uuqfeLd22U/rYoCkADmcircQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@angular-devkit/core": "21.2.19",
|
||||
"rxjs": "7.8.2"
|
||||
},
|
||||
"bin": {
|
||||
"architect": "bin/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
|
||||
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
||||
"yarn": ">= 1.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/cli/node_modules/@angular-devkit/core": {
|
||||
"version": "21.2.19",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.19.tgz",
|
||||
"integrity": "sha512-dtpJMQBz5nhkcIogPmXP/aT2Ak8m/wLRPOSTI/g4vSJSuGiI53PgtWq4/wfQga6E6wdM2XWsblAE89d8w5heQQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ajv": "8.18.0",
|
||||
"ajv-formats": "3.0.1",
|
||||
"jsonc-parser": "3.3.1",
|
||||
"picomatch": "4.0.4",
|
||||
"rxjs": "7.8.2",
|
||||
"source-map": "0.7.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
|
||||
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
||||
"yarn": ">= 1.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"chokidar": "^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"chokidar": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@angular/common": {
|
||||
"version": "21.2.15",
|
||||
"resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.15.tgz",
|
||||
|
|
@ -3523,7 +3593,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz",
|
||||
"integrity": "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
|
|
@ -3970,7 +4039,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
|
||||
"integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"minipass": "^7.0.4"
|
||||
},
|
||||
|
|
@ -5141,7 +5209,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.2.tgz",
|
||||
"integrity": "sha512-EUEuWAxnL07Sp5/iC/1X6Xj+XThUvnbei9zfRWZdEXa7lss9RTHMhAHBeg+MZ5To9s/gGaSI+UwZTPdYMvKSeg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.0",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
|
|
@ -5154,11 +5221,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@npmcli/agent/node_modules/lru-cache": {
|
||||
"version": "11.5.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz",
|
||||
"integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==",
|
||||
"version": "11.5.2",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz",
|
||||
"integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
|
|
@ -5168,7 +5234,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz",
|
||||
"integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"semver": "^7.3.5"
|
||||
},
|
||||
|
|
@ -5181,7 +5246,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.2.tgz",
|
||||
"integrity": "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@gar/promise-retry": "^1.0.0",
|
||||
"@npmcli/promise-spawn": "^9.0.0",
|
||||
|
|
@ -5201,17 +5265,15 @@
|
|||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
|
||||
"integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/@npmcli/git/node_modules/lru-cache": {
|
||||
"version": "11.5.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz",
|
||||
"integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==",
|
||||
"version": "11.5.2",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz",
|
||||
"integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
|
|
@ -5221,7 +5283,6 @@
|
|||
"resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz",
|
||||
"integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"isexe": "^4.0.0"
|
||||
},
|
||||
|
|
@ -5237,7 +5298,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-4.0.0.tgz",
|
||||
"integrity": "sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"npm-bundled": "^5.0.0",
|
||||
"npm-normalize-package-bin": "^5.0.0"
|
||||
|
|
@ -5254,7 +5314,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-5.0.0.tgz",
|
||||
"integrity": "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
|
|
@ -5264,7 +5323,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.5.tgz",
|
||||
"integrity": "sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@npmcli/git": "^7.0.0",
|
||||
"glob": "^13.0.0",
|
||||
|
|
@ -5283,7 +5341,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz",
|
||||
"integrity": "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"which": "^6.0.0"
|
||||
},
|
||||
|
|
@ -5296,7 +5353,6 @@
|
|||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
|
||||
"integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
|
|
@ -5306,7 +5362,6 @@
|
|||
"resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz",
|
||||
"integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"isexe": "^4.0.0"
|
||||
},
|
||||
|
|
@ -5322,7 +5377,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-4.0.0.tgz",
|
||||
"integrity": "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
|
|
@ -5332,7 +5386,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.4.tgz",
|
||||
"integrity": "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@npmcli/node-gyp": "^5.0.0",
|
||||
"@npmcli/package-json": "^7.0.0",
|
||||
|
|
@ -7621,13 +7674,12 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@schematics/angular": {
|
||||
"version": "21.2.13",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.13.tgz",
|
||||
"integrity": "sha512-e5guslSLKbb3PJ6gUuVqM+V9xgn68cJkG1IyBohho34shbpOeoWW2eYdWQQjxvn0KUdgEhYSRBluBamCHngaUA==",
|
||||
"license": "MIT",
|
||||
"version": "21.2.19",
|
||||
"resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.19.tgz",
|
||||
"integrity": "sha512-eL+UU9eizoadhDB4YEctRmmo0A5iwrSmGzeuEa6akrq8nLGVWM8zO91HTJutkPqGQjelF+UOiOShsQSZAU9SIQ==",
|
||||
"dependencies": {
|
||||
"@angular-devkit/core": "21.2.13",
|
||||
"@angular-devkit/schematics": "21.2.13",
|
||||
"@angular-devkit/core": "21.2.19",
|
||||
"@angular-devkit/schematics": "21.2.19",
|
||||
"jsonc-parser": "3.3.1"
|
||||
},
|
||||
"engines": {
|
||||
|
|
@ -7636,12 +7688,37 @@
|
|||
"yarn": ">= 1.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@schematics/angular/node_modules/@angular-devkit/core": {
|
||||
"version": "21.2.19",
|
||||
"resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.19.tgz",
|
||||
"integrity": "sha512-dtpJMQBz5nhkcIogPmXP/aT2Ak8m/wLRPOSTI/g4vSJSuGiI53PgtWq4/wfQga6E6wdM2XWsblAE89d8w5heQQ==",
|
||||
"dependencies": {
|
||||
"ajv": "8.18.0",
|
||||
"ajv-formats": "3.0.1",
|
||||
"jsonc-parser": "3.3.1",
|
||||
"picomatch": "4.0.4",
|
||||
"rxjs": "7.8.2",
|
||||
"source-map": "0.7.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.12.0 || >=24.0.0",
|
||||
"npm": "^6.11.0 || ^7.5.6 || >=8.0.0",
|
||||
"yarn": ">= 1.13.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"chokidar": "^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"chokidar": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@sigstore/bundle": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz",
|
||||
"integrity": "sha512-NwCl5Y0V6Di0NexvkTqdoVfmjTaQwoLM236r89KEojGmq/jMls8S+zb7yOwAPdXvbwfKDlP+lmXgAL4vKSQT+A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@sigstore/protobuf-specs": "^0.5.0"
|
||||
},
|
||||
|
|
@ -7654,7 +7731,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.2.1.tgz",
|
||||
"integrity": "sha512-qRsxPnCrbC/puegGxKuynfnxgLiHqWStrSjxkoB4YKqq3Z3s4cyZyj42ZdWFAEblNP65C+rBH8EuREHIXoi83g==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
|
|
@ -7664,7 +7740,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.5.1.tgz",
|
||||
"integrity": "sha512-/ScWUhhoFasJsSRGTVBwId1loQjjnjAfE4djL6ZhrXRpNCmPTnUKF5Jokd58ILseOMjzET3UrMOtJPS9sYeI0g==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": "^18.17.0 || >=20.5.0"
|
||||
}
|
||||
|
|
@ -7674,7 +7749,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-4.1.1.tgz",
|
||||
"integrity": "sha512-Hf4xglukg0XXQ2RiD5vSoLjdPe8OBUPA8XeVjUObheuDcWdYWrnH/BNmxZCzkAy68MzmNCxXLeurJvs6hcP2OQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@gar/promise-retry": "^1.0.2",
|
||||
"@sigstore/bundle": "^4.0.0",
|
||||
|
|
@ -7692,7 +7766,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-4.0.2.tgz",
|
||||
"integrity": "sha512-TCAzTy0xzdP79EnxSjq9KQ3eaR7+FmudLC6eRKknVKZbV7ZNlGLClAAQb/HMNJ5n2OBNk2GT1tEmU0xuPr+SLQ==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@sigstore/protobuf-specs": "^0.5.0",
|
||||
"tuf-js": "^4.1.0"
|
||||
|
|
@ -7706,7 +7779,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.1.1.tgz",
|
||||
"integrity": "sha512-qv7+G3J2cc6wwFj3yKvXOamzqhMwSk1ogPGmhpS8iXllcPrJaIIBA+4HbttlHVu1pqWTdmaCH/WE7UOC51kdoA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@sigstore/bundle": "^4.0.0",
|
||||
"@sigstore/core": "^3.2.1",
|
||||
|
|
@ -7733,7 +7805,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz",
|
||||
"integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^16.14.0 || >=18.0.0"
|
||||
}
|
||||
|
|
@ -7743,7 +7814,6 @@
|
|||
"resolved": "https://registry.npmjs.org/@tufjs/models/-/models-4.1.0.tgz",
|
||||
"integrity": "sha512-Y8cK9aggNRsqJVaKUlEYs4s7CvQ1b1ta2DVPyAimb0I2qhzjNk+A+mxvll/klL0RlfuIUei8BF7YWiua4kQqww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tufjs/canonical-json": "2.0.0",
|
||||
"minimatch": "^10.1.1"
|
||||
|
|
@ -8758,7 +8828,6 @@
|
|||
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz",
|
||||
"integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
|
|
@ -9444,7 +9513,6 @@
|
|||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-20.0.4.tgz",
|
||||
"integrity": "sha512-M3Lab8NPYlZU2exsL3bMVvMrMqgwCnMWfdZbK28bn3pK6APT/Te/I8hjRPNu1uwORY9a1eEQoifXbKPQMfMTOA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@npmcli/fs": "^5.0.0",
|
||||
"fs-minipass": "^3.0.0",
|
||||
|
|
@ -9462,11 +9530,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/cacache/node_modules/lru-cache": {
|
||||
"version": "11.5.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz",
|
||||
"integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==",
|
||||
"version": "11.5.2",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz",
|
||||
"integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
|
|
@ -9569,7 +9636,6 @@
|
|||
"resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
|
||||
"integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
|
|
@ -10605,13 +10671,6 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/err-code": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz",
|
||||
"integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/errno": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
|
||||
|
|
@ -11111,8 +11170,7 @@
|
|||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz",
|
||||
"integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0"
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "5.2.1",
|
||||
|
|
@ -11440,7 +11498,6 @@
|
|||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz",
|
||||
"integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"minipass": "^7.0.3"
|
||||
},
|
||||
|
|
@ -11706,7 +11763,6 @@
|
|||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-9.0.3.tgz",
|
||||
"integrity": "sha512-Hc+ghLoSt6QaYZUv0WBiIvmMDZuZZ7oaDvdH8MbfOO4lOsxdXLEvuC6ePoGs9H1X9oCLyq6+NVN0MKqD+ydxyg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"lru-cache": "^11.1.0"
|
||||
},
|
||||
|
|
@ -11715,11 +11771,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/hosted-git-info/node_modules/lru-cache": {
|
||||
"version": "11.5.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz",
|
||||
"integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==",
|
||||
"version": "11.5.2",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz",
|
||||
"integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": "20 || >=22"
|
||||
}
|
||||
|
|
@ -11814,8 +11869,7 @@
|
|||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz",
|
||||
"integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause"
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/http-deceiver": {
|
||||
"version": "1.2.7",
|
||||
|
|
@ -11870,7 +11924,6 @@
|
|||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.0",
|
||||
"debug": "^4.3.4"
|
||||
|
|
@ -11966,7 +12019,6 @@
|
|||
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-8.0.0.tgz",
|
||||
"integrity": "sha512-FCeMZT4NiRQGh+YkeKMtWrOmBgWjHjMJ26WQWrRQyoyzqevdaGSakUaJW5xQYmjLlUVk2qUnCjYVBax9EKKg8A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"minimatch": "^10.0.3"
|
||||
},
|
||||
|
|
@ -12044,7 +12096,6 @@
|
|||
"resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz",
|
||||
"integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
|
|
@ -12651,7 +12702,6 @@
|
|||
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz",
|
||||
"integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
|
|
@ -12710,8 +12760,7 @@
|
|||
"dev": true,
|
||||
"engines": [
|
||||
"node >= 0.2.0"
|
||||
],
|
||||
"license": "MIT"
|
||||
]
|
||||
},
|
||||
"node_modules/jsonwebtoken": {
|
||||
"version": "9.0.3",
|
||||
|
|
@ -13772,7 +13821,6 @@
|
|||
"resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.6.tgz",
|
||||
"integrity": "sha512-Je0fLJ0F5atA7F+eIlLzk+Wkcl57JDf4kf+EW8xiP5E31xOQxkIxTbgf1Oi1Lw9tRI9UEMRdI5Vz2xTzoNU1Jw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@gar/promise-retry": "^1.0.0",
|
||||
"@npmcli/agent": "^4.0.0",
|
||||
|
|
@ -14014,7 +14062,6 @@
|
|||
"resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz",
|
||||
"integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"minipass": "^7.0.3"
|
||||
},
|
||||
|
|
@ -14027,7 +14074,6 @@
|
|||
"resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-5.0.2.tgz",
|
||||
"integrity": "sha512-2d0q2a8eCi2IRg/IGubCNRJoYbA1+YPXAzQVRFmB45gdGZafyivnZ5YSEfo3JikbjGxOdntGFvBQGqaSMXlAFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minipass": "^7.0.3",
|
||||
"minipass-sized": "^2.0.0",
|
||||
|
|
@ -14045,7 +14091,6 @@
|
|||
"resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.7.tgz",
|
||||
"integrity": "sha512-TbqTz9cUwWyHS2Dy89P3ocAGUGxKjjLuR9z8w4WUTGAVgEj17/4nhgo2Du56i0Fm3Pm30g4iA8Lcqctc76jCzA==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"minipass": "^3.0.0"
|
||||
},
|
||||
|
|
@ -14058,7 +14103,6 @@
|
|||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
|
|
@ -14070,15 +14114,13 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/minipass-pipeline": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz",
|
||||
"integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"minipass": "^3.0.0"
|
||||
},
|
||||
|
|
@ -14091,7 +14133,6 @@
|
|||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
|
||||
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"yallist": "^4.0.0"
|
||||
},
|
||||
|
|
@ -14103,15 +14144,13 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/minipass-sized": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-2.0.0.tgz",
|
||||
"integrity": "sha512-zSsHhto5BcUVM2m1LurnXY6M//cGhVaegT71OfOXoprxT6o780GZd792ea6FfrQkuU4usHZIUczAQMRUE2plzA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"minipass": "^7.1.2"
|
||||
},
|
||||
|
|
@ -14124,7 +14163,6 @@
|
|||
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz",
|
||||
"integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minipass": "^7.1.2"
|
||||
},
|
||||
|
|
@ -14360,11 +14398,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/node-gyp": {
|
||||
"version": "12.3.0",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.3.0.tgz",
|
||||
"integrity": "sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg==",
|
||||
"version": "12.4.0",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.4.0.tgz",
|
||||
"integrity": "sha512-OMcPNvqTCFUnNaBlmdgq+lfNqY7gTiSmNRDjY3uAXRyudeKZEZxu3CLtjMQrx4zZxCX2b/mpNqTtwuCJgXhHkw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"env-paths": "^2.2.0",
|
||||
"exponential-backoff": "^3.1.1",
|
||||
|
|
@ -14405,17 +14442,15 @@
|
|||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz",
|
||||
"integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/node-gyp/node_modules/undici": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.26.0.tgz",
|
||||
"integrity": "sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==",
|
||||
"version": "6.28.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz",
|
||||
"integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.17"
|
||||
}
|
||||
|
|
@ -14425,7 +14460,6 @@
|
|||
"resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz",
|
||||
"integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"isexe": "^4.0.0"
|
||||
},
|
||||
|
|
@ -14450,7 +14484,6 @@
|
|||
"resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz",
|
||||
"integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"abbrev": "^4.0.0"
|
||||
},
|
||||
|
|
@ -14475,7 +14508,6 @@
|
|||
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-5.0.0.tgz",
|
||||
"integrity": "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"npm-normalize-package-bin": "^5.0.0"
|
||||
},
|
||||
|
|
@ -14488,7 +14520,6 @@
|
|||
"resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz",
|
||||
"integrity": "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"semver": "^7.1.1"
|
||||
},
|
||||
|
|
@ -14501,7 +14532,6 @@
|
|||
"resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz",
|
||||
"integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
|
|
@ -14511,7 +14541,6 @@
|
|||
"resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz",
|
||||
"integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"hosted-git-info": "^9.0.0",
|
||||
"proc-log": "^6.0.0",
|
||||
|
|
@ -14527,7 +14556,6 @@
|
|||
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.4.tgz",
|
||||
"integrity": "sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"ignore-walk": "^8.0.0",
|
||||
"proc-log": "^6.0.0"
|
||||
|
|
@ -14541,7 +14569,6 @@
|
|||
"resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-11.0.3.tgz",
|
||||
"integrity": "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"npm-install-checks": "^8.0.0",
|
||||
"npm-normalize-package-bin": "^5.0.0",
|
||||
|
|
@ -14557,7 +14584,6 @@
|
|||
"resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz",
|
||||
"integrity": "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@npmcli/redact": "^4.0.0",
|
||||
"jsonparse": "^1.3.1",
|
||||
|
|
@ -14761,11 +14787,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/p-map": {
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz",
|
||||
"integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==",
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.6.tgz",
|
||||
"integrity": "sha512-I4Prw6ivkd6p8PiYR1tXASOAOBzIJwu0TB7fqaX0c/8c3QAehNYmX57EijyGGGBt3c/BIowGwV03RVBtXvHEVg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
|
|
@ -14802,12 +14827,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/pacote": {
|
||||
"version": "21.3.1",
|
||||
"resolved": "https://registry.npmjs.org/pacote/-/pacote-21.3.1.tgz",
|
||||
"integrity": "sha512-O0EDXi85LF4AzdjG74GUwEArhdvawi/YOHcsW6IijKNj7wm8IvEWNF5GnfuxNpQ/ZpO3L37+v8hqdVh8GgWYhg==",
|
||||
"version": "21.5.1",
|
||||
"resolved": "https://registry.npmjs.org/pacote/-/pacote-21.5.1.tgz",
|
||||
"integrity": "sha512-KvcJ9iy3crysCsgqc4+PknH/w6jkrp8JN36mpZBPwNaDRwTfMZD37YzRazNstiZUOhuF5pno9f78n9mEJBavwg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@gar/promise-retry": "^1.0.0",
|
||||
"@npmcli/git": "^7.0.0",
|
||||
"@npmcli/installed-package-contents": "^4.0.0",
|
||||
"@npmcli/package-json": "^7.0.0",
|
||||
|
|
@ -14821,7 +14846,6 @@
|
|||
"npm-pick-manifest": "^11.0.1",
|
||||
"npm-registry-fetch": "^19.0.0",
|
||||
"proc-log": "^6.0.0",
|
||||
"promise-retry": "^2.0.1",
|
||||
"sigstore": "^4.0.0",
|
||||
"ssri": "^13.0.0",
|
||||
"tar": "^7.4.3"
|
||||
|
|
@ -15304,7 +15328,6 @@
|
|||
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz",
|
||||
"integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
|
|
@ -15316,20 +15339,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/promise-retry": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz",
|
||||
"integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"err-code": "^2.0.2",
|
||||
"retry": "^0.12.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
|
|
@ -15667,16 +15676,6 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/retry": {
|
||||
"version": "0.12.0",
|
||||
"resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
|
||||
"integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/rfdc": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz",
|
||||
|
|
@ -16412,7 +16411,6 @@
|
|||
"resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.1.1.tgz",
|
||||
"integrity": "sha512-endqECJkfhozrXMK5ngu/UAA0xVcVEFdnHJCElGaExypjW+HK5i6zu3NteLoaX/iFbRUbC3+DjttQs0GARr+5w==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@sigstore/bundle": "^4.0.0",
|
||||
"@sigstore/core": "^3.2.1",
|
||||
|
|
@ -16447,7 +16445,6 @@
|
|||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
|
|
@ -16575,7 +16572,6 @@
|
|||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz",
|
||||
"integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ip-address": "^10.1.1",
|
||||
"smart-buffer": "^4.2.0"
|
||||
|
|
@ -16590,7 +16586,6 @@
|
|||
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
|
||||
"integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "^4.3.4",
|
||||
|
|
@ -16677,15 +16672,13 @@
|
|||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
|
||||
"integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
|
||||
"dev": true,
|
||||
"license": "CC-BY-3.0"
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/spdx-expression-parse": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz",
|
||||
"integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"spdx-exceptions": "^2.1.0",
|
||||
"spdx-license-ids": "^3.0.0"
|
||||
|
|
@ -16695,8 +16688,7 @@
|
|||
"version": "3.0.23",
|
||||
"resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz",
|
||||
"integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==",
|
||||
"dev": true,
|
||||
"license": "CC0-1.0"
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/spdy": {
|
||||
"version": "4.0.2",
|
||||
|
|
@ -16735,7 +16727,6 @@
|
|||
"resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.1.tgz",
|
||||
"integrity": "sha512-QUiRf1+u9wPTL/76GTYlKttDEBWV1ga9ZXW8BG6kfdeyyM8LGPix9gROyg9V2+P0xNyF3X2Go526xKFdMZrHSQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"minipass": "^7.0.3"
|
||||
},
|
||||
|
|
@ -16873,11 +16864,10 @@
|
|||
}
|
||||
},
|
||||
"node_modules/tar": {
|
||||
"version": "7.5.16",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.16.tgz",
|
||||
"integrity": "sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w==",
|
||||
"version": "7.5.22",
|
||||
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz",
|
||||
"integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"dependencies": {
|
||||
"@isaacs/fs-minipass": "^4.0.0",
|
||||
"chownr": "^3.0.0",
|
||||
|
|
@ -16894,7 +16884,6 @@
|
|||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
|
||||
"integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
|
||||
"dev": true,
|
||||
"license": "BlueOak-1.0.0",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
|
|
@ -17159,7 +17148,6 @@
|
|||
"resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-4.1.0.tgz",
|
||||
"integrity": "sha512-50QV99kCKH5P/Vs4E2Gzp7BopNV+KzTXqWeaxrfu5IQJBOULRsTIS9seSsOVT8ZnGXzCyx55nYWAi4qJzpZKEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tufjs/models": "4.1.0",
|
||||
"debug": "^4.4.3",
|
||||
|
|
@ -17431,7 +17419,6 @@
|
|||
"resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz",
|
||||
"integrity": "sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@
|
|||
"@popperjs/core": "2.11.8",
|
||||
"@progress/kendo-angular-barcodes": "24.0.3",
|
||||
"@progress/kendo-angular-buttons": "24.0.3",
|
||||
"@progress/kendo-angular-charts": "24.0.3",
|
||||
"@progress/kendo-angular-chart-wizard": "24.0.3",
|
||||
"@progress/kendo-angular-charts": "24.0.3",
|
||||
"@progress/kendo-angular-common": "24.0.3",
|
||||
"@progress/kendo-angular-dateinputs": "24.0.3",
|
||||
"@progress/kendo-angular-dialog": "24.0.3",
|
||||
|
|
@ -73,15 +73,15 @@
|
|||
"zone.js": "0.16.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "21.2.13",
|
||||
"@angular/compiler-cli": "21.2.15",
|
||||
"@angular/language-service": "21.2.15",
|
||||
"@angular-devkit/build-angular": "21.2.13",
|
||||
"@angular-eslint/builder": "21.4.0",
|
||||
"@angular-eslint/eslint-plugin": "21.4.0",
|
||||
"@angular-eslint/eslint-plugin-template": "21.4.0",
|
||||
"@angular-eslint/schematics": "21.4.0",
|
||||
"@angular-eslint/template-parser": "21.4.0",
|
||||
"@angular/cli": "^21.2.19",
|
||||
"@angular/compiler-cli": "21.2.15",
|
||||
"@angular/language-service": "21.2.15",
|
||||
"@types/crypto-js": "4.2.2",
|
||||
"@types/jasmine": "6.0.0",
|
||||
"@types/jasminewd2": "2.0.13",
|
||||
|
|
|
|||
|
|
@ -33,10 +33,7 @@ export class AppBreadcrumbComponent implements OnDestroy
|
|||
{
|
||||
if (this.authService?.currentUserValue)
|
||||
{
|
||||
if (this.authService.currentUserValue.dbOnStartup)
|
||||
this.router.navigate(['/dashboard']);
|
||||
else
|
||||
this.router.navigate(['/home']);
|
||||
this.router.navigate(['/home']);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { Component, Input, OnInit, AfterViewInit, forwardRef, inject } from '@an
|
|||
import { AppComponent } from './app.component';
|
||||
import { UserService } from '../providers/user/user.service.';
|
||||
import { MenuItemComponent } from './components/menu/menuitem.component';
|
||||
import { MENU_DEFINITION, PROFILE_MENU, MenuNode, buildPermittedMenu } from './components/models/menu.definition';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
|
|
@ -28,9 +29,11 @@ export class AppMenuComponent implements OnInit, AfterViewInit
|
|||
public isAuthenicated: boolean = false;
|
||||
|
||||
private menuItems: any;
|
||||
private routePaths: Set<string>;
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
debugger;
|
||||
this.service.authService.sessionEvent.subscribe(value => this.onAuthenication(value));
|
||||
if (this.service.authService.currentUserValue)
|
||||
{
|
||||
|
|
@ -42,15 +45,14 @@ export class AppMenuComponent implements OnInit, AfterViewInit
|
|||
}
|
||||
|
||||
this.reloadMenu();
|
||||
this.modelUngrouped = [{ label: 'Main Menu', icon: 'fa fa-home', items: this.modelGrouped }];
|
||||
}
|
||||
|
||||
private reloadMenu()
|
||||
{
|
||||
if (this.isAuthenicated && this.service?.authService?.currentUserValue?.moduleIds)
|
||||
const currentUser = this.service?.authService?.currentUserValue;
|
||||
if (this.isAuthenicated && currentUser?.moduleIds)
|
||||
{
|
||||
const dbOnStartup = this.service.authService.currentUserValue.dbOnStartup;
|
||||
this.app.detailInfo = `Version: ${this.app.swVersion} | User: ${this.service.authService.currentUserValue.userName} | Login Time: ${this.service.authService.currentUserValue.loginTime}`;
|
||||
this.app.detailInfo = `Version: ${this.app.swVersion} | User: ${currentUser.userName} | Login Time: ${currentUser.loginTime}`;
|
||||
this.modelGrouped =
|
||||
[
|
||||
{
|
||||
|
|
@ -58,7 +60,7 @@ export class AppMenuComponent implements OnInit, AfterViewInit
|
|||
items:
|
||||
[
|
||||
{ label: 'Logout', icon: 'fa fa-power-off', routerLink: ['/logout'] },
|
||||
{ label: dbOnStartup ? 'Dashboard' : 'Home', icon: dbOnStartup ? 'fa fa-dashboard' : 'fa fa-home', routerLink: [dbOnStartup ? '/dashboard' : '/home'] }
|
||||
{ label: 'Home', icon: 'fa fa-home', routerLink: ['/home'] }
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -78,6 +80,8 @@ export class AppMenuComponent implements OnInit, AfterViewInit
|
|||
items: [{ label: 'Login', icon: 'fa fa-sign-in', routerLink: ['/login'] }]
|
||||
}];
|
||||
}
|
||||
|
||||
this.modelUngrouped = [{ label: 'Main Menu', icon: 'fa fa-home', items: this.modelGrouped }];
|
||||
}
|
||||
|
||||
ngAfterViewInit()
|
||||
|
|
@ -128,35 +132,18 @@ export class AppMenuComponent implements OnInit, AfterViewInit
|
|||
private onAuthenication(value: any): void
|
||||
{
|
||||
this.isAuthenicated = value.loggedIn;
|
||||
if (value.loggedIn && value.userId && value.userId !=0)
|
||||
const currentUser = this.service.authService.currentUserValue;
|
||||
if (value.loggedIn && value.userId && value.userId != 0 && currentUser)
|
||||
{
|
||||
this.service.loadMenu(value.userId).subscribe(
|
||||
{
|
||||
next: (resp: any) =>
|
||||
{
|
||||
this.menuItems = resp || [];
|
||||
this.app.userId = this.service.authService.currentUserValue?.id;
|
||||
this.app.loginId = this.service.authService.currentUserValue?.loginId;
|
||||
this.app.layoutMode = this.service.authService.currentUserValue?.menuLayout;
|
||||
this.app.notificationCount = this.service.authService.currentUserValue?.notificationCount;
|
||||
this.app.autoScrollMenu = (this.app.layoutMode === 'static' || this.app.layoutMode === 'overlay') ? 'auto-scroll-menu' : '';
|
||||
this.changeTheme(this.service.authService.currentUserValue?.themeName, this.service.authService.currentUserValue?.schemeName);
|
||||
this.menuItems = { items: this.buildMenuItems(currentUser.moduleIds) };
|
||||
this.app.userId = currentUser.id;
|
||||
this.app.loginId = currentUser.loginId;
|
||||
this.app.layoutMode = currentUser.menuLayout;
|
||||
this.app.notificationCount = currentUser.notificationCount;
|
||||
this.app.autoScrollMenu = (this.app.layoutMode === 'static' || this.app.layoutMode === 'overlay') ? 'auto-scroll-menu' : '';
|
||||
this.changeTheme(currentUser.themeName, currentUser.schemeName);
|
||||
|
||||
this.reloadMenu();
|
||||
},
|
||||
error: () =>
|
||||
{
|
||||
this.menuItems = [];
|
||||
this.app.layoutMode = 'overlay'
|
||||
this.app.loginId = this.app.autoScrollMenu = '';
|
||||
this.app.userId = this.app.notificationCount = 0;
|
||||
|
||||
this.service.authService.loggedout(false);
|
||||
this.reloadMenu();
|
||||
|
||||
this.router.navigate(['/login']);
|
||||
}
|
||||
});
|
||||
this.reloadMenu();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -171,6 +158,28 @@ export class AppMenuComponent implements OnInit, AfterViewInit
|
|||
this.router.navigate(['/login']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the activity menu out of the permission keys the login endpoint returned
|
||||
* in `moduleIds`, the profile pages are always available to a logged in user.
|
||||
*/
|
||||
private buildMenuItems(moduleIds: string[]): MenuNode[]
|
||||
{
|
||||
const routeExists = (routerLink: string): boolean => this.registeredRoutes.has(routerLink);
|
||||
|
||||
const items: MenuNode[] = buildPermittedMenu([PROFILE_MENU], moduleIds, routeExists);
|
||||
items.push(...buildPermittedMenu(MENU_DEFINITION, moduleIds, routeExists));
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
/** Paths registered in the router, keeps permitted but not yet implemented pages out of the sidebar. */
|
||||
private get registeredRoutes(): Set<string>
|
||||
{
|
||||
this.routePaths ??= new Set(this.router.config.map(route => route.path).filter(path => !!path && path !== '**'));
|
||||
|
||||
return this.routePaths;
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ const routes: Routes = [
|
|||
{ path: 'newuser', loadComponent: () => import('./users/newuser.component').then(m => m.NewUserComponent), canActivate: [AuthGuard], data: { permissionKey: 'ELIT.1.2.2_1' } },
|
||||
{ path: 'edituser', loadComponent: () => import('./users/edituser.component').then(m => m.EditUserComponent), canActivate: [AuthGuard], data: { permissionKey: 'ELIT.1.2.2_2' } },
|
||||
{ path: 'resetPwd', loadComponent: () => import('./users/resetpwd.component').then(m => m.ResetPwdComponent), canActivate: [AuthGuard], data: { permissionKey: 'ELIT.1.2.3,ELIT.1.2.3_1,ELIT.1.2.3_2' } },
|
||||
{ path: 'uploadPwd', loadComponent: () => import('./users/uploadpwd.component').then(m => m.UploadPwdComponent), canActivate: [AuthGuard], data: { permissionKey: 'ELIT.1.2.3,ELIT.1.2.3_2' } },
|
||||
{ path: 'forcelogout', loadComponent: () => import('./forcelogout/forcelogout.component').then(m => m.ForceLogoutComponent), canActivate: [AuthGuard], data: { permissionKey: 'ELIT.1.2.4,ELIT.1.2.4_1,ELIT.1.2.4_2,ELIT.1.2.4_3' } },
|
||||
{ path: 'uploadPassword', loadComponent: () => import('./users/uploadpwd.component').then(m => m.UploadPwdComponent), canActivate: [AuthGuard], data: { permissionKey: 'ELIT.1.2.5,ELIT.1.2.5_1,ELIT.1.2.5_2,ELIT.1.2.5_3' } },
|
||||
|
||||
//Landing Page
|
||||
{ path: 'home', loadComponent: () => import('./home/home.component').then(m => m.HomeComponent), canActivate: [AuthGuard]},
|
||||
|
|
|
|||
425
App/ClientApp/src/app/components/models/menu.definition.ts
Normal file
425
App/ClientApp/src/app/components/models/menu.definition.ts
Normal file
|
|
@ -0,0 +1,425 @@
|
|||
/**
|
||||
* Client side mirror of the server menu (GlobalFunctions.BuildMenu).
|
||||
*
|
||||
* The login response returns the permission keys of the logged in user in `moduleIds`,
|
||||
* so the sidebar is built here instead of calling `v1/users/loadMenu`.
|
||||
*
|
||||
* `moduleIds` holds one entry per permitted module plus the operation suffixes:
|
||||
* ELIT.1.2.2 -> select (the page itself)
|
||||
* ELIT.1.2.2_1 -> add
|
||||
* ELIT.1.2.2_2 -> edit
|
||||
* ELIT.1.2.2_3 -> delete
|
||||
*
|
||||
* Only items that are visible on the server menu are listed below, permission only
|
||||
* keys (ELIT.1.1A, ELIT.4.1.10, ...) never render so they are left out.
|
||||
*/
|
||||
export interface MenuNode
|
||||
{
|
||||
label: string;
|
||||
icon?: string;
|
||||
moduleId?: string;
|
||||
routerLink?: string;
|
||||
items?: MenuNode[];
|
||||
}
|
||||
|
||||
/** Always available to a logged in user, the server adds these without any permission check. */
|
||||
export const PROFILE_MENU: MenuNode =
|
||||
{
|
||||
label: 'User Profile', icon: 'fa fa-user-md',
|
||||
items:
|
||||
[
|
||||
{ label: 'My Profile', icon: 'fa fa-user', routerLink: 'myprofile' },
|
||||
{ label: 'Change My Password', icon: 'fa fa-unlock', routerLink: 'changemypwd' },
|
||||
{ label: 'Change My Theme', icon: 'fa fa-user', routerLink: 'changemytheme' },
|
||||
{ label: 'WhatsApp Message', icon: 'fa fa-whatsapp', routerLink: 'sendwhatsappmsg' },
|
||||
{ label: 'Access Log', icon: 'fa fa-list-alt', routerLink: 'accesslog' }
|
||||
]
|
||||
};
|
||||
|
||||
export const MENU_DEFINITION: MenuNode[] =
|
||||
[
|
||||
{
|
||||
moduleId: 'ELIT.1', label: 'System Setup', icon: 'fa fa-sun-o',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.1.3', label: 'Label Setting', icon: 'fa fa-sliders', routerLink: 'labelsetting' },
|
||||
{ moduleId: 'ELIT.1.1', label: 'System Information', icon: 'fa fa-cog', routerLink: 'thissystem' },
|
||||
{
|
||||
moduleId: 'ELIT.1.2', label: 'User Management', icon: 'fa fa-users',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.1.2.1', label: 'Groups', icon: 'fa fa-address-book-o', routerLink: 'groups' },
|
||||
{ moduleId: 'ELIT.1.2.2', label: 'Users', icon: 'fa fa-address-card-o', routerLink: 'users' },
|
||||
{ moduleId: 'ELIT.1.2.3', label: 'Upload Passwords', icon: 'fa fa-upload', routerLink: 'uploadPwd' },
|
||||
{ moduleId: 'ELIT.1.2.4', label: 'Force Logout', icon: 'fa fa-address-card-o', routerLink: 'forcelogout' }
|
||||
]
|
||||
},
|
||||
{ moduleId: 'ELIT.1.3A', label: 'Lookup Data', icon: 'fa fa-sliders', routerLink: 'lookupdata' },
|
||||
{ moduleId: 'ELIT.1.4', label: 'Custom Report Setup', icon: 'fa fa-table', routerLink: 'customreports' },
|
||||
{
|
||||
moduleId: 'ELIT.1.5', label: 'Basic Setup', icon: 'fa fa-wrench',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.1.5.1', label: 'Clients', icon: 'fa fa-address-card-o', routerLink: 'clients' },
|
||||
{ moduleId: 'ELIT.1.5.2', label: 'Suppliers', icon: 'fa fa-credit-card', routerLink: 'suppliers' },
|
||||
{ moduleId: 'ELIT.1.5.3', label: 'Employees', icon: 'fa fa-user-plus', routerLink: 'employees' },
|
||||
{ moduleId: 'ELIT.1.5.4', label: 'Project Leads', icon: 'fa fa-user-circle-o', routerLink: 'projectleads' },
|
||||
{ moduleId: 'ELIT.1.5.5', label: 'Project Managers', icon: 'fa fa-user-circle-o', routerLink: 'projectmgts' },
|
||||
{ moduleId: 'ELIT.1.5.6', label: 'Projects', icon: 'fa fa-product-hunt', routerLink: 'projects' },
|
||||
{ moduleId: 'ELIT.1.5.7', label: 'Stores', icon: 'fa fa-pencil-square', routerLink: 'stores' },
|
||||
{ moduleId: 'ELIT.1.5.8', label: 'Banks & Branches', icon: 'fa fa-university', routerLink: 'bankbranches' },
|
||||
{ moduleId: 'ELIT.1.5.9', label: 'Bank Accounts', icon: 'fa fa-credit-card', routerLink: 'bankaccounts' },
|
||||
{ moduleId: 'ELIT.1.5.10', label: 'GL Codes', icon: 'fa fa-book', routerLink: 'glcodes' },
|
||||
{ moduleId: 'ELIT.1.5.11', label: 'User Clients & Projects', icon: 'fa fa-product-hunt', routerLink: 'userprojects' },
|
||||
{ moduleId: 'ELIT.1.5.12', label: 'User Suppliers', icon: 'fa fa-product-hunt', routerLink: 'usersuppliers' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.2', label: 'Authentication Process', icon: 'fa fa-cogs',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.2.1', label: 'Authentication', icon: 'fa fa-check', routerLink: 'authentications' },
|
||||
{ moduleId: 'ELIT.2.2', label: 'Authorization', icon: 'fa fa-check-square-o', routerLink: 'authorizations' },
|
||||
{ moduleId: 'ELIT.2.3', label: 'Deactivation', icon: 'fa fa-window-close-o', routerLink: 'deactivations' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.3', label: 'General Ledger', icon: 'fa fa-university',
|
||||
items:
|
||||
[
|
||||
{
|
||||
moduleId: 'ELIT.3.1', label: 'Basic Setup', icon: 'fa fa-wrench',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.3.1.1', label: 'Chart of Accounts', icon: 'fa fa-th-list', routerLink: 'chartofaccounts' },
|
||||
{ moduleId: 'ELIT.3.1.2', label: 'Fix GL Balance', icon: 'fa fa-wrench', routerLink: 'fixBalance' },
|
||||
{ moduleId: 'ELIT.3.1.3', label: 'GL Head Identification', icon: 'fa fa-cog', routerLink: 'identifyglhead' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.3.2', label: 'Transactions', icon: 'fa fa-building',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.3.2.1', label: 'GL Transactions', icon: 'fa fa-archive', routerLink: 'gltrans' },
|
||||
{ moduleId: 'ELIT.3.2.2', label: 'Upload Auto Voucher', icon: 'fa fa-upload', routerLink: 'gltranav' },
|
||||
{ moduleId: 'ELIT.3.2.3', label: 'Year End Process', icon: 'fa fa-cog', routerLink: 'yearendprocess' },
|
||||
{ moduleId: 'ELIT.3.2.4', label: 'Undo Year End', icon: 'fa fa-undo', routerLink: 'undoyearend' },
|
||||
{ moduleId: 'ELIT.3.2.5', label: 'Authorize Transactions', icon: 'fa fa-check-square', routerLink: 'authgltrans' },
|
||||
{ moduleId: 'ELIT.3.2.7', label: 'Rollback Transactions', icon: 'fa fa-undo', routerLink: 'rollbackgltrans' },
|
||||
{ moduleId: 'ELIT.3.2.8', label: 'Dashboard Processor', icon: 'fa fa-cog', routerLink: 'dbprocessor' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.3.3', label: 'Reports', icon: 'fa fa-newspaper-o',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.3.3.1', label: 'Ledger', icon: 'fa fa-file-text-o', routerLink: 'glledger' },
|
||||
{ moduleId: 'ELIT.3.3.2', label: 'Monthly Turnover', icon: 'fa fa-file-text-o', routerLink: 'turnover' },
|
||||
{ moduleId: 'ELIT.3.3.3', label: 'Trial Balance', icon: 'fa fa-file-text-o', routerLink: 'trialbalance' },
|
||||
{ moduleId: 'ELIT.3.3.8', label: 'Income & Expenditure', icon: 'fa fa-file-text-o', routerLink: 'incomeexpense' },
|
||||
{ moduleId: 'ELIT.3.3.4', label: 'Day Book', icon: 'fa fa-file-text-o', routerLink: 'daybook' },
|
||||
{ moduleId: 'ELIT.3.3.5', label: 'Bank/Cash Book', icon: 'fa fa-file-text-o', routerLink: 'bankcashbook' },
|
||||
{ moduleId: 'ELIT.3.3.6', label: 'Schedule', icon: 'fa fa-file-text-o', routerLink: 'glschedule' },
|
||||
{ moduleId: 'ELIT.3.3.7', label: 'Previous Final Reports', icon: 'fa fa-file-text-o', routerLink: 'prvfinalreports' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.4', label: 'Order To Cash', icon: 'fa fa-money',
|
||||
items:
|
||||
[
|
||||
{
|
||||
moduleId: 'ELIT.4.1', label: 'Basic Setup', icon: 'fa fa-wrench',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.4.1.1', label: 'Income GL Codes', icon: 'fa fa-pencil-square-o', routerLink: 'incomeglcodes' },
|
||||
{ moduleId: 'ELIT.4.1.2', label: 'VAT Liability GL Codes', icon: 'fa fa-pencil-square', routerLink: 'vatglcodes' },
|
||||
{ moduleId: 'ELIT.4.1.3', label: 'AIT GL Codes', icon: 'fa fa-book', routerLink: 'aitglcodes' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.4.2', label: 'Regular Activities', icon: 'fa fa-building',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.4.2.1', label: 'Purchase Orders', icon: 'fa fa-smile-o', routerLink: 'purchaseorders' },
|
||||
{ moduleId: 'ELIT.4.2.2', label: 'Invoices', icon: 'fa fa-share-square', routerLink: 'invoices' },
|
||||
{ moduleId: 'ELIT.4.2.3', label: 'Payments', icon: 'fa fa-money', routerLink: 'payments' },
|
||||
{ moduleId: 'ELIT.4.2.4', label: 'Freeze PO/Invoice', icon: 'fa fa-archive', routerLink: 'archivepoinvs' },
|
||||
{ moduleId: 'ELIT.4.2.8', label: 'VAT Challan Update', icon: 'fa fa-sliders', routerLink: 'updvatchlano2c' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.4.3', label: 'Reports', icon: 'fa fa-newspaper-o',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.4.3.1', label: 'GL Vouchers', icon: 'fa fa-th-list', routerLink: 'glvouchers' },
|
||||
{ moduleId: 'ELIT.4.3.2', label: 'Transactional Reports', icon: 'fa fa-file-text-o', routerLink: 'txnreports' },
|
||||
{ moduleId: 'ELIT.4.3.3', label: 'Contract Expiry Report', icon: 'fa fa-file-text-o', routerLink: 'contexpryreports' },
|
||||
{ moduleId: 'ELIT.4.3.4', label: 'Customized Report', icon: 'fa fa-file-text-o', routerLink: 'customreporto2c' },
|
||||
{ moduleId: 'ELIT.4.3.5', label: 'Client Ledger', icon: 'fa fa-file-text-o', routerLink: 'clientledgero2c' },
|
||||
{ moduleId: 'ELIT.4.3.6', label: 'Monthly Trends', icon: 'fa fa-file-text-o', routerLink: 'monthlytrendso2c' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.9', label: 'Sales System', icon: 'fa fa-sitemap',
|
||||
items:
|
||||
[
|
||||
{
|
||||
moduleId: 'ELIT.9.1', label: 'Basic Setup', icon: 'fa fa-wrench',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.9.1.1', label: 'Market Hierarchies', icon: 'fa fa-pencil-square', routerLink: 'markethierarchies' },
|
||||
{ moduleId: 'ELIT.9.1.2', label: 'Sales Points', icon: 'fa fa-pencil-square', routerLink: 'salespoints' },
|
||||
{ moduleId: 'ELIT.9.1.3', label: 'Product Hierarchies', icon: 'fa fa-pencil-square', routerLink: 'producthierarchies' },
|
||||
{ moduleId: 'ELIT.9.1.4', label: 'Brands', icon: 'fa fa-pencil-square', routerLink: 'brands' },
|
||||
{ moduleId: 'ELIT.9.1.5', label: 'SKUs', icon: 'fa fa-pencil-square', routerLink: 'skus' },
|
||||
{ moduleId: 'ELIT.9.1.6', label: 'Channel Hierarchies', icon: 'fa fa-pencil-square', routerLink: 'channelhierarchies' },
|
||||
{ moduleId: 'ELIT.9.1.7', label: 'Customers', icon: 'fa fa-pencil-square', routerLink: 'customers' },
|
||||
{ moduleId: 'ELIT.9.1.8', label: 'Sales Officers', icon: 'fa fa-pencil-square', routerLink: 'salesofficers' },
|
||||
{ moduleId: 'ELIT.9.1.9', label: 'Product Prices', icon: 'fa fa-pencil-square', routerLink: 'skupricess' },
|
||||
{ moduleId: 'ELIT.9.1.10', label: 'Product VAT-SD-Comm', icon: 'fa fa-pencil-square', routerLink: 'skuvattaxes' },
|
||||
{ moduleId: 'ELIT.9.1.11', label: 'Customer Credit', icon: 'fa fa-pencil-square', routerLink: 'customercredit' },
|
||||
{ moduleId: 'ELIT.9.1.12', label: 'External Products', icon: 'fa fa-pencil-square', routerLink: 'extnlproducts' },
|
||||
{ moduleId: 'ELIT.9.1.13', label: 'Sales Promotions', icon: 'fa fa-pencil-square', routerLink: 'salespromotions' },
|
||||
{ moduleId: 'ELIT.9.1.14', label: 'Order Authorization Limit', icon: 'fa fa-pencil-square', routerLink: 'ordrauthlimit' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.9.2', label: 'Regular Activities', icon: 'fa fa-building',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.9.2.1', label: 'Customer Opening Balance', icon: 'fa fa-puzzle-piece', routerLink: 'slscustsopnbal' },
|
||||
{ moduleId: 'ELIT.9.2.2', label: 'Customer Adjustment', icon: 'fa fa-pencil-square', routerLink: 'slscustsadjustment' },
|
||||
{ moduleId: 'ELIT.9.2.3', label: 'Initial Stock', icon: 'fa fa-puzzle-piece', routerLink: 'slsinitstocks' },
|
||||
{ moduleId: 'ELIT.9.2.4', label: 'Receive Stocks', icon: 'fa fa-reply-all', routerLink: 'slsrcvstocks' },
|
||||
{ moduleId: 'ELIT.9.2.5', label: 'Sales Orders', icon: 'fa fa-pencil-square', routerLink: 'slsorders' },
|
||||
{ moduleId: 'ELIT.9.2.6', label: 'Spot Sales', icon: 'fa fa-pencil-square', routerLink: 'slsdirectinvoices' },
|
||||
{ moduleId: 'ELIT.9.2.7', label: 'Sales Invoices', icon: 'fa fa-pencil-square', routerLink: 'slsinvoices' },
|
||||
{ moduleId: 'ELIT.9.2.8', label: 'Payment Against Invoices', icon: 'fa fa-archive', routerLink: 'slsinvpayments' },
|
||||
{ moduleId: 'ELIT.9.2.9', label: 'Stock Transfers', icon: 'fa fa-archive', routerLink: 'slsstockxfers' },
|
||||
{ moduleId: 'ELIT.9.2.10', label: 'Receive Transferred Stocks', icon: 'fa fa-archive', routerLink: 'slsstockxferrcvs' },
|
||||
{ moduleId: 'ELIT.9.2.11', label: 'Fix Transfer Anomalies', icon: 'fa fa-archive', routerLink: 'slsstockxferanmls' },
|
||||
{ moduleId: 'ELIT.9.2.12', label: 'Sales Return', icon: 'fa fa-archive', routerLink: 'slsrtnstocks' },
|
||||
{ moduleId: 'ELIT.9.2.13', label: 'Damage Stocks', icon: 'fa fa-archive', routerLink: 'slsdmgstocks' },
|
||||
{ moduleId: 'ELIT.9.2.14', label: 'Stock Take', icon: 'fa fa-archive', routerLink: 'slsstocktakes' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.9.3', label: 'Reports', icon: 'fa fa-newspaper-o',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.9.3.1', label: 'Customer Balance', icon: 'fa fa-th-list', routerLink: 'salescustbalance' },
|
||||
{ moduleId: 'ELIT.9.3.2', label: 'Customer Ledger', icon: 'fa fa-th-list', routerLink: 'salescustledger' },
|
||||
{ moduleId: 'ELIT.9.3.3', label: 'Current Stock', icon: 'fa fa-file-text-o', routerLink: 'salescurrentstock' },
|
||||
{ moduleId: 'ELIT.9.3.4', label: 'Stock Ledger', icon: 'fa fa-th-list', routerLink: 'salesstockledger' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.5', label: 'Purchase To Pay', icon: 'fa fa-shopping-cart',
|
||||
items:
|
||||
[
|
||||
{
|
||||
moduleId: 'ELIT.5.1', label: 'Basic Setup', icon: 'fa fa-wrench',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.5.1.1', label: 'Product Types', icon: 'fa fa-address-card-o', routerLink: 'prodtypes' },
|
||||
{ moduleId: 'ELIT.5.1.2', label: 'Products', icon: 'fa fa-university', routerLink: 'products' },
|
||||
{ moduleId: 'ELIT.5.1.3', label: 'WO Terms & Conditions', icon: 'fa fa-pencil-square-o', routerLink: 'woterms' },
|
||||
{ moduleId: 'ELIT.5.1.4', label: 'VAT & AIT Rates', icon: 'fa fa-user-circle-o', routerLink: 'aitvatratep2p' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.5.2', label: 'Regular Activities', icon: 'fa fa-building',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.5.2.0', label: 'Initial Stock', icon: 'fa fa-puzzle-piece', routerLink: 'initstocksp2p' },
|
||||
{ moduleId: 'ELIT.5.2.13', label: 'Purchase Requisitions', icon: 'fa fa-puzzle-piece', routerLink: 'purchrequisitionsp2p' },
|
||||
{ moduleId: 'ELIT.5.2.1', label: 'Issue Work Orders', icon: 'fa fa-smile-o', routerLink: 'workordersp2p' },
|
||||
{ moduleId: 'ELIT.5.2.12', label: 'Advance Payments', icon: 'fa fa-money', routerLink: 'advpaymntsp2p' },
|
||||
{ moduleId: 'ELIT.5.2.2', label: 'Receive Items at CS', icon: 'fa fa-reply-all', routerLink: 'stksrcvdatcsp2p' },
|
||||
{ moduleId: 'ELIT.5.2.3', label: 'Receive Invoices', icon: 'fa fa-money', routerLink: 'invoicesp2p' },
|
||||
{ moduleId: 'ELIT.5.2.4', label: 'Cash Purchase', icon: 'fa fa-archive', routerLink: 'cashpurchases' },
|
||||
{ moduleId: 'ELIT.5.2.5', label: 'Payment Against Invoice', icon: 'fa fa-archive', routerLink: 'paymentsp2p' },
|
||||
{ moduleId: 'ELIT.5.2.6', label: 'Goods Transfer', icon: 'fa fa-archive', routerLink: 'gdstransfers' },
|
||||
{ moduleId: 'ELIT.5.2.7', label: 'Receive Goods Transfer', icon: 'fa fa-archive', routerLink: 'gdsreceives' },
|
||||
{ moduleId: 'ELIT.5.2.8', label: 'Fix Transfer Anomalies', icon: 'fa fa-archive', routerLink: 'transferanomalies' },
|
||||
{ moduleId: 'ELIT.5.2.9', label: 'Consumption of Goods', icon: 'fa fa-archive', routerLink: 'gdscnsmpnsp2p' },
|
||||
{ moduleId: 'ELIT.5.2.10', label: 'Damage of Goods', icon: 'fa fa-archive', routerLink: 'gdsdamagesp2p' },
|
||||
{ moduleId: 'ELIT.5.2.11', label: 'Stock Take of Goods', icon: 'fa fa-archive', routerLink: 'stocktakes' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.5.3', label: 'Reports', icon: 'fa fa-newspaper-o',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.5.3.1', label: 'GL Vouchers', icon: 'fa fa-th-list', routerLink: 'glvouchersp2p' },
|
||||
{ moduleId: 'ELIT.5.3.2', label: 'Current Stock', icon: 'fa fa-file-text-o', routerLink: 'currentstockp2p' },
|
||||
{ moduleId: 'ELIT.5.3.3', label: 'Stock Ledger', icon: 'fa fa-file-text-o', routerLink: 'stockledgerp2p' },
|
||||
{ moduleId: 'ELIT.5.3.4', label: 'Supplier Ledger', icon: 'fa fa-file-text-o', routerLink: 'supplierledgerp2p' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.6', label: 'Fixed Assets', icon: 'fa fa-sitemap',
|
||||
items:
|
||||
[
|
||||
{
|
||||
moduleId: 'ELIT.6.1', label: 'Basic Setup', icon: 'fa fa-wrench',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.6.1.1', label: 'Asset Types', icon: 'fa fa-address-card-o', routerLink: 'assettypes' },
|
||||
{ moduleId: 'ELIT.6.1.2', label: 'Asset Categories', icon: 'fa fa-university', routerLink: 'assetcategories' },
|
||||
{ moduleId: 'ELIT.6.1.3', label: 'Asset Items', icon: 'fa fa-credit-card', routerLink: 'assetitems' },
|
||||
{ moduleId: 'ELIT.6.1.6', label: 'Asset Hierarchies', icon: 'fa fa-credit-card', routerLink: 'assethierarchies' },
|
||||
{ moduleId: 'ELIT.6.1.4', label: 'Locations', icon: 'fa fa-pencil-square', routerLink: 'locations' },
|
||||
{ moduleId: 'ELIT.6.1.5', label: 'VAT & AIT Rates', icon: 'fa fa-user-circle-o', routerLink: 'aitvatratefa' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.6.2', label: 'Regular Activities', icon: 'fa fa-building',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.6.2.0', label: 'Initial Fixed Assets', icon: 'fa fa-puzzle-piece', routerLink: 'initstocksfa' },
|
||||
{ moduleId: 'ELIT.6.2.15', label: 'Purchase Requisitions', icon: 'fa fa-puzzle-piece', routerLink: 'purchrequisitionsfa' },
|
||||
{ moduleId: 'ELIT.6.2.1', label: 'Issue Work Orders', icon: 'fa fa-smile-o', routerLink: 'workordersfa' },
|
||||
{ moduleId: 'ELIT.6.2.14', label: 'Advance Payments', icon: 'fa fa-money', routerLink: 'advpaymntsfa' },
|
||||
{ moduleId: 'ELIT.6.2.2', label: 'Received Items At CS', icon: 'fa fa-reply-all', routerLink: 'stksrcvdatcsfa' },
|
||||
{ moduleId: 'ELIT.6.2.3', label: 'Receive Invoices', icon: 'fa fa-money', routerLink: 'invoicesfa' },
|
||||
{ moduleId: 'ELIT.6.2.4', label: 'Payment Against Invoice', icon: 'fa fa-archive', routerLink: 'paymentsfa' },
|
||||
{ moduleId: 'ELIT.6.2.5', label: 'Item Acquisition', icon: 'fa fa-smile-o', routerLink: 'itemsacquisition' },
|
||||
{ moduleId: 'ELIT.6.2.5A', label: 'Update Item Data', icon: 'fa fa-smile-o', routerLink: 'updfaitmdescription' },
|
||||
{ moduleId: 'ELIT.6.2.6', label: 'Item Installation', icon: 'fa fa-share-square', routerLink: 'astinstalns' },
|
||||
{ moduleId: 'ELIT.6.2.7', label: 'Transfer Fixed Asset', icon: 'fa fa-money', routerLink: 'assetxfers' },
|
||||
{ moduleId: 'ELIT.6.2.8', label: 'Write Off', icon: 'fa fa-archive', routerLink: 'astwriteoffs' },
|
||||
{ moduleId: 'ELIT.6.2.9', label: 'Asset Sales', icon: 'fa fa-archive', routerLink: 'astsales' },
|
||||
{ moduleId: 'ELIT.6.2.10', label: 'Add Asset Value', icon: 'fa fa-archive', routerLink: 'astaddvalues' },
|
||||
{ moduleId: 'ELIT.6.2.11', label: 'Reduce Asset Value', icon: 'fa fa-archive', routerLink: 'assetreducesvalue' },
|
||||
{ moduleId: 'ELIT.6.2.12', label: 'No Depreciation Mark', icon: 'fa fa-user-circle-o', routerLink: 'nodeprnmark' },
|
||||
{ moduleId: 'ELIT.6.2.13', label: 'Depreciation Calculation', icon: 'fa fa-user-circle-o', routerLink: 'calcdepreciation' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.6.3', label: 'Reports', icon: 'fa fa-newspaper-o',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.6.3.1', label: 'GL Vouchers', icon: 'fa fa-th-list', routerLink: 'glvouchersfa' },
|
||||
{ moduleId: 'ELIT.6.3.2', label: 'Current Stock', icon: 'fa fa-file-text-o', routerLink: 'currentstockfa' },
|
||||
{ moduleId: 'ELIT.6.3.3', label: 'Stock Ledger', icon: 'fa fa-file-text-o', routerLink: 'stockledgerfa' },
|
||||
{ moduleId: 'ELIT.6.3.4', label: 'Item Details', icon: 'fa fa-file-text-o', routerLink: 'faitemdetail' },
|
||||
{ moduleId: 'ELIT.6.3.5', label: 'Fixed Asset List', icon: 'fa fa-file-text-o', routerLink: 'faitemsatglance' },
|
||||
{ moduleId: 'ELIT.6.3.6', label: 'Waiting Acquisition', icon: 'fa fa-file-text-o', routerLink: 'faitemswtngaqstn' },
|
||||
{ moduleId: 'ELIT.6.3.7', label: 'Acquired Assets', icon: 'fa fa-file-text-o', routerLink: 'faitemsacquire' },
|
||||
{ moduleId: 'ELIT.6.3.8', label: 'Waiting Installation', icon: 'fa fa-file-text-o', routerLink: 'faitemswtnginstall' },
|
||||
{ moduleId: 'ELIT.6.3.9', label: 'No Depreciation Marked', icon: 'fa fa-file-text-o', routerLink: 'faitemsnodprn' },
|
||||
{ moduleId: 'ELIT.6.3.10', label: 'Depreciation Report', icon: 'fa fa-file-text-o', routerLink: 'faitemsdprnrpt' },
|
||||
{ moduleId: 'ELIT.6.3.11', label: 'Supplier Ledger', icon: 'fa fa-file-text-o', routerLink: 'fasupplierledger' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.7', label: 'Task Management', icon: 'fa fa-users',
|
||||
items:
|
||||
[
|
||||
{
|
||||
moduleId: 'ELIT.7.1', label: 'Basic Setup', icon: 'fa fa-wrench',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.7.1.1', label: 'Developers', icon: 'fa fa-user-circle-o', routerLink: 'developers' },
|
||||
{ moduleId: 'ELIT.7.1.2', label: 'Support Teams', icon: 'fa fa-user-circle-o', routerLink: 'supportteams' },
|
||||
{ moduleId: 'ELIT.7.1.2A', label: 'QA Teams', icon: 'fa fa-user-circle-o', routerLink: 'qateams' },
|
||||
{ moduleId: 'ELIT.7.1.3', label: 'Priorities', icon: 'fa fa-check-square-o', routerLink: 'priorities' },
|
||||
{ moduleId: 'ELIT.7.1.4', label: 'Task Statuses', icon: 'fa fa-pencil-square', routerLink: 'taskstatuses' },
|
||||
{ moduleId: 'ELIT.7.1.5', label: 'Task Categories', icon: 'fa fa-check-square-o', routerLink: 'taskcategories' },
|
||||
{ moduleId: 'ELIT.7.1.6', label: 'Task Types', icon: 'fa fa-check-square-o', routerLink: 'tasktypes' },
|
||||
{ moduleId: 'ELIT.7.1.7', label: 'Team Spaces', icon: 'fa fa-user-circle-o', routerLink: 'teamspaces' },
|
||||
{ moduleId: 'ELIT.7.1.9', label: 'User Projects', icon: 'fa fa-product-hunt', routerLink: 'tsuserprojects' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.7.2', label: 'Regular Activities', icon: 'fa fa-building',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.7.2.1', label: 'Tasks', icon: 'fa fa-smile-o', routerLink: 'tasks' },
|
||||
{ moduleId: 'ELIT.7.2.2', label: 'My Tasks', icon: 'fa fa-tasks', routerLink: 'mytasks' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.7.3', label: 'Reports', icon: 'fa fa-newspaper-o',
|
||||
items: [{ moduleId: 'ELIT.7.3.1', label: 'Task Reports', icon: 'fa fa-file-text-o', routerLink: 'taskreport' }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.8', label: 'Attendance System', icon: 'fa fa-calendar',
|
||||
items:
|
||||
[
|
||||
{
|
||||
moduleId: 'ELIT.8.1', label: 'Basic Setup', icon: 'fa fa-wrench',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.8.1.1', label: 'Ip/Mac Entries', icon: 'fa fa-user-circle-o', routerLink: 'ipmacentries' },
|
||||
{ moduleId: 'ELIT.8.1.2', label: 'Holiday Calendar', icon: 'fa fa-calendar', routerLink: 'calendar' },
|
||||
{ moduleId: 'ELIT.8.1.3', label: 'Ramadan Calendar', icon: 'fa fa-calendar', routerLink: 'ramadan' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.8.2', label: 'Regular Activities', icon: 'fa fa-building',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.8.2.1', label: 'Employee Leaves', icon: 'fa fa-smile-o', routerLink: 'empleaves' },
|
||||
{ moduleId: 'ELIT.8.2.2', label: 'Late Entries', icon: 'fa fa-tasks', routerLink: 'emplates' },
|
||||
{ moduleId: 'ELIT.8.2.3', label: 'Client Visits', icon: 'fa fa-tasks', routerLink: 'empclntvsts' },
|
||||
{ moduleId: 'ELIT.8.2.4', label: 'Home Offices', icon: 'fa fa-tasks', routerLink: 'emphmofcs' },
|
||||
{ moduleId: 'ELIT.8.2.6', label: 'Asset Bookings', icon: 'fa fa-tasks', routerLink: 'assetbookings' }
|
||||
]
|
||||
},
|
||||
{
|
||||
moduleId: 'ELIT.8.3', label: 'Reports', icon: 'fa fa-newspaper-o',
|
||||
items:
|
||||
[
|
||||
{ moduleId: 'ELIT.8.3.1', label: 'Login History', icon: 'fa fa-tasks', routerLink: 'loginhistory' },
|
||||
{ moduleId: 'ELIT.8.3.2', label: 'Attendance Reports', icon: 'fa fa-file-text-o', routerLink: 'atnreports' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Keeps the nodes the user is permitted to see.
|
||||
*
|
||||
* A group is kept only when its own key is permitted and at least one of its children survives,
|
||||
* a page is kept only when its key is permitted and the route is actually registered in the app,
|
||||
* so a permitted but not yet implemented page never lands in the sidebar as a dead link.
|
||||
*/
|
||||
export function buildPermittedMenu(nodes: MenuNode[], moduleIds: string[], routeExists: (routerLink: string) => boolean): MenuNode[]
|
||||
{
|
||||
const permitted: MenuNode[] = [];
|
||||
for (const node of nodes ?? [])
|
||||
{
|
||||
if (node.moduleId && !moduleIds?.includes(node.moduleId))
|
||||
continue;
|
||||
|
||||
if (node.items?.length)
|
||||
{
|
||||
const items = buildPermittedMenu(node.items, moduleIds, routeExists);
|
||||
if (items.length)
|
||||
permitted.push({ moduleId: node.moduleId, label: node.label, icon: node.icon, items: items });
|
||||
}
|
||||
else if (node.routerLink && routeExists(node.routerLink))
|
||||
{
|
||||
permitted.push({ moduleId: node.moduleId, label: node.label, icon: node.icon, routerLink: node.routerLink });
|
||||
}
|
||||
}
|
||||
|
||||
return permitted;
|
||||
}
|
||||
|
|
@ -1,35 +1,39 @@
|
|||
export class UserModel
|
||||
{
|
||||
id: number;
|
||||
logId: number;
|
||||
expires?: Date;
|
||||
loginId: string;
|
||||
userName: string;
|
||||
systemDate: Date;
|
||||
idleTime: number;
|
||||
pingTime: number;
|
||||
loginTime: string;
|
||||
logoutTime?: Date;
|
||||
validUser: boolean;
|
||||
employeeId: number;
|
||||
timeoutTime: number;
|
||||
loginStatus: number;
|
||||
bmProcessId: number;
|
||||
prProcessId: number;
|
||||
dbOnStartup: boolean;
|
||||
batchEnabled: boolean;
|
||||
viewOwnTaskOnly: boolean;
|
||||
authMethod: number;
|
||||
notificationCount: number;
|
||||
pwdChangeRequired: boolean;
|
||||
authenticationToken?: string;
|
||||
authRequiredAtLogin: boolean;
|
||||
|
||||
idsValue: string;
|
||||
moduleIds: any[] = [];
|
||||
//Returned by the login endpoint since the token based authentication
|
||||
refreshToken?: string;
|
||||
userPlatFormType?: number;
|
||||
userRoleType?: string;
|
||||
employeeNumber?: string;
|
||||
|
||||
//Permission keys of the logged in user, "<moduleId>" = select, "_1" = add, "_2" = edit, "_3" = delete
|
||||
moduleIds: string[] = [];
|
||||
returnStatus: number;
|
||||
returnMessage: any[] = [];
|
||||
validationErrors: any[] = [];
|
||||
|
||||
//Not returned by the login endpoint anymore, defaults are applied on the client
|
||||
logId?: number;
|
||||
idleTime?: number;
|
||||
pingTime?: number;
|
||||
employeeId?: number;
|
||||
timeoutTime?: number;
|
||||
dbOnStartup?: boolean;
|
||||
schemeName: string = 'dark';
|
||||
themeName: string = 'yellow';
|
||||
menuLayout: string = 'overlay';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()" style="background-image:linear-gradient(360deg, #17c3f0,#1D81b1);">
|
||||
<div class="mb-2 login-body">
|
||||
<div class="login-content">
|
||||
<h1 style="color:green;">Ease Taskforce</h1>
|
||||
<h1 style="color:green;">Auto Crop</h1>
|
||||
<p style="color: black;">Please use the form to Sign-in.</p>
|
||||
|
||||
<div class="mb-3 col-lg-4 col-md-8 col-sm-12">
|
||||
|
|
@ -41,38 +41,7 @@
|
|||
<input type="checkbox" id="remberMe" name="remberMe" formControlName="remberMe" class="form-check-input" />
|
||||
<label class="form-check-label" for="remberMe" style="font-weight:500;color:black;">Remember me</label>
|
||||
</div>
|
||||
@if (attendanceEnabled)
|
||||
{
|
||||
<div class="mb-1 form-check form-switch">
|
||||
<input type="checkbox" id="atndnceLogin" name="atndnceLogin" formControlName="atndnceLogin" class="form-check-input" (change)="eventCheck($event)" />
|
||||
<label class="form-check-label" for="atndnceLogin" style="font-weight:500;color:maroon;">Login into Attendance System</label>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (remarksRequired && f.atndnceLogin.value)
|
||||
{
|
||||
<div class="mb-2 col-lg-4 col-md-8 col-sm-12">
|
||||
<span class="required" style="color: black;">Late Login Remarks:</span>
|
||||
<br />
|
||||
<kendo-combobox [data]="lateLoginRemarks"
|
||||
id="loginRemarks"
|
||||
name="loginRemarks"
|
||||
formControlName="loginRemarks"
|
||||
[textField]="'itemValue'"
|
||||
[valueField]="'itemValue'"
|
||||
[valuePrimitive]="true"
|
||||
[placeholder]="'Late Login Remarks...'"
|
||||
[kendoDropDownFilter]="filterSettings"
|
||||
[ngClass]="{ 'k-invalid': submitted && f.loginRemarks.errors}">
|
||||
</kendo-combobox>
|
||||
@if (submitted && f.loginRemarks.errors)
|
||||
{
|
||||
<div class="invalid-feedback">
|
||||
Late Login Remarks is required
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
<div class="mt-3 mb-4">
|
||||
<button style="min-width:6.2em;" class="ui-button ui-widget ui-state-default ui-corner-all ui-button-raised ui-button-text-only">
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { AppConfig, ComputerConfig } from '../components/models/app.config.model
|
|||
})
|
||||
export class LoginComponent implements OnInit
|
||||
{
|
||||
|
||||
private readonly router = inject(Router);
|
||||
private readonly route = inject(ActivatedRoute);
|
||||
private readonly modalService = inject(NgbModal);
|
||||
|
|
@ -58,17 +59,15 @@ export class LoginComponent implements OnInit
|
|||
|
||||
constructor()
|
||||
{
|
||||
debugger;
|
||||
this.alertService.clear();
|
||||
const configSvc = inject(ConfigurationService);
|
||||
this.appConfig = configSvc.configuration?.appConfig;
|
||||
this.compConfig = configSvc.configuration?.computerConfig;
|
||||
|
||||
debugger;
|
||||
if (this.authService.currentUserValue?.id)
|
||||
{
|
||||
if (this.authService.currentUserValue.dbOnStartup)
|
||||
this.router.navigate(['/dashboard']);
|
||||
else
|
||||
this.router.navigate(['/home']);
|
||||
this.router.navigate(['/home']);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -79,6 +78,7 @@ export class LoginComponent implements OnInit
|
|||
|
||||
ngOnInit(): void
|
||||
{
|
||||
debugger;
|
||||
this.alertService.clear();
|
||||
this.spinnerService.hide();
|
||||
this.appVersion = packageJson.version;
|
||||
|
|
@ -132,6 +132,7 @@ export class LoginComponent implements OnInit
|
|||
|
||||
private loadLoginRemarks(): void
|
||||
{
|
||||
debugger;
|
||||
const autId = this.fnSvc.cipherData(Api.cipherSecretKey ?? '');
|
||||
this.authService.getLoginRemarks(autId).subscribe(
|
||||
{
|
||||
|
|
@ -266,110 +267,107 @@ export class LoginComponent implements OnInit
|
|||
{
|
||||
this.loading = false;
|
||||
this.spinnerService.hide();
|
||||
|
||||
//The endpoint answers 200 only for a valid user, guard anyway so a partial
|
||||
//response never leaves a half logged in session behind
|
||||
if (!data?.validUser || !data.id || !data.authenticationToken)
|
||||
{
|
||||
this.abortLogin(this.parseReturnMessage(data) || 'Login failed, please try again.');
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.authRequiredAtLogin)
|
||||
{
|
||||
this.authService.loggedIn(data, false);
|
||||
const modalOptions: NgbModalOptions = { backdrop: 'static', keyboard: false, backdropClass: 'customBackdrop', centered: true, windowClass: 'misc-width' };
|
||||
const modalRef = this.modalService.open(OtpComponent, modalOptions);
|
||||
|
||||
modalRef.componentInstance.fromParent = { userId: data.id, authMethod: data.authMethod };
|
||||
modalRef.result.then((result) =>
|
||||
{
|
||||
if (result)
|
||||
{
|
||||
if (data.pwdChangeRequired)
|
||||
{
|
||||
this.authService.loggedIn(data, false);
|
||||
const modalOptions1: NgbModalOptions = { backdrop: 'static', keyboard: false, backdropClass: 'customBackdrop', centered: true };
|
||||
const modalRef1 = this.modalService.open(ChangePwdComponent, modalOptions1);
|
||||
modalRef1.componentInstance.fromParent = { userId: data.id, loginId: data.loginId, userName: data.userName };
|
||||
|
||||
modalRef1.result.then(() =>
|
||||
{
|
||||
this.authService.loggedout();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
this.authService.refreshToken().subscribe(
|
||||
{
|
||||
next: () =>
|
||||
{
|
||||
localStorage.setItem('OnlineSalesAutoCrop.sysdate', sysDate);
|
||||
if (this.f.remberMe.value)
|
||||
localStorage.setItem('OnlineSalesAutoCrop.rlap', loginInf);
|
||||
else
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.rlap');
|
||||
|
||||
this.idleSvc.startMonitor();
|
||||
this.authService.raiseLoginEvent(data.id, true);
|
||||
const returnUrl = this.authService.currentUserValue?.dbOnStartup ? this.route.snapshot.queryParams['returnUrl'] ?? '/dashboard' : this.route.snapshot.queryParams['returnUrl'] ?? '/home';
|
||||
this.router.navigate([returnUrl]);
|
||||
},
|
||||
error: () =>
|
||||
{
|
||||
this.authService.loggedout();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.rlap');
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.sysdate');
|
||||
|
||||
this.authService.loggedout();
|
||||
}
|
||||
});
|
||||
this.verifyOtp(data, sysDate, loginInf);
|
||||
}
|
||||
else if (data.pwdChangeRequired)
|
||||
{
|
||||
this.authService.loggedIn(data, false);
|
||||
const modalOptions: NgbModalOptions = { backdrop: 'static', keyboard: false, backdropClass: 'customBackdrop', centered: true };
|
||||
const modalRef = this.modalService.open(ChangePwdComponent, modalOptions);
|
||||
modalRef.componentInstance.fromParent = { userId: data.id, loginId: data.loginId, userName: data.userName };;
|
||||
|
||||
modalRef.result.then(() =>
|
||||
{
|
||||
this.authService.loggedout();
|
||||
});
|
||||
this.changePassword(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.authService.refreshToken().subscribe(
|
||||
{
|
||||
next: () =>
|
||||
{
|
||||
localStorage.setItem('OnlineSalesAutoCrop.sysdate', sysDate);
|
||||
if (this.f.remberMe.value)
|
||||
localStorage.setItem('OnlineSalesAutoCrop.rlap', loginInf);
|
||||
else
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.rlap');
|
||||
|
||||
this.idleSvc.startMonitor();
|
||||
this.authService.raiseLoginEvent(data.id, true);
|
||||
const returnUrl = this.authService.currentUserValue?.dbOnStartup ? this.route.snapshot.queryParams['returnUrl'] ?? '/dashboard' : this.route.snapshot.queryParams['returnUrl'] ?? '/home';
|
||||
this.router.navigate([returnUrl]);
|
||||
},
|
||||
error: () =>
|
||||
{
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.rlap');
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.sysdate');
|
||||
|
||||
this.authService.loggedout();
|
||||
}
|
||||
});
|
||||
this.completeLogin(data, sysDate, loginInf);
|
||||
}
|
||||
},
|
||||
error: (errorMessage: string) =>
|
||||
{
|
||||
this.loading = false;
|
||||
this.spinnerService.hide();
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.rlap');
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.sysdate');
|
||||
|
||||
this.alertService.error(errorMessage);
|
||||
this.abortLogin(errorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Second factor, the user is cached already so the otp call travels with the token. */
|
||||
private verifyOtp(data: any, sysDate: string, loginInf: string): void
|
||||
{
|
||||
this.authService.loggedIn(data, false);
|
||||
const modalOptions: NgbModalOptions = { backdrop: 'static', keyboard: false, backdropClass: 'customBackdrop', centered: true, windowClass: 'misc-width' };
|
||||
const modalRef = this.modalService.open(OtpComponent, modalOptions);
|
||||
|
||||
modalRef.componentInstance.fromParent = { userId: data.id, authMethod: data.authMethod };
|
||||
modalRef.result.then((result) =>
|
||||
{
|
||||
if (!result)
|
||||
{
|
||||
this.abortLogin('');
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.pwdChangeRequired)
|
||||
this.changePassword(data);
|
||||
else
|
||||
this.completeLogin(data, sysDate, loginInf);
|
||||
},
|
||||
() => this.abortLogin(''));
|
||||
}
|
||||
|
||||
/** Expired/first time password, the user has to sign in again with the new one. */
|
||||
private changePassword(data: any): void
|
||||
{
|
||||
this.authService.loggedIn(data, false);
|
||||
const modalOptions: NgbModalOptions = { backdrop: 'static', keyboard: false, backdropClass: 'customBackdrop', centered: true };
|
||||
const modalRef = this.modalService.open(ChangePwdComponent, modalOptions);
|
||||
modalRef.componentInstance.fromParent = { userId: data.id, loginId: data.loginId, userName: data.userName };
|
||||
|
||||
modalRef.result.then(() => this.authService.loggedout(), () => this.authService.loggedout());
|
||||
}
|
||||
|
||||
/**
|
||||
* The login response already carries the authentication token, the refresh token and the
|
||||
* permission keys (moduleIds), so nothing else has to be fetched before entering the app.
|
||||
* Raising the login event makes the sidebar rebuild itself from those permission keys.
|
||||
*/
|
||||
private completeLogin(data: any, sysDate: string, loginInf: string): void
|
||||
{
|
||||
localStorage.setItem('OnlineSalesAutoCrop.sysdate', sysDate);
|
||||
if (this.f.remberMe.value)
|
||||
localStorage.setItem('OnlineSalesAutoCrop.rlap', loginInf);
|
||||
else
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.rlap');
|
||||
|
||||
this.idleSvc.startMonitor();
|
||||
this.authService.raiseLoginEvent(data.id, true);
|
||||
|
||||
const returnUrl = this.route.snapshot.queryParams['returnUrl'] ?? '/home';
|
||||
this.router.navigate([returnUrl]);
|
||||
}
|
||||
|
||||
private abortLogin(errorMessage: string): void
|
||||
{
|
||||
this.loading = false;
|
||||
this.spinnerService.hide();
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.rlap');
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.sysdate');
|
||||
|
||||
this.authService.loggedout();
|
||||
if (errorMessage)
|
||||
this.alertService.error(errorMessage);
|
||||
}
|
||||
|
||||
private parseReturnMessage(data: any): string
|
||||
{
|
||||
return Array.isArray(data?.returnMessage) ? data.returnMessage.join('<br/>') : '';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
58
App/ClientApp/src/app/users/uploadpwd.component.html
Normal file
58
App/ClientApp/src/app/users/uploadpwd.component.html
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<form [formGroup]="uploadPwdForm" (ngSubmit)="onSubmit()">
|
||||
<div class="mb-2">
|
||||
<span>Excel file must have <b>EmployeeCode</b> and <b>Password</b> columns in the first row.</span>
|
||||
</div>
|
||||
|
||||
<div class="mb-2 row g-0">
|
||||
<span class="required">Excel File:</span>
|
||||
<br />
|
||||
<div class="col-lg-4 col-md-8 col-sm-12">
|
||||
<div class="custom-file">
|
||||
<input type="file" class="custom-file-input" accept="{{acceptFileType}}" formControlName="uploadFile" name="uploadFile" id="uploadFile" (change)="onFileSelected($event)" [ngClass]="{ 'is-invalid': submitted && f.fileName.errors }">
|
||||
<label class="custom-file-label" #uploadFileLabel for="uploadFile" data-browse="Browse"><i class="fa fa-search button-search"></i> Choose file</label>
|
||||
</div>
|
||||
@if (submitted && f.fileName.errors)
|
||||
{
|
||||
<div class="invalid-feedback d-block">
|
||||
<span>Please select an excel file to upload.</span>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-2 col-lg-4 col-md-8 col-sm-12">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="forcePasswordChange" formControlName="forcePasswordChange">
|
||||
<label class="form-check-label" for="forcePasswordChange">Force user to change password at next login</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (canSave)
|
||||
{
|
||||
<div class="mb-2">
|
||||
<hr class="osds" />
|
||||
<button class="ui-button ui-widget ui-state-default ui-corner-all ui-button-raised ui-button-text-only" [disabled]="loading">
|
||||
<span class="ui-button-text-only ui-c"><i class="fa fa-upload button-edit" aria-hidden="true"></i> Upload & Update</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (totalRows > 0)
|
||||
{
|
||||
<div class="mb-2">
|
||||
<span>Total Row(s): <b>{{totalRows}}</b> | Updated: <b>{{successCount}}</b> | Failed: <b>{{failedCount}}</b></span>
|
||||
<br />
|
||||
<kendo-grid id="grdUploadPwd"
|
||||
[data]="items"
|
||||
[resizable]="true"
|
||||
[loading]="loading"
|
||||
[rowClass]="rowCallback"
|
||||
class="grid-font-900">
|
||||
<kendo-grid-column field="rowNo" title="Row" [width]="70" class="cell-padding" [headerStyle]="{'font-weight':'bold'}" [style]="{'text-align':'center'}"></kendo-grid-column>
|
||||
<kendo-grid-column field="employeeCode" title="Employee Code" [width]="150" class="cell-padding" [headerStyle]="{'font-weight':'bold'}"></kendo-grid-column>
|
||||
<kendo-grid-column field="loginId" title="Login Id" [width]="150" class="cell-padding" [headerStyle]="{'font-weight':'bold'}"></kendo-grid-column>
|
||||
<kendo-grid-column field="message" title="Remarks" class="cell-padding" [headerStyle]="{'font-weight':'bold'}"></kendo-grid-column>
|
||||
</kendo-grid>
|
||||
</div>
|
||||
}
|
||||
</form>
|
||||
143
App/ClientApp/src/app/users/uploadpwd.component.ts
Normal file
143
App/ClientApp/src/app/users/uploadpwd.component.ts
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
import { Router } from '@angular/router';
|
||||
import { NgClass } from '@angular/common';
|
||||
import { KENDO_GRID } from '@progress/kendo-angular-grid';
|
||||
import { Component, ElementRef, OnInit, ViewChild, inject } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
|
||||
import { AlertService } from '../components/alert';
|
||||
import { BreadcrumbService } from '../breadcrumb.service';
|
||||
import { UserService } from '../../providers/user/user.service.';
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: 'user-upload-pwd',
|
||||
templateUrl: './uploadpwd.component.html',
|
||||
styles: ['#grdUploadPwd tr.failed{color:#f00;}'],
|
||||
imports: [FormsModule, ReactiveFormsModule, NgClass, KENDO_GRID]
|
||||
})
|
||||
export class UploadPwdComponent implements OnInit
|
||||
{
|
||||
private readonly router = inject(Router);
|
||||
private readonly service = inject(UserService);
|
||||
private readonly formBuilder = inject(FormBuilder);
|
||||
private readonly alertService = inject(AlertService);
|
||||
|
||||
@ViewChild('uploadFileLabel') private uploadFileLabel: ElementRef;
|
||||
|
||||
public uploadPwdForm: FormGroup;
|
||||
public loading: boolean = false;
|
||||
public canSave: boolean = false;
|
||||
public submitted: boolean = false;
|
||||
public items: any[] = [];
|
||||
public totalRows: number = 0;
|
||||
public successCount: number = 0;
|
||||
public failedCount: number = 0;
|
||||
public readonly acceptFileType: string = '.xls,.xlsx';
|
||||
|
||||
private formData: FormData;
|
||||
|
||||
constructor()
|
||||
{
|
||||
const bcService = inject(BreadcrumbService);
|
||||
|
||||
this.alertService.clear();
|
||||
bcService.setItems([{ label: 'System Setup' }, { label: 'User Management' }, { label: 'Upload Passwords', routerLink: ['/uploadPwd'] }]);
|
||||
if (!this.service.currentUserValue)
|
||||
{
|
||||
this.router.navigate(['/login']);
|
||||
return;
|
||||
}
|
||||
|
||||
this.canSave = this.service.currentUserValue?.moduleIds?.includes('ELIT.1.2.3_2');
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
this.uploadPwdForm = this.formBuilder.group(
|
||||
{
|
||||
uploadFile: '',
|
||||
fileName: ['', Validators.required],
|
||||
forcePasswordChange: false
|
||||
});
|
||||
}
|
||||
|
||||
get f() { return this.uploadPwdForm.controls; }
|
||||
|
||||
public rowCallback = (context: any) => { return { failed: !context.dataItem.updated }; };
|
||||
|
||||
public onFileSelected(event: any): void
|
||||
{
|
||||
this.clearData();
|
||||
|
||||
const selectedFile = event.target.files[0];
|
||||
if (!selectedFile)
|
||||
{
|
||||
this.uploadPwdForm.patchValue({ fileName: '' });
|
||||
return;
|
||||
}
|
||||
|
||||
const fileName = selectedFile.name;
|
||||
const extension = fileName.substring(fileName.lastIndexOf('.')).toLowerCase();
|
||||
if (extension !== '.xls' && extension !== '.xlsx')
|
||||
{
|
||||
this.uploadPwdForm.patchValue({ fileName: '' });
|
||||
this.alertService.error('Only excel (.xls/.xlsx) file is allowed to process.');
|
||||
return;
|
||||
}
|
||||
|
||||
this.uploadFileLabel.nativeElement.innerText = fileName;
|
||||
this.uploadPwdForm.patchValue({ fileName: fileName });
|
||||
|
||||
this.formData = new FormData();
|
||||
this.formData.append('fileName', fileName);
|
||||
this.formData.append('fileData', selectedFile);
|
||||
}
|
||||
|
||||
public clearData(): void
|
||||
{
|
||||
this.items = [];
|
||||
this.totalRows = this.successCount = this.failedCount = 0;
|
||||
}
|
||||
|
||||
public onSubmit(): void
|
||||
{
|
||||
this.submitted = true;
|
||||
this.alertService.clear();
|
||||
if (this.uploadPwdForm.invalid || !this.formData)
|
||||
return;
|
||||
|
||||
this.clearData();
|
||||
this.loading = true;
|
||||
this.formData.set('forcePasswordChange', `${this.f.forcePasswordChange.value === true}`);
|
||||
this.service.uploadPasswords(this.formData).subscribe(
|
||||
{
|
||||
next: (resp: any) =>
|
||||
{
|
||||
this.loading = false;
|
||||
this.items = resp.items ?? [];
|
||||
this.totalRows = resp.totalRows ?? 0;
|
||||
this.failedCount = resp.failedCount ?? 0;
|
||||
this.successCount = resp.successCount ?? 0;
|
||||
|
||||
if (resp.returnStatus === 200)
|
||||
{
|
||||
if (this.failedCount > 0)
|
||||
this.alertService.info(resp.returnMessage);
|
||||
else
|
||||
this.alertService.success(resp.returnMessage);
|
||||
|
||||
this.submitted = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.alertService.error(resp.returnMessage);
|
||||
}
|
||||
},
|
||||
error: (errorMessage: string) =>
|
||||
{
|
||||
this.loading = false;
|
||||
this.alertService.error(errorMessage);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ export class AuthGuard
|
|||
let keys: string[] = permissionkey.split(',');
|
||||
for (const key of keys)
|
||||
{
|
||||
found = currentUser.moduleIds.includes(key);
|
||||
found = currentUser.moduleIds?.includes(key) === true;
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
|
|
@ -33,7 +33,7 @@ export class AuthGuard
|
|||
if (found === false)
|
||||
this.router.navigate(['/accessdenied']);
|
||||
|
||||
return true;
|
||||
return found;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ export class AuthenticationService
|
|||
|
||||
constructor()
|
||||
{
|
||||
debugger;
|
||||
this.sessionEvent = new EventEmitter();
|
||||
this.taskStatusEvent = new EventEmitter();
|
||||
this.notificationEvent = new EventEmitter();
|
||||
|
|
@ -58,12 +59,7 @@ export class AuthenticationService
|
|||
return this.api.postAsync<any>('v1/users/login', params)
|
||||
.pipe(map(user =>
|
||||
{
|
||||
user.moduleIds = JSON.parse(this.functionService.decipherData(user.idsValue));
|
||||
user.idsValue = '';
|
||||
const encString: string = this.functionService.encrypt(JSON.stringify(user));
|
||||
localStorage.setItem('OnlineSalesAutoCrop.currentUser', encString);
|
||||
|
||||
this.currentUserSubject.next(user);
|
||||
this.storeCurrentUser(user);
|
||||
return user;
|
||||
}));
|
||||
}
|
||||
|
|
@ -73,6 +69,31 @@ export class AuthenticationService
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The login endpoint returns the permission keys in `moduleIds` and no longer returns the
|
||||
* theme/idle settings, so the client defaults are applied here before the user is cached.
|
||||
*/
|
||||
public storeCurrentUser(user: any): void
|
||||
{
|
||||
user.moduleIds = user.moduleIds ?? [];
|
||||
|
||||
const defaults = new UserModel();
|
||||
user.themeName = user.themeName || defaults.themeName;
|
||||
user.schemeName = user.schemeName || defaults.schemeName;
|
||||
user.menuLayout = user.menuLayout || defaults.menuLayout;
|
||||
|
||||
const encString: string = this.functionService.encrypt(JSON.stringify(user));
|
||||
localStorage.setItem('OnlineSalesAutoCrop.currentUser', encString);
|
||||
|
||||
this.currentUserSubject.next(user);
|
||||
}
|
||||
|
||||
/** True when the permission key is granted, pass "<moduleId>_1|_2|_3" to check add/edit/delete. */
|
||||
public hasPermission(moduleId: string): boolean
|
||||
{
|
||||
return this.currentUserValue?.moduleIds?.includes(moduleId) === true;
|
||||
}
|
||||
|
||||
public refreshToken()
|
||||
{
|
||||
try
|
||||
|
|
@ -98,13 +119,13 @@ export class AuthenticationService
|
|||
{
|
||||
try
|
||||
{
|
||||
if (!this.currentUserValue?.logId)
|
||||
if (!this.currentUserValue?.id)
|
||||
{
|
||||
localStorage.removeItem('OnlineSalesAutoCrop.currentUser');
|
||||
return;
|
||||
}
|
||||
|
||||
const params: any = { logId: this.currentUserValue.logId, attendanceLogout: attendanceLogout, ipAddress: ipAddress, macAddress: macAddress, hostName: hostName, logoutRemarks: logoutRemarks };
|
||||
const params: any = { logId: this.currentUserValue.logId ?? 0, attendanceLogout: attendanceLogout, ipAddress: ipAddress, macAddress: macAddress, hostName: hostName, logoutRemarks: logoutRemarks };
|
||||
return this.api.postAsync<any>('v1/users/logout', params)
|
||||
.pipe(map(value =>
|
||||
{
|
||||
|
|
@ -141,7 +162,7 @@ export class AuthenticationService
|
|||
{
|
||||
try
|
||||
{
|
||||
const params: any = { logId: this.currentUserValue.logId };
|
||||
const params: any = { logId: this.currentUserValue?.logId ?? 0 };
|
||||
return this.api.postAsync<any>('v1/users/sessionExpired', params)
|
||||
.pipe(map(value =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ import { inject, Injectable } from '@angular/core';
|
|||
|
||||
import { Base } from '../base/base';
|
||||
|
||||
@Injectable()
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class UserService extends Base
|
||||
{
|
||||
public addUser(params: any)
|
||||
|
|
@ -112,6 +114,11 @@ export class UserService extends Base
|
|||
return this.api.post('v1/users/resetPassword', params);
|
||||
}
|
||||
|
||||
public uploadPasswords(formdata: FormData)
|
||||
{
|
||||
return this.api.uplaodFormData('v1/users/uploadPasswords', formdata);
|
||||
}
|
||||
|
||||
public findAccount(accountId: string)
|
||||
{
|
||||
const params: any = { accountId: accountId };
|
||||
|
|
|
|||
3
Deployment/App/prerendered-routes.json
Normal file
3
Deployment/App/prerendered-routes.json
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"routes": {}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user