import base64 import logging from plans.models import Plan from django.urls import reverse from django.conf import settings from django.utils import timezone from django.db import transaction from django_ledger.io import roles from django_q.tasks import async_task from django.core.mail import send_mail from appointment.models import StaffMember from django.utils.translation import activate from django.core.files.base import ContentFile from django.contrib.auth import get_user_model from allauth.account.models import EmailAddress from django.core.mail import EmailMultiAlternatives from django.template.loader import render_to_string from django.utils.translation import gettext_lazy as _ from django.contrib.auth.models import User, Group, Permission from inventory.models import DealerSettings, Dealer,Schedule,Notification logger = logging.getLogger(__name__) logging.basicConfig(level=logging.INFO) def create_settings(pk): instance = Dealer.objects.get(pk=pk) DealerSettings.objects.create( dealer=instance, invoice_cash_account=instance.entity.get_all_accounts() .filter(role=roles.ASSET_CA_CASH) .first(), invoice_prepaid_account=instance.entity.get_all_accounts() .filter(role=roles.ASSET_CA_RECEIVABLES) .first(), invoice_unearned_account=instance.entity.get_all_accounts() .filter(role=roles.LIABILITY_CL_DEFERRED_REVENUE) .first(), bill_cash_account=instance.entity.get_all_accounts() .filter(role=roles.ASSET_CA_CASH) .first(), bill_prepaid_account=instance.entity.get_all_accounts() .filter(role=roles.ASSET_CA_PREPAID) .first(), bill_unearned_account=instance.entity.get_all_accounts() .filter(role=roles.LIABILITY_CL_ACC_PAYABLE) .first(), ) def create_coa_accounts(instance): entity = instance.entity coa = entity.get_default_coa() accounts_data = [ # Current Assets (must start with 1) { "code": "1010", "name": "Cash on Hand", "role": roles.ASSET_CA_CASH, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for ASSET_CA_CASH }, { "code": "1020", "name": "Bank", "role": roles.ASSET_CA_CASH, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "1030", "name": "Accounts Receivable", "role": roles.ASSET_CA_RECEIVABLES, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for ASSET_CA_RECEIVABLES }, { "code": "1040", "name": "Inventory (Cars)", "role": roles.ASSET_CA_INVENTORY, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for ASSET_CA_INVENTORY }, { "code": "1045", "name": "Spare Parts Inventory", "role": roles.ASSET_CA_INVENTORY, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "1050", "name": "Employee Advances", "role": roles.ASSET_CA_RECEIVABLES, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "1060", "name": "Prepaid Expenses", "role": roles.ASSET_CA_PREPAID, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for ASSET_CA_PREPAID }, { "code": "1070", "name": "Notes Receivable", "role": roles.ASSET_LTI_NOTES_RECEIVABLE, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for ASSET_LTI_NOTES_RECEIVABLE }, # Fixed Assets (must also start with 1) { "code": "1110", "name": "Lands", "role": roles.ASSET_LTI_LAND, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for ASSET_LTI_LAND }, { "code": "1111", "name": "Buildings", "role": roles.ASSET_PPE_BUILDINGS, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for ASSET_PPE_BUILDINGS }, { "code": "1112", "name": "Company Vehicles", "role": roles.ASSET_PPE_EQUIPMENT, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for ASSET_PPE_EQUIPMENT }, { "code": "1113", "name": "Equipment & Tools", "role": roles.ASSET_PPE_EQUIPMENT, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "1114", "name": "Furniture & Fixtures", "role": roles.ASSET_PPE_EQUIPMENT, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "1115", "name": "Other Fixed Assets", "role": roles.ASSET_PPE_EQUIPMENT, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "1120", "name": "Long-term Investments", "role": roles.ASSET_LTI_SECURITIES, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for ASSET_LTI_SECURITIES }, { "code": "1130", "name": "Intangible Assets", "role": roles.ASSET_INTANGIBLE_ASSETS, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for ASSET_INTANGIBLE_ASSETS }, # Current Liabilities (must start with 2) { "code": "2010", "name": "Accounts Payable", "role": roles.LIABILITY_CL_ACC_PAYABLE, "balance_type": roles.CREDIT, "locked": True, "default": True, # Default for LIABILITY_CL_ACC_PAYABLE }, { "code": "2020", "name": "Notes Payable", "role": roles.LIABILITY_CL_ST_NOTES_PAYABLE, "balance_type": roles.CREDIT, "locked": False, "default": True, # Default for LIABILITY_CL_ST_NOTES_PAYABLE }, { "code": "2030", "name": "Short-term Loans", "role": roles.LIABILITY_CL_ST_NOTES_PAYABLE, "balance_type": roles.CREDIT, "locked": False, "default": False, }, { "code": "2040", "name": "Employee Payables", "role": roles.LIABILITY_CL_WAGES_PAYABLE, "balance_type": roles.CREDIT, "locked": False, "default": True, # Default for LIABILITY_CL_WAGES_PAYABLE }, { "code": "2050", "name": "Accrued Expenses", "role": roles.LIABILITY_CL_OTHER, "balance_type": roles.CREDIT, "locked": False, "default": True, # Default for LIABILITY_CL_OTHER }, { "code": "2060", "name": "Accrued Taxes", "role": roles.LIABILITY_CL_TAXES_PAYABLE, "balance_type": roles.CREDIT, "locked": False, "default": False, # Default for LIABILITY_CL_TAXES_PAYABLE }, { "code": "2070", "name": "Provisions", "role": roles.LIABILITY_CL_OTHER, "balance_type": roles.CREDIT, "locked": False, "default": False, }, # Long-term Liabilities (must also start with 2) { "code": "2103", "name": "Deferred Revenue", "role": roles.LIABILITY_CL_DEFERRED_REVENUE, "balance_type": roles.CREDIT, "locked": False, "default": True, # Default for LIABILITY_CL_DEFERRED_REVENUE }, { "code": "2200", "name": "Tax Payable", "role": roles.LIABILITY_CL_TAXES_PAYABLE, "balance_type": roles.CREDIT, "locked": False, "default": True, }, { "code": "2210", "name": "Long-term Bank Loans", "role": roles.LIABILITY_LTL_NOTES_PAYABLE, "balance_type": roles.CREDIT, "locked": False, "default": True, # Default for LIABILITY_LTL_NOTES_PAYABLE }, { "code": "2220", "name": "Lease Liabilities", "role": roles.LIABILITY_LTL_NOTES_PAYABLE, "balance_type": roles.CREDIT, "locked": False, "default": False, }, { "code": "2230", "name": "Other Long-term Liabilities", "role": roles.LIABILITY_LTL_NOTES_PAYABLE, "balance_type": roles.CREDIT, "locked": False, "default": False, }, # Equity (must start with 3) { "code": "3010", "name": "Capital", "role": roles.EQUITY_CAPITAL, "balance_type": roles.CREDIT, "locked": True, "default": True, # Default for EQUITY_CAPITAL }, { "code": "3020", "name": "Statutory Reserve", "role": roles.EQUITY_ADJUSTMENT, "balance_type": roles.CREDIT, "locked": False, "default": True, # Default for EQUITY_ADJUSTMENT }, { "code": "3030", "name": "Retained Earnings", "role": roles.EQUITY_ADJUSTMENT, "balance_type": roles.CREDIT, "locked": False, "default": False, }, { "code": "3040", "name": "Profit & Loss for the Period", "role": roles.EQUITY_ADJUSTMENT, "balance_type": roles.CREDIT, "locked": False, "default": False, }, # Revenue (must start with 4) { "code": "4010", "name": "Car Sales", "role": roles.INCOME_OPERATIONAL, "balance_type": roles.CREDIT, "locked": True, "default": True, # Default for INCOME_OPERATIONAL }, { "code": "4020", "name": "After-Sales Services", "role": roles.INCOME_OPERATIONAL, "balance_type": roles.CREDIT, "locked": False, "default": False, }, { "code": "4030", "name": "Car Rental Income", "role": roles.INCOME_PASSIVE, "balance_type": roles.CREDIT, "locked": False, "default": True, # Default for INCOME_PASSIVE }, { "code": "4040", "name": "Other Income", "role": roles.INCOME_OTHER, "balance_type": roles.CREDIT, "locked": False, "default": True, # Default for INCOME_OTHER }, # Expenses (must start with 5 for COGS, 6 for others) { "code": "5010", "name": "Cost of Goods Sold", "role": roles.COGS, "balance_type": roles.DEBIT, "locked": True, "default": True, # Default for COGS }, { "code": "5015", "name": "Spare Parts Cost Consumed", "role": roles.COGS, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "6010", "name": "Salaries & Wages", "role": roles.EXPENSE_OPERATIONAL, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for EXPENSE_OPERATIONAL }, { "code": "6020", "name": "Rent", "role": roles.EXPENSE_OPERATIONAL, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "6030", "name": "Utilities", "role": roles.EXPENSE_OPERATIONAL, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "6040", "name": "Advertising & Marketing", "role": roles.EXPENSE_OPERATIONAL, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "6050", "name": "Maintenance", "role": roles.EXPENSE_OPERATIONAL, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "6060", "name": "Operating Expenses", "role": roles.EXPENSE_OPERATIONAL, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "6070", "name": "Depreciation", "role": roles.EXPENSE_DEPRECIATION, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for EXPENSE_DEPRECIATION }, { "code": "6080", "name": "Fees & Taxes", "role": roles.EXPENSE_OPERATIONAL, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "6090", "name": "Bank Charges", "role": roles.EXPENSE_OPERATIONAL, "balance_type": roles.DEBIT, "locked": False, "default": False, }, { "code": "6100", "name": "Other Expenses", "role": roles.EXPENSE_OTHER, "balance_type": roles.DEBIT, "locked": False, "default": True, # Default for EXPENSE_OTHER }, ] for account_data in accounts_data: try: account = entity.create_account( coa_model=coa, code=account_data["code"], name=_(account_data["name"]), role=_(account_data["role"]), balance_type=_(account_data["balance_type"]), active=True, ) account.role_default = account_data["default"] account.save() logger.info(f"Created default account: {account}") except Exception as e: logger.error(f"Error creating default account: {account_data['code']}, {e}") def create_coa_accounts1(pk): with transaction.atomic(): instance = Dealer.objects.select_for_update().get(pk=pk) entity = instance.entity coa = entity.get_default_coa() # Cash Account asset_ca_cash = entity.create_account( coa_model=coa, code="1101", role=roles.ASSET_CA_CASH, name=_("Cash"), balance_type="debit", active=True, ) asset_ca_cash.role_default = True asset_ca_cash.save() # Accounts Receivable Account asset_ca_receivables = entity.create_account( coa_model=coa, code="1102", role=roles.ASSET_CA_RECEIVABLES, name=_("Accounts Receivable"), balance_type="debit", active=True, ) asset_ca_receivables.role_default = True asset_ca_receivables.save() # Inventory Account asset_ca_inventory = entity.create_account( coa_model=coa, code="1103", role=roles.ASSET_CA_INVENTORY, name=_("Inventory"), balance_type="debit", active=True, ) asset_ca_inventory.role_default = True asset_ca_inventory.save() # Prepaid Expenses Account asset_ca_prepaid = entity.create_account( coa_model=coa, code="1104", role=roles.ASSET_CA_PREPAID, name=_("Prepaid Expenses"), balance_type="debit", active=True, ) asset_ca_prepaid.role_default = True asset_ca_prepaid.save() # Employee Expenses Account asset_ca_prepaid_employee = entity.create_account( coa_model=coa, code="1105", role=roles.ASSET_CA_PREPAID, name=_("Employee Advance"), balance_type="debit", active=True, ) # VAT Payable Account liability_ltl_vat_receivable = entity.create_account( coa_model=coa, code="1106", role=roles.ASSET_CA_RECEIVABLES, name=_("VAT Receivable"), balance_type="debit", active=True, ) # Buildings Accumulated Depreciation Account asset_ppe_buildings_accum_depreciation = entity.create_account( coa_model=coa, code="1201", role=roles.ASSET_PPE_BUILDINGS_ACCUM_DEPRECIATION, name=_("Buildings - Accum. Depreciation"), balance_type="credit", active=True, ) asset_ppe_buildings_accum_depreciation.role_default = True asset_ppe_buildings_accum_depreciation.save() # intangible Account asset_lti_land_intangable = entity.create_account( coa_model=coa, code="1202", role=roles.ASSET_INTANGIBLE_ASSETS, name=_("Intangible Assets"), balance_type="debit", active=True, ) asset_lti_land_intangable.role_default = True asset_lti_land_intangable.save() # investment property Account asset_lti_land_investment = entity.create_account( coa_model=coa, code="1204", role=roles.ASSET_LTI_SECURITIES, name=_("Investments"), balance_type="debit", active=True, ) asset_lti_land_investment.role_default = True asset_lti_land_investment.save() # # Notes Receivable Account # asset_lti_notes_receivable = entity.create_account( # coa_model=coa, # code="1201", # role=roles.ASSET_LTI_NOTES_RECEIVABLE, # name=_("Notes Receivable"), # balance_type="debit", # active=True, # ) # asset_lti_notes_receivable.role_default = True # asset_lti_notes_receivable.save() # # Land Account # asset_lti_land = entity.create_account( # coa_model=coa, # code="1202", # role=roles.ASSET_LTI_LAND, # name=_("Land"), # balance_type="debit", # active=True, # ) # asset_lti_land.role_default = True # asset_lti_land.save() # Buildings Account asset_ppe_buildings = entity.create_account( coa_model=coa, code="1301", role=roles.ASSET_PPE_BUILDINGS, name=_("Buildings"), balance_type="debit", active=True, ) asset_ppe_buildings.role_default = True asset_ppe_buildings.save() # Accounts Payable Account liability_cl_acc_payable = entity.create_account( coa_model=coa, code="2101", role=roles.LIABILITY_CL_ACC_PAYABLE, name=_("Accounts Payable"), balance_type="credit", active=True, ) liability_cl_acc_payable.role_default = True liability_cl_acc_payable.save() # Deferred Revenue Account liability_cl_def_rev = entity.create_account( coa_model=coa, code="2103", role=roles.LIABILITY_CL_DEFERRED_REVENUE, name=_("Deferred Revenue"), balance_type="credit", active=True, ) liability_cl_def_rev.role_default = True liability_cl_def_rev.save() # Wages Payable Account liability_cl_wages_payable = entity.create_account( coa_model=coa, code="2102", role=roles.LIABILITY_CL_WAGES_PAYABLE, name=_("Wages Payable"), balance_type="credit", active=True, ) liability_cl_wages_payable.role_default = True liability_cl_wages_payable.save() # Long-Term Notes Payable Account liability_ltl_notes_payable = entity.create_account( coa_model=coa, code="2201", role=roles.LIABILITY_LTL_NOTES_PAYABLE, name=_("Long-Term Notes Payable"), balance_type="credit", active=True, ) liability_ltl_notes_payable.role_default = True liability_ltl_notes_payable.save() # VAT Payable Account liability_ltl_vat_payable = entity.create_account( coa_model=coa, code="2106", role=roles.LIABILITY_CL_OTHER, name=_("VAT Payable"), balance_type="credit", active=True, ) # taxes Payable Account liability_ltl_taxes_payable = entity.create_account( coa_model=coa, code="2107", role=roles.LIABILITY_CL_OTHER, name=_("Taxes Payable"), balance_type="credit", active=True, ) # social insurance Payable Account liability_ltl_social_insurance_payable = entity.create_account( coa_model=coa, code="2108", role=roles.LIABILITY_LTL_NOTES_PAYABLE, name=_("Social Insurance Payable"), balance_type="credit", active=True, ) # End of Service Benefits entity.create_account( coa_model=coa, code="2202", role=roles.LIABILITY_LTL_NOTES_PAYABLE, name=_("End of Service Benefits"), balance_type="credit", active=True, ) # Mortgage Payable Account liability_ltl_mortgage_payable = entity.create_account( coa_model=coa, code="2203", role=roles.LIABILITY_LTL_MORTGAGE_PAYABLE, name=_("Mortgage Payable"), balance_type="credit", active=True, ) liability_ltl_mortgage_payable.role_default = True liability_ltl_mortgage_payable.save() # Capital equity_capital = entity.create_account( coa_model=coa, code="3101", role=roles.EQUITY_CAPITAL, name=_("Registered Capital"), balance_type="credit", active=True, ) equity_capital.role_default = True equity_capital.save() entity.create_account( coa_model=coa, code="3102", role=roles.EQUITY_CAPITAL, name=_("Additional Paid-In Capital"), balance_type="credit", active=True, ) # Other Equity other_equity = entity.create_account( coa_model=coa, code="3201", role=roles.EQUITY_COMMON_STOCK, name=_("Opening Balances"), balance_type="credit", active=True, ) other_equity.role_default = True other_equity.save() # Reserves reserve = entity.create_account( coa_model=coa, code="3301", role=roles.EQUITY_ADJUSTMENT, name=_("Statutory Reserve"), balance_type="credit", active=True, ) reserve.role_default = True reserve.save() entity.create_account( coa_model=coa, code="3302", role=roles.EQUITY_ADJUSTMENT, name=_("Foreign Currency Translation Reserve"), balance_type="credit", active=True, ) # Retained Earnings Account equity_retained_earnings = entity.create_account( coa_model=coa, code="3401", role=roles.EQUITY_PREFERRED_STOCK, name=_("Operating Profits and Losses"), balance_type="credit", active=True, ) equity_retained_earnings.role_default = True equity_retained_earnings.save() equity_retained_earnings_losses = entity.create_account( coa_model=coa, code="3402", role=roles.EQUITY_PREFERRED_STOCK, name=_("Retained Earnings (or Losses)"), balance_type="credit", active=True, ) # Sales Revenue Account income_operational = entity.create_account( coa_model=coa, code="4101", role=roles.INCOME_OPERATIONAL, name=_("Sales Revenue"), balance_type="credit", active=True, ) income_operational.role_default = True income_operational.save() # Interest Income Account income_interest = entity.create_account( coa_model=coa, code="4102", role=roles.INCOME_INTEREST, name=_("Interest Income"), balance_type="credit", active=True, ) income_interest.role_default = True income_interest.save() # Uneared Income Account income_unearned = entity.create_account( coa_model=coa, code="4103", role=roles.INCOME_OTHER, name=_("Unearned Income"), balance_type="credit", active=True, ) # Operating Revenues entity.create_account( coa_model=coa, code="4104", role=roles.INCOME_OPERATIONAL, name=_("Sales/Service Revenue"), balance_type="credit", active=True, ) # Non-Operating Revenues entity.create_account( coa_model=coa, code="4201", role=roles.INCOME_OTHER, name=_("Non-Operating Revenues"), balance_type="credit", active=True, ) # Cost of Goods Sold (COGS) Account expense_cogs = entity.create_account( coa_model=coa, code="5101", role=roles.COGS, name=_("Cost of Goods Sold"), balance_type="debit", active=True, ) expense_cogs.role_default = True expense_cogs.save() # accrued Expenses Account expense_cogs = entity.create_account( coa_model=coa, code="6117", role=roles.EXPENSE_OPERATIONAL, name=_("Accrued Expenses"), balance_type="debit", active=True, ) # accrued salaries Account expense_cogs = entity.create_account( coa_model=coa, code="6118", role=roles.EXPENSE_OPERATIONAL, name=_("Accrued Salaries"), balance_type="debit", active=True, ) # Rent Expense Account expense_rent = entity.create_account( coa_model=coa, code="6102", role=roles.EXPENSE_OPERATIONAL, name=_("Rent Expense"), balance_type="debit", active=True, ) # expense_rent.role_default = True # expense_rent.save() # Salaries and Administrative Fees expense_salaries = entity.create_account( coa_model=coa, code="6103", role=roles.EXPENSE_OPERATIONAL, name=_("Salaries and Administrative Fees"), balance_type="debit", active=True, ) # Medical Insurance expense_medical_insurance = entity.create_account( coa_model=coa, code="6104", role=roles.EXPENSE_OPERATIONAL, name=_("Medical Insurance"), balance_type="debit", active=True, ) # Marketing and Advertising Expenses expense_marketing = entity.create_account( coa_model=coa, code="6105", role=roles.EXPENSE_OPERATIONAL, name=_("Marketing and Advertising Expenses"), balance_type="debit", active=True, ) # Commissions and Incentives expense_commissions = entity.create_account( coa_model=coa, code="6106", role=roles.EXPENSE_OPERATIONAL, name=_("Commissions and Incentives"), balance_type="debit", active=True, ) # Travel Tickets expense_travel = entity.create_account( coa_model=coa, code="6107", role=roles.EXPENSE_OPERATIONAL, name=_("Travel Tickets"), balance_type="debit", active=True, ) # Social Insurance expense_other = entity.create_account( coa_model=coa, code="6108", role=roles.EXPENSE_OPERATIONAL, name=_("Social Insurance"), balance_type="debit", active=True, ) # Government Fees expense_other = entity.create_account( coa_model=coa, code="6109", role=roles.EXPENSE_OPERATIONAL, name=_("Government Fees"), balance_type="debit", active=True, ) # Fees and Subscriptions expense_other = entity.create_account( coa_model=coa, code="6110", role=roles.EXPENSE_OPERATIONAL, name=_("Fees and Subscriptions"), balance_type="debit", active=True, ) # Office Services Expenses expense_other = entity.create_account( coa_model=coa, code="6111", role=roles.EXPENSE_OPERATIONAL, name=_("Office Services Expenses"), balance_type="debit", active=True, ) # Office Supplies and Printing expense_other = entity.create_account( coa_model=coa, code="6112", role=roles.EXPENSE_OPERATIONAL, name=_("Office Supplies and Printing"), balance_type="debit", active=True, ) # Hospitality Expenses expense_other = entity.create_account( coa_model=coa, code="6113", role=roles.EXPENSE_OPERATIONAL, name=_("Hospitality Expenses"), balance_type="debit", active=True, ) # Bank Commissions expense_other = entity.create_account( coa_model=coa, code="6114", role=roles.EXPENSE_OPERATIONAL, name=_("Bank Commissions"), balance_type="debit", active=True, ) # Other Expenses expense_other = entity.create_account( coa_model=coa, code="6115", role=roles.EXPENSE_OPERATIONAL, name=_("Other Expenses"), balance_type="debit", active=True, ) # Transportation Expenses expense_other = entity.create_account( coa_model=coa, code="6116", role=roles.EXPENSE_OPERATIONAL, name=_("Transportation Expenses"), balance_type="debit", active=True, ) # 5.1 Direct Costs entity.create_account( coa_model=coa, code="6201", role=roles.EXPENSE_OPERATIONAL, name=_("Cost of Goods Sold"), balance_type="debit", active=True, ) entity.create_account( coa_model=coa, code="6202", role=roles.EXPENSE_OPERATIONAL, name=_("Salaries and Wages"), balance_type="debit", active=True, ) entity.create_account( coa_model=coa, code="6203", role=roles.EXPENSE_OPERATIONAL, name=_("Sales Commissions"), balance_type="debit", active=True, ) entity.create_account( coa_model=coa, code="6204", role=roles.EXPENSE_OPERATIONAL, name=_("Shipping and Customs Clearance"), balance_type="debit", active=True, ) # 5.3 Non-Operating Expenses entity.create_account( coa_model=coa, code="6301", role=roles.EXPENSE_OTHER, name=_("Zakat"), balance_type="debit", active=True, ) entity.create_account( coa_model=coa, code="6302", role=roles.EXPENSE_OTHER, name=_("Taxes"), balance_type="debit", active=True, ) entity.create_account( coa_model=coa, code="6303", role=roles.EXPENSE_OTHER, name=_("Foreign Currency Translation"), balance_type="debit", active=True, ) entity.create_account( coa_model=coa, code="6304", role=roles.EXPENSE_OTHER, name=_("Interest Expenses"), balance_type="debit", active=True, ) # create_settings(instance.pk) # @background # def create_groups(instance): # group_names = ["Inventory", "Accountant", "Sales"] # for group_name in group_names: # group, _ = Group.objects.get_or_create(name=f"{instance.pk}_{group_name}") # group_manager,_ = CustomGroup.objects.get_or_create(name=group_name, dealer=instance, group=group) # group_manager.set_default_permissions() # instance.user.groups.add(group) # @background def create_accounts_for_make(dealer, makes): entity = dealer.entity coa = entity.get_default_coa() name = ["Inventory", "Revenue", "Cogs"] role = [roles.ASSET_CA_INVENTORY, roles.ASSET_CA_RECEIVABLES, roles.COGS] balance_type = ["debit", "credit", "debit"] for name, role, balance_type in zip(name, role, balance_type): create_make_accounts(entity, coa, makes, name, role, balance_type) def create_make_accounts(entity, coa, makes, name, role, balance_type): for make in makes: last_account = ( entity.get_all_accounts().filter(role=role).order_by("-created").first() ) if len(last_account.code) == 4: code = f"{int(last_account.code)}{1:03d}" elif len(last_account.code) > 4: code = f"{int(last_account.code) + 1}" acc = ( entity.get_all_accounts() .filter( name=f"{name}:{make.name}", role=role, coa_model=coa, balance_type=balance_type, active=True, ) .first() ) if not acc: acc = entity.create_account( name=f"{name}:{make.name}", code=code, role=role, coa_model=coa, balance_type=balance_type, active=True, ) return acc def send_email(from_, to_, subject, message): subject = subject message = message from_email = from_ recipient_list = [to_] async_task(send_mail, subject, message, from_email, recipient_list) def create_user_dealer(email, password, name, arabic_name, phone, crn, vrn, address): with transaction.atomic(): user = User.objects.create(username=email, email=email) user.set_password(password) user.save() # EmailAddress.objects.create(user=user, email=email, verified=True, primary=True) group = Group.objects.create(name=f"{user.pk}-Admin") user.groups.add(group) for perm in Permission.objects.filter( content_type__app_label__in=["inventory", "django_ledger"] ): group.permissions.add(perm) # StaffMember.objects.create(user=user) dealer = Dealer.objects.create( user=user, name=name, arabic_name=arabic_name, crn=crn, vrn=vrn, phone_number=phone, address=address, ) return dealer # def create_groups(dealer_slug): # from inventory.models import CustomGroup # instance = Dealer.objects.get(slug=dealer_slug) # def run(): # for group_name in ["Inventory", "Accountant", "Sales", "Manager"]: # group, created = Group.objects.get_or_create( # name=f"{instance.slug}_{group_name}" # ) # group_manager, created = CustomGroup.objects.get_or_create( # name=group_name, dealer=instance, group=group # ) # if created: # group_manager.set_default_permissions() # instance.user.groups.add(group) # transaction.on_commit(run) def send_bilingual_reminder(user_id, plan_id, expiration_date, days_until_expire): """Send bilingual email reminder using Django-Q""" try: user = User.objects.get(id=user_id) plan = Plan.objects.get(id=plan_id) # Determine user language preference user_language = getattr(user, 'language', settings.LANGUAGE_CODE) activate(user_language) # Context data context = { 'user': user, 'plan': plan, 'expiration_date': expiration_date, 'days_until_expire': days_until_expire, 'SITE_NAME': settings.SITE_NAME, 'RENEWAL_URL': "url" ,#settings.RENEWAL_URL, 'direction': 'rtl' if user_language.startswith('ar') else 'ltr' } # Subject with translation subject_en = f"Your {plan.name} subscription expires in {days_until_expire} days" subject_ar = f"اشتراكك في {plan.name} ينتهي خلال {days_until_expire} أيام" # Render templates text_content = render_to_string([ f'emails/expiration_reminder_{user_language}.txt', 'emails/expiration_reminder.txt' ], context) html_content = render_to_string([ f'emails/expiration_reminder_{user_language}.html', 'emails/expiration_reminder.html' ], context) # Create email email = EmailMultiAlternatives( subject=subject_ar if user_language.startswith('ar') else subject_en, body=text_content, from_email=settings.DEFAULT_FROM_EMAIL, to=[user.email] ) email.attach_alternative(html_content, "text/html") email.send() return f"Sent to {user.email} in {user_language}" except Exception as e: logger.error(f"Email failed: {str(e)}") raise def handle_email_result(task): """Callback for email results""" if task.success: logger.info(f"Email task succeeded: {task.result}") else: logger.error(f"Email task failed: {task.result}") def send_schedule_reminder_email(schedule_id): """ Sends an email reminder for a specific schedule. This function is designed to be called by django-q. """ try: schedule = Schedule.objects.get(pk=schedule_id) # Ensure the user has an email and the schedule is not completed/canceled if not schedule.scheduled_by.email or schedule.status in ["completed", "canceled"]: logger.error(f"Skipping email for Schedule ID {schedule_id}: No email or schedule status is {schedule.status}.") return user_email = schedule.scheduled_by.email Notification.objects.create( user=schedule.scheduled_by, message=_( """ Reminder: You have an appointment scheduled for {scheduled_type} After 15 minutes View. """ ).format(scheduled_type=schedule.scheduled_type, url=reverse("schedule_calendar", kwargs={"dealer_slug": schedule.dealer.slug})),) # Prepare context for email templates context = { 'schedule_purpose': schedule.purpose, 'scheduled_at': schedule.scheduled_at.astimezone(timezone.get_current_timezone()).strftime('%Y-%m-%d %H:%M %Z'), # Format with timezone 'schedule_type': schedule.scheduled_type, 'customer_name': schedule.customer.customer_name if schedule.customer else 'N/A', 'notes': schedule.notes, 'user_name': schedule.scheduled_by.get_full_name() or schedule.scheduled_by.email, } # Render email content from templates html_message = render_to_string('emails/schedule_reminder.html', context) plain_message = render_to_string('emails/schedule_reminder.txt', context) send_mail( f'Reminder: Your Upcoming Schedule - {schedule.purpose}', plain_message, settings.DEFAULT_FROM_EMAIL, [user_email], html_message=html_message, ) logger.info(f"Successfully sent reminder email for Schedule ID: {schedule_id} to {user_email}") except Schedule.DoesNotExist: logger.info(f"Schedule with ID {schedule_id} does not exist. Cannot send reminder.") except Exception as e: logger.info(f"Error sending reminder email for Schedule ID {schedule_id}: {e}") # Optional: A hook function to log the status of the email task (add to your_app/tasks.py) def log_email_status(task): """ This function will be called by django-q after the send_schedule_reminder_email task completes. It logs whether the task was successful or not. """ if task.success: logger.info(f"Email task for Schedule ID {task.args[0]} completed successfully. Result: {task.result}") else: logger.error(f"Email task for Schedule ID {task.args[0]} failed. Error: {task.result}")