# -*- coding: utf-8 -*-
###############################################################################
#
#    Tech-Receptives Solutions Pvt. Ltd.
#    Copyright (C) 2009-TODAY Tech-Receptives(<http://www.techreceptives.com>).
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Lesser General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Lesser General Public License for more details.
#
#    You should have received a copy of the GNU Lesser General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
###############################################################################

from odoo.osv import expression
from odoo.tools.float_utils import float_round as round
from odoo.tools import float_is_zero, float_compare, DEFAULT_SERVER_DATETIME_FORMAT
#from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.exceptions import UserError, ValidationError
from odoo import api, fields, models, _
from odoo import workflow
import time
import datetime

def _offset_format_timestamp1(src_tstamp_str, src_format, dst_format,
                               ignore_unparsable_time=True, context=None):
     """
     Convert a source timeStamp string into a destination timeStamp string,
     attempting to apply the correct offset if both the server and local
     timeZone are recognized,or no offset at all if they aren't or if
     tz_offset is false (i.e. assuming they are both in the same TZ).
 
     @param src_tstamp_str: the STR value containing the timeStamp.
     @param src_format: the format to use when parsing the local timeStamp.
     @param dst_format: the format to use when formatting the resulting
      timeStamp.
     @param server_to_client: specify timeZone offset direction (server=src
                              and client=dest if True, or client=src and
                              server=dest if False)
     @param ignore_unparsable_time: if True, return False if src_tstamp_str
                                    cannot be parsed using src_format or
                                    formatted using dst_format.
     @return: destination formatted timestamp, expressed in the destination
              timezone if possible and if tz_offset is true, or src_tstamp_str
              if timezone offset could not be determined.
     """
     if not src_tstamp_str:
         return False
     res = src_tstamp_str
     if src_format and dst_format:
         try:
             # dt_value needs to be a datetime.datetime object\
             # (so notime.struct_time or mx.DateTime.DateTime here!)
             dt_value = datetime.datetime.strptime(src_tstamp_str, src_format)
             if context.get('tz', False):
                 try:
                     import pytz
                     src_tz = pytz.timezone('UTC')
                     dst_tz = pytz.timezone(context['tz'])
                     src_dt = src_tz.localize(dt_value, is_dst=True)
                     dt_value = src_dt.astimezone(dst_tz)
                 except Exception:
                     pass
             res = dt_value.strftime(dst_format)
         except Exception:
             # Normal ways to end up here are if strptime or strftime failed
             if not ignore_unparsable_time:
                 return False
             pass
     return res

class EtourismEnterpriseFolio(models.Model):

    @api.multi
    def name_get(self):
        res = []
        disp = ''
        for rec in self:
            if rec.order_id:
                disp = str(rec.name)
                res.append((rec.id, disp))
        return res

    @api.model
    def name_search(self, name='', args=None, operator='ilike', limit=100):
        if args is None:
            args = []
        args += ([('name', operator, name)])
        mids = self.search(args, limit=100)
        return mids.name_get()

    @api.model
    def _needaction_count(self, domain=None):
        """
         Show a count of draft state folio on the menu badge.
         @param self: object pointer
        """
        return self.search_count([('state', '=', 'draft')])

    @api.model
    def _get_checkin_date(self):
        if self._context.get('tz'):
            to_zone = self._context.get('tz')
        else:
            to_zone = 'UTC'
        return _offset_format_timestamp1(time.strftime("%Y-%m-%d 15:00:00"),
                                         '%Y-%m-%d %H:%M:%S',
                                         '%Y-%m-%d %H:%M:%S',
                                         ignore_unparsable_time=True,
                                         context={'tz': to_zone})

    @api.model
    def _get_checkout_date(self):
        if self._context.get('tz'):
            to_zone = self._context.get('tz')
        else:
            to_zone = 'UTC'
        tm_delta = datetime.timedelta(days=1)
        return datetime.datetime.strptime(_offset_format_timestamp1
                                          (time.strftime("%Y-%m-%d 15:00:00"),
                                           '%Y-%m-%d %H:%M:%S',
                                           '%Y-%m-%d %H:%M:%S',
                                           ignore_unparsable_time=True,
                                           context={'tz': to_zone}),
                                          '%Y-%m-%d %H:%M:%S') + tm_delta

    @api.multi
    def copy(self, default=None):
        '''
        @param self: object pointer
        @param default: dict of default values to be set
        '''
        return super(EtourismEnterpriseFolio, self).copy(default=default)

    @api.multi
    def _invoiced(self, name, arg):
        '''
        @param self: object pointer
        @param name: Names of fields.
        @param arg: User defined arguments
        '''
        return self.env['sale.order']._invoiced(name, arg)

    @api.multi
    def _invoiced_search(self, obj, name, args):
        '''
        @param self: object pointer
        @param name: Names of fields.
        @param arg: User defined arguments
        '''
        return self.env['sale.order']._invoiced_search(obj, name, args)

    _name = 'etourism.enterprise.folio'
    _description = 'enterprise folio new'
    _rec_name = 'order_id'
    _order = 'id'
    _inherit = ['ir.needaction_mixin','mail.thread']

    name = fields.Char('Folio Number', readonly=True, index=True,default='New')
    order_id = fields.Many2one('sale.order', 'Order', delegate=True,required=True, ondelete='cascade')
    checkin_date = fields.Datetime('Check In', required=True, readonly=True,
                                   states={'draft': [('readonly', False)]},
                                   default=_get_checkin_date)
    checkout_date = fields.Datetime('Check Out', required=True, readonly=True,
                                    states={'draft': [('readonly', False)]},
                                    default=_get_checkout_date)
    room_lines = fields.One2many('etourism.enterprise.folio.line', 'folio_id',
                                 readonly=True,
                                 states={'draft': [('readonly', False)],
                                         'sent': [('readonly', False)]},
                                 help="Enterprise room booking detail.")
    enterprise_policy = fields.Selection([('prepaid', 'On Booking'),
                                     ('manual', 'On Check In'),
                                     ('picking', 'On Checkout')],
                                    'Enterprise Policy', default='manual',
                                    help="Enterprise policy for payment that either the guest has to pay at "
                                    "booking time or check-in check-out time.")
    duration = fields.Float('Duration in Days',
                            help="Number of days which will automatically "
                            "count from the check-in and check-out date. ")
    #currrency_ids = fields.One2many('currency.exchange', 'folio_no',readonly=True)
    enterprise_invoice_id = fields.Many2one('account.invoice', 'Invoice')
    enterprise_id = fields.Many2one('etourism.enterprise', 'Enterprise')

    invoice_count = fields.Integer(related="order_id.invoice_count", string="Total Invoices", readonly=True)

    @api.model
    def default_get(self, fields):
        res = super(EtourismEnterpriseFolio, self).default_get(fields)
        if self.env.uid:
            enterprise_id = self.env['res.users'].browse([self.env.uid])[0].enterprise_id
            if enterprise_id:
                res.update({'enterprise_id': enterprise_id.id})
        return res

    @api.constrains('room_lines')
    def folio_room_lines(self):
        '''
        This method is used to validate the room_lines.
        ------------------------------------------------
        @param self: object pointer
        @return: raise warning depending on the validation
        '''
        folio_rooms = []
        for room in self[0].room_lines:
            if room.product_id.id in folio_rooms:
                raise ValidationError(_('You Cannot Take Same Room Twice'))
            folio_rooms.append(room.product_id.id)

    @api.constrains('checkin_date', 'checkout_date')
    def check_dates(self):
        '''
        This method is used to validate the checkin_date and checkout_date.
        -------------------------------------------------------------------
        @param self: object pointer
        @return: raise warning depending on the validation
        '''
        if self.checkin_date >= self.checkout_date:
                raise ValidationError(_('Check in Date Should be \
                less than the Check Out Date!'))
        '''if self.date_order and self.checkin_date:
            if self.checkin_date < self.date_order:
                raise ValidationError(_('Check in date should be \
                greater than the current date.'))'''

    @api.model
    def create(self, vals, check=True):
        """
        Overrides orm create method.
        @param self: The object pointer
        @param vals: dictionary of fields value.
        @return: new record set for hotel folio.
        """
        if not vals:
            vals = {}
        #get sequence:
        enterprise_id = vals.get('enterprise_id', False)
        name_sequence = self.create_uid.etourism_get_next_sequence('F', self._name, 'name', enterprise_id)

        vals['name'] = name_sequence

        if 'folio_id' in vals:
            tmp_room_lines = vals.get('room_lines', [])
            vals['order_policy'] = vals.get('enterprise_policy', 'manual')
            vals.update({'room_lines': []})
            folio_id = super(EtourismEnterpriseFolio, self).create(vals)
            for line in (tmp_room_lines):
                line[2].update({'folio_id': folio_id})
            vals.update({'room_lines': tmp_room_lines})
            folio_id.write(vals)
        else:
            folio_id = super(EtourismEnterpriseFolio, self).create(vals)
            folio_room_line_obj = self.env['etourism.folio.room.line']
            h_room_obj = self.env['etourism.room']
            try:
                for rec in folio_id:
                    if not rec.booking_group_id:
                        for room_rec in rec.room_lines:
                            prod = room_rec.product_id.name
                            room_obj = h_room_obj.search([('name', '=', prod)])
                            room_obj.write({'isroom_available': False})
                            vals = {'room_id': room_obj.id,
                                    'check_in': rec.checkin_date,
                                    'check_out': rec.checkout_date,
                                    'folio_id': rec.id,
                                    }
                            folio_room_line_obj.create(vals)
            except:
                for rec in folio_id:
                    for room_rec in rec.room_lines:
                        prod = room_rec.product_id.name
                        room_obj = h_room_obj.search([('name', '=', prod)])
                        room_obj.write({'isroom_available': False})
                        vals = {'room_id': room_obj.id,
                                'check_in': rec.checkin_date,
                                'check_out': rec.checkout_date,
                                'folio_id': rec.id,
                                }
                        folio_room_line_obj.create(vals)
        
        #update related sales order's no
        sale_order_no = self.create_uid.etourism_get_next_sequence('SO', 'sale.order', 'name', enterprise_id)
        sale_id = folio_id.order_id.write({'name': sale_order_no})
        
        return folio_id

    @api.multi
    def write(self, vals):
        """
        Overrides orm write method.
        @param self: The object pointer
        @param vals: dictionary of fields value.
        """
        folio_room_line_obj = self.env['etourism.folio.room.line']
        booking_line_obj = self.env['etourism.booking']
        product_obj = self.env['product.product']
        h_room_obj = self.env['etourism.room']
        room_lst1 = []
        for rec in self:
            for res in rec.room_lines:
                room_lst1.append(res.product_id.id)
        folio_write = super(EtourismEnterpriseFolio, self).write(vals)
        room_lst = []
        for folio_obj in self:
            for folio_rec in folio_obj.room_lines:
                room_lst.append(folio_rec.product_id.id)
            new_rooms = set(room_lst).difference(set(room_lst1))
            if len(list(new_rooms)) != 0:
                room_list = product_obj.browse(list(new_rooms))
                for rm in room_list:
                    room_obj = h_room_obj.search([('name', '=', rm.name)])
                    room_obj.write({'isroom_available': False})
                    vals = {'room_id': room_obj.id,
                            'check_in': folio_obj.checkin_date,
                            'check_out': folio_obj.checkout_date,
                            'folio_id': folio_obj.id,
                            }
                    folio_room_line_obj.create(vals)
            if len(list(new_rooms)) == 0:
                room_list_obj = product_obj.browse(room_lst1)
                for rom in room_list_obj:
                    room_obj = h_room_obj.search([('name', '=', rom.name)])
                    room_obj.write({'isroom_available': False})
                    room_vals = {'room_id': room_obj.id,
                                 'check_in': folio_obj.checkin_date,
                                 'check_out': folio_obj.checkout_date,
                                 'folio_id': folio_obj.id,
                                 }
                    folio_romline_rec = (folio_room_line_obj.search
                                         ([('folio_id', '=', folio_obj.id)]))
                    folio_romline_rec.write(room_vals)
            '''if folio_obj.booking_group_id:
                for booking in folio_obj.booking_group_id:
                    booking_group_obj = (booking_line_obj.search
                                       ([('booking_group_id', '=',
                                          booking.id)]))
                    if len(booking_group_obj) == 1:
                        for line_id in booking.booking_line:
                            line_id = line_id.reserve
                            for room_id in line_id:
                                vals = {'room_id': room_id.id,
                                        'check_in': folio_obj.checkin_date,
                                        'check_out': folio_obj.checkout_date,
                                        'state': 'assigned',
                                        'booking_group_id': booking.id,
                                        }
                                booking_group_obj.write(vals)'''
        return folio_write

    @api.multi
    def get_ebusiness_contacts(self,field=''):
        email,phone,mobile = '','',''
        if self.enterprise_id:
            ebusiness_id = self.enterprise_id.ebusiness_id
            for contact in ebusiness_id.contacts_line:
                if contact.default_contact:
                    email = contact.email
                    phone = contact.phone
                    mobile = contact.mobile
            if field == 'email':
                return email
            elif field == 'phone':
                return phone
            elif field == 'mobile':
                return mobile
        else:
            return ''

    @api.multi
    def action_sale_create_invoice(self):
        """Create Invoice directly without intermediate confirmation screen.
        """
        if self.order_id:
            invoice_ids = self.order_id.with_context(active_id=self.order_id and self.order_id.id or False,active_model='sale.order', booking_group_id=self.booking_group_id or False).action_invoice_create()
            if invoice_ids:
                action = self.env.ref('account.action_invoice_tree1').read()[0]
                if len(invoice_ids) == 1:
                    action['view_mode'] = 'form'
                    action['view_type'] = 'form'
                action['domain'] = [('id', 'in', invoice_ids)]
                return action
        return True

    @api.multi
    def action_invoice_create2(self, grouped=False, final=False):
        """
        Create the invoice associated to the SO.
        :param grouped: if True, invoices are grouped by SO id. If False, invoices are grouped by
                        (partner_invoice_id, currency)
        :param final: if True, refunds will be generated if necessary
        :returns: list of created invoices
        """
        inv_obj = self.env['account.invoice']
        booking_group_obj = self.env['etourism.booking.group']
        precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
        invoices = {}
        references = {}
        enterprise_id=self.booking_group_id.enterprise_id.id
        for order in self:
            group_key = order.id if grouped else (order.partner_invoice_id.id, order.currency_id.id)
            booking_group_id=self.booking_group_id.id
            for line in order.order_line.sorted(key=lambda l: l.qty_to_invoice < 0):
                if float_is_zero(line.qty_to_invoice, precision_digits=precision):
                    continue
                if group_key not in invoices:
                    inv_data = order.order_id._prepare_invoice()
                    inv_data.update({'enterprise_id':enterprise_id,'booking_group_id':booking_group_id})
                    invoice = inv_obj.create(inv_data)
                    references[invoice] = order
                    invoices[group_key] = invoice
                elif group_key in invoices:
                    vals = {}
                    if order.name not in invoices[group_key].origin.split(', '):
                        vals['origin'] = invoices[group_key].origin + ', ' + order.name
                    if order.client_order_ref and order.client_order_ref not in invoices[group_key].name.split(', '):
                        vals['name'] = invoices[group_key].name + ', ' + order.client_order_ref
                    invoices[group_key].write(vals)
                if line.qty_to_invoice > 0:
                    line.invoice_line_create(invoices[group_key].id, line.qty_to_invoice)
                elif line.qty_to_invoice < 0 and final:
                    line.invoice_line_create(invoices[group_key].id, line.qty_to_invoice)

            if references.get(invoices.get(group_key)):
                if order not in references[invoices[group_key]]:
                    references[invoice] = references[invoice] | order

        if not invoices:
            raise UserError(_('There is no invoicable line.'))

        for invoice in invoices.values():
            if not invoice.invoice_line_ids:
                raise UserError(_('There is no invoicable line.'))
            # If invoice is negative, do a refund invoice instead
            if invoice.amount_untaxed < 0:
                invoice.type = 'out_refund'
                for line in invoice.invoice_line_ids:
                    line.quantity = -line.quantity
            # Use additional field helper function (for account extensions)
            for line in invoice.invoice_line_ids:
                line._set_additional_fields(invoice)
            # Necessary to force computation of taxes. In account_invoice, they are triggered
            # by onchanges, which are not triggered when doing a create.
            invoice.compute_taxes()
            invoice.message_post_with_view('mail.message_origin_link',
                values={'self': invoice, 'origin': references[invoice]},
                subtype_id=self.env.ref('mail.mt_note').id)
        book_obj = booking_group_obj.browse([booking_group_id])
        book_obj.write({'has_invoice': True})

        return [inv.id for inv in invoices.values()]

    @api.onchange('warehouse_id')
    def onchange_warehouse_id(self):
        '''
        When you change warehouse it will update the warehouse of
        the hotel folio as well
        ----------------------------------------------------------
        @param self: object pointer
        '''
        return self.order_id._onchange_warehouse_id()

    @api.onchange('partner_id')
    def onchange_partner_id(self):
        '''
        When you change partner_id it will update the partner_invoice_id,
        partner_shipping_id and pricelist_id of the hotel folio as well
        ---------------------------------------------------------------
        @param self: object pointer
        '''
        if self.partner_id:
            partner_rec = self.env['res.partner'].browse(self.partner_id.id)
            order_ids = [folio.order_id.id for folio in self]
            if not order_ids:
                self.partner_invoice_id = partner_rec.id
                self.partner_shipping_id = partner_rec.id
                self.pricelist_id = partner_rec.property_product_pricelist.id
                raise _('Not Any Order For  %s ' % (partner_rec.name))
            else:
                self.partner_invoice_id = partner_rec.id
                self.partner_shipping_id = partner_rec.id
                self.pricelist_id = partner_rec.property_product_pricelist.id

    @api.multi
    def button_dummy(self):
        '''
        @param self: object pointer
        '''
        for folio in self:
            folio.order_id.button_dummy()
        return True

    @api.multi
    def action_done(self):
        self.write({'state': 'done'})

    @api.multi
    def action_invoice_create(self, grouped=False, states=None):
        '''
        @param self: object pointer
        '''
        if states is None:
            states = ['confirmed', 'done']
        order_ids = [folio.order_id.id for folio in self]
        room_lst = []
        sale_obj = self.env['sale.order'].browse(order_ids)
        invoice_id = sale_obj.action_invoice_create(grouped=False)
        for line in self:
            values = {'invoiced': True,
                      'state': 'sale',
                      'enterprise_invoice_id': invoice_id and invoice_id[0] or False
                      }
            line.write(values)
            for rec in line.room_lines:
                room_lst.append(rec.product_id)
            for room in room_lst:
                room_obj = self.env['etourism.room'
                                    ].search([('name', '=', room.name)])
                room_obj.write({'isroom_available': True})
        return invoice_id

    @api.multi
    def action_invoice_cancel(self):
        '''
        @param self: object pointer
        '''
        order_ids = [folio.order_id.id for folio in self]
        sale_obj = self.env['sale.order'].browse(order_ids)
        res = sale_obj.action_invoice_cancel()
        for sale in self:
            for line in sale.order_line:
                line.write({'invoiced': 'invoiced'})
        sale.write({'state': 'invoice_except'})
        return res

    @api.multi
    def action_cancel(self):
        '''
        @param self: object pointer
        '''
        order_ids = [folio.order_id.id for folio in self]
        sale_obj = self.env['sale.order'].browse(order_ids)
        rv = sale_obj.action_cancel()
        for sale in self:
            for pick in sale.picking_ids:
                workflow.trg_validate(self._uid, 'stock.picking', pick.id,
                                      'button_cancel', self._cr)
            for invoice in sale.invoice_ids:
                workflow.trg_validate(self._uid, 'account.invoice',
                                      invoice.id, 'invoice_cancel',
                                      self._cr)
                sale.write({'state': 'cancel'})
        return rv

    @api.multi
    def action_confirm(self):
        for order in self.order_id:
            order.state = 'sale'
            order.order_line._action_procurement_create()
            if not order.project_id:
                for line in order.order_line:
                    if line.product_id.invoice_policy == 'cost':
                        order._create_analytic_account()
                        break
        for booking_group in self.booking_group_id:
            #print "FOR BOOKING GROUP::::::::::::::::::::::",booking_group.id
            booking_group_obj = self.env['etourism.booking.group'].search([('id', '=', booking_group.id)])
            if booking_group_obj:
                #print "VAI ACTUALIZAR RESERVA:::::::::::::::::::::::::::::::::"
                booking_group_obj.write({'has_order': True})

        if self.env['ir.values'].get_default('sale.config.settings',
                                             'auto_done_setting'):
            self.order_id.action_done()

    @api.multi
    def test_state(self, mode):
        '''
        @param self: object pointer
        @param mode: state of workflow
        '''
        write_done_ids = []
        write_cancel_ids = []
        if write_done_ids:
            test_obj = self.env['sale.order.line'].browse(write_done_ids)
            test_obj.write({'state': 'done'})
        if write_cancel_ids:
            test_obj = self.env['sale.order.line'].browse(write_cancel_ids)
            test_obj.write({'state': 'cancel'})

    @api.multi
    def action_ship_create(self):
        '''
        @param self: object pointer
        '''
        for folio in self:
            folio.order_id.action_ship_create()
        return True

    @api.multi
    def action_ship_end(self):
        '''
        @param self: object pointer
        '''
        for order in self:
            order.write({'shipped': True})

    @api.multi
    def has_stockable_products(self):
        '''
        @param self: object pointer
        '''
        for folio in self:
            folio.order_id.has_stockable_products()
        return True

    @api.multi
    def action_cancel_draft(self):
        '''
        @param self: object pointer
        '''
        if not len(self._ids):
            return False
        query = "select id from sale_order_line \
        where order_id IN %s and state=%s"
        self._cr.execute(query, (tuple(self._ids), 'cancel'))
        cr1 = self._cr
        line_ids = map(lambda x: x[0], cr1.fetchall())
        self.write({'state': 'draft', 'invoice_ids': [], 'shipped': 0})
        sale_line_obj = self.env['sale.order.line'].browse(line_ids)
        sale_line_obj.write({'invoiced': False, 'state': 'draft',
                             'invoice_lines': [(6, 0, [])]})
        return True

    @api.multi
    def action_quotation_send(self):
        '''
        This function opens a window to compose an email, with the edi sale template message loaded by default
        '''
        self.ensure_one()
        ir_model_data = self.env['ir.model.data']
        try:
            template_id = ir_model_data.get_object_reference('etourism', 'email_template_edi_folio')[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 = dict()
        ctx.update({
            'default_model': 'etourism.enterprise.folio',
            'default_res_id': self.ids[0],
            'default_use_template': bool(template_id),
            'default_template_id': template_id,
            'default_composition_mode': 'comment',
            'mark_so_as_sent': True,
            'custom_layout': "etourism.mail_template_data_notification_email_folio"
        })
        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,
        }

    @api.multi
    def action_view_invoice(self):
        for folio in self:
            return folio.order_id.action_view_invoice()

    @api.multi
    def print_quotation(self):
        #self.filtered(lambda s: s.state == 'draft').write({'state': 'sent'})
        return self.env['report'].get_action(self, 'etourism.folio_report')

    @api.multi
    def get_signup_url(self):
        self.ensure_one()
        return self.partner_id.with_context(signup_valid=True)._get_signup_url_for_action(
            action='/mail/view',
            model=self._name,
            res_id=self.id)[self.partner_id.id]

class EtourismFolioRoomLine(models.Model):

    _name = 'etourism.folio.room.line'
    _description = 'Hotel Room Booking'
    _rec_name = 'room_id'

    room_id = fields.Many2one(comodel_name='etourism.room', string='Room id')
    check_in = fields.Datetime('Check In Date', required=True)
    check_out = fields.Datetime('Check Out Date', required=True)
    folio_id = fields.Many2one('etourism.enterprise.folio', string='Folio Number')
    status = fields.Selection(string='state', related='folio_id.state')

class EtourismEnterpriseFolioLine(models.Model):

    @api.multi
    def copy(self, default=None):
        '''
        @param self: object pointer
        @param default: dict of default values to be set
        '''
        return super(EtourismEnterpriseFolioLine, self).copy(default=default)

    @api.multi
    def _amount_line(self, field_name, arg):
        '''
        @param self: object pointer
        @param field_name: Names of fields.
        @param arg: User defined arguments
        '''
        return self.env['sale.order.line']._amount_line(field_name, arg)

    @api.multi
    def _number_packages(self, field_name, arg):
        '''
        @param self: object pointer
        @param field_name: Names of fields.
        @param arg: User defined arguments
        '''
        return self.env['sale.order.line']._number_packages(field_name, arg)

    @api.model
    def _get_checkin_date(self):
        if 'checkin' in self._context:
            return self._context['checkin']
        return time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)

    @api.model
    def _get_checkout_date(self):
        if 'checkout' in self._context:
            return self._context['checkout']
        return time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)

    _name = 'etourism.enterprise.folio.line'
    _description = 'enterprise folio1 room line'

    order_line_id = fields.Many2one('sale.order.line', string='Order Line',
                                    required=True, delegate=True,
                                    ondelete='cascade')
    folio_id = fields.Many2one('etourism.enterprise.folio', string='Folio',
                               ondelete='cascade')
    checkin_date = fields.Datetime('Check In', required=True,
                                   default=_get_checkin_date)
    checkout_date = fields.Datetime('Check Out', required=True,
                                    default=_get_checkout_date)
    is_reserved = fields.Boolean('Is Reserved',
                                 help='True when folio line created from \
                                 Booking')
    booking_id = fields.Many2one('etourism.booking',string='Booking', related='order_line_id.booking_line_id',store=True)
    room_id = fields.Many2one('etourism.room', string='Room',ondelete='cascade')
    #discount = fields.Float(string='Discount', related='order_line_id.discount',store=True)

    @api.model
    def create(self, vals, check=True):
        """
        Overrides orm create method.
        @param self: The object pointer
        @param vals: dictionary of fields value.
        @return: new record set for hotel folio line.
        """
        #print "CREATE FOLIO LINE::::::::::::::"
        #print vals
        if 'folio_id' in vals:
            folio = self.env["etourism.enterprise.folio"].browse(vals['folio_id'])
            vals.update({'order_id': folio.order_id.id})
        else:
            if 'booking_id' in vals:
                booking = self.env["etourism.booking"].browse(vals['booking_id'])
                if booking.booking_group_id:
                    folio = self.env["etourism.enterprise.folio"].search([('booking_group_id', '=', booking.booking_group_id.id)],limit=1)
                    if folio:
                        vals.update({'order_id': folio.order_id.id,'folio_id': folio.id})

        return super(EtourismEnterpriseFolioLine, self).create(vals)

    @api.constrains('checkin_date', 'checkout_date')
    def check_dates(self):
        '''
        This method is used to validate the checkin_date and checkout_date.
        -------------------------------------------------------------------
        @param self: object pointer
        @return: raise warning depending on the validation
        '''

        if self.checkin_date >= self.checkout_date:
                raise ValidationError(_('Room line Check In Date Should be \
                less than the Check Out Date!'))
        '''if self.folio_id.date_order and self.checkin_date:
            checkin_date = datetime.datetime.strptime(self.checkin_date, '%Y-%m-%d %H:%M:%S').date()
            date_order = datetime.datetime.strptime(self.folio_id.date_order, '%Y-%m-%d %H:%M:%S').date()
            if checkin_date <= date_order:
                raise ValidationError(_('Room line check in date should be \
                greater than the current date.'))'''

    @api.multi
    def unlink(self):
        """
        Overrides orm unlink method.
        @param self: The object pointer
        @return: True/False.
        """
        sale_line_obj = self.env['sale.order.line']
        fr_obj = self.env['etourism.folio.room.line']
        for line in self:
            if line.order_line_id:
                sale_unlink_obj = (sale_line_obj.browse
                                   ([line.order_line_id.id]))
                for rec in sale_unlink_obj:
                    room_obj = self.env['etourism.room'
                                        ].search([('name', '=', rec.name)])
                    if room_obj.id:
                        folio_arg = [('folio_id', '=', line.folio_id.id),
                                     ('room_id', '=', room_obj.id)]
                        folio_room_line_myobj = fr_obj.search(folio_arg)
                        if folio_room_line_myobj.id:
                            folio_room_line_myobj.unlink()
                            room_obj.write({'isroom_available': True,
                                            'status': 'available'})
                sale_unlink_obj.unlink()
        return super(EtourismEnterpriseFolioLine, self).unlink()

#    @api.multi
#    def uos_change(self, product_uos, product_uos_qty=0, product_id=None):
#         '''
#             @param self: object pointer
#         '''
#         for folio in self:
#             line = folio.order_line_id
#             line.uos_change(product_uos, product_uos_qty=0,
#                             product_id=None)
#         return True

    @api.multi
    def get_booking_duration(self,checkin_date,checkout_date):
        ''' This function returns the duration of the booking related to the folio
        '''
        if not checkin_date:
            checkin_date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
        if not checkout_date:
            checkout_date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
        chckin = checkin_date
        chckout = checkout_date
        myduration=0
        if chckin and chckout:
            server_dt = DEFAULT_SERVER_DATETIME_FORMAT
            chkin_dt = datetime.datetime.strptime(chckin, server_dt)
            chkout_dt = datetime.datetime.strptime(chckout, server_dt)
            dur = chkout_dt - chkin_dt
            sec_dur = dur.seconds
            if (not dur.days and not sec_dur) or (dur.days and not sec_dur):
                myduration = dur.days
            else:
                myduration = dur.days + 1
		return myduration

    @api.onchange('product_id')
    def onchange_product(self):
        if self.product_id:
            self.name = self.product_id.name
            self.price_unit = self.product_id.list_price
            self.product_uom = self.product_id.uom_id
            if self.product_id.isroom:
                self.product_uom_qty = self.get_booking_duration(self.checkin_date,self.checkout_date)
            elif self.product_id.tourist_tax:
                self.product_uom_qty = self.get_booking_duration(self.checkin_date,self.checkout_date)
            else:
                self.product_uom_qty = 1

            tax_obj = self.env['account.tax']
            prod = self.product_id
            self.price_unit = tax_obj._fix_tax_included_price(prod.price,
                                                              prod.taxes_id,
                                                              self.tax_id)

    @api.onchange('product_uom')
    def product_uom_change(self):
        if not self.product_uom:
            self.price_unit = 0.0
            return
        self.price_unit = self.product_id.lst_price
        if self.folio_id.partner_id:
            prod = self.product_id.with_context(
                lang=self.folio_id.partner_id.lang,
                partner=self.folio_id.partner_id.id,
                quantity=1,
                date_order=self.folio_id.checkin_date,
                pricelist=self.folio_id.pricelist_id.id,
                uom=self.product_uom.id
            )
            tax_obj = self.env['account.tax']
            self.price_unit = tax_obj._fix_tax_included_price(prod.price,
                                                              prod.taxes_id,
                                                              self.tax_id)

    @api.onchange('checkin_date', 'checkout_date')
    def on_change_checkout(self):
        '''
        When you change checkin_date or checkout_date it will checked it
        and update the qty of hotel folio line
        -----------------------------------------------------------------
        @param self: object pointer
        '''
        if not self.checkin_date:
            self.checkin_date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
        if not self.checkout_date:
            self.checkout_date = time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)
        chckin = self.checkin_date
        chckout = self.checkout_date
        if chckin and chckout:
            server_dt = DEFAULT_SERVER_DATETIME_FORMAT
            chkin_dt = datetime.datetime.strptime(chckin, server_dt)
            chkout_dt = datetime.datetime.strptime(chckout, server_dt)
            dur = chkout_dt - chkin_dt
            sec_dur = dur.seconds
            if (not dur.days and not sec_dur) or (dur.days and not sec_dur):
                myduration = dur.days
            else:
                myduration = dur.days + 1
        if self.product_id.isroom:
            self.product_uom_qty = myduration
        else:
            self.product_uom_qty = 1

    @api.multi
    def button_confirm(self):
        '''
        @param self: object pointer
        '''
        for folio in self:
            line = folio.order_line_id
            line.button_confirm()
        return True

    @api.multi
    def button_done(self):
        '''
        @param self: object pointer
        '''
        lines = [folio_line.order_line_id for folio_line in self]
        lines.button_done()
        self.write({'state': 'done'})
        for folio_line in self:
            workflow.trg_write(self._uid, 'sale.order',
                               folio_line.order_line_id.order_id.id,
                               self._cr)
        return True

    @api.multi
    def copy_data(self, default=None):
        '''
        @param self: object pointer
        @param default: dict of default values to be set
        '''
        line_id = self.order_line_id.id
        sale_line_obj = self.env['sale.order.line'].browse(line_id)
        return sale_line_obj.copy_data(default=default)
		
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
