diff --git a/apps/data/serializers.py b/apps/data/serializers.py index ab81fec..645467d 100644 --- a/apps/data/serializers.py +++ b/apps/data/serializers.py @@ -107,7 +107,7 @@ class ClientSerializer(BaseSerializer): class Meta: model = Client - read_only_fields = ['id', 'level_display', 'category_name', 'arrears_amount', 'has_arrears'] + read_only_fields = ['id', 'level_display', 'category_name'] fields = ['number', 'name', 'level', 'category', 'contact', 'phone', 'email', 'address', 'remark', 'order', 'is_active', 'initial_arrears_amount', *read_only_fields] @@ -221,7 +221,7 @@ class SupplierSerializer(BaseSerializer): class Meta: model = Supplier - read_only_fields = ['id', 'category_name', 'arrears_amount', 'has_arrears'] + read_only_fields = ['id', 'category_name'] fields = ['number', 'name', 'category', 'contact', 'phone', 'email', 'address', 'bank_account', 'bank_name', 'remark', 'order', 'is_active', 'initial_arrears_amount', *read_only_fields] diff --git a/apps/data/views.py b/apps/data/views.py index 38ab0c1..7ee9ea9 100644 --- a/apps/data/views.py +++ b/apps/data/views.py @@ -161,7 +161,7 @@ class ClientViewSet(ModelViewSet, DataProtectMixin, ExportMixin, ImportMixin): serializer_class = ClientSerializer permission_classes = [IsAuthenticated, ClientPermission] - filterset_fields = ['level', 'category', 'has_arrears', 'is_active'] + filterset_fields = ['level', 'category', 'is_active'] search_fields = ['number', 'name', 'contact', 'remark'] ordering_fields = ['id', 'number', 'name', 'order'] ordering = ['order', 'id'] @@ -274,7 +274,7 @@ class SupplierViewSet(ModelViewSet, DataProtectMixin, ExportMixin, ImportMixin): serializer_class = SupplierSerializer permission_classes = [IsAuthenticated, SupplierPermission] - filterset_fields = ['category', 'has_arrears', 'is_active'] + filterset_fields = ['category', 'is_active'] search_fields = ['number', 'name', 'contact', 'remark'] ordering_fields = ['id', 'number', 'name', 'order'] ordering = ['order', 'id'] diff --git a/apps/finance/permissions.py b/apps/finance/permissions.py index 999d6ca..3c7de31 100644 --- a/apps/finance/permissions.py +++ b/apps/finance/permissions.py @@ -1,6 +1,14 @@ from extensions.permissions import ModelPermission +class ClientArrearsPermission(ModelPermission): + code = 'client_arrears' + + +class SupplierArrearsPermission(ModelPermission): + code = 'supplier_arrears' + + class PaymentOrderPermission(ModelPermission): code = 'payment_order' @@ -18,6 +26,7 @@ class AccountTransferRecordPermission(ModelPermission): __all__ = [ + 'ClientArrearsPermission', 'SupplierArrearsPermission', 'PaymentOrderPermission', 'CollectionOrderPermission', 'ChargeOrderPermission', 'AccountTransferRecordPermission', ] diff --git a/apps/finance/serializers.py b/apps/finance/serializers.py index 4849f10..df35a60 100644 --- a/apps/finance/serializers.py +++ b/apps/finance/serializers.py @@ -6,6 +6,31 @@ from apps.data.models import * from apps.system.models import * +class ClientArrearsSerializer(BaseSerializer): + """应收欠款""" + + level_display = CharField(source='get_level_display', read_only=True, label='等级') + category_name = CharField(source='category.name', read_only=True, label='分类名称') + + class Meta: + model = Client + fields = ['id', 'number', 'name', 'level', 'level_display', 'category', 'category_name', + 'contact', 'phone', 'email', 'address', 'remark', 'order', 'is_active', + 'initial_arrears_amount', 'arrears_amount', 'has_arrears'] + + +class SupplierArrearsSerializer(BaseSerializer): + """应付欠款""" + + category_name = CharField(source='category.name', read_only=True, label='分类名称') + + class Meta: + model = Supplier + fields = ['id', 'number', 'name', 'category', 'category_name', 'contact', 'phone', 'email', + 'address', 'bank_account', 'bank_name', 'remark', 'order', 'is_active', + 'initial_arrears_amount', 'arrears_amount', 'has_arrears'] + + class PaymentOrderSerializer(BaseSerializer): """付款单据""" @@ -226,10 +251,10 @@ class ChargeOrderSerializer(BaseSerializer): client = attrs.get('client') if (supplier and client) or not (supplier or client): raise ValidationError('供应商或客户选择重复') - + if attrs['type'] != attrs['charge_item'].type: raise ValidationError('收支类型与收支项目不匹配') - + if attrs['charge_amount'] > attrs['total_amount']: raise ValidationError('实收/付金额大于应收/付金额') return super().validate(attrs) @@ -292,6 +317,7 @@ class AccountTransferRecordSerializer(BaseSerializer): __all__ = [ + 'ClientArrearsSerializer', 'SupplierArrearsSerializer', 'PaymentOrderSerializer', 'CollectionOrderSerializer', 'ChargeOrderSerializer', 'AccountTransferRecordSerializer', ] diff --git a/apps/finance/urls.py b/apps/finance/urls.py index 03a1c26..f638995 100644 --- a/apps/finance/urls.py +++ b/apps/finance/urls.py @@ -3,6 +3,8 @@ from apps.finance.views import * router = BaseRouter() +router.register('client_arrears', ClientArrearsViewSet, 'client_arrears') +router.register('supplier_arrears', SupplierArrearsViewSet, 'supplier_arrears') router.register('payment_orders', PaymentOrderViewSet, 'payment_order') router.register('collection_orders', CollectionOrderViewSet, 'collection_order') router.register('charge_orders', ChargeOrderViewSet, 'charge_order') diff --git a/apps/finance/views.py b/apps/finance/views.py index 5add283..67ff6fd 100644 --- a/apps/finance/views.py +++ b/apps/finance/views.py @@ -9,6 +9,33 @@ from apps.finance.filters import * from apps.finance.schemas import * from apps.finance.models import * from apps.flow.models import * +from apps.data.models import * + + +class ClientArrearsViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin): + """应收欠款""" + + serializer_class = ClientArrearsSerializer + permission_classes = [IsAuthenticated, ClientArrearsPermission] + filterset_fields = ['category', 'level', 'is_active', 'has_arrears'] + search_fields = ['number', 'name', 'contact', 'remark'] + ordering_fields = ['id', 'number', 'name', 'order', 'initial_arrears_amount', 'arrears_amount'] + ordering = ['order', 'id'] + select_related_fields = ['category'] + queryset = Client.objects.all() + + +class SupplierArrearsViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin): + """应付欠款""" + + serializer_class = SupplierArrearsSerializer + permission_classes = [IsAuthenticated, SupplierArrearsPermission] + filterset_fields = ['category', 'is_active', 'has_arrears'] + search_fields = ['number', 'name', 'contact', 'remark'] + ordering_fields = ['id', 'number', 'name', 'order', 'initial_arrears_amount', 'arrears_amount'] + ordering = ['order', 'id'] + select_related_fields = ['category'] + queryset = Supplier.objects.all() class PaymentOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, CreateModelMixin): @@ -416,6 +443,7 @@ class AccountTransferRecordViewSet(BaseViewSet, ListModelMixin, RetrieveModelMix __all__ = [ + 'ClientArrearsViewSet', 'SupplierArrearsViewSet', 'PaymentOrderViewSet', 'CollectionOrderViewSet', 'ChargeOrderViewSet', 'AccountTransferRecordViewSet', ] diff --git a/apps/option/permissions.py b/apps/option/permissions.py index 68783cc..ec913ac 100644 --- a/apps/option/permissions.py +++ b/apps/option/permissions.py @@ -30,6 +30,10 @@ PurchaseOrderOptionPermission = BasePermission # Sales SalesOrderOptionPermission = BasePermission +# Finance +ClientArrearsOptionPermission = BasePermission +SupplierArrearsOptionPermission = BasePermission + __all__ = [ 'RoleOptionPermission', 'UserOptionPermission', @@ -39,4 +43,5 @@ __all__ = [ 'BatchOptionPermission', 'InventoryOptionPermission', 'PurchaseOrderOptionPermission', 'SalesOrderOptionPermission', + 'ClientArrearsOptionPermission', 'SupplierArrearsOptionPermission', ] diff --git a/apps/option/serializers.py b/apps/option/serializers.py index 6bf445b..d8cc29d 100644 --- a/apps/option/serializers.py +++ b/apps/option/serializers.py @@ -202,6 +202,26 @@ class SalesOrderOptionSerializer(ModelSerializer): 'creator_name', 'create_time', 'sales_goods_items', 'sales_account_items'] +# Finance +class ClientArrearsOptionSerializer(BaseSerializer): + category_name = CharField(source='category.name', read_only=True, label='分类名称') + + class Meta: + model = Client + fields = ['id', 'number', 'name', 'category', 'category_name', 'contact', 'phone', 'email', + 'address', 'remark', 'is_active', 'arrears_amount', 'has_arrears'] + + +class SupplierArrearsOptionSerializer(BaseSerializer): + category_name = CharField(source='category.name', read_only=True, label='分类名称') + + class Meta: + model = Supplier + fields = ['id', 'number', 'name', 'category', 'category_name', 'contact', 'phone', 'email', + 'address', 'remark', 'is_active', 'arrears_amount', 'has_arrears'] + + + __all__ = [ 'RoleOptionSerializer', 'UserOptionSerializer', 'WarehouseOptionSerializer', @@ -212,4 +232,5 @@ __all__ = [ 'BatchOptionSerializer', 'InventoryOptionSerializer', 'PurchaseOrderOptionSerializer', 'SalesOrderOptionSerializer', + 'ClientArrearsOptionSerializer', 'SupplierArrearsOptionSerializer', ] diff --git a/apps/option/urls.py b/apps/option/urls.py index 1c80bf3..1e41475 100644 --- a/apps/option/urls.py +++ b/apps/option/urls.py @@ -31,4 +31,8 @@ router.register('purchase_orders/options', PurchaseOrderOptionViewSet, 'purchase # Sales router.register('sales_orders/options', SalesOrderOptionViewSet, 'sales_order_option') +# Finance +router.register('client_arrears/options', ClientArrearsOptionViewSet, 'client_arrear_option') +router.register('supplier_arrears/options', SupplierArrearsOptionViewSet, 'supplier_arrear_option') + urlpatterns = router.urls diff --git a/apps/option/views.py b/apps/option/views.py index 9a17a86..3dd904e 100644 --- a/apps/option/views.py +++ b/apps/option/views.py @@ -165,6 +165,29 @@ class SalesOrderOptionViewSet(LimitedOptionViewSet): queryset = SalesOrder.objects.all() +# Finance +class ClientArrearsOptionViewSet(InfiniteOptionViewSet): + serializer_class = ClientArrearsOptionSerializer + permission_classes = [IsAuthenticated, ClientArrearsOptionPermission] + filterset_fields = ['category', 'level', 'is_active', 'has_arrears'] + search_fields = ['number', 'name', 'contact', 'remark'] + ordering_fields = ['id', 'number', 'name', 'order', 'arrears_amount'] + ordering = ['order', 'id'] + select_related_fields = ['category'] + queryset = Client.objects.all() + + +class SupplierArrearsOptionViewSet(InfiniteOptionViewSet): + serializer_class = SupplierArrearsOptionSerializer + permission_classes = [IsAuthenticated, SupplierArrearsOptionPermission] + filterset_fields = ['category', 'is_active', 'has_arrears'] + search_fields = ['number', 'name', 'contact', 'remark'] + ordering_fields = ['id', 'number', 'name', 'order', 'arrears_amount'] + ordering = ['order', 'id'] + select_related_fields = ['category'] + queryset = Supplier.objects.all() + + __all__ = [ 'RoleOptionViewSet', 'UserOptionViewSet', 'WarehouseOptionViewSet', @@ -175,4 +198,5 @@ __all__ = [ 'BatchOptionViewSet', 'InventoryOptionViewSet', 'PurchaseOrderOptionViewSet', 'SalesOrderOptionViewSet', + 'ClientArrearsOptionViewSet', 'SupplierArrearsOptionViewSet', ] diff --git a/documents/项目文档/财务管理/付款.md b/documents/项目文档/财务管理/付款.md index 348f8f2..bd384ea 100644 --- a/documents/项目文档/财务管理/付款.md +++ b/documents/项目文档/财务管理/付款.md @@ -3,5 +3,20 @@ ## 功能 +- 查询/创建付款单: +[/api/payment_orders/] + +- 获取付款单号: +[/api/payment_orders/number/] + +- 作废付款单: +[/api/payment_orders/{id}/void/] + ## 其他接口 + +- 供应商选项: +[/api/supplier_arrears/options/]{is_active: true, has_arrears: true} + +- 经手人选项: +[/api/users/options/]{is_active: true} diff --git a/documents/项目文档/财务管理/应付欠款.md b/documents/项目文档/财务管理/应付欠款.md index 9e300bc..1a36074 100644 --- a/documents/项目文档/财务管理/应付欠款.md +++ b/documents/项目文档/财务管理/应付欠款.md @@ -3,5 +3,8 @@ ## 功能 +- 查询应付欠款: +[/api/supplier_arrears/]{search, page, has_arrears: true} + ## 其他接口 diff --git a/documents/项目文档/财务管理/应收欠款.md b/documents/项目文档/财务管理/应收欠款.md index 4162df6..be94799 100644 --- a/documents/项目文档/财务管理/应收欠款.md +++ b/documents/项目文档/财务管理/应收欠款.md @@ -3,5 +3,8 @@ ## 功能 +- 查询应收欠款: +[/api/client_arrears/]{search, page, has_arrears: true} + ## 其他接口 diff --git a/documents/项目文档/财务管理/收款.md b/documents/项目文档/财务管理/收款.md index a02705c..c633d37 100644 --- a/documents/项目文档/财务管理/收款.md +++ b/documents/项目文档/财务管理/收款.md @@ -3,5 +3,20 @@ ## 功能 +- 查询/创建收款单: +[/api/collection_orders/] + +- 获取收款单号: +[/api/collection_orders/number/] + +- 作废收款单: +[/api/collection_orders/{id}/void/] + ## 其他接口 + +- 客户选项: +[/api/client_arrears/options/]{is_active: true, has_arrears: true} + +- 经手人选项: +[/api/users/options/]{is_active: true} diff --git a/documents/项目文档/财务管理/日常收支.md b/documents/项目文档/财务管理/日常收支.md index 87c1c58..2e463ae 100644 --- a/documents/项目文档/财务管理/日常收支.md +++ b/documents/项目文档/财务管理/日常收支.md @@ -3,5 +3,29 @@ ## 功能 +- 查询/创建收支单: +[/api/charge_orders/] + +- 获取收支单号: +[/api/charge_orders/number/] + +- 作废收支单: +[/api/charge_orders/{id}/void/] + ## 其他接口 + +- 客户选项: +[/api/clients/options/]{is_active: true} + +- 供应商选项: +[/api/suppliers/options/]{is_active: true} + +- 收支项目选项: +[/api/charge_items/options/] + +- 经手人选项: +[/api/users/options/]{is_active: true} + +- 结算账户选项: +[/api/accounts/options/]{is_active: true} diff --git a/documents/项目文档/财务管理/账户转账.md b/documents/项目文档/财务管理/账户转账.md index eb8efd2..3873904 100644 --- a/documents/项目文档/财务管理/账户转账.md +++ b/documents/项目文档/财务管理/账户转账.md @@ -3,5 +3,17 @@ ## 功能 +- 查询/创建账户转账: +[/api/account_transfer_records/] + +- 作废账户转账: +[/api/account_transfer_records/{id}/void/] + ## 其他接口 + +- 结算账户选项: +[/api/accounts/options/]{is_active: true} + +- 经手人选项: +[/api/users/options/]{is_active: true} diff --git a/documents/项目文档/财务管理/资金流水.md b/documents/项目文档/财务管理/资金流水.md index 6039e03..8640832 100644 --- a/documents/项目文档/财务管理/资金流水.md +++ b/documents/项目文档/财务管理/资金流水.md @@ -3,5 +3,8 @@ ## 功能 +- 查询资金流水: +[/api/finance_flows/] + ## 其他接口