Skip to content

Commit

Permalink
v0.5.5.1 (arrobalytics#164)
Browse files Browse the repository at this point in the history
* Template Bugfixes
OFX Import Fix
JE Activity Exception ignored if JE is a closing entry with multiple roles involved (Trial Balance Import)

* OFX Import Fix

* OFX Import Workflow BugFixes

* v0.5.5.1
Open Financial Exchange Imports (OFX) Bugfixes and Optimizations

* Account Activate/Deactivate Actions
CFS Activity Generation Update

* Data Import Txs Split

* Staged Transaction Split

* v0.5.5.1
Data Import View Optimization

* v0.5.5.1
Open Financial Exchange Imports (OFX) Bugfixes and Optimizations

* v0.5.5.1
Data Import View Optimization

* v0.5.5.1
LT/ST Interest Expense Roles
OFX/QFX EntityUnit Import

* v0.5.5.1
Data Import View Optimization

* OFX/QFX Form BugFixes

* Can delete Journal Entries

* Import Job Migrate

* StagedTransaction can be bundled or split into individual transactions so Journal Entry activity can be identified correctly.
Active Account only view.
Importing OFX files workflow is now working.
Import jobs can be updated and deleted.
Fixed Income Statement populating wrong Other Income Amount (UI bug only).
Ledger can now post all journal entries at once - if allowed.

* Data import bugfix.
  • Loading branch information
elarroba authored Oct 12, 2023
1 parent 08de6d0 commit 8788b93
Show file tree
Hide file tree
Showing 43 changed files with 1,569 additions and 538 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ More details available in the [Django Ledger v0.5 Page](https://www.arrobalytics
* ~~__0.5.3__~~: High Level EntityModel API.
* ~~__0.5.4__~~: Balance Sheet Statement, Income Statement & Cash Flow Statement API & PDF report export.
* __0.5.5__: Closing Entries.
* 0.5.5.1: Closing Entries will be used if requested date is present. Documentation Update.
* 0.5.5.1: Open Financial Exchange Imports (OFX) Bugfixes and Optimizations.
* 0.5.5.2: Closing Entries will be used if requested date is present. Documentation Update.
* __0.5.6__: Chart of Accounts Import.
* __0.5.7__: Trial Balance Import.
* __0.5.8__: GraphQL API.
Expand Down
2 changes: 1 addition & 1 deletion django_ledger/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
default_app_config = 'django_ledger.apps.DjangoLedgerConfig'

"""Django Ledger"""
__version__ = '0.5.5.0'
__version__ = '0.5.5.1'
__license__ = 'GPLv3 License'

__author__ = 'Miguel Sanda'
Expand Down
167 changes: 111 additions & 56 deletions django_ledger/forms/data_import.py
Original file line number Diff line number Diff line change
@@ -1,74 +1,124 @@
from django import forms
from django.forms import ModelForm, BaseModelFormSet, modelformset_factory, Select, HiddenInput, ValidationError
from django.forms import (ModelForm, BaseModelFormSet, modelformset_factory, Select, NumberInput, HiddenInput,
TextInput,
ValidationError)
from django.utils.translation import gettext_lazy as _

from django_ledger.models import StagedTransactionModel, AccountModel, ImportJobModel
from django_ledger.models import StagedTransactionModel, AccountModel, EntityUnitModel, ImportJobModel
from django_ledger.settings import DJANGO_LEDGER_FORM_INPUT_CLASSES


class OFXFileImportForm(forms.Form):
class ImportJobModelCreateForm(ModelForm):
ofx_file = forms.FileField(
label='Select File...',
widget=forms.FileInput(attrs={
'class': 'file-input'
}))
widget=forms.FileInput(
attrs={
'class': 'file-input'
})
)

class Meta:
model = ImportJobModel
fields = [
'description'
]
widgets = {
'description': TextInput(attrs={
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-large',
'placeholder': _('What\'s this import about?...')
})
}


class ImportJobModelUpdateForm(ModelForm):
class Meta:
model = ImportJobModel
fields = [
'description'
]
widgets = {
'description': TextInput(attrs={
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
})
}


class StagedTransactionModelForm(ModelForm):
tx_import = forms.BooleanField(initial=False, required=False)
tx_split = forms.BooleanField(initial=False, required=False)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
instance = getattr(self, 'instance', None)
instance: StagedTransactionModel = getattr(self, 'instance', None)
if instance:
if instance.earnings_account and instance.tx:
self.fields['earnings_account'].widget.attrs['disabled'] = True
self.fields['earnings_account'].widget.attrs['value'] = instance.earnings_account
self.fields['tx_import'].widget.attrs['disabled'] = True
self.fields['tx_import'].widget.attrs['value'] = True
elif not instance.earnings_account:
self.fields['tx_import'].widget.attrs['disabled'] = True
elif instance.earnings_account and not instance.tx:
self.fields['tx_import'].widget.attrs['disabled'] = False

if not instance.is_children():
self.fields['amount_split'].widget = HiddenInput()
self.fields['amount_split'].disabled = True
else:
self.fields['bundle_split'].widget = HiddenInput()
self.fields['bundle_split'].disabled = True

if not instance.can_have_account():
self.fields['account_model'].widget = HiddenInput()
self.fields['account_model'].disabled = True

if not instance.can_have_unit():
self.fields['unit_model'].widget = HiddenInput()
self.fields['unit_model'].disabled = True

if not instance.can_import():
self.fields['tx_import'].widget = HiddenInput()
self.fields['tx_import'].disabled = True
if not instance.can_split():
self.fields['tx_split'].widget = HiddenInput()
self.fields['tx_split'].disabled = True

def clean_account_model(self):
staged_txs_model: StagedTransactionModel = self.instance
if staged_txs_model.has_children():
return None
return self.cleaned_data['account_model']

def clean_unit_model(self):
staged_txs_model: StagedTransactionModel = self.instance
if not staged_txs_model.can_have_unit():
if staged_txs_model.parent_id:
return staged_txs_model.parent.unit_model
return self.cleaned_data['unit_model']

def clean_tx_import(self):
staged_txs_model: StagedTransactionModel = self.instance
if staged_txs_model.is_children():
return False
return self.cleaned_data['tx_import']

def clean(self):
# cannot import and split at the same time
if self.cleaned_data['tx_import'] and self.cleaned_data['tx_split']:
raise ValidationError(message=_('Cannot import and split at the same time'))

class Meta:
model = StagedTransactionModel
model = StagedTransactionModel.objects.get_queryset().model
fields = [
'tx_import',
'date_posted',
'name',
'amount',
'earnings_account',
'import_job',
'tx'
'bundle_split',
'amount_split',
'account_model',
'unit_model'
]
widgets = {
'tx': HiddenInput(attrs={
'readonly': True
}),
'date_posted': HiddenInput(attrs={
'readonly': True
}),
'import_job': HiddenInput(attrs={
'readonly': True
}),
'name': HiddenInput(attrs={
'readonly': True
}),
'amount': HiddenInput(attrs={
'readonly': True
'account_model': Select(attrs={
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small',
}),
'earnings_account': Select(attrs={
'unit_model': Select(attrs={
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small',
}),
'amount_split': NumberInput(attrs={
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES + ' is-small'
})
}

def clean(self):
earnings_account = self.cleaned_data['earnings_account']
tx = self.cleaned_data['tx']

if tx and not earnings_account:
raise ValidationError('If tx, ea must be present.')


class BaseStagedTransactionModelFormSet(BaseModelFormSet):

Expand All @@ -79,27 +129,32 @@ def __init__(self, *args, entity_slug, user_model, exclude_account=None, **kwarg
self.IMPORT_DISABLED = not exclude_account
self.CASH_ACCOUNT = exclude_account

accounts_qs = AccountModel.objects.for_entity_available(
account_model_qs = AccountModel.objects.for_entity_available(
user_model=self.USER_MODEL,
entity_slug=self.ENTITY_SLUG
)
if exclude_account:
accounts_qs = accounts_qs.exclude(uuid__exact=exclude_account.uuid)
).order_by('role', 'name')

import_job_qs = ImportJobModel.objects.for_entity(
entity_slug=self.ENTITY_SLUG,
user_model=self.USER_MODEL
unit_model_qs = EntityUnitModel.objects.for_entity(
user_model=self.USER_MODEL,
entity_slug=self.ENTITY_SLUG
)

if exclude_account:
account_model_qs = account_model_qs.exclude(uuid__exact=exclude_account.uuid)

for form in self.forms:
form.fields['earnings_account'].queryset = accounts_qs
form.fields['earnings_account'].widget.attrs['disabled'] = self.IMPORT_DISABLED
form.fields['import_job'].queryset = import_job_qs
form.fields['account_model'].queryset = account_model_qs
form.fields['account_model'].widget.attrs['disabled'] = self.IMPORT_DISABLED
form.fields['unit_model'].queryset = unit_model_qs

# def get_queryset(self):


StagedTransactionModelFormSet = modelformset_factory(
model=StagedTransactionModel,
form=StagedTransactionModelForm,
formset=BaseStagedTransactionModelFormSet,
can_delete=False,
can_delete=True,
can_delete_extra=0,
can_order=False,
extra=0)
2 changes: 1 addition & 1 deletion django_ledger/io/io_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ def digest(self):
'other': {
'revenues': [acc for acc in self.DIGEST['group_account']['GROUP_INCOME'] if
acc['role'] in roles_module.GROUP_IC_OTHER_REVENUES],
'expenses': [acc for acc in self.DIGEST['group_account']['GROUP_INCOME'] if
'expenses': [acc for acc in self.DIGEST['group_account']['GROUP_EXPENSES'] if
acc['role'] in roles_module.GROUP_IC_OTHER_EXPENSES],
}
}
Expand Down
Loading

0 comments on commit 8788b93

Please sign in to comment.