Пример #1
0
def index(request):
  template = loader.get_template('page_index.html')
  accounts = [Account.from_path(path) for path in settings.ACCOUNTS_LIST]

  all_accounts = Account.get_all()
  all_accounts.sort(key=lambda a: a.path)

  c = RequestContext(request, {
    'accounts': accounts,
    'all_accounts': all_accounts,
    'showing_index': True,
  })
  return HttpResponse(template.render(c))
Пример #2
0
def account(request, key):
  template = loader.get_template('page_account_details.html')

  account = get_account(key)
  splits = filters.TransactionSplitFilter(account)

  all_accounts = Account.get_all()
  all_accounts.sort(key=lambda a: a.path)
  all_accounts_dict = {}
  for a in all_accounts:
    all_accounts_dict[a.guid] = {
      'path': a.path,
      'name': a.name
    }

  choices = forms.AccountChoices(account)

  filter_form = forms.FilterForm(choices, request.GET)
  if filter_form.is_valid():
    splits.filter_splits(filter_form.cleaned_data)

  splits.order_filtered_splits()

  modify_form_data = request.GET.copy()
  modify_form_data['save_rule'] = True
  modify_form = forms.ModifyForm(choices, modify_form_data, auto_id="modify_id_%s")

  try:
    page_num = int(request.GET.get('page'))
  except:
    page_num = 1

  pages = Paginator(splits.filtered_splits, settings.NUM_TRANSACTIONS_PER_PAGE)

  try:
    page = pages.page(page_num)
  except PageNotAnInteger:
    page = pages.page(1)
  except EmptyPage:
    page = pages.page(pages.num_pages)

  Transaction.cache_from_splits(page.object_list)

  c = RequestContext(request, {
    'any_filters_applied': splits.any_filters_applied,
    'one_opposing_account_filter_applied': splits.one_opposing_account_filter_applied,
    'regex_chars_js': json.dumps(filters.TransactionSplitFilter.REGEX_CHARS),
    'all_accounts': all_accounts,
    'accounts_js': json.dumps(all_accounts_dict),
    'current_account_js': json.dumps(account.guid),
    'num_transactions_js': json.dumps(page.paginator.count),
    'api_functions_js': json.dumps(api.function_urls.urls_dict),
    'account': account,
    'page': page,
    'filter_form': filter_form,
    'modify_form': modify_form,
  })
  return HttpResponse(template.render(c))
Пример #3
0
def modify(request, key):
  template = loader.get_template('page_modify.html')

  accounts = misc_functions.get_accounts_by_webapp_key(key)
  splits = filters.TransactionSplitFilter(accounts)

  errors = False

  choices = forms.AccountChoices(accounts)

  opposing_account_guid = request.POST['change_opposing_account']
  opposing_account = None
  try:
    if opposing_account_guid != 'DELETE':
      opposing_account = Account.get(opposing_account_guid)
  except Account.DoesNotExist:
    errors = "Account '%s' not found." % opposing_account_guid

  form_data = request.POST.copy()

  modified_tx_count = 0

  if not errors:
    modify_form = forms.ModifyForm(choices, request.POST)
    if modify_form.is_valid():
      splits.filter_splits(modify_form.cleaned_data)

      save_rule = modify_form.cleaned_data['save_rule']
      if save_rule and not splits.tx_desc:
        errors = 'Cannot save rule with no description filter.'
        save_rule = False

      modified_tx_count = filters.RuleHelper.apply(
        splits=splits,
        opposing_account=opposing_account,
        min_amount=modify_form.cleaned_data['min_amount'],
        max_amount=modify_form.cleaned_data['max_amount'],
        save_rule=save_rule)

      if modified_tx_count:
        form_data['opposing_accounts'] = opposing_account_guid

    else:
      # modify_form is not valid
      errors = str(modify_form.errors)

  hidden_filter_form = forms.HiddenFilterForm(choices, form_data)

  c = RequestContext(request, {
    'accounts': accounts,
    'current_accounts_key': misc_functions.accounts_webapp_key(accounts),
    'opposing_account': opposing_account,
    'hidden_filter_form': hidden_filter_form,
    'errors': errors,
    'modified_tx_count': modified_tx_count,
  })
  return HttpResponse(template.render(c))
Пример #4
0
def index(request):
  template = loader.get_template('index.html')
  accounts = [Account.from_path(path) for path in settings.ACCOUNTS_LIST]

  c = RequestContext(request, {
    'accounts': accounts,
    'show_account_links': True,
  })
  return HttpResponse(template.render(c))
Пример #5
0
def modify(request, index):
  template = loader.get_template('modify.html')

  path = settings.ACCOUNTS_LIST[int(index)]
  account = Account.from_path(path)
  splits = filters.TransactionSplitFilter(account)

  errors = False

  choices = forms.AccountChoices(account)

  opposing_account_guid = request.POST['change_opposing_account']
  opposing_account = None
  try:
    opposing_account = Account.objects.get(guid=opposing_account_guid)
  except Account.DoesNotExist:
    errors = "Account '%s' not found." % opposing_account_guid

  form_data = request.POST.copy()

  modified_tx_count = 0

  if not errors:
    modify_form = forms.ModifyForm(choices, request.POST)
    if modify_form.is_valid():
      splits.filter_splits(modify_form.cleaned_data)

      save_rule = modify_form.cleaned_data['save_rule']
      if save_rule and not splits.tx_desc:
        errors = 'Cannot save rule with no description filter.'
        save_rule = False

      modified_tx_count = filters.RuleHelper.apply(
        splits=splits,
        opposing_account=opposing_account,
        min_amount=modify_form.cleaned_data['min_amount'],
        max_amount=modify_form.cleaned_data['max_amount'],
        save_rule=save_rule)

      if modified_tx_count:
        form_data['opposing_accounts'] = opposing_account_guid

    else:
      # modify_form is not valid
      errors = str(modify_form.errors)

  hidden_filter_form = forms.HiddenFilterForm(choices, form_data)

  c = RequestContext(request, {
    'account': account,
    'opposing_account': opposing_account,
    'hidden_filter_form': hidden_filter_form,
    'errors': errors,
    'modified_tx_count': modified_tx_count,
  })
  return HttpResponse(template.render(c))
Пример #6
0
def batch_categorize(request, index):
  template = loader.get_template('batch_categorize.html')

  path = settings.ACCOUNTS_LIST[int(index)]
  account = Account.from_path(path)
  splits = filters.TransactionSplitFilter(account)

  imbalance = Account.from_path('Imbalance-USD')
  choices = forms.AccountChoices(account, exclude=imbalance)

  merchants = splits.get_merchants_info(imbalance)
  no_merchants = (len(merchants) == 0)
  batch_modify_form = forms.BatchModifyForm(choices, merchants)

  c = RequestContext(request, {
    'account': account,
    'batch_modify_form': batch_modify_form,
    'no_merchants': no_merchants,
    'imbalance': imbalance,
  })
  return HttpResponse(template.render(c))
Пример #7
0
def apply_categorize(request, key):
  template = loader.get_template('page_apply_categorize.html')

  accounts = misc_functions.get_accounts_by_webapp_key(key)
  splits = filters.TransactionSplitFilter(accounts)

  imbalance = Account.from_path('Imbalance-USD')
  choices = forms.AccountChoices(accounts, exclude=imbalance)

  merchants = splits.get_merchants_info(imbalance)
  batch_modify_form = forms.BatchModifyForm(choices, merchants, request.POST)

  if not batch_modify_form.is_valid():
    raise ValueError(batch_modify_form.errors)

  modified_tx_count = 0
  rule_count = 0

  for i in range(settings.NUM_MERCHANTS_BATCH_CATEGORIZE):
    if 'merchant_' + str(i) in batch_modify_form.cleaned_data:
      tx_desc = batch_modify_form.cleaned_data['merchant_name_' + str(i)]
      opposing_account_guid = batch_modify_form.cleaned_data['merchant_' + str(i)]
      if opposing_account_guid:
        rule_count += 1
        opposing_account = None
        if opposing_account_guid != 'DELETE':
          opposing_account = Account.get(opposing_account_guid)
        modified_tx_count += filters.RuleHelper.apply(
          splits=splits,
          tx_desc=tx_desc,
          opposing_account=opposing_account,
          save_rule=True)

  c = RequestContext(request, {
    'accounts': accounts,
    'current_accounts_key': misc_functions.accounts_webapp_key(accounts),
    'modified_tx_count': modified_tx_count,
    'rule_count': rule_count,
  })
  return HttpResponse(template.render(c))
Пример #8
0
def apply_categorize(request, index):
  template = loader.get_template('apply_categorize.html')

  path = settings.ACCOUNTS_LIST[int(index)]
  account = Account.from_path(path)
  imbalance = Account.from_path('Imbalance-USD')

  choices = forms.AccountChoices(account, exclude=imbalance)

  splits = filters.TransactionSplitFilter(account)
  merchants = splits.get_merchants_info(imbalance)
  batch_modify_form = forms.BatchModifyForm(choices, merchants, request.POST)

  if not batch_modify_form.is_valid():
    raise ValueError(batch_modify_form.errors)

  modified_tx_count = 0
  rule_count = 0

  for i in range(settings.NUM_MERCHANTS_BATCH_CATEGORIZE):
    if 'merchant_' + str(i) in batch_modify_form.cleaned_data:
      tx_desc = batch_modify_form.cleaned_data['merchant_name_' + str(i)]
      opposing_account_guid = batch_modify_form.cleaned_data['merchant_' + str(i)]
      if opposing_account_guid:
        rule_count += 1
        modified_tx_count += filters.RuleHelper.apply(
          splits=splits,
          tx_desc=tx_desc,
          opposing_account=Account.objects.get(guid=opposing_account_guid),
          save_rule=True)

  c = RequestContext(request, {
    'account': account,
    'modified_tx_count': modified_tx_count,
    'rule_count': rule_count,
  })
  return HttpResponse(template.render(c))
Пример #9
0
def account(request, index):
  template = loader.get_template('account_details.html')

  path = settings.ACCOUNTS_LIST[int(index)]
  account = Account.from_path(path)
  splits = filters.TransactionSplitFilter(account)

  choices = forms.AccountChoices(account)

  filter_form = forms.FilterForm(choices, request.GET)
  if filter_form.is_valid():
    splits.filter_splits(filter_form.cleaned_data)

  splits.order_filtered_splits()

  modify_form_data = request.GET.copy()
  modify_form_data['save_rule'] = True
  modify_form = forms.ModifyForm(choices, modify_form_data, auto_id="modify_id_%s")

  try:
    page_num = int(request.GET.get('page'))
  except:
    page_num = 1

  pages = Paginator(splits.filtered_splits, settings.NUM_TRANSACTIONS_PER_PAGE)

  try:
    page = pages.page(page_num)
  except PageNotAnInteger:
    page = pages.page(1)
  except EmptyPage:
    page = pages.page(pages.num_pages)

  c = RequestContext(request, {
    'any_filters_applied': splits.any_filters_applied,
    'one_opposing_account_filter_applied': splits.one_opposing_account_filter_applied,
    'regex_chars_js': json.dumps(filters.TransactionSplitFilter.REGEX_CHARS),
    'accounts_js': json.dumps(choices.accounts_dict),
    'num_transactions_js': json.dumps(page.paginator.count),
    'account': account,
    'page': page,
    'filter_form': filter_form,
    'modify_form': modify_form,
  })
  return HttpResponse(template.render(c))
Пример #10
0
def batch_categorize(request, key):
  template = loader.get_template('page_batch_categorize.html')

  accounts = misc_functions.get_accounts_by_webapp_key(key)
  splits = filters.TransactionSplitFilter(accounts)

  imbalance = Account.from_path('Imbalance-USD')
  choices = forms.AccountChoices(accounts, exclude=imbalance)

  merchants = splits.get_merchants_info(imbalance)
  no_merchants = (len(merchants) == 0)
  batch_modify_form = forms.BatchModifyForm(choices, merchants)

  c = RequestContext(request, {
    'accounts': accounts,
    'current_accounts_key': misc_functions.accounts_webapp_key(accounts),
    'batch_modify_form': batch_modify_form,
    'no_merchants': no_merchants,
    'imbalance': imbalance,
  })
  return HttpResponse(template.render(c))
Пример #11
0
def account(request, key):
  template = loader.get_template('page_account_details.html')

  accounts = misc_functions.get_accounts_by_webapp_key(key)
  splits = filters.TransactionSplitFilter(accounts)

  all_accounts = Account.get_all()
  all_accounts.sort(key=lambda a: a.path)
  all_accounts_dict = {}
  for a in all_accounts:
    all_accounts_dict[a.guid] = {
      'path': a.path,
      'name': a.name
    }

  choices = forms.AccountChoices(accounts)

  filter_form = forms.FilterForm(choices, request.GET)
  if filter_form.is_valid():
    splits.filter_splits(filter_form.cleaned_data)

  splits.order_filtered_splits()

  modify_form_data = request.GET.copy()
  modify_form_data['save_rule'] = True
  modify_form = forms.ModifyForm(choices, modify_form_data, auto_id="modify_id_%s")

  try:
    can_add_transactions = settings.ENABLE_ADD_TRANSACTIONS
  except AttributeError:
    can_add_transactions = False

  can_add_transactions = (can_add_transactions and len(accounts) == 1)

  if can_add_transactions:
    new_transaction_form = forms.NewTransactionForm(choices, auto_id='id_new_trans_%s')
  else:
    new_transaction_form = None

  try:
    page_num = int(request.GET.get('page'))
  except:
    page_num = 1

  pages = Paginator(splits.filtered_splits, settings.NUM_TRANSACTIONS_PER_PAGE)

  try:
    page = pages.page(page_num)
  except PageNotAnInteger:
    page = pages.page(1)
  except EmptyPage:
    page = pages.page(pages.num_pages)

  Transaction.cache_from_splits(page.object_list)

  current_accounts_key = misc_functions.accounts_webapp_key(accounts)

  c = RequestContext(request, {
    'any_filters_applied': splits.any_filters_applied,
    'one_opposing_account_filter_applied': splits.one_opposing_account_filter_applied,
    'query_params_js': json.dumps(request.GET),
    'regex_chars_js': json.dumps(filters.TransactionSplitFilter.REGEX_CHARS),
    'all_accounts': all_accounts,
    'accounts_js': json.dumps(all_accounts_dict),
    'current_accounts_js': json.dumps([a.guid for a in accounts]),
    'num_transactions_js': json.dumps(page.paginator.count),
    'api_functions_js': json.dumps(api.function_urls.urls_dict),
    'accounts': accounts,
    'current_accounts_key': current_accounts_key,
    'current_accounts_key_js': json.dumps(current_accounts_key),
    'can_add_transactions': can_add_transactions,
    'account': accounts[0],
    'page': page,
    'filter_form': filter_form,
    'modify_form': modify_form,
    'new_transaction_form': new_transaction_form,
    'total_balance': sum(a.balance for a in accounts),
  })
  return HttpResponse(template.render(c))
Пример #12
0
def get_account_by_webapp_key(key):
    try:
        path = settings.ACCOUNTS_LIST[int(key)]
        return Account.from_path(path)
    except ValueError:
        return Account.get(key)
Пример #13
0
  def __init__(self, accounts, **kwargs):
    cursor = connections['gnucash'].cursor()
    sql = '''
        SELECT a.guid,

          CASE
            WHEN s.account_guid IS NULL THEN 0
            ELSE 1
          END AS is_present,

          a.placeholder

        FROM accounts a

        LEFT JOIN (
          SELECT s2.account_guid,
            MAX(t.post_date) post_date

          FROM splits s

          INNER JOIN transactions t
          ON s.tx_guid = t.guid

          INNER JOIN splits s2
          ON s2.tx_guid = t.guid

          WHERE s.account_guid IN (%s)
          AND s2.account_guid NOT IN (%s)

          GROUP BY 1
        ) s
        ON s.account_guid = a.guid

        WHERE a.account_type <> 'ROOT'
      '''

    params = ', '.join('%s' for a in accounts)
    sql = sql % (params, params)
    account_guids = [a.guid for a in accounts]
    cursor.execute(sql, account_guids + account_guids)

    filter_all_account_choices = []
    filter_account_choices = []
    modify_account_choices = []

    exclude_guids = account_guids
    if 'exclude' in kwargs:
      exclude_guids.append(kwargs['exclude'].guid)

    for row in cursor.fetchall():
      guid = row[0]
      path = Account.get(guid).path
      is_present = row[1]
      placeholder = row[2]
      filter_all_account_choices.append((guid, path))
      if is_present:
        filter_account_choices.append((guid, path))
      if not placeholder and guid not in exclude_guids:
        modify_account_choices.append((guid, path))

    get_account_path = lambda a: a[1]
    filter_account_choices.sort(key=get_account_path)
    modify_account_choices.sort(key=get_account_path)

    self.filter_all_account_choices = \
      DEFAULT_FILTER_ACCOUNT_CHOICES + filter_all_account_choices
    self.filter_account_choices = \
      DEFAULT_FILTER_ACCOUNT_CHOICES + filter_account_choices
    self.modify_account_choices = \
      DEFAULT_MODIFY_ACCOUNT_CHOICES + modify_account_choices
Пример #14
0
 def process_request(self, request):
   Account.clear_caches()
   Transaction.clear_caches()
   return None
Пример #15
0
def get_account(key):
  try:
    path = settings.ACCOUNTS_LIST[int(key)]
    return Account.from_path(path)
  except ValueError:
    return Account.get(key)
Пример #16
0
 def process_request(self, request):
     Account.clear_caches()
     Transaction.clear_caches()
     return None