first commit

This commit is contained in:
root
2026-03-14 09:42:12 +00:00
commit 0adbd20c2c
10991 changed files with 1646955 additions and 0 deletions

View File

@@ -0,0 +1,276 @@
# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
import datetime as dt
from decimal import Decimal
from sql import Null
from trytond.model import Check, ModelSQL, ModelView, Unique, fields
from trytond.modules.product import round_price
from trytond.modules.sale_rental import to_datetime
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Eval
from trytond.report import Report
from trytond.transaction import Transaction
from trytond.wizard import Button, StateTransition, StateView, Wizard
class Rental(metaclass=PoolMeta):
__name__ = 'sale.rental'
@classmethod
def __setup__(cls):
super().__setup__()
cls._buttons.update({
'add_progress': {
'invisible': (
Eval('state').in_(['draft', 'quote'])
| ~Eval('has_returnable_lines')),
'icon': 'tryton-date',
'depends': ['state', 'has_returnable_lines'],
},
})
@classmethod
@ModelView.button_action(
'sale_rental_progress_invoice.wizard_sale_rental_add_progress')
def add_progress(cls, rentals):
pass
class RentalProgress(ModelSQL, ModelView):
__name__ = 'sale.rental.progress'
rental = fields.Many2One(
'sale.rental', "Rental",
required=True, ondelete='CASCADE', readonly=True)
date = fields.Date("Date", required=True, readonly=True)
line = fields.Many2One(
'sale.rental.line', "Line", readonly=True,
domain=[
('rental', '=', Eval('rental', -1)),
('id', 'in', Eval('lines', [])),
],
states={
'required': ~Eval('previous'),
'invisible': ~Eval('line'),
})
previous = fields.Many2One(
'sale.rental.progress', "Previous", readonly=True,
domain=[
('rental', '=', Eval('rental', -1)),
('date', '<', Eval('date', None)),
('lines', 'in', Eval('lines', [])),
],
states={
'required': ~Eval('line'),
'invisible': ~Eval('previous'),
})
lines = fields.Many2Many(
'sale.rental.line-sale.rental.progress',
'progress', 'line', "Lines", readonly=True,
domain=[
('rental', '=', Eval('rental', -1)),
])
duration = fields.Function(
fields.TimeDelta(
"Duration",
states={
'invisible': ~Eval('duration'),
}),
'on_change_with_duration')
invoice_lines = fields.One2Many(
'account.invoice.line', 'origin', "Invoice Lines", readonly=True)
@classmethod
def __setup__(cls):
super().__setup__()
cls.__access__.add('rental')
cls._order.insert(0, ('date', 'ASC'))
t = cls.__table__()
cls._sql_constraints = [
('line_unique', Unique(t, t.line),
'sale_rental_progress_invoice.'
'msg_sale_rental_progress_line_unique'),
('previous_unique', Unique(t, t.previous),
'sale_rental_progress_invoice.'
'msg_sale_rental_progress_previous_unique'),
('line_previous',
Check(t, (t.line == Null) | (t.previous == Null)),
'sale_rental_progress_invoice.'
'msg_sale_rental_progress_line_previous'),
]
@property
@fields.depends('line', 'previous')
def start(self):
if self.line:
return self.line.start
elif self.previous:
return self.previous.date
@property
@fields.depends('date')
def end(self):
return self.date
@fields.depends('rental', methods=['start', 'end'])
def on_change_with_duration(self, name=None):
if self.rental:
start = to_datetime(self.start, company=self.rental.company)
end = to_datetime(self.end, company=self.rental.company)
if start and end:
return end - start
def get_rec_name(self, name):
pool = Pool()
Lang = pool.get('ir.lang')
lang = Lang.get()
converter = self.__class__.duration.converter
duration = Report.format_timedelta(
self.duration, converter=converter, lang=lang)
rental = self.rental.rec_name
return f'{duration} @ {rental}'
def get_invoice_lines(self, line):
pool = Pool()
InvoiceLine = pool.get('account.invoice.line')
assert line in self.lines
if self.invoice_lines:
return []
tmp_line = line.__class__(
line.id, duration=self.duration, progresses=[])
duration_unit = tmp_line.duration_unit
invoice_line = InvoiceLine(invoice_type='out', type='line')
invoice_line.currency = self.rental.currency
invoice_line.company = self.rental.company
invoice_line.origin = self
invoice_line.quantity = line.quantity
invoice_line.unit = line.unit
invoice_line.product = line.product
invoice_line.unit_price = round_price(
line.unit_price * Decimal(duration_unit))
invoice_line.taxes = line.taxes
invoice_line.account = line.product.account_rental_used
return [invoice_line]
class RentalLine(metaclass=PoolMeta):
__name__ = 'sale.rental.line'
progresses = fields.Many2Many(
'sale.rental.line-sale.rental.progress',
'line', 'progress', "Progresses",
domain=[
('rental', '=', Eval('rental', -1)),
],
order=[
('progress.date', 'ASC'),
('id', None),
],
states={
'readonly': True, # to be copied on split
'invisible': ~Eval('progresses'),
})
@property
def to_invoice(self):
to_invoice = super().to_invoice
return (
to_invoice
or any(not p.invoice_lines for p in self.progresses))
@property
def start_invoice(self):
start = super().start_invoice
if self.progresses:
start = self.progresses[-1].end
return start
@property
def duration_invoice(self):
duration = super().duration_invoice
if self.progresses:
for progress in self.progresses:
if p_duration := progress.duration:
duration -= p_duration
return duration
def get_invoice_lines(self):
invoice_lines = super().get_invoice_lines()
for progress in self.progresses:
invoice_lines.extend(progress.get_invoice_lines(self))
return invoice_lines
def get_progress(self, date):
pool = Pool()
Progress = pool.get('sale.rental.progress')
actual_start = (
to_datetime(self.actual_start, company=self.company)
or dt.datetime.max)
actual_end = (
to_datetime(self.actual_end, company=self.company)
or dt.datetime.max)
datetime = to_datetime(date, company=self.company)
if actual_start < datetime < actual_end:
progress = Progress(rental=self.rental, lines=[self])
progress.date = date
if self.progresses:
progress.previous = self.progresses[-1]
else:
progress.line = self
return progress
@classmethod
def copy(cls, lines, default=None):
default = default.copy() if default is not None else {}
if not Transaction().context.get('_sale_rental_line_split'):
default.setdefault('progresses', None)
return super().copy(lines, default=default)
class RentalLine_Progress(ModelSQL):
__name__ = 'sale.rental.line-sale.rental.progress'
line = fields.Many2One(
'sale.rental.line', "Rental Line", required=True, ondelete='CASCADE')
progress = fields.Many2One(
'sale.rental.progress', "Progress", required=True, ondelete='CASCADE')
class RentalAddProgress(Wizard):
__name__ = 'sale.rental.add_progress'
start = StateView(
'sale.rental.add_progress.start',
'sale_rental_progress_invoice.'
'sale_rental_add_progress_start_view_form', [
Button("Cancel", 'end', 'tryton-cancel'),
Button("Add", 'add', 'tryton-ok', default=True),
])
add = StateTransition()
def transition_add(self):
pool = Pool()
Progress = pool.get('sale.rental.progress')
date = self.start.date
progresses = []
for rental in self.records:
for line in rental.lines:
if progress := line.get_progress(date):
progresses.append(progress)
Progress.save(progresses)
return 'end'
class RentalAddProgressStart(ModelView):
__name__ = 'sale.rental.add_progress.start'
date = fields.Date("Date", required=True)