production-evyos-systems-an.../ServicesBank/Finder/Payment/old_runner.py

327 lines
19 KiB
Python

import sys
import arrow
from decimal import Decimal
from Schemas import BuildDecisionBookPayments, AccountRecords, ApiEnumDropdown
# Counters for tracking conditions
counter_current_currency_not_positive = 0 # Track when current_currency_value <= 0
counter_net_amount_not_positive = 0 # Track when net_amount <= 0
counter_account_records_updated = 0 # Track number of account records updated
counter_payments_found = 0 # Track how many payments were found
counter_found_payment_skips = 0 # Track how many times we skip due to found_payment
counter_payment_exceptions = 0 # Track exceptions during payment processing
counter_missing_build_parts_id = 0 # Track accounts with missing build_parts_id
counter_null_payment_types = 0 # Track payments with null payment_types_id
def pay_the_registration(account_record, receive_enum, debit_enum, is_old_record: bool = False, session=None):
# If no session is provided, create a new one
if session is None:
with AccountRecords.new_session() as new_session:
AccountRecords.set_session(new_session)
BuildDecisionBookPayments.set_session(new_session)
return _process_payment(account_record, receive_enum, debit_enum, is_old_record, new_session)
else:
# Use the provided session
AccountRecords.set_session(session)
BuildDecisionBookPayments.set_session(session)
return _process_payment(account_record, receive_enum, debit_enum, is_old_record, session)
def _process_payment(account_record, receive_enum, debit_enum, is_old_record, session):
"""Internal function to process payments with a given session"""
current_currency_value = float(Decimal(account_record.currency_value)) - float(Decimal(account_record.remainder_balance))
if not current_currency_value > 0:
global counter_current_currency_not_positive
counter_current_currency_not_positive += 1
return current_currency_value
# Check if account_record has build_parts_id
if account_record.build_parts_id is None:
global counter_missing_build_parts_id
counter_missing_build_parts_id += 1
return current_currency_value
process_date = arrow.get(account_record.bank_date)
account_bank_date_year, account_bank_date_month = (process_date.date().year, process_date.date().month)
# First, try to find payments with null payment_types_id
payment_arguments_debit = [
BuildDecisionBookPayments.build_parts_id == account_record.build_parts_id,
BuildDecisionBookPayments.account_records_id == None,
]
# Add date filters if not processing old records
if not is_old_record:
payment_arguments_debit.extend([BuildDecisionBookPayments.process_date_y == int(account_bank_date_year), BuildDecisionBookPayments.process_date_m == int(account_bank_date_month)])
# First try with debit_enum.id
payments = BuildDecisionBookPayments.query.filter(*payment_arguments_debit, BuildDecisionBookPayments.payment_types_id == debit_enum.id).order_by(BuildDecisionBookPayments.process_date.asc()).all()
# If no payments found, try with null payment_types_id
if len(payments) == 0:
payments = BuildDecisionBookPayments.query.filter(*payment_arguments_debit, BuildDecisionBookPayments.payment_types_id == None).order_by(BuildDecisionBookPayments.process_date.asc()).all()
if len(payments) > 0:
global counter_null_payment_types
counter_null_payment_types += len(payments)
global counter_payments_found
counter_payments_found += len(payments)
# Debug: Print info about the first few payments found (if any)
if len(payments) > 0 and account_record.id % 100 == 0: # Only print for every 100th record to avoid too much output
print(f"DEBUG: Found {len(payments)} payments for account_record {account_record.id}")
if len(payments) > 0:
sample_payment = payments[0]
print(f" Sample payment: ID={getattr(sample_payment, 'id', 'N/A')}, amount={getattr(sample_payment, 'payment_amount', 'N/A')}")
if len(payments) == 0:
# No payments found for this account record
return current_currency_value
for payment in payments:
if not current_currency_value > 0:
return current_currency_value
payment_arguments_receive = [
BuildDecisionBookPayments.build_parts_id == account_record.build_parts_id,
BuildDecisionBookPayments.payment_plan_time_periods == payment.payment_plan_time_periods,
BuildDecisionBookPayments.payment_types_id == receive_enum.id,
BuildDecisionBookPayments.build_decision_book_item_id == payment.build_decision_book_item_id,
BuildDecisionBookPayments.decision_book_project_id == payment.decision_book_project_id,
BuildDecisionBookPayments.process_date == payment.process_date,
]
if not is_old_record:
payment_arguments_receive.extend([BuildDecisionBookPayments.process_date_y == int(account_bank_date_year), BuildDecisionBookPayments.process_date_m == int(account_bank_date_month)])
payment_received = BuildDecisionBookPayments.query.filter(*payment_arguments_receive).all()
sum_of_payment_received = sum([abs(payment.payment_amount) for payment in payment_received])
net_amount = float(abs(Decimal(payment.payment_amount))) - float(abs(Decimal(sum_of_payment_received)))
if not net_amount > 0:
global counter_net_amount_not_positive
counter_net_amount_not_positive += 1
continue
if float(abs(current_currency_value)) < float(abs(net_amount)):
net_amount = float(current_currency_value)
process_date = arrow.get(payment.process_date)
try:
found_payment = BuildDecisionBookPayments.query.filter_by(
build_parts_id=payment.build_parts_id, payment_plan_time_periods=payment.payment_plan_time_periods,
payment_types_id=receive_enum.id, build_decision_book_item_id=payment.build_decision_book_item_id,
decision_book_project_id=payment.decision_book_project_id, process_date=str(process_date),
).first()
if found_payment:
global counter_found_payment_skips
counter_found_payment_skips += 1
continue
created_book_payment = BuildDecisionBookPayments.create(
payment_plan_time_periods=payment.payment_plan_time_periods, payment_amount=float(abs(net_amount)),
payment_types_id=receive_enum.id, payment_types_uu_id=str(receive_enum.uu_id),
process_date=str(process_date), process_date_m=process_date.date().month, process_date_y=process_date.date().year,
period_time=f"{process_date.year}-{str(process_date.month).zfill(2)}", build_parts_id=payment.build_parts_id,
build_parts_uu_id=str(payment.build_parts_uu_id), account_records_id=account_record.id,
account_records_uu_id=str(account_record.uu_id), build_decision_book_item_id=payment.build_decision_book_item_id,
build_decision_book_item_uu_id=str(payment.build_decision_book_item_uu_id), decision_book_project_id=payment.decision_book_project_id,
decision_book_project_uu_id=str(payment.decision_book_project_uu_id),
)
created_book_payment.save()
created_payment_amount = float(Decimal(created_book_payment.payment_amount))
remainder_balance = float(Decimal(account_record.remainder_balance)) + float(abs(created_payment_amount))
account_record.update(remainder_balance=remainder_balance)
account_record.save()
global counter_account_records_updated
counter_account_records_updated += 1
if current_currency_value >= abs(net_amount):
current_currency_value -= abs(net_amount)
except Exception as e:
print("Exception of decision payment:", e)
global counter_payment_exceptions
counter_payment_exceptions += 1
return current_currency_value
def create_direct_payment(account_record, receive_enum, session):
"""
Create a direct payment record for an account record without relying on matching BuildDecisionBookPayments
"""
try:
# Calculate the amount to process
payment_amount = float(Decimal(account_record.currency_value)) - float(Decimal(account_record.remainder_balance))
if payment_amount <= 0:
return False
# Get process date information
process_date = arrow.get(account_record.bank_date)
process_date_y = process_date.date().year
process_date_m = process_date.date().month
period_time = f"{process_date_y}-{str(process_date_m).zfill(2)}"
# Check if a payment already exists for this account record
existing_payment = BuildDecisionBookPayments.query.filter_by(account_records_id=account_record.id, payment_types_id=receive_enum.id).first()
if existing_payment: # Skip if payment already exists
return False
# Create a new payment record directly
created_book_payment = BuildDecisionBookPayments.create(
payment_plan_time_periods=1, # Default value
payment_types_id=receive_enum.id, payment_types_uu_id=str(receive_enum.uu_id), payment_amount=payment_amount, process_date=str(process_date), process_date_y=process_date_y,
process_date_m=process_date_m, period_time=period_time, account_records_id=account_record.id, account_records_uu_id=str(account_record.uu_id),
build_parts_id=account_record.build_parts_id, build_parts_uu_id=str(account_record.build_parts_uu_id) if hasattr(account_record, 'build_parts_uu_id') and account_record.build_parts_uu_id else None,
decision_book_project_id=getattr(account_record, 'decision_book_project_id', None),
decision_book_project_uu_id=str(account_record.decision_book_project_uu_id) if hasattr(account_record, 'decision_book_project_uu_id') and account_record.decision_book_project_uu_id else None,
)
created_book_payment.save()
# Update the account record
remainder_balance = float(Decimal(account_record.remainder_balance)) + float(abs(payment_amount))
account_record.update(remainder_balance=remainder_balance)
account_record.save()
global counter_account_records_updated
counter_account_records_updated += 1
return True
except Exception as e:
print(f"Exception in create_direct_payment for account {account_record.id}: {e}")
global counter_payment_exceptions
counter_payment_exceptions += 1
return False
def send_accounts_to_decision_payment():
with ApiEnumDropdown.new_session() as session:
# Set the session for all models that will be used
ApiEnumDropdown.set_session(session)
AccountRecords.set_session(session)
BuildDecisionBookPayments.set_session(session)
try:
# Get required enum values
receive_enum = ApiEnumDropdown.query.filter_by(enum_class="DebitTypes", key="DT-R").first()
debit_enum = ApiEnumDropdown.query.filter_by(enum_class="DebitTypes", key="DT-D").first()
if not receive_enum or not debit_enum:
print("Error: Could not find required enum values")
return
# Check if there are any BuildDecisionBookPayments records at all
total_payments = BuildDecisionBookPayments.query.count()
print(f"\n--- DEBUG: Database Statistics ---")
print(f"Total BuildDecisionBookPayments records in database: {total_payments}")
# Check how many have payment_types_id = debit_enum.id
debit_payments = BuildDecisionBookPayments.query.filter_by(payment_types_id=debit_enum.id).count()
print(f"BuildDecisionBookPayments with payment_types_id={debit_enum.id} (DT-D): {debit_payments}")
# Check how many have account_records_id = None
null_account_payments = BuildDecisionBookPayments.query.filter(BuildDecisionBookPayments.account_records_id == None).count()
print(f"BuildDecisionBookPayments with account_records_id=None: {null_account_payments}")
# Check a sample payment record
sample_payment = BuildDecisionBookPayments.query.first()
if sample_payment:
print("\n--- Sample BuildDecisionBookPayment ---")
print(f"ID: {getattr(sample_payment, 'id', 'N/A')}")
print(f"payment_types_id: {getattr(sample_payment, 'payment_types_id', 'N/A')}")
print(f"build_parts_id: {getattr(sample_payment, 'build_parts_id', 'N/A')}")
print(f"account_records_id: {getattr(sample_payment, 'account_records_id', 'N/A')}")
print(f"process_date_y: {getattr(sample_payment, 'process_date_y', 'N/A')}")
print(f"process_date_m: {getattr(sample_payment, 'process_date_m', 'N/A')}")
else:
print("No BuildDecisionBookPayment records found in the database!")
# Check a sample account record
sample_account = AccountRecords.query.filter(AccountRecords.remainder_balance < AccountRecords.currency_value, AccountRecords.receive_debit == receive_enum.id).first()
if sample_account:
print("\n--- Sample AccountRecord ---")
print(f"ID: {getattr(sample_account, 'id', 'N/A')}")
print(f"build_parts_id: {getattr(sample_account, 'build_parts_id', 'N/A')}")
print(f"bank_date: {getattr(sample_account, 'bank_date', 'N/A')}")
# Try to find payments for this specific account record
if sample_account.bank_date:
process_date = arrow.get(sample_account.bank_date)
account_bank_date_year, account_bank_date_month = (process_date.date().year, process_date.date().month)
print("\n--- Checking for payments for sample account ---")
print(f"Looking for payments with build_parts_id={sample_account.build_parts_id}, payment_types_id={debit_enum.id}, account_records_id=None")
# Try without date filters first
basic_payments = BuildDecisionBookPayments.query.filter(
BuildDecisionBookPayments.build_parts_id == sample_account.build_parts_id, BuildDecisionBookPayments.payment_types_id == debit_enum.id,
BuildDecisionBookPayments.account_records_id == None
).count()
print(f"Found {basic_payments} payments without date filters")
# Now try with date filters
dated_payments = BuildDecisionBookPayments.query.filter(
BuildDecisionBookPayments.build_parts_id == sample_account.build_parts_id, BuildDecisionBookPayments.payment_types_id == debit_enum.id,
BuildDecisionBookPayments.account_records_id == None, BuildDecisionBookPayments.process_date_y == int(account_bank_date_year),
BuildDecisionBookPayments.process_date_m == int(account_bank_date_month)
).count()
print(f"Found {dated_payments} payments with date filters (year={account_bank_date_year}, month={account_bank_date_month})")
else:
print("No matching AccountRecord found for debugging!")
# Query for account records that need payment processing
# Note: We removed the approved_record condition as it was too restrictive
account_records_list = AccountRecords.query.filter(AccountRecords.remainder_balance < AccountRecords.currency_value, AccountRecords.receive_debit == receive_enum.id
).order_by(AccountRecords.bank_date.desc()).all()
print(f"\nProcessing {len(account_records_list)} account records")
# Track how many records were processed with each method
traditional_method_count = 0
direct_method_count = 0
for account_record in account_records_list:
# Try the traditional method first
current_currency_value = pay_the_registration(account_record, receive_enum, debit_enum, False, session)
if current_currency_value > 0:
# If first pass found payments, try with old records too
pay_the_registration(account_record, receive_enum, debit_enum, True, session)
traditional_method_count += 1
else:
# If traditional method didn't work, try direct payment for all records
# This will handle records with missing build_parts_id
if create_direct_payment(account_record, receive_enum, session):
direct_method_count += 1
if direct_method_count % 10 == 0: # Only print every 10th record to avoid too much output
print(f"Direct payment created for account_record {account_record.id}")
# Refresh the account record to get updated values
session.refresh(account_record)
# Update status if the remainder balance equals the currency value
if abs(float(Decimal(account_record.remainder_balance))) == abs(float(Decimal(account_record.currency_value))):
account_record.update(status_id=97)
account_record.save()
print(f"\nProcessed with traditional method: {traditional_method_count} records")
print(f"Processed with direct payment method: {direct_method_count} records")
print("Payment processing completed successfully")
except Exception as e:
print(f"Error in send_accounts_to_decision_payment: {e}")
import traceback
traceback.print_exc()
# Rollback the session in case of error
session.rollback()
return
if __name__ == "__main__":
print("Payment Service is running...")
try:
send_accounts_to_decision_payment()
# Print counter statistics
print("\n--- Processing Statistics ---")
print(f"Records where current_currency_value <= 0: {counter_current_currency_not_positive}")
print(f"Records where net_amount <= 0: {counter_net_amount_not_positive}")
print(f"Account records updated: {counter_account_records_updated}")
print(f"Total payments found: {counter_payments_found}")
print(f"Skips due to found_payment: {counter_found_payment_skips}")
print(f"Payment exceptions: {counter_payment_exceptions}")
except Exception as e:
print(f"Error: {e}")
print("Payment Service is finished...")