Merge branch 'feature-quote-to-order' into dev-v6

This commit is contained in:
Frede Hundewadt 2022-12-14 16:47:28 +01:00
commit 94f67d4d36
11 changed files with 243 additions and 102 deletions

View file

@ -24,14 +24,14 @@ public interface ICrmActivityHttpRepository
/// Get a list of open quotes /// Get a list of open quotes
/// </summary> /// </summary>
/// <returns>List of Activities with ActivityStatus == Quote</returns> /// <returns>List of Activities with ActivityStatus == Quote</returns>
Task<List<ActivityDto>> GetQuotes(); Task<List<ReportItemView>> GetQuotes();
/// <summary> /// <summary>
/// Convert quote to sale /// Convert quote to sale
/// </summary> /// </summary>
/// <param name="activity"></param> /// <param name="activity"></param>
/// <returns></returns> /// <returns></returns>
Task<ApiResponseView> AcceptQuote(ActivityDto activity); Task<ApiResponseView> AcceptQuote(ReportItemView activity);
/// <summary> /// <summary>
/// Get activities by date /// Get activities by date

View file

@ -50,10 +50,9 @@ public class CrmActivityHttpRepository : ICrmActivityHttpRepository
/// Get a list of quotes /// Get a list of quotes
/// </summary> /// </summary>
/// <returns>List of activities with Quote status </returns> /// <returns>List of activities with Quote status </returns>
public async Task<List<ActivityDto>> GetQuotes() public async Task<List<ReportItemView>> GetQuotes()
{ {
var result = await _client.GetFromJsonAsync<List<ActivityDto>>($"{_api.CrmActivities}/quotes", _options); return await _client.GetFromJsonAsync<List<ReportItemView>>($"{_api.CrmActivities}/quotes", _options);
return result ?? new List<ActivityDto>();
} }
/// <summary> /// <summary>
@ -61,10 +60,10 @@ public class CrmActivityHttpRepository : ICrmActivityHttpRepository
/// </summary> /// </summary>
/// <param name="activity"></param> /// <param name="activity"></param>
/// <returns></returns> /// <returns></returns>
public async Task<ApiResponseView> AcceptQuote(ActivityDto activity) public async Task<ApiResponseView> AcceptQuote(ReportItemView activity)
{ {
var response = await _client.PutAsJsonAsync( var response = await _client.PutAsJsonAsync(
$"{_api.CrmActivities}/{activity.SalesHeadId}/accept", activity, _options); $"{_api.CrmActivities}/{activity.ActivityId}/accept", activity, _options);
var content = await response.Content.ReadAsStringAsync(); var content = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<ApiResponseView>(content); var result = JsonSerializer.Deserialize<ApiResponseView>(content);

View file

@ -20,6 +20,7 @@
@attribute [Authorize(Roles = "Admin,Office,Warehouse,Advisor")] @attribute [Authorize(Roles = "Admin,Office,Warehouse,Advisor")]
@page "/companies/{CompanyId}/orders/{OrderId}" @page "/companies/{CompanyId}/orders/{OrderId}"
@page "/companies/{CompanyId}/quotes/{OrderId}"
@* <ReportItemComponent ReportItem="@_item" /> *@ @* <ReportItemComponent ReportItem="@_item" /> *@
@ -31,7 +32,7 @@
<h2 class="fw-bold text-center">@ReportItem.Company.Name</h2> <h2 class="fw-bold text-center">@ReportItem.Company.Name</h2>
@if (ReportItem.StatusTypeEnum.ToLower() is "quote") @if (ReportItem.StatusTypeEnum.ToLower() is "quote")
{ {
<h3 class="text-center">TILBUD</h3> <h3 class="text-center">TILBUD <span style="font-family: monospace;">@ReportItem.ESalesNumber</span></h3>
} }
@if (ReportItem.VisitTypeEnum.ToLower() == "phone" || ReportItem.OurRef.Contains("T:")) @if (ReportItem.VisitTypeEnum.ToLower() == "phone" || ReportItem.OurRef.Contains("T:"))
{ {

View file

@ -43,6 +43,7 @@ public partial class CrmCompanyInventoryPage : IDisposable
Interceptor.RegisterBeforeSendEvent(); Interceptor.RegisterBeforeSendEvent();
Company = await CompanyRepo.GetCompanyById(CompanyId); Company = await CompanyRepo.GetCompanyById(CompanyId);
while (string.IsNullOrWhiteSpace(Company.HistorySync)) while (string.IsNullOrWhiteSpace(Company.HistorySync))
{ {
await Task.Delay(1000); await Task.Delay(1000);
@ -52,6 +53,7 @@ public partial class CrmCompanyInventoryPage : IDisposable
{ {
await Task.Delay(1000); await Task.Delay(1000);
} }
await FetchInventory(); await FetchInventory();
Working = false; Working = false;
} }

View file

@ -27,6 +27,18 @@ public partial class CrmCompanyInvoiceListPage : IDisposable
Company = await CompanyRepo.GetCompanyById(CompanyId); Company = await CompanyRepo.GetCompanyById(CompanyId);
while (string.IsNullOrWhiteSpace(Company.HistorySync))
{
await Task.Delay(1000);
}
var ts = await HistoryRepo.ErpInvoiceToCrmRpc(CompanyId, Company.HistorySync);
while (string.IsNullOrWhiteSpace(ts))
{
await Task.Delay(1000);
}
Company = await CompanyRepo.GetCompanyById(CompanyId);
while (string.IsNullOrWhiteSpace(Company.HistorySync)) while (string.IsNullOrWhiteSpace(Company.HistorySync))
{ {
await Task.Delay(1000); await Task.Delay(1000);

View file

@ -129,11 +129,13 @@
<div class="col"> <div class="col">
<a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/invoices">Faktura</a> <a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/invoices">Faktura</a>
</div> </div>
@*
<div class="col"> <div class="col">
<a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/quotes">Tilbud</a> <a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/quotes">Tilbud</a>
</div> </div>
*@
<div class="col"> <div class="col">
<a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/activities">Besøg</a> <a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/activities">Tidl. Besøg</a>
</div> </div>
<div class="col"> <div class="col">
<a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/h/i">Produkter</a> <a class="btn btn-dark opacity-50 d-block" href="/companies/@Company.CompanyId/h/i">Produkter</a>

View file

@ -1,15 +1,69 @@
@page "/open-quotes" @page "/open-quotes"
@using Wonky.Client.HttpInterfaces @using Wonky.Client.Components
<div class="row"> <div class="row g-3">
<h3>Åbne tilbud</h3> <div class="col-sm-12">
<h3 class="text-center">Åbne tilbud</h3>
</div>
</div>
<div class="list-group list-group-flush">
<div class="list-group-item bg-dark text-white">
<div class="row g-3">
<div class="col-sm-2">
Reference
</div>
<div class="col-sm-4">
Kunde
</div>
<div class="col-sm-1">
Dato
</div>
<div class="col-sm-2 text-end">
Tilbudssum
</div>
<div class="col-sm-3"></div>
</div>
</div>
@if (Quotes.Any())
{
foreach (var quote in Quotes)
{
<div class="list-group-item list-group-item-action">
<div class="row align-items-center">
<div class="col-sm-2" style="font-family: monospace;">
<a class="btn btn-outline-dark d-block" href="/companies/@quote.Company.CompanyId/quotes/@quote.ActivityId">@quote.ESalesNumber</a>
</div>
<div class="col-sm-4">
@quote.Company.Name
</div>
<di class="col-sm-1">
@quote.OrderDate
</di>
<div class="col-sm-2 text-end">
@($"{quote.OrderAmount:N2}")
</div>
<div class="col-sm-1"><button type="button" class="btn btn-outline-danger" @onclick="() => SetQuote(2)"><i class="bi-hand-thumbs-down-fill"></i> </button></div>
<div class="col-sm-1"><button type="button" class="btn btn-outline-dark" @onclick="() => SetQuote(3)"><i class="bi-trash2-fill"></i> </button></div>
<div class="col-sm-1"><button type="button" class="btn btn-outline-success" @onclick="() => SetQuote(1)"><i class="bi-hand-thumbs-up-fill"></i> </button></div>
<div class="col-sm-1"></div>
@if (!string.IsNullOrWhiteSpace(quote.OfficeNote))
{
<div class="col-sm-2"><i class="bi-pencil"></i> Note</div>
<div class="col-sm-10">
@quote.OfficeNote
</div>
}
</div>
</div>
}
}
else
{
<div class="list-group-item">Ingen data</div>
}
</div> </div>
@code {
[Inject] ICrmHistoryHttpRepository HistoryRepo { get; set; }
protected override Task OnParametersSetAsync() @if (Working)
{ {
return base.OnParametersSetAsync(); <WorkingThreeDots/>
}
} }

View file

@ -0,0 +1,39 @@
using Microsoft.AspNetCore.Components;
using Wonky.Client.HttpInterceptors;
using Wonky.Client.HttpInterfaces;
using Wonky.Entity.DTO;
using Wonky.Entity.Views;
namespace Wonky.Client.Pages;
public partial class CrmQuotes : IDisposable
{
[Inject] public ICrmActivityHttpRepository ActivityRepo { get; set; }
[Inject] public HttpInterceptorService Interceptor { get; set; }
private List<ReportItemView> Quotes { get; set; } = new();
private bool Working { get; set; } = true;
protected override async Task OnInitializedAsync()
{
Interceptor.RegisterEvent();
Interceptor.RegisterBeforeSendEvent();
Quotes = await ActivityRepo.GetQuotes();
if (Quotes.Any())
Quotes = Quotes.OrderBy(x => x.CreateTimestamp).ToList();
Working = false;
}
private void SetQuote(int status)
{
// todo - implement update quote from status
// status matches QuoteStatusEnum
// 0 - None
// 1 - Win
// 2 - Lose
// 3 - Draw
}
public void Dispose()
{
Interceptor.DisposeEvent();
}
}

View file

@ -33,12 +33,12 @@
<NotAuthorized> <NotAuthorized>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/" Match="NavLinkMatch.All"> <NavLink class="nav-link ps-2" href="/" Match="NavLinkMatch.All">
<span class="oi oi-dashboard"></span> Start <i class="bi-person-workspace pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Start
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/login"> <NavLink class="nav-link ps-2" href="/login">
<span class="oi oi-account-login"></span> Log ind <i class="bi-lock pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Log ind
</NavLink> </NavLink>
</div> </div>
</NotAuthorized> </NotAuthorized>
@ -47,12 +47,12 @@
<AuthorizeView Roles="Admin"> <AuthorizeView Roles="Admin">
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/office/users/advisors"> <NavLink class="nav-link ps-2" href="/office/users/advisors">
<span class="oi oi-people" aria-hidden="true"></span> Sælgere <i class="bi-people pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Sælgere
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/price-catalog"> <NavLink class="nav-link ps-2" href="/price-catalog">
<span class="oi oi-spreadsheet" aria-hidden="true"></span> Priskatalog <i class="bi-file-spreadsheet pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Priskatalog
</NavLink> </NavLink>
</div> </div>
</AuthorizeView> </AuthorizeView>
@ -60,17 +60,12 @@
<AuthorizeView Roles="Office"> <AuthorizeView Roles="Office">
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/office/users/advisors"> <NavLink class="nav-link ps-2" href="/office/users/advisors">
<span class="oi oi-people" aria-hidden="true"></span> Sælgere <i class="bi-people pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Sælgere
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/price-catalog"> <NavLink class="nav-link ps-2" href="/price-catalog">
<span class="oi oi-spreadsheet" aria-hidden="true"></span> Priskatalog <i class="bi-file-spreadsheet pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Priskatalog
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/warehouse/orders">
<span class="oi oi-box" aria-hidden="true"></span> Forsendelse
</NavLink> </NavLink>
</div> </div>
</AuthorizeView> </AuthorizeView>
@ -78,7 +73,7 @@
<AuthorizeView Roles="Warehouse,Admin,Office"> <AuthorizeView Roles="Warehouse,Admin,Office">
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/warehouse/orders/none"> <NavLink class="nav-link ps-2" href="/warehouse/orders/none">
<span class="oi oi-box" aria-hidden="true"></span> Forsendelse <i class="bi-box pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Forsendelse
</NavLink> </NavLink>
</div> </div>
</AuthorizeView> </AuthorizeView>
@ -87,33 +82,38 @@
<Authorized> <Authorized>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/home"> <NavLink class="nav-link ps-2" href="/home">
<span class="oi oi-calendar" aria-hidden="true"></span> ToDo <i class="bi-calendar pe-2" style="font-size:1.3em;" aria-hidden="true"></i> ToDo
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/companies"> <NavLink class="nav-link ps-2" href="/companies">
<span class="oi oi-file" aria-hidden="true"></span> Firmaer <i class="bi-building pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Firmaer
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/price-catalog"> <NavLink class="nav-link ps-2" href="/price-catalog">
<span class="oi oi-spreadsheet" aria-hidden="true"></span> Priskatalog <i class="bi-file-spreadsheet pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Priskatalog
</NavLink>
</div>
<div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/open-quotes">
<i class="bi-calculator pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Åbne Tilbud
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/activity-today"> <NavLink class="nav-link ps-2" href="/activity-today">
<span class="oi oi-dashboard" aria-hidden="true"></span> Aktivitet <i class="bi-activity pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Aktivitet
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/sales-reports"> <NavLink class="nav-link ps-2" href="/sales-reports">
<span class="oi oi-document" aria-hidden="true"></span> Dagsrapporter <i class="bi-file-earmark-spreadsheet pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Dagsrapporter
</NavLink> </NavLink>
</div> </div>
<div class="nav-item px-3"> <div class="nav-item px-3">
<NavLink class="nav-link ps-2" href="/info"> <NavLink class="nav-link ps-2" href="/info">
<span class="oi oi-question-mark" aria-hidden="true"></span> Hjælp <i class="bi-question pe-2" style="font-size:1.3em;" aria-hidden="true"></i> Hjælp
</NavLink> </NavLink>
</div> </div>
</Authorized> </Authorized>

View file

@ -1,7 +1,7 @@
{ {
"appInfo": { "appInfo": {
"name": "Wonky Client", "name": "Wonky Client",
"version": "0.84.3", "version": "0.85.4",
"rc": true, "rc": true,
"sandBox": false, "sandBox": false,
"image": "grumpy-coder.png" "image": "grumpy-coder.png"

View file

@ -21,96 +21,128 @@ public class ReportItemView
/// Customer company info /// Customer company info
/// </summary> /// </summary>
public ReportItemCustomer Company { get; set; } = new(); public ReportItemCustomer Company { get; set; } = new();
/// <summary> /// <summary>
/// Lines /// Lines
/// </summary> /// </summary>
public List<ReportItemLine> Lines { get; set; } = new(); public List<ReportItemLine> Lines { get; set; } = new();
/// <summary>
/// entity id for sales rep
/// </summary>
public string SalesRepId { get; set; } = "";
/// <summary> /// <summary>
/// Activity entity id /// Activity entity id
/// </summary> /// </summary>
public string ActivityId { get; set; } = ""; public string ActivityId { get; set; } = "";
/// <summary>
/// Entity CreateTimestamp as string
/// </summary>
public string CreateTimestamp { get; set; } = "";
/// <summary> /// <summary>
/// Closed sale /// Closed sale
/// </summary> /// </summary>
public bool Closed { get; set; } public bool Closed { get; set; }
/// <summary> /// <summary>
/// ProcessStatus as string /// Entity CreateTimestamp as string
/// </summary> /// </summary>
public string ProcessStatusEnum { get; set; } = ""; public string CreateTimestamp { get; set; } = "";
/// <summary> /// <summary>
/// express flag /// CRM Note
/// </summary> /// </summary>
public bool Express { get; set; } public string CrmNote { get; set; } = "";
/// <summary>
/// ESales number
/// </summary>
public string ESalesNumber { get; set; } = "";
/// <summary>
/// Order amount
/// </summary>
public decimal OrderAmount { get; set; }
/// <summary>
/// Order safe seal amount
/// </summary>
public decimal SasAmount { get; set; }
/// <summary>
/// Order date
/// </summary>
public string OrderDate { get; set; } = "";
/// <summary>
/// Office note
/// </summary>
public string OfficeNote { get; set; } = "";
/// <summary> /// <summary>
/// Product demo /// Product demo
/// </summary> /// </summary>
public string Demo { get; set; } = ""; public string Demo { get; set; } = "";
/// <summary>
/// Product sale resume
/// </summary>
public string Sales { get; set; } = "";
/// <summary>
/// Our reference
/// </summary>
public string OurRef { get; set; } = "";
/// <summary>
/// Customer reference
/// </summary>
public string YourRef { get; set; } = "";
/// <summary>
/// Customer reference number
/// </summary>
public string ReferenceNumber { get; set; } = "";
/// <summary>
/// Visit type enum as string
/// </summary>
public string VisitTypeEnum { get; set; } = "";
/// <summary>
/// Status type enum as string
/// </summary>
public string StatusTypeEnum { get; set; } = "";
/// <summary>
/// Customer deliver name
/// </summary>
public string DlvName { get; set; } = "";
/// <summary> /// <summary>
/// Customer delivery address line 1 /// Customer delivery address line 1
/// </summary> /// </summary>
public string DlvAddress1 { get; set; } = ""; public string DlvAddress1 { get; set; } = "";
/// <summary> /// <summary>
/// Customer delivery address line 2 /// Customer delivery address line 2
/// </summary> /// </summary>
public string DlvAddress2 { get; set; } = ""; public string DlvAddress2 { get; set; } = "";
/// <summary>
/// Customer deliver name
/// </summary>
public string DlvName { get; set; } = "";
/// <summary> /// <summary>
/// Customer delivery post code and city name /// Customer delivery post code and city name
/// </summary> /// </summary>
public string DlvZipCity { get; set; } = ""; public string DlvZipCity { get; set; } = "";
/// <summary>
/// ESales number
/// </summary>
public string ESalesNumber { get; set; } = "";
/// <summary>
/// express flag
/// </summary>
public bool Express { get; set; }
/// <summary>
/// Office note
/// </summary>
public string OfficeNote { get; set; } = "";
/// <summary>
/// Order amount
/// </summary>
public decimal OrderAmount { get; set; }
/// <summary>
/// Order date
/// </summary>
public string OrderDate { get; set; } = "";
/// <summary>
/// Our reference
/// </summary>
public string OurRef { get; set; } = "";
/// <summary>
/// ProcessStatus as string
/// </summary>
public string ProcessStatusEnum { get; set; } = "";
/// <summary>
/// QuoteStatus as string
/// </summary>
public string QuoteStatusEnum { get; set; } = "";
/// <summary>
/// Customer reference number
/// </summary>
public string ReferenceNumber { get; set; } = "";
/// <summary>
/// Product sale resume
/// </summary>
public string Sales { get; set; } = "";
/// <summary>
/// entity id for sales rep
/// </summary>
public string SalesRepId { get; set; } = "";
/// <summary>
/// Order safe seal amount
/// </summary>
public decimal SasAmount { get; set; }
/// <summary>
/// Status type enum as string
/// </summary>
public string StatusTypeEnum { get; set; } = "";
/// <summary>
/// Visit type enum as string
/// </summary>
public string VisitTypeEnum { get; set; } = "";
/// <summary>
/// Customer reference
/// </summary>
public string YourRef { get; set; } = "";
} }