Compare commits

...

2 Commits

25 changed files with 1545 additions and 119 deletions

View File

@ -16,6 +16,10 @@ import { Routes } from "./components/services/Routes";
import Transactions from "./components/transactions/Transactions";
import CreateTransaction from "./components/transactions/CreateTransaction";
import DeleteTransaction from "./components/transactions/DeleteTransaction";
import AccountDashboard from "./components/accounts/AccountDashboard";
import CreateEnvelope from "./components/envelope/CreateEnvelope";
import Envelopes from "./components/envelope/Envelopes";
const AppRoutes = [
{
@ -51,15 +55,15 @@ const AppRoutes = [
element: <Users />
},
{
path: Routes.USER_CREATE,
path: Routes.USERS_CREATE,
element: <CreateUser />
},
{
path: Routes.USER_EDIT,
path: Routes.USERS_EDIT,
element: <UpdateUser />
},
{
path: Routes.USER_DELETE,
path: Routes.USERS_DELETE,
element: <DeleteUser />
},
{
@ -67,15 +71,19 @@ const AppRoutes = [
element: <Accounts />
},
{
path: Routes.ACCOUNT_CREATE,
path: Routes.ACCOUNTS_DASHBOARD,
element: <AccountDashboard />
},
{
path: Routes.ACCOUNTS_CREATE,
element: <CreateAccount />
},
{
path: Routes.ACCOUNT_EDIT,
path: Routes.ACCOUNTS_EDIT,
element: <UpdateAccount />
},
{
path: Routes.ACCOUNT_DELETE,
path: Routes.ACCOUNTS_DELETE,
element: <DeleteAccount />
},
{
@ -83,16 +91,32 @@ const AppRoutes = [
element: <Transactions />
},
{
path: Routes.TRANSACTION_CREATE,
path: Routes.TRANSACTIONS_CREATE,
element: <CreateTransaction />
},
{
path: Routes.TRANSACTION_EDIT,
path: Routes.TRANSACTIONS_EDIT,
element: <UpdateAccount />
},
{
path: Routes.TRANSACTION_DELETE,
element: <DeleteAccount />
path: Routes.TRANSACTIONS_DELETE,
element: <DeleteTransaction />
},
{
path: Routes.ENVELOPES,
element: <Envelopes />
},
{
path: Routes.ENVELOPES_CREATE,
element: <CreateEnvelope />
},
{
path: Routes.ENVELOPES_EDIT,
element: <UpdateAccount />
},
{
path: Routes.ENVELOPES_DELETE,
element: <DeleteTransaction />
},
];

View File

@ -53,12 +53,12 @@ export class NavMenu extends Component {
<NavItem>
<NavLink tag={Link} className="text-dark" to={Routes.ACCOUNTS}>Accounts</NavLink>
</NavItem>
<NavItem>
<NavLink tag={Link} className="text-dark" to={Routes.ENVELOPES}>Envelopes</NavLink>
</NavItem>
<NavItem>
<NavLink tag={Link} className="text-dark" to={Routes.TRANSACTIONS}>Transactions</NavLink>
</NavItem>
{/*<NavItem>
<NavLink tag={Link} className="text-dark" to={Routes.LOGIN}>{sessionStorage.getItem('firstName')}</NavLink>
</NavItem>*/}
<NavItem>
<NavLink tag={Link} className="text-dark" to={Routes.LOGOUT}>Logout</NavLink>
</NavItem>

View File

@ -0,0 +1,262 @@
import { EndPoints, getData } from "../services/AccessAPI";
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { useState } from 'react';
import { useLocation } from 'react-router-dom';
import { Routes } from "../services/Routes";
import RowButton from "../ui-elements/table/RowButton";
import DataFormatter, { RenderType } from "../ui-elements/table/DataFormatter";
export default function AccountDashboard() {
const search = useLocation().search;
const id = new URLSearchParams(search).get('id')
useEffect(() => {
getData(EndPoints.ACCOUNTS + "/" + id).then(
(result) => {
if (result) {
setAccount({
name: result.name,
lastActivity: result.lastActivity,
createdOn: result.createdOn,
balance: result.balance,
initialBalance: result.initialBalance,
currencyId: result.currencyId,
externalAccountNumber: result.externalAccountNumber,
loading: false
});
}
}
);
getAllTransactionsData();
getAllAccountsData();
getAccountEnvelopeData();
}, [id])
let navigate = useNavigate();
const [loading, setLoading] = useState(true);
const [transactions, setTransactions] = useState([]);
const [accounts, setAccounts] = useState([]);
const [envelopes, setEnvelopes] = useState([]);
const [account, setAccount] = useState({
name: '',
lastActivity: null,
createdOn: null,
balance: 0,
initialBalance: 0,
currencyId: 0,
externalAccountNumber: '',
loading: true
});
//const [users, setUsers] = useState(null);
function onTransactionEdit(id){
let query = "?id=" + id
navigate(Routes.TRANSACTIONS_EDIT + query);
}
function onTransactionDelete(id){
let query = "?id=" + id
navigate(Routes.TRANSACTIONS_DELETE + query);
}
function getAllTransactionsData() {
getData(EndPoints.TRANSACTIONS).then(
(result) => {
if (result) {
console.log()
setTransactions(result);
setLoading(false);
}
}
);
}
/*function getAllUsersData() {
getData(EndPoints.USERS).then(
(result) => {
if (result) {
setUsers(result);
}
}
);
}*/
function getAllAccountsData() {
getData(EndPoints.ACCOUNTS).then(
(result) => {
if (result) {
setAccounts(result);
setLoading(false);
}
}
);
}
function getAccountEnvelopeData() {
getData(EndPoints.ENVELOPES).then(
(result) => {
if (result) {
setEnvelopes(result);
setLoading(false);
}
}
);
}
function findAccountName(id) {
let name = accounts?.find(x => x.id === id)?.name;
console.log("Id: " + id + ", Name: " + name);
return name;
}
/*function findUserName(id) {
return users?.find(x => x.id)?.username;
}*/
function renderTransactionsTable() {
return (
<table className="table table-sm table-striped">
<thead>
<tr>
<th>Amount</th>
<th>Description</th>
<th>Date</th>
<th>External ID</th>
<th>Debit Acc</th>
<th>Credit Acc</th>
<th>Pending</th>
</tr>
</thead>
<tbody>
{
transactions.map(transaction => (
<tr key={transaction.id}>
<td><DataFormatter data={transaction.amount} renderType={RenderType.MoneyUnsigned}/></td>
<td><DataFormatter data={transaction.description} /></td>
<td><DataFormatter data={transaction.date} /></td>
<td><DataFormatter data={transaction.externalId} /></td>
<td><DataFormatter data={findAccountName(transaction.debitAccountId)} /></td>
<td><DataFormatter data={findAccountName(transaction.creditAccountId)} /></td>
<td><DataFormatter data={transaction.isPending ? "True" : "False"} /></td>
<td>
<RowButton className="btn btn-sm btn-outline-primary" text="Edit" onClick={() => onTransactionEdit(transaction.id)} />
<RowButton className="btn btn-sm btn-outline-danger" text="Delete" onClick={() => onTransactionDelete(transaction.id)} />
</td>
</tr>
))
}
</tbody>
</table>
);
}
function renderEnvelopesTable() {
return (
<table className="table table-sm table-striped">
<thead>
<tr>
<th>Name</th>
<th>Balance</th>
<th>Status</th>
<th>Persistant</th>
<th>Priority</th>
<th>Period</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{
envelopes.map(env => (
<tr key={env.id}>
<td><DataFormatter data={env.name} /></td>
<td><DataFormatter data={env.balance} renderType={RenderType.MoneyUnsigned}/></td>
<td><DataFormatter data={env.enabled ? "Enabled" : "Disabled"} /></td>
<td><DataFormatter data={env.isPersistant ? "True" : "False"} /></td>
<td><DataFormatter data={env.priority} /></td>
<td><DataFormatter data={env.period} /></td>
<td>
<RowButton
className="btn btn-sm btn-outline-primary"
text="Edit"
onClick={() => navigate(Routes.ENVELOPES_EDIT + "?id=" + env.id)} />
<RowButton
className="btn btn-sm btn-outline-danger"
text="Delete"
onClick={() => navigate(Routes.ENVELOPES_DELETE + "?id=" + env.id)} />
</td>
</tr>
))
}
</tbody>
</table>
);
}
let transactionsContent = loading ? (
<p>
<em>Loading...</em>
</p>
) : (renderTransactionsTable())
let envelopesContent = loading ? (
<p>
<em>Loading...</em>
</p>
) : (renderEnvelopesTable())
return (
<div>
<h2>{account.name + " "}
<RowButton
className="btn btn-sm btn-outline-primary"
text="Edit"
onClick={() => navigate(Routes.ACCOUNTS_EDIT + "?id=" + id)} />
<RowButton
className="btn btn-sm btn-outline-danger"
text="Delete"
onClick={() => navigate(Routes.ACCOUNTS_DELETE + "?id=" + id)} />
</h2>
<div className="container-fluid">
<div className="row">
<div className="col-md-6">
<h3><DataFormatter data={account.balance} renderType={RenderType.MoneyUnsigned} /></h3>
<h5><DataFormatter data={"Last activity: " + account.lastActivity} /></h5>
</div>
<div className="col-md-6">
<h4><DataFormatter data={account.externalAccountNumber} /></h4>
</div>
</div>
<hr />
<div className="row">
<div className="col-md-6">
<div className="row">
<div className="text-center">
<h3 className="">Envelopes <button onClick={() => navigate(Routes.ENVELOPES_CREATE + "?id=" + id)} className="btn btn-sm btn-outline-primary">+</button></h3>
</div>
</div>
{envelopesContent}
</div>
<div className="col-md-6">
<div className="row">
<div className="text-center">
<h3 className="">Transactions <button onClick={() => navigate(Routes.TRANSACTIONS_CREATE)} className="btn btn-sm btn-outline-primary">+</button></h3>
</div>
</div>
{transactionsContent}
</div>
</div>
</div>
</div>
);
}

View File

@ -1,5 +1,5 @@
import { EndPoints, getData, putData } from "../services/AccessAPI";
import { RouterProvider, useNavigate } from "react-router-dom";
import { EndPoints, getData } from "../services/AccessAPI";
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { useState } from 'react';
import { Routes } from "../services/Routes";
@ -22,17 +22,22 @@ export default function Accounts() {
const [users, setUsers] = useState(null);
function onAccountCreate() {
navigate(Routes.ACCOUNT_CREATE);
navigate(Routes.ACCOUNTS_CREATE);
}
function onAccountDashboard(id) {
let query = "?id=" + id
navigate(Routes.ACCOUNTS_DASHBOARD + query);
}
function onAccountEdit(id) {
let query = "?id=" + id
navigate(Routes.ACCOUNT_EDIT + query);
navigate(Routes.ACCOUNTS_EDIT + query);
}
function onAccountDelete(id) {
let query = "?id=" + id
navigate(Routes.ACCOUNT_DELETE + query);
navigate(Routes.ACCOUNTS_DELETE + query);
}
function getAllAccountsData() {
@ -91,7 +96,7 @@ export default function Accounts() {
{
accounts.map(account => (
<tr key={account.id}>
<td><DataFormatter data={account.name} /></td>
<td><button onClick={() => onAccountDashboard(account.id)}><DataFormatter data={account.name} /></button></td>
<td><DataFormatter data={findUserName(account.ownerId)} /></td>
<td><DataFormatter data={account.balance} renderType={RenderType.MoneyUnsigned} /></td>
<td><DataFormatter data={account.externalAccountNumber} /></td>

View File

@ -0,0 +1,147 @@
import SessionManager from "../auth/SessionManager";
import { EndPoints, postData, getData } from "../services/AccessAPI";
import { useLocation, useNavigate } from 'react-router-dom';
import { useState, useEffect } from 'react';
import { Routes } from "../services/Routes";
import Select from 'react-select'
export default function CreateEnvelope() {
const search = useLocation().search;
const id = new URLSearchParams(search).get('id')
const [showAccounts, setShowAccounts] = useState(true);
useEffect(() => {
getAllAccountsData();
if (id !== undefined && id !== null) {
setShowAccounts();
setAccount(Number(id));
}
}, [id])
let navigate = useNavigate();
const [accounts, setAccounts] = useState([]);
const [name, setName] = useState("");
const [account, setAccount] = useState(0);
const [initBalance, setInitBalance] = useState(0);
const [enabled, setEnabled] = useState(true);
const [isPersistant, setIsPersistant] = useState(true);
const [priority, setPriority] = useState(0);
const [extNum, setExtNum] = useState("");
const [loading, setLoading] = useState(true);
function onSubmit(e) {
e.preventDefault();
let accountObj = {
name: name,
account: account,
initialBalance: initBalance.toString(),
enabled: enabled,
isPersistant: isPersistant,
priority: Number(priority),
externalAccountNumber: extNum
}
postData(EndPoints.ENVELOPES, accountObj).then((result) => {
setLoading(false);
let responseJson = result;
if (responseJson) {
navigate(Routes.ENVELOPES);
}
});
}
function getAllAccountsData() {
getData(EndPoints.ACCOUNTS).then(
(result) => {
if (result) {
setAccounts(result.map(a => {
return {
value: a.id,
label: a.name
}
}));
setLoading(false);
}
}
);
}
function onClickBack(e){
e.preventDefault();
if(SessionManager.getToken()){
navigate(Routes.ENVELOPES);
}else{
navigate(Routes.LOGIN);
}
}
return (
<div className="row">
<div className="col-md-4">
<h3>Create new account</h3>
<form onSubmit={onSubmit}>
<div className="form-group">
<label className="control-label">Envelope Name: </label>
<input className="form-control" type="text" name="name" value={name} onChange={(e) => setName(e.target.value)}></input>
</div>
{showAccounts && <div className="form-group">
<label className="control-label">Account: </label>
<Select onChange={(e) => setAccount(e.value)} name="account" options={accounts} isSearchable="true" isLoading={loading} />
</div>}
<div className="form-group">
<label className="control-label">Initial Balance: </label>
<input className="form-control" type="text" name="initBalance" value={initBalance} onChange={(e) => setInitBalance(e.target.value)}></input>
</div>
<div className="form-group">
<label className="control-label">Priority: </label>
<input className="form-control" type="text" name="priority" value={priority} onChange={(e) => setPriority(e.target.value)}></input>
</div>
<div className="form-check">
<label>
<input
type="checkbox"
name="enabled"
checked={enabled}
onChange={(e) => setEnabled(!enabled)}
className="form-check-input"
/>
Enabled
</label>
</div>
<div className="form-check">
<label>
<input
type="checkbox"
name="isPersistant"
checked={isPersistant}
onChange={(e) => setIsPersistant(!isPersistant)}
className="form-check-input"
/>
Is Persistant
</label>
</div>
<div className="form-group">
<label className="control-label">External Account Number: </label>
<input className="form-control" type="text" name="extNum" value={extNum} onChange={(e) => setExtNum(e.target.value)}></input>
</div>
<div className="form-group">
<input type="submit" value="Create Envelope" className="btn btn-primary"></input> &nbsp; &nbsp;
<input type="button" value="Back" onClick={onClickBack} className="btn btn-primary"></input>
</div>
</form>
</div>
</div>
);
}

View File

@ -0,0 +1,111 @@
import { EndPoints, getData } from "../services/AccessAPI";
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { useState } from 'react';
import { Routes } from "../services/Routes";
import RowButton from "../ui-elements/table/RowButton";
import DataFormatter, { RenderType } from "../ui-elements/table/DataFormatter";
export default function Envelopes() {
useEffect(() => {;
getAllAccountsData();
getAllEnvelopesData();
setLoading(false);
}, [])
let navigate = useNavigate();
const [loading, setLoading] = useState(true);
const [envelopes, setEnvelopes] = useState([]);
const [accounts, setAccounts] = useState([]);
function getAllEnvelopesData() {
getData(EndPoints.ENVELOPES).then(
(result) => {
if (result) {
setEnvelopes(result);
}
}
);
}
function getAllAccountsData() {
getData(EndPoints.ACCOUNTS).then(
(result) => {
if (result) {
setAccounts(result);
}
}
);
}
function findAccountName(id) {
let name = accounts?.find(x => x.id === id)?.name;
console.log("Id: " + id + ", Name: " + name);
return name;
}
function renderAllEnvelopesTable() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-md-12">
<table className="table table-sm table-striped">
<thead>
<tr>
<th>Name</th>
<th>Account</th>
<th>Balance</th>
<th>Initial Balance</th>
<th>Status</th>
<th>Persistant</th>
<th>Priority</th>
<th>Period</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{
envelopes.map(env => (
<tr key={env.id}>
<td><DataFormatter data={env.name} /></td>
<td><DataFormatter data={findAccountName(env.accountId)} /></td>
<td><DataFormatter data={env.balance} renderType={RenderType.MoneyUnsigned}/></td>
<td><DataFormatter data={env.initialBalance} renderType={RenderType.MoneyUnsigned}/></td>
<td><DataFormatter data={env.enabled ? "Enabled" : "Disabled"} /></td>
<td><DataFormatter data={env.isPersistant ? "True" : "False"} /></td>
<td><DataFormatter data={env.priority} /></td>
<td><DataFormatter data={env.period} /></td>
<td>
<RowButton className="btn btn-sm btn-outline-primary" text="Edit" onClick={() => navigate(Routes.ENVELOPES_EDIT)} />
<RowButton className="btn btn-sm btn-outline-danger" text="Delete" onClick={() => navigate(Routes.ENVELOPES_DELETE)} />
</td>
</tr>
))
}
</tbody>
</table>
</div>
</div>
</div>
);
}
let content = loading ? (
<p>
<em>Loading...</em>
</p>
) : (
renderAllEnvelopesTable()
)
return (
<div>
<h3>List of Envelopes</h3>
<button onClick={() => navigate(Routes.ENVELOPES_CREATE)} className="btn btn-primary">Create new envelope</button>
{content}
</div>
);
}

View File

@ -9,6 +9,7 @@ export const EndPoints = {
ACCOUNTS_REFRESHBALANCE: "Accounts/RefreshBalance",
CURRENCYTYPES: "CurrencyTypes",
TRANSACTIONS: "Transactions",
ENVELOPES: "Envelopes",
}
export function getData(endPoint) {

View File

@ -6,15 +6,20 @@ export const Routes = {
LOGOUT: "/logout",
REGISTER: "/register",
USERS: "/admin/users",
USER_CREATE: "/admin/user/create",
USER_EDIT: "/admin/user/edit",
USER_DELETE: "/admin/user/delete",
USERS_CREATE: "/admin/users/create",
USERS_EDIT: "/admin/users/edit",
USERS_DELETE: "/admin/users/delete",
ACCOUNTS: "/admin/accounts",
ACCOUNT_CREATE: "/admin/account/create",
ACCOUNT_EDIT: "/admin/account/edit",
ACCOUNT_DELETE: "/admin/account/delete",
ACCOUNTS_DASHBOARD: "/admin/accounts/dashboard",
ACCOUNTS_CREATE: "/admin/accounts/create",
ACCOUNTS_EDIT: "/admin/accounts/edit",
ACCOUNTS_DELETE: "/admin/accounts/delete",
TRANSACTIONS: "/admin/transactions",
TRANSACTION_CREATE: "/admin/transaction/create",
TRANSACTION_EDIT: "/admin/transaction/edit",
TRANSACTION_DELETE: "/admin/transaction/delete",
TRANSACTIONS_CREATE: "/admin/transactions/create",
TRANSACTIONS_EDIT: "/admin/transactions/edit",
TRANSACTIONS_DELETE: "/admin/transactions/delete",
ENVELOPES: "/admin/envelopes",
ENVELOPES_CREATE: "/admin/envelopes/create",
ENVELOPES_EDIT: "/admin/envelopes/edit",
ENVELOPES_DELETE: "/admin/envelopes/delete",
};

View File

@ -90,18 +90,12 @@ export default function CreateTransaction() {
navigate(Routes.LOGIN);
}
}
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
]
/*
{
"date": "2023-12-23T21:44:31.930Z",
"isPending": true
}
*/
/*
{
"date": "2023-12-23T21:44:31.930Z",
"isPending": true
}
*/
return (
<div className="row">
<div className="col-md-4">

View File

@ -0,0 +1,139 @@
import { useNavigate } from "react-router-dom";
import { EndPoints, deleteData, getData } from "../services/AccessAPI";
import { useEffect } from "react";
import { useState } from 'react';
import { useLocation } from 'react-router-dom';
import { Routes } from "../services/Routes";
import DataFormatter, { RenderType } from "../ui-elements/table/DataFormatter";
export default function DeleteTransaction() {
const search = useLocation().search;
const id = new URLSearchParams(search).get('id')
useEffect(() => {
getData(EndPoints.TRANSACTIONS + "/" + id).then(
(result) => {
if (result) {
setState({
amount: result.amount,
description: result.description,
date: result.date,
externalId: result.externalId,
debitAccountId: result.debitAccountId,
creditAccountId: result.creditAccountId,
isPending: result.isPending,
loading: false
});
}
}
);
}, [id])
let navigate = useNavigate();
const [state, setState] = useState({
amount: 0,
description: '',
date: '',
externalId: '',
debitAccountId: 0,
creditAccountId: 0,
isPending: false,
loading: true
});
function onCancel() {
navigate(Routes.TRANSACTIONS);
}
function onConfirmation(e) {
e.preventDefault();
deleteData(EndPoints.TRANSACTIONS + "/" + id).then((result) => {
let responseJson = result;
if (responseJson) {
navigate(Routes.TRANSACTIONS);
}
}
);
}
return (
<div>
<h2>::Delete Transaction::</h2>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>Transaction Information</h4>
<dl className="row">
<dt className="col-sm-2">
Transaction Description:
</dt>
<dd className="col-sm-10">
{state.description}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Amount:
</dt>
<dd className="col-sm-10">
<DataFormatter data={state.amount} renderType={RenderType.MoneyUnsigned}/>
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Date:
</dt>
<dd className="col-sm-10">
{state.date}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Debit Account:
</dt>
<dd className="col-sm-10">
{state.debitAccountId}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Credit Account:
</dt>
<dd className="col-sm-10">
{state.creditAccountId}
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
Is Pending:
</dt>
<dd className="col-sm-10">
<DataFormatter data={state.isPending ? "True" : "False"} />
</dd>
</dl>
<dl className="row">
<dt className="col-sm-2">
External Transaction Number:
</dt>
<dd className="col-sm-10">
{state.externalId}
</dd>
</dl>
<form onSubmit={onConfirmation}>
<input type="hidden" asp-for="Id" />
<button type="submit" className="btn btn-danger">Delete</button> |
<button onClick={onCancel} className="btn btn-primary">Back to List</button>
</form>
</div>
</div>
)
}

View File

@ -1,5 +1,5 @@
import { EndPoints, getData } from "../services/AccessAPI";
import { useNavigate, useLocation } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import { useEffect } from "react";
import { useState } from 'react';
import { Routes } from "../services/Routes";
@ -21,17 +21,17 @@ export default function Transactions() {
const [accounts, setAccounts] = useState([]);
function onTransactionCreate() {
navigate(Routes.TRANSACTION_CREATE);
navigate(Routes.TRANSACTIONS_CREATE);
}
function onTransactionEdit(id){
let query = "?id=" + id
navigate(Routes.TRANSACTION_EDIT + query);
navigate(Routes.TRANSACTIONS_EDIT + query);
}
function onTransactionDelete(id){
let query = "?id=" + id
navigate(Routes.TRANSACTION_DELETE + query);
navigate(Routes.TRANSACTIONS_DELETE + query);
}
function getAllTransactionsData() {
@ -63,7 +63,7 @@ export default function Transactions() {
}
function findAccountName(id) {
let name = accounts?.find(x => x.id == id)?.name;
let name = accounts?.find(x => x.id === id)?.name;
console.log("Id: " + id + ", Name: " + name);
return name;
}

View File

@ -18,17 +18,17 @@ export default function Users() {
});
function onUserCreate() {
navigate(Routes.USER_CREATE);
navigate(Routes.USERS_CREATE);
}
function onUserEdit(id){
let query = "?id=" + id
navigate(Routes.USER_EDIT + query);
navigate(Routes.USERS_EDIT + query);
}
function onUserDelete(id){
let query = "?id=" + id
navigate(Routes.USER_DELETE + query);
navigate(Routes.USERS_DELETE + query);
}
function getAllUsersData() {
@ -45,7 +45,7 @@ export default function Users() {
);
}
function renderAllUsersTable(users) {
/*function renderAllUsersTable(users) {
return (
<table className="table table-striped">
<thead>
@ -73,7 +73,7 @@ export default function Users() {
</tbody>
</table>
);
}
}*/
function renderBootstrapTable(users) {
return (

View File

@ -0,0 +1,77 @@
namespace active_allocator.Controllers;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using active_allocator.Models.Envelopes;
using active_allocator.Services;
using active_allocator.Authorization;
using active_allocator.Helpers;
using System.Collections.Generic;
using active_allocator.Entities;
[Authorize]
[ApiController]
[Route("[controller]")]
public class EnvelopesController : ControllerBase
{
private IEnvelopeService _envelopeService;
private IMapper _mapper;
private readonly AppSettings _appSettings;
public EnvelopesController(
IEnvelopeService envelopeService,
IMapper mapper,
IOptions<AppSettings> appSettings)
{
_envelopeService = envelopeService;
_mapper = mapper;
_appSettings = appSettings.Value;
}
[HttpGet]
public IActionResult GetAll(int? accountId = null)
{
List<EnvelopeDTO> envelopeDtos = new List<EnvelopeDTO>();
foreach (Envelope env in _envelopeService.GetAll(accountId))
envelopeDtos.Add(_mapper.Map<Envelope, EnvelopeDTO>(env));
return Ok(envelopeDtos);
}
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
Envelope envelope = _envelopeService.GetById(id);
return Ok(_mapper.Map<Envelope, EnvelopeDTO>(envelope));
}
[HttpPost]
public IActionResult Create([FromBody]EnvelopeCreateRequest model)
{
_envelopeService.Create(model);
return Ok(new { message = "envelope created" });
}
/*[HttpPut("{id}")]
public IActionResult Update(int id, [FromBody]EnvelopeUpdateRequest model)
{
_envelopeService.Update(id, model);
return Ok(new { message = "envelope updated" });
}*/
[HttpDelete("{id}")]
public IActionResult Delete(int id)
{
_envelopeService.Delete(id);
return Ok(new { message = "envelope deleted" });
}
/*[HttpGet("RefreshBalance/{id}")]
public IActionResult RefreshBalance(int id)
{
Envelope envelope = _envelopeService.RefreshEnvelopeBalance(id);
return Ok(_mapper.Map<Envelope, EnvelopeDTO>(envelope));
}*/
}

View File

@ -15,7 +15,7 @@ public class Account
public int CurrencyId { get; set; }
public CurrencyType Currency { get; set; }
public string ExternalAccountNumber { get; set; }
public ICollection<Alloc> Allocs { get; set; }
public ICollection<Envelope> Envelopes { get; set; }
//public ICollection<Transaction> Transactions { get; set; }
//public Institution institution { get; set; }
}

View File

@ -3,16 +3,16 @@ using System.Text.Json.Serialization;
namespace active_allocator.Entities;
public class Alloc
public class Envelope
{
public int Id { get; set; }
public string Name { get; set; }
public Account Account { get; set; }
public bool Enabled { get; set; }
public TimeSpan Period { get; set; }
public Account Account { get; set; }
public bool PersistanceEnabled { get; set; }
public ICollection<Operation> Operations { get; set; }
public decimal CurrentBalance { get; set; }
public DateTime LastTriggeredOn { get; set; }
public decimal LastBalanceAdded { get; set; }
public bool IsPersistant { get; set; }
public int Priority { get; set; }
public decimal Balance { get; set; }
public decimal InitialBalance { get; set; }
public DateTime? LastTriggeredOn { get; set; }
}

View File

@ -4,6 +4,7 @@ using AutoMapper;
using active_allocator.Entities;
using active_allocator.Models.Users;
using active_allocator.Models.Accounts;
using active_allocator.Models.Envelopes;
using active_allocator.Models.CurrencyType;
using active_allocator.Services;
using System.Runtime.Serialization;
@ -76,6 +77,19 @@ public class AutoMapperProfile : Profile
}
));
// Envelope -> EnvelopeDTO
CreateMap<Envelope, EnvelopeDTO>()
.ForAllMembers(x => x.Condition(
(src, dest, prop) =>
{
// ignore both null & empty string properties
if (prop == null) return false;
if (prop.GetType() == typeof(string) && string.IsNullOrEmpty((string)prop)) return false;
return true;
}
));
// Transaction -> TransactionDto
CreateMap<Transaction, TransactionDto>()
.ForMember(dest => dest.DebitAccountId, opt => opt.MapFrom(src => src.DebitAccount.Id))

View File

@ -60,7 +60,7 @@ public class DataContext : DbContext
public DbSet<User> Users { get; set; }
public DbSet<Account> Accounts { get; set; }
public DbSet<Alloc> Allocs { get; set; }
public DbSet<Envelope> Envelopes { get; set; }
public DbSet<CurrencyType> CurrencyTypes { get; set; }
public DbSet<Operation> Operations { get; set; }
public DbSet<Transaction> Transactions { get; set; }

View File

@ -0,0 +1,351 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
using active_allocator.Helpers;
#nullable disable
namespace active_allocator.Migrations
{
[DbContext(typeof(DataContext))]
[Migration("20231226233044_EnvelopeEntity")]
partial class EnvelopeEntity
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.9")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("active_allocator.Entities.Account", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<decimal>("Balance")
.HasColumnType("numeric");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<int>("CurrencyId")
.HasColumnType("integer");
b.Property<string>("ExternalAccountNumber")
.IsRequired()
.HasColumnType("text");
b.Property<decimal>("InitialBalance")
.HasColumnType("numeric");
b.Property<DateTime>("LastActivity")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<int>("OwnerId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("CurrencyId");
b.HasIndex("OwnerId");
b.ToTable("Accounts");
});
modelBuilder.Entity("active_allocator.Entities.CurrencyType", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Code")
.IsRequired()
.HasColumnType("text");
b.Property<int>("DecimalPlaces")
.HasColumnType("integer");
b.Property<string>("Symbol")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("CurrencyTypes");
});
modelBuilder.Entity("active_allocator.Entities.Envelope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("AccountId")
.HasColumnType("integer");
b.Property<decimal>("Balance")
.HasColumnType("numeric");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<decimal>("InitialBalance")
.HasColumnType("numeric");
b.Property<bool>("IsPersistant")
.HasColumnType("boolean");
b.Property<DateTime?>("LastTriggeredOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<TimeSpan>("Period")
.HasColumnType("interval");
b.Property<int>("Priority")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("AccountId");
b.ToTable("Envelopes");
});
modelBuilder.Entity("active_allocator.Entities.Operation", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<decimal>("AbsoluteValue")
.HasColumnType("numeric");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<int>("HistoricLookbackDepth")
.HasColumnType("integer");
b.Property<TimeSpan>("HistoricPeriod")
.HasColumnType("interval");
b.Property<int>("HistoricStatistic")
.HasColumnType("integer");
b.Property<int>("Mode")
.HasColumnType("integer");
b.Property<bool>("Negative")
.HasColumnType("boolean");
b.Property<int>("Order")
.HasColumnType("integer");
b.Property<decimal>("Percentage")
.HasColumnType("numeric");
b.HasKey("Id");
b.ToTable("Operations");
});
modelBuilder.Entity("active_allocator.Entities.Transaction", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<decimal>("Amount")
.HasColumnType("numeric");
b.Property<DateTime>("CreatedOn")
.HasColumnType("timestamp with time zone");
b.Property<int>("CreditAccountId")
.HasColumnType("integer");
b.Property<int>("CurrencyTypeId")
.HasColumnType("integer");
b.Property<DateTime>("Date")
.HasColumnType("timestamp with time zone");
b.Property<int>("DebitAccountId")
.HasColumnType("integer");
b.Property<string>("Description")
.IsRequired()
.HasColumnType("text");
b.Property<string>("ExternalId")
.IsRequired()
.HasColumnType("text");
b.Property<bool>("IsPending")
.HasColumnType("boolean");
b.Property<string>("Notes")
.IsRequired()
.HasColumnType("text");
b.Property<int>("OwnerId")
.HasColumnType("integer");
b.Property<DateTime>("UpdatedOn")
.HasColumnType("timestamp with time zone");
b.HasKey("Id");
b.HasIndex("CreditAccountId");
b.HasIndex("CurrencyTypeId");
b.HasIndex("DebitAccountId");
b.HasIndex("OwnerId");
b.ToTable("Transactions");
});
modelBuilder.Entity("active_allocator.Entities.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("Email")
.IsRequired()
.HasColumnType("text");
b.Property<string>("FirstName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("LastName")
.IsRequired()
.HasColumnType("text");
b.Property<string>("PasswordHash")
.IsRequired()
.HasColumnType("text");
b.Property<int>("Role")
.HasColumnType("integer");
b.Property<string>("Username")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("Users");
});
modelBuilder.Entity("active_allocator.Entities.Account", b =>
{
b.HasOne("active_allocator.Entities.CurrencyType", "Currency")
.WithMany()
.HasForeignKey("CurrencyId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("active_allocator.Entities.User", "Owner")
.WithMany("Accounts")
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Currency");
b.Navigation("Owner");
});
modelBuilder.Entity("active_allocator.Entities.Envelope", b =>
{
b.HasOne("active_allocator.Entities.Account", "Account")
.WithMany("Envelopes")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Account");
});
modelBuilder.Entity("active_allocator.Entities.Transaction", b =>
{
b.HasOne("active_allocator.Entities.Account", "CreditAccount")
.WithMany()
.HasForeignKey("CreditAccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("active_allocator.Entities.CurrencyType", "CurrencyType")
.WithMany()
.HasForeignKey("CurrencyTypeId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("active_allocator.Entities.Account", "DebitAccount")
.WithMany()
.HasForeignKey("DebitAccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("active_allocator.Entities.User", "Owner")
.WithMany()
.HasForeignKey("OwnerId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("CreditAccount");
b.Navigation("CurrencyType");
b.Navigation("DebitAccount");
b.Navigation("Owner");
});
modelBuilder.Entity("active_allocator.Entities.Account", b =>
{
b.Navigation("Envelopes");
});
modelBuilder.Entity("active_allocator.Entities.User", b =>
{
b.Navigation("Accounts");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,119 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace active_allocator.Migrations
{
/// <inheritdoc />
public partial class EnvelopeEntity : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_Operations_Allocs_AllocId",
table: "Operations");
migrationBuilder.DropTable(
name: "Allocs");
migrationBuilder.DropIndex(
name: "IX_Operations_AllocId",
table: "Operations");
migrationBuilder.DropColumn(
name: "AllocId",
table: "Operations");
migrationBuilder.CreateTable(
name: "Envelopes",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
Name = table.Column<string>(type: "text", nullable: false),
AccountId = table.Column<int>(type: "integer", nullable: false),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
Period = table.Column<TimeSpan>(type: "interval", nullable: false),
IsPersistant = table.Column<bool>(type: "boolean", nullable: false),
Priority = table.Column<int>(type: "integer", nullable: false),
Balance = table.Column<decimal>(type: "numeric", nullable: false),
InitialBalance = table.Column<decimal>(type: "numeric", nullable: false),
LastTriggeredOn = table.Column<DateTime>(type: "timestamp with time zone", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Envelopes", x => x.Id);
table.ForeignKey(
name: "FK_Envelopes_Accounts_AccountId",
column: x => x.AccountId,
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Envelopes_AccountId",
table: "Envelopes",
column: "AccountId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Envelopes");
migrationBuilder.AddColumn<int>(
name: "AllocId",
table: "Operations",
type: "integer",
nullable: true);
migrationBuilder.CreateTable(
name: "Allocs",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
AccountId = table.Column<int>(type: "integer", nullable: false),
CurrentBalance = table.Column<decimal>(type: "numeric", nullable: false),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
LastBalanceAdded = table.Column<decimal>(type: "numeric", nullable: false),
LastTriggeredOn = table.Column<DateTime>(type: "timestamp with time zone", nullable: false),
Name = table.Column<string>(type: "text", nullable: false),
Period = table.Column<TimeSpan>(type: "interval", nullable: false),
PersistanceEnabled = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Allocs", x => x.Id);
table.ForeignKey(
name: "FK_Allocs_Accounts_AccountId",
column: x => x.AccountId,
principalTable: "Accounts",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Operations_AllocId",
table: "Operations",
column: "AllocId");
migrationBuilder.CreateIndex(
name: "IX_Allocs_AccountId",
table: "Allocs",
column: "AccountId");
migrationBuilder.AddForeignKey(
name: "FK_Operations_Allocs_AllocId",
table: "Operations",
column: "AllocId",
principalTable: "Allocs",
principalColumn: "Id");
}
}
}

View File

@ -65,46 +65,6 @@ namespace active_allocator.Migrations
b.ToTable("Accounts");
});
modelBuilder.Entity("active_allocator.Entities.Alloc", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("AccountId")
.HasColumnType("integer");
b.Property<decimal>("CurrentBalance")
.HasColumnType("numeric");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<decimal>("LastBalanceAdded")
.HasColumnType("numeric");
b.Property<DateTime>("LastTriggeredOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<TimeSpan>("Period")
.HasColumnType("interval");
b.Property<bool>("PersistanceEnabled")
.HasColumnType("boolean");
b.HasKey("Id");
b.HasIndex("AccountId");
b.ToTable("Allocs");
});
modelBuilder.Entity("active_allocator.Entities.CurrencyType", b =>
{
b.Property<int>("Id")
@ -129,6 +89,49 @@ namespace active_allocator.Migrations
b.ToTable("CurrencyTypes");
});
modelBuilder.Entity("active_allocator.Entities.Envelope", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("AccountId")
.HasColumnType("integer");
b.Property<decimal>("Balance")
.HasColumnType("numeric");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
b.Property<decimal>("InitialBalance")
.HasColumnType("numeric");
b.Property<bool>("IsPersistant")
.HasColumnType("boolean");
b.Property<DateTime?>("LastTriggeredOn")
.HasColumnType("timestamp with time zone");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.Property<TimeSpan>("Period")
.HasColumnType("interval");
b.Property<int>("Priority")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("AccountId");
b.ToTable("Envelopes");
});
modelBuilder.Entity("active_allocator.Entities.Operation", b =>
{
b.Property<int>("Id")
@ -140,9 +143,6 @@ namespace active_allocator.Migrations
b.Property<decimal>("AbsoluteValue")
.HasColumnType("numeric");
b.Property<int?>("AllocId")
.HasColumnType("integer");
b.Property<bool>("Enabled")
.HasColumnType("boolean");
@ -169,8 +169,6 @@ namespace active_allocator.Migrations
b.HasKey("Id");
b.HasIndex("AllocId");
b.ToTable("Operations");
});
@ -289,10 +287,10 @@ namespace active_allocator.Migrations
b.Navigation("Owner");
});
modelBuilder.Entity("active_allocator.Entities.Alloc", b =>
modelBuilder.Entity("active_allocator.Entities.Envelope", b =>
{
b.HasOne("active_allocator.Entities.Account", "Account")
.WithMany("Allocs")
.WithMany("Envelopes")
.HasForeignKey("AccountId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
@ -300,13 +298,6 @@ namespace active_allocator.Migrations
b.Navigation("Account");
});
modelBuilder.Entity("active_allocator.Entities.Operation", b =>
{
b.HasOne("active_allocator.Entities.Alloc", null)
.WithMany("Operations")
.HasForeignKey("AllocId");
});
modelBuilder.Entity("active_allocator.Entities.Transaction", b =>
{
b.HasOne("active_allocator.Entities.Account", "CreditAccount")
@ -344,12 +335,7 @@ namespace active_allocator.Migrations
modelBuilder.Entity("active_allocator.Entities.Account", b =>
{
b.Navigation("Allocs");
});
modelBuilder.Entity("active_allocator.Entities.Alloc", b =>
{
b.Navigation("Operations");
b.Navigation("Envelopes");
});
modelBuilder.Entity("active_allocator.Entities.User", b =>

View File

@ -1,4 +1,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using active_allocator.Entities;
namespace active_allocator.Models.Accounts;
@ -13,4 +16,5 @@ public class AccountDTO
public decimal InitialBalance { get; set; }
public int CurrencyId { get; set; }
public string ExternalAccountNumber { get; set; }
public List<Envelope> Envelopes { get; set; }
}

View File

@ -0,0 +1,16 @@
namespace active_allocator.Models.Envelopes;
using System.ComponentModel.DataAnnotations;
using System.Runtime.InteropServices;
using active_allocator.Entities;
public class EnvelopeCreateRequest
{
public string Name { get; set; }
public int Account { get; set; }
public string InitialBalance { get; set; }
public bool Enabled { get; set; }
public bool IsPersistant { get; set; }
public int Priority { get; set; }
public string ExternalAccountNumber { get; set; }
}

View File

@ -0,0 +1,20 @@
using System.Collections;
using System.Collections.Generic;
using System.Text.Json.Serialization;
using active_allocator.Entities;
namespace active_allocator.Models.Envelopes;
public class EnvelopeDTO
{
public int Id { get; set; }
public string Name { get; set; }
public int AccountId { get; set; }
public bool Enabled { get; set; }
public TimeSpan Period { get; set; }
public bool IsPersistant { get; set; }
public int Priority { get; set; }
public decimal Balance { get; set; }
public decimal InitialBalance { get; set; }
public DateTime? LastTriggeredOn { get; set; }
}

View File

@ -52,6 +52,7 @@ internal class Program
builder.Services.AddScoped<IAccountService, AccountService>();
builder.Services.AddScoped<ICurrencyTypeService, CurrencyTypeService>();
builder.Services.AddScoped<ITransactionService, TransactionService>();
builder.Services.AddScoped<IEnvelopeService, EnvelopeService>();
var app = builder.Build();

View File

@ -0,0 +1,150 @@
namespace active_allocator.Services;
using AutoMapper;
using BCrypt.Net;
using active_allocator.Entities;
using active_allocator.Helpers;
using active_allocator.Models.Envelopes;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System;
using Internal;
using Microsoft.EntityFrameworkCore;
public interface IEnvelopeService
{
IEnumerable<Envelope> GetAll(int? accountId = null);
Envelope GetById(int envelopeId);
void Create(EnvelopeCreateRequest model);
//void Update(int envelopeId, EnvelopeUpdateRequest model);
//Envelope RefreshEnvelopeBalance(int envelopeId);
void Delete(int envelopeId);
}
public class EnvelopeService : IEnvelopeService
{
private DataContext _context;
private readonly IMapper _mapper;
public EnvelopeService(
DataContext context,
IMapper mapper)
{
_context = context;
_mapper = mapper;
}
public IEnumerable<Envelope> GetAll(int? accountId = null)
{
if (accountId != null)
return _context.Envelopes
.Include(e => e.Account)
.Where(e => e.Account.Id == accountId.Value);
return _context.Envelopes
.Include(e => e.Account);
}
public Envelope GetById(int envelopeId)
{
return getEnvelope(envelopeId);
}
public void Create(EnvelopeCreateRequest model)
{
Account account = _context.Accounts.Find(model.Account);
if (account == null)
throw new AppException("Could not create envelope. Account with id '" + model.Account + "' not found.");
// Check that envelope with same name or same external number doesn't exist
IEnumerable<Envelope> envelopesWithSameName = _context.Envelopes
.Include(e => e.Account)
.Where(e =>
e.Name.ToUpper() == model.Name.ToUpper()
&& e.Account.Id == model.Account);
if (envelopesWithSameName.Count() > 0)
throw new AppException("Envelope with name '" + model.Name + "' already exists for account '" + account.Name + "'.");
// map model to new envelope object
//var envelope = _mapper.Map<Envelope>(model);
Envelope envelope = new Envelope {
Name = model.Name,
Account = account,
InitialBalance = Convert.ToDecimal(model.InitialBalance),
Balance = Convert.ToDecimal(model.InitialBalance),
Enabled = model.Enabled,
IsPersistant = model.IsPersistant,
Priority = model.Priority,
LastTriggeredOn = null
};
_context.Envelopes.Add(envelope);
_context.SaveChanges();
}
/*
public void Update(int envelopeId, EnvelopeUpdateRequest model)
{
Envelope envelope = getEnvelope(envelopeId);
// validate
if (model.Name != envelope.Name && _context.Envelopes.Any(x => x.Name == model.Name))
throw new AppException("Envelope with the name '" + model.Name + "' already exists");
// Name
if (!string.IsNullOrWhiteSpace(model.Name))
envelope.Name = model.Name;
// Owner
if (model.Owner.HasValue)
{
envelope.OwnerId = model.Owner.Value;
envelope.Owner = _userService.GetById(model.Owner.Value);
}
// Initial Balance
if (!string.IsNullOrWhiteSpace(model.InitialBalance))
envelope.InitialBalance = Convert.ToDecimal(model.InitialBalance);
// CurrencyType
if (model.Currency.HasValue)
{
envelope.CurrencyId = model.Currency.Value;
envelope.Currency = _context.CurrencyTypes.Find(model.Currency.Value);
}
// External Envelope Number
if (!string.IsNullOrWhiteSpace(model.ExternalEnvelopeNumber))
envelope.ExternalEnvelopeNumber = model.ExternalEnvelopeNumber;
// copy model to envelope and save
//_mapper.Map(model, envelope);
_context.Envelopes.Update(envelope);
_context.SaveChanges();
_context.RecalculateEnvelopeBalance(envelopeId);
}*/
/*
public Envelope RefreshEnvelopeBalance(int envelopeId)
{
_context.RecalculateEnvelopeBalance(envelopeId);
return _context.Envelopes.Find(envelopeId);
}*/
public void Delete(int envelopeId)
{
var envelope = getEnvelope(envelopeId);
_context.Envelopes.Remove(envelope);
_context.SaveChanges();
}
// helper methods
private Envelope getEnvelope(int id)
{
var envelope = _context.Envelopes.Find(id);
if (envelope == null) throw new KeyNotFoundException("Envelope not found");
return envelope;
}
}