Skip to content

Commit

Permalink
Simple transaction overview
Browse files Browse the repository at this point in the history
  • Loading branch information
oxisto committed Dec 14, 2023
1 parent 73b49f9 commit 1cf5e2a
Show file tree
Hide file tree
Showing 17 changed files with 1,070 additions and 573 deletions.
1,024 changes: 548 additions & 476 deletions gen/mgo.pb.go

Large diffs are not rendered by default.

141 changes: 116 additions & 25 deletions gen/portfoliov1connect/mgo.connect.go

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion mgo.proto
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ message GetPortfolioSnapshotRequest {

message CreatePortfolioTransactionRequest { PortfolioEvent transaction = 1; }

message GetPortfolioTransactionRequest { string name = 1; }

message ListPortfolioTransactionsRequest { string portfolio_name = 1; }

message ListPortfolioTransactionsResponse {
Expand Down Expand Up @@ -161,8 +163,14 @@ service PortfolioService {

rpc CreatePortfolioTransaction(CreatePortfolioTransactionRequest)
returns (PortfolioEvent);
rpc GetPortfolioTransaction(GetPortfolioTransactionRequest)
returns (PortfolioEvent) {
option idempotency_level = NO_SIDE_EFFECTS;
};
rpc ListPortfolioTransactions(ListPortfolioTransactionsRequest)
returns (ListPortfolioTransactionsResponse);
returns (ListPortfolioTransactionsResponse) {
option idempotency_level = NO_SIDE_EFFECTS;
};
rpc UpdatePortfolioTransaction(UpdatePortfolioTransactionRequest)
returns (PortfolioEvent);
rpc DeletePortfolioTransaction(DeletePortfolioTransactionRequest)
Expand Down
12 changes: 11 additions & 1 deletion service/portfolio/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@ func (svc *service) CreatePortfolioTransaction(ctx context.Context, req *connect
)
}

func (svc *service) GetPortfolioTransaction(ctx context.Context, req *connect.Request[portfoliov1.GetPortfolioTransactionRequest]) (res *connect.Response[portfoliov1.PortfolioEvent], err error) {
return crud.Get(
req.Msg.Name,
svc.events,
func(obj *portfoliov1.PortfolioEvent) *portfoliov1.PortfolioEvent {
return obj
},

Check warning on line 55 in service/portfolio/transactions.go

View check run for this annotation

Codecov / codecov/patch

service/portfolio/transactions.go#L49-L55

Added lines #L49 - L55 were not covered by tests
)
}

func (svc *service) ListPortfolioTransactions(ctx context.Context, req *connect.Request[portfoliov1.ListPortfolioTransactionsRequest]) (res *connect.Response[portfoliov1.ListPortfolioTransactionsResponse], err error) {
return crud.List(
svc.events,
Expand All @@ -59,7 +69,7 @@ func (svc *service) ListPortfolioTransactions(ctx context.Context, req *connect.
)
}

func (svc *service) UpdatePortfolioTransactions(ctx context.Context, req *connect.Request[portfoliov1.UpdatePortfolioTransactionRequest]) (res *connect.Response[portfoliov1.PortfolioEvent], err error) {
func (svc *service) UpdatePortfolioTransaction(ctx context.Context, req *connect.Request[portfoliov1.UpdatePortfolioTransactionRequest]) (res *connect.Response[portfoliov1.PortfolioEvent], err error) {
return crud.Update(
req.Msg.Transaction.Name,
req.Msg.Transaction,
Expand Down
4 changes: 2 additions & 2 deletions service/portfolio/transactions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func Test_service_ListPortfolioTransactions(t *testing.T) {
}
}

func Test_service_UpdatePortfolioTransactions(t *testing.T) {
func Test_service_UpdatePortfolioTransaction(t *testing.T) {
type fields struct {
portfolios persistence.StorageOperations[*portfoliov1.Portfolio]
securities portfoliov1connect.SecuritiesServiceClient
Expand Down Expand Up @@ -177,7 +177,7 @@ func Test_service_UpdatePortfolioTransactions(t *testing.T) {
events: persistence.Relationship[*portfoliov1.PortfolioEvent](tt.fields.portfolios),
securities: tt.fields.securities,
}
gotRes, err := svc.UpdatePortfolioTransactions(tt.args.ctx, tt.args.req)
gotRes, err := svc.UpdatePortfolioTransaction(tt.args.ctx, tt.args.req)
if (err != nil) != tt.wantErr {
t.Errorf("service.UpdatePortfolioTransactions() error = %v, wantErr %v", err, tt.wantErr)
return
Expand Down
105 changes: 54 additions & 51 deletions ui/src/lib/components/PortfolioPositionsTable.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@
<TableSorter
active={sortBy == 'displayName'}
column="displayName"
on:change-direction={toggleSortDirection}
on:change-sort-by={(column) => changeSortBy('displayName')}
on:changeDirection={toggleSortDirection}
on:changeSortBy={(column) => changeSortBy('displayName')}
>
Name
</TableSorter>
Expand All @@ -77,8 +77,8 @@
<TableSorter
active={sortBy == 'amount'}
column="amount"
on:change-direction={toggleSortDirection}
on:change-sort-by={(column) => changeSortBy('amount')}>Amount</TableSorter
on:changeDirection={toggleSortDirection}
on:changeSortBy={(column) => changeSortBy('amount')}>Amount</TableSorter
>
</th>
<th
Expand All @@ -88,8 +88,8 @@
<TableSorter
active={sortBy == 'purchaseValue'}
column="purchaseValue"
on:change-direction={toggleSortDirection}
on:change-sort-by={(column) => changeSortBy('purchaseValue')}
on:changeDirection={toggleSortDirection}
on:changeSortBy={(column) => changeSortBy('purchaseValue')}
>Purchase Value
</TableSorter>
</th>
Expand All @@ -100,16 +100,16 @@
<TableSorter
active={sortBy == 'marketValue'}
column="marketValue"
on:change-direction={toggleSortDirection}
on:change-sort-by={(column) => changeSortBy('marketValue')}>Market Value</TableSorter
on:changeDirection={toggleSortDirection}
on:changeSortBy={(column) => changeSortBy('marketValue')}>Market Value</TableSorter
>
</th>
<th scope="col" class="px-3 py-3.5 text-right text-sm font-semibold text-gray-900">
<TableSorter
active={sortBy == 'profit'}
column="profit"
on:change-direction={toggleSortDirection}
on:change-sort-by={(column) => changeSortBy('profit')}>Profit/Loss</TableSorter
on:changeDirection={toggleSortDirection}
on:changeSortBy={(column) => changeSortBy('profit')}>Profit/Loss</TableSorter
>
</th>
</tr>
Expand All @@ -120,47 +120,50 @@
{/each}
</tbody>
<tfoot>
<th scope="col" class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-0"
>Total</th
>
<th
scope="col"
class="hidden px-3 py-3.5 text-right text-sm font-semibold text-gray-900 md:table-cell"
></th>
<th
scope="col"
class="hidden px-3 py-3.5 text-right text-sm font-semibold text-gray-900 lg:table-cell"
>
{currency(snapshot.totalPurchaseValue, 'EUR')}
</th>
<th
scope="col"
class="hidden px-3 py-3.5 text-right text-sm font-semibold text-gray-900 sm:table-cell"
>
{currency(snapshot.totalMarketValue, 'EUR')}
</th>
<th
scope="col"
class="{perf < 0
? 'text-red-500'
: perf <= 1
? 'text-gray-500'
: 'text-green-500'} px-3 py-3.5 text-right text-sm font-semibold"
>
<div>
{Intl.NumberFormat(navigator.language, {
maximumFractionDigits: 2
}).format(perf)} %
<Icon
src={perf < 0 ? ArrowDown : perf < 1 ? ArrowRight : ArrowUp}
class="float-right mt-0.5 h-4 w-4"
aria-hidden="true"
/>
</div>
<div class="pr-4">
{currency(snapshot.totalMarketValue - snapshot.totalPurchaseValue, 'EUR')}
</div>
</th>
<tr>
<th
scope="col"
class="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-0">Total</th
>
<th
scope="col"
class="hidden px-3 py-3.5 text-right text-sm font-semibold text-gray-900 md:table-cell"
></th>
<th
scope="col"
class="hidden px-3 py-3.5 text-right text-sm font-semibold text-gray-900 lg:table-cell"
>
{currency(snapshot.totalPurchaseValue, 'EUR')}
</th>
<th
scope="col"
class="hidden px-3 py-3.5 text-right text-sm font-semibold text-gray-900 sm:table-cell"
>
{currency(snapshot.totalMarketValue, 'EUR')}
</th>
<th
scope="col"
class="{perf < 0
? 'text-red-500'
: perf <= 1
? 'text-gray-500'
: 'text-green-500'} px-3 py-3.5 text-right text-sm font-semibold"
>
<div>
{Intl.NumberFormat(navigator.language, {
maximumFractionDigits: 2
}).format(perf)} %
<Icon
src={perf < 0 ? ArrowDown : perf < 1 ? ArrowRight : ArrowUp}
class="float-right mt-0.5 h-4 w-4"
aria-hidden="true"
/>
</div>
<div class="pr-4">
{currency(snapshot.totalMarketValue - snapshot.totalPurchaseValue, 'EUR')}
</div>
</th>
</tr>
</tfoot>
</table>
</div>
57 changes: 57 additions & 0 deletions ui/src/lib/components/PortfolioTransactionRow.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<script lang="ts">
import { PortfolioEventType, type PortfolioEvent } from '$lib/gen/mgo_pb';
import { currency as formatCurrency } from '$lib/intl';
import { PencilSquare } from '@steeze-ui/heroicons';
import { Icon } from '@steeze-ui/svelte-icon';
import Date from './Date.svelte';
export let tx: PortfolioEvent;
export let currency = 'EUR';
$: total = tx.amount * (tx.price + tx.fees + tx.taxes);
</script>

<tr>
<td class="truncate whitespace-nowrap py-2 pl-4 pr-3 text-sm font-medium sm:pl-0">
<Date date={tx.time?.toDate()} />
</td>
<td class="truncate whitespace-nowrap py-2 pl-4 pr-3 text-sm font-medium sm:pl-0">
{PortfolioEventType[tx.type]}
</td>
<td class="truncate whitespace-nowrap py-2 pl-4 pr-3 text-sm font-medium sm:pl-0">
<div class="text-gray-900">
{tx.securityName}
</div>
<div class="text-gray-400">NAME</div>
</td>
<td class="hidden whitespace-nowrap px-3 py-2 text-right text-sm text-gray-500 md:table-cell">
{Intl.NumberFormat(navigator.language, {
maximumFractionDigits: 2
}).format(tx.amount)}
</td>
<td class="hidden whitespace-nowrap px-3 py-2 text-right text-sm lg:table-cell">
<div class="text-gray-500">
{formatCurrency(tx.price, currency)}
</div>
</td>
<td class="hidden whitespace-nowrap px-3 py-2 text-right text-sm sm:table-cell">
<div class="text-gray-500">
{formatCurrency(tx.fees, currency)}
</div>
</td>
<td class="hidden whitespace-nowrap px-3 py-2 text-right text-sm sm:table-cell">
<div class="text-gray-500">
{formatCurrency(tx.taxes, currency)}
</div>
</td>
<td class="hidden whitespace-nowrap px-3 py-2 text-right text-sm sm:table-cell">
<div class="text-gray-500">
{formatCurrency(total, currency)}
</div>
</td>
<td>
<a href="/portfolios/{tx.portfolioName}/transactions/{tx.name}">
<Icon src={PencilSquare} class="h-5 w-5 text-gray-400" theme="mini" />
</a>
</td>
</tr>
Loading

0 comments on commit 1cf5e2a

Please sign in to comment.