using Ease.NetCore.DataAccess;
using Ease.NetCore.DataAccess.SQL;
using Ease.NetCore.Utility;
using Microsoft.Data.SqlClient;
using Microsoft.Extensions.Options;
using OnlineSalesAutoCrop.CoreAPI.Models;
using OnlineSalesAutoCrop.CoreAPI.Models.Global;
using OnlineSalesAutoCrop.CoreAPI.Models.Objects.Systems;
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Integrations;
using OnlineSalesAutoCrop.CoreAPI.Models.Requests.Systems;
using OnlineSalesAutoCrop.CoreAPI.Models.Responses.Integrations;
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Integrations;
using OnlineSalesAutoCrop.CoreAPI.Services.Contracts.Systems;
using System;
using System.Collections.Generic;
using System.Data;
using System.Text;
using System.Threading.Tasks;

namespace OnlineSalesAutoCrop.CoreAPI.Services.Services.Integrations;

public class IntegrationService : IIntegrationService
{
    private readonly AppSettings _settings;
    private readonly IUserService _userService;

    public IntegrationService(IOptions<AppSettings> options, IUserService userService)
    {
        _settings = options.Value;
        _userService = userService;
    }

    
    public async Task<CustomerByCompanyCodeResponse> GetCustomerByCompanyCodeAsync(CustomerByCompanyCodeRequest request)
    {
        CustomerByCompanyCodeResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                await GetCustomerByCompanyCodeAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<IntegrationCustomerResponse> UpsertCustomerAsync(IntegrationCustomerRequest request)
    {
        IntegrationCustomerResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode,true);
            try
            {
                var customer = await GetCustomerByCompanyCodeAsync(tc, new CustomerByCompanyCodeRequest() { CompanyCode = request.CompanyCode, CustomerNumber = request.CustomerNumber });

                if( customer != null && customer.CustomerId>0)
                {
                    //Update Here
                    UpdateCustomer(tc, request);
                    response.IsUpdated = true;
                }
                else
                {
                    //Insert Here 

                    CreateCustomer(tc, request);             
                    response.IsUpdated = false;
                }

                response.CustomerNumber = request.CustomerNumber;
                response.CompanyCode = request.CompanyCode;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }


    public async Task<IntegrationEmployeeResponse> GetEmployeeBySalesOrgAsync(EmployeeIntegrationByComapanyRequest request)
    {
        IntegrationEmployeeResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                await GetEmployeeBySalesOrgAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<EmployeeIntegrationReqResponse> UpsertEmployeeAsync(IntegrationEmployeeRequest request)
    {
        EmployeeIntegrationReqResponse response = new EmployeeIntegrationReqResponse();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
            try
            {
                IntegrationEmployeeResponse employee = await GetEmployeeBySalesOrgAsync(tc,
                            new EmployeeIntegrationByComapanyRequest() { EmployeeVendorCode = request.EmployeeVendorCode, CompanyCode = request.CompanyCode });


                if (employee != null && employee.EmployeeId > 0)
                {
                    UpdateEmployee(tc, request);             
                    response.IsUpdated = true;
                }
                else
                {
                    InsertEmployee(tc, request);
                    response.IsUpdated = false;
                }

                int roleTypeId = GetRegionAreaTerritoryLevel(request);
                bool isUserExist = await IsUserExistByEmployeeNumberAsync(tc, request.EmployeeVendorCode);

                if (!isUserExist)
                {
                    AppUserCreateRequest appUser = new()
                    {
                        LoginId = request.EmployeeVendorCode,
                        UserName = request.EmployeeVendorCode,
                        Status = (int)EnumStatus.Authorized,
                        AccessStatus = (int)EnumAccessStatus.FirstTime,
                        MobileNo = request.MobileNo,
                        EmailAddress = request.Mail,
                        IsLocked = 0,
                        Password ="12345",
                        UserRoleType = roleTypeId,
                        UserPlatformId = (int)UserPlatFormType.AppUser,
                        EmployeeNumber = request.EmployeeVendorCode
                    };

                    await AddUserAsync(tc, appUser);
                }

                response.EmployeeVendorCode = request.EmployeeVendorCode;
                response.CompanyCode = request.CompanyCode;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    private  int GetRegionAreaTerritoryLevel(IntegrationEmployeeRequest request)
    {
        bool hasRegion = !string.IsNullOrWhiteSpace(request.RegionAreaCode);
        bool hasArea = !string.IsNullOrWhiteSpace(request.AreaAVSalesUnitCode);
        bool hasTerritory = !string.IsNullOrWhiteSpace(request.Territory);

        if (hasRegion && hasArea && hasTerritory)
        {
            return (int)UserRoleTypeEnum.OrderCollector;
        }

        if (hasRegion && hasArea && !hasTerritory)
        {
            return (int)UserRoleTypeEnum.OrderValidator;
        }

        if (hasRegion && !hasArea && !hasTerritory)
        {
            return (int)UserRoleTypeEnum.OrderApprover;
        }

        return 0;
    }

    public async Task<MaterialIntegrationReqResponse> UpsertMaterialAsync(IntegrationMaterialRequest request)
    {
        MaterialIntegrationReqResponse response = new MaterialIntegrationReqResponse();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
            try
            {
                IntegrationMaterialResponse meterial = await GetMaterialByCodeAsync(tc,
                            new GetMaterialByCodeRequest() { MaterialCode = request.MaterialCode });

                if (meterial != null && meterial.MeterialId > 0)
                {
                    UpdateMaterial(tc, request);
                    response.IsUpdated = true;
                }
                else
                {
                    CreateMaterial(tc, request);
                    response.IsUpdated = false;
                }

                response.MaterialCode = request.MaterialCode;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<IntegrationMaterialResponse> GetMaterialByCodeAsync(GetMaterialByCodeRequest request)
    {
        IntegrationMaterialResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                response= await GetMaterialByCodeAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }


    public async Task<MaterialIntegrationPriceReqResponse> UpsertMaterialPriceAsync(IntegrationMaterialPriceRequest request)
    {
        MaterialIntegrationPriceReqResponse response = new MaterialIntegrationPriceReqResponse();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
            try
            {
                IntegrationMaterialPriceResponse meterialPrice = await GetMaterialPriceByCodeAndConditionTypeAsync(tc,
                            new GetMaterialPriceByCodeRequest() { MaterialCode = request.MaterialCode, ConditionType = request.ConditionType,
                                SalesOrg=request.SalesOrg, CustomerNumber = request.CustomerNumber,CustomerGroupCode = request.CustomerGroupCode });

                if (meterialPrice != null && !string.IsNullOrWhiteSpace(meterialPrice.MaterialCode))
                {
                    UpdateMaterialPrice(tc, request);
                    response.IsUpdated = true;
                }
                else
                {
                    CreateMaterialPrice(tc, request);
                    response.IsUpdated = false;
                }

                response.MaterialCode = request.MaterialCode;
                response.ConditionType = request.ConditionType;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<IntegrationMaterialPriceResponse> GetMaterialPriceByCodeAsync(GetMaterialPriceByCodeRequest request)
    {
        IntegrationMaterialPriceResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                response = await GetMaterialPriceByCodeAndConditionTypeAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }


    public async Task<MaterialFreeGoodsByReqResponse> UpsertMaterialFreeGoodsAsync(IntegrationMaterialFreeGoodsRequest request)
    {
        MaterialFreeGoodsByReqResponse response = new MaterialFreeGoodsByReqResponse();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
            try
            {
                IntegrationMaterialFreeGoodsResponse meterialFreeGoods = await GetMaterialFreeGoodsByFilterAsync(tc,
                            new GetMaterialFreeGoodsByFilterRequest() { SalesOrg = request.SalesOrg, DistributionChannel = request.DistributionChannel,
                                CustomerPriceGroup = request.CustomerPriceGroup,MaterialCode = request.MaterialCode, CustomerNumber = request.CustomerNumber });

                if (meterialFreeGoods != null && !string.IsNullOrWhiteSpace(meterialFreeGoods.MaterialCode))
                {
                    UpdateMaterialFreeGoods(tc, request);
                    response.IsUpdated = true;
                }
                else
                {
                    CreateMaterialFreeGoods(tc, request);
                    response.IsUpdated = false;
                }

                response.SalesOrg = request.SalesOrg;
                response.DistributionChannel = request.DistributionChannel;
                response.CustomerPriceGroup = request.CustomerPriceGroup;
                response.MaterialCode = request.MaterialCode;
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<IntegrationMaterialFreeGoodsResponse> GetMaterialFreeGoodseByFilterAsync(GetMaterialFreeGoodsByFilterRequest request)
    {
        IntegrationMaterialFreeGoodsResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                response = await GetMaterialFreeGoodsByFilterAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }


    public async Task<IntegrationPaymentTermReqResponse> UpsertPaymentTermsAsync(IntegrationPaymentTermRequest request)
    {
        IntegrationPaymentTermReqResponse response = new IntegrationPaymentTermReqResponse();

        using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode, true);
        try
        {
            IntegrationPaymentTermResponse paymentTerms = await GetPaymentTermByFilterAsync(tc,
                        new GetIntegrationPaymentTermRequest()
                        {
                            CreditCode = request.CreditCode,
                            SalesOrg = request.SalesOrg
                        });

            if (paymentTerms != null && !string.IsNullOrWhiteSpace(paymentTerms.CreditCode))
            {
                UpdatePaymentTerm(tc, request);
                response.IsUpdated = true;
            }
            else
            {
                CreatePaymentTerm(tc, request);
                response.IsUpdated = false;
            }

            response.SalesOrg = request.SalesOrg;
            response.CreditCode = request.CreditCode;
            tc.End();
        }
        catch (Exception ie)
        {
            tc?.HandleError();

            throw DBCustomError.GenerateCustomError(ie);
        }

        return response;
    }

    public async Task<IntegrationPaymentTermResponse> GetPaymentTermsByFilterAsync(GetIntegrationPaymentTermRequest request)
    {
        IntegrationPaymentTermResponse response = new();
        try
        {
            using TransactionContext tc = await TransactionContext.BeginAsync(_settings.DefaultConnection.ConnectionNode);
            try
            {
                response = await GetPaymentTermByFilterAsync(tc, request);
                tc.End();
            }
            catch (Exception ie)
            {
                tc?.HandleError();

                throw DBCustomError.GenerateCustomError(ie);
            }
        }
        catch (Exception ex)
        {
            throw;
        }

        return response;
    }

    public async Task<IntegrationInvoiceReqResponse> SaveInvoiceAsync(IntegrationInvoiceRequest request)
    {
        throw new NotImplementedException();
    }


    #region Customer Private Functions

    private async Task<CustomerByCompanyCodeResponse> GetCustomerByCompanyCodeAsync(TransactionContext tc, CustomerByCompanyCodeRequest request)
    {
        CustomerByCompanyCodeResponse response = new CustomerByCompanyCodeResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@CompanyCode",    pType: SqlDbType.NVarChar, pValue: request.CompanyCode),
                SqlHelperExtension.CreateInParam(pName: "@CustomerNumber", pType: SqlDbType.NVarChar, pValue: request.CustomerNumber)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetCustomerByCompanyCode", parameterValues: p))
            {
                if (dr.Read())
                {
                    response = new CustomerByCompanyCodeResponse()
                    {
                        CustomerId = dr.GetInt32(0),
                        CustomerNumber = dr.GetString(1),
                        CustomerName = dr.GetString(2),
                        AccountGroup = dr.GetString(3),
                        AccountGroupDescription = dr.GetString(4),
                        CompanyCode = dr.GetString(5),
                        CompanyCodeDescription = dr.GetString(6),
                        SalesOrganization = dr.GetString(7),
                        SalesOrganizationDescription = dr.GetString(8),
                        DistributionChannel = dr.GetString(9),
                        DistributionChannelDescription = dr.GetString(10),
                        Division = dr.GetString(11),
                        DivisionDescription = dr.GetString(12),
                        MobileNumber = dr.GetString(13),
                        EmailAddress = dr.GetString(14),
                        BusinessTaxNumber = dr.GetString(15),
                        CreditLimit = dr.GetDecimal(16),
                        SalesGroup = dr.GetString(17),
                        SalesGroupDescription = dr.GetString(18),
                        CustomerGroup = dr.GetString(19),
                        CustomerGroupDescription = dr.GetString(20),
                        CustomerPriceGroup = dr.GetString(21),
                        CustomerPriceGroupDescription = dr.GetString(22),
                        StatusCode = dr.GetString(23),
                        StatusDescription = dr.GetString(24),
                        PaymentTerms = dr.GetString(25),
                        PaymentTermsDescription = dr.GetString(26),
                        SearchTerm = dr.GetString(27),
                        AreaRegion = dr.GetString(28),
                        AreaRegionDescription = dr.GetString(29),
                        SalesUnitAreaAV = dr.GetString(30),
                        SalesUnitAreaAVDescription = dr.GetString(31),
                        Territory = dr.GetString(32),
                        TerritoryName = dr.GetString(33),
                        Plant = dr.GetString(34),
                        PlantName = dr.GetString(35)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }
    
    private bool CreateCustomer(TransactionContext tc, IntegrationCustomerRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@CustomerNumber",                 SqlDbType.NVarChar, request.CustomerNumber),
                SqlHelperExtension.CreateInParam("@CustomerName",                   SqlDbType.NVarChar, request.CustomerName),

                SqlHelperExtension.CreateInParam("@AccountGroup",                   SqlDbType.NVarChar, request.AccountGroup),
                SqlHelperExtension.CreateInParam("@AccountGroupDescription",        SqlDbType.NVarChar, request.AccountGroupDescription),

                SqlHelperExtension.CreateInParam("@CompanyCode",                    SqlDbType.NVarChar, request.CompanyCode),
                SqlHelperExtension.CreateInParam("@CompanyCodeDescription",         SqlDbType.NVarChar, request.CompanyCodeDescription),

                SqlHelperExtension.CreateInParam("@SalesOrganization",              SqlDbType.NVarChar, request.SalesOrganization),
                SqlHelperExtension.CreateInParam("@SalesOrganizationDescription",   SqlDbType.NVarChar, request.SalesOrganizationDescription),

                SqlHelperExtension.CreateInParam("@DistributionChannel",            SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@DistributionChannelDescription", SqlDbType.NVarChar, request.DistributionChannelDescription),

                SqlHelperExtension.CreateInParam("@Division",                       SqlDbType.NVarChar, request.Division),
                SqlHelperExtension.CreateInParam("@DivisionDescription",            SqlDbType.NVarChar, request.DivisionDescription),

                SqlHelperExtension.CreateInParam("@MobileNumber",                   SqlDbType.NVarChar, request.MobileNumber),
                SqlHelperExtension.CreateInParam("@EmailAddress",                   SqlDbType.NVarChar, request.EmailAddress),

                SqlHelperExtension.CreateInParam("@BusinessTaxNumber",              SqlDbType.NVarChar, request.BusinessTaxNumber),
                SqlHelperExtension.CreateInParam("@CreditLimit",                    SqlDbType.Decimal,  request.CreditLimit),

                SqlHelperExtension.CreateInParam("@SalesGroup",                     SqlDbType.NVarChar, request.SalesGroup),
                SqlHelperExtension.CreateInParam("@SalesGroupDescription",          SqlDbType.NVarChar, request.SalesGroupDescription),

                SqlHelperExtension.CreateInParam("@CustomerGroup",                  SqlDbType.NVarChar, request.CustomerGroup),
                SqlHelperExtension.CreateInParam("@CustomerGroupDescription",       SqlDbType.NVarChar, request.CustomerGroupDescription),

                SqlHelperExtension.CreateInParam("@CustomerPriceGroup",             SqlDbType.NVarChar, request.CustomerPriceGroup),
                SqlHelperExtension.CreateInParam("@CustomerPriceGroupDescription",  SqlDbType.NVarChar, request.CustomerPriceGroupDescription),

                SqlHelperExtension.CreateInParam("@StatusCode",                     SqlDbType.NChar,    request.StatusCode),
                SqlHelperExtension.CreateInParam("@StatusDescription",              SqlDbType.NVarChar, request.StatusDescription),

                SqlHelperExtension.CreateInParam("@PaymentTerms",                   SqlDbType.NVarChar, request.PaymentTerms),
                SqlHelperExtension.CreateInParam("@PaymentTermsDescription",        SqlDbType.NVarChar, request.PaymentTermsDescription),

                SqlHelperExtension.CreateInParam("@SearchTerm",                     SqlDbType.NVarChar, request.SearchTerm),

                SqlHelperExtension.CreateInParam("@AreaRegion",                     SqlDbType.NVarChar, request.AreaRegion),
                SqlHelperExtension.CreateInParam("@AreaRegionDescription",          SqlDbType.NVarChar, request.AreaRegionDescription),

                SqlHelperExtension.CreateInParam("@SalesUnitAreaAV",                SqlDbType.NVarChar, request.SalesUnitAreaAV),
                SqlHelperExtension.CreateInParam("@SalesUnitAreaAVDescription",     SqlDbType.NVarChar, request.SalesUnitAreaAVDescription),

                SqlHelperExtension.CreateInParam("@Territory",                      SqlDbType.NVarChar, request.Territory),
                SqlHelperExtension.CreateInParam("@TerritoryName",                  SqlDbType.NVarChar, request.TerritoryName),

                SqlHelperExtension.CreateInParam("@Plant",                          SqlDbType.NVarChar, request.Plant),
                SqlHelperExtension.CreateInParam("@PlantName",                      SqlDbType.NVarChar, request.PlantName)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.CreateCustomer", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    private bool UpdateCustomer(TransactionContext tc, IntegrationCustomerRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@CustomerNumber",                 SqlDbType.NVarChar, request.CustomerNumber),
                SqlHelperExtension.CreateInParam("@CustomerName",                   SqlDbType.NVarChar, request.CustomerName),

                SqlHelperExtension.CreateInParam("@AccountGroup",                   SqlDbType.NVarChar, request.AccountGroup),
                SqlHelperExtension.CreateInParam("@AccountGroupDescription",        SqlDbType.NVarChar, request.AccountGroupDescription),

                SqlHelperExtension.CreateInParam("@CompanyCode",                    SqlDbType.NVarChar, request.CompanyCode),
                SqlHelperExtension.CreateInParam("@CompanyCodeDescription",         SqlDbType.NVarChar, request.CompanyCodeDescription),

                SqlHelperExtension.CreateInParam("@SalesOrganization",              SqlDbType.NVarChar, request.SalesOrganization),
                SqlHelperExtension.CreateInParam("@SalesOrganizationDescription",   SqlDbType.NVarChar, request.SalesOrganizationDescription),

                SqlHelperExtension.CreateInParam("@DistributionChannel",            SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@DistributionChannelDescription", SqlDbType.NVarChar, request.DistributionChannelDescription),

                SqlHelperExtension.CreateInParam("@Division",                       SqlDbType.NVarChar, request.Division),
                SqlHelperExtension.CreateInParam("@DivisionDescription",            SqlDbType.NVarChar, request.DivisionDescription),

                SqlHelperExtension.CreateInParam("@MobileNumber",                   SqlDbType.NVarChar, request.MobileNumber),
                SqlHelperExtension.CreateInParam("@EmailAddress",                   SqlDbType.NVarChar, request.EmailAddress),

                SqlHelperExtension.CreateInParam("@BusinessTaxNumber",              SqlDbType.NVarChar, request.BusinessTaxNumber),
                SqlHelperExtension.CreateInParam("@CreditLimit",                    SqlDbType.Decimal,  request.CreditLimit),

                SqlHelperExtension.CreateInParam("@SalesGroup",                     SqlDbType.NVarChar, request.SalesGroup),
                SqlHelperExtension.CreateInParam("@SalesGroupDescription",          SqlDbType.NVarChar, request.SalesGroupDescription),

                SqlHelperExtension.CreateInParam("@CustomerGroup",                  SqlDbType.NVarChar, request.CustomerGroup),
                SqlHelperExtension.CreateInParam("@CustomerGroupDescription",       SqlDbType.NVarChar, request.CustomerGroupDescription),

                SqlHelperExtension.CreateInParam("@CustomerPriceGroup",             SqlDbType.NVarChar, request.CustomerPriceGroup),
                SqlHelperExtension.CreateInParam("@CustomerPriceGroupDescription",  SqlDbType.NVarChar, request.CustomerPriceGroupDescription),

                SqlHelperExtension.CreateInParam("@StatusCode",                     SqlDbType.NChar,    request.StatusCode),
                SqlHelperExtension.CreateInParam("@StatusDescription",              SqlDbType.NVarChar, request.StatusDescription),

                SqlHelperExtension.CreateInParam("@PaymentTerms",                   SqlDbType.NVarChar, request.PaymentTerms),
                SqlHelperExtension.CreateInParam("@PaymentTermsDescription",        SqlDbType.NVarChar, request.PaymentTermsDescription),

                SqlHelperExtension.CreateInParam("@SearchTerm",                     SqlDbType.NVarChar, request.SearchTerm),

                SqlHelperExtension.CreateInParam("@AreaRegion",                     SqlDbType.NVarChar, request.AreaRegion),
                SqlHelperExtension.CreateInParam("@AreaRegionDescription",          SqlDbType.NVarChar, request.AreaRegionDescription),

                SqlHelperExtension.CreateInParam("@SalesUnitAreaAV",                SqlDbType.NVarChar, request.SalesUnitAreaAV),
                SqlHelperExtension.CreateInParam("@SalesUnitAreaAVDescription",     SqlDbType.NVarChar, request.SalesUnitAreaAVDescription),

                SqlHelperExtension.CreateInParam("@Territory",                      SqlDbType.NVarChar, request.Territory),
                SqlHelperExtension.CreateInParam("@TerritoryName",                  SqlDbType.NVarChar, request.TerritoryName),

                SqlHelperExtension.CreateInParam("@Plant",                          SqlDbType.NVarChar, request.Plant),
                SqlHelperExtension.CreateInParam("@PlantName",                      SqlDbType.NVarChar, request.PlantName)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateCustomer", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    #endregion

    #region Employee Private Functions

    private async Task<IntegrationEmployeeResponse> GetEmployeeBySalesOrgAsync(TransactionContext tc, EmployeeIntegrationByComapanyRequest request)
    {
        IntegrationEmployeeResponse response = new IntegrationEmployeeResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@EmployeeVendorCode", pType: SqlDbType.NVarChar, pValue: request.EmployeeVendorCode),
                SqlHelperExtension.CreateInParam(pName: "@CompanyCode",        pType: SqlDbType.NVarChar, pValue: request.CompanyCode)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetEmployeeByVendorCode", parameterValues: p))
            {
                if (dr.Read())
                {
                    response = new IntegrationEmployeeResponse()
                    {
                        EmployeeId = dr.GetInt32(0),
                        EmployeeVendorCode = dr.GetString(1),
                        EmployeeVendorName = dr.GetString(2),
                        Designation = dr.GetString(3),
                        DesignationDescription = dr.GetString(4),
                        MobileNo = dr.GetString(5),
                        Mail = dr.GetString(6),
                        CompanyCode = dr.GetString(7),
                        CompanyName = dr.GetString(8),
                        SalesOrg = dr.GetString(9),
                        SalesOrgDescription = dr.GetString(10),
                        DistChannel = dr.GetString(11),
                        DistChannelDescription = dr.GetString(12),
                        Division = dr.GetString(13),
                        DivisionDescription = dr.GetString(14),
                        RegionAreaCode = dr.GetString(15),
                        RegionAreaDescription = dr.GetString(16),
                        AreaAVSalesUnitCode = dr.GetString(17),
                        AreaAVSalesUnitDescription = dr.GetString(18),
                        Territory = dr.GetString(19),
                        TerritoryDescription = dr.GetString(20),
                        Plant = dr.GetString(21),
                        PlantDescription = dr.GetString(22),
                        Status = dr.GetString(23),
                        StatusDescription = dr.GetString(24)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }


    public async Task<bool> AddUserAsync(TransactionContext tc, AppUserCreateRequest user)
    {
        bool returnValue;
        try
        {
            int userId = 0;
            user.Password = EncryptPassword(password: user.Password);

            if (!string.IsNullOrEmpty(user.EmailAddress))
                user.EmailAddress = user.EmailAddress.Replace(" ", "");


            SqlParameter[] p =
            [
                    SqlHelperExtension.CreateInParam(pName: "@LoginId",        pType: SqlDbType.VarChar, pValue: user.LoginId,                                size: 100),
                    SqlHelperExtension.CreateInParam(pName: "@UserName",       pType: SqlDbType.VarChar, pValue: user.UserName,                               size: 150),
                    SqlHelperExtension.CreateInParam(pName: "@Status",         pType: SqlDbType.Int,     pValue: user.Status),
                    SqlHelperExtension.CreateInParam(pName: "@AccessStatus",   pType: SqlDbType.Int,     pValue: user.AccessStatus),
                    SqlHelperExtension.CreateInParam(pName: "@MobileNo",       pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(user.MobileNo),       size: 20),
                    SqlHelperExtension.CreateInParam(pName: "@EmailAddress",   pType: SqlDbType.VarChar, pValue: user.EmailAddress,                           size: 200),
                    SqlHelperExtension.CreateInParam(pName: "@IsLocked",       pType: SqlDbType.Int,     pValue: user.IsLocked),
                    SqlHelperExtension.CreateInParam(pName: "@Password",       pType: SqlDbType.NVarChar, pValue: user.Password,                               size: 500),
                    SqlHelperExtension.CreateInParam(pName: "@UserPlatformId", pType: SqlDbType.Int,     pValue: DataReader.GetNullValue(user.UserPlatformId)),
                    SqlHelperExtension.CreateInParam(pName: "@UserRoleType",   pType: SqlDbType.Int,     pValue: DataReader.GetNullValue(user.UserRoleType)),
                    SqlHelperExtension.CreateInParam(pName: "@EmployeeNumber", pType: SqlDbType.VarChar, pValue: DataReader.GetNullValue(user.EmployeeNumber), size: 10),
                    SqlHelperExtension.CreateOutParam(pName: "@NewUserId",     pType: SqlDbType.Int)      // index 11 — output
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertUser", parameterValues: p);
            userId = (p[11]?.Value != null && p[11]?.Value != DBNull.Value)
                ? Convert.ToInt32(p[11].Value)
                : 0;

            returnValue = userId > 0;
        }
        catch (Exception e)
        {
            throw new InvalidOperationException(e.Message, e);
        }

        return returnValue;
    }


    private string EncryptPassword(string password)
    {
        try
        {
            string pwdSecretKey = GlobalFunctions.ConvertFromBase64String(_settings.PwdSecretKey);
            return Global.CipherFunctions.EncryptByAES(privateKey: pwdSecretKey, publicKey: pwdSecretKey, data: password);
        }
        catch (Exception e)
        {
            throw new InvalidOperationException(e.Message, e);
        }

    }

    private async Task<bool> IsUserExistByEmployeeNumberAsync(TransactionContext tc, string employeeNumber)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@EmployeeNumber", pType: SqlDbType.NVarChar, pValue: employeeNumber)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.IsUserExistByEmployeeNumber", parameterValues: p))
            {
                if (dr.Read())
                {
                    response = dr.GetInt32(0) > 0 ? true: false;                 
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool InsertEmployee(TransactionContext tc, IntegrationEmployeeRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@EmployeeVendorCode",         pType: SqlDbType.NVarChar, pValue: request.EmployeeVendorCode),
                SqlHelperExtension.CreateInParam(pName: "@EmployeeVendorName",         pType: SqlDbType.NVarChar, pValue: request.EmployeeVendorName),

                SqlHelperExtension.CreateInParam(pName: "@Designation",                pType: SqlDbType.NVarChar, pValue: request.Designation),
                SqlHelperExtension.CreateInParam(pName: "@DesignationDescription",     pType: SqlDbType.NVarChar, pValue: request.DesignationDescription),

                SqlHelperExtension.CreateInParam(pName: "@MobileNo",                   pType: SqlDbType.NVarChar, pValue: request.MobileNo),
                SqlHelperExtension.CreateInParam(pName: "@Mail",                       pType: SqlDbType.NVarChar, pValue: request.Mail),

                SqlHelperExtension.CreateInParam(pName: "@CompanyCode",                pType: SqlDbType.NVarChar, pValue: request.CompanyCode),
                SqlHelperExtension.CreateInParam(pName: "@CompanyName",                pType: SqlDbType.NVarChar, pValue: request.CompanyName),

                SqlHelperExtension.CreateInParam(pName: "@SalesOrg",                   pType: SqlDbType.NVarChar, pValue: request.SalesOrg),
                SqlHelperExtension.CreateInParam(pName: "@SalesOrgDescription",        pType: SqlDbType.NVarChar, pValue: request.SalesOrgDescription),

                SqlHelperExtension.CreateInParam(pName: "@DistChannel",                pType: SqlDbType.NVarChar, pValue: request.DistChannel),
                SqlHelperExtension.CreateInParam(pName: "@DistChannelDescription",     pType: SqlDbType.NVarChar, pValue: request.DistChannelDescription),

                SqlHelperExtension.CreateInParam(pName: "@Division",                   pType: SqlDbType.NVarChar, pValue: request.Division),
                SqlHelperExtension.CreateInParam(pName: "@DivisionDescription",        pType: SqlDbType.NVarChar, pValue: request.DivisionDescription),

                SqlHelperExtension.CreateInParam(pName: "@RegionAreaCode",             pType: SqlDbType.NVarChar, pValue: request.RegionAreaCode),
                SqlHelperExtension.CreateInParam(pName: "@RegionAreaDescription",      pType: SqlDbType.NVarChar, pValue: request.RegionAreaDescription),

                SqlHelperExtension.CreateInParam(pName: "@AreaAVSalesUnitCode",        pType: SqlDbType.NVarChar, pValue: request.AreaAVSalesUnitCode),
                SqlHelperExtension.CreateInParam(pName: "@AreaAVSalesUnitDescription", pType: SqlDbType.NVarChar, pValue: request.AreaAVSalesUnitDescription),

                SqlHelperExtension.CreateInParam(pName: "@Territory",                  pType: SqlDbType.NVarChar, pValue: request.Territory),
                SqlHelperExtension.CreateInParam(pName: "@TerritoryDescription",       pType: SqlDbType.NVarChar, pValue: request.TerritoryDescription),

                SqlHelperExtension.CreateInParam(pName: "@Plant",                      pType: SqlDbType.NVarChar, pValue: request.Plant),
                SqlHelperExtension.CreateInParam(pName: "@PlantDescription",           pType: SqlDbType.NVarChar, pValue: request.PlantDescription),

                SqlHelperExtension.CreateInParam(pName: "@Status",                     pType: SqlDbType.NChar,    pValue: request.Status),
                SqlHelperExtension.CreateInParam(pName: "@StatusDescription",          pType: SqlDbType.NVarChar, pValue: request.StatusDescription)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertEmployee", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    private bool UpdateEmployee(TransactionContext tc, IntegrationEmployeeRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@EmployeeVendorCode",         pType: SqlDbType.NVarChar, pValue: request.EmployeeVendorCode),
            SqlHelperExtension.CreateInParam(pName: "@CompanyCode",                pType: SqlDbType.NVarChar, pValue: request.CompanyCode),

            SqlHelperExtension.CreateInParam(pName: "@EmployeeVendorName",         pType: SqlDbType.NVarChar, pValue: request.EmployeeVendorName),

            SqlHelperExtension.CreateInParam(pName: "@Designation",                pType: SqlDbType.NVarChar, pValue: request.Designation),
            SqlHelperExtension.CreateInParam(pName: "@DesignationDescription",     pType: SqlDbType.NVarChar, pValue: request.DesignationDescription),

            SqlHelperExtension.CreateInParam(pName: "@MobileNo",                   pType: SqlDbType.NVarChar, pValue: request.MobileNo),
            SqlHelperExtension.CreateInParam(pName: "@Mail",                       pType: SqlDbType.NVarChar, pValue: request.Mail),

            SqlHelperExtension.CreateInParam(pName: "@CompanyName",                pType: SqlDbType.NVarChar, pValue: request.CompanyName),

            SqlHelperExtension.CreateInParam(pName: "@SalesOrg",                   pType: SqlDbType.NVarChar, pValue: request.SalesOrg),
            SqlHelperExtension.CreateInParam(pName: "@SalesOrgDescription",        pType: SqlDbType.NVarChar, pValue: request.SalesOrgDescription),

            SqlHelperExtension.CreateInParam(pName: "@DistChannel",                pType: SqlDbType.NVarChar, pValue: request.DistChannel),
            SqlHelperExtension.CreateInParam(pName: "@DistChannelDescription",     pType: SqlDbType.NVarChar, pValue: request.DistChannelDescription),

            SqlHelperExtension.CreateInParam(pName: "@Division",                   pType: SqlDbType.NVarChar, pValue: request.Division),
            SqlHelperExtension.CreateInParam(pName: "@DivisionDescription",        pType: SqlDbType.NVarChar, pValue: request.DivisionDescription),

            SqlHelperExtension.CreateInParam(pName: "@RegionAreaCode",             pType: SqlDbType.NVarChar, pValue: request.RegionAreaCode),
            SqlHelperExtension.CreateInParam(pName: "@RegionAreaDescription",      pType: SqlDbType.NVarChar, pValue: request.RegionAreaDescription),

            SqlHelperExtension.CreateInParam(pName: "@AreaAVSalesUnitCode",        pType: SqlDbType.NVarChar, pValue: request.AreaAVSalesUnitCode),
            SqlHelperExtension.CreateInParam(pName: "@AreaAVSalesUnitDescription", pType: SqlDbType.NVarChar, pValue: request.AreaAVSalesUnitDescription),

            SqlHelperExtension.CreateInParam(pName: "@Territory",                  pType: SqlDbType.NVarChar, pValue: request.Territory),
            SqlHelperExtension.CreateInParam(pName: "@TerritoryDescription",       pType: SqlDbType.NVarChar, pValue: request.TerritoryDescription),

            SqlHelperExtension.CreateInParam(pName: "@Plant",                      pType: SqlDbType.NVarChar, pValue: request.Plant),
            SqlHelperExtension.CreateInParam(pName: "@PlantDescription",           pType: SqlDbType.NVarChar, pValue: request.PlantDescription),

            SqlHelperExtension.CreateInParam(pName: "@Status",                     pType: SqlDbType.NChar,    pValue: request.Status),
            SqlHelperExtension.CreateInParam(pName: "@StatusDescription",          pType: SqlDbType.NVarChar, pValue: request.StatusDescription)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateEmployee", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    #endregion

    #region Meterial Private Functions

    private async Task<IntegrationMaterialResponse> GetMaterialByCodeAsync(TransactionContext tc, GetMaterialByCodeRequest request)
    {
        IntegrationMaterialResponse response = new IntegrationMaterialResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam(pName: "@MaterialCode", pType: SqlDbType.NVarChar, pValue: request.MaterialCode)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetMaterialByMaterialCode", parameterValues: p))
            {
                if (dr.Read())
                {
                    response = new IntegrationMaterialResponse()
                    {
                        MeterialId = dr.GetInt32(0),
                        MaterialType = dr.GetString(1),
                        MaterialTypeDescription = dr.GetString(2),
                        MaterialCode = dr.GetString(3),
                        MaterialDescription = dr.GetString(4),
                        MaterialGroupCode = dr.GetString(5),
                        MaterialGroupDescription = dr.GetString(6),
                        BaseUnitOfMeasure = dr.GetString(7),
                        SalesUnitOfMeasure = dr.GetString(8),
                        UnitConversionWithBaseUoM = dr.GetDecimal(9),
                        PlantCode = dr.GetString(10),
                        PlantDescription = dr.GetString(11),
                        StorageLocationCode = dr.GetString(12),
                        StorageLocationDescription = dr.GetString(13),
                        SalesOrganization = dr.GetString(14),
                        SalesOrganizationDescription = dr.GetString(15),
                        BrandCode = dr.GetString(16),
                        BrandName = dr.GetString(17)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool CreateMaterial(TransactionContext tc, IntegrationMaterialRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@MaterialType",               SqlDbType.NVarChar, request.MaterialType),
                SqlHelperExtension.CreateInParam("@MaterialTypeDescription",     SqlDbType.NVarChar, request.MaterialTypeDescription),

                SqlHelperExtension.CreateInParam("@MaterialCode",               SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@MaterialDescription",        SqlDbType.NVarChar, request.MaterialDescription),

                SqlHelperExtension.CreateInParam("@MaterialGroupCode",          SqlDbType.NVarChar, request.MaterialGroupCode),
                SqlHelperExtension.CreateInParam("@MaterialGroupDescription",   SqlDbType.NVarChar, request.MaterialGroupDescription),

                SqlHelperExtension.CreateInParam("@BaseUnitOfMeasure",          SqlDbType.NVarChar, request.BaseUnitOfMeasure),
                SqlHelperExtension.CreateInParam("@SalesUnitOfMeasure",         SqlDbType.NVarChar, request.SalesUnitOfMeasure),

                SqlHelperExtension.CreateInParam("@UnitConversionWithBaseUoM",  SqlDbType.Decimal,  request.UnitConversionWithBaseUoM),

                SqlHelperExtension.CreateInParam("@PlantCode",                  SqlDbType.NVarChar, request.PlantCode),
                SqlHelperExtension.CreateInParam("@PlantDescription",           SqlDbType.NVarChar, request.PlantDescription),

                SqlHelperExtension.CreateInParam("@StorageLocationCode",        SqlDbType.NVarChar, request.StorageLocationCode),
                SqlHelperExtension.CreateInParam("@StorageLocationDescription", SqlDbType.NVarChar, request.StorageLocationDescription),

                SqlHelperExtension.CreateInParam("@SalesOrganization",            SqlDbType.NVarChar, request.SalesOrganization),
                SqlHelperExtension.CreateInParam("@SalesOrganizationDescription", SqlDbType.NVarChar, request.SalesOrganizationDescription),

                SqlHelperExtension.CreateInParam("@BrandCode",                    SqlDbType.NVarChar, request.BrandCode),
                SqlHelperExtension.CreateInParam("@BrandName",                    SqlDbType.NVarChar, request.BrandName)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.CreateMaterial", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    private bool UpdateMaterial(TransactionContext tc, IntegrationMaterialRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@MaterialType",               SqlDbType.NVarChar, request.MaterialType),
                SqlHelperExtension.CreateInParam("@MaterialTypeDescription",     SqlDbType.NVarChar, request.MaterialTypeDescription),

                SqlHelperExtension.CreateInParam("@MaterialCode",               SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@MaterialDescription",        SqlDbType.NVarChar, request.MaterialDescription),

                SqlHelperExtension.CreateInParam("@MaterialGroupCode",          SqlDbType.NVarChar, request.MaterialGroupCode),
                SqlHelperExtension.CreateInParam("@MaterialGroupDescription",   SqlDbType.NVarChar, request.MaterialGroupDescription),

                SqlHelperExtension.CreateInParam("@BaseUnitOfMeasure",          SqlDbType.NVarChar, request.BaseUnitOfMeasure),
                SqlHelperExtension.CreateInParam("@SalesUnitOfMeasure",         SqlDbType.NVarChar, request.SalesUnitOfMeasure),

                SqlHelperExtension.CreateInParam("@UnitConversionWithBaseUoM",  SqlDbType.Decimal,  request.UnitConversionWithBaseUoM),

                SqlHelperExtension.CreateInParam("@PlantCode",                  SqlDbType.NVarChar, request.PlantCode),
                SqlHelperExtension.CreateInParam("@PlantDescription",           SqlDbType.NVarChar, request.PlantDescription),

                SqlHelperExtension.CreateInParam("@StorageLocationCode",        SqlDbType.NVarChar, request.StorageLocationCode),
                SqlHelperExtension.CreateInParam("@StorageLocationDescription", SqlDbType.NVarChar, request.StorageLocationDescription),

                SqlHelperExtension.CreateInParam("@SalesOrganization",            SqlDbType.NVarChar, request.SalesOrganization),
                SqlHelperExtension.CreateInParam("@SalesOrganizationDescription", SqlDbType.NVarChar, request.SalesOrganizationDescription),

                SqlHelperExtension.CreateInParam("@BrandCode",                    SqlDbType.NVarChar, request.BrandCode),
                SqlHelperExtension.CreateInParam("@BrandName",                    SqlDbType.NVarChar, request.BrandName)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateMaterial", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    #endregion

    #region Material Price Private Functions

    private async Task<IntegrationMaterialPriceResponse> GetMaterialPriceByCodeAndConditionTypeAsync(
        TransactionContext tc, GetMaterialPriceByCodeRequest request)
    {
        IntegrationMaterialPriceResponse response = new IntegrationMaterialPriceResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@SalesOrg",  SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@MaterialCode",  SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@ConditionType", SqlDbType.NVarChar, request.ConditionType),
                SqlHelperExtension.CreateInParam("@CustomerNumber", SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.CustomerNumber)? null : request.CustomerNumber ),
                SqlHelperExtension.CreateInParam("@CustomerGroup", SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.CustomerGroupCode)? null : request.CustomerGroupCode )
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetMaterialPriceByMaterialCodeAndConditionType", parameterValues: p))
            {
                if (dr.Read())
                {
                    response=new IntegrationMaterialPriceResponse()
                    {
                        MaterialPriceId = dr.GetInt32(0),
                        SalesOrg = dr.GetString(1),
                        DistributionChannel = dr.GetString(2),
                        CustomerNumber = dr.IsDBNull(3) ? null : dr.GetString(3),
                        CustomerGroupCode = dr.IsDBNull(4) ? null : dr.GetString(4),
                        MaterialCode = dr.GetString(5),
                        ConditionType = dr.GetString(6),
                        CalculationType = dr.GetString(7),
                        PricingUnit = dr.GetString(8),
                        UnitOfMeasure = dr.GetString(9),
                        ValidFrom = dr.GetDateTime(10),
                        ValidTo = dr.GetDateTime(11),
                        Status = dr.IsDBNull(12) ? null : dr.GetString(12),
                        ConditionValue = dr.GetDecimal(13)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool CreateMaterialPrice(TransactionContext tc, IntegrationMaterialPriceRequest request)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, request.CustomerNumber),
                SqlHelperExtension.CreateInParam("@CustomerGroupCode",   SqlDbType.NVarChar, request.CustomerGroupCode),
                SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@ConditionType",       SqlDbType.NVarChar, request.ConditionType),
                SqlHelperExtension.CreateInParam("@CalculationType",     SqlDbType.NVarChar, request.CalculationType),
                SqlHelperExtension.CreateInParam("@PricingUnit",         SqlDbType.NVarChar, request.PricingUnit),
                SqlHelperExtension.CreateInParam("@UnitOfMeasure",       SqlDbType.NVarChar, request.UnitOfMeasure),
                SqlHelperExtension.CreateInParam("@ValidFrom",           SqlDbType.DateTime, request.ValidFrom),
                SqlHelperExtension.CreateInParam("@ValidTo",             SqlDbType.DateTime, request.ValidTo),
                SqlHelperExtension.CreateInParam("@Status",              SqlDbType.NVarChar, request.Status),
                SqlHelperExtension.CreateInParam("@ConditionValue",      SqlDbType.Decimal,  request.ConditionValue)                       
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertIntegrationMaterialPrice", parameterValues: p);

            response = true;
        }
        catch (Exception)
        {
            throw;
        }

        return response;
    }

    private bool UpdateMaterialPrice(TransactionContext tc, IntegrationMaterialPriceRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.CustomerNumber) ? null : request.CustomerNumber),
                SqlHelperExtension.CreateInParam("@CustomerGroupCode",   SqlDbType.NVarChar, request.CustomerGroupCode),
                SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@ConditionType",       SqlDbType.NVarChar, request.ConditionType),
                SqlHelperExtension.CreateInParam("@CalculationType",     SqlDbType.NVarChar, request.CalculationType),
                SqlHelperExtension.CreateInParam("@PricingUnit",         SqlDbType.NVarChar, request.PricingUnit),
                SqlHelperExtension.CreateInParam("@UnitOfMeasure",       SqlDbType.NVarChar, request.UnitOfMeasure),
                SqlHelperExtension.CreateInParam("@ValidFrom",           SqlDbType.DateTime, request.ValidFrom),
                SqlHelperExtension.CreateInParam("@ValidTo",             SqlDbType.DateTime, request.ValidTo),
                SqlHelperExtension.CreateInParam("@Status",              SqlDbType.NVarChar, request.Status),
                SqlHelperExtension.CreateInParam("@ConditionValue",      SqlDbType.Decimal,  request.ConditionValue)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateIntegrationMaterialPrice", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    #endregion

    #region Material Free Goods Private Functions

    private async Task<IntegrationMaterialFreeGoodsResponse> GetMaterialFreeGoodsByFilterAsync(
        TransactionContext tc, GetMaterialFreeGoodsByFilterRequest request)
    {
        IntegrationMaterialFreeGoodsResponse response = new IntegrationMaterialFreeGoodsResponse();

        try
        {
            SqlParameter[] p =
            [
                
                SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, request.CustomerNumber),
                SqlHelperExtension.CreateInParam("@CustomerPriceGroup",  SqlDbType.NVarChar, request.CustomerPriceGroup),
                SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetAllMaterialFreeGoodsForUpdate", parameterValues: p))
            {
                while (dr.Read())
                {
                    response= new IntegrationMaterialFreeGoodsResponse()
                    {
                        FreeGoodsId = dr.GetInt32(0),
                        SalesOrg = dr.GetString(1),
                        DistributionChannel = dr.GetString(2),
                        CustomerNumber = dr.IsDBNull(3) ? null : dr.GetString(3),
                        CustomerPriceGroup = dr.GetString(4),
                        MaterialCode = dr.GetString(5),
                        MinOrderQuantity = dr.GetDecimal(6),
                        ForQuantity = dr.GetDecimal(7),
                        UnitOfMeasure = dr.GetString(8),
                        FreeQuantity = dr.GetDecimal(9),
                        FocUnitOfMeasure = dr.GetString(10),
                        ValidFrom =  dr.GetDateTime(11),
                        ValidTo = dr.GetDateTime(12),
                        Status = dr.IsDBNull(13) ? null : dr.GetString(13)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool CreateMaterialFreeGoods(TransactionContext tc, IntegrationMaterialFreeGoodsRequest request)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, (object?)request.CustomerNumber ?? DBNull.Value),
                SqlHelperExtension.CreateInParam("@CustomerPriceGroup",  SqlDbType.NVarChar, request.CustomerPriceGroup),
                SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@MinOrderQuantity",    SqlDbType.Decimal,  request.MinOrderQuantity),
                SqlHelperExtension.CreateInParam("@ForQuantity",         SqlDbType.Decimal,  request.ForQuantity),
                SqlHelperExtension.CreateInParam("@UnitOfMeasure",       SqlDbType.NVarChar, request.UnitOfMeasure),
                SqlHelperExtension.CreateInParam("@FreeQuantity",        SqlDbType.Decimal,  request.FreeQuantity),
                SqlHelperExtension.CreateInParam("@FocUnitOfMeasure",    SqlDbType.NVarChar, request.FocUnitOfMeasure),
                SqlHelperExtension.CreateInParam("@ValidFrom",           SqlDbType.Date,     request.ValidFrom),
                SqlHelperExtension.CreateInParam("@ValidTo",             SqlDbType.Date,     request.ValidTo),
                SqlHelperExtension.CreateInParam("@Status",              SqlDbType.NVarChar, (object?)request.Status ?? DBNull.Value),
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertIntegrationMaterialFreeGoods", parameterValues: p);

            response = true;
        }
        catch (Exception)
        {
            throw;
        }

        return response;
    }

    private bool UpdateMaterialFreeGoods(TransactionContext tc, IntegrationMaterialFreeGoodsRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@SalesOrg",            SqlDbType.NVarChar, request.SalesOrg),
                SqlHelperExtension.CreateInParam("@DistributionChannel", SqlDbType.NVarChar, request.DistributionChannel),
                SqlHelperExtension.CreateInParam("@CustomerNumber",      SqlDbType.NVarChar, string.IsNullOrWhiteSpace(request.CustomerNumber)? null : request.CustomerNumber ),
                SqlHelperExtension.CreateInParam("@CustomerPriceGroup",  SqlDbType.NVarChar, request.CustomerPriceGroup),
                SqlHelperExtension.CreateInParam("@MaterialCode",        SqlDbType.NVarChar, request.MaterialCode),
                SqlHelperExtension.CreateInParam("@MinOrderQuantity",    SqlDbType.Decimal,  request.MinOrderQuantity),
                SqlHelperExtension.CreateInParam("@ForQuantity",         SqlDbType.Decimal,  request.ForQuantity),
                SqlHelperExtension.CreateInParam("@UnitOfMeasure",       SqlDbType.NVarChar, request.UnitOfMeasure),
                SqlHelperExtension.CreateInParam("@FreeQuantity",        SqlDbType.Decimal,  request.FreeQuantity),
                SqlHelperExtension.CreateInParam("@FocUnitOfMeasure",    SqlDbType.NVarChar, request.FocUnitOfMeasure),
                SqlHelperExtension.CreateInParam("@ValidFrom",           SqlDbType.Date,     request.ValidFrom),
                SqlHelperExtension.CreateInParam("@ValidTo",             SqlDbType.Date,     request.ValidTo),
                SqlHelperExtension.CreateInParam("@Status",              SqlDbType.NVarChar, (object?)request.Status ?? DBNull.Value)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateIntegrationMaterialFreeGoods", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    #endregion

    #region Payment Terms Private Functions

    private async Task<IntegrationPaymentTermResponse> GetPaymentTermByFilterAsync(TransactionContext tc,
        GetIntegrationPaymentTermRequest request)
    {
        IntegrationPaymentTermResponse response = new IntegrationPaymentTermResponse();

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@CreditCode", SqlDbType.NVarChar, request.CreditCode),
                SqlHelperExtension.CreateInParam("@SalesOrg",   SqlDbType.NVarChar, request.SalesOrg)
            ];

            using (IDataReader dr = await tc.ExecuteReaderSpAsync("dbo.GetPaymentTermByFilter", parameterValues: p))
            {
                if (dr.Read())
                {
                    response=new IntegrationPaymentTermResponse()
                    {
                        CreditCodeId = dr.GetInt32(0),
                        CreditCode = dr.GetString(1),
                        Description = dr.GetString(2),
                        ValidFrom = dr.GetDateTime(3),
                        ValidTo = dr.GetDateTime(4),
                        SalesOrg = dr.GetString(5)
                    };
                }
                dr.Close();
            }
        }
        catch (Exception ex)
        {
            throw DBCustomError.GenerateCustomError(ex);
        }

        return response;
    }

    private bool CreatePaymentTerm(TransactionContext tc, IntegrationPaymentTermRequest request)
    {
        bool response = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@CreditCode",   SqlDbType.NVarChar, request.CreditCode),
                SqlHelperExtension.CreateInParam("@Description",  SqlDbType.NVarChar, request.Description),
                SqlHelperExtension.CreateInParam("@ValidFrom",    SqlDbType.DateTime, request.ValidFrom),
                SqlHelperExtension.CreateInParam("@ValidTo",      SqlDbType.DateTime, request.ValidTo),
                SqlHelperExtension.CreateInParam("@SalesOrg",     SqlDbType.NVarChar, request.SalesOrg)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.InsertIntegrationPaymentTerm", parameterValues: p);

            response = true;
        }
        catch (Exception)
        {
            throw;
        }

        return response;
    }

    private bool UpdatePaymentTerm(TransactionContext tc, IntegrationPaymentTermRequest request)
    {
        bool returnValue = false;

        try
        {
            SqlParameter[] p =
            [
                SqlHelperExtension.CreateInParam("@CreditCode",   SqlDbType.NVarChar, request.CreditCode),
                SqlHelperExtension.CreateInParam("@Description",  SqlDbType.NVarChar, request.Description),
                SqlHelperExtension.CreateInParam("@ValidFrom",    SqlDbType.DateTime, request.ValidFrom),
                SqlHelperExtension.CreateInParam("@ValidTo",      SqlDbType.DateTime, request.ValidTo),
                SqlHelperExtension.CreateInParam("@SalesOrg",     SqlDbType.NVarChar, request.SalesOrg)
            ];

            _ = tc.ExecuteNonQuerySp(spName: "dbo.UpdateIntegrationPaymentTerms", parameterValues: p);

            returnValue = true;
        }
        catch (Exception)
        {
            throw;
        }

        return returnValue;
    }

    #endregion
}
