Compare commits

...

2 Commits

Author SHA1 Message Date
Sirttas 42c7e59d63 balance endpoint 2026-06-01 17:39:14 +02:00
Sirttas 192cf7d9cb ledger view page structure 2026-06-01 16:24:35 +02:00
10 changed files with 414 additions and 279 deletions
+47
View File
@@ -350,6 +350,29 @@ paths:
type: array type: array
items: items:
$ref: "#/components/schemas/TransactionResponse" $ref: "#/components/schemas/TransactionResponse"
/ledgers/{ledgerId}/balance:
get:
tags:
- ledger
operationId: findBalanceByLedgerId
parameters:
- name: ledgerId
in: path
required: true
schema:
type: string
format: uuid
responses:
"404":
description: Not Found
"400":
description: Bad Request
"200":
description: OK
content:
'*/*':
schema:
$ref: "#/components/schemas/BalanceResponse"
/characters: /characters:
get: get:
tags: tags:
@@ -660,6 +683,30 @@ components:
enum: enum:
- ISK - ISK
- ITEM - ITEM
BalanceResponse:
type: object
properties:
iskBalance:
type: number
itemBalances:
type: array
items:
$ref: "#/components/schemas/ItemBalanceResponse"
required:
- iskBalance
- itemBalances
ItemBalanceResponse:
type: object
properties:
typeId:
type: integer
format: int64
quantity:
type: integer
format: int64
required:
- quantity
- typeId
CharacterResponse: CharacterResponse:
type: object type: object
properties: properties:
+233 -244
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -14,6 +14,7 @@
"@vueuse/components": "^14.3.0", "@vueuse/components": "^14.3.0",
"@vueuse/core": "^14.3.0", "@vueuse/core": "^14.3.0",
"@vueuse/integrations": "^14.3.0", "@vueuse/integrations": "^14.3.0",
"@vueuse/router": "^14.3.0",
"axios": "^1.4.0", "axios": "^1.4.0",
"axios-rate-limit": "^1.3.1", "axios-rate-limit": "^1.3.1",
"gemory": "file:", "gemory": "file:",
+72
View File
@@ -23,6 +23,10 @@ import type { RequestArgs } from './base';
// @ts-ignore // @ts-ignore
import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base'; import { BASE_PATH, COLLECTION_FORMATS, BaseAPI, RequiredError, operationServerMap } from './base';
export interface BalanceResponse {
'iskBalance': number;
'itemBalances': Array<ItemBalanceResponse>;
}
export interface CharacterResponse { export interface CharacterResponse {
'characterId': number; 'characterId': number;
'name': string; 'name': string;
@@ -76,6 +80,10 @@ export const IskTransferResponseTypeEnum = {
export type IskTransferResponseTypeEnum = typeof IskTransferResponseTypeEnum[keyof typeof IskTransferResponseTypeEnum]; export type IskTransferResponseTypeEnum = typeof IskTransferResponseTypeEnum[keyof typeof IskTransferResponseTypeEnum];
export interface ItemBalanceResponse {
'typeId': number;
'quantity': number;
}
export interface ItemTransferResponse extends TransferResponse { export interface ItemTransferResponse extends TransferResponse {
'fromLedgerId': string; 'fromLedgerId': string;
'toLedgerId': string; 'toLedgerId': string;
@@ -635,6 +643,39 @@ export const LedgerApiAxiosParamCreator = function (configuration?: Configuratio
options: localVarRequestOptions, options: localVarRequestOptions,
}; };
}, },
/**
*
* @param {string} ledgerId
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
findBalanceByLedgerId: async (ledgerId: string, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'ledgerId' is not null or undefined
assertParamExists('findBalanceByLedgerId', 'ledgerId', ledgerId)
const localVarPath = `/ledgers/{ledgerId}/balance`
.replace('{ledgerId}', encodeURIComponent(String(ledgerId)));
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}
const localVarRequestOptions = { method: 'GET', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;
localVarHeaderParameter['Accept'] = '*/*';
setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/** /**
* *
* @param {string} ledgerId * @param {string} ledgerId
@@ -788,6 +829,18 @@ export const LedgerApiFp = function(configuration?: Configuration) {
const localVarOperationServerBasePath = operationServerMap['LedgerApi.findAllLedgers']?.[localVarOperationServerIndex]?.url; const localVarOperationServerBasePath = operationServerMap['LedgerApi.findAllLedgers']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath); return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
}, },
/**
*
* @param {string} ledgerId
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async findBalanceByLedgerId(ledgerId: string, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<BalanceResponse>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.findBalanceByLedgerId(ledgerId, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['LedgerApi.findBalanceByLedgerId']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/** /**
* *
* @param {string} ledgerId * @param {string} ledgerId
@@ -861,6 +914,15 @@ export const LedgerApiFactory = function (configuration?: Configuration, basePat
findAllLedgers(options?: RawAxiosRequestConfig): AxiosPromise<Array<FindAllLedgers200ResponseInner>> { findAllLedgers(options?: RawAxiosRequestConfig): AxiosPromise<Array<FindAllLedgers200ResponseInner>> {
return localVarFp.findAllLedgers(options).then((request) => request(axios, basePath)); return localVarFp.findAllLedgers(options).then((request) => request(axios, basePath));
}, },
/**
*
* @param {string} ledgerId
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
findBalanceByLedgerId(ledgerId: string, options?: RawAxiosRequestConfig): AxiosPromise<BalanceResponse> {
return localVarFp.findBalanceByLedgerId(ledgerId, options).then((request) => request(axios, basePath));
},
/** /**
* *
* @param {string} ledgerId * @param {string} ledgerId
@@ -926,6 +988,16 @@ export class LedgerApi extends BaseAPI {
return LedgerApiFp(this.configuration).findAllLedgers(options).then((request) => request(this.axios, this.basePath)); return LedgerApiFp(this.configuration).findAllLedgers(options).then((request) => request(this.axios, this.basePath));
} }
/**
*
* @param {string} ledgerId
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
public findBalanceByLedgerId(ledgerId: string, options?: RawAxiosRequestConfig) {
return LedgerApiFp(this.configuration).findBalanceByLedgerId(ledgerId, options).then((request) => request(this.axios, this.basePath));
}
/** /**
* *
* @param {string} ledgerId * @param {string} ledgerId
+2 -2
View File
@@ -3,7 +3,7 @@
import {isCombined, Ledger} from "@/ledger/ledger.ts"; import {isCombined, Ledger} from "@/ledger/ledger.ts";
import {FolderOpenIcon} from '@heroicons/vue/24/outline'; import {FolderOpenIcon} from '@heroicons/vue/24/outline';
import {RouterLink} from "vue-router"; import {RouterLink} from "vue-router";
import {routeNames} from "@/routes.ts"; import {routeNames} from "@/routes";
interface Props { interface Props {
ledger: Ledger; ledger: Ledger;
@@ -17,7 +17,7 @@ const props = defineProps<Props>();
<div class="flex"> <div class="flex">
<FolderOpenIcon v-if="isCombined(ledger)" class="w-4 me-1" /> <FolderOpenIcon v-if="isCombined(ledger)" class="w-4 me-1" />
<div v-else class="w-4 me-1"/> <div v-else class="w-4 me-1"/>
<RouterLink v-if="link" :to="{name: routeNames.listLedgerTransactions, params: {ledgerId: ledger.ledgerId}}">{{ ledger.name }}</RouterLink> <RouterLink v-if="link" :to="{name: routeNames.viewLedger, params: {ledgerId: ledger.ledgerId}}">{{ ledger.name }}</RouterLink>
<span v-else>{{ ledger.name }}</span> <span v-else>{{ ledger.name }}</span>
</div> </div>
</template> </template>
+9 -1
View File
@@ -12,8 +12,9 @@ import {
UpdateMainLedgerRequest UpdateMainLedgerRequest
} from "@/generated/mammon"; } from "@/generated/mammon";
import {defineStore} from "pinia"; import {defineStore} from "pinia";
import {ref, triggerRef} from "vue"; import {computed, ref, triggerRef} from "vue";
import {ledgerApi, transactionApi} from "@/mammon"; import {ledgerApi, transactionApi} from "@/mammon";
import {useRouteParams} from "@vueuse/router";
export const LedgerTypes = LedgerResponseTypeEnum; export const LedgerTypes = LedgerResponseTypeEnum;
@@ -76,3 +77,10 @@ export const useLedgersStore = defineStore('ledgers', () => {
export const findAllTransactionInLeger = (ledger: Ledger | string): Promise<TransactionResponse[]> => transactionApi.finAllTransactionsInLedger(typeof ledger == 'string' ? ledger : ledger.ledgerId).then(response => response.data) export const findAllTransactionInLeger = (ledger: Ledger | string): Promise<TransactionResponse[]> => transactionApi.finAllTransactionsInLedger(typeof ledger == 'string' ? ledger : ledger.ledgerId).then(response => response.data)
export const useLedgerParam = () => {
const {findById} = useLedgersStore();
const ledgerId = useRouteParams<string, string>('ledgerId', '', { transform: v => typeof v === 'string' ? v : v[0]});
const ledger = computed(() => findById(ledgerId.value))
return {ledgerId, ledger};
}
+7 -28
View File
@@ -1,29 +1,22 @@
<script setup lang="ts"> <script setup lang="ts">
import {ref, watch} from "vue"; import {findAllTransactionInLeger, TransferTypes, useLedgerParam} from "@/ledger";
import {useRoute} from "vue-router";
import log from "loglevel";
import {findAllTransactionInLeger, Ledger, TransferTypes, useLedgersStore} from "@/ledger";
import {computedAsync} from "@vueuse/core"; import {computedAsync} from "@vueuse/core";
import {TransactionResponse} from "@/generated/mammon"; import {TransactionResponse} from "@/generated/mammon";
import {formatEveDate} from "@/formaters.ts"; import {formatEveDate} from "@/formaters.ts";
import {IskLabel} from "@/market"; import {IskLabel} from "@/market";
const {findById, refresh} = useLedgersStore(); const {ledgerId, ledger} = useLedgerParam();
const ledger = ref<Ledger>();
const transactions = computedAsync<TransactionResponse[]>(async () => { const transactions = computedAsync<TransactionResponse[]>(async () => {
if (ledger.value) { if (ledgerId.value) {
return await findAllTransactionInLeger(ledger.value.ledgerId); return await findAllTransactionInLeger(ledgerId.value);
} }
return []; return [];
}, []); }, []);
const getIskBalance = (transaction: TransactionResponse) => { const getIskBalance = (transaction: TransactionResponse) => {
const ledgerId = ledger.value?.ledgerId; if (!ledgerId.value) {
if (!ledgerId) {
return 0; return 0;
} }
@@ -31,29 +24,15 @@ const getIskBalance = (transaction: TransactionResponse) => {
for (const transfer of transaction.transfers) { for (const transfer of transaction.transfers) {
if (transfer.type === TransferTypes.Isk) { if (transfer.type === TransferTypes.Isk) {
if (transfer.toLedgerId === ledgerId) { if (transfer.toLedgerId === ledgerId.value) {
balance += transfer.amount; balance += transfer.amount;
} else if (transfer.fromLedgerId === ledgerId) { } else if (transfer.fromLedgerId === ledgerId.value) {
balance -= transfer.amount; balance -= transfer.amount;
} }
} }
} }
return balance; return balance;
} }
watch(useRoute(), async route => {
if (route.params.ledgerId) {
const id = typeof route.params.ledgerId === 'string' ? route.params.ledgerId : route.params.ledgerId[0];
await refresh() // FIXME
ledger.value = findById(id)
log.info('Loaded ledger:', ledger.value);
} else {
ledger.value = undefined;
log.info('No ledger to load');
}
}, { immediate: true })
</script> </script>
<template> <template>
+22
View File
@@ -0,0 +1,22 @@
<script setup lang="ts">
import {RouterLink, RouterView} from 'vue-router';
import {isMain, useLedgerParam} from "@/ledger";
import {routeNames} from "@/routes.ts";
const {ledgerId, ledger} = useLedgerParam();
</script>
<template>
<div v-if="ledger" class="mt-4">
<div class="flex border-b-2 border-emerald-500">
<RouterLink :to="{name: routeNames.viewLedgerBalance}" class="tab">
<span>Balance</span>
</RouterLink>
<RouterLink v-if="isMain(ledger)" :to="{name: routeNames.listLedgerTransactions}" class="tab">
<span>Transactions</span>
</RouterLink>
</div>
<RouterView />
</div>
</template>
+11
View File
@@ -0,0 +1,11 @@
<script setup lang="ts">
import {useLedgerParam} from "@/ledger";
const {ledgerId, ledger} = useLedgerParam();
</script>
<template>
<div class="mt-4">
</div>
</template>
+10 -4
View File
@@ -3,7 +3,9 @@ import {RouteRecordRaw} from 'vue-router';
export const routeNames = { export const routeNames = {
home: 'home', home: 'home',
callback: 'callback', callback: 'callback',
listLedgerTransactions: 'list-ledger-tTransactions', viewLedger: 'view-ledger',
viewLedgerBalance: 'view-ledger-balance',
listLedgerTransactions: 'list-ledger-transactions',
listRuleBooks: 'list-rule-books', listRuleBooks: 'list-rule-books',
newRuleBook: 'new-rule-book', newRuleBook: 'new-rule-book',
editRuleBook: 'edit-rule-book', editRuleBook: 'edit-rule-book',
@@ -18,11 +20,15 @@ export const routes: RouteRecordRaw[] = [
{path: '/ledgers', component: () => import('@/pages/Ledgers.vue'), children: [ {path: '/ledgers', component: () => import('@/pages/Ledgers.vue'), children: [
{path: '', component: () => import('@/pages/ledger/ListLedgers.vue')}, {path: '', component: () => import('@/pages/ledger/ListLedgers.vue')},
{path: ':ledgerId/transactions', name: routeNames.listLedgerTransactions, component: () => import('@/pages/ledger/ListLedgerTransactions.vue')}, {path: ':ledgerId', component: () => import('./pages/ledger/ViewLedger.vue'), children: [
{path: '', name: routeNames.viewLedger, redirect: {name: routeNames.viewLedgerBalance}},
{path: 'balance', name: routeNames.viewLedgerBalance, component: () => import('@/pages/ledger/ViewLedgerBalance.vue')},
{path: 'transactions', name: routeNames.listLedgerTransactions, component: () => import('@/pages/ledger/ListLedgerTransactions.vue')},
]},
]}, ]},
{path: '/rules', component: () => import('@/pages/Rules.vue'), children: [ {path: '/rules', component: () => import('@/pages/Rules.vue'), children: [
{path: '', redirect: '/rule-books'}, {path: '', redirect: {name: routeNames.listRuleBooks}},
{path: '/rule-books', children: [ {path: '/rule-books', children: [
{path: '', name: routeNames.listRuleBooks, component: () => import('@/pages/rules/ListRuleBooks.vue')}, {path: '', name: routeNames.listRuleBooks, component: () => import('@/pages/rules/ListRuleBooks.vue')},
{path: 'new', name: routeNames.newRuleBook, component: () => import('@/pages/rules/EditRuleBook.vue')}, {path: 'new', name: routeNames.newRuleBook, component: () => import('@/pages/rules/EditRuleBook.vue')},
@@ -35,7 +41,7 @@ export const routes: RouteRecordRaw[] = [
]}, ]},
{path: '/market', component: () => import('@/pages/Market.vue'), children: [ {path: '/market', component: () => import('@/pages/Market.vue'), children: [
{path: '', redirect: '/market/types'}, {path: '', redirect: {name: routeNames.marketTypes}},
{path: 'types/:type?', name: routeNames.marketTypes, component: () => import('@/pages/market/TypeInfo.vue')}, {path: 'types/:type?', name: routeNames.marketTypes, component: () => import('@/pages/market/TypeInfo.vue')},
{path: 'tracking', component: () => import('@/pages/market/Tracking.vue')}, {path: 'tracking', component: () => import('@/pages/market/Tracking.vue')},
{path: 'acquisitions', component: () => import('@/pages/market/Acquisitions.vue')}, {path: 'acquisitions', component: () => import('@/pages/market/Acquisitions.vue')},