checkpoint: goals feature, wallet balance, and goals/wallet detail UI
- Add goals feature (models, migrations, API, web pages) - Add reserved/centralized wallet balance service - Add wallet detail page and overview components - Add new UI components (progress, multi-select, FAB) - Remove stray empty -H/-d files from working tree
This commit is contained in:
105
apps/api/dist/wallets/wallet-balance.service.js
vendored
Executable file
105
apps/api/dist/wallets/wallet-balance.service.js
vendored
Executable file
@@ -0,0 +1,105 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WalletBalanceService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const prisma_service_1 = require("../prisma/prisma.service");
|
||||
const library_1 = require("@prisma/client/runtime/library");
|
||||
let WalletBalanceService = class WalletBalanceService {
|
||||
prisma;
|
||||
constructor(prisma) {
|
||||
this.prisma = prisma;
|
||||
}
|
||||
async calculateBalance(walletId) {
|
||||
const wallet = await this.prisma.wallet.findUnique({
|
||||
where: { id: walletId },
|
||||
include: {
|
||||
transactions: {
|
||||
orderBy: { date: 'asc' },
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!wallet) {
|
||||
throw new Error('Wallet not found');
|
||||
}
|
||||
console.log(`[Balance] Calculating for wallet ${walletId}:`, {
|
||||
name: wallet.name,
|
||||
kind: wallet.kind,
|
||||
initialAmount: wallet.initialAmount?.toString(),
|
||||
transactionCount: wallet.transactions.length,
|
||||
});
|
||||
const reservedBalance = new library_1.Decimal(wallet.reservedBalance || 0);
|
||||
if (wallet.kind === 'money') {
|
||||
let totalBalance = wallet.initialAmount ? new library_1.Decimal(wallet.initialAmount) : new library_1.Decimal(0);
|
||||
for (const tx of wallet.transactions) {
|
||||
if (tx.direction === 'in') {
|
||||
totalBalance = totalBalance.plus(tx.amount);
|
||||
}
|
||||
else {
|
||||
totalBalance = totalBalance.minus(tx.amount);
|
||||
}
|
||||
}
|
||||
const availableBalance = totalBalance.minus(reservedBalance);
|
||||
return {
|
||||
walletId: wallet.id,
|
||||
kind: wallet.kind,
|
||||
currency: wallet.currency || 'IDR',
|
||||
totalBalance,
|
||||
reservedBalance,
|
||||
availableBalance: availableBalance.greaterThanOrEqualTo(0) ? availableBalance : new library_1.Decimal(0),
|
||||
pricePerUnit: wallet.pricePerUnit || undefined,
|
||||
};
|
||||
}
|
||||
else {
|
||||
let totalUnits = wallet.initialAmount ? new library_1.Decimal(wallet.initialAmount) : new library_1.Decimal(0);
|
||||
for (const tx of wallet.transactions) {
|
||||
if (tx.direction === 'in') {
|
||||
totalUnits = totalUnits.plus(tx.amount);
|
||||
}
|
||||
else {
|
||||
totalUnits = totalUnits.minus(tx.amount);
|
||||
}
|
||||
}
|
||||
const pricePerUnit = wallet.pricePerUnit ? new library_1.Decimal(wallet.pricePerUnit) : new library_1.Decimal(0);
|
||||
const totalValue = totalUnits.times(pricePerUnit);
|
||||
const reservedUnits = pricePerUnit.greaterThan(0) ? reservedBalance.dividedBy(pricePerUnit) : new library_1.Decimal(0);
|
||||
const availableUnits = totalUnits.minus(reservedUnits);
|
||||
const availableValue = totalValue.minus(reservedBalance);
|
||||
return {
|
||||
walletId: wallet.id,
|
||||
kind: wallet.kind,
|
||||
unit: wallet.unit || 'units',
|
||||
totalUnits,
|
||||
pricePerUnit,
|
||||
totalValue,
|
||||
totalBalance: totalUnits,
|
||||
reservedBalance: reservedUnits,
|
||||
availableBalance: availableUnits.greaterThanOrEqualTo(0) ? availableUnits : new library_1.Decimal(0),
|
||||
};
|
||||
}
|
||||
}
|
||||
async calculateMultipleBalances(walletIds) {
|
||||
return Promise.all(walletIds.map(id => this.calculateBalance(id)));
|
||||
}
|
||||
async getAllUserWalletBalances(userId) {
|
||||
const wallets = await this.prisma.wallet.findMany({
|
||||
where: { userId, deletedAt: null },
|
||||
select: { id: true },
|
||||
});
|
||||
return this.calculateMultipleBalances(wallets.map(w => w.id));
|
||||
}
|
||||
};
|
||||
exports.WalletBalanceService = WalletBalanceService;
|
||||
exports.WalletBalanceService = WalletBalanceService = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__metadata("design:paramtypes", [prisma_service_1.PrismaService])
|
||||
], WalletBalanceService);
|
||||
//# sourceMappingURL=wallet-balance.service.js.map
|
||||
Reference in New Issue
Block a user