fix
This commit is contained in:
@@ -3,6 +3,7 @@
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Models.Accounts;
|
using Models.Accounts;
|
||||||
|
using MyOffice.Data.Models.Currencies;
|
||||||
using MyOffice.Data.Repositories;
|
using MyOffice.Data.Repositories;
|
||||||
|
|
||||||
public class AccountRepository : AppRepository<Account>, IAccountRepository
|
public class AccountRepository : AppRepository<Account>, IAccountRepository
|
||||||
@@ -184,8 +185,8 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
|
|||||||
Id = x.Id,
|
Id = x.Id,
|
||||||
Name = x.Name,
|
Name = x.Name,
|
||||||
Type = x.Type,
|
Type = x.Type,
|
||||||
CurrencyName = x.Currency!.Name,
|
CurrencyName = x.Currency?.Name,
|
||||||
CurrencyShortName = x.Currency!.ShortName,
|
CurrencyShortName = x.Currency?.ShortName,
|
||||||
CurrencyRate = x.CurrentRate?.Rate,
|
CurrencyRate = x.CurrentRate?.Rate,
|
||||||
CurrencyQuantity = x.CurrentRate?.Quantity,
|
CurrencyQuantity = x.CurrentRate?.Quantity,
|
||||||
TotalMinus = x.Minus,
|
TotalMinus = x.Minus,
|
||||||
@@ -201,12 +202,19 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
|
|||||||
.Where(x => x.DateTime >= from && x.DateTime <= to)
|
.Where(x => x.DateTime >= from && x.DateTime <= to)
|
||||||
.Where(x => x.Item.Category!.UserId == userId)
|
.Where(x => x.Item.Category!.UserId == userId)
|
||||||
.Where(x => !x.Item.Category!.IsInternal)
|
.Where(x => !x.Item.Category!.IsInternal)
|
||||||
.GroupBy(x => new { x.Item.CategoryId, x.Item.Category!.Name })
|
.GroupBy(x => new
|
||||||
|
{
|
||||||
|
ItemId = x.Item.CategoryId,
|
||||||
|
ItemName = x.Item.Category!.Name,
|
||||||
|
CurrencyId = x.Account.CurrencyGlobalId,
|
||||||
|
CurrencyName = x.Account.CurrencyGlobal!.Name,
|
||||||
|
})
|
||||||
.Select(x => new MotionTotalSimple
|
.Select(x => new MotionTotalSimple
|
||||||
{
|
{
|
||||||
Id = x.Key.CategoryId,
|
CurrencyId = x.Key.CurrencyId,
|
||||||
Name = x.Key.Name,
|
CurrencyName = x.Key.CurrencyName,
|
||||||
Amount = x.Sum(a => a.AmountPlus)
|
Name = x.Key.ItemName,
|
||||||
|
Amount = x.Sum(a => a.AmountPlus),
|
||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,10 +225,18 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
|
|||||||
.Where(x => x.Item.CategoryId == categoryId)
|
.Where(x => x.Item.CategoryId == categoryId)
|
||||||
.Where(x => !x.Item.Category!.IsInternal)
|
.Where(x => !x.Item.Category!.IsInternal)
|
||||||
.Where(x => x.Item.Category!.UserId == userId)
|
.Where(x => x.Item.Category!.UserId == userId)
|
||||||
.GroupBy(x => new { Id = x.Item.ItemGlobalId, x.Item.ItemGlobal.Name })
|
.GroupBy(x => new
|
||||||
|
{
|
||||||
|
ItemId = x.Item.ItemGlobalId,
|
||||||
|
ItemName = x.Item.ItemGlobal!.Name,
|
||||||
|
CurrencyId = x.Account.CurrencyGlobalId,
|
||||||
|
CurrencyName = x.Account.CurrencyGlobal!.Name,
|
||||||
|
})
|
||||||
.Select(x => new MotionTotalSimple
|
.Select(x => new MotionTotalSimple
|
||||||
{
|
{
|
||||||
Name = x.Key.Name,
|
CurrencyId = x.Key.CurrencyId,
|
||||||
|
CurrencyName = x.Key.CurrencyName,
|
||||||
|
Name = x.Key.ItemName,
|
||||||
Amount = x.Sum(a => a.AmountPlus),
|
Amount = x.Sum(a => a.AmountPlus),
|
||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
@@ -232,12 +248,20 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
|
|||||||
.Where(x => x.DateTime >= from && x.DateTime <= to)
|
.Where(x => x.DateTime >= from && x.DateTime <= to)
|
||||||
.Where(x => x.Item.Category!.UserId == userId)
|
.Where(x => x.Item.Category!.UserId == userId)
|
||||||
.Where(x => !x.Item.Category!.IsInternal)
|
.Where(x => !x.Item.Category!.IsInternal)
|
||||||
.GroupBy(x => new { x.Item.CategoryId, x.Item.Category!.Name })
|
.GroupBy(x => new
|
||||||
|
{
|
||||||
|
ItemId = x.Item.CategoryId,
|
||||||
|
ItemName = x.Item.Category!.Name,
|
||||||
|
CurrencyId = x.Account.CurrencyGlobalId,
|
||||||
|
CurrencyName = x.Account.CurrencyGlobal!.Name,
|
||||||
|
})
|
||||||
.Select(x => new MotionTotalSimple
|
.Select(x => new MotionTotalSimple
|
||||||
{
|
{
|
||||||
Id = x.Key.CategoryId,
|
Id = x.Key.ItemId,
|
||||||
Name = x.Key.Name,
|
Name = x.Key.ItemName,
|
||||||
Amount = x.Sum(a => a.AmountMinus)
|
CurrencyId = x.Key.CurrencyId,
|
||||||
|
CurrencyName = x.Key.CurrencyName,
|
||||||
|
Amount = x.Sum(a => a.AmountPlus),
|
||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
namespace MyOffice.Data.Repositories.Currency;
|
namespace MyOffice.Data.Repositories.Currency;
|
||||||
|
|
||||||
|
using System.Xml.Schema;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Models.Currencies;
|
using Models.Currencies;
|
||||||
|
|
||||||
@@ -18,18 +19,23 @@ public class CurrencyRateRepository : AppRepository<CurrencyRate>, ICurrencyRate
|
|||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<CurrencyRate> GetLastRates(List<string> currencyIds)
|
public Dictionary<string, CurrencyRate> GetLastRates(Guid userId, List<string> currencyIds, DateTime? before = null)
|
||||||
{
|
{
|
||||||
return _context.CurrencyRates
|
return _context.CurrencyRates
|
||||||
.Include(x => x.Currency)
|
.Include(x => x.Currency)
|
||||||
|
.Include(x => x.Currency!.CurrencyGlobal)
|
||||||
|
.Where(x => x.DateTime <= before)
|
||||||
|
.Where(x => x.Currency!.UserId == userId)
|
||||||
.Where(x => currencyIds.Contains(x.Currency!.CurrencyGlobalId))
|
.Where(x => currencyIds.Contains(x.Currency!.CurrencyGlobalId))
|
||||||
.GroupBy(x => new
|
.GroupBy(x => new
|
||||||
{
|
{
|
||||||
x.CurrencyId,
|
x.Currency!.CurrencyGlobalId
|
||||||
//x.Currency!.Name,
|
}, (key, g) => new
|
||||||
//x.Currency!.CurrencyGlobalId,
|
{
|
||||||
}, (key, g) => g.OrderByDescending(x => x.DateTime).First())
|
key.CurrencyGlobalId,
|
||||||
.ToList();
|
rate = g.OrderByDescending(x => x.DateTime).First()
|
||||||
|
})
|
||||||
|
.ToDictionary(x => x.CurrencyGlobalId, x => x.rate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AddRate(CurrencyRate currencyRate)
|
public bool AddRate(CurrencyRate currencyRate)
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ using Models.Currencies;
|
|||||||
public interface ICurrencyRateRepository
|
public interface ICurrencyRateRepository
|
||||||
{
|
{
|
||||||
List<CurrencyRate> GetLastRates(Guid currencyId, DateTime? before = null, int count = 1);
|
List<CurrencyRate> GetLastRates(Guid currencyId, DateTime? before = null, int count = 1);
|
||||||
List<CurrencyRate> GetLastRates(List<string> currencyIds);
|
Dictionary<string, CurrencyRate> GetLastRates(Guid userId, List<string> currencyIds, DateTime? before = null);
|
||||||
bool AddRate(CurrencyRate currencyRate);
|
bool AddRate(CurrencyRate currencyRate);
|
||||||
List<CurrencyRate> GetAtDate(Guid currencyId, DateTime date);
|
List<CurrencyRate> GetAtDate(Guid currencyId, DateTime date);
|
||||||
}
|
}
|
||||||
@@ -45,7 +45,7 @@ export class LockedComponent implements OnInit {
|
|||||||
if (this.authForm.invalid) {
|
if (this.authForm.invalid) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
this.router.navigate(['/dashboard/dashboard']);
|
this.router.navigate(['/dashboard/rests']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,50 +5,20 @@
|
|||||||
<app-breadcrumb [title]="'MENUITEMS.DASHBOARD.LIST.INCOME'" [items]="['HOME']" [active_item]="'MENUITEMS.DASHBOARD.LIST.INCOME'"></app-breadcrumb>
|
<app-breadcrumb [title]="'MENUITEMS.DASHBOARD.LIST.INCOME'" [items]="['HOME']" [active_item]="'MENUITEMS.DASHBOARD.LIST.INCOME'"></app-breadcrumb>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
<div class="col-xl-12 col-lg-12 col-md-12 col-sm-12">
|
||||||
<div class="col-4 col-sm-4 col-md-4">
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="header">
|
||||||
<div class="d-flex justify-content-between">
|
<h2>{{'PERIOD' | translate}}</h2>
|
||||||
<div>
|
|
||||||
<h5>{{'BALANCE' | translate}}</h5>
|
|
||||||
</div>
|
</div>
|
||||||
<h3 class="text-danger">{{dashboardModel?.balance | number: '0.2-2'}}</h3>
|
<div class="body">
|
||||||
</div>
|
<div class="example-container">
|
||||||
</div>
|
<app-date-period [from]="dateFrom" [to]="dateTo" (onChange)="onChangePeriod($event)"></app-date-period>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-4 col-sm-4 col-md-4">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<div>
|
|
||||||
<h5>{{'DEBIT.BALANCE' | translate}}</h5>
|
|
||||||
<p class="text-muted"></p>
|
|
||||||
</div>
|
|
||||||
<h3 class="text-success">{{dashboardModel?.balanceDebit | number: '0.2-2'}}</h3>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-4 col-sm-4 col-md-4">
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-body">
|
|
||||||
<div class="d-flex justify-content-between">
|
|
||||||
<div>
|
|
||||||
<h5>{{'CREDIT.BALANCE' | translate}}</h5>
|
|
||||||
</div>
|
|
||||||
<h3 class="text-danger">{{dashboardModel?.balanceCredit | number: '0.2-2'}}</h3>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
-->
|
|
||||||
|
|
||||||
<div class="row clearfix">
|
<div class="row clearfix">
|
||||||
<!-- Bar chart with line -->
|
<!-- Bar chart with line -->
|
||||||
@@ -73,10 +43,19 @@
|
|||||||
[dataLabels]="chartOptions.dataLabels!"
|
[dataLabels]="chartOptions.dataLabels!"
|
||||||
[plotOptions]="chartOptions.plotOptions!"
|
[plotOptions]="chartOptions.plotOptions!"
|
||||||
[title]="chartOptions.title!"
|
[title]="chartOptions.title!"
|
||||||
[legend]="chartOptions.legend!"
|
[legend]="chartOptions.legend!">
|
||||||
>
|
|
||||||
</apx-chart>
|
</apx-chart>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="table-responsive m-t-15" *ngIf="dashboardModel">
|
||||||
|
<table class="table align-items-center">
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let item of dashboardModel!.details">
|
||||||
|
<td><i class="fa fa-circle col-cyan msr-2"></i> {{item.currency}}</td>
|
||||||
|
<td [ngClass]="{ 'col-green': item.value != 0, 'col-red': item.value == 0}" style="text-align: right;">{{item.value | number: '1.2'}} ({{item.valueRaw}})</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import {
|
|||||||
ApexPlotOptions,
|
ApexPlotOptions,
|
||||||
ApexLegend
|
ApexLegend
|
||||||
} from "ng-apexcharts";
|
} from "ng-apexcharts";
|
||||||
|
import * as moment from 'moment'
|
||||||
|
|
||||||
// app
|
// app
|
||||||
import { ApiRoutes } from '../../api-routes';
|
import { ApiRoutes } from '../../api-routes';
|
||||||
@@ -40,6 +41,8 @@ export class DashboardIncomeComponent implements OnInit {
|
|||||||
@ViewChild("chart") chart!: ChartComponent;
|
@ViewChild("chart") chart!: ChartComponent;
|
||||||
public chartOptions!: Partial<ChartOptions>;
|
public chartOptions!: Partial<ChartOptions>;
|
||||||
dashboardModel?: DashboardInOutModel;
|
dashboardModel?: DashboardInOutModel;
|
||||||
|
public dateFrom: Date = moment(new Date).add(-30, 'days').toDate();
|
||||||
|
public dateTo: Date = moment(new Date).add(0, 'days').toDate();
|
||||||
|
|
||||||
colors: string[] = ["#fd7f6f", "#7eb0d5", "#b2e061", "#bd7ebe", "#ffb55a", "#ffee65", "#beb9db", "#fdcce5", "#8bd3c7"];
|
colors: string[] = ["#fd7f6f", "#7eb0d5", "#b2e061", "#bd7ebe", "#ffb55a", "#ffee65", "#beb9db", "#fdcce5", "#8bd3c7"];
|
||||||
|
|
||||||
@@ -51,15 +54,29 @@ export class DashboardIncomeComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
onChangePeriod(dates: Date[]) {
|
||||||
|
this.dateFrom = dates[0];
|
||||||
|
this.dateTo = dates[1];
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadData(update?: boolean, category?: string) {
|
||||||
let params = new HttpParams()
|
let params = new HttpParams()
|
||||||
.set('from', '2023-07-01')
|
.set('from', moment(this.dateFrom).format('YYYY-MM-DD'))
|
||||||
.set('to', '2023-08-01');
|
.set('to', moment(this.dateTo).format('YYYY-MM-DD'))
|
||||||
|
.set('category', category || '')
|
||||||
|
;
|
||||||
|
|
||||||
this.httpClient
|
this.httpClient
|
||||||
.get<DashboardInOutModel>(ApiRoutes.DashboardIncome, { params: params })
|
.get<DashboardInOutModel>(ApiRoutes.DashboardIncome, { params: params })
|
||||||
.subscribe(response => {
|
.subscribe(response => {
|
||||||
|
this.dashboardModel = response;
|
||||||
|
|
||||||
var series = response.data.map(x => ({
|
var series = response.data.map(x => ({
|
||||||
x: x.name + '(' + this._decimalPipe.transform(x.value, '1.2-2') || "" + ')',
|
x: x.name + '(' + (this._decimalPipe.transform(x.value, '1.2-2') || "") + ')',
|
||||||
y: x.value
|
y: x.value
|
||||||
}));
|
}));
|
||||||
var min = Math.min(...response.data.map(x => x.value));
|
var min = Math.min(...response.data.map(x => x.value));
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row clearfix">
|
<div class="row clearfix">
|
||||||
<!-- Bar chart with line -->
|
<!-- Bar chart with line -->
|
||||||
<div class="col-xl-12 col-lg-12 col-md-12 col-sm-12">
|
<div class="col-xl-12 col-lg-12 col-md-12 col-sm-12">
|
||||||
@@ -45,9 +46,21 @@
|
|||||||
[title]="chartOptions.title!"
|
[title]="chartOptions.title!"
|
||||||
[legend]="chartOptions.legend!">
|
[legend]="chartOptions.legend!">
|
||||||
</apx-chart>
|
</apx-chart>
|
||||||
|
<div class="table-responsive m-t-15" *ngIf="dashboardModel!.details">
|
||||||
|
<table class="table align-items-center">
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let item of dashboardModel!.details!">
|
||||||
|
<td><i class="fa fa-circle col-cyan msr-2"></i> {{item.name}}</td>
|
||||||
|
<td [ngClass]="{ 'col-green': item.value != 0, 'col-red': item.value == 0}" style="text-align: right;">{{item.value | number: '1.2'}} ({{item.currency}})</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import { HttpClient } from '@angular/common/http';
|
|||||||
import { HttpParams } from '@angular/common/http';
|
import { HttpParams } from '@angular/common/http';
|
||||||
import { DecimalPipe } from '@angular/common';
|
import { DecimalPipe } from '@angular/common';
|
||||||
import { UntypedFormBuilder } from '@angular/forms';
|
import { UntypedFormBuilder } from '@angular/forms';
|
||||||
import { UntypedFormGroup } from '@angular/forms';
|
|
||||||
import { Validators } from '@angular/forms';
|
|
||||||
|
|
||||||
// libs
|
// libs
|
||||||
import {
|
import {
|
||||||
@@ -44,7 +42,6 @@ export class DashboardOutcomeComponent implements OnInit {
|
|||||||
@ViewChild("chart") chart!: ChartComponent;
|
@ViewChild("chart") chart!: ChartComponent;
|
||||||
public chartOptions!: Partial<ChartOptions>;
|
public chartOptions!: Partial<ChartOptions>;
|
||||||
dashboardModel?: DashboardInOutModel;
|
dashboardModel?: DashboardInOutModel;
|
||||||
public form!: UntypedFormGroup;
|
|
||||||
public dateFrom: Date = moment(new Date).add(-30, 'days').toDate();
|
public dateFrom: Date = moment(new Date).add(-30, 'days').toDate();
|
||||||
public dateTo: Date = moment(new Date).add(0, 'days').toDate();
|
public dateTo: Date = moment(new Date).add(0, 'days').toDate();
|
||||||
|
|
||||||
@@ -58,8 +55,6 @@ export class DashboardOutcomeComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.form = this.fb.group({
|
|
||||||
});
|
|
||||||
this.loadData();
|
this.loadData();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export class HeaderComponent extends UnsubscribeOnDestroyAdapter implements OnIn
|
|||||||
|
|
||||||
this.setUser();
|
this.setUser();
|
||||||
|
|
||||||
this.homePage = 'dashboard/dashboard';
|
this.homePage = 'dashboard/rests';
|
||||||
|
|
||||||
this.langStoreValue = localStorage.getItem('lang') as string;
|
this.langStoreValue = localStorage.getItem('lang') as string;
|
||||||
const val = this.listLang.filter((x) => x.lang === this.langStoreValue);
|
const val = this.listLang.filter((x) => x.lang === this.langStoreValue);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<ul class="nav navbar-nav flex-row">
|
<ul class="nav navbar-nav flex-row">
|
||||||
<li class="nav-item logo">
|
<li class="nav-item logo">
|
||||||
<a class="navbar-brand" routerLink="dashboard/dashboard">
|
<a class="navbar-brand" routerLink="dashboard/rests">
|
||||||
<img src="assets/images/logo.png" alt=""/>
|
<img src="assets/images/logo.png" alt=""/>
|
||||||
<span class="logo-name">ase.com.ua</span>
|
<span class="logo-name">ase.com.ua</span>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -26,10 +26,13 @@ export interface DashboardRestModel {
|
|||||||
|
|
||||||
export interface DashboardInOutModel {
|
export interface DashboardInOutModel {
|
||||||
data: DashboardInOutItemModel[];
|
data: DashboardInOutItemModel[];
|
||||||
|
details: DashboardInOutItemModel[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DashboardInOutItemModel {
|
export interface DashboardInOutItemModel {
|
||||||
id: string;
|
id: string;
|
||||||
|
currency: string;
|
||||||
name: string;
|
name: string;
|
||||||
value: number;
|
value: number;
|
||||||
|
valueRaw: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,9 @@
|
|||||||
<button class="btn-space" (click)="setRate(item)" mat-raised-button color="primary">
|
<button class="btn-space" (click)="setRate(item)" mat-raised-button color="primary">
|
||||||
Edit
|
Edit
|
||||||
</button>
|
</button>
|
||||||
|
<button class="btn-space" (click)="delete(item)" mat-raised-button color="warn">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { HttpClient } from '@angular/common/http';
|
|||||||
|
|
||||||
// libs
|
// libs
|
||||||
import { MatDialog } from '@angular/material/dialog';
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
|
import Swal from 'sweetalert2';
|
||||||
|
|
||||||
// app
|
// app
|
||||||
import { ApiRoutes } from '../../../api-routes';
|
import { ApiRoutes } from '../../../api-routes';
|
||||||
@@ -60,6 +61,33 @@ export class SettingsCurrencyComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete(currency: CurrencyModel) {
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Delete currency ' + currency.name,
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: 'Delete',
|
||||||
|
showLoaderOnConfirm: true,
|
||||||
|
preConfirm: (name) => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.httpClient.delete(ApiRoutes.SettingsCurrency.replace(':id', currency.id!))
|
||||||
|
.subscribe(data => {
|
||||||
|
resolve(data);
|
||||||
|
}, error => {
|
||||||
|
Swal.showValidationMessage(error.detail);
|
||||||
|
reject();
|
||||||
|
});
|
||||||
|
|
||||||
|
}).catch(x => {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
allowOutsideClick: () => !Swal.isLoading(),
|
||||||
|
}).then((result) => {
|
||||||
|
this.load();
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private load() {
|
private load() {
|
||||||
this.httpClient
|
this.httpClient
|
||||||
.get<CurrencyModel[]>(ApiRoutes.GeneralCurrencies)
|
.get<CurrencyModel[]>(ApiRoutes.GeneralCurrencies)
|
||||||
@@ -73,7 +101,9 @@ export class SettingsCurrencyComponent {
|
|||||||
this.httpClient
|
this.httpClient
|
||||||
.get<CurrencyModel[]>(ApiRoutes.SettingsCurrencies)
|
.get<CurrencyModel[]>(ApiRoutes.SettingsCurrencies)
|
||||||
.subscribe(data => {
|
.subscribe(data => {
|
||||||
this.myCurrencies = data.map(myCurrency => {
|
this.myCurrencies = data
|
||||||
|
.sort((a, b) => a.code!.localeCompare(b.code!))
|
||||||
|
.map(myCurrency => {
|
||||||
var globalCurrency = this.currencies?.find(x => x.id === myCurrency.code);
|
var globalCurrency = this.currencies?.find(x => x.id === myCurrency.code);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -163,4 +163,22 @@ public class CurrencyService
|
|||||||
|
|
||||||
return result.Set(_mapper.Map<CurrencyRateDto>(rate));
|
return result.Set(_mapper.Map<CurrencyRateDto>(rate));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Exec<CurrencyDto, GeneralExecStatus> Remove(Guid userId, Guid id)
|
||||||
|
{
|
||||||
|
var result = new Exec<CurrencyDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||||
|
|
||||||
|
var currency = _currencyRepository.Get(userId, id);
|
||||||
|
if (currency == null)
|
||||||
|
{
|
||||||
|
return result.Set(GeneralExecStatus.not_found);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_currencyRepository.Remove(currency))
|
||||||
|
{
|
||||||
|
return result.Set(GeneralExecStatus.failure);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.Set(_mapper.Map<CurrencyDto>(currency));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Core.Extensions;
|
|||||||
using Data.Repositories.Account;
|
using Data.Repositories.Account;
|
||||||
using Data.Repositories.Currency;
|
using Data.Repositories.Currency;
|
||||||
using MyOffice.Data.Models.Accounts;
|
using MyOffice.Data.Models.Accounts;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
public class DashboardService
|
public class DashboardService
|
||||||
{
|
{
|
||||||
@@ -70,13 +71,44 @@ public class DashboardService
|
|||||||
? _accountRepository.GetIncomeByCategory(userId, category.Value, from.ToUtc(), to.ToUtc())
|
? _accountRepository.GetIncomeByCategory(userId, category.Value, from.ToUtc(), to.ToUtc())
|
||||||
: _accountRepository.GetIncomeByCategories(userId, from.ToUtc(), to.ToUtc());
|
: _accountRepository.GetIncomeByCategories(userId, from.ToUtc(), to.ToUtc());
|
||||||
|
|
||||||
|
data = data
|
||||||
|
.Where(x => x.Amount != 0)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var currencies = data
|
||||||
|
.Where(x => x.Amount != 0)
|
||||||
|
.Select(x => x.CurrencyId)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var rates = _currencyRateRepository
|
||||||
|
.GetLastRates(userId, currencies, to.ToUtc())
|
||||||
|
.ToDictionary(x => x.Key, x => x.Value.Rate * x.Value.Quantity);
|
||||||
|
|
||||||
return new DashboardIncomeData
|
return new DashboardIncomeData
|
||||||
{
|
{
|
||||||
Data = data.Select(x => new DashboardIncomeDataItem
|
Data = data.Select(x => new
|
||||||
{
|
{
|
||||||
Id = x.Id?.ToShort(),
|
Id = x.Id.ToShort(),
|
||||||
Name = x.Name,
|
Name = x.Name,
|
||||||
Value = x.Amount,
|
Value = (x.Amount * rates.FirstOrDefault(r => r.Key == x.CurrencyId).Value),
|
||||||
|
})
|
||||||
|
.GroupBy(x => new { x.Id, x.Name })
|
||||||
|
.Select( x => new DashboardIncomeDataItem
|
||||||
|
{
|
||||||
|
Id = x.Key.Id,
|
||||||
|
Name = x.Key.Name,
|
||||||
|
Value = x.Sum(s => s.Value),
|
||||||
|
})
|
||||||
|
.ToList(),
|
||||||
|
|
||||||
|
Details = data.Select(x => new DashboardIncomeDataItem
|
||||||
|
{
|
||||||
|
Id = x.Id.ToShort(),
|
||||||
|
Currency = x.CurrencyId,
|
||||||
|
Name = x.Name,
|
||||||
|
ValueRaw = x.Amount,
|
||||||
|
Value = (x.Amount * rates.FirstOrDefault(r => r.Key == x.CurrencyId).Value),
|
||||||
}).ToList()
|
}).ToList()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -87,6 +119,12 @@ public class DashboardService
|
|||||||
? _accountRepository.GetOutcomeByCategory(userId, category.Value, from.ToUtc(), to.ToUtc())
|
? _accountRepository.GetOutcomeByCategory(userId, category.Value, from.ToUtc(), to.ToUtc())
|
||||||
: _accountRepository.GetOutcomeByCategories(userId, from.ToUtc(), to.ToUtc());
|
: _accountRepository.GetOutcomeByCategories(userId, from.ToUtc(), to.ToUtc());
|
||||||
|
|
||||||
|
var currencies = data
|
||||||
|
.Where(x => x.Amount != 0)
|
||||||
|
.Select(x => x.CurrencyId)
|
||||||
|
.Distinct()
|
||||||
|
.ToList();
|
||||||
|
|
||||||
return new DashboardIncomeData
|
return new DashboardIncomeData
|
||||||
{
|
{
|
||||||
Data = data.Select(x => new DashboardIncomeDataItem
|
Data = data.Select(x => new DashboardIncomeDataItem
|
||||||
|
|||||||
@@ -32,11 +32,14 @@ public class DashboardRestData
|
|||||||
public class DashboardIncomeData
|
public class DashboardIncomeData
|
||||||
{
|
{
|
||||||
public List<DashboardIncomeDataItem> Data { get; set; } = null!;
|
public List<DashboardIncomeDataItem> Data { get; set; } = null!;
|
||||||
|
public List<DashboardIncomeDataItem> Details { get; set; } = null!;
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DashboardIncomeDataItem
|
public class DashboardIncomeDataItem
|
||||||
{
|
{
|
||||||
public string? Id { get; set; } = null!;
|
public string? Id { get; set; }
|
||||||
|
public string Currency { get; set; } = null!;
|
||||||
public string Name { get; set; } = null!;
|
public string Name { get; set; } = null!;
|
||||||
public decimal Value { get; set; }
|
public decimal Value { get; set; }
|
||||||
|
public decimal ValueRaw { get; set; }
|
||||||
}
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
namespace MyOffice.Web.Controllers;
|
namespace MyOffice.Web.Controllers;
|
||||||
|
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
|
using Core;
|
||||||
using Core.Extensions;
|
using Core.Extensions;
|
||||||
using Data.Models.Currencies;
|
using Data.Models.Currencies;
|
||||||
|
using Infrastructure.Attributes;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Models.Currency;
|
using Models.Currency;
|
||||||
@@ -92,6 +94,25 @@ public class CurrencyController : BaseApiController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpDelete("~/api/settings/currencies/{id}")]
|
||||||
|
public ObjectResult Update([AsGuid] string id)
|
||||||
|
{
|
||||||
|
var exec = _currencyService.Remove(UserId, id.AsGuid());
|
||||||
|
|
||||||
|
switch (exec.Status)
|
||||||
|
{
|
||||||
|
case GeneralExecStatus.success:
|
||||||
|
return OkResponse(_mapper.Map<CurrencyViewModel>(exec.Result!));
|
||||||
|
|
||||||
|
case GeneralExecStatus.not_found:
|
||||||
|
case GeneralExecStatus.failure:
|
||||||
|
return ProblemBadResponse("Currency not found.");
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new NotSupportedException(exec.Status.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPost("~/api/settings/currencies/{id}/rate")]
|
[HttpPost("~/api/settings/currencies/{id}/rate")]
|
||||||
public ObjectResult Add(string id, CurrencyRateModel currencyRate)
|
public ObjectResult Add(string id, CurrencyRateModel currencyRate)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user