refactor work date component - refactor inventory page

adding product from inventory page using modal
show current product prices above history
This commit is contained in:
Frede Hundewadt 2022-10-15 07:48:44 +02:00
parent 7f4c2cb297
commit fbc9e21461
43 changed files with 1077 additions and 650 deletions

View file

@ -1,2 +1,3 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=kontrolleres/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Venligst/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> <s:Boolean x:Key="/Default/UserDictionary/Words/=Venligst/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -37,4 +37,3 @@
</Router> </Router>
</DraftStateProvider> </DraftStateProvider>
</CascadingAuthenticationState> </CascadingAuthenticationState>

View file

@ -21,16 +21,9 @@
<PageTitle>Inno Web CRM</PageTitle> <PageTitle>Inno Web CRM</PageTitle>
<AuthorizeView Roles="Advisor"> <AuthorizeView Roles="Advisor">
<div class="alert bg-light border-dark"> <div class="bg-dark text-white rounded-2 mb-2 py-2">
<div class="row"> <WorkDateComponent OnChangedCallback="GetWorkdayTasks"/>
<div class="col">
<h2 style="font-variant: all-small-caps">@(DateTime.Now.ToLongDateString())</h2>
</div>
<div class="col">
<WorkDateComponent SelectedDate="@_today" OnChanged="GetWorkdayTasks" />
</div>
</div>
</div> </div>
<TaskItemTableComponent TaskItemList="_taskItems" OnCompleteTask="OnCompleteTask" <TaskItemTableComponent TaskItemList="_taskItems" OnCompleteTask="OnCompleteTask"
OnDeleteTask="OnDeleteConfirmed" OnTaskCompleted="OnTaskCompleted" /> OnDeleteTask="OnDeleteConfirmed" OnTaskCompleted="OnTaskCompleted"/>
</AuthorizeView> </AuthorizeView>

View file

@ -46,16 +46,13 @@ public partial class LandingComponentAdvisor : IDisposable
}; };
private Preferences _prefs { get; set; } = new(); private Preferences _prefs { get; set; } = new();
private string _workDate { get; set; } = $"{DateTime.Now:yyyy-MM-dd}"; private DateTime SelectedDate { get; set; }
private string _today { get; set; } = $"{DateTime.Now:yyyy-MM-dd}";
private List<TaskItemDto>? _taskItems { get; set; } = new(); private List<TaskItemDto>? _taskItems { get; set; } = new();
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
_prefs = await _preferenceService.GetPreferences(); _prefs = await _preferenceService.GetPreferences();
if(!string.IsNullOrWhiteSpace(_prefs.WorkDate)) SelectedDate = string.IsNullOrWhiteSpace(_prefs.WorkDate) ? DateTime.Now : DateTime.Parse(_prefs.WorkDate);
_workDate = _prefs.WorkDate;
_interceptor.RegisterEvent(); _interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent(); _interceptor.RegisterBeforeSendEvent();
@ -78,9 +75,9 @@ public partial class LandingComponentAdvisor : IDisposable
private async Task GetWorkdayTasks(string workDate) private async Task GetWorkdayTasks(string workDate)
{ {
_workDate = workDate; SelectedDate = DateTime.Parse(workDate);
_taskItems = new List<TaskItemDto>(); _taskItems = new List<TaskItemDto>();
_taskItems = await CrmTaskItemRepo.GetTaskList(workDate); _taskItems = await CrmTaskItemRepo.GetTaskList($"{SelectedDate:yyyy-MM-dd}");
} }
private async Task OnTaskCompleted(string taskItemId) private async Task OnTaskCompleted(string taskItemId)

View file

@ -48,10 +48,12 @@
@product.Quantity @product.Quantity
</td> </td>
<td class="align-middle"> <td class="align-middle">
<a class="btn btn-warning d-block" href="/companies/@CompanyId/h/p/@product.Sku">Linjer</a> <button class="btn btn-info" type="button" @onclick="() => CallShowReorderModal(product.Sku)">Historik</button>
</td> </td>
</tr> </tr>
} }
</tbody> </tbody>
</table> </table>
} }
<InventoryReorderModal OnSelected="@OnSelectedItem" CompanyId="@CompanyId" SalesItem="@SalesItem" @ref="ReorderModal"/>

View file

@ -13,7 +13,11 @@
// 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 System.Globalization;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.Models;
using Wonky.Client.Shared;
using Wonky.Entity.DTO; using Wonky.Entity.DTO;
using Wonky.Entity.Views; using Wonky.Entity.Views;
@ -21,6 +25,50 @@ namespace Wonky.Client.Components;
public partial class ProductInventoryTableComponent public partial class ProductInventoryTableComponent
{ {
[CascadingParameter] DraftStateProvider DraftStateProvider { get; set; }
[Parameter] public List<ProductInventoryView> Inventory { get; set; } = new(); [Parameter] public List<ProductInventoryView> Inventory { get; set; } = new();
[Parameter] public string CompanyId { get; set; } = ""; [Parameter] public string CompanyId { get; set; } = "";
[Inject] public ICatalogHttpRepository Catalog { get; set; }
private SalesItemView SalesItem { get; set; } = new();
private string Price { get; set; } = "0";
private string Quantity { get; set; } = "1";
private string Sku { get; set; } = "";
private InventoryReorderModal ReorderModal { get; set; } = new();
private SelectedSku Item { get; set; } = new();
private async Task CallShowReorderModal(string sku)
{
SalesItem = await Catalog.GetSalesItemSku(sku);
ReorderModal.Show();
}
private async Task OnSelectedItem(DraftItem draftItem)
{
DraftStateProvider.Draft.Items.Add(draftItem);
await DraftStateProvider.SaveChangesAsync();
}
// private async Task AddItem(SalesItemView salesItem)
// {
// // create a new cart item
// var item = new DraftItem
// {
// Item = salesItem,
// Quantity = Convert.ToInt32(Quantity),
// Price = Convert.ToDecimal(Price, CultureInfo.InvariantCulture),
// Discount = Convert.ToDecimal(Discount, CultureInfo.InvariantCulture),
// Sas = Sas
// };
// // reset internals to initial state
// Sas = false;
// Quantity = "1";
// Price = "0";
// Discount = "0";
// // add it to the cart
// DraftStateProvider.Draft.Items.Add(item);
// // save the item using the CartStateProvider's save method
// await DraftStateProvider.SaveChangesAsync();
// }
} }

View file

@ -41,6 +41,12 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr>
<th scope="row">Vores Ref.</th>
<td class="fw-bold">@ReportItem.OurRef</td>
<th scope="row">EOrdre</th>
<td class="fw-bold">@ReportItem.ESalesNumber</td>
</tr>
<tr> <tr>
<th scope="row">Dato</th> <th scope="row">Dato</th>
<td class="fw-bold">@ReportItem.OrderDate</td> <td class="fw-bold">@ReportItem.OrderDate</td>

View file

@ -53,6 +53,9 @@
case "Meeting": case "Meeting":
<span>Salgsmøde</span> <span>Salgsmøde</span>
break; break;
case "Supervisor":
<span>Supervisor</span>
break;
default: default:
<span></span> <span></span>
break; break;

View file

@ -63,6 +63,9 @@
case "Leave": case "Leave":
<span>Ferie</span> <span>Ferie</span>
break; break;
case "Supervisor":
<span>Supervisor</span>
break;
} }
} }
</div> </div>

View file

@ -18,5 +18,15 @@
@using Blazored.LocalStorage @using Blazored.LocalStorage
@using Wonky.Client.Services @using Wonky.Client.Services
<input type="date" class="form-control" <EditForm EditContext="WorkDateContext">
@bind-Value="SelectedDate" @bind-Value:event="oninput" @onchange="OnDateChanged" /> <div class="container-fluid">
<div class="row align-items-center">
<div class="col-8 work-date fw-bold">
@SelectedDate.ToLongDateString()
</div>
<div class="col-4">
<InputDate class="form-control calendar" @bind-Value="SelectedDate" @oninput="OnDateChanged"/>
</div>
</div>
</div>
</EditForm>

View file

@ -17,6 +17,7 @@
using System.Globalization; using System.Globalization;
using Blazored.LocalStorage; using Blazored.LocalStorage;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Wonky.Client.Services; using Wonky.Client.Services;
namespace Wonky.Client.Components; namespace Wonky.Client.Components;
@ -27,47 +28,43 @@ public partial class WorkDateComponent : IDisposable
/// User preference service /// User preference service
/// </summary> /// </summary>
[Inject] public PreferenceService Prefs { get; set; } [Inject] public PreferenceService Prefs { get; set; }
/// <summary> /// <summary>
/// OnChanged callback function /// OnChanged callback function
/// </summary> /// </summary>
[Parameter] public EventCallback<string> OnChanged { get; set; } [Parameter] public EventCallback<string> OnChangedCallback { get; set; }
private EditContext WorkDateContext { get; set; }
/// <summary> /// <summary>
/// Selected data /// Selected data
/// </summary> /// </summary>
[Parameter] public string SelectedDate { get; set; } = $"{DateOnly.FromDateTime(DateTime.Now):yyyy-MM-dd}"; private DateTime SelectedDate { get; set; }
/// <summary> /// <summary>
/// user preferences /// user preferences
/// </summary> /// </summary>
private Preferences _prefs = new(); private Preferences _prefs = new();
/// <summary> /// <summary>
/// Component Initialization /// Component Initialization
/// </summary> /// </summary>
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
WorkDateContext = new EditContext(SelectedDate);
Prefs.OnChange += ProfileServiceOnOnChange; Prefs.OnChange += ProfileServiceOnOnChange;
_prefs = await Prefs.GetPreferences(); _prefs = await Prefs.GetPreferences();
SelectedDate = string.IsNullOrWhiteSpace(_prefs.WorkDate)
if (!string.IsNullOrWhiteSpace(_prefs.WorkDate)) ? DateTime.Now
SelectedDate = _prefs.WorkDate; : DateTime.Parse(_prefs.WorkDate);
} }
/// <summary> /// <summary>
/// OnDateChanged function call to invoke the event callback /// OnDateChanged function call to invoke the event callback
/// </summary> /// </summary>
/// <param name="e"></param> /// <param name="e"></param>
private async Task OnDateChanged(ChangeEventArgs e) private async Task OnDateChanged(ChangeEventArgs e)
{ {
var val = $"{DateOnly.Parse(e.Value?.ToString()!):yyyy-MM-dd}"; var val = DateTime.Parse(e.Value.ToString());
await Prefs.SetWorkDate(DateTime.Parse(val)); await Prefs.SetWorkDate(val);
await OnChanged.InvokeAsync(val); await OnChangedCallback.InvokeAsync($"{val:yyyy-MM-dd}");
} }
/// <summary> /// <summary>
/// /// ProfileService
/// </summary> /// </summary>
/// <param name="newPreferences"></param> /// <param name="newPreferences"></param>
private void ProfileServiceOnOnChange(Preferences newPreferences) private void ProfileServiceOnOnChange(Preferences newPreferences)
@ -75,7 +72,6 @@ public partial class WorkDateComponent : IDisposable
_prefs = newPreferences; _prefs = newPreferences;
StateHasChanged(); StateHasChanged();
} }
/// <summary> /// <summary>
/// Component dispose /// Component dispose
/// </summary> /// </summary>

View file

@ -0,0 +1,7 @@
.work-date {
font-size: 1.2rem;
font-variant: all-small-caps;
}
.calendar {
min-width: 250px;
}

View file

@ -24,4 +24,6 @@ public interface ICatalogHttpRepository
Task<PagingResponse<SalesItemView>> GetSalesItemsPaged(CatalogPagingParams pagingParameters); Task<PagingResponse<SalesItemView>> GetSalesItemsPaged(CatalogPagingParams pagingParameters);
Task<SalesItemView> GetSalesItemId(string salesItemId); Task<SalesItemView> GetSalesItemId(string salesItemId);
Task<SalesItemView> GetSalesVariantId(string variantId); Task<SalesItemView> GetSalesVariantId(string variantId);
Task<SalesItemView> GetSalesItemSku(string sku);
Task<SalesItemView> GetSalesItemSku(string countryCode, string sku);
} }

View file

@ -91,4 +91,15 @@ public class CatalogHttpRepository : ICatalogHttpRepository
.GetFromJsonAsync<SalesItemView>($"{_apiConfig.Catalog}/variant/{variantId}"); .GetFromJsonAsync<SalesItemView>($"{_apiConfig.Catalog}/variant/{variantId}");
return salesItem ?? new SalesItemView(); return salesItem ?? new SalesItemView();
} }
public async Task<SalesItemView> GetSalesItemSku(string sku)
{
var salesItem = await _client.GetFromJsonAsync<SalesItemView>($"{_apiConfig.Catalog}/sku/{sku}");
return salesItem ?? new SalesItemView();
}
public async Task<SalesItemView> GetSalesItemSku(string countryCode, string sku)
{
var salesItem = await _client.GetFromJsonAsync<SalesItemView>($"{_apiConfig.Catalog}/{countryCode}/sku/{sku}");
return salesItem ?? new SalesItemView();
}
} }

View file

@ -30,6 +30,7 @@ public class DraftItem
public class Draft public class Draft
{ {
public string DraftId { get; set; } = "";
public List<DraftItem> Items { get; set; } = new (); public List<DraftItem> Items { get; set; } = new ();
public decimal Total public decimal Total
{ {

View file

@ -20,60 +20,60 @@
@attribute [Authorize(Roles = "Advisor")] @attribute [Authorize(Roles = "Advisor")]
@using Wonky.Client.Components @using Wonky.Client.Components
<PriceListModal OnSelected="SelectSku" @ref="PriceListModal"/> <div class="row bg-dark text-white rounded-2 mb-2 py-2 align-items-center">
<ProductHistoryModal CompanyId="@CompanyId" ItemSku="@_selectedItem.Sku" @ref="HistoryModal"/> <div class="col">
<ProductPriceHistoryModal OnSelected="SelectPrice" CompanyId="@CompanyId" ItemSku="@_selectedItem.Sku" @ref="PriceHistoryModal"/> <WorkDateComponent OnChangedCallback="WorkDateComponentCallback"/>
<div class="row align-items-center bg-dark text-white rounded-3 p-3">
<div class="col-9">
<h3 class="workDate">@_workDate.ToLongDateString()</h3>
</div>
<div class="col-3">
<WorkDateComponent SelectedDate="@_selectedDate" OnChanged="SetWorkDate"></WorkDateComponent>
</div> </div>
</div> </div>
<div class="row bg-light border-1 border-dark rounded-3 p-3"> <div class="row bg-light border-1 border-dark rounded-3 p-3">
<div class="col"> <div class="col">
<h3>@_activity.Name - @_activity.Account</h3> <h3>@Activity.Name - @Activity.Account</h3>
</div> </div>
</div> </div>
@if (_reportClosed) @if (ReportClosed)
{ {
<h5>Der kan ikke oprettes besøg når der findes rapport for @_workDate.ToShortDateString()</h5> <h5>Der kan ikke oprettes besøg når der findes rapport for @SelectedDate.ToShortDateString()</h5>
} }
else else
{ {
<EditForm EditContext="_editContext"> <EditForm EditContext="ActivityContext">
<DataAnnotationsValidator/> <DataAnnotationsValidator/>
<div class="row mb-1"> <div class="row mb-1">
<label for="activityType" class="col-md-2 col-form-label">Ordre Type</label> <label for="activityType" class="col-md-2 col-form-label">Ordre Type</label>
<div class="col-md-4"> <div class="col-md-4">
<InputSelect id="activityType" class="form-select" @bind-Value="@_activity.ActivityTypeEnum"> <InputSelect id="activityType" class="form-select" @bind-Value="@Activity.ActivityTypeEnum">
<option value="">&rarr; TAG MIG &larr;</option> <option value="">&rarr; TAG MIG &larr;</option>
<option value="onSite">Besøg</option> <option value="onSite">Besøg</option>
<option value="phone">Telefon</option> <option value="phone">Telefon</option>
</InputSelect> </InputSelect>
<ValidationMessage For="@(() => _activity.ActivityTypeEnum)"></ValidationMessage> <ValidationMessage For="@(() => Activity.ActivityTypeEnum)"></ValidationMessage>
</div> </div>
<label for="statusType" class="col-md-2 col-form-label">Status</label> <label for="statusType" class="col-md-2 col-form-label">Status</label>
<div class="col-md-4"> <div class="col-md-4">
<InputSelect id="statusType" class="form-select" @bind-Value="@_activity.ActivityStatusEnum"> <InputSelect id="statusType" class="form-select" @bind-Value="@Activity.ActivityStatusEnum">
<option value="noSale" selected>Ingen salg</option> <option value="noSale">Ingen salg</option>
@if (!string.IsNullOrEmpty(_activity.VatNumber) && !string.IsNullOrWhiteSpace(_activity.Address1) && _company.HasFolded == 0) @if (!string.IsNullOrEmpty(Activity.VatNumber) && !string.IsNullOrWhiteSpace(Activity.Address1) && Company.HasFolded == 0)
{ {
<option value="order">Bestilling</option> @if (DraftStateProvider.Draft.Items.Any())
{
<option value="order" selected>Bestilling</option>
}
else
{
<option value="order">Bestilling</option>
}
<option value="quote">Tilbud</option> <option value="quote">Tilbud</option>
} }
</InputSelect> </InputSelect>
<ValidationMessage For="@(() => _activity.ActivityStatusEnum)"></ValidationMessage> <ValidationMessage For="@(() => Activity.ActivityStatusEnum)"></ValidationMessage>
@if (_activity.ActivityStatusEnum == "order") @if (Activity.ActivityStatusEnum == "order")
{ {
<div class="form-check"> <div class="form-check">
<InputCheckbox id="express" class="form-check-input" @bind-Value="@_activity.Express"/> <InputCheckbox id="express" class="form-check-input" @bind-Value="@Activity.Express"/>
<label class="form-check-label" for="express">Express</label> <label class="form-check-label" for="express">Express</label>
</div> </div>
} }
@ -83,63 +83,178 @@ else
<div class="row mb-1"> <div class="row mb-1">
<label for="demo" class="col-md-2 col-form-label">Demo</label> <label for="demo" class="col-md-2 col-form-label">Demo</label>
<div class="col-md-4"> <div class="col-md-4">
<InputText id="demo" class="form-control" @bind-Value="_activity.Demo"/> <InputText id="demo" class="form-control" @bind-Value="Activity.Demo"/>
<ValidationMessage For="@(() => _activity.Demo)"></ValidationMessage> <ValidationMessage For="@(() => Activity.Demo)"></ValidationMessage>
</div> </div>
<label for="email" class="col-md-2 col-form-label">Epost</label> <label for="email" class="col-md-2 col-form-label">Epost</label>
<div class="col-md-4"> <div class="col-md-4">
<InputText id="email" class="form-control" @bind-Value="_activity.Email"/> <InputText id="email" class="form-control" @bind-Value="Activity.Email"/>
<ValidationMessage For="@(() => _activity.Email)"></ValidationMessage> <ValidationMessage For="@(() => Activity.Email)"></ValidationMessage>
</div> </div>
</div> </div>
<div class="row mb-1"> <div class="row mb-1">
<label for="referenceNumber" class="col-md-2 col-form-label">Rekvisition</label> <label for="referenceNumber" class="col-md-2 col-form-label">Rekvisition</label>
<div class="col-md-4"> <div class="col-md-4">
<InputText id="referenceNumber" class="form-control" @bind-Value="_activity.ReferenceNumber"/> <InputText id="referenceNumber" class="form-control" @bind-Value="Activity.ReferenceNumber"/>
<ValidationMessage For="@(() => _activity.ReferenceNumber)"></ValidationMessage> <ValidationMessage For="@(() => Activity.ReferenceNumber)"></ValidationMessage>
</div> </div>
<label for="yourRef" class="col-md-2 col-form-label">Indkøber</label> <label for="yourRef" class="col-md-2 col-form-label">Indkøber</label>
<div class="col-md-4"> <div class="col-md-4">
<InputText id="yourRef" class="form-control" @bind-Value="_activity.YourRef"/> <InputText id="yourRef" class="form-control" @bind-Value="Activity.YourRef"/>
<ValidationMessage For="@(() => _activity.YourRef)"></ValidationMessage> <ValidationMessage For="@(() => Activity.YourRef)"></ValidationMessage>
</div> </div>
</div> </div>
<div class="row mb-1"> <div class="row mb-1">
<label for="orderMessage" class="col-md-2 col-form-label">Note /Kontor</label> <label for="orderMessage" class="col-md-2 col-form-label">Note /Kontor</label>
<div class="col-md-4"> <div class="col-md-4">
<InputTextArea id="orderMessage" class="form-control" @bind-Value="_activity.OrderMessage"/> <InputTextArea id="orderMessage" class="form-control" @bind-Value="Activity.OrderMessage"/>
<ValidationMessage For="@(() => _activity.OrderMessage)"></ValidationMessage> <ValidationMessage For="@(() => Activity.OrderMessage)"></ValidationMessage>
</div> </div>
<label for="crmNote" class="col-md-2 col-form-label">Note /Selv</label> <label for="crmNote" class="col-md-2 col-form-label">Note /Selv</label>
<div class="col-md-4"> <div class="col-md-4">
<InputTextArea id="crmNote" class="form-control" @bind-Value="_activity.CrmNote"/> <InputTextArea id="crmNote" class="form-control" @bind-Value="Activity.CrmNote"/>
<ValidationMessage For="@(() => _activity.CrmNote)"></ValidationMessage> <ValidationMessage For="@(() => Activity.CrmNote)"></ValidationMessage>
</div> </div>
</div> </div>
<div class="row mb-1"> <div class="row mb-2">
<label for="attention" class="col-md-2 col-form-label">Att.</label> <label for="attention" class="col-md-2 col-form-label">Att.</label>
<div class="col-md-4"> <div class="col-md-4">
<InputText id="attention" class="form-control" @bind-Value="_activity.Attention"/> <InputText id="attention" class="form-control" @bind-Value="Activity.Attention"/>
<ValidationMessage For="@(() => _activity.Attention)"></ValidationMessage> <ValidationMessage For="@(() => Activity.Attention)"></ValidationMessage>
</div> </div>
<label for="phone" class="col-md-2 col-form-label">Tlf.</label> <label for="phone" class="col-md-2 col-form-label">Tlf.</label>
<div class="col-md-4"> <div class="col-md-4">
<InputText id="phone" class="form-control" @bind-Value="_activity.Phone"/> <InputText id="phone" class="form-control" @bind-Value="Activity.Phone"/>
<ValidationMessage For="@(() => _activity.Phone)"></ValidationMessage> <ValidationMessage For="@(() => Activity.Phone)"></ValidationMessage>
</div> </div>
</div> </div>
<div id="this-draft" style="@(Activity.ActivityStatusEnum is "order" or "quote" ? "display: block" : "display:none")">
@* Order lines -----------------------------------------------------*@
<div class="row">
<div class="col">
<table class="sticky-top table table-hover table-striped table-bordered">
<thead>
<tr class="bg-dark text-white">
<th scope="col" colspan="7">
Ordrekladde <span class="mx-2 draft-expires-msg">Global kladde (udløber efter @(DraftStateProvider.Draft.TimeToLiveInSeconds / 60)m inaktivitet)</span>
</th>
<th scope="col" class="text-end">
<button type="button" class="btn btn-danger btn-sm" @onclick="@DeleteDraft" disabled="@(DraftStateProvider.Draft.Items.Count == 0)"><i class="bi-trash"></i> Slet kladde</button>
</th>
</tr>
<tr class="bg-dark opacity-75 text-white">
<th scope="col">Navn</th>
<th scope="col" class="text-nowrap">Varenr</th>
<th scope="col" class="text-end">Antal</th>
<th scope="col" class="text-end">Enhedspris</th>
<th scope="col" class="text-center">%</th>
<th scope="col" class="text-end">Linjesum</th>
<th scope="col" class="text-end">SAS</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@if (DraftStateProvider.Draft.Items.Count > 0)
{
@foreach (var cartItem in DraftStateProvider.Draft.Items)
{
<tr>
<td class="align-middle">@cartItem.Item.Name</td>
<td class="align-middle">@cartItem.Item.Sku</td>
<td class="align-middle text-end">@cartItem.Quantity</td>
<td class="align-middle text-end">@($"{cartItem.Price:N2}")</td>
<td class="align-middle text-end">@($"{cartItem.Discount:N2}")</td>
<td class="align-middle text-end">@($"{cartItem.LineTotal:N2}")</td>
<td class="align-middle text-center">
<input type="checkbox" checked="@cartItem.Sas" disabled/>
</td>
<td class="align-middle text-end">
<button type="button" class="btn btn-danger" @onclick="@(() => RemoveItem(cartItem))"><i class="bi-trash2"></i> Slet Linje</button>
</td>
</tr>
}
}
<tr>
<td colspan="4"></td>
<td class="align-middle text-black text-end fw-bold">Total</td>
<td class="align-middle text-black text-end fw-bold">@($"{DraftStateProvider.Draft.Total:N2}")</td>
<td></td>
<td class="align-middle text-end">
<button class="btn btn-primary" type="button" @onclick="CallPriceListModal">
<i class="bi-plus"></i> Ny linje
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
@* draft line ----------------------------------------------------- *@
<div class="row">
<div class="col">
@if (!string.IsNullOrWhiteSpace(SelectedItem.Name) && ShowItem)
{
<table id="draft-line" class="table table-bordered">
<thead>
<tr class="bg-dark text-white">
<th scope="col" colspan="6">Kladdelinje</th>
</tr>
<tr>
<th scope="col">Antal</th>
<th scope="col">Pris</th>
<th scope="col">Rabat</th>
<th class="align-content-center justify-content-center" scope="col">SAS</th>
<th scope="col">Varenr.</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-middle">
<input type="number" class="form-control" @bind-value="@Quantity"/>
</td>
<td class="align-middle">
<div class="input-group">
<input type="number" class="form-control" @bind-value="@Price"/>
<button class="btn btn-warning" type="button" @onclick="CallPriceHistoryModal">
<i class="bi-list-ul"></i>
</button>
@*
<button class="btn btn-info btn-sm" type="button" @onclick="CallHistoryModal">
<i class="oi oi-list"></i>
</button>
*@
</div>
</td>
<td class="align-middle">
<input type="number" class="form-control" @bind-value="@Discount"/>
</td>
<td class="align-middle align-content-center justify-content-center">
<input type="checkbox" class="form-check" @bind-value="@Sas"/>
</td>
<td class="align-middle">@SelectedItem.Sku</td>
<td class="align-middle">
<button type="button" class="btn btn-warning text-nowrap d-block" @onclick="@(() => AddItem(SelectedItem))">bestil @Quantity stk @SelectedItem.Name</button>
</td>
</tr>
</tbody>
</table>
}
</div>
</div>
</div>
<div class="accordion" id="crmActivity"> <div class="accordion" id="crmActivity">
@* Order lines *@ @*
<div class="accordion-item" style="@(_activity.ActivityStatusEnum is "order" or "quote" ? "display: block" : "display:none")"> $1$ Order lines #1#
<div class="accordion-item" style="@(Activity.ActivityStatusEnum is "order" or "quote" ? "display: block" : "display:none")">
<h2 class="accordion-header" id="catalogHeader"> <h2 class="accordion-header" id="catalogHeader">
<button class="accordion-button collapsed bg-light" type="button" <button class="accordion-button collapsed bg-light" type="button"
data-bs-toggle="collapse" data-bs-target="#catalogBody" data-bs-toggle="collapse" data-bs-target="#catalogBody"
@ -149,122 +264,13 @@ else
</h2> </h2>
<div id="catalogBody" class="accordion-collapse collapse" aria-labelledby="catalogHeader" data-bs-parent="#crmActivity"> <div id="catalogBody" class="accordion-collapse collapse" aria-labelledby="catalogHeader" data-bs-parent="#crmActivity">
<div class="accordion-body"> <div class="accordion-body">
<div class="row">
<div class="col">
@* Order draft lines -----------------------------------------------------*@
<table class="sticky-top table table-hover table-striped table-bordered">
<thead>
<tr class="bg-dark text-white">
<th scope="col" colspan="6">
Ordrekladde <span class="mx-2 draft-expires-msg">Global kladde (udløber efter @(DraftStateProvider.Draft.TimeToLiveInSeconds / 60)m inaktivitet)</span>
</th>
<th scope="col" class="text-end">
<button type="button" class="btn btn-danger btn-sm" @onclick="@DeleteDraft" disabled="@(DraftStateProvider.Draft.Items.Count == 0)">Slet kladde</button>
</th>
</tr>
<tr class="bg-dark opacity-75 text-white">
<th scope="col">Navn</th>
<th scope="col" class="text-nowrap">Varenr</th>
<th scope="col" class="text-end">Antal</th>
<th scope="col" class="text-end">Enhedspris</th>
<th scope="col" class="text-end">Linjesum</th>
<th scope="col" class="text-end">SAS</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@if (DraftStateProvider.Draft.Items.Count > 0)
{
@foreach (var cartItem in DraftStateProvider.Draft.Items)
{
<tr>
<td class="align-middle">@cartItem.Item.Name</td>
<td class="align-middle">@cartItem.Item.Sku</td>
<td class="align-middle text-end">@cartItem.Quantity</td>
<td class="align-middle text-end">@cartItem.Price</td>
<td class="align-middle text-end">@cartItem.LineTotal</td>
<td class="align-middle text-center">
<input type="checkbox" checked="@cartItem.Sas" disabled/>
</td>
<td class="align-middle text-end">
<button type="button" class="btn btn-danger" @onclick="@(() => RemoveItem(cartItem))">Slet Linje</button>
</td>
</tr>
}
}
<tr>
<td colspan="3"></td>
<td class="align-middle text-black text-end fw-bold">Total</td>
<td class="align-middle text-black text-end fw-bold">@DraftStateProvider.Draft.Total</td>
<td></td>
<td class="align-middle text-end">
<button class="btn btn-primary" type="button" @onclick="CallPriceListModal">
<i class="oi oi-plus"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="row">
<div class="col">
@* draft line ----------------------------------------------------- *@
@if (!string.IsNullOrWhiteSpace(_selectedItem.Name) && ShowItem)
{
<table id="draft-line" class="table table-bordered">
<thead>
<tr class="bg-dark text-white">
<th scope="col" colspan="6">Kladdelinje</th>
</tr>
<tr>
<th scope="col">Antal</th>
<th scope="col">Pris</th>
<th scope="col">Rabat</th>
<th class="align-content-center justify-content-center" scope="col">SAS</th>
<th scope="col">Varenr.</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
<tr>
<td class="align-middle">
<input type="number" class="form-control" @bind-value="@Quantity"/>
</td>
<td class="align-middle">
<div class="input-group">
<input type="number" class="form-control" @bind-value="@Price"/>
<button class="btn btn-warning btn-sm" type="button" @onclick="CallPriceHistoryModal">
<i class="oi oi-list"></i>
</button>
@*
<button class="btn btn-info btn-sm" type="button" @onclick="CallHistoryModal">
<i class="oi oi-list"></i>
</button>
*@
</div>
</td>
<td class="align-middle">
<input type="number" class="form-control" @bind-value="@Discount"/>
</td>
<td class="align-middle align-content-center justify-content-center">
<input type="checkbox" class="form-check" @bind-value="@Sas"/>
</td>
<td class="align-middle">@_selectedItem.Sku</td>
<td class="align-middle">
<button type="button" class="btn btn-warning text-nowrap d-block" @onclick="@(() => AddItem(_selectedItem))">bestil @Quantity stk @_selectedItem.Name</button>
</td>
</tr>
</tbody>
</table>
}
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
*@
@* Delivery address *@ @* Delivery address *@
<div class="accordion-item" style="@(_activity.ActivityStatusEnum == "order" ? "display: block" : "display:none")"> <div class="accordion-item" style="@(Activity.ActivityStatusEnum == "order" ? "display: block" : "display:none")">
<h2 class="accordion-header" id="deliveryHeader"> <h2 class="accordion-header" id="deliveryHeader">
<button class="accordion-button collapsed bg-light" type="button" data-bs-toggle="collapse" data-bs-target="#deliveryBody" aria-expanded="false" aria-controls="deliveryBody"> <button class="accordion-button collapsed bg-light" type="button" data-bs-toggle="collapse" data-bs-target="#deliveryBody" aria-expanded="false" aria-controls="deliveryBody">
Leveringsadresse Leveringsadresse
@ -276,31 +282,31 @@ else
<div class="row mb-1"> <div class="row mb-1">
<label for="dlvName" class="col-md-2 col-form-label">Lev. Navn</label> <label for="dlvName" class="col-md-2 col-form-label">Lev. Navn</label>
<div class="col-md-10"> <div class="col-md-10">
<InputText id="dlvName" class="form-control" @bind-Value="_activity.DlvName"/> <InputText id="dlvName" class="form-control" @bind-Value="Activity.DlvName"/>
</div> </div>
</div> </div>
<div class="row mb-1"> <div class="row mb-1">
<label for="dlvAddress1" class="col-md-2 col-form-label">Lev. Adresse</label> <label for="dlvAddress1" class="col-md-2 col-form-label">Lev. Adresse</label>
<div class="col-md-10"> <div class="col-md-10">
<InputText id="dlvAddress1" class="form-control" @bind-Value="_activity.DlvAddress1"/> <InputText id="dlvAddress1" class="form-control" @bind-Value="Activity.DlvAddress1"/>
</div> </div>
</div> </div>
<div class="row mb-1"> <div class="row mb-1">
<label for="dlvAddress2" class="col-md-2 col-form-label">Lev. Adresse</label> <label for="dlvAddress2" class="col-md-2 col-form-label">Lev. Adresse</label>
<div class="col-md-10"> <div class="col-md-10">
<InputText id="dlvAddress2" class="form-control" @bind-Value="_activity.DlvAddress2"/> <InputText id="dlvAddress2" class="form-control" @bind-Value="Activity.DlvAddress2"/>
</div> </div>
</div> </div>
<div class="row mb-1"> <div class="row mb-1">
<label for="dlvZipCode" class="col-md-2 col-form-label">Lev. Postnr</label> <label for="dlvZipCode" class="col-md-2 col-form-label">Lev. Postnr</label>
<div class="col-md-10"> <div class="col-md-10">
<InputText id="dlvZipCode" class="form-control" @bind-Value="_activity.DlvZipCode"/> <InputText id="dlvZipCode" class="form-control" @bind-Value="Activity.DlvZipCode"/>
</div> </div>
</div> </div>
<div class="row mb-1"> <div class="row mb-1">
<label for="dlvCity" class="col-md-2 col-form-label">Lev. Bynavn</label> <label for="dlvCity" class="col-md-2 col-form-label">Lev. Bynavn</label>
<div class="col-md-10"> <div class="col-md-10">
<InputText id="dlvCity" class="form-control" @bind-Value="_activity.DlvCity"/> <InputText id="dlvCity" class="form-control" @bind-Value="Activity.DlvCity"/>
</div> </div>
</div> </div>
</div> </div>
@ -313,12 +319,15 @@ else
<a class="btn btn-info" href="/companies">Til Oversigt</a> <a class="btn btn-info" href="/companies">Til Oversigt</a>
</div> </div>
<div class="col"> <div class="col">
<a class="btn btn-warning" href="/companies/@_company.CompanyId">Tilbage</a> <a class="btn btn-warning" href="/companies/@Company.CompanyId">Tilbage</a>
</div> </div>
<div class="col"> <div class="col">
<button type="button" class="btn btn-primary" @onclick="CreateActivity" disabled="@_poFormInvalid">Opret besøg</button> <button type="button" class="btn btn-primary" @onclick="CreateActivity" disabled="@PoFormInvalid">Opret besøg</button>
</div> </div>
</div> </div>
} }
<ConfirmationModal BodyMessage="@_confirmDatePrompt" OnOkClicked="WorkDateConfirmed" @ref="ConfirmWorkDate" /> <ConfirmWorkDateModal BodyMessage="@PromptDateConfirm" OnOkClicked="WorkDateConfirmCallback" @ref="ConfirmWorkDate"/>
<PriceListModal OnSelected="PriceListCallback" @ref="PriceListModal"/>
<ProductHistoryModal CompanyId="@CompanyId" ItemSku="@SelectedItem.Sku" @ref="HistoryModal"/>
<ProductPriceHistoryModal OnSelected="PriceHistoryCallback" CompanyId="@CompanyId" Sku="@SelectedItem.Sku" @ref="PriceHistoryModal"/>

View file

@ -38,7 +38,7 @@ public partial class CrmActivityNewPage : IDisposable
// Services // Services
[Inject] public ILogger<CrmActivityNewPage> Logger { get; set; } [Inject] public ILogger<CrmActivityNewPage> Logger { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; } [Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public PreferenceService PreferenceService { get; set; } [Inject] public PreferenceService Prefs { get; set; }
[Inject] public IToastService Toast { get; set; } [Inject] public IToastService Toast { get; set; }
[Inject] public NavigationManager Navigator { get; set; } [Inject] public NavigationManager Navigator { get; set; }
[Inject] public ILocalStorageService Storage { get; set; } [Inject] public ILocalStorageService Storage { get; set; }
@ -47,13 +47,13 @@ public partial class CrmActivityNewPage : IDisposable
[Inject] public ICrmActivityHttpRepository CrmActivityRepo { get; set; } [Inject] public ICrmActivityHttpRepository CrmActivityRepo { get; set; }
[Inject] public ICrmReportHttpRepository CrmReportRepo { get; set; } [Inject] public ICrmReportHttpRepository CrmReportRepo { get; set; }
// variables // variables
private readonly JsonSerializerOptions? _options = new JsonSerializerOptions{PropertyNameCaseInsensitive = true}; private readonly JsonSerializerOptions? _options = new() {PropertyNameCaseInsensitive = true};
private SalesItemView _selectedItem { get; set; } = new(); private SalesItemView SelectedItem { get; set; } = new();
private Preferences _prefs { get; set; } = new(); private Preferences UserPrefs { get; set; } = new();
private ActivityDto _activity { get; set; } = new(); private ActivityDto Activity { get; set; } = new();
private CompanyDto _company = new(); private CompanyDto Company = new();
private EditContext _editContext { get; set; } private EditContext ActivityContext { get; set; }
private bool _poFormInvalid { get; set; } = true; private bool PoFormInvalid { get; set; } = true;
private bool ShowItem { get; set; } private bool ShowItem { get; set; }
private string Quantity = "1"; private string Quantity = "1";
private string Price = "0"; private string Price = "0";
@ -64,129 +64,131 @@ public partial class CrmActivityNewPage : IDisposable
private bool InvalidActivity = true; private bool InvalidActivity = true;
private bool InvalidCanvas = true; private bool InvalidCanvas = true;
private bool NoHistory = true; private bool NoHistory = true;
private bool _reportClosed { get; set; } private bool ReportClosed { get; set; }
private UserInfoView _ux { get; set; } = new(); private UserInfoView ThisUserInfo { get; set; } = new();
private DateTime _workDate { get; set; } = DateTime.Now; private DateTime SelectedDate { get; set; }
private string _selectedDate { get; set; } = ""; private string OldPhone { get; set; } = "";
private string _phone { get; set; } = ""; private string PromptDateConfirm { get; set; }
private string _confirmDatePrompt { get; set; }
// MODAL DIALOGS // MODAL DIALOGS
private PriceListModal PriceListModal { get; set; } private PriceListModal PriceListModal { get; set; }
private ProductHistoryModal HistoryModal { get; set; } private ProductHistoryModal HistoryModal { get; set; }
private ProductPriceHistoryModal PriceHistoryModal { get; set; } private ProductPriceHistoryModal PriceHistoryModal { get; set; }
private ConfirmationModal ConfirmWorkDate { get; set; } = new(); private ConfirmWorkDateModal ConfirmWorkDate { get; set; } = new();
protected override async Task OnParametersSetAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
_prefs = await PreferenceService.GetPreferences();
if (!string.IsNullOrWhiteSpace(_prefs.WorkDate))
_workDate = DateTime.Parse(_prefs.WorkDate);
_selectedDate = $"{_workDate:yyyy-MM-dd}";
// raise flag if report is closed
_reportClosed = await CrmReportRepo.ReportExist(_selectedDate);
}
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
_editContext = new EditContext(_activity); ActivityContext = new EditContext(Activity);
_editContext.OnFieldChanged += HandleFieldChanged; ActivityContext.OnFieldChanged += HandleFieldChanged;
_editContext.OnValidationStateChanged += ValidationChanged; ActivityContext.OnValidationStateChanged += ValidationChanged;
_activity.ActivityDate = $"{_workDate:yyyy-MM-dd}" ;
_ux = await Storage.GetItemAsync<UserInfoView>("_xu");
// get company
_company = await CompanyRepo.GetCompanyById(CompanyId);
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
// User Preferences
UserPrefs = await Prefs.GetPreferences();
// User Info
ThisUserInfo = await Storage.GetItemAsync<UserInfoView>("_xu");
// Fetch Customer from http
Company = await CompanyRepo.GetCompanyById(CompanyId);
if (Company.HasFolded == 1)
// Company has shutdown activities
Activity.OrderMessage = "BEMÆRK: CVR nummer er ophørt.";
// variable to validate if customer needs phone number update // variable to validate if customer needs phone number update
_phone = _company.Phone; OldPhone = Company.Phone;
if (string.IsNullOrWhiteSpace(_company.Phone) if (string.IsNullOrWhiteSpace(Company.Phone)
&& !string.IsNullOrWhiteSpace(_company.Account) && !string.IsNullOrWhiteSpace(Company.Account)
&& _company.Account != "NY" && _company.Account.Length > 7) && Company.Account != "NY" && Company.Account.Length > 7)
{ {
_company.Phone = _company.Account[..8]; Company.Phone = Company.Account[..8];
} }
// Populate base activity information
_activity.BcId = _company.BcId; Activity.BcId = Company.BcId;
_activity.ActivityStatusEnum = "noSale"; Activity.ActivityStatusEnum = "noSale";
_activity.VisitTypeEnum = _company.Account is "" or "NY" ? "new" : "recall"; Activity.VisitTypeEnum = Company.Account is "" or "NY" ? "new" : "recall";
Activity.CompanyId = Company.CompanyId;
if (_company.HasFolded == 1) Activity.SalesRepId = ThisUserInfo.Id;
_activity.OrderMessage = "Virksomheden er ophørt."; Activity.SalesRep = ThisUserInfo.Advisor;
Activity.CountryCode = ThisUserInfo.CountryCode;
// permanent identifications Activity.Account = Company.Account;
_activity.CompanyId = _company.CompanyId; Activity.VatNumber = Company.VatNumber;
_activity.SalesRepId = _ux.Id; Activity.Email = Company.Email;
_activity.SalesRep = _ux.Advisor; Activity.Phone = Company.Phone;
_activity.CountryCode = _ux.CountryCode; Activity.Mobile = Company.Mobile;
Activity.Name = Company.Name;
_activity.Account = _company.Account; Activity.Address1 = Company.Address1;
_activity.VatNumber = _company.VatNumber; Activity.Address2 = Company.Address2;
_activity.Email = _company.Email; Activity.ZipCode = Company.ZipCode;
_activity.Phone = _company.Phone; Activity.City = Company.City;
_activity.Mobile = _company.Mobile; Activity.DlvName = Company.Name;
Activity.DlvAddress1 = Company.Address1;
_activity.Name = _company.Name; Activity.DlvAddress2 = Company.Address2;
_activity.Address1 = _company.Address1; Activity.DlvZipCode = Company.ZipCode;
_activity.Address2 = _company.Address2; Activity.DlvCity = Company.City;
_activity.ZipCode = _company.ZipCode; // Initialize date variable
_activity.City = _company.City; SelectedDate = string.IsNullOrWhiteSpace(UserPrefs.WorkDate) ? DateTime.Now : DateTime.Parse(UserPrefs.WorkDate);
// raise flag if report is closed
_activity.DlvName = _company.Name; ReportClosed = await CrmReportRepo.ReportExist($"{SelectedDate:yyyy-MM-dd}");
_activity.DlvAddress1 = _company.Address1; // Ask for confirmation of date
_activity.DlvAddress2 = _company.Address2; Logger.LogDebug("Preferences.DateConfirmed => {}", UserPrefs.DateConfirmed);
_activity.DlvZipCode = _company.ZipCode; if (!UserPrefs.DateConfirmed)
_activity.DlvCity = _company.City; {
PromptDateConfirm = $"Aktiviteter oprettes med dato {SelectedDate.ToShortDateString()}. Er dette OK?";
ConfirmWorkDate.Show();
}
// Lines may already have been added from the company inventory page
if (DraftStateProvider.Draft.Items.Any())
{
// set dropdown selection accordingly
Activity.ActivityTypeEnum = "onSite";
Activity.ActivityStatusEnum = "order";
}
StateHasChanged();
} }
/// <summary>
/// Work Date confirm callback
/// </summary>
private async Task WorkDateConfirmCallback()
{
await Prefs.SetDateConfirmed(true);
ConfirmWorkDate.Hide();
StateHasChanged();
}
/// <summary>
/// Show Price list modal
/// </summary>
private void CallPriceListModal() private void CallPriceListModal()
{ {
PriceListModal.Show(); PriceListModal.Show();
} }
/// <summary>
private void VerifyWorkDateConfirmed() /// Price List modal callback
{ /// </summary>
Logger.LogDebug("Preferences.DateConfirmed => {}", _prefs.DateConfirmed); /// <param name="sku"></param>
private async Task PriceListCallback(SelectedSku sku)
if (_prefs.DateConfirmed) return;
_confirmDatePrompt = $"Dato {_activity.ActivityDate}?";
ConfirmWorkDate.Show();
}
private async Task WorkDateConfirmed()
{
await PreferenceService.SetDateConfirmed(true);
ConfirmWorkDate.Hide();
}
private async Task SelectSku(SelectedSku sku)
{ {
// get selected item // get selected item
if (string.IsNullOrWhiteSpace(sku.ItemId)) if (string.IsNullOrWhiteSpace(sku.ItemId))
return; return;
_selectedItem = await Catalog.GetSalesItemId(sku.ItemId); SelectedItem = await Catalog.GetSalesItemId(sku.ItemId);
ShowItem = true; ShowItem = true;
Price = sku.Rate; Price = sku.Rate;
Quantity = sku.Quantity; Quantity = sku.Quantity;
StateHasChanged(); StateHasChanged();
} }
/// <summary>
/// Show Price History modal
/// </summary>
private void CallPriceHistoryModal() private void CallPriceHistoryModal()
{ {
if(ShowItem) if(ShowItem)
PriceHistoryModal.Show(); PriceHistoryModal.Show();
} }
/// <summary>
private void SelectPrice(decimal price) /// Price History modal callback
/// </summary>
/// <param name="price"></param>
private void PriceHistoryCallback(decimal price)
{ {
if (price == 0) if (price == 0)
return; return;
@ -195,30 +197,29 @@ public partial class CrmActivityNewPage : IDisposable
StateHasChanged(); StateHasChanged();
} }
private async Task SetWorkDate(string workDate) /// <summary>
/// Work Date component callback
/// </summary>
/// <param name="workDate"></param>
private async Task WorkDateComponentCallback(string workDate)
{ {
_selectedDate = workDate; ReportClosed = await CrmReportRepo.ReportExist(workDate);
_workDate = DateTime.Parse(_selectedDate); SelectedDate = DateTime.Parse(workDate);
_activity.ActivityDate = _selectedDate; Activity.ActivityDate = workDate;
_reportClosed = await CrmReportRepo.ReportExist(_selectedDate);
} }
/// <summary>
/// Validate and Create Activity
/// </summary>
private async Task CreateActivity() private async Task CreateActivity()
{ {
// if (!_prefs.DateConfirmed) if (string.IsNullOrWhiteSpace(Activity.Address1))
// {
// _confirmDatePrompt = $"Er arbejdsdato {_selectedDate} korrekt?";
// CallConfirmWorkDate();
// }
if (string.IsNullOrWhiteSpace(_activity.Address1))
{ {
Toast.ShowError("Kunde adresse er ufuldstændig."); Toast.ShowError("Kunde adresse er ufuldstændig.");
return; return;
} }
if (_activity.ActivityStatusEnum == "order") if (Activity.ActivityStatusEnum == "order")
{ {
if (DraftStateProvider.Draft.Items.Count == 0) if (DraftStateProvider.Draft.Items.Count == 0)
{ {
@ -226,27 +227,36 @@ public partial class CrmActivityNewPage : IDisposable
return; return;
} }
if (string.IsNullOrWhiteSpace(_activity.Phone)) if (string.IsNullOrWhiteSpace(Activity.Phone))
{ {
Toast.ShowError("Ved bestilling til ny kunde skal telefon nummer angives."); Toast.ShowError("Ved bestilling til ny kunde skal telefon nummer angives.");
return; return;
} }
} }
_poFormInvalid = true; PoFormInvalid = true;
// reset selected item
_activity.ActivityDate = $"{_workDate:yyyy-MM-dd}"; SelectedItem = new SalesItemView();
_activity.OurRef = _activity.ActivityTypeEnum switch // check if phone number need to be updated
if (OldPhone != Activity.Phone)
{ {
"phone" => $"T:{_ux.FullName.Split(" ")[0]}", Company.Phone = Activity.Phone;
"onSite" => $"B:{_ux.FullName.Split(" ")[0]}", // update company phone record
Logger.LogDebug("CrmNewActivityPage => \n New Phone Number \n {}", Activity.Phone);
await CompanyRepo.UpdateCompany(Company.CompanyId, Company);
}
// begin assembling activity
Activity.ActivityDate = $"{SelectedDate:yyyy-MM-dd}";
Activity.OurRef = Activity.ActivityTypeEnum switch
{
"phone" => $"T:{ThisUserInfo.FullName.Split(" ")[0]}",
"onSite" => $"B:{ThisUserInfo.FullName.Split(" ")[0]}",
_ => "" _ => ""
}; };
if (_activity.Express) if (Activity.Express)
_activity.OurRef = $"E{_activity.OurRef}"; Activity.OurRef = $"E{Activity.OurRef}";
// begin lines
_activity.Lines = new List<ActivityLineDto>(); Activity.Lines = new List<ActivityLineDto>();
var ln = 0; var ln = 0;
if (DraftStateProvider.Draft.Items.Count != 0) if (DraftStateProvider.Draft.Items.Count != 0)
{ {
@ -264,22 +274,12 @@ public partial class CrmActivityNewPage : IDisposable
Location = item.Item.Location Location = item.Item.Location
}) })
.ToList(); .ToList();
_activity.Lines = lines; Activity.Lines = lines;
} }
if (_phone != _activity.Phone) Logger.LogDebug("CrmNewActivityPage => \n {}", JsonSerializer.Serialize(Activity));
{
_company.Phone = _activity.Phone;
// update company phone record
await CompanyRepo.UpdateCompany(_company.CompanyId, _company);
}
Logger.LogDebug("CrmNewActivityPage => \n {}", JsonSerializer.Serialize(_activity));
// post to api // post to api
var result = await CrmActivityRepo.CreateActivity(_activity); var result = await CrmActivityRepo.CreateActivity(Activity);
Logger.LogDebug("ApiResponseView => \n {}", JsonSerializer.Serialize(result)); Logger.LogDebug("ApiResponseView => \n {}", JsonSerializer.Serialize(result));
// show result message // show result message
if (result.IsSuccess) if (result.IsSuccess)
{ {
@ -289,21 +289,20 @@ public partial class CrmActivityNewPage : IDisposable
return; return;
} }
_poFormInvalid = false; PoFormInvalid = false;
Toast.ShowError(result.Message, "ORDRE FEJL"); Toast.ShowError(result.Message, "ORDRE FEJL");
_selectedItem = new SalesItemView();
} }
/// <summary>
private void CheckActivity() /// Delete current draft
{ /// </summary>
InvalidActivityType = string.IsNullOrWhiteSpace(_activity.ActivityTypeEnum);
}
private async Task DeleteDraft() private async Task DeleteDraft()
{ {
await DraftStateProvider.DeleteDraftAsync(); await DraftStateProvider.DeleteDraftAsync();
} }
/// <summary>
/// Add item to draft
/// </summary>
/// <param name="salesItem"></param>
private async Task AddItem(SalesItemView salesItem) private async Task AddItem(SalesItemView salesItem)
{ {
ShowItem = false; ShowItem = false;
@ -326,6 +325,10 @@ public partial class CrmActivityNewPage : IDisposable
// save the item using the CartStateProvider's save method // save the item using the CartStateProvider's save method
await DraftStateProvider.SaveChangesAsync(); await DraftStateProvider.SaveChangesAsync();
} }
/// <summary>
/// Remove item from draft
/// </summary>
/// <param name="item"></param>
private async Task RemoveItem(DraftItem item) private async Task RemoveItem(DraftItem item)
{ {
// remove item // remove item
@ -333,53 +336,57 @@ public partial class CrmActivityNewPage : IDisposable
// save the remaining draft // save the remaining draft
await DraftStateProvider.SaveChangesAsync(); await DraftStateProvider.SaveChangesAsync();
} }
/// <summary>
/// Edit Context handle field change
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HandleFieldChanged(object sender, FieldChangedEventArgs e) private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
{ {
// InvalidCanvas = InvalidActivityType; // InvalidCanvas = InvalidActivityType;
InvalidActivity = InvalidActivityType InvalidActivity = InvalidActivityType
|| _poFormInvalid || PoFormInvalid
|| DraftStateProvider.Draft.Items.Count == 0 || DraftStateProvider.Draft.Items.Count == 0
|| (_activity.ActivityStatusEnum == "offer" && string.IsNullOrWhiteSpace(_activity.Email)); || (Activity.ActivityStatusEnum == "offer" && string.IsNullOrWhiteSpace(Activity.Email));
if (_activity.YourRef.Length > 35 || _activity.ReferenceNumber.Length > 20) if (Activity.YourRef.Length > 35 || Activity.ReferenceNumber.Length > 20)
{ {
_poFormInvalid = true; PoFormInvalid = true;
return; return;
} }
if (InvalidActivity) if (InvalidActivity)
{ {
_poFormInvalid = true; PoFormInvalid = true;
return; return;
} }
PoFormInvalid = !ActivityContext.Validate();
_poFormInvalid = !_editContext.Validate();
StateHasChanged(); StateHasChanged();
} }
/// <summary>
/// Edit Context handle validation change
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ValidationChanged(object sender, ValidationStateChangedEventArgs e) private void ValidationChanged(object sender, ValidationStateChangedEventArgs e)
{ {
if (string.IsNullOrEmpty(_activity.ActivityTypeEnum) && !_reportClosed) if (string.IsNullOrEmpty(Activity.ActivityTypeEnum) && !ReportClosed)
{ {
Toast.ShowWarning("Aktivitet type kan ikke være tom"); Toast.ShowWarning("Aktivitet type kan ikke være tom");
return; return;
} }
PoFormInvalid = false;
_poFormInvalid = false; ActivityContext.OnFieldChanged -= HandleFieldChanged;
ActivityContext.OnValidationStateChanged -= ValidationChanged;
_editContext.OnFieldChanged -= HandleFieldChanged; ActivityContext = new EditContext(Activity);
_editContext.OnValidationStateChanged -= ValidationChanged; ActivityContext.OnFieldChanged += HandleFieldChanged;
_editContext = new EditContext(_activity); ActivityContext.OnValidationStateChanged += ValidationChanged;
_editContext.OnFieldChanged += HandleFieldChanged;
_editContext.OnValidationStateChanged += ValidationChanged;
VerifyWorkDateConfirmed();
} }
/// <summary>
/// Implement Dispose from IDisposable
/// </summary>
public void Dispose() public void Dispose()
{ {
Interceptor.DisposeEvent(); Interceptor.DisposeEvent();
_editContext.OnFieldChanged -= HandleFieldChanged; ActivityContext.OnFieldChanged -= HandleFieldChanged;
_editContext.OnValidationStateChanged -= ValidationChanged; ActivityContext.OnValidationStateChanged -= ValidationChanged;
} }
} }

View file

@ -20,12 +20,9 @@
@attribute [Authorize(Roles = "Advisor")] @attribute [Authorize(Roles = "Advisor")]
@page "/activity-today" @page "/activity-today"
<div class="row mb-1 align-items-center"> <div class="row bg-dark text-white rounded-2 mb-2 py-2 align-items-center">
<div class="col-md-5"> <div class="col">
<h3 class="workDate">@(string.IsNullOrWhiteSpace(_workDate) ? "" : $"{DateTime.Parse(_workDate).ToLongDateString()}")</h3> <WorkDateComponent OnChangedCallback="GetActivities" />
</div>
<div class="col-md-2">
<WorkDateComponent OnChanged="GetActivities" />
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<AdvisorActivityKmStartComponent /> <AdvisorActivityKmStartComponent />
@ -33,7 +30,7 @@
<div class="col-md-2"> <div class="col-md-2">
@if (_reportExist) @if (_reportExist)
{ {
<a class="btn btn-primary" href="/sales-reports/view/@_workDate">RAPPORT</a> <a class="btn btn-primary" href="/sales-reports/view/@($"{SelectedDate:yyyy-MM-dd}")">RAPPORT</a>
} }
else else
{ {

View file

@ -36,30 +36,28 @@ public partial class CrmActivityTodayPage : IDisposable
[Inject] public IToastService _toast { get; set; } [Inject] public IToastService _toast { get; set; }
private ReportStatusView? ReportStatusView { get; set; } = new(); private ReportStatusView? ReportStatusView { get; set; } = new();
private Preferences _prefs { get; set; } = new(); private Preferences _prefs { get; set; } = new();
private string _workDate { get; set; } = $"{DateTime.Now:yyyy-MM-dd}"; private DateTime SelectedDate { get; set; }
private bool _reportExist = false; private bool _reportExist = false;
private bool Loading { get; set; } = true; private bool Loading { get; set; } = true;
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
_prefs = await _preferenceService.GetPreferences(); _prefs = await _preferenceService.GetPreferences();
if(!string.IsNullOrWhiteSpace(_prefs.WorkDate)) SelectedDate = string.IsNullOrWhiteSpace(_prefs.WorkDate) ? DateTime.Now : DateTime.Parse(_prefs.WorkDate);
_workDate = _prefs.WorkDate;
_interceptor.RegisterEvent(); _interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent(); _interceptor.RegisterBeforeSendEvent();
_reportExist = await CrmReportRepo.ReportExist(_workDate); _reportExist = await CrmReportRepo.ReportExist($"{SelectedDate:yyyy-MM-dd}");
await GetActivities($"{SelectedDate:yyyy-MM-dd}");
await GetActivities(_workDate);
} }
private async Task GetActivities(string workDate) private async Task GetActivities(string workDate)
{ {
_toast.ShowInfo("Vent nogle sekunder for data"); _toast.ShowInfo("Vent nogle sekunder for data");
_workDate = workDate; SelectedDate = DateTime.Parse(workDate);
ReportStatusView = new ReportStatusView(); ReportStatusView = new ReportStatusView();
ReportStatusView = await CrmActivityRepo.GetActivities(workDate); ReportStatusView = await CrmActivityRepo.GetActivities($"{SelectedDate:yyyy-MM-dd}");
_logger.LogDebug("Activities => {}", JsonSerializer.Serialize(ReportStatusView)); _logger.LogDebug("Activities => {}", JsonSerializer.Serialize(ReportStatusView));
Loading = false; Loading = false;
} }

View file

@ -19,23 +19,21 @@
@using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Authorization
@page "/companies/{CompanyId}/h/i" @page "/companies/{CompanyId}/h/i"
@attribute [Authorize(Roles = "Advisor")] @attribute [Authorize(Roles = "Advisor")]
@if (!Loading)
<div class="card"> {
<div class="card-header"> <div class="row">
<div class="row"> <div class="col-6">
<div class="col-6"> <h3>@Company.Name</h3>
<h3>@_company.Name</h3> </div>
</div> <div class="col-6 align-content-end">
<div class="col-3 align-content-end"> <a class="btn btn-primary" href="/companies/@Company.CompanyId">Kundekort</a>
<a class="btn btn-primary" href="/companies/@_company.CompanyId">Kundekort</a> <a class="btn btn-primary" href="/companies/@Company.CompanyId/activities/new">Besøg</a>
</div>
<div class="col-3">
<button class="btn btn-warning" @onclick="RefreshHistory" disabled="@_working">@_btnUpdateText</button>
<label class="fw-bold ms-2">@_company.HistorySync</label>
</div>
</div> </div>
</div> </div>
<div class="card-body"> <ProductInventoryTableComponent CompanyId="@CompanyId" Inventory="Inventory" />
<ProductInventoryTableComponent CompanyId="@CompanyId" Inventory="_inventory"></ProductInventoryTableComponent> }
</div> @if (Loading)
</div> {
<LoaderThreeDots Loading="Loading" />
}

View file

@ -28,39 +28,39 @@ public partial class CrmCompanyInventoryPage : IDisposable
{ {
[Parameter] public string CompanyId { get; set; } = ""; [Parameter] public string CompanyId { get; set; } = "";
[Inject] public ICrmHistoryHttpRepository CrmHistoryRepo { get; set; } [Inject] public ICrmHistoryHttpRepository CrmHistoryRepo { get; set; }
[Inject] public ICrmCompanyHttpRepository _companyRepo { get; set; } [Inject] public ICrmCompanyHttpRepository CompanyRepo { get; set; }
[Inject] public HttpInterceptorService _interceptor { get; set; } [Inject] public HttpInterceptorService Interceptor { get; set; }
[Inject] public IToastService _toast { get; set; } [Inject] public IToastService Toaster { get; set; }
private CompanyDto _company { get; set; } = new(); private CompanyDto Company { get; set; } = new();
private List<ProductInventoryView> _inventory { get; set; } = new(); private List<ProductInventoryView> Inventory { get; set; } = new();
private string _btnUpdateText { get; set; } = "check"; private bool Loading { get; set; } = true;
private bool _working { get; set; }
protected override async Task OnInitializedAsync() protected override async Task OnInitializedAsync()
{ {
Console.WriteLine($"CompanyId => {CompanyId}"); Interceptor.RegisterEvent();
_interceptor.RegisterEvent(); Interceptor.RegisterBeforeSendEvent();
_interceptor.RegisterBeforeSendEvent(); Company = await CompanyRepo.GetCompanyById(CompanyId);
_company = await _companyRepo.GetCompanyById(CompanyId); var ts = await CrmHistoryRepo.UpdateProductHistory(Company.CompanyId, $"{DateTime.Parse(Company.HistorySync):yyyy-MM-dd}");;
_inventory = await CrmHistoryRepo.FetchInventory(CompanyId); Inventory = await CrmHistoryRepo.FetchInventory(CompanyId);
_inventory = _inventory.OrderBy(x => x.Description).ToList(); Inventory = Inventory.OrderBy(x => x.Description).ToList();
Loading = false;
} }
private async Task RefreshHistory() // private async Task RefreshHistory()
{ // {
_working = true; // _working = true;
_btnUpdateText = "vent venligst ..."; // _btnUpdateText = "vent venligst ...";
_toast.ShowInfo("Vent mens data checkes ..."); // _toast.ShowInfo("Vent mens data checkes ...");
var ts = await CrmHistoryRepo.UpdateProductHistory(_company.CompanyId, $"{DateTime.Parse(_company.HistorySync):yyyy-MM-dd}");; // var ts = await CrmHistoryRepo.UpdateProductHistory(_company.CompanyId, $"{DateTime.Parse(_company.HistorySync):yyyy-MM-dd}");;
_company.HistorySync = ts.Replace("\"", ""); // _company.HistorySync = ts.Replace("\"", "");
_btnUpdateText = "check"; // _btnUpdateText = "check";
_inventory = await CrmHistoryRepo.FetchInventory(CompanyId); // _inventory = await CrmHistoryRepo.FetchInventory(CompanyId);
_inventory = _inventory.OrderBy(x => x.Description).ToList(); // _inventory = _inventory.OrderBy(x => x.Description).ToList();
_working = false; // _working = false;
// }
}
public void Dispose() public void Dispose()
{ {
_interceptor.DisposeEvent(); Interceptor.DisposeEvent();
} }
} }

View file

@ -20,25 +20,19 @@
@attribute [Authorize(Roles = "Advisor")] @attribute [Authorize(Roles = "Advisor")]
@page "/sales-reports/new" @page "/sales-reports/new"
<EditForm EditContext="_editContext"> <div class="row bg-dark text-white rounded-2 mb-2 py-2 align-items-center">
<div class="card"> <div class="col">
<div class="card-header bg-dark text-white rounded-2"> <WorkDateComponent OnChangedCallback="SetWorkDate"/>
<div class="row"> </div>
<div class="col-md-6 justify-content-center"> <div class="col-3 justify-content-center">
<h3 class="workDate">@(_workDate.ToLongDateString())</h3> @if (_working)
</div> {
<div class="col-md-4 justify-content-center"> <LoaderThreeDots/>
<WorkDateComponent SelectedDate="@($"{_workDate:yyyy-MM-dd}")" OnChanged="SetWorkDate"></WorkDateComponent> }
</div>
<div class="col-md-2 justify-content-center">
@if (_working)
{
<LoaderThreeDots />
}
</div>
</div> </div>
</div> </div>
<div class="card-body">
<EditForm EditContext="_editContext">
<div class="sticky-top bg-success bg-opacity-50 rounded-2 px-3"> <div class="sticky-top bg-success bg-opacity-50 rounded-2 px-3">
<table class="table"> <table class="table">
<thead> <thead>
@ -100,167 +94,188 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> @if (!_report.DayTypeEnum.ToLower().Contains("leave"))
@if (!_report.DayTypeEnum.ToLower().Contains("leave"))
{
<table class="table">
<thead>
<tr>
<th scope="col" style="width:60%">Tekst</th>
<th scope="col">Medkørende Supervisor</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<InputTextArea id="description" class="form-control" @bind-Value="_report.Description"/>
<ValidationMessage For="@(() => _report.Description)"/>
</td>
<td>
<InputText id="supervisedBy" class="form-control" @bind-Value="_report.SupervisedBy"/>
<ValidationMessage For="@(() => _report.SupervisedBy)"/>
</td>
</tr>
</tbody>
</table>
<table class="table">
<thead>
<tr>
<th scope="col">Km aften</th>
<th scope="col">Km morgen</th>
<th scope="col">Km privat</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<InputNumber class="form-control" @bind-Value="@_report.Figures.KmEvening"
disabled="@(_noFigures)"/>
</td>
<td>
<InputNumber class="form-control" @bind-Value="@_report.Figures.KmMorning"
disabled="@(_noFigures)"/>
</td>
<td>
<InputNumber class="form-control" @bind-Value="@_report.Figures.DistancePrivate"
disabled="@(_noFigures)"/>
</td>
</tr>
</tbody>
</table>
<table class="table table-striped">
<thead>
<tr class="bg-dark text-white opacity-75">
<th></th>
<th class="text-center" colspan="2" scope="col">Dagens Demo @(_report.Figures.NewDemoCount + _report.Figures.RecallDemoCount)</th>
<th class="text-center border-end" colspan="2" scope="col">Dagens Resultat</th>
<th class="text-center" colspan="4" scope="col">Måneds Resultat</th>
</tr>
</thead>
<tbody>
<tr class="bg-dark bg-opacity-50">
<td></td>
<th class="text-end text-white" scope="col">Besøg</th>
<th class="text-end text-white" scope="col">Demo</th>
<th class="text-end text-white" scope="col">Salg</th>
<th class="text-end text-white border-end" scope="col">Beløb</th>
<th class="text-end text-white" scope="col">Besøg</th>
<th class="text-end text-white" scope="col">Demo</th>
<th class="text-end text-white" scope="col">Salg</th>
<th class="text-end text-white" scope="col">Beløb</th>
</tr>
<tr>
<th scope="row">N</th>
<td class="text-end">@_report.Figures.NewVisitCount</td>
<td class="text-end">@_report.Figures.NewDemoCount</td>
<td class="text-end">@_report.Figures.NewSaleCount</td>
<td class="text-end border-end">@_report.Figures.NewTurnover</td>
<td class="text-end">@_report.Figures.NewVisitCountMonth</td>
<td class="text-end">@_report.Figures.NewDemoCountMonth</td>
<td class="text-end">@_report.Figures.NewSaleCountMonth</td>
<td class="text-end">@_report.Figures.NewTurnoverMonth</td>
</tr>
<tr>
<th scope="row">R</th>
<td class="text-end">@_report.Figures.RecallVisitCount</td>
<td class="text-end">@_report.Figures.RecallDemoCount</td>
<td class="text-end">@_report.Figures.RecallSaleCount</td>
<td class="text-end border-end">@_report.Figures.RecallTurnover</td>
<td class="text-end">@_report.Figures.RecallVisitCountMonth</td>
<td class="text-end">@_report.Figures.RecallDemoCountMonth</td>
<td class="text-end">@_report.Figures.RecallSaleCountMonth</td>
<td class="text-end">@_report.Figures.RecallTurnoverMonth</td>
</tr>
<tr>
<th scope="row">SAS</th>
<td class="bg-light"></td>
<td class="bg-light"></td>
<td class="text-end">@_report.Figures.SasCount</td>
<td class="text-end border-end">@_report.Figures.SasTurnover</td>
<td class="bg-light"></td>
<td class="bg-light"></td>
<td class="text-end">@_report.Figures.SasCountMonth</td>
<td class="text-end">@_report.Figures.SasTurnoverMonth</td>
</tr>
<tr>
<th scope="row">TOTAL</th>
<td class="text-end">@_report.Figures.TotalVisitCount</td>
<td class="text-end">@_report.Figures.TotalDemoCount</td>
<td class="text-end">@_report.Figures.TotalSaleCount</td>
<td class="text-end border-end">@_report.Figures.TotalTurnover</td>
<td class="text-end">@_report.Figures.TotalVisitCountMonth</td>
<td class="text-end">@_report.Figures.TotalDemoCountMonth</td>
<td class="text-end">@_report.Figures.TotalSaleCountMonth</td>
<td class="text-end">@_report.Figures.TotalTurnoverMonth</td>
</tr>
</tbody>
</table>
@if (_activities != null)
{ {
<table class="table"> <table class="table">
<thead> <thead>
<tr class="bg-black opacity-75 text-white"> <tr>
<th scope="col">Kunde</th> <th scope="col" style="width:60%">Tekst</th>
<th scope="col">Bynavn</th> <th scope="col">Medkørende Supervisor</th>
<th scope="col">Demo</th>
<th scope="col">Salg</th>
<th scope="col">Note</th>
<th scope="col" class="text-end">sas</th>
<th scope="col" class="text-end">Beløb</th>
<th scope="col" class="text-center"><i class="oi oi-phone"></i></th>
<th scope="col" class="text-center"><i class="oi oi-flash"></i></th>
<th scope="col" class="text-center"><i class="oi oi-calculator"></i></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach (var activity in _activities)
{
<tr>
<td class="text-sm-start">@activity.Company.Name</td>
<td class="text-sm-start">@activity.Company.City</td>
<td class="text-sm-start">@activity.Demo</td>
<td class="text-sm-start">@activity.Sales</td>
<td class="text-sm-start">@activity.OfficeNote</td>
<td class="text-end">@($"{activity.SasAmount:N2}")</td>
<td class="text-center">@(activity.StatusTypeEnum.Contains("Quote") ? $"{0:N2}" : $"{activity.OrderAmount:N2}")</td>
<td class="text-center">@if(activity.OurRef.Contains("T:")){ <i class="oi oi-phone"></i> }</td>
<td class="text-center">@if(activity.Express){ <i class="oi oi-flash"></i> }</td>
<td class="text-center">@if(activity.StatusTypeEnum == "Quote"){ <i class="oi oi-calculator"></i> }</td>
</tr>
}
<tr> <tr>
<td colspan="5"></td> <td>
<td class="text-end">Total</td> <InputTextArea id="description" class="form-control" @bind-Value="_report.Description"/>
<td class="text-end">@_activities.Where(x => x.StatusTypeEnum != "Quote").Sum(x => x.OrderAmount)</td> <ValidationMessage For="@(() => _report.Description)"/>
<td colspan="2"></td> </td>
<td>
<InputText id="supervisedBy" class="form-control" @bind-Value="_report.SupervisedBy"/>
<ValidationMessage For="@(() => _report.SupervisedBy)"/>
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<table class="table">
<thead>
<tr>
<th scope="col">Km aften</th>
<th scope="col">Km morgen</th>
<th scope="col">Km privat</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<InputNumber class="form-control" @bind-Value="@_report.Figures.KmEvening"
disabled="@(_noFigures)"/>
</td>
<td>
<InputNumber class="form-control" @bind-Value="@_report.Figures.KmMorning"
disabled="@(_noFigures)"/>
</td>
<td>
<InputNumber class="form-control" @bind-Value="@_report.Figures.DistancePrivate"
disabled="@(_noFigures)"/>
</td>
</tr>
</tbody>
</table>
<table class="table table-striped">
<thead>
<tr class="bg-dark text-white opacity-75">
<th></th>
<th class="text-center" colspan="2" scope="col">Dagens Demo @(_report.Figures.NewDemoCount + _report.Figures.RecallDemoCount)</th>
<th class="text-center border-end" colspan="2" scope="col">Dagens Resultat</th>
<th class="text-center" colspan="4" scope="col">Måneds Resultat</th>
</tr>
</thead>
<tbody>
<tr class="bg-dark bg-opacity-50">
<td></td>
<th class="text-end text-white" scope="col">Besøg</th>
<th class="text-end text-white" scope="col">Demo</th>
<th class="text-end text-white" scope="col">Salg</th>
<th class="text-end text-white border-end" scope="col">Beløb</th>
<th class="text-end text-white" scope="col">Besøg</th>
<th class="text-end text-white" scope="col">Demo</th>
<th class="text-end text-white" scope="col">Salg</th>
<th class="text-end text-white" scope="col">Beløb</th>
</tr>
<tr>
<th scope="row">N</th>
<td class="text-end">@_report.Figures.NewVisitCount</td>
<td class="text-end">@_report.Figures.NewDemoCount</td>
<td class="text-end">@_report.Figures.NewSaleCount</td>
<td class="text-end border-end">@_report.Figures.NewTurnover</td>
<td class="text-end">@_report.Figures.NewVisitCountMonth</td>
<td class="text-end">@_report.Figures.NewDemoCountMonth</td>
<td class="text-end">@_report.Figures.NewSaleCountMonth</td>
<td class="text-end">@_report.Figures.NewTurnoverMonth</td>
</tr>
<tr>
<th scope="row">R</th>
<td class="text-end">@_report.Figures.RecallVisitCount</td>
<td class="text-end">@_report.Figures.RecallDemoCount</td>
<td class="text-end">@_report.Figures.RecallSaleCount</td>
<td class="text-end border-end">@_report.Figures.RecallTurnover</td>
<td class="text-end">@_report.Figures.RecallVisitCountMonth</td>
<td class="text-end">@_report.Figures.RecallDemoCountMonth</td>
<td class="text-end">@_report.Figures.RecallSaleCountMonth</td>
<td class="text-end">@_report.Figures.RecallTurnoverMonth</td>
</tr>
<tr>
<th scope="row">SAS</th>
<td class="bg-light"></td>
<td class="bg-light"></td>
<td class="text-end">@_report.Figures.SasCount</td>
<td class="text-end border-end">@_report.Figures.SasTurnover</td>
<td class="bg-light"></td>
<td class="bg-light"></td>
<td class="text-end">@_report.Figures.SasCountMonth</td>
<td class="text-end">@_report.Figures.SasTurnoverMonth</td>
</tr>
<tr>
<th scope="row">TOTAL</th>
<td class="text-end">@_report.Figures.TotalVisitCount</td>
<td class="text-end">@_report.Figures.TotalDemoCount</td>
<td class="text-end">@_report.Figures.TotalSaleCount</td>
<td class="text-end border-end">@_report.Figures.TotalTurnover</td>
<td class="text-end">@_report.Figures.TotalVisitCountMonth</td>
<td class="text-end">@_report.Figures.TotalDemoCountMonth</td>
<td class="text-end">@_report.Figures.TotalSaleCountMonth</td>
<td class="text-end">@_report.Figures.TotalTurnoverMonth</td>
</tr>
</tbody>
</table>
@if (_activities != null)
{
<table class="table">
<thead>
<tr class="bg-black opacity-75 text-white">
<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 scope="col" class="text-end">sas</th>
<th scope="col" class="text-end">Beløb</th>
<th scope="col" class="text-center">
<i class="oi oi-phone"></i>
</th>
<th scope="col" class="text-center">
<i class="oi oi-flash"></i>
</th>
<th scope="col" class="text-center">
<i class="oi oi-calculator"></i>
</th>
</tr>
</thead>
<tbody>
@foreach (var activity in _activities)
{
<tr>
<td class="text-sm-start">@activity.Company.Name</td>
<td class="text-sm-start">@activity.Company.City</td>
<td class="text-sm-start">@activity.Demo</td>
<td class="text-sm-start">@activity.Sales</td>
<td class="text-sm-start">@activity.OfficeNote</td>
<td class="text-end">@($"{activity.SasAmount:N2}")</td>
<td class="text-center">@(activity.StatusTypeEnum.Contains("Quote") ? $"{0:N2}" : $"{activity.OrderAmount:N2}")</td>
<td class="text-center">
@if (activity.OurRef.Contains("T:"))
{
<i class="oi oi-phone"></i>
}
</td>
<td class="text-center">
@if (activity.Express)
{
<i class="oi oi-flash"></i>
}
</td>
<td class="text-center">
@if (activity.StatusTypeEnum == "Quote")
{
<i class="oi oi-calculator"></i>
}
</td>
</tr>
}
<tr>
<td colspan="5"></td>
<td class="text-end">Total</td>
<td class="text-end">@_activities.Where(x => x.StatusTypeEnum != "Quote").Sum(x => x.OrderAmount)</td>
<td colspan="2"></td>
</tr>
</tbody>
</table>
}
} }
}
</div>
</div> </div>
</EditForm> </EditForm>
<ConfirmationModal BodyMessage="@_prompt" OnOkClicked="ReportSaveConfirmed" @ref="_confirmReport"/> <ConfirmationModal BodyMessage="@_prompt" OnOkClicked="ReportSaveConfirmed" @ref="_confirmReport"/>

View file

@ -21,14 +21,12 @@
@attribute [Authorize(Roles = "Advisor,Admin,Supervisor")] @attribute [Authorize(Roles = "Advisor,Admin,Supervisor")]
<div class="report-main"> <div class="report-main">
<div class="row mb-3 d-print-none">
<div class="col-md-6 align-content-center"> <div class="row bg-dark text-white rounded-2 mb-2 py-2 align-items-center d-print-none">
<h3 class="workDate">@DateTime.Parse(ReportDate).ToLongDateString()</h3> <div class="col">
<WorkDateComponent OnChangedCallback="GetReport" />
</div> </div>
<div class="col col-md-4 align-content-center"> <div class="col col-md-3 align-content-center">
<WorkDateComponent SelectedDate="@ReportDate" OnChanged="GetReport" />
</div>
<div class="col col-md-1 align-content-center">
<button class="btn btn-warning" type="button" onclick="window.print();">Print</button> <button class="btn btn-warning" type="button" onclick="window.print();">Print</button>
</div> </div>
</div> </div>

View file

@ -41,6 +41,7 @@ public partial class CrmReportViewPage
{ {
_report = new ReportView(); _report = new ReportView();
_items = new List<ReportItemView>(); _items = new List<ReportItemView>();
if(workDate != ReportDate) if(workDate != ReportDate)
_navigator.NavigateTo($"/sales-reports/view/{workDate}"); _navigator.NavigateTo($"/sales-reports/view/{workDate}");
_report = await CrmReportRepo.GetReport(workDate); _report = await CrmReportRepo.GetReport(workDate);

View file

@ -23,13 +23,13 @@
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<div class="row mb-1 align-items-center"> <div class="row mb-1 align-items-center">
<div class="col"> @* <div class="col"> *@
<h3 class="workDate">@(string.IsNullOrWhiteSpace(_workDate) ? "" : $"{DateTime.Parse(_workDate).ToLongDateString()}")</h3> @* <h3 class="workDate">@(string.IsNullOrWhiteSpace(_workDate) ? "" : $"{DateTime.Parse(_workDate).ToLongDateString()}")</h3> *@
@* </div> *@
<div class="col-md-6">
<WorkDateComponent OnChangedCallback="GetTaskItems" />
</div> </div>
<div class="col"> <div class="col-md-6">
<WorkDateComponent SelectedDate="_workDate" OnChanged="GetTaskItems"></WorkDateComponent>
</div>
<div class="col">
<a class="btn btn-primary" href="/task-items/new">NY OPGAVE</a> <a class="btn btn-primary" href="/task-items/new">NY OPGAVE</a>
</div> </div>
</div> </div>

View file

@ -22,13 +22,13 @@
<div class="report-main"> <div class="report-main">
<div class="row mb-3 d-print-none"> <div class="row mb-3 d-print-none">
<div class="col-md-6 align-content-center"> @* <div class="col-md-6 align-content-center"> *@
<h3 class="workDate">@DateTime.Parse(ReportDate).ToLongDateString()</h3> @* <h3 class="workDate">@DateTime.Parse(ReportDate).ToLongDateString()</h3> *@
@* </div> *@
<div class="col col-md-6 align-content-center">
<WorkDateComponent OnChangedCallback="GetReport" />
</div> </div>
<div class="col col-md-4 align-content-center"> <div class="col col-md-6 align-content-center">
<WorkDateComponent SelectedDate="@ReportDate" OnChanged="GetReport" />
</div>
<div class="col col-md-1 align-content-center">
<button class="btn btn-warning" type="button" onclick="window.print();">Print</button> <button class="btn btn-warning" type="button" onclick="window.print();">Print</button>
</div> </div>
</div> </div>

View file

@ -78,6 +78,7 @@ builder.Services.AddScoped<IAuthenticationService, AuthenticationService>();
builder.Services.AddScoped<RefreshTokenService>(); builder.Services.AddScoped<RefreshTokenService>();
builder.Services.AddScoped<VatInfoLookupService>(); builder.Services.AddScoped<VatInfoLookupService>();
builder.Services.AddScoped<PreferenceService>(); builder.Services.AddScoped<PreferenceService>();
builder.Services.AddScoped<OrderDraftService>();
// --------------------------------------- // ---------------------------------------

View file

@ -0,0 +1,39 @@
// 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]
//
using Blazored.LocalStorage;
using Wonky.Client.Models;
namespace Wonky.Client.Services;
public class OrderDraftService
{
private readonly ILocalStorageService _localStorageService;
public OrderDraftService(ILocalStorageService localStorageService)
{
_localStorageService = localStorageService;
}
public async Task<Draft> GetDraft(string companyId)
{
return await _localStorageService.GetItemAsync<Draft>(companyId) ?? new Draft();
}
public async Task SaveDraft(string companyId, Draft draft)
{
await _localStorageService.SetItemAsync(companyId, draft);
}
}

View file

@ -0,0 +1,38 @@
@*
// 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]
//
*@
<div class="modal" tabindex="-1" role="dialog" style="display:@_modalDisplay">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h3 class="modal-title">Bekræft Venligst</h3>
<button type="button" class="btn-close" @onclick="Hide" data-bs-dismiss="modal" aria-label="Luk"></button>
</div>
<div class="modal-body">
<p class="fw-bold">@BodyMessage</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @onclick="Hide">Afbryd</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" @onclick="() => OnOkClicked.InvokeAsync()">OK</button>
</div>
</div>
</div>
</div>
@if (_showBackdrop)
{
<div class="modal-backdrop fade show"></div>
}

View file

@ -0,0 +1,42 @@
// 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]
//
using Microsoft.AspNetCore.Components;
namespace Wonky.Client.Shared;
public partial class ConfirmWorkDateModal
{
private string _modalDisplay = "";
private bool _showBackdrop;
[Parameter] public string BodyMessage { get; set; } = "";
[Parameter] public EventCallback OnOkClicked { get; set; }
public void Show()
{
_modalDisplay = "block;";
_showBackdrop = true;
StateHasChanged();
}
public void Hide()
{
_modalDisplay = "none;";
_showBackdrop = false;
StateHasChanged();
}
}

View file

@ -22,7 +22,7 @@ namespace Wonky.Client.Shared;
public partial class DraftStateProvider public partial class DraftStateProvider
{ {
[Parameter] public RenderFragment ChildContent { get; set; } [Parameter] public RenderFragment ChildContent { get; set; }
[Parameter] public string Account { get; set; } = "MyCart"; [Parameter] public string DraftId { get; set; } = "";
[Inject] public ILocalStorageService LocalStorageService { get; set; } [Inject] public ILocalStorageService LocalStorageService { get; set; }
public Draft Draft { get; set; } = new(); public Draft Draft { get; set; } = new();
@ -30,8 +30,10 @@ public partial class DraftStateProvider
protected override async Task OnParametersSetAsync() protected override async Task OnParametersSetAsync()
{ {
Draft = await LocalStorageService.GetItemAsync<Draft>(Account); if (string.IsNullOrWhiteSpace(DraftId))
DraftId = "default";
Draft = await LocalStorageService.GetItemAsync<Draft>(DraftId);
if (Draft == null || Draft.Items.Count == 0) if (Draft == null || Draft.Items.Count == 0)
{ {
Draft = new Draft(); Draft = new Draft();
@ -49,12 +51,12 @@ public partial class DraftStateProvider
public async Task SaveChangesAsync() public async Task SaveChangesAsync()
{ {
await LocalStorageService.SetItemAsync(Account, Draft); await LocalStorageService.SetItemAsync(DraftId, Draft);
} }
public async Task DeleteDraftAsync() public async Task DeleteDraftAsync()
{ {
Draft.Items.Clear(); Draft.Items.Clear();
await LocalStorageService.SetItemAsync(Account, Draft); await LocalStorageService.SetItemAsync(DraftId, Draft);
} }
} }

View file

@ -15,7 +15,8 @@
// //
*@ *@
<div class="modal" tabindex="-1" role="dialog" style="display:@_modalDisplay"> @* <div class="modal" tabindex="-1" role="dialog" style="display:@_modalDisplay"> *@
<div class="modal fade" tabindex="-1" style="display:@_modalDisplay">
<div class="modal-dialog"> <div class="modal-dialog">
<div class="modal-content"> <div class="modal-content">
<div class="modal-header bg-info"> <div class="modal-header bg-info">

View file

@ -0,0 +1,94 @@
@*
// 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]
//
*@
@using Wonky.Client.Components
@using Wonky.Client.Helpers
<div class="modal" tabindex="-1" role="dialog" style="display:@_modalDisplay">
<div class="modal-dialog modal-dialog-scrollable modal-lg modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@ProductName</h5>
<button type="button" class="btn-close" @onclick="Hide" data-bs-dismiss="modal" aria-label="Luk"></button>
</div>
<div class="modal-body">
<div class="row align-middle">
<div class="col-sm-4 text-sm-start">
@SalesItem.Name
</div>
<div class="col-sm-2 text-sm-start">
@SalesItem.Sku
</div>
<div class="col-sm-2 text-sm-start">
@SalesItem.ShortName
</div>
<div class="col-sm-4">
<ul class="list-group">
@foreach (var rate in SalesItem.Rates)
{
<li class="list-group-item d-flex justify-content-between align-items-end">
<div class="text-sm-end me-1">@rate.Quantity</div>
<div class="text-sm-end me-1">@rate.Rate</div>
<div>
<a class="btn btn-primary btn-sm" data-bs-dismiss="modal" @onclick="@(() => SelectItem(rate.Quantity, rate.Rate))">
<i class="oi oi-plus"></i>
</a>
</div>
</li>
}
</ul>
</div>
</div>
@if (!string.IsNullOrWhiteSpace(ProductName))
{
<table class="table table-striped">
<thead>
<tr>
<th scope="col">Dato</th>
<th scope="col">Antal</th>
<th scope="col">Rabat</th>
<th scope="col">Pris</th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@foreach (var entry in History)
{
<tr>
<td>@entry.DeliveryDate</td>
<td>@entry.Quantity</td>
<td>@entry.Discount</td>
<td>@entry.Price</td>
<td>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal" @onclick="() => SelectLine(entry)">Overfør</button>
</td>
</tr>
}
</tbody>
</table>
}
else
{
<h3>Ingen data</h3>
}
</div>
</div>
</div>
</div>
@if (_showBackdrop)
{
<div class="modal-backdrop fade show"></div>
}

View file

@ -0,0 +1,92 @@
// 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]
//
using System.Globalization;
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Client.HttpRepository;
using Wonky.Client.Models;
using Wonky.Client.Services;
using Wonky.Entity.Requests;
using Wonky.Entity.Views;
namespace Wonky.Client.Shared;
public partial class InventoryReorderModal
{
[Parameter] public string CompanyId { get; set; } = "";
[Parameter] public SalesItemView SalesItem { get; set; } = new();
[Inject] public ICrmHistoryHttpRepository CrmHistoryRepo { get; set; }
[Parameter] public EventCallback<DraftItem> OnSelected { get; set; }
private List<ProductHistoryView> History { get; set; }
private string ProductName { get; set; } = "";
private string _modalDisplay = "";
private bool _showBackdrop;
protected override async Task OnParametersSetAsync()
{
if (string.IsNullOrWhiteSpace(SalesItem.Sku))
return;
History = await CrmHistoryRepo.FetchHistory(CompanyId, SalesItem.Sku);
if (History.Any())
{
ProductName = History[0].Description;
}
}
private void SelectItem(string quantity, string rate)
{
var result = new DraftItem
{
Discount = 0,
Item = SalesItem,
Price = decimal.Parse(rate, CultureInfo.InvariantCulture),
Quantity = int.Parse(quantity)
};
OnSelected.InvokeAsync(result);
Hide();
}
private void SelectLine(ProductHistoryView item)
{
var result = new DraftItem
{
Discount = item.Discount,
Item = SalesItem,
Price = item.Price,
Quantity = item.Quantity,
};
OnSelected.InvokeAsync(result);
Hide();
}
public void Show()
{
_modalDisplay = "block;";
_showBackdrop = true;
StateHasChanged();
}
private void Hide()
{
_modalDisplay = "none;";
_showBackdrop = false;
StateHasChanged();
}
}

View file

@ -11,7 +11,17 @@ main {
.sidebar { .sidebar {
background-image: linear-gradient(180deg, rgb(22, 21, 23) 10%, #ffaa00 100%); background-image: linear-gradient(180deg, rgb(22, 21, 23) 10%, #ffaa00 100%);
} }
.bar-system-date {
color: #ffaa00;
background-color: #0e0e0e;
border-bottom: 1px solid #d6d5d5;
justify-content: flex-start;
height: 3.5rem;
display: flex;
align-items: center;
font-size: 2rem;
font-variant: all-petite-caps;
}
.top-row { .top-row {
color: #ffaa00; color: #ffaa00;
background-color: #0e0e0e; background-color: #0e0e0e;

View file

@ -20,9 +20,7 @@
<div class="top-row ps-3 navbar navbar-dark"> <div class="top-row ps-3 navbar navbar-dark">
<div class="container-fluid"> <div class="container-fluid">
<a class="navbar-brand" href="/"> <a class="navbar-brand" href="/"><TopbarDisplayUser /></a>
<TopbarDisplayUser></TopbarDisplayUser>
</a>
<button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu"> <button title="Navigation menu" class="navbar-toggler" @onclick="ToggleNavMenu">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>
</button> </button>

View file

@ -28,7 +28,7 @@ public partial class ProductPriceHistoryModal
{ {
[Parameter] public EventCallback<decimal> OnSelected { get; set; } [Parameter] public EventCallback<decimal> OnSelected { get; set; }
[Parameter] public string CompanyId { get; set; } = ""; [Parameter] public string CompanyId { get; set; } = "";
[Parameter] public string ItemSku { get; set; } = ""; [Parameter] public string Sku { get; set; } = "";
[Inject] public ICrmHistoryHttpRepository CrmHistoryRepo { get; set; } [Inject] public ICrmHistoryHttpRepository CrmHistoryRepo { get; set; }
private List<ProductHistoryView> History { get; set; } private List<ProductHistoryView> History { get; set; }
private string ProductName { get; set; } = ""; private string ProductName { get; set; } = "";
@ -37,10 +37,10 @@ public partial class ProductPriceHistoryModal
protected override async Task OnParametersSetAsync() protected override async Task OnParametersSetAsync()
{ {
if (string.IsNullOrWhiteSpace(ItemSku)) if (string.IsNullOrWhiteSpace(Sku))
return; return;
History = await CrmHistoryRepo.FetchHistory(CompanyId, ItemSku); History = await CrmHistoryRepo.FetchHistory(CompanyId, Sku);
if (History.Any()) if (History.Any())
{ {
ProductName = History[0].Description; ProductName = History[0].Description;

View file

@ -1,13 +1,13 @@
{ {
"appInfo": { "appInfo": {
"name": "Wonky Client", "name": "Wonky Client",
"version": "0.26.5", "version": "0.27.1",
"rc": true, "rc": true,
"sandBox": false, "sandBox": false,
"image": "grumpy-coder.png" "image": "grumpy-coder.png"
}, },
"apiConfig": { "apiConfig": {
"innoBaseUrl": "https://zeta.innotec.dk", "innoBaseUrl": "https://dev.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",
@ -34,9 +34,9 @@
}, },
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Debug",
"System": "Information", "System": "Debug",
"Microsoft": "None" "Microsoft": "Information"
}, },
"Debug": { "Debug": {
"LogLevel": { "LogLevel": {

View file

@ -36,7 +36,7 @@ a, .btn-link {
border-color: #1861ac; border-color: #1861ac;
} }
.text-inno { .inno {
color: #ffaa00; color: #ffaa00;
} }

View file

@ -1,6 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="da"> <html lang="da">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>Inno Web CRM</title> <title>Inno Web CRM</title>
@ -29,7 +28,6 @@
<img src="/svg-loaders/three-dots.svg" alt="loading ..."/> <img src="/svg-loaders/three-dots.svg" alt="loading ..."/>
</div> </div>
</div> </div>
<script src="/bootstrap/js/bootstrap.bundle.js"></script> <script src="/bootstrap/js/bootstrap.bundle.js"></script>
<!--<script src="/scripts/bsTooltip.js"></script>--> <!--<script src="/scripts/bsTooltip.js"></script>-->
<script src="_framework/blazor.webassembly.js"></script> <script src="_framework/blazor.webassembly.js"></script>

View file

@ -17,7 +17,16 @@ namespace Wonky.Entity.Views;
public class ProductInventoryView public class ProductInventoryView
{ {
/// <summary>
/// entity description
/// </summary>
public string Description { get; set; } = ""; public string Description { get; set; } = "";
/// <summary>
/// entity item number
/// </summary>
public string Sku { get; set; } = ""; public string Sku { get; set; } = "";
/// <summary>
/// quantity bought over time
/// </summary>
public int Quantity { get; set; } public int Quantity { get; set; }
} }

View file

@ -25,5 +25,6 @@ public class SalesItemView
public string ProductGroup { get; set; } = ""; public string ProductGroup { get; set; } = "";
public string PictureLink { get; set; } = ""; public string PictureLink { get; set; } = "";
public string Location { get; set; } = ""; public string Location { get; set; } = "";
public bool Discontinued { get; set; }
public List<SalesRateView> Rates { get; set; } = new(); public List<SalesRateView> Rates { get; set; } = new();
} }