diff --git a/apps/business_central/exports/journal_entry/models.py b/apps/business_central/exports/journal_entry/models.py index 230b37b..acff462 100644 --- a/apps/business_central/exports/journal_entry/models.py +++ b/apps/business_central/exports/journal_entry/models.py @@ -85,8 +85,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(null=True, help_text='Business Central dimensions') + 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' diff --git a/apps/business_central/exports/journal_entry/tasks.py b/apps/business_central/exports/journal_entry/tasks.py index 1b3d209..504e8ce 100644 --- a/apps/business_central/exports/journal_entry/tasks.py +++ b/apps/business_central/exports/journal_entry/tasks.py @@ -92,13 +92,12 @@ def post(self, accounting_export, item, lineitem): # Post the journal entry to Business Central response = business_central_connection.bulk_post_journal_lineitems(batch_journal_entry_payload, accounting_export) - 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" + dimension_set_line_payloads, "JOURNAL_ENTRY", item.id ) ) response["dimension_line_responses"] = dimension_line_responses @@ -119,30 +118,18 @@ def post(self, accounting_export, item, lineitem): def construct_dimension_set_line_payload(self, dimensions: list, exported_response: dict): """ - construct payload for setting dimension for Purchase Invoice + construct payload for setting dimension for Journal Entry """ - - dimension = dimensions[0] - - #we are only supporting grouping by expense for JE, so only two payloads will always exist - # one for each line - dimension_payload = [ - { - "id": dimension['id'], - "code": dimension['code'], - "parentId": exported_response[0]['body']['id'], - "valueId": dimension['valueId'], - "valueCode": dimension['valueCode'], - "exported_module_id": dimension['exported_module_id'] - }, - { - "id": dimension['id'], - "code": dimension['code'], - "parentId": exported_response[1]['body']['id'], - "valueId": dimension['valueId'], - "valueCode": dimension['valueCode'], - "exported_module_id": dimension['exported_module_id'] - }] + + 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 diff --git a/apps/business_central/exports/purchase_invoice/models.py b/apps/business_central/exports/purchase_invoice/models.py index c911fd7..0379955 100644 --- a/apps/business_central/exports/purchase_invoice/models.py +++ b/apps/business_central/exports/purchase_invoice/models.py @@ -63,8 +63,9 @@ class PurchaseInvoiceLineitems(BaseExportModel): amount = FloatNullField(help_text='Amount of the invoice') description = TextNotNullField(help_text='description for the invoice') location_id = StringNullField(help_text='location id of the invoice') - dimensions = JSONField(null=True, help_text='Business Central dimensions') + 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 = 'purchase_invoice_lineitems' diff --git a/apps/business_central/exports/purchase_invoice/tasks.py b/apps/business_central/exports/purchase_invoice/tasks.py index abb0fc0..4c49c0a 100644 --- a/apps/business_central/exports/purchase_invoice/tasks.py +++ b/apps/business_central/exports/purchase_invoice/tasks.py @@ -50,6 +50,11 @@ def __construct_purchase_invoice(self, body: PurchaseInvoice, lineitems: List[Pu } for lineitem in lineitems: + for dimension in lineitem.dimensions: + dimension['exported_module_id'] = lineitem.id + + print('lineitem.dimensions', lineitem.dimensions) + dimensions.extend(lineitem.dimensions) purchase_invoice_lineitem_payload = { "lineType": "Account", @@ -80,18 +85,13 @@ def post(self, accounting_export, item, lineitem): response = business_central_connection.post_purchase_invoice(purchase_invoice_payload, batch_purchase_invoice_payload) - try: - if dimensions: - dimension_set_line_payloads = self.construct_dimension_set_line_payload(dimensions, response['bulk_post_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, 'PURCHASE_INVOICE' - ) - response['dimension_line_responses'] = dimension_line_responses - except Exception as exception: - lineitem.dimension_error_log = str(exception.response) - response['dimension_line_responses'] = str(exception.response) - lineitem.save() + if dimensions: + dimension_set_line_payloads = self.construct_dimension_set_line_payload(dimensions, response['bulk_post_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, 'PURCHASE_INVOICE', item.id + ) + response['dimension_line_responses'] = dimension_line_responses expenses = accounting_export.expenses.all() @@ -131,7 +131,8 @@ def construct_dimension_set_line_payload(self, dimensions: list, exported_respon "code": dimension['code'], "parentId": parent_id, "valueId": dimension['valueId'], - "valueCode": dimension['valueCode'] + "valueCode": dimension['valueCode'], + "exported_module_id": dimension['exported_module_id'] }) return dimension_payload diff --git a/apps/business_central/migrations/0004_journalentrylineitems_dimension_success_log_and_more.py b/apps/business_central/migrations/0004_journalentrylineitems_dimension_success_log_and_more.py new file mode 100644 index 0000000..027eaeb --- /dev/null +++ b/apps/business_central/migrations/0004_journalentrylineitems_dimension_success_log_and_more.py @@ -0,0 +1,33 @@ +# Generated by Django 4.1.2 on 2024-11-21 09:04 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('business_central', '0003_journalentrylineitems_dimension_error_log_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='journalentrylineitems', + name='dimension_success_log', + field=models.JSONField(help_text='dimension set success response log', null=True), + ), + migrations.AddField( + model_name='purchaseinvoicelineitems', + name='dimension_success_log', + field=models.JSONField(help_text='dimension set success response log', null=True), + ), + migrations.AlterField( + model_name='journalentrylineitems', + name='dimensions', + field=models.JSONField(default=list, help_text='Business Central dimensions'), + ), + migrations.AlterField( + model_name='purchaseinvoicelineitems', + name='dimensions', + field=models.JSONField(default=list, help_text='Business Central dimensions'), + ), + ] diff --git a/apps/business_central/utils.py b/apps/business_central/utils.py index 3c0eab0..10dc100 100644 --- a/apps/business_central/utils.py +++ b/apps/business_central/utils.py @@ -295,32 +295,50 @@ def post_purchase_invoice(self, purchase_invoice_payload, purchase_invoice_linei } return response - def post_dimension_lines(self, dimension_line_payloads: List[Dict], export_module_type: str): + def post_dimension_lines(self, dimension_line_payloads: List[Dict], export_module_type: str, top_level_id: int) -> List[Dict]: """ - Post dimension line for purchase invoice line and Journal line item + Post dimension lines for purchase invoice line and journal line items. + + :param dimension_line_payloads: List of payload dictionaries for dimension lines. + :param export_module_type: Type of export module ('JOURNAL_ENTRY' and 'PURCHASE_INVOICE'). + :return: List of exception responses, if any. """ exception_response = [] + def get_lineitem_by_id(module_type: str, item_id: int): + if module_type == 'JOURNAL_ENTRY': + return JournalEntryLineItems.objects.get(id=item_id, journal_entry_id=top_level_id) + else: + return PurchaseInvoiceLineitems.objects.get(id=item_id, purchase_invoice_id=top_level_id) + for dimension_line_payload in dimension_line_payloads: - exported_module_id = dimension_line_payload['exported_module_id'] - dimension_line_payload.pop('exported_module_id') + exported_module_id = dimension_line_payload.pop('exported_module_id') + try: if export_module_type == 'JOURNAL_ENTRY': - response = self.connection.journal_line_items.post_journal_entry_dimensions(journal_line_item_id=dimension_line_payload['parentId'], data=dimension_line_payload) - else: - response = self.connection.purchase_invoice_line_items.post_purchase_invoice_dimensions(purchase_invoice_item_id=dimension_line_payload['parentId'], data=dimension_line_payload) - except Exception as exception: - if export_module_type == 'JOURNAL_ENTRY': - lineitem = JournalEntryLineItems.objects.get(id=exported_module_id) + response = self.connection.journal_line_items.post_journal_entry_dimensions( + journal_line_item_id=dimension_line_payload['parentId'], + data=dimension_line_payload + ) else: - lineitem = PurchaseInvoiceLineitems.objects.get(id=exported_module_id) + response = self.connection.purchase_invoice_line_items.post_purchase_invoice_dimensions( + purchase_invoice_item_id=dimension_line_payload['parentId'], + data=dimension_line_payload + ) - lineitem.dimension_error_log = str(exception.response) + lineitem = get_lineitem_by_id(export_module_type, exported_module_id) + lineitem.dimension_success_log = str(response) lineitem.save() - exception_response.append(str(exception.response)) - + + except Exception as exception: + lineitem = get_lineitem_by_id(export_module_type, exported_module_id) + error_message = str(getattr(exception, 'response', exception)) + lineitem.dimension_error_log = error_message + lineitem.save() + return exception_response + def post_attachments( self, ref_type: str, ref_id: str, attachments: List[Dict] ) -> List: