public void Calculate_GST_Value()
        {
            // Arrange
            decimal total = 1000.00m;

            // Act
            decimal gstValue = FinancialCalculations.CalculateGSTValueFromTotalGross(total);

            // Assert
            Assert.AreEqual(130.43m, gstValue);
        }
        /// <summary>
        /// Extracts expense data from a block of text
        /// </summary>
        /// <param name="text">Text to process</param>
        /// <param name="cancellationToken">Default cancellation token</param>
        /// <returns></returns>
        public async Task <ExpenseResourceModel> ExtractExpenseAsync(string text, CancellationToken cancellationToken = default)
        {
            ExpenseResourceModel resourceModel = new ExpenseResourceModel();

            await Task.Run(() =>
            {
                if (string.IsNullOrEmpty(text))
                {
                    throw new EmailProcessingException("Text block can not be empty");
                }

                // Load the email text as html doc
                HtmlDocument htmlDocument = new HtmlDocument();
                htmlDocument.LoadHtml(text);

                // Detect tags that are not closed
                if (htmlDocument.ContainsUnclosedTags())
                {
                    throw new UnclosedTagException("Block of text has unclosed tag(s)");
                }

                // Extract data
                HtmlNode expenseNode = htmlDocument.DocumentNode.SelectSingleNode("//expense");
                if (expenseNode == null)
                {
                    throw new EmailProcessingException("Expense element does not exist or is invalid");
                }

                if (expenseNode.HasChildNodes)
                {
                    HtmlNode costCentre    = expenseNode.SelectSingleNode("//cost_centre");
                    HtmlNode total         = expenseNode.SelectSingleNode("//total");
                    HtmlNode paymentMethod = expenseNode.SelectSingleNode("//payment_method");

                    if (total == null)
                    {
                        throw new MissingElementException("Total node is required");
                    }

                    decimal totalValue = decimal.Parse(total.InnerText, CultureInfo.InvariantCulture);

                    resourceModel.CostCentre        = costCentre != null ? costCentre.InnerText : "UNKNOWN";
                    resourceModel.Total             = totalValue;
                    resourceModel.PaymentMethod     = paymentMethod.InnerText;
                    resourceModel.TotalExcludingGST = FinancialCalculations.CalculateTotalNetFromTotalGross(totalValue);
                    resourceModel.GSTValue          = FinancialCalculations.CalculateGSTValueFromTotalGross(totalValue);
                }
            }, cancellationToken);

            return(resourceModel);
        }