namespace Hims.Infrastructure.Services
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Threading.Tasks;
    using Dapper;
    using Domain.Entities;
    using Domain.Repositories.UnitOfWork;
    using Domain.Services;
    using Hims.Domain.Entities.Enums;
    using Hims.Domain.Entities.Pharmacy;
    using Hims.Shared.DataFilters;
    using Hims.Shared.UserModels.Filters;
    using Hims.Shared.UserModels.Laboratory;
    using Hims.Shared.UserModels.OperationTheater;
    using Hims.Shared.UserModels.Pharmacy;
    using Hims.Shared.UserModels.PharmacyRequest;

    using Shared.EntityModels;
    using Shared.UserModels;

    /// <inheritdoc />
    public class PharmacyServices : IPharmacyService
    {
        /// <summary>
        /// The unit of work.
        /// </summary>
        private readonly IUnitOfWork unitOfWork;

        /// <summary>
        /// The appointment transaction services.
        /// </summary>
        private readonly IAppointmentTransactionService appointmentTransactionsServices;

        /// <summary>
        /// The payment map helper service
        /// </summary>
        private readonly IPaymentMapHelperService paymentMapHelperService;

        /// <summary>
        /// Initializes a new instance of the <see cref="PharmacyServices"/> class.
        /// </summary>
        /// <param name="unitOfWork">
        /// The unit of work.
        /// </param>
        public PharmacyServices(IUnitOfWork unitOfWork, IAppointmentTransactionService appointmentTransactionsServices, IPaymentMapHelperService paymentMapHelperService)
        {
            this.unitOfWork = unitOfWork;
            this.appointmentTransactionsServices = appointmentTransactionsServices;
            this.paymentMapHelperService = paymentMapHelperService;
        }

        /// <inheritdoc/>
        public async Task<int> CreateUnitAsync(LookupValueModel model)
        {
            if (model.LookupId == 0)
            {
                model.LookupId = await this.GetLookupId("PharmacyUnit", "The Pharmacy Unit");
            }

            var valueModel = new LookupValue
            {
                LookupId = model.LookupId,
                Name = model.Name,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                CreatedBy = model.CreatedBy
            };
            if (await this.CheckLookupValueName(model.Name, model.LookupId))
            {
                return -1;
            }

            return await this.unitOfWork.LookupValues.InsertAsync(valueModel);
        }

        /// <inheritdoc/>
        public async Task<int> CreateCategoryAsync(LookupValueModel model)
        {
            if (model.LookupId == 0)
            {
                model.LookupId = await this.GetLookupId("PharmacyCategory", "Pharmacy category types.");
            }

            var valueModel = new LookupValue
            {
                LookupId = model.LookupId,
                Name = model.Name,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                CreatedBy = model.CreatedBy
            };
            if (await this.CheckLookupValueName(model.Name, model.LookupId))
            {
                return -1;
            }

            return await this.unitOfWork.LookupValues.InsertAsync(valueModel);
        }

        /// <inheritdoc/>
        public async Task<int> CreateRackAsync(LookupValueModel model)
        {
            if (model.LookupId == 0)
            {
                model.LookupId = await this.GetLookupId("PharmacyRack", "Pharmacy Rack numbers.");
            }

            var valueModel = new LookupValue
            {
                LookupId = model.LookupId,
                Name = model.Name,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                CreatedBy = model.CreatedBy
            };
            if (await this.CheckLookupValueName(model.Name, model.LookupId))
            {
                return -1;
            }

            return await this.unitOfWork.LookupValues.InsertAsync(valueModel);
        }

        /// <inheritdoc/>
        public async Task<int> CreateLookupValueAsync(LookupValueModel model)
        {
            if (model.LookupId == 0)
            {
                model.LookupId = await this.GetLookupId(model.TypeOf, "For medication taking ways");
            }

            var valueModel = new LookupValue
            {
                LookupId = model.LookupId,
                Name = model.Name,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                CreatedBy = model.CreatedBy
            };
            if (await this.CheckLookupValueName(model.Name, model.LookupId))
            {
                return -1;
            }

            return await this.unitOfWork.LookupValues.InsertAsync(valueModel);
        }


        /// <inheritdoc/>
        public async Task<int> CreateGstAsync(LookupValueModel model)
        {
            if (model.LookupId == 0)
            {
                model.LookupId = await this.GetLookupId("PharmacyGst", "The pharmacy gst.");
            }

            var valueModel = new LookupValue
            {
                LookupId = model.LookupId,
                Name = model.Name,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                CreatedBy = model.CreatedBy
            };
            if (await this.CheckLookupValueName(model.Name, model.LookupId))
            {
                return -1;
            }

            return await this.unitOfWork.LookupValues.InsertAsync(valueModel);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<LookupValueModel>> FetchLookupValues(LookupValueModel model)
        {
            var where = "where 1=1";
            if (model.UnitName != null)
            {
                where += $@"and Lower ( L.""Name"" ) = '{model.UnitName.ToLower()}'";
            }

            if (model.FromDate != null)
            {
                where += $@" AND L.""CreatedDate""::DATE >= '{model.FromDate}'::timestamp without time zone ";
            }
            if (model.ToDate != null)
            {
                where += $@" AND L.""CreatedDate""::DATE <= '{model.ToDate}'::timestamp without time zone ";
            }
            if (model.CreatedBy != null)
            {
                where += $@" and L.""CreatedBy""={model.CreatedBy}";
            }
            if (model.LookupValueId != 0)
            {
                where += $@" and L.""LookupValueId""={model.LookupValueId}";
            }
            if (model.CategoryName != null)
            {
                where += $@" and L.""Name"" ilike '%{model.CategoryName}%'";
            }
            var query = $@"SELECT L.*
                        , A.""FullName"" as ""CreatedByName"",CR.""RoleName"" as ""CreatedByRole"",M.""FullName"" as ""ModifiedByName""
                       ,MR.""RoleName"" ""ModifiedByRole""
	                            FROM ""LookupValue"" L
                                left join ""Account"" A on A.""AccountId"" = L.""CreatedBy""
                                left join ""Role"" CR on CR.""RoleId""=A.""RoleId""
                                left join ""Account"" M on M.""AccountId"" = L.""ModifiedBy""
                                left join ""Role"" MR on MR.""RoleId""= M.""RoleId""
                                {where} and ""LookupId"" = (Select ""LookupId"" from ""Lookup"" where ""Name"" = '{model.Name}') 
                                    order by L.""CreatedDate"" desc";
            return await this.unitOfWork.Current.QueryAsync<LookupValueModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> UpdateLookupValueAsync(LookupValueModel model)
        {
            var lookupValueName = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<int>($@"select count(""LookupValueId"") from ""LookupValue"" where LOWER(TRIM(""Name"")) = LOWER(TRIM('{model.Name}')) AND ""LookupId"" = {model.LookupId} AND ""LookupValueId"" <> {model.LookupValueId}");
            if (lookupValueName > 0)
            {
                return -1;
            }

            var lookupValue = await this.unitOfWork.LookupValues.FindAsync(m => m.LookupValueId == model.LookupValueId);
            lookupValue.Name = model.Name;
            lookupValue.ModifiedBy = model.LoginAccountId;
            lookupValue.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            return await this.unitOfWork.LookupValues.UpdateAsync(lookupValue);
        }

        /// <inheritdoc/>
        public async Task<int> DeleteLookupValueAsync(int lookupValueId)
        {
            var query = $@"Delete from ""LookupValue"" where ""LookupValueId"" = {lookupValueId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc/>
        public async Task<int> CreatePharmacyProduct(ProductModel model)
        {
            var productName = await this.unitOfWork.PharmacyProducts.FindAsync(m => m.ProductName == model.ProductName);

            if (productName != null)
            {
                if (model.IsGetProductId)
                {
                    return productName.PharmacyProductId * -1;
                }
                else
                {
                    return -1;
                }
            }
            var PharmacyMedicationModuleMaster = await this.unitOfWork.ModulesMasters.FindAsync(m => m.ModuleName == "Pharmacy Medications");
            if (PharmacyMedicationModuleMaster == null)
            {
                return -33;
            }
            var product = new PharmacyProduct
            {
                Active = true,
                Barcode = model.Barcode,
                CategoryId = (int)model.CategoryId,
                CompanyId = model.CompanyId,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                GenericName = model.GenericName,
                IsProductExpire = model.IsProductExpire,
                ProductName = model.ProductName,
                PurchaseUnit = model.PurchaseUnit,
                PurchaseUnitQty = model.PurchaseUnitQty,
                SaleUnit = model.SaleUnit,
                SaleUnitQty = model.SaleUnitQty,
                TaxId = model.TaxId,
                SupplierId = model.SupplierId,
                HSNCode = model.HSNCode,
                MedicationId = model.MedicationId,
                Suppliers = model.Suppliers,
                ScheduledDrug = model.ScheduledDrug,
                IsGeneralItem = model.IsGeneralItem,
                StorageTypeId = model.StorageTypeId,
                PharmacyProductTypeId = model.PharmacyProductTypeId,
                PharmacyProductSubTypeId = model.PharmacyProductSubTypeId,
                OnlyConsumable = model.OnlyConsumable,
                AlchoholInteraction = model.AlchoholInteraction,
                CommonSideEffects = model.CommonSideEffects,
                Dosage = model.Dosage,
                DosageTypeId = model.DosageTypeId,
                DrugRiskId = model.DrugRiskId,
                ExpertAdvice = model.ExpertAdvice,
                FixedDose = model.FixedDose,
                Formula = model.Formula,
                FormulationId = model.FormulationId,
                InventoryExpiry = model.InventoryExpiry,
                MedFrequencyMasterId = model.MedFrequencyMasterId,
                MedicineFaq = model.MedicineFaq,
                MedicineInteraction = model.MedicineInteraction,
                MedRouteId = model.MedRouteId,
                NABHCategoryId = model.NABHCategoryId,
                NoOfTimes = model.NoOfTimes,
                Potency = model.Potency,
                PregnancyInteraction = model.PregnancyInteraction,
                SaleLoose = model.SaleLoose,
                Strength = model.Strength,
                Usage = model.Usage,
                InventoryItem = model.InventoryItem,
                ModulesMasterId = PharmacyMedicationModuleMaster.ModulesMasterId
            };

            var id = await this.unitOfWork.PharmacyProducts.InsertAsync(product);
            if (id > 0 && !string.IsNullOrEmpty(product.Suppliers))
            {
                var supplierId = product.Suppliers.Split(",");
                foreach (var supplier in supplierId)
                {
                    var supplierProduct = new SupplierProduct
                    {
                        CreatedBy = model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        PharmacyProductId = id,
                        SupplierId = Convert.ToInt32(supplier),
                        PurchaseRate = null
                    };

                    try
                    {
                        await this.unitOfWork.SupplierProducts.InsertAsync(supplierProduct);
                    }
                    catch (Exception)
                    {
                        // ignore
                    }
                }
            }
            return id;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<ProductModel>> FetchPharmacyProduct(ProductModel model)
        {
            var where = "where 1=1";

            if (!string.IsNullOrEmpty(model.ProductName))
            {
                where += $@" and PP.""ProductName"" ilike '%{model.ProductName}%'";
            }

            if (!string.IsNullOrEmpty(model.GenericName))
            {
                where += $@" and PP.""GenericName"" ilike '%{model.GenericName}%'";
            }

            if (!string.IsNullOrEmpty(model.CategoryName))
            {
                where += $@" and Cat.""Name"" ilike '%{model.CategoryName}%'";
            }
            if (!string.IsNullOrEmpty(model.RackName))
            {
                where += $@" and Rack.""Name"" ilike '%{model.RackName}%'";
            }
            if (!string.IsNullOrEmpty(model.CompanyName))
            {
                where += $@" and C.""Name"" ilike '%{model.CompanyName}%'";
            }
            if (model.CategoryId > 0)
            {
                where += $@" and PP.""CategoryId"" = {model.CategoryId}";
            }

            if (model.PharmacyProductId > 0)
            {
                where += $@" and PP.""PharmacyProductId"" = {model.PharmacyProductId}";
            }

            if (!string.IsNullOrEmpty(model.BulkProductIds))
            {
                where += $@" and PP.""PharmacyProductId"" in ({model.BulkProductIds})";
            }

            if (!string.IsNullOrEmpty(model.SearchParam))
            {
                where += $@" and PP.""ProductName"" ilike '%{model.SearchParam}%' or PP.""GenericName"" ilike '%{model.SearchParam}%'";
            }

            var query =
                $@"SELECT count(PP.*) over() as ""TotalItems"", PP.""PharmacyProductId"", PP.""ProductName"", PP.""GenericName"", PP.""HSNCode"",
                                    PP.""Barcode"",PP.""PurchaseUnitQty"", PP.""SaleUnitQty"", PP.""CategoryId"", PP.""CompanyId"", PP.""SupplierId"", PP.""PurchaseUnit"",
                                    PP.""SaleUnit"", PP.""TaxId"", PP.""IsProductExpire"", PP.""Active"", PP.""CreatedBy"", PP.""CreatedDate"", PP.""OnlyConsumable"",
                                    C.""Name"" as ""CompanyName"",Cat.""Name"" as ""CategoryName"",Tax.""Name"" as ""Tax"",
                                    PurchaseUnit.""Name"" as ""PurchaseUnitName"", SaleUnit.""Name"" as ""SaleUnitName"",
                                    A.""FullName"" as ""CreatedByName"",PP.""MedicationId"", PP.""Suppliers"", PP.""ScheduledDrug"", PP.""IsGeneralItem"",
                                    PP.""StorageTypeId"", stor.""Name"" as ""StorageTypeName"", ppt.""TypeName"", ppst.""SubTypeName"",PP.""PharmacyProductTypeId"",PP.""PharmacyProductSubTypeId"",
                                    concat(pp.""ProductName"",pp.""GenericName"") as ""SearchParam"" ,PP.""Potency"",PP.""DrugRiskId"", drugR.""Name""
                                    as ""DrugRiskName"", PP.""Dosage"" ,PP.""Formula"",PP.""NABHCategoryId"", nabh.""Name"" as ""NABHCategoryName"",
                                    PP.""DosageTypeId"", dosage.""Name"" as ""DosageTypeName"", PP.""Strength"" ,PP.""FixedDose"" ,
                                    PP. ""MedFrequencyMasterId"",mfm.""FrequencyName"" ,PP.""NoOfTimes"",PP.""SaleLoose"",PP.""InventoryExpiry"" ,
                                    PP.""FormulationId"", formu.""Name"" as ""FormulationName"",PP.""MedRouteId"", medR.""Name"" as ""MedRouteName"",
                                    PP.""AlchoholInteraction"",PP.""PregnancyInteraction"", PP.""ExpertAdvice"",PP.""CommonSideEffects"" ,
                                    PP.""MedicineFaq"" ,PP.""MedicineInteraction"",PP.""Usage"" , PP.""InventoryItem""
	                                    FROM ""PharmacyProduct"" PP join ""Company"" C on C.""CompanyId"" = PP.""CompanyId""
	                                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
	                                    join ""LookupValue"" Tax on Tax.""LookupValueId"" = PP.""TaxId""
	                                    join ""LookupValue"" PurchaseUnit on PurchaseUnit.""LookupValueId"" = PP.""PurchaseUnit""
	                                    join ""LookupValue"" SaleUnit on SaleUnit.""LookupValueId"" = PP.""SaleUnit""
	                                    left join ""LookupValue"" drugR ON drugR.""LookupValueId"" = PP.""DrugRiskId""
	                                    left join ""LookupValue"" nabh ON nabh.""LookupValueId"" = PP.""NABHCategoryId""
	                                    left join ""LookupValue"" dosage on dosage.""LookupValueId"" = PP.""DosageTypeId""
	                                    left join ""MedFrequencyMaster"" mfm on mfm.""MedFrequencyMasterId"" = PP.""MedFrequencyMasterId"" 
	                                    left join ""LookupValue"" formu on formu.""LookupValueId"" = PP.""FormulationId""
	                                    left join ""LookupValue"" medR on medR.""LookupValueId""  = PP.""MedRouteId""  
	                                    left join ""Account"" A on A.""AccountId"" = PP.""CreatedBy""
                                        left join ""LookupValue"" stor on stor.""LookupValueId"" = PP.""StorageTypeId""
                                        left join ""PharmacyProductType"" ppt on ppt.""PharmacyProductTypeId"" = PP.""PharmacyProductTypeId""
                                        left join ""PharmacyProductSubType"" ppst on ppst.""PharmacyProductSubTypeId"" = PP.""PharmacyProductSubTypeId""
	                                    {where} order by PP.""CreatedDate"" desc ";

            if (model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;
                query += $@" limit {model.PageSize} offset {model.PageIndex * model.PageSize}";
            }

            return await this.unitOfWork.Current.QueryAsync<ProductModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<ProductModel>> FetchPharmacyProducts()
        {
            var query =
                $@"SELECT count(PP.*) over() as ""TotalItems"", PP.""PharmacyProductId"", PP.""ProductName"", PP.""GenericName"", PP.""HSNCode"",
                                    PP.""Barcode"",PP.""PurchaseUnitQty"", PP.""SaleUnitQty"", PP.""CategoryId"", PP.""CompanyId"", PP.""SupplierId"", PP.""PurchaseUnit"",
                                    PP.""SaleUnit"", PP.""TaxId"",PP.""IsProductExpire"", PP.""Active"", PP.""CreatedBy"", PP.""CreatedDate"",
                                    C.""Name"" as ""CompanyName"",Cat.""Name"" as ""CategoryName"",Tax.""Name"" as ""Tax"",--Rack.""Name"" as ""RackName"",
                                    PurchaseUnit.""Name"" as ""PurchaseUnitName"", SaleUnit.""Name"" as ""SaleUnitName"",
                                    A.""FullName"" as ""CreatedByName"", PP.""ScheduledDrug"", PP.""IsGeneralItem""
	                                    FROM ""PharmacyProduct"" PP join ""Company"" C on C.""CompanyId"" = PP.""CompanyId""
	                                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
	                                    join ""LookupValue"" Tax on Tax.""LookupValueId"" = PP.""TaxId""
	                                    join ""LookupValue"" PurchaseUnit on PurchaseUnit.""LookupValueId"" = PP.""PurchaseUnit""
	                                    join ""LookupValue"" SaleUnit on SaleUnit.""LookupValueId"" = PP.""SaleUnit""
	                                    left join ""Account"" A on A.""AccountId"" = PP.""CreatedBy""
	                                    order by PP.""CreatedDate"" desc ";

            return await this.unitOfWork.Current.QueryAsync<ProductModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> UpdatePharmacyProduct(ProductModel model)
        {
            var product =
                await this.unitOfWork.PharmacyProducts.FindAsync(m => m.PharmacyProductId == model.PharmacyProductId);
            product.Barcode = model.Barcode;
            product.CategoryId = (int)model.CategoryId;
            product.CompanyId = model.CompanyId;
            product.GenericName = model.GenericName;
            product.IsProductExpire = model.IsProductExpire;
            product.ProductName = model.ProductName;
            product.PurchaseUnit = model.PurchaseUnit;
            product.PurchaseUnitQty = model.PurchaseUnitQty;
            product.SaleUnit = model.SaleUnit;
            product.SaleUnitQty = model.SaleUnitQty;
            product.TaxId = model.TaxId;
            product.SupplierId = model.SupplierId;
            product.HSNCode = model.HSNCode;
            product.MedicationId = model.MedicationId;
            product.ScheduledDrug = model.ScheduledDrug;
            product.StorageTypeId = model.StorageTypeId;
            product.PharmacyProductTypeId = model.PharmacyProductTypeId;
            product.PharmacyProductSubTypeId = model.PharmacyProductSubTypeId;
            product.AlchoholInteraction = model.AlchoholInteraction;
            product.CommonSideEffects = model.CommonSideEffects;
            product.Dosage = model.Dosage;
            product.DosageTypeId = model.DosageTypeId;
            product.DrugRiskId = model.DrugRiskId;
            product.ExpertAdvice = model.ExpertAdvice;
            product.FixedDose = model.FixedDose;
            product.Formula = model.Formula;
            product.FormulationId = model.FormulationId;
            product.InventoryExpiry = model.InventoryExpiry;
            product.MedFrequencyMasterId = model.MedFrequencyMasterId;
            product.MedicineFaq = model.MedicineFaq;
            product.MedicineInteraction = model.MedicineInteraction;
            product.MedRouteId = model.MedRouteId;
            product.NABHCategoryId = model.NABHCategoryId;
            product.NoOfTimes = model.NoOfTimes;
            product.Potency = model.Potency;
            product.PregnancyInteraction = model.PregnancyInteraction;
            product.SaleLoose = model.SaleLoose;
            product.Strength = model.Strength;
            product.Usage = model.Usage;
            product.InventoryItem = model.InventoryItem;
            if (!string.IsNullOrEmpty(product.Suppliers))
            {
                foreach (var id in product.Suppliers.Split(","))
                {
                    var query = $@"DELETE FROM ""SupplierProduct""  WHERE ""PharmacyProductId"" = {product.PharmacyProductId} and ""SupplierId"" = {id}";
                    await this.unitOfWork.Current.ExecuteAsync(query);
                }
            }
            if (!string.IsNullOrEmpty(model.Suppliers))
            {
                var supplierId = model.Suppliers.Split(",");
                foreach (var supplier in supplierId)
                {
                    var supplierProduct = new SupplierProduct
                    {
                        CreatedBy = model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        PharmacyProductId = product.PharmacyProductId,
                        SupplierId = Convert.ToInt32(supplier),
                        PurchaseRate = null
                    };

                    try
                    {
                        await this.unitOfWork.SupplierProducts.InsertAsync(supplierProduct);
                    }
                    catch (Exception)
                    {
                        // ignore
                    }
                }
            }
            product.Suppliers = model.Suppliers;
            return await this.unitOfWork.PharmacyProducts.UpdateAsync(product);
        }

        /// <inheritdoc/>
        public async Task<int> DeletePharmacyProduct(int pharmacyProductId)
        {
            var query = $@"Delete from ""PharmacyProduct"" where ""PharmacyProductId"" = {pharmacyProductId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyBillModel>> FetchAddedBill(int purchaseHeaderId)
        {
            var query = $@"SELECT PPH.""PharmacyPurchaseHeaderId"", PH.""ProductName"",C.""Name"" as ""CompanyName"",SS.""Name"" as ""SupplierName"",Cat.""Name"" as ""CategoryName"",Ph.""GenericName"",A.""FullName"" as ""CreatedByName"",PPH.""BillNumber"", PPH.""BillDate"", PPH.""BillType"", PPH.""SupplierId"", PPH.""BillAmount"", 
                                PPH.""Discount"" as ""OverallDiscount"", PPH.""Taxes"", PPH.""Netamount"" as ""TotalNetAmount"",PPD.""PharmacyPurchaseDetailId"", PPD.""PharmacyPurchaseHeaderId"", PPD.""SerialNum"", PPD.""PharmacyProductId"", PPD.""Quantity"", PPD.""Free"", 
                                PPD.""PurchaseRate"", PPD.""Mrp"", PPD.""Total"", PPD.""TaxPerItem"", PPD.""TaxAmount"", PPD.""DiscountPerItem"", PPD.""DiscountAmount"", 
                                PPD.""NetAmount"", PPD.""Barcode"", PPD.""PharmacyStockId"",PPD.""PharmacyRetailStockId"",
								(case when PPD.""PharmacyStockId"" is null then PRS.""BatchNumber"" else PS.""BatchNumber"" end) as ""BatchNumber"",
								(case when PPD.""PharmacyStockId"" is null then PRS.""ExpiryDate"" else PS.""ExpiryDate"" end) as ""ExpiryDate"",
                                PH.""ScheduledDrug""
								    FROM ""PharmacyPurchaseHeader"" PPH
	                                join ""PharmacyPurchaseDetail"" PPD on PPD.""PharmacyPurchaseHeaderId"" = PPH.""PharmacyPurchaseHeaderId""
	                                join ""Supplier"" SS on SS.""SupplierId"" = PPH.""SupplierId""
                                    join ""PharmacyProduct"" PH on PH.""PharmacyProductId"" = PPD.""PharmacyProductId""
                                    join ""Company"" C on C.""CompanyId"" = PH.""CompanyId""
									left join ""PharmacyStock"" PS on PS.""PharmacyStockId"" = PPD.""PharmacyStockId"" 
									left join ""PharmacyRetailStock"" PRS on PRS.""PharmacyRetailStockId"" = PPD.""PharmacyRetailStockId""
                                    left join ""Account"" A on A.""AccountId"" = PPH.""CreatedBy""
	                                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PH.""CategoryId""
                                    where PPH.""PharmacyPurchaseHeaderId"" = {purchaseHeaderId}";

            return await this.unitOfWork.Current.QueryAsync<PharmacyBillModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyPurchaseBill>> FetchPharmacyPurchaseBill(int purchaseHeaderId, string type)
        {

            var query = $@"select pp.""ProductName"",pp.""GenericName"",pp.""Barcode"", pp.""ScheduledDrug"" ,lv.""Name"" ""CategoryName"",c.""Name"" ""CompanyName"",
                            s.""Name"" ""SupplierName"",s.""SupplierId"",pph.""BillNumber"",pph.""BillDate"",pph.""BillType"" , pph.""PharmacyWareHouseId"",pwh.""WareHouseName"",ppd.* 
                            from ""PharmacyPurchaseDetail""  ppd
                            join ""PharmacyProduct"" pp on pp.""PharmacyProductId""=ppd.""PharmacyProductId""
                            join ""LookupValue"" lv on lv.""LookupValueId""= pp.""CategoryId""
                            join ""Company"" c on c.""CompanyId"" = pp.""CompanyId""
                            join ""PharmacyPurchaseHeader"" pph on pph.""PharmacyPurchaseHeaderId"" = ppd.""PharmacyPurchaseHeaderId""
                            join ""Supplier"" s on s.""SupplierId"" = pph.""SupplierId""
                            join ""PharmacyWareHouse"" pwh on pwh.""PharmacyWareHouseId"" = pph.""PharmacyWareHouseId""
                            where ppd.""PharmacyPurchaseHeaderId"" = {purchaseHeaderId}";

            if (!string.IsNullOrEmpty(type) && type == "R")
            {
                query = $@"select pp.""ProductName"",pp.""GenericName"",pp.""Barcode"", pp.""ScheduledDrug"" ,lv.""Name"" ""CategoryName"",c.""Name"" ""CompanyName"",pprd.""PurchaseRate"",
                            s.""Name"" ""SupplierName"",ppr.""BillNumber"",ppr.""CreatedDate"" ""BillDate"",pph.""BillType"" ,ppr.""OverallTaxes"" ""TaxAmount"",ppd.* 
                            from ""PharmacyPurchaseReturnDetail""  ppd
                            join ""PharmacyProduct"" pp on pp.""PharmacyProductId""=ppd.""PharmacyProductId""
                            join ""LookupValue"" lv on lv.""LookupValueId""= pp.""CategoryId""
                            join ""Company"" c on c.""CompanyId"" = pp.""CompanyId""
                            join ""PharmacyPurchaseReturnHeader"" ppr on ppr.""PharmacyPurchaseReturnHeaderId"" = ppd.""PharmacyPurchaseReturnHeaderId""
							join ""PharmacyPurchaseDetail"" pprd on pprd.""PharmacyPurchaseHeaderId"" = ppr.""PharmacyPurchaseHeaderId"" and pprd.""PharmacyProductId""=ppd.""PharmacyProductId""
                            join ""PharmacyPurchaseHeader"" pph on pph.""PharmacyPurchaseHeaderId"" = ppr.""PharmacyPurchaseHeaderId""
							join ""Supplier"" s on s.""SupplierId"" = pph.""SupplierId""
                            where pph.""PharmacyPurchaseHeaderId"" = {purchaseHeaderId}";
            }
            return await this.unitOfWork.Current.QueryAsync<PharmacyPurchaseBill>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyStockModel>> FetchPharmacyStocks(PharmacyStockModel model)
        {
            var extraColumns = string.Empty;
            var extraCondition = string.Empty;
            var where = $@"where 1=1 and (PS.""QuantityIn"" - PS.""QuantityOut"") > 0";

            if (!string.IsNullOrEmpty(model.UnavailableStock))
            {
                if (model.UnavailableStock == "yes")
                {
                    where = $@"where 1=1 and (PS.""QuantityIn"" - PS.""QuantityOut"") >= 0";
                }
                if (model.UnavailableStock == "no")
                {
                    where = $@"where 1=1 and (PS.""QuantityIn"" - PS.""QuantityOut"") > 0";
                }
            }

            if (!string.IsNullOrEmpty(model.CategoryName))
            {
                where += $@" and Cat.""Name"" ilike '%{model.CategoryName}%'";
            }

            if (!string.IsNullOrEmpty(model.ProductName))
            {
                where += $@" and  PP.""ProductName"" ilike '%{model.ProductName}%'";
            }

            if (!string.IsNullOrEmpty(model.BatchNumber))
            {
                where += $@" and   PS.""BatchNumber"" ilike '%{model.BatchNumber}%'";
            }

            if (!string.IsNullOrEmpty(model.GenericName))
            {
                where += $@" and  PP.""GenericName"" ilike '%{model.GenericName}%'";
            }

            if (!string.IsNullOrEmpty(model.BillNumber))
            {
                where += $@" and  PPH.""BillNumber"" ilike '%{model.BillNumber}%'";
            }

            if (model.PharmacyProductId > 0)
            {
                where += $@" and PS.""PharmacyProductId"" = {model.PharmacyProductId}";
            }

            if (model.PharmacyStockId > 0)
            {
                where += $@" and PS.""PharmacyStockId"" = {model.PharmacyStockId}";
            }

            if (model.IsExpiryProduct == true)
            {
                where += $@" and PS.""ExpiryDate""::date <= current_date ";
            }

            if (model.PharmacyWareHouseId != null)
            {
                where += $@" and PS.""PharmacyWareHouseId"" = {model.PharmacyWareHouseId}";
                extraColumns = $@" ,PPDH.""ROQ"",PPDH.""ROL"",PPR.""RackName"",PPDH.""PharmacyProductDetailId"" ";
                extraCondition = $@"  left join ""PharmacyProductDetail"" PPDH on PPDH.""PharmacyProductId"" = PS.""PharmacyProductId"" and PPDH.""PharmacyWareHouseId"" = {model.PharmacyWareHouseId}
										left join ""PharmacyProductRack"" PPR on PPR.""PharmacyProductRackId"" = PPDH.""PharmacyProductRackId""";

            }

            if (!string.IsNullOrEmpty(model.WareHouseIds))
            {
                where += $@" and PS.""PharmacyWareHouseId"" in ({model.WareHouseIds})";
            }

            var query =
                $@"SELECT distinct PS.""PharmacyStockId"",count(PS.*) over() as ""TotalItems"", PS.""PharmacyProductId"", PS.""TaxId"", PS.""QuantityIn"", PS.""QuantityOut"", PS.""BatchNumber"", PS.""ExpiryDate"",
                                    PS.""PurchaseRate"", PS.""Mrp"", PS.""Barcode"", PS.""MrpChangeReason"", PP.""ProductName"",PP.""GenericName"",PS.""CreatedDate"",
                                    (PS.""QuantityIn"" - PS.""QuantityOut"") as ""AvailableQuantity"",Cat.""Name"" as ""CategoryName"",Tax.""Name""::int as ""TaxPercentage"",
                                    PS.""IsSGST"", PS.""IsIGST"",  PP.""ScheduledDrug"" ,PP.""IsGeneralItem"",
									PPH.""BillNumber"" {extraColumns}
	                                    FROM ""PharmacyStock"" PS  
	                                    join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PS.""PharmacyProductId""
	                                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
	                                    join ""LookupValue"" Tax on Tax.""LookupValueId"" = PS.""TaxId""
										join ""PharmacyPurchaseDetail"" PPD on PPD.""PharmacyStockId"" = PS.""PharmacyStockId""
										join ""PharmacyPurchaseHeader"" PPH on PPH.""PharmacyPurchaseHeaderId"" = PPD.""PharmacyPurchaseHeaderId""
                                        {extraCondition}										
                                        {where}
										group by PS.""PharmacyStockId"",PS.""PharmacyProductId"", PS.""TaxId"", PS.""QuantityIn"", PS.""QuantityOut"", PS.""BatchNumber"", PS.""ExpiryDate"",
                                    PS.""PurchaseRate"", PS.""Mrp"", PS.""Barcode"", PS.""MrpChangeReason"", PP.""ProductName"",PP.""GenericName"",PS.""CreatedDate""
                                    ,Cat.""Name"",Tax.""Name""::int ,PPH.""BillNumber"",PP.""ScheduledDrug"" ,PP.""IsGeneralItem"" {extraColumns}
									order by PP.""ProductName""";

            if (model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;

                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }

            return await this.unitOfWork.Current.QueryAsync<PharmacyStockModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyStockModel>> FetchPharmacyRetailStocks(PharmacyStockModel model)
        {
            var where = $@"where 1=1 and (PS.""QuantityIn"" - PS.""QuantityOut"") > 0";

            var extraColumns = string.Empty;
            var extraCondition = string.Empty;

            if (!string.IsNullOrEmpty(model.UnavailableStock))
            {
                if (model.UnavailableStock == "yes")
                {
                    where = $@"where 1=1 and (PS.""QuantityIn"" - PS.""QuantityOut"") >= 0";
                }
                if (model.UnavailableStock == "no")
                {
                    where = $@"where 1=1 and (PS.""QuantityIn"" - PS.""QuantityOut"") > 0";
                }
            }

            if (!string.IsNullOrEmpty(model.CategoryName))
            {
                where += $@" and Cat.""Name"" ilike '%{model.CategoryName}%'";
            }

            if (!string.IsNullOrEmpty(model.ProductName))
            {
                where += $@" and  PP.""ProductName"" ilike '%{model.ProductName}%'";
            }

            if (!string.IsNullOrEmpty(model.GenericName))
            {
                where += $@" and  PP.""GenericName"" ilike '%{model.GenericName}%'";
            }

            if (model.PharmacyProductId > 0)
            {
                where += $@" and PS.""PharmacyProductId"" = {model.PharmacyProductId}";
            }

            if (model.RetailPharmacyId != null)
            {
                where += $@" and PS.""RetailWareHouseLinkId"" in (Select ""RetailWareHouseLinkId"" from ""RetailWareHouseLink"" where ""RetailPharmacyId"" = {model.RetailPharmacyId}) ";
                extraColumns = $@" ,PPD.""ROQ"",PPD.""ROL"",PPR.""RackName"",PPD.""PharmacyProductDetailId"" ";
                extraCondition = $@"  left join ""PharmacyProductDetail"" PPD on PPD.""PharmacyProductId"" = PS.""PharmacyProductId"" and PPD.""RetailPharmacyId"" = {model.RetailPharmacyId}
										left join ""PharmacyProductRack"" PPR on PPR.""PharmacyProductRackId"" = PPD.""PharmacyProductRackId""";
            }

            if (model.IsExpiryProduct == true)
            {
                where += $@" and PS.""ExpiryDate""::date <= current_date ";
            }

            if (!string.IsNullOrEmpty(model.PharmacyRetailStockIds))
            {
                where += $@" and PS.""PharmacyRetailStockId"" in ({model.PharmacyRetailStockIds})";
            }

            if (!string.IsNullOrEmpty(model.Term))
            {
                where += $@" and (lower(PP.""ProductName"") ilike '%{model.Term.ToLower()}%' or  lower(PP.""GenericName"") ilike '%{model.Term.ToLower()}%')";
            }

            var query =
                $@"SELECT count(PS.*) over() as ""TotalItems"", PS.""PharmacyRetailStockId"",PS.""PharmacyStockId"", PS.""PharmacyProductId"", PS.""TaxId"", PS.""QuantityIn"", PS.""QuantityOut"", PS.""BatchNumber"", PS.""ExpiryDate"",
                                    PS.""PurchaseRate"", PS.""Mrp"", PS.""Barcode"", PP.""ProductName"",PP.""GenericName"",PS.""CreatedDate"",PP.""CategoryId"",
                                    (PS.""QuantityIn"" - PS.""QuantityOut"") as ""AvailableQuantity"",Cat.""Name"" as ""CategoryName"",Tax.""Name""::int as ""TaxPercentage"",PS.""RetailWareHouseLinkId""
                                    ,rp.""RetailName"", pwh.""WareHouseName"", PS.""IsIGST"",PS.""IsSGST"", PP.""ScheduledDrug"" , PP.""IsGeneralItem""
                                    {extraColumns}
	                                    FROM ""PharmacyRetailStock"" PS  
	                                    join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PS.""PharmacyProductId""
	                                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
	                                    join ""LookupValue"" Tax on Tax.""LookupValueId"" = PS.""TaxId""
                                        join ""RetailWareHouseLink"" rwhl ON rwhl.""RetailWareHouseLinkId"" = PS.""RetailWareHouseLinkId""                                         
                                        join ""RetailPharmacy"" rp on rp.""RetailPharmacyId"" = rwhl.""RetailPharmacyId"" 
	                                    join ""PharmacyWareHouse"" pwh on pwh.""PharmacyWareHouseId"" = rwhl.""PharmacyWareHouseId"" 
                                        {extraCondition}
                                        {where} order by PS.""CreatedDate"" desc";

            if (model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;

                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }

            return await this.unitOfWork.Current.QueryAsync<PharmacyStockModel>(query);
        }

        /// <inheritdoc/>
        public async Task<Tuple<int, string>> AddSaleBill(PharmacySaleBillModel model)
        {
            using var transaction = this.unitOfWork.BeginTransaction();
            var billHeader = new PharmacySaleHeader
            {
                BillNumber = await this.GetBillNumber(),
                AdmissionId = model.AdmissionId,
                BillType = model.BillType,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                Mobile = model.Mobile,
                OverallDiscount = model.Discount,
                OverallNetAmount = model.NetAmount,
                OverallTaxes = model.TaxAmount,
                PatientId = model.PatientId,
                PatientName = model.PatientName,
                ProviderName = model.ProviderName,
                SaleDate = model.SaleDate.Add(DateTime.UtcNow.AddMinutes(330).TimeOfDay),
                Total = model.Total,
                // PaidVia = model.PaidVia,
                ProviderId = model.ProviderId,
                PayTypeId = model.PayTypeId,
                PaymentNumber = model.PaymentNumber

            };
            billHeader.PharmacySaleHeaderId =
                await this.unitOfWork.PharmacySaleHeaders.InsertAsync(billHeader, transaction);
            if (billHeader.PharmacySaleHeaderId == 0)
            {
                transaction.Rollback();
                return new Tuple<int, string>(-1, null);
            }

            var detail = new PharmacySaleDetail
            {
                PharmacySaleHeaderId = billHeader.PharmacySaleHeaderId,
                SerialNum = 1,
                Total = model.Total,
                TaxAmount = model.TaxAmount,
                Discount = model.Discount,
                NetAmount = model.NetAmount,
                DiscountPerItem = model.DiscountPerItem,
                PharmacyProductId = model.PharmacyProductId,
                PharmacyRetailStockId = model.PharmacyRetailStockId,
                Quantity = model.Quantity,
                TaxId = model.TaxId
            };
            detail.PharmacySaleDetailId = await this.AddPharmacySalesDetails(detail, transaction);
            if (detail.PharmacySaleDetailId == 0)
            {
                transaction.Rollback();
                return new Tuple<int, string>(-2, null);
            }

            var rawStock = await this.unitOfWork.PharmacyRetailStocks.FindAsync(
                               m => m.PharmacyRetailStockId == model.PharmacyRetailStockId);
            rawStock.QuantityOut += model.Quantity;
            rawStock.ModifiedBy = model.CreatedBy;
            rawStock.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            var response = await this.unitOfWork.PharmacyRetailStocks.UpdateAsync(rawStock, transaction);
            if (response <= 0)
            {
                transaction.Rollback();
                return new Tuple<int, string>(-3, null);
            }

            transaction.Commit();
            return new Tuple<int, string>(billHeader.PharmacySaleHeaderId, billHeader.BillNumber);
        }

        /// <inheritdoc/>
        public async Task<Tuple<int, string>> UpdateSaleBill(PharmacySaleBillModel model)
        {
            var headerRecord =
                await this.unitOfWork.PharmacySaleHeaders.FindAsync(
                    m => m.PharmacySaleHeaderId == model.PharmacySaleHeaderId);
            if (headerRecord == null)
            {
                return new Tuple<int, string>(-1, null);
            }

            using var transaction = this.unitOfWork.BeginTransaction();
            headerRecord.Total += Math.Round(model.Total, 2);
            if (model.Discount != null)
            {
                headerRecord.OverallDiscount += Math.Round((double)model.Discount, 2);
            }

            headerRecord.OverallNetAmount += Math.Round(model.NetAmount, 2);
            headerRecord.OverallTaxes += Math.Round(model.TaxAmount, 2);
            headerRecord.ModifiedBy = model.CreatedBy;
            headerRecord.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            var headerResponse = await this.unitOfWork.PharmacySaleHeaders.UpdateAsync(headerRecord);
            if (headerResponse == 0)
            {
                transaction.Rollback();
                return new Tuple<int, string>(-1, null);
            }

            var detail = new PharmacySaleDetail
            {
                PharmacySaleHeaderId = model.PharmacySaleHeaderId,
                SerialNum = 1,
                Total = model.Total,
                TaxAmount = model.TaxAmount,
                Discount = model.Discount,
                NetAmount = model.NetAmount,
                DiscountPerItem = model.DiscountPerItem,
                PharmacyProductId = model.PharmacyProductId,
                PharmacyRetailStockId = model.PharmacyRetailStockId,
                Quantity = model.Quantity,
                TaxId = model.TaxId
            };
            detail.PharmacySaleDetailId = await this.AddPharmacySalesDetails(detail, transaction);
            if (detail.PharmacySaleDetailId == 0)
            {
                transaction.Rollback();
                return new Tuple<int, string>(-2, null);
            }

            var rawStock = await this.unitOfWork.PharmacyRetailStocks.FindAsync(
                               m => m.PharmacyRetailStockId == model.PharmacyRetailStockId);
            rawStock.QuantityOut += model.Quantity;
            rawStock.ModifiedBy = model.CreatedBy;
            rawStock.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            var response = await this.unitOfWork.PharmacyRetailStocks.UpdateAsync(rawStock, transaction);
            if (response <= 0)
            {
                transaction.Rollback();
                return new Tuple<int, string>(-3, null);
            }

            transaction.Commit();

            return new Tuple<int, string>(model.PharmacySaleHeaderId, null);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacySaleBill>> FetchSaleAddedBill(int? pharmacySaleHeaderId, string billNumber, int? locationId)
        {
            var where = " where 1 = 1";
            if (pharmacySaleHeaderId != null)
            {
                where += $@" and  PSH.""PharmacySaleHeaderId"" = {pharmacySaleHeaderId} ";
            }

            if (!string.IsNullOrEmpty(billNumber))
            {
                where += $@"  and PSH.""BillNumber"" = '{billNumber}' ";
            }

            if (locationId != null)
            {
                where += $@" and PSH.""LocationId"" = {locationId}";
            }

            var query =
                $@"SELECT PSD.""PharmacySaleDetailId"", PSD.""PharmacySaleHeaderId"", PSD.""SerialNum"", PSD.""PharmacyProductId"", PSD.""TaxId"",PSD.""ReturnQuantity"",
                PSD.""PharmacyRetailStockId"",PRS.""BatchNumber"", PSD.""Quantity"", PSD.""Total"", PSD.""TaxAmount"", PSD.""DiscountPerItem"", PSD.""Discount"", PSD.""NetAmount"",
                PSH.""PharmacySaleHeaderId"", PSH.""BillType"", PSH.""BillNumber"", PSH.""SaleDate"", PSH.""PatientId"", PSH.""PatientName"",PSH.""IsSalucroBill"",
                P.""FirstName"",P.""MiddleName"",P.""LastName"", PP.""ScheduledDrug"", PP.""IsGeneralItem"",
                PSH.""Mobile"", PSH.""AdmissionId"", PSH.""ProviderName"",PSH.""SpecializationId"",spl.""SpecializationName"", PSH.""Total"" as ""OverallTotal"", PSH.""OverallDiscount"" , 
                PSH.""OverallTaxes"", PSH.""OverallNetAmount"", PP.""ProductName"",PP.""HSNCode"",PRS.""ExpiryDate"",PRS.""Mrp"",
				Cat.""Name"" as ""CategoryName"", Com.""Name"" as ""CompanyName"",PSH.""CreatedDate"",P.""UMRNo"",P.""Gender"",P.""Age"",P.""DateOfBirth"",PSH.""ReasonForDiscount"",
                Tax.""Name"" as ""TaxPercentage"",PRS.""IsIGST"", PRS.""IsSGST"",PSH.""ReasonForDiscount"",Coalesce(MB.""RemovedAmount"",0) ""RemovedAmount"",                
                (select SUM(COALESCE(RC.""Cost"",0)) from ""Receipt"" RC where RC.""RespectiveId""=PSH.""PharmacySaleHeaderId"" and RC.""ReceiptAreaTypeId""=1 and RC.""ReceiptTypeId""=1)
				-case when SRH.""SaleReturnHeaderId"" is not null then (select SUM(COALESCE(RR.""Cost"",0)) from ""Receipt"" RR where RR.""RespectiveId""=SRH.""SaleReturnHeaderId"" and RR.""ReceiptAreaTypeId""=7 and RR.""ReceiptTypeId""=2) else 0 end ""PaidAmount""
                    FROM ""PharmacySaleDetail"" PSD
                    join ""PharmacySaleHeader"" PSH on PSH.""PharmacySaleHeaderId"" = PSD.""PharmacySaleHeaderId""
                    join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PSD.""PharmacyProductId""
                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
                    join ""LookupValue"" Tax on Tax.""LookupValueId"" = PSD.""TaxId""
                    join ""Company"" Com on Com.""CompanyId"" = PP.""CompanyId""
                    join ""PharmacyRetailStock"" PRS on PRS.""PharmacyRetailStockId"" = PSD.""PharmacyRetailStockId""
                    left join ""Patient"" P on P.""PatientId"" = PSH.""PatientId""
                    left join ""Specialization"" spl on spl.""SpecializationId"" = PSH.""SpecializationId""
                    --left Join ""Receipt"" RC on RC.""RespectiveId""=PSH.""PharmacySaleHeaderId"" and RC.""ReceiptAreaTypeId""=1 and RC.""ReceiptTypeId""=1
                    left Join ""MasterBill"" MB on MB.""ModuleId""=PSH.""PharmacySaleHeaderId"" and MB.""ReceiptAreaTypeId""=1
                    left Join ""SaleReturnHeader"" SRH on SRH.""PharmacySaleHeaderId""=PSH.""PharmacySaleHeaderId""
                    --left Join ""Receipt"" RR on RR.""RespectiveId""=SRH.""SaleReturnHeaderId"" and RR.""ReceiptAreaTypeId""=7 and RR.""ReceiptTypeId""=2
                     {where}
                     group by PSD.""PharmacySaleDetailId"", PSD.""PharmacySaleHeaderId"", PSD.""SerialNum"", PSD.""PharmacyProductId"", PSD.""TaxId"",PSD.""ReturnQuantity"",
                PSD.""PharmacyRetailStockId"",PRS.""BatchNumber"", PSD.""Quantity"", PSD.""Total"", PSD.""TaxAmount"", PSD.""DiscountPerItem"", PSD.""Discount"", PSD.""NetAmount"",
                PSH.""PharmacySaleHeaderId"", PSH.""BillType"", PSH.""BillNumber"", PSH.""SaleDate"", PSH.""PatientId"", PSH.""PatientName"",PSH.""IsSalucroBill"",
                P.""FirstName"",P.""MiddleName"",P.""LastName"", PP.""ScheduledDrug"", PP.""IsGeneralItem"",
                PSH.""Mobile"", PSH.""AdmissionId"", PSH.""ProviderName"",PSH.""SpecializationId"",spl.""SpecializationName"", PSH.""Total"", PSH.""OverallDiscount"" , 
                PSH.""OverallTaxes"", PSH.""OverallNetAmount"", PP.""ProductName"",PP.""HSNCode"",PRS.""ExpiryDate"",PRS.""Mrp"",
				Cat.""Name"", Com.""Name"" ,PSH.""CreatedDate"",P.""UMRNo"",P.""Gender"",P.""Age"",P.""DateOfBirth"",
                Tax.""Name"",PRS.""IsIGST"", PRS.""IsSGST"", MB.""RemovedAmount"",SRH.""SaleReturnHeaderId""                     
	                order by PSD.""PharmacySaleDetailId"" desc";
            return await this.unitOfWork.Current.QueryAsync<PharmacySaleBill>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacySaleReturnBillDetailsModel>> FetchSaleReturnDetialsBill(int? pharmacySaleHeaderId, string billNumber, int? saleReturnHeaderId)
        {
            var where = " where 1 = 1";
            if (pharmacySaleHeaderId != null)
            {
                where += $@" and  PSH.""PharmacySaleHeaderId"" = {pharmacySaleHeaderId} ";
            }

            if (!string.IsNullOrEmpty(billNumber))
            {
                where += $@"  and PSH.""BillNumber"" = '{billNumber}' ";
            }

            if (saleReturnHeaderId != null)
            {
                where += $@" and SRD.""SaleReturnHeaderId"" = {saleReturnHeaderId}";
            }

            var query =
                $@"SELECT SRD.""SaleReturnDetailId"", SRH.""PharmacySaleHeaderId"", SRD.""PharmacyProductId"", 
                SRD.""PharmacyRetailStockId"", SRD.""Quantity"", SRD.""Total"", SRD.""TaxAmount"",SRD.""NetAmount"",
                SRH.""PharmacySaleHeaderId"", SRH.""BillType"", PSH.""BillNumber"", SRH.""ReturnDate"", SRH.""PatientId"", SRH.""PatientName"",
                 P.""FirstName"",P.""MiddleName"",P.""LastName"",PP.""ScheduledDrug"", PP.""IsGeneralItem"",
                PSH.""Mobile"", SRH.""AdmissionId"", PSH.""ProviderName"", SRD.""Total"" as ""OverallTotal"", SRH.""OverallDiscount"" , 
                SRH.""OverallTaxes"", SRH.""OverallNetAmount"", PP.""ProductName"",PRS.""ExpiryDate"",PRS.""Mrp"",
				Cat.""Name"" as ""CategoryName"", Com.""Name"" as ""CompanyName"",SRH.""CreatedDate"",P.""UMRNo"",P.""Gender"",P.""Age"",P.""DateOfBirth""
	                FROM ""SaleReturnDetail"" SRD 
	                join ""SaleReturnHeader"" SRH on SRH.""SaleReturnHeaderId"" = SRD.""SaleReturnHeaderId""
	                join ""PharmacySaleHeader"" PSH on PSH.""PharmacySaleHeaderId"" = SRH.""PharmacySaleHeaderId""
	                join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = SRD.""PharmacyProductId"" 
					join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
					join ""Company"" Com on Com.""CompanyId"" = PP.""CompanyId""
	                join ""PharmacyRetailStock"" PRS on PRS.""PharmacyRetailStockId"" = SRD.""PharmacyRetailStockId""
                    left join ""Patient"" P on P.""PatientId"" = SRH.""PatientId""
	                 {where}
	                order by SRD.""SaleReturnDetailId"" desc";
            return await this.unitOfWork.Current.QueryAsync<PharmacySaleReturnBillDetailsModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> AddSurgeryKit(SurgeryHeaderModel model)
        {
            var checkIfQuery = $@"select count(*) from ""SurgeryKitHeader"" where lower(""KitName"") = '{model.KitName.ToLower()}'";
            var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkIfQuery);
            if (checkIf > 0)
            {
                return -1;
            }
            using var transaction = this.unitOfWork.BeginTransaction();
            var surgeryHeader = new SurgeryKitHeader
            {
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                KitName = model.KitName
            };
            surgeryHeader.SurgeryKitHeaderId = await this.unitOfWork.SurgeryKitHeaders.InsertAsync(surgeryHeader, transaction);

            if (surgeryHeader.SurgeryKitHeaderId == 0)
            {
                transaction.Rollback();
                return -1;
            }

            foreach (var detail in model.Products)
            {
                var details = new SurgeryKitDetail
                {
                    PharmacyProductId = detail.PharmacyProductId,
                    SurgeryKitHeaderId = surgeryHeader.SurgeryKitHeaderId,
                    Quantity = detail.Quantity
                };
                details.SurgeryKitDetailId =
                    await this.unitOfWork.SurgeryKitDetails.InsertAsync(details, transaction);
                if (details.SurgeryKitDetailId == 0)
                {
                    transaction.Rollback();
                    return -2;
                }
            }

            transaction.Commit();
            return 1;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<SurgeryHeaderModel>> FetchSurgeryKitHeaders()
        {
            var query = $@"SELECT SKH.""SurgeryKitHeaderId"", SKH.""KitName"", SKH.""CreatedBy"", SKH.""CreatedDate"",A.""FullName"" as ""CreatedByName"",
		                            AR.""RoleName"" as ""CreatedByRole"", AR.""RoleName"" as ""CreatedByRole"",M.""FullName"" as ""ModifiedByName"",
		                            MR.""RoleName"" as ""ModifiedByRole"", SKH.""ModifiedDate""
	                                FROM ""SurgeryKitHeader"" SKH 
	                                join ""Account"" A on A.""AccountId"" = SKH.""CreatedBy"" 
									join ""Role"" AR on AR.""RoleId"" = A.""RoleId""
									left join ""Account"" M on M.""AccountId"" = SKH.""ModifiedBy""
									left join ""Role"" MR on MR.""RoleId"" = M.""RoleId""
	                                order by SKH.""CreatedDate"" desc";
            return await this.unitOfWork.Current.QueryAsync<SurgeryHeaderModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<SurgeryDetailModel>> FetchSurgeryDetails(int headerId)
        {
            var query =
                $@"SELECT SKD.""SurgeryKitDetailId"", SKD.""SurgeryKitHeaderId"", SKD.""Quantity"", SKD.""PharmacyProductId"",PP.""ProductName"",PP.""GenericName""
	                                FROM ""SurgeryKitDetail"" SKD
	                                join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = SKD.""PharmacyProductId""
	                                where SKD.""SurgeryKitHeaderId"" = {headerId}
	                                order by SKD.""SurgeryKitDetailId"" desc";
            return await this.unitOfWork.Current.QueryAsync<SurgeryDetailModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> UpdateSurgeryKit(SurgeryHeaderModel model)
        {
            var checkIfQuery = $@"select count(*) from ""SurgeryKitHeader"" where lower(""KitName"") = '{model.KitName.ToLower()}' and ""SurgeryKitHeaderId"" <> {model.SurgeryKitHeaderId}";
            var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkIfQuery);
            if (checkIf > 0)
            {
                return -1;
            }
            using var transaction = this.unitOfWork.BeginTransaction();
            var header =
                await this.unitOfWork.SurgeryKitHeaders.FindAsync(
                    m => m.SurgeryKitHeaderId == model.SurgeryKitHeaderId);
            header.KitName = model.KitName;
            header.ModifiedBy = model.CreatedBy;
            header.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            var responseHeader = await this.unitOfWork.SurgeryKitHeaders.UpdateAsync(header, transaction);
            if (responseHeader <= 0)
            {
                transaction.Rollback();
                return -1;
            }

            var details =
                await this.unitOfWork.SurgeryKitDetails.FindAllAsync(m => m.SurgeryKitHeaderId == model.SurgeryKitHeaderId);
            foreach (var surgeryKitDetail in details)
            {
                var detail = model.Products.Find(m => m.SurgeryKitDetailId == surgeryKitDetail.SurgeryKitDetailId);
                if (detail == null)
                {
                    var deleteResponse =
                        await this.unitOfWork.SurgeryKitDetails.DeleteAsync(surgeryKitDetail, transaction);
                    if (!deleteResponse)
                    {
                        transaction.Rollback();
                        return -2;
                    }
                }
                else
                {
                    surgeryKitDetail.Quantity = detail.Quantity;
                    var updateResponse =
                        await this.unitOfWork.SurgeryKitDetails.UpdateAsync(surgeryKitDetail, transaction);
                    if (updateResponse == 0)
                    {
                        transaction.Rollback();
                        return -3;
                    }
                }
            }

            var newlyAddedRecord = model.Products.FindAll(r => r.SurgeryKitDetailId == 0);
            if (newlyAddedRecord.Count > 0)
            {
                foreach (var record in newlyAddedRecord)
                {
                    var newRecord = new SurgeryKitDetail
                    {
                        PharmacyProductId = record.PharmacyProductId,
                        SurgeryKitHeaderId = header.SurgeryKitHeaderId,
                        Quantity = record.Quantity
                    };
                    record.SurgeryKitDetailId =
                        await this.unitOfWork.SurgeryKitDetails.InsertAsync(newRecord, transaction);
                    if (record.SurgeryKitDetailId == 0)
                    {
                        transaction.Rollback();
                        return -2;
                    }
                }
            }

            transaction.Commit();
            return 1;
        }

        /// <inheritdoc/>
        public async Task<int> DeleteSurgeryKit(int headerId)
        {
            try
            {
                var deleteDetails = $@"Delete from ""SurgeryKitDetail"" where ""SurgeryKitHeaderId"" = {headerId}";
                var deleteResponse = await this.unitOfWork.Current.ExecuteAsync(deleteDetails);
                if (deleteResponse > 0)
                {
                    var headerQuery = $@"Delete from ""SurgeryKitHeader"" where ""SurgeryKitHeaderId"" = {headerId}";
                    return await this.unitOfWork.Current.ExecuteAsync(headerQuery);
                }
                else
                {
                    return -1;
                }
            }
            catch (Exception)
            {
                return -2;
            }
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyDashboardModel>> FetchProductExpiryNextMonth(int? locationId)
        {
            var where = " and 1=1";
            if (locationId != null)
            {
                where += $@" and PW.""LocationId"" = {locationId}";
            }
            var query = $@"Select (PS.""QuantityIn"" - PS.""QuantityOut"") as ""AvailableQty"",* ,PW.""WareHouseName""
                            from ""PharmacyStock"" PS 
                            join ""PharmacyWareHouse"" PW on PW.""PharmacyWareHouseId"" = PS.""PharmacyWareHouseId""
                            join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PS.""PharmacyProductId""
                                                        where (Extract(Month from PS.""ExpiryDate"") = (extract(Month from now())+1) and 
								                          Extract(Year from PS.""ExpiryDate"") = (extract(Year from now()))) {where}";
            return await this.unitOfWork.Current.QueryAsync<PharmacyDashboardModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyDashboardModel>> FetchProductExpiryInNextMonths(PharmacyReportFilterModel model)
        {
            var where = "";
            if (!string.IsNullOrEmpty(model.ProductName))
            {
                where += $@" and PP.""ProductName"" ilike '%{model.ProductName}%'";
            }

            if (!string.IsNullOrEmpty(model.GenericName))
            {
                where += $@" and PP.""GenericName"" ilike '%{model.GenericName}%'";
            }

            if (model.LocationId != null)
            {
                where += $@" and (PW.""LocationId"" = {model.LocationId} or PW.""LocationId"" is null)";
            }

            var query = $@"Select count(PS.*) over() as ""TotalItems"", (PS.""QuantityIn"" - PS.""QuantityOut"") as ""AvailableQty"",*,PW.""WareHouseName"",PS.""PharmacyWareHouseId"" ,
							ppd.""ROL"" ,ppd.""ROQ"" , ""PharmacyStockId""::text as ""StockId""
                                 from ""PharmacyStock"" PS 
                                 join ""PharmacyWareHouse"" PW on PW.""PharmacyWareHouseId"" = PS.""PharmacyWareHouseId""
                                 join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PS.""PharmacyProductId""
                                 left join ""PharmacyProductDetail"" ppd on ppd.""PharmacyProductId""  = PS.""PharmacyProductId"" and ppd.""PharmacyWareHouseId"" = PS.""PharmacyWareHouseId""                                  
                                 where PS.""ExpiryDate"" <='{model.ToDate}'::date and (PS.""QuantityIn"" - PS.""QuantityOut"") <> 0
                                 {where}
                                 order by PS.""ExpiryDate"" asc";

            if (model.PageIndex != 0 && model.PageSize != 0)
            {
                model.PageIndex -= 1;
                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }
            return await this.unitOfWork.Current.QueryAsync<PharmacyDashboardModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyDashboardModel>> FetchProductExpiryThisMonth(int? locationId)
        {
            var where = "";
            if (locationId != null)
            {
                where += $@" and PW.""LocationId""={locationId}";
            }
            var query = $@"Select (PS.""QuantityIn"" - PS.""QuantityOut"") as ""AvailableQty"",* ,PW.""WareHouseName""  
                            from ""PharmacyStock"" PS 
                            join ""PharmacyWareHouse"" PW on PW.""PharmacyWareHouseId"" = PS.""PharmacyWareHouseId""
                            join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PS.""PharmacyProductId""
                                                        where (Extract(Month from PS.""ExpiryDate"") = (extract(Month from now())) and 
								                          Extract(Year from PS.""ExpiryDate"") = (extract(Year from now()))) {where}";
            return await this.unitOfWork.Current.QueryAsync<PharmacyDashboardModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyDashboardModel>> FetchProductUnderReorderLevel(PharmacyReportFilterModel model)
        {
            var where = "1=1 ";
            if (!string.IsNullOrEmpty(model.ProductName))
            {
                where += $@" and PP.""ProductName"" ilike '%{model.ProductName}%'";
            }

            if (!string.IsNullOrEmpty(model.GenericName))
            {
                where += $@" and PP.""GenericName"" ilike '%{model.GenericName}%'";
            }

            if (model.LocationId != null)
            {
                where += $@" and (PW.""LocationId"" = {model.LocationId} or PW.""LocationId"" is null)";
            }

            if (!string.IsNullOrEmpty(model.CategoryName))
            {
                where += $@" and LV.""Name""  ilike '%{model.CategoryName}%'";
            }

            if (!string.IsNullOrEmpty(model.WareHouseName))
            {
                where += $@" and PW.""WareHouseName""  ilike '%{model.WareHouseName}%'";
            }

            var query = $@"with temp as(with mainData as(select (PS.""QuantityIn"" - PS.""QuantityOut"") as ""AvailableQty"",PW.""WareHouseName"", PS.""PharmacyWareHouseId"",
						 PP.""ProductName"" ,PP.""GenericName"",PS.""BatchNumber"" ,PS.""PharmacyProductId"", PS.""PharmacyStockId"" 
                            from ""PharmacyStock"" PS 
                            join ""PharmacyWareHouse"" PW on PW.""PharmacyWareHouseId"" = PS.""PharmacyWareHouseId""
                            join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PS.""PharmacyProductId""
                            join ""LookupValue"" LV on LV.""LookupValueId"" = PP.""CategoryId""
                            where {where})
                    select  SUM(m.""AvailableQty"") as ""AvailableQty"",m.""WareHouseName"", m.""PharmacyWareHouseId"",
						 m.""ProductName"" ,m.""GenericName"" ,STRING_AGG (m.""BatchNumber"" ,',') as ""BatchNumber"",m.""PharmacyProductId"",ppd.""ROQ"",ppd.""ROL"",
						 STRING_AGG (m.""PharmacyStockId""::text  ,',') as ""StockId""
						 from ""PharmacyProductDetail"" ppd
 						join mainData m on m.""PharmacyProductId"" = ppd.""PharmacyProductId"" and m.""PharmacyWareHouseId"" = ppd.""PharmacyWareHouseId"" 											
 						group by m.""WareHouseName"", m.""PharmacyWareHouseId"",
						 m.""ProductName"" ,m.""GenericName"" ,m.""PharmacyProductId"",ppd.""ROQ"",ppd.""ROL"")
						  select count(t.*) over() as ""TotalItems"", t.*,ts.""Status""  from temp t
                    join ""PharmacyProductDetail"" ppd on ppd.""PharmacyProductId"" = t.""PharmacyProductId"" and ppd.""PharmacyWareHouseId"" = t.""PharmacyWareHouseId""                    
                    left join vendors.""PharmacyProductRequest"" ppr on ppr.""PharmacyWareHouseId"" = t.""PharmacyWareHouseId"" and ppr.""PharmacyProductId"" = t.""PharmacyProductId""
                      and ppr.""TenderStatusId"" in (select ""TenderStatusId"" from vendors.""TendorStatus"" where ""Status"" != 'Completed') 
                    left join vendors.""TendorStatus"" ts on ts.""TenderStatusId"" = ppr.""TenderStatusId"" 
                    where ppd.""ROL""  >= t.""AvailableQty""
";

            if (model.PageIndex != 0 && model.PageSize != 0)
            {
                model.PageIndex -= 1;
                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }
            return await this.unitOfWork.Current.QueryAsync<PharmacyDashboardModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyDashboardModel>> FetchProductExpiryNextMonthRetail(PharmacyReportFilterModel model)
        {
            var where = "";
            if (!string.IsNullOrEmpty(model.ProductName))
            {
                where += $@" and PP.""ProductName"" ilike '%{model.ProductName}%'";
            }
            if (model.PharmacyRetailStockId != null)
            {
                where += $@" and PS.""PharmacyRetailStockId"" = {model.PharmacyRetailStockId}";
            }

            if (!string.IsNullOrEmpty(model.GenericName))
            {
                where += $@" and PP.""GenericName"" ilike '%{model.GenericName}%'";
            }

            if (model.LocationId != null)
            {
                where += $@" and PW.""LocationId""={model.LocationId}";
            }

            var query = $@"Select count(PS.*) over() as ""TotalItems"", (PS.""QuantityIn"" - PS.""QuantityOut"") as ""AvailableQty"",*,RP.""RetailName""
                            from ""PharmacyRetailStock"" PS 
                            join ""RetailWareHouseLink"" PWL on PWL.""RetailWareHouseLinkId"" = PS.""RetailWareHouseLinkId""	
                             join ""PharmacyWareHouse"" PW on PW.""PharmacyWareHouseId"" = PWL.""PharmacyWareHouseId""
                            join ""RetailPharmacy"" RP on RP.""RetailPharmacyId"" = PWL.""RetailPharmacyId""
                            join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PS.""PharmacyProductId""
                            where PS.""ExpiryDate"" <='{model.ToDate}'::date and (PS.""QuantityIn"" - PS.""QuantityOut"") <> 0 {where} order by PS.""ExpiryDate"" asc";

            if (model.PageIndex != 0 && model.PageSize != 0)
            {
                model.PageIndex -= 1;
                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }

            return await this.unitOfWork.Current.QueryAsync<PharmacyDashboardModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyDashboardModel>> FetchProductExpiryThisMonthRetail(int? locationId)
        {
            var where = string.Empty;
            if (locationId != null)
            {
                where += $@" and PW.""LocationId"" = {locationId}";
            }

            var query = $@"Select (PS.""QuantityIn"" - PS.""QuantityOut"") as ""AvailableQty"",*,RP.""RetailName"" 
                            from ""PharmacyRetailStock"" PS  
                            join ""RetailWareHouseLink"" PWL on PWL.""RetailWareHouseLinkId"" = PS.""RetailWareHouseLinkId""
                            join ""PharmacyWareHouse"" PW on PW.""PharmacyWareHouseId"" = PWL.""PharmacyWareHouseId""
                            join ""RetailPharmacy"" RP on RP.""RetailPharmacyId"" = PWL.""RetailPharmacyId""
                            join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PS.""PharmacyProductId""
                                                        where (Extract(Month from PS.""ExpiryDate"") = (extract(Month from now())) and 
								                          Extract(Year from PS.""ExpiryDate"") = (extract(Year from now()))) {where}";
            return await this.unitOfWork.Current.QueryAsync<PharmacyDashboardModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyDashboardModel>> FetchProductUnderReorderLevelRetail(PharmacyReportFilterModel model)
        {
            var where = "";
            if (!string.IsNullOrEmpty(model.ProductName))
            {
                where += $@" and PP.""ProductName"" ilike '%{model.ProductName}%'";
            }

            if (!string.IsNullOrEmpty(model.GenericName))
            {
                where += $@" and PP.""GenericName"" ilike '%{model.GenericName}%'";
            }

            if (model.LocationId != null)
            {
                where += $@" and PW.""LocationId"" = {model.LocationId}";
            }

            if (!string.IsNullOrEmpty(model.CategoryName))
            {
                where += $@" and LV.""Name"" ilike '%{model.CategoryName}%'";
            }

            if (!string.IsNullOrEmpty(model.RetailStoreName))
            {
                where += $@" and RP.""RetailName"" ilike '%{model.RetailStoreName}%'";
            }

            var query = $@"Select count(PS.*) over() as ""TotalItems"",(sum(PS.""QuantityIn"") - sum(PS.""QuantityOut"")) as ""AvailableQty"",*,RP.""RetailName"",
                            ppd.""ROL"",ppd.""ROQ""                            
                   from ""PharmacyRetailStock"" PS 
                             join ""RetailWareHouseLink"" PWL on PWL.""RetailWareHouseLinkId"" = PS.""RetailWareHouseLinkId""
                             join ""PharmacyWareHouse"" PW on PW.""PharmacyWareHouseId"" = PWL.""PharmacyWareHouseId""
                            join ""RetailPharmacy"" RP on RP.""RetailPharmacyId"" = PWL.""RetailPharmacyId""
                            join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PS.""PharmacyProductId""
                             join ""PharmacyProductDetail"" ppd on ppd.""PharmacyProductId""=PP.""PharmacyProductId""
                            join ""LookupValue"" LV on LV.""LookupValueId"" = PP.""CategoryId""
                            where ppd.""ROL"" >= (PS.""QuantityIn"" - PS.""QuantityOut"") {where}
                            group  by PS.*,RP.""RetailName"",ppd.""ROL"",ppd.""ROQ"",ps.""PharmacyRetailStockId"",pwl.""RetailWareHouseLinkId"",
                                    pw.""PharmacyWareHouseId"",rp.""RetailPharmacyId"",pp.""PharmacyProductId"",ppd.""PharmacyProductDetailId""
                            ,lv.""LookupValueId""";

            if (model.PageIndex != 0 && model.PageSize != 0)
            {
                model.PageIndex -= 1;
                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }
            return await this.unitOfWork.Current.QueryAsync<PharmacyDashboardModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> AddPharmacySaleBillReturnAsync(PharmacySaleReturnBillModel model)
        {
            using var transaction = this.unitOfWork.BeginTransaction();
            var billHeader =
                await this.unitOfWork.PharmacySaleHeaders.FindAsync(
                    m => m.PharmacySaleHeaderId == model.PharmacySaleHeaderId);
            if (billHeader == null)
            {
                return -1;
            }

            var billDetail =
                await this.unitOfWork.PharmacySaleDetails.FindAsync(
                    m => m.PharmacySaleDetailId == model.PharmacySaleDetailId);

            var returnHeader = new SaleReturnHeader
            {
                SaleReturnHeaderId = model.SaleReturnHeaderId ?? 0,
                BillType = model.BillType,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                PharmacySaleHeaderId = model.PharmacySaleHeaderId,
                OverallDiscount = model.DiscountAmount != null ? Math.Round((double)model.DiscountAmount, 2) : model.DiscountAmount,
                OverallTaxes = 0,
                OverallNetAmount = Math.Round(model.NetAmount, 2),
                OverallTotal = Math.Round(model.Total, 2),
                PatientId = billHeader.PatientId,
                PatientName = billHeader.PatientName,
                ReturnDate = model.ReturnDate.Add(DateTime.UtcNow.AddMinutes(330).TimeOfDay)
            };
            var returnHeaderPrev = new SaleReturnHeader();
            if (returnHeader.SaleReturnHeaderId > 0)
            {
                returnHeaderPrev = await this.unitOfWork.SaleReturnHeaders.FindAsync(
                                            m => m.SaleReturnHeaderId == returnHeader.SaleReturnHeaderId);
            }

            if (returnHeaderPrev.CreatedDate.ToString("yyyy-MM-dd") != DateTime.Now.ToString("yyyy-MM-dd"))
            {
                model.SaleReturnHeaderId = null;
            }

            if (model.SaleReturnHeaderId != null)
            {
#pragma warning disable S2583 // Conditionally executed code should be reachable
                if (returnHeaderPrev != null)
#pragma warning restore S2583 // Conditionally executed code should be reachable
                {
                    returnHeaderPrev.OverallTaxes += returnHeader.OverallTaxes;
                    returnHeaderPrev.OverallNetAmount += returnHeader.OverallNetAmount;
                    returnHeaderPrev.OverallDiscount += returnHeader.OverallDiscount;
                    returnHeaderPrev.OverallTotal += returnHeader.OverallTotal;
                    returnHeaderPrev.ModifiedBy = returnHeader.CreatedBy;
                    returnHeaderPrev.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
                    returnHeader.ModifiedDate = DateTime.UtcNow.AddMinutes(330);

                    var updateResponse = await this.unitOfWork.SaleReturnHeaders.UpdateAsync(returnHeaderPrev, transaction);
                    if (updateResponse <= 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }
                else
                {
                    transaction.Rollback();
                    return -2;
                }
            }
            else
            {
                returnHeader.SaleReturnHeaderId =
                    await this.unitOfWork.SaleReturnHeaders.InsertAsync(returnHeader, transaction);
                if (returnHeader.SaleReturnHeaderId <= 0)
                {
                    transaction.Rollback();
                    return -3;
                }
            }

            var returnDetail = new SaleReturnDetail
            {
                SaleReturnHeaderId = returnHeader.SaleReturnHeaderId,
                DiscountAmount = model.DiscountAmount,
                DiscountPercentage = billDetail.DiscountPerItem,
                Total = Math.Round(model.Total, 2),
                NetAmount = Math.Round(model.NetAmount, 2),
                PharmacyProductId = model.PharmacyProductId,
                PharmacyRetailStockId = model.PharmacyRetailStockId,
                Quantity = model.Quantity,
                TaxAmount = (billDetail.TaxAmount / billDetail.Quantity) * model.Quantity,
                TaxPercentage = billDetail.TaxId,
                PayTypeId = model.PayTypeId,
                PaymentNumber = model.PaymentNumber
            };

            returnDetail.SaleReturnDetailId =
                await this.unitOfWork.SaleReturnDetails.InsertAsync(returnDetail, transaction);
            if (returnDetail.SaleReturnDetailId <= 0)
            {
                transaction.Rollback();
                return -4;
            }

            if (billDetail.ReturnQuantity == null)
            {
                billDetail.ReturnQuantity = model.Quantity;
            }
            else
            {
                billDetail.ReturnQuantity += model.Quantity;
            }

            var billDetailResponse = await this.unitOfWork.PharmacySaleDetails.UpdateAsync(billDetail, transaction);
            if (billDetailResponse <= 0)
            {
                transaction.Rollback();
                return -5;
            }

            var retailStock = await this.unitOfWork.PharmacyRetailStocks.FindAsync(
                                  m => m.PharmacyRetailStockId == model.PharmacyRetailStockId);
            if (retailStock == null)
            {
                transaction.Rollback();
                return -6;
            }

            retailStock.QuantityOut -= model.Quantity;
            retailStock.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            retailStock.ModifiedBy = model.CreatedBy;

            var retailStockResponse =
                await this.unitOfWork.PharmacyRetailStocks.UpdateAsync(retailStock, transaction);

            if (retailStockResponse <= 0)
            {
                transaction.Rollback();
                return -7;
            }

            if (returnHeader.SaleReturnHeaderId > 0)
            {

                if (model.PaymentInitiationLogId != null && model.PaymentInitiationLogId != 0)
                {
                    PaymentMapHelperModel paymentHelper = new PaymentMapHelperModel { PaymentInitiationLogId = ((int)model.PaymentInitiationLogId), BillId = returnHeader.SaleReturnHeaderId };
                    paymentHelper.PaymentMapHelperId = await this.paymentMapHelperService.AddAsync(paymentHelper);
                    if (paymentHelper.PaymentMapHelperId == 0)
                    {
                        transaction.Rollback();
                        return -10;
                    }
                }
                //to get bill
                var getbillrecord = await this.unitOfWork.MasterBill.FindAsync(x => x.ReceiptAreaTypeId == (int)ReceiptAreaType.Pharmacy && x.ModuleId == billHeader.PharmacySaleHeaderId); //need to check more

                //transaction for the sale return
                var commonTransaction = new AppointmentTransaction
                {
                    AppointmentId = returnHeader.SaleReturnHeaderId,
                    Transaction = model.Transaction ?? "",
                    TransactionDate = DateTime.Now,
                    TransactionId = model.TransactionId ?? await this.appointmentTransactionsServices.GetATransactionId(),
                    VoucherNumber = await this.appointmentTransactionsServices.GetVoucherNumber(),
                    BankReference = "",
                    BankCode = "",
                    Active = true,
                    PaymentId = 0,
                    PaymentModeId = 1,
                    SettledAmount = (decimal)returnHeader.OverallNetAmount,
                    CreatedBy = (int)model.CreatedBy,
                    CreatedDate = DateTime.Now,
                    LocationId = (int)model.LocationId,
                    ReceiptTypeId = (int)ReceiptType.Refund,
                    ReceiptAreaTypeId = (int)ReceiptAreaType.PharmacyReturn,
                    SalucroStatusCode = model.SalucroStatusCode,
                    SalucroTransactionId = model.SalucroTransactionId,
                    PatientId = billHeader.PatientId,
                    //PayStatus-not impl for return
                };
                commonTransaction.AppointmentTransactionId = await this.unitOfWork.AppointmentTransactions.InsertAsync(commonTransaction, transaction);
                if (commonTransaction.AppointmentTransactionId == 0)
                {
                    transaction.Rollback();
                    return -8;
                }
                var paymentDetails = model.PaymentNumber != null ? model.PaymentNumber : null;
                var receipt = new Receipt
                {
                    Active = true,
                    Cost = returnHeader.OverallNetAmount,
                    CreatedBy = (int)model.CreatedBy,
                    CreatedDate = DateTime.Now,
                    IsAdvance = false,
                    IsRefunded = false,
                    PayTypeId = model.PayTypeId,
                    PaymentDetails = paymentDetails,
                    ReceiptTypeId = ReceiptType.Refund,
                    ReceiptAreaTypeId = ReceiptAreaType.PharmacyReturn,
                    RespectiveId = returnHeader.SaleReturnHeaderId,
                    TransactionId = commonTransaction.AppointmentTransactionId,
                    MasterBillId = getbillrecord != null ? getbillrecord.MasterBillId : 0
                };
                receipt.ReceiptId = await this.unitOfWork.Receipt.InsertAsync(receipt);
                if (receipt.ReceiptId == 0)
                {
                    transaction.Rollback();
                    return -9;
                }

                var paidReceipts = await this.unitOfWork.Receipt.FindAllAsync(x => x.MasterBillId == receipt.MasterBillId && x.ReceiptAreaTypeId == ReceiptAreaType.Pharmacy);                
                var paidSum = 0.0;
                foreach (var item in paidReceipts)
                {
                    paidSum += item.Cost;
                }

                var refundReceipts = await this.unitOfWork.Receipt.FindAllAsync(x => x.MasterBillId == receipt.MasterBillId && x.ReceiptAreaTypeId == ReceiptAreaType.PharmacyReturn);
                var refundSum = 0.0;
                foreach (var item in refundReceipts)
                {
                    refundSum += item.Cost;
                }

                //update bill refund
                if (getbillrecord != null)
                {
                    getbillrecord.Refund += (double)returnHeader.OverallNetAmount;
                    getbillrecord.RemovedAmount += model.RemovedProductAmount;
                    if (paidSum == refundSum)
                    {
                        getbillrecord.Active = false;
                    }
                    await this.unitOfWork.MasterBill.UpdateAsync(getbillrecord);
                }
            }

            transaction.Commit();
            return returnHeader.SaleReturnHeaderId;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacySaleReturnFetchModel>> FetchSaleReturnBill(int? id, string billNumber)
        {
            var where = "where 1=1";
            if (id != null)
            {
                where += $@" and SRH.""SaleReturnHeaderId"" = {id}";
            }

            if (!string.IsNullOrEmpty(billNumber))
            {
                where = $@" and PSH.""BillNumber"" = '{billNumber}'";
            }

            var query =
                $@"SELECT SRH.""SaleReturnHeaderId"", SRH.""ReturnDate"", SRH.""BillType"", SRH.""PatientId"", SRH.""PatientName"", SRH.""OverallTotal"",  
                                SRH.""OverallNetAmount"", SRH.""CreatedBy"", SRH.""CreatedDate"",SRH.""PharmacySaleHeaderId"",SRD.""SaleReturnDetailId"", SRD.""PharmacyProductId"",
                                SRD.""Quantity"", SRD.""Total"", SRD.""TaxPercentage"", SRD.""TaxAmount"",SRD.""DiscountPercentage"", SRD.""DiscountAmount"", SRD.""NetAmount"",
                                PP.""ProductName"",PRS.""ExpiryDate"",PRS.""Mrp"",A.""FullName"" as ""CreatedByName"", PP.""ScheduledDrug""
	                                FROM ""SaleReturnHeader"" SRH 
	                                join ""SaleReturnDetail"" SRD on SRD.""SaleReturnHeaderId"" = SRH.""SaleReturnHeaderId""
	                                join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = SRD.""PharmacyProductId""
	                                join ""PharmacyRetailStock"" PRS on PRS.""PharmacyRetailStockId"" = SRD.""PharmacyRetailStockId"" 
	                                join ""PharmacySaleHeader"" PSH on PSH.""PharmacySaleHeaderId"" = SRH.""PharmacySaleHeaderId""
	                                join ""Account"" A on A.""AccountId"" = SRH.""CreatedBy""
                                    {where}  order by SRH.""SaleReturnHeaderId"" desc";

            return await this.unitOfWork.Current.QueryAsync<PharmacySaleReturnFetchModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> AddRetailStock(PharmacyRetailStockModel model)
        {
            var retailStock = new PharmacyRetailStock
            {
                Barcode = model.Barcode,
                BatchNumber = model.BatchNumber,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                ExpiryDate = model.ExpiryDate,
                Mrp = model.Mrp,
                PharmacyProductId = model.PharmacyProductId,
                PharmacyStockId = null,
                PurchaseRate = model.PurchaseRate,
                QuantityIn = model.QuantityIn,
                QuantityOut = 0,
                TaxId = model.TaxId,
                IsAddedDirectly = true,
                ManuallyUpdated = 0
            };

            return await this.unitOfWork.PharmacyRetailStocks.InsertAsync(retailStock);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyStockModel>> FetchSurgeryProductsStock(string ids, int? retailPharmacyId)
        {
            var where = $@"where 1=1 and PS.""PharmacyProductId"" in ({ids}) and (PS.""QuantityIn"" - PS.""QuantityOut"") > 0 ";

            if (retailPharmacyId != null)
            {
                where += $@" and PS.""RetailWareHouseLinkId"" in (Select ""RetailWareHouseLinkId"" from ""RetailWareHouseLink"" where ""RetailPharmacyId"" = {retailPharmacyId})";
            }

            var query =
                $@"SELECT PS.""PharmacyRetailStockId"",PS.""PharmacyStockId"", PS.""PharmacyProductId"", PS.""TaxId"", PS.""QuantityIn"", PS.""QuantityOut"", PS.""BatchNumber"", PS.""ExpiryDate"",
                                    PS.""PurchaseRate"", PS.""Mrp"", PS.""Barcode"", PP.""ProductName"",PP.""GenericName"",PS.""CreatedDate"",
                                    (PS.""QuantityIn"" - PS.""QuantityOut"") as ""AvailableQuantity"",Cat.""Name"" as ""CategoryName"",Tax.""Name""::int as ""TaxPercentage"", C.""Name"" as ""CompanyName"",
                                    PP.""ScheduledDrug""
 	                                    FROM ""PharmacyRetailStock"" PS  
	                                    join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PS.""PharmacyProductId""
	                                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
	                                    join ""LookupValue"" Tax on Tax.""LookupValueId"" = PS.""TaxId""
                                        join ""Company"" C on C.""CompanyId"" = PP.""CompanyId"" 
										{where}
										order by PS.""CreatedDate"" desc";
            return await this.unitOfWork.Current.QueryAsync<PharmacyStockModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> UpdateMainStock(PharmacyRetailStockModel model)
        {
            var record = await this.unitOfWork.PharmacyStocks.FindAsync(m => m.PharmacyStockId == model.PharmacyStockId);
            record.Mrp = model.Mrp;
            record.PurchaseRate = model.PurchaseRate;
            record.QuantityIn = model.QuantityIn;
            record.QuantityOut = model.QuantityOut;
            record.BatchNumber = model.BatchNumber;
            record.ExpiryDate = model.ExpiryDate ?? record.ExpiryDate;
            record.ModifiedBy = model.CreatedBy;
            record.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            record.ManuallyUpdated += 1;
            return await this.unitOfWork.PharmacyStocks.UpdateAsync(record);
        }

        /// <inheritdoc/>
        public async Task<int> UpdateRetailStock(PharmacyRetailStockModel model)
        {
            var record = await this.unitOfWork.PharmacyRetailStocks.FindAsync(m => m.PharmacyRetailStockId == model.PharmacyRetailStockId);
            record.Mrp = model.Mrp;
            record.PurchaseRate = model.PurchaseRate;
            record.QuantityIn = model.QuantityIn;
            record.QuantityOut = model.QuantityOut;
            record.BatchNumber = model.BatchNumber;
            record.ExpiryDate = model.ExpiryDate ?? record.ExpiryDate;
            record.ModifiedBy = model.CreatedBy;
            record.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            record.ManuallyUpdated += 1;
            return await this.unitOfWork.PharmacyRetailStocks.UpdateAsync(record);
        }

        /// <inheritdoc/>
        public async Task<int> DeleteSaleBillItem(PharmacySaleBill model)
        {
            var saleHeader = await this.unitOfWork.PharmacySaleHeaders.FindAsync(m => m.PharmacySaleHeaderId == model.PharmacySaleHeaderId);
            if (saleHeader == null)
            {
                return -1;
            }
            var saleDetail = await this.unitOfWork.PharmacySaleDetails.FindAsync(m => m.PharmacySaleDetailId == model.PharmacySaleDetailId);
            if (saleDetail == null)
            {
                return -2;
            }
            var oldRetailStock = await this.unitOfWork.PharmacyRetailStocks.FindAsync(m => m.PharmacyRetailStockId == saleDetail.PharmacyRetailStockId);
            if (oldRetailStock == null)
            {
                return -3;
            }
            using var transaction = this.unitOfWork.BeginTransaction();
            saleHeader.Total -= saleDetail.Total;
            if (saleHeader.OverallDiscount != null && saleDetail.Discount != null)
            {
                saleHeader.OverallDiscount -= saleDetail.Discount;
            }
            saleHeader.OverallNetAmount -= saleDetail.NetAmount;
            saleHeader.OverallTaxes -= saleDetail.TaxAmount;
            saleHeader.ModifiedBy = model.CreatedBy;
            saleHeader.ModifiedDate = DateTime.UtcNow.AddMinutes(330);

            var headerResponse = await this.unitOfWork.PharmacySaleHeaders.UpdateAsync(saleHeader, transaction);
            if (headerResponse <= 0)
            {
                transaction.Rollback();
                return -4;
            }

            oldRetailStock.QuantityOut -= saleDetail.Quantity;
            oldRetailStock.ModifiedBy = model.CreatedBy;
            oldRetailStock.ModifiedDate = DateTime.UtcNow.AddMinutes(330);

            var stockResponse = await this.unitOfWork.PharmacyRetailStocks.UpdateAsync(oldRetailStock, transaction);
            if (stockResponse <= 0)
            {
                transaction.Rollback();
                return -5;
            }

            var detailResponse = await this.unitOfWork.PharmacySaleDetails.DeleteAsync(saleDetail, transaction);
            if (!detailResponse)
            {
                transaction.Rollback();
                return -6;
            }

            transaction.Commit();
            return 1;
        }

        /// <inheritdoc/>
        public async Task<int> UpdateSaleBillQuantity(PharmacySaleBill model)
        {
            var saleDetail = await this.unitOfWork.PharmacySaleDetails.FindAsync(m => m.PharmacySaleDetailId == model.PharmacySaleDetailId);
            if (saleDetail == null)
            {
                return -2;
            }

            var deleteResponse = await this.DeleteSaleBillItem(model);
            if (deleteResponse <= 0)
            {
                return -1;
            }

            var bill = new PharmacySaleBillModel
            {
                CreatedBy = (int)model.CreatedBy,
                Discount = model.Discount,
                DiscountPerItem = saleDetail.DiscountPerItem,
                NetAmount = (double)model.NetAmount,
                PharmacyProductId = model.PharmacyProductId,
                PharmacyRetailStockId = (int)model.PharmacyRetailStockId,
                PharmacySaleHeaderId = (int)model.PharmacySaleHeaderId,
                Quantity = (int)model.Quantity,
                TaxAmount = (double)model.TaxAmount,
                Total = (double)model.Total,
                TaxId = saleDetail.TaxId,
                // PaidVia=model.PaidVia
            };

            var (updateResponse, res) = await this.UpdateSaleBill(bill);

            if (updateResponse <= 0)
            {
                return -2;
            }
            return updateResponse;
        }

        /// <inheritdoc/>
        public async Task<int> CancelSaleBill(int saleHeaderId)
        {
            var headerRecord = await this.unitOfWork.PharmacySaleHeaders.FindAsync(m => m.PharmacySaleHeaderId == saleHeaderId);
            if (headerRecord == null)
            {
                return -1;
            }

            var detailRecords = await this.unitOfWork.PharmacySaleDetails.FindAllAsync(m => m.PharmacySaleHeaderId == headerRecord.PharmacySaleHeaderId);
            var listDetailRecord = detailRecords.ToList();
            if (listDetailRecord.Count == 0)
            {
                return -2;
            }

            foreach (var item in listDetailRecord)
            {
                if (item.ReturnQuantity != null)
                {
                    return -5;
                }
            }

            foreach (var item in listDetailRecord)
            {
                var record = new PharmacySaleBill
                {
                    PharmacyProductId = item.PharmacyProductId,
                    PharmacyRetailStockId = item.PharmacyRetailStockId,
                    PharmacySaleDetailId = item.PharmacySaleDetailId,
                    PharmacySaleHeaderId = item.PharmacySaleHeaderId
                };

                var deleteDetail = await this.DeleteSaleBillItem(record);
                if (deleteDetail < 0)
                {
                    return -3;
                }
            }

            using var transaction = this.unitOfWork.BeginTransaction();
            var deleteHeader = await this.unitOfWork.PharmacySaleHeaders.DeleteAsync(headerRecord, transaction);
            if (!deleteHeader)
            {
                transaction.Rollback();
                return -4;
            }
            transaction.Commit();
            return 1;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<ProductModel>> FetchPharmacyProductWithRetailStockAsync(ProductModel model)
        {
            var where = $@"where 1=1 and (PS.""QuantityIn"" - PS.""QuantityOut"") > 0";
            var extraColumns = string.Empty;
            var extraCondition = string.Empty;

            if (!string.IsNullOrEmpty(model.ProductName))
            {
                where += $@" and PP.""ProductName"" ilike '%{model.ProductName}%'";
            }

            if (!string.IsNullOrEmpty(model.GenericName))
            {
                where += $@" and PP.""GenericName"" ilike '%{model.GenericName}%'";
            }

            if (model.RetailPharmacyId != null)
            {
                where += $@" and PS.""RetailWareHouseLinkId"" in (Select ""RetailWareHouseLinkId"" from ""RetailWareHouseLink"" where ""RetailPharmacyId"" = {model.RetailPharmacyId})";
                extraColumns = $@" ,PPD.""ROQ"",PPD.""ROL"",PPR.""RackName"",PPD.""PharmacyProductDetailId"" ";
                extraCondition = $@"  left join ""PharmacyProductDetail"" PPD on PPD.""PharmacyProductId"" = PS.""PharmacyProductId"" and PPD.""RetailPharmacyId"" = {model.RetailPharmacyId}
										left join ""PharmacyProductRack"" PPR on PPR.""PharmacyProductRackId"" = PPD.""PharmacyProductRackId""";

            }
            if (!string.IsNullOrEmpty(model.Barcode))
            {
                where += $@" and PS.""Barcode"" = '{model.Barcode}'";
            }

            if (!string.IsNullOrEmpty(model.BulkProductIds))
            {
                where += $@" and PS.""PharmacyProductId"" in ({model.BulkProductIds})";
            }

            if (model.PharmacyProductId > 0)
            {
                where += $@" and PS.""PharmacyProductId"" = {model.PharmacyProductId}";
            }

            var query = $@"SELECT count(PP.*) over() as ""TotalItems"", PP.""PharmacyProductId"", PP.""ProductName"", PP.""GenericName"", 
                                    PP.""Barcode"",PP.""PurchaseUnitQty"", PP.""SaleUnitQty"", PP.""CategoryId"", PP.""CompanyId"", PP.""SupplierId"", PP.""PurchaseUnit"",
                                    PP.""SaleUnit"", PP.""TaxId"", PP.""IsProductExpire"", PP.""Active"", PP.""CreatedBy"", PP.""CreatedDate"",
                                    C.""Name"" as ""CompanyName"",Cat.""Name"" as ""CategoryName"",--Tax.""Name"" as ""Tax"",									
                                    PurchaseUnit.""Name"" as ""PurchaseUnitName"", SaleUnit.""Name"" as ""SaleUnitName"",
                                    A.""FullName"" as ""CreatedByName"",
									Tax.""Name""::int as ""TaxPercentage"",PS.""PharmacyRetailStockId"",PS.""PharmacyStockId"",
									PS.""PharmacyProductId"",PS.""TaxId"", PS.""QuantityIn"", PS.""QuantityOut"", 
									PS.""BatchNumber"", PS.""ExpiryDate"",
                                    PS.""PurchaseRate"", PS.""Mrp"", PS.""Barcode"", PS.""CreatedDate"",
                                    (PS.""QuantityIn"" - PS.""QuantityOut"") as ""AvailableQuantity"",PP.""ScheduledDrug"",
                                    PS.""IsIGST"",PS.""IsSGST""
                                    {extraColumns}
	                                    FROM ""PharmacyProduct"" PP join ""Company"" C on C.""CompanyId"" = PP.""CompanyId""
	                                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
	                                    join ""LookupValue"" PurchaseUnit on PurchaseUnit.""LookupValueId"" = PP.""PurchaseUnit""
	                                    join ""LookupValue"" SaleUnit on SaleUnit.""LookupValueId"" = PP.""SaleUnit""
	                                    left join ""Account"" A on A.""AccountId"" = PP.""CreatedBy""
										join ""PharmacyRetailStock"" PS on PS.""PharmacyProductId"" = PP.""PharmacyProductId""
										left join ""LookupValue"" Tax on Tax.""LookupValueId"" = PS.""TaxId""
                                        {extraCondition}
	                                    {where}
										order by PS.""CreatedDate"" desc";

            if (model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageIndex;

                query += $@" limit {model.PageSize} offset {model.PageSize * model.PageIndex}";
            }
            return await this.unitOfWork.Current.QueryAsync<ProductModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> MoveRetailStockToMainAsync(PharmacyMoveQuantity model)
        {
            var issueDetail = await this.unitOfWork.IssueDetails.FindAsync(m => m.StockId == model.PharmacyStockId && m.ProductId == model.PharmacyProductId);
            if (issueDetail == null)
            {
                return -1;
            }

            var pharmacyStock = await this.unitOfWork.PharmacyStocks.FindAsync(m => m.PharmacyStockId == model.PharmacyStockId);
            if (pharmacyStock == null)
            {
                return -2;
            }

            using var transaction = this.unitOfWork.BeginTransaction();
            pharmacyStock.QuantityOut -= model.Quantity;
            pharmacyStock.ModifiedBy = model.CreatedBy;
            pharmacyStock.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            pharmacyStock.ManuallyUpdated += 1;
            var pharmacyStockResponse = await this.unitOfWork.PharmacyStocks.UpdateAsync(pharmacyStock, transaction);
            if (pharmacyStockResponse <= 0)
            {
                transaction.Rollback();
                return -3;
            }

            var pharmacyRetailStock = await this.unitOfWork.PharmacyRetailStocks.FindAsync(m => m.PharmacyRetailStockId == model.PharmacyRetailStockId);
            if (pharmacyRetailStock == null)
            {
                transaction.Rollback();
                return -4;
            }

            pharmacyRetailStock.QuantityIn -= model.Quantity;
            pharmacyRetailStock.ModifiedBy = model.CreatedBy;
            pharmacyRetailStock.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            pharmacyRetailStock.ManuallyUpdated += 1;
            var pharmacyRetailStockResponse = await this.unitOfWork.PharmacyRetailStocks.UpdateAsync(pharmacyRetailStock, transaction);
            if (pharmacyRetailStockResponse <= 0)
            {
                transaction.Rollback();
                return -5;
            }

            var mainToRetail = new PharmacyRetailToMain()
            {
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                IssueDetailId = issueDetail.IssueDetailId,
                PharmacyProductId = model.PharmacyProductId,
                PharmacyRetailStockId = model.PharmacyRetailStockId,
                PharmacyStockId = model.PharmacyStockId,
                Quantity = model.Quantity,
                Reason = model.Reason
            };

            var retailToMainResponse = await this.unitOfWork.PhamrmacyRetailToMains.InsertAsync(mainToRetail, transaction);
            if (retailToMainResponse == 0)
            {
                transaction.Rollback();
                return -6;
            }

            transaction.Commit();
            return retailToMainResponse;
        }

        /// <inheritdoc/>
        public async Task<PharmacyPurchaseBill> FetchPurchaseBillItem(int pharmacyStockId)
        {
            var query = $@"SELECT PPH.""PharmacyPurchaseHeaderId"", PH.""ProductName"",PPH.""BillNumber"", PPH.""BillDate"", PPH.""BillType"", PPH.""SupplierId"", PPH.""BillAmount"", 
                                PPH.""Discount"" as ""OverallDiscount"", PPH.""Taxes"", PPH.""Netamount"" as ""TotalNetAmount"",PPD.""PharmacyPurchaseDetailId"", PPD.""PharmacyPurchaseHeaderId"", 
								PPD.""SerialNum"", PPD.""PharmacyProductId"", PPD.""Quantity"", PPD.""Free"", SS.""Name"" as ""SupplierName"",
                                PPD.""PurchaseRate"", PPD.""Mrp"", PPD.""Total"", PPD.""TaxPerItem"", PPD.""TaxAmount"", PPD.""DiscountPerItem"",PPD.""DiscountAmount"", 
                                PPD.""NetAmount"", PPD.""Barcode"", PPD.""PharmacyStockId"",PPD.""PharmacyRetailStockId"",PS.""BatchNumber"",PS.""ExpiryDate"",
                                PH.""ScheduledDrug""
								    FROM ""PharmacyPurchaseHeader"" PPH
	                                join ""PharmacyPurchaseDetail"" PPD on PPD.""PharmacyPurchaseHeaderId"" = PPH.""PharmacyPurchaseHeaderId""
	                                join ""PharmacyProduct"" PH on PH.""PharmacyProductId"" = PPD.""PharmacyProductId""
									join ""PharmacyStock"" PS on PS.""PharmacyStockId"" = PPD.""PharmacyStockId""
									join ""Supplier"" SS on SS.""SupplierId"" = PPH.""SupplierId""
									where PPD.""PharmacyStockId"" = {pharmacyStockId}";
            var record = (await this.unitOfWork.Current.QueryAsync<PharmacyPurchaseBill>(query)).ToList();
            return record[0];
        }

        /// <inheritdoc/>
        public async Task<int> ReturnPurchaseBill(PharmacyPurchaseReturnBillModel model)
        {
            using var transaction = this.unitOfWork.BeginTransaction();
            var product = await this.unitOfWork.PharmacyProducts.FindAsync(p => p.PharmacyProductId == model.PharmacyProductId);

            if (product == null)
            {
                transaction.Rollback();
                return -4;
            }

            var returnHeader = await this.unitOfWork.PharmacyPurchaseReturnHeaders.FindAsync(m => m.PharmacyPurchaseHeaderId == model.PharmacyPurchaseHeaderId);
            var header = new PharmacyPurchaseReturnHeader
            {
                ReturnDate = DateTime.UtcNow.AddMinutes(330),
                PharmacyPurchaseHeaderId = model.PharmacyPurchaseHeaderId,
                BillNumber = model.BillNumber,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                OverallBillAmount = model.Amount,
                OverallDiscount = model.DiscountAmount,
                OverallTaxes = model.TaxAmount,
                OverallNetamount = model.NetAmount
            };
            if (returnHeader == null)
            {
                header.PharmacyPurchaseReturnHeaderId = await this.unitOfWork.PharmacyPurchaseReturnHeaders.InsertAsync(header, transaction);
                if (header.PharmacyPurchaseReturnHeaderId == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }
            else
            {
                returnHeader.ModifiedBy = model.CreatedBy;
                returnHeader.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
                returnHeader.OverallBillAmount += header.OverallBillAmount;
                returnHeader.OverallDiscount += header.OverallDiscount;
                returnHeader.OverallNetamount += header.OverallNetamount;
                returnHeader.OverallTaxes += header.OverallTaxes;
                header.PharmacyPurchaseReturnHeaderId = returnHeader.PharmacyPurchaseReturnHeaderId;
                var headerResponse = await this.unitOfWork.PharmacyPurchaseReturnHeaders.UpdateAsync(returnHeader, transaction);
                if (headerResponse <= 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }

            var detailReturn = new PharmacyPurchaseReturnDetail
            {
                Amount = model.Amount,
                DiscountAmount = model.DiscountAmount,
                DiscountPercentage = model.DiscountPercentage,
                NetAmount = model.NetAmount,
                PharmacyProductId = model.PharmacyProductId,
                PharmacyPurchaseDetailId = model.PharmacyPurchaseDetailId,
                PharmacyPurchaseReturnHeaderId = header.PharmacyPurchaseReturnHeaderId,
                ReturnQuantity = model.ReturnQuantity,
                PharmacyStockId = model.PharmacyStockId,
                TaxPercentage = model.TaxPercentage
            };

            detailReturn.PharmacyPurchaseReturnDetailId = await this.unitOfWork.PharmacyPurchaseReturnDetails.InsertAsync(detailReturn, transaction);
            if (detailReturn.PharmacyPurchaseReturnDetailId == 0)
            {
                transaction.Rollback();
                return -3;
            }

            var stock = await this.unitOfWork.PharmacyStocks.FindAsync(s => s.PharmacyStockId == model.PharmacyStockId);
            if (stock == null)
            {
                transaction.Rollback();
                return -5;
            }

            var quantityToReduce = model.ReturnQuantity * (product.PurchaseUnitQty * product.SaleUnitQty);

            stock.QuantityIn -= quantityToReduce;
            stock.ModifiedBy = model.CreatedBy;
            stock.ModifiedDate = DateTime.Now;
            stock.ManuallyUpdated += 1;

            var stockResponse = await this.unitOfWork.PharmacyStocks.UpdateAsync(stock, transaction);

            if (stockResponse <= 0)
            {
                transaction.Rollback();
                return -6;
            }

            transaction.Commit();
            return header.PharmacyPurchaseReturnHeaderId;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyExplorerModel>> FetchCategoryRevenue(PharmacyExplorerFilterModel model)
        {
            var paramsString = "";
            if (model.FromDate != null)
            {
                paramsString += $@" '{model.FromDate}'";
            }
            else
            {
                paramsString += $@" null";
            }

            if (model.ToDate != null)
            {
                paramsString += $@", '{model.ToDate}'";
            }
            else
            {
                paramsString += $@", null";
            }
            //category wise
            var query = $@"select * from ""udf_Graphs_PharmacySalesRevenue_Category_Wise""({paramsString})";
            return await this.unitOfWork.Current.QueryAsync<PharmacyExplorerModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyExplorerModel>> FetchProductRevenue(PharmacyExplorerFilterModel model)
        {
            var paramsString = "";
            if (model.FromDate != null)
            {
                paramsString += $@" '{model.FromDate}'";
            }
            else
            {
                paramsString += $@" null";
            }

            if (model.ToDate != null)
            {
                paramsString += $@", '{model.ToDate}'";
            }
            else
            {
                paramsString += $@", null";
            }
            //product wise
            var query = $@"select * from ""udf_Graphs_PharmacySalesRevenue_Product_Wise""({paramsString})";
            return await this.unitOfWork.Current.QueryAsync<PharmacyExplorerModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyExplorerModel>> FetchTopProductsRevenue(PharmacyExplorerFilterModel model)
        {
            var paramsString = "";
            if (model.FromDate != null)
            {
                paramsString += $@" '{model.FromDate}'";
            }
            else
            {
                paramsString += $@" null";
            }

            if (model.ToDate != null)
            {
                paramsString += $@", '{model.ToDate}'";
            }
            else
            {
                paramsString += $@", null";
            }
            //top products wise
            var query = $@"select * from ""udf_Graphs_PharmacySalesRevenue_Of_TopTenProducts""({paramsString})";
            return await this.unitOfWork.Current.QueryAsync<PharmacyExplorerModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyDoctorCollection>> FetchDoctorCollection(PharmacyExplorerFilterModel model)
        {
            var paramsString = "";

            if (model.ProviderId != null)
            {
                paramsString += $@" '{model.ProviderId}'";
            }
            else
            {
                paramsString += $@" null";
            }

            if (model.FromDate != null)
            {
                paramsString += $@", '{model.FromDate}'";
            }
            else
            {
                paramsString += $@", null";
            }

            if (model.ToDate != null)
            {
                paramsString += $@", '{model.ToDate}'";
            }
            else
            {
                paramsString += $@", null";
            }

            var query = $@"select * from ""udf_Graphs_Doctor_Collection_InPharmacyRevenue""({paramsString})";
            return await this.unitOfWork.Current.QueryAsync<PharmacyDoctorCollection>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyEmployeeCollection>> FetchEmployeeCollection(PharmacyExplorerFilterModel model)
        {
            var paramsString = "";

            if (model.AccountId != null)
            {
                paramsString += $@" '{model.AccountId}'";
            }
            else
            {
                paramsString += $@" null";
            }

            if (model.RoleId != null)
            {
                paramsString += $@", '{model.RoleId}'";
            }
            else
            {
                paramsString += $@", null";
            }

            if (model.FromDate != null)
            {
                paramsString += $@", '{model.FromDate}'";
            }
            else
            {
                paramsString += $@", null";
            }

            if (model.ToDate != null)
            {
                paramsString += $@", '{model.ToDate}'";
            }
            else
            {
                paramsString += $@", null";
            }

            var query = $@"select * from ""udf_Graphs_Employee_Collection_InPharmacyRevenue""({paramsString})";
            return await this.unitOfWork.Current.QueryAsync<PharmacyEmployeeCollection>(query);
        }

        /// <inheritdoc/>
        public async Task<Tuple<int, PharmacyPurchaseBill>> DeletePurchaseBillItems(PharmacyPurchaseBill model)
        {
            var purchaseHeader = await this.unitOfWork.PharmacyPurchaseHeaders.FindAsync(m => m.PharmacyPurchaseHeaderId == model.PharmacyPurchaseHeaderId);
            if (purchaseHeader == null)
            {
                return new Tuple<int, PharmacyPurchaseBill>(-1, model);
            }

            model.BillDate = purchaseHeader.BillDate;
            model.BillType = purchaseHeader.BillType;
            model.SupplierId = purchaseHeader.SupplierId;
            model.BillNumber = purchaseHeader.BillNumber;

            var purchaseDetail = await this.unitOfWork.PharmacyPurchaseDetails.FindAsync(m => m.PharmacyPurchaseDetailId == model.PharmacyPurchaseDetailId);
            if (purchaseDetail == null)
            {
                return new Tuple<int, PharmacyPurchaseBill>(-2, model);
            }

            var productDetail = await this.unitOfWork.PharmacyProducts.FindAsync(p => p.PharmacyProductId == purchaseDetail.PharmacyProductId);

            if (productDetail == null)
            {
                return new Tuple<int, PharmacyPurchaseBill>(-4, model);
            }

            var stock = await this.unitOfWork.PharmacyStocks.FindAsync(s => s.PharmacyStockId == purchaseDetail.PharmacyStockId);
            if (stock == null)
            {
                return new Tuple<int, PharmacyPurchaseBill>(-3, model);
            }

            var transaction = this.unitOfWork.BeginTransaction();
            var quantityForStockReduction = purchaseDetail.Quantity * (productDetail.PurchaseUnitQty * productDetail.SaleUnitQty);

            #region header
            purchaseHeader.Netamount -= purchaseDetail.NetAmount;
            purchaseHeader.BillAmount -= purchaseDetail.Total;
            purchaseHeader.Discount -= purchaseDetail.DiscountAmount;
            purchaseHeader.Taxes -= purchaseDetail.TaxAmount;
            purchaseHeader.ModifiedBy = model.CreatedBy;
            purchaseHeader.ModifiedDate = DateTime.UtcNow.AddMinutes(330);

            var updateHeader = await this.unitOfWork.PharmacyPurchaseHeaders.UpdateAsync(purchaseHeader, transaction);
            if (updateHeader <= 0)
            {
                transaction.Rollback();
                return new Tuple<int, PharmacyPurchaseBill>(-5, model);
            }
            #endregion

            #region stock
            stock.QuantityIn -= quantityForStockReduction;
            stock.ManuallyUpdated += 1;
            stock.ModifiedBy = model.CreatedBy;
            stock.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
            var stockResponse = await this.unitOfWork.PharmacyStocks.UpdateAsync(stock, transaction);
            if (stockResponse <= 0)
            {
                transaction.Rollback();
                return new Tuple<int, PharmacyPurchaseBill>(-6, model);
            }
            #endregion

            var detailResponse = await this.unitOfWork.PharmacyPurchaseDetails.DeleteAsync(purchaseDetail, transaction);
            if (!detailResponse)
            {
                transaction.Rollback();
                return new Tuple<int, PharmacyPurchaseBill>(-7, model);
            }
            transaction.Commit();

            var getDetailCount = (await this.unitOfWork.PharmacyPurchaseDetails.FindAllAsync(m => m.PharmacyPurchaseHeaderId == purchaseHeader.PharmacyPurchaseHeaderId)).ToList();
            if (getDetailCount.Count == 0)
            {
                await this.unitOfWork.PharmacyPurchaseHeaders.DeleteAsync(purchaseHeader);
            }

#pragma warning disable S2583 // Conditionally executed code should be reachable
            return new Tuple<int, PharmacyPurchaseBill>(detailResponse ? 1 : 0, model);
#pragma warning restore S2583 // Conditionally executed code should be reachable
        }

        /// <inheritdoc/>
        public async Task<Tuple<int, PharmacyPurchaseBill>> DeletePharmacyPurchaseBillItems(PharmacyPurchaseBill model)
        {
            var purchaseHeader = await this.unitOfWork.PharmacyPurchaseHeaders.FindAsync(m => m.PharmacyPurchaseHeaderId == model.PharmacyPurchaseHeaderId);
            if (purchaseHeader == null)
            {
                return new Tuple<int, PharmacyPurchaseBill>(-1, model);
            }

            model.BillDate = purchaseHeader.BillDate;
            model.BillType = purchaseHeader.BillType;
            model.SupplierId = purchaseHeader.SupplierId;

            var purchaseDetail = await this.unitOfWork.PharmacyPurchaseDetails.FindAsync(m => m.PharmacyPurchaseDetailId == model.PharmacyPurchaseDetailId);
            if (purchaseDetail == null)
            {
                return new Tuple<int, PharmacyPurchaseBill>(-2, model);
            }

            var productDetail = await this.unitOfWork.PharmacyProducts.FindAsync(p => p.PharmacyProductId == purchaseDetail.PharmacyProductId);

            if (productDetail == null)
            {
                return new Tuple<int, PharmacyPurchaseBill>(-4, model);
            }


            var transaction = this.unitOfWork.BeginTransaction();

            #region header
            purchaseHeader.Netamount -= purchaseDetail.NetAmount;
            purchaseHeader.BillAmount -= purchaseDetail.Total;
            purchaseHeader.Discount -= purchaseDetail.DiscountAmount;
            purchaseHeader.Taxes -= purchaseDetail.TaxAmount;
            purchaseHeader.ModifiedBy = model.CreatedBy;
            purchaseHeader.ModifiedDate = DateTime.UtcNow.AddMinutes(330);

            var updateHeader = await this.unitOfWork.PharmacyPurchaseHeaders.UpdateAsync(purchaseHeader, transaction);
            if (updateHeader <= 0)
            {
                transaction.Rollback();
                return new Tuple<int, PharmacyPurchaseBill>(-5, model);
            }
            #endregion

            var detailResponse = await this.unitOfWork.PharmacyPurchaseDetails.DeleteAsync(purchaseDetail, transaction);
            if (!detailResponse)
            {
                transaction.Rollback();
                return new Tuple<int, PharmacyPurchaseBill>(-7, model);
            }
            transaction.Commit();
#pragma warning disable S2583 // Conditionally executed code should be reachable
            return new Tuple<int, PharmacyPurchaseBill>(detailResponse ? 1 : 0, model);
#pragma warning restore S2583 // Conditionally executed code should be reachable
        }

        /// <inheritdoc/>
        public async Task<int> AddPayType(PharmacySaleBillModel model)
        {
            var query = $@" update ""PharmacySaleHeader"" set ""PaidVia"" = '{model.PaidVia}' where ""PharmacySaleHeaderId"" = {model.PharmacySaleHeaderId}";

            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc/>
        public async Task<string> FindKitNameBySurgeryKitHeaderId(int surgeryKitHeaderId)
        {
            var query = $@"SELECT ""KitName"" FROM ""SurgeryKitHeader""
                                        Where ""SurgeryKitHeaderId"" ={surgeryKitHeaderId}";

            var kitName = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(query);
            return kitName;
        }

        public async Task<IEnumerable<PharmacyBillModel>> FetchAddedPurchaseBillAsync(int? pharmacyPurchaseHeaderId, string billNumber)
        {
            var where = " where 1=1 ";
            if (pharmacyPurchaseHeaderId != null)
            {
                where += $@" and PPH.""PharmacyPurchaseHeaderId"" = {pharmacyPurchaseHeaderId}";
            }

            if (!string.IsNullOrEmpty(billNumber))
            {
                where += $@" and PPH.""BillNumber"" = '{billNumber}'";
            }

            var query =
                $@"SELECT PPH.""PharmacyPurchaseHeaderId"", PP.""ProductName"",PP.""Barcode"",PP.""GenericName"",PPD.""PurchaseRate"",PPD.""Mrp"",PPD.""Quantity"", PPD.""Free"",PPD.""Total"", 
                                PPD.""DiscountPerItem"", PPD.""DiscountAmount"",PPH.""Discount"" as ""OverallDiscount"",PPD.""TaxPerItem"",PPD.""TaxAmount"",PPD.""NetAmount"",
                                PPH.""BillAmount"", PPH.""Taxes"", PPH.""Netamount"" as ""OverallAmount"",
								S.""Name"" as ""SupplierName"",A.""FullName"" as ""CreatedByName"", R.""RoleName"",
								PPH.""BillNumber"", PPH.""BillDate"", PPH.""BillType"",PPH.""SupplierId"",
								PS.""BatchNumber"" ,PS.""ExpiryDate"" 
	                                FROM ""PharmacyPurchaseHeader"" PPH 
	                                join ""PharmacyPurchaseDetail"" PPD on PPD.""PharmacyPurchaseHeaderId"" = PPH.""PharmacyPurchaseHeaderId""
	                                join ""PharmacyStock"" PS on PS.""PharmacyStockId"" = PPD.""PharmacyStockId"" 
	                                join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PPD.""PharmacyProductId""
									join ""Supplier"" S on S.""SupplierId"" = PPH.""SupplierId""
									join ""Account"" A on A.""AccountId"" = PPH.""CreatedBy""
									join ""Role"" R on R.""RoleId"" = A.""RoleId""
	                                {where} ";
            return await this.unitOfWork.Current.QueryAsync<PharmacyBillModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<RetailPharmacyModel>> FetchAllRetailStores(RetailPharmacyModel model)
        {

            var where = "where 1=1";
            var insideWhere = "where 1=1";

            if (model.RetailPharmacyId > 0)
            {
                where += $@" and T.""RetailPharmacyId"" = {model.RetailPharmacyId}";
            }
            if (model.UserBasedStore > 0)
            {
                where += $@" and  pd.""AllowedAccountId""= {model.UserBasedStore}";
            }

            if (model.Active != null)
            {
                if ((bool)model.Active)
                {
                    where += $@" and T.""Active"" is true";
                }
                else
                {
                    where += $@" and T.""Active"" is false";
                }
            }

            if (model.LocationId != null)
            {
                where += $@" and T.""LocationId"" = {model.LocationId}";
            }

            if (!string.IsNullOrEmpty(model.RetailPharmacyIds))
            {
                where += $@" and T.""RetailPharmacyId"" in ({model.RetailPharmacyIds}) and T.""LocationId"" is not null";
            }

            if (model.PharmacyWareHouseId != null)
            {
                insideWhere += $@" and PWH.""PharmacyWareHouseId"" = {model.PharmacyWareHouseId}";
            }

            var query = $@"with test as ( select 	string_agg(PWH.""WareHouseName"", ',') ""WareHouseNames"", PWH.""LocationId"",
                                            (Select ""Name"" from ""Location"" where ""LocationId"" = PWH.""LocationId"") as ""LocationName"",
	                                            string_agg(RLD.""PharmacyWareHouseId""::text, ',') ""PharmacyWareHouseIds"",
                                          rp.""RetailPharmacyId"",rp.""RetailName"" ,
                                         ma.""FullName"" as ""ModifiedByName"", ca.""FullName"" as ""CreatedByName"",
                                            rp.""CreatedDate"", rp.""ModifiedDate"",rp.""Active"",
			  				                string_agg(RLD.""RetailWareHouseLinkId""::text,',') as ""RetailWareHouseLinkIdIds""

                                 from ""RetailPharmacy"" rp 			
                                  join ""RetailWareHouseLink"" RLD on RLD.""RetailPharmacyId"" = rp.""RetailPharmacyId""
	                              join ""PharmacyWareHouse"" PWH on PWH.""PharmacyWareHouseId"" = RLD.""PharmacyWareHouseId""     
	                             left join ""Account"" ma on rp.""ModifiedBy"" = ma.""AccountId""
	                             left join ""Account"" ca on rp.""CreatedBy"" = ca.""AccountId""
                                    {insideWhere}
                                 group by rp.""RetailPharmacyId"",rp.""RetailName""  ,ma.""FullName"", ca.""FullName"",rp.""CreatedDate"",
	                             rp.""ModifiedDate"",rp.""Active"",PWH.""LocationId""
                            ) 
                    ,primaryData as (select ""RetailPharmacyId"",""AccountId"" as ""AllowedAccountId"" from ""PharmacyRetailUser"")

                            Select T.*,string_agg(pd.""AllowedAccountId""::text, ',') ""AllowedAccountId"", 
                                    string_agg(ac.""FullName"", ',') as ""UserNames"" 
                            from test T
                            left join primaryData pd ON pd.""RetailPharmacyId"" = T.""RetailPharmacyId"" 
                            left join ""Account"" ac on ac.""AccountId"" = pd.""AllowedAccountId""
                            {where}
                            group by T.""WareHouseNames"",T.""PharmacyWareHouseIds"",T.""RetailPharmacyId"",T.""RetailName"" ,
                               T.""ModifiedByName"", T.""CreatedByName"",
                               T.""CreatedDate"", T.""ModifiedDate"",T.""Active"", T.""RetailWareHouseLinkIdIds"", T.""LocationId"",
                               T.""LocationName""";
            return await this.unitOfWork.Current.QueryAsync<RetailPharmacyModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> DeleteRetailStoreAsync(int retailPharmacyId)
        {
            var query = $@" DELETE FROM ""RetailPharmacy"" WHERE ""RetailPharmacyId""= {retailPharmacyId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc/>
        public async Task<int> DiscountOnBill(DiscountBills model)
        {
            //Main Query
            var billNos = string.Empty;
            foreach (var bill in model.Bills.Where(bill => !string.IsNullOrEmpty(billNos)))
            {
                billNos = $@"'{bill}',";
            }

            billNos += $@"'abc'";

            var query = $@"Select * from ""PharmacySaleHeader"" where ""BillNumber"" in ({billNos})
                        order by 1 desc";

            var mainData = await this.unitOfWork.Current.QueryAsync<PharmacySaleHeader>(query);
            if (mainData == null)
            {
                return -1;
            }
            foreach (var header in mainData)
            {
                var mainHeaderData = await this.unitOfWork.PharmacySaleHeaders.FindAsync(h => h.PharmacySaleHeaderId == header.PharmacySaleHeaderId);
                if (mainHeaderData == null)
                {
                    return 0;
                }
                var getBillDetails = (await this.unitOfWork.PharmacySaleDetails.FindAllAsync(m => m.PharmacySaleHeaderId == mainHeaderData.PharmacySaleHeaderId)).ToList();
                if (getBillDetails.Count == 0)
                {
                    return 0;
                }

                foreach (var item in getBillDetails)
                {
                    var getTaxes = await this.unitOfWork.LookupValues.FindAsync(l => l.LookupValueId == item.TaxId);
                    var total = item.Total;
                    item.DiscountPerItem = model.Discount;
                    var discountPercentageAmount = (total * 60) / 100;
                    item.Discount = Math.Round(discountPercentageAmount, 2);
                    item.NetAmount = Math.Round((total - (double)item.Discount), 2);

                    // New Tax Calculation
                    var taxPercentage = 100 + int.Parse(getTaxes.Name);
                    var amountWithoutTax = Math.Round((item.NetAmount / taxPercentage) * 100, 2);
                    item.TaxAmount = Math.Round((item.NetAmount - amountWithoutTax), 2);
                    // End

                    var updateResponse = await this.unitOfWork.PharmacySaleDetails.UpdateAsync(item);
                    if (updateResponse < 0)
                    {
                        return 0;
                    }
                }

                var getBillDetailsAgain = (await this.unitOfWork.PharmacySaleDetails.FindAllAsync(m => m.PharmacySaleHeaderId == mainHeaderData.PharmacySaleHeaderId)).ToList();
                mainHeaderData.OverallTaxes = 0;
                foreach (var item in getBillDetailsAgain)
                {

                    mainHeaderData.OverallTaxes += item.TaxAmount;
                }

                var mainTotal = mainHeaderData.Total;
                var discountRs = (mainTotal * model.Discount) / 100;
                mainHeaderData.OverallDiscount = Math.Round(discountRs, 2);
                mainHeaderData.OverallNetAmount = Math.Round((mainTotal - (double)mainHeaderData.OverallDiscount), 2);
                var mainUpdate = await this.unitOfWork.PharmacySaleHeaders.UpdateAsync(mainHeaderData);
                if (mainUpdate < 0)
                {
                    return 0;
                }
            }

            return 1;
        }

        /// <inheritdoc/>
        public async Task<int> RevokeDiscountedBill(DiscountBills model)
        {
            //Main Query
            var billNos = string.Empty;
            foreach (var bill in model.Bills.Where(bill => !string.IsNullOrEmpty(billNos)))
            {
                billNos = $@"'{bill}',";
            }

            billNos += $@"'abc'";

            var query = $@"Select * from ""PharmacySaleHeader"" where ""BillNumber"" in ({billNos})
                        order by 1 desc";

            var mainData = await this.unitOfWork.Current.QueryAsync<PharmacySaleHeader>(query);

            if (mainData == null)
            {
                return -1;
            }

            foreach (var header in mainData)
            {
                var getDetails = (await this.unitOfWork.PharmacySaleDetails.FindAllAsync(d => d.PharmacySaleHeaderId == header.PharmacySaleHeaderId)).ToList();
                if (getDetails.Count == 0)
                {
                    return -1;
                }

                foreach (var detail in getDetails)
                {
                    detail.Discount = 0;
                    detail.DiscountPerItem = 0;
                    detail.NetAmount = detail.Total;

                    var detailResponse = await this.unitOfWork.PharmacySaleDetails.UpdateAsync(detail);
                    if (detailResponse <= 0)
                    {
                        return -1;
                    }
                }

                header.OverallDiscount = 0;
                header.OverallNetAmount = header.Total;

                var headerResponse = await this.unitOfWork.PharmacySaleHeaders.UpdateAsync(header);
                if (headerResponse <= 0)
                {
                    return -1;
                }
            }
            return 1;
        }

        /// <inheritdoc/>
        public async Task<Tuple<int, string>> AddNewSalesBillAsync(NewSalesBill model, int locationId)
        {
            using var transaction = this.unitOfWork.BeginTransaction();
            dynamic paymentType;
            if (model.TypeOfPayment == "PartialPayment" || (model.TypeOfPayment == "MultiPaymodes" && model.TotalAmount < model.OverallNetAmount))
            {
                paymentType = 'P';
            }
            else
            {
                paymentType = 'F';
            }
            var saleHeader = new PharmacySaleHeader
            {
                BillNumber = await this.GetBillNumber(),
                AdmissionId = null,
                BillType = string.IsNullOrEmpty(model.BillType) ? "U" : model.BillType,
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                Mobile = model.Mobile,
                OverallDiscount = model.OverallDiscount,
                OverallNetAmount = model.OverallNetAmount,
                OverallTaxes = model.OverallTax,
                PatientId = model.PatientId,
                PatientName = model.PatientName,
                ProviderName = model.ProviderName,
                SaleDate = model.SaleDate.Add(DateTime.UtcNow.AddMinutes(330).TimeOfDay),
                Total = model.OverallTotal,
                PaidVia = model.PaidVia,
                ProviderId = model.ProviderId,
                LocationId = locationId,
                PayTypeId = model.PayTypeId,
                PaymentNumber = model.PaymentNumber,
                SpecializationId = model.SpecializationId,
                PaymentStatus = model.PaymentStatus,
                IsSalucroBill = model.IsSalucroBill,
                PaymentType = paymentType,
                ReasonForDiscount = model.ReasonForDiscount
            };

            saleHeader.PharmacySaleHeaderId =
                await this.unitOfWork.PharmacySaleHeaders.InsertAsync(saleHeader, transaction);
            if (saleHeader.PharmacySaleHeaderId == 0)
            {
                transaction.Rollback();
                return new Tuple<int, string>(-1, null);
            }

            var saleDetails = model.Products.Select((m, i) => new PharmacySaleDetail
            {
                PharmacySaleHeaderId = saleHeader.PharmacySaleHeaderId,
                SerialNum = i + 1,
                Total = (double)m.Total,
                TaxAmount = (double)m.TaxAmount,
                Discount = m.Discount,
                NetAmount = (double)m.NetAmount,
                DiscountPerItem = m.DiscountPerItem,
                PharmacyProductId = m.PharmacyProductId,
                PharmacyRetailStockId = m.PharmacyRetailStockId,
                Quantity = m.Quantity,
                TaxId = m.TaxId
            });

            var saleDetailResponse = await this.unitOfWork.PharmacySaleDetails.BulkInsertAsync(saleDetails, transaction);
            if (saleDetailResponse == 0)
            {
                transaction.Rollback();
                return new Tuple<int, string>(-2, null);
            }

            foreach (var detail in model.Products)
            {
                var rawStock = await this.unitOfWork.PharmacyRetailStocks.FindAsync(
                               m => m.PharmacyRetailStockId == detail.PharmacyRetailStockId);
                rawStock.QuantityOut += detail.Quantity;
                rawStock.ModifiedBy = model.CreatedBy;
                rawStock.ModifiedDate = DateTime.UtcNow.AddMinutes(330);
                var response = await this.unitOfWork.PharmacyRetailStocks.UpdateAsync(rawStock, transaction);
                if (response <= 0)
                {
                    transaction.Rollback();
                    return new Tuple<int, string>(-3, null);
                }
            }

            if (saleHeader.PharmacySaleHeaderId > 0)
            {

                if (model.PaymentInitiationLogId != null && model.PaymentInitiationLogId != 0)
                {
                    PaymentMapHelperModel paymentHelper = new PaymentMapHelperModel { PaymentInitiationLogId = ((int)model.PaymentInitiationLogId), BillId = saleHeader.PharmacySaleHeaderId };

                    paymentHelper.PaymentMapHelperId = await this.paymentMapHelperService.AddAsync(paymentHelper);
                    if (paymentHelper.PaymentMapHelperId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, string>(-6, null);
                    }
                }

                //begin-MasterBill
                var getbillrecord = await this.unitOfWork.MasterBill.FindAsync(x => x.PatientId == model.PatientId && x.BillStatusTypeId == 2 && x.ReceiptAreaTypeId == (int)ReceiptAreaType.Pharmacy && x.ModuleId == saleHeader.PharmacySaleHeaderId); //need to check more
                var billId = 0;
                if (getbillrecord == null)
                {
                    var onebill = new MasterBill
                    {
                        ReceiptAreaTypeId = (int)ReceiptAreaType.Pharmacy,
                        ModuleId = saleHeader.PharmacySaleHeaderId,
                        BillDate = DateTime.Now,
                        BillNumber = string.Format("{0:000000}", new Random().Next(0, 999999).ToString()),
                        BillStatusTypeId = (int)BillStatusType.Not_Generated,
                        CreatedBy = (int)model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        Active = true,
                        PatientId = model.PatientId,
                        Total = Math.Round(model.OverallTotal),
                        NetTotal = (double)model.OverallNetAmount,
                        Tax = (double)model.OverallTax,
                        Discount = (double)model.OverallDiscount,
                        Rounding = (int)model.OverallNetAmount - (double)model.OverallNetAmount,
                        LocationId = locationId
                    };
                    onebill.MasterBillId = await this.unitOfWork.MasterBill.InsertAsync(onebill, transaction);
                    billId = onebill.MasterBillId;
                    if (onebill.MasterBillId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, string>(-6, null);
                    }
                }
                //end-MasterBill

                //transaction for the sale bill
                var commonTransaction = new AppointmentTransaction
                {
                    AppointmentId = saleHeader.PharmacySaleHeaderId,
                    Transaction = model.Transaction ?? "",
                    TransactionDate = DateTime.Now,
                    TransactionId = model.TransactionId ?? await this.appointmentTransactionsServices.GetATransactionId(),
                    VoucherNumber = model.SalucroStatusCode == 1201 ? null : await this.appointmentTransactionsServices.GetVoucherNumber(),
                    BankReference = "",
                    BankCode = "",
                    Active = true,
                    PaymentId = 0,
                    PaymentModeId = 1,
                    SettledAmount = (decimal)model.TotalAmount,
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.Now,
                    LocationId = locationId,
                    ReceiptTypeId = (int)ReceiptType.Cash,
                    ReceiptAreaTypeId = (int)ReceiptAreaType.Pharmacy,
                    SalucroStatusCode = model.SalucroStatusCode,
                    SalucroTransactionId = model.SalucroTransactionId,
                    PatientId = model.PatientId,
                    PayStatus = saleHeader.PaymentType
                };
                commonTransaction.AppointmentTransactionId = await this.unitOfWork.AppointmentTransactions.InsertAsync(commonTransaction, transaction);
                if (commonTransaction.AppointmentTransactionId == 0)
                {
                    transaction.Rollback();
                    return new Tuple<int, string>(-4, null);
                }
                if (model.SalucroStatusCode != 1201)
                {
                    var receipt = new Receipt
                    {
                        Active = true,
                        Cost = (double)model.TotalAmount,
                        CreatedBy = model.CreatedBy,
                        CreatedDate = DateTime.Now,
                        IsAdvance = false,
                        IsRefunded = false,
                        PayTypeId = model.PayTypeId,
                        PaymentDetails = model.PaymentNumber,
                        ReceiptTypeId = ReceiptType.Cash,
                        ReceiptAreaTypeId = ReceiptAreaType.Pharmacy,
                        RespectiveId = saleHeader.PharmacySaleHeaderId,
                        TransactionId = commonTransaction.AppointmentTransactionId,
                        MasterBillId = getbillrecord != null && getbillrecord.MasterBillId > 0 ? getbillrecord.MasterBillId : billId > 0 ? billId : (int?)null
                    };

                    receipt.ReceiptId = await this.unitOfWork.Receipt.InsertAsync(receipt, transaction);
                    if (receipt.ReceiptId == 0)
                    {
                        transaction.Rollback();
                        return new Tuple<int, string>(-5, null);
                    }
                    //begin-to update bill status as genereated.
                    var allreceiptforbill = await this.unitOfWork.Receipt.FindAllAsync(x => x.MasterBillId == receipt.MasterBillId);
                    allreceiptforbill.ToList();
                    var receiptcostsum = 0.0;
                    foreach (var item in allreceiptforbill.ToList())
                    {
                        receiptcostsum += item.Cost;
                    }
                    var getbill = await this.unitOfWork.MasterBill.FindAsync(x => x.MasterBillId == receipt.MasterBillId);
                    if (getbill != null)
                    {
                        getbill.Deposit = receiptcostsum;
                        await this.unitOfWork.MasterBill.UpdateAsync(getbill);
                    }
                    if (getbill != null && receiptcostsum == getbill.NetTotal)
                    {
                        getbill.BillStatusTypeId = (int)BillStatusType.Generated;
                        getbill.ModifiedBy = (int)model.CreatedBy;
                        getbill.ModifiedDate = DateTime.Now;

                        await this.unitOfWork.MasterBill.UpdateAsync(getbill);
                    }

                    //end-to update bill status as genereated.
                }
            }

            transaction.Commit();

            return new Tuple<int, string>(saleHeader.PharmacySaleHeaderId, saleHeader.BillNumber);
        }

        /// <inheritdoc/>
        //public async Task<int> UpdatePharmacyPurchaseBillAsync(PharmacyPurchaseBill model)
        //{
        //    var transaction = this.unitOfWork.BeginTransaction();
        //    var headerRecord =
        //         await this.unitOfWork.PharmacyPurchaseHeaders.FindAsync(
        //             m => m.PharmacyPurchaseHeaderId == model.PharmacyPurchaseHeaderId);

        //    headerRecord.BillAmount = Math.Round(model.Bills.Sum(x => x.Total), 2);
        //    headerRecord.Discount = Math.Round(model.Discount ?? 0, 2);
        //    headerRecord.Netamount = Math.Round(model.Bills.Sum(x => x.NetAmount), 2);
        //    headerRecord.Taxes = Math.Round(model.TaxAmount, 2);
        //    headerRecord.ModifiedBy = model.ModifiedBy;
        //    headerRecord.ModifiedDate = DateTime.Now;

        //    foreach (var bill in model.Bills)
        //    {
        //        var exists = await this.unitOfWork.PharmacyPurchaseDetails.FindAsync(
        //                        m => m.PharmacyPurchaseDetailId == bill.PharmacyPurchaseDetailId, transaction);

        //        exists.Quantity = bill.Quantity;
        //        exists.Free = (int)bill.Free;
        //        exists.PurchaseRate = bill.PurchaseRate;
        //        exists.DiscountPerItem = bill.DiscountPerItem;
        //        exists.TaxAmount = bill.TaxAmount;
        //        exists.NetAmount = bill.NetAmount;
        //        exists.Total = bill.Total;

        //        var detailResponse = await this.unitOfWork.PharmacyPurchaseDetails.UpdateAsync(exists);

        //        if (detailResponse <= 0)
        //        {
        //            transaction.Rollback();
        //            return -2;
        //        }
        //    }

        //    transaction.Commit();
        //    return 1;
        //}

        /// <inheritdoc/>
        public async Task<string> FetchBillNumber()
        {
            var lastBillNumberQuery = $@"SELECT ""BillNumber"" FROM ""PharmacyPurchaseHeader""
                                                ORDER BY ""PharmacyPurchaseHeaderId"" DESC LIMIT 1";
            var oldBillNumber = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(lastBillNumberQuery);
            if (!string.IsNullOrEmpty(oldBillNumber))
            {
                // GRN2021040101
                return "GRN" + DateTime.Now.ToString("yyyyMMdd") + "1";
            }
            else
            {
                var stringLiterals = oldBillNumber?.Substring(0, 4);
                var previousBillDateWithCount = oldBillNumber?.Substring(4);
                var counter = previousBillDateWithCount?.Substring(8);
                var date = previousBillDateWithCount?.Substring(0, 8);
                if (date != DateTime.Now.ToString("yyyyMMdd"))
                {
                    return "GRN" + DateTime.Now.ToString("yyyyMMdd") + "1";
                }

                counter = (int.Parse(counter) + 1).ToString();
                return stringLiterals + date + counter;
            }
        }

        /// <inheritdoc/>
        public async Task<string> FindPharmacyRetailName(int pharmacyRetailStockId)
        {
            var query =
              $@"SELECT   RP.""RetailName""
                        from ""RetailPharmacy"" RP
						join ""RetailWareHouseLink"" RWL on RWL.""RetailPharmacyId"" = RP.""RetailPharmacyId""
                        join ""PharmacyRetailStock"" PRS on PRS.""RetailWareHouseLinkId"" = RWL.""RetailWareHouseLinkId""
                        where ""PharmacyRetailStockId"" =  {pharmacyRetailStockId} ";
            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<string>(query);

        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyStockModel>> FetchMainStockForProductsInBulk(string productIds, int? wareHouseId)
        {
            var where = $@"where 1=1 and (PS.""QuantityIn"" - PS.""QuantityOut"") > 0 ";

            if (wareHouseId != null)
            {
                where += $@" and PS.""PharmacyWareHouseId"" = {wareHouseId}";
            }

            if (!string.IsNullOrEmpty(productIds))
            {
                where += $@" and PS.""PharmacyProductId"" in ({productIds})";
            }

            var query =
               $@"SELECT count(PS.*) over() as ""TotalItems"", PS.""PharmacyStockId"", PS.""PharmacyProductId"", PS.""TaxId"", PS.""QuantityIn"", PS.""QuantityOut"", PS.""BatchNumber"", PS.""ExpiryDate"",
                                    PS.""PurchaseRate"", PS.""Mrp"", PS.""Barcode"", PS.""MrpChangeReason"", PP.""ProductName"",PP.""GenericName"",PS.""CreatedDate"",
                                    (PS.""QuantityIn"" - PS.""QuantityOut"") as ""AvailableQuantity"",Cat.""Name"" as ""CategoryName"",Tax.""Name""::int as ""TaxPercentage""
	                                    FROM ""PharmacyStock"" PS  
	                                    join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PS.""PharmacyProductId""
	                                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
	                                    join ""LookupValue"" Tax on Tax.""LookupValueId"" = PS.""TaxId"" {where} order by PP.""ProductName""";

            return await this.unitOfWork.Current.QueryAsync<PharmacyStockModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<string>> FetchExistingBatchNumbers(int pharmacyProductId, int? locationId)
        {
            var where = $@" where PS.""PharmacyProductId"" = {pharmacyProductId}";
            if (locationId != null)
            {
                where += $@" and PWH.""LocationId"" = {locationId}";
            }

            var query = $@"Select distinct PS.""BatchNumber"" from ""PharmacyStock"" PS
                                join ""PharmacyWareHouse"" PWH on PWH.""PharmacyWareHouseId"" = PS.""PharmacyWareHouseId""
                                 {where}
                                group by ""BatchNumber""";
            return await this.unitOfWork.Current.QueryAsync<string>(query);
        }

        /// <inheritdoc/>
        public async Task<int> AddNewPurchaseBill(PurchaseBillHeaderModel model)
        {
            var transaction = this.unitOfWork.BeginTransaction();

            var indianDate = DateTime.UtcNow.AddMinutes(330);

            var purchaseHeader = new PharmacyPurchaseHeader
            {
                CreatedDate = indianDate,
                CreatedBy = model.CreatedBy,
                BillAmount = model.BillAmount,
                BillDate = model.BillDate.Add(DateTime.Now.TimeOfDay),
                BillNumber = model.BillNumber,
                BillType = model.BillType,
                Discount = model.Discount,
                DueDate = model.DueDate,
                Netamount = model.NetAmount,
                Taxes = model.Taxes,
                SupplierId = model.SupplierId,
                PharmacyWareHouseId = model.PharmacyWareHouseId,
                PurchaseOrderHeaderId = model.PurchaseOrderHeaderId
            };

            var previousHeader = await this.unitOfWork.PharmacyPurchaseHeaders.FindAsync(h => h.PharmacyPurchaseHeaderId == model.PharmacyPurchaseHeaderId);

            if (previousHeader != null)
            {
                previousHeader.ModifiedBy = model.CreatedBy;
                previousHeader.ModifiedDate = indianDate;
                previousHeader.Netamount = purchaseHeader.Netamount;
                previousHeader.Discount = purchaseHeader.Discount;
                previousHeader.Taxes = purchaseHeader.Taxes;
                previousHeader.BillAmount = purchaseHeader.BillAmount;
                purchaseHeader.PharmacyPurchaseHeaderId = previousHeader.PharmacyPurchaseHeaderId;
                previousHeader.DueDate = purchaseHeader.DueDate;
                previousHeader.BillType = purchaseHeader.BillType;

                var updateHeader = await this.unitOfWork.PharmacyPurchaseHeaders.UpdateAsync(previousHeader, transaction);
                if (updateHeader == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }
            else
            {
                purchaseHeader.PharmacyPurchaseHeaderId = await this.unitOfWork.PharmacyPurchaseHeaders.InsertAsync(purchaseHeader, transaction);
                if (purchaseHeader.PharmacyPurchaseHeaderId == 0)
                {
                    transaction.Rollback();
                    return -1;
                }
            }


            int index = 0;
            foreach (var product in model.Products)
            {
                ++index;
                var pharmacyProduct = await this.unitOfWork.PharmacyProducts.FindAsync(p => p.PharmacyProductId == product.PharmacyProductId);

                #region stockCalculation
                var purchaseBasedOnUnit = product.PurchaseRate / (pharmacyProduct.PurchaseUnitQty * pharmacyProduct.SaleUnitQty);
                var mrp = product.Mrp / (pharmacyProduct.PurchaseUnitQty * pharmacyProduct.SaleUnitQty);
                purchaseBasedOnUnit = Math.Round(purchaseBasedOnUnit, 2);
                mrp = Math.Round(mrp, 2);
                var quantityForStock = product.Quantity * (pharmacyProduct.PurchaseUnitQty * pharmacyProduct.SaleUnitQty);
                int freeForStock;
                if (product.Free != null)
                {
                    freeForStock = ((int)product.Free * pharmacyProduct.PurchaseUnitQty) * pharmacyProduct.SaleUnitQty;
                }
                else
                {
                    freeForStock = 0;
                }

                #endregion

                var purchaseDetail = new PharmacyPurchaseDetail
                {
                    Barcode = product.Barcode, //string.Empty,
                    DiscountAmount = product.DiscountAmount,
                    DiscountPerItem = product.DiscountPerItem,
                    Free = product.Free ?? 0,
                    Mrp = product.Mrp,
                    NetAmount = product.NetAmount,
                    PharmacyProductId = product.PharmacyProductId,
                    PharmacyPurchaseHeaderId = purchaseHeader.PharmacyPurchaseHeaderId,
                    PurchaseRate = product.PurchaseRate,
                    Quantity = product.Quantity,
                    SerialNum = index,
                    TaxAmount = product.TaxAmount,
                    TaxPerItem = product.TaxPerItem,
                    Total = product.Total,
                    PharmacyPurchaseDetailId = product.PharmacyPurchaseDetailId,
                    PurchaseOrderDetailId = product.PurchaseOrderDetailId
                };

                if (product.PharmacyPurchaseDetailId == 0)
                {
                    var newStock = new PharmacyStock
                    {
                        Barcode = product.Barcode, //string.Empty,
                        BatchNumber = product.BatchNumber,
                        CreatedBy = model.CreatedBy,
                        CreatedDate = indianDate,
                        ExpiryDate = product.ExpiryDate,
                        ManuallyUpdated = 0,
                        Mrp = mrp,
                        PharmacyProductId = product.PharmacyProductId,
                        PurchaseRate = purchaseBasedOnUnit,
                        QuantityIn = (quantityForStock + freeForStock),
                        QuantityOut = 0,
                        TaxId = product.TaxId,
                        MrpChangeReason = string.Empty,
                        PharmacyWareHouseId = model.PharmacyWareHouseId,
                        IsIGST = product.TaxPerItem > 0 && !string.IsNullOrEmpty(product.GSTType) && product.GSTType == "igst",
                        IsSGST = product.TaxPerItem > 0 && !string.IsNullOrEmpty(product.GSTType) && product.GSTType == "sgst"
                    };

                    var stockWhereCondition = " and 1=1";
                    if (!string.IsNullOrEmpty(product.Barcode))
                    {
                        stockWhereCondition += $@" and PS.""Barcode""='{product.Barcode}'";
                    }

                    var getPreviousStockQuery = $@"Select PS.* from ""PharmacyStock"" PS
                                join ""PharmacyPurchaseDetail"" ppd on ppd.""PharmacyStockId"" = PS.""PharmacyStockId"" 
                                join ""PharmacyPurchaseHeader"" pph on pph.""PharmacyPurchaseHeaderId"" = ppd.""PharmacyPurchaseHeaderId"" 
                                where PS.""PharmacyProductId"" = {product.PharmacyProductId} and pph.""BillNumber"" = '{purchaseHeader.BillNumber}'
                                and lower(PS.""BatchNumber"") = lower('{product.BatchNumber}') and PS.""PharmacyWareHouseId"" = {model.PharmacyWareHouseId} {stockWhereCondition} order by ""CreatedDate"" desc limit 1";

                    var getPreviousStock = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PharmacyStock>(getPreviousStockQuery);

                    if (getPreviousStock != null && (getPreviousStock.QuantityIn - getPreviousStock.QuantityOut) > 0)
                    {
                        if (getPreviousStock.ExpiryDate == product.ExpiryDate && getPreviousStock.Mrp == mrp && getPreviousStock.PurchaseRate == purchaseBasedOnUnit)
                        {
                            getPreviousStock.QuantityIn += (quantityForStock + freeForStock);
                            getPreviousStock.ModifiedBy = model.CreatedBy;
                            getPreviousStock.ModifiedDate = indianDate;
                            newStock.PharmacyStockId = getPreviousStock.PharmacyStockId;
                            var stockUpdateResponse = await this.unitOfWork.PharmacyStocks.UpdateAsync(getPreviousStock, transaction);
                            if (stockUpdateResponse == 0)
                            {
                                transaction.Rollback();
                                return -1;
                            }
                            purchaseDetail.PharmacyStockId = getPreviousStock.PharmacyStockId;
                        }
                        else
                        {
                            newStock.PharmacyStockId = await this.unitOfWork.PharmacyStocks.InsertAsync(newStock, transaction);
                            if (newStock.PharmacyStockId == 0)
                            {
                                transaction.Rollback();
                                return -1;
                            }

                            purchaseDetail.PharmacyStockId = newStock.PharmacyStockId;
                        }
                    }
                    else
                    {
                        newStock.PharmacyStockId = await this.unitOfWork.PharmacyStocks.InsertAsync(newStock, transaction);
                        if (newStock.PharmacyStockId == 0)
                        {
                            transaction.Rollback();
                            return -1;
                        }
                        purchaseDetail.PharmacyStockId = newStock.PharmacyStockId;
                    }

                    purchaseDetail.PharmacyPurchaseDetailId = await this.unitOfWork.PharmacyPurchaseDetails.InsertAsync(purchaseDetail, transaction);
                    if (purchaseDetail.PharmacyPurchaseDetailId == 0)
                    {
                        transaction.Rollback();
                        return -1;
                    }
                }
            }

            transaction.Commit();
            return purchaseHeader.PharmacyPurchaseHeaderId;
        }

        /// <inheritdoc/>
        public async Task<PurchaseBillHeaderModel> FetchPurchaseBill(int supplierId, string billNumber, int? locationId)
        {
            var where = $@" where 1=1 and PPH.""SupplierId"" ={supplierId}  and PPH.""BillNumber"" = '{billNumber}'";
            if (locationId != null)
            {
                where += $@" and PWH.""LocationId"" = {locationId}";
            }
            var query = $@"SELECT PPH.""PharmacyPurchaseHeaderId"", PPH.""BillNumber"", PPH.""BillDate"", PPH.""BillType"", PPH.""SupplierId"", PPH.""BillAmount"", 
		                    PPH.""Discount"", PPH.""Taxes"", PPH.""Netamount"", PPH.""CreatedBy"", PPH.""CreatedDate"", PPH.""ModifiedBy"", PPH.""ModifiedDate"", PPH.""DueDate"", 
		                    PPH.""AutoGenerateBillNumber"", PPH.""IsCreditClear"", PPH.""PaidOnDate"",PPH.""PharmacyWareHouseId"",PWH.""WareHouseName""
	                    FROM ""PharmacyPurchaseHeader"" PPH
                        join ""PharmacyWareHouse"" PWH on PWH.""PharmacyWareHouseId"" = PPH.""PharmacyWareHouseId""
	                    {where}  order by PPH.""CreatedDate"" desc limit 1";

            var header = await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PurchaseBillHeaderModel>(query);
            if (header == null)
            {
                return header;
            }

            header.Products = new List<PurchaseBillDetailModel>();

            var detailQuery = $@"SELECT PPD.""PharmacyPurchaseDetailId"", PPD.""PharmacyPurchaseHeaderId"", PPD.""SerialNum"", PPD.""PharmacyProductId"", 
		                        PPD.""Quantity"", PPD.""Free"", PPD.""PurchaseRate"", PPD.""Mrp"", PPD.""Total"", PPD.""TaxPerItem"", PPD.""TaxAmount"", 
		                        PPD.""DiscountPerItem"", PPD.""DiscountAmount"", PPD.""NetAmount"", PPD.""Barcode"", PPD.""PharmacyStockId"", 
		                        PPD.""PharmacyRetailStockId"", PP.""ProductName"",PP.""GenericName"",Com.""Name"" as ""CompanyName"",PS.""BatchNumber"",
		                        Cat.""Name"" as ""CategoryName"",PP.""TaxId"",PPD.""TaxPerItem""::text as ""TaxPercentage"",PP.""IsProductExpire"" as ""IsExpiry"",
                                PS.""ExpiryDate"",
                                case when PS.""IsIGST"" then 'igst' when PS.""IsSGST"" then 'sgst' else '' end as ""GSTType""
	                        FROM ""PharmacyPurchaseDetail"" PPD
	                        join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = PPD.""PharmacyProductId""
	                        join ""Company"" Com on Com.""CompanyId"" = PP.""CompanyId""
	                        join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
                            join ""PharmacyStock"" PS on PS.""PharmacyStockId"" = PPD.""PharmacyStockId""
	                        where PPD.""PharmacyPurchaseHeaderId"" = {header.PharmacyPurchaseHeaderId}";

            header.Products = (await this.unitOfWork.Current.QueryAsync<PurchaseBillDetailModel>(detailQuery)).ToList();

            return header;
        }

        /// <inheritdoc/>
        public async Task<int> AddRetailStoreIndentAsync(OTRaiseIndentModel model)
        {
            var departmentId = 0;

            var dep = await this.unitOfWork.Departments.FindAsync(m => m.DepartmentName == $@"{(model.IndentTo == "P" ? "Pharmacy" : "PharmacyDepartment")}");

            if (dep == null)
            {
                var department = new Department
                {
                    CreatedBy = model.CreatedBy,
                    DepartmentName = model.IndentTo == "P" ? "Pharmacy" : "PharmacyDepartment",
                    CreatedDate = DateTime.Now,
                    Active = true
                };
                departmentId = await this.unitOfWork.Departments.InsertAsync(department);
            }
            else
            {
                departmentId = dep.DepartmentId;
            }

            if (departmentId == 0)
            {
                return -1;
            }

            var transaction = this.unitOfWork.BeginTransaction();

            var indentHeader = new IndentHeader
            {
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                IndentTo = model.IndentTo,
                ReasonForRequirement = model.Reason,
                RetailPharmacyId = model.RetailPharmacyId,
                ApprovedBy = null,
                DepartmentId = departmentId,
                RequiredDate = model.RequiredDate,
                LocationId = (int)model.LocationId,
                PharmacyDepartmentId = model.PharmacyDepartmentId
            };

            indentHeader.IndentHeaderId = await this.unitOfWork.IndentHeaders.InsertAsync(indentHeader, transaction);

            if (indentHeader.IndentHeaderId == 0)
            {
                transaction.Rollback();
                return -1;
            }

            var details = model.Products.Select(p => new IndentDetail
            {
                IndentHeaderId = indentHeader.IndentHeaderId,
                ProductId = p.PharmacyProductId,
                Quantity = p.Quantity
            });

            var detailResponse = await this.unitOfWork.IndentDetails.BulkInsertAsync(details, transaction);
            if (detailResponse == 0)
            {
                transaction.Rollback();
                return -1;
            }

            transaction.Commit();

            return indentHeader.IndentHeaderId;
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<OTIndentModel>> FetchRetailIndentAsync(OTIndentModel model)
        {
            var where = $@"where 1=1 and IH.""IndentTo"" <> 'I'";

            if (!string.IsNullOrEmpty(model.From) && model.From == "issue")
            {
                where = $@"where 1=1 and IH.""IndentTo"" = 'D'";
            }

            if (!string.IsNullOrEmpty(model.Type))
            {
                switch (model.Type)
                {
                    case "Pending":
                        where += $@" and IH.""ApprovedBy"" is null";
                        break;
                    case "Approved":
                        where += $@" and IH.""ApprovedBy"" is not null";
                        break;
                }
            }
            if (model.CreatedBy > 0)
            {
                where += $@" and IH.""CreatedBy"" = {model.CreatedBy}";
            }

            if (model.FromDate != null)
            {
                where += $@" AND IH.""CreatedDate""::DATE >= '{model.FromDate}'::timestamp without time zone ";
            }
            if (model.ToDate != null)
            {
                where += $@" AND IH.""CreatedDate""::DATE <= '{model.ToDate}'::timestamp without time zone ";
            }
            if (model.RetailPharmacyId != null)
            {
                where += $@" AND RP.""RetailPharmacyId"" = {model.RetailPharmacyId}";
            }

            if (model.ProductId != null)
            {
                if (model.Type == "Approved")
                {
                    var qry2 = $@"select ""IssueHeaderId"" from ""IssueDetail"" where ""ProductId"" = {model.ProductId}";
                    var issues = await this.unitOfWork.Current.QueryAsync<OTIndentModel>(qry2);
                    var rec = issues.ToList();
                    if (rec.Count > 0)
                    {
                        var id = string.Join(",", rec.Select(x => x.IssueHeaderId));
                        where += $@" AND ISH.""IssueHeaderId"" in ({id})";
                    }
                }
                else
                {
                    var qry1 = $@"select ""IndentHeaderId"" from ""IndentDetail"" where ""ProductId"" = {model.ProductId}";
                    var indents = await this.unitOfWork.Current.QueryAsync<OTIndentModel>(qry1);
                    var records = indents.ToList();
                    if (records.Count > 0)
                    {
                        var ids = string.Join(",", records.Select(x => x.IndentHeaderId));
                        where += $@" AND IH.""IndentHeaderId"" in ({ids})";

                    }
                }
            }

            if (model.IssuingWareHouseId != null)
            {
                where += $@" and RWL.""PharmacyWareHouseId"" = {model.IssuingWareHouseId}";
            }

            if (model.LocationId != null)
            {
                where += $@" and IH.""LocationId"" = {model.LocationId} ";
            }

            if (model.PharmacyDepartmentId != null)
            {
                where += $@" and IH.""PharmacyDepartmentId"" = {model.PharmacyDepartmentId}";
            }

            var query = $@"SELECT count(IH.""IndentHeaderId"") over() as ""TotalItems"", IH.""IndentHeaderId"", IH.""DepartmentId"",
                            IH.""RequiredDate"", IH.""ReasonForRequirement"" as ""Reason"", IH.""IndentTo"", IH.""ApprovedBy"", 
		                    IH.""CreatedBy"", IH.""CreatedDate"", IH.""ModifiedBy"", IH.""ModifiedDate"", IH.""ApprovedDate"", IH.""RetailPharmacyId"",
		                    RP.""RetailName"", CA.""FullName"" as ""CreatedByName"",CR.""RoleName"" as ""CreatedByRole"",
		                    APP.""FullName"" as ""ApprovedByName"",APPR.""RoleName"" as ""ApprovedByRole"",
		                    MA.""FullName"" as ""ModifiedByName"",MR.""RoleName"" as ""ModifiedByRole"",
							string_agg(PWH.""WareHouseName"",',' ) as ""WareHouseNames"",
							STRING_AGG(RWL.""PharmacyWareHouseId""::text,',') as ""WareHouoseIds"",
							PWHI.""WareHouseName"" as ""ApprovedWareHouse"",
							PD.""Name"" as ""PharmacyDepartmentName"",IH.""PharmacyDepartmentId"",ISH.""IssueHeaderId""
							FROM ""IndentHeader"" IH	                   
	                    join ""Account"" CA on CA.""AccountId"" = IH.""CreatedBy""
	                    join ""Role"" CR on CR.""RoleId"" = CA.""RoleId""
						left join ""RetailPharmacy"" RP on RP.""RetailPharmacyId"" = IH.""RetailPharmacyId""
						left join ""RetailWareHouseLink"" RWL on RWL.""RetailPharmacyId"" = IH.""RetailPharmacyId""
						left join ""PharmacyWareHouse"" PWH on PWH.""PharmacyWareHouseId"" = RWL.""PharmacyWareHouseId""
	                    left join ""Account"" APP on APP.""AccountId"" = IH.""ApprovedBy""
	                    left join ""Role"" APPR on APPR.""RoleId"" = APP.""RoleId""
	                    left join ""Account"" MA on MA.""AccountId"" = IH.""ModifiedBy""
	                    left join ""Role"" MR on MR.""RoleId"" = MA.""RoleId""
	                    left join ""IssueHeader"" ISH on ISH.""IndentHeaderId"" = IH.""IndentHeaderId"" 
	                    left join ""PharmacyWareHouse"" PWHI on PWHI.""PharmacyWareHouseId"" = ISH.""PharmacyWareHouseId""
						left join ""PharmacyDepartment"" PD on PD.""PharmacyDepartmentId"" = IH.""PharmacyDepartmentId""
                        {where}
						group by IH.""IndentHeaderId"", IH.""DepartmentId"",
                            IH.""RequiredDate"", IH.""ReasonForRequirement"", IH.""IndentTo"", IH.""ApprovedBy"", 
		                    IH.""CreatedBy"", IH.""CreatedDate"", IH.""ModifiedBy"", IH.""ModifiedDate"", IH.""ApprovedDate"", IH.""RetailPharmacyId"",
		                    RP.""RetailName"", CA.""FullName"",CR.""RoleName"" ,
		                    APP.""FullName"" ,APPR.""RoleName"" ,
		                    MA.""FullName"" ,MR.""RoleName"" ,PWHI.""WareHouseName"",PD.""Name"",IH.""PharmacyDepartmentId"",ISH.""IssueHeaderId""
	                    order by IH.""CreatedDate"" desc";

            if (model.PageIndex != null && model.PageSize != null)
            {
                model.PageIndex = model.PageIndex > 0 ? model.PageIndex - 1 : model.PageSize;
                query += $@" limit {model.PageSize} offset {model.PageIndex * model.PageSize}";
            }

            return await this.unitOfWork.Current.QueryAsync<OTIndentModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<ProductModel>> FetchRetailIndentDetailAsync(OTIndentModel model)
        {
            var where = "where 1=1";

            if (model.IndentHeaderId != 0 && model.Type != "Approved")
            {
                where += $@" AND OID.""IndentHeaderId"" ={model.IndentHeaderId}";
            }
            else if (model.IndentHeaderId != 0 && model.Type == "Approved")
            {
                where += $@" and IH.""IndentHeaderId"" = {model.IndentHeaderId}";
            }

            if (model.IssueHeaderId != 0)
            {
                where += $@" AND IH.""IssueHeaderId"" ={model.IssueHeaderId}";
            }

            if ((!string.IsNullOrEmpty(model.Product)) && (model.Product != "null"))
            {
                where += $@" AND PP.""ProductName"" ILIKE '%{model.Product}%'";
            }

            string query;
            if (model.Type != "Approved")
            {
                query = $@"SELECT PP.""PharmacyProductId"", OID.""IndentDetailId"",PP.""ProductName"", PP.""GenericName"", 
                                    PP.""Barcode"",PP.""PurchaseUnitQty"", PP.""SaleUnitQty"", PP.""CategoryId"", PP.""CompanyId"", PP.""SupplierId"", PP.""PurchaseUnit"",
                                    PP.""SaleUnit"", PP.""TaxId"", PP.""IsProductExpire"", PP.""Active"", PP.""CreatedBy"", PP.""CreatedDate"",
                                    C.""Name"" as ""CompanyName"",Cat.""Name"" as ""CategoryName"",Tax.""Name"" as ""Tax"",
                                    PurchaseUnit.""Name"" as ""PurchaseUnitName"", SaleUnit.""Name"" as ""SaleUnitName"",
									OID.""Quantity"" from ""IndentDetail"" OID								 
	                                    join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = OID.""ProductId""
										join ""Company"" C on C.""CompanyId"" = PP.""CompanyId""
	                                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
	                                    join ""LookupValue"" Tax on Tax.""LookupValueId"" = PP.""TaxId""
	                                    join ""LookupValue"" PurchaseUnit on PurchaseUnit.""LookupValueId"" = PP.""PurchaseUnit""
	                                    join ""LookupValue"" SaleUnit on SaleUnit.""LookupValueId"" = PP.""SaleUnit""
                                        {where}";
                return await this.unitOfWork.Current.QueryAsync<ProductModel>(query);
            }
            else
            {
                query = $@"SELECT PP.""PharmacyProductId"", PP.""ProductName"", PP.""GenericName"", 
                                    PP.""Barcode"",PP.""PurchaseUnitQty"", PP.""SaleUnitQty"", PP.""CategoryId"", PP.""CompanyId"", PP.""SupplierId"", PP.""PurchaseUnit"",
                                    PP.""SaleUnit"", PP.""TaxId"",PP.""IsProductExpire"", PP.""Active"", PP.""CreatedBy"", PP.""CreatedDate"",
                                    C.""Name"" as ""CompanyName"",Cat.""Name"" as ""CategoryName"",Tax.""Name"" as ""Tax"",
                                    PurchaseUnit.""Name"" as ""PurchaseUnitName"", SaleUnit.""Name"" as ""SaleUnitName"",
									OID.""Quantity"",PS.""BatchNumber"",
									(select ""Quantity"" from ""IndentDetail"" where ""IndentHeaderId"" = IH.""IndentHeaderId"" and ""ProductId""=PP.""PharmacyProductId"") as ""RequestedQuantity""
									    from ""IssueDetail"" OID								 
	                                    join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = OID.""ProductId""
										join ""Company"" C on C.""CompanyId"" = PP.""CompanyId""
	                                    join ""LookupValue"" Cat on Cat.""LookupValueId"" = PP.""CategoryId""
	                                    join ""LookupValue"" Tax on Tax.""LookupValueId"" = PP.""TaxId""
	                                    join ""LookupValue"" PurchaseUnit on PurchaseUnit.""LookupValueId"" = PP.""PurchaseUnit""
	                                    join ""LookupValue"" SaleUnit on SaleUnit.""LookupValueId"" = PP.""SaleUnit""
										join ""IssueHeader"" IH on IH.""IssueHeaderId"" = OID.""IssueHeaderId""
										join ""PharmacyStock"" PS on PS.""PharmacyStockId"" = OID.""StockId""
                                        {where}";
                var data = (await this.unitOfWork.Current.QueryAsync<ProductModel>(query)).ToList();
                if (data.Count > 0)
                {
                    var approvedProductIds = string.Join(",", data.Select(p => p.PharmacyProductId));
                    var notApprovedProductQuery = $@"select PP.""PharmacyProductId"", PP.""ProductName"",ID.""Quantity"" as ""RequestedQuantity"",PP.""GenericName""
		                                        from ""IndentDetail"" ID  
		                                        join ""PharmacyProduct"" PP on PP.""PharmacyProductId"" = ID.""ProductId""
		                                        where 1=1 and ID.""IndentHeaderId"" = {model.IndentHeaderId} and PP.""PharmacyProductId"" not in ({approvedProductIds})";
                    var notApprovedProducts = (await this.unitOfWork.Current.QueryAsync<ProductModel>(notApprovedProductQuery)).ToList();
                    if (notApprovedProducts.Count > 0)
                    {
                        data.AddRange(notApprovedProducts);
                    }
                }

                return data;
            }
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyPurchaseReportBill>> FetchCreditPurchaseBillAsync(PharmacyPurchaseReportBill model)
        {
            var where = "where 1 = 1";
            if (model.FromDate != null)
            {
                where += $@" and  PH.""CreatedDate""::timestamp without time zone >= '{model.FromDate}'::timestamp without time zone ";
            }
            if (model.ToDate != null)
            {
                where += $@" and  PH.""CreatedDate""::timestamp without time zone <= '{model.ToDate}'::timestamp without time zone ";
            }
            if (model.BillNumber != null)
            {
                where += $@" and  PH.""BillNumber"" = '{model.BillNumber}'";
            }
            if (model.SupplierId != null)
            {
                where += $@" and  PH.""SupplierId"" = '{model.SupplierId}'";
            }
            if (model.LocationId != null)
            {
                where += $@" and PW.""LocationId"" = {model.LocationId} ";
            }

            var query =
                $@"SELECT
                    PH.""PharmacyPurchaseHeaderId"" ,PH.""DueDate"",PH.""BillNumber"",PH.""BillType"",PH. ""BillDate"",
                       ( SELECT DATE_PART('day', PH.""DueDate""::timestamp - CURRENT_DATE::timestamp)) as ""DueDays"",
                    PH.""Netamount"",PH.""IsCreditClear"" ,--PH.""BillAmount"",
		            PH.""CreatedDate"", PH.""ModifiedDate"",PH.""PaidOnDate"",
		            CA.""FullName"" ""CreatedByName"",CR.""RoleName"", --""CreatedByRole"",
		            MA.""FullName"" ""ModifiedByName"",MR.""RoleName"" ""ModifiedByRole"",
            		S.""Name"" ""SupplierName"",S.""SupplierId"" ,PW.""WareHouseName""
                    ,PRH.""ReturnDate"",PRH.""OverallNetamount"" as ""ReturnNetamount"",lc.""Name"" ""LocationName""
                        from ""PharmacyPurchaseHeader"" PH
                        join ""Supplier"" S on S.""SupplierId"" = PH.""SupplierId""
                        join ""Account"" CA on CA.""AccountId"" = PH.""CreatedBy""
                        join ""Role"" CR on CR.""RoleId"" = CA.""RoleId""
                        left join ""Account"" MA on MA.""AccountId"" = PH.""ModifiedBy""
                        left join ""Role"" MR on MR.""RoleId"" = MA.""RoleId""   
                        left join ""PharmacyPurchaseReturnHeader"" PRH on PRH.""PharmacyPurchaseHeaderId""=PH.""PharmacyPurchaseHeaderId"" 
                        join ""PharmacyWareHouse"" PW on PW.""PharmacyWareHouseId"" = PH.""PharmacyWareHouseId""
                        join ""Location"" lc on lc.""LocationId""=PW.""LocationId""
                         {where}
                            and PH.""BillType"" = 'Credit'
                                 Order by PH.""CreatedDate"" desc ;";

            return await this.unitOfWork.Current.QueryAsync<PharmacyPurchaseReportBill>(query);
        }
        /// <inheritdoc/>
        public async Task<int> UpdatePurchasePayAsync(PharmacyPurchaseReportBill model)
        {

            var purchaseHeader = await this.unitOfWork.PharmacyPurchaseHeaders.FindAsync(m => m.PharmacyPurchaseHeaderId == model.PharmacyPurchaseHeaderId);
            purchaseHeader.IsCreditClear = true;
            purchaseHeader.PayTypeId = model.PayTypeId;
            purchaseHeader.PaymentNumber = model.PaymentNumber;
            purchaseHeader.ModifiedBy = model.ModifiedBy;
            purchaseHeader.ModifiedDate = DateTime.Now;
            purchaseHeader.PaidOnDate = DateTime.Now;
            purchaseHeader.BillType = "Cash";
            //var query = $@" update ""PharmacyPurchaseHeader""
            //                set ""IsCreditClear"" = True ,""BillType""='Cash',""PayTypeId""={model.PayTypeId},""PaymentNumber""='{model.PaymentNumber}',
            //                     ""ModifiedBy""={model.ModifiedBy},""ModifiedDate""=now(),""PaidOnDate""=now()
            //                where ""PharmacyPurchaseHeaderId"" = {model.PharmacyPurchaseHeaderId}";
            //return await this.unitOfWork.Current.ExecuteAsync(query);
            return await this.unitOfWork.PharmacyPurchaseHeaders.UpdateAsync(purchaseHeader);
        }

        /// <inheritdoc/>
        public async Task<int> GetPharmacySaleBillHeaderCounts()
        {
            var query = $@"Select count(*) from ""PharmacySaleHeader""";
            return await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(query);
        }

        /// <inheritdoc/>
        public async Task<int> CorrectGSTCalculationInPharmacySale(int pageSize, int pageIndex)
        {
            pageIndex = pageIndex > 0 ? pageIndex - 1 : pageIndex;
            var headerQuery = $@"Select * from ""PharmacySaleHeader"" order by 1 asc limit {pageSize} offset {pageIndex * pageSize}";
            var headerResponse = (await this.unitOfWork.Current.QueryAsync<PharmacySaleHeader>(headerQuery)).ToList();
            if (headerResponse.Count > 0)
            {
                var transaction = this.unitOfWork.BeginTransaction();
                for (int i = 0; i < headerResponse.Count; i++)
                {
                    PharmacySaleHeader header = headerResponse[i];
                    var previousHeader = await this.unitOfWork.PharmacySaleHeaders.FindAsync(h => h.PharmacySaleHeaderId == header.PharmacySaleHeaderId);
                    previousHeader.OverallDiscount = 0;
                    previousHeader.OverallNetAmount = 0;
                    previousHeader.OverallTaxes = 0;
                    previousHeader.Total = 0;


                    var detailQuery = $@"Select PR.""Mrp"",LV.""Name""::int as ""TaxPercentage"" ,PS.* from ""PharmacySaleDetail"" PS
                                             join ""LookupValue"" LV on LV.""LookupValueId"" = PS.""TaxId""
                                             JOIN ""PharmacyRetailStock"" PR on PR.""PharmacyRetailStockId"" = PS.""PharmacyRetailStockId""
                                             where ""PharmacySaleHeaderId"" = {header.PharmacySaleHeaderId}";

                    var detailResponse = (await this.unitOfWork.Current.QueryAsync<PharmacySaleDetailModel>(detailQuery)).ToList();
                    if (detailResponse.Count > 0)
                    {
                        foreach (var detail in detailResponse)
                        {
                            detail.Total = Math.Round((detail.Quantity * detail.Mrp), 2);
                            if (detail.DiscountPerItem != null)
                            {
                                detail.Discount = Math.Round(((detail.Total * (double)detail.DiscountPerItem) / 100), 2);
                                detail.NetAmount = Math.Round((detail.Total - (double)detail.Discount), 2);
                            }
                            else
                            {
                                detail.NetAmount = detail.Total;
                            }

                            // Tax calculationArea
                            var divideFactor = 100 + detail.TaxPercentage;
                            var amountWithoutTax = Math.Round(((detail.NetAmount / divideFactor) * 100), 2);
                            detail.TaxAmount = Math.Round((detail.NetAmount - amountWithoutTax), 2);
                            // end

                            previousHeader.Total += detail.Total;
                            previousHeader.OverallDiscount += detail.Discount;
                            previousHeader.OverallTaxes += detail.TaxAmount;
                            previousHeader.OverallNetAmount += detail.NetAmount;

                            // update detail here .
                            var getPreviousDetailBill = await this.unitOfWork.PharmacySaleDetails.FindAsync(m => m.PharmacySaleDetailId == detail.PharmacySaleDetailId);

                            getPreviousDetailBill.Total = detail.Total;
                            getPreviousDetailBill.TaxAmount = detail.TaxAmount;
                            getPreviousDetailBill.Discount = detail.Discount;
                            getPreviousDetailBill.NetAmount = detail.NetAmount;

                            var updateDetailResponse = await this.unitOfWork.PharmacySaleDetails.UpdateAsync(getPreviousDetailBill, transaction);
                            if (updateDetailResponse == 0)
                            {
                                transaction.Rollback();
                                return -1;
                            }
                        }

                        // update header here.

                        var headerUpdateResponse = await this.unitOfWork.PharmacySaleHeaders.UpdateAsync(previousHeader, transaction);
                        if (headerUpdateResponse == 0)
                        {
                            transaction.Rollback();
                            return -1;
                        }
                    }
                }
                transaction.Commit();
                return 1;
            }
            else
            {
                return 0;
            }
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<RetailPharmacyModel>> FetchAllRetailStoresOnly(RetailPharmacyModel model)
        {
            var where = "where 1=1";

            if (model.RetailPharmacyId > 0)
            {
                where += $@" and RP.""RetailPharmacyId"" = {model.RetailPharmacyId}";
            }

            var query = $@"SELECT RP.""RetailPharmacyId"", RP.""RetailName"", RP.""CreatedBy"", RP.""CreatedDate"", RP.""ModifiedBy"", RP.""ModifiedDate"",
                                 A.""FullName"" as ""CreatedByName"",M.""FullName"" as ""ModifiedByName""
                            FROM ""RetailPharmacy"" RP                       
                            join ""Account"" A on A.""AccountId"" = RP.""CreatedBy""
                            left join ""Account"" M on M.""AccountId"" = RP.""ModifiedBy""
                            {where}
                            order by RP.""CreatedDate"" desc  ";
            return await this.unitOfWork.Current.QueryAsync<RetailPharmacyModel>(query);
        }


        /// <inheritdoc/>
        public async Task<int> CreateRetailStoreAsync(RetailPharmacyModel model)
        {
            var checkIfQuery = $@"SELECT count(*)	FROM ""RetailPharmacy"" where lower(""RetailName"") = lower('{model.RetailName}')";
            if (model.RetailPharmacyId == 0)
            {
                var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkIfQuery);
                if (checkIf > 0)
                {
                    return -2;
                }
                using var transaction = this.unitOfWork.BeginTransaction();
                var retailStore = new RetailPharmacy
                {
                    CreatedBy = model.CreatedBy,
                    CreatedDate = DateTime.UtcNow.AddMinutes(330),
                    RetailName = model.RetailName,
                    Active = true
                };

                var retailPharmacyId = await this.unitOfWork.RetailPharmacy.InsertAsync(retailStore, transaction);

                if (model.AllowedAccountId != null)
                {
                    var ids = model.AllowedAccountId.Split(',');

                    if (retailPharmacyId > 0)
                    {
                        foreach (var id in ids)
                        {
                            var retailUser = new PharmacyRetailUser
                            {
                                Active = true,
                                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                                CreatedBy = model.CreatedBy,
                                AccountId = Convert.ToInt32(id),
                                RetailPharmacyId = retailPharmacyId
                            };
                            await this.unitOfWork.PharmacyRetailUsers.InsertAsync(retailUser, transaction);
                        }
                    }
                }

                var linkedWarehouses = new List<RetailWareHouseLink>();
                if (!string.IsNullOrEmpty(model.PharmacyWareHouseIds))
                {
                    var wareHouseIds = model.PharmacyWareHouseIds.Split(",").Select(x => new RetailWareHouseLink
                    {
                        PharmacyWareHouseId = int.Parse(x),
                        RetailPharmacyId = retailPharmacyId
                    });

                    if (wareHouseIds.ToList().Count > 0)
                    {
                        linkedWarehouses.AddRange(wareHouseIds);
                    }
                }


                var getGlobalWareHouses = (await this.unitOfWork.PharmacyWareHouses.FindAllAsync(x => x.LocationId == null)).ToList();
                if (getGlobalWareHouses.Count > 0)
                {
                    var global = getGlobalWareHouses.Select(x => new RetailWareHouseLink
                    {
                        PharmacyWareHouseId = x.PharmacyWareHouseId,
                        RetailPharmacyId = retailPharmacyId
                    });
                    linkedWarehouses.AddRange(global);
                }

                var retailWareHouseLinkId = await this.unitOfWork.RetailWareHouseLinks.BulkInsertAsync(linkedWarehouses, transaction);
                if (retailWareHouseLinkId == 0)
                {
                    transaction.Rollback();
                    return -1;
                }

                transaction.Commit();
                return retailPharmacyId;
            }
            else
            {
                checkIfQuery += $@" and ""RetailPharmacyId"" <> {model.RetailPharmacyId}";
                var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkIfQuery);
                if (checkIf > 0)
                {
                    return -2;
                }
                using var transaction = this.unitOfWork.BeginTransaction();
                var oldRecord = await this.unitOfWork.RetailPharmacy.FindAsync(m => m.RetailPharmacyId == model.RetailPharmacyId);
                if (oldRecord == null)
                {
                    return -1;
                }

                oldRecord.RetailName = model.RetailName;
                oldRecord.ModifiedBy = model.CreatedBy;
                oldRecord.ModifiedDate = DateTime.UtcNow.AddMinutes(330);

                var response = await this.unitOfWork.RetailPharmacy.UpdateAsync(oldRecord, transaction);

                var query = $@"DELETE from ""PharmacyRetailUser"" where ""RetailPharmacyId""= {model.RetailPharmacyId} ";
                await this.unitOfWork.Current.QuerySingleOrDefaultAsync(query, transaction);

                if (model.AllowedAccountId != null)
                {
                    var receivedAccountIds = model.AllowedAccountId.Split(',');

                    if (!string.IsNullOrEmpty(receivedAccountIds[0]) && model.RetailPharmacyId > 0)
                    {
                        foreach (var id in receivedAccountIds)
                        {

                            var retailUser = new PharmacyRetailUser
                            {
                                Active = true,
                                CreatedDate = DateTime.UtcNow.AddMinutes(330),
                                CreatedBy = model.CreatedBy,
                                AccountId = Convert.ToInt32(id),
                                RetailPharmacyId = (int)model.RetailPharmacyId
                            };
                            await this.unitOfWork.PharmacyRetailUsers.InsertAsync(retailUser, transaction);
                        }
                    }
                }

                if (model.PharmacyWareHouseIds != null)
                {
                    var newIds = new List<int>();

                    var alreadyExistedQuery = $@"Select RWHL.* from ""RetailWareHouseLink"" RWHL
                                                        join ""PharmacyWareHouse"" pwh ON pwh.""PharmacyWareHouseId"" = rwhl.""PharmacyWareHouseId""
                                                        where RWHL.""RetailPharmacyId"" = {oldRecord.RetailPharmacyId} and pwh.""LocationId"" is not null";
                    var getAlreadyExist = (await this.unitOfWork.Current.QueryAsync<RetailWareHouseLink>(alreadyExistedQuery)).ToList();

                    var oldIds = ((string.Join(",", getAlreadyExist.Select(m => m.PharmacyWareHouseId))).Split(",")).ToList();
                    var recievedWareHouseId = (model.PharmacyWareHouseIds.Split(",")).ToList();

                    var removedIds = new List<int>();

                    foreach (var oldId in oldIds)
                    {
                        if (!string.IsNullOrEmpty(oldId))
                        {
                            var getData = (recievedWareHouseId.Where(m => m == oldId)).ToList();
                            if (getData.Count == 0)
                            {
                                removedIds.Add(int.Parse(oldId));
                            }
                        }
                    }

                    foreach (var newId in recievedWareHouseId)
                    {
                        var getId = (oldIds.Where(m => m == newId)).ToList();
                        if (getId.Count == 0)
                        {
                            newIds.Add(int.Parse(newId));
                        }
                    }

                    try
                    {
                        foreach (var toBeDeleteId in removedIds)
                        {
                            var deleteQuery = $@"DELETE FROM ""RetailWareHouseLink"" WHERE ""RetailPharmacyId"" ={oldRecord.RetailPharmacyId} 
                                            and ""PharmacyWareHouseId"" = {toBeDeleteId}";
                            await this.unitOfWork.Current.QuerySingleOrDefaultAsync(deleteQuery, transaction);
                        }

                    }
                    catch (Exception)
                    {
                        transaction.Rollback();
                        return -3;
                    }

                    foreach (var id in newIds)
                    {
                        var linkModel = new RetailWareHouseLink
                        {
                            PharmacyWareHouseId = id,
                            RetailPharmacyId = oldRecord.RetailPharmacyId
                        };

                        linkModel.RetailWareHouseLinkId = await this.unitOfWork.RetailWareHouseLinks.InsertAsync(linkModel, transaction);
                        if (linkModel.RetailWareHouseLinkId == 0)
                        {
                            transaction.Rollback();
                            return -1;
                        }
                    }
                }
                transaction.Commit();
                return response;
            }
        }

        /// <inheritdoc/>
        public async Task<int> DeActiveRetailStoreAsync(int retailPharmacyId, int modifiedBy)
        {
            var record = await this.unitOfWork.RetailPharmacy.FindAsync(x => x.RetailPharmacyId == retailPharmacyId);

            if (record == null)
            {
                return -1;
            }
            record.ModifiedBy = modifiedBy;
            record.ModifiedDate = DateTime.Now;
            record.Active = false;

            return await this.unitOfWork.RetailPharmacy.UpdateAsync(record);
        }

        /// <inheritdoc/>
        public async Task<int> ToActiveRetailStoreAsync(int retailPharmacyId, int modifiedBy)
        {
            var record = await this.unitOfWork.RetailPharmacy.FindAsync(x => x.RetailPharmacyId == retailPharmacyId);

            if (record == null)
            {
                return -1;
            }
            record.ModifiedBy = modifiedBy;
            record.ModifiedDate = DateTime.Now;
            record.Active = true;

            return await this.unitOfWork.RetailPharmacy.UpdateAsync(record);
        }

        /// <inheritdoc/>
        public async Task<int> AddRetailStoreDetails(PharmacyStoreModel model)
        {
            var pharmacyStore = new PharmacyStore
            {
                CreatedBy = model.CreatedBy,
                CreatedDate = DateTime.Now,
                GSTNumber = model.GSTNumber,
                HospitalName = model.HospitalName,
                Location = model.Location,
                Name = model.Name,
                PinCode = model.PinCode,
                Active = false,
                LocationId = model.LocationId
            };

            return await this.unitOfWork.PharmacyStores.InsertAsync(pharmacyStore);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PharmacyStoreModel>> FetchAllStoresSettings(int? locationId)
        {
            var extraCondition = " where 1=1";
            if (locationId != null)
            {
                extraCondition = $@" and PS.""LocationId"" = {locationId}";
            }

            var query = $@"SELECT PS.""PharmacyStoreId"", PS.""Name"", PS.""HospitalName"", PS.""Location"", PS.""PinCode"", 
                            PS.""GSTNumber"", PS.""Active"", PS.""CreatedBy"", PS.""CreatedDate"",
		                    A.""FullName"" as ""CreatedByName""
	                    FROM ""PharmacyStore"" PS
	                    join ""Account"" A on A.""AccountId"" = PS.""CreatedBy""
                        {extraCondition}
                        order by PS.""CreatedDate"" desc";
            return await this.unitOfWork.Current.QueryAsync<PharmacyStoreModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> ApplyStoreSettingInPharmacy(int pharmacyStoreId, int? locationId)
        {
            var extraCondition = " where 1=1";
            if (locationId != null)
            {
                extraCondition = $@" and ""LocationId"" = {locationId}";
            }
            var query = $@"UPDATE ""PharmacyStore""	SET ""Active""= false {extraCondition}; 
                            UPDATE ""PharmacyStore"" SET ""Active""= true where ""PharmacyStoreId"" = {pharmacyStoreId}";
            return await this.unitOfWork.Current.ExecuteAsync(query);
        }

        /// <inheritdoc/>
        public async Task<PharmacyStoreModel> GetAppliedSetting(int? id, int? locationId)
        {
            var where = $@" where ""Active""= true";
            if (id != null)
            {
                where = $@" where ""PharmacyStoreId""= {id}";
            }
            if (locationId != null)
            {
                where += $@" and ""LocationId"" = {locationId}";
            }

            var query = $@"Select * from ""PharmacyStore"" {where}  limit 1";
            return await this.unitOfWork.Current.QueryFirstOrDefaultAsync<PharmacyStoreModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<RetailWareUser>> FetchPharmacyUsersRetailAsync(int? accountId, int? pharmacyWareHouseId)
        {
            var where = "where 1=1";

            if ((accountId != null) && (accountId != 0))
            {
                where += $@" and A.""AccountId"" = {accountId}";
            }
            if (pharmacyWareHouseId != null)
            {
                where += $@" and PWU.""PharmacyWareHouseId"" = {pharmacyWareHouseId}";
            }

            var query = $@"select A.""AccountId"",A.""FullName"",string_agg( distinct PW.""WareHouseName"",',') as ""WareHouseName"",string_agg(distinct RP.""RetailName"",',') as ""RetailName"" from ""Account"" A 
                             join ""PharmacyWareHouseUser"" PWU on PWU.""AccountId"" = A.""AccountId""
                             join ""PharmacyWareHouse"" PW on PW.""PharmacyWareHouseId"" = PWU.""PharmacyWareHouseId""
                             join ""RetailWareHouseLink"" RWL on RWL.""PharmacyWareHouseId"" = PW.""PharmacyWareHouseId""
                             join ""RetailPharmacy"" RP on RP.""RetailPharmacyId"" = RWL.""RetailPharmacyId""
                            {where}
                             group by A.""FullName"",A.""AccountId"", RWL.""RetailPharmacyId""";

            return await this.unitOfWork.Current.QueryAsync<RetailWareUser>(query);
        }
        /// <inheritdoc/>
        public async Task<IEnumerable<PharmaPurchaseBill>> FetchPharmacyCreditPurchaseBillAsync(int purchaseHeaderId)
        {

            var query = $@"select pp.""ProductName"",PS.""BatchNumber"",pp.""GenericName"",pp.""Barcode"",
                            lv.""Name"" ""CategoryName"",
                            c.""Name"" ""CompanyName"",
                            s.""Name"" ""SupplierName"",s.""SupplierId"",
                    pph.""BillDate"",pprh.""ReturnDate"",
                           pph.""BillNumber"",pph. ""CreatedDate"" ,          --pprh.""BillNumber"",
                            pph.""BillType"" ,
-- ppd.* 
ppd.""Quantity"",ppd.""Free"" ,ppd.""PurchaseRate"",ppd.""Mrp""
,ppd.""Total"" ,ppd.""TaxAmount"",ppd.""DiscountAmount"",ppd.""NetAmount"",--purchase product wise(detail)
 pph.""BillAmount"" as ""BillTotal"" ,pph.""Discount"" as ""BillDiscount"",pph.""Taxes"" as ""BillTaxes"",pph.""Netamount"" as ""BillNetAmount"" , --purchase bill wise(header)
 --pprd.* ,
 pprd.""ReturnQuantity"",
 pprd.""Amount"" as ""ReturnTotal"",pprd.""NetAmount"" as ""ReturnNetAmount""     --purchase return Product wise(detail)
 ,pprh.""OverallBillAmount"",pprh.""OverallDiscount"",pprh.""OverallTaxes"",pprh.""OverallNetamount""    -- Purchase return bill wise(header)
,lc.""Name"" ""LocationName"" -- ""LocationDetails""
                          from ""PharmacyPurchaseDetail"" ppd
                           join ""PharmacyPurchaseHeader"" pph on pph.""PharmacyPurchaseHeaderId"" = ppd.""PharmacyPurchaseHeaderId""
                            left join ""PharmacyPurchaseReturnDetail""  pprd on pprd.""PharmacyPurchaseDetailId"" = ppd.""PharmacyPurchaseDetailId""-- or ppd.""PharmacyProductId"" = pprd.""PharmacyProductId""
                            left join ""PharmacyPurchaseReturnHeader"" pprh on pprh.""PharmacyPurchaseReturnHeaderId"" = pprd.""PharmacyPurchaseReturnHeaderId""

                            join ""PharmacyProduct"" pp on  pp.""PharmacyProductId"" = ppd.""PharmacyProductId""
                            join ""LookupValue"" lv on lv.""LookupValueId"" = pp.""CategoryId""
                            join ""Company"" c on c.""CompanyId"" = pp.""CompanyId""
                            join ""Supplier"" s on s.""SupplierId"" = pph.""SupplierId""
                            join ""PharmacyStock"" PS on PS.""PharmacyStockId""=ppd.""PharmacyStockId""
							join ""PharmacyWareHouse"" pw on pw.""PharmacyWareHouseId""=pph.""PharmacyWareHouseId""
                            join ""Location"" lc on lc.""LocationId"" = pw.""LocationId""
                            where ppd.""PharmacyPurchaseHeaderId"" ={purchaseHeaderId}";

            return await this.unitOfWork.Current.QueryAsync<PharmaPurchaseBill>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<PurchaseBillHistoryModel>> FetchProductPurchaseHistoryAsync(PurchaseBillHistoryModel model)
        {
            var where = "where 1=1";
            if (model.PharmacyProductId != null)
            {
                where += $@" and ppd.""PharmacyProductId"" = {model.PharmacyProductId} ";
            }

            var query = $@"SELECT ppd.""PharmacyPurchaseDetailId"", ppd.""PharmacyPurchaseHeaderId"", ppd.""PharmacyProductId"", ppd.""Quantity"", ppd.""Free"", ppd.""PurchaseRate"", ppd.""Mrp"",
	                                ppd.""PharmacyStockId"", pp.""ProductName"",pp.""GenericName"",cat.""Name"" as ""CategoryName"", c.""Name"" as ""CompanyName"",ps.""BatchNumber"", pph.""BillDate"",
	                                pph.""BillNumber"" , s.""Name""  as ""SupplierName"", pwh.""WareHouseName"", l.""Name"" as ""LocationName""
	                                FROM ""PharmacyPurchaseDetail"" ppd
	                                join ""PharmacyProduct"" pp ON pp.""PharmacyProductId"" = ppd.""PharmacyProductId"" 
	                                join ""Company"" c on c.""CompanyId"" = pp.""CompanyId"" 
	                                join ""LookupValue"" cat on cat.""LookupValueId"" = pp.""CategoryId"" 
	                                left join ""PharmacyStock"" ps ON ps.""PharmacyStockId"" = ppd.""PharmacyStockId"" 
	                                join ""PharmacyPurchaseHeader"" pph on pph.""PharmacyPurchaseHeaderId"" = ppd.""PharmacyPurchaseHeaderId"" 
	                                join ""Supplier"" s on s.""SupplierId"" = pph.""SupplierId"" 
                                    join ""PharmacyWareHouse"" pwh on pwh.""PharmacyWareHouseId"" = pph.""PharmacyWareHouseId"" 
                                    join ""Location"" l on l.""LocationId"" = pwh.""LocationId"" 
	                                {where}  
	                                order by pph.""BillDate"" desc";

            return await this.unitOfWork.Current.QueryAsync<PurchaseBillHistoryModel>(query);
        }

        /// <inheritdoc/>
        public async Task<IEnumerable<DrugModel>> FetchDrugAsync(string term)
        {
            var query = $@"select distinct d.""DrugName"", d.""CompanyName"", d.""PackagingOfMedicines"", d.""MedicineType"", d.""Composition"" ,
                                 d.""AlchoholInteraction"" ,d.""PregnancyInteraction"" , d.""ExpertAdvice"" , d.""CommonSideEffects"" ,d.""MedicineFaq"" , d.""MedicineInteraction"",d.""Usage""
                                from ""Drug"" d where lower(""DrugName"") ilike '%{term}%' order by ""DrugName"" desc limit 20";
            return await this.unitOfWork.Current.QueryAsync<DrugModel>(query);
        }

        /// <inheritdoc/>
        public async Task<int> ModifyMedicationFreqAsync(MedFrequencyMasterModel model)
        {
            var checkIfQuery = $@"select count(*) FROM ""MedFrequencyMaster"" where lower(""FrequencyName"") = '{model.FrequencyName}'";

            if (model.MedFrequencyMasterId == 0)
            {
                var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkIfQuery);
                if (checkIf > 0)
                {
                    return -1;
                }

                var iModel = new MedFrequencyMaster
                {
                    Active = true,
                    CalculationUnit = model.CalculationUnit,
                    CreatedBy = model.CreatedBy,
                    FreqType = model.FreqType,
                    CreatedDate = DateTime.Now,
                    FrequencyDescription = model.FrequencyDescription,
                    FrequencyName = model.FrequencyName
                };

                return await this.unitOfWork.MedFrequencyMasters.InsertAsync(iModel);
            }
            else
            {
                checkIfQuery += $@" and ""MedFrequencyMasterId"" <> {model.MedFrequencyMasterId}";
                var checkIf = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<int>(checkIfQuery);
                if (checkIf > 0)
                {
                    return -1;
                }

                var getOld = await this.unitOfWork.MedFrequencyMasters.FindAsync(x => x.MedFrequencyMasterId == model.MedFrequencyMasterId);
                if (getOld == null)
                {
                    return 0;
                }

                getOld.FrequencyDescription = model.FrequencyDescription;
                getOld.FrequencyName = model.FrequencyName;
                getOld.CalculationUnit = model.CalculationUnit;
                getOld.FreqType = model.FreqType;

                return await this.unitOfWork.MedFrequencyMasters.UpdateAsync(getOld);
            }

        }

        /// <inheritdoc/>
        public async Task<IEnumerable<MedFrequencyMasterModel>> FetchMedicationFreqAsync(MedFrequencyMasterModel model)
        {
            var query = $@"SELECT mf.""MedFrequencyMasterId"", mf.""FrequencyName"", mf.""FrequencyDescription"", mf.""FreqType"", mf.""CalculationUnit"", mf.""Active"", mf.""CreatedBy"", mf.""CreatedDate"" ,
		                            a.""FullName"" as ""CreatedByName""
	                            FROM ""MedFrequencyMaster"" mf
	                            join ""Account"" a on a.""AccountId"" = mf.""CreatedBy"" 
	                            order by mf.""CreatedDate"" desc";

            return await this.unitOfWork.Current.QueryAsync<MedFrequencyMasterModel>(query);
        }

        public async Task<int> ChangeActiveStatusForMedFrequency(MedFrequencyMasterModel model)
        {
            var getOld = await this.unitOfWork.MedFrequencyMasters.FindAsync(x => x.MedFrequencyMasterId == model.MedFrequencyMasterId);
            if (getOld == null)
            {
                return 0;
            }
            getOld.Active = model.Active;
            return await this.unitOfWork.MedFrequencyMasters.UpdateAsync(getOld);
        }

        /// <summary>
        /// The add pharmacy sales details.
        /// </summary>
        /// <param name="model">
        /// The model.
        /// </param>
        /// <param name="transaction">
        /// The transaction.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        private async Task<int> AddPharmacySalesDetails(PharmacySaleDetail model, IDbTransaction transaction)
        {
            var checkPrevious =
                await this.unitOfWork.PharmacySaleDetails.FindAllAsync(
                    m => m.PharmacySaleHeaderId == model.PharmacySaleHeaderId);
            var records = checkPrevious.ToList();
            if (records.Count > 0)
            {
                var maxId = records.Max(m => m.PharmacySaleDetailId);
                var record = records.Find(m => m.PharmacySaleDetailId == maxId);
                if (record != null)
                {
                    model.SerialNum = record.SerialNum + 1;
                }
            }

            return await this.unitOfWork.PharmacySaleDetails.InsertAsync(model, transaction);
        }

        /// <summary>
        /// The get lookup id.
        /// </summary>
        /// <param name="lookupName">
        /// The lookup name.
        /// </param>
        /// <param name="description">
        /// The description.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        private async Task<int> GetLookupId(string lookupName, string description)
        {
            int lookupId;
            var lookup = await this.unitOfWork.Lookups.FindAsync(m => m.Name == lookupName);
            if (lookup == null)
            {
                var lookupModel = new Lookup { Name = lookupName, Description = description };
                lookupId = await this.unitOfWork.Lookups.InsertAsync(lookupModel);
            }
            else
            {
                lookupId = lookup.LookupId;
            }

            return lookupId;
        }

        /// <summary>
        /// The check lookup value name.
        /// </summary>
        /// <param name="name">
        /// The name.
        /// </param>
        /// <param name="lookupId">
        /// The lookup id.
        /// </param>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        private async Task<bool> CheckLookupValueName(string name, int lookupId)
        {
            var lookup = await this.unitOfWork.LookupValues.FindAllAsync(m => m.LookupId == lookupId);
            var match = lookup?.ToList().Find(
                m => string.Equals(m.Name, name, StringComparison.CurrentCultureIgnoreCase));
            return match != null;
        }

        /// <summary>
        /// The get bill number.
        /// </summary>
        /// <returns>
        /// The <see cref="Task"/>.
        /// </returns>
        private async Task<string> GetBillNumber()
        {
            var billQuery = $@"SELECT ""BillNumber"" FROM ""PharmacySaleHeader""
                                        ORDER BY ""PharmacySaleHeaderId"" DESC LIMIT 1";
            var oldBillNumber = await this.unitOfWork.Current.QuerySingleOrDefaultAsync<string>(billQuery);
            if (string.IsNullOrEmpty(oldBillNumber))
            {
                // PHAB2021040101
                return "PH" + CoreFilter.Random(2) + DateTime.Now.ToString("yyyyMMdd") + "1";
            }
            else
            {
                var stringLiterals = oldBillNumber.Substring(0, 4);
                var previousBillDateWithCount = oldBillNumber.Substring(4);
                var counter = previousBillDateWithCount.Substring(8);
                var date = previousBillDateWithCount.Substring(0, 8);
                if (date != DateTime.Now.ToString("yyyyMMdd"))
                {
                    return "PH" + CoreFilter.Random(2) + DateTime.Now.ToString("yyyyMMdd") + "1";
                }

                counter = (int.Parse(counter) + 1).ToString();
                return stringLiterals + date + counter;
            }
        }

        /// <summary>
        /// gets the All Units
        /// </summary>
        /// <returns></returns>
        public async Task<IEnumerable<string>> GetAllUnitTypes()
        {

            var query = $@"SELECT  L.""Name"" 
	                            FROM ""LookupValue"" L
                             
                               where  ""LookupId"" = (Select ""LookupId"" from ""Lookup"" where ""Name"" = 'LaboratoryUnit')";

            return await this.unitOfWork.Current.QueryAsync<string>(query);
        }
    }
}
