-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat: Add sync method for bank accounts, dimensions and dimension_values #173
base: master
Are you sure you want to change the base?
Changes from all commits
2cba6e8
44c18a3
83ede99
085d86c
c638418
382a3a4
3e3e4fe
86701d5
1f1295d
70ba7b8
c2ecbed
a028652
280e1d4
271ef81
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -182,3 +182,43 @@ def get_location_id(accounting_export: AccountingExport, lineitem: Expense): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if mapping: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
location_id = mapping.destination.destination_id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return location_id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
def get_dimension_object(accounting_export: AccountingExport, lineitem: Expense): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mapping_settings = MappingSetting.objects.filter(workspace_id=accounting_export.workspace_id).all() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dimensions = [] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
default_expense_attributes = ['CATEGORY', 'EMPLOYEE'] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
default_destination_attributes = ['COMPANIES', 'ACCOUNTS', 'VENDORS', 'EMPLOYEES', 'LOCATIONS', 'BANK_ACCOUNTS'] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
for setting in mapping_settings: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if setting.source_field not in default_expense_attributes and \ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
setting.destination_field not in default_destination_attributes: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if setting.source_field == 'PROJECT': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
source_value = lineitem.project | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
elif setting.source_field == 'COST_CENTER': | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
source_value = lineitem.cost_center | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
attribute = ExpenseAttribute.objects.filter( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
attribute_type=setting.source_field, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
workspace_id=accounting_export.workspace_id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
).first() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
source_value = lineitem.custom_properties.get(attribute.display_name, None) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+196
to
+206
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Optimize database queries and add error handling. The current implementation may cause N+1 query issues and lacks error handling for missing attributes. Consider these improvements:
def get_dimension_object(accounting_export: AccountingExport, lineitem: Expense):
mapping_settings = MappingSetting.objects.filter(workspace_id=accounting_export.workspace_id).all()
+ expense_attributes = {
+ attr.attribute_type: attr.display_name
+ for attr in ExpenseAttribute.objects.filter(
+ workspace_id=accounting_export.workspace_id
+ )
+ }
else:
- attribute = ExpenseAttribute.objects.filter(
- attribute_type=setting.source_field,
- workspace_id=accounting_export.workspace_id
- ).first()
- source_value = lineitem.custom_properties.get(attribute.display_name, None)
+ display_name = expense_attributes.get(setting.source_field)
+ if not display_name:
+ continue
+ source_value = lineitem.custom_properties.get(display_name)
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mapping: Mapping = Mapping.objects.filter( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
source_type=setting.source_field, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
destination_type=setting.destination_field, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
source__value=source_value, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
workspace_id=accounting_export.workspace_id | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
).first() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if mapping: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dimension_data = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'id': mapping.destination.detail['dimension_id'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'code': mapping.destination.attribute_type, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'valueId': mapping.destination.destination_id, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'valueCode': mapping.destination.detail['code'], | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
'expense_number': lineitem.expense_number | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
dimensions.append(dimension_data) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return dimensions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+207
to
+224
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add validation and optimize mapping lookups. The current implementation lacks validation for required fields and may have performance issues with mapping lookups. Consider these improvements:
def get_dimension_object(accounting_export: AccountingExport, lineitem: Expense):
mapping_settings = MappingSetting.objects.filter(workspace_id=accounting_export.workspace_id).all()
+ # Prefetch all mappings for the workspace
+ all_mappings = {
+ (m.source_type, m.source.value): m
+ for m in Mapping.objects.filter(
+ workspace_id=accounting_export.workspace_id
+ ).select_related('destination')
+ }
- mapping: Mapping = Mapping.objects.filter(
- source_type=setting.source_field,
- destination_type=setting.destination_field,
- source__value=source_value,
- workspace_id=accounting_export.workspace_id
- ).first()
+ mapping = all_mappings.get((setting.source_field, source_value))
if mapping:
+ detail = mapping.destination.detail
+ if not all(k in detail for k in ['dimension_id', 'code']):
+ continue
+
dimension_data = {
- 'id': mapping.destination.detail['dimension_id'],
+ 'id': detail['dimension_id'],
'code': mapping.destination.attribute_type,
'valueId': mapping.destination.destination_id,
- 'valueCode': mapping.destination.detail['code'],
+ 'valueCode': detail['code'],
'expense_number': lineitem.expense_number
}
dimensions.append(dimension_data) 📝 Committable suggestion
Suggested change
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,4 +1,6 @@ | ||||||
from django.db import models | ||||||
from django.db.models import JSONField | ||||||
|
||||||
from fyle_accounting_mappings.models import CategoryMapping | ||||||
|
||||||
from apps.accounting_exports.models import AccountingExport | ||||||
|
@@ -39,22 +41,24 @@ def create_or_update_object(self, accounting_export: AccountingExport, _: Advanc | |||||
:param accounting_export: expense group | ||||||
:return: purchase invoices object | ||||||
""" | ||||||
expenses = accounting_export.expenses.all() | ||||||
expense = accounting_export.expenses.first() | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for missing expense. The code assumes an expense will always exist. Add proper error handling for cases where no expense is found. - expense = accounting_export.expenses.first()
+ expense = accounting_export.expenses.first()
+ if not expense:
+ raise ValueError('No expense found for this accounting export')
document_number = expense.expense_number Also applies to: 52-54 |
||||||
|
||||||
accounts_payable_account_id = export_settings.default_bank_account_id | ||||||
|
||||||
document_number = accounting_export.description['claim_number'] if accounting_export.description and accounting_export.description.get('claim_number') else accounting_export.description['expense_number'] | ||||||
advance_setting = AdvancedSetting.objects.get(workspace_id=accounting_export.workspace_id) | ||||||
|
||||||
document_number = expense.expense_number | ||||||
|
||||||
comment = "Consolidated Credit Entry For Report/Expense {}".format(document_number) | ||||||
comment = self.get_expense_comment(accounting_export.workspace_id, expense, expense.category, advance_setting) | ||||||
|
||||||
invoice_date = self.get_invoice_date(accounting_export=accounting_export) | ||||||
|
||||||
account_type, account_id = self.get_account_id_type(accounting_export=accounting_export, export_settings=export_settings) | ||||||
account_type, account_id = self.get_account_id_type(accounting_export=accounting_export, export_settings=export_settings, merchant=expense.vendor) | ||||||
|
||||||
journal_entry_object, _ = JournalEntry.objects.update_or_create( | ||||||
accounting_export= accounting_export, | ||||||
defaults={ | ||||||
'amount': sum([expense.amount for expense in expenses]), | ||||||
'amount': expense.amount, | ||||||
'document_number': document_number, | ||||||
'accounts_payable_account_id': accounts_payable_account_id, | ||||||
'account_id': account_id, | ||||||
|
@@ -83,6 +87,9 @@ class JournalEntryLineItems(BaseExportModel): | |||||
invoice_date = CustomDateTimeField(help_text='date of invoice') | ||||||
document_number = TextNotNullField(help_text='document number of the invoice') | ||||||
journal_entry = models.ForeignKey(JournalEntry, on_delete=models.PROTECT, help_text='Journal Entry reference', related_name='journal_entry_lineitems') | ||||||
dimensions = JSONField(default=list, help_text='Business Central dimensions') | ||||||
dimension_error_log = JSONField(null=True, help_text='dimension set response log') | ||||||
dimension_success_log = JSONField(null=True, help_text='dimension set success response log') | ||||||
|
||||||
class Meta: | ||||||
db_table = 'journal_entries_lineitems' | ||||||
|
@@ -94,42 +101,44 @@ def create_or_update_object(self, accounting_export: AccountingExport, advance_s | |||||
:param accounting_export: expense group | ||||||
:return: purchase invoices object | ||||||
""" | ||||||
expenses = accounting_export.expenses.all() | ||||||
lineitem = accounting_export.expenses.first() | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for missing journal entry. Add proper error handling for cases where journal entry or category mapping is not found. lineitem = accounting_export.expenses.first()
+ if not lineitem:
+ raise ValueError('No expense found for this accounting export')
+
journal_entry = JournalEntry.objects.get(accounting_export=accounting_export)
+ if not journal_entry:
+ raise ValueError('No journal entry found for this accounting export')
# ... later in the code ...
account = CategoryMapping.objects.filter(
source_category__value=category,
workspace_id=accounting_export.workspace_id
).first()
+ if not account:
+ raise ValueError(f'No category mapping found for category: {category}') Also applies to: 128-143 |
||||||
journal_entry = JournalEntry.objects.get(accounting_export=accounting_export) | ||||||
|
||||||
journal_entry_lineitems = [] | ||||||
|
||||||
for lineitem in expenses: | ||||||
category = lineitem.category if (lineitem.category == lineitem.sub_category or lineitem.sub_category == None) else '{0} / {1}'.format(lineitem.category, lineitem.sub_category) | ||||||
|
||||||
account = CategoryMapping.objects.filter( | ||||||
source_category__value=category, | ||||||
workspace_id=accounting_export.workspace_id | ||||||
).first() | ||||||
|
||||||
comment = self.get_expense_comment(accounting_export.workspace_id, lineitem, lineitem.category, advance_setting) | ||||||
|
||||||
invoice_date = self.get_invoice_date(accounting_export=accounting_export) | ||||||
|
||||||
account_type, account_id = self.get_account_id_type(accounting_export=accounting_export, export_settings=export_settings, merchant=lineitem.vendor) | ||||||
|
||||||
document_number = accounting_export.description['claim_number'] if accounting_export.description and accounting_export.description.get('claim_number') else accounting_export.description['expense_number'] | ||||||
|
||||||
journal_entry_lineitems_object, _ = JournalEntryLineItems.objects.update_or_create( | ||||||
journal_entry_id = journal_entry.id, | ||||||
expense_id=lineitem.id, | ||||||
defaults={ | ||||||
'amount': lineitem.amount * -1, | ||||||
'account_id': account_id, | ||||||
'account_type': account_type, | ||||||
'document_number': document_number, | ||||||
'accounts_payable_account_id': account.destination_account.destination_id, | ||||||
'comment': comment, | ||||||
'workspace_id': accounting_export.workspace_id, | ||||||
'invoice_date': invoice_date, | ||||||
'description': lineitem.purpose if lineitem.purpose else None | ||||||
} | ||||||
) | ||||||
journal_entry_lineitems.append(journal_entry_lineitems_object) | ||||||
category = lineitem.category if (lineitem.category == lineitem.sub_category or lineitem.sub_category == None) else '{0} / {1}'.format(lineitem.category, lineitem.sub_category) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix None comparison style. Use Python's identity comparison for None. - category = lineitem.category if (lineitem.category == lineitem.sub_category or lineitem.sub_category == None) else '{0} / {1}'.format(lineitem.category, lineitem.sub_category)
+ category = lineitem.category if (lineitem.category == lineitem.sub_category or lineitem.sub_category is None) else '{0} / {1}'.format(lineitem.category, lineitem.sub_category) 📝 Committable suggestion
Suggested change
🧰 Tools🪛 Ruff (0.7.0)111-111: Comparison to Replace with (E711) |
||||||
|
||||||
account = CategoryMapping.objects.filter( | ||||||
source_category__value=category, | ||||||
workspace_id=accounting_export.workspace_id | ||||||
).first() | ||||||
Comment on lines
+111
to
+114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Optimize database query for CategoryMapping. The current implementation might lead to N+1 query issues. Consider prefetching related fields and adding appropriate indexes. + from django.db.models import Index
class CategoryMapping(models.Model):
class Meta:
indexes = [
Index(fields=['source_category', 'workspace_id']),
] Also, consider caching the mapping results if they're frequently accessed: from django.core.cache import cache
def get_category_mapping(category, workspace_id):
cache_key = f'category_mapping_{workspace_id}_{category}'
mapping = cache.get(cache_key)
if mapping is None:
mapping = CategoryMapping.objects.filter(
source_category__value=category,
workspace_id=workspace_id
).first()
cache.set(cache_key, mapping, timeout=3600) # Cache for 1 hour
return mapping
Comment on lines
+104
to
+114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Optimize database queries. The current implementation makes multiple separate database queries which could lead to N+1 query issues. Consider these optimizations:
lineitem = accounting_export.expenses.select_related('expense_number', 'category', 'sub_category', 'vendor').first()
class CategoryMapping(models.Model):
class Meta:
indexes = [
models.Index(fields=['source_category', 'workspace_id']),
] 🧰 Tools🪛 Ruff (0.7.0)109-109: Comparison to Replace with (E711) |
||||||
|
||||||
comment = self.get_expense_comment(accounting_export.workspace_id, lineitem, lineitem.category, advance_setting) | ||||||
|
||||||
invoice_date = self.get_invoice_date(accounting_export=accounting_export) | ||||||
|
||||||
account_type, account_id = self.get_account_id_type(accounting_export=accounting_export, export_settings=export_settings, merchant=lineitem.vendor) | ||||||
|
||||||
document_number = lineitem.expense_number | ||||||
|
||||||
dimensions = self.get_dimension_object(accounting_export, lineitem) | ||||||
|
||||||
Comment on lines
+124
to
+125
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling for dimension retrieval. The Apply this diff: - dimensions = self.get_dimension_object(accounting_export, lineitem)
+ try:
+ dimensions = self.get_dimension_object(accounting_export, lineitem)
+ except Exception as e:
+ dimensions = []
+ # Log the error or handle it appropriately
+ logger.error(f'Failed to get dimensions for expense {lineitem.id}: {str(e)}')
|
||||||
journal_entry_lineitems_object, _ = JournalEntryLineItems.objects.update_or_create( | ||||||
journal_entry_id = journal_entry.id, | ||||||
expense_id=lineitem.id, | ||||||
defaults={ | ||||||
'amount': lineitem.amount * -1, | ||||||
'account_id': account_id, | ||||||
'account_type': account_type, | ||||||
'document_number': document_number, | ||||||
'accounts_payable_account_id': account.destination_account.destination_id, | ||||||
'comment': comment, | ||||||
'workspace_id': accounting_export.workspace_id, | ||||||
'invoice_date': invoice_date, | ||||||
'description': lineitem.purpose if lineitem.purpose else None, | ||||||
'dimensions': dimensions | ||||||
} | ||||||
) | ||||||
journal_entry_lineitems.append(journal_entry_lineitems_object) | ||||||
|
||||||
return journal_entry_lineitems |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,8 @@ | |
from apps.business_central.utils import BusinessCentralConnector | ||
from apps.workspaces.models import BusinessCentralCredentials | ||
|
||
from fyle_accounting_mappings.models import DestinationAttribute | ||
|
||
logger = logging.getLogger(__name__) | ||
logger.level = logging.INFO | ||
|
||
|
@@ -40,6 +42,13 @@ def __construct_journal_entry(self, body: JournalEntry, lineitems: List[JournalE | |
:return: constructed expense_report | ||
''' | ||
batch_journal_entry_payload = [] | ||
dimensions = [] | ||
|
||
account_attribute_type = DestinationAttribute.objects.filter(workspace_id=body.workspace_id, destination_id=body.accounts_payable_account_id).first() | ||
|
||
balance_account_type = 'G/L Account' | ||
if account_attribute_type and account_attribute_type.attribute_type == 'BANK_ACCOUNT': | ||
balance_account_type = 'Bank Account' | ||
|
||
journal_entry_payload = { | ||
'accountType': body.account_type, | ||
|
@@ -49,14 +58,18 @@ def __construct_journal_entry(self, body: JournalEntry, lineitems: List[JournalE | |
'amount': body.amount, | ||
'comment': body.comment, | ||
'description': body.description, | ||
'balanceAccountType': 'G/L Account', | ||
'balanceAccountType': balance_account_type, | ||
'balancingAccountNumber': body.accounts_payable_account_id | ||
|
||
} | ||
|
||
batch_journal_entry_payload.append(journal_entry_payload) | ||
|
||
for lineitem in lineitems: | ||
for dimension in lineitem.dimensions: | ||
dimension['exported_module_id'] = lineitem.id | ||
|
||
dimensions.extend(lineitem.dimensions) | ||
Comment on lines
+69
to
+72
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handle potential If Apply this diff to handle possible for lineitem in lineitems:
+ if lineitem.dimensions:
for dimension in lineitem.dimensions:
dimension['exported_module_id'] = lineitem.id
dimensions.extend(lineitem.dimensions)
|
||
journal_entry_lineitem_payload = { | ||
'accountType': lineitem.account_type, | ||
'accountNumber': lineitem.account_id, | ||
|
@@ -65,30 +78,39 @@ def __construct_journal_entry(self, body: JournalEntry, lineitems: List[JournalE | |
'amount': lineitem.amount, | ||
'comment': lineitem.comment, | ||
'description': lineitem.description if lineitem.description else '', | ||
'balanceAccountType': 'G/L Account', | ||
'balanceAccountType': balance_account_type, | ||
'balancingAccountNumber': lineitem.accounts_payable_account_id | ||
} | ||
|
||
batch_journal_entry_payload.append(journal_entry_lineitem_payload) | ||
|
||
return batch_journal_entry_payload | ||
return batch_journal_entry_payload, dimensions | ||
|
||
def post(self, accounting_export, item, lineitem): | ||
''' | ||
Export the Journal Entry to Business Central. | ||
''' | ||
|
||
batch_journal_entry_payload = self.__construct_journal_entry(item, lineitem) | ||
logger.info('WORKSPACE_ID: {0}, ACCOUNTING_EXPORT_ID: {1}, BATCH_PURCHASE_INVOICE_PAYLOAD: {2}'.format(accounting_export.workspace_id, accounting_export.id, batch_journal_entry_payload)) | ||
batch_journal_entry_payload, dimensions = self.__construct_journal_entry(item, lineitem) | ||
logger.info('WORKSPACE_ID: {0}, ACCOUNTING_EXPORT_ID: {1}, JOURNAL_ENTRY_PAYLOAD: {2}'.format(accounting_export.workspace_id, accounting_export.id, batch_journal_entry_payload)) | ||
business_central_credentials = BusinessCentralCredentials.get_active_business_central_credentials(accounting_export.workspace_id) | ||
# Establish a connection to Business Central | ||
business_central_connection = BusinessCentralConnector(business_central_credentials, accounting_export.workspace_id) | ||
|
||
# Post the journal entry to Business Central | ||
response = business_central_connection.bulk_post_journal_lineitems(batch_journal_entry_payload, accounting_export) | ||
|
||
expenses = accounting_export.expenses.all() | ||
if dimensions: | ||
dimension_set_line_payloads = self.construct_dimension_set_line_payload(dimensions, response['responses']) | ||
logger.info('WORKSPACE_ID: {0}, ACCOUNTING_EXPORT_ID: {1}, DIMENSION_SET_LINE_PAYLOADS: {2}'.format(accounting_export.workspace_id, accounting_export.id, dimension_set_line_payloads)) | ||
dimension_line_responses = ( | ||
business_central_connection.post_dimension_lines( | ||
dimension_set_line_payloads, "JOURNAL_ENTRY", item.id | ||
) | ||
) | ||
response["dimension_line_responses"] = dimension_line_responses | ||
|
||
expenses = accounting_export.expenses.all() | ||
# Load attachments to Business Central | ||
for i in range(1, len(response["responses"])): | ||
load_attachments( | ||
|
@@ -100,6 +122,23 @@ def post(self, accounting_export, item, lineitem): | |
|
||
return response | ||
|
||
def construct_dimension_set_line_payload(self, dimensions: list, exported_response: dict): | ||
""" | ||
construct payload for setting dimension for Journal Entry | ||
""" | ||
|
||
dimension_payload = [] | ||
|
||
for response in exported_response: | ||
parent_id = response['body']['id'] | ||
for dimension in dimensions: | ||
dimension_copy = dimension.copy() | ||
dimension_copy.pop('expense_number') | ||
dimension_copy['parentId'] = parent_id | ||
dimension_payload.append(dimension_copy) | ||
|
||
return dimension_payload | ||
|
||
Comment on lines
+125
to
+141
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Potential mismatch when associating dimensions with journal entries. In the Consider modifying the code to correctly associate each dimension with its corresponding journal entry. Here's a possible refactor: def construct_dimension_set_line_payload(self, dimensions: list, exported_response: list):
"""
Construct payload for setting dimensions for Journal Entry
"""
dimension_payload = []
+ # Assuming that dimensions and exported_response are in the same order
+ for response, dimension in zip(exported_response, dimensions):
parent_id = response['body']['id']
- for dimension in dimensions:
dimension_copy = dimension.copy()
dimension_copy.pop('expense_number', None)
dimension_copy['parentId'] = parent_id
dimension_payload.append(dimension_copy)
return dimension_payload This change ensures that each dimension is correctly linked to its corresponding journal entry.
|
||
|
||
@handle_business_central_exceptions() | ||
def create_journal_entry(accounting_export: AccountingExport, last_export: bool): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Add type hints and documentation.
The method signature could be improved with type hints and documentation for better maintainability and clarity.
Apply this diff:
📝 Committable suggestion