diff --git a/api/__pycache__/settings.cpython-313.pyc b/api/__pycache__/settings.cpython-313.pyc index 6c33a0b0..e4ac958e 100644 Binary files a/api/__pycache__/settings.cpython-313.pyc and b/api/__pycache__/settings.cpython-313.pyc differ diff --git a/api/__pycache__/urls.cpython-313.pyc b/api/__pycache__/urls.cpython-313.pyc index 22abd86f..c6bad9d7 100644 Binary files a/api/__pycache__/urls.cpython-313.pyc and b/api/__pycache__/urls.cpython-313.pyc differ diff --git a/api/urls.py b/api/urls.py index 71468b34..43a61bff 100644 --- a/api/urls.py +++ b/api/urls.py @@ -14,10 +14,9 @@ Including another URLconf 2. Add a URL to urlpatterns: re_path('blog/', include('blog.urls')) """ from django.urls import re_path -from app import views, cob, payment, contract, cleardata, email, backup, server, workflows,api_workflow, importdata +from app import views, cob, payment, contract, cleardata, email, backup, server,api_workflow, importdata urlpatterns = [ - # New Workflow Endpoints re_path("workflow/execute/$", api_workflow.execute_workflow), # Existing Endpoints diff --git a/app/workflows.py b/app/workflows.py deleted file mode 100644 index 26f9a5da..00000000 --- a/app/workflows.py +++ /dev/null @@ -1,325 +0,0 @@ -# workflows.py -from rest_framework.decorators import api_view -from rest_framework.response import Response -from rest_framework import status -from django.db import transaction -from django.db.models import F -from decimal import Decimal -from app.models import ( - Transaction,User, Transaction_Detail, Product, Product_Status, Payment_Schedule, - Transaction_Phase, Transaction_Status, Payment_Status, Entry_Category, - Payment_Plan,Product_Booked -) -from app.payment import account_entry_api -from datetime import datetime, timedelta # Corrected: Import timedelta - -@api_view(['POST']) -@transaction.atomic -def create_reservation(request): - """ - Tạo một giao dịch giữ chỗ (24h hoặc giữ chỗ thường). - """ - data = request.data - try: - phase_code = data.get('phase_code') - deposit_received = data.get('deposit_received') - customer_id = data.get('customer_id') - product_id = data.get('product_id') - policy_id = data.get('policy_id') - user_id = data.get('user_id') - origin_price = data.get('origin_price') - discount_amount = data.get('discount_amount', 0) - sale_price = data.get('sale_price') - deposit_amount = data.get('deposit_amount') - installments = data.get('installments', []) - payment_plan = data.get('payment_plan', None) - - reservation_phase = Transaction_Phase.objects.get(code=phase_code) - initial_detail_status = Transaction_Status.objects.get(code='new') - # Correction: Use 'unpaid' for unconfirmed payment status - unconfirmed_payment_status = Payment_Status.objects.get(code='unpaid') - - if phase_code == 'reserved24H': - product_status_code = 'resvered24H' - elif phase_code == 'deposit': - product_status_code = 'deposit' - elif phase_code == 'fulfillwish': - product_status_code = 'deposit' - else: - product_status_code = 'resvered' - product_status_reserved = Product_Status.objects.get(code=product_status_code) - - transaction_obj = Transaction.objects.create( - customer_id=customer_id, product_id=product_id, policy_id=policy_id, - phase=reservation_phase, date=datetime.now().strftime('%Y-%m-%d'), - origin_price=origin_price, discount_amount=discount_amount, sale_price=sale_price, - deposit_amount=deposit_amount, deposit_received=0, - deposit_remaining=deposit_amount, amount_received=0, - payment_plan=payment_plan - ) - - amount_recived = installments[0].get('amount') if installments else 0 - transaction_detail_obj = Transaction_Detail.objects.create( - transaction=transaction_obj, phase=reservation_phase, status=initial_detail_status, - date=datetime.now().strftime('%Y-%m-%d'),amount=deposit_amount,amount_recived=amount_recived, - due_date=datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=2), - creator_id=user_id - ) - - product_obj = Product.objects.get(id=product_id) - product_obj.status = product_status_reserved - product_obj.save() - - product_booked_obj = Product_Booked.objects.create( - transaction=transaction_obj, - product=product_obj - ) - - schedules = [] - for i, installment in enumerate(installments): - schedule = Payment_Schedule.objects.create( - txn_detail=transaction_detail_obj, - from_date=datetime.now().strftime('%Y-%m-%d'), - to_date=datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=installment.get('due_days', 0)), - amount=installment.get('amount'), cycle=i + 1, - cycle_days=installment.get('due_days', 0), type_id=1, - status=unconfirmed_payment_status, updater_id=user_id, - detail={'note': f"Thanh toán cọc đợt {i+1}"} - ) - schedules.append(schedule.id) - - return Response({ - 'message': f'Giao dịch "{reservation_phase.name}" đã được tạo thành công.', - 'transaction_id': transaction_obj.id, - 'transaction_code': transaction_obj.code, - 'transaction_detail_id': transaction_detail_obj.id, - 'product_status': product_obj.status.name, - 'payment_schedule_ids': schedules - }, status=status.HTTP_201_CREATED) - - except Exception as e: - return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) - -@api_view(['POST']) -@transaction.atomic -def confirm_payment_schedule(request): - """ - Kế toán xác nhận một công nợ (Payment_Schedule). - Job chạy ngầm sẽ lo việc chuyển trạng thái detail. - """ - data = request.data - try: - payment_schedule_id = data.get('payment_schedule_id') - accountant_id = data.get('user_id') - internal_account_code = data.get('internal_account_code', 'HOAC02VND') - - # Correction: Use 'paid' for confirmed payment status - confirmed_payment_status = Payment_Status.objects.get(code='paid') - - schedule_obj = Payment_Schedule.objects.select_related('txn_detail', 'txn_detail__transaction__customer', 'status').get(id=payment_schedule_id) - - if schedule_obj.status.code == 'paid': - return Response({'message': 'Công nợ này đã được xác nhận trước đó.'}, status=status.HTTP_200_OK) - - schedule_obj.status = confirmed_payment_status - schedule_obj.updater_id = accountant_id - - entry_content = f"Xác nhận thanh toán đợt {schedule_obj.cycle} cho GD {schedule_obj.txn_detail.code} của KH {schedule_obj.txn_detail.transaction.customer.code}" - deposit_category = Entry_Category.objects.get(code='THU_COC') - - entry_data = account_entry_api( - code=internal_account_code, amount=schedule_obj.amount, content=entry_content, - type='CR', category=deposit_category.id, userid=accountant_id, - ref=schedule_obj.txn_detail.code - ) - - if 'error' in entry_data: - raise Exception(entry_data['error']) - - schedule_obj.entry_id = entry_data['id'] - schedule_obj.save() - - transaction_obj = schedule_obj.txn_detail.transaction - - schedule_amount = Decimal(str(schedule_obj.amount)) - - transaction_obj.amount_received = (transaction_obj.amount_received or Decimal('0')) + schedule_amount - transaction_obj.deposit_received = (transaction_obj.deposit_received or Decimal('0')) + schedule_amount - transaction_obj.deposit_remaining = (transaction_obj.deposit_remaining or Decimal('0')) - schedule_amount - transaction_obj.save() - - return Response({ - 'message': 'Công nợ đã được xác nhận thành công.' - }, status=status.HTTP_200_OK) - - except Exception as e: - return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) - - -@api_view(['POST']) -@transaction.atomic -def approve_transaction_detail(request): - """ - Duyệt một Transaction_Detail. - Nếu phase là 'reserved24H', sẽ tự động chuyển Transaction sang phase 'reserved'. - """ - data = request.data - try: - transaction_detail_id = data.get('transaction_detail_id') - approver_id = data.get('user_id') - - detail_obj = Transaction_Detail.objects.select_related('status', 'phase', 'transaction').get(id=transaction_detail_id) - - user_obj = User.objects.get(id=approver_id) - - if detail_obj.status.code != 'pending': - return Response( - {'error': f'Giao dịch không ở trạng thái "Chờ duyệt". Trạng thái hiện tại: {detail_obj.status.name}'}, - status=status.HTTP_400_BAD_REQUEST - ) - - # Correction: Use 'approved' for approved status - approved_status = Transaction_Status.objects.get(code='approved') - detail_obj.status = approved_status - detail_obj.approver = user_obj - detail_obj.approve_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') - detail_obj.save() - - if detail_obj.phase.code == 'reserved24H': - transaction_obj = detail_obj.transaction - - next_phase_obj = Transaction_Phase.objects.get(code='reserved') - transaction_obj.phase = next_phase_obj - transaction_obj.save() - - productId = transaction_obj.product_id - product_obj = Product.objects.get(id=productId) - product_obj.status = Product_Status.objects.get(code='resvered') - product_obj.save() - - new_detail_obj = Transaction_Detail.objects.create( - transaction=transaction_obj, phase=next_phase_obj, - status=Transaction_Status.objects.get(code='new'), - date=datetime.now().strftime('%Y-%m-%d'), - amount=0, creator_id=approver_id - ) - - return Response({ - 'message': 'Giao dịch đã được duyệt và tự động chuyển sang giai đoạn "Giữ chỗ".', - 'transaction_id': transaction_obj.id, - 'new_transaction_phase': next_phase_obj.name, - 'new_transaction_detail_id': new_detail_obj.id - }, status=status.HTTP_200_OK) - else: - return Response({ - 'message': 'Giao dịch đã được duyệt thành công.', - 'transaction_detail_id': detail_obj.id, - 'new_status': approved_status.name - }, status=status.HTTP_200_OK) - - except Exception as e: - return Response({'error ': str(e)}, status=status.HTTP_400_BAD_REQUEST) - -@api_view(['POST']) -@transaction.atomic -def advance_transaction_phase(request): - """ - Chuyển một Transaction sang một giai đoạn mới và tự động tạo công nợ nếu cần. - """ - data = request.data - try: - transaction_id = data.get('transaction_id') - next_phase_code = data.get('next_phase_code') - user_id = data.get('user_id') - product_status = data.get('product_status') - - - if not all([transaction_id, next_phase_code, user_id]): - return Response({'error': 'transaction_id, next_phase_code, và user_id là bắt buộc.'}, status=status.HTTP_400_BAD_REQUEST) - - transaction_obj = Transaction.objects.select_related('phase', 'product', 'policy').get(id=transaction_id) - - next_phase_obj = Transaction_Phase.objects.get(code=next_phase_code) - initial_detail_status = Transaction_Status.objects.get(code='new') - - next_product_status = Product_Status.objects.get(code=product_status) - - transaction_obj.phase = next_phase_obj - transaction_obj.save() - - productId = transaction_obj.product_id - product_obj = Product.objects.get(id=productId) - product_obj.status = next_product_status - product_obj.save() - - new_detail_obj = Transaction_Detail.objects.create( - transaction=transaction_obj, phase=next_phase_obj, status=initial_detail_status, - date=datetime.now().strftime('%Y-%m-%d'), - amount=0, creator_id=user_id - ) - - if next_phase_code == 'pertrade': - unconfirmed_payment_status = Payment_Status.objects.get(code='unpaid') - total_plan_amount = 0 - - # Ưu tiên kế hoạch thanh toán riêng trong giao dịch - if transaction_obj.payment_plan and isinstance(transaction_obj.payment_plan, list): - for i, plan_item in enumerate(transaction_obj.payment_plan): - plan_amount = Decimal(str(plan_item.get('amount', 0))) - due_days = plan_item.get('due_days', 0) - total_plan_amount += plan_amount - Payment_Schedule.objects.create( - txn_detail=new_detail_obj, - from_date=datetime.now().strftime('%Y-%m-%d'), - to_date=datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=due_days), - amount=plan_amount, - cycle=i + 1, - cycle_days=due_days, - type_id=2, # Giả sử type_id=2 cho thanh toán mua bán - status=unconfirmed_payment_status, - updater_id=user_id, - detail={'note': f"Thanh toán đợt {i + 1} theo kế hoạch riêng"} - ) - new_detail_obj.amount = total_plan_amount - new_detail_obj.save() - - # Nếu không có kế hoạch riêng, dùng chính sách bán hàng - elif transaction_obj.policy: - payment_plans_from_policy = Payment_Plan.objects.filter(policy=transaction_obj.policy).select_related('type').order_by('cycle') - if payment_plans_from_policy.exists(): - for plan in payment_plans_from_policy: - plan_amount = 0 - if plan.type.code == 'percentage': - plan_amount = (transaction_obj.sale_price * plan.value) / 100 - elif plan.type.code == 'money': - plan_amount = plan.value - - total_plan_amount += Decimal(str(plan_amount)) - Payment_Schedule.objects.create( - txn_detail=new_detail_obj, from_date=datetime.now().strftime('%Y-%m-%d'), - to_date=datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) + timedelta(days=plan.days), - amount=plan_amount, cycle=plan.cycle, cycle_days=plan.days, - type_id=2, status=unconfirmed_payment_status, updater_id=user_id, - detail={'note': f"Thanh toán đợt {plan.cycle} theo chính sách {transaction_obj.policy.name}"} - ) - new_detail_obj.amount = total_plan_amount - new_detail_obj.save() - else: - raise Exception("Giao dịch không có chính sách bán hàng hoặc kế hoạch thanh toán riêng để tạo công nợ.") - - return Response({ - 'message': f'Giao dịch đã được chuyển thành công sang giai đoạn "{next_phase_obj.name}".', - 'transaction_id': transaction_obj.id, - 'new_transaction_detail_id': new_detail_obj.id, - 'new_transaction_detail_code': new_detail_obj.code, - 'product_id': productId, - 'customer':transaction_obj.customer.id, - 'new_product_status': next_product_status.name - }, status=status.HTTP_200_OK) - - except Transaction.DoesNotExist: - return Response({'error': 'Giao dịch không tồn tại.'}, status=status.HTTP_404_NOT_FOUND) - except Transaction_Phase.DoesNotExist: - return Response({'error': f'Giai đoạn mới "{next_phase_code}" không hợp lệ.'}, status=status.HTTP_400_BAD_REQUEST) - except Exception as e: - return Response({'error': str(e)}, status=status.HTTP_400_BAD_REQUEST) \ No newline at end of file diff --git a/static/contract/1. Phiếu xác lập thỏa thuận ưu tiên một người.docx b/static/contract/1. Phiếu xác lập thỏa thuận ưu tiên một người.docx new file mode 100644 index 00000000..c56ceb06 Binary files /dev/null and b/static/contract/1. Phiếu xác lập thỏa thuận ưu tiên một người.docx differ diff --git a/static/contract/agreement.docx b/static/contract/agreement.docx deleted file mode 100644 index 9fc5d042..00000000 Binary files a/static/contract/agreement.docx and /dev/null differ diff --git a/static/contract/agreement_phone-old.docx b/static/contract/agreement_phone-old.docx deleted file mode 100644 index a69ee002..00000000 Binary files a/static/contract/agreement_phone-old.docx and /dev/null differ diff --git a/static/contract/agreement_phone.docx b/static/contract/agreement_phone.docx deleted file mode 100644 index 4bdd477a..00000000 Binary files a/static/contract/agreement_phone.docx and /dev/null differ diff --git a/static/contract/commitment.docx b/static/contract/commitment.docx deleted file mode 100644 index 41922580..00000000 Binary files a/static/contract/commitment.docx and /dev/null differ diff --git a/static/contract/confirmation.docx b/static/contract/confirmation.docx deleted file mode 100644 index a8569968..00000000 Binary files a/static/contract/confirmation.docx and /dev/null differ diff --git a/static/contract/confirmation_unsecured-old.docx b/static/contract/confirmation_unsecured-old.docx deleted file mode 100644 index 90bc8321..00000000 Binary files a/static/contract/confirmation_unsecured-old.docx and /dev/null differ diff --git a/static/contract/confirmation_unsecured.docx b/static/contract/confirmation_unsecured.docx deleted file mode 100644 index f391eb17..00000000 Binary files a/static/contract/confirmation_unsecured.docx and /dev/null differ diff --git a/static/contract/contract (copy).docx b/static/contract/contract (copy).docx deleted file mode 100644 index f21dda3d..00000000 Binary files a/static/contract/contract (copy).docx and /dev/null differ diff --git a/static/contract/contract.docx b/static/contract/contract.docx deleted file mode 100644 index 098ba1ab..00000000 Binary files a/static/contract/contract.docx and /dev/null differ diff --git a/static/contract/contract_unsecured.docx b/static/contract/contract_unsecured.docx deleted file mode 100644 index 65e1e362..00000000 Binary files a/static/contract/contract_unsecured.docx and /dev/null differ diff --git a/static/contract/pawn-old.docx b/static/contract/pawn-old.docx deleted file mode 100644 index d979c965..00000000 Binary files a/static/contract/pawn-old.docx and /dev/null differ diff --git a/static/contract/pawn.docx b/static/contract/pawn.docx deleted file mode 100644 index 7caf84c0..00000000 Binary files a/static/contract/pawn.docx and /dev/null differ diff --git a/static/contract/pawn1.docx b/static/contract/pawn1.docx deleted file mode 100644 index a021b9e2..00000000 Binary files a/static/contract/pawn1.docx and /dev/null differ diff --git a/static/contract/v0/agreement.docx b/static/contract/v0/agreement.docx deleted file mode 100644 index 38a776c8..00000000 Binary files a/static/contract/v0/agreement.docx and /dev/null differ diff --git a/static/contract/v0/agreement_phone.docx b/static/contract/v0/agreement_phone.docx deleted file mode 100644 index a69ee002..00000000 Binary files a/static/contract/v0/agreement_phone.docx and /dev/null differ diff --git a/static/contract/v0/commitment.docx b/static/contract/v0/commitment.docx deleted file mode 100644 index 0194d026..00000000 Binary files a/static/contract/v0/commitment.docx and /dev/null differ diff --git a/static/contract/v0/confirmation.docx b/static/contract/v0/confirmation.docx deleted file mode 100644 index 60451703..00000000 Binary files a/static/contract/v0/confirmation.docx and /dev/null differ diff --git a/static/contract/v0/contract.docx b/static/contract/v0/contract.docx deleted file mode 100644 index 64f8cd70..00000000 Binary files a/static/contract/v0/contract.docx and /dev/null differ diff --git a/static/contract/v0/contract_unsecured.docx b/static/contract/v0/contract_unsecured.docx deleted file mode 100644 index 65e1e362..00000000 Binary files a/static/contract/v0/contract_unsecured.docx and /dev/null differ diff --git a/static/contract/v0/pawn.docx b/static/contract/v0/pawn.docx deleted file mode 100644 index d49e9654..00000000 Binary files a/static/contract/v0/pawn.docx and /dev/null differ diff --git a/static/contract/v1/GIẤY ĐỀ NGHỊ CẦM CỐ TÀI SẢN VAY TIỀN MẶT (ĐIỆN THOẠI) A-V.docx b/static/contract/v1/GIẤY ĐỀ NGHỊ CẦM CỐ TÀI SẢN VAY TIỀN MẶT (ĐIỆN THOẠI) A-V.docx deleted file mode 100644 index c354c44d..00000000 Binary files a/static/contract/v1/GIẤY ĐỀ NGHỊ CẦM CỐ TÀI SẢN VAY TIỀN MẶT (ĐIỆN THOẠI) A-V.docx and /dev/null differ diff --git a/static/contract/v1/THỎA THUẬN CHO MƯỢN LẠI TÀI SẢN (ĐIỆN THOẠI) A-V.docx b/static/contract/v1/THỎA THUẬN CHO MƯỢN LẠI TÀI SẢN (ĐIỆN THOẠI) A-V.docx deleted file mode 100644 index 4521bead..00000000 Binary files a/static/contract/v1/THỎA THUẬN CHO MƯỢN LẠI TÀI SẢN (ĐIỆN THOẠI) A-V.docx and /dev/null differ diff --git a/static/contract/v1/commitment.docx b/static/contract/v1/commitment.docx deleted file mode 100644 index 56ca7d18..00000000 Binary files a/static/contract/v1/commitment.docx and /dev/null differ diff --git a/static/contract/v1/confirmation.docx b/static/contract/v1/confirmation.docx deleted file mode 100644 index ca987bd9..00000000 Binary files a/static/contract/v1/confirmation.docx and /dev/null differ diff --git a/static/contract/v1/contract.docx b/static/contract/v1/contract.docx deleted file mode 100644 index 9cb7c307..00000000 Binary files a/static/contract/v1/contract.docx and /dev/null differ diff --git a/static/contract/v1/pawn.docx b/static/contract/v1/pawn.docx deleted file mode 100644 index 7859c6ec..00000000 Binary files a/static/contract/v1/pawn.docx and /dev/null differ