Introduce budget, reimbursements for expenses #195

Merged
raucao merged 57 commits from feature/expenses into master 2021-06-03 14:23:45 +00:00
7 changed files with 72 additions and 52 deletions
Showing only changes of commit 25b2a8b0e5 - Show all commits
@@ -10,6 +10,7 @@ import isValidAmount from 'kredits-web/utils/is-valid-amount';
export default class AddReimbursementComponent extends Component {
@service kredits;
@service exchangeRates;
@alias('kredits.contributorsSorted') contributors;
@@ -19,6 +20,11 @@ export default class AddReimbursementComponent extends Component {
@tracked expenses = A([]);
@tracked expenseFormVisible = true;
constructor() {
super(...arguments);
this.exchangeRates.fetchRates();
}
get isValidTotal () {
return isValidAmount(this.total);
}
@@ -1,3 +1,6 @@
<p>
{{this.exchangeRates.btceur}}, {{this.exchangeRates.btcusd}}
</p>
<form onsubmit={{action "submit"}} novalidate>
<label>
<p class="label">Contributor:</p>
+29
View File
@@ -0,0 +1,29 @@
import Service from '@ember/service';
import { tracked } from '@glimmer/tracking';
import config from 'kredits-web/config/environment';
// Need to go through proxy for CORS headers
const bitstampBaseUrl = `${config.corsProxy}https://www.bitstamp.net/api/v2`;
async function fetchFromBitstamp(currencyPair) {
try {
const res = await fetch(`${bitstampBaseUrl}/ticker/${currencyPair}/`).then(r => r.json());
return res.vwap; // Last 24 hours volume weighted average price
} catch(e) {
galfert commented 2020-11-13 16:05:44 +00:00 (Migrated from github.com)
Review

Same as the comment in the community-funds service. This should probably check if the response is ok.

Same as the comment in the `community-funds` service. This should probably check if the response is ok.
raucao commented 2020-11-17 11:49:20 +00:00 (Migrated from github.com)
Review

If it is not OK, then this already just gracefully fails by not automatically converting numbers.

If it is not OK, then this already just gracefully fails by not automatically converting numbers.
console.error('Could not fetch exchange rate from Bitstamp:', e);
return 0;
}
}
export default class ExchangeRatesService extends Service {
@tracked btceur = 0;
@tracked btcusd = 0;
async fetchRates (source='bitstamp') {
switch(source) {
case 'bitstamp':
this.btceur = await fetchFromBitstamp('btceur');
this.btcusd = await fetchFromBitstamp('btcusd');
}
}
}
-20
View File
@@ -1,20 +0,0 @@
const bitstampBaseUrl = 'https://www.bitstamp.net/api/v2';
async function fetchFromBitstamp(currencyPair) {
try {
const res = await fetch(`${bitstampBaseUrl}/ticker/${currencyPair}/`).then(r => r.json());
return res.vwap; // Last 24 hours volume weighted average price
} catch(e) {
console.error('Could not fetch exchange rate from Bitstamp:', e);
return 0;
}
}
export default function fetchExchangeRate(currencyPair, source='bitstamp') {
if (!currencyPair) throw 'Currency pair required';
switch(source) {
case 'bitstamp':
return fetchFromBitstamp(currencyPair);
}
}
+5 -1
View File
@@ -55,7 +55,9 @@ module.exports = function(environment) {
gnosisSafe: {
txServiceHost: 'https://safe-transaction.mainnet.gnosis.io',
address: '0x9CC29b8373FF92B01C1f09F31B5DD862350c167E'
}
},
corsProxy: 'https://cors.5apps.com/?uri='
};
if (environment === 'development') {
@@ -75,6 +77,8 @@ module.exports = function(environment) {
protocol: 'http',
gatewayUrl: 'http://localhost:8080/ipfs'
};
ENV.corsProxy = 'https://cors-anywhere.herokuapp.com/';
}
if (environment === 'test') {
@@ -0,0 +1,29 @@
import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';
import config from 'kredits-web/config/environment';
import fetchMock from 'fetch-mock';
const corsProxy = config.corsProxy;
fetchMock.get(`${corsProxy}https://www.bitstamp.net/api/v2/ticker/btceur/`, {
"high": "9258.43", "last": "9165.14", "timestamp": "1601455909", "bid":
"9159.93", "vwap": "9167.57", "volume": "1542.54764854", "low": "9080.20",
"ask": "9165.14", "open": "9240.84"
});
fetchMock.get(`${corsProxy}https://www.bitstamp.net/api/v2/ticker/btcusd/`, {
"high": "10865.00", "last": "10714.62", "timestamp": "1601455914", "bid":
"10711.31", "vwap": "10749.70", "volume": "4460.32091975", "low": "10636.66",
"ask": "10715.99", "open": "10840.00"
});
module('Unit | Service | exchange-rates', function(hooks) {
setupTest(hooks);
test('#fetchRates', async function(assert) {
let service = this.owner.lookup('service:exchange-rates');
await service.fetchRates();
assert.equal(service.btceur, 9167.57, 'fetches BTCEUR from Bitstamp');
assert.equal(service.btcusd, 10749.70, 'fetches BTCUSD from Bitstamp');
});
});
@@ -1,31 +0,0 @@
import fetchExchangeRate from 'kredits-web/utils/fetch-exchange-rate';
import { module, test } from 'qunit';
import fetchMock from 'fetch-mock';
fetchMock.get('https://www.bitstamp.net/api/v2/ticker/btceur/', {
"high": "9258.43", "last": "9165.14", "timestamp": "1601455909", "bid":
"9159.93", "vwap": "9167.57", "volume": "1542.54764854", "low": "9080.20",
"ask": "9165.14", "open": "9240.84"
});
fetchMock.get('https://www.bitstamp.net/api/v2/ticker/btcusd/', {
"high": "10865.00", "last": "10714.62", "timestamp": "1601455914", "bid":
"10711.31", "vwap": "10749.70", "volume": "4460.32091975", "low": "10636.66",
"ask": "10715.99", "open": "10840.00"
});
module('Unit | Utility | fetch-exchange-rate', function() {
test('it requires a currency pair', function(assert) {
assert.throws(fetchExchangeRate);
});
test('it fetches BTCEUR from Bitstamp', async function(assert) {
let result = await fetchExchangeRate('btceur');
assert.equal(result, 9167.57, 'returns 24-hour volume-weighted average price');
});
test('it fetches BTCUSD from Bitstamp', async function(assert) {
let result = await fetchExchangeRate('btcusd');
assert.equal(result, 10749.70, 'returns 24-hour volume-weighted average price');
});
});