From d901ac98f55f77b1a900708e696994f08ad27abf Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Mon, 21 Jan 2019 10:38:06 +0100 Subject: [PATCH] [WIP] Invoice WorkFlow --- hotel/models/hotel_service.py | 63 +++++++--------- hotel/wizard/folio_make_invoice_advance.py | 75 +++++++++++++++---- .../folio_make_invoice_advance_views.xml | 5 +- 3 files changed, 91 insertions(+), 52 deletions(-) diff --git a/hotel/models/hotel_service.py b/hotel/models/hotel_service.py index 7e6505127..e472f3bad 100644 --- a/hotel/models/hotel_service.py +++ b/hotel/models/hotel_service.py @@ -2,7 +2,10 @@ # Copyright 2017 Dario Lodeiros # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import models, fields, api, _ -from odoo.tools import DEFAULT_SERVER_DATE_FORMAT +from odoo.tools import ( + float_is_zero, + float_compare, + DEFAULT_SERVER_DATE_FORMAT) from datetime import timedelta from odoo.exceptions import ValidationError from odoo.addons import decimal_precision as dp @@ -48,7 +51,6 @@ class HotelService(models.Model): @api.model def _default_folio_id(self): - import wdb; wdb.set_trace() if 'folio_id' in self._context: return self._context['folio_id'] return False @@ -59,15 +61,11 @@ class HotelService(models.Model): Compute the quantity to invoice. If the invoice policy is order, the quantity to invoice is calculated from the ordered quantity. Otherwise, the quantity delivered is used. """ - pass - #~ for line in self: - #~ if line.folio_id.state in ['confirm', 'done']: - #~ if line.room_type_id.product_id.invoice_policy == 'order': - #~ line.qty_to_invoice = line.nights - line.qty_invoiced - #~ else: - #~ line.qty_to_invoice = line.qty_delivered - line.qty_invoiced - #~ else: - #~ line.qty_to_invoice = 0 + for line in self: + if line.folio_id.state not in ['draft']: + line.qty_to_invoice = line.product_qty - line.qty_invoiced + else: + line.qty_to_invoice = 0 @api.depends('invoice_line_ids.invoice_id.state', 'invoice_line_ids.quantity') def _get_invoice_qty(self): @@ -77,16 +75,15 @@ class HotelService(models.Model): a refund made would automatically decrease the invoiced quantity, then there is a risk of reinvoicing it automatically, which may not be wanted at all. That's why the refund has to be created from the SO """ - pass - #~ for line in self: - #~ qty_invoiced = 0.0 - #~ for invoice_line in line.invoice_line_ids: - #~ if invoice_line.invoice_id.state != 'cancel': - #~ if invoice_line.invoice_id.type == 'out_invoice': - #~ qty_invoiced += invoice_line.uom_id._compute_quantity(invoice_line.quantity, line.product_uom) - #~ elif invoice_line.invoice_id.type == 'out_refund': - #~ qty_invoiced -= invoice_line.uom_id._compute_quantity(invoice_line.quantity, line.product_uom) - #~ line.qty_invoiced = qty_invoiced + for line in self: + qty_invoiced = 0.0 + for invoice_line in line.invoice_line_ids: + if invoice_line.invoice_id.state != 'cancel': + if invoice_line.invoice_id.type == 'out_invoice': + qty_invoiced += invoice_line.uom_id._compute_quantity(invoice_line.quantity, line.product_id.uom_id) + elif invoice_line.invoice_id.type == 'out_refund': + qty_invoiced -= invoice_line.uom_id._compute_quantity(invoice_line.quantity, line.product_id.uom_id) + line.qty_invoiced = qty_invoiced @api.depends('product_qty', 'qty_to_invoice', 'qty_invoiced') def _compute_invoice_status(self): @@ -103,20 +100,16 @@ class HotelService(models.Model): is removed from the list. - invoiced: the quantity invoiced is larger or equal to the quantity ordered. """ - pass - #~ precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') - #~ for line in self: - #~ if line.state not in ('sale', 'done'): - #~ line.invoice_status = 'no' - #~ elif not float_is_zero(line.qty_to_invoice, precision_digits=precision): - #~ line.invoice_status = 'to invoice' - #~ elif line.state == 'sale' and line.product_id.invoice_policy == 'order' and\ - #~ float_compare(line.qty_delivered, line.product_uom_qty, precision_digits=precision) == 1: - #~ line.invoice_status = 'upselling' - #~ elif float_compare(line.qty_invoiced, line.product_uom_qty, precision_digits=precision) >= 0: - #~ line.invoice_status = 'invoiced' - #~ else: - #~ line.invoice_status = 'no' + precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') + for line in self: + if line.folio_id.state in ('draft'): + line.invoice_status = 'no' + elif not float_is_zero(line.qty_to_invoice, precision_digits=precision): + line.invoice_status = 'to invoice' + elif float_compare(line.qty_invoiced, line.product_qty, precision_digits=precision) >= 0: + line.invoice_status = 'invoiced' + else: + line.invoice_status = 'no' name = fields.Char('Service description', required=True) sequence = fields.Integer(string='Sequence', default=10) diff --git a/hotel/wizard/folio_make_invoice_advance.py b/hotel/wizard/folio_make_invoice_advance.py index af5730db2..7448d558a 100644 --- a/hotel/wizard/folio_make_invoice_advance.py +++ b/hotel/wizard/folio_make_invoice_advance.py @@ -170,6 +170,26 @@ class FolioAdvancePaymentInv(models.TransientModel): subtype_id=self.env.ref('mail.mt_note').id) return invoice + @api.model + def _validate_invoices(self, invoice): + invoice.action_invoice_open() + payment_ids = self.folio_ids.mapped('payment_ids.id') + domain = [('account_id', '=', invoice.account_id.id), + ('payment_id', 'in', payment_ids), ('reconciled', '=', False), + '|', ('amount_residual', '!=', 0.0), + ('amount_residual_currency', '!=', 0.0)] + if invoice.type in ('out_invoice', 'in_refund'): + domain.extend([('credit', '>', 0), ('debit', '=', 0)]) + type_payment = _('Outstanding credits') + else: + domain.extend([('credit', '=', 0), ('debit', '>', 0)]) + type_payment = _('Outstanding debits') + info = {'title': '', 'outstanding': True, 'content': [], 'invoice_id': invoice.id} + lines = self.env['account.move.line'].search(domain) + currency_id = invoice.currency_id + for line in lines: + invoice.assign_outstanding_credit(line.id) + @api.multi def create_invoices(self): inv_obj = self.env['account.invoice'] @@ -185,6 +205,8 @@ class FolioAdvancePaymentInv(models.TransientModel): invoice = inv_obj.create(inv_data) for line in self.line_ids: line.invoice_line_create(invoice.id, line.qty) + self._validate_invoices(invoice) + elif self.advance_payment_method == 'all': pass #Group lines by tax_ids @@ -291,17 +313,19 @@ class FolioAdvancePaymentInv(models.TransientModel): description = folio.name + ' ' + reservation.room_type_id.name + ' (' + \ reservation.board_service_room_id.hotel_board_service_id.name + ')' \ if board_service else folio.name + ' ' + reservation.room_type_id.name - invoice_lines[group_key] = { - 'description' : description, - 'reservation_id': reservation.id, - 'room_type_id': reservation.room_type_id, - 'product_id': self.env['product.product'].browse( - reservation.room_type_id.product_id.id), - 'discount': day.discount, - 'price_unit': day.price + extra_price, - 'reservation_line_ids': [] - } - invoice_lines[group_key][('reservation_line_ids')].append((4,day.id)) + if group_key not in invoice_lines: + invoice_lines[group_key] = { + 'description' : description, + 'reservation_id': reservation.id, + 'room_type_id': reservation.room_type_id, + 'product_id': self.env['product.product'].browse( + reservation.room_type_id.product_id.id), + 'discount': day.discount, + 'price_unit': day.price + extra_price, + 'reservation_line_ids': [(4, day.id)] + } + else: + invoice_lines[group_key][('reservation_line_ids')].append((4,day.id)) for group_key in invoice_lines: vals.append((0, False, invoice_lines[group_key])) self.line_ids = vals @@ -368,7 +392,12 @@ class LineAdvancePaymentInv(models.TransientModel): product_id = fields.Many2one('product.product', string='Down Payment Product', domain=[('type', '=', 'service')]) qty = fields.Integer('Quantity') - price_unit = fields.Float('Price') + price_unit = fields.Float('Price Unit') + price_total = fields.Float('Price Total', compute='_compute_price_total') + price_tax = fields.Float('Price Tax', compute='_compute_price_total') + price_subtotal = fields.Float('Price Subtotal', + compute='_compute_price_total', + store=True) advance_inv_id = fields.Many2one('folio.advance.payment.inv') price_room = fields.Float(compute='_compute_price_room') discount = fields.Float( @@ -384,9 +413,25 @@ class LineAdvancePaymentInv(models.TransientModel): 'hotel.reservation.line', string='Reservation Lines') + @api.depends('qty', 'price_unit', 'discount') + def _compute_price_total(self): + for record in self: + origin = record.reservation_id if record.reservation_id.id else record.service_id + amount_line = record.price_unit * record.qty + if amount_line > 0: + product = record.product_id + price = amount_line * (1 - (record.discount or 0.0) * 0.01) + taxes = origin.tax_ids.compute_all(price, origin.currency_id, 1, product=product) + record.update({ + 'price_tax': sum(t.get('amount', 0.0) for t in taxes.get('taxes', [])), + 'price_total': taxes['total_included'], + 'price_subtotal': taxes['total_excluded'], + }) + def _compute_price_room(self): for record in self: - record.price_room = self.reservation_line_ids[0].price + if record.reservation_id: + record.price_room = record.reservation_line_ids[0].price def _compute_folio_id(self): for record in self: @@ -426,7 +471,6 @@ class LineAdvancePaymentInv(models.TransientModel): if fpos: account = fpos.map_account(account) vals = { - 'name': line.description, 'sequence': origin.sequence, 'origin': origin.name, 'account_id': account.id, @@ -441,13 +485,14 @@ class LineAdvancePaymentInv(models.TransientModel): } if line.reservation_id: vals.update({ + 'name': line.description + ' (' + line.description_dates + ')', 'invoice_id': invoice_id, 'reservation_ids': [(6, 0, [origin.id])], 'reservation_line_ids': [(6, 0, line.reservation_line_ids.ids)] }) - import wdb; wdb.set_trace() elif line.service_id: vals.update({ + 'name': line.description, 'invoice_id': invoice_id, 'service_ids': [(6, 0, [origin.id])] }) diff --git a/hotel/wizard/folio_make_invoice_advance_views.xml b/hotel/wizard/folio_make_invoice_advance_views.xml index 0bef64d74..690803d57 100644 --- a/hotel/wizard/folio_make_invoice_advance_views.xml +++ b/hotel/wizard/folio_make_invoice_advance_views.xml @@ -53,15 +53,16 @@ - + - + +