odex25_standard/odex25_realstate/property_management/models/rental_contract.py

648 lines
32 KiB
Python

# -*- coding: utf-8 -*-
import base64
import re
import calendar
import logging
from datetime import datetime
from datetime import date
from dateutil.relativedelta import relativedelta
from odoo.tools import exception_to_unicode
from odoo import models, fields, api, exceptions, tools, _
_logger = logging.getLogger(__name__)
class ResPartner(models.Model):
_inherit = 'res.partner'
is_tenant = fields.Boolean(string="Is Tenant?")
#
class RentalContractTemplate(models.Model):
_name = 'rental.contract.template'
name = fields.Char(string="Template Name")
template = fields.Html(string="Template")
class Property(models.Model):
_inherit = "internal.property"
action_type = fields.Selection(selection_add=[('rent', 'Rent')])
class ResUnit(models.Model):
_inherit = "re.unit"
action_type = fields.Selection(selection_add=[('rent', 'Rent')])
contract_id = fields.Many2one('rental.contract', string="Rental Contract")
contract_counts = fields.Integer(string='Contracts', compute='count_contracts_number')
def count_contracts_number(self):
contract_count = self.env['rental.contract'].search([('unit_ids', '=', self.id)])
self.contract_counts = len(contract_count)
def get_contract(self):
contract_id = self.env['rental.contract'].search(
[('unit_ids', '=', self.id)])
form_id = self.env.ref('property_management.rental_contract_form_view').id
list_id = self.env.ref('property_management.rental_contract_list_view').id
domain = [('id', 'in', contract_id.ids)]
return {
'name': _('Rental Contract'),
'view_type': 'form',
'view_mode': 'form',
'res_model': 'rental.contract',
'views': [(list_id, 'tree'), (form_id, 'form')],
'type': 'ir.actions.act_window',
'target': 'current',
'domain': domain,
}
class RentalContract(models.Model):
_name = 'rental.contract'
_description = 'Rental Contract'
_inherit = ['mail.thread', 'mail.activity.mixin']
_order = "id desc"
@api.depends('date_to', 'state')
def _compute_is_today_end_date(self):
for record in self:
record.is_today_end_date = False
if record.date_to and isinstance(record.date_to, date):
record.is_today_end_date = record.date_to <= date.today()
if record.state == 'renewed':
record.is_today_end_date = False
@api.onchange('unit_ids')
def get_units_accounts(self):
self.journal_id = self.unit_ids.journal_id
self.debit_account_id = self.unit_ids.debit_account_id
self.accrued_account_id = self.unit_ids.accrued_account_id
self.revenue_account_id = self.unit_ids.revenue_account_id
@api.onchange('rent_method')
def onchange_rent_method(self):
"""
Based on rent method return the following record
to double check in xml domain in unit that only available
:return: if property return the approved property
:return: else return the available unit of approved property
"""
if self.rent_method and self.rent_method == 'property':
property_ids = self.env['internal.property'].sudo().search(
[('state', '=', 'approve'), ('action_type', '=', 'rent')])
return {'domain': {'property_id': [('id', 'in', property_ids.ids)]}}
elif self.rent_method and self.rent_method == 'unit':
if not self.property_id:
self.property_id = False
property_ids = self.env['internal.property'].sudo().search(
[('state', '=', 'approve'), ('action_type', '=', 'rent')])
print()
property_list = property_ids.filtered(
lambda line: len(line.unit_ids) > 0 and any(unit.state == 'available' for unit in line.unit_ids))
return {'domain': {'property_id': [('id', 'in', property_list.ids)]}}
else:
if not self.property_id:
self.property_id = False
active = fields.Boolean(default=True)
is_today_end_date = fields.Boolean(string="Is Today End Date", compute="_compute_is_today_end_date",)
name = fields.Char(string="Name")
date = fields.Date(string="Contract Date")
seq = fields.Char(string="Sequence", default="/", index=True)
state = fields.Selection([('draft', 'Draft'),
('submit', 'Submit'),
('review', 'Review'),
('confirm', 'Confirmed'),
('renewed', 'Renewed'),
('cancel', 'Cancelled'),
('close', 'Closed')], string='Status',
default='draft', tracking=True)
residential_purpose_id = fields.Many2one('residential.purpose', string="Residential Purpose")
rent_method = fields.Selection([('property', 'Property'),
('unit', 'Unit')], string="Rent Method")
property_id = fields.Many2one('internal.property', string="Property", tracking=True)
unit_ids = fields.Many2many('re.unit', string="Units", tracking=True)
partner_id = fields.Many2one('res.partner', string="Renter", domain=[('is_tenant', '=', True)])
identification_type = fields.Selection(related="partner_id.identification_type", string='Identification Type')
identification_number = fields.Char(related="partner_id.identification_number", string='Identification NUmber')
identification_issue_date = fields.Date(related="partner_id.identification_issue_date",
string='Identification Issue Date')
identification_expiry_date = fields.Date(related="partner_id.identification_expiry_date",
string='Identification Expiry Date')
user_id = fields.Many2one('res.users', string="Responsible", default=lambda self: self.env.user.id)
company_id = fields.Many2one('res.company', string='Company', default=lambda self: self.env.user.company_id)
rent_duration = fields.Integer(string="Rent Duration", default=1)
rent_kind = fields.Selection([('year', 'Year'),
('month', 'Month'),
], string="Rent Kind", tracking=True)
date_from = fields.Date(string="Rent Date from", default=fields.Date.today)
date_to = fields.Date(string="Rent Date To", compute="get_to_date", store=True)
# separate_service = fields.Boolean(string="Separate Service ?")
rent_type = fields.Many2one('rent.type', string="Rent Type")
space = fields.Float(string="Space", compute="get_property_unit_space", store=True)
service = fields.Selection([('fixed', 'Fixed'), ('percentage', 'Percentage')], string="Service")
service_cost = fields.Float(string="service cost")
service_amount = fields.Float(string="service amount", compute="compute_service_amount", store=True)
management_type = fields.Selection(related="property_id.management_type", string="Management Type")
property_state_id = fields.Many2one('re.property.state', related="property_id.property_state_id")
property_type_id = fields.Many2one('internal.property.type', related="property_id.property_type_id", string="Type")
market_type = fields.Selection(related="property_id.market_type", string="Market Type")
city_id = fields.Many2one('re.city', related="property_id.city_id", string="City")
district_id = fields.Many2one('district', related="property_id.district_id", string="District")
street = fields.Char(string="Street Name", related="property_id.street")
check_insurance = fields.Boolean(string='Insurance?', default=False)
meter_price = fields.Float(string='Price Per Meter', compute="unit_property_meter_price", store=True)
cal_rent_amount = fields.Float(string='Calculated Rent Amount', compute="get_rent_amount", store=True)
rent_amount = fields.Float(string='Rent Amount')
original_rent_amount = fields.Float(string='Rent Amount')
insurance = fields.Selection([('fixed', 'Fixed'),
('percentage', 'Percentage')], string="Insurance", default="fixed")
insurance_cost = fields.Float(string="Insurance cost")
insurance_amount = fields.Float(string="Insurance Amount", compute="compute_insurance", store=True)
insurance_paid = fields.Float(string="Insurance Paid", compute="get_insurance_paid")
is_services = fields.Boolean(string='Services Exist?', copy=False)
water_meter_no = fields.Char(string='Water Meter No.')
electricity_meter_no = fields.Char(string='Electricity Meter No.')
generated = fields.Boolean(string='Generated')
closed = fields.Boolean(string='Closed')
annual_raise_ids = fields.One2many('annual.raise', 'contract_id', string='Annual Raise', copy=False)
rent_payment_ids = fields.One2many('rent.payment', 'contract_id', string="Rent Payment")
insurance_invoice_id = fields.Many2one('account.move', string="Insurance Invoice")
external_broker = fields.Boolean(string="External Broker")
external_broker_id = fields.Many2one('res.partner', string="External Broker")
external_percent = fields.Float(string="External Broker Percent")
external_commission = fields.Float(string="External Broker Commission")
internal_broker = fields.Boolean(string="Internal Broker")
internal_broker_id = fields.Many2one('res.partner', string="Internal Broker")
internal_percent = fields.Float(string="Internal Broker Percent")
internal_commission = fields.Float(string="Internal Broker Commission")
renter_commission = fields.Boolean(string="Renter Commission")
renter_percent = fields.Float(string="Renter Commission Percent")
renter_value = fields.Float(string="Renter Value")
journal_id = fields.Many2one('account.journal', string="Journal")
debit_account_id = fields.Many2one('account.account', string="Debit Account", domain=lambda self: [
('user_type_id.id', '=', self.env.ref('account.data_account_type_receivable').id)], store=True)
# Debit
accrued_account_id = fields.Many2one('account.account', string="Accrued Account", domain=lambda self: [
('user_type_id.id', 'in', (self.env.ref('account.data_account_type_current_liabilities').id,self.env.ref('account.data_account_type_non_current_liabilities').id,self.env.ref('account.data_account_type_revenue').id,self.env.ref('account.data_account_type_other_income').id))], store=True)
revenue_account_id = fields.Many2one('account.account', string="Revenue Account", domain=lambda self: [
('user_type_id.id', 'in', (self.env.ref('account.data_account_type_revenue').id,
self.env.ref('account.data_account_type_other_income').id))], store=True)
note = fields.Html(string="Note")
water_cost = fields.Float(string="Water Cost")
template_id = fields.Many2one('rental.contract.template', string="Rental Contract Template")
template = fields.Html(string="Template")
commission_profit = fields.Selection([('percentage', "Percentage"),
('number', "Fixed")], string='Commission', copy=False)
company_profit = fields.Selection([('percentage', 'Percentage'), ('number', 'Fixed amount')],
string='Company Profit')
company_profit_amount = fields.Float(string='Company Profit Amount')
company_profit_val = fields.Float(string='Company Profit', compute='_compute_company_profit_val', store=True)
change_price = fields.Boolean(string='Do You want to change rent?', default=False)
new_price = fields.Float(string="New Meter Price")
new_rent_amount = fields.Float(string='New Rent Amount', copy=False, tracking=True)
renew_contract_id = fields.Many2one('rental.contract', string='New Contract')
renew_done = fields.Boolean(string='Renew Completed', default=False)
renewed = fields.Boolean(string='Renewed Contract', default=False)
previous_contract_id = fields.Many2one('rental.contract', string='Previous Contract')
log_rental_contract_ids = fields.One2many('log.rental.contract', 'contract_id', string='Contract')
annual_raise_on_type = fields.Selection([('meter', _('Meter')), ('rent_amount', _('Rent amount'))],
_('الزيادة علي'), default='rent_amount')
# Add Sales Tax Field
tax_id = fields.Many2one('account.tax', string="Tax", domain=[('type_tax_use', '=', 'sale')])
@api.onchange('tax_id')
def _onchange_sales_tax_id(self):
"""
Apply the selected sales tax to all rent payments when a new tax is selected.
"""
for payment in self.rent_payment_ids:
payment.tax_id = self.tax_id
payment.get_untaxed_amount() # Recalculate amounts with the new tax
payment.get_total_amount()
def action_renew(self):
"""
Renew the contract and link the previous contract to the new one
change the state of contract to renewed
:return:
"""
# ToDo: when invoicing is done link the previous created invoice of insurance
flag = True
for payment in self.rent_payment_ids:
if payment.state not in ['paid', 'cancel']:
flag = False
if not flag:
raise exceptions.ValidationError(
_("Renewing process cannot be completed please check the rent payment status"))
if flag:
contract_values = {
'state': 'draft',
'name': self.name,
'rent_method': self.rent_method,
'property_id': self.property_id.id,
'unit_ids': [(4, unit.id) for unit in self.unit_ids],
'user_id': self.env.user.id,
'date_from': self.date_to,
'rent_duration': self.rent_duration,
'rent_kind': self.rent_kind,
'partner_id': self.partner_id.id,
'rent_type': self.rent_type.id,
'rent_amount': self.rent_amount,
'water_cost': self.water_cost,
'service_amount': self.service_amount, # Correct field for service amount
'service_cost': self.service_cost, # Correct field for service cost
'previous_contract_id': self.id,
'insurance_cost': self.insurance_cost,
'insurance_amount': self.insurance_amount,
'insurance_paid': self.insurance_paid,
# 'insurance_calculation_method': self.insurance_calculation_method,
'insurance': self.insurance,
}
renewed_contract_id = self.env['rental.contract'].create(contract_values)
for rec in self.unit_ids:
rec.write({'state': 'available'})
self.write({'renew_contract_id': renewed_contract_id.id,
'renewed': True,
'state': 'renewed'
})
@api.returns('self', lambda value: value.id)
def copy(self, default=None):
self.ensure_one()
raise exceptions.ValidationError(_("Cannot Duplicate The Contractr"))
@api.onchange('change_price')
def set_change_price(self):
if not self.change_price:
self.new_price = 0.0
self.rent_amount = 0.0
@api.depends('company_profit', 'company_profit_amount')
def _compute_company_profit_val(self):
for record in self:
if record.company_profit and record.company_profit == 'percentage':
record.company_profit_val = record.company_profit_amount / 100 * record.rent_amount
elif record.company_profit and record.company_profit == 'number':
record.company_profit_val = record.company_profit_amount
else:
record.company_profit_val = 0.0
@api.constrains('unit_id')
def check_unit_state(self):
for unit in self.unit_ids:
if unit.state != 'available':
raise exceptions.ValidationError(_("Unit %s is not available") %
(unit.name))
else:
pass
@api.onchange('template_id')
def onchange_template(self):
self.template = self.template_id.template
@api.depends('insurance_invoice_id', 'insurance_invoice_id.amount_residual', 'insurance_amount')
def get_insurance_paid(self):
for rec in self:
if rec.insurance_invoice_id:
residual = rec.insurance_invoice_id.amount_total - rec.insurance_invoice_id.amount_residual
rec.insurance_paid = residual if residual != 0.0 else 0.0
else:
rec.insurance_paid = 0.0
def _prepare_invoice_values(self, contract, amount):
self.partner_id.property_account_receivable_id = contract.debit_account_id.id
invoice_vals = {
'ref': _("Insurance payment for ") + contract.name,
'move_type': 'out_invoice',
'invoice_origin': contract.seq,
'invoice_user_id': contract.user_id.id,
'narration': contract.note,
'partner_id': contract.partner_id.id,
'invoice_line_ids': [(0, 0, {
'name': contract.name + ' - ' + contract.seq + ' - ' + str(contract.date),
'price_unit': amount,
'quantity': 1.0,
'account_id': contract.accrued_account_id.id,
})],
'line_ids': [(0, 0, {'account_id': contract.accrued_account_id.id, 'debit': 0.0, 'credit': amount,
'name': contract.name + ' - ' + contract.seq + ' - ' + str(contract.date),
'quantity': 1}),
(0, 0,
{'account_id': contract.debit_account_id.id, 'debit': amount, 'credit': 0.0, 'quantity': 1})]
}
return invoice_vals
def action_confirm(self):
invoice_vals = self._prepare_invoice_values(self, self.insurance_amount)
if self.insurance_amount>0.00 or self.insurance_cost>0.00:
invoice = self.env['account.move'].sudo().create(invoice_vals).with_user(self.env.uid)
# Get the ID of the second line
line_id = invoice.invoice_line_ids[1].id
commands = [(2, line_id, 0)]
invoice.write({'invoice_line_ids': commands})
self.insurance_invoice_id = invoice.id
if self.rent_method != 'property':
for unit in self.unit_ids:
unit.write({'state': 'rented',
'contract_id': self.id})
elif self.rent_method == 'property':
for unit in self.property_id.unit_ids:
unit.write({'state': 'rented',
'contract_id': self.id})
self.property_id.write({'state': 'rent'})
self.env['log.rental.contract'].create({'contract_id': self.id,
'leaser_id': self.partner_id.id,
'date_start': self.date_from,
'date_end': self.date_to})
self.write({'state': 'confirm'})
def action_review(self):
full = True
if self.property_id.state in ['reserve', 'rent'] and self.property_id.contract_counts>1:
raise exceptions.ValidationError(_("Property is already reserved or rented"))
#
for units in self.property_id.unit_ids:
if units.state in ['draft', 'available']:
full = False
if full:
self.property_id.write({'state': 'rent'})
total_rent = round(self.cal_rent_amount * self.rent_duration, 2)
total_service = round(self.service_amount * self.rent_duration, 2)
total_water = round(self.water_cost * self.rent_duration, 2)
rent_payment = round(sum([rent.amount for rent in self.rent_payment_ids]), 2)
service_payment = round(sum([rent.service_cost for rent in self.rent_payment_ids]), 2)
water_payment = round(sum([rent.water_cost for rent in self.rent_payment_ids]), 2)
if total_rent != rent_payment and not self.annual_raise_ids:
raise exceptions.ValidationError(
_("Rent payment %s is not equal the rent total amount %s ") % (rent_payment, total_rent))
if total_service != service_payment:
pass
# raise exceptions.ValidationError(
# _("Service payment %s is not equal the rent total service amount %s ") % (
# service_payment, total_service))
if total_water != water_payment:
pass
# raise exceptions.ValidationError(
# _("Water cost to pay %s is not equal the rent total water cost %s ") % (water_payment, total_water))
self.write({'state': 'review'})
def action_submit(self):
self.seq = self.env['ir.sequence'].next_by_code('rental.contract') or '/'
if not self.rent_payment_ids:
self.generate_payments()
if self.rent_method != 'property':
for unit in self.unit_ids:
if unit.state != 'available':
raise exceptions.ValidationError(_("Unit %s is not available") %
(unit.name))
else:
unit.write({'state': 'reserved',
'contract_id': self.id})
elif self.rent_method == 'property':
for unit in self.property_id.unit_ids:
unit.write({'state': 'reserved',
'contract_id': self.id})
self.property_id.write({'state': 'reserve'})
self.write({'state': 'submit'})
@api.depends('insurance', 'insurance_cost', 'cal_rent_amount')
def compute_insurance(self):
if self.insurance and self.insurance == 'percentage':
self.insurance_amount = (self.insurance_cost / 100.0) * self.cal_rent_amount
elif self.insurance and self.insurance == 'fixed':
self.insurance_amount = self.insurance_cost
def action_draft(self):
self.write({'state': 'draft'})
def action_cancel(self):
if self.rent_payment_ids:
for payment in self.rent_payment_ids:
if payment.state != 'paid':
payment.write({'state': 'cancel'})
if self.rent_method != 'property':
for unit in self.unit_ids:
unit.write({'state': 'available'})
elif self.rent_method == 'property':
for unit in self.property_id.unit_ids:
unit.write({'state': 'available',
'contract_id': self.id})
self.property_id.write({'state': 'register'})
self.write({'state': 'cancel'})
@api.depends('service', 'service_cost', 'cal_rent_amount')
def compute_service_amount(self):
if self.service and self.service == 'percentage':
self.service_amount = (self.service_cost / 100) * self.cal_rent_amount
elif self.service and self.service == 'fixed':
self.service_amount = self.service_cost
@api.depends('rent_kind', 'meter_price', 'space', 'rent_amount', 'new_price', 'change_price')
def get_rent_amount(self):
"""
get total rent based on meter price and space rent kind
:return:
"""
rent_total = 0.0
rent_price = self.meter_price
if self.change_price and self.new_price > 0.0:
rent_price = self.new_price
if self.rent_kind == 'year':
rent_total = (self.space * rent_price)
if self.rent_kind == 'month':
rent_total = (self.space * rent_price / 12)
if self.rent_kind == 'day':
date_from = datetime.strptime(datetime.strftime(self.date_from, '%Y-%m-%d'), "%Y-%m-%d")
if calendar.isleap(date_from.year):
rent_total = (self.space * rent_price / 366)
elif not calendar.isleap(date_from.year):
rent_total = (self.space * rent_price / 365)
if self.rent_kind == 'hour':
date_from = datetime.strptime(
datetime.strftime(self.date_from, "%Y-%m-%d"), "%Y-%m-%d")
if calendar.isleap(date_from.year):
rent_total = (self.space * rent_price / 366) / 24
elif not calendar.isleap(date_from.year):
rent_total = (self.space * rent_price / 365) / 24
self.cal_rent_amount = rent_total if self.rent_amount == 0.0 else self.rent_amount
@api.depends('rent_method', 'property_id.meter_price', 'property_id', 'unit_ids')
def unit_property_meter_price(self):
"""
get meter price based on rent method
:return: if property based on meter_price on property object
:return: if unit get the total unit price of all selected unit
"""
total_price = 0.0
if self.rent_method == 'property':
self.meter_price = self.property_id.meter_price
else:
for unit in self.unit_ids:
total_price += unit.meter_price
self.meter_price = total_price
@api.depends('rent_method', 'property_id', 'unit_ids')
def get_property_unit_space(self):
"""
get space based on rent method
:return: if property return property space
:return: if unit or more than one unit read the sum of space uing for loop
"""
total_space = 0.0
if self.rent_method == 'property':
self.space = self.property_id.property_space
else:
for unit in self.unit_ids:
total_space += unit.space
self.space = total_space
@api.depends('date_from', 'rent_duration', 'rent_kind')
def get_to_date(self):
if self.date_from and self.rent_duration and self.rent_kind:
date_from = datetime.strptime(datetime.strftime(self.date_from, '%Y-%m-%d'), '%Y-%m-%d').date()
date_from = date_from - relativedelta(days=int(1))
if self.rent_kind == 'year':
date_to = date_from + relativedelta(years=int(self.rent_duration))
self.date_to = date_to.strftime('%Y-%m-%d')
elif self.rent_kind == 'month':
date_to = date_from + relativedelta(months=int(self.rent_duration))
self.date_to = date_to.strftime('%Y-%m-%d')
def check_line(self):
"""
if there is a rent line then raise a confirm box if true remove all previous line
and call generate function
:return:
"""
if len(self.rent_payment_ids) > 0:
ctx = self._context.copy()
ctx.update({'rent_payment': True})
return {
'name': _('Confirm'),
'type': 'ir.actions.act_window',
'view_type': 'form',
'view_mode': 'form',
'res_model': 'confirm.wizard',
'context': ctx,
'target': 'new',
}
else:
self.generate_payments()
def remove_payment(self):
"""remove all payment line"""
self._cr.execute('delete from rent_payment where contract_id =%s' % self.id)
def generate_payments(self):
"""
based on user selection system will prepare the rent payment scheduling
and create a rent line
new change service will be like rent payment
:return:
"""
property_id = self.property_id.id
date_from = datetime.strptime(datetime.strftime(self.date_from, '%Y-%m-%d'), '%Y-%m-%d').date()
date_to = datetime.strptime(datetime.strftime(self.date_to, '%Y-%m-%d'), '%Y-%m-%d').date()
months = int(self.rent_type.months)
service_months = 12
names = []
if self.unit_ids:
for unit in self.unit_ids:
names.append(unit.name)
# the rent factor is used to get the number of payments
# also to get the rent amount based on rent_kind as following
rent_factor = 1.0
if self.rent_kind == 'year':
rent_factor = 12.0
if not self.date_from or not self.date_to:
raise exceptions.ValidationError(_('Please set the rent duration and start date'))
if months == 0:
raise exceptions.ValidationError(_("In rent type please make sure that the month number is more than 0"))
# Calculate the number of payments and the amounts per payment
no_payments = (self.rent_duration * rent_factor) / months
no_services_payment = (self.rent_duration * rent_factor) / service_months
rent_amount_per_payment = self.cal_rent_amount / (rent_factor / months)
water_amount_per_payment = self.water_cost / (rent_factor / service_months)
services_amount_per_payment = self.service_amount / (rent_factor / service_months)
untaxed_amount = round(rent_amount_per_payment + water_amount_per_payment + services_amount_per_payment, 2)
tax_amount = round(self.tax_id.amount / 100 * rent_amount_per_payment, 2) if self.tax_id else 0.0
total_amount = round(untaxed_amount + tax_amount, 2)
next_date = date_from
service_next_date = date_from
payment = 0
service = 0
while payment < no_payments:
# Check for any rent raise applicable on the due date
raise_line = next((line for line in self.annual_raise_ids if line.due_date_raise == next_date), None)
if raise_line:
rent_amount_per_payment = raise_line.rent_amount_after_raise / (rent_factor / months)
# Calculate the amounts
self._cr.execute('INSERT INTO rent_payment \
(name, contract_id, due_date, property_id, amount, water_cost, service_cost, user_id, company_id, state, tax_id, untaxed_amount, tax_amount) \
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING id',
(
_('Payment %s') % (payment + 1),
self.id,
next_date.strftime('%Y-%m-%d'),
self.property_id.id,
rent_amount_per_payment,
water_amount_per_payment if payment < no_services_payment else 0.0,
services_amount_per_payment if payment < no_services_payment else 0.0,
self.user_id.id,
self.env.user.company_id.id,
'draft',
self.tax_id.id if self.tax_id else None, # Handle None value for tax_id
untaxed_amount,
tax_amount
))
# Move to the next payment date
next_date += relativedelta(months=months)
payment += 1
# Update any remaining rent payments with service costs
query = """UPDATE rent_payment SET service_cost = %s, water_cost = %s WHERE contract_id = %s AND due_date <= %s"""
self._cr.execute(query,
(services_amount_per_payment, water_amount_per_payment, self.id, date_to.strftime('%Y-%m-%d')))
# Update amounts (e.g., tax calculations) for each rent payment line
for line in self.rent_payment_ids:
line.write({'tax_id': self.tax_id.id if self.tax_id else None})
line.get_untaxed_amount()
line.get_total_amount()
###################################### End of Generating Payment ############################
class ResPartner(models.Model):
_inherit = 'res.partner'
_description = "Renter"
is_renter = fields.Boolean(string="Renter")
class LogRentalContract(models.Model):
_name = 'log.rental.contract'
contract_id = fields.Many2one('rental.contract', string='Contract')
leaser_id = fields.Many2one('res.partner', string='Leaser')
date_start = fields.Date(string='Date Start')
date_end = fields.Date(string='Date End')