ASP .NET Core - Gerenciador de Despesas Pessoais com Gráfico (EF Core) - II


 Hoje vamos criar uma aplicação ASP .NET Core para fazer o gerenciamento de despesas pessoais e exibir um gráfico das despesas usando os recursos do Entity Framework Core 2.0.    

Continuando a primeira parte do artigo vamos definir a interface com o usuário representada pelas Views que irão exibir as informações e interagir com o usuário.

Vamos criar 3 Views em uma pasta Despesa da aplicação :

  1. Index.cshtml
    Esta view vai exibir todos os dados das despesas e contém uma caixa de busca para um item particular e os botões para Editar e Excluir uma despesa.

     
  2. _despesaForm.cshtml
    Esta é uma partial view que contém o formulário para tratar a entrada do usuário. Ela será usasda para tratar as funcionalidades de adicionar e editar e será exibida como um diálogo modal.

     
  3. _despesaReport.cshtml
    É uma partial view que vai exibir um resumo das despesas em um gráfico de barras usando os recursos do HighCharts:

Então vamos ao trabalho...

Incluindo a view Index.cshtml

Clique com o botão direito do mouse no interior do método Action Index do controlador DespesaController, e selecione Add View;

Na janela Add MVC view aceite os valores padrão conforme abaixo e clique no botão Add;

Será criada a view Index.cshtml dentro da pasta Views/Despesa do projeto.

Inclua o código abaixo nesta view:

@model IEnumerable<MinhasFinancas.Models.RelatorioDespesa>
@{
    ViewData["Title"] = "Gerenciandor de Finanças Pessoal";
}
<link href="~/lib/bootstrap/dist/css/bootstrap.css" rel="stylesheet" />
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/js/bootstrap-datepicker.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.css" rel="stylesheet">
<h2>Minhas Finanças</h2>
<br />
<div>
    <div style="float:left">
        <button class="btn btn-primary" onclick="AddEditDespesa(0)">Adicionar Despesa</button>
        <button class="btn btn-success" onclick="ReportDespesa()">Relatório Despesas</button>
    </div>
    <div style="float:right; width:40%;">
        <form asp-controller="Despesa" asp-action="Index" class="form-group">
            <div class="col-sm-6">
                <input class="form-control" type="text" name="criterio" placeholder="Procurar">
            </div>
            <button type="submit" class="btn btn-default btn-info">Filtrar</button>
        </form>
    </div>
</div>
<br />
<br />
<table class="table">
    <thead>
        <tr>
            <th>@Html.DisplayNameFor(model => model.ItemId)</th>
            <th>@Html.DisplayNameFor(model => model.ItemNome)</th>
            <th>@Html.DisplayNameFor(model => model.Valor)</th>
            <th>@Html.DisplayNameFor(model => model.DataDespesa)</th>
            <th>@Html.DisplayNameFor(model => model.Categoria)</th>
            <th>Action Item</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>@Html.DisplayFor(modelItem => item.ItemId)</td>
                <td>@Html.DisplayFor(modelItem => item.ItemNome)</td>
                <td>@Html.DisplayFor(modelItem => item.Valor)</td>
                <td>@Html.DisplayFor(modelItem => item.DataDespesa)</td>
                <td>@Html.DisplayFor(modelItem => item.Categoria)</td>
                <td>
                    <button class="btn btn-default" onclick="AddEditDespesa(@item.ItemId)">Editar</button>
                    <button class="btn btn-danger" onclick="DeleteDespesa(@item.ItemId)">Deletar</button>
                </td>
            </tr>
        }
    </tbody>
</table>
<div class="modal fade" id="despesaFormModel" role="dialog">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <a href="#" class="close" data-dismiss="modal">×</a>
                <h3 id="title" class="modal-title">Adicionar Despesa</h3>
            </div>
            <div class="modal-body" id="despesaFormModelDiv">
            </div>
        </div>
    </div>
</div>
<div class="modal fade" id="despesaReportModal" role="dialog">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <a href="#" class="close" data-dismiss="modal">×</a>
                <h3 class="modal-title">Relatório de Despesas</h3>
            </div>
            <div class="modal-body" id="despesaReportModalDiv">
            </div>
        </div>
    </div>
</div>
<script>
    var AddEditDespesa = function (itemId) {
        var url = "/Despesa/AddEditDespesa?itemId=" + itemId;
        if (itemId > 0)
            $('#title').html("Edita Despesa");
        $("#despesaFormModelDiv").load(url, function () {
            $("#despesaFormModel").modal("show");
        });
        $('#despesaFormModel').on('shown.bs.modal', function () {
            $('#calender-container .input-group.date').datepicker({
                todayBtn: true,
                calendarWeeks: true,
                todayHighlight: true,
                format: 'dd/mm/yyyy',
                autoclose: true,
                container: '#despesaFormModel modal-body'
            });
        });
    }
    var ReportDespesa = function () {
        var url = "/Despesa/DespesaResumo";
        $("#despesaReportModalDiv").load(url, function () {
            $("#despesaReportModal").modal("show");
        })
    }
    var DeleteDespesa = function (itemId) {
        var resp = confirm("Deseja deletar a despesa : " + itemId);
        if (resp) {
            $.ajax({
                type: "POST",
                url: "/Despesa/Delete/" + itemId,
                success: function () {
                    window.location.href = "/Despesa/Index";
                }
            })
        }
    }
</script>
<script>
    $('body').on('click', "#btnSubmit", function () {
        var myformdata = $("#despesaForm").serialize();
        $.ajax({
            type: "POST",
            url: "/Despesa/Create",
            data: myformdata,
            success: function () {
                $("#myModal").modal("hide");
                window.location.href = "/Despesa/Index";
            },
            error: function (errormessage) {
                alert(errormessage.responseText);
            }
        })
    })
</script>

Vamos entender o código acima:

No início da view incluímos as referências bootstrap e jQuery. Depois disso, adicionamos dois botões para adicionar uma nova despesa e para criar o resumo de despesas. Incluímos também um formulário contendo uma caixa de pesquisa para filtrar os registros. Ao clicar no botão "Filtrar", o formulário é enviado e ele invoca o método Index em nosso controlador, que retornará os itens que correspondem aos critérios de pesquisa. A funcionalidade de pesquisa é fornecida apenas no campo do nome do item.

Estamos usando uma tabela para exibir todos os registros de despesas em nosso banco de dados e cada registro tem dois botões de ação correspondentes - Editar e Excluir.

Também criamos dois diálogos modais, um para adicionar/editar os dados de despesas e outro para exibir o relatório de resumo de despesas.

Na seção de script, definimos a função AddEditDespesa que será invocada quando o botão “Adicionar Despesa” ou “Editar” for clicado. Estamos passando o itemId como parâmetro nesse método. Se o valor “ItemId” não for definido, será considerado como uma operação para Adicionar e se o “ItemId” estiver definido, é será considerado uma operação para Editar.

Vamos invocar “AddEditDespesa” em nosso controlador que retornará a  partial view  “_despesaForm” e vinculará ao modelo RelatorioDespesa. O modal ficará vazio para a chamada “Adicionar” e conterá os dados do item de despesa no caso da chamada “Editar”. Estamos usando também o bootstrap datepicker para selecionar a data da despesa, portanto, definimos as propriedades do datepicker na carga de diálogo modal.

A função ReportDespesa vai chamar o método DespesaResumo em nosso controlador, que retornará a partial view “_despesaReport” para ser exibida como um diálogo modal. Essa view parcial vai exibir  o gráfico de resumo de despesas mensal e semanal usando o Highcharts.

A função DeleteDespesa é usada para excluir o registro de uma despesa específica. Ela vai o método "Excluir" em nosso controlador para remover o registro de despesas do nosso banco de dados.

Também estamos usando a vinculação dinâmica para vincular o evento de envio do modal “despesaForm”. Este formulário é definido na exibição “_despesaForm.cshtml”. Ao enviar o formulário, estamos invocando uma chamada ajax para o método "Create" em nossa classe controladora. Como estamos usando o mesmo formato para a funcionalidade Editar e Adicionar, precisamos distinguir entre os dois usando o valor ItemId.

No método “Create” do controller, vamos verificar se o ItemId está configurado, então vamos invocar o método UpdateDespesa, caso contrário, vamos invocar o método AddDespesa. Após o envio ser bem-sucedido, fecharemos o modal e redirecionaremos para a view Index para mostrar a lista atualizada de despesas.

Incluindo a partial view _despesaForm

Esta partial view exibe um diálogo model quando o botão - Adicionar Despesa - da view Index, for clicado.

Clique com o botão direito do mouse sobre a pasta Despesa dentro da pasta Views, e, a seguir clique em Add -> View;

Na janela Add MVC View informe o nome _despesaForm e marque - Create as partial view - conforme mostrado a seguir, e clique em Add:

A seguir inclua o código abaixo nesta partial view:

@model MinhasFinancas.Models.RelatorioDespesa
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.3.0/js/bootstrap-datepicker.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.8.0/css/bootstrap-datepicker.css" rel="stylesheet">
<div>
    <div class="row">
        <div class="col-md-8">
            <form id="despesaForm">
                <input type="hidden" asp-for="ItemId" />
                <div class="form-group">
                    <label asp-for="ItemNome" class="control-label"></label>
                    <input asp-for="ItemNome" class="form-control" />
                </div>
                <div class="form-group">
                    <label asp-for="Categoria" class="control-label"></label>
                    <select asp-for="Categoria" class="form-control">
                        <option value="">-- Selecione a Categoria --</option>
                        <option value="Alimentacao">Alimentação</option>
                        <option value="Compras">Compras</option>
                        <option value="Transporte">Transporte</option>
                        <option value="Saude">Saúde</option>
                        <option value="Moradia">Moradia</option>
                        <option value="Lazer">Lazer</option>
                    </select>
                </div>
                <div class="form-group">
                    <label asp-for="Valor" class="control-label"></label>
                    <input asp-for="Valor" class="form-control" />
                </div>
                <div class="form-group" id="calender-container">
                    <label asp-for="DataDespesa" class="control-label"></label>
                    <div class="input-group date">
                        <input asp-for="DataDespesa" type="text" class="form-control"><span class="input-group-addon">
                        <i class="glyphicon glyphicon-calendar"></i></span>
                    </div>
                </div>
                <div class="form-group">
                    <button type="button" id="btnSubmit" class="btn btn-block btn-info">Salvar</button>
                </div>
            </form>
        </div>
    </div>
</div>

No código desta partial view, no início estamos incluindo a referência cdn para o bootstrap-datepicker, para que possamos usá-lo em nossa caixa de diálogo modal. Então nós temos um elemento de formulário, que se liga ao nosso modal. Também temos um botão de envio que postará os dados do formulário para o método Create em nosso controlador usando a chamada ajax.

Incluindo a partial view _despesaReport

Vamos criar agora a partial view _despesaReport que exibirá a caixa de diálogo model quando o botão - Relatório Despesas , da view Index, for clicado.

Clique com o botão direito do mouse sobre a pasta Despesa dentro da pasta Views, e, a seguir clique em Add -> View;

Na janela Add MVC View informe o nome _despesaReport e marque - Create as partial view - conforme mostrado a seguir, e clique em Add:

A seguir inclua o código abaixo nesta partial view:

<script src="https://code.highcharts.com/highcharts.js"></script>
<button id="btnReportMensal" class="btn btn-info">Relatório Mensal</button>
<button id="btnReportSemanal" class="btn btn-warning">Relatório Semanal</button>
<div id="container" style="min-width: 400px; height: 400px; margin: 0 auto"></div>
<script>
        $(document).ready(function () {
            $("#btnReportSemanal").click(function () {
                var titulomensagem = "Despesa semanal : ";
                $.ajax({
                    type: "GET",
                    url: "/Despesa/GetDepesaPorPeriodoSemanal",
                    contentType: "application/json",
                    dataType: "json",
                    success: function (result) {
                        var keys = Object.keys(result);
                        var datasemanal = new Array();
                        var totalgasto = 0.0;
                        for (var i = 0; i < keys.length; i++) {
                            var arrL = new Array();
                            arrL.push(keys[i]);
                            arrL.push(result[keys[i]]);
                            totalgasto += result[keys[i]];
                            datasemanal .push(arrL);
                        }
                        createCharts(datasemanal , titulomensagem , totalgasto.toFixed(2));
                    }
                })
            })
            $("#btnReportMensal").click(function () {
                var titulomensagem = "Despesa semestral : ";
                $.ajax({
                    type: "GET",
                    url: "/Despesa/GetDepesaPorPeriodo",
                    contentType: "application/json",
                    dataType: "json",
                    success: function (result) {
                        var keys = Object.keys(result);
                        var datamensal = new Array();
                        var totalgasto = 0.0;
                        for (var i = 0; i < keys.length; i++) {
                            var arrL = new Array();
                            arrL.push(keys[i]);
                            arrL.push(result[keys[i]]);
                            totalgasto += result[keys[i]];
                            datamensal .push(arrL);
                        }
                        createCharts(datamensal , titulomensagem , totalgasto.toFixed(2));
                    }
                })
            })
        })
        function createCharts(soma, tituloTexto, totalgasto) {
            Highcharts.chart('container', {
                chart: {
                    type: 'column'
                },
                title: {
                    text: tituloTexto + ' ' + totalgasto
                },
                xAxis: {
                    type: 'category',
                    labels: {
                        rotation: -45,
                        style: {
                            fontSize: '13px',
                            fontFamily: 'Verdana, sans-serif'
                        }
                    }
                },
                yAxis: {
                    min: 0,
                    title: {
                        text: 'Valor Despesas'
                    }
                },
                legend: {
                    enabled: false
                },
                tooltip: {
                    pointFormat: 'Total despesas: <b>{point.y:.2f} </b>'
                },
                series: [{
                    type: 'column',
                    data: soma,
                }]
            });
        }
</script>

No início do código incluímos a referência cdn para usar o Highcharts. Também fornecemos dois botões para visualizar os relatórios mensais dos últimos seis meses e os relatórios semanais das últimas quatro semanas. O relatório será gerado como um gráfico de barras para fornecer um estudo comparativo dos resumos de despesas.

Ao clicar no botão de relatório semanal, invocaremos o método GetDepesaPorPeriodoSemanal do nosso controlador que retornará os dados no formato Json e passaremos isso para a função createCharts para criar o gráfico de barras de despesas semanais usando Highcharts.

Da mesma forma, invocaremos o método GetDepesaPorPeriodo de nosso controlador ao clicar no botão "Relatório mensal" e passaremos o resultado do Json para a função createCharts para criar o gráfico de barras de despesas mensal usando Highcharts.

Antes de executar a aplicação vamos alterar o roteamento definido no arquivo Startup, no método Configure,  para iniciar a execução chamando o método Index do controlador DespesaController:

...

  app.UseMvc(routes =>
  {
     routes.MapRoute(
     name: "default",
    template: "{controller=Despesa}/{action=Index}/{id?}");
 });
...

Agora é só alegria...

Executando o projeto iremos obter o seguinte resultado:

O código do projeto completo esta no módulo Bônus do  Curso de ASP .NET Core.

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti