Skip to content

Commit 85fb92b

Browse files
authored
fix: allocation payload order (#899)
* fix: allocation payload order * increase cov * increase cov * increase cov
1 parent fe84ab0 commit 85fb92b

File tree

3 files changed

+234
-4
lines changed

3 files changed

+234
-4
lines changed

apps/sage_intacct/utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@
1515
from sageintacctsdk import SageIntacctSDK
1616
from sageintacctsdk.exceptions import WrongParamsError
1717

18-
from apps.sage_intacct.errors.helpers import retry
1918
from apps.fyle.models import DependentFieldSetting
2019
from apps.mappings.models import GeneralMapping, LocationEntityMapping
20+
from apps.sage_intacct.errors.helpers import retry
2121
from apps.sage_intacct.exports.helpers import get_source_entity_id
2222
from apps.sage_intacct.models import (
2323
APPayment,
@@ -1489,6 +1489,7 @@ def __construct_bill(self, bill: Bill, bill_lineitems: list[BillLineitem]) -> di
14891489
'TRX_AMOUNT': lineitem.amount - lineitem.tax_amount if (lineitem.tax_code and lineitem.tax_amount) else tax_exclusive_amount,
14901490
'TOTALTRXAMOUNT': lineitem.amount,
14911491
'ENTRYDESCRIPTION': lineitem.memo,
1492+
'ALLOCATION': lineitem.allocation_id,
14921493
'LOCATIONID': lineitem.location_id,
14931494
'DEPARTMENTID': lineitem.department_id,
14941495
'PROJECTID': lineitem.project_id,
@@ -1498,7 +1499,6 @@ def __construct_bill(self, bill: Bill, bill_lineitems: list[BillLineitem]) -> di
14981499
'COSTTYPEID': lineitem.cost_type_id,
14991500
'CLASSID': lineitem.class_id,
15001501
'BILLABLE': lineitem.billable,
1501-
'ALLOCATION': lineitem.allocation_id,
15021502
'TAXENTRIES': {
15031503
'TAXENTRY': {
15041504
'DETAILID': lineitem.tax_code if (lineitem.tax_code and lineitem.tax_amount) else general_mappings.default_tax_code_id
@@ -1759,6 +1759,7 @@ def __construct_base_line_item(self, lineitem: JournalEntryLineitem, dimensions_
17591759
return {
17601760
'currency': journal_entry.currency,
17611761
'description': lineitem.memo,
1762+
'allocation': lineitem.allocation_id,
17621763
'department': dimensions_values['department_id'],
17631764
'location': dimensions_values['location_id'],
17641765
'projectid': dimensions_values['project_id'],
@@ -1769,7 +1770,6 @@ def __construct_base_line_item(self, lineitem: JournalEntryLineitem, dimensions_
17691770
'itemid': dimensions_values['item_id'],
17701771
'taskid': dimensions_values['task_id'],
17711772
'costtypeid': dimensions_values['cost_type_id'],
1772-
'allocation': lineitem.allocation_id,
17731773
'customfields': {
17741774
'customfield': [{
17751775
'customfieldname': 'FYLE_EXPENSE_URL',

tests/test_sageintacct/test_utils.py

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2270,3 +2270,233 @@ def test_sync_methods_persist_count(mocker, db, create_dependent_field_setting):
22702270
sage_intacct_connection.sync_payment_accounts()
22712271
count_record.refresh_from_db()
22722272
assert count_record.payment_accounts_count == 7
2273+
2274+
2275+
@pytest.mark.django_db
2276+
def test_is_duplicate_deletion_skipped(db):
2277+
"""
2278+
Test is_duplicate_deletion_skipped method
2279+
"""
2280+
workspace_id = 1
2281+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2282+
sage_intacct_connection = SageIntacctConnector(
2283+
credentials_object=sage_intacct_credentials,
2284+
workspace_id=workspace_id
2285+
)
2286+
for attribute_type in ['ACCOUNT', 'VENDOR', 'ITEM', 'CUSTOMER', 'DEPARTMENT', 'CLASS', 'EXPENSE_TYPE', 'PROJECT', 'LOCATION']:
2287+
result = sage_intacct_connection.is_duplicate_deletion_skipped(attribute_type)
2288+
assert result is False, f"Expected False for {attribute_type}"
2289+
for attribute_type in ['CUSTOM_FIELD', 'ALLOCATION', 'TAX_DETAIL']:
2290+
result = sage_intacct_connection.is_duplicate_deletion_skipped(attribute_type)
2291+
assert result is True, f"Expected True for {attribute_type}"
2292+
2293+
2294+
@pytest.mark.django_db
2295+
def test_is_import_enabled_no_configuration(db):
2296+
"""
2297+
Test is_import_enabled method when configuration doesn't exist
2298+
"""
2299+
workspace_id = 1
2300+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2301+
sage_intacct_connection = SageIntacctConnector(
2302+
credentials_object=sage_intacct_credentials,
2303+
workspace_id=workspace_id
2304+
)
2305+
Configuration.objects.filter(workspace_id=workspace_id).delete()
2306+
result = sage_intacct_connection.is_import_enabled('ACCOUNT')
2307+
assert result is False
2308+
2309+
2310+
@pytest.mark.django_db
2311+
def test_is_import_enabled_with_categories(db):
2312+
"""
2313+
Test is_import_enabled method with import_categories enabled
2314+
"""
2315+
workspace_id = 1
2316+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2317+
sage_intacct_connection = SageIntacctConnector(
2318+
credentials_object=sage_intacct_credentials,
2319+
workspace_id=workspace_id
2320+
)
2321+
Configuration.objects.filter(workspace_id=workspace_id).update(import_categories=True)
2322+
result = sage_intacct_connection.is_import_enabled('ACCOUNT')
2323+
assert result is True
2324+
result = sage_intacct_connection.is_import_enabled('EXPENSE_TYPE')
2325+
assert result is True
2326+
2327+
2328+
@pytest.mark.django_db
2329+
def test_is_import_enabled_with_vendors_as_merchants(db):
2330+
"""
2331+
Test is_import_enabled method with import_vendors_as_merchants enabled
2332+
"""
2333+
workspace_id = 1
2334+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2335+
sage_intacct_connection = SageIntacctConnector(
2336+
credentials_object=sage_intacct_credentials,
2337+
workspace_id=workspace_id
2338+
)
2339+
Configuration.objects.filter(workspace_id=workspace_id).update(import_vendors_as_merchants=True)
2340+
result = sage_intacct_connection.is_import_enabled('VENDOR')
2341+
assert result is True
2342+
2343+
2344+
@pytest.mark.django_db
2345+
def test_is_import_enabled_with_mapping_settings(db):
2346+
"""
2347+
Test is_import_enabled method with mapping settings (PROJECT has import_to_fyle=True in fixtures)
2348+
"""
2349+
workspace_id = 1
2350+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2351+
sage_intacct_connection = SageIntacctConnector(
2352+
credentials_object=sage_intacct_credentials,
2353+
workspace_id=workspace_id
2354+
)
2355+
result = sage_intacct_connection.is_import_enabled('PROJECT')
2356+
assert result is True
2357+
result = sage_intacct_connection.is_import_enabled('DEPARTMENT')
2358+
assert result is False
2359+
2360+
2361+
@pytest.mark.django_db
2362+
def test_get_attribute_disable_callback_path(db):
2363+
"""
2364+
Test get_attribute_disable_callback_path method
2365+
"""
2366+
workspace_id = 1
2367+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2368+
sage_intacct_connection = SageIntacctConnector(
2369+
credentials_object=sage_intacct_credentials,
2370+
workspace_id=workspace_id
2371+
)
2372+
result = sage_intacct_connection.get_attribute_disable_callback_path('ACCOUNT')
2373+
assert result == 'fyle_integrations_imports.modules.categories.disable_categories'
2374+
result = sage_intacct_connection.get_attribute_disable_callback_path('VENDOR')
2375+
assert result == 'fyle_integrations_imports.modules.merchants.disable_merchants'
2376+
result = sage_intacct_connection.get_attribute_disable_callback_path('PROJECT')
2377+
assert result == 'fyle_integrations_imports.modules.projects.disable_projects'
2378+
2379+
2380+
@pytest.mark.django_db
2381+
def test_post_attachments_empty_list(db):
2382+
"""
2383+
Test post_attachments with empty attachments list
2384+
"""
2385+
workspace_id = 1
2386+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2387+
sage_intacct_connection = SageIntacctConnector(
2388+
credentials_object=sage_intacct_credentials,
2389+
workspace_id=workspace_id
2390+
)
2391+
result = sage_intacct_connection.post_attachments([], 'test_supdoc', 1)
2392+
assert result is False
2393+
2394+
2395+
@pytest.mark.django_db
2396+
def test_post_attachments_update_exception(mocker, db):
2397+
"""
2398+
Test post_attachments when attachment update raises exception
2399+
"""
2400+
workspace_id = 1
2401+
mocker.patch(
2402+
'sageintacctsdk.apis.Attachments.post',
2403+
return_value={'status': 'success', 'key': '3032'}
2404+
)
2405+
mocker.patch(
2406+
'sageintacctsdk.apis.Attachments.update',
2407+
side_effect=Exception('Update failed')
2408+
)
2409+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2410+
sage_intacct_connection = SageIntacctConnector(
2411+
credentials_object=sage_intacct_credentials,
2412+
workspace_id=workspace_id
2413+
)
2414+
attachment = [{'download_url': 'url', 'name': 'file.pdf', 'id': 'att1'}]
2415+
sage_intacct_connection.post_attachments(attachment, 'supdoc1', 1)
2416+
result = sage_intacct_connection.post_attachments(attachment, 'supdoc1', 2)
2417+
assert result is False
2418+
2419+
2420+
@pytest.mark.django_db
2421+
def test_get_location_id_for_journal_entry(db):
2422+
"""
2423+
Test __get_location_id_for_journal_entry method
2424+
"""
2425+
workspace_id = 1
2426+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2427+
sage_intacct_connection = SageIntacctConnector(
2428+
credentials_object=sage_intacct_credentials,
2429+
workspace_id=workspace_id
2430+
)
2431+
GeneralMapping.objects.filter(workspace_id=workspace_id).update(default_location_id=None)
2432+
result = sage_intacct_connection._SageIntacctConnector__get_location_id_for_journal_entry(workspace_id)
2433+
location_entity = LocationEntityMapping.objects.filter(workspace_id=workspace_id).exclude(location_entity_name='Top Level').first()
2434+
if location_entity:
2435+
assert result == location_entity.destination_id
2436+
else:
2437+
assert result is None
2438+
2439+
2440+
@pytest.mark.django_db
2441+
def test_get_location_id_for_journal_entry_no_mappings(db):
2442+
"""
2443+
Test __get_location_id_for_journal_entry when no mappings exist
2444+
"""
2445+
workspace_id = 1
2446+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2447+
sage_intacct_connection = SageIntacctConnector(
2448+
credentials_object=sage_intacct_credentials,
2449+
workspace_id=workspace_id
2450+
)
2451+
GeneralMapping.objects.filter(workspace_id=workspace_id).update(default_location_id=None)
2452+
LocationEntityMapping.objects.filter(workspace_id=workspace_id).exclude(location_entity_name='Top Level').delete()
2453+
result = sage_intacct_connection._SageIntacctConnector__get_location_id_for_journal_entry(workspace_id)
2454+
assert result is None
2455+
2456+
2457+
@pytest.mark.django_db
2458+
def test_sync_cost_codes_with_last_synced_at(db, mocker, create_dependent_field_setting):
2459+
"""
2460+
Test sync_cost_codes when dependent_field_setting.last_synced_at is set
2461+
"""
2462+
from apps.fyle.models import DependentFieldSetting
2463+
workspace_id = 1
2464+
dependent_field_setting = DependentFieldSetting.objects.get(workspace_id=workspace_id)
2465+
dependent_field_setting.last_synced_at = datetime.now()
2466+
dependent_field_setting.save()
2467+
mocker.patch('sageintacctsdk.apis.Tasks.count', return_value=1)
2468+
cost_code_data = [[
2469+
{'RECORDNO': '40', 'TASKID': '112', 'NAME': 'TestCostCode', 'PROJECTID': '1173', 'PROJECTNAME': 'Test Project'}
2470+
]]
2471+
mocker.patch('sageintacctsdk.apis.Tasks.get_all_generator', return_value=cost_code_data)
2472+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2473+
sage_intacct_connection = SageIntacctConnector(
2474+
credentials_object=sage_intacct_credentials,
2475+
workspace_id=workspace_id
2476+
)
2477+
sage_intacct_connection.sync_cost_codes()
2478+
assert CostCode.objects.filter(workspace_id=workspace_id, task_id='112').exists()
2479+
2480+
2481+
@pytest.mark.django_db
2482+
def test_sync_allocations_empty_entries(mocker, db):
2483+
"""
2484+
Test sync_allocations when allocation_entries is empty
2485+
"""
2486+
workspace_id = 1
2487+
2488+
def mock_allocations_generator(field=None, value=None, updated_at=None):
2489+
yield [{'ALLOCATIONID': 'EMPTY_ALLOC', 'STATUS': 'active'}]
2490+
2491+
def mock_allocation_entry_generator(field, value):
2492+
yield []
2493+
2494+
mocker.patch('sageintacctsdk.apis.Allocations.count', return_value=1)
2495+
mocker.patch('sageintacctsdk.apis.Allocations.get_all_generator', side_effect=mock_allocations_generator)
2496+
mocker.patch('sageintacctsdk.apis.AllocationEntry.get_all_generator', side_effect=mock_allocation_entry_generator)
2497+
sage_intacct_credentials = SageIntacctCredential.objects.get(workspace_id=workspace_id)
2498+
sage_intacct_connection = SageIntacctConnector(
2499+
credentials_object=sage_intacct_credentials,
2500+
workspace_id=workspace_id
2501+
)
2502+
sage_intacct_connection.sync_allocations()

0 commit comments

Comments
 (0)