Skip to content

Commit

Permalink
Merge branch 'spotlight-api' of github.com:fylein/fyle-qbd-api into h…
Browse files Browse the repository at this point in the history
…ackathon-base
  • Loading branch information
Shwetabhk committed Sep 12, 2024
2 parents b5ddf15 + 93b3e31 commit 384c6a0
Show file tree
Hide file tree
Showing 3 changed files with 242 additions and 10 deletions.
4 changes: 2 additions & 2 deletions apps/spotlight/prompts/spotlight_prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@
"description": "Set grouping to expense, this grouping reflects how the expense entries are posted in QuickBooks Desktop."
}},
{{
"code": "set_reimbursable_expenses_export_grouping_expense_report",
"title": "Group reimbursable expenses export by expense report",
"code": "set_reimbursable_expenses_export_grouping_report",
"title": "Group reimbursable expenses export by report",
"description": "Set grouping to expense_report, this grouping reflects how the expense entries are posted in QuickBooks Desktop."
}},
{{
Expand Down
241 changes: 235 additions & 6 deletions apps/spotlight/service.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
from dataclasses import dataclass
from typing import Callable, Dict
from django.db import transaction
import json

import requests

from apps.fyle.helpers import get_access_token
from apps.workspaces.models import FyleCredential
from apps.workspaces.models import ExportSettings, FyleCredential
from .prompts.support_genie import PROMPT as SUPPORT_GENIE_PROMPT
from .prompts.spotlight_prompt import PROMPT as SPOTLIGHT_PROMPT

from . import llm

code_action_map = {
"trigger_export": 'http://localhost:8000/api/workspaces/2/trigger_export/'
}

@dataclass
class ActionResponse:
message: str = None
is_success: bool = None


class HelpService:
Expand Down Expand Up @@ -59,7 +64,21 @@ class ActionService:
@classmethod
def _get_action_function_from_code(cls, *, code: str) -> Callable:
code_to_function_map = {
"trigger_export": cls.trigger_export
"trigger_export": cls.trigger_export,
"set_reimbursable_expenses_export_module_bill": cls.set_reimbursable_expenses_export_module_bill,
"set_reimbursable_expenses_export_module_journal_entry": cls.set_reimbursable_expenses_export_module_journal_entry,
"set_reimbursable_expenses_export_grouping_expense": cls.set_reimbursable_expenses_export_grouping_expense,
"set_reimbursable_expenses_export_grouping_report": cls.set_reimbursable_expenses_export_grouping_report,
"set_reimbursable_expenses_export_state_processing": cls.set_reimbursable_expenses_export_state_processing,
"set_reimbursable_expenses_export_state_paid": cls.set_reimbursable_expenses_export_state_paid,
"set_customer_field_mapping_to_project": cls.set_customer_field_mapping_to_project,
"set_customer_field_mapping_to_cost_center": cls.set_customer_field_mapping_to_cost_center,
"set_class_field_mapping_to_project": cls.set_class_field_mapping_to_project,
"set_class_field_mapping_to_cost_center": cls.set_class_field_mapping_to_cost_center,
"set_corporate_credit_card_expenses_export_credit_card_purchase": cls.set_cc_export_to_corporate_card_purchase,
"set_corporate_credit_card_expenses_export_journal_entry": cls.set_cc_export_to_journal_entry,
"set_corporate_credit_card_expenses_export_grouping_report": cls.set_cc_grouping_to_report,
"set_corporate_credit_card_expenses_export_grouping_expense": cls.set_cc_grouping_to_expense,
}
return code_to_function_map[code]

Expand All @@ -75,6 +94,84 @@ def get_access_token(cls, *, workspace_id: int) -> str:
creds = FyleCredential.objects.get(workspace_id=workspace_id)
return get_access_token(creds.refresh_token)

@classmethod
def set_reimbursable_expenses_export_module_bill(cls, *, workspace_id: int):
with transaction.atomic():
export_settings = ExportSettings.objects.filter(
workspace_id=workspace_id
).first()
if export_settings is None:
return ActionResponse(message="Failed to set reimbursable expense export type set to Bill", is_success=False)
else:
export_settings.reimbursable_expenses_export_type = 'BILL'
export_settings.save()
return ActionResponse(message="Reimbursable expense export type set to Bill", is_success=True)

@classmethod
def set_reimbursable_expenses_export_module_journal_entry(cls, *, workspace_id: int):
with transaction.atomic():
export_settings = ExportSettings.objects.filter(
workspace_id=workspace_id
).first()
if export_settings is None:
return ActionResponse(message="Failed to set reimbursable expense export type set to Journal Entry", is_success=False)
else:
export_settings.reimbursable_expenses_export_type = 'JOURNAL_ENTRY'
export_settings.save()
return ActionResponse(message="Reimbursable expense export type set to Journal Entry", is_success=True)

@classmethod
def set_reimbursable_expenses_export_grouping_expense(cls, *, workspace_id: int):
with transaction.atomic():
export_settings = ExportSettings.objects.filter(
workspace_id=workspace_id
).first()
if export_settings is None:
return ActionResponse(message="Failed to set reimbursable expense export grouping to Expenses", is_success=False)
else:
export_settings.reimbursable_expense_grouped_by = 'EXPENSE'
export_settings.save()
return ActionResponse(message="Reimbursable expense export group set to Expenses", is_success=True)

@classmethod
def set_reimbursable_expenses_export_grouping_report(cls, *, workspace_id: int):
with transaction.atomic():
export_settings = ExportSettings.objects.filter(
workspace_id=workspace_id
).first()
if export_settings is None:
return ActionResponse(message="Failed to set reimbursable expense export grouping to Report", is_success=False)
else:
export_settings.reimbursable_expense_grouped_by = 'REPORT'
export_settings.save()
return ActionResponse(message="Reimbursable expense export group set to Report", is_success=True)

@classmethod
def set_reimbursable_expenses_export_state_processing(cls, *, workspace_id: int):
with transaction.atomic():
export_settings = ExportSettings.objects.filter(
workspace_id=workspace_id
).first()
if export_settings is None:
return ActionResponse(message="Failed to set reimbursable expense export state to Processing", is_success=False)
else:
export_settings.reimbursable_expense_state = 'PAYMENT_PROCESSING'
export_settings.save()
return ActionResponse(message="Reimbursable expense export state set to Processing", is_success=True)

@classmethod
def set_reimbursable_expenses_export_state_paid(cls, *, workspace_id: int):
with transaction.atomic():
export_settings = ExportSettings.objects.filter(
workspace_id=workspace_id
).first()
if export_settings is None:
return ActionResponse(message="Failed to set reimbursable expense export state to Paid", is_success=False)
else:
export_settings.reimbursable_expense_state = 'PAID'
export_settings.save()
return ActionResponse(message="Reimbursable expense export state set to Paid", is_success=True)

@classmethod
def trigger_export(cls, *, workspace_id: int):
access_token = cls.get_access_token(workspace_id=workspace_id)
Expand All @@ -85,8 +182,140 @@ def trigger_export(cls, *, workspace_id: int):
}
url = f'http://localhost:8000/api/workspaces/{workspace_id}/trigger_export/'
action_response = requests.post(url, json={}, headers=headers)
if action_response.status_code == 200:
return ActionResponse(message="Export triggered successfully", is_success=True)
return ActionResponse(message="Export triggered failed", is_success=False)


@classmethod
def set_cc_export_to_corporate_card_purchase(cls, *, workspace_id: int):
with transaction.atomic():
export_settings = ExportSettings.objects.filter(workspace_id=workspace_id).first()
if export_settings:
export_settings.credit_card_expense_export_type = 'CREDIT_CARD_PURCHASE'
export_settings.save()
return ActionResponse(message="Successfully set corporate card expense as Credit Card Purchase", is_success=True)

return ActionResponse(message="Export settings doesn't exists!", is_success=False)


@classmethod
def set_cc_export_to_journal_entry(cls, *, workspace_id: int):
with transaction.atomic():
export_settings = ExportSettings.objects.filter(workspace_id=workspace_id).first()
if export_settings:
export_settings.credit_card_expense_export_type = 'JOURNAL_ENTRY'
export_settings.save()
return ActionResponse(message="Successfully set corporate card expense as JOURNAL ENTRY", is_success=True)

return ActionResponse(message="Export settings doesn't exists!", is_success=False)

@classmethod
def set_cc_grouping_to_report(cls, *, workspace_id: int):
with transaction.atomic():
export_settings = ExportSettings.objects.filter(workspace_id=workspace_id).first()
if export_settings:
if export_settings.credit_card_expense_export_type == 'CREDIT_CARD_PURCHASE':
return ActionResponse(message='For Corporate Credit Purchase Export type expenses cannot be grouped by report', is_success=False)
else:
export_settings.credit_card_expense_grouped_by = 'REPORT'
export_settings.save()
return ActionResponse(message='Succesfully set corporate card group by to Report', is_success=True)

return ActionResponse(message="Export settings doesn't exists!", is_success=False)


@classmethod
def set_cc_grouping_to_expense(cls, *, workspace_id: int):
with transaction.atomic():
export_settings = ExportSettings.objects.filter(workspace_id=workspace_id).first()
if export_settings:
if export_settings.credit_card_expense_export_type == 'CREDIT_CARD_PURCHASE':
return ActionResponse(message='Already set to expense', is_success=True)
else:
export_settings.credit_card_expense_grouped_by = 'EXPENSE'
export_settings.save()
return ActionResponse(message='Succesfully set corporate card group by to EXPENSE', is_success=True)

return ActionResponse(message="Export settings doesn't exists!", is_success=False)


@classmethod
def set_customer_field_mapping_to_project(cls, *, workspace_id: int):
access_token = cls.get_access_token(workspace_id=workspace_id)
headers = cls.get_headers(access_token=access_token)
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
url = f'http://localhost:8000/api/workspaces/{workspace_id}/field_mappings/'
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
action_response = requests.get(url, headers=headers)
action_response= action_response.json()
if action_response.get('project_type') != 'PROJECT' and action_response.get('class_type') != 'COST_CENTER':
action_response['project_type'] = 'PROJECT'
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
return ActionResponse(message="Field mapping updated successfully", is_success=True)
return ActionResponse(message="Field mapping already exists", is_success=False)

@classmethod
def set_customer_field_mapping_to_cost_center(cls, *, workspace_id: int):
access_token = cls.get_access_token(workspace_id=workspace_id)
headers = cls.get_headers(access_token=access_token)
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
url = f'http://localhost:8000/api/workspaces/{workspace_id}/field_mappings/'

action_response = requests.get(url, headers=headers)
action_response= action_response.json()
if action_response.get('project_type') != 'COST_CENTER' and action_response.get('class_type') != 'PROJECT':
action_response['project_type'] = 'COST_CENTER'
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
return ActionResponse(message="Field mapping updated successfully", is_success=True)
return ActionResponse(message="Field mapping already exists", is_success=False)

@classmethod
def set_class_field_mapping_to_project(cls, *, workspace_id: int):
access_token = cls.get_access_token(workspace_id=workspace_id)
headers = cls.get_headers(access_token=access_token)
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
url = f'http://localhost:8000/api/workspaces/{workspace_id}/field_mappings/'

action_response = requests.get(url, headers=headers)
action_response= action_response.json()
if action_response.get('project_type') != 'PROJECT' and action_response.get('class_type') != 'COST_CENTER':
action_response['class_type'] = 'PROJECT'
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
return ActionResponse(message="Field mapping updated successfully", is_success=True)
return ActionResponse(message="Field mapping already exists", is_success=False)

@classmethod
def set_class_field_mapping_to_cost_center(cls, *, workspace_id: int):
access_token = cls.get_access_token(workspace_id=workspace_id)
headers = cls.get_headers(access_token=access_token)
headers = {
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
}
url = f'http://localhost:8000/api/workspaces/{workspace_id}/field_mappings/'

action_response = requests.get(url, headers=headers)
action_response= action_response.json()
if action_response.get('project_type') != 'COST_CENTER' and action_response.get('class_type') != 'PROJECT':
action_response['class_type'] = 'COST_CENTER'
post_response = requests.post(url, headers=headers, data=json.dumps(action_response))
return ActionResponse(message="Field mapping updated successfully", is_success=True)
return ActionResponse(message="Field mapping already exists", is_success=False)

@classmethod
def action(cls, *, code: str, workspace_id: str):
action_function = cls._get_action_function_from_code(code=code)
action_function(workspace_id=workspace_id)
return action_function(workspace_id=workspace_id)
7 changes: 5 additions & 2 deletions apps/spotlight/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,11 @@ def post(self, request, *args, **kwargs):
code = payload["code"]

try:
ActionService.action(code=code, workspace_id=workspace_id)
return JsonResponse(data={"message": "Action triggered successfully"}, status=200)
action_response = ActionService.action(code=code, workspace_id=workspace_id)
if action_response.is_success is True:
return JsonResponse(data={"message": action_response.message}, status=200)
else:
return JsonResponse(data={"message": action_response.message}, status=500)
except Exception as e:
print(e)
return JsonResponse(data={"message": "Action failed"}, status=500)

0 comments on commit 384c6a0

Please sign in to comment.