def schedule_export(enterprise_id, user): google_sheet_object = GoogleSpreadSheet() export = Export.objects.filter(enterprise_id=enterprise_id).first() sheet_id = export.google_sheets_link if export else google_sheet_object.create_sheet( ) export, _ = Export.objects.update_or_create(enterprise_id=enterprise_id, defaults={ 'status': DEFAULT_SYNC_STATUS, 'google_sheets_link': sheet_id, }) fyle_credentials = AuthToken.objects.get(user__user_id=user) fyle_connector = FyleConnector(fyle_credentials.refresh_token) created_job = fyle_connector.trigger_job( callback_url='{0}{1}'.format( settings.API_URL, '/enterprises/{0}/exports/'.format(enterprise_id)), callback_method='POST', object_id=export.id, payload={}, job_description='Running export for Enterprise id: {0}'.format( enterprise_id), org_user_id=fyle_connector.get_employee_profile()['id']) export.job_id = created_job['id'] export.save() return created_job
def upload_categories_to_fyle(workspace_id): """ Upload categories to Fyle """ fyle_credentials: FyleCredential = FyleCredential.objects.get( workspace_id=workspace_id) qbo_credentials: QBOCredential = QBOCredential.objects.get( workspace_id=workspace_id) fyle_connection = FyleConnector( refresh_token=fyle_credentials.refresh_token, workspace_id=workspace_id) qbo_connection = QBOConnector(credentials_object=qbo_credentials, workspace_id=workspace_id) fyle_connection.sync_categories(False) qbo_connection.sync_accounts() qbo_attributes: List[ DestinationAttribute] = DestinationAttribute.objects.filter( workspace_id=workspace_id, attribute_type='ACCOUNT').all() qbo_attributes = remove_duplicates(qbo_attributes) fyle_payload: List[Dict] = create_fyle_categories_payload( qbo_attributes, workspace_id) if fyle_payload: fyle_connection.connection.Categories.post(fyle_payload) fyle_connection.sync_categories(False) return qbo_attributes
def auto_create_project_mappings(workspace_id: int): """ Create Project Mappings :return: mappings """ try: fyle_credentials: FyleCredential = FyleCredential.objects.get( workspace_id=workspace_id) qbo_credentials: QBOCredential = QBOCredential.objects.get( workspace_id=workspace_id) fyle_connection = FyleConnector( refresh_token=fyle_credentials.refresh_token, workspace_id=workspace_id) qbo_connection = QBOConnector(credentials_object=qbo_credentials, workspace_id=workspace_id) fyle_connection.sync_projects() qbo_connection.sync_customers() post_projects_in_batches(fyle_connection, workspace_id) except WrongParamsError as exception: logger.error( 'Error while creating projects workspace_id - %s in Fyle %s %s', workspace_id, exception.message, {'error': exception.response}) except Exception: error = traceback.format_exc() error = {'error': error} logger.error( 'Error while creating projects workspace_id - %s error: %s', workspace_id, error)
def async_auto_map_employees(workspace_id: int): try: employee_mapping_preference = WorkspaceGeneralSettings.objects.get( workspace_id=workspace_id).auto_map_employees fyle_credentials = FyleCredential.objects.get( workspace_id=workspace_id) fyle_connection = FyleConnector( refresh_token=fyle_credentials.refresh_token, workspace_id=workspace_id) xero_credentials = XeroCredentials.objects.get( workspace_id=workspace_id) xero_connection = XeroConnector(xero_credentials, workspace_id=workspace_id) fyle_connection.sync_employees() xero_connection.sync_contacts() Mapping.auto_map_employees('CONTACT', employee_mapping_preference, workspace_id) except XeroCredentials.DoesNotExist: logger.error( 'Xero Credentials not found for workspace_id %s', workspace_id, )
def async_auto_map_employees(workspace_id: int): general_settings = WorkspaceGeneralSettings.objects.get( workspace_id=workspace_id) employee_mapping_preference = general_settings.auto_map_employees mapping_setting = MappingSetting.objects.filter( ~Q(destination_field='CREDIT_CARD_ACCOUNT'), source_field='EMPLOYEE', workspace_id=workspace_id).first() destination_type = mapping_setting.destination_field fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) fyle_connection = FyleConnector( refresh_token=fyle_credentials.refresh_token, workspace_id=workspace_id) qbo_credentials = QBOCredential.objects.get(workspace_id=workspace_id) qbo_connection = QBOConnector(credentials_object=qbo_credentials, workspace_id=workspace_id) fyle_connection.sync_employees() if destination_type == 'EMPLOYEE': qbo_connection.sync_employees() else: qbo_connection.sync_vendors() Mapping.auto_map_employees(destination_type, employee_mapping_preference, workspace_id)
def process_reimbursements(workspace_id): fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) fyle_connector = FyleConnector(fyle_credentials.refresh_token, workspace_id) fyle_connector.sync_reimbursements() reimbursements = Reimbursement.objects.filter( state='PENDING', workspace_id=workspace_id).all() reimbursement_ids = [] if reimbursements: for reimbursement in reimbursements: expenses = Expense.objects.filter( settlement_id=reimbursement.settlement_id, fund_source='PERSONAL').all() paid_expenses = expenses.filter(paid_on_qbo=True) all_expense_paid = False if len(expenses): all_expense_paid = len(expenses) == len(paid_expenses) if all_expense_paid: reimbursement_ids.append(reimbursement.reimbursement_id) if reimbursement_ids: fyle_connector.post_reimbursement(reimbursement_ids) fyle_connector.sync_reimbursements()
def get(self, request, *args, **kwargs): """ Get User Details """ fyle_credentials = AuthToken.objects.get(user__user_id=request.user) fyle_connector = FyleConnector(fyle_credentials.refresh_token) employee_profile = fyle_connector.get_employee_profile() return Response(data=employee_profile, status=status.HTTP_200_OK)
def schedule_sync(workspace_id: int, schedule_enabled: bool, hours: int, next_run: str, user: str): ws_settings, _ = WorkspaceSettings.objects.get_or_create( workspace_id=workspace_id) start_datetime = datetime.strptime(next_run, '%Y-%m-%dT%H:%M:00.000Z') if not ws_settings.schedule and schedule_enabled: schedule = WorkspaceSchedule.objects.create( enabled=schedule_enabled, interval_hours=hours, start_datetime=start_datetime) ws_settings.schedule = schedule created_job = create_schedule_job(workspace_id=workspace_id, schedule=schedule, user=user, start_datetime=start_datetime, hours=hours) ws_settings.schedule.fyle_job_id = created_job['id'] ws_settings.schedule.save() ws_settings.save(update_fields=['schedule']) else: ws_settings.schedule.enabled = schedule_enabled ws_settings.schedule.start_datetime = start_datetime ws_settings.schedule.interval_hours = hours fyle_credentials = FyleCredential.objects.get( workspace_id=workspace_id) fyle_connector = FyleConnector(fyle_credentials.refresh_token, workspace_id) fyle_sdk_connection = fyle_connector.connection jobs = FyleJobsSDK(settings.FYLE_JOBS_URL, fyle_sdk_connection) if ws_settings.schedule.fyle_job_id: jobs.delete_job(ws_settings.schedule.fyle_job_id) if schedule_enabled: created_job = create_schedule_job(workspace_id=workspace_id, schedule=ws_settings.schedule, user=user, start_datetime=start_datetime, hours=hours) ws_settings.schedule.fyle_job_id = created_job['id'] else: ws_settings.schedule.fyle_job_id = None ws_settings.schedule.save() return ws_settings
def async_auto_map_ccc_account(workspace_id: str): general_mappings = GeneralMapping.objects.get(workspace_id=workspace_id) default_ccc_account_id = general_mappings.default_ccc_account_id if default_ccc_account_id: fyle_credentials = FyleCredential.objects.get( workspace_id=workspace_id) fyle_connection = FyleConnector( refresh_token=fyle_credentials.refresh_token, workspace_id=workspace_id) fyle_connection.sync_employees() Mapping.auto_map_ccc_employees('CREDIT_CARD_ACCOUNT', default_ccc_account_id, workspace_id)
def get(self, request, *args, **kwargs): """ Get cluster domain from Fyle """ try: fyle_credentials = AuthToken.objects.get( user__user_id=request.user) fyle_connector = FyleConnector(fyle_credentials.refresh_token) cluster_domain = fyle_connector.get_cluster_domain( )['cluster_domain'] return Response(data=cluster_domain, status=status.HTTP_200_OK) except FyleCredential.DoesNotExist: return Response(data={'message': 'Invalid / Expired Token'}, status=status.HTTP_400_BAD_REQUEST)
def schedule_bills_creation(workspace_id: int, expense_group_ids: List[str], user): """ Schedule bills creation :param expense_group_ids: List of expense group ids :param workspace_id: workspace id :param user: user email :return: None """ if expense_group_ids: expense_groups = ExpenseGroup.objects.filter( workspace_id=workspace_id, id__in=expense_group_ids, bill__id__isnull=True).all() else: expense_groups = ExpenseGroup.objects.filter( workspace_id=workspace_id, bill__id__isnull=True).all() fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) fyle_connector = FyleConnector(fyle_credentials.refresh_token, workspace_id) fyle_sdk_connection = fyle_connector.connection jobs = FyleJobsSDK(settings.FYLE_JOBS_URL, fyle_sdk_connection) for expense_group in expense_groups: task_log, _ = TaskLog.objects.update_or_create( workspace_id=expense_group.workspace_id, expense_group=expense_group, defaults={ 'status': 'IN_PROGRESS', 'type': 'CREATING_BILL' }) created_job = jobs.trigger_now( callback_url='{0}{1}'.format( settings.API_URL, '/workspaces/{0}/qbo/bills/'.format(workspace_id)), callback_method='POST', object_id=task_log.id, payload={ 'expense_group_id': expense_group.id, 'task_log_id': task_log.id }, job_description= 'Create Bill: Workspace id - {0}, user - {1}, expense group id - {2}' .format(workspace_id, user, expense_group.id)) task_log.task_id = created_job['id'] task_log.save()
def schedule_expense_reports_creation(workspace_id: int, expense_group_ids: List[str], user): """ Schedule expense reports creation :param expense_group_ids: List of expense group ids :param workspace_id: workspace id :param user: user email :return: None """ if expense_group_ids: expense_groups = ExpenseGroup.objects.filter( workspace_id=workspace_id, id__in=expense_group_ids, expensereport__id__isnull=True).all() else: expense_groups = ExpenseGroup.objects.filter( workspace_id=workspace_id, expensereport__id__isnull=True).all() fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) fyle_connector = FyleConnector(fyle_credentials.refresh_token, workspace_id) fyle_sdk_connection = fyle_connector.connection jobs = fyle_sdk_connection.Jobs user_profile = fyle_sdk_connection.Employees.get_my_profile()['data'] for expense_group in expense_groups: task_log, _ = TaskLog.objects.update_or_create( workspace_id=expense_group.workspace_id, expense_group=expense_group, defaults={ 'status': 'IN_PROGRESS', 'type': 'CREATING_EXPENSE_REPORTS' }) created_job = jobs.trigger_now( callback_url='{0}{1}'.format(settings.API_URL, \ '/workspaces/{0}/sage_intacct/expense_reports/'.format(workspace_id)), callback_method='POST', object_id=task_log.id, payload={ 'expense_group_id': expense_group.id, 'task_log_id': task_log.id }, job_description='Create Expense Report: Workspace id - {0}, user - {1}, expense group id - {2}'.format( workspace_id, user, expense_group.id ), org_user_id=user_profile['id'] ) task_log.task_id = created_job['id'] task_log.save()
def create_schedule_job(workspace_id: int, schedule: WorkspaceSchedule, user: str, start_datetime: datetime, hours: int): fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) fyle_connector = FyleConnector(fyle_credentials.refresh_token) fyle_sdk_connection = fyle_connector.connection jobs = FyleJobsSDK(settings.FYLE_JOBS_URL, fyle_sdk_connection) created_job = jobs.trigger_interval( callback_url='{0}{1}'.format( settings.API_URL, '/workspaces/{0}/schedule/trigger/'.format(workspace_id)), callback_method='POST', object_id=schedule.id, job_description='Fetch expenses: Workspace id - {0}, user - {1}'. format(workspace_id, user), start_datetime=start_datetime.strftime('%Y-%m-%d %H:%M:00.00'), hours=hours) return created_job
def get_expense_purpose(workspace_id, lineitem, category) -> str: fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) fyle_connector = FyleConnector(fyle_credentials.refresh_token, workspace_id) cluster_domain = fyle_connector.get_cluster_domain() org_id = Workspace.objects.get(id=workspace_id).fyle_org_id expense_link = '{0}/app/main/#/enterprise/view_expense/{1}?org_id={2}'.format( cluster_domain['cluster_domain'], lineitem.expense_id, org_id) expense_purpose = ' purpose - {0}'.format( lineitem.purpose) if lineitem.purpose else '' spent_at = ' spent on {0} '.format( lineitem.spent_at.date()) if lineitem.spent_at else '' merchant = ' spent on merchant {0}'.format( lineitem.vendor) if lineitem.vendor else '' return 'Expense by {0}{1} against category {2}{3} with claim number - {4} -{5} - {6}'.format( lineitem.employee_email, merchant, category, spent_at, lineitem.claim_number, expense_purpose, expense_link)
def write_data(self, orgs, sheet_id): data_to_export, total_orgs = [get_headers()], len(orgs) for org in orgs.values(): fyle_connector = FyleConnector(org['refresh_token']) expenses = fyle_connector.get_expenses() data_to_export.extend(format_expenses(expenses)) data = {'values': data_to_export} self.service.spreadsheets().values().clear(spreadsheetId=sheet_id, range=self.range).execute() request = self.service.spreadsheets().values().append( spreadsheetId=sheet_id, range=self.range, valueInputOption='RAW', body=data) response = request.execute() rows = len(data_to_export) - 1 if response: return True, rows, total_orgs return False, 0, total_orgs
def upload_categories_to_fyle(workspace_id): """ Upload categories to Fyle """ try: fyle_credentials: FyleCredential = FyleCredential.objects.get( workspace_id=workspace_id) xero_credentials: XeroCredentials = XeroCredentials.objects.get( workspace_id=workspace_id) fyle_connection = FyleConnector( refresh_token=fyle_credentials.refresh_token, workspace_id=workspace_id) xero_connection = XeroConnector(credentials_object=xero_credentials, workspace_id=workspace_id) fyle_connection.sync_categories(False) xero_connection.sync_accounts() xero_attributes = DestinationAttribute.objects.filter( attribute_type='ACCOUNT', workspace_id=workspace_id) xero_attributes = remove_duplicates(xero_attributes) fyle_payload: List[Dict] = create_fyle_categories_payload( xero_attributes, workspace_id) if fyle_payload: fyle_connection.connection.Categories.post(fyle_payload) fyle_connection.sync_categories(False) return xero_attributes except XeroCredentials.DoesNotExist: logger.error( 'Xero Credentials not found for workspace_id %s', workspace_id, )
def load_attachments(qbo_connection: QBOConnector, ref_id: str, ref_type: str, expense_group: ExpenseGroup): """ Get attachments from fyle :param qbo_connection: QBO Connection :param ref_id: object id :param ref_type: type of object :param expense_group: Expense group """ try: fyle_credentials = FyleCredential.objects.get( workspace_id=expense_group.workspace_id) expense_ids = expense_group.expenses.values_list('expense_id', flat=True) fyle_connector = FyleConnector(fyle_credentials.refresh_token, expense_group.workspace_id) attachments = fyle_connector.get_attachments(expense_ids) qbo_connection.post_attachments(ref_id, ref_type, attachments) except Exception: error = traceback.format_exc() logger.error( 'Attachment failed for expense group id %s / workspace id %s \n Error: %s', expense_group.id, expense_group.workspace_id, {'error': error})
def load_attachments(sage_intacct_connection: SageIntacctConnector, key: str, expense_group: ExpenseGroup): """ Get attachments from fyle :param sage_intacct_connection: Sage Intacct Connection :param key: expense report / bills key :param expense_group: Expense group """ try: fyle_credentials = FyleCredential.objects.get( workspace_id=expense_group.workspace_id) expense_ids = expense_group.expenses.values_list('expense_id', flat=True) fyle_connector = FyleConnector(fyle_credentials.refresh_token, expense_group.workspace_id) claim_number = expense_group.description.get('claim_number') attachments = fyle_connector.get_attachments(expense_ids) return sage_intacct_connection.post_attachments( attachments, claim_number) except Exception: error = traceback.format_exc() logger.error( 'Attachment failed for expense group id %s / workspace id %s \n Error: %s', expense_group.id, expense_group.workspace_id, error)
def create_bill_payment(workspace_id): fyle_credentials = FyleCredential.objects.get(workspace_id=workspace_id) fyle_connector = FyleConnector(fyle_credentials.refresh_token, workspace_id) fyle_connector.sync_reimbursements() bills = Bill.objects.filter(payment_synced=False, expense_group__workspace_id=workspace_id, expense_group__fund_source='PERSONAL').all() if bills: for bill in bills: expense_group_reimbursement_status = check_expenses_reimbursement_status( bill.expense_group.expenses.all()) if expense_group_reimbursement_status: task_log, _ = TaskLog.objects.update_or_create( workspace_id=workspace_id, task_id='PAYMENT_{}'.format(bill.expense_group.id), defaults={ 'status': 'IN_PROGRESS', 'type': 'CREATING_BILL_PAYMENT' }) try: with transaction.atomic(): bill_payment_object = BillPayment.create_bill_payment( bill.expense_group) qbo_object_task_log = TaskLog.objects.get( expense_group=bill.expense_group) linked_transaction_id = qbo_object_task_log.detail[ 'Bill']['Id'] bill_payment_lineitems_objects = BillPaymentLineitem.create_bill_payment_lineitems( bill_payment_object.expense_group, linked_transaction_id) qbo_credentials = QBOCredential.objects.get( workspace_id=workspace_id) qbo_connection = QBOConnector(qbo_credentials, workspace_id) created_bill_payment = qbo_connection.post_bill_payment( bill_payment_object, bill_payment_lineitems_objects) bill.payment_synced = True bill.paid_on_qbo = True bill.save() task_log.detail = created_bill_payment task_log.bill_payment = bill_payment_object task_log.status = 'COMPLETE' task_log.save() except QBOCredential.DoesNotExist: logger.error( 'QBO Credentials not found for workspace_id %s / expense group %s', workspace_id, bill.expense_group) detail = { 'expense_group_id': bill.expense_group, 'message': 'QBO Account not connected' } task_log.status = 'FAILED' task_log.detail = detail task_log.save() except BulkError as exception: logger.error(exception.response) detail = exception.response task_log.status = 'FAILED' task_log.detail = detail task_log.save() except WrongParamsError as exception: logger.error(exception.response) detail = json.loads(exception.response) task_log.status = 'FAILED' task_log.detail = detail task_log.save() except Exception: error = traceback.format_exc() task_log.detail = {'error': error} task_log.status = 'FATAL' task_log.save() logger.error( 'Something unexpected happened workspace_id: %s %s', task_log.workspace_id, task_log.detail)