[NEW] Addons creation - product_rental_bookings

This commit is contained in:
Stéphan Sainléger
2022-04-19 11:54:03 +02:00
parent 73749bcfb6
commit 8e2973526a
55 changed files with 10183 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
from . import account_move
from . import product
from . import product_book
from . import product_contract
from . import product_operation
from . import product_order
from . import product_logs
from . import res_config_settings
from . import stock_move
from . import stock_picking
from . import session_config_settings

View File

@@ -0,0 +1,106 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from odoo import models, fields
from odoo.exceptions import UserError
class AccountInvoice(models.Model):
_inherit = "account.move"
rental_order_id = fields.Many2one("rental.product.order", string="Rental ref ")
interval_type = fields.Selection(
[("days", "Day"), ("weeks", "Week"), ("months", "Month")],
string="Interval Type",
)
interval_number = fields.Integer(string="Interval Number", readonly=1)
is_recurring = fields.Boolean(string="Recurring Invoice", default=False)
contract_id = fields.Many2one("rental.product.contract", string="Contract")
is_hours = fields.Boolean(string="Hours")
is_days = fields.Boolean(string="Days")
def action_invoice_open(self):
# lots of duplicate calls to action_invoice_open, so we remove those already open
to_open_invoices = self.filtered(lambda inv: inv.state != "open")
if to_open_invoices.filtered(lambda inv: inv.state != "draft"):
raise UserError(
_("Invoice must be in draft state in order to validate it.")
)
if to_open_invoices.filtered(lambda inv: inv.amount_total < 0):
raise UserError(
_(
"You cannot validate an invoice with a negative total amount. You should create a credit note instead."
)
)
to_open_invoices.action_date_assign()
to_open_invoices.action_move_create()
if (
self.interval_number > 0
and self.is_recuuring == False
and self.date_due >= datetime.now().strftime("%y-%m-%d-%H-%M")
):
self.is_recuuring = True
sub_name = (
str(self.number)
+ str("-" + self.interval_type if self.interval_type else "")
+ "-"
+ datetime.now().strftime("%Y-%m-%d")
)
model_id = self.env["ir.model"].search([("model", "=", self._name)])
subscription_document_id = self.env["subscription.document"].search(
[("name", "=", "Account Invoice"), ("model", "=", model_id.id)], limit=1
)
if not subscription_document_id:
subscription_document_id = self.env["subscription.document"].create(
{"name": "Account Invoice", "model": model_id.id}
)
subscription_doc_source = (
str(subscription_document_id.model.model) + "," + str(self.id)
)
subscription_id = self.env["subscription.subscription"].create(
{
"name": sub_name,
"partner_id": self.partner_id.id,
"interval_number": self.interval_number,
"interval_type": self.interval_type,
"doc_source": subscription_doc_source,
}
)
subscription_id.set_process()
return to_open_invoices.action_invoice_open()
class AccountInvoiceLine(models.Model):
_inherit = "account.move.line"
product_id = fields.Many2one("product.product", string="Product ID")
enter_hour = fields.Float(string="Hour")
enter_days = fields.Float(string="Days")
def _get_computed_price_unit(self):
self.ensure_one()
if not self.product_id:
return self.price_unit
elif self.move_id.is_sale_document(include_receipts=True):
# Out invoice.
price_unit = self.product_id.lst_price
elif self.move_id.is_purchase_document(include_receipts=True):
# In invoice.
price_unit = self.product_id.standard_price
else:
return self.price_unit
if self.product_uom_id != self.product_id.uom_id:
price_unit = self.product_id.uom_id._compute_price(
price_unit, self.product_uom_id
)
if self.enter_days:
price_unit = price_unit * self.enter_days
elif self.enter_hour:
price_unit = price_unit * self.enter_hour
return price_unit

View File

@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class ProductProduct(models.Model):
_inherit = "product.product"
is_rental = fields.Boolean(string="Rental", default=False)
selected_product = fields.Boolean(string="Select", default=False)
rental_amount = fields.Float(string="Rent Per Day Rate")
rental_amount_per_hour = fields.Float(string="Rent Per Hour Rate")
rental_amount_per_session = fields.Float(string="Rent Per Session Rate")
product_registration_id = fields.Many2one("rental.product.order", string="Order")
rental_qyt = fields.Float("Quantity", default=1.0)

View File

@@ -0,0 +1,368 @@
# -*- coding: utf-8 -*-
from datetime import datetime, date
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError, AccessError
class ProductBooking(models.TransientModel):
_name = "product.booking"
_rec_name = "book_number"
_description = "Book"
@api.depends(
"product_line_ids",
"total_days",
"extra_charges",
"price_based",
"from_date",
"to_date",
)
def compute_rate(self):
for record in self:
record.total = 0
record.sub_total = 0
record.total_days = 0
record.total_hours = 0
if record.from_date and record.to_date:
date_from = datetime.strptime(
str(record.from_date), "%Y-%m-%d %H:%M:%S"
)
date_to = datetime.strptime(str(record.to_date), "%Y-%m-%d %H:%M:%S")
delta = date_from - date_to
record.total_days = abs(delta.days)
record.total_hours = abs(delta.total_seconds() / 3600.0)
sub_total = 0.0
with_tax_total = 0.0
for product in record.product_line_ids.filtered(
lambda fv: fv.selected_product
):
if record.price_based == "per_day":
taxes = product.taxes_id.compute_all(
product.rental_qyt,
product.currency_id,
product.rental_amount * record.total_days,
)
sub_total += taxes["total_excluded"]
with_tax_total += taxes["total_included"]
elif record.price_based == "per_hour":
taxes = product.taxes_id.compute_all(
product.rental_qyt,
product.currency_id,
product.rental_amount_per_hour * record.total_hours,
)
sub_total += taxes["total_excluded"]
with_tax_total += taxes["total_included"]
else:
taxes = product.taxes_id.compute_all(
product.rental_qyt,
product.currency_id,
product.rental_amount_per_session,
)
sub_total += taxes["total_excluded"]
with_tax_total += taxes["total_included"]
record.sub_total = sub_total
record.total = with_tax_total + record.extra_charges
@api.model
def _get_based_on_selections(self):
enabled_day_rent = (
self.env["ir.config_parameter"].sudo().get_param("enabled_day_rent")
)
enabled_hour_rent = (
self.env["ir.config_parameter"].sudo().get_param("enabled_hour_rent")
)
enabled_session_rent = (
self.env["ir.config_parameter"].sudo().get_param("enabled_session_rent")
)
selection = []
if enabled_day_rent:
selection.append(("per_day", "Day"))
if enabled_hour_rent:
selection.append(("per_hour", "Hour"))
if enabled_session_rent:
selection.append(("per_session", "Session"))
return selection
book_number = fields.Char(string="Book Number")
from_date = fields.Datetime(string="From Date")
to_date = fields.Datetime(string="To Date")
product_line_ids = fields.Many2many(
"product.product",
"product_search_table",
"product_search_id",
"product_book_id",
string="Available Product",
)
is_search = fields.Boolean(string="Is Search", default=False)
total_days = fields.Float(string="Total Days", compute="compute_rate")
extra_charges = fields.Monetary(string="Extra Charges")
sub_total = fields.Float(string="Sub Total(Exclusive Tax)", compute="compute_rate")
total = fields.Float(string="Total", compute="compute_rate")
categ_id = fields.Many2one(
"product.category", required=True, string="Product Category"
)
company_id = fields.Many2one(
"res.company", string="Company", default=lambda self: self.env.user.company_id
)
currency_id = fields.Many2one("res.currency", related="company_id.currency_id")
location_id = fields.Many2one("stock.location", string="Location")
price_based = fields.Selection(
selection=_get_based_on_selections, default="per_day", string="Based On"
)
total_hours = fields.Float(string="Total Hours", compute="compute_rate")
session_id = fields.Many2one("session.config", string="Session")
@api.constrains("from_date", "to_date")
def check_date(self):
for record in self:
if (
date.strftime(
datetime.strptime(str(record.from_date), "%Y-%m-%d %H:%M:%S"),
"%Y-%m-%d",
)
< str(date.today())
):
raise ValidationError(_("You cannot enter past date"))
if date.strftime(
datetime.strptime(str(record.to_date), "%Y-%m-%d %H:%M:%S"), "%Y-%m-%d"
) < str(date.today()):
raise ValidationError(_("You cannot enter past date"))
@api.model
def convert_float_to_hh_mm(self, session_id, from_date):
start_date = "{0:02.0f}:{1:02.0f}".format(
*divmod(session_id.start_time * 60, 60)
)
end_date = "{0:02.0f}:{1:02.0f}".format(*divmod(session_id.end_time * 60, 60))
start_date_fmt = (
"%Y-%m-%d "
+ start_date.split(":")[0]
+ ":"
+ start_date.split(":")[1]
+ ":"
+ "00"
)
end_date_fmt = (
"%Y-%m-%d "
+ end_date.split(":")[0]
+ ":"
+ end_date.split(":")[1]
+ ":"
+ "00"
)
start_str_datetime = from_date.strftime(start_date_fmt)
end_str_datetime = from_date.strftime(end_date_fmt)
start_date = self.env["rental.product.order"].convert_TZ_UTC(start_str_datetime)
end_date = self.env["rental.product.order"].convert_TZ_UTC(end_str_datetime)
return start_date, end_date
@api.onchange("price_based", "from_date", "session_id")
def onchange_date_from_price_based(self):
if self.price_based == "per_session" and self.from_date and self.session_id:
start_time, end_time = self.convert_float_to_hh_mm(
self.session_id, self.from_date
)
self.to_date = end_time
self.from_date = start_time
@api.model
def create(self, vals):
vals.update(
{
"book_number": self.env["ir.sequence"].next_by_code("product_booking")
or _("Product Booking")
}
)
return super(ProductBooking, self).create(vals)
def search_product(self):
product_id = []
if self.from_date and self.to_date:
if self.from_date > self.to_date:
raise ValidationError("To Date must be greater than From date")
elif not self.env.user.has_group("stock.group_stock_multi_locations"):
raise AccessError(
_("Manage Multiple Stock Locations need to be assign.")
)
else:
categ_ids = self.env["product.category"].search(
[("parent_id", "child_of", self.categ_id.id)]
)
self.env.cr.execute(
"""
SELECT
propro.id
FROM product_product propro
JOIN product_template protmp ON protmp.id = propro.product_tmpl_id
WHERE
protmp.categ_id IN %s AND
propro.is_rental='t' AND
propro.id IN (
Select product_id from stock_quant where location_id = %s);
""",
(
tuple(categ_ids.ids),
self.location_id.id,
),
)
product_data = self.env.cr.fetchall()
if product_data:
for products in product_data:
product = (
self.env["product.product"]
.sudo()
.search([("id", "in", products)])
)
available_product_stock = self.env["stock.quant"].search(
[
("product_id", "=", product.id),
("quantity", ">", 0),
("location_id", "=", self.location_id.id),
]
)
available_product_stock.product_id.rental_qyt = 1.0
available_product_stock.product_id.selected_product = False
product_id.extend(available_product_stock.product_id.ids)
self.update(
{
"product_line_ids": [(6, 0, product_id)],
"total": self.total,
"is_search": True,
}
)
else:
raise ValidationError("Sorry!!! No any Product Available!!!")
def book_product(self):
product = False
for product_line in self.product_line_ids:
if product_line.selected_product:
product = True
if product:
product_order_id = []
for product_id in self.product_line_ids.filtered(
lambda fv: fv.selected_product
):
# available_product_stock = self.env['stock.quant'].search([('product_id', '=', product_id.id),
# ('location_id', '=',
# self.location_id.id)])
# if product_id.rental_qyt > available_product_stock.quantity:
# raise ValidationError(_('Available quantity for %s is %d') % (product_id.name,
# available_product_stock.quantity))
order_line_obj = self.env["product.order.line"]
start_date = self.from_date
end_date = self.to_date
order_line_ids = order_line_obj.sudo().search(
[
("product_order_id.state", "=", "confirm"),
("product_id", "=", product_id.id),
]
)
total_in_order_qty = 0
for order_line in order_line_ids:
if (
(
start_date
<= order_line.product_order_id.from_date
<= end_date
)
or (
start_date
<= order_line.product_order_id.to_date
<= end_date
)
and order_line.product_order_id.picking_count == 1
):
total_in_order_qty += (
order_line.qty_needed
if order_line.product_order_id.picking_count == 1
else 0
)
elif (
(
order_line.product_order_id.from_date
<= start_date
<= order_line.product_order_id.to_date
)
or (
order_line.product_order_id.from_date
<= end_date
<= order_line.product_order_id.to_date
)
and order_line.product_order_id.picking_count == 1
):
total_in_order_qty += (
order_line.qty_needed
if order_line.product_order_id.picking_count == 1
else 0
)
if product_id.sudo().qty_available and total_in_order_qty:
qty_available = product_id.sudo().qty_available - total_in_order_qty
else:
total_in_order_qty = order_line_ids.filtered(
lambda x: x.qty_needed
if x.product_order_id.picking_count > 1
else 0
)
qty_available = product_id.sudo().qty_available + sum(
total_in_order_qty.mapped("qty_needed")
)
if (
not product_id.rental_qyt
or not qty_available >= product_id.rental_qyt
):
raise ValidationError(
_("Available quantity for %s is %d")
% (product_id.name, qty_available)
)
else:
if self.price_based == "per_day":
rate_total = product_id.rental_amount
else:
if self.price_based == "per_hour":
rate_total = product_id.rental_amount_per_hour
else:
rate_total = product_id.rental_amount_per_session
product_order_id.append(
(
0,
0,
{
"product_id": product_id.id,
"name": product_id.name,
"price_based": self.price_based,
"enter_days": self.total_days
if self.price_based == "per_day"
else 0,
"enter_hour": self.total_hours
if self.price_based in ["per_hour", "per_session"]
else 0,
"price": rate_total,
"qty_needed": product_id.rental_qyt,
"tax_id": [(6, 0, product_id.taxes_id.ids)],
},
)
)
return {
"name": "product order",
"view_type": "form",
"view_mode": "form",
"res_model": "rental.product.order",
"type": "ir.actions.act_window",
"context": {
"default_from_date": self.from_date,
"default_to_date": self.to_date,
"default_extra_charges": self.extra_charges,
"default_is_days": True if self.price_based == "per_day" else False,
"default_is_hours": True
if self.price_based in ["per_hour", "per_session"]
else False,
"default_product_order_lines_ids": product_order_id,
"default_location_id": self.location_id.id,
"default_price_based": self.price_based,
},
}
else:
raise ValidationError(_("First Please Select the Product"))

View File

@@ -0,0 +1,851 @@
# -*- coding: utf-8 -*-
from datetime import datetime, date, timedelta
from dateutil.relativedelta import relativedelta
from odoo import fields, api, models, _
from odoo.exceptions import UserError, ValidationError
class RentalProductContract(models.Model):
_name = "rental.product.contract"
_description = "Product Rental Contract"
name = fields.Char("Name")
partner_id = fields.Many2one("res.partner", string="Customer", required=True)
rental_id = fields.Many2one("rental.product.order", string="Rental Order Id")
contract_date = fields.Date(
string="Contract Date",
)
contractor_id = fields.Many2one("res.users", string="Contractor Name")
from_date = fields.Date(string="From Date")
to_date = fields.Date(string="To Date")
account_payment_term = fields.Many2one(
"account.payment.term", string="Payment Term", required=True
)
damage_charge = fields.Monetary(string="Damage Charge")
additional_charges = fields.Monetary(string="Additional Charges")
subtotal = fields.Monetary(string="Sub Total", readonly=True)
taxes = fields.Float(string="Taxes", compute="_compute_amount", readonly=True)
untaxed_amount = fields.Monetary(
string="Untaxed Amount",
compute="_compute_amount",
)
extra_charges = fields.Monetary(string="Extra Charges")
invoice_ids = fields.Many2one("account.move", string="Invoice Id")
signature = fields.Binary(string="Contractor Signature ")
signature_contractor = fields.Binary(string="Contractor Signature")
signature_customer = fields.Binary(string="Customer Signature")
button_name = fields.Char(string="Button Name")
terms_condition = fields.Text(string="Terms and Condition")
product_contract_lines_ids = fields.One2many(
"product.contract.lines", "product_contract_id", string="Order Line"
)
pricelist_id = fields.Many2one("product.pricelist", string="Pricelist")
total_amount = fields.Monetary(string="Total Amount", compute="_compute_amount")
total = fields.Monetary(string="Total", compute="_compute_total")
cost_generated = fields.Monetary(
string="Recurring Cost",
help="Costs paid at regular intervals, depending on the cost frequency",
)
cost_frequency = fields.Selection(
[
("no", "No"),
("daily", "Daily"),
("weekly", "Weekly"),
("monthly", "Monthly"),
("yearly", "Yearly"),
],
string="Recurring Cost Frequency",
required=True,
)
state = fields.Selection(
[
("futur", "Incoming"),
("open", "In Progress"),
("expired", "Expired"),
("diesoon", "Expiring Soon"),
("closed", "Closed"),
],
"Status",
default="open",
readonly=True,
)
cost = fields.Monetary(
string="Rent Cost",
help="This fields is to determine the cost of rent",
required=True,
)
account_type = fields.Many2one(
"account.account",
"Account",
default=lambda self: self.env["account.account"].search([("id", "=", 17)]),
)
recurring_line = fields.One2many(
"product.rental.line", "rental_number", readonly=True
)
attachment_ids = fields.Many2many(
"ir.attachment",
"product_rent_ir_attachments_rel",
"rental_id",
"attachment_id",
string="Attachments",
)
sum_cost = fields.Float(
compute="_compute_sum_cost", string="Indicative Costs Total"
)
auto_generated = fields.Boolean("Automatically Generated", readonly=True)
generated_cost_ids = fields.One2many(
"product.rental.line", "rental_number", string="Generated Costs"
)
invoice_count = fields.Integer(
compute="_invoice_count", string="# Invoice", copy=False
)
first_payment = fields.Float(string="First Payment", compute="_compute_amount")
first_invoice_created = fields.Boolean(
string="First Invoice Created", default=False
)
origin = fields.Char(string="Order Reference")
picking_id = fields.Many2one("stock.picking", string="Picking")
document_ids = fields.One2many(
"customer.document", "contract_id", string="Contract"
)
company_id = fields.Many2one(
"res.company", string="Company", default=lambda self: self.env.user.company_id
)
currency_id = fields.Many2one("res.currency", related="company_id.currency_id")
cancel_policy_ids = fields.One2many(
"rental.policy", "contract_id", string="Cancel Policy"
)
number_of_slot = fields.Integer(string="Number of Slot")
is_hours = fields.Boolean(string="Hours")
is_days = fields.Boolean(string="Days")
def generate_policy(self):
if not self.cancel_policy_ids and self.number_of_slot != 0:
number_of_days = self.from_date - self.contract_date
cancel_policy_list = []
if number_of_days.days >= (self.number_of_slot * 2):
day_per_slot = int(number_of_days.days / self.number_of_slot - 1)
day = 0
for i in range(self.number_of_slot - 1):
cancel_policy_list.append(
(
0,
0,
{
"from_date": self.contract_date + timedelta(day),
"to_date": self.contract_date
+ timedelta(day_per_slot + day),
},
)
)
day += day_per_slot + 1
cancel_policy_list.append(
(
0,
0,
{
"from_date": self.contract_date + timedelta(day),
"to_date": self.from_date - timedelta(days=2),
},
)
)
cancel_policy_list.append(
(
0,
0,
{
"from_date": self.from_date - timedelta(days=1),
"policy_charged": 100,
},
)
)
self.cancel_policy_ids = cancel_policy_list
else:
raise ValidationError(_("Please enter the sufficient Number of Slot"))
def write(self, vals):
if "button_name" in vals.keys():
if vals["button_name"] == "signature_contractor":
vals["signature_contractor"] = vals["signature"]
elif vals["button_name"] == "signature_customer":
vals["signature_customer"] = vals["signature"]
return super(RentalProductContract, self).write(vals)
@api.depends("product_contract_lines_ids")
def _compute_amount(self):
"""
Compute the total amounts of the SO.
"""
for order in self:
untaxed_amount = 0.0
taxes = 0.0
total_amount = 0.0
for line in order.product_contract_lines_ids:
untaxed_amount += line.sub_total
taxes += line.price_tax
total_amount += line.sub_total + line.price_tax
order.update(
{
"untaxed_amount": untaxed_amount,
"taxes": taxes,
"total_amount": untaxed_amount + taxes + order.extra_charges,
"first_payment": untaxed_amount + taxes + order.extra_charges,
}
)
@api.depends("recurring_line.recurring_amount")
def _compute_sum_cost(self):
for contract in self:
contract.sum_cost = sum(contract.recurring_line.mapped("recurring_amount"))
def _invoice_count(self):
invoice_ids = self.env["account.move"].search(
[("invoice_origin", "=", self.name)]
)
self.invoice_count = len(invoice_ids)
@api.model
def create(self, vals):
sequence_no = self.env["ir.sequence"].next_by_code("product_contract") or _(
"Product Contract"
)
vals.update({"name": sequence_no})
return super(RentalProductContract, self).create(vals)
@api.depends("product_contract_lines_ids", "damage_charge")
def _compute_total(self):
self.total = self.total_amount + self.damage_charge
def contract_close(self):
invoice_ids = self.env["account.move"].search(
[("invoice_origin", "=", self.name)]
)
order_ids = self.env["rental.product.order"].search(
[("res_number", "=", self.origin)]
)
is_paid = 0
for each in invoice_ids:
if each.state != "posted":
is_paid = 1
break
if is_paid == 0:
self.state = "closed"
order_ids.state = "close"
else:
raise UserError("Please Check invoices There are Some Invoices are pending")
def contract_open(self):
for record in self:
order_ids = self.env["rental.product.order"].search(
[("res_number", "=", record.origin)]
)
record.state = "open"
order_ids.state = "draft"
def act_renew_contract(self):
product_list = []
for product_line in self.product_contract_lines_ids:
product_list.append(
(
0,
0,
{
"product_id": product_line.product_id.id,
"price_based": product_line.price_based,
"enter_days": product_line.enter_days,
"price": product_line.price,
"enter_hour": product_line.enter_hour,
},
)
)
assert (
len(self.ids) == 1
), "This operation should only be done for 1 single contract at a time, as it it suppose to open a window as result"
for element in self:
# compute end date
startdate = fields.Date.from_string(element.from_date)
enddate = fields.Date.from_string(element.to_date)
diffdate = enddate - startdate
default = {
"contract_date": fields.Date.context_today(self),
"from_date": fields.Date.to_string(
fields.Date.from_string(element.to_date) + relativedelta(days=1)
),
"to_date": fields.Date.to_string(enddate + diffdate),
"cost_generated": self.cost_generated,
"product_contract_lines_ids": product_list,
}
newid = element.copy(default).id
return {
"name": _("Renew Contract"),
"view_mode": "form",
"view_id": self.env.ref(
"product_rental_bookings.rental_product_contract_form"
).id,
"view_type": "tree,form",
"res_model": "rental.product.contract",
"type": "ir.actions.act_window",
"res_id": newid,
}
def send_product_contract(self):
"""
This is Email for send contract Detail
"""
self.ensure_one()
ir_model_data = self.env["ir.model.data"]
try:
template_id = ir_model_data.get_object_reference(
"product_rental_bookings", "email_template_product_contract"
)[1]
except ValueError:
template_id = False
try:
compose_form_id = ir_model_data.get_object_reference(
"mail", "email_compose_message_wizard_form"
)[1]
except ValueError:
compose_form_id = False
ctx = {
"default_model": "rental.product.contract",
"default_res_id": self.ids[0],
"default_use_template": bool(template_id),
"default_template_id": template_id,
"mark_so_as_sent": True,
}
return {
"type": "ir.actions.act_window",
"view_type": "form",
"view_mode": "form",
"res_model": "mail.compose.message",
"views": [(compose_form_id, "form")],
"view_id": compose_form_id,
"target": "new",
"context": ctx,
}
def send_email_for_firstpayment(self, inv_id, contracts):
"""
Send email for payment.
"""
mail_content = _(
"<h3>First Payment!</h3><br/>Hi %s, <br/> This is to notify that You have to pay amount as per mention below.<br/><br/>"
"Please find the details below:<br/><br/>"
"<table><tr><td>Reference Number<td/><td> %s<td/><tr/>"
"<tr><td>Date<td/><td> %s <td/><tr/><tr><td>Amount <td/><td> %s<td/><tr/><table/>"
) % (
contracts.partner_id.name,
inv_id.invoice_origin,
date.today(),
inv_id.amount_total,
)
main_content = {
"subject": _("You First Payment For: %s") % inv_id.invoice_origin,
"author_id": contracts.env.user.partner_id.id,
"body_html": mail_content,
"email_to": contracts.partner_id.email,
}
self.env["mail.mail"].create(main_content).send()
def notification_email_for_expire_contract(self, contracts):
mail_content = _(
"<h3>Expiration Of Rental Contract</h3>"
"<br/>Dear %s, <br/>"
"Our record indicate that your rental contract <b>%s,</b> expire soon,<br/>"
"If you want to renew this contract Then contact to our agency before last date of contract."
"<br/>"
"<br/>"
"<br/>"
"<br/>"
"<table>"
"<tr>"
"<td>Contract Ref<td/>"
"<td>%s<td/>"
"<tr/>"
"<tr>"
"<td>Responsible Person <td/>"
"<td> %s - %s<td/>"
"<tr/>"
"<table/>"
) % (
contracts.partner_id.name,
contracts.name,
contracts.name,
contracts.contractor_id.name,
contracts.contractor_id.mobile,
)
main_content = {
"subject": "Expiration Of Rental Contract!",
"author_id": contracts.env.user.partner_id.id,
"body_html": mail_content,
"email_to": contracts.partner_id.email,
}
self.env["mail.mail"].create(main_content).send()
def send_email_for_recurring_invoice(self, inv_id, contracts):
mail_content = _(
"<h3>Reminder Recurrent Payment!</h3>"
"<br/>Hi %s, <br/> This is to remind you that the "
"recurrent payment for the "
"rental contract has to be done."
"Please make the payment at the earliest."
"<br/>"
"<br/>"
"Please find the details below:"
"<br/>"
"<br/>"
"<table>"
"<tr>"
"<td>Amount <td/>"
"<td> %s<td/>"
"<tr/>"
"<tr>"
"<td>Due Date <td/>"
"<td> %s<td/>"
"<tr/>"
"<tr>"
"<td>Responsible Person <td/>"
"<td> %s, %s<td/>"
"<tr/>"
"<table/>"
) % (
contracts.partner_id.name,
inv_id.amount_total,
date.today(),
inv_id.user_id.name,
inv_id.user_id.mobile,
)
main_content = {
"subject": "Reminder Recurrent Payment!",
"author_id": contracts.env.user.partner_id.id,
"body_html": mail_content,
"email_to": contracts.partner_id.email,
}
self.env["mail.mail"].create(main_content).send()
def create_invoice(self):
inv_obj = self.env["account.move"]
recurring_obj = self.env["product.rental.line"]
inv_line = []
today = date.today()
journal_id = (
self.env["account.journal"]
.sudo()
.search(
[("type", "=", "sale"), ("company_id", "=", self.company_id.id)],
limit=1,
)
)
for contracts in self.search([]):
if not contracts.first_invoice_created:
contracts.first_invoice_created = True
supplier = contracts.partner_id
account_id = self.env["account.account"].search(
[
("code", "like", "708000"),
("company_id", "=", self.company_id.id),
]
)
if not account_id:
user_type_id = self.env.ref("account.data_account_type_revenue")
account_id = self.env["account.account"].create(
{
"code": "708000",
"name": "Location",
"company_id": self.company_id.id,
"user_type_id": user_type_id.id,
}
)
for each_product in contracts.product_contract_lines_ids:
if each_product.price_based == "per_hour":
total_qty = each_product.enter_hour
else:
total_qty = each_product.enter_days
inv_line_data = (
0,
0,
{
"name": each_product.product_id.name or "Deposit",
"product_id": each_product.product_id.id or False,
"product_id": each_product.product_id.id or False,
"account_id": account_id.id,
"price_unit": each_product.price * total_qty or 0.0,
"quantity": each_product.qty_needed,
"enter_hour": each_product.enter_hour,
"enter_days": each_product.enter_days,
"tax_ids": [(6, 0, each_product.tax_id.ids)],
},
)
inv_line.append(inv_line_data)
if self.extra_charges:
extra_charge_p_id = self.env.ref(
"product_rental_bookings.extra_charge_product_id"
)
extra_charge_inv_line = (
0,
0,
{
"name": extra_charge_p_id.name,
"product_id": extra_charge_p_id.id or False,
"price_unit": self.extra_charges,
"account_id": account_id.id,
"quantity": 1.0,
},
)
inv_line.append(extra_charge_inv_line)
inv_data = {
"move_type": "out_invoice",
"amount_residual": self.total_amount,
"currency_id": self.env.company.currency_id.id,
"journal_id": journal_id.id,
"company_id": self.env.company.id,
"partner_id": supplier.id,
"invoice_date_due": self.to_date,
"invoice_origin": contracts.name,
"contract_id": self.id,
"is_hours": self.is_hours,
"is_days": self.is_days,
"rental_order_id": self.rental_id.id,
"invoice_line_ids": inv_line,
}
bokeh = self.env["ir.module.module"].search(
[("name", "in", ["l10n_in", "l10n_in_purchase", "l10n_in_sale"])],
limit=1,
)
if bokeh and bokeh.state == "installed":
inv_data.update(
{
"l10n_in_gst_treatment": supplier.l10n_in_gst_treatment
or "unregistered",
}
)
inv_id = inv_obj.create(inv_data)
inv_id.action_post()
recurring_data = {
"name": "demo",
"date_today": today,
"rental_number": contracts.id,
"recurring_amount": contracts.first_payment,
"invoice_number": inv_id.id,
"invoice_ref": inv_id.id,
}
recurring_obj.create(recurring_data)
# self.send_email_for_firstpayment(inv_id, contracts)
if inv_id:
return {
"name": _("Account Move"),
"view_mode": "form",
"view_id": self.env.ref("account.view_move_form").id,
"view_type": "tree,form",
"res_model": "account.move",
"type": "ir.actions.act_window",
"res_id": inv_id.id,
}
@api.model
def scheduler_manage_invoice(self):
journal_id = self.env["account.move"].default_get(["journal_id"])["journal_id"]
inv_obj = self.env["account.move"]
recurring_obj = self.env["product.rental.line"]
_inv_line_data = {}
today = date.today()
for contracts in self.search([]):
account_id = self.env["account.account"].search(
[
("code", "like", "708000"),
("company_id", "=", contracts.company_id.id),
]
)
if not account_id:
user_type_id = self.env.ref("account.data_account_type_revenue")
account_id = self.env["account.account"].create(
{
"code": "708000",
"name": "Location",
"company_id": contracts.company_id.id,
"user_type_id": user_type_id.id,
}
)
start_date = datetime.strptime(str(contracts.from_date), "%Y-%m-%d").date()
end_date = datetime.strptime(str(contracts.to_date), "%Y-%m-%d").date()
if end_date >= date.today():
is_recurring = 0
if contracts.cost_frequency == "daily":
is_recurring = 1
elif contracts.cost_frequency == "weekly":
week_days = (date.today() - start_date).days
if week_days % 7 == 0 and week_days != 0:
is_recurring = 1
elif contracts.cost_frequency == "monthly":
if (
start_date.day == date.today().day
and start_date != date.today()
):
is_recurring = 1
elif contracts.cost_frequency == "yearly":
if (
start_date.day == date.today().day
and start_date.month == date.today().month
and start_date != date.today()
):
is_recurring = 1
if (
is_recurring == 1
and contracts.cost_frequency != "no"
and contracts.state != "expire"
and contracts.state != "close"
and contracts.state != "futur"
and contracts.first_invoice_created == True
):
inv_line = []
supplier = contracts.partner_id
line_len = len(contracts.product_contract_lines_ids)
for each_product in contracts.product_contract_lines_ids:
unit_price = contracts.cost_generated / line_len
inv_line_data = (
0,
0,
{
"product_id": each_product.product_id.id,
"name": each_product.product_id.name,
"product_id": each_product.product_id.id,
"account_id": account_id.id,
"price_unit": float(unit_price),
"quantity": 1,
"exclude_from_invoice_tab": False,
},
)
inv_line.append(inv_line_data)
inv_data = {
"type": "out_invoice",
"currency_id": contracts.account_type.company_id.currency_id.id,
"journal_id": journal_id,
"company_id": contracts.account_type.company_id.id,
"name": supplier.name,
"partner_id": supplier.id,
"invoice_date_due": contracts.to_date,
"invoice_origin": contracts.name,
"contract_id": contracts.id,
"invoice_line_ids": inv_line,
"is_hours": contracts.is_hours,
"is_days": contracts.is_days,
}
inv_id = inv_obj.create(inv_data)
payment_id = self.env["account.payment"].create(
{
"payment_type": "inbound",
"partner_type": "supplier",
"partner_id": supplier.id,
"amount": inv_id.amount_total,
"journal_id": journal_id,
"payment_date": date.today(),
"payment_method_id": "1",
"communication": inv_id.name,
}
)
recurring_data = {
"name": "demo",
"date_today": today,
"rental_number": contracts.id,
"recurring_amount": contracts.cost_generated,
"invoice_number": inv_id.id,
"invoice_ref": inv_id.id,
}
recurring_obj.create(recurring_data)
# self.send_email_for_recurring_invoice(inv_id, contracts)
else:
inv_line = []
if (
not contracts.first_invoice_created
and contracts.state != "futur"
and contracts.state != "expired"
):
contracts.first_invoice_created = True
supplier = contracts.partner_id
for each_product in contracts.product_contract_lines_ids:
if each_product.price_based == "per_day":
total_qty = each_product.enter_days
else:
total_qty = each_product.enter_hour
inv_line_data = (
0,
0,
{
"product_id": each_product.product_id.id,
"name": each_product.product_id.name,
"product_id": each_product.product_id.id,
"account_id": supplier.property_account_payable_id.id,
"price_unit": each_product.price,
"quantity": total_qty,
"tax_ids": [(6, 0, each_product.tax_id.ids)],
"exclude_from_invoice_tab": False,
},
)
inv_line.append(inv_line_data)
inv_data = {
"name": supplier.name,
"partner_id": supplier.id,
"currency_id": contracts.account_type.company_id.currency_id.id,
"journal_id": journal_id,
"invoice_origin": contracts.name,
"company_id": contracts.account_type.company_id.id,
"invoice_date_due": self.to_date,
"invoice_line_ids": inv_line,
}
inv_id = inv_obj.create(inv_data)
recurring_data = {
"name": "demo",
"date_today": today,
"rental_number": contracts.id,
"recurring_amount": contracts.first_payment,
"invoice_number": inv_id.id,
"invoice_ref": inv_id.id,
}
recurring_obj.create(recurring_data)
# self.send_email_for_firstpayment(inv_id, contracts)
@api.model
def shedule_manage_contract(self):
date_today = fields.Date.from_string(fields.Date.today())
in_fifteen_days = fields.Date.to_string(date_today + relativedelta(days=+15))
nearly_expired_contracts = self.search(
[("state", "=", "open"), ("to_date", "<", in_fifteen_days)]
)
res = {}
for contract in nearly_expired_contracts:
if contract.partner_id.id in res:
res[contract.partner_id.id] += 1
else:
res[contract.partner_id.id] = 1
# contract.notification_email_for_expire_contract(contract)
nearly_expired_contracts.write({"state": "diesoon"})
expired_contracts = self.search(
[("state", "!=", "expired"), ("to_date", "<", fields.Date.today())]
)
expired_contracts.write({"state": "expired"})
futur_contracts = self.search(
[
("state", "not in", ["futur", "closed"]),
("from_date", ">", fields.Date.today()),
]
)
futur_contracts.write({"state": "futur"})
now_running_contracts = self.search(
[("state", "=", "futur"), ("from_date", "<=", fields.Date.today())]
)
now_running_contracts.write({"state": "open"})
@api.model
def run_scheduler(self):
self.shedule_manage_contract()
self.scheduler_manage_invoice()
class productConLines(models.Model):
_name = "product.contract.lines"
_description = "Product Rental Contract Lines"
product_id = fields.Many2one("product.product", string="product Name")
price_based = fields.Selection(
[("per_day", "Day"), ("per_hour", "Hour"), ("per_session", "Session")],
default="per_day",
string="Based On",
)
enter_hour = fields.Float(string="Hour")
enter_days = fields.Float(string="Days")
price = fields.Monetary(string="Price")
total = fields.Monetary(string="Total")
product_contract_id = fields.Many2one("rental.product.contract", string="Contract")
tax_id = fields.Many2many("account.tax", "product_contract_tax_rel", string="Tax")
sub_total = fields.Monetary(string="Sub Total", compute="_get_subtotal", store=True)
price_tax = fields.Float(
compute="_get_subtotal", string="Taxes", readonly=True, store=True
)
price_total = fields.Monetary(
compute="_get_subtotal", string="Total ", readonly=True, store=True
)
description = fields.Char(string="Description")
currency_id = fields.Many2one(
"res.currency",
related="product_contract_id.currency_id",
store=True,
readonly=True,
)
qty_needed = fields.Integer(string="Quantity", default=1)
@api.depends("product_id", "enter_hour", "enter_days", "price", "tax_id")
def _get_subtotal(self):
for line in self:
if line.price_based == "per_day":
qty = line.enter_days * line.qty_needed
elif line.price_based == "per_session":
qty = line.qty_needed
else:
qty = line.enter_hour * line.qty_needed
print("\n\n\n\n\n\n------>", qty)
taxes = line.tax_id.compute_all(
qty, line.product_contract_id.currency_id, line.price
)
line.update(
{
"price_tax": sum(
t.get("amount", 0.0) for t in taxes.get("taxes", [])
),
"price_total": taxes["total_included"],
"sub_total": taxes["total_excluded"],
}
)
class ProductRentalLine(models.Model):
_name = "product.rental.line"
_description = "Rental Lines"
name = fields.Char(string="Name")
date_today = fields.Date("Date")
recurring_amount = fields.Float("Amount")
rental_number = fields.Many2one("rental.product.contract", string="Rental Number")
payment_info = fields.Char(
compute="paid_info", string="Payment Stage", default="draft"
)
auto_generated = fields.Boolean("Automatically Generated", readonly=True)
invoice_number = fields.Integer(string="Invoice ID")
invoice_ref = fields.Many2one("account.move", string="Invoice Ref")
@api.depends("payment_info")
def paid_info(self):
for record in self:
if self.env["account.move"].browse(record.invoice_number):
record.payment_info = (
self.env["account.move"].browse(record.invoice_number).state
)
else:
record.payment_info = "Record Deleted"
class CustomerDocument(models.Model):
_name = "customer.document"
_description = "Customer Document"
name = fields.Binary(string="Document")
id_number = fields.Char(string="ID Number")
contract_id = fields.Many2one("rental.product.contract", string="Conrtract")
class RentalPolicy(models.Model):
_name = "rental.policy"
_description = "Rental Policy"
contract_id = fields.Many2one("rental.product.contract", string="Contract")
from_date = fields.Date(string="From Date")
to_date = fields.Date(string="To Date")
policy_charged = fields.Float(string="Charge(In Percentage)")

View File

@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class RentalProductLogs(models.Model):
_name = "rental.product.logs"
_description = "product Products Logs"
_rec_name = "product_id"
product_id = fields.Many2one("product.product", string="Product")
customer_id = fields.Many2one("res.partner", string="Customer")
from_date = fields.Date(string="From Date")
to_date = fields.Date(string="To Date")
company_id = fields.Many2one(
"res.company", string="Company", default=lambda self: self.env.user.company_id
)

View File

@@ -0,0 +1,91 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class RentalProductOperation(models.Model):
_name = "rental.product.operation"
_description = "product Products Operation"
name = fields.Char(string="Operation Types Name", required=True, translate=True)
color = fields.Integer(string="Color")
rental_move_type = fields.Selection(
[("outgoing", "Customers"), ("incoming", "Return"), ("internal", "Internal")],
string="Types of Operation",
required=True,
default="outgoing",
)
source_location = fields.Many2one("stock.location", string="Source Location")
destination_location = fields.Many2one(
"stock.location", string="Destination Location"
)
location_id = fields.Many2one("stock.location", string="Location")
state = fields.Selection(
[
("ready", "Ready"),
("on_rent", "On Rent"),
("service", "Service"),
("done", "Done"),
]
)
count_operation_ready = fields.Integer(compute="_compute_operation_count")
count_operation_on_rent = fields.Integer(compute="_compute_operation_count")
count_operation_service = fields.Integer(compute="_compute_operation_count")
operation_type_id = fields.Many2one(
"rental.product.operation", string="Operation Type"
)
company_id = fields.Many2one(
"res.company", string="Company", default=lambda self: self.env.user.company_id
)
rental_move_type = fields.Selection(
[("outgoing", "Customers"), ("incoming", "Return"), ("internal", "Internal")],
string="Types of Operation",
required=True,
default="internal",
)
def _compute_operation_count(self):
for each in self:
ready_state = self.env["stock.picking"].search_count(
[
("state", "in", ["draft"]),
("location_id", "=", each.location_id.id),
("is_rental", "=", True),
]
)
each.count_operation_ready = ready_state
on_rent_state = self.env["stock.picking"].search_count(
[
("location_id", "=", each.location_id.id),
("state", "=", "confirmed"),
("is_rental", "=", True),
]
)
each.count_operation_on_rent = on_rent_state
service_state = self.env["stock.picking"].search_count(
[
("state", "=", "assigned"),
("location_id", "=", each.location_id.id),
("is_rental", "=", True),
]
)
each.count_operation_service = service_state
def get_action_operation(self):
if self.rental_move_type == "outgoing":
state = ["draft"]
elif self.rental_move_type == "incoming":
state = ["confirmed"]
elif self.rental_move_type == "internal":
state = ["assigned"]
action_id = self.env.ref(
"product_rental_bookings.action_rental_product_move"
).read()[0]
action_id["context"] = {"default_rental_move_type": self.rental_move_type}
action_id["domain"] = [
("state", "in", state),
("rental_move_type", "=", self.rental_move_type),
("location_id", "in", self.location_id.ids),
]
return action_id

View File

@@ -0,0 +1,866 @@
# -*- coding: utf-8 -*-
from datetime import timedelta, date, datetime
import pytz
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
class PaymentTransaction(models.Model):
_inherit = "payment.transaction"
@api.model
def _compute_reference_prefix(self, values):
prefix = super(PaymentTransaction, self)._compute_reference_prefix(values)
if not prefix and values:
prefix = "Rental Order"
return prefix
def render_rental_button(self, order, submit_txt=None, render_values=None):
values = {
"partner_id": order.partner_shipping_id.id or order.partner_invoice_id.id,
"billing_partner_id": order.partner_invoice_id.id,
"type": "form_save",
}
if render_values:
values.update(render_values)
self._log_payment_transaction_sent()
return (
self.acquirer_id.with_context(
submit_class="btn btn-primary", submit_txt=submit_txt or _("Pay Now")
)
.sudo()
.render(
self.reference,
order.total_amount,
order.currency_id.id,
values=values,
)
)
class RentalProductOrder(models.Model):
_name = "rental.product.order"
_description = "product Product Order"
_rec_name = "res_number"
def _default_price_list(self):
return (
self.env["product.pricelist"]
.search(
[
("company_id", "in", (False, self.env.company.id)),
("currency_id", "=", self.env.company.currency_id.id),
],
limit=1,
)
.id
)
res_number = fields.Char(string="Order number", readonly=True, default="New")
product_name = fields.Many2one("product.product", string="Product Name")
from_date = fields.Datetime(string="From Date")
date_order = fields.Datetime(string="Date From")
to_date = fields.Datetime(string="To Date")
start_date = fields.Char(string="start Date")
end_date = fields.Char(string="end Date")
customer_name = fields.Many2one("res.partner", string="Customer Name")
book_date = fields.Datetime(string="Booking Date", default=datetime.now())
account_payment_term = fields.Many2one(
"account.payment.term", string="Payment Term", required=True, default=1
)
state = fields.Selection(
[
("draft", "Draft"),
("confirm", "Confirm"),
("cancel", "Cancel"),
("close", "Close"),
],
default="draft",
)
is_invoice = fields.Boolean(string="invoice")
rental_product_ids = fields.One2many(
"product.product", "product_registration_id", string="Product"
)
is_agreement = fields.Boolean(string="Contracts Require?", default=True)
product_order_lines_ids = fields.One2many(
"product.order.line", "product_order_id", string="Order Line "
)
invoice_count = fields.Integer(compute="_invoice_total", string="Total Invoiced")
contract_count = fields.Integer(compute="_contract_total", string="Total Contract")
picking_count = fields.Integer(compute="_picking_total", string="Total Invoiced ")
stock_picking_ids = fields.One2many(
"stock.picking", "product_order_rel_id", string="Picking Id"
)
invoice_ids = fields.One2many(
"account.move", "rental_order_id", string="Invoice Id"
)
contract_ids = fields.One2many(
"rental.product.contract", "rental_id", string="Contract Id"
)
pricelist_id = fields.Many2one(
"product.pricelist", string="Pricelist", default=_default_price_list
) # _default_pricelist
extra_charges = fields.Monetary(string="Extra Charges", readonly=True)
total_amount = fields.Monetary(
string="Total Amount", compute="_compute_amount", store=True
)
taxes = fields.Float(string="Taxes", compute="_compute_amount", store=True)
untaxed_amount = fields.Monetary(
string="Untaxed Amount", compute="_compute_amount", store=True
)
amount_untaxed = fields.Monetary(string="Untaxed Amount 1")
user_id = fields.Many2one(
"res.users", string="Dealer", default=lambda self: self.env.user
)
terms_condition = fields.Text(string="Terms And Condition")
invoice_status = fields.Char(compute="get_invoice_status", string="Invoice Status")
company_id = fields.Many2one(
"res.company",
string="Company",
readonly=True,
default=lambda self: self.env.user.company_id,
)
currency_id = fields.Many2one("res.currency", related="company_id.currency_id")
count = fields.Integer(
string="Count", compute="_compute_count", store=True, invisible=True
)
is_true = fields.Boolean(string="True")
partner_shipping_id = fields.Many2one(
"res.partner", related="customer_name", string="Delivery Address"
)
partner_invoice_id = fields.Many2one(
"res.partner", "Invoicing Address", related="customer_name"
)
return_date = fields.Datetime("Return Date")
location_id = fields.Many2one("stock.location", string="Location")
is_hours = fields.Boolean(string="Hours")
is_days = fields.Boolean(string="Days")
def _create_payment_transaction(self, vals):
"""Similar to self.env['payment.transaction'].create(vals) but the values are filled with the
current sales orders fields (e.g. the partner or the currency).
:param vals: The values to create a new payment.transaction.
:return: The newly created payment.transaction record.
"""
# Try to retrieve the acquirer. However, fallback to the token's acquirer.
acquirer_id = int(vals.get("acquirer_id"))
acquirer = False
payment_token_id = vals.get("payment_token_id")
acquirer = self.env["payment.acquirer"].browse(acquirer_id)
partner = self.env["res.partner"].browse(vals.get("partner_id"))
if payment_token_id and acquirer_id:
payment_token = (
self.env["payment.token"].sudo().browse(int(payment_token_id))
)
if payment_token and payment_token.acquirer_id != acquirer:
raise ValidationError(
_("Invalid token found! Token acquirer %s != %s")
% (payment_token.acquirer_id.name, acquirer.name)
)
if payment_token and payment_token.partner_id != partner:
raise ValidationError(
_("Invalid token found! Token partner %s != %s")
% (payment_token.partner_id.name, partner.name)
)
else:
acquirer = payment_token.acquirer_id
# Check an acquirer is there.
if not acquirer_id and not acquirer:
raise ValidationError(
_("A payment acquirer is required to create a transaction.")
)
if not acquirer:
acquirer = self.env["payment.acquirer"].browse(acquirer_id)
# Check a journal is set on acquirer.
if not acquirer.journal_id:
raise ValidationError(
_("A journal must be specified of the acquirer %s." % acquirer.name)
)
if not acquirer_id and acquirer:
vals["acquirer_id"] = acquirer.id
vals.update(
{
"date": datetime.now(),
"amount": vals.get("amount"),
"currency_id": vals.get("currency_id"),
"partner_id": vals.get("partner_id"),
}
)
transaction = self.env["payment.transaction"].create(vals)
# Process directly if payment_token
if transaction.payment_token_id:
transaction.s2s_do_transaction()
return transaction
@api.depends("customer_name")
def _compute_count(self):
self.ensure_one()
self.count = len(self.search([("customer_name", "=", self.customer_name.id)]))
@api.depends("invoice_status")
def get_invoice_status(self):
for record in self:
record.invoice_status = ""
for invoice in record.invoice_ids:
record.invoice_status = invoice.state
@api.onchange("customer_name")
def onchange_customer(self):
self.account_payment_term = self.customer_name.property_payment_term_id.id
@api.depends("stock_picking_ids")
def _picking_total(self):
for order in self:
order.picking_count = len(order.stock_picking_ids)
@api.depends("invoice_ids")
def _invoice_total(self):
for order in self:
order.invoice_count = len(order.invoice_ids)
def convert_TZ_UTC(self, TZ_datetime):
fmt = "%Y-%m-%d %H:%M:%S"
# Current time in UTC
now_utc = datetime.now(pytz.timezone("UTC"))
# Convert to current user time zone
now_timezone = now_utc.astimezone(pytz.timezone(self.env.user.tz))
UTC_OFFSET_TIMEDELTA = datetime.strptime(
now_utc.strftime(fmt), fmt
) - datetime.strptime(now_timezone.strftime(fmt), fmt)
local_datetime = datetime.strptime(TZ_datetime, fmt)
result_utc_datetime = local_datetime + UTC_OFFSET_TIMEDELTA
return result_utc_datetime.strftime(fmt)
def action_view_order_invoices(self):
action = self.env.ref("account.action_move_out_invoice_type").read()[0]
invoices = self.mapped("invoice_ids")
if len(invoices) > 1:
action["domain"] = [("id", "in", invoices.ids)]
elif invoices:
action["views"] = [(self.env.ref("account.view_move_form").id, "form")]
action["res_id"] = invoices.id
return action
@api.depends("contract_ids")
def _contract_total(self):
for contract in self:
contract.contract_count = len(contract.contract_ids)
def action_view_order_contract(self):
action = self.env.ref(
"product_rental_bookings.action_rental_contract_view_tree"
).read()[0]
contracts = self.mapped("contract_ids")
if len(contracts) > 1:
action["domain"] = [("id", "in", contracts.ids)]
elif contracts:
action["views"] = [
(
self.env.ref(
"product_rental_bookings.rental_product_contract_form"
).id,
"form",
)
]
action["res_id"] = contracts.id
return action
@api.onchange("customer_name")
def customer_pricelist(self):
values = {
"pricelist_id": self.customer_name.property_product_pricelist
and self.customer_name.property_product_pricelist.id
or False,
}
self.update(values)
@api.model
def create(self, vals):
product_order_line = []
if vals.get("is_true"):
for order_line in vals.get("product_order_lines_ids"):
if order_line[2] and order_line[0] != 0:
product_order_line.append([0, False, order_line[2]])
elif order_line[2] and order_line[0] == 0:
product_order_line.append(order_line)
vals.update({"product_order_lines_ids": product_order_line})
sequence = self.env["ir.sequence"].next_by_code("product_registration") or _(
"Product Register"
)
vals.update({"res_number": sequence})
res = super(RentalProductOrder, self).create(vals)
from_date, to_date = self.start_end_date_global(res.from_date, res.to_date)
res.start_date = from_date
res.end_date = to_date
return res
@api.depends("product_order_lines_ids", "customer_name")
def _compute_amount(self):
"""
Compute the total amounts of the RO.
"""
for order in self:
untaxed_amount = 0.0
taxes = 0.0
for line in order.product_order_lines_ids:
untaxed_amount += line.sub_total
taxes += line.price_tax
if order.pricelist_id:
order.update(
{
"untaxed_amount": order.pricelist_id.currency_id.round(
untaxed_amount
),
"taxes": order.pricelist_id.currency_id.round(taxes),
"total_amount": untaxed_amount + taxes + order.extra_charges,
}
)
else:
order.update(
{
"untaxed_amount": untaxed_amount,
"taxes": taxes,
"total_amount": untaxed_amount + taxes + order.extra_charges,
}
)
def book(self):
self.state = "book"
@api.model
def _get_picking_type(self, company_id):
picking_type = self.env["stock.picking.type"].search(
[("code", "=", "incoming"), ("warehouse_id.company_id", "=", company_id)]
)
if not picking_type:
picking_type = self.env["stock.picking.type"].search(
[("code", "=", "incoming"), ("warehouse_id", "=", False)]
)
return picking_type[:1].id
def confirm(self):
product_order_id = []
move_ids_without_package = []
for each in self.product_order_lines_ids:
product_order_id.append((0, 0, {"product_id": each.product_id.id}))
move_ids_without_package.append(
(
0,
0,
{
"product_id": each.product_id.id,
"product_uom_qty": each.qty_needed,
"product_uom": each.product_id.uom_id.id,
"location_id": self.location_id.id
or each.product_id.location_id.id,
"location_dest_id": self.env.ref(
"stock.stock_location_customers"
).id,
"name": each.product_id.name,
"company_id": self.company_id.id,
},
)
)
stock_picking_id = self.env["stock.picking"].create(
{
"partner_id": self.customer_name.id,
"location_id": self.location_id.id,
"location_dest_id": self.env.ref("stock.stock_location_customers").id,
"rental_move_type": "outgoing",
"picking_type_id": self._get_picking_type(self.company_id.id),
"product_order_rel_id": self.id,
"is_rental": True,
"origin": self.res_number,
"move_ids_without_package": move_ids_without_package,
}
)
self.state = "confirm"
if self.is_agreement:
rental_product_contract_obj = self.env["rental.product.contract"]
product_order_id = []
for each in self.product_order_lines_ids:
product_order_id.append(
(
0,
0,
{
"product_id": each.product_id.id or "",
"price_based": each.price_based or "",
"enter_days": each.enter_days or "",
"enter_hour": each.enter_hour or "",
"price": each.price or "",
"qty_needed": each.qty_needed,
"sub_total": each.sub_total or "",
"tax_id": [(6, 0, each.tax_id.ids)],
},
)
)
self.state = "confirm"
view_id = self.env.ref(
"product_rental_bookings.rental_product_contract_form"
)
contract = rental_product_contract_obj.create(
{
"partner_id": self.customer_name.id,
"from_date": self.from_date,
"to_date": self.to_date,
"total_amount": self.total_amount,
"rental_id": self.id,
"product_contract_lines_ids": product_order_id,
"cost_frequency": "no",
"contract_date": self.book_date,
"account_payment_term": self.account_payment_term.id,
"contractor_id": self.user_id.id,
"origin": self.res_number,
"cost": 12,
"is_hours": self.is_hours,
"is_days": self.is_days,
"picking_id": stock_picking_id.id,
"company_id": self.company_id.id,
"name": "New",
}
)
return {
"name": _("product Contract"),
"type": "ir.actions.act_window",
"view_type": "form",
"view_mode": "form",
"res_model": "rental.product.contract",
"res_id": contract.id,
"view_id": view_id.id,
}
self.state = "confirm"
def action_view_invoice(self):
invoices = self.mapped("invoice_ids")
action = self.env.ref("account.action_invoice_tree1").read()[0]
if len(invoices) > 1:
action["domain"] = [("id", "in", invoices.ids)]
elif len(invoices) == 1:
action["views"] = [(self.env.ref("account.move_form").id, "form")]
action["res_id"] = invoices.ids[0]
else:
action = {"type": "ir.actions.act_window_close"}
return action
def action_view_stock_pickings(self):
pickings = self.mapped("stock_picking_ids")
return {
"name": "Pickings",
"view_mode": "tree,form",
"res_model": "stock.picking",
"domain": [("id", "in", pickings.ids)],
"res_id": self.id,
"type": "ir.actions.act_window",
}
def cancel(self):
inv_obj = self.env["account.move"]
order_id = self.env["product.order.line"].browse(int(self.id)).product_order_id
self = order_id
for contract in order_id.contract_ids:
for cancel_policy in contract.cancel_policy_ids:
if cancel_policy.from_date and cancel_policy.to_date:
if (
date.today() >= cancel_policy.from_date
and date.today() <= cancel_policy.to_date
):
invoice_browse = (
self.env["account.move"]
.sudo()
.search(
[
("contract_id", "=", contract.id),
("type", "=", "out_invoice"),
]
)
)
for each_invoice in invoice_browse:
if each_invoice.state == "draft":
invoice_line_data = []
invoice_line_data.append(
(
0,
0,
{
"product_id": self.product_name.id,
"name": "Cancel Policy " + self.res_number,
"account_id": self.customer_name.property_account_receivable_id.id,
"price_unit": (
contract.total_amount
* cancel_policy.policy_charged
)
/ 100,
"quantity": 1,
},
)
)
invoice = inv_obj.create(
{
"name": self.res_number,
"origin": self.res_number,
"partner_id": self.customer_name.id,
"type": "out_invoice",
"date_invoice": date.today(),
"reference": False,
"account_id": self.customer_name.property_account_receivable_id.id,
"invoice_line_ids": invoice_line_data,
}
)
elif each_invoice.state == "paid":
invoice_line_data = []
invoice_line_data.append(
(
0,
0,
{
"product_id": self.product_name.id,
"name": "Cancel Policy " + self.res_number,
"account_id": self.customer_name.property_account_receivable_id.id,
"price_unit": each_invoice.total_amount
- (
(
contract.total_amount
* cancel_policy.policy_charged
)
/ 100
),
"quantity": 1,
},
)
)
invoice = inv_obj.create(
{
"name": self.res_number,
"origin": self.res_number,
"partner_id": self.customer_name.id,
"type": "in_refund",
"date_invoice": date.today(),
"reference": False,
"account_id": self.customer_name.property_account_receivable_id.id,
"invoice_line_ids": invoice_line_data,
}
)
if not cancel_policy.to_date:
if date.today() >= cancel_policy.from_date:
invoice_browse = self.env["account.move"].search(
[
("contract_id", "=", contract.id),
("type", "=", "out_invoice"),
]
)
for each_invoice in invoice_browse:
if each_invoice.state == "draft":
each_invoice.state = "paid"
self.state = "cancel"
def send_product_quote(self):
"""
This is Email for send quotation product order inquiry
"""
self.ensure_one()
ir_model_data = self.env["ir.model.data"]
try:
template_id = ir_model_data.get_object_reference(
"product_rental_bookings", "email_template_product_rental"
)[1]
except ValueError:
template_id = False
try:
compose_form_id = ir_model_data.get_object_reference(
"mail", "email_compose_message_wizard_form"
)[1]
except ValueError:
compose_form_id = False
ctx = {
"default_model": "rental.product.order",
"default_res_id": self.ids[0],
"default_use_template": bool(template_id),
"default_template_id": template_id,
"mark_so_as_sent": True,
}
return {
"type": "ir.actions.act_window",
"view_type": "form",
"view_mode": "form",
"res_model": "mail.compose.message",
"views": [(compose_form_id, "form")],
"view_id": compose_form_id,
"target": "new",
"context": ctx,
}
def close(self):
view_id = self.env.ref("rental_product_rental")
return {
"name": "product Service",
"type": "ir.actions.act_window",
"view_type": "form",
"view_mode": "form",
"res_model": "wizard.product.service",
"view_id": view_id.id,
"target": "new",
}
@api.model
def start_end_date_global(self, start, end):
tz = pytz.utc
current_time = datetime.now(tz)
hour_tz = int(str(current_time)[-5:][:2])
min_tz = int(str(current_time)[-5:][3:])
sign = str(current_time)[-6][:1]
sdate = str(start)
edate = str(end)
if sign == "+":
start_date = (
datetime.strptime(sdate, "%Y-%m-%d %H:%M:%S")
+ timedelta(hours=hour_tz, minutes=min_tz)
).strftime("%Y-%m-%d %H:%M:%S")
end_date = (
datetime.strptime(edate, "%Y-%m-%d %H:%M:%S")
+ timedelta(hours=hour_tz, minutes=min_tz)
).strftime("%Y-%m-%d %H:%M:%S")
if sign == "-":
start_date = (
datetime.strptime(sdate, "%Y-%m-%d %H:%M:%S")
- timedelta(hours=hour_tz, minutes=min_tz)
).strftime("%Y-%m-%d %H:%M:%S")
end_date = (
datetime.strptime(edate, "%Y-%m-%d %H:%M:%S")
- timedelta(hours=hour_tz, minutes=min_tz)
).strftime("%Y-%m-%d %H:%M:%S")
return start_date, end_date
@api.model
def start_and_end_date_global(self, start, end):
tz = pytz.timezone(self.env.user.tz) or "UTC"
current_time = datetime.now(tz)
hour_tz = int(str(current_time)[-5:][:2])
min_tz = int(str(current_time)[-5:][3:])
sign = str(current_time)[-6][:1]
sdate = str(start)
edate = str(end)
if sign == "-":
start_date = (
datetime.strptime(sdate.split(".")[0], "%Y-%m-%d %H:%M:%S")
+ timedelta(hours=hour_tz, minutes=min_tz)
).strftime("%Y-%m-%d %H:%M:%S")
end_date = (
datetime.strptime(edate.split(".")[0], "%Y-%m-%d %H:%M:%S")
+ timedelta(hours=hour_tz, minutes=min_tz)
).strftime("%Y-%m-%d %H:%M:%S")
if sign == "+":
start_date = (
datetime.strptime(sdate.split(".")[0], "%Y-%m-%d %H:%M:%S")
- timedelta(hours=hour_tz, minutes=min_tz)
).strftime("%Y-%m-%d %H:%M:%S")
end_date = (
datetime.strptime(edate.split(".")[0], "%Y-%m-%d %H:%M:%S")
- timedelta(hours=hour_tz, minutes=min_tz)
).strftime("%Y-%m-%d %H:%M:%S")
return start_date, end_date
@api.model
def utc_to_tz(self, start, end):
start_date = pytz.utc.localize(
datetime.strptime(start, "%Y-%m-%d %H:%M:%S")
).astimezone(pytz.timezone(self.env.user.tz))
end_date = pytz.utc.localize(
datetime.strptime(end, "%Y-%m-%d %H:%M:%S")
).astimezone(pytz.timezone(self.env.user.tz))
return start_date, end_date
@api.model
def get_booking_data(self, model_id):
resourcelist = []
eventlist = []
id_list = []
product_booking = self.env["rental.product.order"].search(
[("state", "in", ["confirm"])]
)
categ_ids = self.env["product.category"].search(
[("parent_id", "child_of", int(model_id))]
)
for data in product_booking:
if data.product_order_lines_ids and data.from_date.date() >= date.today():
for line in data.product_order_lines_ids:
if (
line.product_id.categ_id.id in categ_ids.ids
and line.product_id.id not in id_list
):
resourcelist.append(
{
"id": line.product_id.id,
"building": line.product_id.categ_id.name,
"title": line.product_id.name,
"type": line.product_id.categ_id.id or False,
"product_id": line.product_id.id,
}
)
id_list.append(line.product_id.id)
if line.product_id.categ_id.id in categ_ids.ids:
if data.start_date and data.end_date:
start_date, end_date = self.utc_to_tz(
data.start_date, data.end_date
)
start = (
str(start_date.date()) + "T" + str(start_date.time())
)
end = str(end_date.date()) + "T" + str(end_date.time())
else:
start_date, end_date = self.utc_to_tz(
data.start_date, data.end_date
)
start = (
str(start_date.date()) + "T" + str(start_date.time())
)
end = str(end_date.date()) + "T" + str(end_date.time())
eventlist.append(
{
"id": line.id,
"line_id": line.id,
"resourceId": line.product_id.id,
"start": start,
"end": end,
"title": data.res_number,
"type": model_id or False,
"product_id": line.product_id.id,
}
)
product_model = self.env["product.product"].search([("is_rental", "=", True)])
for product in product_model:
if product.categ_id.id in categ_ids.ids and product.id not in id_list:
id_list.append(product.id)
resourcelist.append(
{
"id": product.id,
"building": product.categ_id.name,
"title": product.name,
"type": product.categ_id.id or False,
"product_id": product.id,
}
)
if not resourcelist:
eventlist = []
return [resourcelist, eventlist]
@api.model
def remove_event(self, line_id):
record_line_id = self.env["product.order.line"].browse(int(line_id))
if len(record_line_id.product_order_id.product_order_lines_ids.ids) == 1:
record_line_id.product_order_id.state = "cancel"
elif len(record_line_id.product_order_id.product_order_lines_ids.ids) > 1:
record_line_id.unlink()
class productOrderLine(models.Model):
_name = "product.order.line"
_description = "product Order Line"
product_order_id = fields.Many2one("rental.product.order", string="product order")
product_id = fields.Many2one("product.product", string="product")
price_based = fields.Selection(
[("per_day", "Day"), ("per_hour", "Hour"), ("per_session", "Session")],
default="per_day",
string="Based On",
)
tax_id = fields.Many2many("account.tax", "product_order_tax_rel", string="Tax")
enter_kms = fields.Float(string="KM")
enter_hour = fields.Float(string="Hour")
enter_days = fields.Float(string="Days")
price = fields.Monetary(string="Price")
total = fields.Monetary(string="Total")
sub_total = fields.Monetary(string="Sub Total", compute="_get_subtotal", store=True)
price_tax = fields.Float(compute="_get_subtotal", string="Taxes", store=True)
price_total = fields.Monetary(
compute="`_get_subtotal`", string="Total Price", store=True
)
name = fields.Char(string="Description")
currency_id = fields.Many2one(
"res.currency", related="product_order_id.currency_id"
)
qty_needed = fields.Integer(string="Quantity", default=1)
@api.onchange("price_based")
def get_price_value(self):
self.sub_total = 0.0
if self.price_based == "per_day":
self.price = self.product_id.rental_amount
self.sub_total = (
self.enter_days * self.qty_needed * self.product_id.rental_amount
)
elif self.price_based == "per_hour":
self.price = self.product_id.rental_amount_per_hour
self.sub_total = (
self.enter_hour
* self.qty_needed
* self.product_id.rental_amount_per_hour
)
else:
self.price = self.product_id.rental_amount_per_session
self.sub_total = (
self.enter_hour
* self.qty_needed
* self.product_id.rental_amount_per_session
)
@api.onchange("product_id")
def get_line_value(self):
if self.product_order_id.from_date and self.product_order_id.to_date:
if self.price_based == "per_hour":
self.price = self.product_id.rental_amount_per_hour
elif self.price_based == "per_day":
self.price = self.product_id.rental_amount
else:
self.price = self.product_id.rental_amount_per_session
else:
raise ValidationError(_("Please Select From date Or to date!!!"))
@api.depends("product_id", "price", "tax_id")
def _get_subtotal(self):
for line in self:
if line.price_based == "per_day":
qty = line.enter_days * line.qty_needed
elif line.price_based == "per_session":
qty = line.qty_needed
else:
qty = line.enter_hour * line.qty_needed
taxes = line.tax_id.compute_all(
qty, line.product_order_id.currency_id, line.price
)
line.update(
{
"price_tax": sum(
t.get("amount", 0.0) for t in taxes.get("taxes", [])
),
"price_total": taxes["total_included"],
"sub_total": taxes["total_excluded"],
}
)
line.get_line_value()
class WizardProductServiceModel(models.TransientModel):
_name = "wizard.product.service"
_description = "product Service"
_inherit = "rental.product.order"
is_damaged = fields.Boolean(string="Is Damaged")
service_location_id = fields.Many2one("stock.location", string="Service Location")
product_location_id = fields.Many2one("stock.location", string="Product Location")
def confirm_service(self):
self.state = "confirm"

View File

@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"
enabled_day_rent = fields.Boolean(string="Day Rent")
enabled_hour_rent = fields.Boolean(string="Hour Rent")
enabled_session_rent = fields.Boolean(string="Session Rent")
@api.model
def get_values(self):
res = super(ResConfigSettings, self).get_values()
get_param = self.env["ir.config_parameter"].sudo().get_param
res.update(
enabled_day_rent=get_param("enabled_day_rent"),
enabled_hour_rent=get_param("enabled_hour_rent"),
enabled_session_rent=get_param("enabled_session_rent"),
)
return res
def set_values(self):
self.env["ir.config_parameter"].sudo().set_param(
"enabled_day_rent", self.enabled_day_rent
)
self.env["ir.config_parameter"].sudo().set_param(
"enabled_hour_rent", self.enabled_hour_rent
)
self.env["ir.config_parameter"].sudo().set_param(
"enabled_session_rent", self.enabled_session_rent
)
res = super(ResConfigSettings, self).set_values()
ICPSudo = self.env["ir.config_parameter"].sudo()
ICPSudo.set_param(
"product_rental_bookings.enabled_day_rent", self.enabled_day_rent
)
ICPSudo.set_param(
"product_rental_bookings.enabled_day_rent", self.enabled_hour_rent
)
ICPSudo.set_param(
"product_rental_bookings.enabled_day_rent", self.enabled_session_rent
)
return res

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
class SessionConfigSettings(models.Model):
_name = "session.config"
_description = "Session configuration settings"
name = fields.Char("Name")
start_time = fields.Float("Start Time")
end_time = fields.Float("End Time")
@api.constrains("start_time", "end_time")
def _check_time_constraint(self):
for record in self:
if (
record.start_time < 0.0
or 24.0 < record.start_time
or record.end_time < 0.0
or 24.0 < record.end_time
):
raise ValidationError(_("Start time or End time is wrong"))
elif record.start_time > record.end_time:
raise ValidationError(_("Start time must be smaller than End time"))

View File

@@ -0,0 +1,10 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class StockMove(models.Model):
_inherit = "stock.move"
product_move_id = fields.Many2one("stock.picking", string="Product Move")
products_checked = fields.Boolean(string="Select Products")

View File

@@ -0,0 +1,163 @@
# -*- coding: utf-8 -*-
from datetime import datetime
from odoo import models, fields, api, _
from odoo.exceptions import UserError
from odoo.tests import Form
class StockPicking(models.Model):
_inherit = "stock.picking"
product_order_rel_id = fields.Many2one(
"rental.product.order", string="product Order"
)
contract_ids = fields.One2many(
"rental.product.contract", "picking_id", string="Contract Id"
)
is_rental = fields.Boolean(string="Rental Move")
product_move_line_id = fields.One2many(
"stock.move", "product_move_id", string="Move Lines"
)
rental_move_type = fields.Selection(
[("outgoing", "Customers"), ("incoming", "Return"), ("internal", "Internal")],
string="Types of Operation",
required=True,
default="outgoing",
)
def delivery(self):
move_ids_without_package = []
if all([each.products_checked for each in self.move_ids_without_package]):
self.action_confirm()
self.action_assign()
res = self.button_validate()
if isinstance(res, bool):
pass
else:
Form(
self.env["stock.immediate.transfer"].with_context(res["context"])
).save().process()
for each in self.move_ids_without_package.filtered(
lambda l: l.products_checked
):
move_ids_without_package.append(
(
0,
0,
{
"product_id": each.product_id.id,
"products_checked": each.products_checked,
"name": each.product_id.name,
"product_uom": each.product_uom.id,
"product_uom_qty": each.product_uom_qty,
"location_id": self.env.ref(
"stock.stock_location_customers"
).id,
"location_dest_id": each.picking_id.location_id.id,
},
)
)
stock_picking_receipt = self.env["stock.picking"].create(
{
"partner_id": self.partner_id.id,
"location_id": self.env.ref("stock.stock_location_customers").id,
"rental_move_type": "incoming",
"location_dest_id": self.location_id.id,
"product_order_rel_id": self.product_order_rel_id.id,
"picking_type_id": self.picking_type_id.id,
"is_rental": True,
"origin": self.origin,
"move_ids_without_package": move_ids_without_package,
}
)
stock_picking_receipt.state = "confirmed"
return stock_picking_receipt
elif any([each.products_checked for each in self.move_ids_without_package]):
deliver_move_id = self.copy()
for each in self.move_ids_without_package:
if not each.product_id:
self.unlink()
for each in self.product_move_line_id.filtered(
lambda l: l.products_checked
):
move_ids_without_package.append(
(
0,
0,
{
"product_id": each.product_id.id,
"products_checked": each.products_checked,
"name": each.product_id.name,
"product_uom_qty": each.product_uom_qty,
"product_uom": each.product_uom.id,
"location_id": each.picking_id.location_id.id,
"location_dest_id": self.env.ref(
"stock.stock_location_customers"
).id,
},
)
)
each.unlink()
deliver_move_id.write(
{
"rental_move_type": "incoming",
"state": "confirmed",
"move_ids_without_package": move_ids_without_package,
}
)
return deliver_move_id
else:
raise UserError(_("Please Select Some Product to Move"))
def incoming(self):
self.write({"rental_move_type": "incoming"})
product_order_id = []
for each in self.move_ids_without_package:
product_order_id.append(
(
0,
0,
{
"product_id": each.product_id.id,
"products_checked": each.products_checked,
"name": each.product_id.name,
"product_uom": each.product_uom.id,
"location_id": each.picking_id.location_id.id,
"location_dest_id": self.env.ref(
"stock.stock_location_customers"
).id,
},
)
)
self.env["rental.product.logs"].create(
{
"customer_id": self.partner_id.id,
"product_id": each.product_id.id,
"from_date": self.scheduled_date,
"to_date": self.scheduled_date,
}
)
order_id = self.env["rental.product.order"].search(
[("res_number", "=", self.origin)]
)
for each_order in order_id:
each_order.state = "close"
each_order.return_date = datetime.now()
self.state = "assigned"
def move(self):
self.state = "done"
self.action_confirm()
self.action_assign()
res = self.button_validate()
if isinstance(res, bool):
pass
else:
Form(
self.env["stock.immediate.transfer"].with_context(res["context"])
).save().process()