wip - refactor sales report init - database update

This commit is contained in:
Frede Hundewadt 2022-06-12 18:20:19 +02:00
parent 2daf236c4a
commit ddfc22993f
14 changed files with 273 additions and 175 deletions

View file

@ -18,7 +18,15 @@
<PageTitle>Innotec Danmark A/S</PageTitle>
<WorkDateComponent OnChanged="FetchActivities"></WorkDateComponent>
<div class="row mb-1">
<div class="col-md-4">
<span class="workDate">@($"{DateTime.Parse(_workDate).ToLongDateString()}")</span>
</div>
<div class="col-md-4">
<WorkDateComponent OnChanged="FetchActivities"></WorkDateComponent>
</div>
</div>
<hr />
<h5>Dagens aktivitet</h5>

View file

@ -36,14 +36,14 @@ public partial class Home : IDisposable
[Inject] public IActivityHttpRepository ActivityRepo { get; set; }
private List<ReportActivityDto> Activities { get; set; }
private Preferences _prefs { get; set; } = new();
private string _workDate { get; set; } = "";
private string _workDate { get; set; } = $"{DateTime.Now:yyyy-MM-dd}";
protected override async Task OnInitializedAsync()
{
_prefs = await UserPrefs.GetPreferences();
_workDate = string.IsNullOrWhiteSpace(_prefs.WorkDate)
? $"{DateTime.Now:yyyy-MM-dd}"
: _prefs.WorkDate;
if(!string.IsNullOrWhiteSpace(_prefs.WorkDate))
_workDate = _prefs.WorkDate;
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();

View file

@ -0,0 +1,5 @@
.workDate {
font-size: 1.2em;
font-weight: bold;
font-variant: small-caps;
}

View file

@ -1,13 +1,5 @@
@using Blazored.LocalStorage
@using Wonky.Client.Services
<div class="row mb-1">
<div class="col-md-4">
<h5 class="fw-bold">@DateTime.Parse(_workDate).ToLongDateString()</h5>
</div>
<div class="col-md-4">
<input type="date" class="form-control"
@bind-Value="_workDate" @bind-Value:event="oninput"
@onchange="OnDateChanged" />
</div>
</div>
<input type="date" class="form-control"
@bind-Value="_selectedDate" @bind-Value:event="oninput" @onchange="OnDateChanged" />

View file

@ -11,14 +11,14 @@ public partial class WorkDateComponent : IDisposable
[Parameter] public EventCallback<string> OnChanged { get; set; }
private Preferences _prefs = new();
private string _workDate = $"{DateOnly.FromDateTime(DateTime.Now):yyyy-MM-dd}";
private string _selectedDate = $"{DateOnly.FromDateTime(DateTime.Now):yyyy-MM-dd}";
protected override async Task OnInitializedAsync()
{
UserPrefs.OnChange += ProfileServiceOnOnChange;
_prefs = await UserPrefs.GetPreferences();
_workDate = string.IsNullOrWhiteSpace(_prefs.WorkDate)
_selectedDate = string.IsNullOrWhiteSpace(_prefs.WorkDate)
? $"{DateOnly.FromDateTime(DateTime.Now):yyyy-MM-dd}"
: _prefs.WorkDate;
}

View file

@ -1,3 +0,0 @@
h5 {
font-variant: small-caps;
}

View file

@ -83,7 +83,7 @@ namespace Wonky.Client.HttpInterceptors
if (e.Response == null || e.Response.IsSuccessStatusCode)
return;
string? message;
string message;
var currDoc = _navigation.ToBaseRelativePath(_navigation.Uri);
switch (e.Response.StatusCode)
@ -96,15 +96,73 @@ namespace Wonky.Client.HttpInterceptors
case HttpStatusCode.BadRequest:
ClearInfo();
_navigation.NavigateTo($"/login/{currDoc}");
message = "Verifikation nødvendig ...";
message = "Login info skal fornyes ...";
_toast.ShowInfo(message);
break;
case HttpStatusCode.Unauthorized:
ClearInfo();
_navigation.NavigateTo($"/login/{currDoc}");
message = "Verifikation nødvendig ...";
message = "Login info skal fornyes ...";
_toast.ShowInfo(message);
break;
case HttpStatusCode.Continue:
case HttpStatusCode.SwitchingProtocols:
case HttpStatusCode.Processing:
case HttpStatusCode.EarlyHints:
case HttpStatusCode.OK:
case HttpStatusCode.Created:
case HttpStatusCode.Accepted:
case HttpStatusCode.NonAuthoritativeInformation:
case HttpStatusCode.NoContent:
case HttpStatusCode.ResetContent:
case HttpStatusCode.PartialContent:
case HttpStatusCode.MultiStatus:
case HttpStatusCode.AlreadyReported:
case HttpStatusCode.IMUsed:
case HttpStatusCode.Ambiguous:
case HttpStatusCode.Moved:
case HttpStatusCode.Found:
case HttpStatusCode.RedirectMethod:
case HttpStatusCode.NotModified:
case HttpStatusCode.UseProxy:
case HttpStatusCode.Unused:
case HttpStatusCode.RedirectKeepVerb:
case HttpStatusCode.PermanentRedirect:
case HttpStatusCode.PaymentRequired:
case HttpStatusCode.Forbidden:
case HttpStatusCode.MethodNotAllowed:
case HttpStatusCode.NotAcceptable:
case HttpStatusCode.ProxyAuthenticationRequired:
case HttpStatusCode.RequestTimeout:
case HttpStatusCode.Conflict:
case HttpStatusCode.Gone:
case HttpStatusCode.LengthRequired:
case HttpStatusCode.PreconditionFailed:
case HttpStatusCode.RequestEntityTooLarge:
case HttpStatusCode.RequestUriTooLong:
case HttpStatusCode.UnsupportedMediaType:
case HttpStatusCode.RequestedRangeNotSatisfiable:
case HttpStatusCode.ExpectationFailed:
case HttpStatusCode.MisdirectedRequest:
case HttpStatusCode.UnprocessableEntity:
case HttpStatusCode.Locked:
case HttpStatusCode.FailedDependency:
case HttpStatusCode.UpgradeRequired:
case HttpStatusCode.PreconditionRequired:
case HttpStatusCode.TooManyRequests:
case HttpStatusCode.RequestHeaderFieldsTooLarge:
case HttpStatusCode.UnavailableForLegalReasons:
case HttpStatusCode.InternalServerError:
case HttpStatusCode.NotImplemented:
case HttpStatusCode.BadGateway:
case HttpStatusCode.ServiceUnavailable:
case HttpStatusCode.GatewayTimeout:
case HttpStatusCode.HttpVersionNotSupported:
case HttpStatusCode.VariantAlsoNegotiates:
case HttpStatusCode.InsufficientStorage:
case HttpStatusCode.LoopDetected:
case HttpStatusCode.NotExtended:
case HttpStatusCode.NetworkAuthenticationRequired:
default: _navigation.NavigateTo("/500");
message = "500 - Intern server fejl";
break;

View file

@ -15,132 +15,155 @@
//
*@
@using Microsoft.AspNetCore.Authorization
@using Wonky.Client.Helpers
@using Wonky.Client.Components
@attribute [Authorize(Roles = "Adviser")]
@page "/sales-report"
<div>workDate: @_workDate</div>
<div>checkIn: @_reportDto.CheckIn</div>
<div>checkOut: @_reportDto.CheckOut</div>
<EditForm EditContext="_editContext">
<div class="card">
<div class="card-header">
<h3>Dagsrapport</h3>
<div class="row">
<div class="col">
<div class="h5" style="font-variant: small-caps">Dagsrapport @(_reportDto.CheckIn.ToLongDateString())</div>
</div>
<div class="col">
<WorkDateComponent OnChanged="SetWorkDate"></WorkDateComponent>
</div>
</div>
</div>
<div class="card-body">
<table class="table">
<thead>
<th scope="col">Dag Type</th>
<th scope="col">Dag Begyndt</th>
<th scope="col">Dag Afsluttet</th>
<tr>
<th scope="col">Aktivitet</th>
<th scope="col">Begyndt</th>
<th scope="col">Afsluttet</th>
@if (!_reportDto.DayTypeEnum.ToLower().Contains("leave"))
{
<th></th>
}
</tr>
</thead>
<tbody>
<tr>
<td>
<select id="dayType" class="col-md-3 form-select"
@bind-Value="_reportDto.DayTypeEnum" @bind-Value:event="oninput" @onchange="CheckDayType">
<option value="" selected disabled="">"IKKE VALGT"</option>
<option value="sales">Salgsdag</option>
<select id="dayType" class="col-md-3 form-select"
@bind-Value="_reportDto.DayTypeEnum" @bind-Value:event="oninput">
<option value="sales" selected>Salgsdag</option>
<option value="meeting">Salgsmøde</option>
<option value="office">Kontordag</option>
<option value="supervisor">Supervisor</option>
<option value="sickLeave">Sygdom</option>
<option value="leave">Ferie</option>
</select>
<ValidationMessage For="@(() => _reportDto.DayTypeEnum)"></ValidationMessage>
</td>
<td>
<InputDateTime id="checkIn" class="form-control" @bind-Value="_reportDto.CheckIn"></InputDateTime>
<ValidationMessage For="@(() => _reportDto.CheckIn)"></ValidationMessage>
</td>
<td>
<InputDateTime id="checkOut" class="form-control" @bind-Value="_reportDto.CheckOut"></InputDateTime>
<ValidationMessage For="@(() => _reportDto.CheckOut)"></ValidationMessage>
<ValidationMessage For="@(() => _reportDto.DayTypeEnum)" />
</td>
@if (_reportDto.DayTypeEnum.ToLower().Contains("leave"))
{
<td>
<InputDate class="form-control"
@bind-Value="_leaveBegin" @bind-Value:event="oninput" @onchange="OnLeaveChanged"/>
</td>
<td>
<InputDate class="form-control"
@bind-Value="_leaveEnd" @bind-Value:event="oninput" @onchange="OnLeaveChanged"/>
</td>
}
else
{
<td>
<input type="time" id="checkIn" class="form-control"
@bind-Value="_timestampIn" @bind-Value:event="oninput" @onchange="OnTimeChanged"/>
</td>
<td>
<input type="time" id="checkOut" class="form-control"
@bind-Value="_timestampOut" @bind-Value:event="oninput" @onchange="OnTimeChanged"/>
</td>
<th>
<button type="button" class="btn btn-info" @onclick="GetActivities">Hent Besøg</button>
</th>
}
</tr>
</tbody>
</table>
</div>
<div class="card-body">
<div class="form-group row mb-1">
<label for="supervisedBy" class="col-form-label col-md-2">Supervisor</label>
<div class="col-md-4">
<InputText id="supervisedBy" class="form-control" @bind-Value="_reportDto.SupervisedBy"/>
<ValidationMessage For="@(() => _reportDto.SupervisedBy)"></ValidationMessage>
</div>
</div>
<div class="form-group row mb-1">
<label for="description" class="col-form-label col-md-2">Beskrivelse</label>
<div class="col-md-4">
<InputTextArea id="description" class="form-control" @bind-Value="_reportDto.Description"/>
<ValidationMessage For="@(() => _reportDto.Description)"></ValidationMessage>
</div>
</div>
</div>
<div class="card-body">
<table class="table">
<thead>
<th scope="col">Km Morgen</th>
<th scope="col">Km Aften</th>
<th scope="col">Km Kørt</th>
<th scope="col">Km Privat</th>
</thead>
<tbody>
<tr>
<td>
<InputNumber id="kmMorning" class="form-control" @bind-Value="_reportDto.KmMorning"/>
<ValidationMessage For="@(() => _reportDto.KmMorning)"></ValidationMessage>
</td>
<td>
<InputNumber id="kmEvening" class="form-control" @bind-Value="_reportDto.KmEvening"/>
<ValidationMessage For="@(() => _reportDto.KmEvening)"></ValidationMessage>
</td>
<td>
<InputNumber id="distance" class="form-control" @bind-Value="_reportDto.Distance" readonly=""/>
</td>
<td>
<InputNumber id="kmPrivate" class="form-control" @bind-Value="_reportDto.DistancePrivate"/>
<ValidationMessage For="@(() => _reportDto.DistancePrivate)"></ValidationMessage>
</td>
</tr>
</tbody>
</table>
</div>
<dic class="card-footer">
<div class="col-md-2">
<button type="button" class="btn btn-info" @onclick="GetActivities">Hent</button>
</div>
</dic>
</div>
</EditForm>
<hr/>
<h5>Besøg</h5>
@if (Activities != null)
{
<div class="card-list">
@foreach (var activity in Activities)
{
<div class="card">
<div class="card-header">
@activity.Company.Name - @activity.Company.ZipCity
</div>
<div class="card-body">
<div class="row">
<div class="col">
@activity.Demo
</div>
<div class="col">
@activity.SalesResume
</div>
<div class="col">
@activity.OrderAmount
</div>
@if (!_reportDto.DayTypeEnum.ToLower().Contains("leave"))
{
<div class="form-group row mb-1">
<label for="supervisedBy" class="col-form-label col-md-2">Supervisor</label>
<div class="col-md-4">
<InputText id="supervisedBy" class="form-control" @bind-Value="_reportDto.SupervisedBy"/>
<ValidationMessage For="@(() => _reportDto.SupervisedBy)" />
</div>
<label for="description" class="col-form-label col-md-2">Beskrivelse</label>
<div class="col-md-4">
<InputTextArea id="description" class="form-control" @bind-Value="_reportDto.Description"/>
<ValidationMessage For="@(() => _reportDto.Description)" />
</div>
</div>
</div>
}
<table class="table">
<thead>
<tr>
<th scope="col">Km Morgen</th>
<th scope="col">Km Aften</th>
<th scope="col">Km Kørt</th>
<th scope="col">Km Privat</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<InputNumber class="form-control" @bind-Value="_reportDto.Figures.KmMorning"/>
<ValidationMessage For="@(() => _reportDto.Figures.KmMorning)" />
</td>
<td>
<InputNumber class="form-control" @bind-Value="_reportDto.Figures.KmEvening"/>
<ValidationMessage For="@(() => _reportDto.Figures.KmEvening)" />
</td>
<td>
<InputNumber class="form-control" @bind-Value="_reportDto.Figures.Distance" readonly=""/>
</td>
<td>
<InputNumber class="form-control" @bind-Value="_reportDto.Figures.DistancePrivate"/>
<ValidationMessage For="@(() => _reportDto.Figures.DistancePrivate)" />
</td>
</tr>
</tbody>
</table>
@if (_reportInit.Activities != null)
{
<div class="card-list">
@foreach (var activity in _reportInit.Activities)
{
<div class="card">
<div class="card-header">
@activity.Company.Name - @activity.Company.ZipCity
</div>
<div class="card-body">
<div class="row">
<div class="col">
@activity.Demo
</div>
<div class="col">
@activity.SalesResume
</div>
<div class="col">
@activity.OrderAmount
</div>
</div>
</div>
</div>
}
</div>
}
}
</div>
</div>
}
else
{
<AppSpinner></AppSpinner>
}
</EditForm>

View file

@ -13,6 +13,7 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using System.Runtime.Intrinsics;
using System.Text.Json;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
@ -29,12 +30,17 @@ public partial class SalesReport
[Inject] private HttpInterceptorService Interceptor { get; set; }
[Inject] private UserPreferenceService UserPrefs { get; set; }
[Inject] private IActivityHttpRepository ActivityRepo { get; set; }
[Inject] private IReportHttpRepository ReportRepo { get; set; }
private EditContext _editContext { get; set; }
private ReportDto _reportDto = new();
private ReportDto _reportDto { get; set; } = new();
private NgSalesReportInitDto _reportInit { get; set; } = new();
private Preferences _prefs { get; set; } = new();
private bool _formInvalid = true;
private List<ReportActivityDto>? Activities { get; set; } = new();
private DateTime _workDate;
private DateTime _workDate { get; set; } = DateTime.Now;
private TimeOnly _timestampIn { get; set; } = new(12, 0);
private TimeOnly _timestampOut { get; set; } = new(12, 0);
private DateOnly _leaveBegin { get; set; } = DateOnly.FromDateTime(DateTime.Now);
private DateOnly _leaveEnd { get; set; } = DateOnly.FromDateTime(DateTime.Now);
protected override async Task OnInitializedAsync()
{
Interceptor.RegisterEvent();
@ -44,18 +50,15 @@ public partial class SalesReport
_editContext.OnValidationStateChanged += ValidationChanged;
_prefs = await UserPrefs.GetPreferences();
_workDate =string.IsNullOrWhiteSpace(_prefs.WorkDate)
? DateTime.Now
: DateTime.Parse(_prefs.WorkDate);
if (!string.IsNullOrWhiteSpace(_prefs.WorkDate))
_workDate = DateTime.Parse(_prefs.WorkDate);
_leaveBegin = DateOnly.FromDateTime(_workDate);
_reportDto.CheckIn = new DateTime(_workDate.Year, _workDate.Month, _workDate.Day, 12, 0,0);
_reportDto.CheckOut = _reportDto.CheckIn;
await UserPrefs.SetWorkDate(_reportDto.CheckIn);
}
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
{
_reportDto.Distance = (int) (_reportDto.KmEvening - _reportDto.KmMorning);
_reportDto.Figures.Distance = (int) (_reportDto.Figures.KmEvening - _reportDto.Figures.KmMorning);
_formInvalid = !_editContext.Validate();
StateHasChanged();
}
@ -68,17 +71,47 @@ public partial class SalesReport
_editContext.OnFieldChanged += HandleFieldChanged;
_editContext.OnValidationStateChanged += ValidationChanged;
}
private void CheckDayType()
private async Task SubmitReport()
{
if (_reportDto.DayTypeEnum.ToLower().Contains("leave"))
{
_reportDto.CheckIn = new DateTime(_leaveBegin.Year, _leaveBegin.Month, _leaveBegin.Day, 0, 0, 0);
_reportDto.CheckOut = new DateTime(_leaveEnd.Year, _leaveEnd.Month, _leaveEnd.Day, 0, 0, 0);
}
else
{
_reportDto.CheckIn = _workDate.AddHours(_timestampIn.Hour).AddMinutes(_timestampIn.Minute);
_reportDto.CheckOut = _workDate.AddHours(_timestampOut.Hour).AddMinutes(_timestampOut.Minute);
}
}
private void OnLeaveChanged()
{
}
private void OnTimeChanged()
{
_reportDto.CheckIn = new DateTime(_workDate.Year, _workDate.Month, _workDate.Day, _timestampIn.Hour, _timestampIn.Minute,0);
_reportDto.CheckOut = new DateTime(_workDate.Year, _workDate.Month, _workDate.Day, _timestampOut.Hour, _timestampOut.Minute,0);
}
private void SetWorkDate(string workDate)
{
_workDate = DateTime.Parse(workDate);
_reportDto.CheckIn = new DateTime(_workDate.Year, _workDate.Month, _workDate.Day, 12, 0,0);
_reportDto.CheckOut = new DateTime(_workDate.Year, _workDate.Month, _workDate.Day, 12, 0,0);
}
private async Task GetActivities()
{
Activities = null;
await UserPrefs.SetWorkDate(_reportDto.CheckIn);
Activities = await ActivityRepo
.GetActivities($"{_reportDto.CheckIn:yyyy-MM-dd}");
_prefs = await UserPrefs.GetPreferences();
_reportInit = await ReportRepo.FetchReportInit(_prefs.WorkDate);
_reportDto.Figures = _reportInit.Figures;
_reportDto.Figures.DistanceMonth = _reportInit.Figures.DistanceMonth + _reportDto.Figures.Distance;
_reportDto.Figures.DistancePrivateMonth = _reportInit.Figures.DistancePrivateMonth + _reportDto.Figures.DistancePrivate;
}
public void Dispose()

View file

@ -65,7 +65,7 @@
<div class="nav-item px-3">
<NavLink class="nav-link" href="info">
<span class="oi oi-info" aria-hidden="true"></span> App Info
<span class="oi oi-question-mark" aria-hidden="true"></span> Hjælp
</NavLink>
</div>
</Authorized>

View file

@ -18,7 +18,7 @@
},
"appInfo": {
"name": "Wonky Client",
"version": "0.5.5",
"version": "0.5.6",
"isBeta": true,
"image": "grumpy-coder.png"
},

View file

@ -4,7 +4,7 @@ namespace Wonky.Entity.DTO;
public class NgSalesReportInitDto
{
public ReportFiguresDto ReportFigures { get; set; } = new();
public ReportFiguresDto Figures { get; set; } = new();
public List<ReportActivityDto> Activities { get; set; } = new();
}

View file

@ -10,32 +10,5 @@ public class ReportDto
// Date interval (used for leave, sickLeave and work hours
public DateTime CheckIn { get; set; }
public DateTime CheckOut { get; set; }
// workday
public int VisitsNewCount { get; set; }
public int VisitsRecallCount { get; set; }
public int DemosNewCount { get; set; }
public int DemosRecallCount { get; set; }
public int SalesNewCount { get; set; }
public int SalesRecallCount { get; set; }
// workday turnover
public decimal SalesTurnover { get; set; }
public decimal SasTurnover { get; set; }
public decimal TotalTurnover { get; set; }
// workday distance ledger
public long KmEvening { get; set; }
public long KmMorning { get; set; }
public int Distance { get; set; }
public int DistancePrivate { get; set; }
// month summaries
public int DistanceMonth { get; set; }
public int VisitsNewMonth { get; set; }
public int VisitsRecallMonth { get; set; }
public int DemosNewMonth { get; set; }
public int DemosRecallMonth { get; set; }
public int SalesNewMonth { get; set; }
public int SalesRecallMonth { get; set; }
// month turnover
public decimal SalesTurnoverMonth { get; set; }
public decimal SasTurnoverMonth { get; set; }
public decimal TotalTurnoverMonth { get; set; }
public ReportFiguresDto Figures { get; set; } = new();
}

View file

@ -3,6 +3,11 @@ namespace Wonky.Entity.DTO;
public class ReportFiguresDto
{
public int SalesDayNumber { get; set; }
public long KmMorning { get; set; }
public long KmEvening { get; set; }
public int Distance { get; set; }
public int DistancePrivate { get; set; }
public int NewVisitCount { get; set; }
public int NewDemoCount { get; set; }
public int NewSaleCount { get; set; }
@ -10,7 +15,14 @@ public class ReportFiguresDto
public int RecallDemoCount { get; set; }
public int RecallSaleCount { get; set; }
public int SasCount { get; set; }
// turnover day
public decimal NewTurnover { get; set; }
public decimal RecallTurnover { get; set; }
public decimal SasTurnover { get; set; }
public decimal TotalTurnover { get; set; }
// month summaries
public int DistanceMonth { get; set; }
public int DistancePrivateMonth { get; set; }
public int NewVisitCountMonth { get; set; }
public int NewDemoCountMonth { get; set; }
public int NewSaleCountMonth { get; set; }
@ -18,10 +30,7 @@ public class ReportFiguresDto
public int RecallDemoCountMonth { get; set; }
public int RecallSaleCountMonth { get; set; }
public int SasCountMonth { get; set; }
public decimal NewTurnover { get; set; }
public decimal RecallTurnover { get; set; }
public decimal SasTurnover { get; set; }
public decimal TotalTurnover { get; set; }
// month turnover
public decimal NewTurnoverMonth { get; set; }
public decimal RecallTurnoverMonth { get; set; }
public decimal SasTurnoverMonth { get; set; }