haikal/inventory/tasks.py

1348 lines
44 KiB
Python

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,CarReservation,CarStatusChoices
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 get_accounts_data():
return [
# 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
},
]
def create_account(entity, coa, account_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_accounts(instance):
entity = instance.entity
coa = entity.get_default_coa()
for account_data in get_accounts_data():
create_account(entity, coa, account_data)
# Check if all accounts are created
# check_create_coa_accounts(instance)
def check_create_coa_accounts(instance):
logger.info("Checking if all accounts are created")
entity = instance.entity
coa = entity.get_default_coa()
for account_data in get_accounts_data():
if entity.get_all_accounts().filter(code=account_data["code"]).exists():
logger.info(f"Default account already exists: {account_data['code']}")
continue
logger.info(f"Default account does not exist: {account_data['code']}")
create_account(entity, coa, account_data)
# 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 <a href="{url}" target="_blank">View</a>.
"""
).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}")
def remove_reservation_by_id(reservation_id):
try:
reservation = CarReservation.objects.get(pk=reservation_id)
reservation.car.status = CarStatusChoices.AVAILABLE
reservation.car.save()
reservation.delete()
except Exception as e:
logger.error(f"Error removing reservation with ID {reservation_id}: {e}")