[NEW] Addons creation - product_rental_bookings
This commit is contained in:
13
product_rental_bookings/models/__init__.py
Executable file
13
product_rental_bookings/models/__init__.py
Executable 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
|
106
product_rental_bookings/models/account_move.py
Normal file
106
product_rental_bookings/models/account_move.py
Normal 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
|
15
product_rental_bookings/models/product.py
Executable file
15
product_rental_bookings/models/product.py
Executable 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)
|
368
product_rental_bookings/models/product_book.py
Executable file
368
product_rental_bookings/models/product_book.py
Executable 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"))
|
851
product_rental_bookings/models/product_contract.py
Executable file
851
product_rental_bookings/models/product_contract.py
Executable 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)")
|
17
product_rental_bookings/models/product_logs.py
Normal file
17
product_rental_bookings/models/product_logs.py
Normal 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
|
||||
)
|
91
product_rental_bookings/models/product_operation.py
Executable file
91
product_rental_bookings/models/product_operation.py
Executable 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
|
866
product_rental_bookings/models/product_order.py
Executable file
866
product_rental_bookings/models/product_order.py
Executable 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"
|
45
product_rental_bookings/models/res_config_settings.py
Executable file
45
product_rental_bookings/models/res_config_settings.py
Executable 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
|
27
product_rental_bookings/models/session_config_settings.py
Normal file
27
product_rental_bookings/models/session_config_settings.py
Normal 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"))
|
10
product_rental_bookings/models/stock_move.py
Normal file
10
product_rental_bookings/models/stock_move.py
Normal 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")
|
163
product_rental_bookings/models/stock_picking.py
Normal file
163
product_rental_bookings/models/stock_picking.py
Normal 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()
|
Reference in New Issue
Block a user