391 lines
13 KiB
Python
391 lines
13 KiB
Python
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
|
# this repository contains the full copyright notices and license terms.
|
|
from __future__ import with_statement
|
|
from datetime import timedelta, datetime, time, date
|
|
from collections import OrderedDict
|
|
|
|
from trytond.model import Workflow, ModelView, ModelSQL, fields
|
|
from trytond.pyson import Eval, If, In, Get
|
|
from trytond.transaction import Transaction
|
|
from trytond.pool import Pool
|
|
|
|
STATES = {
|
|
'readonly': (Eval('state') != 'draft')
|
|
}
|
|
|
|
|
|
class Booking(Workflow, ModelSQL, ModelView):
|
|
'Rental Booking'
|
|
__name__ = 'rental.booking'
|
|
_rec_name = 'number'
|
|
number = fields.Char('Number', readonly=True)
|
|
equipment = fields.Many2One('maintenance.equipment', 'Equipment',
|
|
states=STATES)
|
|
type_document = fields.Selection([
|
|
('', ''),
|
|
('passport', 'Passport'),
|
|
('driver_license', 'Driver License'),
|
|
('medicare_card', 'Medicare Card'),
|
|
], 'Document Type', states=STATES)
|
|
doc_number = fields.Char('Doc. Number', required=True)
|
|
party = fields.Many2One('party.party', 'Customer',
|
|
states=STATES)
|
|
first_name = fields.Char('First Name', required=True)
|
|
last_name = fields.Char('Last Name', required=True)
|
|
mobile = fields.Char('Mobile', required=True)
|
|
email = fields.Char('Email', required=True)
|
|
signature = fields.Char('signature')
|
|
subdivision = fields.Many2One('country.subdivision', 'Subdivision')
|
|
address = fields.Char('Address', states=STATES)
|
|
city = fields.Char('City', states=STATES)
|
|
suburb = fields.Char('Suburb', states=STATES)
|
|
post_code = fields.Char('Post Code', states=STATES)
|
|
company = fields.Many2One('company.company', 'Company', required=True,
|
|
states=STATES, domain=[
|
|
('id', If(In('company', Eval('context', {})), '=', '!='),
|
|
Get(Eval('context', {}), 'company', 0))
|
|
])
|
|
product = fields.Many2One('product.product', 'Product', domain=[
|
|
('template.type', '=', 'assets')
|
|
], states=STATES)
|
|
brand = fields.Many2One('maintenance.equipment.brand', 'Brand')
|
|
lapse_time = fields.Integer('Lapse Time', states=STATES)
|
|
booking_date = fields.Date('Booking Date', states=STATES)
|
|
start_date = fields.DateTime('Start Date', states=STATES)
|
|
end_date = fields.DateTime('End Date', states=STATES)
|
|
comment = fields.Char('Comment', states=STATES)
|
|
signature = fields.Char('Signature', states=STATES)
|
|
notification_pickup = fields.Boolean('SMS Notification Pickup')
|
|
state = fields.Selection([
|
|
('draft', 'Draft'),
|
|
('booking', 'Booking'),
|
|
('processed', 'Processed'),
|
|
('cancelled', 'Cancelled'),
|
|
], 'State', readonly=True, required=True)
|
|
state_string = state.translated('state')
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(Booking, cls).__setup__()
|
|
cls._order = [
|
|
('booking_date', 'DESC'),
|
|
('number', 'DESC'),
|
|
]
|
|
cls._transitions |= set((
|
|
('draft', 'cancelled'),
|
|
('booking', 'cancelled'),
|
|
('cancelled', 'booking'),
|
|
('draft', 'booking'),
|
|
('booking', 'draft'),
|
|
('booking', 'processed')
|
|
))
|
|
cls._buttons.update({
|
|
'draft': {
|
|
'invisible': Eval('state').in_(['processed', 'draft']),
|
|
},
|
|
'cancel': {
|
|
'invisible': Eval('state').in_(['cancelled', 'processed']),
|
|
},
|
|
'booking': {
|
|
'invisible': Eval('state') != 'draft',
|
|
},
|
|
'process': {
|
|
'invisible': Eval('state') != 'booking',
|
|
},
|
|
'send_notification_pickup': {
|
|
'invisible': Eval('notification_pickup'),
|
|
}
|
|
})
|
|
|
|
@classmethod
|
|
def copy(cls, records, default=None):
|
|
if default is None:
|
|
default = {}
|
|
default = default.copy()
|
|
default['number'] = None
|
|
default['state'] = 'draft'
|
|
new_records = []
|
|
for record in records:
|
|
new_record, = super(Booking, cls).copy(
|
|
[record], default=default
|
|
)
|
|
new_records.append(new_record)
|
|
return new_records
|
|
|
|
@classmethod
|
|
def search_rec_name(cls, name, clause):
|
|
if clause[1].startswith('!') or clause[1].startswith('not '):
|
|
bool_op = 'AND'
|
|
else:
|
|
bool_op = 'OR'
|
|
return [bool_op, ('mobile',) + tuple(clause[1:])]
|
|
|
|
@staticmethod
|
|
def default_company():
|
|
return Transaction().context.get('company') or None
|
|
|
|
@staticmethod
|
|
def default_booking_date():
|
|
Date = Pool().get('ir.date')
|
|
return Date.today()
|
|
|
|
@staticmethod
|
|
def default_state():
|
|
return 'draft'
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('draft')
|
|
def draft(cls, records):
|
|
print("¡Transición a estado 'draft' realizada con éxito!")
|
|
pass
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('cancelled')
|
|
def cancel(cls, records):
|
|
pass
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('booking')
|
|
def booking(cls, records):
|
|
cls.set_number(records)
|
|
# for rec in records:
|
|
# rec.send_emails()
|
|
|
|
# res = {
|
|
# 'status': 'success',
|
|
# 'msg': 'Booking succesful, please check your mail for more details!'
|
|
# }
|
|
# return res
|
|
|
|
# @classmethod
|
|
# def create(cls, vlist):
|
|
# bookings = super(Booking, cls).create(vlist)
|
|
# print('paso por aca')
|
|
|
|
# for boo in bookings:
|
|
# boo.send_email_confirmation()
|
|
# return bookings
|
|
|
|
def send_email_confirmation(self):
|
|
print(self, "self")
|
|
pool = Pool()
|
|
config = pool.get('rental.configuration')(1)
|
|
Template = pool.get('email.template')
|
|
return Template.send(config.email_booking_customer, self, self.email)
|
|
# return Template.send(config.email_booking_customer, self, self.email, attach=True)
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
def send_notification_pickup(cls, records):
|
|
for record in records:
|
|
record.send_sms_pickup()
|
|
cls.write([record], {'notification_pickup': True})
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
@Workflow.transition('processed')
|
|
def process(cls, records):
|
|
|
|
for record in records:
|
|
record.create_service()
|
|
record.send_emails()
|
|
|
|
@fields.depends('lapse_time', 'start_date', 'end_date')
|
|
def on_change_with_end_date(self, name=None):
|
|
config = Pool().get('rental.configuration')(1)
|
|
if self.start_date and self.lapse_time and config.rental_uom:
|
|
delta = timedelta(days=self.lapse_time)
|
|
if config.rental_uom.symbol == 'h':
|
|
delta = timedelta(hours=self.lapse_time)
|
|
|
|
end_date = self.start_date + delta
|
|
return end_date
|
|
|
|
@classmethod
|
|
def get_hours_available(cls, args):
|
|
pool = Pool()
|
|
config = pool.get('rental.configuration')(1)
|
|
User = pool.get('res.user')
|
|
Company = pool.get('company.company')
|
|
transaction = Transaction()
|
|
|
|
product_id = args.get('product')
|
|
start_date = args.get('start_date')
|
|
user_id = args.get('user')
|
|
if not all([product_id, start_date, user_id]):
|
|
return []
|
|
|
|
user = User(user_id)
|
|
if config.booking_start_time:
|
|
start_tm = config.booking_start_time
|
|
else:
|
|
start_tm = time(0, 0)
|
|
if config.booking_end_time:
|
|
end_tm = config.booking_end_time
|
|
else:
|
|
end_tm = time(23, 59)
|
|
|
|
res = OrderedDict()
|
|
for value in range(start_tm.hour, end_tm.hour):
|
|
fmt_value = time(value, 0)
|
|
fmt_value = fmt_value.strftime('%I:%M %p')
|
|
|
|
res[value] = {
|
|
'id': value,
|
|
'hour': fmt_value,
|
|
'status': 'available'
|
|
}
|
|
|
|
new_date = datetime.strptime(start_date, '%Y-%m-%d').date()
|
|
|
|
ctx = transaction.context.get('user')
|
|
start_date = datetime.combine(new_date, start_tm)
|
|
end_date = datetime.combine(new_date, end_tm)
|
|
with transaction.set_context(ctx):
|
|
start_date = Company.convert_timezone(start_date, True, user.company.id)
|
|
end_date = Company.convert_timezone(end_date, True, user.company.id)
|
|
|
|
bookings = cls.search([
|
|
('product', '=', product_id),
|
|
('start_date', '>=', start_date),
|
|
('start_date', '<=', end_date),
|
|
('state', 'in', ['draft', 'booking', 'processed']),
|
|
])
|
|
|
|
for bk in bookings:
|
|
with transaction.set_context(ctx):
|
|
start_date = Company.convert_timezone(bk.start_date, False, user.company.id)
|
|
hour = start_date.time().hour
|
|
res[hour]['status'] = 'not_available'
|
|
|
|
return res.values()
|
|
|
|
def send_sms_pickup(self):
|
|
pool = Pool()
|
|
config = pool.get('rental.configuration')(1)
|
|
template_sms = config.sms_customer_pickup
|
|
if not template_sms:
|
|
return
|
|
|
|
template_sms.server.send_message(self.mobile, template_sms.content)
|
|
|
|
def send_emails(self):
|
|
pool = Pool()
|
|
config = pool.get('rental.configuration')(1)
|
|
Template = pool.get('email.template')
|
|
print("template", config.email_rental_customer )
|
|
print("selft", self )
|
|
print("self.email", self.email )
|
|
try:
|
|
response = Template.send(config.email_rental_customer, self, self.email)
|
|
if response.status_code == 202:
|
|
print('correo enviado')
|
|
else:
|
|
response.json()
|
|
Template.send(config.email_rental_company, self, self.company.party.email)
|
|
|
|
except Exception as e:
|
|
print(e)
|
|
|
|
def send_emails_asignature(self):
|
|
pool = Pool()
|
|
config = pool.get('rental.configuration')(1)
|
|
Template = pool.get('email.template')
|
|
return Template.send(config.emaild_rental_customer, self, self.email)
|
|
|
|
|
|
def create_service(self):
|
|
print(self, "paso por aca para crear el servicio")
|
|
pool = Pool()
|
|
Party = pool.get('party.party')
|
|
Rental = pool.get('rental.service')
|
|
Config = pool.get('rental.configuration')
|
|
Equipment = pool.get('maintenance.equipment')
|
|
Item = pool.get('product.check_list_item')
|
|
ProductCheckList = pool.get('rental.service.product_check_list')
|
|
config = Config(1)
|
|
|
|
values = {
|
|
'name': self.first_name + ' ' + self.last_name,
|
|
'id_number': self.doc_number,
|
|
'addresses': [('create', [{
|
|
'street': self.address,
|
|
}])],
|
|
'contact_mechanisms': [
|
|
('create', [
|
|
{'type': 'email', 'value': self.email},
|
|
{'type': 'mobile', 'value': self.mobile},
|
|
])
|
|
]
|
|
}
|
|
|
|
if hasattr(Party, 'first_name') and hasattr(Party, 'last_name'):
|
|
values['first_name'] = self.first_name
|
|
values['last_name'] = self.last_name
|
|
|
|
party, = Party.create([values])
|
|
|
|
if not config.default_service:
|
|
return
|
|
|
|
values = {
|
|
'party': party.id,
|
|
'booking': self.id,
|
|
'service_product': config.default_service.id,
|
|
'photo_link_signature': self.signature,
|
|
'service_date': self.booking_date,
|
|
'start_date': date.today(),
|
|
'state': 'draft'
|
|
}
|
|
if self.product:
|
|
values['product'] = self.product.id
|
|
|
|
if self.equipment:
|
|
values['equipment'] = self.equipment.id
|
|
elif self.product:
|
|
equipments = Equipment.search([
|
|
('product', '=', self.product.id)
|
|
])
|
|
if equipments:
|
|
values['equipment'] = equipments[0].id
|
|
|
|
rental, = Rental.create([values])
|
|
|
|
def _get_item(item):
|
|
return {
|
|
'rental_service': rental.id,
|
|
'item': item.id,
|
|
'kind': item.kind,
|
|
}
|
|
|
|
items_to_create = []
|
|
for item in config.default_check_list:
|
|
items_to_create.append(_get_item(item))
|
|
childs = Item.search([
|
|
('parent', '=', item.id)
|
|
])
|
|
for child in childs:
|
|
items_to_create.append(_get_item(child))
|
|
|
|
ProductCheckList.create(items_to_create)
|
|
|
|
@classmethod
|
|
def set_number(cls, records):
|
|
'''
|
|
Fill the number field with the service sequence
|
|
'''
|
|
pool = Pool()
|
|
Config = pool.get('rental.configuration')
|
|
config = Config(1)
|
|
|
|
for record in records:
|
|
if record.number:
|
|
continue
|
|
if not config.rental_booking_sequence:
|
|
continue
|
|
number = config.rental_booking_sequence.get()
|
|
cls.write([record], {'number': number})
|