mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[WIP] workflow invoices
This commit is contained in:
@@ -257,10 +257,32 @@ class HotelFolio(models.Model):
|
|||||||
for record in self:
|
for record in self:
|
||||||
record.rooms_char = ', '.join(record.mapped('room_lines.room_id.name'))
|
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
|
@api.multi
|
||||||
def compute_amount(self):
|
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
|
@api.multi
|
||||||
def action_pay(self):
|
def action_pay(self):
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# Copyright 2017-2018 Alexandre Díaz
|
# Copyright 2017-2018 Alexandre Díaz
|
||||||
# Copyright 2017 Dario Lodeiros
|
# Copyright 2017 Dario Lodeiros
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
||||||
import logging
|
|
||||||
import time
|
import time
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
@@ -14,6 +13,7 @@ from odoo.tools import (
|
|||||||
DEFAULT_SERVER_DATETIME_FORMAT)
|
DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
from odoo import models, fields, api, _
|
from odoo import models, fields, api, _
|
||||||
from odoo.addons import decimal_precision as dp
|
from odoo.addons import decimal_precision as dp
|
||||||
|
import logging
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@@ -168,6 +168,7 @@ class HotelReservation(models.Model):
|
|||||||
track_visibility='onchange')
|
track_visibility='onchange')
|
||||||
reservation_type = fields.Selection(related='folio_id.reservation_type',
|
reservation_type = fields.Selection(related='folio_id.reservation_type',
|
||||||
default=lambda *a: 'normal')
|
default=lambda *a: 'normal')
|
||||||
|
invoice_count = fields.Integer(related='folio_id.invoice_count')
|
||||||
board_service_room_id = fields.Many2one('hotel.board.service.room.type',
|
board_service_room_id = fields.Many2one('hotel.board.service.room.type',
|
||||||
string='Board Service')
|
string='Board Service')
|
||||||
cancelled_reason = fields.Selection([
|
cancelled_reason = fields.Selection([
|
||||||
@@ -333,11 +334,13 @@ class HotelReservation(models.Model):
|
|||||||
board_services = []
|
board_services = []
|
||||||
board = self.env['hotel.board.service.room.type'].browse(vals['board_service_room_id'])
|
board = self.env['hotel.board.service.room.type'].browse(vals['board_service_room_id'])
|
||||||
for line in board.board_service_line_ids:
|
for line in board.board_service_line_ids:
|
||||||
board_services.append((0, False, {
|
res = {
|
||||||
'product_id': line.product_id.id,
|
'product_id': line.product_id.id,
|
||||||
'is_board_service': True,
|
'is_board_service': True,
|
||||||
'folio_id': 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, res))
|
||||||
vals.update({'service_ids': board_services})
|
vals.update({'service_ids': board_services})
|
||||||
if self.compute_price_out_vals(vals):
|
if self.compute_price_out_vals(vals):
|
||||||
days_diff = (
|
days_diff = (
|
||||||
@@ -382,18 +385,15 @@ class HotelReservation(models.Model):
|
|||||||
board_services = []
|
board_services = []
|
||||||
board = self.env['hotel.board.service.room.type'].browse(vals['board_service_room_id'])
|
board = self.env['hotel.board.service.room.type'].browse(vals['board_service_room_id'])
|
||||||
for line in board.board_service_line_ids:
|
for line in board.board_service_line_ids:
|
||||||
board_services.append((0, False, {
|
res = {
|
||||||
'product_id': line.product_id.id,
|
'product_id': line.product_id.id,
|
||||||
'is_board_service': True,
|
'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,(-)) ¿?¿?¿
|
# 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})
|
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):
|
if record.compute_price_out_vals(vals):
|
||||||
record.update(record.prepare_reservation_lines(
|
record.update(record.prepare_reservation_lines(
|
||||||
checkin,
|
checkin,
|
||||||
@@ -457,7 +457,7 @@ class HotelReservation(models.Model):
|
|||||||
line = self.new(values)
|
line = self.new(values)
|
||||||
if any(f not in values for f in onchange_fields):
|
if any(f not in values for f in onchange_fields):
|
||||||
line.onchange_room_id()
|
line.onchange_room_id()
|
||||||
line.onchange_compute_reservation_description()
|
line.onchange_room_type_id()
|
||||||
line.onchange_board_service()
|
line.onchange_board_service()
|
||||||
if 'pricelist_id' not in values:
|
if 'pricelist_id' not in values:
|
||||||
line.onchange_partner_id()
|
line.onchange_partner_id()
|
||||||
@@ -625,7 +625,10 @@ class HotelReservation(models.Model):
|
|||||||
update_old_prices=False))
|
update_old_prices=False))
|
||||||
|
|
||||||
@api.onchange('checkin', 'checkout', 'room_type_id')
|
@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:
|
if self.room_type_id and self.checkin and self.checkout:
|
||||||
checkin_dt = fields.Date.from_string(self.checkin)
|
checkin_dt = fields.Date.from_string(self.checkin)
|
||||||
checkout_dt = fields.Date.from_string(self.checkout)
|
checkout_dt = fields.Date.from_string(self.checkout)
|
||||||
@@ -633,6 +636,7 @@ class HotelReservation(models.Model):
|
|||||||
checkout_str = checkout_dt.strftime('%d/%m/%Y')
|
checkout_str = checkout_dt.strftime('%d/%m/%Y')
|
||||||
self.name = self.room_type_id.name + ': ' + checkin_str + ' - '\
|
self.name = self.room_type_id.name + ': ' + checkin_str + ' - '\
|
||||||
+ checkout_str
|
+ checkout_str
|
||||||
|
self._compute_tax_ids()
|
||||||
|
|
||||||
@api.onchange('checkin', 'checkout')
|
@api.onchange('checkin', 'checkout')
|
||||||
def onchange_update_service_per_day(self):
|
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:
|
for line in self.board_service_room_id.board_service_line_ids:
|
||||||
product = line.product_id
|
product = line.product_id
|
||||||
if product.per_day:
|
if product.per_day:
|
||||||
vals = {
|
res = {
|
||||||
'product_id': product.id,
|
'product_id': product.id,
|
||||||
'is_board_service': True,
|
'is_board_service': True,
|
||||||
'folio_id': self.folio_id.id,
|
'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,
|
dfrom=self.checkin,
|
||||||
days=self.nights,
|
days=self.nights,
|
||||||
per_person=product.per_person,
|
per_person=product.per_person,
|
||||||
persons=self.adults,
|
persons=self.adults,
|
||||||
old_line_days=False))
|
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)
|
other_services = self.service_ids.filtered(lambda r: r.is_board_service == False)
|
||||||
self.update({'service_ids': [(6, 0, other_services.ids)] + board_services})
|
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):
|
for service in self.service_ids.filtered(lambda r: r.is_board_service == True):
|
||||||
@@ -1162,6 +1168,29 @@ class HotelReservation(models.Model):
|
|||||||
INVOICING PROCESS
|
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')
|
@api.depends('qty_invoiced', 'nights', 'folio_id.state')
|
||||||
def _get_to_invoice_qty(self):
|
def _get_to_invoice_qty(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ class HotelService(models.Model):
|
|||||||
def _prepare_add_missing_fields(self, values):
|
def _prepare_add_missing_fields(self, values):
|
||||||
""" Deduce missing required fields from the onchange """
|
""" Deduce missing required fields from the onchange """
|
||||||
res = {}
|
res = {}
|
||||||
onchange_fields = ['price_unit','tax_ids']
|
onchange_fields = ['price_unit','tax_ids','name']
|
||||||
if values.get('product_id'):
|
if values.get('product_id'):
|
||||||
line = self.new(values)
|
line = self.new(values)
|
||||||
if any(f not in values for f in onchange_fields):
|
if any(f not in values for f in onchange_fields):
|
||||||
|
|||||||
@@ -66,7 +66,7 @@
|
|||||||
</button>
|
</button>
|
||||||
<field name="currency_id" invisible="1"/>
|
<field name="currency_id" invisible="1"/>
|
||||||
|
|
||||||
<!-- <button type="object" class="oe_stat_button"
|
<button type="object" class="oe_stat_button"
|
||||||
id="invoices_smart_button"
|
id="invoices_smart_button"
|
||||||
icon="fa-thumbs-up"
|
icon="fa-thumbs-up"
|
||||||
name="action_payments"
|
name="action_payments"
|
||||||
@@ -78,9 +78,9 @@
|
|||||||
</span>
|
</span>
|
||||||
<span class="o_stat_text">Paid out</span>
|
<span class="o_stat_text">Paid out</span>
|
||||||
</div>
|
</div>
|
||||||
</button> -->
|
</button>
|
||||||
|
|
||||||
<!-- <button type="object" class="oe_stat_button"
|
<button type="object" class="oe_stat_button"
|
||||||
id="payment_smart_button"
|
id="payment_smart_button"
|
||||||
icon="fa-money"
|
icon="fa-money"
|
||||||
name="action_pay"
|
name="action_pay"
|
||||||
@@ -92,9 +92,9 @@
|
|||||||
</span>
|
</span>
|
||||||
<span class="o_stat_text">Pending Payment</span>
|
<span class="o_stat_text">Pending Payment</span>
|
||||||
</div>
|
</div>
|
||||||
</button> -->
|
</button>
|
||||||
|
|
||||||
<!-- <button type="object" class="oe_stat_button"
|
<button type="object" class="oe_stat_button"
|
||||||
id="refunds_smart_button"
|
id="refunds_smart_button"
|
||||||
icon="fa-undo"
|
icon="fa-undo"
|
||||||
name="action_return_payments"
|
name="action_return_payments"
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
</span>
|
</span>
|
||||||
<span class="o_stat_text">Refunds</span>
|
<span class="o_stat_text">Refunds</span>
|
||||||
</div>
|
</div>
|
||||||
</button> -->
|
</button>
|
||||||
|
|
||||||
<button type="object" class="oe_stat_button" id="invoice_button"
|
<button type="object" class="oe_stat_button" id="invoice_button"
|
||||||
icon="fa-pencil-square-o" name="open_invoices_folio"
|
icon="fa-pencil-square-o" name="open_invoices_folio"
|
||||||
|
|||||||
@@ -18,10 +18,10 @@
|
|||||||
<form string="Reservation" >
|
<form string="Reservation" >
|
||||||
<header>
|
<header>
|
||||||
<field name="splitted" invisible="True" />
|
<field name="splitted" invisible="True" />
|
||||||
|
<field name="tax_ids" invisible="1"/>
|
||||||
<field name="parent_reservation" invisible="True" />
|
<field name="parent_reservation" invisible="True" />
|
||||||
<field name="has_confirmed_reservations_to_send" invisible="1" />
|
<field name="has_confirmed_reservations_to_send" invisible="1" />
|
||||||
<field name="has_cancelled_reservations_to_send" invisible="1" />
|
<field name="has_cancelled_reservations_to_send" invisible="1" />
|
||||||
<field name="tax_ids" invisible="1"/>
|
|
||||||
<field name="has_checkout_to_send" invisible="1" />
|
<field name="has_checkout_to_send" invisible="1" />
|
||||||
<button name="send_reservation_mail" type="object" string="Send Confirmation Email"
|
<button name="send_reservation_mail" type="object" string="Send Confirmation Email"
|
||||||
attrs="{'invisible': [('has_confirmed_reservations_to_send', '=', False)]}" class="oe_highlight"/>
|
attrs="{'invisible': [('has_confirmed_reservations_to_send', '=', False)]}" class="oe_highlight"/>
|
||||||
@@ -99,6 +99,15 @@
|
|||||||
<span class="o_stat_text">Books</span>
|
<span class="o_stat_text">Books</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
<button type="object" class="oe_stat_button" id="invoice_button"
|
||||||
|
icon="fa-pencil-square-o" name="open_invoices_reservation">
|
||||||
|
<div class="o_form_field o_stat_info">
|
||||||
|
<span class="o_stat_value">
|
||||||
|
<field name="invoice_count"/>
|
||||||
|
</span>
|
||||||
|
<span class="o_stat_text">Invoices</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
<button type="object" class="oe_stat_button"
|
<button type="object" class="oe_stat_button"
|
||||||
id="open_master"
|
id="open_master"
|
||||||
icon="fa-chain-broken"
|
icon="fa-chain-broken"
|
||||||
|
|||||||
@@ -16,42 +16,52 @@
|
|||||||
<field name="model">account.payment</field>
|
<field name="model">account.payment</field>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<form string="Register Payment" version="7">
|
<form string="Register Payment" version="7">
|
||||||
|
<header>
|
||||||
|
<button name="post" class="oe_highlight" states="draft" string="Confirm" type="object"/>
|
||||||
|
<button name="action_draft" class="oe_highlight" states="cancelled" string="Set To Draft" type="object"/>
|
||||||
|
<field name="state" widget="statusbar" statusbar_visible="draft,posted,reconciled,cancelled"/>
|
||||||
|
</header>
|
||||||
<sheet>
|
<sheet>
|
||||||
<div class="oe_button_box" name="button_box">
|
<div class="oe_button_box" name="button_box">
|
||||||
<button class="oe_stat_button" name="button_journal_entries" string="Journal Items" type="object" groups="account.group_account_manager" attrs="{'invisible':[('move_line_ids','=',[])]}" icon="fa-bars"/>
|
<button class="oe_stat_button" name="button_journal_entries"
|
||||||
|
string="Journal Items" type="object"
|
||||||
|
groups="account.group_account_user"
|
||||||
|
attrs="{'invisible':[('move_line_ids','=',[])]}" icon="fa-bars"/>
|
||||||
<field name="move_line_ids" invisible="1"/>
|
<field name="move_line_ids" invisible="1"/>
|
||||||
<button class="oe_stat_button" name="button_invoices" string="Invoices" type="object" attrs="{'invisible':[('has_invoices','=',False)]}" icon="fa-bars"/>
|
<button class="oe_stat_button" name="button_invoices"
|
||||||
|
string="Invoices" type="object"
|
||||||
|
attrs="{'invisible':[('has_invoices','=',False)]}" icon="fa-bars"/>
|
||||||
|
<button class="oe_stat_button" name="open_payment_matching_screen"
|
||||||
|
string="Payment Matching" type="object"
|
||||||
|
attrs="{'invisible':[('move_reconciled','=',True)]}" icon="fa-university"/>
|
||||||
<field name="has_invoices" invisible="1"/>
|
<field name="has_invoices" invisible="1"/>
|
||||||
|
<field name="move_reconciled" invisible="1"/>
|
||||||
|
</div>
|
||||||
|
<field name="id" invisible="1"/>
|
||||||
|
<div class="oe_title" attrs="{'invisible': [('state', '=', 'draft')]}">
|
||||||
|
<h1><field name="name"/></h1>
|
||||||
</div>
|
</div>
|
||||||
<group>
|
<group>
|
||||||
<field name="payment_type" invisible="1"/>
|
|
||||||
<field name="partner_type" invisible="1"/>
|
|
||||||
<field name="state" invisible="1"/>
|
|
||||||
<group>
|
<group>
|
||||||
<field name="journal_id" widget="selection"/>
|
<field name="payment_type" widget="radio" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||||
<field name="partner_id"/>
|
<field name="partner_type" widget="selection" attrs="{'required': [('state', '=', 'draft'), ('payment_type', 'in', ('inbound', 'outbound'))], 'invisible': [('payment_type', 'not in', ('inbound', 'outbound'))], 'readonly': [('state', '!=', 'draft')]}"/>
|
||||||
<field name="hide_payment_method" invisible="1"/>
|
<field name="partner_id" attrs="{'required': [('state', '=', 'draft'), ('payment_type', 'in', ('inbound', 'outbound'))], 'invisible': [('payment_type', 'not in', ('inbound', 'outbound'))], 'readonly': [('state', '!=', 'draft')]}" context="{'default_is_company': True, 'default_supplier': payment_type == 'outbound', 'default_customer': payment_type == 'inbound'}"/>
|
||||||
<field name="payment_method_id" widget="radio" attrs="{'invisible': [('hide_payment_method', '=', True)]}"/>
|
|
||||||
<field name="payment_method_code" invisible="1"/>
|
|
||||||
<label for="amount"/>
|
<label for="amount"/>
|
||||||
<div name="amount_div" class="o_row">
|
<div name="amount_div" class="o_row">
|
||||||
<field name="amount"/>
|
<field name="amount" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||||
|
<field name="currency_id" options="{'no_create': True, 'no_open': True}" groups="base.group_multi_currency" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||||
</div>
|
</div>
|
||||||
|
<field name="journal_id" widget="selection" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||||
|
<field name="destination_journal_id" widget="selection" attrs="{'required': [('payment_type', '=', 'transfer')], 'invisible': [('payment_type', '!=', 'transfer')], 'readonly': [('state', '!=', 'draft')]}"/>
|
||||||
|
<field name="hide_payment_method" invisible="1"/>
|
||||||
|
<field name="payment_method_id" string=" " widget="radio" attrs="{'invisible': [('hide_payment_method', '=', True)], 'readonly': [('state', '!=', 'draft')]}"/>
|
||||||
|
<field name="payment_method_code" invisible="1"/>
|
||||||
</group>
|
</group>
|
||||||
<group>
|
<group>
|
||||||
<field name="payment_date"/>
|
<field name="payment_date" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||||
<field name="communication"/>
|
<field name="communication" attrs="{'invisible': [('state', '!=', 'draft'), ('communication', '=', False)], 'readonly': [('state', '!=', 'draft')]}"/>
|
||||||
<field name="folio_id"/>
|
<field name="folio_id"/>
|
||||||
</group>
|
</group>
|
||||||
<group attrs="{'invisible': [('payment_difference', '=', 0.0)]}">
|
|
||||||
<label for="payment_difference"/>
|
|
||||||
<div>
|
|
||||||
<field name="payment_difference"/>
|
|
||||||
<field name="payment_difference_handling" widget="radio" nolabel="1"/>
|
|
||||||
</div>
|
|
||||||
<field name="writeoff_account_id" string="Post Difference In"
|
|
||||||
attrs="{'invisible': [('payment_difference_handling','=','open')], 'required': [('payment_difference_handling', '=', 'reconcile')]}"/>
|
|
||||||
</group>
|
|
||||||
</group>
|
</group>
|
||||||
</sheet>
|
</sheet>
|
||||||
<footer>
|
<footer>
|
||||||
@@ -65,6 +75,10 @@
|
|||||||
attrs="{'invisible': [('state','=','draft')]}"/>
|
attrs="{'invisible': [('state','=','draft')]}"/>
|
||||||
<button string="Cancel" class="btn-default" special="cancel"/>
|
<button string="Cancel" class="btn-default" special="cancel"/>
|
||||||
</footer>
|
</footer>
|
||||||
|
<div class="oe_chatter">
|
||||||
|
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
|
||||||
|
<field name="message_ids" widget="mail_thread"/>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
@@ -27,20 +27,29 @@ class FolioAdvancePaymentInv(models.TransientModel):
|
|||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _get_default_folio(self):
|
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
|
return folios
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _get_default_reservation(self):
|
def _get_default_reservation(self):
|
||||||
folios = self._get_default_folio()
|
if self._context.get('default_reservation_id'):
|
||||||
reservations = self.env['hotel.reservation']
|
reservations = self.env['hotel.reservation'].browse(self._context.get('active_ids', []))
|
||||||
for folio in folios:
|
else:
|
||||||
reservations |= folio.room_lines
|
folios = self._get_default_folio()
|
||||||
|
reservations = self.env['hotel.reservation']
|
||||||
|
for folio in folios:
|
||||||
|
reservations |= folio.room_lines
|
||||||
return reservations
|
return reservations
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _get_default_partner_invoice(self):
|
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
|
@api.model
|
||||||
def _default_deposit_account_id(self):
|
def _default_deposit_account_id(self):
|
||||||
@@ -72,9 +81,6 @@ class FolioAdvancePaymentInv(models.TransientModel):
|
|||||||
'advance_inv_id',
|
'advance_inv_id',
|
||||||
string="Invoice Lines")
|
string="Invoice Lines")
|
||||||
view_detail = fields.Boolean('View Detail')
|
view_detail = fields.Boolean('View Detail')
|
||||||
line_ids = fields.One2many('line.advance.inv',
|
|
||||||
'advance_inv_id',
|
|
||||||
string="Lines")
|
|
||||||
#Advance Payment
|
#Advance Payment
|
||||||
product_id = fields.Many2one('product.product', string="Product",
|
product_id = fields.Many2one('product.product', string="Product",
|
||||||
domain=[('type', '=', 'service')], default=_default_product_id)
|
domain=[('type', '=', 'service')], default=_default_product_id)
|
||||||
@@ -215,7 +221,24 @@ class FolioAdvancePaymentInv(models.TransientModel):
|
|||||||
'tax_id': [(6, 0, tax_ids)],
|
'tax_id': [(6, 0, tax_ids)],
|
||||||
})
|
})
|
||||||
del context
|
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):
|
if self._context.get('open_invoices', False):
|
||||||
return folios.open_invoices_folio()
|
return folios.open_invoices_folio()
|
||||||
return {'type': 'ir.actions.act_window_close'}
|
return {'type': 'ir.actions.act_window_close'}
|
||||||
@@ -307,11 +330,12 @@ class FolioAdvancePaymentInv(models.TransientModel):
|
|||||||
invoice_lines = {}
|
invoice_lines = {}
|
||||||
reservations = self.env['hotel.reservation']
|
reservations = self.env['hotel.reservation']
|
||||||
services = self.env['hotel.service']
|
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
|
folio_reservations = folio.room_lines
|
||||||
if folio_reservations:
|
if folio_reservations:
|
||||||
reservations |= folio_reservations
|
reservations |= folio_reservations
|
||||||
self.reservation_ids = reservations
|
self.reservation_ids |= reservations
|
||||||
self.prepare_invoice_lines()
|
self.prepare_invoice_lines()
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
@@ -369,6 +393,12 @@ class LineAdvancePaymentInv(models.TransientModel):
|
|||||||
description = fields.Text('Description')
|
description = fields.Text('Description')
|
||||||
reservation_id = fields.Many2one('hotel.reservation')
|
reservation_id = fields.Many2one('hotel.reservation')
|
||||||
service_id = fields.Many2one('hotel.service')
|
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
|
@api.multi
|
||||||
def invoice_line_create(self, invoice_id, qty):
|
def invoice_line_create(self, invoice_id, qty):
|
||||||
@@ -380,7 +410,7 @@ class LineAdvancePaymentInv(models.TransientModel):
|
|||||||
invoice_lines = self.env['account.invoice.line']
|
invoice_lines = self.env['account.invoice.line']
|
||||||
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
|
precision = self.env['decimal.precision'].precision_get('Product Unit of Measure')
|
||||||
for line in self:
|
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 = {}
|
res = {}
|
||||||
product = line.product_id
|
product = line.product_id
|
||||||
account = product.property_account_income_id or product.categ_id.property_account_income_categ_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".') %
|
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))
|
(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:
|
if fpos:
|
||||||
account = fpos.map_account(account)
|
account = fpos.map_account(account)
|
||||||
|
|
||||||
@@ -403,10 +433,13 @@ class LineAdvancePaymentInv(models.TransientModel):
|
|||||||
'uom_id': product.uom_id.id,
|
'uom_id': product.uom_id.id,
|
||||||
'product_id': product.id or False,
|
'product_id': product.id or False,
|
||||||
'invoice_line_tax_ids': [(6, 0, origin.tax_ids.ids)],
|
'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)],
|
'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)
|
invoice_lines |= self.env['account.invoice.line'].create(vals)
|
||||||
|
|
||||||
return invoice_lines
|
return invoice_lines
|
||||||
|
|||||||
@@ -50,6 +50,7 @@
|
|||||||
<tree string="Lines" editable="bottom">
|
<tree string="Lines" editable="bottom">
|
||||||
<field name="product_id" invisible="1"/>
|
<field name="product_id" invisible="1"/>
|
||||||
<field name="reservation_id" />
|
<field name="reservation_id" />
|
||||||
|
<field name="service_id" />
|
||||||
<field name="description" />
|
<field name="description" />
|
||||||
<field name="qty" />
|
<field name="qty" />
|
||||||
<field name="discount" />
|
<field name="discount" />
|
||||||
|
|||||||
Reference in New Issue
Block a user