diff --git a/hotel/models/hotel_folio.py b/hotel/models/hotel_folio.py
index 1f968b977..3f1f34b37 100644
--- a/hotel/models/hotel_folio.py
+++ b/hotel/models/hotel_folio.py
@@ -257,10 +257,32 @@ class HotelFolio(models.Model):
for record in self:
record.rooms_char = ', '.join(record.mapped('room_lines.room_id.name'))
- # @api.depends('order_line.price_total', 'payment_ids', 'return_ids')
+ @api.depends('amount_total', 'payment_ids', 'return_ids')
@api.multi
def compute_amount(self):
- _logger.info('compute_amount')
+ acc_pay_obj = self.env['account.payment']
+ for record in self:
+ if record.reservation_type in ('staff', 'out'):
+ vals = {
+ 'pending_amount': 0,
+ 'invoices_paid': 0,
+ 'refund_amount': 0,
+ }
+ record.update(vals)
+ else:
+ total_inv_refund = 0
+ payments = acc_pay_obj.search([
+ ('folio_id', '=', record.id)
+ ])
+ total_paid = sum(pay.amount for pay in payments)
+ return_lines = self.env['payment.return.line'].search([('move_line_ids','in',payments.mapped('move_line_ids.id')),('return_id.state','=', 'done')])
+ total_inv_refund = sum(pay_return.amount for pay_return in return_lines)
+ vals = {
+ 'pending_amount': record.amount_total - total_paid + total_inv_refund,
+ 'invoices_paid': total_paid,
+ 'refund_amount': total_inv_refund,
+ }
+ record.update(vals)
@api.multi
def action_pay(self):
diff --git a/hotel/models/hotel_reservation.py b/hotel/models/hotel_reservation.py
index 2dd7a37c9..d8643bfec 100644
--- a/hotel/models/hotel_reservation.py
+++ b/hotel/models/hotel_reservation.py
@@ -1,7 +1,6 @@
# Copyright 2017-2018 Alexandre Díaz
# Copyright 2017 Dario Lodeiros
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
-import logging
import time
from datetime import timedelta
from lxml import etree
@@ -14,6 +13,7 @@ from odoo.tools import (
DEFAULT_SERVER_DATETIME_FORMAT)
from odoo import models, fields, api, _
from odoo.addons import decimal_precision as dp
+import logging
_logger = logging.getLogger(__name__)
@@ -168,6 +168,7 @@ class HotelReservation(models.Model):
track_visibility='onchange')
reservation_type = fields.Selection(related='folio_id.reservation_type',
default=lambda *a: 'normal')
+ invoice_count = fields.Integer(related='folio_id.invoice_count')
board_service_room_id = fields.Many2one('hotel.board.service.room.type',
string='Board Service')
cancelled_reason = fields.Selection([
@@ -333,11 +334,13 @@ class HotelReservation(models.Model):
board_services = []
board = self.env['hotel.board.service.room.type'].browse(vals['board_service_room_id'])
for line in board.board_service_line_ids:
- board_services.append((0, False, {
+ res = {
'product_id': line.product_id.id,
'is_board_service': True,
'folio_id': vals.get('folio_id'),
- }))
+ }
+ res.update(self.env['hotel.service']._prepare_add_missing_fields(res))
+ board_services.append((0, False, res))
vals.update({'service_ids': board_services})
if self.compute_price_out_vals(vals):
days_diff = (
@@ -382,18 +385,15 @@ class HotelReservation(models.Model):
board_services = []
board = self.env['hotel.board.service.room.type'].browse(vals['board_service_room_id'])
for line in board.board_service_line_ids:
- board_services.append((0, False, {
+ res = {
'product_id': line.product_id.id,
'is_board_service': True,
- 'folio_id': record.folio_id.id or vals.get('folio_id')
- }))
+ 'folio_id': vals.get('folio_id'),
+ }
+ res.update(self.env['hotel.service']._prepare_add_missing_fields(res))
+ board_services.append((0, False, vals))
# NEED REVIEW: Why I need add manually the old IDs if board service is (0,0,(-)) ¿?¿?¿
record.update({'service_ids': [(6, 0, record.service_ids.ids)] + board_services})
- update_services = record.service_ids.filtered(
- lambda r: r.is_board_service == True
- )
- for service in update_services:
- service.onchange_product_calc_qty()
if record.compute_price_out_vals(vals):
record.update(record.prepare_reservation_lines(
checkin,
@@ -457,7 +457,7 @@ class HotelReservation(models.Model):
line = self.new(values)
if any(f not in values for f in onchange_fields):
line.onchange_room_id()
- line.onchange_compute_reservation_description()
+ line.onchange_room_type_id()
line.onchange_board_service()
if 'pricelist_id' not in values:
line.onchange_partner_id()
@@ -625,7 +625,10 @@ class HotelReservation(models.Model):
update_old_prices=False))
@api.onchange('checkin', 'checkout', 'room_type_id')
- def onchange_compute_reservation_description(self):
+ def onchange_room_type_id(self):
+ """
+ When change de room_type_id, we calc the line description and tax_ids
+ """
if self.room_type_id and self.checkin and self.checkout:
checkin_dt = fields.Date.from_string(self.checkin)
checkout_dt = fields.Date.from_string(self.checkout)
@@ -633,6 +636,7 @@ class HotelReservation(models.Model):
checkout_str = checkout_dt.strftime('%d/%m/%Y')
self.name = self.room_type_id.name + ': ' + checkin_str + ' - '\
+ checkout_str
+ self._compute_tax_ids()
@api.onchange('checkin', 'checkout')
def onchange_update_service_per_day(self):
@@ -670,18 +674,20 @@ class HotelReservation(models.Model):
for line in self.board_service_room_id.board_service_line_ids:
product = line.product_id
if product.per_day:
- vals = {
+ res = {
'product_id': product.id,
'is_board_service': True,
'folio_id': self.folio_id.id,
}
- vals.update(self.env['hotel.service'].prepare_service_lines(
+ line = self.env['hotel.service'].new(res)
+ res.update(self.env['hotel.service']._prepare_add_missing_fields(res))
+ res.update(self.env['hotel.service'].prepare_service_lines(
dfrom=self.checkin,
days=self.nights,
per_person=product.per_person,
persons=self.adults,
old_line_days=False))
- board_services.append((0, False, vals))
+ board_services.append((0, False, res))
other_services = self.service_ids.filtered(lambda r: r.is_board_service == False)
self.update({'service_ids': [(6, 0, other_services.ids)] + board_services})
for service in self.service_ids.filtered(lambda r: r.is_board_service == True):
@@ -1162,6 +1168,29 @@ class HotelReservation(models.Model):
INVOICING PROCESS
"""
+ @api.multi
+ def open_invoices_reservation(self):
+ invoices = self.folio_id.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.invoice_form').id, 'form')]
+ action['res_id'] = invoices.ids[0]
+ else:
+ action = self.env.ref('hotel.action_view_folio_advance_payment_inv').read()[0]
+ action['context'] = {'default_reservation_id': self.id,
+ 'default_folio_id': self.folio_id.id}
+ return action
+
+ @api.multi
+ def _compute_tax_ids(self):
+ for record in self:
+ # If company_id is set, always filter taxes by the company
+ folio = record.folio_id or self.env.context.get('default_folio_id')
+ product = self.env['product.product'].browse(record.room_type_id.product_id.id)
+ record.tax_ids = product.taxes_id.filtered(lambda r: not record.company_id or r.company_id == folio.company_id)
+
@api.depends('qty_invoiced', 'nights', 'folio_id.state')
def _get_to_invoice_qty(self):
"""
diff --git a/hotel/models/hotel_service.py b/hotel/models/hotel_service.py
index e7a21aade..1f8eec577 100644
--- a/hotel/models/hotel_service.py
+++ b/hotel/models/hotel_service.py
@@ -206,7 +206,7 @@ class HotelService(models.Model):
def _prepare_add_missing_fields(self, values):
""" Deduce missing required fields from the onchange """
res = {}
- onchange_fields = ['price_unit','tax_ids']
+ onchange_fields = ['price_unit','tax_ids','name']
if values.get('product_id'):
line = self.new(values)
if any(f not in values for f in onchange_fields):
diff --git a/hotel/views/hotel_folio_views.xml b/hotel/views/hotel_folio_views.xml
index 742454e19..862dea67f 100644
--- a/hotel/views/hotel_folio_views.xml
+++ b/hotel/views/hotel_folio_views.xml
@@ -66,7 +66,7 @@
-
+
-
+
-
+
+
+
+
+
+
+ Invoices
+
+
account.payment
diff --git a/hotel/wizard/folio_make_invoice_advance.py b/hotel/wizard/folio_make_invoice_advance.py
index 7c0ff9acd..d7b28febf 100644
--- a/hotel/wizard/folio_make_invoice_advance.py
+++ b/hotel/wizard/folio_make_invoice_advance.py
@@ -27,20 +27,29 @@ class FolioAdvancePaymentInv(models.TransientModel):
@api.model
def _get_default_folio(self):
- folios = self.env['hotel.folio'].browse(self._context.get('active_ids', []))
+ if self._context.get('default_reservation_id'):
+ folio_ids = self._context.get('default_folio_id', [])
+ else:
+ folio_ids = self._context.get('active_ids', [])
+
+ folios = self.env['hotel.folio'].browse(folio_ids)
return folios
@api.model
def _get_default_reservation(self):
- folios = self._get_default_folio()
- reservations = self.env['hotel.reservation']
- for folio in folios:
- reservations |= folio.room_lines
+ if self._context.get('default_reservation_id'):
+ reservations = self.env['hotel.reservation'].browse(self._context.get('active_ids', []))
+ else:
+ folios = self._get_default_folio()
+ reservations = self.env['hotel.reservation']
+ for folio in folios:
+ reservations |= folio.room_lines
return reservations
@api.model
def _get_default_partner_invoice(self):
- return self.env['hotel.folio'].browse(self._context.get('active_id', [])).partner_invoice_id
+ folios = self._get_default_folio()
+ return folios[0].partner_invoice_id
@api.model
def _default_deposit_account_id(self):
@@ -72,9 +81,6 @@ class FolioAdvancePaymentInv(models.TransientModel):
'advance_inv_id',
string="Invoice Lines")
view_detail = fields.Boolean('View Detail')
- line_ids = fields.One2many('line.advance.inv',
- 'advance_inv_id',
- string="Lines")
#Advance Payment
product_id = fields.Many2one('product.product', string="Product",
domain=[('type', '=', 'service')], default=_default_product_id)
@@ -215,7 +221,24 @@ class FolioAdvancePaymentInv(models.TransientModel):
'tax_id': [(6, 0, tax_ids)],
})
del context
- self._create_invoice(folio, service_line, amount)
+ invoice = self._create_invoice(folio, service_line, amount)
+ invoice.compute_taxes()
+ if not invoice.invoice_line_ids:
+ raise UserError(_('There is no invoiceable line.'))
+ # If invoice is negative, do a refund invoice instead
+ if invoice.amount_total < 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': folios},
+ subtype_id=self.env.ref('mail.mt_note').id)
if self._context.get('open_invoices', False):
return folios.open_invoices_folio()
return {'type': 'ir.actions.act_window_close'}
@@ -307,11 +330,12 @@ class FolioAdvancePaymentInv(models.TransientModel):
invoice_lines = {}
reservations = self.env['hotel.reservation']
services = self.env['hotel.service']
- for folio in folios:
+ old_folio_ids = self.reservation_ids.mapped('folio_id.id')
+ for folio in folios.filtered(lambda r: r.id not in old_folio_ids):
folio_reservations = folio.room_lines
if folio_reservations:
reservations |= folio_reservations
- self.reservation_ids = reservations
+ self.reservation_ids |= reservations
self.prepare_invoice_lines()
@api.model
@@ -369,6 +393,12 @@ class LineAdvancePaymentInv(models.TransientModel):
description = fields.Text('Description')
reservation_id = fields.Many2one('hotel.reservation')
service_id = fields.Many2one('hotel.service')
+ folio_id = fields.Many2one('hotel.folio', compute='_compute_folio_id')
+
+ def _compute_folio_id(self):
+ for record in self:
+ origin = record.reservation_id if record.reservation_id.id else record.service_id
+ record.folio_id = origin.folio_id
@api.multi
def invoice_line_create(self, invoice_id, qty):
@@ -380,7 +410,7 @@ class LineAdvancePaymentInv(models.TransientModel):
invoice_lines = self.env['account.invoice.line']
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
for line in self:
- origin = self.reservation_id if self.reservation_id.id else self.service_id
+ origin = line.reservation_id if line.reservation_id.id else line.service_id
res = {}
product = line.product_id
account = product.property_account_income_id or product.categ_id.property_account_income_categ_id
@@ -388,7 +418,7 @@ class LineAdvancePaymentInv(models.TransientModel):
raise UserError(_('Please define income account for this product: "%s" (id:%d) - or for its category: "%s".') %
(product.name, product.id, product.categ_id.name))
- fpos = origin.folio_id.fiscal_position_id or origin.folio_id.partner_id.property_account_position_id
+ fpos = line.folio_id.fiscal_position_id or line.folio_id.partner_id.property_account_position_id
if fpos:
account = fpos.map_account(account)
@@ -403,10 +433,13 @@ class LineAdvancePaymentInv(models.TransientModel):
'uom_id': product.uom_id.id,
'product_id': product.id or False,
'invoice_line_tax_ids': [(6, 0, origin.tax_ids.ids)],
- 'account_analytic_id': origin.folio_id.analytic_account_id.id,
+ 'account_analytic_id': line.folio_id.analytic_account_id.id,
'analytic_tag_ids': [(6, 0, origin.analytic_tag_ids.ids)],
}
- vals.update({'invoice_id': invoice_id, 'reservation_ids': [(6, 0, [origin.id])]})
+ if line.reservation_id:
+ vals.update({'invoice_id': invoice_id, 'reservation_ids': [(6, 0, [origin.id])]})
+ elif line.service_id:
+ vals.update({'invoice_id': invoice_id, 'service_ids': [(6, 0, [origin.id])]})
invoice_lines |= self.env['account.invoice.line'].create(vals)
return invoice_lines
diff --git a/hotel/wizard/folio_make_invoice_advance_views.xml b/hotel/wizard/folio_make_invoice_advance_views.xml
index 869836796..db8c08a03 100644
--- a/hotel/wizard/folio_make_invoice_advance_views.xml
+++ b/hotel/wizard/folio_make_invoice_advance_views.xml
@@ -50,6 +50,7 @@
+