コード例 #1
0
def invalidate_cache(flash_message=True):
    logging.info('Invalidating cache.')
    if request.method == 'POST':
        Data.invalidate_cache()
        if flash_message:
            flash('Cache was successfully invalidated.', 'info')
    return _standard_render()
コード例 #2
0
ファイル: data.py プロジェクト: MaksimDan/self-finance
def data_upload():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash(f'No file provided.', 'warning')
        else:
            f = request.files['file']
            fn = secure_filename(f.filename)
            if not f or not fn.endswith('.csv'):
                flash('Not an identified CSV file.', 'warning')
            else:
                try:
                    stream = io.StringIO(f.stream.read().decode("UTF8"),
                                         newline=None)
                    stream.seek(0)
                    input_df = pd.read_csv(stream, index_col=False)
                    # TODO - necessary?
                    # input_df = Data.cast_df_to_schema(input_df, Schema.BANK_TB_NAME)
                    Data.merge(input_df)
                    update_html_df()
                    # to ensure visuals and insights take in the most up to date information
                    invalidate_cache(flash=False)
                    refresh_dynamic_insights()
                    refresh_static_insights(ignore_clock=True)
                except IOError as e:
                    flash(f'Unable to parse file. {e}', 'warning')
                flash('Awesome! File processed successfully.', 'success')
    return _standard_render()
コード例 #3
0
def update_transaction_history():
    mrtd_org = Data.get_most_recent_transaction_date(BankSchema.BANK_TB_NAME, files['base_db'])
    mrtd = BankSchema.DATE_FORMAT.format(dateparser.parse(mrtd_org).date()) if mrtd_org else BankSchema.DATE_FORMAT.format(
        datetime.date.min)

    # update on transactions only following the mrtd
    start_date, end_date = mrtd, BankSchema.DATE_FORMAT.format(datetime.datetime.now())
    full_df = get_transactions(start_date, end_date)

    # TODO - this stuff isn't getting flashed
    p1 = 'Successfully updated your bank to the latest transaction history.'
    p2 = '\nNo previous data was found in your database so your entire transactions history was applied.'
    p3 = f'\nFrom date {str(start_date)} to {str(end_date)}.'
    p4 = f'No new transactions have been found.'
    try:
        if full_df is None or full_df.shape[0] == 0:
            flash(p4, 'info')
            return _standard_render()
        logger.info(f'Merging transactions into {BankSchema.BANK_TB_NAME} database.')
        Data.merge(full_df, files['base_db'])
        if not mrtd_org:
            flash(p1 + p2, 'info')
        else:
            flash(p1 + p3, 'info')
    except Exception as e:
        flash(e, 'warning')

    # update data-state on /date end
    if full_df is not None and full_df.shape[0] > 0:
        # note: need to run from `as_html_form_from_sql` because of the
        # additional preprocessing that is handled in merge operation
        update_html_df()
        refresh_static_insights()
        refresh_dynamic_insights()
    return _standard_render()
コード例 #4
0
    def cli_user_populate_missing_categories(
            self, auto_fill_with_model_suggestion=False):
        """
        obj: have the user manually update missing columns, and update the db accordingly.
        this is not used by the flask application itself. it is a command line utility
        """
        missing_cat_df = Data.get_missing_categories()
        if len(missing_cat_df) == 0:
            logger.info('No rows identified to categorize.')
            return

        model_c1 = self.classifier.get_model(BankSchema.BASE_MODEL_C1_NAME)
        model_c2 = self.classifier.get_model(BankSchema.BASE_MODEL_C2_NAME)
        user_c1_cats, user_c2_cats = [], []
        if not auto_fill_with_model_suggestion:
            print(">> Current Categories::")
            print(
                ">> " +
                pprint.pformat(self.get_current_unique_categories(), indent=4))
            print(
                ">> Note: press enter to take suggestion, or 'none' for no category",
                end='\n\n')

        bar = ProgressBar()
        for index in bar(range(missing_cat_df.shape[0])):
            row = missing_cat_df.iloc[index]
            print(">>\n" +
                  tabulate(row.to_frame().T, headers='keys', tablefmt='psql'))
            suggestion_c1 = model_c1.predict(row[
                Data.get_missing_categories()].values) if model_c1 else None
            suggestion_c2 = model_c2.predict(row[
                Data.get_missing_categories()].values) if model_c2 else None

            category_c1, category_c2 = None, None
            if not auto_fill_with_model_suggestion:
                if suggestion_c1:
                    print(f">> Suggestion c1: {suggestion_c1}")
                category_c1 = input(
                    '>> Enter Expense super category: ').lower().strip()
                if suggestion_c2:
                    print(f">> Suggestion c2: {suggestion_c2}")
                category_c2 = input(
                    '>> Enter Expense secondary category: ').lower().strip()
                category_c1 = None if category_c1 == 'none' else category_c1
                category_c2 = None if category_c2 == 'none' else category_c2
                print('\n\n')

            user_c1_cats.append(category_c1 if bool(category_c1)
                                or not suggestion_c1 else suggestion_c1)
            user_c2_cats.append(category_c2 if bool(category_c2)
                                or not suggestion_c2 else suggestion_c2)

        pk_fields, cat_fields = BankSchema.get_pk_fields(
        ), BankSchema.get_table_chase_y_fields()
        filled_cat_df = missing_cat_df[pk_fields]
        pd.options.mode.chained_assignment = None
        filled_cat_df[cat_fields[0]] = user_c1_cats
        filled_cat_df[cat_fields[1]] = user_c2_cats
        Data.update_missing_categories(filled_cat_df.to_dict('records'),
                                       pk_fields, cat_fields)
コード例 #5
0
ファイル: data.py プロジェクト: MaksimDan/self-finance
def data_truncate():
    if request.method == 'POST':
        Data.truncate_all_tables()
        DataState.html_df = None
        invalidate_cache(flash=False)
        refresh_dynamic_insights()
        refresh_static_insights(ignore_clock=True)
        flash(
            f"{BankSchema.BANK_TB_NAME} table has been fully truncated from the base database.",
            'info')
    return _standard_render()
コード例 #6
0
ファイル: data.py プロジェクト: MaksimDan/self-finance
def data_update():
    if request.method == 'POST':
        form = request.form
        update_df = pd.read_html(form['hidden_post_name'],
                                 header=0,
                                 index_col=0,
                                 parse_dates=True)[0]
        update_df = Data.cast_df_to_schema(update_df, BankSchema.BANK_TB_NAME)
        Data.merge(update_df)
        update_html_df()
        invalidate_cache(flash=False)
        refresh_dynamic_insights()
        refresh_static_insights(ignore_clock=True)
        flash('Data updated with new csv.', 'info')
    return _standard_render()
コード例 #7
0
        def get_money_gain_and_spent_this_month_vs_last_month(
                date_range,
                table_name,
                _overide_month=None,
                as_dataframe=False,
                db_path=files['base_db']):
            df = Data.get_table_as_df(date_range, table_name, db_path=db_path)
            if df is None or df.shape[0] == 0:
                return None
            df[BankSchema.SCHEMA_BANK_DATE.name] = pd.to_datetime(
                df[BankSchema.SCHEMA_BANK_DATE.name])
            this_month = _overide_month or datetime.date.today().month
            last_month = this_month - 1 or 12

            inc_this_month, exp_this_month = RawInsights.Static._agg_income_and_expenses_by_month(
                df, this_month)
            sum_income_last_month, exp_last_month = RawInsights.Static._agg_income_and_expenses_by_month(
                df, last_month)
            as_dict = {
                'inc_this_month': "{0:.2f}".format(inc_this_month),
                'exp_this_month': "{0:.2f}".format(exp_this_month),
                'inc_last_month': "{0:.2f}".format(sum_income_last_month),
                'exp_last_month': "{0:.2f}".format(exp_last_month)
            }
            if not as_dataframe:
                return as_dict
            else:
                # convert to a single row dataframe
                _temp_df = pd.DataFrame(list(as_dict.values())).T
                _temp_df.columns = list(as_dict.keys())
                return _temp_df
コード例 #8
0
ファイル: html_helper.py プロジェクト: MaksimDan/self-finance
 def as_html_form_from_sql(table_name, date_range, order_by_col_name, order, table_id=None,
                           replace_default_data_frame_class_with=None):
     rddfcw = replace_default_data_frame_class_with
     df = Data.get_table_as_df(date_range, table_name, order_by_col_name, order)
     if df is None or df.shape[0] == 0:
         return None
     return HTMLHelper.as_html_form_from_df(df, table_id, make_editable=True,
                                            replace_default_data_frame_class_with=rddfcw)
コード例 #9
0
 def _top_n_categories(inc_or_exp, date_range, table_name, n, db_path):
     df = Data.get_table_as_df(date_range, table_name, db_path=db_path)
     if df is None or df.shape[0] == 0:
         return None
     df_filter = df[df[BankSchema.SCHEMA_BANK_INC_OR_EXP.name] ==
                    inc_or_exp]
     most_common_filter = RawInsights.Dynammic._agg_top_n_income_and_expense_categories(
         df_filter, n)
     return pd.DataFrame(most_common_filter,
                         columns=['category', 'frequency'])
コード例 #10
0
 def table_summary_statistics(table_name,
                              date_range,
                              db_path=files['base_db']):
     pd.options.html.border = 0
     summary_df = Data.get_table_as_df(date_range,
                                       table_name,
                                       db_path=db_path)
     if summary_df is None or summary_df.shape[0] == 0:
         logger.debug(
             'Unable to instantiate summary statistics table. The database is probably empty.'
         )
         return None
     else:
         return summary_df.describe()
コード例 #11
0
ファイル: visuals.py プロジェクト: MaksimDan/self-finance
def visuals_redraw():
    if request.method == 'POST':
        form = request.form
        drs, dre = form['start_query_name'], form['end_query_name']
        if not valid_dr(drs, dre):
            return _standard_render()
        State.date_range_start, State.date_range_end = drs, dre

        # update which visuals to draw and redraw them
        requested_plots_to_draw = set(ImageRegistry.get_all_plot_ids()) & set(form.keys())
        _update_requested_plots_to_draw(set(requested_plots_to_draw))
        df = Data.get_table_as_df(DateRange(State.date_range_start, State.date_range_end),
                                  table_name=BankSchema.BANK_TB_NAME)
        if df is None or df.shape[0] == 0:
            flash(f'No data int table {BankSchema.BANK_TB_NAME} produce diagrams.', 'warning')
        else:
            ImageRegistry.plot_all(list(requested_plots_to_draw), df, drs, dre)
    return _standard_render()
コード例 #12
0
ファイル: data.py プロジェクト: MaksimDan/self-finance
def data_download():
    if request.method == 'POST':
        logger.info('Downloading bank data as csv file.')
        with tempfile.TemporaryDirectory() as tmpdir:
            dr = DateRange(State.date_range_start, State.date_range_end)
            bank_df = Data.get_table_as_df(dr, BankSchema.BANK_TB_NAME,
                                           DataState.order_by_column_name,
                                           DataState.order_by)
            if bank_df is None or bank_df.shape[0] == 0:
                flash(
                    f'{BankSchema.BANK_TB_NAME} table is empty. Nothing to download.',
                    'warning')
                return _standard_render()
            bank_df.to_csv(os.path.join(tmpdir, ConstData.FILE_NAME_DOWNLOAD),
                           index=False)
            return send_from_directory(directory=tmpdir,
                                       filename=ConstData.FILE_NAME_DOWNLOAD,
                                       as_attachment=True)
    return _standard_render()
コード例 #13
0
ファイル: _plot.py プロジェクト: MaksimDan/self-finance
 def spending_heatmap(date_range, db_path=files['base_db'], **kwargs):
     logging.info('Plotting spending_heatmap plot')
     hm_df = Data.get_heatmap_df(date_range, db_path)
     if hm_df is None:
         logging.warning(
             'Query for heatmap dataframe returned as empty, ignoring plot.'
         )
         return None
     hm_df = hm_df.dropna()
     hmap = folium.Map(zoom_start=6, location=Visuals.HM_START_LAT_LON)
     hm_wide = HeatMap(list(
         zip(hm_df[BankSchema.SCHEMA_LOCATION_LAT.name].values,
             hm_df[BankSchema.SCHEMA_LOCATION_LON.name].values,
             hm_df[BankSchema.SCHEMA_BANK_AMOUNT.name].values)),
                       min_opacity=0.2,
                       radius=17,
                       blur=15,
                       max_zoom=1)
     hmap.add_child(hm_wide)
     return hmap.get_root().render()
コード例 #14
0
 def __init__(self):
     self.classifier = BankClassifier()
     self.model_df = Data.get_table_as_df(date_range=None)
     self.current_categories_dict = None
     assert self.model_df.shape[0] > 0, "No bank static was found."
コード例 #15
0
ファイル: visuals.py プロジェクト: MaksimDan/self-finance
def _get_html_from_ids():
    return {image_id: Data.get_most_recent_html_from_id(image_id) for image_id in VisualState.plot_selections.keys()
            if VisualState.plot_selections[image_id]}
コード例 #16
0
 def __init__(self):
     self.model_df = Data.get_table_as_df(date_range=None)
     assert self.model_df.shape[0] > 0, "No bank static was found."
コード例 #17
0
 def db():
     Data.create_base_db()