feat(txs): support for partial txs and full bill logging

This commit is contained in:
Damian Mee 2014-09-18 02:37:46 +02:00
parent bb4336b78f
commit 55abaa1bb9
3 changed files with 172 additions and 109 deletions

View file

@ -1,6 +1,8 @@
'use strict';
var pg = require('pg');
var async = require('async');
var logger = require('./logger');
var PG_ERRORS = {
@ -55,7 +57,7 @@ exports.recordBill = function recordBill(deviceFingerprint, rec, cb) {
deviceFingerprint,
rec.currency,
rec.toAddress,
res.txId,
rec.txId,
rec.deviceTime,
rec.satoshis,
@ -67,7 +69,18 @@ exports.recordBill = function recordBill(deviceFingerprint, rec, cb) {
fields.push('total_satoshis', 'total_fiat');
}
client.query(getInsertQuery('bills', fields), values, cb);
// NOTE: if is here to maintain compatibility with older machines
if (rec.uuid) {
values.push(rec.uuid);
fields.push('uuid');
}
client.query(getInsertQuery('bills', fields), values, function(err, billInfo) {
if (err && PG_ERRORS[err.code] === 'uniqueViolation')
return cb(null, {code: 304}); // 304 => Not Modified (vel. already noted)
cb(); // 201 => Accepted (vel. saved)
});
};
exports.recordDeviceEvent = function recordDeviceEvent(deviceFingerprint, event, cb) {
@ -101,14 +114,59 @@ exports.getTransactions = function getTransactions(txId, cb) {
_getTransactions(txId, false, cb);
};
// TODO: this should probably return bills, associated with failed/inexistent tx
exports.getPendingTransactions = function getPendingTransactions(txId, cb) {
// should return
// is_completed === false
// amount from bils is less than sum of all parts with the same txId
// latest bill with txId not present in transactions
//
_getTransactions(txId, true, cb);
exports.getPendingAmount = function getPendingAmount(txId, cb) {
async.parallel({
// NOTE: `async.apply()` would strip context here
txs: function(callback) {
client.query(
'SELECT * FROM transactions WHERE id=$1',
[txId],
callback
);
},
bills: function(callback) {
client.query(
'SELECT * FROM bills WHERE transaction_id=$1 ORDER BY created DESC',
[txId],
callback
);
}
}, function(err, results) {
if (err) return cb(err);
// No bills == nothing to do
if (results.bills.rows.length === 0)
return cb();
var lastBill = results.bills.rows[0];
var newTx = {
txId: txId,
satoshis: lastBill.total_satoshis,
fiat: lastBill.total_fiat,
deviceDingerprint: lastBill.device_fingerprint,
toAddress: lastBill.to_address,
currencyCode: lastBill.currency_code
};
// if there are txs, substract already sent amount
if (results.txs.rows.length > 0) {
newTx.part = results.txs.rows.length + 1;
newTx.satoshis = lastBill.total_satoshis;
newTx.fiat = lastBill.total_fiat;
results.txs.rows.forEach(function(tx) {
newTx.satoshis -= tx.satoshis;
newTx.fiat -= tx.fiat;
});
}
// Nothing to send == nothing to do
if (newTx.satoshis <= 0)
return cb();
cb(null, newTx);
});
};
exports.summonTransaction = function summonTransaction(deviceFingerprint, tx, cb) {
@ -144,7 +202,7 @@ exports.summonTransaction = function summonTransaction(deviceFingerprint, tx, cb
function(err) {
if (err) {
if (PG_ERRORS[err.code] === 'uniqueViolation')
return exports.getTransactions(tx.txId, cb);
return _getTransactions(tx.txId, false, cb);
return cb(err);
}
@ -155,6 +213,7 @@ exports.summonTransaction = function summonTransaction(deviceFingerprint, tx, cb
// `@more` can contain `part`, `hash`, or `error`
exports.changeTxStatus = function changeTxStatus(txId, newStatus, more, cb) {
more = more || {};
cb = typeof cb === 'function' ? cb : function() {};
var query = 'UPDATE transactions SET status=$1';
@ -174,8 +233,14 @@ exports.changeTxStatus = function changeTxStatus(txId, newStatus, more, cb) {
values.push(more.hash);
}
query += ' WHERE id=$' + n;
query += ' WHERE id=$' + n++;
values.push(txId);
var part = parseInt(more.part);
if (part > 1) {
query += ' AND part=$' + n++;
values.push(part);
}
client.query(query, values, cb);
};