def importcsv(): form = ImportCSV() if request.method == "POST": if form.validate_on_submit(): if form.submit.data: if form.csvfile.data: test_file = "thewarden/dailydata/test.csv" filename = os.path.join(current_path(), test_file) os.makedirs(os.path.dirname(filename), exist_ok=True) filename = "thewarden/dailydata/" + form.csvfile.data.filename filename = os.path.join(current_path(), filename) form.csvfile.data.save(filename) csv_reader = open(filename, "r", encoding="utf-8") csv_reader = csv.DictReader(csv_reader) csvfile = form.csvfile.data return render_template( "importcsv.html", title="Import CSV File", form=form, csv=csv_reader, csvfile=csvfile, filename=filename, ) if request.method == "GET": filename = request.args.get("f") if filename: csv_reader = open(filename, "r", encoding="utf-8") # csv_reader = csv.DictReader(csv_reader) errors = 0 errorlist = [] a = 0 # skip first line where field names are accounts = AccountInfo.query.filter_by( user_id=current_user.username).order_by( AccountInfo.account_longname) for line in csv_reader: if a != 0: items = line.split(",") random_hex = secrets.token_hex(21) # Check if there is any data on this line: empty = True for l in range(0, 10): try: if items[l] != "": empty = False except IndexError: pass if empty: continue # import TimeStamp Field try: tradedate = parser.parse(items[0]) except ValueError: tradedate = datetime.now() errors = errors + 1 errorlist.append(f"missing date on line: {a}") # Check the Operation Type try: if "B" in items[2]: qop = 1 operation = "B" elif "S" in items[2]: qop = -1 operation = "S" elif "D" in items[2]: qop = 1 operation = "D" elif "W" in items[2]: qop = -1 operation = "W" else: qop = 0 operation = "X" errors = errors + 1 errorlist.append(f"missing operation on line {a}") except IndexError: qop = 0 operation = "X" errors = errors + 1 errorlist.append(f"missing operation on line {a}") # Import Quantity try: if items[4].replace(" ", "") != "": quant = abs(cleancsv(items[4])) * qop else: quant = 0 except ValueError: quant = 0 errors = errors + 1 errorlist.append( f"Quantity error on line {a} - quantity \ {items[4]} could not be converted") # Import Price try: if items[5].replace(" ", "") != "": price = cleancsv(items[5]) else: price = 0 except ValueError: price = 0 errors = errors + 1 errorlist.append(f"Price error on line {a} - price \ {items[5]} could not be converted") # Import Fees try: if items[6].replace(" ", "").replace("\n", "") != "": fees = cleancsv(items[6]) else: fees = 0 except ValueError: fees = 0 errors = errors + 1 errorlist.append( f"error #{errors}: Fee error on line {a} - Fee --\ {items[6]}-- could not be converted") # Import Notes try: notes = items[8] except IndexError: notes = "" # Import Account try: account = items[1] except ValueError: account = "" errors = errors + 1 errorlist.append(f"Missing account on line {a}") # Import Asset Symbol try: ticker = items[3].replace(" ", "") if ticker != "USD": listcrypto = listofcrypto.query.filter_by( symbol=ticker) if listcrypto is None: errors = errors + 1 errorlist.append( f"ticker {ticker} in line {a} \ imported but not found in pricing list") except ValueError: ticker = "" errors = errors + 1 errorlist.append(f"Missing ticker on line {a}") # Find Trade Reference, if none, assign one try: tradeid = items[9] except (ValueError, IndexError): random_hex = secrets.token_hex(21) tradeid = random_hex # Import Cash Value - if none, calculate try: if items[7].replace(" ", "").replace("\n", "") != "": cashvalue = cleancsv(items[7]) else: cashvalue = ((price) * (quant)) + fees except ValueError: cashvalue = 0 errors = errors + 1 errorlist.append( f"error #{errors}: Cash_Value error on line \ {a} - Cash_Value --{items[7]}-- could not \ be converted") trade = Trades( user_id=current_user.username, trade_date=tradedate, trade_account=account, trade_asset_ticker=ticker, trade_quantity=quant, trade_operation=operation, trade_price=price, trade_fees=fees, trade_notes=notes, cash_value=qop * cashvalue, trade_reference_id=tradeid, ) db.session.add(trade) db.session.commit() regenerate_nav() # Check if current account is in list, if not, include curacc = accounts.filter_by( account_longname=account).first() if not curacc: account = AccountInfo(user_id=current_user.username, account_longname=account) db.session.add(account) db.session.commit() a = a + 1 # re-generates the NAV on the background # re-generates the NAV on the background - delete First # the local NAV file so it's not used. usernamehash = hashlib.sha256( current_user.username.encode("utf-8")).hexdigest() filename = "thewarden/nav_data/" + usernamehash + ".nav" filename = os.path.join(current_path(), filename) logging.info(f"[newtrade] {filename} marked for deletion.") # Since this function can be run as a thread, # it's safer to delete the current NAV file if it exists. # This avoids other tasks reading the local file which # is outdated try: os.remove(filename) logging.info("[importcsv] Local NAV file deleted") except OSError: logging.info("[importcsv] Local NAV file not found" + " for removal - continuing") generatenav_thread = threading.Thread(target=generatenav, args=(current_user.username, True)) logging.info("[importcsv] Change to database - generate NAV") generatenav_thread.start() if errors == 0: flash("CSV Import successful", "success") if errors > 0: logging.error("Errors found. Total of ", errors) flash( "CSV Import done but with errors\ - CHECK TRANSACTION LIST", "danger", ) for error in errorlist: flash(error, "warning") return redirect(url_for("main.home")) return render_template("importcsv.html", title="Import CSV File", form=form)
def custody_account(): form = Custody_Account() title = form_title = "Custody Account" if form.validate_on_submit(): id = request.args.get("id") account_name = request.args.get("name") if id: account = ( AccountInfo.query.filter_by(user_id=current_user.username) .filter_by(account_id=id) .first() ) if account_name: account = ( AccountInfo.query.filter_by(user_id=current_user.username) .filter_by(account_longname=account_name) .first() ) if id or account_name: if account == None: account = AccountInfo() account.user_id = current_user.username account.account_blockchain_id = form.account_blockchain_id.data account.account_longname = form.account_longname.data account.check_method = form.check_method.data account.auto_check = form.auto_check.data account.notes = form.notes.data db.session.commit() # Make sure address is registered with Dojo at = dojo_get_settings()["token"] reg = dojo_add_hd(account.account_blockchain_id, "restore", at) if "error" in reg: flash( f"Something went wrong when registering this address to your Dojo. \ It was added to the database but you may want to check your connection. Error: {reg}", "danger", ) return redirect(url_for("node.bitcoin_monitor")) flash("Account edited", "success") return redirect(url_for("node.bitcoin_monitor")) account = AccountInfo( user_id=current_user.username, account_longname=form.account_longname.data, check_method=form.check_method.data, auto_check=form.auto_check.data, account_blockchain_id=form.account_blockchain_id.data, notes=form.notes.data, ) try: db.session.add(account) db.session.commit() # Import this address into the Dojo database at = dojo_get_settings()["token"] # Register this new address reg = dojo_add_hd(account.account_blockchain_id, "restore", at) if "error" in reg: flash( f"Something went wrong when registering this address to your Dojo. \ It was added to the database but you may want to check your connection. Error: {reg}", "danger", ) return redirect(url_for("node.bitcoin_monitor")) flash(f"Address included.", "success") except Exception as e: flash( f"Account not included. Something went wrong. Try again. | Error Message: {e}", "danger", ) return redirect(url_for("node.bitcoin_monitor")) elif request.method == "GET": title = form_title = "New Custody Account" form.auto_check.data = True id = request.args.get("id") account = None account_name = request.args.get("name") if id: account = ( AccountInfo.query.filter_by(user_id=current_user.username) .filter_by(account_id=id) .first() ) if account_name: account = ( AccountInfo.query.filter_by(user_id=current_user.username) .filter_by(account_longname=account_name) .first() ) if not account: title = form_title = "Include Custody Account Info" form.account_longname.data = account_name if account != None: title = form_title = "Edit Custody Account Info" form.account_longname.data = account.account_longname form.check_method.data = account.check_method form.auto_check.data = account.auto_check form.account_blockchain_id.data = account.account_blockchain_id form.notes.data = account.notes return render_template( "custody_account.html", form=form, form_title=form_title, title=title )