From aaba4481c24dbe8795e078e68a08cd06007f1976 Mon Sep 17 00:00:00 2001 From: Viswas Date: Mon, 18 Nov 2024 21:54:29 +0530 Subject: [PATCH 1/2] feat: support GET and PUT for `split_expense_grouping` in export settings --- apps/workspaces/apis/export_settings/serializers.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/workspaces/apis/export_settings/serializers.py b/apps/workspaces/apis/export_settings/serializers.py index 9ae83898..f771876b 100644 --- a/apps/workspaces/apis/export_settings/serializers.py +++ b/apps/workspaces/apis/export_settings/serializers.py @@ -85,6 +85,7 @@ class ExpenseGroupSettingsSerializer(serializers.ModelSerializer): corporate_credit_card_expense_group_fields = serializers.ListField(allow_null=True, required=False) ccc_export_date_type = serializers.CharField(allow_null=True, allow_blank=True, required=False) ccc_expense_state = serializers.CharField(allow_null=True, allow_blank=True, required=False) + split_expense_grouping = serializers.CharField(allow_null=False, allow_blank=False, required=True) class Meta: model = ExpenseGroupSettings @@ -94,7 +95,8 @@ class Meta: 'expense_state', 'corporate_credit_card_expense_group_fields', 'ccc_export_date_type', - 'ccc_expense_state' + 'ccc_expense_state', + 'split_expense_grouping' ] From 1e79de2ec4dc9029466fef4ec3b60a11690d21d4 Mon Sep 17 00:00:00 2001 From: Viswas Haridas <37623357+JustARatherRidiculouslyLongUsername@users.noreply.github.com> Date: Mon, 25 Nov 2024 12:55:02 +0530 Subject: [PATCH 2/2] feat: implement split expense grouping functionality (#675) * feat: implement split expense grouping functionality * feat: add script for split expense grouping (#676) * feat: add script for split expense grouping Set the default split expense grouping config to SINGLE_LINE_ITEM for all old orgs * test: add missing fixtures * feat: support multiple line items for CC charge exports (#677) * feat: support multiple line items for CC charge exports * test: update tests to account for the new function signature * test: update tests and fixtures Account for tax balancing and credit card charge lineitems changes * refactor: move url out of `for` loop --- apps/fyle/models.py | 47 +++++- apps/netsuite/connector.py | 76 +++++----- apps/netsuite/models.py | 134 +++++++++--------- apps/netsuite/tasks.py | 9 +- ...lt-split-expense-grouping-for-old-orgs.sql | 5 + tests/test_fyle/fixtures.py | 6 + tests/test_netsuite/conftest.py | 2 +- tests/test_netsuite/test_connector.py | 26 ++-- tests/test_netsuite/test_models.py | 18 +-- 9 files changed, 190 insertions(+), 133 deletions(-) create mode 100644 scripts/sql/scripts/030-default-split-expense-grouping-for-old-orgs.sql diff --git a/apps/fyle/models.py b/apps/fyle/models.py index c7529655..4182d338 100644 --- a/apps/fyle/models.py +++ b/apps/fyle/models.py @@ -25,7 +25,8 @@ ALLOWED_FIELDS = [ 'employee_email', 'report_id', 'claim_number', 'settlement_id', 'fund_source', 'vendor', 'category', 'project', 'cost_center', - 'verified_at', 'approved_at', 'spent_at', 'expense_id', 'posted_at' + 'verified_at', 'approved_at', 'spent_at', 'expense_id', 'posted_at', + 'bank_transaction_id' ] @@ -375,6 +376,7 @@ def create_expense_groups_by_report_id_fund_source(expense_objects: List[Expense """ expense_group_settings = ExpenseGroupSettings.objects.get(workspace_id=workspace_id) + # Group Reimbursable Expenses reimbursable_expense_group_fields = expense_group_settings.reimbursable_expense_group_fields reimbursable_expenses = list(filter(lambda expense: expense.fund_source == 'PERSONAL', expense_objects)) @@ -405,6 +407,8 @@ def create_expense_groups_by_report_id_fund_source(expense_objects: List[Expense reimbursable_expenses = list(filter(lambda expense: expense.amount > 0, reimbursable_expenses)) expense_groups = _group_expenses(reimbursable_expenses, reimbursable_expense_group_fields, workspace_id) + + # Group CCC Expenses corporate_credit_card_expense_group_field = expense_group_settings.corporate_credit_card_expense_group_fields corporate_credit_card_expenses = list(filter(lambda expense: expense.fund_source == 'CCC', expense_objects)) @@ -414,10 +418,45 @@ def create_expense_groups_by_report_id_fund_source(expense_objects: List[Expense filter(lambda expense: expense.amount > 0, corporate_credit_card_expenses) ) - corporate_credit_card_expense_groups = _group_expenses( - corporate_credit_card_expenses, corporate_credit_card_expense_group_field, workspace_id) + if corporate_credit_card_expenses: + # Group split Credit Card Charges by `bank_transaction_id` + if ( + configuration.corporate_credit_card_expenses_object == 'CREDIT CARD CHARGE' and + expense_group_settings.split_expense_grouping == 'MULTIPLE_LINE_ITEM' + ): + ccc_expenses_without_bank_transaction_id = list( + filter(lambda expense: not expense.bank_transaction_id, corporate_credit_card_expenses) + ) + + ccc_expenses_with_bank_transaction_id = list( + filter(lambda expense: expense.bank_transaction_id, corporate_credit_card_expenses) + ) + + if ccc_expenses_without_bank_transaction_id: + groups_without_bank_transaction_id = _group_expenses( + ccc_expenses_without_bank_transaction_id, corporate_credit_card_expense_group_field, workspace_id + ) + + expense_groups.extend(groups_without_bank_transaction_id) + + if ccc_expenses_with_bank_transaction_id: + split_expense_group_fields = [ + field for field in corporate_credit_card_expense_group_field + if field not in ('expense_id', 'expense_number') + ] + split_expense_group_fields.append('bank_transaction_id') + + groups_with_bank_transaction_id = _group_expenses( + ccc_expenses_with_bank_transaction_id, split_expense_group_fields, workspace_id + ) + expense_groups.extend(groups_with_bank_transaction_id) + + else: + corporate_credit_card_expense_groups = _group_expenses( + corporate_credit_card_expenses, corporate_credit_card_expense_group_field, workspace_id) + + expense_groups.extend(corporate_credit_card_expense_groups) - expense_groups.extend(corporate_credit_card_expense_groups) for expense_group in expense_groups: if expense_group_settings.reimbursable_export_date_type == 'last_spent_at': expense_group['last_spent_at'] = Expense.objects.filter( diff --git a/apps/netsuite/connector.py b/apps/netsuite/connector.py index d3baa9f5..431d04dd 100644 --- a/apps/netsuite/connector.py +++ b/apps/netsuite/connector.py @@ -1581,51 +1581,50 @@ def get_bill(self, internal_id): return bill def construct_credit_card_charge_lineitems( - self, credit_card_charge_lineitem: CreditCardChargeLineItem, general_mapping: GeneralMapping, + self, credit_card_charge_lineitems: List[CreditCardChargeLineItem], general_mapping: GeneralMapping, attachment_links: Dict, cluster_domain: str, org_id: str) -> List[Dict]: """ Create credit_card_charge line items :return: constructed line items """ - line = credit_card_charge_lineitem - lines = [] - expense = Expense.objects.get(pk=line.expense_id) - - netsuite_custom_segments = self.prepare_custom_segments(line.netsuite_custom_segments, attachment_links, expense, org_id) - - base_line = { - 'account': {'internalId': line.account_id}, - 'amount': line.amount, - 'memo': line.memo, - 'grossAmt': line.amount, - 'department': {'internalId': line.department_id}, - 'class': {'internalId': line.class_id}, - 'location': {'internalId': line.location_id}, - 'customer': {'internalId': line.customer_id}, - 'customFieldList': netsuite_custom_segments, - 'isBillable': line.billable, - 'taxAmount': None, - 'taxCode': { - 'externalId': None, - 'internalId': None, - 'name': None, - 'type': 'taxGroup' - }, - } + for line in credit_card_charge_lineitems: + expense = Expense.objects.get(pk=line.expense_id) - # Handle cases where no tax is applied first - if line.tax_item_id is None or line.tax_amount is None: - lines.append(base_line) - else: - lines += self.handle_taxed_line_items(base_line, line, expense.workspace_id, 'CREDIT_CARD_CHARGE', general_mapping) + netsuite_custom_segments = self.prepare_custom_segments(line.netsuite_custom_segments, attachment_links, expense, org_id) + + base_line = { + 'account': {'internalId': line.account_id}, + 'amount': line.amount, + 'memo': line.memo, + 'grossAmt': line.amount, + 'department': {'internalId': line.department_id}, + 'class': {'internalId': line.class_id}, + 'location': {'internalId': line.location_id}, + 'customer': {'internalId': line.customer_id}, + 'customFieldList': netsuite_custom_segments, + 'isBillable': line.billable, + 'taxAmount': None, + 'taxCode': { + 'externalId': None, + 'internalId': None, + 'name': None, + 'type': 'taxGroup' + }, + } + + # Handle cases where no tax is applied first + if line.tax_item_id is None or line.tax_amount is None: + lines.append(base_line) + else: + lines += self.handle_taxed_line_items(base_line, line, expense.workspace_id, 'CREDIT_CARD_CHARGE', general_mapping) return lines def __construct_credit_card_charge( self, credit_card_charge: CreditCardCharge, - credit_card_charge_lineitem: CreditCardChargeLineItem, general_mapping: GeneralMapping, attachment_links: Dict) -> Dict: + credit_card_charge_lineitems: List[CreditCardChargeLineItem], general_mapping: GeneralMapping, attachment_links: Dict) -> Dict: """ Create a credit_card_charge :return: constructed credit_card_charge @@ -1664,7 +1663,7 @@ def __construct_credit_card_charge( 'memo': credit_card_charge.memo, 'tranid': credit_card_charge.reference_number, 'expenses': self.construct_credit_card_charge_lineitems( - credit_card_charge_lineitem, general_mapping, attachment_links, cluster_domain, org_id + credit_card_charge_lineitems, general_mapping, attachment_links, cluster_domain, org_id ), 'externalId': credit_card_charge.external_id } @@ -1672,7 +1671,7 @@ def __construct_credit_card_charge( return credit_card_charge_payload def post_credit_card_charge(self, credit_card_charge: CreditCardCharge, - credit_card_charge_lineitem: CreditCardChargeLineItem, general_mapping: GeneralMapping, attachment_links: Dict, + credit_card_charge_lineitems: List[CreditCardChargeLineItem], general_mapping: GeneralMapping, attachment_links: Dict, refund: bool): """ Post vendor credit_card_charges to NetSuite @@ -1694,12 +1693,15 @@ def post_credit_card_charge(self, credit_card_charge: CreditCardCharge, f"script=customscript_cc_charge_fyle&deploy=customdeploy_cc_charge_fyle" if refund: - credit_card_charge_lineitem.amount = abs(credit_card_charge_lineitem.amount) + for credit_card_charge_lineitem in credit_card_charge_lineitems: + credit_card_charge_lineitem.amount = abs(credit_card_charge_lineitem.amount) + credit_card_charge_lineitem.save() + url = f"https://{account.lower()}.restlets.api.netsuite.com/app/site/hosting/restlet.nl?" \ - f"script=customscript_cc_refund_fyle&deploy=customdeploy_cc_refund_fyle" + f"script=customscript_cc_refund_fyle&deploy=customdeploy_cc_refund_fyle" credit_card_charges_payload = self.__construct_credit_card_charge( - credit_card_charge, credit_card_charge_lineitem, general_mapping, attachment_links) + credit_card_charge, credit_card_charge_lineitems, general_mapping, attachment_links) logger.info("| Payload for Credit Card Charge creation | Content: {{WORKSPACE_ID: {} EXPENSE_GROUP_ID: {} CREDIT_CARD_CHARGE_PAYLOAD: {}}}".format(self.workspace_id, credit_card_charge.expense_group.id, credit_card_charges_payload)) diff --git a/apps/netsuite/models.py b/apps/netsuite/models.py index d69657b4..580428d1 100644 --- a/apps/netsuite/models.py +++ b/apps/netsuite/models.py @@ -684,103 +684,103 @@ class Meta: db_table = 'credit_card_charge_lineitems' @staticmethod - def create_credit_card_charge_lineitem(expense_group: ExpenseGroup, configuration: Configuration): + def create_credit_card_charge_lineitems(expense_group: ExpenseGroup, configuration: Configuration): """ Create credit card charge lineitems :param expense_group: expense group :param configuration: Workspace Configuration Settings :return: credit card charge lineitems objects """ - lineitem = expense_group.expenses.first() credit_card_charge = CreditCardCharge.objects.get(expense_group=expense_group) general_mappings = GeneralMapping.objects.get(workspace_id=expense_group.workspace_id) credit_card_charge_lineitem_objects = [] + for lineitem in expense_group.expenses.all(): - 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=expense_group.workspace_id - ).first() - - class_id = None - if expense_group.fund_source == 'CCC' and general_mappings.use_employee_class: - employee_mapping = EmployeeMapping.objects.filter( - source_employee__value=expense_group.description.get('employee_email'), - workspace_id=expense_group.workspace_id - ).first() - if employee_mapping and employee_mapping.destination_employee: - class_id = employee_mapping.destination_employee.detail.get('class_id') - - if not class_id: - class_id = get_class_id_or_none(expense_group, lineitem) - - department_id = get_department_id_or_none(expense_group, lineitem) + category = lineitem.category if (lineitem.category == lineitem.sub_category or lineitem.sub_category == None) else '{0} / {1}'.format( + lineitem.category, lineitem.sub_category) - if expense_group.fund_source == 'CCC' and general_mappings.use_employee_department and \ - general_mappings.department_level in ('ALL', 'TRANSACTION_LINE'): - employee_mapping = EmployeeMapping.objects.filter( - source_employee__value=expense_group.description.get('employee_email'), + account = CategoryMapping.objects.filter( + source_category__value=category, workspace_id=expense_group.workspace_id ).first() - if employee_mapping and employee_mapping.destination_employee: - if employee_mapping.destination_employee.detail.get('department_id'): - department_id = employee_mapping.destination_employee.detail.get('department_id') - if not department_id: - if general_mappings.department_id and general_mappings.department_level in ['TRANSACTION_LINE', 'ALL']: - department_id = general_mappings.department_id + class_id = None + if expense_group.fund_source == 'CCC' and general_mappings.use_employee_class: + employee_mapping = EmployeeMapping.objects.filter( + source_employee__value=expense_group.description.get('employee_email'), + workspace_id=expense_group.workspace_id + ).first() + if employee_mapping and employee_mapping.destination_employee: + class_id = employee_mapping.destination_employee.detail.get('class_id') + + if not class_id: + class_id = get_class_id_or_none(expense_group, lineitem) - location_id = get_location_id_or_none(expense_group, lineitem) + department_id = get_department_id_or_none(expense_group, lineitem) - if expense_group.fund_source == 'CCC' and general_mappings.use_employee_location and\ - general_mappings.location_level in ('ALL', 'TRANSACTION_LINE'): + if expense_group.fund_source == 'CCC' and general_mappings.use_employee_department and \ + general_mappings.department_level in ('ALL', 'TRANSACTION_LINE'): employee_mapping = EmployeeMapping.objects.filter( source_employee__value=expense_group.description.get('employee_email'), workspace_id=expense_group.workspace_id ).first() if employee_mapping and employee_mapping.destination_employee: - location_id = employee_mapping.destination_employee.detail.get('location_id') + if employee_mapping.destination_employee.detail.get('department_id'): + department_id = employee_mapping.destination_employee.detail.get('department_id') - if not location_id: - if general_mappings.location_id and general_mappings.location_level in ['TRANSACTION_LINE', 'ALL']: - location_id = general_mappings.location_id + if not department_id: + if general_mappings.department_id and general_mappings.department_level in ['TRANSACTION_LINE', 'ALL']: + department_id = general_mappings.department_id + + location_id = get_location_id_or_none(expense_group, lineitem) + + if expense_group.fund_source == 'CCC' and general_mappings.use_employee_location and\ + general_mappings.location_level in ('ALL', 'TRANSACTION_LINE'): + employee_mapping = EmployeeMapping.objects.filter( + source_employee__value=expense_group.description.get('employee_email'), + workspace_id=expense_group.workspace_id + ).first() + if employee_mapping and employee_mapping.destination_employee: + location_id = employee_mapping.destination_employee.detail.get('location_id') + + if not location_id: + if general_mappings.location_id and general_mappings.location_level in ['TRANSACTION_LINE', 'ALL']: + location_id = general_mappings.location_id - custom_segments = get_custom_segments(expense_group, lineitem) + custom_segments = get_custom_segments(expense_group, lineitem) - customer_id = get_customer_id_or_none(expense_group, lineitem) + customer_id = get_customer_id_or_none(expense_group, lineitem) - billable = lineitem.billable - if customer_id: - if not billable: + billable = lineitem.billable + if customer_id: + if not billable: + billable = False + else: billable = False - else: - billable = False - credit_card_charge_lineitem_object, _ = CreditCardChargeLineItem.objects.update_or_create( - credit_card_charge=credit_card_charge, - expense_id=lineitem.id, - defaults={ - 'account_id': account.destination_account.destination_id \ - if account and account.destination_account else None, - 'location_id': location_id, - 'class_id': class_id, - 'department_id': department_id, - 'customer_id': customer_id, - 'amount': lineitem.amount, - 'tax_item_id': get_tax_item_id_or_none(expense_group, general_mappings,lineitem), - 'tax_amount': lineitem.tax_amount, - 'billable': billable, - 'memo': get_expense_purpose(lineitem, category, configuration), - 'netsuite_custom_segments': custom_segments - } - ) + credit_card_charge_lineitem_object, _ = CreditCardChargeLineItem.objects.update_or_create( + credit_card_charge=credit_card_charge, + expense_id=lineitem.id, + defaults={ + 'account_id': account.destination_account.destination_id \ + if account and account.destination_account else None, + 'location_id': location_id, + 'class_id': class_id, + 'department_id': department_id, + 'customer_id': customer_id, + 'amount': lineitem.amount, + 'tax_item_id': get_tax_item_id_or_none(expense_group, general_mappings,lineitem), + 'tax_amount': lineitem.tax_amount, + 'billable': billable, + 'memo': get_expense_purpose(lineitem, category, configuration), + 'netsuite_custom_segments': custom_segments + } + ) - credit_card_charge_lineitem_objects.append(credit_card_charge_lineitem_object) + credit_card_charge_lineitem_objects.append(credit_card_charge_lineitem_object) - return credit_card_charge_lineitem_object + return credit_card_charge_lineitem_objects class ExpenseReport(models.Model): diff --git a/apps/netsuite/tasks.py b/apps/netsuite/tasks.py index da56208a..9ee71f70 100644 --- a/apps/netsuite/tasks.py +++ b/apps/netsuite/tasks.py @@ -551,7 +551,7 @@ def create_credit_card_charge(expense_group, task_log_id, last_export): with transaction.atomic(): credit_card_charge_object = CreditCardCharge.create_credit_card_charge(expense_group) - credit_card_charge_lineitems_object = CreditCardChargeLineItem.create_credit_card_charge_lineitem( + credit_card_charge_lineitems_objects = CreditCardChargeLineItem.create_credit_card_charge_lineitems( expense_group, configuration ) attachment_links = {} @@ -567,7 +567,7 @@ def create_credit_card_charge(expense_group, task_log_id, last_export): attachment_links[expense.expense_id] = attachment_link created_credit_card_charge = netsuite_connection.post_credit_card_charge( - credit_card_charge_object, credit_card_charge_lineitems_object, general_mappings, attachment_links, refund + credit_card_charge_object, credit_card_charge_lineitems_objects, general_mappings, attachment_links, refund ) worker_logger.info('Created Credit Card Charge with Expense Group %s successfully', expense_group.id) @@ -595,8 +595,9 @@ def create_credit_card_charge(expense_group, task_log_id, last_export): except Exception as e: logger.error('Error while updating expenses for expense_group_id: %s and posting accounting export summary %s', expense_group.id, e) - credit_card_charge_lineitems_object.netsuite_receipt_url = attachment_links.get(credit_card_charge_lineitems_object.expense.expense_id, None) - credit_card_charge_lineitems_object.save() + for credit_card_charge_lineitems_object in credit_card_charge_lineitems_objects: + credit_card_charge_lineitems_object.netsuite_receipt_url = attachment_links.get(credit_card_charge_lineitems_object.expense.expense_id, None) + credit_card_charge_lineitems_object.save() @handle_netsuite_exceptions(payment=False) diff --git a/scripts/sql/scripts/030-default-split-expense-grouping-for-old-orgs.sql b/scripts/sql/scripts/030-default-split-expense-grouping-for-old-orgs.sql new file mode 100644 index 00000000..89797023 --- /dev/null +++ b/scripts/sql/scripts/030-default-split-expense-grouping-for-old-orgs.sql @@ -0,0 +1,5 @@ +rollback; +begin; + +UPDATE expense_group_settings +SET split_expense_grouping = 'SINGLE_LINE_ITEM'; diff --git a/tests/test_fyle/fixtures.py b/tests/test_fyle/fixtures.py index 77217b00..0976095c 100644 --- a/tests/test_fyle/fixtures.py +++ b/tests/test_fyle/fixtures.py @@ -619,6 +619,7 @@ 'Vehicle Type': '', 'Fyle Categories': '', }, + 'bank_transaction_id': 'btxnqmATEEBkJ4', 'is_posted_at_null': True }, { @@ -661,6 +662,7 @@ 'Vehicle Type': '', 'Fyle Categories': '', }, + 'bank_transaction_id': 'btxnqmATEEBkJ4', 'is_posted_at_null': True }, ], @@ -703,6 +705,7 @@ 'tax_group_id': None, 'vendor': 'Dominos Pizza', 'verified_at': None, + 'is_posted_at_null': True }, { 'amount': 2, @@ -742,6 +745,7 @@ 'tax_group_id': None, 'vendor': 'Dominos Pizza', 'verified_at': None, + 'is_posted_at_null': True }, { 'amount': 3, @@ -781,6 +785,7 @@ 'tax_group_id': None, 'vendor': 'Dominos Pizza', 'verified_at': None, + 'is_posted_at_null': True }, { 'amount': 4, @@ -820,6 +825,7 @@ 'tax_group_id': None, 'vendor': 'Dominos Pizza', 'verified_at': None, + 'is_posted_at_null': True }, ], "expenses": [ diff --git a/tests/test_netsuite/conftest.py b/tests/test_netsuite/conftest.py index 6995201e..0aff3b46 100644 --- a/tests/test_netsuite/conftest.py +++ b/tests/test_netsuite/conftest.py @@ -269,7 +269,7 @@ def create_credit_card_charge(db, add_netsuite_credentials, add_fyle_credentials configuration = Configuration.objects.get(workspace_id=1) credit_card_charge_object = CreditCardCharge.create_credit_card_charge(expense_group) - credit_card_charge_lineitems_object = CreditCardChargeLineItem.create_credit_card_charge_lineitem( + credit_card_charge_lineitems_object = CreditCardChargeLineItem.create_credit_card_charge_lineitems( expense_group, configuration ) diff --git a/tests/test_netsuite/test_connector.py b/tests/test_netsuite/test_connector.py index 47d4217b..d1102c4c 100644 --- a/tests/test_netsuite/test_connector.py +++ b/tests/test_netsuite/test_connector.py @@ -289,8 +289,8 @@ def test_contruct_credit_card_charge(create_credit_card_charge): general_mapping = GeneralMapping.objects.get(workspace_id=49) - credit_card_charge, credit_card_charge_lineitem = create_credit_card_charge - credit_card_charge_object = netsuite_connection._NetSuiteConnector__construct_credit_card_charge(credit_card_charge, credit_card_charge_lineitem, general_mapping, []) + credit_card_charge, credit_card_charge_lineitems = create_credit_card_charge + credit_card_charge_object = netsuite_connection._NetSuiteConnector__construct_credit_card_charge(credit_card_charge, credit_card_charge_lineitems, general_mapping, []) credit_card_charge_object['tranDate'] = data['credit_card_charge'][0]['tranDate'] credit_card_charge_object['tranid'] = data['credit_card_charge'][0]['tranid'] @@ -304,12 +304,14 @@ def test_contruct_credit_card_charge_with_tax_balancing(create_credit_card_charg general_mapping = GeneralMapping.objects.get(workspace_id=49) # without tax balancing - credit_card_charge, credit_card_charge_lineitem = create_credit_card_charge - credit_card_charge_lineitem.amount = 100 - credit_card_charge_lineitem.tax_amount = 3 - credit_card_charge_lineitem.tax_item_id = '103578' + credit_card_charge, credit_card_charge_lineitems = create_credit_card_charge - credit_card_charge_object = netsuite_connection._NetSuiteConnector__construct_credit_card_charge(credit_card_charge, credit_card_charge_lineitem, general_mapping, []) + item = credit_card_charge_lineitems[0] + item.amount = 100 + item.tax_amount = 3 + item.tax_item_id = '103578' + + credit_card_charge_object = netsuite_connection._NetSuiteConnector__construct_credit_card_charge(credit_card_charge, credit_card_charge_lineitems, general_mapping, []) assert len(credit_card_charge_object['expenses']) == 1 assert credit_card_charge_object['expenses'][0]['amount'] == 97 @@ -319,7 +321,7 @@ def test_contruct_credit_card_charge_with_tax_balancing(create_credit_card_charg general_mapping.is_tax_balancing_enabled = True general_mapping.save() - credit_card_charge_object = netsuite_connection._NetSuiteConnector__construct_credit_card_charge(credit_card_charge, credit_card_charge_lineitem, general_mapping, []) + credit_card_charge_object = netsuite_connection._NetSuiteConnector__construct_credit_card_charge(credit_card_charge, credit_card_charge_lineitems, general_mapping, []) assert len(credit_card_charge_object['expenses']) == 2 assert credit_card_charge_object['expenses'][0]['amount'] == 60 @@ -328,11 +330,11 @@ def test_contruct_credit_card_charge_with_tax_balancing(create_credit_card_charg assert credit_card_charge_object['expenses'][1]['taxCode']['internalId'] == general_mapping.default_tax_code_id # with tax balancing enabled and right tax amount - credit_card_charge_lineitem.amount = 100 - credit_card_charge_lineitem.tax_amount = 4.76 - credit_card_charge_lineitem.tax_item_id = '103578' + item.amount = 100 + item.tax_amount = 4.76 + item.tax_item_id = '103578' - credit_card_charge_object = netsuite_connection._NetSuiteConnector__construct_credit_card_charge(credit_card_charge, credit_card_charge_lineitem, general_mapping, []) + credit_card_charge_object = netsuite_connection._NetSuiteConnector__construct_credit_card_charge(credit_card_charge, credit_card_charge_lineitems, general_mapping, []) assert len(credit_card_charge_object['expenses']) == 1 assert credit_card_charge_object['expenses'][0]['amount'] == 95.24 diff --git a/tests/test_netsuite/test_models.py b/tests/test_netsuite/test_models.py index baa4b7bf..d9b91b54 100644 --- a/tests/test_netsuite/test_models.py +++ b/tests/test_netsuite/test_models.py @@ -340,11 +340,12 @@ def test_create_credit_card_charge(db): expense_group = ExpenseGroup.objects.get(id=4) credit_card = CreditCardCharge.create_credit_card_charge(expense_group) configuration = Configuration.objects.get(workspace_id=2) - credit_card_charge_lineitem = CreditCardChargeLineItem.create_credit_card_charge_lineitem(expense_group, configuration) + credit_card_charge_lineitems = CreditCardChargeLineItem.create_credit_card_charge_lineitems(expense_group, configuration) - assert credit_card_charge_lineitem.amount == 100.00 - assert credit_card_charge_lineitem.memo == 'ashwin.t@fyle.in - Accounts Payable - 2021-11-16 - C/2021/11/R/1 - ' - assert credit_card_charge_lineitem.billable == False + line = credit_card_charge_lineitems[0] + assert line.amount == 100.00 + assert line.memo == 'ashwin.t@fyle.in - Accounts Payable - 2021-11-16 - C/2021/11/R/1 - ' + assert line.billable == False assert credit_card.currency == '1' assert credit_card.transaction_date <= datetime.now().strftime('%Y-%m-%dT%H:%M:%S') @@ -363,11 +364,12 @@ def test_create_credit_card_charge(db): credit_card = CreditCardCharge.create_credit_card_charge(expense_group) configuration = Configuration.objects.get(workspace_id=1) - credit_card_charge_lineitem = CreditCardChargeLineItem.create_credit_card_charge_lineitem(expense_group, configuration) + credit_card_charge_lineitems = CreditCardChargeLineItem.create_credit_card_charge_lineitems(expense_group, configuration) - assert credit_card_charge_lineitem.amount == 100.00 - assert credit_card_charge_lineitem.memo == 'ashwin.t@fyle.in - Accounts Payable - 2021-11-15 - C/2021/11/R/6 - ' - assert credit_card_charge_lineitem.billable == False + line = credit_card_charge_lineitems[0] + assert line.amount == 100.00 + assert line.memo == 'ashwin.t@fyle.in - Accounts Payable - 2021-11-15 - C/2021/11/R/6 - ' + assert line.billable == False assert credit_card.currency == '1' assert credit_card.transaction_date <= datetime.now().strftime('%Y-%m-%dT%H:%M:%S')