diff --git a/lib/plugins.js b/lib/plugins.js index fdcb7e4c..4d530c90 100644 --- a/lib/plugins.js +++ b/lib/plugins.js @@ -306,6 +306,7 @@ exports.dispenseStatus = function dispenseStatus(deviceFingerprint, sessionId, }; exports.dispenseAck = function dispenseAck(deviceFingerprint, tx) { + db.addDispense(deviceFingerprint, tx); }; exports.fiatBalance = function fiatBalance() { diff --git a/lib/postgresql_interface.js b/lib/postgresql_interface.js index c6a044d7..d5289adb 100644 --- a/lib/postgresql_interface.js +++ b/lib/postgresql_interface.js @@ -2,6 +2,7 @@ var pg = require('pg'); var async = require('async'); +var _ = require('lodash'); var logger = require('./logger'); @@ -119,7 +120,7 @@ function billsAndTxs(client, sessionId, cb) { var txQuery = 'SELECT SUM(fiat) AS fiat, SUM(satoshis) AS satoshis ' + 'FROM transactions ' + 'WHERE session_id=$1 AND stage=$2'; - var txValues = [sessionId, 'partialRequest']; + var txValues = [sessionId, 'partial_request']; async.parallel([ async.apply(query, client, billsQuery, billsValues), @@ -223,7 +224,9 @@ function insertTx(client, deviceFingerprint, tx, satoshis, fiat, stage, 'to_address', 'satoshis', 'currency_code', - 'fiat' + 'fiat', + 'tx_hash', + 'error' ]; var values = [ @@ -235,10 +238,16 @@ function insertTx(client, deviceFingerprint, tx, satoshis, fiat, stage, tx.toAddress, satoshis, tx.currencyCode, - fiat + fiat, + tx.txHash, + tx.error ]; - query(client, getInsertQuery('transactions', fields, true), values, cb); + query(client, getInsertQuery('transactions', fields, true), values, + function(err, results) { + if (err) return cb(err); + cb(null, results.rows[0].id); + }); } function addPendingTx(deviceFingerprint, sessionId, @@ -284,6 +293,21 @@ exports.addOutgoingTx = function addOutgoingTx(deviceFingerprint, tx, cb) { }); }; +exports.sentCoins = function sentCoins(tx, satoshis, fee, error, txHash) { + connect(function(err, client, done) { + if (err) return logger.error(err); + + var newTx = _.clone(tx); + newTx.txHash = txHash; + newTx.error = error; + insertTx(client, newTx.deviceFingerprint, newTx, satoshis, newTx.fiat, + 'partial_send', function(_err) { + done(); + if (err) logger.error(_err); + }); + }); +}; + exports.addIncomingTx = function addIncomingTx(deviceFingerprint, tx, source, satoshisReceived, cb) { connect(function(err, client, done) { @@ -331,7 +355,6 @@ exports.addInitialIncoming = function addInitialIncoming(deviceFingerprint, tx, }); }); }); - }; function lastTxStatus(client, deviceFingerprint, sessionId, cb) { @@ -346,7 +369,7 @@ function lastTxStatus(client, deviceFingerprint, sessionId, cb) { function initialRequest(client, deviceFingerprint, sessionId, cb) { var sql = 'SELECT fiat, satoshis FROM transactions ' + 'WHERE device_fingerprint=$1 AND session_id=$2 AND incoming=$3 ' + - 'AND status=$4'; + 'AND stage=$4'; var values = [deviceFingerprint, sessionId, true, 'initial_request']; query(client, sql, values, cb); @@ -368,7 +391,7 @@ exports.dispenseStatus = function dispenseStatus(deviceFingerprint, sessionId, var pending = (results[0].rows.length === 1) && (results[1].rows.length === 1) && - (results[1].rows[0].status == 'deposit'); + (results[1].rows[0].stage == 'deposit'); if (!pending) return cb(null, null); var requiredSatoshis = results[0].rows[0].requiredSatoshis; @@ -381,7 +404,57 @@ exports.dispenseStatus = function dispenseStatus(deviceFingerprint, sessionId, cb(null, status); }); }); +}; +function lastDispenseCount(client, deviceFingerprint, transactionId, cb) { + var sql = 'SELECT count1, count2 FROM dispenses ' + + 'WHERE device_fingerprint=$1 ' + + 'ORDER BY id DESC LIMIT 1'; + client.query(sql, [deviceFingerprint], function(err, results) { + if (err) return cb(err); + if (results.rows.length === 0) return cb(null, [0, 0]); + cb(null, transactionId, [results.rows[0].count1, results.rows[0].count2]); + }); +} + +function insertDispense(client, tx, transactionId, counts, cb) { + var fields = [ + 'transaction_id', + 'dispense1', 'reject1', 'count1', + 'dispense2', 'reject2', 'count2', + 'refill', 'error' + ]; + + var sql = getInsertQuery('dispenses', fields, true); + + var dispense1 = tx.billDistribution[0].actualDispense; + var dispense2 = tx.billDistribution[1].actualDispense; + var reject1 = tx.billDistribution[0].rejected; + var reject2 = tx.billDistribution[1].rejected; + var count1 = Math.max(counts[0] - (dispense1 + reject1), 0); + var count2 = Math.max(counts[1] - (dispense2 + reject2), 0); + var values = [ + transactionId, + dispense1, reject1, count1, dispense2, reject2, count2, + false, tx.error + ]; + client.query(sql, values, cb); +} + +exports.addDispense = function addDispense(deviceFingerprint, tx) { + connect(function(err, client, done) { + if (err) return logger.error(err); + + async.waterfall([ + async.apply(insertTx, client, deviceFingerprint, tx, 0, tx.fiat, + 'deposit', 'authorized'), + async.apply(lastDispenseCount, client, deviceFingerprint), + async.apply(insertDispense, client, tx) + ], function(_err) { + done(); + if (_err) logger.error(err); + }); + }); }; /* diff --git a/migrations/004-transactions-reload.js b/migrations/004-transactions-reload.js index d24803ca..f04ed8bf 100644 --- a/migrations/004-transactions-reload.js +++ b/migrations/004-transactions-reload.js @@ -46,6 +46,7 @@ exports.up = function(next) { 'CREATE TABLE dispenses ( ' + 'id serial PRIMARY KEY, ' + + 'device_fingerprint text NOT NULL, ' + 'transaction_id integer UNIQUE REFERENCES transactions(id), ' + 'dispense1 integer NOT NULL, ' + 'reject1 integer NOT NULL, ' +