Feature/add currency to order database schema (#3251)

* Add currency to Order database schema

* Update changelog
pull/3252/head
Thomas Kaul 8 months ago committed by GitHub
parent 719bbe156e
commit 07c0e5a612
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added the asset profile icon to the asset profile details dialog of the admin control - Added the asset profile icon to the asset profile details dialog of the admin control
- Added the platform icon to the create or update platform dialog of the admin control - Added the platform icon to the create or update platform dialog of the admin control
- Extended the rules in the _X-ray_ section by a `key` - Extended the rules in the _X-ray_ section by a `key`
- Added `currency` to the `Order` database schema as a preparation to set a custom currency
- Extended the content of the _Self-Hosting_ section by the data providers on the Frequently Asked Questions (FAQ) page - Extended the content of the _Self-Hosting_ section by the data providers on the Frequently Asked Questions (FAQ) page
### Changed ### Changed

@ -112,6 +112,7 @@ export class ImportService {
accountId: Account?.id, accountId: Account?.id,
accountUserId: undefined, accountUserId: undefined,
comment: undefined, comment: undefined,
currency: undefined,
createdAt: undefined, createdAt: undefined,
fee: 0, fee: 0,
feeInBaseCurrency: 0, feeInBaseCurrency: 0,
@ -261,6 +262,7 @@ export class ImportService {
{ {
accountId, accountId,
comment, comment,
currency,
date, date,
error, error,
fee, fee,
@ -285,7 +287,6 @@ export class ImportService {
assetSubClass, assetSubClass,
countries, countries,
createdAt, createdAt,
currency,
dataSource, dataSource,
figi, figi,
figiComposite, figiComposite,
@ -342,6 +343,7 @@ export class ImportService {
if (isDryRun) { if (isDryRun) {
order = { order = {
comment, comment,
currency,
date, date,
fee, fee,
quantity, quantity,
@ -357,7 +359,6 @@ export class ImportService {
assetSubClass, assetSubClass,
countries, countries,
createdAt, createdAt,
currency,
dataSource, dataSource,
figi, figi,
figiComposite, figiComposite,
@ -371,6 +372,7 @@ export class ImportService {
symbolMapping, symbolMapping,
updatedAt, updatedAt,
url, url,
currency: assetProfile.currency,
comment: assetProfile.comment comment: assetProfile.comment
}, },
Account: validatedAccount, Account: validatedAccount,
@ -394,9 +396,9 @@ export class ImportService {
SymbolProfile: { SymbolProfile: {
connectOrCreate: { connectOrCreate: {
create: { create: {
currency,
dataSource, dataSource,
symbol symbol,
currency: assetProfile.currency
}, },
where: { where: {
dataSource_symbol: { dataSource_symbol: {
@ -420,14 +422,14 @@ export class ImportService {
value, value,
feeInBaseCurrency: this.exchangeRateDataService.toCurrency( feeInBaseCurrency: this.exchangeRateDataService.toCurrency(
fee, fee,
currency, assetProfile.currency,
userCurrency userCurrency
), ),
// @ts-ignore // @ts-ignore
SymbolProfile: assetProfile, SymbolProfile: assetProfile,
valueInBaseCurrency: this.exchangeRateDataService.toCurrency( valueInBaseCurrency: this.exchangeRateDataService.toCurrency(
value, value,
currency, assetProfile.currency,
userCurrency userCurrency
) )
}); });

@ -42,6 +42,10 @@ export class CreateOrderDto {
@IsISO4217CurrencyCode() @IsISO4217CurrencyCode()
currency: string; currency: string;
@IsISO4217CurrencyCode()
@IsOptional()
customCurrency?: string;
@IsOptional() @IsOptional()
@IsEnum(DataSource, { each: true }) @IsEnum(DataSource, { each: true })
dataSource?: DataSource; dataSource?: DataSource;

@ -126,13 +126,22 @@ export class OrderController {
@UseGuards(AuthGuard('jwt'), HasPermissionGuard) @UseGuards(AuthGuard('jwt'), HasPermissionGuard)
@UseInterceptors(TransformDataSourceInRequestInterceptor) @UseInterceptors(TransformDataSourceInRequestInterceptor)
public async createOrder(@Body() data: CreateOrderDto): Promise<OrderModel> { public async createOrder(@Body() data: CreateOrderDto): Promise<OrderModel> {
const currency = data.currency;
const customCurrency = data.customCurrency;
if (customCurrency) {
data.currency = customCurrency;
delete data.customCurrency;
}
const order = await this.orderService.createOrder({ const order = await this.orderService.createOrder({
...data, ...data,
date: parseISO(data.date), date: parseISO(data.date),
SymbolProfile: { SymbolProfile: {
connectOrCreate: { connectOrCreate: {
create: { create: {
currency: data.currency, currency,
dataSource: data.dataSource, dataSource: data.dataSource,
symbol: data.symbol symbol: data.symbol
}, },
@ -182,8 +191,16 @@ export class OrderController {
const date = parseISO(data.date); const date = parseISO(data.date);
const accountId = data.accountId; const accountId = data.accountId;
const customCurrency = data.customCurrency;
delete data.accountId; delete data.accountId;
if (customCurrency) {
data.currency = customCurrency;
delete data.customCurrency;
}
return this.orderService.updateOrder({ return this.orderService.updateOrder({
data: { data: {
...data, ...data,

@ -26,6 +26,7 @@ import { endOfToday, isAfter } from 'date-fns';
import { groupBy, uniqBy } from 'lodash'; import { groupBy, uniqBy } from 'lodash';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
import { CreateOrderDto } from './create-order.dto';
import { Activities } from './interfaces/activities.interface'; import { Activities } from './interfaces/activities.interface';
@Injectable() @Injectable()
@ -65,7 +66,6 @@ export class OrderService {
} }
const accountId = data.accountId; const accountId = data.accountId;
let currency = data.currency;
const tags = data.tags ?? []; const tags = data.tags ?? [];
const updateAccountBalance = data.updateAccountBalance ?? false; const updateAccountBalance = data.updateAccountBalance ?? false;
const userId = data.userId; const userId = data.userId;
@ -73,7 +73,6 @@ export class OrderService {
if (['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(data.type)) { if (['FEE', 'INTEREST', 'ITEM', 'LIABILITY'].includes(data.type)) {
const assetClass = data.assetClass; const assetClass = data.assetClass;
const assetSubClass = data.assetSubClass; const assetSubClass = data.assetSubClass;
currency = data.SymbolProfile.connectOrCreate.create.currency;
const dataSource: DataSource = 'MANUAL'; const dataSource: DataSource = 'MANUAL';
const id = uuidv4(); const id = uuidv4();
const name = data.SymbolProfile.connectOrCreate.create.symbol; const name = data.SymbolProfile.connectOrCreate.create.symbol;
@ -81,7 +80,6 @@ export class OrderService {
data.id = id; data.id = id;
data.SymbolProfile.connectOrCreate.create.assetClass = assetClass; data.SymbolProfile.connectOrCreate.create.assetClass = assetClass;
data.SymbolProfile.connectOrCreate.create.assetSubClass = assetSubClass; data.SymbolProfile.connectOrCreate.create.assetSubClass = assetSubClass;
data.SymbolProfile.connectOrCreate.create.currency = currency;
data.SymbolProfile.connectOrCreate.create.dataSource = dataSource; data.SymbolProfile.connectOrCreate.create.dataSource = dataSource;
data.SymbolProfile.connectOrCreate.create.name = name; data.SymbolProfile.connectOrCreate.create.name = name;
data.SymbolProfile.connectOrCreate.create.symbol = id; data.SymbolProfile.connectOrCreate.create.symbol = id;
@ -116,7 +114,6 @@ export class OrderService {
delete data.comment; delete data.comment;
} }
delete data.currency;
delete data.dataSource; delete data.dataSource;
delete data.symbol; delete data.symbol;
delete data.tags; delete data.tags;
@ -155,8 +152,8 @@ export class OrderService {
await this.accountService.updateAccountBalance({ await this.accountService.updateAccountBalance({
accountId, accountId,
amount, amount,
currency,
userId, userId,
currency: data.SymbolProfile.connectOrCreate.create.currency,
date: data.date as Date date: data.date as Date
}); });
} }
@ -442,7 +439,6 @@ export class OrderService {
delete data.assetClass; delete data.assetClass;
delete data.assetSubClass; delete data.assetSubClass;
delete data.currency;
delete data.dataSource; delete data.dataSource;
delete data.symbol; delete data.symbol;
delete data.tags; delete data.tags;

@ -41,6 +41,10 @@ export class UpdateOrderDto {
@IsISO4217CurrencyCode() @IsISO4217CurrencyCode()
currency: string; currency: string;
@IsISO4217CurrencyCode()
@IsOptional()
customCurrency?: string;
@IsString() @IsString()
dataSource: DataSource; dataSource: DataSource;

@ -3,6 +3,7 @@ export const activityDummyData = {
accountUserId: undefined, accountUserId: undefined,
comment: undefined, comment: undefined,
createdAt: new Date(), createdAt: new Date(),
currency: undefined,
feeInBaseCurrency: undefined, feeInBaseCurrency: undefined,
id: undefined, id: undefined,
isDraft: false, isDraft: false,

@ -98,10 +98,6 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
this.data.activity?.SymbolProfile?.currency, this.data.activity?.SymbolProfile?.currency,
Validators.required Validators.required
], ],
currencyOfFee: [
this.data.activity?.SymbolProfile?.currency,
Validators.required
],
currencyOfUnitPrice: [ currencyOfUnitPrice: [
this.data.activity?.SymbolProfile?.currency, this.data.activity?.SymbolProfile?.currency,
Validators.required Validators.required
@ -149,45 +145,16 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
takeUntil(this.unsubscribeSubject) takeUntil(this.unsubscribeSubject)
) )
.subscribe(async () => { .subscribe(async () => {
let exchangeRateOfFee = 1;
let exchangeRateOfUnitPrice = 1; let exchangeRateOfUnitPrice = 1;
this.activityForm.controls['feeInCustomCurrency'].setErrors(null); this.activityForm.controls['feeInCustomCurrency'].setErrors(null);
this.activityForm.controls['unitPriceInCustomCurrency'].setErrors(null); this.activityForm.controls['unitPriceInCustomCurrency'].setErrors(null);
const currency = this.activityForm.controls['currency'].value; const currency = this.activityForm.controls['currency'].value;
const currencyOfFee = this.activityForm.controls['currencyOfFee'].value;
const currencyOfUnitPrice = const currencyOfUnitPrice =
this.activityForm.controls['currencyOfUnitPrice'].value; this.activityForm.controls['currencyOfUnitPrice'].value;
const date = this.activityForm.controls['date'].value; const date = this.activityForm.controls['date'].value;
if (currency && currencyOfFee && currency !== currencyOfFee && date) {
try {
const { marketPrice } = await lastValueFrom(
this.dataService
.fetchExchangeRateForDate({
date,
symbol: `${currencyOfFee}-${currency}`
})
.pipe(takeUntil(this.unsubscribeSubject))
);
exchangeRateOfFee = marketPrice;
} catch {
this.activityForm.controls['feeInCustomCurrency'].setErrors({
invalid: true
});
}
}
const feeInCustomCurrency =
this.activityForm.controls['feeInCustomCurrency'].value *
exchangeRateOfFee;
this.activityForm.controls['fee'].setValue(feeInCustomCurrency, {
emitEvent: false
});
if ( if (
currency && currency &&
currencyOfUnitPrice && currencyOfUnitPrice &&
@ -212,10 +179,18 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
} }
} }
const feeInCustomCurrency =
this.activityForm.controls['feeInCustomCurrency'].value *
exchangeRateOfUnitPrice;
const unitPriceInCustomCurrency = const unitPriceInCustomCurrency =
this.activityForm.controls['unitPriceInCustomCurrency'].value * this.activityForm.controls['unitPriceInCustomCurrency'].value *
exchangeRateOfUnitPrice; exchangeRateOfUnitPrice;
this.activityForm.controls['fee'].setValue(feeInCustomCurrency, {
emitEvent: false
});
this.activityForm.controls['unitPrice'].setValue( this.activityForm.controls['unitPrice'].setValue(
unitPriceInCustomCurrency, unitPriceInCustomCurrency,
{ {
@ -258,7 +233,6 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
})?.currency ?? this.data.user.settings.baseCurrency; })?.currency ?? this.data.user.settings.baseCurrency;
this.activityForm.controls['currency'].setValue(currency); this.activityForm.controls['currency'].setValue(currency);
this.activityForm.controls['currencyOfFee'].setValue(currency);
this.activityForm.controls['currencyOfUnitPrice'].setValue(currency); this.activityForm.controls['currencyOfUnitPrice'].setValue(currency);
if (['FEE', 'INTEREST'].includes(type)) { if (['FEE', 'INTEREST'].includes(type)) {
@ -328,7 +302,6 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
})?.currency ?? this.data.user.settings.baseCurrency; })?.currency ?? this.data.user.settings.baseCurrency;
this.activityForm.controls['currency'].setValue(currency); this.activityForm.controls['currency'].setValue(currency);
this.activityForm.controls['currencyOfFee'].setValue(currency);
this.activityForm.controls['currencyOfUnitPrice'].setValue(currency); this.activityForm.controls['currencyOfUnitPrice'].setValue(currency);
this.activityForm.controls['dataSource'].removeValidators( this.activityForm.controls['dataSource'].removeValidators(
@ -361,7 +334,6 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
})?.currency ?? this.data.user.settings.baseCurrency; })?.currency ?? this.data.user.settings.baseCurrency;
this.activityForm.controls['currency'].setValue(currency); this.activityForm.controls['currency'].setValue(currency);
this.activityForm.controls['currencyOfFee'].setValue(currency);
this.activityForm.controls['currencyOfUnitPrice'].setValue(currency); this.activityForm.controls['currencyOfUnitPrice'].setValue(currency);
this.activityForm.controls['dataSource'].removeValidators( this.activityForm.controls['dataSource'].removeValidators(
@ -486,6 +458,7 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
assetSubClass: this.activityForm.controls['assetSubClass'].value, assetSubClass: this.activityForm.controls['assetSubClass'].value,
comment: this.activityForm.controls['comment'].value, comment: this.activityForm.controls['comment'].value,
currency: this.activityForm.controls['currency'].value, currency: this.activityForm.controls['currency'].value,
customCurrency: this.activityForm.controls['currencyOfUnitPrice'].value,
date: this.activityForm.controls['date'].value, date: this.activityForm.controls['date'].value,
dataSource: this.activityForm.controls['dataSource'].value, dataSource: this.activityForm.controls['dataSource'].value,
fee: this.activityForm.controls['fee'].value, fee: this.activityForm.controls['fee'].value,
@ -549,7 +522,6 @@ export class CreateOrUpdateActivityDialog implements OnDestroy {
) )
.subscribe(({ currency, dataSource, marketPrice }) => { .subscribe(({ currency, dataSource, marketPrice }) => {
this.activityForm.controls['currency'].setValue(currency); this.activityForm.controls['currency'].setValue(currency);
this.activityForm.controls['currencyOfFee'].setValue(currency);
this.activityForm.controls['currencyOfUnitPrice'].setValue(currency); this.activityForm.controls['currencyOfUnitPrice'].setValue(currency);
this.activityForm.controls['dataSource'].setValue(dataSource); this.activityForm.controls['dataSource'].setValue(dataSource);

@ -290,11 +290,7 @@
matTextSuffix matTextSuffix
[ngClass]="{ 'd-none': !activityForm.controls['currency']?.value }" [ngClass]="{ 'd-none': !activityForm.controls['currency']?.value }"
> >
<mat-select formControlName="currencyOfFee"> {{ activityForm.controls['currencyOfUnitPrice'].value }}
<mat-option *ngFor="let currency of currencies" [value]="currency">
{{ currency }}
</mat-option>
</mat-select>
</div> </div>
<mat-error <mat-error
*ngIf=" *ngIf="

@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Order" ADD COLUMN "currency" TEXT;

@ -109,6 +109,7 @@ model Order {
accountUserId String? accountUserId String?
comment String? comment String?
createdAt DateTime @default(now()) createdAt DateTime @default(now())
currency String?
date DateTime date DateTime
fee Float fee Float
id String @id @default(uuid()) id String @id @default(uuid())

Loading…
Cancel
Save