Example #1
0
    bitstamped.getTicker(paidTime, function(err, docs) {
      if (!err && docs.rows && docs.rows.length > 0) {
        var tickerData = docs.rows[0].value;
        var rate = new BigNumber(tickerData.vwap);
        var totalPaid = new BigNumber(invoiceHelper.getTotalPaid(invoice, paymentsArr));
        var remainingBalance = new BigNumber(invoice.balance_due).minus(totalPaid);
        var isUSD = invoice.currency.toUpperCase() === 'USD';
        if (isUSD) {
          var actualPaid = helper.roundToDecimal(rate.times(transaction.amount).valueOf(), 2);
          var closeEnough = new BigNumber(actualPaid).equals(helper.roundToDecimal(remainingBalance, 2));
          if (closeEnough) {
            remainingBalance = transaction.amount;
          }
          else {
            remainingBalance = Number(remainingBalance.dividedBy(rate).valueOf());
          }
        }
        remainingBalance = helper.roundToDecimal(remainingBalance, 8);
        var payment = {
          _id: invoiceId + '_' + transaction.txid,
          invoice_id: invoiceId,
          address: transaction.address,
          amount_paid: Number(transaction.amount),
          expected_amount: Number(remainingBalance),
          block_hash: transaction.blockhash ? transaction.blockhash : null,
          spot_rate: Number(rate.valueOf()), // Exchange rate at time of payment
          created: new Date().getTime(),
          paid_timestamp: paidTime,
          txid: transaction.txid, // Bitcoind txid for transaction
          watched: true,
          type: 'payment'
        };
        payment.status = helper.getPaymentStatus(payment, transaction.confirmations, invoice);

        // New transaction to known address has wallet conflicts. This indicates that 
        // this transaction is a mutated tx of a known payment.
        if (transaction.walletconflicts.length > 0) {
          payment.double_spent_history = transaction.walletconflicts;
          var latestConflictingTx = transaction.walletconflicts[transaction.walletconflicts.length - 1];
          // Need to grab spot rate and expected_amount from conflicting payment
          paymentsArr.forEach(function(curPayment) {
            if (curPayment.txid === latestConflictingTx) {
              payment.expected_amount = curPayment.expected_amount;
              payment.spot_rate = curPayment.spot_rate;
            }
          });
        }
        db.insert(payment, function(err) {
          if (err && err.error === 'conflict' ) {
            console.log('createNewPaymentWithTransaction: Document update conflict: ' + require('util').inspect(err.request.body));
            return cb();
          }
        });
      }
      else {
        return cb(err);
      }
    });
Example #2
0
  db.findInvoiceAndPayments(invoiceId, function(err, invoice, paymentsArr) {
    if (err) {
      return cb(err, null);
    }
    var origInvoice = _.cloneDeep(invoice);
    var paymentHistory = invoicesLib.getPaymentHistory(paymentsArr);
    invoice.payment_history = paymentHistory;

    var isUSD = invoice.currency.toUpperCase() === 'USD';
    invoicesLib.calculateLineTotals(invoice);
    invoicesLib.calculateDiscountTotals(invoice);
    if (!invoice.discounts) {
      invoice.discounts = [];
    }
    invoice.amount_paid = invoicesLib.getTotalPaid(invoice, paymentsArr);
    invoice.balance_due = invoicesLib.getAmountDue(invoice.invoice_total, invoice.amount_paid, invoice.currency);
    invoice.is_expired = false;
    invoice.is_void = invoice.is_void ? invoice.is_void : false;
    invoice.expiration = invoice.expiration ? invoice.expiration : null;
    invoice.text = invoice.text ? invoice.text : null;

    var invoiceExpired = validate.invoiceExpired(invoice);
    invoice.is_expired = invoiceExpired && invoice.balance_due > 0;
    invoice.expiration_time = null;
    if (invoice.expiration && !invoiceExpired && invoice.balance_due > 0) {
      invoice.expiration_time = helper.getExpirationCountDown(invoice.expiration);
    }

    // Is the invoice paid in full?
    var hasPending = false;
    paymentHistory.forEach(function(payment) {
      if(isUSD) {
        var amountUSD = new BigNumber(payment.amount_paid).times(payment.spot_rate);
        amountUSD = helper.roundToDecimal(amountUSD, 2);
        payment.amount_usd = amountUSD;
      }
      payment.url = config.publicURL + '/redirect/txid/' + payment.txid; // populate chain explorer url
      hasPending = payment.status.toLowerCase() === 'pending';
      delete payment._id;
      delete payment._rev;
      delete payment.spot_rate;
    });

    invoice.payment_history = _.sortBy(paymentHistory, function(payment) {
      return payment.created;
    });

    invoice.is_paid = !hasPending && invoice.balance_due <= 0;
    invoice.is_overpaid = !hasPending && invoice.balance_due < 0;

    delete invoice.webhooks;
    delete invoice.metadata;
    delete invoice._rev;
    invoice.demo_mode = config.demoMode || false;
    return cb(null, invoice, origInvoice);
  });
Example #3
0
    it('should calculate the total amount paid', function() {
      var curTime = new Date().getTime();
      var paymentA = { status: 'partial', amount_paid: 0.4, created: (curTime - 10000) };
      var paymentB = { status: 'invalid', amount_paid: 1.5535, created: (curTime - 5000) };
      var paymentC = { status: 'paid', amount_paid: 0.2433, created: curTime };
      var paymentD = { status: 'overpaid', amount_paid: 5.123456789, spot_rate: 400, created: (curTime + 10000) };

      var invoice = { currency: 'BTC' };
      var payments = [ paymentA, paymentB, paymentC, paymentD ];
      assert.equal('5.76675679', invoiceHelper.getTotalPaid(invoice, payments).toString());

      paymentA = { status: 'partial', amount_paid: 0.4, spot_rate: 421, created: (curTime - 10000) };
      paymentB = { status: 'invalid', amount_paid: 1.5535, spot_rate: 411.23, created: (curTime - 5000) };
      paymentC = { status: 'paid', amount_paid: 0.2433, spot_rate: 415.26, created: curTime };
      paymentD = { status: 'overpaid', amount_paid: 5.123456789, spot_rate: 456.43, created: (curTime + 10000) };

      invoice = { currency: 'USD' };
      payments = [ paymentA, paymentB, paymentC, paymentD ];
      assert.equal('2607.93', invoiceHelper.getTotalPaid(invoice, payments).toString());
    });
Example #4
0
  db.findInvoiceAndPayments(invoiceId, function(err, invoice, paymentsArr) {
    if (err) {
      return cb(err, null);
    }
    
    var paymentHistory = invoiceHelper.getPaymentHistory(paymentsArr);
    invoice.payment_history = paymentHistory;

    var isUSD = invoice.currency.toUpperCase() === 'USD';
    invoiceHelper.calculateLineTotals(invoice);
    invoice.total_paid = invoiceHelper.getTotalPaid(invoice, paymentsArr);
    invoice.balance_due = isUSD ? helper.roundToDecimal(invoice.balance_due, 2) : Number(invoice.balance_due);
    invoice.remaining_balance = invoiceHelper.getAmountDue(invoice.balance_due, invoice.total_paid, invoice.currency);

    var invoiceExpired = validate.invoiceExpired(invoice);
    if (invoiceExpired && invoice.remaining_balance > 0) {
      var expiredErr = new Error('Error: Invoice is expired.');
      return cb(expiredErr, null);
    }
    else if (invoice.expiration && !invoiceExpired && invoice.remaining_balance > 0) {
      invoice.expiration_msg = 'Expires: ' + helper.getExpirationCountDown(invoice.expiration);
    }

    // Is the invoice paid in full?
    var hasPending = false;
    paymentHistory.forEach(function(payment) {
      payment.url = config.chainExplorerUrl + '/' + payment.tx_id; // populate chain explorer url
      if(isUSD) {
        var amountUSD = new BigNumber(payment.amount_paid).times(payment.spot_rate);
        amountUSD = helper.roundToDecimal(amountUSD, 2);
        payment.amount_usd = amountUSD;
      }
      if (payment.status.toLowerCase() === 'pending') {
        hasPending = true;
      }
    });

    invoice.is_paid = !hasPending && invoice.remaining_balance <= 0;
    invoice.is_overpaid = !hasPending && invoice.remaining_balance < 0;

    return cb(null, invoice);
  });