Skip to content
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

Expense Model updated, comments fixed #29

Merged
merged 8 commits into from
Nov 29, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions apps/business_central/views.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import logging

from rest_framework import generics

from apps.business_central.serializers import ImportBusinessCentralAttributesSerializer, BusinessCentralFieldSerializer


logger = logging.getLogger(__name__)
logger.level = logging.INFO


class ImportBusinessCentralAttributesView(generics.CreateAPIView):
"""
Import Business Central Attributes View
Expand All @@ -21,6 +15,7 @@ class BusinessCentralFieldsView(generics.ListAPIView):
Business Central Fields View
"""
serializer_class = BusinessCentralFieldSerializer
pagination_class = None

def get_queryset(self):
return BusinessCentralFieldSerializer().format_business_central_fields(self.kwargs["workspace_id"])
85 changes: 78 additions & 7 deletions apps/fyle/models.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from typing import List, Dict

from django.db import models
from django.contrib.postgres.fields import ArrayField
from ms_business_central_api.models.fields import (
Expand All @@ -11,7 +13,7 @@
StringOptionsField,
IntegerOptionsField,
)
from apps.workspaces.models import BaseModel, BaseForeignWorkspaceModel
from apps.workspaces.models import BaseForeignWorkspaceModel


EXPENSE_FILTER_RANK = (
Expand Down Expand Up @@ -40,8 +42,13 @@
('not_in', 'not_in')
)

SOURCE_ACCOUNT_MAP = {
'PERSONAL_CASH_ACCOUNT': 'PERSONAL',
'PERSONAL_CORPORATE_CREDIT_CARD_ACCOUNT': 'CCC'
}


class Expense(BaseModel):
class Expense(BaseForeignWorkspaceModel):
"""
Expense
"""
Expand All @@ -55,14 +62,14 @@ class Expense(BaseModel):
org_id = StringNullField(help_text='Organization ID')
expense_number = StringNotNullField(help_text='Expense Number')
claim_number = StringNotNullField(help_text='Claim Number')
amount = models.FloatField(help_text='Home Amount')
amount = FloatNullField(help_text='Home Amount')
currency = StringNotNullField(max_length=5, help_text='Home Currency')
foreign_amount = models.FloatField(null=True, help_text='Foreign Amount')
foreign_currency = StringNotNullField(max_length=5, help_text='Foreign Currency')
foreign_amount = FloatNullField(help_text='Foreign Amount')
foreign_currency = StringNullField(max_length=5, help_text='Foreign Currency')
settlement_id = StringNullField(help_text='Settlement ID')
reimbursable = BooleanFalseField(help_text='Expense reimbursable or not')
state = StringNotNullField(help_text='Expense state')
vendor = StringNotNullField(help_text='Vendor')
vendor = StringNullField(help_text='Vendor')
cost_center = StringNullField(help_text='Fyle Expense Cost Center')
corporate_card_id = StringNullField(help_text='Corporate Card ID')
purpose = models.TextField(null=True, blank=True, help_text='Purpose')
Expand All @@ -77,15 +84,79 @@ class Expense(BaseModel):
fund_source = StringNotNullField(help_text='Expense fund source')
verified_at = CustomDateTimeField(help_text='Report verified at')
custom_properties = CustomJsonField(help_text="Custom Properties")
report_title = models.TextField(null=True, blank=True, help_text='Report title')
payment_number = StringNullField(max_length=55, help_text='Expense payment number')
tax_amount = FloatNullField(help_text='Tax Amount')
tax_group_id = StringNullField(help_text='Tax Group ID')
exported = BooleanFalseField(help_text='Expense reimbursable or not')
previous_export_state = StringNullField(max_length=255, help_text='Previous export state')
accounting_export_summary = CustomJsonField(default=dict, help_text='Accounting Export Summary')

class Meta:
db_table = 'expenses'

@staticmethod
def create_expense_objects(expenses: List[Dict], workspace_id: int):
ruuushhh marked this conversation as resolved.
Show resolved Hide resolved
"""
Bulk create expense objects
"""

# Create an empty list to store expense objects
expense_objects = []

for expense in expenses:
# Iterate through custom property fields and handle empty values
for custom_property_field in expense['custom_properties']:
if expense['custom_properties'][custom_property_field] == '':
expense['custom_properties'][custom_property_field] = None

# Create or update an Expense object based on expense_id
expense_object, _ = Expense.objects.update_or_create(
expense_id=expense['id'],
defaults={
'employee_email': expense['employee_email'],
'employee_name': expense['employee_name'],
'category': expense['category'],
'sub_category': expense['sub_category'],
'project': expense['project'],
'expense_number': expense['expense_number'],
'org_id': expense['org_id'],
'claim_number': expense['claim_number'],
'amount': round(expense['amount'], 2),
'currency': expense['currency'],
'foreign_amount': expense['foreign_amount'],
'foreign_currency': expense['foreign_currency'],
'tax_amount': expense['tax_amount'],
'tax_group_id': expense['tax_group_id'],
'settlement_id': expense['settlement_id'],
'reimbursable': expense['reimbursable'],
'billable': expense['billable'] if expense['billable'] else False,
'state': expense['state'],
'vendor': expense['vendor'][:250] if expense['vendor'] else None,
'cost_center': expense['cost_center'],
'purpose': expense['purpose'],
'report_id': expense['report_id'],
'report_title': expense['report_title'],
'spent_at': expense['spent_at'],
'approved_at': expense['approved_at'],
'posted_at': expense['posted_at'],
'expense_created_at': expense['expense_created_at'],
'expense_updated_at': expense['expense_updated_at'],
'fund_source': SOURCE_ACCOUNT_MAP[expense['source_account_type']],
'verified_at': expense['verified_at'],
'custom_properties': expense['custom_properties'],
'payment_number': expense['payment_number'],
'file_ids': expense['file_ids'],
'corporate_card_id': expense['corporate_card_id'],
'workspace_id': workspace_id
}
)

# Check if an AccountingExport related to the expense object already exists
if not Expense.objects.filter(accountingexport__isnull=False).distinct():
expense_objects.append(expense_object)

return expense_objects


class ExpenseFilter(BaseForeignWorkspaceModel):
"""
Expand Down
22 changes: 22 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from fyle.platform.platform import Platform
from fyle_rest_auth.models import User, AuthToken

from fyle_accounting_mappings.models import DestinationAttribute

from apps.fyle.helpers import get_access_token
from apps.workspaces.models import (
Workspace,
Expand Down Expand Up @@ -272,3 +274,23 @@ def add_business_central_creds():
is_expired = False,
workspace_id = workspace_id
)


@pytest.fixture()
@pytest.mark.django_db(databases=['default'])
def add_destination_attributes():
"""
Pytest fixture to add destination attributes to a workspace
"""
workspace_ids = [
1, 2, 3
]
for workspace_id in workspace_ids:
DestinationAttribute.objects.create(
attribute_type='DUMMY_ATTRIBUTE_TYPE',
display_name='dummy_attribute_name',
value='dummy_attribute_value',
destination_id='dummy_destination_id',
active=True,
workspace_id=workspace_id
)
4 changes: 2 additions & 2 deletions tests/test_business_central/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def test_sync_dimensions(api_client, test_connection, mocker, create_temp_worksp
assert response['message'] == 'Business Central credentials not found / invalid in workspace'


def test_sage300_fields(api_client, test_connection):
def test_business_central_fields(api_client, test_connection, create_temp_workspace, add_fyle_credentials, add_destination_attributes):
workspace_id = 1

access_token = test_connection.access_token
Expand All @@ -38,4 +38,4 @@ def test_sage300_fields(api_client, test_connection):
response = api_client.get(url)
assert response.status_code == 200

assert response.data['results'] == []
assert response.data == [{'attribute_type': 'DUMMY_ATTRIBUTE_TYPE', 'display_name': 'dummy_attribute_name'}]
Loading