Decompose get_invoice_line and get_move

to ease the customization of invoice and shipment methods.

issue5059
review16751002
This commit is contained in:
Cédric Krier committed 2015-12-13 14:57:02 +01:00
1 parent fa449aafd9
commit bd04a1964a
1 file changed
+122 -90
+122 -90
View File
@@ -652,17 +652,6 @@ class Purchase(Workflow, ModelSQL, ModelView, TaxableMixin):
'total_amount_cache': purchase.total_amount,
})
def _get_invoice_line_purchase_line(self, invoice_type):
'''
Return invoice line for each purchase lines
'''
res = {}
for line in self.lines:
val = line.get_invoice_line(invoice_type)
if val:
res[line.id] = val
return res
def _get_invoice_purchase(self, invoice_type):
'''
Return invoice of type invoice_type
@@ -704,7 +693,11 @@ class Purchase(Workflow, ModelSQL, ModelView, TaxableMixin):
self.raise_user_error('missing_account_payable',
error_args=(self.party.rec_name,))
invoice_lines = self._get_invoice_line_purchase_line(invoice_type)
invoice_lines = {}
for line in self.lines:
ilines = line.get_invoice_line(invoice_type)
if ilines:
invoice_lines[line.id] = ilines
if not invoice_lines:
return
@@ -721,14 +714,16 @@ class Purchase(Workflow, ModelSQL, ModelView, TaxableMixin):
'''
Create move for each purchase lines
'''
new_moves = []
pool = Pool()
Move = pool.get('stock.move')
moves = []
for line in self.lines:
if (line.quantity >= 0) != (move_type == 'in'):
continue
move = line.create_move()
move = line.get_move(move_type)
if move:
new_moves.append(move)
return new_moves
moves.append(move)
Move.save(moves)
return moves
def _get_return_shipment(self):
ShipmentInReturn = Pool().get('stock.shipment.in.return')
@@ -1212,51 +1207,15 @@ class PurchaseLine(ModelSQL, ModelView):
invoice_line.note = self.note
invoice_line.origin = self
if self.type != 'line':
if (self.purchase.invoice_method == 'order'
and not self.invoice_lines
and ((all(l.quantity >= 0 for l in self.purchase.lines
if l.type == 'line')
and invoice_type == 'in_invoice')
or (all(l.quantity <= 0 for l in self.purchase.lines
if l.type == 'line')
and invoice_type == 'in_credit_note'))):
if self._get_invoice_not_line(invoice_type):
return [invoice_line]
else:
return []
if (invoice_type == 'in_invoice') != (self.quantity >= 0):
return []
stock_moves = []
if (self.purchase.invoice_method == 'order'
or not self.product
or self.product.type == 'service'):
quantity = abs(self.quantity)
stock_moves = self.moves
else:
quantity = 0.0
for move in self.moves:
if move.state == 'done':
quantity += Uom.compute_qty(move.uom, move.quantity,
self.unit)
if move.invoiced_quantity < move.quantity:
stock_moves.append(move)
invoice_line.stock_moves = stock_moves
skip_ids = set(l.id for i in self.purchase.invoices_recreated
for l in i.lines)
for old_invoice_line in self.invoice_lines:
if old_invoice_line.type != 'line':
continue
if old_invoice_line.id not in skip_ids:
if old_invoice_line.invoice:
old_invoice_type = old_invoice_line.invoice.type
else:
old_invoice_type = old_invoice_line.invoice_type
sign = 1 if old_invoice_type == invoice_type else -1
quantity -= Uom.compute_qty(old_invoice_line.unit,
sign * old_invoice_line.quantity, self.unit)
quantity = (self._get_invoice_line_quantity(invoice_type)
- self._get_invoiced_quantity(invoice_type))
rounding = self.unit.rounding if self.unit else 0.01
invoice_line.quantity = Uom.round(quantity, rounding)
@@ -1283,26 +1242,72 @@ class PurchaseLine(ModelSQL, ModelView):
if not invoice_line.account:
self.raise_user_error('missing_account_expense_property',
{'purchase': self.purchase.rec_name})
invoice_line.stock_moves = self._get_invoice_line_moves(invoice_type)
return [invoice_line]
@classmethod
def view_attributes(cls):
return [
('/form//field[@name="note"]|/form//field[@name="description"]',
'spell', Eval('_parent_purchase', {}).get('party_lang'))]
def _get_invoice_not_line(self, invoice_type):
'Return if the not line should be invoiced'
return (self.purchase.invoice_method == 'order'
and not self.invoice_lines
and ((all(l.quantity >= 0 for l in self.purchase.lines
if l.type == 'line')
and invoice_type == 'in_invoice')
or (all(l.quantity <= 0 for l in self.purchase.lines
if l.type == 'line')
and invoice_type == 'in_credit_note')))
@classmethod
def copy(cls, lines, default=None):
if default is None:
default = {}
default = default.copy()
default['moves'] = None
default['moves_ignored'] = None
default['moves_recreated'] = None
default['invoice_lines'] = None
return super(PurchaseLine, cls).copy(lines, default=default)
def _get_invoice_line_quantity(self, invoice_type):
'Return the quantity that should be invoiced'
pool = Pool()
Uom = pool.get('product.uom')
def get_move(self):
if (self.purchase.invoice_method == 'order'
or not self.product
or self.product.type == 'service'):
return abs(self.quantity)
elif self.purchase.invoice_method == 'shipment':
quantity = 0.0
for move in self.moves:
if move.state == 'done':
quantity += Uom.compute_qty(move.uom, move.quantity,
self.unit)
return quantity
def _get_invoiced_quantity(self, invoice_type):
'Return the quantity already invoiced'
pool = Pool()
Uom = pool.get('product.uom')
quantity = 0
skips = {l for i in self.purchase.invoices_recreated for l in i.lines}
for invoice_line in self.invoice_lines:
if invoice_line.type != 'line':
continue
if invoice_line not in skips:
if invoice_line.invoice:
line_type = invoice_line.invoice.type
else:
line_type = invoice_line.invoice_type
sign = 1 if line_type == invoice_type else -1
quantity += Uom.compute_qty(invoice_line.unit,
sign * invoice_line.quantity, self.unit)
return quantity
def _get_invoice_line_moves(self, invoice_type):
'Return the stock moves that should be invoiced'
moves = []
if self.purchase.invoice_method == 'order':
moves.extend(self.moves)
elif self.purchase.invoice_method == 'shipment':
for move in self.moves:
if move.state == 'done':
if move.invoiced_quantity < move.quantity:
moves.append(move)
return moves
def get_move(self, move_type):
'''
Return move values for purchase line
'''
@@ -1316,12 +1321,12 @@ class PurchaseLine(ModelSQL, ModelView):
return
if self.product.type == 'service':
return
skip = set(self.moves_recreated)
quantity = abs(self.quantity)
for move in self.moves:
if move not in skip:
quantity -= Uom.compute_qty(move.uom, move.quantity,
self.unit)
if (self.quantity >= 0) != (move_type == 'in'):
return
quantity = (self._get_move_quantity(move_type)
- self._get_shipped_quantity(move_type))
quantity = Uom.round(quantity, self.unit.rounding)
if quantity <= 0:
@@ -1343,20 +1348,47 @@ class PurchaseLine(ModelSQL, ModelView):
move.unit_price = self.unit_price
move.currency = self.purchase.currency
move.planned_date = self.delivery_date
move.invoice_lines = [l for l in self.invoice_lines
if not l.stock_moves]
move.invoice_lines = self._get_move_invoice_lines(move_type)
move.origin = self
return move
def create_move(self):
'''
Create move line
'''
move = self.get_move()
if not move:
return
move.save()
return move
def _get_move_quantity(self, move_type):
'Return the quantity that should be shipped'
return abs(self.quantity)
def _get_shipped_quantity(self, move_type):
'Return the quantity already shipped'
pool = Pool()
Uom = pool.get('product.uom')
quantity = 0
skip = set(self.moves_recreated)
for move in self.moves:
if move not in skip:
quantity += Uom.compute_qty(move.uom, move.quantity,
self.unit)
return quantity
def _get_move_invoice_lines(self, move_type):
'Return the invoice lines that should be shipped'
return [l for l in self.invoice_lines if not l.stock_moves]
@classmethod
def view_attributes(cls):
return [
('/form//field[@name="note"]|/form//field[@name="description"]',
'spell', Eval('_parent_purchase', {}).get('party_lang'))]
@classmethod
def copy(cls, lines, default=None):
if default is None:
default = {}
default = default.copy()
default['moves'] = None
default['moves_ignored'] = None
default['moves_recreated'] = None
default['invoice_lines'] = None
return super(PurchaseLine, cls).copy(lines, default=default)
class PurchaseLineTax(ModelSQL):