Support multiple expenses in one reimburesement
This commit is contained in:
parent
19f212f283
commit
7fdeb78617
@ -60,12 +60,13 @@ contract Reimbursement is AragonApp {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function add(uint256 amount, address token, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_REIMBURSEMENT_ROLE) {
|
function add(uint256 amount, address token, address recipient, bytes32 hashDigest, uint8 hashFunction, uint8 hashSize) public isInitialized auth(ADD_REIMBURSEMENT_ROLE) {
|
||||||
uint32 reimbursementId = reimbursementsCount + 1;
|
uint32 reimbursementId = reimbursementsCount + 1;
|
||||||
ReimbursementData storage r = reimbursements[reimbursementId];
|
ReimbursementData storage r = reimbursements[reimbursementId];
|
||||||
r.exists = true;
|
r.exists = true;
|
||||||
r.amount = amount;
|
r.amount = amount;
|
||||||
r.token = token;
|
r.token = token;
|
||||||
|
r.recipient = recipient;
|
||||||
r.hashDigest = hashDigest;
|
r.hashDigest = hashDigest;
|
||||||
r.hashFunction = hashFunction;
|
r.hashFunction = hashFunction;
|
||||||
r.hashSize = hashSize;
|
r.hashSize = hashSize;
|
||||||
|
@ -39,7 +39,8 @@ const contractCalls = [
|
|||||||
['Contribution', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-web] Reviewed stuff', url: '' }, { gasLimit: 350000 }]],
|
['Contribution', 'add', [{ contributorId: 2, contributorIpfsHash: 'QmcHzEeAM26HV2zHTf5HnZrCtCtGdEccL5kUtDakAB7ozB', date: '2019-04-11', amount: 1500, kind: 'dev', description: '[67P/kredits-web] Reviewed stuff', url: '' }, { gasLimit: 350000 }]],
|
||||||
['Contribution', 'claim', [1, { gasLimit: 300000 }]],
|
['Contribution', 'claim', [1, { gasLimit: 300000 }]],
|
||||||
|
|
||||||
['Reimbursement', 'add', [{title: 'Server Hosting', description: 'All the serverz', amount: 1, token: '0xa3048576e296207eb0141f2803590ad044f81928', currency: 'WBTC', date: '2020-05-28'}, { gasLimit: 300000 }]],
|
['Reimbursement', 'add', [{amount: 100, recipient: '0x7e8f313c56f809188313aa274fa67ee58c31515d', token: '0xa3048576e296207eb0141f2803590ad044f81928', expenses: [{title: 'Server Hosting', description: 'All the serverz', amount: 100, currency: 'EUR', date: '2020-05-28'}]}, { gasLimit: 300000 }]],
|
||||||
|
['Reimbursement', 'add', [{amount: 10, recipient: '0xa502eb4021f3b9ab62f75b57a94e1cfbf81fd827', token: '0xa3048576e296207eb0141f2803590ad044f81928', expenses: [{title: 'Domain', description: 'All the domain', amount: 10, currency: 'EUR', date: '2020-05-28'}]}, { gasLimit: 300000 }]],
|
||||||
];
|
];
|
||||||
|
|
||||||
const funds = [
|
const funds = [
|
||||||
|
File diff suppressed because one or more lines are too long
@ -9,7 +9,10 @@ class Reimbursement extends Record {
|
|||||||
getById (id) {
|
getById (id) {
|
||||||
return this.functions.get(id)
|
return this.functions.get(id)
|
||||||
.then(data => {
|
.then(data => {
|
||||||
return this.ipfs.catAndMerge(data, ExpenseSerializer.deserialize);
|
return this.ipfs.catAndMerge(data, (ipfsDocument) => {
|
||||||
|
const expenses = JSON.parse(ipfsDocument);
|
||||||
|
return { expenses };
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,26 +21,32 @@ class Reimbursement extends Record {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async add (attrs, callOptions = {}) {
|
async add (attrs, callOptions = {}) {
|
||||||
const reimbursement = new ExpenseSerializer(attrs);
|
const amount = parseInt(attrs.amount);
|
||||||
|
const token = attrs.token;
|
||||||
|
const recipient = attrs.recipient;
|
||||||
|
const expenses = attrs.expenses.map( e => new ExpenseSerializer(e) );
|
||||||
|
|
||||||
try { await reimbursement.validate(); }
|
if (!amount > 0 || !token || token === '' || !recipient || recipient === '' || !expenses.length > 0) {
|
||||||
catch (error) { return Promise.reject(error); }
|
return Promise.reject(new Error('Invalid data. amount, token, expenses is required.'));
|
||||||
|
}
|
||||||
|
|
||||||
const jsonStr = reimbursement.serialize();
|
return Promise.all(expenses.map(e => e.validate()))
|
||||||
|
.then(() => {
|
||||||
|
const jsonStr = JSON.stringify(expenses.map(e => e.data), null, 2);
|
||||||
|
return this.ipfs
|
||||||
|
.add(jsonStr)
|
||||||
|
.then(ipfsHashAttr => {
|
||||||
|
let reimbursement = [
|
||||||
|
amount,
|
||||||
|
token,
|
||||||
|
recipient,
|
||||||
|
ipfsHashAttr.hashDigest,
|
||||||
|
ipfsHashAttr.hashFunction,
|
||||||
|
ipfsHashAttr.hashSize,
|
||||||
|
];
|
||||||
|
|
||||||
return this.ipfs
|
return this.functions.add(...reimbursement, callOptions);
|
||||||
.add(jsonStr)
|
});
|
||||||
.then(ipfsHashAttr => {
|
|
||||||
let reimbursement = [
|
|
||||||
attrs.amount,
|
|
||||||
attrs.token,
|
|
||||||
ipfsHashAttr.hashDigest,
|
|
||||||
ipfsHashAttr.hashFunction,
|
|
||||||
ipfsHashAttr.hashSize,
|
|
||||||
];
|
|
||||||
|
|
||||||
console.log(reimbursement)
|
|
||||||
return this.functions.add(...reimbursement, callOptions);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,11 @@ class Expense {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
serialize () {
|
serialize () {
|
||||||
|
// Write it pretty to ipfs
|
||||||
|
return JSON.stringify(this.data, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
get data () {
|
||||||
let {
|
let {
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
@ -47,8 +52,7 @@ class Expense {
|
|||||||
data['url'] = url;
|
data['url'] = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write it pretty to ipfs
|
return data;
|
||||||
return JSON.stringify(data, null, 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,7 +62,6 @@ class Expense {
|
|||||||
*/
|
*/
|
||||||
validate () {
|
validate () {
|
||||||
const serialized = JSON.parse(this.serialize());
|
const serialized = JSON.parse(this.serialize());
|
||||||
console.log(schemas['expense']);
|
|
||||||
const valid = validator.validate(serialized, schemas['expense']);
|
const valid = validator.validate(serialized, schemas['expense']);
|
||||||
return valid ? Promise.resolve() : Promise.reject(validator.error);
|
return valid ? Promise.resolve() : Promise.reject(validator.error);
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ module.exports = async function(callback) {
|
|||||||
console.log(`Using Reimbursement at: ${kredits.Reimbursement.contract.address}`);
|
console.log(`Using Reimbursement at: ${kredits.Reimbursement.contract.address}`);
|
||||||
|
|
||||||
const table = new Table({
|
const table = new Table({
|
||||||
head: ['ID', 'Title', 'Description', 'Amount', 'Token', 'Recipent', 'Confirmed?', 'Vetoed?', 'Claimed?', 'IPFS']
|
head: ['ID', 'Amount', 'Token', 'Recipent', 'Confirmed?', 'Vetoed?', 'IPFS', 'Expenses']
|
||||||
})
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -24,21 +24,19 @@ module.exports = async function(callback) {
|
|||||||
|
|
||||||
let kreditsSum = 0;
|
let kreditsSum = 0;
|
||||||
console.log(`Current block number: ${blockNumber}`);
|
console.log(`Current block number: ${blockNumber}`);
|
||||||
reimbursements.forEach((r) => {
|
reimbursements.forEach(r => {
|
||||||
const confirmed = r.confirmedAtBlock <= blockNumber;
|
const confirmed = r.confirmedAtBlock <= blockNumber;
|
||||||
|
|
||||||
table.push([
|
table.push([
|
||||||
r.id.toString(),
|
r.id.toString(),
|
||||||
`${r.title}`,
|
|
||||||
`${r.description}`,
|
|
||||||
r.amount.toString(),
|
r.amount.toString(),
|
||||||
`${r.token}`,
|
`${r.token}`,
|
||||||
`${r.recipient}`,
|
`${r.recipient}`,
|
||||||
`${confirmed} (${r.confirmedAtBlock})`,
|
`${confirmed}`,
|
||||||
r.vetoed,
|
`${r.vetoed}`,
|
||||||
r.claimed,
|
`${r.ipfsHash}`,
|
||||||
r.ipfsHash
|
`${r.expenses.length}`
|
||||||
])
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(table.toString());
|
console.log(table.toString());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user