using System.Data;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;

namespace Fast.Web.Logic.ReportSources;

class ValuationData(MyDbContext context, SpreadsheetDocument wb, string reportName, int dataSourceId, int filterId, string filterName, List<ReportFilterParameter> filterParams, int userInfoId)
    : ReportSourceBase(context, wb, reportName, dataSourceId, filterId, filterName, filterParams, userInfoId)
{

    private class CrudeData
    {
        public string ContractNum = "";
        public decimal PipeLossAllowance;
        public decimal Differential;
        public bool IsDiffBeforePipeLoss;
        public DateOnly EffectiveDate;
        public List<int> PointIds = [];
    }

    public override async Task<List<ReportFilterParameter>> Run()
    {
        var val = new Valuater();
        var valParams = await GetValParams();
        var vals = await val.GetValuationValues(valParams);

        if (!vals.Any())
            return GetNewFilterParams();

        DataTable dtMainData = InitValuationDataTable();

        var TransIds = valParams.TransactionTypeIds;
        var FilterTransIds = false;
        if (TransIds.Any())
            FilterTransIds = true;

        var dealQuery = (from d in db.VwRptValuationDataDeals select d);
        var dealExp = Util.Date.GetDateRangeExpression<VwRptValuationDataDeal>(valParams.PositionDateRanges, "StartDate", "EndDate", false);
        dealQuery = dealQuery.Where(dealExp);
        dealQuery = dealQuery.Where(x => !FilterTransIds || TransIds.Contains(x.TransactionTypeId!.Value));
        var deals = await dealQuery.AsNoTracking().ToArrayAsync();

        var crudeContractQuery = (
            from q in db.ContractCrudes
            select new CrudeData
            {
                ContractNum = q.Contract.ContractNum,
                PipeLossAllowance = q.PipeLossAllowance,
                Differential = q.Differential,
                IsDiffBeforePipeLoss = q.IsDiffBeforePipeLoss,
                EffectiveDate = q.EffectiveDate,
                PointIds = q.ContractCrudePoints.Select(x => x.PointId).ToList()
            }
        );

        var crudeDataByContractNum = (await crudeContractQuery.AsNoTracking().ToListAsync()).ToLookup(x => x.ContractNum);

        var Detail = (
            from v in vals
            join d in deals on v.DealId.GetValueOrDefault() equals d.Id
            select new
            {
                v.TicketNum,
                v.MasterTicketNum,
                TradeDate = d.TradingDate,
                PositionMonth = Util.Date.FirstDayOfMonth(v.PositionStartDate),
                v.PositionStartDate,
                v.PositionEndDate,
                v.PositionAmount,
                v.MarketPrice,
                v.ContractPrice,
                v.PriceParts.PriceCm,
                v.PriceParts.PricePm,
                v.PriceParts.Price2m,
                v.PriceParts.Price3m,
                v.PriceParts.PriceAg1,
                v.PriceParts.PriceAg2,
                v.PriceParts.BD1,
                v.PriceParts.BD2,
                v.PriceParts.BDT,
                v.InvoicePrice,
                v.IsPosted,
                Basis = v.BasisPrice,
                d.PremiumOrDiscount,
                PNL_MTM = v.PnL,
                d.Counterparty,
                d.CounterpartyNickname,
                d.TransactionType,
                d.TransactionTypeId,
                d.Pipeline,
                d.PipeShort,
                d.Point,
                d.Broker,
                d.PriceIndex,
                d.PriceIndex2,
                d.DealPurpose,
                d.DealType,
                d.InternalEntity,
                d.IsFixedPrice,
                IsSupplyDeal = d.BuyButton == (int)Enums.BuyButton.Buy,
                d.FixedPrice,
                IsMonthlyIndex = v.IsMonthlyIndexDeal,
                d.BrokerAccount,
                d.Book,
                d.Portfolio,
                d.Strategy,
                d.Region,
                d.NymexExecutionFee,
                d.ExecutionMargin,
                d.SalesMargin,
                d.StartDate,
                d.EndDate,
                d.BuyButton,
                d.CommissionPerContract,
                d.TraderShortName,
                d.TraderName,
                d.Comments,
                d.InternalMemo,
                d.DealPurposeId,
                d.PointId,
                d.VolumeTypeId,
                d.ContractNum,
                d.TheirContractNum,
                d.IsHybridWithSuffix
            }
        ).ToArray();

        var Detail2 = (
            from q in Detail
            let toGroup = (q.IsFixedPrice.GetValueOrDefault() == 1 || q.IsMonthlyIndex || q.IsHybridWithSuffix.GetValueOrDefault())
            select new { toGroup, q }
        ).ToLookup(x => x.toGroup, x => x.q);

        var items = Detail2[false].ToList();

        var itemsToGroup = Detail2[true];

        var distinctTicketss = itemsToGroup.Select(n => n.TicketNum).Distinct();

        var ticketDataL = itemsToGroup.ToLookup(x => x.TicketNum);

        var monthlyDataL = itemsToGroup.ToLookup(x => new { x.TicketNum, x.PositionMonth });

        var minPositionStart = val.allPositionDays.First();
        var maxPositionEnd = val.allPositionDays.Last();

        foreach (var tck in distinctTicketss)
        {
            var ticket = tck;

            var ticketData = ticketDataL[ticket];

            foreach (DateOnly positionMonth in val.allPositionMonths)
            {
                var month = positionMonth;
                var key = new { TicketNum = ticket, PositionMonth = month };
                var monthlyData = monthlyDataL[key];

                if (monthlyData.Any())
                {
                    var minStartDate = monthlyData.Min(n => n.PositionStartDate);
                    var maxEndDate = monthlyData.Max(n => n.PositionEndDate);

                    var positionAmount = monthlyData.Sum(n => n.PositionAmount);

                    var mtm = monthlyData.Sum(n => n.PNL_MTM);

                    var groupedItem = (
                        from v in monthlyData
                        select new
                        {
                            v.TicketNum,
                            v.MasterTicketNum,
                            v.TradeDate,
                            PositionMonth = month,
                            PositionStartDate = minStartDate,
                            PositionEndDate = maxEndDate,
                            PositionAmount = positionAmount,
                            v.MarketPrice,
                            v.ContractPrice,
                            v.PriceCm,
                            v.PricePm,
                            v.Price2m,
                            v.Price3m,
                            v.PriceAg1,
                            v.PriceAg2,
                            v.BD1,
                            v.BD2,
                            v.BDT,
                            v.InvoicePrice,
                            v.IsPosted,
                            v.Basis,
                            v.PremiumOrDiscount,
                            PNL_MTM = mtm,
                            v.Counterparty,
                            v.CounterpartyNickname,
                            v.TransactionType,
                            v.TransactionTypeId,
                            v.Pipeline,
                            v.PipeShort,
                            v.Point,
                            v.Broker,
                            v.PriceIndex,
                            v.PriceIndex2,
                            v.DealPurpose,
                            v.DealType,
                            v.InternalEntity,
                            v.IsFixedPrice,
                            v.IsSupplyDeal,
                            v.FixedPrice,
                            v.IsMonthlyIndex,
                            v.BrokerAccount,
                            v.Book,
                            v.Portfolio,
                            v.Strategy,
                            v.Region,
                            v.NymexExecutionFee,
                            v.ExecutionMargin,
                            v.SalesMargin,
                            v.StartDate,
                            v.EndDate,
                            v.BuyButton,
                            v.CommissionPerContract,
                            v.TraderShortName,
                            v.TraderName,
                            v.Comments,
                            v.InternalMemo,
                            v.DealPurposeId,
                            v.PointId,
                            v.VolumeTypeId,
                            v.ContractNum,
                            v.TheirContractNum,
                            v.IsHybridWithSuffix
                        }
                    ).First();

                    items.Add(groupedItem);
                }
            }
        }

        items = (from i in items orderby i.TransactionType, i.TicketNum.TicketSort() select i).ToList();

        foreach (var item in items)
        {
            DataRow r = dtMainData.NewRow();
            {
                var withBlock = r;
                withBlock[ColumnName.TicketNum] = item.TicketNum;
                withBlock[ColumnName.MasterTicketNum] = item.MasterTicketNum;
                withBlock[ColumnName.BuyOrSell] = item.BuyButton.GetValueOrDefault() == 1 ? "Buy" : "Sell";
                withBlock[ColumnName.TradeDate] = item.TradeDate == null ? DBNull.Value : (object)item.TradeDate;
                withBlock[ColumnName.CustomerOrSupply] = GetCustomerSupplyCaption(item.TransactionTypeId!.Value, item.IsSupplyDeal, item.BuyButton);

                if (item.TransactionTypeId == 1 & item.IsFixedPrice.GetValueOrDefault() == 1 & item.IsSupplyDeal == false)
                    withBlock[ColumnName.PositionType] = "Customer Fixed WASP";
                else if (item.TransactionTypeId == 1 & item.IsFixedPrice.GetValueOrDefault() == 1 & item.IsSupplyDeal == true)
                    withBlock[ColumnName.PositionType] = "Physical Fixed Price Supply";
                else if (item.TransactionTypeId == 3 || item.TransactionTypeId == 6)
                    withBlock[ColumnName.PositionType] = "Financial Supply Hedges in Place";
                else if (item.IsSupplyDeal == true)
                    withBlock[ColumnName.PositionType] = "Supply Deal";
                else
                    withBlock[ColumnName.PositionType] = "Other";

                withBlock[ColumnName.PositionMonth] = item.PositionMonth;
                withBlock[ColumnName.PositionStartDate] = item.PositionStartDate;
                withBlock[ColumnName.PositionEndDate] = item.PositionEndDate;
                withBlock[ColumnName.DealStartDate] = item.StartDate;
                withBlock[ColumnName.DealEndDate] = item.EndDate;
                withBlock[ColumnName.Volume] = item.PositionAmount;
                withBlock[ColumnName.MarketPrice] = item.MarketPrice;
                withBlock[ColumnName.ContractPrice] = item.ContractPrice;
                withBlock[ColumnName.OurContractNum] = (object?)item.ContractNum ?? DBNull.Value;
                withBlock[ColumnName.TheirContractNum] = (object?)item.TheirContractNum ?? DBNull.Value;
                withBlock[ColumnName.PriceCM] = (object?)item.PriceCm ?? DBNull.Value;
                withBlock[ColumnName.PricePM] = (object?)item.PricePm ?? DBNull.Value;
                withBlock[ColumnName.Price2M] = (object?)item.Price2m ?? DBNull.Value;
                withBlock[ColumnName.Price3M] = (object?)item.Price3m ?? DBNull.Value;
                withBlock[ColumnName.PriceAG1] = (object?)item.PriceAg1 ?? DBNull.Value;
                withBlock[ColumnName.PriceAG2] = (object?)item.PriceAg2 ?? DBNull.Value;
                withBlock[ColumnName.BD1] = (object?)item.BD1 ?? DBNull.Value;
                withBlock[ColumnName.BD2] = (object?)item.BD2 ?? DBNull.Value;
                withBlock[ColumnName.BDT] = (object?)item.BDT ?? DBNull.Value;

                var crudeData = GetDealCrudeData(item.ContractNum ?? "", crudeDataByContractNum, item.PointId, item.PositionStartDate);
                withBlock[ColumnName.PipeLossPercent] = (object?)crudeData?.PipeLossAllowance ?? DBNull.Value;
                withBlock[ColumnName.Differential] = (object?)crudeData?.Differential ?? DBNull.Value;
                withBlock[ColumnName.IsDiffBeforePipeLoss] = (object?)crudeData?.IsDiffBeforePipeLoss ?? DBNull.Value;

                withBlock[ColumnName.InvoicePrice] = item.InvoicePrice;
                withBlock[ColumnName.IsPosted] = item.IsPosted;
                withBlock[ColumnName.Basis] = item.Basis == 0 ? DBNull.Value : (object)item.Basis;
                withBlock[ColumnName.PremiumOrDiscount] = item.PremiumOrDiscount == null ? DBNull.Value : (object)item.PremiumOrDiscount;
                withBlock[ColumnName.PNL_MTM] = item.PNL_MTM;
                withBlock[ColumnName.Counterparty] = item.Counterparty;
                withBlock[ColumnName.CounterpartyNickname] = item.CounterpartyNickname;
                withBlock[ColumnName.InternalEntity] = item.InternalEntity;
                withBlock[ColumnName.TransactionType] = item.TransactionType;
                withBlock[ColumnName.ProductGroup] = GetProductGroupName(item.TransactionTypeId.Value, item.TransactionType);
                withBlock[ColumnName.Pipeline] = item.Pipeline;
                withBlock[ColumnName.PipeShort] = item.PipeShort;
                withBlock[ColumnName.Point] = item.Point;
                withBlock[ColumnName.Broker] = item.Broker;
                withBlock[ColumnName.PriceIndex] = item.PriceIndex;
                withBlock[ColumnName.PriceIndex2] = item.PriceIndex2;
                withBlock[ColumnName.DealPurpose] = item.DealPurpose;
                withBlock[ColumnName.DealType] = item.DealType;

                if (item.IsFixedPrice.HasValue == false)
                    withBlock[ColumnName.PriceType] = "";
                else if (item.IsFixedPrice.GetValueOrDefault() == 1)
                    withBlock[ColumnName.PriceType] = "Fixed Price";
                else if (item.IsFixedPrice.GetValueOrDefault() == 0)
                    withBlock[ColumnName.PriceType] = "Index Price";
                withBlock[ColumnName.FixedPrice] = item.FixedPrice.GetValueOrDefault();

                withBlock[ColumnName.BrokerAccount] = item.BrokerAccount;
                withBlock[ColumnName.Book] = item.Book;
                withBlock[ColumnName.Portfolio] = item.Portfolio;
                withBlock[ColumnName.Strategy] = item.Strategy;
                withBlock[ColumnName.Region] = item.Region;
                withBlock[ColumnName.TotalFixedPrice] = item.FixedPrice.GetValueOrDefault() + item.Basis;
                withBlock[ColumnName.NymexExecutionFee] = item.NymexExecutionFee == null ? DBNull.Value : (object)item.NymexExecutionFee;
                withBlock[ColumnName.ExecutionMargin] = item.ExecutionMargin == null ? DBNull.Value : (object)item.ExecutionMargin;
                withBlock[ColumnName.SalesMargin] = item.SalesMargin == null ? DBNull.Value : (object)item.SalesMargin;
                withBlock[ColumnName.CommissionPerContract] = item.CommissionPerContract == null ? DBNull.Value : (object)item.CommissionPerContract;
                withBlock[ColumnName.TraderShortName] = item.TraderShortName == null ? DBNull.Value : (object)item.TraderShortName;
                withBlock[ColumnName.TraderName] = item.TraderName == null ? DBNull.Value : (object)item.TraderName;
                withBlock[ColumnName.Comments] = item.Comments;
                withBlock[ColumnName.InternalMemo] = item.InternalMemo;
                withBlock[ColumnName.IsFixed] = string.IsNullOrWhiteSpace(item.PriceIndex);
                withBlock[ColumnName.IsMonthlyIndex] = item.IsMonthlyIndex;
                withBlock[ColumnName.IsVolumeMonthly] = item.VolumeTypeId == 1;
            }
            dtMainData.Rows.Add(r);
        }

        FillSheet("Valuation Data", dtMainData);

        return GetNewFilterParams();
    }

    internal static string GetProductGroupName(int transactionTypeId, string transactionTypeName)
    {
        if (transactionTypeId == (int)Enums.TransactionType.PhysicalGas)
            return "Natural Gas";
        else if (transactionTypeId == (int)Enums.TransactionType.PhysicalCrudeOil)
            return "Crude Oil";
        else if (transactionTypeId == (int)Enums.TransactionType.PhysicalNGL)
            return "NGLs";
        else
            return transactionTypeName;
    }

    internal static string GetCustomerSupplyCaption(int transTypeId, bool isSupply, int? buyButton)
    {
        if (transTypeId == 1)
        {
            if (isSupply)
            {
                if (buyButton.GetValueOrDefault() == 1)
                    return "Supply Offset";
                else
                    return "Customer Offset";
            }
            else if (buyButton.GetValueOrDefault() == 1)
                return "Supply Deal";
            else
                return "Customer Deal";
        }
        else
            return "";
    }

    private CrudeData? GetDealCrudeData(string ContractNum, ILookup<string, CrudeData> crudeDataByContractNum, int? PointId, DateOnly positionDate)
    {
        if (string.IsNullOrWhiteSpace(ContractNum) || !crudeDataByContractNum.Contains(ContractNum))
            return null;

        CrudeData? result = null;
        var allDataForContract = crudeDataByContractNum[ContractNum].OrderBy(x => x.EffectiveDate).Where(x => x.EffectiveDate <= positionDate).ToList();
        List<CrudeData> specificPointCrudeData = PointId.HasValue ? allDataForContract.Where(x => x.PointIds.Contains(PointId.Value)).ToList() : new List<CrudeData>();
        List<CrudeData> anyPointCrudeData = allDataForContract.Where(x => x.PointIds.Count == 0).ToList();

        if (PointId.HasValue && specificPointCrudeData.Count > 0)
            result = specificPointCrudeData.Last();
        else if (anyPointCrudeData.Count > 0)
            result = anyPointCrudeData.Last();

        return result;
    }

    private DataTable InitValuationDataTable()
    {
        DataTable myDt = new();

        {
            var withBlock = myDt.Columns;
            withBlock.Add(ColumnName.TicketNum, typeof(string));
            withBlock.Add(ColumnName.BuyOrSell, typeof(string));
            withBlock.Add(ColumnName.CustomerOrSupply, typeof(string));
            withBlock.Add(ColumnName.TradeDate, typeof(DateOnly));
            withBlock.Add(ColumnName.PositionType, typeof(string));
            withBlock.Add(ColumnName.PositionMonth, typeof(DateOnly));
            withBlock.Add(ColumnName.PositionStartDate, typeof(DateOnly));
            withBlock.Add(ColumnName.PositionEndDate, typeof(DateOnly));
            withBlock.Add(ColumnName.DealStartDate, typeof(DateOnly));
            withBlock.Add(ColumnName.DealEndDate, typeof(DateOnly));
            withBlock.Add(ColumnName.Volume, typeof(double));
            withBlock.Add(ColumnName.MarketPrice, typeof(double));
            withBlock.Add(ColumnName.ContractPrice, typeof(double));
            withBlock.Add(ColumnName.OurContractNum, typeof(string));
            withBlock.Add(ColumnName.TheirContractNum, typeof(string));
            withBlock.Add(ColumnName.PriceCM, typeof(double));
            withBlock.Add(ColumnName.PricePM, typeof(double));
            withBlock.Add(ColumnName.Price2M, typeof(double));
            withBlock.Add(ColumnName.Price3M, typeof(double));
            withBlock.Add(ColumnName.PriceAG1, typeof(double));
            withBlock.Add(ColumnName.PriceAG2, typeof(double));
            withBlock.Add(ColumnName.BD1, typeof(int));
            withBlock.Add(ColumnName.BD2, typeof(int));
            withBlock.Add(ColumnName.BDT, typeof(int));
            withBlock.Add(ColumnName.PipeLossPercent, typeof(double));
            withBlock.Add(ColumnName.Differential, typeof(double));
            withBlock.Add(ColumnName.IsDiffBeforePipeLoss, typeof(bool));
            withBlock.Add(ColumnName.InvoicePrice, typeof(double));
            withBlock.Add(ColumnName.IsPosted, typeof(bool));
            withBlock.Add(ColumnName.Basis, typeof(double));
            withBlock.Add(ColumnName.PremiumOrDiscount, typeof(double));
            withBlock.Add(ColumnName.PNL_MTM, typeof(double));
            withBlock.Add(ColumnName.Counterparty, typeof(string));
            withBlock.Add(ColumnName.CounterpartyNickname, typeof(string));
            withBlock.Add(ColumnName.TransactionType, typeof(string));
            withBlock.Add(ColumnName.ProductGroup, typeof(string));
            withBlock.Add(ColumnName.Pipeline, typeof(string));
            withBlock.Add(ColumnName.PipeShort, typeof(string));
            withBlock.Add(ColumnName.Point, typeof(string));
            withBlock.Add(ColumnName.Broker, typeof(string));
            withBlock.Add(ColumnName.PriceIndex, typeof(string));
            withBlock.Add(ColumnName.PriceIndex2, typeof(string));
            withBlock.Add(ColumnName.DealPurpose, typeof(string));
            withBlock.Add(ColumnName.DealType, typeof(string));
            withBlock.Add(ColumnName.InternalEntity, typeof(string));
            withBlock.Add(ColumnName.PriceType, typeof(string));
            withBlock.Add(ColumnName.FixedPrice, typeof(double));
            withBlock.Add(ColumnName.BrokerAccount, typeof(string));
            withBlock.Add(ColumnName.Book, typeof(string));
            withBlock.Add(ColumnName.Portfolio, typeof(string));
            withBlock.Add(ColumnName.Strategy, typeof(string));
            withBlock.Add(ColumnName.Region, typeof(string));
            withBlock.Add(ColumnName.TotalFixedPrice, typeof(double));
            withBlock.Add(ColumnName.NymexExecutionFee, typeof(double));
            withBlock.Add(ColumnName.ExecutionMargin, typeof(double));
            withBlock.Add(ColumnName.SalesMargin, typeof(double));
            withBlock.Add(ColumnName.MasterTicketNum, typeof(string));
            withBlock.Add(ColumnName.TraderShortName, typeof(string));
            withBlock.Add(ColumnName.TraderName, typeof(string));
            withBlock.Add(ColumnName.CommissionPerContract, typeof(double));
            withBlock.Add(ColumnName.IsFixed, typeof(bool));
            withBlock.Add(ColumnName.IsMonthlyIndex, typeof(bool));
            withBlock.Add(ColumnName.IsVolumeMonthly, typeof(bool));
            withBlock.Add(ColumnName.Comments, typeof(string));
            withBlock.Add(ColumnName.InternalMemo, typeof(string));
        }
        return myDt;
    }

    private class ColumnName
    {
        public const string TicketNum = "TicketNum";
        public const string MasterTicketNum = "Master TicketNum";
        public const string BuyOrSell = "Buy/Sell";
        public const string CustomerOrSupply = "Customer/Supply";
        public const string TradeDate = "Trade Date";
        public const string PositionMonth = "Position Month";
        public const string PositionStartDate = "Position Start Date";
        public const string PositionEndDate = "Position End Date";
        public const string DealStartDate = "Deal Start Date";
        public const string DealEndDate = "Deal End Date";
        public const string Volume = "Volume";
        public const string MarketPrice = "Market Price";
        public const string ContractPrice = "Contract Price";
        public const string OurContractNum = "Our Contract #";
        public const string TheirContractNum = "Their Contract #";
        public const string PriceCM = "CM Price";
        public const string PricePM = "PM Price";
        public const string Price2M = "2M Price";
        public const string Price3M = "3M Price";
        public const string PriceAG1 = "AG1 Price";
        public const string PriceAG2 = "AG2 Price";
        public const string BD1 = "BD1";
        public const string BD2 = "BD2";
        public const string BDT = "BDT";
        public const string PipeLossPercent = "PLA %";
        public const string Differential = "Differential";
        public const string IsDiffBeforePipeLoss = "Diff before PLA?";
        public const string InvoicePrice = "Invoice Price";
        public const string IsPosted = "Is Posted";
        public const string Basis = "Basis";
        public const string PremiumOrDiscount = "Premium or Discount";
        public const string PNL_MTM = "MTM";
        public const string Counterparty = "Counterparty";
        public const string CounterpartyNickname = "Counterparty Nickname";
        public const string TransactionType = "Transaction Type";
        public const string ProductGroup = "Product Group";
        public const string Pipeline = "Pipeline";
        public const string PipeShort = "Pipe Short";
        public const string Point = "Point";
        public const string Broker = "Broker";
        public const string PriceIndex = "Price Index";
        public const string PriceIndex2 = "Price Index 2";
        public const string DealPurpose = "Deal Purpose";
        public const string DealType = "Deal Type";
        public const string InternalEntity = "Internal Entity";
        public const string PriceType = "Price Type";
        public const string FixedPrice = "Fixed Price";
        public const string PositionType = "Position Type";
        public const string BrokerAccount = "Broker Account";
        public const string Book = "Book";
        public const string Portfolio = "Portfolio";
        public const string Strategy = "Strategy";
        public const string Region = "Region";
        public const string TotalFixedPrice = "Total Fixed Price";
        public const string NymexExecutionFee = "Nymex Execution Fee";
        public const string ExecutionMargin = "Execution Margin";
        public const string SalesMargin = "Sales Margin";
        public const string CommissionPerContract = "Commission Per Contract";
        public const string TraderShortName = "Trader Short Name";
        public const string TraderName = "Trader Name";
        public const string IsFixed = "Is Fixed";
        public const string IsMonthlyIndex = "Is Monthly Index";
        public const string IsVolumeMonthly = "Is Volume Monthly";
        public const string Comments = "Comments";
        public const string InternalMemo = "Internal Memo";
    }
}
