Skip to content

Commit 9b4d020

Browse files
elarrobapablokillinstreakshucontech
authored
v0.7.10 (#280)
* v.0.7.7 * Enhance account list views and update icon styles. Implemented dynamic page titles and subtitles for account pages by overriding `get_context_data`. Updated template text and classes for greater consistency, including standardizing icon colors for active, locked, and default roles. * Adding TransactionModel attributes during commit_txs. * Fixed a couple of hard coded dollar "$" symbols and changed them with `{% currency_symbol %}` tag to render the correct symbol when `DJANGO_LEDGER_CURRENCY_SYMBOL` is other than default ("$"). (#265) * Dependency update * Update contribution guidelines in README and Contribute.md Clarified the types of pull requests that are encouraged, emphasizing those that address bug fixes, enhancements, or valuable additions. Added a note discouraging submissions focused only on cosmetic changes like linting or refactoring. * Update ManyToManyField configurations and bump version to 0.7.8 Adjusted `ManyToManyField` relationships in `BillModel`, `InvoiceModel`, and `PurchaseOrderModel` to include `through` and `through_fields` for `ItemTransactionModel`. Incremented package version to `0.7.8`. * Add support for bank account type validation and retrieval based on OFX standards - Introduced `bank_account_type` field in `BankAccountModel` with predefined choices. - Added methods to retrieve routing number, account type, and account type validation in `OFXImport` class. - Enhanced account queries with a new `.cash()` method to filter accounts with `ASSET_CA_CASH` role. - Updated indexing and unique constraints for `BankAccountModel`. * Migration Update * Refactor bank account type handling and account type mapping logic - Replaced `BankAccountModel.BANK_ACCOUNT_TYPES` with explicit OFX types. - Renamed `ACCOUNT_TYPE_ROLE_MAPPING` to `ACCOUNT_TYPE_DEFAULT_ROLE_MAPPING`. - Centralized OFX type mappings in `ACCOUNT_TYPE_OFX_MAPPING`. - Removed `bank_account_type` field from `BankAccountModel`. - Added `get_account_type_from_ofx` method for retrieving account type from OFX data. * Add financial institution field and utility methods to account models - Introduced `financial_institution` field in account mixin for storing bank details. - Added `get_account_last_digits` utility for partial account number retrieval. - Implemented `can_hide` and `can_unhide` methods in `BankAccountModel`. * Refactor account handling and enhance validation methods - Renamed `get_account_type` to `get_ofx_account_type` for clarity in OFX implementation. - Added `get_account_type` method to map OFX account types to internal account types. - Introduced `get_routing_last_digits` method for masked routing number retrieval. - Improved handling of missing account and routing numbers in utility methods. * Sort node issue fix * Update chart_of_accounts.py * Bump version to 0.7.9 and update `for_entity` method to accept `EntityModel` instances. * V0.7.10 (#279) * Add customer and vendor code fields, picture upload functionality, and UI improvements - Introduced `customer_code` and `vendor_code` fields for user-defined unique codes in `CustomerModel` and `VendorModel`. - Added support for customer and vendor picture uploads with specified upload paths. - Updated migration `0023` to reflect the new fields and modifications. - Improved UI consistency in templates and added icons for enhanced usability. - Updated `pyproject.toml` to bump version to `0.7.10`. * Bump version to 0.7.10. --------- Co-authored-by: Pablo Santa Cruz <pablo@roshka.com.py> Co-authored-by: killinstreak <killinstreak@killinstreaks-Laptop.local> Co-authored-by: Shucon Tech <85239205+shucontech@users.noreply.github.com>
1 parent a838b00 commit 9b4d020

File tree

13 files changed

+179
-46
lines changed

13 files changed

+179
-46
lines changed

django_ledger/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
default_app_config = 'django_ledger.apps.DjangoLedgerConfig'
77

88
"""Django Ledger"""
9-
__version__ = '0.7.9'
9+
__version__ = '0.7.10'
1010
__license__ = 'GPLv3 License'
1111

1212
__author__ = 'Miguel Sanda'

django_ledger/forms/account.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from treebeard.forms import MoveNodeForm
1414

1515
from django_ledger.io import ACCOUNT_CHOICES_NO_ROOT
16-
from django_ledger.models import ChartOfAccountModel, EntityModel
16+
from django_ledger.models import ChartOfAccountModel
1717
from django_ledger.models.accounts import AccountModel
1818
from django_ledger.settings import DJANGO_LEDGER_FORM_INPUT_CLASSES
1919

@@ -24,8 +24,6 @@ class AccountModelCreateForm(ModelForm):
2424
2525
Attributes
2626
----------
27-
ENTITY_MODEL : Model
28-
The entity model being used in the form.
2927
COA_MODEL : Model
3028
The Chart of Account Model being used in the form.
3129
"""

django_ledger/forms/customer.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ class Meta:
2323
model = CustomerModel
2424
fields = [
2525
'customer_name',
26+
'customer_code',
2627
'address_1',
2728
'address_2',
2829
'city',
@@ -43,6 +44,10 @@ class Meta:
4344
'customer_name': TextInput(attrs={
4445
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
4546
}),
47+
'customer_code': TextInput(attrs={
48+
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES,
49+
'placeholder': 'Ex: CDR-78987-2025...'
50+
}),
4651
'address_1': TextInput(attrs={
4752
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
4853
}),

django_ledger/forms/vendor.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class Meta:
2222
model = VendorModel
2323
fields = [
2424
'vendor_name',
25+
'vendor_code',
2526
'address_1',
2627
'address_2',
2728
'city',
@@ -39,6 +40,10 @@ class Meta:
3940
'vendor_name': TextInput(attrs={
4041
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
4142
}),
43+
'vendor_code': TextInput(attrs={
44+
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES,
45+
'placeholder': 'Ex: GRB-67987-2025...'
46+
}),
4247
'address_1': TextInput(attrs={
4348
'class': DJANGO_LEDGER_FORM_INPUT_CLASSES
4449
}),
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Generated by Django 5.2.1 on 2025-08-22 19:05
2+
3+
import django.db.models.deletion
4+
import django_ledger.models.customer
5+
import django_ledger.models.vendor
6+
from django.db import migrations, models
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
dependencies = [
12+
('django_ledger', '0022_bankaccountmodel_financial_institution_and_more'),
13+
]
14+
15+
operations = [
16+
migrations.AddField(
17+
model_name='customermodel',
18+
name='customer_code',
19+
field=models.SlugField(blank=True, null=True, unique=True, verbose_name='User defined customer code'),
20+
),
21+
migrations.AddField(
22+
model_name='customermodel',
23+
name='picture',
24+
field=models.ImageField(blank=True, null=True, upload_to=django_ledger.models.customer.customer_picture_upload_to),
25+
),
26+
migrations.AddField(
27+
model_name='vendormodel',
28+
name='picture',
29+
field=models.ImageField(blank=True, null=True, upload_to=django_ledger.models.vendor.vendor_picture_upload_to),
30+
),
31+
migrations.AddField(
32+
model_name='vendormodel',
33+
name='vendor_code',
34+
field=models.SlugField(blank=True, null=True, verbose_name='User defined vendor code.'),
35+
),
36+
migrations.AlterField(
37+
model_name='customermodel',
38+
name='customer_number',
39+
field=models.CharField(editable=False, help_text='System generated customer number.', max_length=30, verbose_name='Customer Number'),
40+
),
41+
migrations.AlterField(
42+
model_name='vendormodel',
43+
name='entity_model',
44+
field=models.ForeignKey(editable=False, on_delete=django.db.models.deletion.CASCADE, to='django_ledger.entitymodel', verbose_name='Vendor Entity'),
45+
),
46+
migrations.AlterField(
47+
model_name='vendormodel',
48+
name='vendor_number',
49+
field=models.CharField(blank=True, editable=False, help_text='System generated vendor number.', max_length=30, null=True, verbose_name='Vendor Number'),
50+
),
51+
]

django_ledger/models/customer.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,32 @@
66
created before it can be assigned to the InvoiceModel. Only customers who are active can be assigned to new Invoices.
77
"""
88

9+
import os
910
from uuid import uuid4
1011

1112
from django.core.exceptions import ObjectDoesNotExist
1213
from django.db import models, transaction, IntegrityError
1314
from django.db.models import Q, F, QuerySet, Manager
15+
from django.utils.text import slugify
1416
from django.utils.translation import gettext_lazy as _
1517

1618
from django_ledger.models.mixins import ContactInfoMixIn, CreateUpdateMixIn, TaxCollectionMixIn
1719
from django_ledger.models.utils import lazy_loader
1820
from django_ledger.settings import DJANGO_LEDGER_DOCUMENT_NUMBER_PADDING, DJANGO_LEDGER_CUSTOMER_NUMBER_PREFIX
1921

2022

23+
def customer_picture_upload_to(instance, filename):
24+
"""
25+
Stores pictures under: customer_pictures/<customer_number>/<sanitized-filename>.<ext>
26+
"""
27+
if not instance.customer_number:
28+
instance.generate_customer_number(commit=False)
29+
customer_number = instance.customer_number
30+
name, ext = os.path.splitext(filename)
31+
safe_name = slugify(name)
32+
return f'customer_pictures/{customer_number}/{safe_name}{ext.lower()}'
33+
34+
2135
class CustomerModelQueryset(QuerySet):
2236
"""
2337
A custom defined QuerySet for the CustomerModel. This implements multiple methods or queries needed to get a
@@ -170,15 +184,24 @@ class CustomerModelAbstract(ContactInfoMixIn, TaxCollectionMixIn, CreateUpdateMi
170184
"""
171185

172186
uuid = models.UUIDField(default=uuid4, editable=False, primary_key=True)
187+
customer_code = models.SlugField(
188+
max_length=50,
189+
unique=True,
190+
null=True,
191+
blank=True,
192+
verbose_name='User defined customer code'
193+
)
173194
customer_name = models.CharField(max_length=100)
174-
customer_number = models.CharField(max_length=30, editable=False, verbose_name=_('Customer Number'))
195+
customer_number = models.CharField(max_length=30, editable=False, verbose_name=_('Customer Number'),
196+
help_text='System generated customer number.')
175197
entity_model = models.ForeignKey('django_ledger.EntityModel',
176198
editable=False,
177199
on_delete=models.CASCADE,
178200
verbose_name=_('Customer Entity'))
179201
description = models.TextField()
180202
active = models.BooleanField(default=True)
181203
hidden = models.BooleanField(default=False)
204+
picture = models.ImageField(upload_to=customer_picture_upload_to, null=True, blank=True)
182205

183206
additional_info = models.JSONField(null=True, blank=True, default=dict)
184207

django_ledger/models/vendor.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,29 @@
1010
whether temporarily or indefinitely may be flagged as inactive (i.e. active is False). Hidden Vendors will not show up
1111
as an option in the UI, but can still be used programmatically (via API).
1212
"""
13-
13+
import os
1414
from uuid import uuid4
1515

1616
from django.core.exceptions import ObjectDoesNotExist, ValidationError
1717
from django.db import models, transaction, IntegrityError
18-
from django.db.models import Q, F, QuerySet
18+
from django.db.models import Q, F, QuerySet, Manager
19+
from django.utils.text import slugify
1920
from django.utils.translation import gettext_lazy as _
2021

2122
from django_ledger.models.mixins import ContactInfoMixIn, CreateUpdateMixIn, FinancialAccountInfoMixin, TaxInfoMixIn
2223
from django_ledger.models.utils import lazy_loader
2324
from django_ledger.settings import DJANGO_LEDGER_DOCUMENT_NUMBER_PADDING, DJANGO_LEDGER_VENDOR_NUMBER_PREFIX
2425

2526

27+
def vendor_picture_upload_to(instance, filename):
28+
if not instance.customer_number:
29+
instance.generate_customer_number(commit=False)
30+
vendor_number = instance.customer_number
31+
name, ext = os.path.splitext(filename)
32+
safe_name = slugify(name)
33+
return f'vendor_pictures/{vendor_number}/{safe_name}{ext.lower()}'
34+
35+
2636
class VendorModelValidationError(ValidationError):
2737
pass
2838

@@ -83,7 +93,7 @@ def visible(self) -> QuerySet:
8393
)
8494

8595

86-
class VendorModelManager(models.Manager):
96+
class VendorModelManager(Manager):
8797
"""
8898
Custom defined VendorModel Manager, which defines many methods for initial query of the Database.
8999
"""
@@ -173,15 +183,27 @@ class VendorModelAbstract(ContactInfoMixIn,
173183
174184
"""
175185
uuid = models.UUIDField(default=uuid4, editable=False, primary_key=True)
176-
vendor_number = models.CharField(max_length=30, null=True, blank=True)
186+
vendor_code = models.SlugField(
187+
max_length=50,
188+
null=True,
189+
blank=True,
190+
verbose_name='User defined vendor code.'
191+
)
192+
vendor_number = models.CharField(max_length=30,
193+
null=True,
194+
blank=True,
195+
editable=False,
196+
verbose_name=_('Vendor Number'), help_text='System generated vendor number.')
177197
vendor_name = models.CharField(max_length=100)
178198

179199
entity_model = models.ForeignKey('django_ledger.EntityModel',
180200
on_delete=models.CASCADE,
181-
verbose_name=_('Vendor Entity'))
201+
verbose_name=_('Vendor Entity'),
202+
editable=False)
182203
description = models.TextField()
183204
active = models.BooleanField(default=True)
184205
hidden = models.BooleanField(default=False)
206+
picture = models.ImageField(upload_to=vendor_picture_upload_to, null=True, blank=True)
185207

186208
additional_info = models.JSONField(null=True, blank=True, default=dict)
187209

@@ -215,7 +237,7 @@ def can_generate_vendor_number(self) -> bool:
215237
Returns
216238
-------
217239
bool
218-
True if vendor number can be generated, else False.
240+
True if the vendor number can be generated, else False.
219241
"""
220242
return all([
221243
self.entity_model_id,

django_ledger/templates/django_ledger/customer/tags/customer_table.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
<th class="has-text-centered">{% trans 'Customer Number' %}</th>
99
<th class="has-text-centered">{% trans 'Customer' %}</th>
1010
<th class="has-text-centered">{% trans 'Address' %}</th>
11+
<th class="has-text-centered">{% trans 'Customer Code' %}</th>
1112
<th class="has-text-centered">{% trans 'Active' %}</th>
1213
<th class="has-text-centered">{% trans 'Hidden' %}</th>
1314
<th class="has-text-centered">{% trans 'Actions' %}</th>
@@ -19,6 +20,7 @@
1920
<td>{{ customer.customer_number }}</td>
2021
<td>{{ customer.customer_name }}</td>
2122
<td>{{ customer.address_1 }}</td>
23+
<td>{% if customer.customer_code %}{{ customer.customer_code }}{% endif %}</td>
2224
<td>
2325
{% if customer.active %}
2426
<span class="icon has-text-success-dark">

django_ledger/templates/django_ledger/entity/entity_dashboard.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@
4747
<section class="hero is-light is-bold is-small">
4848
<div class="hero-body">
4949
<div class="container">
50-
<h1 class="title">{% trans 'Receivables' %}</h1>
51-
<h2 class="subtitle">
50+
<h1 class="is-size-2 is-bold">{% trans 'Receivables' %}</h1>
51+
<h2 class="is-size-5 has-text-weight-light">
5252
<span class="icon">{% icon "ic:baseline-business" 16 %}</span>{{ entity.name }}</h2>
5353
</div>
5454
</div>
@@ -80,8 +80,8 @@ <h2 class="subtitle">
8080
<section class="hero is-light is-bold is-small">
8181
<div class="hero-body">
8282
<div class="container">
83-
<h1 class="title">{% trans 'Payables' %}</h1>
84-
<h2 class="subtitle">
83+
<h1 class="is-size-2 is-bold">{% trans 'Payables' %}</h1>
84+
<h2 class="is-size-5 has-text-weight-light">
8585
<span class="icon">{% icon "ic:baseline-business" 16 %}</span>{{ entity.name }}</h2>
8686
</div>
8787
</div>

django_ledger/templates/django_ledger/includes/page_header.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@
1919
</div>
2020
{% endif %}
2121
<div class="column is-9">
22-
<h1 class="title has-text-weight-light">{{ header_title }}</h1>
22+
<h1 class="is-size-2 is-bold">{{ header_title }}</h1>
2323
{% if header_subtitle %}
24-
<h2 class="subtitle">{{ header_subtitle }}</h2>
24+
<h2 class="is-size-5 has-text-weight-light">{{ header_subtitle }}</h2>
2525
{% endif %}
2626
</div>
2727
</div>

0 commit comments

Comments
 (0)