From c5d3f7faccfa8422d5a116ac57e14df61440bdad Mon Sep 17 00:00:00 2001 From: Dario Lodeiros Date: Thu, 17 Jan 2019 23:21:53 +0100 Subject: [PATCH] [ADD] Invoice qty --- hotel/models/hotel_reservation.py | 75 +++++++------------ hotel/models/hotel_reservation_line.py | 7 +- hotel/models/hotel_service.py | 1 - .../models/inherited_account_invoice_line.py | 8 +- .../views/inherited_account_invoice_views.xml | 3 + hotel/wizard/folio_make_invoice_advance.py | 21 ++++-- .../folio_make_invoice_advance_views.xml | 1 + 7 files changed, 60 insertions(+), 56 deletions(-) diff --git a/hotel/models/hotel_reservation.py b/hotel/models/hotel_reservation.py index 06f3234b8..1863c09e7 100644 --- a/hotel/models/hotel_reservation.py +++ b/hotel/models/hotel_reservation.py @@ -82,31 +82,22 @@ class HotelReservation(models.Model): def _compute_invoice_status(self): """ Compute the invoice status of a Reservation. Possible statuses: - - no: if the SO is not in status 'sale' or 'done', we consider that there is nothing to + - no: if the Folio is not in status 'sale' or 'done', we consider that there is nothing to invoice. This is also hte default value if the conditions of no other status is met. - to invoice: we refer to the quantity to invoice of the line. Refer to method `_get_to_invoice_qty()` for more information on how this quantity is calculated. - - upselling: this is possible only for a product invoiced on ordered quantities for which - we delivered more than expected. The could arise if, for example, a project took more - time than expected but we decided not to invoice the extra cost to the client. This - occurs onyl in state 'sale', so that when a SO is set to done, the upselling opportunity - 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 ('confirm', '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.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, len(line.reservation_line_ids), precision_digits=precision) >= 0: + line.invoice_status = 'invoiced' + else: + line.invoice_status = 'no' @api.model @@ -269,7 +260,6 @@ class HotelReservation(models.Model): related='pricelist_id.currency_id', string='Currency', readonly=True, required=True) invoice_status = fields.Selection([ - ('upselling', 'Upselling Opportunity'), ('invoiced', 'Fully Invoiced'), ('to invoice', 'To Invoice'), ('no', 'Nothing to Invoice') @@ -283,7 +273,7 @@ class HotelReservation(models.Model): qty_invoiced = fields.Float( compute='_get_invoice_qty', string='Invoiced', store=True, readonly=True, digits=dp.get_precision('Product Unit of Measure')) - invoice_line_ids = fields.Many2many('account.invoice.line', 'reservation_line_invoice_rel', 'reservation_id', 'invoice_line_id', string='Invoice Lines', copy=False) + invoice_line_ids = fields.Many2many('account.invoice.line', 'reservation_invoice_rel', 'reservation_id', 'invoice_line_id', string='Invoice Lines', copy=False) # qty_delivered = fields.Float(string='Delivered', copy=False, digits=dp.get_precision('Product Unit of Measure'), default=0.0) # qty_delivered_updateable = fields.Boolean(compute='_compute_qty_delivered_updateable', string='Can Edit Delivered', readonly=True, default=True) price_subtotal = fields.Monetary(string='Subtotal', @@ -327,7 +317,7 @@ class HotelReservation(models.Model): vals.update({'folio_id': folio.id, 'reservation_type': vals.get('reservation_type'), 'channel_type': vals.get('channel_type')}) - if 'service_ids' in vals: + if 'service_ids' in vals and vals['service_ids'][0][2]: for service in vals['service_ids']: service[2]['folio_id'] = folio.id vals.update({ @@ -1043,7 +1033,7 @@ class HotelReservation(models.Model): 'ignore_avail_restrictions': True}).create(vals) if not reservation_copy: raise ValidationError(_("Unexpected error copying record. \ - Can't split reservation!")) + Can't split reservation!")) record.write({ 'checkout': new_start_date_dt.strftime(DEFAULT_SERVER_DATETIME_FORMAT), 'price_total': tprice[0], @@ -1189,31 +1179,22 @@ class HotelReservation(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 = len(line.reservation_line_ids) - 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): """ - Compute the quantity invoiced. If case of a refund, the quantity invoiced is decreased. Note - that this is the case only if the refund is generated from the SO and that is intentional: if - 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 + Compute the quantity invoiced. If case of a refund, the quantity invoiced is decreased. We + must check day per day and sum or decreased on 1 unit per invoice_line """ - 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 day in line.reservation_line_ids: + invoice_lines = day.invoice_line_ids.filtered(lambda r: r.invoice_id.state != 'cancel') + qty_invoiced += len(invoice_lines.filtered(lambda r: r.invoice_id.type == 'out_invoice')) - \ + len(invoice_lines.filtered(lambda r: r.invoice_id.type == 'out_refund')) + line.qty_invoiced = qty_invoiced diff --git a/hotel/models/hotel_reservation_line.py b/hotel/models/hotel_reservation_line.py index c5120ff65..84a1e5ff5 100644 --- a/hotel/models/hotel_reservation_line.py +++ b/hotel/models/hotel_reservation_line.py @@ -17,8 +17,11 @@ class HotelReservationLine(models.Model): discount = fields.Float( string='Discount (%)', digits=dp.get_precision('Discount'), default=0.0) - invoiced = fields.Boolean('Invoiced') - + invoice_line_ids = fields.Many2many( + 'account.invoice.line', + 'reservation_line_invoice_rel', + 'reservation_line_id', 'invoice_line_id', + string='Invoice Lines', readonly=True, copy=False) @api.constrains('date') def constrains_duplicated_date(self): diff --git a/hotel/models/hotel_service.py b/hotel/models/hotel_service.py index 309a59c29..7e6505127 100644 --- a/hotel/models/hotel_service.py +++ b/hotel/models/hotel_service.py @@ -135,7 +135,6 @@ class HotelService(models.Model): product_image = fields.Binary('Product Image', related="product_id.image", store=False) company_id = fields.Many2one(related='folio_id.company_id', string='Company', store=True, readonly=True) invoice_status = fields.Selection([ - ('upselling', 'Upselling Opportunity'), ('invoiced', 'Fully Invoiced'), ('to invoice', 'To Invoice'), ('no', 'Nothing to Invoice') diff --git a/hotel/models/inherited_account_invoice_line.py b/hotel/models/inherited_account_invoice_line.py index 1c251cc37..3a5e6ff16 100644 --- a/hotel/models/inherited_account_invoice_line.py +++ b/hotel/models/inherited_account_invoice_line.py @@ -8,7 +8,7 @@ class AccountInvoiceLine(models.Model): reservation_ids = fields.Many2many( 'hotel.reservation', - 'reservation_line_invoice_rel', + 'reservation_invoice_rel', 'invoice_line_id', 'reservation_id', string='Reservations', readonly=True, copy=False) service_ids = fields.Many2many( @@ -16,3 +16,9 @@ class AccountInvoiceLine(models.Model): 'service_line_invoice_rel', 'invoice_line_id', 'service_id', string='Services', readonly=True, copy=False) + reservation_line_ids = fields.Many2many( + 'hotel.reservation.line', + 'reservation_line_invoice_rel', + 'invoice_line_id', 'reservation_line_id', + string='Reservation Lines', readonly=True, copy=False) + diff --git a/hotel/views/inherited_account_invoice_views.xml b/hotel/views/inherited_account_invoice_views.xml index 02f80b616..775bb1912 100644 --- a/hotel/views/inherited_account_invoice_views.xml +++ b/hotel/views/inherited_account_invoice_views.xml @@ -9,6 +9,9 @@ + + + {'invisible': ['|',('from_folio','=',True)]} diff --git a/hotel/wizard/folio_make_invoice_advance.py b/hotel/wizard/folio_make_invoice_advance.py index d7b28febf..c42df85a6 100644 --- a/hotel/wizard/folio_make_invoice_advance.py +++ b/hotel/wizard/folio_make_invoice_advance.py @@ -317,8 +317,10 @@ class FolioAdvancePaymentInv(models.TransientModel): 'qty': 1, 'discount': day.discount, 'price_unit': day.price + extra_price, - 'date_to': day.date + 'date_to': day.date, + 'reservation_line_ids': [] } + 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 @@ -394,6 +396,9 @@ class LineAdvancePaymentInv(models.TransientModel): reservation_id = fields.Many2one('hotel.reservation') service_id = fields.Many2one('hotel.service') folio_id = fields.Many2one('hotel.folio', compute='_compute_folio_id') + reservation_line_ids = fields.Many2many( + 'hotel.reservation.line', + string='Reservation Lines') def _compute_folio_id(self): for record in self: @@ -421,7 +426,6 @@ class LineAdvancePaymentInv(models.TransientModel): fpos = line.folio_id.fiscal_position_id or line.folio_id.partner_id.property_account_position_id if fpos: account = fpos.map_account(account) - vals = { 'name': line.description, 'sequence': origin.sequence, @@ -434,12 +438,19 @@ class LineAdvancePaymentInv(models.TransientModel): 'product_id': product.id or False, 'invoice_line_tax_ids': [(6, 0, origin.tax_ids.ids)], '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)] } if line.reservation_id: - vals.update({'invoice_id': invoice_id, 'reservation_ids': [(6, 0, [origin.id])]}) + vals.update({ + 'invoice_id': invoice_id, + 'reservation_ids': [(6, 0, [origin.id])], + 'reservation_line_ids': [(6, 0, line.reservation_line_ids.ids)] + }) elif line.service_id: - vals.update({'invoice_id': invoice_id, 'service_ids': [(6, 0, [origin.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 db8c08a03..38a6de868 100644 --- a/hotel/wizard/folio_make_invoice_advance_views.xml +++ b/hotel/wizard/folio_make_invoice_advance_views.xml @@ -49,6 +49,7 @@ nolabel="1"> +