Merge pull request #181 from eitchtee/dev

fix(export): unable to import decimals
This commit is contained in:
Herculino Trotta
2025-02-19 15:44:50 -03:00
committed by GitHub
6 changed files with 74 additions and 10 deletions

View File

@@ -2,13 +2,15 @@ from import_export import fields, resources, widgets
from apps.accounts.models import Account
from apps.currencies.models import Currency, ExchangeRate, ExchangeRateService
from apps.export_app.widgets.foreign_key import SkipMissingForeignKeyWidget
from apps.export_app.widgets.numbers import UniversalDecimalWidget
class CurrencyResource(resources.ModelResource):
exchange_currency = fields.Field(
attribute="exchange_currency",
column_name="exchange_currency",
widget=widgets.ForeignKeyWidget(Currency, "name"),
widget=SkipMissingForeignKeyWidget(Currency, "name"),
)
class Meta:
@@ -26,6 +28,9 @@ class ExchangeRateResource(resources.ModelResource):
column_name="to_currency",
widget=widgets.ForeignKeyWidget(Currency, "name"),
)
rate = fields.Field(
attribute="rate", column_name="rate", widget=UniversalDecimalWidget()
)
class Meta:
model = ExchangeRate

View File

@@ -3,6 +3,7 @@ from import_export.widgets import ForeignKeyWidget
from apps.dca.models import DCAStrategy, DCAEntry
from apps.currencies.models import Currency
from apps.export_app.widgets.numbers import UniversalDecimalWidget
class DCAStrategyResource(resources.ModelResource):
@@ -22,5 +23,16 @@ class DCAStrategyResource(resources.ModelResource):
class DCAEntryResource(resources.ModelResource):
amount_paid = fields.Field(
attribute="amount_paid",
column_name="amount_paid",
widget=UniversalDecimalWidget(),
)
amount_received = fields.Field(
attribute="amount_received",
column_name="amount_received",
widget=UniversalDecimalWidget(),
)
class Meta:
model = DCAEntry

View File

@@ -13,6 +13,7 @@ from apps.transactions.models import (
RecurringTransaction,
InstallmentPlan,
)
from apps.export_app.widgets.numbers import UniversalDecimalWidget
class TransactionResource(resources.ModelResource):
@@ -44,6 +45,12 @@ class TransactionResource(resources.ModelResource):
column_name="internal_id", attribute="internal_id"
)
amount = fields.Field(
attribute="amount",
column_name="amount",
widget=UniversalDecimalWidget(),
)
class Meta:
model = Transaction
@@ -91,6 +98,12 @@ class RecurringTransactionResource(resources.ModelResource):
widget=AutoCreateManyToManyWidget(TransactionEntity, field="name"),
)
amount = fields.Field(
attribute="amount",
column_name="amount",
widget=UniversalDecimalWidget(),
)
class Meta:
model = RecurringTransaction
@@ -120,5 +133,11 @@ class InstallmentPlanResource(resources.ModelResource):
widget=AutoCreateManyToManyWidget(TransactionEntity, field="name"),
)
installment_amount = fields.Field(
attribute="installment_amount",
column_name="installment_amount",
widget=UniversalDecimalWidget(),
)
class Meta:
model = InstallmentPlan

View File

@@ -240,11 +240,6 @@ def process_imports(request, cleaned_data):
dataset = Dataset()
dataset.load(content, format="csv")
# Debug logging
logger.debug(f"Importing {field_name}")
logger.debug(f"Headers: {dataset.headers}")
logger.debug(f"First row: {dataset[0] if len(dataset) > 0 else 'No data'}")
# Perform the import
result = resource.import_data(
dataset,
@@ -265,6 +260,8 @@ def process_imports(request, cleaned_data):
raise ImportError(f"Error importing {field_name}: {str(e)}")
with transaction.atomic():
files = {}
if zip_file := cleaned_data.get("zip_file"):
# Process ZIP file
with zipfile.ZipFile(zip_file) as z:
@@ -273,10 +270,12 @@ def process_imports(request, cleaned_data):
with z.open(filename) as f:
content = f.read().decode("utf-8")
for field_name, resource_class in import_order:
if name == field_name:
import_dataset(content, resource_class, field_name)
break
files[name] = content
for field_name, resource_class in import_order:
if field_name in files.keys():
content = files[field_name]
import_dataset(content, resource_class, field_name)
else:
# Process individual files
for field_name, resource_class in import_order:

View File

@@ -9,3 +9,14 @@ class AutoCreateForeignKeyWidget(ForeignKeyWidget):
except self.model.DoesNotExist:
return self.model.objects.create(name=value)
return None
class SkipMissingForeignKeyWidget(ForeignKeyWidget):
def clean(self, value, row=None, *args, **kwargs):
if not value:
return None
try:
return super().clean(value, row, *args, **kwargs)
except self.model.DoesNotExist:
return None

View File

@@ -0,0 +1,18 @@
from decimal import Decimal
from import_export.widgets import NumberWidget
class UniversalDecimalWidget(NumberWidget):
def clean(self, value, row=None, *args, **kwargs):
if self.is_empty(value):
return None
# Replace comma with dot if present
if isinstance(value, str):
value = value.replace(",", ".")
return Decimal(str(value))
def render(self, value, obj=None, **kwargs):
if value is None:
return ""
return str(value).replace(",", ".")