changes
This commit is contained in:
6
fusion_rental/models/__init__.py
Normal file
6
fusion_rental/models/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
||||
from . import sale_order
|
||||
from . import sale_order_line
|
||||
from . import renewal_log
|
||||
from . import cancellation_request
|
||||
from . import stock_warehouse
|
||||
from . import res_config_settings
|
||||
123
fusion_rental/models/cancellation_request.py
Normal file
123
fusion_rental/models/cancellation_request.py
Normal file
@@ -0,0 +1,123 @@
|
||||
import uuid
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
|
||||
|
||||
class RentalCancellationRequest(models.Model):
|
||||
_name = 'rental.cancellation.request'
|
||||
_description = 'Rental Cancellation Request'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'request_date desc'
|
||||
_rec_name = 'display_name'
|
||||
|
||||
order_id = fields.Many2one(
|
||||
'sale.order',
|
||||
string="Rental Order",
|
||||
required=True,
|
||||
ondelete='cascade',
|
||||
index=True,
|
||||
)
|
||||
partner_id = fields.Many2one(
|
||||
related='order_id.partner_id',
|
||||
store=True,
|
||||
string="Customer",
|
||||
)
|
||||
request_date = fields.Datetime(
|
||||
string="Request Date",
|
||||
default=fields.Datetime.now,
|
||||
)
|
||||
requested_pickup_date = fields.Datetime(string="Requested Pickup Date")
|
||||
reason = fields.Text(string="Reason")
|
||||
state = fields.Selection(
|
||||
[
|
||||
('new', 'New'),
|
||||
('confirmed', 'Confirmed'),
|
||||
('pickup_scheduled', 'Pickup Scheduled'),
|
||||
('completed', 'Completed'),
|
||||
('rejected', 'Rejected'),
|
||||
],
|
||||
string="Status",
|
||||
default='new',
|
||||
required=True,
|
||||
tracking=True,
|
||||
)
|
||||
assigned_user_id = fields.Many2one(
|
||||
'res.users',
|
||||
string="Assigned To",
|
||||
tracking=True,
|
||||
)
|
||||
pickup_activity_id = fields.Many2one(
|
||||
'mail.activity',
|
||||
string="Pickup Activity",
|
||||
ondelete='set null',
|
||||
)
|
||||
token = fields.Char(
|
||||
string="Security Token",
|
||||
default=lambda self: uuid.uuid4().hex,
|
||||
copy=False,
|
||||
index=True,
|
||||
)
|
||||
|
||||
def _compute_display_name(self):
|
||||
for rec in self:
|
||||
rec.display_name = (
|
||||
f"{rec.order_id.name or 'New'} - {rec.partner_id.name or 'Customer'}"
|
||||
)
|
||||
|
||||
def action_confirm(self):
|
||||
"""Confirm the cancellation and stop auto-renewal."""
|
||||
self.ensure_one()
|
||||
self.order_id.write({'rental_auto_renew': False})
|
||||
self.write({'state': 'confirmed'})
|
||||
self._schedule_pickup_activity()
|
||||
self._send_cancellation_confirmation()
|
||||
|
||||
def action_schedule_pickup(self):
|
||||
"""Mark pickup as scheduled."""
|
||||
self.ensure_one()
|
||||
self.write({'state': 'pickup_scheduled'})
|
||||
|
||||
def action_complete(self):
|
||||
"""Mark the cancellation and pickup as completed."""
|
||||
self.ensure_one()
|
||||
self.write({'state': 'completed'})
|
||||
if self.pickup_activity_id and not self.pickup_activity_id.date_done:
|
||||
self.pickup_activity_id.action_done()
|
||||
|
||||
def action_reject(self):
|
||||
"""Reject the cancellation request."""
|
||||
self.ensure_one()
|
||||
self.write({'state': 'rejected'})
|
||||
|
||||
def _schedule_pickup_activity(self):
|
||||
"""Create a to-do activity on the sale order for staff to schedule pickup."""
|
||||
self.ensure_one()
|
||||
assigned_user = (
|
||||
self.assigned_user_id
|
||||
or self.order_id.user_id
|
||||
or self.env.user
|
||||
)
|
||||
activity = self.order_id.activity_schedule(
|
||||
'mail.mail_activity_data_todo',
|
||||
date_deadline=fields.Date.today(),
|
||||
summary=_(
|
||||
"Schedule rental pickup for %s",
|
||||
self.partner_id.name or self.order_id.partner_id.name,
|
||||
),
|
||||
note=_(
|
||||
"Customer has requested cancellation and pickup for rental %s. "
|
||||
"Please contact them to schedule a pickup.",
|
||||
self.order_id.name,
|
||||
),
|
||||
user_id=assigned_user.id,
|
||||
)
|
||||
self.pickup_activity_id = activity
|
||||
|
||||
def _send_cancellation_confirmation(self):
|
||||
"""Send confirmation email to the customer."""
|
||||
template = self.env.ref(
|
||||
'fusion_rental.mail_template_rental_cancellation_confirmed',
|
||||
raise_if_not_found=False,
|
||||
)
|
||||
if template:
|
||||
template.send_mail(self.order_id.id, force_send=True)
|
||||
74
fusion_rental/models/renewal_log.py
Normal file
74
fusion_rental/models/renewal_log.py
Normal file
@@ -0,0 +1,74 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class RentalRenewalLog(models.Model):
|
||||
_name = 'rental.renewal.log'
|
||||
_description = 'Rental Renewal Log'
|
||||
_order = 'create_date desc'
|
||||
_rec_name = 'display_name'
|
||||
|
||||
order_id = fields.Many2one(
|
||||
'sale.order',
|
||||
string="Rental Order",
|
||||
required=True,
|
||||
ondelete='cascade',
|
||||
index=True,
|
||||
)
|
||||
partner_id = fields.Many2one(
|
||||
related='order_id.partner_id',
|
||||
store=True,
|
||||
string="Customer",
|
||||
)
|
||||
renewal_number = fields.Integer(
|
||||
string="Renewal #",
|
||||
required=True,
|
||||
)
|
||||
previous_start_date = fields.Datetime(string="Previous Start")
|
||||
previous_return_date = fields.Datetime(string="Previous Return")
|
||||
new_start_date = fields.Datetime(string="New Start")
|
||||
new_return_date = fields.Datetime(string="New Return")
|
||||
invoice_id = fields.Many2one(
|
||||
'account.move',
|
||||
string="Invoice",
|
||||
ondelete='set null',
|
||||
)
|
||||
payment_status = fields.Selection(
|
||||
[
|
||||
('pending', 'Pending'),
|
||||
('paid', 'Paid'),
|
||||
('failed', 'Failed'),
|
||||
],
|
||||
string="Payment Status",
|
||||
default='pending',
|
||||
)
|
||||
payment_transaction_id = fields.Many2one(
|
||||
'payment.transaction',
|
||||
string="Payment Transaction",
|
||||
ondelete='set null',
|
||||
)
|
||||
renewal_type = fields.Selection(
|
||||
[
|
||||
('automatic', 'Automatic'),
|
||||
('manual', 'Manual'),
|
||||
],
|
||||
string="Renewal Type",
|
||||
required=True,
|
||||
)
|
||||
state = fields.Selection(
|
||||
[
|
||||
('draft', 'Draft'),
|
||||
('done', 'Done'),
|
||||
('failed', 'Failed'),
|
||||
('cancelled', 'Cancelled'),
|
||||
],
|
||||
string="Status",
|
||||
default='draft',
|
||||
required=True,
|
||||
)
|
||||
notes = fields.Text(string="Notes")
|
||||
|
||||
def _compute_display_name(self):
|
||||
for rec in self:
|
||||
rec.display_name = (
|
||||
f"{rec.order_id.name or 'New'} - Renewal #{rec.renewal_number}"
|
||||
)
|
||||
19
fusion_rental/models/res_config_settings.py
Normal file
19
fusion_rental/models/res_config_settings.py
Normal file
@@ -0,0 +1,19 @@
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class ResConfigSettings(models.TransientModel):
|
||||
_inherit = 'res.config.settings'
|
||||
|
||||
rental_google_review_url = fields.Char(
|
||||
string="Google Review URL",
|
||||
config_parameter='fusion_rental.google_review_url',
|
||||
help="Google Review link shown in thank-you emails after rental close. "
|
||||
"For multi-location, set per warehouse in Inventory > Configuration > Warehouses.",
|
||||
)
|
||||
rental_deposit_hold_days = fields.Integer(
|
||||
string="Deposit Hold Period (Days)",
|
||||
config_parameter='fusion_rental.deposit_hold_days',
|
||||
default=3,
|
||||
help="Number of days to hold the security deposit after pickup before "
|
||||
"processing the refund. Default is 3 days.",
|
||||
)
|
||||
1040
fusion_rental/models/sale_order.py
Normal file
1040
fusion_rental/models/sale_order.py
Normal file
File diff suppressed because it is too large
Load Diff
63
fusion_rental/models/sale_order_line.py
Normal file
63
fusion_rental/models/sale_order_line.py
Normal file
@@ -0,0 +1,63 @@
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class SaleOrderLine(models.Model):
|
||||
_inherit = 'sale.order.line'
|
||||
|
||||
is_security_deposit = fields.Boolean(
|
||||
string="Is Security Deposit",
|
||||
default=False,
|
||||
help="Marks this line as a security deposit for a rental product.",
|
||||
)
|
||||
rental_deposit_source_line_id = fields.Many2one(
|
||||
'sale.order.line',
|
||||
string="Deposit For",
|
||||
ondelete='cascade',
|
||||
help="The rental product line this deposit is associated with.",
|
||||
)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
lines = super().create(vals_list)
|
||||
deposit_vals = []
|
||||
for line in lines:
|
||||
if not line.is_rental or line.is_security_deposit:
|
||||
continue
|
||||
if not line.order_id.is_rental_order:
|
||||
continue
|
||||
deposit_amount = line.order_id._compute_deposit_amount_for_line(line)
|
||||
if deposit_amount <= 0:
|
||||
continue
|
||||
existing = line.order_id.order_line.filtered(
|
||||
lambda l: (
|
||||
l.is_security_deposit
|
||||
and l.rental_deposit_source_line_id == line
|
||||
)
|
||||
)
|
||||
if existing:
|
||||
continue
|
||||
deposit_product = line.order_id._get_deposit_product()
|
||||
deposit_vals.append({
|
||||
'order_id': line.order_id.id,
|
||||
'product_id': deposit_product.id,
|
||||
'product_uom_id': deposit_product.uom_id.id,
|
||||
'name': f"SECURITY DEPOSIT - REFUNDABLE - {line.product_id.display_name}",
|
||||
'product_uom_qty': 1,
|
||||
'price_unit': deposit_amount,
|
||||
'is_security_deposit': True,
|
||||
'rental_deposit_source_line_id': line.id,
|
||||
})
|
||||
if deposit_vals:
|
||||
super().create(deposit_vals)
|
||||
return lines
|
||||
|
||||
def unlink(self):
|
||||
deposit_lines = self.env['sale.order.line']
|
||||
for line in self:
|
||||
if line.is_rental and not line.is_security_deposit:
|
||||
deposit_lines |= line.order_id.order_line.filtered(
|
||||
lambda l: l.rental_deposit_source_line_id == line
|
||||
)
|
||||
if deposit_lines:
|
||||
deposit_lines.unlink()
|
||||
return super().unlink()
|
||||
10
fusion_rental/models/stock_warehouse.py
Normal file
10
fusion_rental/models/stock_warehouse.py
Normal file
@@ -0,0 +1,10 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class StockWarehouse(models.Model):
|
||||
_inherit = 'stock.warehouse'
|
||||
|
||||
google_review_url = fields.Char(
|
||||
string="Google Review URL",
|
||||
help="Paste the Google Review link for this location.",
|
||||
)
|
||||
Reference in New Issue
Block a user