mirror of
https://github.com/OCA/pms.git
synced 2025-01-29 00:17:45 +02:00
[WIP] Invoice WorkFlow
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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])]
|
||||
})
|
||||
|
||||
@@ -53,15 +53,16 @@
|
||||
<field name="service_id"
|
||||
options="{'no_create': True,'no_open': True}"/>
|
||||
<field name="description" />
|
||||
<field name="description_dates" readonly="1" />
|
||||
<field name="description_dates" readonly="1" force_save="1"/>
|
||||
<field name="reservation_line_ids"
|
||||
widget="many2many_tags" string="Nights"
|
||||
domain="[('reservation_id','=',reservation_id),
|
||||
('price','=', price_room)]"
|
||||
options="{'no_create': True,'no_open': True}"/>
|
||||
<field name="qty" />
|
||||
<field name="discount" />
|
||||
<field name="price_unit" />
|
||||
<field name="discount" />
|
||||
<field name="price_total" />
|
||||
</tree>
|
||||
</field>
|
||||
</group>
|
||||
|
||||
Reference in New Issue
Block a user