[ADD] Invoice qty

This commit is contained in:
Dario Lodeiros
2019-01-17 23:21:53 +01:00
parent 45ebbdc4a9
commit c5d3f7facc
7 changed files with 60 additions and 56 deletions

View File

@@ -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

View File

@@ -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):

View File

@@ -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')

View File

@@ -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)

View File

@@ -9,6 +9,9 @@
<field name="folio_ids" widget="many2many_tags"/>
<field name="from_folio" invisible="1" />
</xpath>
<xpath expr="//field[@name='product_id']" position="after">
<field name="reservation_line_ids" widget="many2many_tags"/>
</xpath>
<xpath expr="//button[@name='%(account.action_account_invoice_payment)d']" position="attributes">
<attribute name="attrs">{'invisible': ['|',('from_folio','=',True)]}</attribute>
</xpath>

View File

@@ -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

View File

@@ -49,6 +49,7 @@
nolabel="1">
<tree string="Lines" editable="bottom">
<field name="product_id" invisible="1"/>
<field name="reservation_line_ids" />
<field name="reservation_id" />
<field name="service_id" />
<field name="description" />