HimoolERP/apps/finance/views.py
2022-03-25 18:15:20 +08:00

472 lines
22 KiB
Python

from extensions.common.schema import *
from extensions.common.base import *
from extensions.permissions import *
from extensions.exceptions import *
from extensions.viewsets import *
from apps.finance.serializers import *
from apps.finance.permissions import *
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 = ['level', 'is_active', 'has_arrears']
search_fields = ['number', 'name', 'contact', 'remark']
ordering_fields = ['id', 'number', 'name', 'initial_arrears_amount', 'arrears_amount']
ordering = ['id']
queryset = Client.objects.all()
class SupplierArrearsViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin):
"""应付欠款"""
serializer_class = SupplierArrearsSerializer
permission_classes = [IsAuthenticated, SupplierArrearsPermission]
filterset_fields = ['is_active', 'has_arrears']
search_fields = ['number', 'name', 'contact', 'remark']
ordering_fields = ['id', 'number', 'name', 'initial_arrears_amount', 'arrears_amount']
ordering = ['id']
queryset = Supplier.objects.all()
class PaymentOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, CreateModelMixin):
"""付款单据"""
serializer_class = PaymentOrderSerializer
permission_classes = [IsAuthenticated, PaymentOrderPermission]
filterset_class = PaymentOrderFilter
search_fields = ['number', 'supplier__number', 'supplier__name', 'remark']
ordering_fields = ['id', 'number', 'total_amount', 'create_time']
select_related_fields = ['supplier', 'handler', 'creator']
prefetch_related_fields = ['payment_accounts', 'payment_accounts__account']
queryset = PaymentOrder.objects.all()
@transaction.atomic
def perform_create(self, serializer):
payment_order = serializer.save()
# 同步欠款
supplier = payment_order.supplier
supplier.arrears_amount = NP.minus(supplier.arrears_amount, payment_order.total_amount)
supplier.has_arrears = supplier.arrears_amount > 0
supplier.save(update_fields=['arrears_amount', 'has_arrears'])
# 同步余额, 流水
finance_flows = []
for payment_account in payment_order.payment_accounts.all():
account = payment_account.account
amount_before = account.balance_amount
amount_change = payment_account.payment_amount
amount_after = NP.minus(amount_before, amount_change)
finance_flows.append(FinanceFlow(
account=account, type=FinanceFlow.Type.PAYMENT, amount_before=amount_before,
amount_change=amount_change, amount_after=amount_after, payment_order=payment_order,
creator=self.user, team=self.team
))
account.balance_amount = amount_after
if account.balance_amount < 0:
raise ValidationError(f'结算账户[{account.name}]余额不足')
account.has_balance = account.balance_amount > 0
account.save(update_fields=['balance_amount', 'has_balance'])
else:
FinanceFlow.objects.bulk_create(finance_flows)
@extend_schema(responses={200: NumberResponse})
@action(detail=False, methods=['get'])
def number(self, request, *args, **kwargs):
"""获取编号"""
number = PaymentOrder.get_number(self.team)
return Response(data={'number': number}, status=status.HTTP_200_OK)
@transaction.atomic
@extend_schema(request=None, responses={200: PaymentOrderSerializer})
@action(detail=True, methods=['post'])
def void(self, request, *args, **kwargs):
"""作废"""
payment_order = self.get_object()
payment_order.is_void = True
payment_order.save(update_fields=['is_void'])
# 同步欠款
supplier = payment_order.supplier
supplier.arrears_amount = NP.plus(supplier.arrears_amount, payment_order.total_amount)
supplier.has_arrears = supplier.arrears_amount > 0
supplier.save(update_fields=['arrears_amount', 'has_arrears'])
# 同步余额, 流水
finance_flows = []
for payment_account in payment_order.payment_accounts.all():
account = payment_account.account
amount_before = account.balance_amount
amount_change = payment_account.payment_amount
amount_after = NP.plus(amount_before, amount_change)
finance_flows.append(FinanceFlow(
account=account, type=FinanceFlow.Type.VOID_PAYMENT, amount_before=amount_before,
amount_change=amount_change, amount_after=amount_after, void_payment_order=payment_order,
creator=self.user, team=self.team
))
account.balance_amount = amount_after
if account.balance_amount < 0:
raise ValidationError(f'结算账户[{account.name}]余额不足')
account.has_balance = account.balance_amount > 0
account.save(update_fields=['balance_amount', 'has_balance'])
else:
FinanceFlow.objects.bulk_create(finance_flows)
serializer = PaymentOrderSerializer(instance=payment_order)
return Response(data=serializer.data, status=status.HTTP_200_OK)
class CollectionOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, CreateModelMixin):
"""付款单据"""
serializer_class = CollectionOrderSerializer
permission_classes = [IsAuthenticated, CollectionOrderPermission]
filterset_class = CollectionOrderFilter
search_fields = ['number', 'client__number', 'client__name', 'remark']
ordering_fields = ['id', 'number', 'total_amount', 'create_time']
select_related_fields = ['client', 'handler', 'creator']
prefetch_related_fields = ['collection_accounts', 'collection_accounts__account']
queryset = CollectionOrder.objects.all()
@transaction.atomic
def perform_create(self, serializer):
collection_order = serializer.save()
# 同步欠款
client = collection_order.client
client.arrears_amount = NP.minus(client.arrears_amount, collection_order.total_amount)
client.has_arrears = client.arrears_amount > 0
client.save(update_fields=['arrears_amount', 'has_arrears'])
# 同步余额, 流水
finance_flows = []
for collection_account in collection_order.collection_accounts.all():
account = collection_account.account
amount_before = account.balance_amount
amount_change = collection_account.collection_amount
amount_after = NP.plus(amount_before, amount_change)
finance_flows.append(FinanceFlow(
account=account, type=FinanceFlow.Type.COLLECTION, amount_before=amount_before,
amount_change=amount_change, amount_after=amount_after, collection_order=collection_order,
creator=self.user, team=self.team
))
account.balance_amount = amount_after
if account.balance_amount < 0:
raise ValidationError(f'结算账户[{account.name}]余额不足')
account.has_balance = account.balance_amount > 0
account.save(update_fields=['balance_amount', 'has_balance'])
else:
FinanceFlow.objects.bulk_create(finance_flows)
@extend_schema(responses={200: NumberResponse})
@action(detail=False, methods=['get'])
def number(self, request, *args, **kwargs):
"""获取编号"""
number = PaymentOrder.get_number(self.team)
return Response(data={'number': number}, status=status.HTTP_200_OK)
@transaction.atomic
@extend_schema(request=None, responses={200: CollectionOrderSerializer})
@action(detail=True, methods=['post'])
def void(self, request, *args, **kwargs):
"""作废"""
collection_order = self.get_object()
collection_order.is_void = True
collection_order.save(update_fields=['is_void'])
# 同步欠款
client = collection_order.client
client.arrears_amount = NP.plus(client.arrears_amount, collection_order.total_amount)
client.has_arrears = client.arrears_amount > 0
client.save(update_fields=['arrears_amount', 'has_arrears'])
# 同步余额, 流水
finance_flows = []
for collection_account in collection_order.collection_accounts.all():
account = collection_account.account
amount_before = account.balance_amount
amount_change = collection_account.collection_amount
amount_after = NP.minus(amount_before, amount_change)
finance_flows.append(FinanceFlow(
account=account, type=FinanceFlow.Type.VOID_COLLECTION, amount_before=amount_before,
amount_change=amount_change, amount_after=amount_after, void_collection_order=collection_order,
creator=self.user, team=self.team
))
account.balance_amount = amount_after
if account.balance_amount < 0:
raise ValidationError(f'结算账户[{account.name}]余额不足')
account.has_balance = account.balance_amount > 0
account.save(update_fields=['balance_amount', 'has_balance'])
else:
FinanceFlow.objects.bulk_create(finance_flows)
serializer = CollectionOrderSerializer(instance=collection_order)
return Response(data=serializer.data, status=status.HTTP_200_OK)
class ChargeOrderViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, CreateModelMixin):
"""收支单据"""
serializer_class = ChargeOrderSerializer
permission_classes = [IsAuthenticated, ChargeOrderPermission]
filterset_class = ChargeOrderFilter
search_fields = ['number', 'supplier__number', 'supplier__name', 'client__number',
'client__name', 'remark']
ordering_fields = ['id', 'number', 'total_amount', 'charge_amount', 'create_time']
select_related_fields = ['supplier', 'client', 'handler', 'creator']
queryset = ChargeOrder.objects.all()
@transaction.atomic
def perform_create(self, serializer):
charge_order = serializer.save()
account = charge_order.account
amount_before = account.balance_amount
arrears_amount = NP.minus(charge_order.total_amount, charge_order.charge_amount)
if charge_order.type == ChargeOrder.Type.INCOME:
amount_change = charge_order.charge_amount
# 同步欠款
if supplier := charge_order.supplier:
supplier.arrears_amount = NP.minus(supplier.arrears_amount, arrears_amount)
supplier.has_arrears = supplier.arrears_amount > 0
supplier.save(update_fields=['arrears_amount', 'has_arrears'])
elif client := charge_order.client:
client.arrears_amount = NP.plus(client.arrears_amount, arrears_amount)
client.has_arrears = client.arrears_amount > 0
client.save(update_fields=['arrears_amount', 'has_arrears'])
elif charge_order.type == ChargeOrder.Type.EXPENDITURE:
amount_change = -charge_order.charge_amount
# 同步欠款
if supplier := charge_order.supplier:
supplier.arrears_amount = NP.plus(supplier.arrears_amount, arrears_amount)
supplier.has_arrears = supplier.arrears_amount > 0
supplier.save(update_fields=['arrears_amount', 'has_arrears'])
elif client := charge_order.client:
client.arrears_amount = NP.minus(client.arrears_amount, arrears_amount)
client.has_arrears = client.arrears_amount > 0
client.save(update_fields=['arrears_amount', 'has_arrears'])
amount_after = NP.plus(amount_before, amount_change)
FinanceFlow.objects.create(
account=account, type=FinanceFlow.Type.CHARGE, amount_before=amount_before,
amount_change=amount_change, amount_after=amount_after, charge_order=charge_order,
creator=self.user, team=self.team
)
account.balance_amount = amount_after
if account.balance_amount < 0:
raise ValidationError(f'结算账户[{account.name}]余额不足')
account.has_balance = account.balance_amount > 0
account.save(update_fields=['balance_amount', 'has_balance'])
@extend_schema(responses={200: NumberResponse})
@action(detail=False, methods=['get'])
def number(self, request, *args, **kwargs):
"""获取编号"""
number = ChargeOrder.get_number(self.team)
return Response(data={'number': number}, status=status.HTTP_200_OK)
@transaction.atomic
@extend_schema(request=None, responses={200: ChargeOrderSerializer})
@action(detail=True, methods=['post'])
def void(self, request, *args, **kwargs):
"""作废"""
charge_order = self.get_object()
charge_order.is_void = True
charge_order.save(update_fields=['is_void'])
account = charge_order.account
amount_before = account.balance_amount
arrears_amount = NP.minus(charge_order.total_amount, charge_order.charge_amount)
if charge_order.type == ChargeOrder.Type.INCOME:
amount_change = charge_order.charge_amount
# 同步欠款
if supplier := charge_order.supplier:
supplier.arrears_amount = NP.plus(supplier.arrears_amount, arrears_amount)
supplier.has_arrears = supplier.arrears_amount > 0
supplier.save(update_fields=['arrears_amount', 'has_arrears'])
elif client := charge_order.client:
client.arrears_amount = NP.minus(client.arrears_amount, arrears_amount)
client.has_arrears = client.arrears_amount > 0
client.save(update_fields=['arrears_amount', 'has_arrears'])
elif charge_order.type == ChargeOrder.Type.EXPENDITURE:
amount_change = -charge_order.charge_amount
# 同步欠款
if supplier := charge_order.supplier:
supplier.arrears_amount = NP.minus(supplier.arrears_amount, arrears_amount)
supplier.has_arrears = supplier.arrears_amount > 0
supplier.save(update_fields=['arrears_amount', 'has_arrears'])
elif client := charge_order.client:
client.arrears_amount = NP.plus(client.arrears_amount, arrears_amount)
client.has_arrears = client.arrears_amount > 0
client.save(update_fields=['arrears_amount', 'has_arrears'])
amount_after = NP.minus(amount_before, amount_change)
FinanceFlow.objects.create(
account=account, type=FinanceFlow.Type.VOID_CHARGE, amount_before=amount_before,
amount_change=amount_change, amount_after=amount_after, void_charge_order=charge_order,
creator=self.user, team=self.team
)
account.balance_amount = amount_after
if account.balance_amount < 0:
raise ValidationError(f'结算账户[{account.name}]余额不足')
account.has_balance = account.balance_amount > 0
account.save(update_fields=['balance_amount', 'has_balance'])
serializer = ChargeOrderSerializer(instance=charge_order)
return Response(data=serializer.data, status=status.HTTP_200_OK)
class AccountTransferRecordViewSet(BaseViewSet, ListModelMixin, RetrieveModelMixin, CreateModelMixin):
"""结算账户转账记录"""
serializer_class = AccountTransferRecordSerializer
permission_classes = [IsAuthenticated, AccountTransferRecordPermission]
filterset_class = AccountTransferRecordFilter
search_fields = ['out_account__number', 'out_account__name', 'in_account__number',
'in_account__name', 'remark']
ordering_fields = ['id', 'transfer_out_time', 'transfer_in_time', 'create_time']
select_related_fields = ['out_account', 'in_account', 'handler', 'creator']
queryset = AccountTransferRecord.objects.all()
@transaction.atomic
def perform_create(self, serializer):
account_transfer_record = serializer.save()
out_account = account_transfer_record.out_account
transfer_out_amount = account_transfer_record.transfer_amount
in_account = account_transfer_record.in_account
transfer_in_amount = account_transfer_record.transfer_amount
service_charge_payer = account_transfer_record.service_charge_payer
if service_charge_payer == AccountTransferRecord.ServiceChargePayer.TRANSFER_IN:
transfer_in_amount = NP.minus(transfer_in_amount,
account_transfer_record.service_charge_amount)
elif service_charge_payer == AccountTransferRecord.ServiceChargePayer.TRANSFER_OUT:
transfer_out_amount = NP.minus(transfer_out_amount,
account_transfer_record.service_charge_amount)
# 同步账户余额
finance_flows = []
amount_before = out_account.balance_amount
amount_change = transfer_out_amount
amount_after = NP.minus(amount_before, transfer_out_amount)
finance_flows.append(FinanceFlow(
account=out_account, type=FinanceFlow.Type.ACCOUNT_TRANSFER_OUT,
amount_before=amount_before, amount_change=amount_change, amount_after=amount_after,
account_transfer_record=account_transfer_record, creator=self.user, team=self.team
))
out_account.balance_amount = amount_after
if out_account.balance_amount < 0:
raise ValidationError(f'结算账户[{out_account.name}]余额不足')
out_account.has_balance = out_account.balance_amount > 0
out_account.save(update_fields=['balance_amount', 'has_balance'])
amount_before = in_account.balance_amount
amount_change = transfer_in_amount
amount_after = NP.plus(amount_before, transfer_in_amount)
finance_flows.append(FinanceFlow(
account=in_account, type=FinanceFlow.Type.ACCOUNT_TRANSFER_IN,
amount_before=amount_before, amount_change=amount_change, amount_after=amount_after,
account_transfer_record=account_transfer_record, creator=self.user, team=self.team
))
in_account.balance_amount = amount_after
if in_account.balance_amount < 0:
raise ValidationError(f'结算账户[{in_account.name}]余额不足')
in_account.has_balance = in_account.balance_amount > 0
in_account.save(update_fields=['balance_amount', 'has_balance'])
@transaction.atomic
@extend_schema(request=None, responses={200: AccountTransferRecordSerializer})
@action(detail=True, methods=['post'])
def void(self, request, *args, **kwargs):
"""作废"""
account_transfer_record = self.get_object()
account_transfer_record.is_void = True
account_transfer_record.save(update_fields=['is_void'])
out_account = account_transfer_record.out_account
transfer_out_amount = account_transfer_record.transfer_amount
in_account = account_transfer_record.in_account
transfer_in_amount = account_transfer_record.transfer_amount
service_charge_payer = account_transfer_record.service_charge_payer
if service_charge_payer == AccountTransferRecord.ServiceChargePayer.TRANSFER_IN:
transfer_in_amount = NP.minus(transfer_in_amount,
account_transfer_record.service_charge_amount)
elif service_charge_payer == AccountTransferRecord.ServiceChargePayer.TRANSFER_OUT:
transfer_out_amount = NP.minus(transfer_out_amount,
account_transfer_record.service_charge_amount)
# 同步账户余额
finance_flows = []
amount_before = out_account.balance_amount
amount_change = transfer_out_amount
amount_after = NP.plus(amount_before, transfer_out_amount)
finance_flows.append(FinanceFlow(
account=out_account, type=FinanceFlow.Type.VOID_ACCOUNT_TRANSFER_OUT,
amount_before=amount_before, amount_change=amount_change, amount_after=amount_after,
void_account_transfer_record=account_transfer_record, creator=self.user, team=self.team
))
out_account.balance_amount = amount_after
if out_account.balance_amount < 0:
raise ValidationError(f'结算账户[{out_account.name}]余额不足')
out_account.has_balance = out_account.balance_amount > 0
out_account.save(update_fields=['balance_amount', 'has_balance'])
amount_before = in_account.balance_amount
amount_change = transfer_in_amount
amount_after = NP.minus(amount_before, transfer_in_amount)
finance_flows.append(FinanceFlow(
account=in_account, type=FinanceFlow.Type.VOID_ACCOUNT_TRANSFER_IN,
amount_before=amount_before, amount_change=amount_change, amount_after=amount_after,
void_account_transfer_record=account_transfer_record, creator=self.user, team=self.team
))
in_account.balance_amount = amount_after
if in_account.balance_amount < 0:
raise ValidationError(f'结算账户[{in_account.name}]余额不足')
in_account.has_balance = in_account.balance_amount > 0
in_account.save(update_fields=['balance_amount', 'has_balance'])
serializer = AccountTransferRecordSerializer(instance=account_transfer_record)
return Response(data=serializer.data, status=status.HTTP_200_OK)
__all__ = [
'ClientArrearsViewSet', 'SupplierArrearsViewSet',
'PaymentOrderViewSet', 'CollectionOrderViewSet',
'ChargeOrderViewSet', 'AccountTransferRecordViewSet',
]