Skip to content

Commit

Permalink
Fyle Card <> Vendor Mapping setup (#181)
Browse files Browse the repository at this point in the history
* Fyle Card <> Vendor Mapping setup

* Added script to add mapping_settings

* Fix post release script

* Modified script, added additional test case

* lint fix

* modify post-release script
  • Loading branch information
Hrishabh17 authored Jun 10, 2024
1 parent 00f5d42 commit ba304b8
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 17 deletions.
2 changes: 1 addition & 1 deletion apps/accounting_exports/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def _group_expenses(expenses: List[Expense], export_setting: ExportSetting, fund
reimbursable_expense_date = export_setting.reimbursable_expense_date

default_fields = ['employee_email', 'fund_source']
report_grouping_fields = ['report_id', 'claim_number']
report_grouping_fields = ['report_id', 'claim_number', 'corporate_card_id']
expense_grouping_fields = ['expense_id', 'expense_number']

# Define a mapping for fund sources and their associated group fields
Expand Down
29 changes: 14 additions & 15 deletions apps/sage300/exports/base_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from django.db import models
from django.db.models import Sum
from fyle_accounting_mappings.models import ExpenseAttribute, Mapping, MappingSetting, EmployeeMapping, DestinationAttribute
from fyle_accounting_mappings.models import ExpenseAttribute, Mapping, MappingSetting, EmployeeMapping

from apps.accounting_exports.models import AccountingExport
from apps.fyle.models import DependentFieldSetting, Expense
Expand Down Expand Up @@ -60,7 +60,6 @@ def get_expense_purpose(workspace_id, lineitem: Expense, category: str, advance_
def get_vendor_id(accounting_export: AccountingExport):
# Retrieve export settings for the given workspace
export_settings = ExportSetting.objects.get(workspace_id=accounting_export.workspace_id)

# Extract the description from the accounting export
description = accounting_export.description

Expand All @@ -81,22 +80,22 @@ def get_vendor_id(accounting_export: AccountingExport):
# Check if the fund source is 'CCC'
elif accounting_export.fund_source == 'CCC':
# Retrieve the vendor from the first expense
expense_vendor = accounting_export.expenses.first().vendor
vendor_id = None
corporate_card_id = accounting_export.expenses.first().corporate_card_id

# Query DestinationAttribute for the vendor with case-insensitive search
if expense_vendor:
vendor = DestinationAttribute.objects.filter(
if corporate_card_id:
vendor_mapping = Mapping.objects.filter(
workspace_id=accounting_export.workspace_id,
value__icontains=expense_vendor,
attribute_type='VENDOR'
).values_list('destination_id', flat=True).first()
if not vendor:
vendor = export_settings.default_vendor_id
else:
vendor = export_settings.default_vendor_id
source_type='CORPORATE_CARD',
destination_type='VENDOR',
source__source_id=corporate_card_id
).first()

# Update vendor_id with the retrieved vendor or default to export settings
vendor_id = vendor
if vendor_mapping:
vendor_id = vendor_mapping.destination.destination_id

if not vendor_id:
vendor_id = export_settings.default_vendor_id

# Return the determined vendor_id
return vendor_id
Expand Down
11 changes: 11 additions & 0 deletions apps/workspaces/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,17 @@ def create(self, validated_data):
# Update workspace onboarding state
workspace = export_settings.workspace

if export_settings.credit_card_expense_export_type == 'PURCHASE_INVOICE':
MappingSetting.objects.update_or_create(
workspace_id = workspace_id,
defaults={
'source_field':'CORPORATE_CARD',
'destination_field':'VENDOR',
'import_to_fyle': False,
'is_custom': False
}
)

if workspace.onboarding_state == 'EXPORT_SETTINGS':
workspace.onboarding_state = 'IMPORT_SETTINGS'
workspace.save()
Expand Down
20 changes: 20 additions & 0 deletions scripts/002_add_vendor_fyle_card_mapping.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
rollback;
begin;

insert into mapping_settings (source_field, destination_field, import_to_fyle, is_custom, workspace_id, created_at, updated_at)
select 'CORPORATE_CARD', 'VENDOR', 'f', 'f', ws.id, now(), now()
from workspaces ws
where not exists (
select 1
from mapping_settings ms
inner join export_settings es
on es.workspace_id = ms.workspace_id
where ms.source_field = 'CORPORATE_CARD'
and ms.destination_field = 'VENDOR'
and ms.workspace_id = ws.id
and es.credit_card_expense_export_type = 'PURCHASE_INVOICE'
);

select COUNT(*) from export_settings where credit_card_expense_export_type = 'PURCHASE_INVOICE';

select COUNT(distinct(workspace_id)) from mapping_settings where workspace_id not in (select distinct(workspace_id) from mapping_settings where source_field = 'CORPORATE_CARD' and destination_field = 'VENDOR');
146 changes: 145 additions & 1 deletion tests/test_sage300/test_exports/test_base_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@
from apps.fyle.models import Expense, DependentFieldSetting
from fyle_accounting_mappings.models import (
ExpenseAttribute,
DestinationAttribute,
Mapping,
MappingSetting,
EmployeeMapping
)
from apps.workspaces.models import ExportSetting
from apps.accounting_exports.models import _group_expenses


def test_base_model_get_invoice_date(
Expand Down Expand Up @@ -186,8 +189,10 @@ def test_get_vendor_id_2(
accounting_export=accounting_export
)

export_settings = ExportSetting.objects.filter(workspace_id=accounting_export.workspace_id).first()

assert return_value is not None
assert return_value == 'dest_vendor123'
assert return_value == export_settings.default_vendor_id


def test_get_vendor_id_3(
Expand Down Expand Up @@ -220,6 +225,145 @@ def test_get_vendor_id_3(
assert return_value == '1'


def test_get_vendor_id_4(
db,
create_temp_workspace,
create_expense_objects,
add_export_settings,
add_accounting_export_expenses,
create_employee_mapping_with_vendor
):
workspace_id = 1
base_model = PurchaseInvoice

corporate_card, _ = ExpenseAttribute.objects.update_or_create(
workspace_id=workspace_id,
defaults = {
'attribute_type':'CORPORATE_CARD',
'display_name':'Corporate Card',
'value':'Bank of Fyle - T1711',
'source_id':'bankoffyle123',
'detail': {'cardholder_name': None}
}
)

vendor = DestinationAttribute.objects.filter(workspace_id=workspace_id, attribute_type='VENDOR').first()

Mapping.objects.update_or_create(
workspace_id=workspace_id,
defaults = {
'source_type':'CORPORATE_CARD',
'destination_type':'VENDOR',
'source':corporate_card,
'destination':vendor
}
)

expense = Expense.objects.filter(workspace_id=workspace_id).first()
expense.fund_source = 'CCC'
expense.corporate_card_id = corporate_card.source_id
expense.save()

accounting_export = AccountingExport.objects.filter(workspace_id=workspace_id).first()
accounting_export.expenses.set([expense])
accounting_export.fund_source = 'CCC'
accounting_export.description = {'employee_email': '[email protected]'}
accounting_export.save()

return_value = base_model.get_vendor_id(
accounting_export=accounting_export
)

assert return_value is not None
assert return_value == vendor.destination_id


def test_group_expenses(
db,
create_temp_workspace,
create_expense_objects,
add_export_settings,
add_accounting_export_expenses,
create_employee_mapping_with_vendor
):
workspace_id = 1

corporate_card_x, _ = ExpenseAttribute.objects.update_or_create(
workspace_id=workspace_id,
defaults = {
'attribute_type':'CORPORATE_CARD',
'display_name':'Corporate Card',
'value':'Bank of Fyle - X',
'source_id':'bankoffyle123X',
'detail': {'cardholder_name': None}
}
)

corporate_card_y, _ = ExpenseAttribute.objects.update_or_create(
workspace_id=workspace_id,
defaults = {
'attribute_type':'CORPORATE_CARD',
'display_name':'Corporate Card',
'value':'Bank of Fyle - Y',
'source_id':'bankoffyle123Y',
'detail': {'cardholder_name': None}
}
)

vendors = DestinationAttribute.objects.filter(workspace_id=workspace_id, attribute_type='VENDOR')[0:2]

Mapping.objects.update_or_create(
workspace_id=workspace_id,
defaults = {
'source_type':'CORPORATE_CARD',
'destination_type':'VENDOR',
'source':corporate_card_x,
'destination':vendors[0]
}
)

Mapping.objects.update_or_create(
workspace_id=workspace_id,
defaults = {
'source_type':'CORPORATE_CARD',
'destination_type':'VENDOR',
'source':corporate_card_y,
'destination':vendors[0]
}
)

expenses = []
for _ in range(3):
expense = Expense.objects.filter(workspace_id=workspace_id).first()
expense.pk = None
expenses.append(expense)

expenses[0].fund_source = 'CCC'
expenses[0].expense_id = 'tx4ziVSA124'
expenses[0].corporate_card_id = None
expenses[0].save()

expenses[1].fund_source = 'CCC'
expenses[1].expense_id = 'tx4ziVSAsfsf'
expenses[1].corporate_card_id = corporate_card_x.source_id
expenses[1].save()

expenses[2].fund_source = 'CCC'
expenses[2].expense_id = 'tx4zisdAssda'
expenses[2].corporate_card_id = corporate_card_y.source_id
expenses[2].save()

export_settings = ExportSetting.objects.filter(workspace_id=workspace_id).first()
export_settings.credit_card_expense_grouped_by = 'REPORT'
export_settings.credit_card_expense_date = 'POSTED_AT'
export_settings.reimbursable_expense_grouped_by = 'REPORT'
export_settings.reimbursable_expense_date = 'PAYMENT_PROCESSING'
export_settings.save()

accounting_export = _group_expenses(expenses=expenses, export_setting=export_settings, fund_source='CCC')
assert len(accounting_export) == 3


def test_get_job_id(
db,
mocker,
Expand Down

0 comments on commit ba304b8

Please sign in to comment.