Added account diffs and cleaned up transaction page.
This commit is contained in:
parent
30715947a3
commit
534071cbe0
|
|
@ -79,6 +79,23 @@ void handleDeleteAccount(ref ServerHttpRequest request, ref ServerHttpResponse r
|
|||
ds.getAccountRepository().deleteById(accountId);
|
||||
}
|
||||
|
||||
void handleGetAccountBalance(ref ServerHttpRequest request, ref ServerHttpResponse response) {
|
||||
ulong accountId = request.getPathParamAs!ulong("accountId");
|
||||
auto ds = getProfileDataSource(request);
|
||||
SysTime timestamp = Clock.currTime(UTC());
|
||||
string providedTimestamp = request.getParamAs!string("timestamp");
|
||||
if (providedTimestamp != null && providedTimestamp.length > 0) {
|
||||
timestamp = SysTime.fromISOExtString(providedTimestamp);
|
||||
}
|
||||
Optional!long balance = getBalance(ds, accountId, timestamp);
|
||||
if (balance.isNull) {
|
||||
response.writeBodyString("{\"balance\": null}", ContentTypes.APPLICATION_JSON);
|
||||
} else {
|
||||
import std.conv : to;
|
||||
response.writeBodyString("{\"balance\": " ~ balance.value.to!string ~ "}", ContentTypes.APPLICATION_JSON);
|
||||
}
|
||||
}
|
||||
|
||||
void handleGetAccountHistory(ref ServerHttpRequest request, ref ServerHttpResponse response) {
|
||||
ulong accountId = request.getPathParamOrThrow!ulong("accountId");
|
||||
PageRequest pagination = PageRequest.parse(request, PageRequest(1, 10, [Sort("timestamp", SortDir.DESC)]));
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ HttpRequestHandler mapApiHandlers(string webOrigin) {
|
|||
a.map(HttpMethod.GET, ACCOUNT_PATH, &handleGetAccount);
|
||||
a.map(HttpMethod.PUT, ACCOUNT_PATH, &handleUpdateAccount);
|
||||
a.map(HttpMethod.DELETE, ACCOUNT_PATH, &handleDeleteAccount);
|
||||
a.map(HttpMethod.GET, ACCOUNT_PATH ~ "/balance", &handleGetAccountBalance);
|
||||
a.map(HttpMethod.GET, ACCOUNT_PATH ~ "/history", &handleGetAccountHistory);
|
||||
a.map(HttpMethod.GET, ACCOUNT_PATH ~ "/value-records", &handleGetValueRecords);
|
||||
a.map(HttpMethod.GET, ACCOUNT_PATH ~ "/value-records/:valueRecordId:ulong", &handleGetValueRecord);
|
||||
|
|
|
|||
|
|
@ -173,6 +173,14 @@ export class AccountApiClient extends ApiClient {
|
|||
return super.delete(this.path + '/' + id)
|
||||
}
|
||||
|
||||
async getBalance(id: number, timestamp: Date): Promise<number | undefined> {
|
||||
const result: { balance: number | null } = await super.getJson(
|
||||
`${this.path}/${id}/balance?timestamp=${timestamp.toISOString()}`,
|
||||
)
|
||||
if (result.balance === null) return undefined
|
||||
return result.balance
|
||||
}
|
||||
|
||||
getHistory(id: number, pageRequest: PageRequest): Promise<Page<AccountHistoryItem>> {
|
||||
return super.getJsonPage(`${this.path}/${id}/history`, pageRequest)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,3 +14,8 @@
|
|||
margin-left: 0.5rem;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
.my-1 {
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,17 +15,26 @@ import AttachmentRow from '@/components/common/AttachmentRow.vue'
|
|||
import LineItemCard from '@/components/LineItemCard.vue'
|
||||
import AppBadge from '@/components/common/AppBadge.vue'
|
||||
import ButtonBar from '@/components/common/ButtonBar.vue'
|
||||
import { AccountApiClient } from '@/api/account'
|
||||
|
||||
interface BalanceDiff {
|
||||
before: number
|
||||
after: number
|
||||
}
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
const transactionApi = new TransactionApiClient(getSelectedProfile(route))
|
||||
|
||||
const transaction: Ref<TransactionDetail | undefined> = ref()
|
||||
const creditedAccountBalanceDiff = ref<BalanceDiff | undefined>()
|
||||
const debitedAccountBalanceDiff = ref<BalanceDiff | undefined>()
|
||||
|
||||
onMounted(async () => {
|
||||
const transactionId = parseInt(route.params.id as string)
|
||||
try {
|
||||
transaction.value = await transactionApi.getTransaction(transactionId)
|
||||
fetchBalanceDiffs()
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
await router.replace('/')
|
||||
|
|
@ -35,6 +44,34 @@ onMounted(async () => {
|
|||
}
|
||||
})
|
||||
|
||||
async function fetchBalanceDiffs() {
|
||||
const txn = transaction.value
|
||||
if (!txn) return
|
||||
const txnTime = new Date(txn.timestamp).getTime()
|
||||
const beforeTs = new Date(txnTime - 1000)
|
||||
const afterTs = new Date(txnTime + 1000)
|
||||
const accountApi = new AccountApiClient(route)
|
||||
const p1: Promise<number | undefined> = txn.creditedAccount
|
||||
? accountApi.getBalance(txn.creditedAccount.id, beforeTs)
|
||||
: Promise.resolve(undefined)
|
||||
const p2: Promise<number | undefined> = txn.creditedAccount
|
||||
? accountApi.getBalance(txn.creditedAccount.id, afterTs)
|
||||
: Promise.resolve(undefined)
|
||||
const p3: Promise<number | undefined> = txn.debitedAccount
|
||||
? accountApi.getBalance(txn.debitedAccount.id, beforeTs)
|
||||
: Promise.resolve(undefined)
|
||||
const p4: Promise<number | undefined> = txn.debitedAccount
|
||||
? accountApi.getBalance(txn.debitedAccount.id, afterTs)
|
||||
: Promise.resolve(undefined)
|
||||
const results = await Promise.all([p1, p2, p3, p4])
|
||||
if (results[0] !== undefined && results[1] !== undefined) {
|
||||
creditedAccountBalanceDiff.value = { before: results[0], after: results[1] }
|
||||
}
|
||||
if (results[2] !== undefined && results[3] !== undefined) {
|
||||
debitedAccountBalanceDiff.value = { before: results[2], after: results[3] }
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteTransaction() {
|
||||
if (!transaction.value) return
|
||||
const conf = await showConfirm(
|
||||
|
|
@ -68,18 +105,39 @@ async function deleteTransaction() {
|
|||
|
||||
<p>{{ transaction.description }}</p>
|
||||
|
||||
<p v-if="transaction.creditedAccount">
|
||||
<div v-if="transaction.creditedAccount" class="my-1">
|
||||
<strong class="text-negative">Credited</strong> from
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile(route)}/accounts/${transaction.creditedAccount.id}`">
|
||||
{{ transaction.creditedAccount.name }} (#{{ transaction.creditedAccount.numberSuffix }})
|
||||
</RouterLink>
|
||||
</p>
|
||||
<p v-if="transaction.debitedAccount">
|
||||
<div v-if="creditedAccountBalanceDiff" class="font-size-xsmall">
|
||||
Balance Before:
|
||||
<span class="font-mono">
|
||||
{{ formatMoney(creditedAccountBalanceDiff.before, transaction.currency) }}
|
||||
</span>
|
||||
/ After:
|
||||
<span class="font-mono">
|
||||
{{ formatMoney(creditedAccountBalanceDiff.after, transaction.currency) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="transaction.debitedAccount" class="my-1">
|
||||
<strong class="text-positive">Debited</strong> to
|
||||
<RouterLink :to="`/profiles/${getSelectedProfile(route)}/accounts/${transaction.debitedAccount.id}`">
|
||||
{{ transaction.debitedAccount.name }} (#{{ transaction.debitedAccount.numberSuffix }})
|
||||
</RouterLink>
|
||||
</p>
|
||||
<div v-if="debitedAccountBalanceDiff" class="font-size-xsmall">
|
||||
Balance Before:
|
||||
<span class="font-mono">
|
||||
{{ formatMoney(debitedAccountBalanceDiff.before, transaction.currency) }}
|
||||
</span>
|
||||
/ After:
|
||||
<span class="font-mono">
|
||||
{{ formatMoney(debitedAccountBalanceDiff.after, transaction.currency) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- All remaining properties are put in this table. -->
|
||||
<PropertiesTable>
|
||||
|
|
|
|||
Loading…
Reference in New Issue