Merge branch 'dev'

This commit is contained in:
Frede Hundewadt 2022-08-30 09:00:56 +02:00
commit f1812527a8
66 changed files with 634 additions and 213 deletions

View file

@ -1,13 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Rider ignored files
/modules.xml
/contentModel.xml
/projectSettingsUpdater.xml
/.idea.Wonky.Client.iml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View file

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="com.jetbrains.rider.android.RiderAndroidMiscFileCreationComponent">
<option name="ENSURE_MISC_FILE_EXISTS" value="true" />
</component>
</project>

View file

@ -0,0 +1,2 @@
<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/=Venligst/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

View file

@ -27,6 +27,9 @@
<th scope="col">Note</th>
<th class="text-end" scope="col">sas</th>
<th class="text-end" scope="col">Beløb</th>
<th class="text-center" scope="col"><i class="oi oi-phone"></i></th>
<th class="text-center" scope="col"><i class="oi oi-flash"></i></th>
<th class="text-center" scope="col"><i class="oi oi-calculator"></i></th>
</tr>
</thead>
<tbody>
@ -38,14 +41,17 @@
<td>@activity.Demo</td>
<td>@activity.Sales</td>
<td>@activity.OfficeNote</td>
<td class="text-end">@activity.SasAmount</td>
<td class="text-end">@(activity.StatusTypeEnum == "Quote" ? 0 : activity.OrderAmount)</td>
<td class="text-end">@($"{activity.SasAmount:N2}")</td>
<td class="text-end">@(activity.StatusTypeEnum == "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-end">@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.Sum(x => x.OrderAmount)</td>
<td class="text-end">@Activities.Where(x => x.StatusTypeEnum == "Order").Sum(x => x.OrderAmount)</td>
</tr>
</tbody>
</table>

View file

@ -0,0 +1,23 @@
@*
// 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="input-group">
<input id="search-input" type="text" class="form-control" placeholder="Søg ..." aria-described-by="search-addon"
@bind-value="@SearchTerm" @bind-value:event="oninput" @onkeyup="OnSearchChanged" />
<span class="input-group-text" id="search-addon"><i class="oi oi-delete" @onclick="ClearSearch"></i></span>
</div>

View file

@ -0,0 +1,65 @@
// 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.Timers;
using Microsoft.AspNetCore.Components;
using Wonky.Client.Services;
using Timer = System.Timers.Timer;
namespace Wonky.Client.Components
{
public partial class CompanySearchPhraseComponent
{
private Timer InputTimer { get; set; } = new();
private string SearchTerm { get; set; } = "";
private Preferences Preferences { get; set; } = new ();
[Inject] private UserPreferenceService PreferenceService { get; set; }
[Parameter] public EventCallback<string> OnChanged { get; set; }
protected override async Task OnInitializedAsync()
{
Preferences = await PreferenceService.GetPreferences();
SearchTerm = string.IsNullOrWhiteSpace(Preferences.CompanyFilterPhrase) ? "" : Preferences.CompanyFilterPhrase.Trim();
if(!string.IsNullOrWhiteSpace(SearchTerm))
await OnChanged.InvokeAsync(SearchTerm);
}
private async Task ClearSearch()
{
InputTimer.Dispose();
SearchTerm = "";
await PreferenceService.SetCompanyFilterPhrase(SearchTerm.Trim());
await OnChanged.InvokeAsync(SearchTerm);
}
private async Task OnSearchChanged()
{
await PreferenceService.SetCompanyFilterPhrase(SearchTerm.Trim());
InputTimer.Dispose();
InputTimer = new Timer(500);
InputTimer.AutoReset = false;
InputTimer.Elapsed += OnTimerElapsed;
InputTimer.Enabled = true;
}
private void OnTimerElapsed(object? sender, ElapsedEventArgs e)
{
InputTimer.Dispose();
OnChanged.InvokeAsync(SearchTerm);
}
}
}

View file

@ -19,40 +19,25 @@ using Timer = System.Timers.Timer;
namespace Wonky.Client.Components
{
public partial class SearchPhraseComponent
public partial class ItemSearchPhraseComponent
{
private Timer _timer = new();
private Timer _timer { get; set; } = new();
private string _searchTerm { get; set; } = "";
[Parameter] public EventCallback<string> OnChanged { get; set; }
[Parameter] public string SavedSearch { get; set; } = "";
protected override void OnParametersSet()
{
_searchTerm = SavedSearch;
}
protected override void OnInitialized()
{
if (string.IsNullOrWhiteSpace(_searchTerm)) return;
OnChanged.InvokeAsync(_searchTerm);
}
private void ClearSearch()
{
SavedSearch = "";
_searchTerm = "";
OnChanged.InvokeAsync(_searchTerm);
OnChanged.InvokeAsync("");
}
private void OnSearchChanged()
{
_timer.Enabled = false;
_timer.Dispose();
_timer = new Timer(500);
_timer.Elapsed += OnTimerElapsed;
_timer.AutoReset = false;
_timer.Elapsed += OnTimerElapsed;
_timer.Enabled = true;
}
private void OnTimerElapsed(object? sender, ElapsedEventArgs e)

View file

@ -0,0 +1,25 @@
@using Wonky.Client.Services
<div class="input-group">
<label class="col-form-label me-2" for="kmMorning">Morgen</label>
<input type="number" id="kmMorning" class="form-control" @bind-Value="KmMorning" @bind-Value:event="oninput" @onchange="OnKmChanged"/>
</div>
@code {
[Inject] private UserPreferenceService PreferenceService { get; set; }
private int KmMorning { get; set; }
private Preferences Preferences { get; set; } = new();
protected override async Task OnInitializedAsync()
{
Preferences = await PreferenceService.GetPreferences();
KmMorning = Preferences.KmMorning;
}
private async Task OnKmChanged()
{
await PreferenceService.SetKmMorning(KmMorning);
}
}

View file

@ -19,3 +19,42 @@
@using Wonky.Client.Components
<PageTitle>Inno Web CRM</PageTitle>
<div class="card mb-3" style="max-width: 300px">
<div class="row g-0">
<div class="col-4">
<i class="img-fluid rounded-start fi fi-dk" alt="dk flag"></i>
</div>
<div class="col-8">
<div class="card-body">
Danmark
</div>
</div>
</div>
</div>
<div class="card mb-3" style="max-width: 300px">
<div class="row g-0">
<div class="col-4">
<i class="img-fluid rounded-start fi fi-no" alt="no flag"></i>
</div>
<div class="col-8">
<div class="card-body">
Norge
</div>
</div>
</div>
</div>
<div class="card mb-3" style="max-width: 300px">
<div class="row g-0">
<div class="col-4">
<i class="img-fluid rounded-start fi fi-se" alt="se flag"></i>
</div>
<div class="col-8">
<div class="card-body">
Sverige
</div>
</div>
</div>
</div>

View file

@ -47,7 +47,6 @@ public partial class LandingComponentAdmin : IDisposable
private Preferences _prefs { get; set; } = new();
private string _workDate { get; set; } = $"{DateTime.Now:yyyy-MM-dd}";
private string _today { get; set; } = $"{DateTime.Now:yyyy-MM-dd}";
private List<TaskItemDto>? _taskItems { get; set; } = new();
protected override async Task OnInitializedAsync()
@ -58,45 +57,6 @@ public partial class LandingComponentAdmin : IDisposable
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
//await GetTaskItems(_workDate);
await GetAllTasks();
}
private async Task GetAllTasks()
{
_taskItems = await _taskItemRepo.GetTaskList();
}
private async Task OnCompleteTask(string taskItemId)
{
await _preferenceService.SetWorkDate(DateTime.Now);
var item = _taskItems.Find(x => x.TaskItemId == taskItemId);
_navigator.NavigateTo($"/companies/{item.ReferenceId}/activities/new");
}
private async Task GetTaskItems(string workDate)
{
_workDate = workDate;
_taskItems = new List<TaskItemDto>();
_taskItems = await _taskItemRepo.GetTaskList(workDate);
}
private async Task OnTaskCompleted(string taskItemId)
{
var item = _taskItems.Find(x => x.TaskItemId == taskItemId);
item.IsCompleted = true;
await _taskItemRepo.UpdateTaskItem(taskItemId, item);
_taskItems.Remove(item);
_toast.ShowInfo("Opgaven er markeret som udført.");
}
private async Task OnDeleteConfirmed(string taskItemId)
{
var item = _taskItems.First(x => x.TaskItemId == taskItemId);
_taskItems.Remove(item);
await _taskItemRepo.DeleteTaskItem(taskItemId);
_toast.ShowInfo("Opgaven er slettet.");
}
public void Dispose()

View file

@ -1,3 +1,4 @@
.workDate {
font-size: 1.2em;
font-weight: bold;

View file

@ -17,12 +17,26 @@
@using Wonky.Entity.Views
<div class="report-page d-block">
<table class="table table-sm table-striped table-bordered d-print-table">
<div class="report-page-item d-block">
<table class="table table-sm table-striped d-print-table">
<thead>
<tr class="bg-light text-black">
<th colspan="4">
<h2 class="text-center">@ReportItem.Company.Name</h2>
<tr>
<th class="p-0" colspan="4">
<div class="bg-light text-dark border border-1 rounded-3 pt-3 mb-2">
<h2 class="fw-bold text-center">@ReportItem.Company.Name</h2>
@if (ReportItem.StatusTypeEnum.ToLower() is "quote")
{
<h3 class="text-center">TILBUD</h3>
}
@if (ReportItem.VisitTypeEnum.ToLower() == "phone" || ReportItem.OurRef.Contains("T:"))
{
<h3 class="text-center">TELEFONORDRE</h3>
}
@if (ReportItem.Express)
{
<h3 class="fw-bold text-center">HASTER</h3>
}
</div>
</th>
</tr>
</thead>
@ -115,5 +129,4 @@
[Parameter]
public ReportItemView ReportItem { get; set; } = new();
}

View file

@ -27,6 +27,7 @@
<th scope="col"></th>
<th scope="col"></th>
<th scope="col"></th>
<th scope="col"></th>
</tr>
</thead>
<tbody>
@ -45,6 +46,11 @@
}
</label>
</td>
<td class="align-middle">
<a class="btn btn-light border-dark" href="/tasks/@task.TaskItemId">
<i class="oi oi-calendar"></i>
</a>
</td>
<td class="align-middle">
<button type="button" class="btn btn-light border-dark" @onclick="() => CallConfirmationModal(task.TaskItemId)">
<i class="oi oi-circle-x"></i>

View file

@ -49,9 +49,12 @@
<div class="col-md-4">
<h4>Kundenavn</h4>
</div>
<div class="col-md-4">
<div class="col-md-3">
<h4>Postnr. Bynavn</h4>
</div>
<div class="col-md-1 text-center">
<h4>H</h4>
</div>
<div class="col-md-2">
<h4>Status</h4>
</div>
@ -67,9 +70,15 @@
<div class="col-md-4">
@order.Company.Name
</div>
<div class="col-md-4">
<div class="col-md-3">
@order.Company.ZipCode @order.Company.City
</div>
<div class="col-md-1 text-center">
@if (order.Express)
{
<i class="oi oi-flash"></i>
}
</div>
<div class="col-md-2">
@switch (order.ProcessStatusEnum.ToLower())
{

View file

@ -0,0 +1,40 @@
@using Wonky.Entity.DTO
@using Wonky.Entity.Views
@if (Workplaces.Any())
{
<div class="list-group">
<div class="row">
<div class="col">
Arbejdssted
</div>
<div class="col">
Note
</div>
</div>
@foreach (var workplace in Workplaces)
{
<a class="list-group-item list-group-item-action" href="/companies/@CompanyId/workplaces/@workplace.WorkplaceId">
<div class="row">
<div class="col">
@workplace.Name
</div>
<div class="col">
@workplace.Description
</div>
</div>
</a>
}
</div>
}
else
{
<div>Ingen data</div>
}
@code {
[Parameter] public List<WorkplaceListView> Workplaces { get; set; } = new();
[Parameter] public string CompanyId { get; set; } = "";
}

View file

@ -92,8 +92,8 @@ namespace Wonky.Client.HttpInterceptors
switch (e.Response.StatusCode)
{
case HttpStatusCode.NotFound:
message = "Der var ingen data ...";
_toast.ShowInfo(message);
// message = "Der var ingen data ...";
// _toast.ShowInfo(message);
break;
case HttpStatusCode.BadRequest:
// message = "Der er et problem med data ...";
@ -102,7 +102,7 @@ namespace Wonky.Client.HttpInterceptors
case HttpStatusCode.Unauthorized:
ClearInfo();
_navigation.NavigateTo($"/login/{currDoc}");
message = "Login skal fornyes ...";
message = "Venligst login ...";
_toast.ShowWarning(message);
break;
case HttpStatusCode.InternalServerError:
@ -118,7 +118,7 @@ namespace Wonky.Client.HttpInterceptors
private async void ClearInfo()
{
await _storage.RemoveItemsAsync(new List<string> {"_xa", "_xr", "_xe", "_xu"});
await _storage.ClearAsync();
}
}
}

View file

@ -24,5 +24,6 @@ namespace Wonky.Client.HttpRepository;
public interface ISalesItemHttpRepository
{
Task<PagingResponse<SalesItemView>> GetSalesItemsPaged(CatalogPagingParams pagingParameters);
Task<SalesItemView> GetSalesItem(string id);
Task<SalesItemView> GetSalesItemId(string salesItemId);
Task<SalesItemView> GetSalesVariantId(string variantId);
}

View file

@ -77,10 +77,17 @@ public class SalesItemHttpRepository : ISalesItemHttpRepository
return pagingResponse;
}
public async Task<SalesItemView> GetSalesItem(string id)
public async Task<SalesItemView> GetSalesItemId(string salesItemId)
{
var salesItem = await _client
.GetFromJsonAsync<SalesItemView>($"{_apiConfig.CrmCatalog}/{id}");
.GetFromJsonAsync<SalesItemView>($"{_apiConfig.CrmCatalog}/{salesItemId}");
return salesItem ?? new SalesItemView();
}
public async Task<SalesItemView> GetSalesVariantId(string variantId)
{
var salesItem = await _client
.GetFromJsonAsync<SalesItemView>($"{_apiConfig.CrmCatalog}/variant/{variantId}");
return salesItem ?? new SalesItemView();
}
}

View file

@ -54,7 +54,9 @@ public class UserHttpRepository : IUserHttpRepository
public async Task<UserInfoDto> GetAdvisorInfo(string userId)
{
return await _client.GetFromJsonAsync<UserInfoDto>($"{_api.AdminUser}/{userId}");
var user = await _client.GetFromJsonAsync<UserInfoDto>($"{_api.AdminUser}/{userId}");
Console.WriteLine(JsonSerializer.Serialize(user));
return user;
}
public async Task UpdateAdvisor(string userId, UserUpdateDto model)
@ -64,12 +66,16 @@ public class UserHttpRepository : IUserHttpRepository
public async Task<List<UserListAdminView>> GetAdminUsers()
{
return await _client.GetFromJsonAsync<List<UserListAdminView>>(_api.AdminOffice);
var users =await _client.GetFromJsonAsync<List<UserListAdminView>>(_api.AdminOffice);
Console.WriteLine(JsonSerializer.Serialize(users));
return users;
}
public async Task<UserInfoDto> GetAdminUserInfo(string userId)
{
return await _client.GetFromJsonAsync<UserInfoDto>($"{_api.AdminOffice}/{userId}");
var user = await _client.GetFromJsonAsync<UserInfoDto>($"{_api.AdminOffice}/{userId}");
Console.WriteLine(JsonSerializer.Serialize(user));
return user;
}
public async Task UpdateAdminUser(string userId, UserUpdateDto model)

View file

@ -57,13 +57,6 @@ else
<option value="phone">Telefon</option>
</InputSelect>
<ValidationMessage For="@(() => _draft.ActivityTypeEnum)"></ValidationMessage>
@if (_draft.ActivityTypeEnum == "phone")
{
<div class="form-check">
<InputCheckbox id="express" class="form-check-input" @bind-Value="@_draft.Express"/>
<label class="form-check-label" for="express">Express</label>
</div>
}
</div>
<label for="statusType" class="col-md-2 col-form-label">Status</label>
@ -77,6 +70,13 @@ else
}
</InputSelect>
<ValidationMessage For="@(() => _draft.ActivityStatusEnum)"></ValidationMessage>
@if (_draft.ActivityStatusEnum == "order")
{
<div class="form-check">
<InputCheckbox id="express" class="form-check-input" @bind-Value="@_draft.Express"/>
<label class="form-check-label" for="express">Express</label>
</div>
}
</div>
</div>
@ -97,7 +97,7 @@ else
<div class="row mb-1">
<label for="referenceNumber" class="col-md-2 col-form-label">Rekvisition</label>
<div class="col-md-4">
<InputText id="referenceNumber" class="form-control" @bind-Value="_draft.ReferenceNumber"/>
<InputText id="referenceNumber" class="form-control" @bind-Value="_draft.ReferenceNumber" />
<ValidationMessage For="@(() => _draft.ReferenceNumber)"></ValidationMessage>
</div>

View file

@ -76,30 +76,33 @@ public partial class ActivityNewVisitPage : IDisposable
protected override async Task OnParametersSetAsync()
{
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
_prefs = await _userPrefs.GetPreferences();
if (!string.IsNullOrWhiteSpace(_prefs.WorkDate))
_workDate = DateTime.Parse(_prefs.WorkDate);
_selectedDate = $"{_workDate:yyyy-MM-dd}";
// raise flag if report is closed
_reportClosdd = await _reportRepo.ReportExist(_selectedDate);
}
protected override async Task OnInitializedAsync()
{
_editContext = new EditContext(_draft);
_editContext.OnFieldChanged += HandleFieldChanged;
_editContext.OnValidationStateChanged += ValidationChanged;
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
_draft.ActivityDate = $"{_workDate:yyyy-MM-dd}" ;
_ux = await _storage.GetItemAsync<UserInfoView>("_xu");
// get company
_company = await _companyRepo.GetCompanyById(CompanyId);
// variable to validate if customer needs phone number update
_phone = _company.Phone;
if (string.IsNullOrWhiteSpace(_company.Phone)
@ -146,9 +149,11 @@ public partial class ActivityNewVisitPage : IDisposable
private async Task SelectSku(SelectedSku sku)
{
// fetch selected item
_selectedItem = await _itemRepo.GetSalesItem(sku.ItemId);
// get selected item
if (string.IsNullOrWhiteSpace(sku.ItemId))
return;
_selectedItem = await _itemRepo.GetSalesItemId(sku.ItemId);
ShowItem = true;
Price = sku.Rate;
Quantity = sku.Quantity;
@ -156,11 +161,6 @@ public partial class ActivityNewVisitPage : IDisposable
StateHasChanged();
}
private void CallHistoryModal()
{
_historyModal.Show();
}
private void CallPriceHistoryModal()
{
_priceHistoryModal.Show();
@ -168,6 +168,9 @@ public partial class ActivityNewVisitPage : IDisposable
private void SelectPrice(decimal price)
{
if (price == 0)
return;
Price = price.ToString("N2", CultureInfo.InvariantCulture);
StateHasChanged();
}
@ -205,13 +208,16 @@ public partial class ActivityNewVisitPage : IDisposable
}
HideButtons = true;
_draft.ActivityDate = _prefs.WorkDate;
_draft.ActivityDate = $"{_workDate:yyyy-MM-dd}";
_draft.OurRef = _draft.ActivityTypeEnum switch
{
"phone" => $"T:{_ux.FullName.Split(" ")[0]}",
"onSite" => $"B:{_ux.FullName.Split(" ")[0]}",
_ => ""
};
if (_draft.ActivityTypeEnum == "phone" && _draft.Express)
_draft.OurRef = $"E{_draft.OurRef}";
_draft.Lines = new List<ActivityLineDto>();
var ln = 0;
if (DraftStateProvider.Draft.Items.Count != 0)
@ -235,12 +241,13 @@ public partial class ActivityNewVisitPage : IDisposable
{
_company.Phone = _draft.Phone;
await _companyRepo.UpdateCompany(_company.CompanyId, _company);
_toast.ShowInfo("Kunde telefon nummer er opdateret.");
// _toast.ShowInfo("Kunde telefon nummer er opdateret.");
}
// post to api
var result = await _activityRepo.CreateActivity(_draft);
// show result message
_toast.ShowSuccess($"{result.Message}.");
_selectedItem = new SalesItemView();
await DraftStateProvider.DeleteDraftAsync();
_navigator.NavigateTo($"/companies");
}
@ -287,11 +294,19 @@ public partial class ActivityNewVisitPage : IDisposable
private void HandleFieldChanged(object sender, FieldChangedEventArgs e)
{
if (_draft.ActivityTypeEnum != "phone")
_draft.Express = false;
// InvalidCanvas = InvalidActivityType;
InvalidActivity = InvalidActivityType
|| _poFormInvalid
|| DraftStateProvider.Draft.Items.Count == 0
|| (_draft.ActivityStatusEnum == "offer" && string.IsNullOrWhiteSpace(_draft.Email));
if (_draft.YourRef.Length > 35 || _draft.ReferenceNumber.Length > 20)
{
_poFormInvalid = true;
return;
}
if (InvalidActivity)
{

View file

@ -21,11 +21,14 @@
@page "/activity-today"
<div class="row mb-1 align-items-center">
<div class="col-md-6">
<h2 class="workDate">@(string.IsNullOrWhiteSpace(_workDate) ? "" : $"{DateTime.Parse(_workDate).ToLongDateString()}")</h2>
<div class="col-md-5">
<h3 class="workDate">@(string.IsNullOrWhiteSpace(_workDate) ? "" : $"{DateTime.Parse(_workDate).ToLongDateString()}")</h3>
</div>
<div class="col-md-4">
<WorkDateComponent OnChanged="GetActivities"></WorkDateComponent>
<div class="col-md-2">
<WorkDateComponent OnChanged="GetActivities" />
</div>
<div class="col-md-3">
<KmMorningComponent />
</div>
<div class="col-md-2">
@if (_reportExist)
@ -41,7 +44,7 @@
@if (ReportItemListView.ReportItems.Any())
{
<ActivityTableComponent Activities="ReportItemListView.ReportItems"></ActivityTableComponent>
<ActivityTableComponent Activities="ReportItemListView.ReportItems" />
}
else
{

View file

@ -32,7 +32,7 @@
<CompanySearchColumnComponent OnChanged="SetSearchCol" />
</div>
<div class="col-md-3">
<SearchPhraseComponent SavedSearch="@_savedSearch" OnChanged="SetSearchPhrase" />
<CompanySearchPhraseComponent SavedSearch="@_savedSearch" OnChanged="SetSearchPhrase" />
</div>
<div class="col-md-3">
<CompanySortComponent OnChanged="SetSortCol" />

View file

@ -110,14 +110,14 @@
<div class="row mb-3">
<label for="newPasswd" class="col-md-2 col-form-label">Ny</label>
<div class="col-md-10">
<InputText id="newPasswd" type="password" class="form-control" @bind-Value="@_passwords.NewPassword"/>
<InputText id="newPasswd" class="form-control" @bind-Value="@_passwords.NewPassword"/>
<ValidationMessage For="@(() => _passwords.NewPassword)"></ValidationMessage>
</div>
</div>
<div class="row mb-3">
<label for="verifyPasswd" class="col-md-2 col-form-label">Bekræft</label>
<div class="col-md-10">
<InputText id="verifyPasswd" type="password" class="form-control" @bind-Value="@_passwords.ConfirmPassword"/>
<InputText id="verifyPasswd" class="form-control" @bind-Value="@_passwords.ConfirmPassword"/>
<ValidationMessage For="@(() => _passwords.ConfirmPassword)"></ValidationMessage>
</div>
</div>

View file

@ -28,7 +28,7 @@
<CompanySearchColumnComponent OnChanged="SetSearchCol" />
</div>
<div class="col-md-3">
<SearchPhraseComponent SavedSearch="@_savedSearch" OnChanged="SetSearchPhrase" />
<CompanySearchPhraseComponent OnChanged="SetSearchPhrase" />
</div>
<div class="col-md-3">
<CompanySortComponent OnChanged="SetSortCol" />

View file

@ -92,12 +92,17 @@ namespace Wonky.Client.Pages
private async Task SetSearchPhrase(string searchTerm)
{
_savedSearch = searchTerm;
await _preferenceService.SetCompanyFilterPhrase(searchTerm.Trim());
// if (!string.IsNullOrWhiteSpace(searchTerm) && searchTerm.Length < 3) return;
_companyList = new List<CompanyDto>();
_paging.PageNumber = 1;
_paging.SearchTerm = searchTerm;
await GetCompanies();
if (!string.IsNullOrWhiteSpace(searchTerm) && searchTerm.TrimEnd().Length > 2)
{
_savedSearch = searchTerm;
await _preferenceService.SetCompanyFilterPhrase(searchTerm.Trim());
}
}
private async Task SetSortCol(string orderBy)

View file

@ -31,13 +31,13 @@
<ItemSearchComponent OnChanged="SetSearchCol"/>
</div>
<div class="col">
<SearchPhraseComponent SavedSearch="@_searchTerm" OnChanged="SetSearchPhrase"/>
<ItemSearchPhraseComponent OnChanged="SetSearchPhrase"/>
</div>
<div class="col">
<ItemSortComponent OnChanged="SetSortCol"/>
</div>
<div class="col-md-2">
<PageSizeComponent OnChanged="SetPageSize"></PageSizeComponent>
<PageSizeComponent OnChanged="SetPageSize" />
</div>
</div>
<div class="row mb-3">

View file

@ -38,7 +38,6 @@ public partial class ItemCatalogPage : IDisposable
private MetaData? _metaData { get; set; } = new();
private CatalogPagingParams _paging = new();
private Preferences _preferences = new();
private string _searchTerm { get; set; } = "";
protected override async Task OnInitializedAsync()
{
@ -61,7 +60,6 @@ public partial class ItemCatalogPage : IDisposable
private async Task SetSearchPhrase(string searchTerm)
{
_searchTerm = searchTerm;
_items = new List<SalesItemView>();
_paging.PageNumber = 1;
_paging.SearchTerm = searchTerm;

View file

@ -35,7 +35,7 @@ public partial class KrvItemViewPage : IDisposable
{
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
_item = await _itemRepo.GetSalesItem(SalesItemId);
_item = await _itemRepo.GetSalesVariantId(SalesItemId);
}
/// <summary>

View file

@ -40,11 +40,12 @@ public partial class OfficeNewOrderPage : IDisposable
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
_company = await _companyRepo.GetCompanyById(CompanyId);
_userInfo = await _userRepo.GetAdvisorInfo(_company.SalesRepId);
}
protected override async Task OnInitializedAsync()
{
_userInfo = await _userRepo.GetAdvisorInfo(_company.SalesRepId);
_editContext = new EditContext(_draft);
_editContext.OnFieldChanged += HandleFieldChanged;
_editContext.OnValidationStateChanged += ValidationChanged;
@ -99,10 +100,11 @@ public partial class OfficeNewOrderPage : IDisposable
{
_priceList.Show();
}
private async Task SelectSku(SelectedSku sku)
{
ShowItem = true;
_selectedItem = await _itemRepo.GetSalesItem(sku.ItemId);
_selectedItem = await _itemRepo.GetSalesVariantId(sku.ItemId);
Price = sku.Rate;
Quantity = sku.Quantity;
}

View file

@ -229,25 +229,32 @@
<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>@activity.Company.Name</td>
<td>@activity.Company.City</td>
<td>@activity.Demo</td>
<td>@activity.Sales</td>
<td>@activity.OfficeNote</td>
<td class="text-end">@activity.SasAmount</td>
<td class="text-end">@activity.OrderAmount</td>
<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.Sum(x => x.OrderAmount)</td>
<td class="text-end">@_activities.Where(x => x.StatusTypeEnum != "Quote").Sum(x => x.OrderAmount)</td>
<td colspan="2"></td>
</tr>
</tbody>
</table>

View file

@ -45,7 +45,7 @@ public partial class ReportNewPageAdvisor : IDisposable
private Preferences _prefs { get; set; } = new();
private bool _formInvalid = true;
private bool _noFigures = true;
private bool _working = false;
private bool _working;
private DateTime _workDate { get; set; } = DateTime.Now;
private TimeOnly _checkIn { get; set; } = new(12, 0);
private TimeOnly _checkOut { get; set; } = new(12, 0);
@ -54,7 +54,6 @@ public partial class ReportNewPageAdvisor : IDisposable
protected override async Task OnInitializedAsync()
{
_working = true;
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
_editContext = new EditContext(_report);
@ -65,8 +64,6 @@ public partial class ReportNewPageAdvisor : IDisposable
if (!string.IsNullOrWhiteSpace(_prefs.WorkDate))
_workDate = DateTime.Parse(_prefs.WorkDate);
_working = false;
if(await _reportRepo.ReportExist(_prefs.WorkDate))
_navigator.NavigateTo($"/sales-reports/view/{_prefs.WorkDate}");
@ -103,6 +100,12 @@ public partial class ReportNewPageAdvisor : IDisposable
return;
}
if (_report.Figures.KmMorning > _report.Figures.KmEvening)
{
_toast.ShowError("Km udregning er negativ - kontroller venligst km tal");
return;
}
_working = true;
DateTime checkIn;
@ -130,7 +133,7 @@ public partial class ReportNewPageAdvisor : IDisposable
_logger.LogDebug("_report => {report}", JsonSerializer.Serialize(_report));
var result = await _reportRepo.PostReport($"{_workDate:yyyy-MM-dd}", _report);
await _userPrefs.SetKmMorning(0);
_toast.ShowInfo($"Rapport oprettet {_workDate}");
_working = false;
@ -173,6 +176,7 @@ public partial class ReportNewPageAdvisor : IDisposable
_report.Figures = data.ReportData;
_init = data.ReportData;
_activities = data.ReportItems;
_report.Figures.KmMorning = _prefs.KmMorning;
_working = false;
}

View file

@ -20,7 +20,7 @@
@page "/sales-reports/view/{ReportDate}"
@attribute [Authorize(Roles = "Advisor,Admin,Supervisor")]
<div class="report-page d-print-block">
<div class="report-page">
<div class="row mb-3 d-print-none">
<div class="col-md-6 align-content-center">
<h3 class="workDate">@DateTime.Parse(ReportDate).ToLongDateString()</h3>
@ -57,6 +57,11 @@
</div>
}
</div>
<div class="report-page">
&nbsp;
</div>
@if (_items.Any())
{
@foreach (var item in _items)

View file

@ -43,6 +43,8 @@ public partial class ReportViewPageAdvisor
if(workDate != ReportDate)
_navigator.NavigateTo($"/sales-reports/view/{workDate}");
_report = await _reportRepo.GetReport(workDate);
_items = _report.ReportItems.Where(x => x.OrderAmount > 0).ToList();
_items = _report.ReportItems.Where(x => x.Lines.Any()).ToList();
}
}

View file

@ -62,6 +62,10 @@
</div>
<div class="report-page">
&nbsp;
</div>
@if (_items.Any())
{
@foreach (var item in _items)

View file

@ -80,7 +80,8 @@ public partial class ReportViewPageOffice : IDisposable
_items = new List<ReportItemView>();
Report = await GetUserReport(UserId, workDate);
_items = Report.ReportItems.Where(x => x.OrderAmount > 0).ToList();
//_items = Report.ReportItems.Where(x => x.OrderAmount > 0).ToList();
_items = Report.ReportItems.Where(x => x.Lines.Any()).ToList();
}
/// <summary>

View file

@ -15,7 +15,12 @@
//
*@
@page "/task-items/{TaskItemId}"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Roles = "Advisor")]
@page "/tasks/{TaskItemId}"
@* {"TaskItemId":"","ErpUserId":"","ReferenceId":"","Name":"","Description":"","DueTimestamp":"","TaskTypeEnum":"","Interval":0,"IsCompleted":false,"OverDue":false,"Recurring":false} *@
<div class="card">
<div class="card-header">
<h3>Opgave</h3>
@ -23,11 +28,78 @@
<div class="card-body">
<EditForm EditContext="_editContext">
<DataAnnotationsValidator/>
<div class="row mb-2">
<div class="input-group">
<label for="taskItemId" class="col-md-2 col-form-label">EntityId</label>
<InputText id="taskItemId" class="col-md-10 form-control" @bind-Value="_taskItem.TaskItemId" readonly=""/>
</div>
</div>
<div class="row mb-2">
<div class="input-group">
<label for="erpUserId" class="col-md-2 col-form-label">BrugerId</label>
<InputText id="erpUserId" class="col-md-10 form-control" @bind-Value="_taskItem.ErpUserId" readonly=""/>
</div>
</div>
<div class="row mb-2">
<div class="input-group">
<label for="referenceId" class="col-md-2 col-form-label">ReferenceId</label>
<InputText id="referenceId" class="col-md-10 form-control" @bind-Value="_taskItem.ReferenceId" readonly=""/>
</div>
</div>
<div class="row mb-2">
<div class="input-group">
<label for="name" class="col-md-2 col-form-label">Opgave</label>
<InputText id="name" class="col-md-10 form-control" @bind-Value="_taskItem.Name"/>
</div>
</div>
<div class="row mb-2">
<div class="input-group">
<label for="description" class="col-md-2 col-form-label">Beskrivelse</label>
<InputText id="description" class="col-md-10 form-control" @bind-Value="_taskItem.Description"/>
</div>
</div>
<div class="row mb-2">
<div class="input-group">
<label for="dueTimestamp" class="col-md-2 col-form-label">Forfald</label>
<InputText id="dueTimestamp" class="col-md-10 form-control" @bind-Value="_taskItem.DueTimestamp"/>
</div>
</div>
<div class="row mb-2">
<div class="input-group">
<label for="taskTypeEnum" class="col-md-2 col-form-label">OpgaveType</label>
<InputText id="taskTypeEnum" class="col-md-10 form-control" @bind-Value="_taskItem.TaskTypeEnum"/>
</div>
</div>
<div class="row mb-2">
<div class="input-group">
<label for="isCompleted" class="col-md-2 col-form-label">Afsluttet</label>
<InputCheckbox id="isCompleted" class="col-md-10 form-check-input" @bind-Value="_taskItem.IsCompleted"/>
</div>
</div>
<div class="row mb-2">
<div class="input-group">
<label for="overDue" class="col-md-2 col-form-label">Overskredet</label>
<InputCheckbox id="overDue" class="col-md-10 form-check-input" @bind-Value="_taskItem.OverDue" disabled />
</div>
</div>
<div class="row mb-2">
<div class="input-group">
<label for="recurring" class="col-md-2 col-form-label">Gentagelse</label>
<InputCheckbox id="recurring" class="col-md-10 form-check-input" @bind-Value="_taskItem.Recurring"/>
</div>
</div>
@if (_taskItem.Recurring)
{
<div class="row mb-2">
<div class="input-group">
<label for="interval" class="col-md-2 col-form-label">Interval</label>
<InputNumber id="interval" class="col-md-10 form-control" @bind-Value="_taskItem.Interval"/>
</div>
</div>
}
</EditForm>
</div>
<div class="card-footer">
</div>
</div>
</div>
</div>

View file

@ -13,6 +13,8 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Forms;
using Wonky.Client.HttpInterceptors;
@ -36,6 +38,7 @@ public partial class TaskItemViewPage : IDisposable
_interceptor.RegisterBeforeSendEvent();
_taskItem = await _taskItemRepo.GetTaskItem(TaskItemId);
Console.WriteLine(JsonSerializer.Serialize(_taskItem));
}
protected override void OnInitialized()

View file

@ -26,7 +26,11 @@
<thead>
<tr>
<th colspan="4">
<h2 class="text-center">@_order.Company.Name</h2>
@if (_order.Express)
{
<h2 class="text-center fw-bold">HASTE ORDRE</h2>
}
<h2 class="text-center">@_order.Company.Name</h2>
</th>
</tr>
</thead>

View file

@ -16,26 +16,15 @@
*@
@using Microsoft.AspNetCore.Authorization
@using Wonky.Client.Components
@attribute [Authorize(Roles = "Advisor")]
@page "/companies/{CompanyId}/workplaces"
<div class="card">
<div class="card-header">
<div class="card-title">
<h2>@_company.Name</h2>
</div>
</div>
<div class="card-body">
@if (_workplaces.Any())
{
<ul class="list-group">
@foreach (var workplace in _workplaces)
{
<a class="list-group-item list-group-item-action" href="/companies/@CompanyId/workplaces/@workplace.WorkplaceId">
@workplace.Name @(!string.IsNullOrWhiteSpace(workplace.Description) ? $"- {workplace.Description}" : "")
</a>
}
</ul>
}
<div class="row bg-light border border-1 rounded-2">
<div class="col">
<h2>@_company.Name</h2>
</div>
</div>
<div class="row">
<WorkplaceListComponent CompanyId="@CompanyId" Workplaces="@_workplaces" />
</div>

View file

@ -37,9 +37,11 @@ public partial class WorkplaceListPage : IDisposable
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
_company = await _companyRepo.GetCompanyById(CompanyId);
}
protected override async Task OnInitializedAsync()
{
_workplaces = await _workplaceRepo.GetWorkplaces(CompanyId);
Console.WriteLine(JsonSerializer.Serialize(_workplaces));
}
public void Dispose()

View file

@ -13,6 +13,7 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using System.Net.Http.Headers;
using Microsoft.AspNetCore.Components.Web;
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
using Microsoft.AspNetCore.Components.Authorization;
@ -40,6 +41,8 @@ builder.Services.AddHttpClient("InnoAPI", (sp, cl) =>
{
var apiConfig = sp.GetRequiredService<IOptions<ApiConfig>>();
cl.BaseAddress = new Uri(apiConfig.Value.InnoBaseUrl);
cl.DefaultRequestHeaders.CacheControl = CacheControlHeaderValue.Parse("no-cache, no-store, must-revalidate");
cl.DefaultRequestHeaders.Add("Pragma", "no-cache");
cl.EnableIntercept(sp);
});

View file

@ -33,15 +33,17 @@ namespace Wonky.Client.Services
private readonly AuthenticationStateProvider _authStateProvider;
private readonly ILocalStorageService _localStorage;
private readonly IOptions<ApiConfig> _apiConfig;
private readonly ILogger<AuthenticationService> _logger;
public AuthenticationService(HttpClient client,
AuthenticationStateProvider authStateProvider,
ILocalStorageService localStorage, IOptions<ApiConfig> apiConfig)
ILocalStorageService localStorage, IOptions<ApiConfig> apiConfig, ILogger<AuthenticationService> logger)
{
_client = client;
_authStateProvider = authStateProvider;
_localStorage = localStorage;
_apiConfig = apiConfig;
_logger = logger;
}
public async Task<AuthResponseView> Login(CredentialDto credentials)
@ -111,13 +113,17 @@ namespace Wonky.Client.Services
{
((AuthStateProvider)_authStateProvider).NotifyUserLogout();
_client.DefaultRequestHeaders.Authorization = null;
await _localStorage.ClearAsync();
await _localStorage.RemoveItemsAsync(new List<string> {"_xa", "_xe", "_xr", "_xu"});
}
public async Task<UserInfoView> UserInfo(bool write = false)
{
var infoResponse = await _client.GetAsync(_apiConfig.Value.CrmUser);
var infoContent = await infoResponse.Content.ReadAsStringAsync();
_logger.LogDebug("UserInfo <= {}", infoContent);
var userInfo = JsonSerializer.Deserialize<UserInfoView>(infoContent, _options);
if(write)
await _localStorage.SetItemAsync("_xu", userInfo);

View file

@ -25,6 +25,7 @@ public record Preferences
public string? ItemSort { get; set; } = "name";
public string PageSize { get; set; } = "10";
public string WorkDate { get; set; } = "";
public int KmMorning { get; set; }
}
public class UserPreferenceService
{
@ -34,6 +35,18 @@ public class UserPreferenceService
{
_localStorageService = localStorageService;
}
public async Task SetKmMorning(int kmMorning)
{
var preferences = await GetPreferences();
var newPreferences = preferences
with
{
KmMorning = kmMorning
};
await _localStorageService.SetItemAsync("preferences", newPreferences);
OnChange?.Invoke(newPreferences);
}
public async Task SetCompanyFilterPhrase(string filterPhrase)
{
@ -46,6 +59,7 @@ public class UserPreferenceService
await _localStorageService.SetItemAsync("preferences", newPreferences);
OnChange?.Invoke(newPreferences);
}
public async Task SetWorkDate(DateTime workDate)
{
var preferences = await GetPreferences();
@ -57,6 +71,7 @@ public class UserPreferenceService
await _localStorageService.SetItemAsync("preferences", newPreferences);
OnChange?.Invoke(newPreferences);
}
public async Task SetCompanySearch(string companySearch)
{
var preferences = await GetPreferences();
@ -92,6 +107,7 @@ public class UserPreferenceService
await _localStorageService.SetItemAsync("preferences", newPreferences);
OnChange?.Invoke(newPreferences);
}
public async Task SetPageSize(string pageSize)
{
var preferences = await GetPreferences();
@ -100,6 +116,7 @@ public class UserPreferenceService
await _localStorageService.SetItemAsync("preferences", newPreferences);
OnChange?.Invoke(newPreferences);
}
public async Task<Preferences> GetPreferences()
{
return await _localStorageService.GetItemAsync<Preferences>("preferences").ConfigureAwait(true)

View file

@ -32,6 +32,6 @@
<div class="content d-none d-print-block">
@Body
</div>
<BlazoredToasts Position="ToastPosition.BottomCenter" Timeout="2"/>
<BlazoredToasts Position="ToastPosition.BottomCenter" Timeout="3"/>
</main>
</div>

View file

@ -30,7 +30,7 @@
<ItemSearchComponent OnChanged="SetSearchCol"/>
</div>
<div class="col">
<SearchPhraseComponent SavedSearch="@_searchTerm" OnChanged="SetSearchPhrase"/>
<ItemSearchPhraseComponent OnChanged="SetSearchPhrase"/>
</div>
@* <div class="col"> *@
@* <ItemSortComponent OnChanged="SetSortCol"/> *@
@ -65,7 +65,7 @@
<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(item.ItemId, rate.Quantity, rate.Rate))">
<a class="btn btn-primary btn-sm" data-bs-dismiss="modal" @onclick="@(() => SelectItem(item.SalesItemId, rate.Quantity, rate.Rate))">
<i class="oi oi-plus"></i>
</a>
</div>

View file

@ -35,15 +35,15 @@ public partial class PriceListModal : IDisposable
private MetaData? _metaData { get; set; } = new();
private CatalogPagingParams _paging = new();
private Preferences _preferences = new();
private string _searchTerm { get; set; } = "";
protected override async Task OnInitializedAsync()
{
_preferences = await _preferenceService.GetPreferences();
_paging.OrderBy = _preferences.ItemSort;
_paging.SearchColumn = _preferences.ItemSort;
_paging.PageSize = Convert.ToInt32((_preferences.PageSize));
_paging.SearchColumn = _preferences.ItemSearch;
_paging.PageSize = Convert.ToInt32(_preferences.PageSize);
_interceptor.RegisterEvent();
_interceptor.RegisterBeforeSendEvent();
await GetSalesItems();
}
@ -55,7 +55,6 @@ public partial class PriceListModal : IDisposable
private async Task SetSearchPhrase(string searchTerm)
{
_searchTerm = searchTerm;
_items = new List<SalesItemView>();
_paging.PageNumber = 1;
_paging.SearchTerm = searchTerm;

View file

@ -36,6 +36,9 @@ public partial class ProductPriceHistoryModal
protected override async Task OnParametersSetAsync()
{
if (string.IsNullOrWhiteSpace(ItemSku))
return;
History = await _historyRepo.FetchHistory(CompanyId, ItemSku);
if (History.Any())
{

View file

@ -11,10 +11,10 @@
<PackageReference Include="Blazored.LocalStorage" Version="4.2.0" />
<PackageReference Include="Blazored.Toast" Version="3.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.7" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.7" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="6.0.8" />
<PackageReference Include="Microsoft.AspNetCore.Components.Authorization" Version="6.0.8" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="6.0.8" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="6.0.8" PrivateAssets="all" />
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
<PackageReference Include="Microsoft.Extensions.Http" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />

View file

@ -1,18 +1,18 @@
{
"appInfo": {
"name": "Wonky Client",
"version": "0.10.72",
"version": "0.11.122",
"rc": false,
"sandBox": false,
"image": "grumpy-coder.png"
},
"apiConfig": {
"innoBaseUrl": "https://app.innotec.dk",
"innoBaseUrl": "https://eta.innotec.dk",
"glsTrackUrl": "https://www.gls-group.eu/276-I-PORTAL-WEB/content/GLS/DK01/DA/5004.htm?txtAction=71000&txtRefNo=",
"glsId": "",
"serviceVirk": "api/v2/services/virk",
"serviceBrReg": "api/v2/services/brReg",
"servcieVies": "api/v2/services/vies",
"serviceVies": "api/v2/services/vies",
"crmAuth": "token",
"crmUser": "api/auth/userinfo",
"crmCatalog": "api/v2/crm/catalog",

View file

@ -149,11 +149,24 @@ footer.version {
color-adjust: exact;
}
.report-page {
/*break-before: page;*/
break-after: page;
/*break-before: page;*/
height: initial;
border: initial;
border-radius: initial;
box-shadow: initial;
margin: 0;
width: initial;
-webkit-print-color-adjust: exact;
color-adjust: exact;
}
.report-page-item {
break-after: page;
break-inside: avoid-page;
height: initial;
/*font-size: 10px;*/
border: initial;
border-radius: initial;
box-shadow: initial;

View file

@ -0,0 +1,40 @@
.fib {
background-size: contain;
background-position: 50%;
background-repeat: no-repeat;
}
.fi {
font-size: 64px;
background-size: contain;
background-position: 50%;
background-repeat: no-repeat;
position: relative;
display: inline-block;
width: 1.33333333em;
line-height: 1em;
}
.fi:before {
content: '\00a0';
}
.fi.fis {
width: 1em;
}
.fi-dk {
background-image: url(flags/4x3/dk.svg);
}
.fi-dk.fis {
background-image: url(flags/1x1/dk.svg);
}
.fi-no {
background-image: url(flags/4x3/no.svg);
}
.fi-no.fis {
background-image: url(flags/1x1/no.svg);
}
.fi-se {
background-image: url(flags/4x3/se.svg);
}
.fi-se.fis {
background-image: url(flags/1x1/se.svg);
}

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-dk" viewBox="0 0 512 512">
<path fill="#c8102e" d="M0 0h512.1v512H0z"/>
<path fill="#fff" d="M144 0h73.1v512H144z"/>
<path fill="#fff" d="M0 219.4h512.1v73.2H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 232 B

View file

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-no" viewBox="0 0 512 512">
<path fill="#ed2939" d="M0 0h512v512H0z"/>
<path fill="#fff" d="M128 0h128v512H128z"/>
<path fill="#fff" d="M0 192h512v128H0z"/>
<path fill="#002664" d="M160 0h64v512h-64z"/>
<path fill="#002664" d="M0 224h512v64H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 318 B

View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-se" viewBox="0 0 512 512">
<path fill="#005293" d="M0 0h512v512H0z"/>
<path fill="#fecb00" d="M134 0v204.8H0v102.4h134V512h102.4V307.2H512V204.8H236.4V0H134z"/>
</svg>

After

Width:  |  Height:  |  Size: 227 B

View file

@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-dk" viewBox="0 0 640 480">
<path fill="#c8102e" d="M0 0h640.1v480H0z"/>
<path fill="#fff" d="M205.7 0h68.6v480h-68.6z"/>
<path fill="#fff" d="M0 205.7h640.1v68.6H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 236 B

View file

@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-no" viewBox="0 0 640 480">
<path fill="#ed2939" d="M0 0h640v480H0z"/>
<path fill="#fff" d="M180 0h120v480H180z"/>
<path fill="#fff" d="M0 180h640v120H0z"/>
<path fill="#002664" d="M210 0h60v480h-60z"/>
<path fill="#002664" d="M0 210h640v60H0z"/>
</svg>

After

Width:  |  Height:  |  Size: 318 B

View file

@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" id="flag-icons-se" viewBox="0 0 640 480">
<path fill="#005293" d="M0 0h640v480H0z"/>
<path fill="#fecb00" d="M176 0v192H0v96h176v192h96V288h368v-96H272V0h-96z"/>
</svg>

After

Width:  |  Height:  |  Size: 213 B

View file

@ -2,18 +2,22 @@
<html lang="da">
<head>
<title>Inno Web CRM</title>
<meta charset="utf-8" />
<title>Inno Web CRM</title>
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png" />
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png" />
<link rel="mask-icon" href="safari-pinned-tab.svg" color="#5bbad5" />
<meta name="msapplication-TileColor" content="#ffaa00" />
<meta name="application-TileColor" content="#ffaa00" />
<meta name="theme-color" content="#000" />
<base href="/" />
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" />
<link href="flag-icons/flag-icons.css" rel="stylesheet" />
<link href="css/app-v0.10.101.css" rel="stylesheet" />
<link href="Wonky.Client.styles.css" rel="stylesheet" />
<link href="_content/Blazored.Toast/blazored-toast.min.css" rel="stylesheet" />
</head>

View file

@ -113,10 +113,12 @@ namespace Wonky.Entity.DTO
/// </summary>
[Required(ErrorMessage = "Vælg aktivitetstype")]
public string ActivityTypeEnum { get; set; } = "";
/// <summary>
/// Flag express order
/// </summary>
public bool Express { get; set; }
/// <summary>
/// Activity status enum as string
/// </summary>

View file

@ -13,6 +13,7 @@
// along with this program. If not, see [https://www.gnu.org/licenses/agpl-3.0.en.html]
//
using System.Collections.Concurrent;
using System.ComponentModel.DataAnnotations;
namespace Wonky.Entity.DTO;
@ -61,15 +62,20 @@ public class UserInfoDto
public string Advisor { get; set; } = "";
/// <summary>
/// Country name
/// User Id
/// </summary>
public string CountryName { get; set; } = "";
public string UserId { get; set; } = "";
/// <summary>
/// Lockout flag
/// </summary>
public bool LockoutEnabled { get; set; }
/// <summary>
/// Country name
/// </summary>
public string CountryName { get; set; } = "";
/// <summary>
/// Email confirmed flag
/// </summary>
@ -84,9 +90,12 @@ public class UserInfoDto
/// Admin flag
/// </summary>
public bool IsAdmin { get; set; }
/// <summary>
/// User Id
/// </summary>
public string UserId { get; set; } = "";
public bool IsEDoc { get; set; }
public bool IsEShop { get; set; }
public bool IsSupervisor { get; set; }
public bool IsOffice { get; set; }
public bool IsWarehouse { get; set; }
public string Roles { get; set; } = "";
public string ReferenceId { get; set; } = "";
}

View file

@ -29,7 +29,10 @@ public class ReportItemView
/// Closed sale
/// </summary>
public bool Closed { get; set; }
/// <summary>
/// express flag
/// </summary>
public bool Express { get; set; }
/// <summary>
/// ESales number
/// </summary>

View file

@ -17,7 +17,8 @@ namespace Wonky.Entity.Views;
public class SalesItemView
{
public string ItemId { get; set; } = "";
public string SalesItemId { get; set; } = "";
public string VariantId { get; set; } = "";
public string Name { get; set; } = "";
public string Sku { get; set; } = "";
public string ShortName { get; set; } = "";

View file

@ -20,8 +20,8 @@ namespace Wonky.Entity.Views;
public class UserInfoView
{
[JsonPropertyName("id")] public string Id { get; set; } = "";
[JsonPropertyName("Advisor")] public string Advisor { get; set; } = "";
[JsonPropertyName("companyId")] public string CrmCompanyKey { get; set; } = "";
[JsonPropertyName("advisor")] public string Advisor { get; set; } = "";
[JsonPropertyName("companyId")] public string ReferenceId { get; set; } = "";
[JsonPropertyName("countryCode")] public string CountryCode { get; set; } = "";
[JsonPropertyName("countryName")] public string CountryName { get; set; } = "";
[JsonPropertyName("email")] public string Email { get; set; } = "";

View file

@ -59,4 +59,8 @@ public class WarehouseOrderView
/// Current process status
/// </summary>
public string ProcessStatusEnum { get; set; } = "";
/// <summary>
/// express flag
/// </summary>
public bool Express { get; set; }
}