This commit is contained in:
Frede Hundewadt 2022-09-06 17:30:26 +02:00
parent dda16f22ec
commit fdab3dc2bb
20 changed files with 295 additions and 78 deletions

View file

@ -0,0 +1,75 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
@if (Activities.Any())
{
<table class="table table-bordered d-print-table table-striped">
<thead>
<tr class="bg-dark text-white opacity-75 border-bottom">
<th scope="col">Kunde</th>
<th scope="col">Bynavn</th>
<th scope="col">Demo</th>
<th scope="col">Salg</th>
<th scope="col">Note</th>
<th class="text-end" scope="col">sas</th>
<th class="text-end" scope="col">Beløb</th>
<th class="text-center" scope="col"><i class="oi oi-phone"></i></th>
<th class="text-center" scope="col"><i class="oi oi-flash"></i></th>
<th class="text-center" scope="col"><i class="oi oi-calculator"></i></th>
<th class="text-center" scope="col"><i class="bi bi-box"></i></th>
</tr>
</thead>
<tbody>
@foreach (var activity in Activities)
{
<tr>
<td class="align-middle"><a href="/companies/@activity.Company.CompanyId/orders/@activity.ActivityId">@activity.Company.Name</a></td>
<td class="align-middle">@activity.Company.City</td>
<td class="align-middle">@activity.Demo</td>
<td class="align-middle">@activity.Sales</td>
<td class="align-middle">@activity.OfficeNote</td>
<td class="align-middle text-end">@($"{activity.SasAmount:N2}")</td>
<td class="align-middle text-end">@(activity.StatusTypeEnum == "Quote" ? $"{0:N2}" : $"{activity.OrderAmount:N2}")</td>
<td class="align-middle text-center">
@if (activity.OurRef.Contains("T:"))
{<i class="oi oi-phone"></i>}
</td>
<td class="align-middle text-center">
@if (activity.Express)
{<i class="oi oi-flash"></i>}
</td>
<td class="align-middle text-end">
@if (activity.StatusTypeEnum == "Quote")
{<i class="oi oi-calculator"></i>}
</td>
<td class="align-middle state">
@if (activity.Lines.Any())
{
<ProcessStateComponent StateClass="@GetProcessStatus(activity.ProcessStatusEnum)"/>
}
</td>
</tr>
}
<tr>
<td colspan="5" class="bg-light"></td>
<td class="align-middle text-center">Total</td>
<td class="align-middle text-end">@Activities.Where(x => x.StatusTypeEnum == "Order").Sum(x => x.OrderAmount)</td>
<td colspan="4" class="bg-light"></td>
</tr>
</tbody>
</table>
}

View file

@ -13,33 +13,30 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html] // along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
// //
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors; using Wonky.Entity.Views;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.HttpRepository;
using Wonky.Entity.DTO;
namespace Wonky.Client.Components; namespace Wonky.Client.Components;
public partial class OrderCreateComponent : IDisposable public partial class AdvisorActivityTableComponent
{ {
[Parameter] public string CustomerId { get; set; } = ""; [Parameter] public List<ReportItemView> Activities { get; set; }
[Inject] private NavigationManager _navigator { get; set; }
[Inject] private ICompanyHttpRepository _companyRepo { get; set; } private static string GetProcessStatus(string processStatus)
[Inject] private HttpInterceptorService _interceptor { get; set; }
private CompanyDto _company { get; set; }
protected override async Task OnParametersSetAsync()
{ {
_interceptor.RegisterEvent(); return processStatus.ToLower() switch
_interceptor.RegisterBeforeSendEvent(); {
_company = await _companyRepo.GetCompanyById(CustomerId); "none" => "the-ugly-fg",
"picked" => "the-bad-fg",
"packed" => "the-good-fg",
"shipped" => "the-draw-fg",
_ => "the-dead"
};
} }
public void Dispose() private void ShowOrder(string companyId, string orderId)
{ {
_interceptor.DisposeEvent(); _navigator.NavigateTo($"office/customers/{companyId}/orders/{orderId}");
} }
} }

View file

@ -33,5 +33,4 @@
</div> </div>
<TaskItemTableComponent TaskItemList="_taskItems" OnCompleteTask="OnCompleteTask" <TaskItemTableComponent TaskItemList="_taskItems" OnCompleteTask="OnCompleteTask"
OnDeleteTask="OnDeleteConfirmed" OnTaskCompleted="OnTaskCompleted" /> OnDeleteTask="OnDeleteConfirmed" OnTaskCompleted="OnTaskCompleted" />
</AuthorizeView>
</AuthorizeView>

View file

@ -18,7 +18,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Components; namespace Wonky.Client.Components;
public partial class ActivityTableComponent public partial class OfficeActivityTableComponent
{ {
[Parameter] public List<ReportItemView> Activities { get; set; } [Parameter] public List<ReportItemView> Activities { get; set; }
[Inject] private NavigationManager _navigator { get; set; } [Inject] private NavigationManager _navigator { get; set; }

View file

@ -48,8 +48,8 @@
<a class=" list-group-item list-group-item-action" href="#"> <a class=" list-group-item list-group-item-action" href="#">
<div class="row align-items-center"> <div class="row align-items-center">
<div class="col-sm-1 col-md-1"> <div class="col-sm-1 col-md-1">
<DisplayStateComponent StateClass="@(company.HasFolded == 1 ? "the-dead" : Utils.GetVisitState(company.NextVisit))"> <DisplayStateComponent
</DisplayStateComponent> StateClass="@(company.HasFolded == 1 ? "the-dead" : Utils.GetVisitState(company.NextVisit))" />
</div> </div>
<div class="col"> <div class="col">
@company.Name @company.Name

View file

@ -1,22 +0,0 @@
@*
// Copyright (C) 2022 FCS Frede's Computer Services.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
*@
<h3>OrderCreateComponent</h3>
@code {
}

View file

@ -26,4 +26,5 @@ public interface IActivityHttpRepository
Task<ApiResponseView> AcceptOffer(string id); Task<ApiResponseView> AcceptOffer(string id);
Task<ReportStatusView> GetActivities(string activityDate); Task<ReportStatusView> GetActivities(string activityDate);
Task<List<ReportItemView>> GetCustomerActivities(string customerId); Task<List<ReportItemView>> GetCustomerActivities(string customerId);
Task UpdateOfficeNote(ActivityOfficeNote model);
} }

View file

@ -55,6 +55,12 @@ public class ActivityHttpRepository : IActivityHttpRepository
_apiConfig = configuration.Value; _apiConfig = configuration.Value;
} }
public async Task UpdateOfficeNote(ActivityOfficeNote model)
{
_logger.LogDebug("UpdateOfficeNote => model \n{}", JsonSerializer.Serialize(model) );
_logger.LogDebug("UpdateOfficeNote => url \n{}", $"{_apiConfig.CrmSale}/activity/{model.ActivityId}" );
await _client.PostAsJsonAsync($"{_apiConfig.CrmSale}/activity/{model.ActivityId}", model, _options);
}
public async Task<ReportStatusView> GetActivities(string activityDate) public async Task<ReportStatusView> GetActivities(string activityDate)
{ {
var response = await _client var response = await _client

View file

@ -28,7 +28,7 @@
<WorkDateComponent OnChanged="GetActivities" /> <WorkDateComponent OnChanged="GetActivities" />
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<ActivityKmStartComponent /> <AdvisorActivityKmStartComponent />
</div> </div>
<div class="col-md-2"> <div class="col-md-2">
@if (_reportExist) @if (_reportExist)
@ -44,7 +44,7 @@
@if (ReportStatusView.ReportItems.Any()) @if (ReportStatusView.ReportItems.Any())
{ {
<ActivityTableComponent Activities="ReportStatusView.ReportItems" /> <AdvisorActivityTableComponent Activities="ReportStatusView.ReportItems" />
} }
else else
{ {

View file

@ -218,7 +218,7 @@ public partial class AdvisorNewActivityPage : IDisposable
"onSite" => $"B:{_ux.FullName.Split(" ")[0]}", "onSite" => $"B:{_ux.FullName.Split(" ")[0]}",
_ => "" _ => ""
}; };
if (_draft.ActivityTypeEnum == "phone" && _draft.Express) if (_draft.Express)
_draft.OurRef = $"E{_draft.OurRef}"; _draft.OurRef = $"E{_draft.OurRef}";
_draft.Lines = new List<ActivityLineDto>(); _draft.Lines = new List<ActivityLineDto>();

View file

@ -1,5 +1,114 @@
<h3>AdvisorViewActivityPage</h3> @using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "Admin,Office,Warehouse,Advisor")]
@page "/companies/{CompanyId}/orders/{OrderId}"
@code { @* <ReportItemComponent ReportItem="@_item" /> *@
} <table class="table table-sm table-striped d-print-table">
<thead>
<tr>
<th class="p-0" colspan="4">
<div class="bg-light text-dark border border-1 rounded-3 pt-3 mb-2">
<h2 class="fw-bold text-center">@ReportItem.Company.Name</h2>
@if (ReportItem.StatusTypeEnum.ToLower() is "quote")
{
<h3 class="text-center">TILBUD</h3>
}
@if (ReportItem.VisitTypeEnum.ToLower() == "phone" || ReportItem.OurRef.Contains("T:"))
{
<h3 class="text-center">TELEFONORDRE</h3>
}
@if (ReportItem.Express)
{
<h2 class="fw-bold text-center">HASTER</h2>
}
</div>
</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Dato</th>
<td>@ReportItem.OrderDate</td>
<th scope="row">Konto</th>
<td>@ReportItem.Company.Account</td>
</tr>
<tr>
<th scope="col">Telefon</th>
<td>@ReportItem.Company.Phone</td>
<th scope="col">Køber</th>
<td>@ReportItem.YourRef</td>
</tr>
<tr>
<th scope="col">CVR/VAT</th>
<td>@ReportItem.Company.VatNumber</td>
<th scope="col">Rekvisition</th>
<td>@ReportItem.ReferenceNumber</td>
</tr>
<tr>
<th scope="col">Navn</th>
<td>@ReportItem.Company.Name</td>
<th scope="col">Lev.Navn</th>
<td>@ReportItem.DlvName</td>
</tr>
<tr>
<th scope="col">Adresse</th>
<td>@ReportItem.Company.Address1</td>
<th scope="col">Lev.Adresse</th>
<td>@ReportItem.DlvAddress1</td>
</tr>
<tr>
<th scope="col">Adresse</th>
<td>@ReportItem.Company.Address2</td>
<th scope="col">Lev.Adresse</th>
<td>@ReportItem.DlvAddress2</td>
</tr>
<tr>
<th scope="col">Postnr By</th>
<td>@ReportItem.Company.ZipCode @ReportItem.Company.City</td>
<th scope="col">Lev.Postnr By</th>
<td>@ReportItem.DlvZipCity</td>
</tr>
</tbody>
</table>
<table class="table table-sm table-striped table-bordered">
<thead>
<tr class="bg-light text-black">
<th scope="col">Antal</th>
<th scope="col">Varnr</th>
<th scope="col">Beskrivelse</th>
<th class="text-end" scope="col">Pris</th>
<th class="text-end" scope="col">R%</th>
<th class="text-end" scope="col">Beløb</th>
</tr>
</thead>
<tbody>
@foreach (var line in ReportItem.Lines)
{
<tr>
<td>@line.Quantity</td>
<td>@line.Sku</td>
<td>@line.Description</td>
<td class="text-end">@($"{line.Price:N2}")</td>
<td class="text-end">@($"{line.Discount:N2}")</td>
<td class="text-end">@($"{line.LineSum:N2}")</td>
</tr>
}
<tr>
<td colspan="4"></td>
<td>Ordresum</td>
<td class="text-end">@ReportItem.OrderAmount</td>
</tr>
</tbody>
</table>
<div class="alert border border-1 border-primary">
<EditForm EditContext="OfficeNote">
<div class="row mb-2">
<label class="form-label mb-1" for="office-note">Ordre Note</label>
<InputTextArea class="form-control mb-1" id="office-note" rows="5" @bind-Value="_note.OfficeNote"></InputTextArea>
</div>
<div class="row mb-1">
<button class="btn btn-primary btn-lg" type="button" @onclick="UpdateOfficeNote" disabled="@_disabled" >Gem note</button>
</div>
</EditForm>
</div>

View file

@ -0,0 +1,55 @@
using System.Text.Json;
using System.Text.Json.Serialization;
using Blazored.Toast.Services;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.HttpRepository;
using Wonky.Entity.DTO;
using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class AdvisorViewActivityPage : IDisposable
{
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public string OrderId { get; set; } = "";
[Inject] private HttpInterceptorService _interceptor { get; set; }
[Inject] private IActivityHttpRepository _activityRepo { get; set; }
[Inject] private ILogger<AdvisorViewActivityPage> _logger { get; set; }
[Inject] private IToastService _toast { get; set; }
private ReportItemView ReportItem { get; set; } = new();
private ActivityOfficeNote _note { get; set; } = new();
private EditContext OfficeNote { get; set; }
private bool _disabled { get; set; }
protected override async Task OnInitializedAsync()
{
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
OfficeNote = new EditContext(_note);
OfficeNote.OnFieldChanged += HandleFieldChanged;
ReportItem = await _activityRepo.GetReportItem(OrderId);
_note.ActivityId = ReportItem.ActivityId;
_note.OfficeNote = ReportItem.OfficeNote;
}
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
{
StateHasChanged();
}
private async Task UpdateOfficeNote()
{
_disabled = true;
_logger.LogDebug("OfficeNote => \n {}", JsonSerializer.Serialize(_note));
await _activityRepo.UpdateOfficeNote(_note);
_toast.ShowInfo($"{ReportItem.ESalesNumber} - notat opdateret");
}
public void Dispose()
{
_interceptor.DisposeEvent();
}
}

View file

@ -47,7 +47,7 @@
<ReportDistanceLedgerComponent ReportData="_report.ReportData" /> <ReportDistanceLedgerComponent ReportData="_report.ReportData" />
</div> </div>
</div> </div>
<ActivityTableComponent Activities="_report.ReportItems" /> <OfficeActivityTableComponent Activities="_report.ReportItems" />
<ReportActivityLedgerComponent ReportData="_report.ReportData" /> <ReportActivityLedgerComponent ReportData="_report.ReportData" />
} }
else else

View file

@ -48,7 +48,7 @@
<ReportDistanceLedgerComponent ReportData="Report.ReportData" /> <ReportDistanceLedgerComponent ReportData="Report.ReportData" />
</div> </div>
</div> </div>
<ActivityTableComponent Activities="Report.ReportItems" /> <OfficeActivityTableComponent Activities="Report.ReportItems" />
<ReportActivityLedgerComponent ReportData="Report.ReportData" /> <ReportActivityLedgerComponent ReportData="Report.ReportData" />
} }
else else

View file

@ -8,7 +8,7 @@ using Wonky.Entity.Views;
namespace Wonky.Client.Pages; namespace Wonky.Client.Pages;
public partial class SalesActivityViewPage public partial class OfficeViewSalesActivityPage
{ {
[Parameter] public string CompanyId { get; set; } = ""; [Parameter] public string CompanyId { get; set; } = "";
[Parameter] public string OrderId { get; set; } = ""; [Parameter] public string OrderId { get; set; } = "";

View file

@ -46,14 +46,6 @@
</NotAuthorized> </NotAuthorized>
</AuthorizeView> </AuthorizeView>
<AuthorizeView Roles="Warehouse">
<div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/warehouse/orders">
<span class="oi oi-box" aria-hidden="true"></span> Forsendelse
</NavLink>
</div>
</AuthorizeView>
<AuthorizeView Roles="Admin"> <AuthorizeView Roles="Admin">
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/admin/users/advisors"> <NavLink class="nav-link ps-2" href="/admin/users/advisors">
@ -65,11 +57,6 @@
<span class="oi oi-spreadsheet" aria-hidden="true"></span> Priskatalog <span class="oi oi-spreadsheet" aria-hidden="true"></span> Priskatalog
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/warehouse/orders">
<span class="oi oi-box" aria-hidden="true"></span> Forsendelse
</NavLink>
</div>
</AuthorizeView> </AuthorizeView>
<AuthorizeView Roles="Office"> <AuthorizeView Roles="Office">
@ -90,6 +77,14 @@
</div> </div>
</AuthorizeView> </AuthorizeView>
<AuthorizeView Roles="Warehouse,Admin,Office">
<div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/warehouse/orders/none">
<span class="oi oi-box" aria-hidden="true"></span> Forsendelse
</NavLink>
</div>
</AuthorizeView>
<AuthorizeView Roles="Advisor"> <AuthorizeView Roles="Advisor">
<Authorized> <Authorized>
<div class="nav-item px-3"> <div class="nav-item px-3">

View file

@ -1,13 +1,13 @@
{ {
"appInfo": { "appInfo": {
"name": "Wonky Client", "name": "Wonky Client",
"version": "0.12.30", "version": "0.14.5",
"rc": true, "rc": true,
"sandBox": false, "sandBox": false,
"image": "grumpy-coder.png" "image": "grumpy-coder.png"
}, },
"apiConfig": { "apiConfig": {
"innoBaseUrl": "https://dev.innotec.dk", "innoBaseUrl": "https://app.innotec.dk",
"glsTrackUrl": "https://www.gls-group.eu/276-I-PORTAL-WEB/content/GLS/DK01/DA/5004.htm?txtAction=71000&txtRefNo=", "glsTrackUrl": "https://www.gls-group.eu/276-I-PORTAL-WEB/content/GLS/DK01/DA/5004.htm?txtAction=71000&txtRefNo=",
"glsId": "", "glsId": "",
"serviceVirk": "api/v2/services/virk", "serviceVirk": "api/v2/services/virk",
@ -31,19 +31,14 @@
}, },
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Debug", "Default": "Information",
"System": "Debug", "System": "Information",
"Microsoft": "Information" "Microsoft": "Information"
}, },
"Debug": { "Debug": {
"LogLevel": { "LogLevel": {
"Default": "Critical" "Default": "Critical"
} }
},
"ActivityHttpRepository": {
"LogLevel": {
"Default": "Error"
}
} }
} }
} }

View file

@ -0,0 +1,7 @@
namespace Wonky.Entity.DTO;
public class ActivityOfficeNote
{
public string ActivityId { get; set; } = "";
public string OfficeNote { get; set; } = "";
}