save invoices
This commit is contained in:
parent
2bbcae449c
commit
513f9c2d89
|
@ -181,7 +181,8 @@ class ElectrumGui:
|
||||||
return
|
return
|
||||||
|
|
||||||
def payment_request():
|
def payment_request():
|
||||||
self.payment_request = paymentrequest.PaymentRequest(request_url)
|
self.payment_request = paymentrequest.PaymentRequest(self.config)
|
||||||
|
self.payment_request.read(request_url)
|
||||||
if self.payment_request.verify():
|
if self.payment_request.verify():
|
||||||
self.main_window.emit(SIGNAL('payment_request_ok'))
|
self.main_window.emit(SIGNAL('payment_request_ok'))
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -129,6 +129,7 @@ class ElectrumWindow(QMainWindow):
|
||||||
tabs.addTab(self.create_send_tab(), _('Send') )
|
tabs.addTab(self.create_send_tab(), _('Send') )
|
||||||
tabs.addTab(self.create_receive_tab(), _('Receive') )
|
tabs.addTab(self.create_receive_tab(), _('Receive') )
|
||||||
tabs.addTab(self.create_contacts_tab(), _('Contacts') )
|
tabs.addTab(self.create_contacts_tab(), _('Contacts') )
|
||||||
|
tabs.addTab(self.create_invoices_tab(), _('Invoices') )
|
||||||
tabs.addTab(self.create_console_tab(), _('Console') )
|
tabs.addTab(self.create_console_tab(), _('Console') )
|
||||||
tabs.setMinimumSize(600, 400)
|
tabs.setMinimumSize(600, 400)
|
||||||
tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
tabs.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
|
@ -468,6 +469,7 @@ class ElectrumWindow(QMainWindow):
|
||||||
self.update_receive_tab()
|
self.update_receive_tab()
|
||||||
self.update_contacts_tab()
|
self.update_contacts_tab()
|
||||||
self.update_completions()
|
self.update_completions()
|
||||||
|
self.update_invoices_tab()
|
||||||
|
|
||||||
|
|
||||||
def create_history_tab(self):
|
def create_history_tab(self):
|
||||||
|
@ -808,7 +810,7 @@ class ElectrumWindow(QMainWindow):
|
||||||
if addr is None or not bitcoin.is_address(addr):
|
if addr is None or not bitcoin.is_address(addr):
|
||||||
QMessageBox.warning(self, _('Error'), _('Invalid Bitcoin Address'), _('OK'))
|
QMessageBox.warning(self, _('Error'), _('Invalid Bitcoin Address'), _('OK'))
|
||||||
return
|
return
|
||||||
if type(x) is not int:
|
if x is None:
|
||||||
QMessageBox.warning(self, _('Error'), _('Invalid Amount'), _('OK'))
|
QMessageBox.warning(self, _('Error'), _('Invalid Amount'), _('OK'))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -912,6 +914,7 @@ class ElectrumWindow(QMainWindow):
|
||||||
|
|
||||||
def prepare_for_payment_request(self):
|
def prepare_for_payment_request(self):
|
||||||
self.tabs.setCurrentIndex(1)
|
self.tabs.setCurrentIndex(1)
|
||||||
|
self.payto_e.is_pr = True
|
||||||
for e in [self.payto_e, self.amount_e, self.message_e]:
|
for e in [self.payto_e, self.amount_e, self.message_e]:
|
||||||
e.setFrozen(True)
|
e.setFrozen(True)
|
||||||
for h in [self.payto_help, self.amount_help, self.message_help]:
|
for h in [self.payto_help, self.amount_help, self.message_help]:
|
||||||
|
@ -921,6 +924,13 @@ class ElectrumWindow(QMainWindow):
|
||||||
|
|
||||||
def payment_request_ok(self):
|
def payment_request_ok(self):
|
||||||
pr = self.gui_object.payment_request
|
pr = self.gui_object.payment_request
|
||||||
|
pr_id = pr.get_id()
|
||||||
|
# save it
|
||||||
|
invoices = self.wallet.storage.get('invoices', {})
|
||||||
|
invoices[pr_id] = (pr.get_domain(), pr.get_amount())
|
||||||
|
invoices = self.wallet.storage.put('invoices', invoices)
|
||||||
|
self.update_invoices_tab()
|
||||||
|
|
||||||
self.payto_help.show()
|
self.payto_help.show()
|
||||||
self.payto_help.set_alt(pr.status)
|
self.payto_help.set_alt(pr.status)
|
||||||
self.payto_e.setGreen()
|
self.payto_e.setGreen()
|
||||||
|
@ -952,6 +962,7 @@ class ElectrumWindow(QMainWindow):
|
||||||
|
|
||||||
|
|
||||||
def do_clear(self):
|
def do_clear(self):
|
||||||
|
self.payto_e.is_pr = False
|
||||||
self.payto_sig.setVisible(False)
|
self.payto_sig.setVisible(False)
|
||||||
for e in [self.payto_e, self.message_e, self.amount_e, self.fee_e]:
|
for e in [self.payto_e, self.message_e, self.amount_e, self.fee_e]:
|
||||||
e.setText('')
|
e.setText('')
|
||||||
|
@ -1049,6 +1060,30 @@ class ElectrumWindow(QMainWindow):
|
||||||
return w
|
return w
|
||||||
|
|
||||||
|
|
||||||
|
def create_invoices_tab(self):
|
||||||
|
l,w,hbox = self.create_list_tab([_('Recipient'), _('Amount'), _('Status')])
|
||||||
|
l.setContextMenuPolicy(Qt.CustomContextMenu)
|
||||||
|
#l.customContextMenuRequested.connect(self.create_contact_menu)
|
||||||
|
#self.connect(l, SIGNAL('itemDoubleClicked(QTreeWidgetItem*, int)'), lambda a, b: self.address_label_clicked(a,b,l,0,1))
|
||||||
|
#self.connect(l, SIGNAL('itemChanged(QTreeWidgetItem*, int)'), lambda a,b: self.address_label_changed(a,b,l,0,1))
|
||||||
|
self.invoices_list = l
|
||||||
|
hbox.addStretch(1)
|
||||||
|
return w
|
||||||
|
|
||||||
|
def update_invoices_tab(self):
|
||||||
|
invoices = self.wallet.storage.get('invoices', {})
|
||||||
|
l = self.invoices_list
|
||||||
|
l.clear()
|
||||||
|
|
||||||
|
for item, value in invoices.items():
|
||||||
|
domain, amount = value
|
||||||
|
item = QTreeWidgetItem( [ domain, self.format_amount(amount), ""] )
|
||||||
|
l.addTopLevelItem(item)
|
||||||
|
|
||||||
|
l.setCurrentItem(l.topLevelItem(0))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def delete_imported_key(self, addr):
|
def delete_imported_key(self, addr):
|
||||||
if self.question(_("Do you want to remove")+" %s "%addr +_("from your wallet?")):
|
if self.question(_("Do you want to remove")+" %s "%addr +_("from your wallet?")):
|
||||||
self.wallet.delete_imported_key(addr)
|
self.wallet.delete_imported_key(addr)
|
||||||
|
|
|
@ -42,6 +42,7 @@ class PayToEdit(QTextEdit):
|
||||||
self.c = None
|
self.c = None
|
||||||
self.textChanged.connect(self.check_text)
|
self.textChanged.connect(self.check_text)
|
||||||
self.outputs = []
|
self.outputs = []
|
||||||
|
self.is_pr = False
|
||||||
|
|
||||||
def lock_amount(self):
|
def lock_amount(self):
|
||||||
self.amount_edit.setFrozen(True)
|
self.amount_edit.setFrozen(True)
|
||||||
|
@ -54,8 +55,10 @@ class PayToEdit(QTextEdit):
|
||||||
self.setStyleSheet(frozen_style if b else normal_style)
|
self.setStyleSheet(frozen_style if b else normal_style)
|
||||||
|
|
||||||
def setGreen(self):
|
def setGreen(self):
|
||||||
|
self.is_pr = True
|
||||||
self.setStyleSheet("QWidget { background-color:#00ff00;}")
|
self.setStyleSheet("QWidget { background-color:#00ff00;}")
|
||||||
|
|
||||||
|
|
||||||
def parse_address_and_amount(self, line):
|
def parse_address_and_amount(self, line):
|
||||||
x, y = line.split(',')
|
x, y = line.split(',')
|
||||||
address = self.parse_address(x)
|
address = self.parse_address(x)
|
||||||
|
@ -77,6 +80,9 @@ class PayToEdit(QTextEdit):
|
||||||
|
|
||||||
|
|
||||||
def check_text(self):
|
def check_text(self):
|
||||||
|
if self.is_pr:
|
||||||
|
return
|
||||||
|
|
||||||
# filter out empty lines
|
# filter out empty lines
|
||||||
lines = filter( lambda x: x, self.lines())
|
lines = filter( lambda x: x, self.lines())
|
||||||
outputs = []
|
outputs = []
|
||||||
|
|
|
@ -18,6 +18,7 @@ import urlparse
|
||||||
import requests
|
import requests
|
||||||
from M2Crypto import X509
|
from M2Crypto import X509
|
||||||
|
|
||||||
|
import bitcoin
|
||||||
from bitcoin import is_valid
|
from bitcoin import is_valid
|
||||||
import urlparse
|
import urlparse
|
||||||
|
|
||||||
|
@ -29,6 +30,15 @@ import transaction
|
||||||
REQUEST_HEADERS = {'Accept': 'application/bitcoin-paymentrequest', 'User-Agent': 'Electrum'}
|
REQUEST_HEADERS = {'Accept': 'application/bitcoin-paymentrequest', 'User-Agent': 'Electrum'}
|
||||||
ACK_HEADERS = {'Content-Type':'application/bitcoin-payment','Accept':'application/bitcoin-paymentack','User-Agent':'Electrum'}
|
ACK_HEADERS = {'Content-Type':'application/bitcoin-payment','Accept':'application/bitcoin-paymentack','User-Agent':'Electrum'}
|
||||||
|
|
||||||
|
# status can be:
|
||||||
|
PR_UNPAID = 0
|
||||||
|
PR_EXPIRED = 1
|
||||||
|
PR_SENT = 2 # sent but not propagated
|
||||||
|
PR_PAID = 3 # send and propagated
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ca_path = os.path.expanduser("~/.electrum/ca/ca-bundle.crt")
|
ca_path = os.path.expanduser("~/.electrum/ca/ca-bundle.crt")
|
||||||
ca_list = {}
|
ca_list = {}
|
||||||
try:
|
try:
|
||||||
|
@ -52,32 +62,52 @@ except Exception:
|
||||||
|
|
||||||
class PaymentRequest:
|
class PaymentRequest:
|
||||||
|
|
||||||
def __init__(self, url):
|
def __init__(self, config):
|
||||||
self.url = url
|
self.config = config
|
||||||
self.outputs = []
|
self.outputs = []
|
||||||
self.error = ""
|
self.error = ""
|
||||||
|
|
||||||
|
def read(self, url):
|
||||||
|
self.url = url
|
||||||
|
|
||||||
def verify(self):
|
u = urlparse.urlparse(url)
|
||||||
u = urlparse.urlparse(self.url)
|
|
||||||
self.domain = u.netloc
|
self.domain = u.netloc
|
||||||
|
|
||||||
try:
|
try:
|
||||||
connection = httplib.HTTPConnection(u.netloc) if u.scheme == 'http' else httplib.HTTPSConnection(u.netloc)
|
connection = httplib.HTTPConnection(u.netloc) if u.scheme == 'http' else httplib.HTTPSConnection(u.netloc)
|
||||||
connection.request("GET",u.geturl(), headers=REQUEST_HEADERS)
|
connection.request("GET",u.geturl(), headers=REQUEST_HEADERS)
|
||||||
resp = connection.getresponse()
|
response = connection.getresponse()
|
||||||
except:
|
except:
|
||||||
self.error = "cannot read url"
|
self.error = "cannot read url"
|
||||||
return
|
return
|
||||||
|
|
||||||
paymntreq = paymentrequest_pb2.PaymentRequest()
|
|
||||||
try:
|
try:
|
||||||
r = resp.read()
|
r = response.read()
|
||||||
paymntreq.ParseFromString(r)
|
except:
|
||||||
|
self.error = "cannot read"
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.data = paymentrequest_pb2.PaymentRequest()
|
||||||
|
self.data.ParseFromString(r)
|
||||||
except:
|
except:
|
||||||
self.error = "cannot parse payment request"
|
self.error = "cannot parse payment request"
|
||||||
return
|
return
|
||||||
|
|
||||||
|
self.id = bitcoin.sha256(r)[0:16].encode('hex')
|
||||||
|
print self.id
|
||||||
|
|
||||||
|
dir_path = os.path.join( self.config.path, 'requests')
|
||||||
|
if not os.path.exists(dir_path):
|
||||||
|
os.mkdir(dir_path)
|
||||||
|
filename = os.path.join(dir_path, self.id)
|
||||||
|
with open(filename,'w') as f:
|
||||||
|
f.write(r)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def verify(self):
|
||||||
|
paymntreq = self.data
|
||||||
sig = paymntreq.signature
|
sig = paymntreq.signature
|
||||||
if not sig:
|
if not sig:
|
||||||
self.error = "No signature"
|
self.error = "No signature"
|
||||||
|
@ -187,6 +217,14 @@ class PaymentRequest:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def get_amount(self):
|
||||||
|
return sum(map(lambda x:x[1], self.outputs))
|
||||||
|
|
||||||
|
def get_domain(self):
|
||||||
|
return self.domain
|
||||||
|
|
||||||
|
def get_id(self):
|
||||||
|
return self.id
|
||||||
|
|
||||||
def send_ack(self, raw_tx, refund_addr):
|
def send_ack(self, raw_tx, refund_addr):
|
||||||
|
|
||||||
|
@ -228,7 +266,6 @@ class PaymentRequest:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in New Issue