Skip to content

Commit

Permalink
Accounting exports summary APIs (#17)
Browse files Browse the repository at this point in the history
* Accounting exports summary APIs

* Errors APIs (#18)

* Errors APIs

* Expense filter api (#19)

* Expense Filter APIs

* Expense Filter APIs

* Expense Filter APIs

* Resolved
  • Loading branch information
ruuushhh authored Nov 7, 2023
1 parent c01029b commit 6155790
Show file tree
Hide file tree
Showing 15 changed files with 446 additions and 17 deletions.
51 changes: 47 additions & 4 deletions apps/accounting_exports/models.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
from django.db import models
from django.contrib.postgres.fields import ArrayField

from fyle_accounting_mappings.models import ExpenseAttribute

from ms_business_central_api.models.fields import (
StringNotNullField,
StringNullField,
CustomJsonField,
CustomDateTimeField,
StringOptionsField
StringOptionsField,
IntegerNullField,
BooleanFalseField,
TextNotNullField
)
from apps.workspaces.models import BaseForeignWorkspaceModel
from apps.workspaces.models import BaseForeignWorkspaceModel, BaseModel
from apps.fyle.models import Expense

TYPE_CHOICES = (
Expand All @@ -18,7 +23,7 @@
('FETCHING_CREDIT_CARD_EXPENENSES', 'FETCHING_CREDIT_CARD_EXPENENSES')
)

ERROR_TYPE_CHOICES = (('EMPLOYEE_MAPPING', 'EMPLOYEE_MAPPING'), ('CATEGORY_MAPPING', 'CATEGORY_MAPPING'), ('SAGE300_ERROR', 'SAGE300_ERROR'))
ERROR_TYPE_CHOICES = (('EMPLOYEE_MAPPING', 'EMPLOYEE_MAPPING'), ('CATEGORY_MAPPING', 'CATEGORY_MAPPING'), ('BUSINESS_CENTRAL_ERROR', 'BUSINESS_CENTRAL_ERROR'))

EXPORT_MODE_CHOICES = (
('MANUAL', 'MANUAL'),
Expand All @@ -39,8 +44,46 @@ class AccountingExport(BaseForeignWorkspaceModel):
description = CustomJsonField(help_text='Description')
status = StringNotNullField(help_text='Task Status')
detail = CustomJsonField(help_text='Task Response')
sage_300_errors = CustomJsonField(help_text='Sage 300 Errors')
business_central_errors = CustomJsonField(help_text='Business Central Errors')
exported_at = CustomDateTimeField(help_text='time of export')

class Meta:
db_table = 'accounting_exports'


class AccountingExportSummary(BaseModel):
"""
Table to store accounting export summary
"""
id = models.AutoField(primary_key=True)
last_exported_at = CustomDateTimeField(help_text='Last exported at datetime')
next_export_at = CustomDateTimeField(help_text='next export datetime')
export_mode = StringOptionsField(choices=EXPORT_MODE_CHOICES, help_text='Export mode')
total_accounting_export_count = IntegerNullField(help_text='Total count of accounting export exported')
successful_accounting_export_count = IntegerNullField(help_text='count of successful accounting export')
failed_accounting_export_count = IntegerNullField(help_text='count of failed accounting export')

class Meta:
db_table = 'accounting_export_summary'


class Error(BaseForeignWorkspaceModel):
"""
Table to store errors
"""
id = models.AutoField(primary_key=True)
type = StringOptionsField(max_length=50, choices=ERROR_TYPE_CHOICES, help_text='Error type')
accounting_export = models.ForeignKey(
AccountingExport, on_delete=models.PROTECT,
null=True, help_text='Reference to Expense group'
)
expense_attribute = models.OneToOneField(
ExpenseAttribute, on_delete=models.PROTECT,
null=True, help_text='Reference to Expense Attribute'
)
is_resolved = BooleanFalseField(help_text='Is resolved')
error_title = StringNotNullField(help_text='Error title')
error_detail = TextNotNullField(help_text='Error detail')

class Meta:
db_table = 'errors'
22 changes: 21 additions & 1 deletion apps/accounting_exports/serializers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from rest_framework import serializers

from apps.accounting_exports.models import AccountingExport
from apps.accounting_exports.models import AccountingExport, AccountingExportSummary, Error


class AccountingExportSerializer(serializers.ModelSerializer):
Expand All @@ -11,3 +11,23 @@ class AccountingExportSerializer(serializers.ModelSerializer):
class Meta:
model = AccountingExport
fields = '__all__'


class AccountingExportSummarySerializer(serializers.ModelSerializer):
"""
Accounting Export Summary serializer
"""

class Meta:
model = AccountingExportSummary
fields = '__all__'


class ErrorSerializer(serializers.ModelSerializer):
"""
Serializer for the Errors
"""

class Meta:
model = Error
fields = '__all__'
6 changes: 4 additions & 2 deletions apps/accounting_exports/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""sage_desktop_api URL Configuration
"""ms_business_central_api URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Expand All @@ -14,10 +14,12 @@
"""
from django.urls import path

from apps.accounting_exports.views import AccountingExportView, AccountingExportCountView
from apps.accounting_exports.views import AccountingExportView, AccountingExportCountView, AccountingExportSummaryView, ErrorsView


urlpatterns = [
path('', AccountingExportView.as_view(), name='accounting-exports'),
path('count/', AccountingExportCountView.as_view(), name='accounting-exports-count'),
path('summary/', AccountingExportSummaryView.as_view(), name='accounting-exports-summary'),
path('errors/', ErrorsView.as_view(), name='errors'),
]
22 changes: 20 additions & 2 deletions apps/accounting_exports/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from rest_framework.response import Response

from ms_business_central_api.utils import LookupFieldMixin
from apps.accounting_exports.serializers import AccountingExportSerializer
from apps.accounting_exports.models import AccountingExport
from apps.accounting_exports.serializers import AccountingExportSerializer, AccountingExportSummarySerializer, ErrorSerializer
from apps.accounting_exports.models import AccountingExport, AccountingExportSummary, Error


logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -35,3 +35,21 @@ def get(self, request, *args, **kwargs):
params["status__in"] = request.query_params.get("status__in").split(",")

return Response({"count": AccountingExport.objects.filter(**params).count()})


class AccountingExportSummaryView(generics.RetrieveAPIView):
"""
Retrieve Accounting Export Summary
"""
lookup_field = 'workspace_id'
lookup_url_kwarg = 'workspace_id'

queryset = AccountingExportSummary.objects.filter(last_exported_at__isnull=False, total_accounting_export_count__gt=0)
serializer_class = AccountingExportSummarySerializer


class ErrorsView(LookupFieldMixin, generics.ListAPIView):
serializer_class = ErrorSerializer
queryset = Error.objects.all()
filter_backends = (DjangoFilterBackend,)
filterset_fields = {"type": {"exact"}, "is_resolved": {"exact"}}
50 changes: 48 additions & 2 deletions apps/fyle/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,38 @@
CustomJsonField,
CustomDateTimeField,
CustomEmailField,
FloatNullField
FloatNullField,
StringOptionsField,
IntegerOptionsField,
)
from apps.workspaces.models import BaseModel, BaseForeignWorkspaceModel


EXPENSE_FILTER_RANK = (
(1, 1),
(2, 2)
)

EXPENSE_FILTER_JOIN_BY = (
('AND', 'AND'),
('OR', 'OR')
)

EXPENSE_FILTER_CUSTOM_FIELD_TYPE = (
('SELECT', 'SELECT'),
('NUMBER', 'NUMBER'),
('TEXT', 'TEXT')
)

EXPENSE_FILTER_OPERATOR = (
('isnull', 'isnull'),
('in', 'in'),
('iexact', 'iexact'),
('icontains', 'icontains'),
('lt', 'lt'),
('lte', 'lte'),
('not_in', 'not_in')
)
from apps.workspaces.models import BaseModel


class Expense(BaseModel):
Expand Down Expand Up @@ -58,6 +87,23 @@ class Meta:
db_table = 'expenses'


class ExpenseFilter(BaseForeignWorkspaceModel):
"""
Reimbursements
"""
id = models.AutoField(primary_key=True)
condition = StringNotNullField(help_text='Condition for the filter')
operator = StringOptionsField(choices=EXPENSE_FILTER_OPERATOR, help_text='Operator for the filter')
values = ArrayField(base_field=models.CharField(max_length=255), null=True, help_text='Values for the operator')
rank = IntegerOptionsField(choices=EXPENSE_FILTER_RANK, help_text='Rank for the filter')
join_by = StringOptionsField(choices=EXPENSE_FILTER_JOIN_BY, max_length=3, help_text='Used to join the filter (AND/OR)')
is_custom = BooleanFalseField(help_text='Custom Field or not')
custom_field_type = StringOptionsField(help_text='Custom field type', choices=EXPENSE_FILTER_CUSTOM_FIELD_TYPE)

class Meta:
db_table = 'expense_filters'


class Reimbursement:
"""
Creating a dummy class to be able to user
Expand Down
21 changes: 21 additions & 0 deletions apps/fyle/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
Fyle Serializers
"""
import logging
from rest_framework import serializers

from apps.fyle.models import ExpenseFilter

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


class ExpenseFilterSerializer(serializers.ModelSerializer):
"""
Expense Filter Serializer
"""

class Meta:
model = ExpenseFilter
fields = '__all__'
read_only_fields = ('id', 'workspace', 'created_at', 'updated_at')
Empty file removed apps/fyle/serializers.py.py
Empty file.
24 changes: 24 additions & 0 deletions apps/fyle/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""fyle_ms_business_central URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.0/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""

from django.urls import path
from apps.fyle.views import ExpenseFilterView, ExpenseFilterDeleteView


urlpatterns = [
path('expense_filters/<int:pk>/', ExpenseFilterDeleteView.as_view(), name='expense-filters'),
path('expense_filters/', ExpenseFilterView.as_view(), name='expense-filters'),
]
26 changes: 26 additions & 0 deletions apps/fyle/views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import logging
from rest_framework import generics
from ms_business_central_api.utils import LookupFieldMixin
from apps.fyle.serializers import ExpenseFilterSerializer
from apps.fyle.models import ExpenseFilter

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


class ExpenseFilterView(LookupFieldMixin, generics.ListCreateAPIView):
"""
Expense Filter view
"""

queryset = ExpenseFilter.objects.all()
serializer_class = ExpenseFilterSerializer


class ExpenseFilterDeleteView(generics.DestroyAPIView):
"""
Expense Filter Delete view
"""

queryset = ExpenseFilter.objects.all()
serializer_class = ExpenseFilterSerializer
6 changes: 3 additions & 3 deletions apps/workspaces/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ class Meta:

REIMBURSABLE_EXPENSE_STATE_CHOICES = (
('PAYMENT_PROCESSING', 'PAYMENT_PROCESSING'),
('CLOSED', 'CLOSED')
('PAID', 'PAID')
)

REIMBURSABLE_EXPENSES_GROUPED_BY_CHOICES = (
Expand Down Expand Up @@ -180,8 +180,8 @@ class ImportSetting(BaseModel):
Table to store Import setting
"""
id = models.AutoField(auto_created=True, primary_key=True, verbose_name='ID', serialize=False)
import_categories = BooleanFalseField(help_text='toggle for import of chart of accounts from sage300')
import_vendors_as_merchants = BooleanFalseField(help_text='toggle for import of vendors as merchant from sage300')
import_categories = BooleanFalseField(help_text='toggle for import of chart of accounts from Business Central')
import_vendors_as_merchants = BooleanFalseField(help_text='toggle for import of vendors as merchant from Business Central')

class Meta:
db_table = 'import_settings'
Expand Down
1 change: 1 addition & 0 deletions apps/workspaces/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

other_app_paths = [
path('<int:workspace_id>/accounting_exports/', include('apps.accounting_exports.urls')),
path('<int:workspace_id>/fyle/', include('apps.fyle.urls')),
]

urlpatterns = []
Expand Down
Loading

0 comments on commit 6155790

Please sign in to comment.