[tryton-debian-vcs] tryton-modules-stock branch debian updated. debian/3.0.1-2-4-gfe1db50
Mathias Behrle
tryton-debian-vcs at alioth.debian.org
Tue Apr 22 13:10:38 UTC 2014
The following commit has been merged in the debian branch:
https://alioth.debian.org/plugins/scmgit/cgi-bin/gitweb.cgi/?p=tryton/tryton-modules-stock.git;a=commitdiff;h=debian/3.0.1-2-4-gfe1db50
commit fe1db50d3a2ea393bf4ecae96714857ad3ab1c15
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Tue Apr 22 15:00:21 2014 +0200
Bumping minimal required Python version to 2.7.
diff --git a/debian/control b/debian/control
index ba0053e..cdcf41b 100644
--- a/debian/control
+++ b/debian/control
@@ -9,7 +9,7 @@ Standards-Version: 3.9.5
Homepage: http://www.tryton.org/
Vcs-Browser: http://anonscm.debian.org/gitweb/?p=tryton/tryton-modules-stock.git
Vcs-Git: git://anonscm.debian.org/tryton/tryton-modules-stock.git
-X-Python-Version: >= 2.6
+X-Python-Version: >= 2.7
Package: tryton-modules-stock
Architecture: all
commit bf33b1610793234ddae8267a7309c2bcf04dfec4
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Tue Apr 22 14:46:52 2014 +0200
Updating copyright.
diff --git a/debian/copyright b/debian/copyright
index 79dc1e6..b9b85af 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -2,9 +2,9 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Files: *
Copyright: 2012 Openlabs Technologies & Consulting (P) LTD
- 2008-2013 Cédric Krier
+ 2008-2014 Cédric Krier
2008-2013 Bertrand Chenal
- 2008-2013 B2CK SPRL
+ 2008-2014 B2CK SPRL
2004-2008 Tiny SPRL
License: GPL-3+
commit cc234e8449583df9e07571f65cc4c354369f5369
Author: Mathias Behrle <mathiasb at m9s.biz>
Date: Tue Apr 22 14:23:40 2014 +0200
Merging upstream version 3.2.0.
diff --git a/CHANGELOG b/CHANGELOG
index e2c3071..8f18144 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,13 @@
-Version 3.0.1 - 2014-01-18
+Version 3.2.0 - 2014-04-21
* Bug fixes (see mercurial logs for details)
+* Add warning for moves without origin
+* Allow to define the effective date of shipments
+* Prevent changing product type if stock moves exist
+* Use new methods to compute quantities in StockMixin._search_quantity()
+* Split products_by_location into two methods on Move:
+ compute_quantities_query and compute_quantities
+* Use origin for inventory moves
+* Allow partial assignation on Supplier Shipment Return
Version 3.0.0 - 2013-10-21
* Bug fixes (see mercurial logs for details)
diff --git a/COPYRIGHT b/COPYRIGHT
index b9e8d97..06390fa 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -1,7 +1,7 @@
Copyright (C) 2012 Openlabs Technologies & Consulting (P) LTD.
-Copyright (C) 2008-2013 Cédric Krier.
+Copyright (C) 2008-2014 Cédric Krier.
Copyright (C) 2008-2013 Bertrand Chenal.
-Copyright (C) 2008-2013 B2CK SPRL.
+Copyright (C) 2008-2014 B2CK SPRL.
Copyright (C) 2004-2008 Tiny SPRL.
This program is free software: you can redistribute it and/or modify
diff --git a/INSTALL b/INSTALL
index 3902b76..1f11ac2 100644
--- a/INSTALL
+++ b/INSTALL
@@ -4,7 +4,7 @@ Installing trytond_stock
Prerequisites
-------------
- * Python 2.6 or later (http://www.python.org/)
+ * Python 2.7 or later (http://www.python.org/)
* trytond (http://www.tryton.org/)
* python-sql (http://code.google.com/p/python-sql/)
* trytond_party (http://www.tryton.org/)
diff --git a/MANIFEST.in b/MANIFEST.in
index f040e5e..fb91042 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,5 @@
include INSTALL
include README
-include TODO
include COPYRIGHT
include CHANGELOG
include LICENSE
diff --git a/PKG-INFO b/PKG-INFO
index be9e89d..a395af4 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,12 @@
Metadata-Version: 1.1
Name: trytond_stock
-Version: 3.0.1
+Version: 3.2.0
Summary: Tryton module for stock and inventory
Home-page: http://www.tryton.org/
Author: Tryton
-Author-email: UNKNOWN
+Author-email: issue_tracker at tryton.org
License: GPL-3
-Download-URL: http://downloads.tryton.org/3.0/
+Download-URL: http://downloads.tryton.org/3.2/
Description: trytond_stock
=============
@@ -43,6 +43,7 @@ Description: trytond_stock
http://www.tryton.org/
+Keywords: tryton stock
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Plugins
@@ -63,6 +64,5 @@ Classifier: Natural Language :: Russian
Classifier: Natural Language :: Slovenian
Classifier: Natural Language :: Spanish
Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Topic :: Office/Business
diff --git a/inventory.py b/inventory.py
index b4c6218..3c515b3 100644
--- a/inventory.py
+++ b/inventory.py
@@ -21,14 +21,14 @@ class Inventory(Workflow, ModelSQL, ModelView):
'stock.location', 'Location', required=True,
domain=[('type', '=', 'storage')], states={
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('lines'))),
+ Bool(Eval('lines', [0]))),
},
- depends=['state', 'lines'])
+ depends=['state'])
date = fields.Date('Date', required=True, states={
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('lines'))),
+ Bool(Eval('lines', [0]))),
},
- depends=['state', 'lines'])
+ depends=['state'])
lost_found = fields.Many2One(
'stock.location', 'Lost and Found', required=True,
domain=[('type', '=', 'lost_found')], states=STATES, depends=DEPENDS)
@@ -38,9 +38,9 @@ class Inventory(Workflow, ModelSQL, ModelView):
company = fields.Many2One('company.company', 'Company', required=True,
states={
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('lines'))),
+ Bool(Eval('lines', [0]))),
},
- depends=['state', 'lines'])
+ depends=['state'])
state = fields.Selection([
('draft', 'Draft'),
('done', 'Done'),
@@ -117,7 +117,7 @@ class Inventory(Workflow, ModelSQL, ModelView):
@Workflow.transition('done')
def confirm(self, inventories):
Move = Pool().get('stock.move')
- move_ids = []
+ moves = []
for inventory in inventories:
keys = set()
for line in inventory.lines:
@@ -126,11 +126,12 @@ class Inventory(Workflow, ModelSQL, ModelView):
self.raise_user_error('unique_line',
(line.rec_name, inventory.rec_name))
keys.add(key)
- move_id = line.create_move()
- if move_id:
- move_ids.append(move_id)
- if move_ids:
- Move.do(Move.browse(move_ids))
+ move = line.get_move()
+ if move:
+ moves.append(move)
+ if moves:
+ moves = Move.create([m._save_values for m in moves])
+ Move.do(moves)
@classmethod
@ModelView.button
@@ -158,7 +159,7 @@ class Inventory(Workflow, ModelSQL, ModelView):
Line.copy(inventory.lines,
default={
'inventory': new_inventory.id,
- 'move': None,
+ 'moves': None,
})
cls.complete_lines([new_inventory])
new_inventories.append(new_inventory)
@@ -230,8 +231,7 @@ class InventoryLine(ModelSQL, ModelView):
domain=[
('type', '=', 'goods'),
('consumable', '=', False),
- ],
- on_change=['product'])
+ ])
uom = fields.Function(fields.Many2One('product.uom', 'UOM'), 'get_uom')
unit_digits = fields.Function(fields.Integer('Unit Digits'),
'get_unit_digits')
@@ -240,7 +240,7 @@ class InventoryLine(ModelSQL, ModelView):
depends=['unit_digits'])
quantity = fields.Float('Quantity', required=True,
digits=(16, Eval('unit_digits', 2)), depends=['unit_digits'])
- move = fields.Many2One('stock.move', 'Move', readonly=True)
+ moves = fields.One2Many('stock.move', 'origin', 'Moves', readonly=True)
inventory = fields.Many2One('stock.inventory', 'Inventory', required=True,
ondelete='CASCADE')
@@ -257,6 +257,10 @@ class InventoryLine(ModelSQL, ModelView):
def __register__(cls, module_name):
TableHandler = backend.get('TableHandler')
cursor = Transaction().cursor
+ pool = Pool()
+ Move = pool.get('stock.move')
+ sql_table = cls.__table__()
+ move_table = Move.__table__()
super(InventoryLine, cls).__register__(module_name)
@@ -264,6 +268,17 @@ class InventoryLine(ModelSQL, ModelView):
# Migration from 2.8: Remove constraint inventory_product_uniq
table.drop_constraint('inventory_product_uniq')
+ # Migration from 3.0: use Move origin
+ if table.column_exist('move'):
+ cursor.execute(*sql_table.select(sql_table.id, sql_table.move,
+ where=sql_table.move != None))
+ for line_id, move_id in cursor.fetchall():
+ cursor.execute(*move_table.update(
+ columns=[move_table.origin],
+ values=['%s,%s' % (cls.__name__, line_id)],
+ where=move_table.id == move_id))
+ table.drop_column('move')
+
@staticmethod
def default_unit_digits():
return 2
@@ -272,6 +287,7 @@ class InventoryLine(ModelSQL, ModelView):
def default_expected_quantity():
return 0.
+ @fields.depends('product')
def on_change_product(self):
change = {}
change['unit_digits'] = 2
@@ -297,13 +313,11 @@ class InventoryLine(ModelSQL, ModelView):
@classmethod
def cancel_move(cls, lines):
Move = Pool().get('stock.move')
- Move.cancel([l.move for l in lines if l.move])
- Move.delete([l.move for l in lines if l.move])
- cls.write([l for l in lines if l.move], {
- 'move': None,
- })
+ moves = [m for l in lines for m in l.moves if l.moves]
+ Move.cancel(moves)
+ Move.delete(moves)
- def _get_move(self):
+ def get_move(self):
'''
Return Move instance for the inventory line
'''
@@ -322,7 +336,7 @@ class InventoryLine(ModelSQL, ModelView):
(from_location, to_location, delta_qty) = \
(to_location, from_location, -delta_qty)
- move = Move(
+ return Move(
from_location=from_location,
to_location=to_location,
quantity=delta_qty,
@@ -330,16 +344,8 @@ class InventoryLine(ModelSQL, ModelView):
uom=self.uom,
company=self.inventory.company,
effective_date=self.inventory.date,
+ origin=self,
)
- return move
-
- def create_move(self):
- '''
- Create move for an inventory line and return id
- '''
- self.move = self._get_move()
- self.save()
- return self.move.id if self.move else None
def update_values4complete(self, quantity, uom_id):
'''
diff --git a/locale/bg_BG.po b/locale/bg_BG.po
index 1fe13bc..c63aaef 100644
--- a/locale/bg_BG.po
+++ b/locale/bg_BG.po
@@ -10,6 +10,11 @@ msgstr ""
"Не може да променяте мер. ед. на продукт който е свързан с движения на "
"наличност."
+msgctxt "error:product.template:"
+msgid ""
+"You cannot change the type for a product which is associated to stock moves."
+msgstr ""
+
msgctxt "error:stock.inventory.line:"
msgid "Line quantity must be positive."
msgstr ""
@@ -45,6 +50,10 @@ msgid "Source and destination location must be different"
msgstr "Източника и целта на местонахождението трябва да са различни"
msgctxt "error:stock.move:"
+msgid "The stock move \"%s\" has no origin."
+msgstr ""
+
+msgctxt "error:stock.move:"
msgid ""
"You can not delete stock move \"%s\" because it is not in draft or cancelled"
" state."
@@ -279,9 +288,10 @@ msgctxt "field:stock.inventory.line,inventory:"
msgid "Inventory"
msgstr "Инвентаризация"
-msgctxt "field:stock.inventory.line,move:"
-msgid "Move"
-msgstr "Движение"
+#, fuzzy
+msgctxt "field:stock.inventory.line,moves:"
+msgid "Moves"
+msgstr "Движения"
msgctxt "field:stock.inventory.line,product:"
msgid "Product"
@@ -1981,6 +1991,11 @@ msgctxt "view:product.by_location.start:"
msgid "Product by Location"
msgstr "Продукт по местонахождение"
+#, fuzzy
+msgctxt "view:product.product:"
+msgid "Cost Value"
+msgstr "Себестойност"
+
msgctxt "view:product.product:"
msgid "Products"
msgstr "Продукти"
@@ -2177,9 +2192,10 @@ msgctxt "view:stock.shipment.internal:"
msgid "Internal Shipments"
msgstr "Вътрешни пратки"
+#, fuzzy
msgctxt "view:stock.shipment.internal:"
-msgid "Waiting"
-msgstr "Изчакващ"
+msgid "Wait"
+msgstr "Очаквано"
msgctxt "view:stock.shipment.out.assign.failed:"
msgid "Unable to Assign"
@@ -2257,9 +2273,10 @@ msgctxt "view:stock.shipment.out:"
msgid "Outgoing Moves"
msgstr "Изходящи движения"
+#, fuzzy
msgctxt "view:stock.shipment.out:"
-msgid "Waiting"
-msgstr "Изчакващ"
+msgid "Wait"
+msgstr "Очаквано"
msgctxt "wizard_button:product.by_location,start,end:"
msgid "Cancel"
diff --git a/locale/ca_ES.po b/locale/ca_ES.po
index 856c644..7d47685 100644
--- a/locale/ca_ES.po
+++ b/locale/ca_ES.po
@@ -8,7 +8,14 @@ msgid ""
" moves."
msgstr ""
"No podeu canviar la UdM predeterminada d'un producte que està associat amb "
-"moviments d'existències."
+"moviments d'estoc."
+
+msgctxt "error:product.template:"
+msgid ""
+"You cannot change the type for a product which is associated to stock moves."
+msgstr ""
+"No podeu canviar el tipus d'un producte que està associat amb moviments "
+"d'estoc."
msgctxt "error:stock.inventory.line:"
msgid "Line quantity must be positive."
@@ -33,7 +40,7 @@ msgid ""
"Location \"%s\" with existing moves cannot be changed to a type that does "
"not support moves."
msgstr ""
-"No es pot canviar la ubicació \"%s\" amb moviments existens a un tipus que "
+"No es pot canviar la ubicació \"%s\" amb moviments existents a un tipus que "
"no suporta moviments."
msgctxt "error:stock.move:"
@@ -49,6 +56,10 @@ msgid "Source and destination location must be different"
msgstr "Les ubicacions origen i destí han de ser diferents."
msgctxt "error:stock.move:"
+msgid "The stock move \"%s\" has no origin."
+msgstr "El moviment d'estoc \"%s\" no té origen."
+
+msgctxt "error:stock.move:"
msgid ""
"You can not delete stock move \"%s\" because it is not in draft or cancelled"
" state."
@@ -66,7 +77,7 @@ msgctxt "error:stock.move:"
msgid "You can not modify stock move \"%s\" because it is in \"Assigned\" state."
msgstr ""
"No podeu canviar el moviment d'estoc \"%s\" perquè es troba en l'estat "
-"\"Assignat\"."
+"\"Reservat\"."
msgctxt "error:stock.move:"
msgid ""
@@ -78,7 +89,7 @@ msgstr ""
msgctxt "error:stock.move:"
msgid "You can not set stock move \"%s\" to assigned state."
-msgstr "No podeu canviar el moviment d'estoc \"%s\" a estat assignat."
+msgstr "No podeu canviar el moviment d'estoc \"%s\" a estat reservat."
msgctxt "error:stock.move:"
msgid "You can not set stock move \"%s\" to done state."
@@ -90,11 +101,11 @@ msgstr "No podeu canviar el moviment d'estoc \"%s\" a estat esborrany."
msgctxt "error:stock.period:"
msgid "You can not close a period in the future or today."
-msgstr "No es pot tancar un període d'avui o proximament."
+msgstr "No es pot tancar un període actual o futur."
msgctxt "error:stock.period:"
msgid "You can not close a period when there still are assigned moves."
-msgstr "No podeu tancar un període que encara te moviments assignats."
+msgstr "No podeu tancar un període que encara té moviments reservats."
msgctxt "error:stock.shipment.in.return:"
msgid "Supplier Return Shipment \"%s\" must be cancelled before deletion."
@@ -114,8 +125,8 @@ msgctxt "error:stock.shipment.in:"
msgid ""
"Inventory Moves must have the warehouse input location as source location."
msgstr ""
-"Els moviments d'inventari han de tenir la ubicació d'entrada del magatzem "
-"com a ubicació origen."
+"Els moviments interns han de tenir la ubicació d'entrada del magatzem com a "
+"ubicació origen."
msgctxt "error:stock.shipment.in:"
msgid "Supplier Shipment \"%s\" must be cancelled before deletion."
@@ -299,9 +310,9 @@ msgctxt "field:stock.inventory.line,inventory:"
msgid "Inventory"
msgstr "Inventari"
-msgctxt "field:stock.inventory.line,move:"
-msgid "Move"
-msgstr "Moviment"
+msgctxt "field:stock.inventory.line,moves:"
+msgid "Moves"
+msgstr "Moviments"
msgctxt "field:stock.inventory.line,product:"
msgid "Product"
@@ -673,7 +684,7 @@ msgstr "Moviments d'entrada"
msgctxt "field:stock.shipment.in,inventory_moves:"
msgid "Inventory Moves"
-msgstr "Moviments d'inventari"
+msgstr "Moviments interns"
msgctxt "field:stock.shipment.in,moves:"
msgid "Moves"
@@ -905,7 +916,7 @@ msgstr "ID"
msgctxt "field:stock.shipment.out,inventory_moves:"
msgid "Inventory Moves"
-msgstr "Moviments d'inventari"
+msgstr "Moviments interns"
msgctxt "field:stock.shipment.out,moves:"
msgid "Moves"
@@ -961,7 +972,7 @@ msgstr "ID"
msgctxt "field:stock.shipment.out.assign.failed,inventory_moves:"
msgid "Inventory Moves"
-msgstr "Moviments d'inventari"
+msgstr "Moviments interns"
msgctxt "field:stock.shipment.out.return,code:"
msgid "Code"
@@ -1005,7 +1016,7 @@ msgstr "Moviments d'entrada"
msgctxt "field:stock.shipment.out.return,inventory_moves:"
msgid "Inventory Moves"
-msgstr "Moviments d'inventari"
+msgstr "Moviments interns"
msgctxt "field:stock.shipment.out.return,moves:"
msgid "Moves"
@@ -1151,7 +1162,7 @@ msgstr "Crea albarà de devolució"
msgctxt "model:ir.action,name:report_shipment_in_restocking_list"
msgid "Restocking List"
-msgstr "Llista de renovació d'inventari"
+msgstr "Llista de proveïment"
msgctxt "model:ir.action,name:report_shipment_internal"
msgid "Internal Shipment"
@@ -1159,7 +1170,7 @@ msgstr "Albarans interns"
msgctxt "model:ir.action,name:report_shipment_out_delivery_note"
msgid "Delivery Note"
-msgstr "Nota enviament"
+msgstr "Nota d'enviament"
msgctxt "model:ir.action,name:report_shipment_out_picking_list"
msgid "Picking List"
@@ -1167,7 +1178,7 @@ msgstr "Llista de selecció"
msgctxt "model:ir.action,name:report_shipment_out_return_restocking_list"
msgid "Restocking List"
-msgstr "Llista de renovació d'inventari"
+msgstr "Llista de proveïment"
msgctxt "model:ir.action,name:wizard_product_by_location"
msgid "Product by Locations"
@@ -1183,15 +1194,15 @@ msgstr "Productes per ubicació"
msgctxt "model:ir.action,name:wizard_shipment_in_return_assign"
msgid "Assign Purchase Return Shipment"
-msgstr "Assignar albarà de devolució de compra"
+msgstr "Reserva albarà de devolució de compra"
msgctxt "model:ir.action,name:wizard_shipment_internal_assign"
msgid "Assign Shipment Internal"
-msgstr "Assignar albarà intern"
+msgstr "Reserva albarà intern"
msgctxt "model:ir.action,name:wizard_shipment_out_assign"
msgid "Assign Shipment Out"
-msgstr "Assignació d'albarà de sortida"
+msgstr "Reserva albarà de sortida"
msgctxt "model:ir.action.act_window.domain,name:act_inventory_form_domain_all"
msgid "All"
@@ -1244,7 +1255,7 @@ msgstr "Tots"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_in_return_form_domain_assigned"
msgid "Assigned"
-msgstr "Assignat"
+msgstr "Reservat"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_in_return_form_domain_draft"
@@ -1254,7 +1265,7 @@ msgstr "Esborrany"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_in_return_form_domain_waiting"
msgid "Waiting"
-msgstr "Esperant"
+msgstr "En espera"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_internal_form_domain_all"
@@ -1264,7 +1275,7 @@ msgstr "Tots"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_internal_form_domain_assigned"
msgid "Assigned"
-msgstr "Assignat"
+msgstr "Reservat"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_internal_form_domain_draft"
@@ -1274,7 +1285,7 @@ msgstr "Esborrany"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_internal_form_domain_waiting"
msgid "Waiting"
-msgstr "Esperant"
+msgstr "En espera"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_form_domain_all"
@@ -1284,7 +1295,7 @@ msgstr "Tots"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_form_domain_assigned"
msgid "Assigned"
-msgstr "Assignat"
+msgstr "Reservat"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_form_domain_draft"
@@ -1299,7 +1310,7 @@ msgstr "Empaquetat"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_form_domain_waiting"
msgid "Waiting"
-msgstr "Esperant"
+msgstr "En espera"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_return_form_domain_all"
@@ -1426,7 +1437,7 @@ msgstr "Administració de logística"
msgctxt "model:res.group,name:group_stock_force_assignment"
msgid "Stock Force Assignment"
-msgstr "Forçar reserves en la logística"
+msgstr "Forçar reserves a logística"
msgctxt "model:stock.configuration,name:"
msgid "Stock Configuration"
@@ -1434,15 +1445,15 @@ msgstr "Configuració d'estoc"
msgctxt "model:stock.inventory,name:"
msgid "Stock Inventory"
-msgstr "Inventari d'existència"
+msgstr "Inventari d'estoc"
msgctxt "model:stock.inventory.line,name:"
msgid "Stock Inventory Line"
-msgstr "Línia d'existència en inventari "
+msgstr "Línia d'inventari d'estoc"
msgctxt "model:stock.location,name:"
msgid "Stock Location"
-msgstr "Ubicació d'existència"
+msgstr "Ubicació d'estoc"
msgctxt "model:stock.location,name:location_customer"
msgid "Customer"
@@ -1474,7 +1485,7 @@ msgstr "Magatzem"
msgctxt "model:stock.move,name:"
msgid "Stock Move"
-msgstr "Moviment d'existències"
+msgstr "Moviment d'estoc"
msgctxt "model:stock.period,name:"
msgid "Stock Period"
@@ -1482,7 +1493,7 @@ msgstr "Període d'estoc"
msgctxt "model:stock.period.cache,name:"
msgid "Stock Period Cache"
-msgstr "Període estoc precalculat"
+msgstr "Període d'estoc precalculat"
msgctxt "model:stock.product_quantities_warehouse,name:"
msgid "Product Quantities By Warehouse"
@@ -1506,7 +1517,7 @@ msgstr "Albarà devolució proveïdor"
msgctxt "model:stock.shipment.in.return.assign.failed,name:"
msgid "Assign Supplier Return Shipment"
-msgstr "Reservar albarans de devolució de proveïdor"
+msgstr "Reserva albarà de devolució de proveïdor"
msgctxt "model:stock.shipment.internal,name:"
msgid "Internal Shipment"
@@ -1514,7 +1525,7 @@ msgstr "Albarà intern"
msgctxt "model:stock.shipment.internal.assign.failed,name:"
msgid "Assign Shipment Internal"
-msgstr "Assignar albarà intern"
+msgstr "Reserva albarà intern"
msgctxt "model:stock.shipment.out,name:"
msgid "Customer Shipment"
@@ -1522,7 +1533,7 @@ msgstr "Albarà client"
msgctxt "model:stock.shipment.out.assign.failed,name:"
msgid "Assign Shipment Out"
-msgstr "Assignació d'albarà de sortida"
+msgstr "Reserva albarà de sortida"
msgctxt "model:stock.shipment.out.return,name:"
msgid "Customer Return Shipment"
@@ -1566,7 +1577,7 @@ msgstr "Referència:"
msgctxt "odt:stock.shipment.in.restocking_list:"
msgid "Restocking List"
-msgstr "Llista de renovació d'existències"
+msgstr "Llista de proveïment"
msgctxt "odt:stock.shipment.in.restocking_list:"
msgid "Supplier:"
@@ -1654,7 +1665,7 @@ msgstr "Data:"
msgctxt "odt:stock.shipment.out.delivery_note:"
msgid "Delivery Note"
-msgstr "Nota enviament"
+msgstr "Nota d'enviament"
msgctxt "odt:stock.shipment.out.delivery_note:"
msgid "E-Mail:"
@@ -1786,7 +1797,7 @@ msgstr "Referència:"
msgctxt "odt:stock.shipment.out.return.restocking_list:"
msgid "Restocking List"
-msgstr "Llista de renovació d'existències"
+msgstr "Llista de proveïment"
msgctxt "odt:stock.shipment.out.return.restocking_list:"
msgid "To Location"
@@ -1842,7 +1853,7 @@ msgstr "Magatzem"
msgctxt "selection:stock.move,state:"
msgid "Assigned"
-msgstr "Assignat"
+msgstr "Reservat"
msgctxt "selection:stock.move,state:"
msgid "Canceled"
@@ -1882,7 +1893,7 @@ msgstr "Rebut"
msgctxt "selection:stock.shipment.in.return,state:"
msgid "Assigned"
-msgstr "Assignat"
+msgstr "Reservat"
msgctxt "selection:stock.shipment.in.return,state:"
msgid "Canceled"
@@ -1902,7 +1913,7 @@ msgstr "En espera"
msgctxt "selection:stock.shipment.internal,state:"
msgid "Assigned"
-msgstr "Assignat"
+msgstr "Reservat"
msgctxt "selection:stock.shipment.internal,state:"
msgid "Canceled"
@@ -1922,7 +1933,7 @@ msgstr "En espera"
msgctxt "selection:stock.shipment.out,state:"
msgid "Assigned"
-msgstr "Assignat"
+msgstr "Reservat"
msgctxt "selection:stock.shipment.out,state:"
msgid "Canceled"
@@ -1962,13 +1973,17 @@ msgstr "Rebut"
msgctxt "view:party.party:"
msgid "Stock"
-msgstr "Existències"
+msgstr "Logística"
msgctxt "view:product.by_location.start:"
msgid "Product by Location"
msgstr "Producte per ubicació"
msgctxt "view:product.product:"
+msgid "Cost Value"
+msgstr "Valor de cost"
+
+msgctxt "view:product.product:"
msgid "Products"
msgstr "Productes"
@@ -2066,7 +2081,7 @@ msgstr "Productes per ubicació"
msgctxt "view:stock.shipment.in.return.assign.failed:"
msgid "Unable to Assign"
-msgstr "No es poden reservar aquests productes:"
+msgstr "No es pot reservar"
msgctxt "view:stock.shipment.in.return.assign.failed:"
msgid "Unable to assign those products:"
@@ -2074,7 +2089,7 @@ msgstr "No es poden reservar aquests productes:"
msgctxt "view:stock.shipment.in.return:"
msgid "Assign"
-msgstr "Assigna"
+msgstr "Reserva"
msgctxt "view:stock.shipment.in.return:"
msgid "Cancel"
@@ -2114,7 +2129,7 @@ msgstr "Moviments d'entrada"
msgctxt "view:stock.shipment.in:"
msgid "Inventory Moves"
-msgstr "Moviments d'inventari"
+msgstr "Moviments interns"
msgctxt "view:stock.shipment.in:"
msgid "Receive"
@@ -2134,7 +2149,7 @@ msgstr "Albarans proveïdors"
msgctxt "view:stock.shipment.internal.assign.failed:"
msgid "Unable to Assign"
-msgstr "No es poden reservar aquests productes:"
+msgstr "No es pot reservar"
msgctxt "view:stock.shipment.internal.assign.failed:"
msgid "Unable to assign those products:"
@@ -2142,7 +2157,7 @@ msgstr "No es poden reservar aquests productes:"
msgctxt "view:stock.shipment.internal:"
msgid "Assign"
-msgstr "Assigna"
+msgstr "Reserva"
msgctxt "view:stock.shipment.internal:"
msgid "Cancel"
@@ -2165,12 +2180,12 @@ msgid "Internal Shipments"
msgstr "Albarans interns"
msgctxt "view:stock.shipment.internal:"
-msgid "Waiting"
+msgid "Wait"
msgstr "En espera"
msgctxt "view:stock.shipment.out.assign.failed:"
msgid "Unable to Assign"
-msgstr "No es poden reservar aquests productes:"
+msgstr "No es pot reservar"
msgctxt "view:stock.shipment.out.assign.failed:"
msgid "Unable to assign those products:"
@@ -2202,7 +2217,7 @@ msgstr "Moviments d'entrada"
msgctxt "view:stock.shipment.out.return:"
msgid "Inventory Moves"
-msgstr "Moviments d'inventari"
+msgstr "Moviments interns"
msgctxt "view:stock.shipment.out.return:"
msgid "Received"
@@ -2210,7 +2225,7 @@ msgstr "Rebut"
msgctxt "view:stock.shipment.out:"
msgid "Assign"
-msgstr "Assigna"
+msgstr "Reserva"
msgctxt "view:stock.shipment.out:"
msgid "Cancel"
@@ -2234,18 +2249,18 @@ msgstr "Esborrany"
msgctxt "view:stock.shipment.out:"
msgid "Inventory Moves"
-msgstr "Moviments d'inventari"
+msgstr "Moviments interns"
msgctxt "view:stock.shipment.out:"
msgid "Make shipment"
-msgstr "Realiza enviament"
+msgstr "Realitza enviament"
msgctxt "view:stock.shipment.out:"
msgid "Outgoing Moves"
msgstr "Moviments de sortida"
msgctxt "view:stock.shipment.out:"
-msgid "Waiting"
+msgid "Wait"
msgstr "En espera"
msgctxt "wizard_button:product.by_location,start,end:"
@@ -2286,7 +2301,7 @@ msgstr "Accepta"
msgctxt "wizard_button:stock.shipment.internal.assign,failed,force:"
msgid "Force Assign"
-msgstr "Forçar reserva"
+msgstr "Força reserva"
msgctxt "wizard_button:stock.shipment.out.assign,failed,end:"
msgid "Ok"
diff --git a/locale/cs_CZ.po b/locale/cs_CZ.po
index 4e74862..67511c8 100644
--- a/locale/cs_CZ.po
+++ b/locale/cs_CZ.po
@@ -8,6 +8,11 @@ msgid ""
" moves."
msgstr ""
+msgctxt "error:product.template:"
+msgid ""
+"You cannot change the type for a product which is associated to stock moves."
+msgstr ""
+
msgctxt "error:stock.inventory.line:"
msgid "Line quantity must be positive."
msgstr ""
@@ -43,6 +48,10 @@ msgid "Source and destination location must be different"
msgstr ""
msgctxt "error:stock.move:"
+msgid "The stock move \"%s\" has no origin."
+msgstr ""
+
+msgctxt "error:stock.move:"
msgid ""
"You can not delete stock move \"%s\" because it is not in draft or cancelled"
" state."
@@ -277,8 +286,8 @@ msgctxt "field:stock.inventory.line,inventory:"
msgid "Inventory"
msgstr ""
-msgctxt "field:stock.inventory.line,move:"
-msgid "Move"
+msgctxt "field:stock.inventory.line,moves:"
+msgid "Moves"
msgstr ""
msgctxt "field:stock.inventory.line,product:"
@@ -1939,6 +1948,10 @@ msgid "Product by Location"
msgstr ""
msgctxt "view:product.product:"
+msgid "Cost Value"
+msgstr ""
+
+msgctxt "view:product.product:"
msgid "Products"
msgstr ""
@@ -2135,7 +2148,7 @@ msgid "Internal Shipments"
msgstr ""
msgctxt "view:stock.shipment.internal:"
-msgid "Waiting"
+msgid "Wait"
msgstr ""
msgctxt "view:stock.shipment.out.assign.failed:"
@@ -2215,7 +2228,7 @@ msgid "Outgoing Moves"
msgstr ""
msgctxt "view:stock.shipment.out:"
-msgid "Waiting"
+msgid "Wait"
msgstr ""
msgctxt "wizard_button:product.by_location,start,end:"
diff --git a/locale/de_DE.po b/locale/de_DE.po
index 1ddfd41..8618ca7 100644
--- a/locale/de_DE.po
+++ b/locale/de_DE.po
@@ -10,6 +10,13 @@ msgstr ""
"Die Standardmaßeinheit kann nicht für einen Artikel geändert werden, der "
"Lagerbewegungen zugeordnet ist."
+msgctxt "error:product.template:"
+msgid ""
+"You cannot change the type for a product which is associated to stock moves."
+msgstr ""
+"Für Artikel, die Lagerbewegungen zugeordnet sind, kann der Typ nicht "
+"geändert werden."
+
msgctxt "error:stock.inventory.line:"
msgid "Line quantity must be positive."
msgstr "Anzahl auf der Zeile muss einen positiven Wert aufweisen."
@@ -51,6 +58,10 @@ msgid "Source and destination location must be different"
msgstr "Herkunfts- und Bestimmungsort müssen unterschiedlich sein"
msgctxt "error:stock.move:"
+msgid "The stock move \"%s\" has no origin."
+msgstr "Die Lagerbewegung \"%s\" hat keinen Ursprung."
+
+msgctxt "error:stock.move:"
msgid ""
"You can not delete stock move \"%s\" because it is not in draft or cancelled"
" state."
@@ -311,9 +322,9 @@ msgctxt "field:stock.inventory.line,inventory:"
msgid "Inventory"
msgstr "Lagerbestand"
-msgctxt "field:stock.inventory.line,move:"
-msgid "Move"
-msgstr "Bewegung"
+msgctxt "field:stock.inventory.line,moves:"
+msgid "Moves"
+msgstr "Lagerbewegungen"
msgctxt "field:stock.inventory.line,product:"
msgid "Product"
@@ -329,7 +340,7 @@ msgstr "Name"
msgctxt "field:stock.inventory.line,unit_digits:"
msgid "Unit Digits"
-msgstr "Anzahl Stellen"
+msgstr "Nachkommastellen"
msgctxt "field:stock.inventory.line,uom:"
msgid "UOM"
@@ -433,7 +444,7 @@ msgstr "Unternehmen"
msgctxt "field:stock.move,cost_price:"
msgid "Cost Price"
-msgstr "Einkaufspreis"
+msgstr "Kostenpreis"
msgctxt "field:stock.move,create_date:"
msgid "Create Date"
@@ -501,7 +512,7 @@ msgstr "Zu Lagerort"
msgctxt "field:stock.move,unit_digits:"
msgid "Unit Digits"
-msgstr "Anzahl Stellen"
+msgstr "Nachkommastellen"
msgctxt "field:stock.move,unit_price:"
msgid "Unit Price"
@@ -1097,15 +1108,15 @@ msgstr "Bestandskorrekturen"
msgctxt "model:ir.action,name:act_location_form"
msgid "Locations"
-msgstr "Orte"
+msgstr "Lagerorte"
msgctxt "model:ir.action,name:act_location_quantity_tree"
msgid "Locations"
-msgstr "Orte"
+msgstr "Lagerorte"
msgctxt "model:ir.action,name:act_location_tree"
msgid "Locations"
-msgstr "Orte"
+msgstr "Lagerorte"
msgctxt "model:ir.action,name:act_move_form"
msgid "Moves"
@@ -1448,7 +1459,7 @@ msgstr "Lager Lagerbestand"
msgctxt "model:stock.inventory.line,name:"
msgid "Stock Inventory Line"
-msgstr "Lager Lagerbestand Position"
+msgstr "Lagerbestandsposition"
msgctxt "model:stock.location,name:"
msgid "Stock Location"
@@ -1979,6 +1990,10 @@ msgid "Product by Location"
msgstr "Artikel nach Lagerort"
msgctxt "view:product.product:"
+msgid "Cost Value"
+msgstr "Kosten"
+
+msgctxt "view:product.product:"
msgid "Products"
msgstr "Artikel"
@@ -2175,8 +2190,8 @@ msgid "Internal Shipments"
msgstr "Interne Lieferposten"
msgctxt "view:stock.shipment.internal:"
-msgid "Waiting"
-msgstr "Wartend"
+msgid "Wait"
+msgstr "Warten"
msgctxt "view:stock.shipment.out.assign.failed:"
msgid "Unable to Assign"
@@ -2255,8 +2270,8 @@ msgid "Outgoing Moves"
msgstr "Ausgehende Bewegungen"
msgctxt "view:stock.shipment.out:"
-msgid "Waiting"
-msgstr "Wartend"
+msgid "Wait"
+msgstr "Warten"
msgctxt "wizard_button:product.by_location,start,end:"
msgid "Cancel"
diff --git a/locale/es_AR.po b/locale/es_AR.po
index d3b2834..63029e0 100644
--- a/locale/es_AR.po
+++ b/locale/es_AR.po
@@ -10,6 +10,13 @@ msgstr ""
"No puede cambiar la UdM por defecto de un producto que está asociado con "
"movimientos de existencias."
+msgctxt "error:product.template:"
+msgid ""
+"You cannot change the type for a product which is associated to stock moves."
+msgstr ""
+"No puede cambiar el tipo de un producto que está asociado con movimientos de"
+" existencias."
+
msgctxt "error:stock.inventory.line:"
msgid "Line quantity must be positive."
msgstr "La cantidad de la línea debe ser positiva."
@@ -49,6 +56,10 @@ msgid "Source and destination location must be different"
msgstr "Las ubicaciones origen y destino deben ser distintas."
msgctxt "error:stock.move:"
+msgid "The stock move \"%s\" has no origin."
+msgstr "El movimiento de existencias «%s» no tiene origen."
+
+msgctxt "error:stock.move:"
msgid ""
"You can not delete stock move \"%s\" because it is not in draft or cancelled"
" state."
@@ -298,9 +309,9 @@ msgctxt "field:stock.inventory.line,inventory:"
msgid "Inventory"
msgstr "Inventario"
-msgctxt "field:stock.inventory.line,move:"
-msgid "Move"
-msgstr "Movimiento"
+msgctxt "field:stock.inventory.line,moves:"
+msgid "Moves"
+msgstr "Movimientos"
msgctxt "field:stock.inventory.line,product:"
msgid "Product"
@@ -1969,6 +1980,10 @@ msgid "Product by Location"
msgstr "Producto por ubicación"
msgctxt "view:product.product:"
+msgid "Cost Value"
+msgstr "Valor de costo"
+
+msgctxt "view:product.product:"
msgid "Products"
msgstr "Productos"
@@ -2165,8 +2180,8 @@ msgid "Internal Shipments"
msgstr "Remitos internos"
msgctxt "view:stock.shipment.internal:"
-msgid "Waiting"
-msgstr "En espera"
+msgid "Wait"
+msgstr "Espera"
msgctxt "view:stock.shipment.out.assign.failed:"
msgid "Unable to Assign"
@@ -2245,8 +2260,8 @@ msgid "Outgoing Moves"
msgstr "Movimientos de salida"
msgctxt "view:stock.shipment.out:"
-msgid "Waiting"
-msgstr "En espera"
+msgid "Wait"
+msgstr "Espera"
msgctxt "wizard_button:product.by_location,start,end:"
msgid "Cancel"
diff --git a/locale/es_CO.po b/locale/es_CO.po
index 4a4e37e..42a21e9 100644
--- a/locale/es_CO.po
+++ b/locale/es_CO.po
@@ -10,6 +10,13 @@ msgstr ""
"No puede cambiar la UdM predeterminada de un producto que está asociado con "
"movimientos de existencias."
+msgctxt "error:product.template:"
+msgid ""
+"You cannot change the type for a product which is associated to stock moves."
+msgstr ""
+"No puede cambiar el tipo de un producto el cual esta asociado a movimientos "
+"de inventarios."
+
msgctxt "error:stock.inventory.line:"
msgid "Line quantity must be positive."
msgstr "La cantidad en la línea debe ser positiva."
@@ -25,7 +32,7 @@ msgstr "La línea \"%s\" no es única en el Inventario \"%s\"."
msgctxt "error:stock.location:"
msgid "Location \"%(location)s\" must be a child of warehouse \"%(warehouse)s\"."
msgstr ""
-"La(s) bodega(s) \"%(locations)s\" deben ser hijas del almacén "
+"La(s) bodega(s) \"%(location)s\" deben ser hijas del almacén "
"\"%(warehouse)s\"."
msgctxt "error:stock.location:"
@@ -33,8 +40,8 @@ msgid ""
"Location \"%s\" with existing moves cannot be changed to a type that does "
"not support moves."
msgstr ""
-"Bodega(s) \"%s\" con movimientos realizados no pueden ser cambiadas a un "
-"tipo no soportado."
+"Bodega \"%s\" tiene movimientos y no pueden ser cambiada a un tipo que no "
+"soporta movimientos. "
msgctxt "error:stock.move:"
msgid "Internal move quantity must be positive"
@@ -49,18 +56,22 @@ msgid "Source and destination location must be different"
msgstr "Las bodegas origen y destino deben ser distintas"
msgctxt "error:stock.move:"
+msgid "The stock move \"%s\" has no origin."
+msgstr "El movimiento de invetario \"%s\" no tiene origen."
+
+msgctxt "error:stock.move:"
msgid ""
"You can not delete stock move \"%s\" because it is not in draft or cancelled"
" state."
msgstr ""
-"No puede borrar movimientos de inventarios \"%s\" porque no estan en estado "
-"borrador o cancelados."
+"No puede borrar los movimientos de inventarios \"%s\" porque no estan en "
+"borrador o anulados."
msgctxt "error:stock.move:"
msgid "You can not modify move \"%(move)s\" because period \"%(period)s\" is closed."
msgstr ""
-"Usted no puede modificar movimientos \"%(move)s\" porque el periodo "
-"\"%(period)s\" esta cerrado."
+"No puede modificar movimientos \"%(move)s\" porque el periodo \"%(period)s\""
+" esta cerrado."
msgctxt "error:stock.move:"
msgid "You can not modify stock move \"%s\" because it is in \"Assigned\" state."
@@ -78,7 +89,7 @@ msgstr ""
msgctxt "error:stock.move:"
msgid "You can not set stock move \"%s\" to assigned state."
-msgstr "No puede establecer el movimiento de inventarios \"%s\" como asignado."
+msgstr "No puede devolver el movimiento de inventarios \"%s\" como asignado."
msgctxt "error:stock.move:"
msgid "You can not set stock move \"%s\" to done state."
@@ -90,11 +101,12 @@ msgstr "No puede establecer el movimiento de inventarios \"%s\" como borrador."
msgctxt "error:stock.period:"
msgid "You can not close a period in the future or today."
-msgstr "No se puede cerrar un período en el futuro o hoy mismo!"
+msgstr "No se puede cerrar un período de hoy o del futuro."
msgctxt "error:stock.period:"
msgid "You can not close a period when there still are assigned moves."
-msgstr "No se puede cerrar un período cuando existen movimientos asignados!"
+msgstr ""
+"No se puede cerrar un período cuando todavía hay movimientos asignados."
msgctxt "error:stock.shipment.in.return:"
msgid "Supplier Return Shipment \"%s\" must be cancelled before deletion."
@@ -299,9 +311,9 @@ msgctxt "field:stock.inventory.line,inventory:"
msgid "Inventory"
msgstr "Inventario"
-msgctxt "field:stock.inventory.line,move:"
-msgid "Move"
-msgstr "Movimiento"
+msgctxt "field:stock.inventory.line,moves:"
+msgid "Moves"
+msgstr "Movimientos"
msgctxt "field:stock.inventory.line,product:"
msgid "Product"
@@ -321,7 +333,7 @@ msgstr "Decimales de Unidad"
msgctxt "field:stock.inventory.line,uom:"
msgid "UOM"
-msgstr "UdM"
+msgstr "UDM"
msgctxt "field:stock.inventory.line,write_date:"
msgid "Write Date"
@@ -421,7 +433,7 @@ msgstr "Compañia"
msgctxt "field:stock.move,cost_price:"
msgid "Cost Price"
-msgstr "Precio de Costo"
+msgstr "Costo"
msgctxt "field:stock.move,create_date:"
msgid "Create Date"
@@ -709,7 +721,7 @@ msgstr "Bodega del Proveedor"
msgctxt "field:stock.shipment.in,warehouse:"
msgid "Warehouse"
-msgstr "Almacén"
+msgstr "Depósito"
msgctxt "field:stock.shipment.in,warehouse_input:"
msgid "Warehouse Input"
@@ -833,7 +845,7 @@ msgstr "Movimientos"
msgctxt "field:stock.shipment.internal,planned_date:"
msgid "Planned Date"
-msgstr "Fecha estimada"
+msgstr "Fecha Planeada"
msgctxt "field:stock.shipment.internal,rec_name:"
msgid "Name"
@@ -905,7 +917,7 @@ msgstr "ID"
msgctxt "field:stock.shipment.out,inventory_moves:"
msgid "Inventory Moves"
-msgstr "Movimientos de inventario"
+msgstr "Movimientos de Inventario"
msgctxt "field:stock.shipment.out,moves:"
msgid "Moves"
@@ -921,7 +933,7 @@ msgstr "Movimientos de Salida"
msgctxt "field:stock.shipment.out,planned_date:"
msgid "Planned Date"
-msgstr "Fecha estimada"
+msgstr "Fecha Planeada"
msgctxt "field:stock.shipment.out,rec_name:"
msgid "Name"
@@ -937,7 +949,7 @@ msgstr "Estado"
msgctxt "field:stock.shipment.out,warehouse:"
msgid "Warehouse"
-msgstr "Almacén"
+msgstr "Depósito"
msgctxt "field:stock.shipment.out,warehouse_output:"
msgid "Warehouse Output"
@@ -1005,7 +1017,7 @@ msgstr "Movimientos de Entrada"
msgctxt "field:stock.shipment.out.return,inventory_moves:"
msgid "Inventory Moves"
-msgstr "Movimientos de inventario"
+msgstr "Movimientos de Inventario"
msgctxt "field:stock.shipment.out.return,moves:"
msgid "Moves"
@@ -1017,7 +1029,7 @@ msgstr "Orígenes"
msgctxt "field:stock.shipment.out.return,planned_date:"
msgid "Planned Date"
-msgstr "Fecha planeada"
+msgstr "Fecha Planeada"
msgctxt "field:stock.shipment.out.return,rec_name:"
msgid "Name"
@@ -1114,7 +1126,7 @@ msgstr "Productos"
msgctxt "model:ir.action,name:act_shipment_in_form"
msgid "Supplier Shipments"
-msgstr "Envíos del Proveedor"
+msgstr "Envíos de Proveedores"
msgctxt "model:ir.action,name:act_shipment_in_return_form"
msgid "Supplier Return Shipments"
@@ -1134,11 +1146,11 @@ msgstr "Envíos a Clientes"
msgctxt "model:ir.action,name:act_shipment_out_form3"
msgid "Supplier Shipments"
-msgstr "Envíos de Proveedor"
+msgstr "Envíos de Proveedores"
msgctxt "model:ir.action,name:act_shipment_out_return_form"
msgid "Customer Return Shipments"
-msgstr "Devoluciones a Clientes"
+msgstr "Devoluciones de Clientes"
msgctxt "model:ir.action,name:act_stock_configuration_form"
msgid "Stock Configuration"
@@ -1253,7 +1265,7 @@ msgstr "Borrador"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_in_return_form_domain_waiting"
msgid "Waiting"
-msgstr "Esperando"
+msgstr "En Espera"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_internal_form_domain_all"
@@ -1273,7 +1285,7 @@ msgstr "Borrador"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_internal_form_domain_waiting"
msgid "Waiting"
-msgstr "Esperando"
+msgstr "En Espera"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_form_domain_all"
@@ -1298,7 +1310,7 @@ msgstr "Empacado"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_form_domain_waiting"
msgid "Waiting"
-msgstr "Esperando"
+msgstr "En Espera"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_return_form_domain_all"
@@ -1333,7 +1345,7 @@ msgstr "Envío a Cliente"
msgctxt "model:ir.sequence,name:sequence_shipment_out_return"
msgid "Customer Return Shipment"
-msgstr "Envío de Devolución de Cliente"
+msgstr "Devolución de Cliente"
msgctxt "model:ir.sequence.type,name:sequence_type_shipment_in"
msgid "Supplier Shipment"
@@ -1353,7 +1365,7 @@ msgstr "Envío a Cliente"
msgctxt "model:ir.sequence.type,name:sequence_type_shipment_out_return"
msgid "Customer Return Shipment"
-msgstr "Envío de Devolución de Cliente"
+msgstr "Devolución de Cliente"
msgctxt "model:ir.ui.menu,name:menu_configuration"
msgid "Configuration"
@@ -1385,7 +1397,7 @@ msgstr "Informes"
msgctxt "model:ir.ui.menu,name:menu_shipment_in_form"
msgid "Supplier Shipments"
-msgstr "Envíos del Proveedor"
+msgstr "Envíos de Proveedores"
msgctxt "model:ir.ui.menu,name:menu_shipment_in_return_form"
msgid "Supplier Return Shipments"
@@ -1397,7 +1409,7 @@ msgstr "Envíos Internos"
msgctxt "model:ir.ui.menu,name:menu_shipment_out_form"
msgid "Customer Shipments"
-msgstr "Envíos al Cliente"
+msgstr "Envíos a Clientes"
msgctxt "model:ir.ui.menu,name:menu_shipment_out_return_form"
msgid "Customer Return Shipments"
@@ -1549,7 +1561,7 @@ msgstr "Teléfono:"
msgctxt "odt:stock.shipment.in.restocking_list:"
msgid "Planned Date:"
-msgstr "Fecha planeada:"
+msgstr "Fecha Planeada:"
msgctxt "odt:stock.shipment.in.restocking_list:"
msgid "Product"
@@ -1577,11 +1589,11 @@ msgstr "A Bodega"
msgctxt "odt:stock.shipment.in.restocking_list:"
msgid "VAT Number:"
-msgstr "NIT:"
+msgstr "Número Identificación:"
msgctxt "odt:stock.shipment.in.restocking_list:"
msgid "Warehouse:"
-msgstr "Almacén:"
+msgstr "Depósito:"
msgctxt "odt:stock.shipment.internal.report:"
msgid "/"
@@ -1613,7 +1625,7 @@ msgstr "Teléfono:"
msgctxt "odt:stock.shipment.internal.report:"
msgid "Planned Date:"
-msgstr "Fecha estimada:"
+msgstr "Fecha Planeada:"
msgctxt "odt:stock.shipment.internal.report:"
msgid "Product"
@@ -1637,7 +1649,7 @@ msgstr "A Bodega:"
msgctxt "odt:stock.shipment.internal.report:"
msgid "VAT Number:"
-msgstr "NIT:"
+msgstr "Número Identificación:"
msgctxt "odt:stock.shipment.out.delivery_note:"
msgid "/"
@@ -1681,7 +1693,7 @@ msgstr "Número de Envío:"
msgctxt "odt:stock.shipment.out.delivery_note:"
msgid "VAT Number:"
-msgstr "NIT:"
+msgstr "Número Identificación:"
msgctxt "odt:stock.shipment.out.picking_list:"
msgid "/"
@@ -1713,7 +1725,7 @@ msgstr "Lista de selección"
msgctxt "odt:stock.shipment.out.picking_list:"
msgid "Planned Date:"
-msgstr "Fecha estimada:"
+msgstr "Fecha Planeada:"
msgctxt "odt:stock.shipment.out.picking_list:"
msgid "Product"
@@ -1733,11 +1745,11 @@ msgstr "A Bodega"
msgctxt "odt:stock.shipment.out.picking_list:"
msgid "VAT Number:"
-msgstr "NIT:"
+msgstr "Número Identificación:"
msgctxt "odt:stock.shipment.out.picking_list:"
msgid "Warehouse:"
-msgstr "Almacén:"
+msgstr "Depósito:"
msgctxt "odt:stock.shipment.out.return.restocking_list:"
msgid "/"
@@ -1745,7 +1757,7 @@ msgstr "/"
msgctxt "odt:stock.shipment.out.return.restocking_list:"
msgid ":"
-msgstr ""
+msgstr ":"
msgctxt "odt:stock.shipment.out.return.restocking_list:"
msgid "Code:"
@@ -1769,7 +1781,7 @@ msgstr "Teléfono:"
msgctxt "odt:stock.shipment.out.return.restocking_list:"
msgid "Planned Date:"
-msgstr "Fecha estimada:"
+msgstr "Fecha Planeada:"
msgctxt "odt:stock.shipment.out.return.restocking_list:"
msgid "Product"
@@ -1793,15 +1805,15 @@ msgstr "A Bodega"
msgctxt "odt:stock.shipment.out.return.restocking_list:"
msgid "VAT Number:"
-msgstr "NIT:"
+msgstr "Número Identificación:"
msgctxt "odt:stock.shipment.out.return.restocking_list:"
msgid "Warehouse:"
-msgstr "Almacén:"
+msgstr "Depósito:"
msgctxt "selection:stock.inventory,state:"
msgid "Canceled"
-msgstr "Cancelado"
+msgstr "Anulado"
msgctxt "selection:stock.inventory,state:"
msgid "Done"
@@ -1845,7 +1857,7 @@ msgstr "Asignado"
msgctxt "selection:stock.move,state:"
msgid "Canceled"
-msgstr "Cancelado"
+msgstr "Anulado"
msgctxt "selection:stock.move,state:"
msgid "Done"
@@ -1865,7 +1877,7 @@ msgstr "Borrador"
msgctxt "selection:stock.shipment.in,state:"
msgid "Canceled"
-msgstr "Cancelado"
+msgstr "Anulado"
msgctxt "selection:stock.shipment.in,state:"
msgid "Done"
@@ -1885,7 +1897,7 @@ msgstr "Asignado"
msgctxt "selection:stock.shipment.in.return,state:"
msgid "Canceled"
-msgstr "Cancelado"
+msgstr "Anulado"
msgctxt "selection:stock.shipment.in.return,state:"
msgid "Done"
@@ -1897,7 +1909,7 @@ msgstr "Borrador"
msgctxt "selection:stock.shipment.in.return,state:"
msgid "Waiting"
-msgstr "Esperando"
+msgstr "En Espera"
msgctxt "selection:stock.shipment.internal,state:"
msgid "Assigned"
@@ -1905,7 +1917,7 @@ msgstr "Asignado"
msgctxt "selection:stock.shipment.internal,state:"
msgid "Canceled"
-msgstr "Cancelado"
+msgstr "Anulado"
msgctxt "selection:stock.shipment.internal,state:"
msgid "Done"
@@ -1917,7 +1929,7 @@ msgstr "Borrador"
msgctxt "selection:stock.shipment.internal,state:"
msgid "Waiting"
-msgstr "Esperando"
+msgstr "En Espera"
msgctxt "selection:stock.shipment.out,state:"
msgid "Assigned"
@@ -1925,7 +1937,7 @@ msgstr "Asignado"
msgctxt "selection:stock.shipment.out,state:"
msgid "Canceled"
-msgstr "Cancelado"
+msgstr "Anulado"
msgctxt "selection:stock.shipment.out,state:"
msgid "Done"
@@ -1941,11 +1953,11 @@ msgstr "Empacado"
msgctxt "selection:stock.shipment.out,state:"
msgid "Waiting"
-msgstr "Esperando"
+msgstr "En Espera"
msgctxt "selection:stock.shipment.out.return,state:"
msgid "Canceled"
-msgstr "Cancelado"
+msgstr "Anulado"
msgctxt "selection:stock.shipment.out.return,state:"
msgid "Done"
@@ -1968,6 +1980,10 @@ msgid "Product by Location"
msgstr "Producto por Bodega"
msgctxt "view:product.product:"
+msgid "Cost Value"
+msgstr "Costo"
+
+msgctxt "view:product.product:"
msgid "Products"
msgstr "Productos"
@@ -2164,8 +2180,8 @@ msgid "Internal Shipments"
msgstr "Envíos Internos"
msgctxt "view:stock.shipment.internal:"
-msgid "Waiting"
-msgstr "Esperando"
+msgid "Wait"
+msgstr "Espera"
msgctxt "view:stock.shipment.out.assign.failed:"
msgid "Unable to Assign"
@@ -2221,7 +2237,7 @@ msgstr "Envío a Cliente"
msgctxt "view:stock.shipment.out:"
msgid "Customer Shipments"
-msgstr "Envíos a Clientes"
+msgstr "Envíos al Cliente"
msgctxt "view:stock.shipment.out:"
msgid "Done"
@@ -2244,8 +2260,8 @@ msgid "Outgoing Moves"
msgstr "Movimientos de Salida"
msgctxt "view:stock.shipment.out:"
-msgid "Waiting"
-msgstr "Esperando"
+msgid "Wait"
+msgstr "Espera"
msgctxt "wizard_button:product.by_location,start,end:"
msgid "Cancel"
diff --git a/locale/es_ES.po b/locale/es_ES.po
index bd028a9..560d191 100644
--- a/locale/es_ES.po
+++ b/locale/es_ES.po
@@ -9,6 +9,13 @@ msgid ""
msgstr ""
"No puede cambiar la UdM por defecto de un producto con movimientos de stock."
+msgctxt "error:product.template:"
+msgid ""
+"You cannot change the type for a product which is associated to stock moves."
+msgstr ""
+"No se puede cambiar el tipo de un producto del cual existen movimientos de "
+"stock."
+
msgctxt "error:stock.inventory.line:"
msgid "Line quantity must be positive."
msgstr "La cantidad de la línea debe ser positiva."
@@ -43,7 +50,11 @@ msgstr "La cantidad del movimiento tiene que ser positiva."
msgctxt "error:stock.move:"
msgid "Source and destination location must be different"
-msgstr "Las ubicaciones orígen y destino deben ser distintas."
+msgstr "Las ubicaciones origen y destino deben ser distintas."
+
+msgctxt "error:stock.move:"
+msgid "The stock move \"%s\" has no origin."
+msgstr "El movimiento de stock \"%s\" no tiene ningún origen."
msgctxt "error:stock.move:"
msgid ""
@@ -62,37 +73,37 @@ msgstr ""
msgctxt "error:stock.move:"
msgid "You can not modify stock move \"%s\" because it is in \"Assigned\" state."
msgstr ""
-"No puede establecer el movimiento de stock \"%s\" porque se encuentra en "
-"estado \"Asignado\"."
+"No puede cambiar el movimiento de stock \"%s\" porque se encuentra en estado"
+" \"Reservado\"."
msgctxt "error:stock.move:"
msgid ""
"You can not modify stock move \"%s\" because it is in \"Done\" or \"Cancel\""
" state."
msgstr ""
-"No puede establecer el movimiento de stock \"%s\" porque se encuentra en "
-"estado \"Realizado\" o \"Cancelado\"."
+"No puede cambiar el movimiento de stock \"%s\" porque se encuentra en estado"
+" \"Realizado\" o \"Cancelado\"."
msgctxt "error:stock.move:"
msgid "You can not set stock move \"%s\" to assigned state."
-msgstr "No puede establecer el movimiento de stock \"%s\" a estado asignado."
+msgstr "No puede cambiar el movimiento de stock \"%s\" a estado reservado."
msgctxt "error:stock.move:"
msgid "You can not set stock move \"%s\" to done state."
-msgstr "No puede establecer el movimiento de stock \"%s\" a estado realizado."
+msgstr "No puede cambiar el movimiento de stock \"%s\" a estado realizado."
msgctxt "error:stock.move:"
msgid "You can not set stock move \"%s\" to draft state."
-msgstr "No puede establecer el movimiento de stock \"%s\" al estado borrador."
+msgstr "No puede cambiar el movimiento de stock \"%s\" a estado borrador."
msgctxt "error:stock.period:"
msgid "You can not close a period in the future or today."
-msgstr "No puede cerrar un período con fecha futura o de hoy."
+msgstr "No puede cerrar un período actual o futuro."
msgctxt "error:stock.period:"
msgid "You can not close a period when there still are assigned moves."
msgstr ""
-"No puede cerrar un período cuando todavía dispone de movimientos asignados."
+"No puede cerrar un período cuando todavía dispone de movimientos reservados."
msgctxt "error:stock.shipment.in.return:"
msgid "Supplier Return Shipment \"%s\" must be cancelled before deletion."
@@ -109,7 +120,7 @@ msgctxt "error:stock.shipment.in:"
msgid ""
"Inventory Moves must have the warehouse input location as source location."
msgstr ""
-"Los movimientos de inventario deben indicar una ubicación de entrada como "
+"Los movimientos internos deben indicar una ubicación de entrada como "
"origen."
msgctxt "error:stock.shipment.in:"
@@ -292,9 +303,9 @@ msgctxt "field:stock.inventory.line,inventory:"
msgid "Inventory"
msgstr "Inventario"
-msgctxt "field:stock.inventory.line,move:"
-msgid "Move"
-msgstr "Movimiento"
+msgctxt "field:stock.inventory.line,moves:"
+msgid "Moves"
+msgstr "Movimientos"
msgctxt "field:stock.inventory.line,product:"
msgid "Product"
@@ -674,7 +685,7 @@ msgstr "Movimientos"
msgctxt "field:stock.shipment.in,origins:"
msgid "Origins"
-msgstr "Orígen"
+msgstr "Orígenes"
msgctxt "field:stock.shipment.in,planned_date:"
msgid "Planned Date"
@@ -754,7 +765,7 @@ msgstr "Movimientos"
msgctxt "field:stock.shipment.in.return,origins:"
msgid "Origins"
-msgstr "Orígen"
+msgstr "Orígenes"
msgctxt "field:stock.shipment.in.return,planned_date:"
msgid "Planned Date"
@@ -1006,7 +1017,7 @@ msgstr "Movimientos"
msgctxt "field:stock.shipment.out.return,origins:"
msgid "Origins"
-msgstr "Orígen"
+msgstr "Orígenes"
msgctxt "field:stock.shipment.out.return,planned_date:"
msgid "Planned Date"
@@ -1144,7 +1155,7 @@ msgstr "Crear albarán de devolución"
msgctxt "model:ir.action,name:report_shipment_in_restocking_list"
msgid "Restocking List"
-msgstr "Lista reabastecimiento"
+msgstr "Lista de reabastecimiento"
msgctxt "model:ir.action,name:report_shipment_internal"
msgid "Internal Shipment"
@@ -1160,7 +1171,7 @@ msgstr "Lista recogida"
msgctxt "model:ir.action,name:report_shipment_out_return_restocking_list"
msgid "Restocking List"
-msgstr "Lista reabastecimiento"
+msgstr "Lista de reabastecimiento"
msgctxt "model:ir.action,name:wizard_product_by_location"
msgid "Product by Locations"
@@ -1419,7 +1430,7 @@ msgstr "Administración de logística"
msgctxt "model:res.group,name:group_stock_force_assignment"
msgid "Stock Force Assignment"
-msgstr "Forzar reserva en la logística"
+msgstr "Forzar reserva en logística"
msgctxt "model:stock.configuration,name:"
msgid "Stock Configuration"
@@ -1475,7 +1486,7 @@ msgstr "Período de stock"
msgctxt "model:stock.period.cache,name:"
msgid "Stock Period Cache"
-msgstr "Período stock precalculado"
+msgstr "Período de stock precalculado"
msgctxt "model:stock.product_quantities_warehouse,name:"
msgid "Product Quantities By Warehouse"
@@ -1559,7 +1570,7 @@ msgstr "Referencia:"
msgctxt "odt:stock.shipment.in.restocking_list:"
msgid "Restocking List"
-msgstr "Lista reabastecimiento"
+msgstr "Lista de reabastecimiento"
msgctxt "odt:stock.shipment.in.restocking_list:"
msgid "Supplier:"
@@ -1779,7 +1790,7 @@ msgstr "Referencia:"
msgctxt "odt:stock.shipment.out.return.restocking_list:"
msgid "Restocking List"
-msgstr "Lista reabastecimiento"
+msgstr "Lista de reabastecimiento"
msgctxt "odt:stock.shipment.out.return.restocking_list:"
msgid "To Location"
@@ -1955,13 +1966,17 @@ msgstr "Recibido"
msgctxt "view:party.party:"
msgid "Stock"
-msgstr "Stock"
+msgstr "Logística"
msgctxt "view:product.by_location.start:"
msgid "Product by Location"
msgstr "Productos por ubicación"
msgctxt "view:product.product:"
+msgid "Cost Value"
+msgstr "Valor de coste"
+
+msgctxt "view:product.product:"
msgid "Products"
msgstr "Productos"
@@ -2158,7 +2173,7 @@ msgid "Internal Shipments"
msgstr "Albaranes internos"
msgctxt "view:stock.shipment.internal:"
-msgid "Waiting"
+msgid "Wait"
msgstr "En espera"
msgctxt "view:stock.shipment.out.assign.failed:"
@@ -2238,7 +2253,7 @@ msgid "Outgoing Moves"
msgstr "Movimientos de salida"
msgctxt "view:stock.shipment.out:"
-msgid "Waiting"
+msgid "Wait"
msgstr "En espera"
msgctxt "wizard_button:product.by_location,start,end:"
diff --git a/locale/fr_FR.po b/locale/fr_FR.po
index 7a721e8..249d529 100644
--- a/locale/fr_FR.po
+++ b/locale/fr_FR.po
@@ -10,13 +10,20 @@ msgstr ""
"Vous ne pouvez pas changer l'UDM par défaut pour un produit qui a déjà fait "
"l'objet de mouvements de stock"
+msgctxt "error:product.template:"
+msgid ""
+"You cannot change the type for a product which is associated to stock moves."
+msgstr ""
+"Vous ne pouvez pas changer le type d'un produit qui a déjà fait l'objet de "
+"mouvements de stock"
+
msgctxt "error:stock.inventory.line:"
msgid "Line quantity must be positive."
msgstr "La quantité de la ligne doit être positive."
msgctxt "error:stock.inventory:"
msgid "Inventory \"%s\" must be cancelled before deletion."
-msgstr "l'inventaire \"%s\" doit être annulé avant sa suppression"
+msgstr "L'inventaire \"%s\" doit être annulé avant suppression"
msgctxt "error:stock.inventory:"
msgid "Line \"%s\" is not unique on Inventory \"%s\"."
@@ -49,6 +56,10 @@ msgid "Source and destination location must be different"
msgstr "Les emplacements d'origine et de destination doivent être distincts"
msgctxt "error:stock.move:"
+msgid "The stock move \"%s\" has no origin."
+msgstr "Le mouvement de stock \"%s\" n'a pas d'origine."
+
+msgctxt "error:stock.move:"
msgid ""
"You can not delete stock move \"%s\" because it is not in draft or cancelled"
" state."
@@ -102,8 +113,8 @@ msgstr ""
msgctxt "error:stock.shipment.in.return:"
msgid "Supplier Return Shipment \"%s\" must be cancelled before deletion."
msgstr ""
-"Le retour d'expédition fournisseur \"%s\" doit être annulé pour pouvoir être"
-" supprimé."
+"Le retour d'expédition fournisseur \"%s\" doit être annulé avant "
+"suppression."
msgctxt "error:stock.shipment.in:"
msgid ""
@@ -122,14 +133,11 @@ msgstr ""
msgctxt "error:stock.shipment.in:"
msgid "Supplier Shipment \"%s\" must be cancelled before deletion."
-msgstr ""
-"L'expédition fournisseur \"%s\" doit être annulée pour pouvoir être "
-"supprimée."
+msgstr "L'expédition fournisseur \"%s\" doit être annulée avant suppression."
msgctxt "error:stock.shipment.internal:"
msgid "Internal Shipment \"%s\" must be cancelled before deletion."
-msgstr ""
-"L'expédition interne \"%s\" doit être annulée pour pouvoir être supprimée."
+msgstr "L'expédition interne \"%s\" doit être annulée avant suppression."
msgctxt "error:stock.shipment.out.return.create:"
msgid "The shipment with code \"%s\" is not yet sent."
@@ -141,15 +149,11 @@ msgstr "Vous ne pouvez pas créer d'expédition retour"
msgctxt "error:stock.shipment.out.return:"
msgid "Customer Return Shipment \"%s\" must be cancelled before deletion."
-msgstr ""
-"Le retour d'expédition client \"%s\" doit être annulé avant de pouvoir être "
-"supprimé."
+msgstr "Le retour d'expédition client \"%s\" doit être annulé avant suppression."
msgctxt "error:stock.shipment.out:"
msgid "Customer Shipment \"%s\" must be cancelled before deletion."
-msgstr ""
-"L'expédition cliente \"%s\" doit être annulés avant de pouvoir être "
-"supprimée."
+msgstr "L'expédition cliente \"%s\" doit être annulées avant suppression."
msgctxt "field:party.address,delivery:"
msgid "Delivery"
@@ -307,9 +311,9 @@ msgctxt "field:stock.inventory.line,inventory:"
msgid "Inventory"
msgstr "Inventaire"
-msgctxt "field:stock.inventory.line,move:"
-msgid "Move"
-msgstr "Mouvement"
+msgctxt "field:stock.inventory.line,moves:"
+msgid "Moves"
+msgstr "Mouvements"
msgctxt "field:stock.inventory.line,product:"
msgid "Product"
@@ -1973,6 +1977,10 @@ msgid "Product by Location"
msgstr "Produits par emplacement"
msgctxt "view:product.product:"
+msgid "Cost Value"
+msgstr "Valeur du coût"
+
+msgctxt "view:product.product:"
msgid "Products"
msgstr "Produits"
@@ -2169,8 +2177,8 @@ msgid "Internal Shipments"
msgstr "Expéditions internes"
msgctxt "view:stock.shipment.internal:"
-msgid "Waiting"
-msgstr "En attente"
+msgid "Wait"
+msgstr "Attendre"
msgctxt "view:stock.shipment.out.assign.failed:"
msgid "Unable to Assign"
@@ -2249,8 +2257,8 @@ msgid "Outgoing Moves"
msgstr "Mouvements sortants"
msgctxt "view:stock.shipment.out:"
-msgid "Waiting"
-msgstr "En attente"
+msgid "Wait"
+msgstr "Attendre"
msgctxt "wizard_button:product.by_location,start,end:"
msgid "Cancel"
diff --git a/locale/nl_NL.po b/locale/nl_NL.po
index fcf82c8..344d323 100644
--- a/locale/nl_NL.po
+++ b/locale/nl_NL.po
@@ -8,6 +8,11 @@ msgid ""
" moves."
msgstr ""
+msgctxt "error:product.template:"
+msgid ""
+"You cannot change the type for a product which is associated to stock moves."
+msgstr ""
+
msgctxt "error:stock.inventory.line:"
msgid "Line quantity must be positive."
msgstr ""
@@ -43,6 +48,10 @@ msgid "Source and destination location must be different"
msgstr ""
msgctxt "error:stock.move:"
+msgid "The stock move \"%s\" has no origin."
+msgstr ""
+
+msgctxt "error:stock.move:"
msgid ""
"You can not delete stock move \"%s\" because it is not in draft or cancelled"
" state."
@@ -286,9 +295,9 @@ msgid "Inventory"
msgstr ""
#, fuzzy
-msgctxt "field:stock.inventory.line,move:"
-msgid "Move"
-msgstr "Boeking"
+msgctxt "field:stock.inventory.line,moves:"
+msgid "Moves"
+msgstr "Boekingen"
#, fuzzy
msgctxt "field:stock.inventory.line,product:"
@@ -2107,6 +2116,10 @@ msgctxt "view:product.by_location.start:"
msgid "Product by Location"
msgstr ""
+msgctxt "view:product.product:"
+msgid "Cost Value"
+msgstr ""
+
#, fuzzy
msgctxt "view:product.product:"
msgid "Products"
@@ -2321,10 +2334,9 @@ msgctxt "view:stock.shipment.internal:"
msgid "Internal Shipments"
msgstr ""
-#, fuzzy
msgctxt "view:stock.shipment.internal:"
-msgid "Waiting"
-msgstr "In afwachting"
+msgid "Wait"
+msgstr ""
msgctxt "view:stock.shipment.out.assign.failed:"
msgid "Unable to Assign"
@@ -2408,10 +2420,9 @@ msgctxt "view:stock.shipment.out:"
msgid "Outgoing Moves"
msgstr ""
-#, fuzzy
msgctxt "view:stock.shipment.out:"
-msgid "Waiting"
-msgstr "In afwachting"
+msgid "Wait"
+msgstr ""
#, fuzzy
msgctxt "wizard_button:product.by_location,start,end:"
diff --git a/locale/ru_RU.po b/locale/ru_RU.po
index d25fcea..f4e0981 100644
--- a/locale/ru_RU.po
+++ b/locale/ru_RU.po
@@ -10,6 +10,11 @@ msgstr ""
"Вы не можете изменить единицу измерения по умолчанию для продукта, который "
"связан со складом перемещения."
+msgctxt "error:product.template:"
+msgid ""
+"You cannot change the type for a product which is associated to stock moves."
+msgstr ""
+
msgctxt "error:stock.inventory.line:"
msgid "Line quantity must be positive."
msgstr "Количество в строке должно быть положительным."
@@ -49,6 +54,10 @@ msgid "Source and destination location must be different"
msgstr "Исходное и принимающее местоположения должны быть разными"
msgctxt "error:stock.move:"
+msgid "The stock move \"%s\" has no origin."
+msgstr ""
+
+msgctxt "error:stock.move:"
msgid ""
"You can not delete stock move \"%s\" because it is not in draft or cancelled"
" state."
@@ -291,9 +300,10 @@ msgctxt "field:stock.inventory.line,inventory:"
msgid "Inventory"
msgstr "Инвентаризация"
-msgctxt "field:stock.inventory.line,move:"
-msgid "Move"
-msgstr "Перемещение"
+#, fuzzy
+msgctxt "field:stock.inventory.line,moves:"
+msgid "Moves"
+msgstr "Перемещения"
msgctxt "field:stock.inventory.line,product:"
msgid "Product"
@@ -1960,6 +1970,11 @@ msgctxt "view:product.by_location.start:"
msgid "Product by Location"
msgstr "Продукция по местоположению"
+#, fuzzy
+msgctxt "view:product.product:"
+msgid "Cost Value"
+msgstr "Цена"
+
msgctxt "view:product.product:"
msgid "Products"
msgstr "Продукция"
@@ -2156,9 +2171,10 @@ msgctxt "view:stock.shipment.internal:"
msgid "Internal Shipments"
msgstr "Внутренние перемещения"
+#, fuzzy
msgctxt "view:stock.shipment.internal:"
-msgid "Waiting"
-msgstr "Ожидание"
+msgid "Wait"
+msgstr "Ожидают"
msgctxt "view:stock.shipment.out.assign.failed:"
msgid "Unable to Assign"
@@ -2236,9 +2252,10 @@ msgctxt "view:stock.shipment.out:"
msgid "Outgoing Moves"
msgstr "Внешнее перемещение"
+#, fuzzy
msgctxt "view:stock.shipment.out:"
-msgid "Waiting"
-msgstr "Ожидание"
+msgid "Wait"
+msgstr "Ожидают"
msgctxt "wizard_button:product.by_location,start,end:"
msgid "Cancel"
diff --git a/locale/sl_SI.po b/locale/sl_SI.po
index bb7bee4..890ee6a 100644
--- a/locale/sl_SI.po
+++ b/locale/sl_SI.po
@@ -10,6 +10,11 @@ msgstr ""
"Privzete ME za izdelek, ki je povezan s prometom zaloge, ni možno "
"spreminjati."
+msgctxt "error:product.template:"
+msgid ""
+"You cannot change the type for a product which is associated to stock moves."
+msgstr "Vrste izdelka, povezanega s prometom zaloge, ni možno popravljati."
+
msgctxt "error:stock.inventory.line:"
msgid "Line quantity must be positive."
msgstr "Količina postavke mora biti večja od nič."
@@ -47,11 +52,15 @@ msgid "Source and destination location must be different"
msgstr "Izvorna in ciljna lokacija mora biti različni."
msgctxt "error:stock.move:"
+msgid "The stock move \"%s\" has no origin."
+msgstr "Promet zaloge \"%s\" nima porekla."
+
+msgctxt "error:stock.move:"
msgid ""
"You can not delete stock move \"%s\" because it is not in draft or cancelled"
" state."
msgstr ""
-"Prometa zaloge \"%s\" ni možno brisati, ker ni v stanju osnutka ali "
+"Prometa zaloge \"%s\" ni možno brisati, ker niso v stanju priprave ali "
"preklica."
msgctxt "error:stock.move:"
@@ -82,7 +91,7 @@ msgstr "Prometa zaloge \"%s\" ni možno postaviti v stanje \"končano\". "
msgctxt "error:stock.move:"
msgid "You can not set stock move \"%s\" to draft state."
-msgstr "Prometa zaloge \"%s\" ni možno postaviti v stanje \"osnutek\". "
+msgstr "Prometa zaloge \"%s\" ni možno postaviti v stanje priprave. "
msgctxt "error:stock.period:"
msgid "You can not close a period in the future or today."
@@ -226,7 +235,7 @@ msgstr "Zapisal"
msgctxt "field:stock.inventory,company:"
msgid "Company"
-msgstr "Podjetje"
+msgstr "Družba"
msgctxt "field:stock.inventory,create_date:"
msgid "Create Date"
@@ -292,8 +301,8 @@ msgctxt "field:stock.inventory.line,inventory:"
msgid "Inventory"
msgstr "Popis"
-msgctxt "field:stock.inventory.line,move:"
-msgid "Move"
+msgctxt "field:stock.inventory.line,moves:"
+msgid "Moves"
msgstr "Promet"
msgctxt "field:stock.inventory.line,product:"
@@ -410,7 +419,7 @@ msgstr "Zapisal"
msgctxt "field:stock.move,company:"
msgid "Company"
-msgstr "Podjetje"
+msgstr "Družba"
msgctxt "field:stock.move,cost_price:"
msgid "Cost Price"
@@ -510,7 +519,7 @@ msgstr "Predpomnjenja"
msgctxt "field:stock.period,company:"
msgid "Company"
-msgstr "Podjetje"
+msgstr "Družba"
msgctxt "field:stock.period,create_date:"
msgid "Create Date"
@@ -638,7 +647,7 @@ msgstr "Šifra"
msgctxt "field:stock.shipment.in,company:"
msgid "Company"
-msgstr "Podjetje"
+msgstr "Družba"
msgctxt "field:stock.shipment.in,contact_address:"
msgid "Contact Address"
@@ -726,7 +735,7 @@ msgstr "Šifra"
msgctxt "field:stock.shipment.in.return,company:"
msgid "Company"
-msgstr "Podjetje"
+msgstr "Družba"
msgctxt "field:stock.shipment.in.return,create_date:"
msgid "Create Date"
@@ -798,7 +807,7 @@ msgstr "Šifra"
msgctxt "field:stock.shipment.internal,company:"
msgid "Company"
-msgstr "Podjetje"
+msgstr "Družba"
msgctxt "field:stock.shipment.internal,create_date:"
msgid "Create Date"
@@ -866,7 +875,7 @@ msgstr "Šifra"
msgctxt "field:stock.shipment.out,company:"
msgid "Company"
-msgstr "Podjetje"
+msgstr "Družba"
msgctxt "field:stock.shipment.out,create_date:"
msgid "Create Date"
@@ -962,7 +971,7 @@ msgstr "Šifra"
msgctxt "field:stock.shipment.out.return,company:"
msgid "Company"
-msgstr "Podjetje"
+msgstr "Družba"
msgctxt "field:stock.shipment.out.return,create_date:"
msgid "Create Date"
@@ -1046,11 +1055,11 @@ msgstr "Zapisal"
msgctxt "help:party.party,customer_location:"
msgid "The default destination location when sending products to the party."
-msgstr "Privzeta ciljna lokacija pri odpremi izdelkov k stranki."
+msgstr "Privzeta ciljna lokacija pri odpremi izdelkov k partnerju."
msgctxt "help:party.party,supplier_location:"
msgid "The default source location when receiving products from the party."
-msgstr "Privzeta izvorna lokacija pri prevzemu izdelkov od stranke."
+msgstr "Privzeta izvorna lokacija pri prevzemu izdelkov od partnerja."
msgctxt "help:product.by_location.start,forecast_date:"
msgid ""
@@ -1191,7 +1200,7 @@ msgstr "Vse"
msgctxt ""
"model:ir.action.act_window.domain,name:act_inventory_form_domain_draft"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "Priprava"
msgctxt "model:ir.action.act_window.domain,name:act_move_form_domain_all"
msgid "All"
@@ -1220,7 +1229,7 @@ msgstr "Vse"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_in_form_domain_draft"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "Priprava"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_in_form_domain_received"
@@ -1240,7 +1249,7 @@ msgstr "Dodeljeno"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_in_return_form_domain_draft"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "Priprava"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_in_return_form_domain_waiting"
@@ -1260,7 +1269,7 @@ msgstr "Dodeljeno"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_internal_form_domain_draft"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "Priprava"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_internal_form_domain_waiting"
@@ -1280,7 +1289,7 @@ msgstr "Dodeljeno"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_form_domain_draft"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "Priprava"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_form_domain_packed"
@@ -1300,7 +1309,7 @@ msgstr "Vse"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_return_form_domain_draft"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "Priprava"
msgctxt ""
"model:ir.action.act_window.domain,name:act_shipment_out_return_form_domain_received"
@@ -1801,7 +1810,7 @@ msgstr "Zaključeno"
msgctxt "selection:stock.inventory,state:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "V pripravi"
msgctxt "selection:stock.location,type:"
msgid "Customer"
@@ -1845,7 +1854,7 @@ msgstr "Zaključeno"
msgctxt "selection:stock.move,state:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "V pripravi"
msgctxt "selection:stock.period,state:"
msgid "Closed"
@@ -1853,7 +1862,7 @@ msgstr "Zaprto"
msgctxt "selection:stock.period,state:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "V pripravi"
msgctxt "selection:stock.shipment.in,state:"
msgid "Canceled"
@@ -1865,7 +1874,7 @@ msgstr "Zaključeno"
msgctxt "selection:stock.shipment.in,state:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "V pripravi"
msgctxt "selection:stock.shipment.in,state:"
msgid "Received"
@@ -1885,7 +1894,7 @@ msgstr "Zaključeno"
msgctxt "selection:stock.shipment.in.return,state:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "V pripravi"
msgctxt "selection:stock.shipment.in.return,state:"
msgid "Waiting"
@@ -1905,7 +1914,7 @@ msgstr "Zaključeno"
msgctxt "selection:stock.shipment.internal,state:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "V pripravi"
msgctxt "selection:stock.shipment.internal,state:"
msgid "Waiting"
@@ -1925,7 +1934,7 @@ msgstr "Zaključeno"
msgctxt "selection:stock.shipment.out,state:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "V pripravi"
msgctxt "selection:stock.shipment.out,state:"
msgid "Packed"
@@ -1945,7 +1954,7 @@ msgstr "Zaključeno"
msgctxt "selection:stock.shipment.out.return,state:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "V pripravi"
msgctxt "selection:stock.shipment.out.return,state:"
msgid "Received"
@@ -1960,6 +1969,10 @@ msgid "Product by Location"
msgstr "Izdelek po lokaciji"
msgctxt "view:product.product:"
+msgid "Cost Value"
+msgstr "Nabavna vrednost"
+
+msgctxt "view:product.product:"
msgid "Products"
msgstr "Izdelki"
@@ -2033,7 +2046,7 @@ msgstr "Zaključitev"
msgctxt "view:stock.period:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "Priprava"
msgctxt "view:stock.period:"
msgid "Period"
@@ -2077,7 +2090,7 @@ msgstr "Zaključeno"
msgctxt "view:stock.shipment.in.return:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "Priprava"
msgctxt "view:stock.shipment.in.return:"
msgid "Supplier Return Shipment"
@@ -2145,7 +2158,7 @@ msgstr "Zaključeno"
msgctxt "view:stock.shipment.internal:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "Priprava"
msgctxt "view:stock.shipment.internal:"
msgid "Internal Shipment"
@@ -2156,8 +2169,8 @@ msgid "Internal Shipments"
msgstr "Notranje odpremnice"
msgctxt "view:stock.shipment.internal:"
-msgid "Waiting"
-msgstr "Čakajoče"
+msgid "Wait"
+msgstr "Čakanje"
msgctxt "view:stock.shipment.out.assign.failed:"
msgid "Unable to Assign"
@@ -2185,7 +2198,7 @@ msgstr "Zaključeno"
msgctxt "view:stock.shipment.out.return:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "Priprava"
msgctxt "view:stock.shipment.out.return:"
msgid "Incoming Moves"
@@ -2221,7 +2234,7 @@ msgstr "Zaključeno"
msgctxt "view:stock.shipment.out:"
msgid "Draft"
-msgstr "Osnutek"
+msgstr "Priprava"
msgctxt "view:stock.shipment.out:"
msgid "Inventory Moves"
@@ -2236,8 +2249,8 @@ msgid "Outgoing Moves"
msgstr "Izhodni promet"
msgctxt "view:stock.shipment.out:"
-msgid "Waiting"
-msgstr "Čakajoče"
+msgid "Wait"
+msgstr "Čakanje"
msgctxt "wizard_button:product.by_location,start,end:"
msgid "Cancel"
diff --git a/location.py b/location.py
index 2d9afdf..4613081 100644
--- a/location.py
+++ b/location.py
@@ -244,8 +244,9 @@ class Location(ModelSQL, ModelView):
return locations
@classmethod
- def write(cls, locations, vals):
- super(Location, cls).write(locations, vals)
+ def write(cls, *args):
+ super(Location, cls).write(*args)
+ locations = sum(args[::2], [])
cls._set_warehouse_parent(locations)
ids = [l.id for l in locations]
@@ -312,8 +313,9 @@ class Location(ModelSQL, ModelView):
default=default)
warehouse_locations = Transaction().context.get(
'cp_warehouse_locations') or {}
- cp_warehouse = cls(Transaction().context['cp_warehouse_id'])
if location.id in warehouse_locations.values():
+ cp_warehouse = cls(
+ Transaction().context['cp_warehouse_id'])
for field, loc_id in warehouse_locations.iteritems():
if loc_id == location.id:
cls.write([cp_warehouse], {
diff --git a/location.xml b/location.xml
index 8d106ec..99c7050 100644
--- a/location.xml
+++ b/location.xml
@@ -86,6 +86,12 @@ this repository contains the full copyright notices and license terms. -->
<field name="model">stock.location,-1</field>
<field name="action" ref="wizard_products_by_locations"/>
</record>
+ <record model="ir.action.keyword"
+ id="act_products_by_locations_keyword2">
+ <field name="keyword">form_relate</field>
+ <field name="model">stock.location,-1</field>
+ <field name="action" ref="wizard_products_by_locations"/>
+ </record>
<record model="ir.model.access" id="access_location">
<field name="model" search="[('model', '=', 'stock.location')]"/>
diff --git a/move.py b/move.py
index 2d4749c..057da67 100644
--- a/move.py
+++ b/move.py
@@ -4,12 +4,15 @@ import datetime
import operator
from decimal import Decimal
from functools import partial
-from sql import Column
+from sql import Literal, Union, Column
+from sql.aggregate import Sum
+from sql.conditionals import Coalesce
from sql.operators import Concat
from trytond.model import Workflow, Model, ModelView, ModelSQL, fields
from trytond import backend
-from trytond.pyson import In, Eval, Not, Equal, If, Get, Bool
+from trytond.pyson import In, Eval, Not, Equal, If, Bool
+from trytond.tools import reduce_ids
from trytond.transaction import Transaction
from trytond.pool import Pool
@@ -49,7 +52,7 @@ class StockMixin:
product.
location_ids is the list of IDs of locations to take account to compute
- the stock. It can't be empty.
+ the stock.
products restrict the stock computation to the this products (more
efficient), so it should be the products related to records.
If it is None all products are used.
@@ -88,50 +91,59 @@ class StockMixin:
Compute the domain to filter records which validates the domain over
quantity field.
+ The context with keys:
+ stock_skip_warehouse: if set, quantities on a warehouse are no more
+ quantities of all child locations but quantities of the storage
+ zone.
location_ids is the list of IDs of locations to take account to compute
- the stock. It can't be empty.
+ the stock.
grouping defines how stock moves are grouped.
position defines which field of grouping corresponds to the record
whose quantity is computed.
"""
pool = Pool()
- Product = pool.get('product.product')
+ Location = pool.get('stock.location')
+ Move = pool.get('stock.move')
if not location_ids or not domain:
return []
- def _search_quantity_eval_domain(line, domain):
- operator_funcs = {
- '=': operator.eq,
- '>=': operator.ge,
- '>': operator.gt,
- '<=': operator.le,
- '<': operator.lt,
- '!=': operator.ne,
- 'in': lambda v, l: v in l,
- 'not in': lambda v, l: v not in l,
- }
-
- field, op, operand = domain
- value = line.get(field)
- return operator_funcs[op](value, operand)
+ # Skip warehouse location in favor of their storage location
+ # to compute quantities. Keep track of which ids to remove
+ # and to add after the query.
+ if Transaction().context.get('stock_skip_warehouse'):
+ location_ids = set(location_ids)
+ for location in Location.browse(list(location_ids)):
+ if location.type == 'warehouse':
+ location_ids.remove(location.id)
+ location_ids.add(location.storage_location.id)
+ location_ids = list(location_ids)
with Transaction().set_context(cls._quantity_context(name)):
- pbl = Product.products_by_location(
- location_ids=location_ids,
- with_childs=True, grouping=grouping)
+ query = Move.compute_quantities_query(location_ids,
+ with_childs=True, grouping=grouping,
+ grouping_filter=None)
+ having_domain = getattr(cls, name)._field.convert_domain(domain, {
+ None: (query, {}),
+ }, cls)
+ # The last column of 'query' is always the quantity for the 'key'.
+ # It is computed with a SUM() aggregator so in having we have to
+ # use the SUM() expression and not the name of column
+ having_domain.left = query.columns[-1].expression
+ if query.having:
+ query.having &= having_domain
+ else:
+ query.having = having_domain
+ quantities = Move.compute_quantities(query, location_ids,
+ with_childs=True, grouping=grouping,
+ grouping_filter=None)
- processed_lines = []
- for key, quantity in pbl.iteritems():
+ record_ids = []
+ for key, quantity in quantities.iteritems():
# pbl could return None in some keys
if key[position] is not None:
- processed_lines.append({
- 'record_id': key[position],
- name: quantity,
- })
+ record_ids.append(key[position])
- record_ids = [line['record_id'] for line in processed_lines
- if _search_quantity_eval_domain(line, domain)]
return [('id', 'in', record_ids)]
@@ -141,23 +153,18 @@ class Move(Workflow, ModelSQL, ModelView):
_order_name = 'product'
product = fields.Many2One("product.product", "Product", required=True,
select=True, states=STATES,
- on_change=['product', 'currency', 'uom', 'company',
- 'from_location', 'to_location'],
domain=[('type', '!=', 'service')],
depends=DEPENDS)
product_uom_category = fields.Function(
- fields.Many2One('product.uom.category', 'Product Uom Category',
- on_change_with=['product']),
+ fields.Many2One('product.uom.category', 'Product Uom Category'),
'on_change_with_product_uom_category')
uom = fields.Many2One("product.uom", "Uom", required=True, states=STATES,
domain=[
('category', '=', Eval('product_uom_category')),
],
- on_change=['product', 'currency', 'uom', 'company',
- 'from_location', 'to_location'],
depends=['state', 'product_uom_category'])
- unit_digits = fields.Function(fields.Integer('Unit Digits',
- on_change_with=['uom']), 'on_change_with_unit_digits')
+ unit_digits = fields.Function(fields.Integer('Unit Digits'),
+ 'on_change_with_unit_digits')
quantity = fields.Float("Quantity", required=True,
digits=(16, Eval('unit_digits', 2)), states=STATES,
depends=['state', 'unit_digits'])
@@ -181,7 +188,11 @@ class Move(Workflow, ModelSQL, ModelView):
| Eval('shipment'))
}, depends=['state', 'shipment'],
select=True)
- effective_date = fields.Date("Effective Date", readonly=True, select=True)
+ effective_date = fields.Date("Effective Date", readonly=True, select=True,
+ states={
+ 'required': Eval('state') == 'done',
+ },
+ depends=['state'])
state = fields.Selection([
('draft', 'Draft'),
('assigned', 'Assigned'),
@@ -212,8 +223,7 @@ class Move(Workflow, ModelSQL, ModelView):
'readonly': Not(Equal(Eval('state'), 'draft')),
},
depends=['unit_price_required', 'state'])
- unit_price_required = fields.Function(fields.Boolean('Unit Price Required',
- on_change_with=['from_location', 'to_location']),
+ unit_price_required = fields.Function(fields.Boolean('Unit Price Required'),
'on_change_with_unit_price_required')
@classmethod
@@ -251,6 +261,7 @@ class Move(Workflow, ModelSQL, ModelView):
'it is in "Assigned" state.'),
'modify_done_cancel': ('You can not modify stock move "%s" '
'because it is in "Done" or "Cancel" state.'),
+ 'no_origin': 'The stock move "%s" has no origin.',
})
cls._transitions |= set((
('draft', 'assigned'),
@@ -364,11 +375,14 @@ class Move(Workflow, ModelSQL, ModelView):
def default_unit_digits():
return 2
+ @fields.depends('uom')
def on_change_with_unit_digits(self, name=None):
if self.uom:
return self.uom.digits
return 2
+ @fields.depends('product', 'currency', 'uom', 'company', 'from_location',
+ 'to_location')
def on_change_product(self):
pool = Pool()
Uom = pool.get('product.uom')
@@ -397,10 +411,13 @@ class Move(Workflow, ModelSQL, ModelView):
res['unit_price'] = unit_price
return res
+ @fields.depends('product')
def on_change_with_product_uom_category(self, name=None):
if self.product:
return self.product.default_uom_category.id
+ @fields.depends('product', 'currency', 'uom', 'company', 'from_location',
+ 'to_location')
def on_change_uom(self):
pool = Pool()
Uom = pool.get('product.uom')
@@ -421,6 +438,7 @@ class Move(Workflow, ModelSQL, ModelView):
res['unit_price'] = unit_price
return res
+ @fields.depends('from_location', 'to_location')
def on_change_with_unit_price_required(self, name=None):
if (self.from_location
and self.from_location.type in ('supplier', 'production')):
@@ -457,7 +475,7 @@ class Move(Workflow, ModelSQL, ModelView):
@staticmethod
def _get_origin():
'Return list of Model names for origin Reference'
- return []
+ return ['stock.inventory.line']
@classmethod
def get_origin(cls):
@@ -565,36 +583,39 @@ class Move(Workflow, ModelSQL, ModelView):
product.default_uom, round=True)
return internal_quantity
+ def set_effective_date(self):
+ pool = Pool()
+ Date = pool.get('ir.date')
+
+ if not self.effective_date and self.shipment:
+ self.effective_date = self.shipment.effective_date
+ if not self.effective_date:
+ self.effective_date = Date.today()
+
@classmethod
@ModelView.button
@Workflow.transition('draft')
def draft(cls, moves):
- pass
+ cls.write(moves, {
+ 'effective_date': None,
+ })
@classmethod
@ModelView.button
@Workflow.transition('assigned')
def assign(cls, moves):
- pool = Pool()
- Date = pool.get('ir.date')
-
- today = Date.today()
+ cls.check_origin(moves)
for move in moves:
- if not move.effective_date:
- move.effective_date = today
+ move.set_effective_date()
move.save()
@classmethod
@ModelView.button
@Workflow.transition('done')
def do(cls, moves):
- pool = Pool()
- Date = pool.get('ir.date')
-
- today = Date.today()
+ cls.check_origin(moves)
for move in moves:
- if not move.effective_date:
- move.effective_date = today
+ move.set_effective_date()
if (move.from_location.type in ('supplier', 'production')
and move.to_location.type == 'storage'
and move.product.cost_price_method == 'average'):
@@ -648,31 +669,35 @@ class Move(Workflow, ModelSQL, ModelView):
return moves
@classmethod
- def write(cls, moves, vals):
- vals_set = set(vals)
- if cls._deny_modify_assigned & vals_set:
- for move in moves:
- if move.state == 'assigned':
- cls.raise_user_error('modify_assigned', (move.rec_name,))
- if cls._deny_modify_done_cancel & vals_set:
- for move in moves:
- if move.state in ('done', 'cancel'):
- cls.raise_user_error('modify_done_cancel',
- (move.rec_name,))
-
- if any(f not in cls._allow_modify_closed_period for f in vals):
- cls.check_period_closed(moves)
+ def write(cls, *args):
+ actions = iter(args)
+ for moves, values in zip(actions, actions):
+ vals_set = set(values)
+ if cls._deny_modify_assigned & vals_set:
+ for move in moves:
+ if move.state == 'assigned':
+ cls.raise_user_error('modify_assigned', move.rec_name)
+ if cls._deny_modify_done_cancel & vals_set:
+ for move in moves:
+ if move.state in ('done', 'cancel'):
+ cls.raise_user_error('modify_done_cancel',
+ (move.rec_name,))
- super(Move, cls).write(moves, vals)
+ super(Move, cls).write(*args)
- for move in moves:
- internal_quantity = cls._get_internal_quantity(move.quantity,
- move.uom, move.product)
- if (internal_quantity != move.internal_quantity
- and internal_quantity != vals.get('internal_quantity')):
- cls.write([move], {
- 'internal_quantity': internal_quantity,
- })
+ actions = iter(args)
+ for moves, values in zip(actions, actions):
+ if any(f not in cls._allow_modify_closed_period for f in values):
+ cls.check_period_closed(moves)
+ for move in moves:
+ internal_quantity = cls._get_internal_quantity(move.quantity,
+ move.uom, move.product)
+ if (internal_quantity != move.internal_quantity
+ and internal_quantity
+ != values.get('internal_quantity')):
+ cls.write([move], {
+ 'internal_quantity': internal_quantity,
+ })
@classmethod
def delete(cls, moves):
@@ -681,6 +706,24 @@ class Move(Workflow, ModelSQL, ModelView):
cls.raise_user_error('del_draft_cancel', (move.rec_name,))
super(Move, cls).delete(moves)
+ @staticmethod
+ def check_origin_types():
+ "Location types to check for origin"
+ return set()
+
+ @classmethod
+ def check_origin(cls, moves, types=None):
+ if types is None:
+ types = cls.check_origin_types()
+ if not types:
+ return
+ for move in moves:
+ if ((move.from_location.type in types
+ or move.to_location.type in types)
+ and not move.origin):
+ cls.raise_user_warning('%s.done' % move,
+ 'no_origin', move.rec_name)
+
def pick_product(self, location_quantities):
"""
Pick the product across the location. Naive (fast) implementation.
@@ -706,7 +749,7 @@ class Move(Workflow, ModelSQL, ModelView):
return to_pick
@classmethod
- def assign_try(cls, moves, grouping=('product',)):
+ def assign_try(cls, moves, with_childs=True, grouping=('product',)):
'''
Try to assign moves.
It will split the moves to assign as much possible.
@@ -720,9 +763,13 @@ class Move(Workflow, ModelSQL, ModelView):
Transaction().cursor.lock(cls._table)
- locations = Location.search([
- ('parent', 'child_of', [x.from_location.id for x in moves]),
- ])
+ if with_childs:
+ locations = Location.search([
+ ('parent', 'child_of',
+ [x.from_location.id for x in moves]),
+ ])
+ else:
+ locations = list(set((m.from_location for m in moves)))
with Transaction().set_context(
stock_date_end=Date.today(),
stock_assign=True):
@@ -746,9 +793,12 @@ class Move(Workflow, ModelSQL, ModelView):
continue
to_location = move.to_location
location_qties = {}
- childs = Location.search([
- ('parent', 'child_of', [move.from_location.id]),
- ])
+ if with_childs:
+ childs = Location.search([
+ ('parent', 'child_of', [move.from_location.id]),
+ ])
+ else:
+ childs = [move.from_location]
for location in childs:
key = get_key(location)
if key in pbl:
@@ -789,3 +839,367 @@ class Move(Workflow, ModelSQL, ModelView):
pbl[from_key] = pbl.get(from_key, 0.0) - qty_default_uom
pbl[to_key] = pbl.get(to_key, 0.0) + qty_default_uom
return success
+
+ @classmethod
+ def compute_quantities_query(cls, location_ids, with_childs=False,
+ grouping=('product',), grouping_filter=None):
+ """
+ Prepare a query object to compute for each location and product the
+ stock quantity in the default uom of the product.
+
+ The context with keys:
+ stock_date_end: if set the date of the stock computation.
+ stock_date_start: if set return the delta of the stock between the
+ two dates, (ignored if stock_date_end is missing).
+ stock_assign: if set compute also the assigned moves as done.
+ forecast: if set compute the forecast quantity.
+ stock_destinations: A list of location ids. If set, restrict the
+ computation to moves from and to those locations.
+ stock_skip_warehouse: if set, quantities on a warehouse are no more
+ quantities of all child locations but quantities of the storage
+ zone.
+ If with_childs, it computes also for child locations.
+ grouping is a tuple of Move field names and defines how stock moves are
+ grouped.
+ grouping_filter is a tuple of values, for the Move's field at the same
+ position in grouping tuple, used to filter which moves are used to
+ compute quantities. It must be None or have the same number of
+ elements than grouping. If no grouping_filter is provided it
+ returns quantities for all products.
+
+ The query return the location as first column, after the fields in
+ grouping, and the last column is the quantity.
+ """
+ pool = Pool()
+ Rule = pool.get('ir.rule')
+ Location = pool.get('stock.location')
+ Date = pool.get('ir.date')
+ Period = pool.get('stock.period')
+ Move = pool.get('stock.move')
+ Product = pool.get('product.product')
+ Template = pool.get('product.template')
+
+ move = Move.__table__()
+ product = Product.__table__()
+ template = Template.__table__()
+
+ today = Date.today()
+
+ if not location_ids:
+ return None
+ context = Transaction().context.copy()
+
+ for field in grouping:
+ if field not in Move._fields:
+ raise ValueError('"%s" has no field "%s"' % (Move, field))
+ assert grouping_filter is None or len(grouping_filter) == len(grouping)
+
+ move_rule_query = Rule.domain_get('stock.move')
+ if move_rule_query is None:
+ move_rule_query = Literal(True)
+
+ PeriodCache = Period.get_cache(grouping)
+ period = None
+ if PeriodCache:
+ period_cache = PeriodCache.__table__()
+
+ if not context.get('stock_date_end'):
+ context['stock_date_end'] = datetime.date.max
+
+ # date end in the past or today: filter on state done
+ if (context['stock_date_end'] < today
+ or (context['stock_date_end'] == today
+ and not context.get('forecast'))):
+ state_date_clause = (
+ move.state.in_(['done',
+ context.get('stock_assign') and 'assigned' or 'done'])
+ & (
+ (
+ (move.effective_date == None)
+ & (move.planned_date <= context['stock_date_end'])
+ )
+ | (move.effective_date <= context['stock_date_end'])
+ )
+ )
+ # future date end: filter move on state done and date
+ # before today, or on all state and date between today and
+ # date_end.
+ else:
+ state_date_clause = (
+ (move.state.in_(['done',
+ context.get('stock_assign') and 'assigned'
+ or 'done'])
+ & (
+ (
+ (move.effective_date == None)
+ & (move.planned_date <= today)
+ )
+ | (move.effective_date <= today)
+ )
+ )
+ | (move.state.in_(['done', 'assigned', 'draft'])
+ & (
+ (
+ (move.effective_date == None)
+ & (Coalesce(move.planned_date, datetime.date.max)
+ <= context['stock_date_end'])
+ & (Coalesce(move.planned_date, datetime.date.max)
+ >= today)
+ )
+ | (
+ (move.effective_date <= context['stock_date_end'])
+ & (move.effective_date >= today)
+ )
+ )
+ )
+ )
+
+ if context.get('stock_date_start'):
+ if context['stock_date_start'] > today:
+ state_date_clause &= (
+ move.state.in_(['done', 'assigned', 'draft'])
+ & (
+ (
+ (move.effective_date == None)
+ & (
+ (move.planned_date >=
+ context['stock_date_start'])
+ | (move.planned_date == None)
+ )
+ )
+ | (move.effective_date >= context['stock_date_start'])
+ )
+ )
+ else:
+ state_date_clause &= (
+ (
+ move.state.in_(['done', 'assigned', 'draft'])
+ & (
+ (
+ (move.effective_date == None)
+ & (
+ (move.planned_date >= today)
+ | (move.planned_date == None)
+ )
+ )
+ | (move.effective_date >= today)
+ )
+ )
+ | (
+ move.state.in_(['done',
+ context.get('stock_assign') and 'assigned'
+ or 'done'])
+ & (
+ (
+ (move.effective_date == None)
+ & (
+ (
+ (move.planned_date >=
+ context['stock_date_start'])
+ & (move.planned_date < today)
+ )
+ | (move.planned_date == None)
+ )
+ )
+ | (
+ (move.effective_date >=
+ context['stock_date_start'])
+ & (move.effective_date < today)
+ )
+ )
+ )
+ )
+ elif PeriodCache:
+ with Transaction().set_user(0, set_context=True):
+ periods = Period.search([
+ ('date', '<', context['stock_date_end']),
+ ('state', '=', 'closed'),
+ ], order=[('date', 'DESC')], limit=1)
+ if periods:
+ period, = periods
+ state_date_clause &= (
+ Coalesce(move.effective_date, move.planned_date,
+ datetime.date.max) > period.date)
+
+ if with_childs:
+ location_query = Location.search([
+ ('parent', 'child_of', location_ids),
+ ], query=True, order=[])
+ else:
+ location_query = location_ids[:]
+
+ from_ = move
+ if PeriodCache:
+ from_period = period_cache
+ if grouping_filter and any(grouping_filter):
+ where = where_period = Literal(True)
+ for fieldname, grouping_ids in zip(grouping, grouping_filter):
+ if not grouping_ids:
+ continue
+ column = Column(move, fieldname)
+ if PeriodCache:
+ cache_column = Column(period_cache, fieldname)
+ if isinstance(grouping_ids[0], (int, long, float, Decimal)):
+ where &= reduce_ids(column, grouping_ids)
+ if PeriodCache:
+ where_period &= reduce_ids(cache_column, grouping_ids)
+ else:
+ where &= column.in_(grouping_ids)
+ if PeriodCache:
+ where_period &= cache_column.in_(grouping_ids)
+ else:
+ where = where_period = template.active == True
+ from_ = from_.join(product, condition=move.product == product.id)
+ from_ = from_.join(template,
+ condition=product.template == template.id)
+ if PeriodCache:
+ from_period = from_period.join(product,
+ condition=period_cache.product == product.id)
+ from_period = from_period.join(template,
+ condition=product.template == template.id)
+
+ if context.get('stock_destinations'):
+ destinations = context['stock_destinations']
+ dest_clause_from = move.from_location.in_(destinations)
+ dest_clause_to = move.to_location.in_(destinations)
+
+ if PeriodCache:
+ dest_clause_period = period_cache.location.in_(destinations)
+
+ else:
+ dest_clause_from = dest_clause_to = dest_clause_period = \
+ Literal(True)
+
+ # The main select clause is a union between three similar subqueries.
+ # One that sums incoming moves towards locations, one that sums
+ # outgoing moves and one for the period cache. UNION ALL is used
+ # because we already know that there will be no duplicates.
+ move_keys = [Column(move, key).as_(key) for key in grouping]
+ query = from_.select(move.to_location.as_('location'),
+ Sum(move.internal_quantity).as_('quantity'),
+ *move_keys,
+ where=state_date_clause
+ & where
+ & move.to_location.in_(location_query)
+ & move.id.in_(move_rule_query)
+ & dest_clause_from,
+ group_by=[move.to_location] + move_keys)
+ query = Union(query, from_.select(move.from_location.as_('location'),
+ (-Sum(move.internal_quantity)).as_('quantity'),
+ *move_keys,
+ where=state_date_clause
+ & where
+ & move.from_location.in_(location_query)
+ & move.id.in_(move_rule_query)
+ & dest_clause_to,
+ group_by=[move.from_location] + move_keys),
+ all_=True)
+ if PeriodCache:
+ period_keys = [Column(period_cache, key).as_(key)
+ for key in grouping]
+ query = Union(query, from_period.select(
+ period_cache.location.as_('location'),
+ period_cache.internal_quantity.as_('quantity'),
+ *period_keys,
+ where=(period_cache.period
+ == (period.id if period else None))
+ & where_period
+ & period_cache.location.in_(location_query)
+ & dest_clause_period),
+ all_=True)
+ query_keys = [Column(query, key).as_(key) for key in grouping]
+ columns = ([query.location.as_('location')]
+ + query_keys
+ + [Sum(query.quantity).as_('quantity')])
+ query = query.select(*columns,
+ group_by=[query.location] + query_keys)
+ return query
+
+ @classmethod
+ def compute_quantities(cls, query, location_ids, with_childs=False,
+ grouping=('product',), grouping_filter=None):
+ """
+ Executes the supplied query to compute for each location and product
+ the stock quantity in the default uom of the product and rounded to
+ Uom's rounding digits.
+
+ See compute_quantites_query for params explanation.
+
+ Return a dictionary with location id and grouping as key
+ and quantity as value.
+ """
+ pool = Pool()
+ Location = pool.get('stock.location')
+ Product = pool.get('product.product')
+ Uom = pool.get('product.uom')
+
+ assert query is not None, (
+ "Query in Move.compute_quantities() can't be None")
+ assert 'product' in grouping
+
+ cursor = Transaction().cursor
+ cursor.execute(*query)
+ raw_lines = cursor.fetchall()
+
+ product_getter = operator.itemgetter(grouping.index('product') + 1)
+ res_product_ids = set()
+ quantities = {}
+ keys = set()
+ for line in raw_lines:
+ location = line[0]
+ key = tuple(line[1:-1])
+ quantity = line[-1]
+ quantities[(location,) + key] = quantity
+ res_product_ids.add(product_getter(line))
+ keys.add(key)
+
+ # Propagate quantities on from child locations to their parents
+ if with_childs:
+ # Fetch all child locations
+ locations = Location.search([
+ ('parent', 'child_of', location_ids),
+ ])
+ # Generate a set of locations without childs and a dict
+ # giving the parent of each location.
+ leafs = set([l.id for l in locations])
+ parent = {}
+ for location in locations:
+ if not location.parent:
+ continue
+ if location.parent.id in leafs:
+ leafs.remove(location.parent.id)
+ parent[location.id] = location.parent.id
+ locations = set((l.id for l in locations))
+ while leafs:
+ for l in leafs:
+ locations.remove(l)
+ if l not in parent:
+ continue
+ for key in keys:
+ parent_key = (parent[l],) + key
+ quantities.setdefault(parent_key, 0)
+ quantities[parent_key] += quantities.get((l,) + key, 0)
+ next_leafs = set(locations)
+ for l in locations:
+ if l not in parent:
+ continue
+ if parent[l] in next_leafs and parent[l] in locations:
+ next_leafs.remove(parent[l])
+ leafs = next_leafs
+
+ # clean result
+ for key in quantities.keys():
+ location = key[0]
+ if location not in location_ids:
+ del quantities[key]
+
+ # Round quantities
+ default_uom = dict((p.id, p.default_uom) for p in
+ Product.browse(list(res_product_ids)))
+ for key, quantity in quantities.iteritems():
+ location = key[0]
+ product = product_getter(key)
+ uom = default_uom[product]
+ quantities[key] = Uom.round(quantity, uom.rounding)
+
+ return quantities
diff --git a/party.xml b/party.xml
index 4e32c9a..9892d32 100644
--- a/party.xml
+++ b/party.xml
@@ -6,7 +6,7 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.action.act_window" id="act_shipment_out_form2">
<field name="name">Customer Shipments</field>
<field name="res_model">stock.shipment.out</field>
- <field name="domain">[("customer", "=", Eval('active_id'))]</field>
+ <field name="domain">[('customer', 'in', Eval('active_ids'))]</field>
</record>
<record model="ir.action.keyword"
id="act_open_purchase_keyword1">
@@ -23,7 +23,7 @@ this repository contains the full copyright notices and license terms. -->
<record model="ir.action.act_window" id="act_shipment_out_form3">
<field name="name">Supplier Shipments</field>
<field name="res_model">stock.shipment.in</field>
- <field name="domain">[("supplier", "=", Eval('active_id'))]</field>
+ <field name="domain">[('supplier', 'in', Eval('active_ids'))]</field>
</record>
<record model="ir.action.keyword"
id="act_open_purchase_keyword2">
diff --git a/product.py b/product.py
index 4ca8975..9acfc84 100644
--- a/product.py
+++ b/product.py
@@ -2,9 +2,8 @@
#this repository contains the full copyright notices and license terms.
import datetime
from decimal import Decimal
-from operator import itemgetter
-from sql import Literal, Union, Column
-from sql.aggregate import Max, Sum
+from sql import Literal
+from sql.aggregate import Max
from sql.functions import Now
from sql.conditionals import Coalesce
@@ -12,7 +11,6 @@ from trytond.model import ModelSQL, ModelView, fields
from trytond.wizard import Wizard, StateView, StateAction, Button
from trytond.pyson import PYSONEncoder, Eval, Or
from trytond.transaction import Transaction
-from trytond.tools import reduce_ids
from trytond.pool import Pool, PoolMeta
from .move import StockMixin
@@ -46,35 +44,41 @@ class Template:
cls._error_messages.update({
'change_default_uom': ('You cannot change the default uom for '
'a product which is associated to stock moves.'),
+ 'change_type': ('You cannot change the type for a product '
+ 'which is associated to stock moves.'),
})
cls.cost_price.states['required'] = Or(
cls.cost_price.states.get('required', True),
Eval('type').in_(['goods', 'assets']))
cls.cost_price.depends.append('type')
+ cls._modify_no_move = [
+ ('default_uom', 'change_default_uom'),
+ ('type', 'change_type'),
+ ]
@classmethod
- def write(cls, templates, vals):
+ def check_no_move(cls, templates, error):
Move = Pool().get('stock.move')
cursor = Transaction().cursor
- if not vals.get("default_uom"):
- super(Template, cls).write(templates, vals)
- return
-
for i in range(0, len(templates), cursor.IN_MAX):
sub_ids = [t.id for t in templates[i:i + cursor.IN_MAX]]
- templates_to_check = cls.search([
- ('id', 'in', sub_ids),
- ('default_uom', '!=', vals['default_uom']),
- ])
-
- if templates_to_check:
- if Move.search([
- ('product.template', 'in',
- [t.id for t in templates_to_check]),
- ], limit=1):
- cls.raise_user_error('change_default_uom')
+ moves = Move.search([
+ ('product.template', 'in', sub_ids),
+ ],
+ limit=1, order=[])
+ if moves:
+ cls.raise_user_error(error)
- super(Template, cls).write(templates, vals)
+ @classmethod
+ def write(cls, *args):
+ if Transaction().user != 0:
+ actions = iter(args)
+ for templates, values in zip(actions, actions):
+ for field, error in cls._modify_no_move:
+ if values.get(field):
+ cls.check_no_move(templates, error)
+ break
+ super(Template, cls).write(*args)
class Product(object, StockMixin):
@@ -122,346 +126,52 @@ class Product(object, StockMixin):
uom of the product.
The context with keys:
- stock_date_end: if set the date of the stock computation.
- stock_date_start: if set return the delta of the stock
- between the two dates, (ignored if stock_date_end is
- missing).
- stock_assign: if set compute also the assigned moves as done.
- forecast: if set compute the forecast quantity.
- stock_destinations: A list of location ids. If set, restrict
- the computation to moves from and to those locations.
- stock_skip_warehouse: if set, quantities on a warehouse are no
- more quantities of all child locations but quantities of
- the storage zone.
- If product_ids is None all products are used.
- If with_childs, it computes also for child locations.
- grouping defines how stock moves are grouped.
+ stock_skip_warehouse: if set, quantities on a warehouse are no more
+ quantities of all child locations but quantities of the storage
+ zone.
Return a dictionary with location id and grouping as key
and quantity as value.
"""
pool = Pool()
- Uom = pool.get('product.uom')
- Rule = pool.get('ir.rule')
Location = pool.get('stock.location')
- Date = pool.get('ir.date')
- Period = pool.get('stock.period')
Move = pool.get('stock.move')
- Product = pool.get('product.product')
- Template = pool.get('product.template')
-
- move = Move.__table__()
- product = Product.__table__()
- template = Template.__table__()
-
- today = Date.today()
-
- if not location_ids:
- return {}
- cursor = Transaction().cursor
- context = Transaction().context.copy()
-
- for field in grouping:
- if field not in Move._fields:
- raise ValueError('"%s" has no field "%s"' % (Move, field))
- assert 'product' in grouping
# Skip warehouse location in favor of their storage location
# to compute quantities. Keep track of which ids to remove
# and to add after the query.
- location_ids = set(location_ids)
storage_to_remove = set()
wh_to_add = {}
- for location in Location.browse(list(location_ids)):
- if (location.type == 'warehouse'
- and Transaction().context.get('stock_skip_warehouse')):
- location_ids.remove(location.id)
- if location.storage_location.id not in location_ids:
- storage_to_remove.add(location.storage_location.id)
- location_ids.add(location.storage_location.id)
- wh_to_add[location.id] = location.storage_location.id
- location_ids = list(location_ids)
-
- move_rule_query = Rule.domain_get('stock.move')
- if move_rule_query is None:
- move_rule_query = Literal(True)
-
- PeriodCache = Period.get_cache(grouping)
- period = None
- if PeriodCache:
- period_cache = PeriodCache.__table__()
-
- if not context.get('stock_date_end'):
- context['stock_date_end'] = datetime.date.max
-
- # date end in the past or today: filter on state done
- if (context['stock_date_end'] < today
- or (context['stock_date_end'] == today
- and not context.get('forecast'))):
- state_date_clause = (
- move.state.in_(['done',
- context.get('stock_assign') and 'assigned' or 'done'])
- & (
- (
- (move.effective_date == None)
- & (move.planned_date <= context['stock_date_end'])
- )
- | (move.effective_date <= context['stock_date_end'])
- )
- )
- # future date end: filter move on state done and date
- # before today, or on all state and date between today and
- # date_end.
- else:
- state_date_clause = (
- (move.state.in_(['done',
- context.get('stock_assign') and 'assigned'
- or 'done'])
- & (
- (
- (move.effective_date == None)
- & (move.planned_date <= today)
- )
- | (move.effective_date <= today)
- )
- )
- | (move.state.in_(['done', 'assigned', 'draft'])
- & (
- (
- (move.effective_date == None)
- & (Coalesce(move.planned_date, datetime.date.max)
- <= context['stock_date_end'])
- & (Coalesce(move.planned_date, datetime.date.max)
- >= today)
- )
- | (
- (move.effective_date <= context['stock_date_end'])
- & (move.effective_date >= today)
- )
- )
- )
- )
-
- if context.get('stock_date_start'):
- if context['stock_date_start'] > today:
- state_date_clause &= (
- move.state.in_(['done', 'assigned', 'draft'])
- & (
- (
- (move.effective_date == None)
- & (
- (move.planned_date >=
- context['stock_date_start'])
- | (move.planned_date == None)
- )
- )
- | (move.effective_date >= context['stock_date_start'])
- )
- )
- else:
- state_date_clause &= (
- (
- move.state.in_(['done', 'assigned', 'draft'])
- & (
- (
- (move.effective_date == None)
- & (
- (move.planned_date >= today)
- | (move.planned_date == None)
- )
- )
- | (move.effective_date >= today)
- )
- )
- | (
- move.state.in_(['done',
- context.get('stock_assign') and 'assigned'
- or 'done'])
- & (
- (
- (move.effective_date == None)
- & (
- (
- (move.planned_date >=
- context['stock_date_start'])
- & (move.planned_date < today)
- )
- | (move.planned_date == None)
- )
- )
- | (
- (move.effective_date >=
- context['stock_date_start'])
- & (move.effective_date < today)
- )
- )
- )
- )
- elif PeriodCache:
- with Transaction().set_user(0, set_context=True):
- periods = Period.search([
- ('date', '<', context['stock_date_end']),
- ('state', '=', 'closed'),
- ], order=[('date', 'DESC')], limit=1)
- if periods:
- period, = periods
- state_date_clause &= (
- Coalesce(move.effective_date, move.planned_date,
- datetime.date.max) > period.date)
-
- if with_childs:
- location_query = Location.search([
- ('parent', 'child_of', location_ids),
- ], query=True, order=[])
- else:
- location_query = location_ids[:]
-
- from_ = move
- if PeriodCache:
- from_period = period_cache
- if product_ids:
- where = reduce_ids(move.product, product_ids)
- if PeriodCache:
- where_period = reduce_ids(period_cache.product, product_ids)
- else:
- where = where_period = template.active == True
- from_ = from_.join(product, condition=move.product == product.id)
- from_ = from_.join(template,
- condition=product.template == template.id)
- if PeriodCache:
- from_period = from_period.join(product,
- condition=period_cache.product == product.id)
- from_period = from_period.join(template,
- condition=product.template == template.id)
-
- if context.get('stock_destinations'):
- destinations = context.get('stock_destinations')
- dest_clause_from = move.from_location.in_(destinations)
- dest_clause_to = move.to_location.in_(destinations)
-
- if PeriodCache:
- dest_clause_period = period_cache.location.in_(destinations)
-
- else:
- dest_clause_from = dest_clause_to = dest_clause_period = \
- Literal(True)
-
- # The main select clause is a union between three similar subqueries.
- # One that sums incoming moves towards locations, one that sums
- # outgoing moves and one for the period cache. UNION ALL is used
- # because we already know that there will be no duplicates.
- move_keys = [Column(move, key).as_(key) for key in grouping]
- query = from_.select(move.to_location.as_('location'),
- Sum(move.internal_quantity).as_('quantity'),
- *move_keys,
- where=state_date_clause
- & where
- & move.to_location.in_(location_query)
- & move.id.in_(move_rule_query)
- & dest_clause_from,
- group_by=[move.to_location] + move_keys)
- query = Union(query, from_.select(move.from_location.as_('location'),
- (-Sum(move.internal_quantity)).as_('quantity'),
- *move_keys,
- where=state_date_clause
- & where
- & move.from_location.in_(location_query)
- & move.id.in_(move_rule_query)
- & dest_clause_to,
- group_by=[move.from_location] + move_keys),
- all_=True)
- if PeriodCache:
- period_keys = [Column(period_cache, key).as_(key)
- for key in grouping]
- query = Union(query, from_period.select(
- period_cache.location.as_('location'),
- period_cache.internal_quantity.as_('quantity'),
- *period_keys,
- where=(period_cache.period
- == (period.id if period else None))
- & where_period
- & period_cache.location.in_(location_query)
- & dest_clause_period),
- all_=True)
- query_keys = [Column(query, key).as_(key) for key in grouping]
- columns = ([query.location.as_('location')]
- + query_keys
- + [Sum(query.quantity).as_('quantity')])
- query = query.select(*columns,
- group_by=[query.location] + query_keys)
- cursor.execute(*query)
- raw_lines = cursor.fetchall()
-
- product_getter = itemgetter(grouping.index('product') + 1)
- res_product_ids = set()
- res = {}
- keys = set()
- for line in raw_lines:
- location = line[0]
- key = tuple(line[1:-1])
- quantity = line[-1]
- res[(location,) + key] = quantity
- res_product_ids.add(product_getter(line))
- keys.add(key)
-
- # Propagate quantities on from child locations to their parents
- if with_childs:
- # Fetch all child locations
- locations = Location.search([
- ('parent', 'child_of', location_ids),
- ])
- # Generate a set of locations without childs and a dict
- # giving the parent of each location.
- leafs = set([l.id for l in locations])
- parent = {}
- for location in locations:
- if not location.parent:
- continue
- if location.parent.id in leafs:
- leafs.remove(location.parent.id)
- parent[location.id] = location.parent.id
- locations = set((l.id for l in locations))
- while leafs:
- for l in leafs:
- locations.remove(l)
- if l not in parent:
- continue
- for key in keys:
- parent_key = (parent[l],) + key
- res.setdefault(parent_key, 0)
- res[parent_key] += res.get((l,) + key, 0)
- next_leafs = set(locations)
- for l in locations:
- if l not in parent:
- continue
- if parent[l] in next_leafs and parent[l] in locations:
- next_leafs.remove(parent[l])
- leafs = next_leafs
-
- # clean result
- for key in res.keys():
- location = key[0]
- if location not in location_ids:
- del res[key]
-
- # Round quantities
- default_uom = dict((p.id, p.default_uom) for p in
- cls.browse(list(res_product_ids)))
- for key, quantity in res.iteritems():
- location = key[0]
- product = product_getter(key)
- uom = default_uom[product]
- res[key] = Uom.round(quantity, uom.rounding)
+ if Transaction().context.get('stock_skip_warehouse'):
+ location_ids = set(location_ids)
+ for location in Location.browse(list(location_ids)):
+ if location.type == 'warehouse':
+ location_ids.remove(location.id)
+ if location.storage_location.id not in location_ids:
+ storage_to_remove.add(location.storage_location.id)
+ location_ids.add(location.storage_location.id)
+ wh_to_add[location.id] = location.storage_location.id
+ location_ids = list(location_ids)
+
+ grouping_filter = (product_ids,) + tuple(None for k in grouping[1:])
+ query = Move.compute_quantities_query(location_ids, with_childs,
+ grouping=grouping, grouping_filter=grouping_filter)
+ if query is None:
+ return {}
+ quantities = Move.compute_quantities(query, location_ids, with_childs,
+ grouping=grouping, grouping_filter=grouping_filter)
if wh_to_add:
+ if product_ids is None:
+ product_ids = set((p for s, p in quantities))
for wh, storage in wh_to_add.iteritems():
for product in product_ids:
- if (storage, product) in res:
- res[(wh, product)] = res[(storage, product)]
+ if (storage, product) in quantities:
+ quantities[(wh, product)] = quantities[
+ (storage, product)]
if storage in storage_to_remove:
- del res[(storage, product)]
-
- return res
+ del quantities[(storage, product)]
+ return quantities
class ProductByLocationStart(ModelView):
diff --git a/setup.py b/setup.py
index 0ca2154..433d031 100644
--- a/setup.py
+++ b/setup.py
@@ -11,35 +11,52 @@ import ConfigParser
def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()
+
+def get_require_version(name):
+ if minor_version % 2:
+ require = '%s >= %s.%s.dev0, < %s.%s'
+ else:
+ require = '%s >= %s.%s, < %s.%s'
+ require %= (name, major_version, minor_version,
+ major_version, minor_version + 1)
+ return require
+
config = ConfigParser.ConfigParser()
config.readfp(open('tryton.cfg'))
info = dict(config.items('tryton'))
for key in ('depends', 'extras_depend', 'xml'):
if key in info:
info[key] = info[key].strip().splitlines()
-major_version, minor_version, _ = info.get('version', '0.0.1').split('.', 2)
+version = info.get('version', '0.0.1')
+major_version, minor_version, _ = version.split('.', 2)
major_version = int(major_version)
minor_version = int(minor_version)
+name = 'trytond_stock'
+
+download_url = 'http://downloads.tryton.org/%s.%s/' % (
+ major_version, minor_version)
+if minor_version % 2:
+ version = '%s.%s.dev0' % (major_version, minor_version)
+ download_url = (
+ 'hg+http://hg.tryton.org/modules/%s#egg=%s-%s' % (
+ name[8:], name, version))
requires = ['python-sql']
for dep in info.get('depends', []):
if not re.match(r'(ir|res|webdav)(\W|$)', dep):
- requires.append('trytond_%s >= %s.%s, < %s.%s' %
- (dep, major_version, minor_version, major_version,
- minor_version + 1))
-requires.append('trytond >= %s.%s, < %s.%s' %
- (major_version, minor_version, major_version, minor_version + 1))
-tests_require = ['proteus >= %s.%s, < %s.%s' %
- (major_version, minor_version, major_version, minor_version + 1)]
+ requires.append(get_require_version('trytond_%s' % dep))
+requires.append(get_require_version('trytond'))
+tests_require = [get_require_version('proteus')]
-setup(name='trytond_stock',
- version=info.get('version', '0.0.1'),
+setup(name=name,
+ version=version,
description='Tryton module for stock and inventory',
long_description=read('README'),
author='Tryton',
+ author_email='issue_tracker at tryton.org',
url='http://www.tryton.org/',
- download_url=("http://downloads.tryton.org/" +
- info.get('version', '0.0.1').rsplit('.', 1)[0] + '/'),
+ download_url=download_url,
+ keywords='tryton stock',
package_dir={'trytond.modules.stock': '.'},
packages=[
'trytond.modules.stock',
@@ -70,7 +87,6 @@ setup(name='trytond_stock',
'Natural Language :: Slovenian',
'Natural Language :: Spanish',
'Operating System :: OS Independent',
- 'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
'Topic :: Office/Business',
],
diff --git a/shipment.py b/shipment.py
index 80c0be1..47a3b38 100644
--- a/shipment.py
+++ b/shipment.py
@@ -40,7 +40,11 @@ class ShipmentIn(Workflow, ModelSQL, ModelView):
"Supplier Shipment"
__name__ = 'stock.shipment.in'
_rec_name = 'code'
- effective_date = fields.Date('Effective Date', readonly=True)
+ effective_date = fields.Date('Effective Date',
+ states={
+ 'readonly': Eval('state').in_(['cancel', 'done']),
+ },
+ depends=['state'])
planned_date = fields.Date('Planned Date', states={
'readonly': Not(Equal(Eval('state'), 'draft')),
}, depends=['state'])
@@ -60,11 +64,11 @@ class ShipmentIn(Workflow, ModelSQL, ModelView):
supplier = fields.Many2One('party.party', 'Supplier',
states={
'readonly': And(Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('incoming_moves'))), Bool(Eval('supplier'))),
- }, on_change=['supplier'], required=True,
- depends=['state', 'incoming_moves', 'supplier'])
+ Bool(Eval('incoming_moves', [0]))), Bool(Eval('supplier'))),
+ }, required=True,
+ depends=['state', 'supplier'])
supplier_location = fields.Function(fields.Many2One('stock.location',
- 'Supplier Location', on_change_with=['supplier']),
+ 'Supplier Location'),
'on_change_with_supplier_location')
contact_address = fields.Many2One('party.address', 'Contact Address',
states={
@@ -75,13 +79,13 @@ class ShipmentIn(Workflow, ModelSQL, ModelView):
required=True, domain=[('type', '=', 'warehouse')],
states={
'readonly': Or(In(Eval('state'), ['cancel', 'done']),
- Bool(Eval('incoming_moves'))),
- }, depends=['state', 'incoming_moves'])
+ Bool(Eval('incoming_moves', [0]))),
+ }, depends=['state'])
warehouse_input = fields.Function(fields.Many2One('stock.location',
- 'Warehouse Input', on_change_with=['warehouse']),
+ 'Warehouse Input'),
'on_change_with_warehouse_input')
warehouse_storage = fields.Function(fields.Many2One('stock.location',
- 'Warehouse Storage', on_change_with=['warehouse']),
+ 'Warehouse Storage'),
'on_change_with_warehouse_storage')
incoming_moves = fields.Function(fields.One2Many('stock.move', 'shipment',
'Incoming Moves',
@@ -259,12 +263,14 @@ class ShipmentIn(Workflow, ModelSQL, ModelView):
def default_company():
return Transaction().context.get('company')
+ @fields.depends('supplier')
def on_change_supplier(self):
address = None
if self.supplier:
address = self.supplier.address_get()
return {'contact_address': address.id if address else None}
+ @fields.depends('supplier')
def on_change_with_supplier_location(self, name=None):
if self.supplier:
return self.supplier.supplier_location.id
@@ -275,6 +281,7 @@ class ShipmentIn(Workflow, ModelSQL, ModelView):
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_input()
+ @fields.depends('warehouse')
def on_change_with_warehouse_input(self, name=None):
if self.warehouse:
return self.warehouse.input_location.id
@@ -285,6 +292,7 @@ class ShipmentIn(Workflow, ModelSQL, ModelView):
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_storage()
+ @fields.depends('warehouse')
def on_change_with_warehouse_storage(self, name=None):
if self.warehouse:
return self.warehouse.storage_location.id
@@ -375,9 +383,9 @@ class ShipmentIn(Workflow, ModelSQL, ModelView):
return shipments
@classmethod
- def write(cls, shipments, values):
- super(ShipmentIn, cls).write(shipments, values)
- cls._set_move_planned_date(shipments)
+ def write(cls, *args):
+ super(ShipmentIn, cls).write(*args)
+ cls._set_move_planned_date(sum(args[::2], []))
@classmethod
def copy(cls, shipments, default=None):
@@ -465,7 +473,7 @@ class ShipmentIn(Workflow, ModelSQL, ModelView):
Move = pool.get('stock.move')
Date = pool.get('ir.date')
Move.do([m for s in shipments for m in s.inventory_moves])
- cls.write(shipments, {
+ cls.write([s for s in shipments if not s.effective_date], {
'effective_date': Date.today(),
})
@@ -474,7 +482,11 @@ class ShipmentInReturn(Workflow, ModelSQL, ModelView):
"Supplier Return Shipment"
__name__ = 'stock.shipment.in.return'
_rec_name = 'code'
- effective_date = fields.Date('Effective Date', readonly=True)
+ effective_date = fields.Date('Effective Date',
+ states={
+ 'readonly': Eval('state').in_(['cancel', 'done']),
+ },
+ depends=['state'])
planned_date = fields.Date('Planned Date',
states={
'readonly': Not(Equal(Eval('state'), 'draft')),
@@ -496,15 +508,15 @@ class ShipmentInReturn(Workflow, ModelSQL, ModelView):
from_location = fields.Many2One('stock.location', "From Location",
required=True, states={
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('moves'))),
+ Bool(Eval('moves', [0]))),
}, domain=[('type', '=', 'storage')],
- depends=['state', 'moves'])
+ depends=['state'])
to_location = fields.Many2One('stock.location', "To Location",
required=True, states={
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('moves'))),
+ Bool(Eval('moves', [0]))),
}, domain=[('type', '=', 'supplier')],
- depends=['state', 'moves'])
+ depends=['state'])
moves = fields.One2Many('stock.move', 'shipment', 'Moves',
states={
'readonly': And(Or(Not(Equal(Eval('state'), 'draft')),
@@ -672,9 +684,9 @@ class ShipmentInReturn(Workflow, ModelSQL, ModelView):
return shipments
@classmethod
- def write(cls, shipments, values):
- super(ShipmentInReturn, cls).write(shipments, values)
- cls._set_move_planned_date(shipments)
+ def write(cls, *args):
+ super(ShipmentInReturn, cls).write(*args)
+ cls._set_move_planned_date(sum(args[::2], []))
@classmethod
def delete(cls, shipments):
@@ -718,7 +730,7 @@ class ShipmentInReturn(Workflow, ModelSQL, ModelView):
Date = pool.get('ir.date')
Move.do([m for s in shipments for m in s.moves])
- cls.write(shipments, {
+ cls.write([s for s in shipments if not s.effective_date], {
'effective_date': Date.today(),
})
@@ -738,37 +750,13 @@ class ShipmentInReturn(Workflow, ModelSQL, ModelView):
@ModelView.button
def assign_try(cls, shipments):
pool = Pool()
- Product = pool.get('product.product')
- Uom = pool.get('product.uom')
- Date = pool.get('ir.date')
Move = pool.get('stock.move')
-
- Transaction().cursor.lock(Move._table)
-
- moves = [m for s in shipments for m in s.moves]
- location_ids = [m.from_location.id for m in moves]
- with Transaction().set_context(
- stock_date_end=Date.today(),
- stock_assign=True):
- pbl = Product.products_by_location(location_ids=location_ids,
- product_ids=[m.product.id for m in moves])
-
- for move in moves:
- if move.state != 'draft':
- continue
- if (move.from_location.id, move.product.id) in pbl:
- qty_default_uom = pbl[(move.from_location.id, move.product.id)]
- qty = Uom.compute_qty(move.product.default_uom,
- qty_default_uom, move.uom, round=False)
- if qty < move.quantity:
- return False
- pbl[(move.from_location.id, move.product.id)] = (
- pbl[(move.from_location.id, move.product.id)]
- - qty_default_uom)
- else:
- return False
- cls.assign(shipments)
- return True
+ if Move.assign_try([m for s in shipments for m in s.moves],
+ with_childs=False):
+ cls.assign(shipments)
+ return True
+ else:
+ return False
@classmethod
@ModelView.button
@@ -780,7 +768,11 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
"Customer Shipment"
__name__ = 'stock.shipment.out'
_rec_name = 'code'
- effective_date = fields.Date('Effective Date', readonly=True)
+ effective_date = fields.Date('Effective Date',
+ states={
+ 'readonly': Eval('state').in_(['cancel', 'done']),
+ },
+ depends=['state'])
planned_date = fields.Date('Planned Date',
states={
'readonly': Not(Equal(Eval('state'), 'draft')),
@@ -797,12 +789,11 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
customer = fields.Many2One('party.party', 'Customer', required=True,
states={
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('outgoing_moves'))),
- }, on_change=['customer'],
- depends=['state', 'outgoing_moves'])
+ Bool(Eval('outgoing_moves', [0]))),
+ },
+ depends=['state'])
customer_location = fields.Function(fields.Many2One('stock.location',
- 'Customer Location', on_change_with=['customer']),
- 'on_change_with_customer_location')
+ 'Customer Location'), 'on_change_with_customer_location')
delivery_address = fields.Many2One('party.address',
'Delivery Address', required=True,
states={
@@ -816,15 +807,13 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
warehouse = fields.Many2One('stock.location', "Warehouse", required=True,
states={
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('outgoing_moves'))),
+ Bool(Eval('outgoing_moves', [0]))),
}, domain=[('type', '=', 'warehouse')],
- depends=['state', 'outgoing_moves'])
+ depends=['state'])
warehouse_storage = fields.Function(fields.Many2One('stock.location',
- 'Warehouse Storage', on_change_with=['warehouse']),
- 'on_change_with_warehouse_storage')
+ 'Warehouse Storage'), 'on_change_with_warehouse_storage')
warehouse_output = fields.Function(fields.Many2One('stock.location',
- 'Warehouse Output', on_change_with=['warehouse']),
- 'on_change_with_warehouse_output')
+ 'Warehouse Output'), 'on_change_with_warehouse_output')
outgoing_moves = fields.Function(fields.One2Many('stock.move', 'shipment',
'Outgoing Moves',
domain=[
@@ -990,12 +979,14 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
def default_company():
return Transaction().context.get('company')
+ @fields.depends('customer')
def on_change_customer(self):
address = None
if self.customer:
address = self.customer.address_get(type='delivery')
return {'delivery_address': address.id if address else None}
+ @fields.depends('customer')
def on_change_with_customer_location(self, name=None):
if self.customer:
return self.customer.customer_location.id
@@ -1006,6 +997,7 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_storage()
+ @fields.depends('warehouse')
def on_change_with_warehouse_storage(self, name=None):
if self.warehouse:
return self.warehouse.storage_location.id
@@ -1016,6 +1008,7 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_output()
+ @fields.depends('warehouse')
def on_change_with_warehouse_output(self, name=None):
if self.warehouse:
return self.warehouse.output_location.id
@@ -1086,22 +1079,26 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
for move in shipment.outgoing_moves:
if move.state in ('cancel', 'done'):
continue
- to_create.append({
- 'from_location': (
- move.shipment.warehouse.storage_location.id),
- 'to_location': move.from_location.id,
- 'product': move.product.id,
- 'uom': move.uom.id,
- 'quantity': move.quantity,
- 'shipment': str(shipment),
- 'planned_date': move.planned_date,
- 'state': 'draft',
- 'company': move.company.id,
- 'currency': move.currency.id,
- 'unit_price': move.unit_price,
- })
+ to_create.append(shipment._get_inventory_move(move))
if to_create:
- Move.create(to_create)
+ Move.create([m._save_values for m in to_create])
+
+ def _get_inventory_move(self, move):
+ 'Return inventory move for the outgoing move'
+ pool = Pool()
+ Move = pool.get('stock.move')
+ return Move(
+ from_location=move.shipment.warehouse.storage_location,
+ to_location=move.from_location,
+ product=move.product,
+ uom=move.uom,
+ quantity=move.quantity,
+ shipment=self,
+ planned_date=move.planned_date,
+ company=move.company,
+ currency=move.currency,
+ unit_price=move.unit_price,
+ )
@classmethod
@Workflow.transition('assigned')
@@ -1114,9 +1111,33 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
def pack(cls, shipments):
pool = Pool()
Move = pool.get('stock.move')
- Uom = pool.get('product.uom')
Move.do([m for s in shipments for m in s.inventory_moves])
+ cls._sync_inventory_to_outgoing(shipments)
+ Move.assign([m for s in shipments for m in s.outgoing_moves])
+ def _get_outgoing_move(self, move):
+ 'Return outgoing move for the inventory move'
+ pool = Pool()
+ Move = pool.get('stock.move')
+ return Move(
+ from_location=move.to_location,
+ to_location=self.customer.customer_location,
+ product=move.product,
+ uom=move.uom,
+ quantity=move.quantity,
+ shipment=self,
+ planned_date=self.planned_date,
+ company=move.company,
+ currency=move.company.currency,
+ unit_price=move.unit_price,
+ )
+
+ @classmethod
+ def _sync_inventory_to_outgoing(cls, shipments):
+ 'Synchronise outgoing moves with inventory moves'
+ pool = Pool()
+ Move = pool.get('stock.move')
+ Uom = pool.get('product.uom')
for shipment in shipments:
# Sum all outgoing quantities
outgoing_qty = {}
@@ -1152,21 +1173,11 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
unit_price = Uom.compute_price(move.product.default_uom,
move.product.list_price, move.uom)
- to_create.append({
- 'from_location': move.to_location.id,
- 'to_location': shipment.customer.customer_location.id,
- 'product': move.product.id,
- 'uom': move.uom.id,
- 'quantity': out_quantity,
- 'shipment': str(shipment),
- 'state': 'draft',
- 'planned_date': shipment.planned_date,
- 'company': move.company.id,
- 'currency': move.company.currency.id,
- 'unit_price': unit_price,
- })
+ to_create.append(shipment._get_outgoing_move(move))
+ to_create[-1].quantity = out_quantity
+ to_create[-1].unit_price = unit_price
if to_create:
- Move.create(to_create)
+ Move.create([m._save_values for m in to_create])
#Re-read the shipment and remove exceeding quantities
for move in shipment.outgoing_moves:
@@ -1183,8 +1194,6 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
})
outgoing_qty[move.product.id] -= removed_qty
- Move.assign([m for s in shipments for m in s.outgoing_moves])
-
@classmethod
@ModelView.button
@Workflow.transition('done')
@@ -1194,7 +1203,7 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
Date = pool.get('ir.date')
Move.do([m for s in shipments for m in s.outgoing_moves])
- cls.write(shipments, {
+ cls.write([s for s in shipments if not s.effective_date], {
'effective_date': Date.today(),
})
@@ -1247,9 +1256,9 @@ class ShipmentOut(Workflow, ModelSQL, ModelView):
return shipments
@classmethod
- def write(cls, shipments, values):
- super(ShipmentOut, cls).write(shipments, values)
- cls._set_move_planned_date(shipments)
+ def write(cls, *args):
+ super(ShipmentOut, cls).write(*args)
+ cls._set_move_planned_date(sum(args[::2], []))
@classmethod
def copy(cls, shipments, default=None):
@@ -1312,7 +1321,11 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
"Customer Return Shipment"
__name__ = 'stock.shipment.out.return'
_rec_name = 'code'
- effective_date = fields.Date('Effective Date', readonly=True)
+ effective_date = fields.Date('Effective Date',
+ states={
+ 'readonly': Eval('state').in_(['cancel', 'done']),
+ },
+ depends=['state'])
planned_date = fields.Date('Planned Date',
states={
'readonly': Not(Equal(Eval('state'), 'draft')),
@@ -1329,12 +1342,11 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
customer = fields.Many2One('party.party', 'Customer', required=True,
states={
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('incoming_moves'))),
- }, on_change=['customer'],
- depends=['state', 'incoming_moves'])
+ Bool(Eval('incoming_moves', [0]))),
+ },
+ depends=['state'])
customer_location = fields.Function(fields.Many2One('stock.location',
- 'Customer Location', on_change_with=['customer']),
- 'on_change_with_customer_location')
+ 'Customer Location'), 'on_change_with_customer_location')
delivery_address = fields.Many2One('party.address',
'Delivery Address', required=True,
states={
@@ -1348,15 +1360,13 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
warehouse = fields.Many2One('stock.location', "Warehouse", required=True,
states={
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('incoming_moves'))),
+ Bool(Eval('incoming_moves', [0]))),
}, domain=[('type', '=', 'warehouse')],
- depends=['state', 'incoming_moves'])
+ depends=['state'])
warehouse_storage = fields.Function(fields.Many2One('stock.location',
- 'Warehouse Storage', on_change_with=['warehouse']),
- 'on_change_with_warehouse_storage')
+ 'Warehouse Storage'), 'on_change_with_warehouse_storage')
warehouse_input = fields.Function(fields.Many2One('stock.location',
- 'Warehouse Input', on_change_with=['warehouse']),
- 'on_change_with_warehouse_input')
+ 'Warehouse Input'), 'on_change_with_warehouse_input')
incoming_moves = fields.Function(fields.One2Many('stock.move', 'shipment',
'Incoming Moves',
domain=[
@@ -1492,6 +1502,7 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
def default_company():
return Transaction().context.get('company')
+ @fields.depends('customer')
def on_change_customer(self):
address = None
if self.customer:
@@ -1500,6 +1511,7 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
'delivery_address': address.id if address else None,
}
+ @fields.depends('customer')
def on_change_with_customer_location(self, name=None):
if self.customer:
return self.customer.customer_location.id
@@ -1510,6 +1522,7 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_storage()
+ @fields.depends('warehouse')
def on_change_with_warehouse_storage(self, name=None):
if self.warehouse:
return self.warehouse.storage_location.id
@@ -1520,6 +1533,7 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
if warehouse:
return cls(warehouse=warehouse).on_change_with_warehouse_input()
+ @fields.depends('warehouse')
def on_change_with_warehouse_input(self, name=None):
if self.warehouse:
return self.warehouse.input_location.id
@@ -1605,9 +1619,9 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
return shipments
@classmethod
- def write(cls, shipments, values):
- super(ShipmentOutReturn, cls).write(shipments, values)
- cls._set_move_planned_date(shipments)
+ def write(cls, *args):
+ super(ShipmentOutReturn, cls).write(*args)
+ cls._set_move_planned_date(sum(args[::2], []))
@classmethod
def copy(cls, shipments, default=None):
@@ -1654,7 +1668,7 @@ class ShipmentOutReturn(Workflow, ModelSQL, ModelView):
Move = pool.get('stock.move')
Date = pool.get('ir.date')
Move.do([m for s in shipments for m in s.inventory_moves])
- cls.write(shipments, {
+ cls.write([s for s in shipments if not s.effective_date], {
'effective_date': Date.today(),
})
@@ -1752,7 +1766,11 @@ class ShipmentInternal(Workflow, ModelSQL, ModelView):
"Internal Shipment"
__name__ = 'stock.shipment.internal'
_rec_name = 'code'
- effective_date = fields.Date('Effective Date', readonly=True)
+ effective_date = fields.Date('Effective Date',
+ states={
+ 'readonly': Eval('state').in_(['cancel', 'done']),
+ },
+ depends=['state'])
planned_date = fields.Date('Planned Date',
states={
'readonly': Not(Equal(Eval('state'), 'draft')),
@@ -1774,18 +1792,18 @@ class ShipmentInternal(Workflow, ModelSQL, ModelView):
from_location = fields.Many2One('stock.location', "From Location",
required=True, states={
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('moves'))),
+ Bool(Eval('moves', [0]))),
},
domain=[
('type', 'in', ['storage', 'lost_found']),
- ], depends=['state', 'moves'])
+ ], depends=['state'])
to_location = fields.Many2One('stock.location', "To Location",
required=True, states={
'readonly': Or(Not(Equal(Eval('state'), 'draft')),
- Bool(Eval('moves'))),
+ Bool(Eval('moves', [0]))),
}, domain=[
('type', 'in', ['storage', 'lost_found']),
- ], depends=['state', 'moves'])
+ ], depends=['state'])
moves = fields.One2Many('stock.move', 'shipment', 'Moves',
states={
'readonly': ((Eval('state') != 'draft')
@@ -1972,7 +1990,7 @@ class ShipmentInternal(Workflow, ModelSQL, ModelView):
Move = pool.get('stock.move')
Date = pool.get('ir.date')
Move.do([m for s in shipments for m in s.moves])
- cls.write(shipments, {
+ cls.write([s for s in shipments if not s.effective_date], {
'effective_date': Date.today(),
})
diff --git a/tests/scenario_stock_average_cost_price.rst b/tests/scenario_stock_average_cost_price.rst
index d638797..3423ecb 100644
--- a/tests/scenario_stock_average_cost_price.rst
+++ b/tests/scenario_stock_average_cost_price.rst
@@ -101,8 +101,8 @@ Make 1 unit of the product available @ 100 ::
Check Cost Price is 100::
>>> product.reload()
- >>> product.template.cost_price == Decimal('100')
- True
+ >>> product.template.cost_price
+ Decimal('100.0000')
Add 1 more unit @ 200::
@@ -123,5 +123,5 @@ Add 1 more unit @ 200::
Check Cost Price Average is 150::
>>> product.reload()
- >>> product.template.cost_price == Decimal('150')
- True
+ >>> product.template.cost_price
+ Decimal('150.0000')
diff --git a/tests/scenario_stock_average_cost_price.rst b/tests/scenario_stock_inventory.rst
similarity index 74%
copy from tests/scenario_stock_average_cost_price.rst
copy to tests/scenario_stock_inventory.rst
index d638797..149842c 100644
--- a/tests/scenario_stock_average_cost_price.rst
+++ b/tests/scenario_stock_inventory.rst
@@ -1,5 +1,5 @@
========================
-Stock Average Cost Price
+Stock Inventory Scenario
========================
=============
@@ -22,8 +22,8 @@ Create database::
Install stock Module::
>>> Module = Model.get('ir.module.module')
- >>> modules = Module.find([('name', '=', 'stock')])
- >>> Module.install([x.id for x in modules], config.context)
+ >>> stock_module, = Module.find([('name', '=', 'stock')])
+ >>> stock_module.click('install')
>>> Wizard('ir.module.module.install_upgrade').execute('upgrade')
Create company::
@@ -57,6 +57,12 @@ Reload the context::
>>> User = Model.get('res.user')
>>> config._context = User.get_preferences(True, config.context)
+Get stock locations::
+
+ >>> Location = Model.get('stock.location')
+ >>> supplier_loc, = Location.find([('code', '=', 'SUP')])
+ >>> storage_loc, = Location.find([('code', '=', 'STO')])
+
Create product::
>>> ProductUom = Model.get('product.uom')
@@ -75,13 +81,7 @@ Create product::
>>> product.template = template
>>> product.save()
-Get stock locations::
-
- >>> Location = Model.get('stock.location')
- >>> supplier_loc, = Location.find([('code', '=', 'SUP')])
- >>> storage_loc, = Location.find([('code', '=', 'STO')])
-
-Make 1 unit of the product available @ 100 ::
+Fill storage::
>>> StockMove = Model.get('stock.move')
>>> incoming_move = StockMove()
@@ -96,32 +96,26 @@ Make 1 unit of the product available @ 100 ::
>>> incoming_move.unit_price = Decimal('100')
>>> incoming_move.currency = currency
>>> incoming_move.save()
- >>> StockMove.do([incoming_move.id], config.context)
+ >>> incoming_move.click('do')
-Check Cost Price is 100::
+Create an inventory::
- >>> product.reload()
- >>> product.template.cost_price == Decimal('100')
+ >>> Inventory = Model.get('stock.inventory')
+ >>> inventory = Inventory()
+ >>> inventory.location = storage_loc
+ >>> inventory.save()
+ >>> inventory.click('complete_lines')
+ >>> line, = inventory.lines
+ >>> line.expected_quantity == 1
True
-
-Add 1 more unit @ 200::
-
- >>> incoming_move = StockMove()
- >>> incoming_move.product = product
- >>> incoming_move.uom = unit
- >>> incoming_move.quantity = 1
- >>> incoming_move.from_location = supplier_loc
- >>> incoming_move.to_location = storage_loc
- >>> incoming_move.planned_date = today
- >>> incoming_move.effective_date = today
- >>> incoming_move.company = company
- >>> incoming_move.unit_price = Decimal('200')
- >>> incoming_move.currency = currency
- >>> incoming_move.save()
- >>> StockMove.do([incoming_move.id], config.context)
-
-Check Cost Price Average is 150::
-
- >>> product.reload()
- >>> product.template.cost_price == Decimal('150')
+ >>> line.quantity = 2
+ >>> inventory.save()
+ >>> inventory.click('confirm')
+ >>> line.reload()
+ >>> move, = line.moves
+ >>> move.quantity == 1
+ True
+ >>> move.from_location == inventory.lost_found
+ True
+ >>> move.to_location == inventory.location
True
diff --git a/tests/scenario_stock_shipment_out.rst b/tests/scenario_stock_shipment_out.rst
index d2689cf..144c3c6 100644
--- a/tests/scenario_stock_shipment_out.rst
+++ b/tests/scenario_stock_shipment_out.rst
@@ -13,6 +13,7 @@ Imports::
>>> from decimal import Decimal
>>> from proteus import config, Model, Wizard
>>> today = datetime.date.today()
+ >>> yesterday = today - relativedelta(days=1)
Create database::
@@ -35,14 +36,14 @@ Create company::
>>> company_config = Wizard('company.company.config')
>>> company_config.execute('company')
>>> company = company_config.form
- >>> party = Party(name='OPENLABS')
+ >>> party = Party(name='Dunder Mifflin')
>>> party.save()
>>> company.party = party
- >>> currencies = Currency.find([('code', '=', 'EUR')])
+ >>> currencies = Currency.find([('code', '=', 'USD')])
>>> if not currencies:
- ... currency = Currency(name='Euro', symbol=u'€', code='EUR',
+ ... currency = Currency(name='U.S. Dollar', symbol='$', code='USD',
... rounding=Decimal('0.01'), mon_grouping='[3, 3, 0]',
- ... mon_decimal_point=',')
+ ... mon_decimal_point='.', mon_thousands_sep=',')
... currency.save()
... CurrencyRate(date=today + relativedelta(month=1, day=1),
... rate=Decimal('1.0'), currency=currency).save()
@@ -158,6 +159,14 @@ Assign the shipment now::
>>> states.sort()
>>> states
[u'assigned', u'draft']
+ >>> effective_dates = [m.effective_date for m in
+ ... shipment_out.inventory_moves]
+ >>> len(set(effective_dates))
+ 2
+ >>> planned_dates = [m.planned_date for m in
+ ... shipment_out.outgoing_moves]
+ >>> len(set(planned_dates))
+ 1
Delete the draft move, assign and pack shipment::
@@ -188,6 +197,14 @@ Set the state as Done::
>>> shipment_out.reload()
>>> set([m.state for m in shipment_out.outgoing_moves])
set([u'done'])
+ >>> planned_dates = [m.planned_date for m in
+ ... shipment_out.outgoing_moves]
+ >>> planned_dates == [today, today]
+ True
+ >>> effective_dates = [m.effective_date for m in
+ ... shipment_out.outgoing_moves]
+ >>> len(set(effective_dates))
+ 1
>>> len(shipment_out.outgoing_moves)
2
>>> len(shipment_out.inventory_moves)
@@ -197,3 +214,56 @@ Set the state as Done::
>>> sum([m.quantity for m in shipment_out.inventory_moves]) == \
... sum([m.quantity for m in shipment_out.outgoing_moves])
True
+
+Create Shipment Out with effective date::
+
+ >>> ShipmentOut = Model.get('stock.shipment.out')
+ >>> shipment_out = ShipmentOut()
+ >>> shipment_out.planned_date = yesterday
+ >>> shipment_out.effective_date = yesterday
+ >>> shipment_out.customer = customer
+ >>> shipment_out.warehouse = warehouse_loc
+ >>> shipment_out.company = company
+ >>> move = shipment_out.outgoing_moves.new()
+ >>> move.product = product
+ >>> move.uom =unit
+ >>> move.quantity = 1
+ >>> move.from_location = output_loc
+ >>> move.to_location = customer_loc
+ >>> move.company = company
+ >>> move.unit_price = Decimal('1')
+ >>> move.currency = currency
+ >>> shipment_out.click('wait')
+
+Make 1 unit of the product available::
+
+ >>> incoming_move = StockMove()
+ >>> incoming_move.product = product
+ >>> incoming_move.uom = unit
+ >>> incoming_move.quantity = 1
+ >>> incoming_move.from_location = supplier_loc
+ >>> incoming_move.to_location = storage_loc
+ >>> incoming_move.planned_date = yesterday
+ >>> incoming_move.effective_date = yesterday
+ >>> incoming_move.company = company
+ >>> incoming_move.unit_price = Decimal('1')
+ >>> incoming_move.currency = currency
+ >>> incoming_move.save()
+ >>> StockMove.do([incoming_move.id], config.context)
+
+Finish the shipment::
+
+ >>> ShipmentOut.assign_try([shipment_out.id], config.context)
+ True
+ >>> shipment_out.click('pack')
+ >>> shipment_out.click('done')
+ >>> shipment_out.reload()
+ >>> shipment_out.state
+ u'done'
+ >>> outgoing_move, = shipment_out.outgoing_moves
+ >>> outgoing_move.effective_date == yesterday
+ True
+ >>> inventory_move, = shipment_out.inventory_moves
+ >>> inventory_move.effective_date == yesterday
+ True
+
diff --git a/tests/test_stock.py b/tests/test_stock.py
index f83c075..4f260a9 100644
--- a/tests/test_stock.py
+++ b/tests/test_stock.py
@@ -1,14 +1,5 @@
-#!/usr/bin/env python
#This file is part of Tryton. The COPYRIGHT file at the top level of
#this repository contains the full copyright notices and license terms.
-
-import sys
-import os
-DIR = os.path.abspath(os.path.normpath(os.path.join(__file__,
- '..', '..', '..', '..', '..', 'trytond')))
-if os.path.isdir(DIR):
- sys.path.insert(0, os.path.dirname(DIR))
-
import unittest
import doctest
import datetime
@@ -17,15 +8,13 @@ from dateutil.relativedelta import relativedelta
from functools import partial
import trytond.tests.test_tryton
from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, test_view,\
- test_depends
-from trytond.backend.sqlite.database import Database as SQLiteDatabase
+ test_depends, doctest_dropdb
from trytond.transaction import Transaction
+from trytond.exceptions import UserWarning
class StockTestCase(unittest.TestCase):
- '''
- Test Stock module.
- '''
+ 'Test Stock module'
def setUp(self):
trytond.tests.test_tryton.install_module('stock')
@@ -41,21 +30,15 @@ class StockTestCase(unittest.TestCase):
self.cache = POOL.get('stock.period.cache')
def test0005views(self):
- '''
- Test views.
- '''
+ 'Test views'
test_view('stock')
def test0006depends(self):
- '''
- Test depends.
- '''
+ 'Test depends'
test_depends()
def test0010move_internal_quantity(self):
- '''
- Test Move.internal_quantity.
- '''
+ 'Test Move.internal_quantity'
with Transaction().start(DB_NAME, USER, context=CONTEXT):
category, = self.category.create([{
'name': 'Test Move.internal_quantity',
@@ -76,7 +59,9 @@ class StockTestCase(unittest.TestCase):
}])
supplier, = self.location.search([('code', '=', 'SUP')])
storage, = self.location.search([('code', '=', 'STO')])
- company, = self.company.search([('rec_name', '=', 'B2CK')])
+ company, = self.company.search([
+ ('rec_name', '=', 'Dunder Mifflin'),
+ ])
currency = company.currency
self.user.write([self.user(USER)], {
'main_company': company.id,
@@ -112,9 +97,7 @@ class StockTestCase(unittest.TestCase):
internal_quantity)
def test0020products_by_location(self):
- '''
- Test products_by_location.
- '''
+ 'Test products_by_location'
with Transaction().start(DB_NAME, USER,
context=CONTEXT) as transaction:
category, = self.category.create([{
@@ -137,7 +120,9 @@ class StockTestCase(unittest.TestCase):
supplier, = self.location.search([('code', '=', 'SUP')])
customer, = self.location.search([('code', '=', 'CUS')])
storage, = self.location.search([('code', '=', 'STO')])
- company, = self.company.search([('rec_name', '=', 'B2CK')])
+ company, = self.company.search([
+ ('rec_name', '=', 'Dunder Mifflin'),
+ ])
currency = company.currency
self.user.write([self.user(USER)], {
'main_company': company.id,
@@ -280,6 +265,62 @@ class StockTestCase(unittest.TestCase):
else:
self.assertEqual(product_reloaded.quantity, quantity)
+ def tests_product_search_quantity(context, quantity):
+ with transaction.set_context(locations=[storage.id]):
+ if (not context.get('stock_date_end')
+ or context['stock_date_end'] > today
+ or context.get('forecast')):
+ fname = 'forecast_quantity'
+ else:
+ fname = 'quantity'
+ found_products = self.product.search([
+ (fname, '=', quantity),
+ ])
+ self.assertIn(product, found_products)
+
+ found_products = self.product.search([
+ (fname, '!=', quantity),
+ ])
+ self.assertNotIn(product, found_products)
+
+ found_products = self.product.search([
+ (fname, 'in', (quantity, quantity + 1)),
+ ])
+ self.assertIn(product, found_products)
+
+ found_products = self.product.search([
+ (fname, 'not in', (quantity, quantity + 1)),
+ ])
+ self.assertNotIn(product, found_products)
+
+ found_products = self.product.search([
+ (fname, '<', quantity),
+ ])
+ self.assertNotIn(product, found_products)
+ found_products = self.product.search([
+ (fname, '<', quantity + 1),
+ ])
+ self.assertIn(product, found_products)
+
+ found_products = self.product.search([
+ (fname, '>', quantity),
+ ])
+ self.assertNotIn(product, found_products)
+ found_products = self.product.search([
+ (fname, '>', quantity - 1),
+ ])
+ self.assertIn(product, found_products)
+
+ found_products = self.product.search([
+ (fname, '>=', quantity),
+ ])
+ self.assertIn(product, found_products)
+
+ found_products = self.product.search([
+ (fname, '<=', quantity),
+ ])
+ self.assertIn(product, found_products)
+
def test_products_by_location():
for context, quantity in tests:
with transaction.set_context(context):
@@ -289,6 +330,7 @@ class StockTestCase(unittest.TestCase):
self.assertEqual(products_by_location(),
{(storage.id, product.id): quantity})
tests_product_quantity(context, quantity)
+ tests_product_search_quantity(context, quantity)
test_products_by_location()
@@ -325,10 +367,12 @@ class StockTestCase(unittest.TestCase):
self.period.close([period])
test_products_by_location()
- # Test with_childs
+ # Test with_childs and stock_skip_warehouse
with Transaction().start(DB_NAME, USER,
context=CONTEXT) as transaction:
- company, = self.company.search([('rec_name', '=', 'B2CK')])
+ company, = self.company.search([
+ ('rec_name', '=', 'Dunder Mifflin'),
+ ])
self.user.write([self.user(USER)], {
'main_company': company.id,
'company': company.id,
@@ -350,6 +394,7 @@ class StockTestCase(unittest.TestCase):
lost_found, = self.location.search([('type', '=', 'lost_found')])
warehouse, = self.location.search([('type', '=', 'warehouse')])
storage, = self.location.search([('code', '=', 'STO')])
+ input_, = self.location.search([('code', '=', 'IN')])
storage1, = self.location.create([{
'name': 'Storage 1',
'type': 'view',
@@ -375,6 +420,15 @@ class StockTestCase(unittest.TestCase):
'planned_date': today,
'effective_date': today,
'company': company.id,
+ }, {
+ 'product': product.id,
+ 'uom': unit.id,
+ 'quantity': 1,
+ 'from_location': input_.id,
+ 'to_location': storage.id,
+ 'planned_date': today,
+ 'effective_date': today,
+ 'company': company.id,
}])
self.move.do(moves)
@@ -383,10 +437,18 @@ class StockTestCase(unittest.TestCase):
self.assertEqual(products_by_location[(warehouse.id, product.id)],
1)
+ with Transaction().set_context(stock_skip_warehouse=True):
+ products_by_location = self.product.products_by_location(
+ [warehouse.id], [product.id], with_childs=True)
+ products_by_location_all = self.product.products_by_location(
+ [warehouse.id], None, with_childs=True)
+ self.assertEqual(products_by_location[(warehouse.id, product.id)],
+ 2)
+ self.assertEqual(
+ products_by_location_all[(warehouse.id, product.id)], 2)
+
def test0030period(self):
- '''
- Test period.
- '''
+ 'Test period'
with Transaction().start(DB_NAME, USER,
context=CONTEXT) as transaction:
category, = self.category.create([{
@@ -408,7 +470,9 @@ class StockTestCase(unittest.TestCase):
supplier, = self.location.search([('code', '=', 'SUP')])
customer, = self.location.search([('code', '=', 'CUS')])
storage, = self.location.search([('code', '=', 'STO')])
- company, = self.company.search([('rec_name', '=', 'B2CK')])
+ company, = self.company.search([
+ ('rec_name', '=', 'Dunder Mifflin'),
+ ])
currency = company.currency
self.user.write([self.user(USER)], {
'main_company': company.id,
@@ -558,18 +622,42 @@ class StockTestCase(unittest.TestCase):
}])
self.assertRaises(Exception, self.period.close, [period])
+ def test0040check_origin(self):
+ 'Test Move check_origin'
+ with Transaction().start(DB_NAME, USER, context=CONTEXT):
+ uom, = self.uom.search([('name', '=', 'Unit')])
+ template, = self.template.create([{
+ 'name': 'Test Move.check_origin',
+ 'type': 'goods',
+ 'list_price': Decimal(1),
+ 'cost_price': Decimal(0),
+ 'cost_price_method': 'fixed',
+ 'default_uom': uom.id,
+ }])
+ product, = self.product.create([{
+ 'template': template.id,
+ }])
+ storage, = self.location.search([('code', '=', 'STO')])
+ customer, = self.location.search([('code', '=', 'CUS')])
+ company, = self.company.search([
+ ('rec_name', '=', 'Dunder Mifflin'),
+ ])
-def doctest_dropdb(test):
- '''
- Remove sqlite memory database
- '''
- database = SQLiteDatabase().connect()
- cursor = database.cursor(autocommit=True)
- try:
- database.drop(cursor, ':memory:')
- cursor.commit()
- finally:
- cursor.close()
+ moves = self.move.create([{
+ 'product': product.id,
+ 'uom': uom.id,
+ 'quantity': 1,
+ 'from_location': storage.id,
+ 'to_location': customer.id,
+ 'company': company.id,
+ 'unit_price': Decimal(1),
+ 'currency': company.currency.id,
+ }])
+
+ self.move.check_origin(moves, set())
+ self.move.check_origin(moves, {'supplier'})
+ self.assertRaises(UserWarning, self.move.check_origin, moves,
+ {'customer'})
def suite():
@@ -586,7 +674,8 @@ def suite():
'scenario_stock_average_cost_price.rst',
setUp=doctest_dropdb, tearDown=doctest_dropdb, encoding='utf-8',
optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
+ suite.addTests(doctest.DocFileSuite(
+ 'scenario_stock_inventory.rst',
+ setUp=doctest_dropdb, tearDown=doctest_dropdb, encoding='utf-8',
+ optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
return suite
-
-if __name__ == '__main__':
- unittest.TextTestRunner(verbosity=2).run(suite())
diff --git a/tryton.cfg b/tryton.cfg
index 651d7df..639b32a 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -1,5 +1,5 @@
[tryton]
-version=3.0.1
+version=3.2.0
depends:
company
currency
diff --git a/trytond_stock.egg-info/PKG-INFO b/trytond_stock.egg-info/PKG-INFO
index f2715e7..ed043a0 100644
--- a/trytond_stock.egg-info/PKG-INFO
+++ b/trytond_stock.egg-info/PKG-INFO
@@ -1,12 +1,12 @@
Metadata-Version: 1.1
Name: trytond-stock
-Version: 3.0.1
+Version: 3.2.0
Summary: Tryton module for stock and inventory
Home-page: http://www.tryton.org/
Author: Tryton
-Author-email: UNKNOWN
+Author-email: issue_tracker at tryton.org
License: GPL-3
-Download-URL: http://downloads.tryton.org/3.0/
+Download-URL: http://downloads.tryton.org/3.2/
Description: trytond_stock
=============
@@ -43,6 +43,7 @@ Description: trytond_stock
http://www.tryton.org/
+Keywords: tryton stock
Platform: UNKNOWN
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Plugins
@@ -63,6 +64,5 @@ Classifier: Natural Language :: Russian
Classifier: Natural Language :: Slovenian
Classifier: Natural Language :: Spanish
Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
Classifier: Topic :: Office/Business
diff --git a/trytond_stock.egg-info/SOURCES.txt b/trytond_stock.egg-info/SOURCES.txt
index 2acd70d..7910ad4 100644
--- a/trytond_stock.egg-info/SOURCES.txt
+++ b/trytond_stock.egg-info/SOURCES.txt
@@ -45,6 +45,7 @@ locale/nl_NL.po
locale/ru_RU.po
locale/sl_SI.po
tests/scenario_stock_average_cost_price.rst
+tests/scenario_stock_inventory.rst
tests/scenario_stock_shipment_out.rst
trytond_stock.egg-info/PKG-INFO
trytond_stock.egg-info/SOURCES.txt
diff --git a/trytond_stock.egg-info/requires.txt b/trytond_stock.egg-info/requires.txt
index f714b59..191e6a7 100644
--- a/trytond_stock.egg-info/requires.txt
+++ b/trytond_stock.egg-info/requires.txt
@@ -1,6 +1,6 @@
python-sql
-trytond_company >= 3.0, < 3.1
-trytond_currency >= 3.0, < 3.1
-trytond_party >= 3.0, < 3.1
-trytond_product >= 3.0, < 3.1
-trytond >= 3.0, < 3.1
\ No newline at end of file
+trytond_company >= 3.2, < 3.3
+trytond_currency >= 3.2, < 3.3
+trytond_party >= 3.2, < 3.3
+trytond_product >= 3.2, < 3.3
+trytond >= 3.2, < 3.3
\ No newline at end of file
diff --git a/view/inventory_line_form.xml b/view/inventory_line_form.xml
index 161332f..9a94652 100644
--- a/view/inventory_line_form.xml
+++ b/view/inventory_line_form.xml
@@ -2,6 +2,9 @@
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of
this repository contains the full copyright notices and license terms. -->
<form string="Inventory Line" col="4">
+ <label name="inventory"/>
+ <field name="inventory"/>
+ <newline/>
<label name="product"/>
<field name="product"/>
<label name="uom"/>
@@ -11,9 +14,5 @@ this repository contains the full copyright notices and license terms. -->
<field name="expected_quantity"/>
<label name="quantity"/>
<field name="quantity"/>
- <label name="move"/>
- <field name="move"/>
- <label name="inventory"/>
- <field name="inventory"/>
- <field name="unit_digits" invisible="1" colspan="4"/>
+ <field name="moves" colspan="4"/>
</form>
diff --git a/view/product_tree_qty.xml b/view/product_tree_qty.xml
index ac84701..d8c5b7d 100644
--- a/view/product_tree_qty.xml
+++ b/view/product_tree_qty.xml
@@ -5,8 +5,8 @@ this repository contains the full copyright notices and license terms. -->
<field name="template"/>
<field name="code"/>
<field name="quantity"/>
- <field name="cost_value"/>
<field name="forecast_quantity"/>
<field name="default_uom"/>
+ <field name="cost_value" sum="Cost Value"/>
<field name="active"/>
</tree>
diff --git a/view/shipment_internal_form.xml b/view/shipment_internal_form.xml
index 5a8442b..d095731 100644
--- a/view/shipment_internal_form.xml
+++ b/view/shipment_internal_form.xml
@@ -22,7 +22,7 @@ this repository contains the full copyright notices and license terms. -->
<group col="5" colspan="2" id="buttons">
<button string="Cancel" name="cancel" icon="tryton-cancel"/>
<button string="Draft" name="draft"/>
- <button string="Waiting" name="wait"/>
+ <button string="Wait" name="wait"/>
<button string="Assign" name="assign_wizard" icon="tryton-go-next"/>
<button string="Done" name="done" icon="tryton-ok"/>
</group>
diff --git a/view/shipment_out_form.xml b/view/shipment_out_form.xml
index ac51e97..1d36ae4 100644
--- a/view/shipment_out_form.xml
+++ b/view/shipment_out_form.xml
@@ -32,7 +32,7 @@ this repository contains the full copyright notices and license terms. -->
<group col="6" colspan="2" id="buttons">
<button string="Cancel" name="cancel" icon="tryton-cancel"/>
<button string="Draft" name="draft"/>
- <button string="Waiting" name="wait"/>
+ <button string="Wait" name="wait"/>
<button string="Assign" name="assign_wizard"
icon="tryton-go-next"/>
<button string="Make shipment" name="pack" icon="tryton-go-next"/>
--
tryton-modules-stock
More information about the tryton-debian-vcs
mailing list