// Import modules import * as async from 'async' // Import interfaces import { DeGiroClassInterface } from './interfaces' // Import types import { DeGiroSettupType, LoginResponseType, AccountConfigType, AccountDataType, CashFoundType, SearchProductResultType, GetPorfolioConfigType, SearchProductOptionsType, OrderType, CreateOrderResultType, IsLoginOptionsType, GetOrdersConfigType, GetOrdersResultType, GetAccountStateOptionsType, AccountReportsType, AccountInfoType, GetHistoricalOrdersOptionsType, HistoricalOrdersType, FavouriteProductType, StockType, GetNewsOptionsType, NewsType, WebUserSettingType, ConfigDictionaryType, i18nMessagesType, WebSettingsType, GetPopularStocksConfigType, GetTransactionsOptionsType, TransactionType, } from './types' // Import requests import { loginRequest, getAccountConfigRequest, getAccountDataRequest, getPortfolioRequest, getProductsByIdsRequest, searchProductRequest, createOrderRequest, executeOrderRequest, deleteOrderRequest, logoutRequest, getOrdersRequest, getAccountStateRequest, getConfigDictionaryRequest, getAccountInfoRequest, getWebi18nMessagesRequest, getNewsRequest, getWebSettingsRequest, getWebUserSettingsRequest, getAccountReportsRequest, getCashFundstRequest, getPopularStocksRequest, getTransactionsRequest, } from './api' import { runInThisContext } from 'vm' /** * @class DeGiro * @description Main class of DeGiro Unofficial API. */ export class DeGiro implements DeGiroClassInterface { /* Properties */ private readonly username: string | undefined private readonly pwd: string | undefined private readonly oneTimePassword: string | undefined private jsessionId: string | undefined private accountConfig: AccountConfigType | undefined private accountData: AccountDataType | undefined /* Constructor and generator function */ constructor(params: DeGiroSettupType = {}) { let { username, pwd, oneTimePassword, jsessionId } = params username = username || process.env['DEGIRO_USER'] pwd = pwd || process.env['DEGIRO_PWD'] oneTimePassword = oneTimePassword || process.env['DEGIRO_OTP'] jsessionId = jsessionId || process.env['DEGIRO_JSESSIONID'] if (!username && !jsessionId) throw new Error('DeGiro api needs an username to access') if (!pwd && !jsessionId) throw new Error('DeGiro api needs an password to access') this.username = username this.pwd = pwd this.oneTimePassword = oneTimePassword this.jsessionId = jsessionId } static create(params: DeGiroSettupType): DeGiro { return new DeGiro(params) } /* Session methods */ login(): Promise { if (this.jsessionId) return this.loginWithJSESSIONID(this.jsessionId) return new Promise((resolve, reject) => { loginRequest({ username: this.username as string, pwd: this.pwd as string, oneTimePassword: this.oneTimePassword, }) .then((loginResponse: LoginResponseType) => { if (!loginResponse.sessionId) reject('Login response have not a sessionId field') else return this.getAccountConfig(loginResponse.sessionId) }) .then(() => this.getAccountData()) .then(resolve) .catch(reject) }) } logout(): Promise { return new Promise((resolve, reject) => { if (!this.accountData || !this.accountConfig) { return reject('You must log in first') } logoutRequest(this.accountData, this.accountConfig) .then(() => { delete this.accountData delete this.accountConfig resolve() }) .catch(reject) }) } isLogin(options?: IsLoginOptionsType): boolean | Promise { if (!options || !options.secure) return this.hasSessionId() && !!this.accountData return new Promise((resolve) => { this.getAccountConfig() .then(() => resolve(true)) .catch(() => resolve(false)) }) } private hasSessionId = (): boolean => !!this.accountConfig && !!this.accountConfig.data && !!this.accountConfig.data.sessionId private loginWithJSESSIONID(jsessionId: string): Promise { return new Promise((resolve, reject) => { this.getAccountConfig(jsessionId) .then(() => this.getAccountData()) .then((accountData) => { this.jsessionId = undefined // Remove the jsessionId to prevent reuse resolve(accountData) }) .catch(reject) }) } getJSESSIONID = () => this.hasSessionId() ? (this.accountConfig).data.sessionId : undefined /* Account methods */ getAccountConfig(sessionId?: string): Promise { return new Promise((resolve, reject) => { if (!sessionId && !this.hasSessionId()) { return reject('You must log in first or provide a JSESSIONID') } getAccountConfigRequest(sessionId || (this.accountConfig).data.sessionId) .then((accountConfig: AccountConfigType) => { this.accountConfig = accountConfig resolve(accountConfig) }) .catch(reject) }) } getAccountData(): Promise { return new Promise((resolve, reject) => { if (!this.hasSessionId()) { return reject('You must log in first') } getAccountDataRequest(this.accountConfig) .then((accountData: AccountDataType) => { this.accountData = accountData resolve(accountData) }) .catch(reject) }) } getAccountState(options: GetAccountStateOptionsType): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getAccountStateRequest(this.accountData, this.accountConfig, options) } getAccountReports(): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getAccountReportsRequest(this.accountData, this.accountConfig) } getAccountInfo(): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getAccountInfoRequest(this.accountData, this.accountConfig) } /* Search methods */ searchProduct(options: SearchProductOptionsType): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return searchProductRequest(options, this.accountData, this.accountConfig) } /* Cash Funds methods */ getCashFunds(): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getCashFundstRequest(this.accountData, this.accountConfig) } /* Porfolio methods */ getPortfolio(config: GetPorfolioConfigType): Promise { return new Promise((resolve, reject) => { if (!this.hasSessionId()) { return reject('You must log in first') } getPortfolioRequest(this.accountData, this.accountConfig, config) .then(portfolio => this.completePortfolioDetails(portfolio, config.getProductDetails || false)) .then(resolve) .catch(reject) }) } private completePortfolioDetails(portfolio: any[], getProductDetails: boolean): Promise { if (!getProductDetails) return Promise.resolve(portfolio) return new Promise((resolve, reject) => { async.map(portfolio, (position, next) => { if (position.positionType !== 'PRODUCT') return next(null, position) this.getProductsByIds([(position.id)]) .then((product) => { position.productData = product[position.id] next(null, position) }) .catch(error => next(error)) // tslint:disable-next-line: align }, (error, portfolio) => { if (error) return reject(error) resolve(portfolio) }) }) } /* Stocks methods */ getFavouriteProducts(): Promise { return new Promise((resolve, reject) => { reject('Method not implemented') }) } getPopularStocks(config: GetPopularStocksConfigType = {}): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getPopularStocksRequest(this.accountData, this.accountConfig, config) } /* Orders methods */ getOrders(config: GetOrdersConfigType): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getOrdersRequest(this.accountData, this.accountConfig, config) } getHistoricalOrders(options: GetHistoricalOrdersOptionsType): Promise { return new Promise((resolve, reject) => { reject('Method not implemented') }) } createOrder(order: OrderType): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return createOrderRequest(order, this.accountData, this.accountConfig) } executeOrder(order: OrderType, executeId: String): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return executeOrderRequest(order, executeId, this.accountData, this.accountConfig) } deleteOrder(orderId: String): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return deleteOrderRequest(orderId, this.accountData, this.accountConfig) } getTransactions(options: GetTransactionsOptionsType): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first'); } return getTransactionsRequest(this.accountData, this.accountConfig, options); } /* Miscellaneous methods */ getProductsByIds(ids: string[]): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getProductsByIdsRequest(ids, this.accountData, this.accountConfig) } getNews(options: GetNewsOptionsType): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getNewsRequest(options, this.accountData, this.accountConfig) } getWebi18nMessages(lang: string = 'es_ES'): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getWebi18nMessagesRequest(lang, this.accountData, this.accountConfig) } getWebSettings(): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getWebSettingsRequest(this.accountData, this.accountConfig) } getWebUserSettings(): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getWebUserSettingsRequest(this.accountData, this.accountConfig) } getConfigDictionary(): Promise { if (!this.hasSessionId()) { return Promise.reject('You must log in first') } return getConfigDictionaryRequest(this.accountData, this.accountConfig) } }