1348 lines
44 KiB
Python
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}") |