207 lines
4.7 KiB
TypeScript
207 lines
4.7 KiB
TypeScript
// DBIS Accounting Standards Service
|
|
// Fair value marking, commodity feed integration
|
|
|
|
import prisma from '@/shared/database/prisma';
|
|
import { Decimal } from '@prisma/client/runtime/library';
|
|
|
|
|
|
export interface ValuationData {
|
|
assetType: string;
|
|
assetId: string;
|
|
fairValue: number;
|
|
currencyCode: string;
|
|
valuationDate: Date;
|
|
source: string;
|
|
}
|
|
|
|
export class AccountingStandardsService {
|
|
/**
|
|
* Get valuation rule for asset type
|
|
*/
|
|
async getValuationRule(assetType: string) {
|
|
return await prisma.valuationRule.findFirst({
|
|
where: {
|
|
assetType,
|
|
status: 'active',
|
|
effectiveDate: {
|
|
lte: new Date(),
|
|
},
|
|
OR: [
|
|
{ expiryDate: null },
|
|
{ expiryDate: { gte: new Date() } },
|
|
],
|
|
},
|
|
orderBy: { effectiveDate: 'desc' },
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Mark asset to fair value
|
|
*/
|
|
async markToFairValue(assetId: string, assetType: string, fairValue: number, currencyCode: string) {
|
|
const rule = await this.getValuationRule(assetType);
|
|
|
|
if (!rule) {
|
|
throw new Error(`No valuation rule found for asset type: ${assetType}`);
|
|
}
|
|
|
|
// Update asset value based on type
|
|
switch (assetType) {
|
|
case 'commodity':
|
|
await this.updateCommodityValue(assetId, fairValue);
|
|
break;
|
|
case 'security':
|
|
await this.updateSecurityValue(assetId, fairValue);
|
|
break;
|
|
case 'fiat':
|
|
case 'cbdc':
|
|
// Fiat and CBDC are already at fair value
|
|
break;
|
|
default:
|
|
throw new Error(`Unsupported asset type for fair value marking: ${assetType}`);
|
|
}
|
|
|
|
// Log valuation
|
|
await prisma.auditLog.create({
|
|
data: {
|
|
eventType: 'valuation',
|
|
entityType: assetType,
|
|
entityId: assetId,
|
|
action: 'mark_to_fair_value',
|
|
details: {
|
|
fairValue,
|
|
currencyCode,
|
|
valuationMethod: rule.valuationMethod,
|
|
timestamp: new Date(),
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Update commodity value
|
|
*/
|
|
private async updateCommodityValue(commodityId: string, fairValue: number) {
|
|
// In production, would update commodity price
|
|
// For now, update commodity spot price if exists
|
|
const commodity = await prisma.commodity.findFirst({
|
|
where: {
|
|
id: commodityId,
|
|
},
|
|
});
|
|
|
|
if (commodity) {
|
|
await prisma.commodity.update({
|
|
where: { id: commodityId },
|
|
data: {
|
|
spotPrice: new Decimal(fairValue),
|
|
lastUpdated: new Date(),
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update security value
|
|
*/
|
|
private async updateSecurityValue(securityId: string, fairValue: number) {
|
|
const security = await prisma.security.findFirst({
|
|
where: {
|
|
securityId,
|
|
},
|
|
});
|
|
|
|
if (security) {
|
|
await prisma.security.update({
|
|
where: { id: security.id },
|
|
data: {
|
|
price: new Decimal(fairValue),
|
|
updatedAt: new Date(),
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get commodity feed price
|
|
*/
|
|
async getCommodityFeedPrice(commodityType: string, unit: string): Promise<number | null> {
|
|
const commodity = await prisma.commodity.findUnique({
|
|
where: {
|
|
commodityType_unit: {
|
|
commodityType,
|
|
unit,
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!commodity) {
|
|
return null;
|
|
}
|
|
|
|
return parseFloat(commodity.spotPrice.toString());
|
|
}
|
|
|
|
/**
|
|
* Get FX reference rate
|
|
*/
|
|
async getFXReferenceRate(baseCurrency: string, quoteCurrency: string): Promise<number | null> {
|
|
const fxPair = await prisma.fxPair.findFirst({
|
|
where: {
|
|
OR: [
|
|
{
|
|
baseCurrency,
|
|
quoteCurrency,
|
|
},
|
|
{
|
|
baseCurrency: quoteCurrency,
|
|
quoteCurrency: baseCurrency,
|
|
},
|
|
],
|
|
status: 'active',
|
|
},
|
|
include: {
|
|
trades: {
|
|
where: {
|
|
status: 'settled',
|
|
},
|
|
orderBy: { timestampUtc: 'desc' },
|
|
take: 1,
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!fxPair || fxPair.trades.length === 0) {
|
|
return null;
|
|
}
|
|
|
|
return parseFloat(fxPair.trades[0].price.toString());
|
|
}
|
|
|
|
/**
|
|
* Create valuation rule
|
|
*/
|
|
async createValuationRule(
|
|
assetType: string,
|
|
valuationMethod: string,
|
|
feedSource?: string,
|
|
updateFrequency: string = 'real_time'
|
|
) {
|
|
return await prisma.valuationRule.create({
|
|
data: {
|
|
id: require('uuid').v4(),
|
|
ruleId: require('uuid').v4(),
|
|
assetType,
|
|
valuationMethod,
|
|
feedSource,
|
|
updateFrequency,
|
|
status: 'active',
|
|
effectiveDate: new Date(),
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
export const accountingStandardsService = new AccountingStandardsService();
|
|
|