[tryton-debian-vcs] tryton-modules-purchase branch debian updated. debian/3.2.0-1-5-g78a0eb3

Mathias Behrle tryton-debian-vcs at alioth.debian.org
Thu Oct 23 12:17:30 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-purchase.git;a=commitdiff;h=debian/3.2.0-1-5-g78a0eb3

commit 78a0eb37f249028b7e95827458e52a9c67074d12
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Thu Oct 23 13:32:06 2014 +0200

    Releasing debian version 3.4.0-1.
    
    Signed-off-by: Mathias Behrle <mathiasb at m9s.biz>

diff --git a/debian/changelog b/debian/changelog
index 68dbb11..22ce535 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+tryton-modules-purchase (3.4.0-1) unstable; urgency=medium
+
+  * Updating signing key while using now plain .asc files instead of .pgp
+    binaries.
+  * Adding actual upstream signing key.
+  * Updating to Standards-Version: 3.9.6, no changes needed.
+  * Merging upstream version 3.4.0.
+
+ -- Mathias Behrle <mathiasb at m9s.biz>  Tue, 21 Oct 2014 20:24:20 +0200
+
 tryton-modules-purchase (3.2.0-1) unstable; urgency=medium
 
   * Removing  LC_ALL=C.UTF-8 as build environment.
commit 5a5077c2a874a698520ba35eca2615beebb25bc1
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Tue Oct 21 11:29:18 2014 +0200

    Merging upstream version 3.4.0.

diff --git a/CHANGELOG b/CHANGELOG
index 47d1e58..6697de8 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+Version 3.4.0 - 2014-10-20
+* Bug fixes (see mercurial logs for details)
+* Confirmed state split into Confirmed and Processing
+* Use MatchMixin for ProductSupplier
+
 Version 3.2.0 - 2014-04-21
 * Bug fixes (see mercurial logs for details)
 * Add link between stock moves and invoice lines
diff --git a/PKG-INFO b/PKG-INFO
index f525b62..a2fb331 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,12 @@
 Metadata-Version: 1.1
 Name: trytond_purchase
-Version: 3.2.0
+Version: 3.4.0
 Summary: Tryton module for purchase
 Home-page: http://www.tryton.org/
 Author: Tryton
 Author-email: issue_tracker at tryton.org
 License: GPL-3
-Download-URL: http://downloads.tryton.org/3.2/
+Download-URL: http://downloads.tryton.org/3.4/
 Description: trytond_purchase
         ================
         
diff --git a/invoice.py b/invoice.py
index 55cf40f..fb08125 100644
--- a/invoice.py
+++ b/invoice.py
@@ -17,10 +17,10 @@ def process_purchase(func):
     def wrapper(cls, invoices):
         pool = Pool()
         Purchase = pool.get('purchase.purchase')
-        with Transaction().set_user(0, set_context=True):
+        with Transaction().set_context(_check_access=False):
             purchases = [p for i in cls.browse(invoices) for p in i.purchases]
         func(cls, invoices)
-        with Transaction().set_user(0, set_context=True):
+        with Transaction().set_context(_check_access=False):
             Purchase.process(purchases)
     return wrapper
 
@@ -43,26 +43,17 @@ class Invoice:
                     'an invoice generated by a purchase.'),
                 })
 
-    @classmethod
-    def get_purchase_exception_state(cls, invoices, name):
-        Purchase = Pool().get('purchase.purchase')
-        with Transaction().set_user(0, set_context=True):
-            purchases = Purchase.search([
-                    ('invoices', 'in', [i.id for i in invoices]),
-                    ])
+    def get_purchase_exception_state(self, name):
+        purchases = self.purchases
 
         recreated = tuple(i for p in purchases for i in p.invoices_recreated)
         ignored = tuple(i for p in purchases for i in p.invoices_ignored)
 
-        res = {}
-        for invoice in invoices:
-            if invoice in recreated:
-                res[invoice.id] = 'recreated'
-            elif invoice in ignored:
-                res[invoice.id] = 'ignored'
-            else:
-                res[invoice.id] = ''
-        return res
+        if self in recreated:
+            return 'recreated'
+        elif self in ignored:
+            return 'ignored'
+        return ''
 
     def get_purchases(self, name):
         pool = Pool()
@@ -96,10 +87,9 @@ class Invoice:
     @Workflow.transition('draft')
     def draft(cls, invoices):
         Purchase = Pool().get('purchase.purchase')
-        with Transaction().set_user(0, set_context=True):
-            purchases = Purchase.search([
-                    ('invoices', 'in', [i.id for i in invoices]),
-                    ])
+        purchases = Purchase.search([
+                ('invoices', 'in', [i.id for i in invoices]),
+                ])
         if purchases and any(i.state == 'cancel' for i in invoices):
             cls.raise_user_error('reset_invoice_purchase')
 
diff --git a/locale/bg_BG.po b/locale/bg_BG.po
index c71e95e..b28635d 100644
--- a/locale/bg_BG.po
+++ b/locale/bg_BG.po
@@ -7,11 +7,8 @@ msgid "You cannot reset to draft an invoice generated by a purchase."
 msgstr "Не може да прехвърляте в проект фактура генерирана при покупка."
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
+msgid "Purchase prices are based on the purchase uom."
 msgstr ""
-"Покупните цени се основават мер, ед, на покупката, сигурни ли сте че искате "
-"да я смените?"
 
 msgctxt "error:purchase.line:"
 msgid ""
@@ -31,10 +28,6 @@ msgid "A warehouse must be defined for quotation of purchase \"%s\"."
 msgstr ""
 
 msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr ""
-
-msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
 msgstr ""
 
@@ -421,6 +414,11 @@ msgctxt "field:purchase.product_supplier.price,rec_name:"
 msgid "Name"
 msgstr "Име"
 
+#, fuzzy
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr "Последователност"
+
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr "Единична цена"
@@ -706,6 +704,16 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr "Партньори свързани с покупки"
 
+#, fuzzy
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr "Доставчици на продукт"
+
+#, fuzzy
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr "Цени"
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr "Конфигуриране на покупка"
@@ -778,6 +786,11 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr "Конфигурация"
 
+#, fuzzy
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr "Доставчици на продукт"
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
 msgstr "Управление на покупки"
@@ -1022,6 +1035,11 @@ msgctxt "selection:purchase.purchase,state:"
 msgid "Draft"
 msgstr "Проект"
 
+#, fuzzy
+msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr "Обработване"
+
 msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr "Запитване"
@@ -1130,6 +1148,11 @@ msgctxt "view:purchase.purchase:"
 msgid "Other Info"
 msgstr "Друга информация"
 
+#, fuzzy
+msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr "Обработване"
+
 msgctxt "view:purchase.purchase:"
 msgid "Purchase"
 msgstr "Покупка"
diff --git a/locale/ca_ES.po b/locale/ca_ES.po
index f7bc172..5e2a519 100644
--- a/locale/ca_ES.po
+++ b/locale/ca_ES.po
@@ -7,10 +7,8 @@ msgid "You cannot reset to draft an invoice generated by a purchase."
 msgstr "No podeu restaurar a esborrany una factura generada per una compra."
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
-msgstr ""
-"Els preus de compra estan basats en la UdM de compra. Voleu canviar-ho?"
+msgid "Purchase prices are based on the purchase uom."
+msgstr "Els preus de compra es basen en UdM de compra."
 
 msgctxt "error:purchase.line:"
 msgid ""
@@ -36,11 +34,6 @@ msgid "A warehouse must be defined for quotation of purchase \"%s\"."
 msgstr "S'ha de definir un magatzem pel pressupost de la compta \"%s\"."
 
 msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr ""
-"S'ha de definir una adreça de facturació pel pressupost de la compta \"%s\"."
-
-msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
 msgstr "No es troba el \"Compte a pagar\" del tercer \"%s\"."
 
@@ -366,7 +359,7 @@ msgstr "Moneda"
 
 msgctxt "field:purchase.product_supplier,delivery_time:"
 msgid "Delivery Time"
-msgstr "Temps d'enviament"
+msgstr "Termini de lliurament"
 
 msgctxt "field:purchase.product_supplier,id:"
 msgid "ID"
@@ -428,6 +421,10 @@ msgctxt "field:purchase.product_supplier.price,rec_name:"
 msgid "Name"
 msgstr "Nom"
 
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr "Seqüència"
+
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr "Preu unitari"
@@ -709,6 +706,14 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr "Tercers amb compres"
 
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr "Proveïdors de productes"
+
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr "Preus"
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr "Configuració de les compres"
@@ -776,6 +781,10 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr "Configuració"
 
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr "Proveïdors de productes"
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
 msgstr "Compres"
@@ -870,7 +879,7 @@ msgstr "Descripció:"
 
 msgctxt "odt:purchase.purchase:"
 msgid "Draft Purchase Order"
-msgstr "Comanda de compra en esborrany"
+msgstr "Comanda de compra esborrany"
 
 msgctxt "odt:purchase.purchase:"
 msgid "E-Mail:"
@@ -914,11 +923,11 @@ msgstr "Preu unitari"
 
 msgctxt "odt:purchase.purchase:"
 msgid "VAT Number:"
-msgstr "IVA:"
+msgstr "CIF/NIF:"
 
 msgctxt "odt:purchase.purchase:"
 msgid "VAT:"
-msgstr "IVA:"
+msgstr "CIF/NIF:"
 
 msgctxt "selection:account.invoice,purchase_exception_state:"
 msgid ""
@@ -1021,6 +1030,10 @@ msgid "Draft"
 msgstr "Esborrany"
 
 msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr "En procés"
+
+msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr "Pressupost"
 
@@ -1129,6 +1142,10 @@ msgid "Other Info"
 msgstr "Informació addicional"
 
 msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr "Processa"
+
+msgctxt "view:purchase.purchase:"
 msgid "Purchase"
 msgstr "Compra"
 
diff --git a/locale/cs_CZ.po b/locale/cs_CZ.po
index 87e92e3..3bf6de3 100644
--- a/locale/cs_CZ.po
+++ b/locale/cs_CZ.po
@@ -7,8 +7,7 @@ msgid "You cannot reset to draft an invoice generated by a purchase."
 msgstr ""
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
+msgid "Purchase prices are based on the purchase uom."
 msgstr ""
 
 msgctxt "error:purchase.line:"
@@ -29,10 +28,6 @@ msgid "A warehouse must be defined for quotation of purchase \"%s\"."
 msgstr ""
 
 msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr ""
-
-msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
 msgstr ""
 
@@ -418,6 +413,10 @@ msgctxt "field:purchase.product_supplier.price,rec_name:"
 msgid "Name"
 msgstr ""
 
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr ""
+
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr ""
@@ -699,6 +698,14 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr ""
 
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr ""
+
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr ""
@@ -766,6 +773,10 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr ""
 
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
 msgstr ""
@@ -1011,6 +1022,10 @@ msgid "Draft"
 msgstr ""
 
 msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr ""
+
+msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr ""
 
@@ -1119,6 +1134,10 @@ msgid "Other Info"
 msgstr ""
 
 msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr ""
+
+msgctxt "view:purchase.purchase:"
 msgid "Purchase"
 msgstr ""
 
diff --git a/locale/de_DE.po b/locale/de_DE.po
index 6162c66..71326c0 100644
--- a/locale/de_DE.po
+++ b/locale/de_DE.po
@@ -9,11 +9,8 @@ msgstr ""
 "zurückgesetzt werden."
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
-msgstr ""
-"Einkaufspreise basieren auf der Maßeinheit für den Einkauf.\n"
-"Soll sie wirklich geändert werden?"
+msgid "Purchase prices are based on the purchase uom."
+msgstr "Einkaufspreise werden auf Basis der Einkaufseinheit berechnet."
 
 msgctxt "error:purchase.line:"
 msgid ""
@@ -39,10 +36,6 @@ msgid "A warehouse must be defined for quotation of purchase \"%s\"."
 msgstr "Für Angebotsanfrage \"%s\" muss ein Warenlager angegeben werden."
 
 msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr "Für Angebotsanfrage \"%s\" muss eine Rechnungsadresse angegeben werden."
-
-msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
 msgstr "Fehlendes \"Verbindlichkeitskonto\" für Partei \"%s\"."
 
@@ -370,7 +363,7 @@ msgstr "Währung"
 
 msgctxt "field:purchase.product_supplier,delivery_time:"
 msgid "Delivery Time"
-msgstr "Lieferfrist"
+msgstr "Lieferzeitraum"
 
 msgctxt "field:purchase.product_supplier,id:"
 msgid "ID"
@@ -432,6 +425,10 @@ msgctxt "field:purchase.product_supplier.price,rec_name:"
 msgid "Name"
 msgstr "Name"
 
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr "Reihenfolge"
+
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr "Einzelpreis"
@@ -717,6 +714,14 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr "Parteien: Einkäufen zugeordnet"
 
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr "Lieferanten"
+
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr "Preise"
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr "Einstellungen Einkauf"
@@ -784,6 +789,10 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr "Einstellungen"
 
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr "Lieferanten"
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
 msgstr "Einkauf"
@@ -1029,6 +1038,10 @@ msgid "Draft"
 msgstr "Entwurf"
 
 msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr "In Ausführung"
+
+msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr "Angebot"
 
@@ -1137,6 +1150,10 @@ msgid "Other Info"
 msgstr "Sonstiges"
 
 msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr "Ausführen"
+
+msgctxt "view:purchase.purchase:"
 msgid "Purchase"
 msgstr "Einkauf"
 
diff --git a/locale/es_AR.po b/locale/es_AR.po
index 3171cd0..3a090bd 100644
--- a/locale/es_AR.po
+++ b/locale/es_AR.po
@@ -7,10 +7,8 @@ msgid "You cannot reset to draft an invoice generated by a purchase."
 msgstr "No puede restablecer a borrador una factura generada por una compra."
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
-msgstr ""
-"Los precios de compra están basados en la UdM de compra, ¿desea cambiarlo?"
+msgid "Purchase prices are based on the purchase uom."
+msgstr "Los precios de compra se basan en la UdM de compra."
 
 msgctxt "error:purchase.line:"
 msgid ""
@@ -35,12 +33,6 @@ msgid "A warehouse must be defined for quotation of purchase \"%s\"."
 msgstr "Se debe definir un almacén para el presupuesto de la compra «%s»."
 
 msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr ""
-"Se debe definir la dirección de facturación para el presupuesto de la compra"
-" «%s»."
-
-msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
 msgstr "Falta la «Cuenta a pagar» en la entidad «%s»."
 
@@ -429,6 +421,10 @@ msgctxt "field:purchase.product_supplier.price,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr "Secuencia"
+
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr "Precio unitario"
@@ -712,6 +708,14 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr "Entidades asociadas con compras"
 
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr "Proveedores de productos"
+
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr "Precios"
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr "Configuración de compras"
@@ -779,6 +783,10 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr "Configuración"
 
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr "Proveedores de productos"
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
 msgstr "Compras"
@@ -1024,6 +1032,10 @@ msgid "Draft"
 msgstr "Borrador"
 
 msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr "Procesamiento"
+
+msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr "Presupuesto"
 
@@ -1132,6 +1144,10 @@ msgid "Other Info"
 msgstr "Información adicional"
 
 msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr "Procesar"
+
+msgctxt "view:purchase.purchase:"
 msgid "Purchase"
 msgstr "Compra"
 
diff --git a/locale/es_CO.po b/locale/es_CO.po
index fa5eaee..009255e 100644
--- a/locale/es_CO.po
+++ b/locale/es_CO.po
@@ -7,10 +7,8 @@ msgid "You cannot reset to draft an invoice generated by a purchase."
 msgstr "No puede devolver a borrador una factura generada por una compra."
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
-msgstr ""
-"Los precios de compra están basados en la UdM de compra. ¿Desea cambiarlo?"
+msgid "Purchase prices are based on the purchase uom."
+msgstr "Los precios de compra se basan en la udm de la compra."
 
 msgctxt "error:purchase.line:"
 msgid ""
@@ -36,12 +34,6 @@ msgid "A warehouse must be defined for quotation of purchase \"%s\"."
 msgstr "Debe definir una bodega para la cotización de compra \"%s\"."
 
 msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr ""
-"La dirección de la factura debe definirse en la cotización de la compra "
-"\"%s\"."
-
-msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
 msgstr "Falta la \"Cuenta por Pagar\" en el tercero \"%s\"."
 
@@ -429,6 +421,10 @@ msgctxt "field:purchase.product_supplier.price,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr "Secuencia"
+
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr "Precio Unitario"
@@ -712,6 +708,14 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr "Proveedores"
 
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr "Proveedores de Producto"
+
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr "Precios"
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr "Configuración de Compras"
@@ -779,6 +783,10 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr "Configuración"
 
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr "Proveedores de Producto"
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
 msgstr "Gestión de Compras"
@@ -1024,6 +1032,10 @@ msgid "Draft"
 msgstr "Borrador"
 
 msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr "En Proceso"
+
+msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr "Cotización"
 
@@ -1132,6 +1144,10 @@ msgid "Other Info"
 msgstr "Info Adicional"
 
 msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr "Procesar"
+
+msgctxt "view:purchase.purchase:"
 msgid "Purchase"
 msgstr "Compra"
 
diff --git a/locale/es_CO.po b/locale/es_EC.po
similarity index 92%
copy from locale/es_CO.po
copy to locale/es_EC.po
index fa5eaee..9d6bbb6 100644
--- a/locale/es_CO.po
+++ b/locale/es_EC.po
@@ -4,42 +4,34 @@ msgstr "Content-Type: text/plain; charset=utf-8\n"
 
 msgctxt "error:account.invoice:"
 msgid "You cannot reset to draft an invoice generated by a purchase."
-msgstr "No puede devolver a borrador una factura generada por una compra."
+msgstr "No puede restaurar a borrador una factura generada por una compra."
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
-msgstr ""
-"Los precios de compra están basados en la UdM de compra. ¿Desea cambiarlo?"
+msgid "Purchase prices are based on the purchase uom."
+msgstr "Los precios de compra se basan en la unidad de medida de la compra."
 
 msgctxt "error:purchase.line:"
 msgid ""
 "Product \"%(product)s\" of purchase %(purchase)s misses an expense account."
 msgstr ""
-"El producto \"%(product)s\" de la compra \"%(purchase)s\" le falta una "
-"cuenta de gastos."
+"El producto \"%(product)s\" de la compra %(purchase)s le falta una cuenta de"
+" gastos."
 
 msgctxt "error:purchase.line:"
 msgid "Purchase \"%(purchase)s\" misses an \"account expense\" default property."
 msgstr ""
-"La compra \"%(purchase)s\" le falta la propiedad por defecto \"Cuenta de "
-"Gastos\"."
+"Falta la propiedad por defecto \"Cuenta de Gastos\" de la compra "
+"\"%(purchase)s\"."
 
 msgctxt "error:purchase.line:"
 msgid "Purchase \"%(purchase)s\" misses the supplier location for line \"%(line)s\"."
 msgstr ""
-"La compra \"%(purchase)s\" le falta la bodega del proveedor para la línea "
-"\"%(line)s\"."
+"Falta la ubicación del proveedor en la línea \"%(line)s\" de la compra "
+"\"%(purchase)s\"."
 
 msgctxt "error:purchase.purchase:"
 msgid "A warehouse must be defined for quotation of purchase \"%s\"."
-msgstr "Debe definir una bodega para la cotización de compra \"%s\"."
-
-msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr ""
-"La dirección de la factura debe definirse en la cotización de la compra "
-"\"%s\"."
+msgstr "Debe definir una bodega para la cotización de la compra \"%s\"."
 
 msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
@@ -51,19 +43,19 @@ msgstr "La compra \"%s\" debe ser cancelada antes de ser eliminada."
 
 msgctxt "error:stock.shipment.in.return:"
 msgid "You cannot reset to draft a move generated by a purchase."
-msgstr "No puede devolver a borrador un movimiento generado por una compra."
+msgstr "No puede restaurar a borrador un movimiento generado por una compra."
 
 msgctxt "error:stock.shipment.in:"
 msgid ""
 "You cannot reset to draft move \"%s\" because it was generated by a "
 "purchase."
 msgstr ""
-"No puede devolver a borrador el movimiento \"%s\" porque fue generado por "
-"una compra."
+"No puede restaurar a borrador el movimiento \"%s\" porque se generó mediante"
+" una compra."
 
 msgctxt "field:account.invoice,purchase_exception_state:"
 msgid "Exception State"
-msgstr "Estado Excepción"
+msgstr "Estado de Excepción"
 
 msgctxt "field:account.invoice,purchases:"
 msgid "Purchases"
@@ -99,7 +91,7 @@ msgstr "Método de Facturación"
 
 msgctxt "field:purchase.configuration,purchase_sequence:"
 msgid "Purchase Reference Sequence"
-msgstr "Secuencia Orden de Compra"
+msgstr "Secuencia de Referencia de Compra"
 
 msgctxt "field:purchase.configuration,rec_name:"
 msgid "Name"
@@ -159,7 +151,7 @@ msgstr "Descripción"
 
 msgctxt "field:purchase.line,from_location:"
 msgid "From Location"
-msgstr "Desde Bodega"
+msgstr "Desde Ubicación"
 
 msgctxt "field:purchase.line,id:"
 msgid "ID"
@@ -171,7 +163,7 @@ msgstr "Líneas de Factura"
 
 msgctxt "field:purchase.line,move_done:"
 msgid "Moves Done"
-msgstr "Movimientos Hechos"
+msgstr "Movimientos Realizados"
 
 msgctxt "field:purchase.line,move_exception:"
 msgid "Moves Exception"
@@ -199,7 +191,7 @@ msgstr "Producto"
 
 msgctxt "field:purchase.line,product_uom_category:"
 msgid "Product Uom Category"
-msgstr "Categoría UdM del producto"
+msgstr "Categoría UdM del Producto"
 
 msgctxt "field:purchase.line,purchase:"
 msgid "Purchase"
@@ -351,7 +343,7 @@ msgstr "Código"
 
 msgctxt "field:purchase.product_supplier,company:"
 msgid "Company"
-msgstr "Compañia"
+msgstr "Empresa"
 
 msgctxt "field:purchase.product_supplier,create_date:"
 msgid "Create Date"
@@ -429,6 +421,10 @@ msgctxt "field:purchase.product_supplier.price,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr "Secuencia"
+
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr "Precio Unitario"
@@ -447,7 +443,7 @@ msgstr "Comentario"
 
 msgctxt "field:purchase.purchase,company:"
 msgid "Company"
-msgstr "Compañia"
+msgstr "Empresa"
 
 msgctxt "field:purchase.purchase,create_date:"
 msgid "Create Date"
@@ -483,7 +479,7 @@ msgstr "Método de Facturación"
 
 msgctxt "field:purchase.purchase,invoice_state:"
 msgid "Invoice State"
-msgstr "Estado Factura"
+msgstr "Estado de Factura"
 
 msgctxt "field:purchase.purchase,invoices:"
 msgid "Invoices"
@@ -515,7 +511,7 @@ msgstr "Idioma del Tercero"
 
 msgctxt "field:purchase.purchase,payment_term:"
 msgid "Payment Term"
-msgstr "Forma de Pago"
+msgstr "Plazo de Pago"
 
 msgctxt "field:purchase.purchase,purchase_date:"
 msgid "Purchase Date"
@@ -531,7 +527,7 @@ msgstr "Referencia"
 
 msgctxt "field:purchase.purchase,shipment_returns:"
 msgid "Shipment Returns"
-msgstr "Devolución"
+msgstr "Devoluciones"
 
 msgctxt "field:purchase.purchase,shipment_state:"
 msgid "Shipment State"
@@ -539,7 +535,7 @@ msgstr "Estado de Envío"
 
 msgctxt "field:purchase.purchase,shipments:"
 msgid "Shipments"
-msgstr "Envios"
+msgstr "Envíos"
 
 msgctxt "field:purchase.purchase,state:"
 msgid "State"
@@ -567,11 +563,11 @@ msgstr "Cache del Total"
 
 msgctxt "field:purchase.purchase,untaxed_amount:"
 msgid "Untaxed"
-msgstr "Base"
+msgstr "Base (sin impuestos)"
 
 msgctxt "field:purchase.purchase,untaxed_amount_cache:"
 msgid "Untaxed Cache"
-msgstr "Cache de Base Sin Impuesto"
+msgstr "Cache de Base sin Impuestos"
 
 msgctxt "field:purchase.purchase,warehouse:"
 msgid "Warehouse"
@@ -659,7 +655,7 @@ msgstr "Moneda de Compra"
 
 msgctxt "field:stock.move,purchase_exception_state:"
 msgid "Exception State"
-msgstr "Estado Excepción"
+msgstr "Estado de Excepción"
 
 msgctxt "field:stock.move,purchase_quantity:"
 msgid "Purchase Quantity"
@@ -698,7 +694,7 @@ msgstr ""
 
 msgctxt "help:purchase.product_supplier,delivery_time:"
 msgid "In number of days"
-msgstr "En número de días."
+msgstr "En número de días"
 
 msgctxt "help:purchase.product_supplier.price,quantity:"
 msgid "Minimal quantity"
@@ -712,6 +708,14 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr "Proveedores"
 
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr "Proveedores de Producto"
+
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr "Precios"
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr "Configuración de Compras"
@@ -742,11 +746,11 @@ msgstr "Compra"
 
 msgctxt "model:ir.action,name:wizard_invoice_handle_exception"
 msgid "Handle Invoice Exception"
-msgstr "Excepció Manual de Factura"
+msgstr "Gestionar Excepción de Factura"
 
 msgctxt "model:ir.action,name:wizard_shipment_handle_exception"
 msgid "Handle Shipment Exception"
-msgstr "Excepción Manual de Envío"
+msgstr "Gestionar Excepción de Envío"
 
 msgctxt "model:ir.action.act_window.domain,name:act_purchase_form_domain_all"
 msgid "All"
@@ -755,7 +759,7 @@ msgstr "Todo"
 msgctxt ""
 "model:ir.action.act_window.domain,name:act_purchase_form_domain_confirmed"
 msgid "Confirmed"
-msgstr "Confirmada"
+msgstr "Confirmado"
 
 msgctxt ""
 "model:ir.action.act_window.domain,name:act_purchase_form_domain_draft"
@@ -779,9 +783,13 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr "Configuración"
 
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr "Proveedores de Producto"
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
-msgstr "Gestión de Compras"
+msgstr "Compras"
 
 msgctxt "model:ir.ui.menu,name:menu_purchase_configuration"
 msgid "Purchase Configuration"
@@ -805,7 +813,7 @@ msgstr "Configuración de Compras"
 
 msgctxt "model:purchase.handle.invoice.exception.ask,name:"
 msgid "Handle Invoice Exception"
-msgstr "Excepción Manual de Factura"
+msgstr "Gestionar Excepción de Factura"
 
 msgctxt "model:purchase.handle.shipment.exception.ask,name:"
 msgid "Handle Shipment Exception"
@@ -917,11 +925,11 @@ msgstr "Precio Unitario"
 
 msgctxt "odt:purchase.purchase:"
 msgid "VAT Number:"
-msgstr "Número Identificación:"
+msgstr "Número de RUC:"
 
 msgctxt "odt:purchase.purchase:"
 msgid "VAT:"
-msgstr "NIT:"
+msgstr "RUC:"
 
 msgctxt "selection:account.invoice,purchase_exception_state:"
 msgid ""
@@ -1017,13 +1025,17 @@ msgstr "Confirmada"
 
 msgctxt "selection:purchase.purchase,state:"
 msgid "Done"
-msgstr "Hecha"
+msgstr "Realizada"
 
 msgctxt "selection:purchase.purchase,state:"
 msgid "Draft"
 msgstr "Borrador"
 
 msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr "En Proceso"
+
+msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr "Cotización"
 
@@ -1053,19 +1065,19 @@ msgstr "Configuración de Compras"
 
 msgctxt "view:purchase.handle.invoice.exception.ask:"
 msgid "Choose invoices to recreate"
-msgstr "Seleccione facturas a rehacer"
+msgstr "Seleccione facturas a recrear"
 
 msgctxt "view:purchase.handle.invoice.exception.ask:"
 msgid "Handle Invoice Exception"
-msgstr "Excepción Manual de Factura"
+msgstr "Gestionar Excepción de Factura"
 
 msgctxt "view:purchase.handle.shipment.exception.ask:"
 msgid "Choose move to recreate"
-msgstr "Seleccione movimientos a rehacer"
+msgstr "Seleccione movimientos a recrear"
 
 msgctxt "view:purchase.handle.shipment.exception.ask:"
 msgid "Handle shipment Exception"
-msgstr "Excepción Manual de Envío"
+msgstr "Gestionar Excepción de Envío"
 
 msgctxt "view:purchase.line:"
 msgid "General"
@@ -1097,7 +1109,7 @@ msgstr "Precios del Proveedor del Producto"
 
 msgctxt "view:purchase.product_supplier:"
 msgid "Product Supplier"
-msgstr "Proveedor de Producto"
+msgstr "Proveedor del Producto"
 
 msgctxt "view:purchase.product_supplier:"
 msgid "Product Suppliers"
@@ -1117,11 +1129,11 @@ msgstr "Borrador"
 
 msgctxt "view:purchase.purchase:"
 msgid "Handle Invoice Exception"
-msgstr "Excepción Manual de Factura"
+msgstr "Gestionar Excepción de Factura"
 
 msgctxt "view:purchase.purchase:"
 msgid "Handle Shipment Exception"
-msgstr "Excepción Manual de Envío"
+msgstr "Gestionar Excepción de Envío"
 
 msgctxt "view:purchase.purchase:"
 msgid "Invoices"
@@ -1129,7 +1141,11 @@ msgstr "Facturas"
 
 msgctxt "view:purchase.purchase:"
 msgid "Other Info"
-msgstr "Info Adicional"
+msgstr "Información Adicional"
+
+msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr "Procesar"
 
 msgctxt "view:purchase.purchase:"
 msgid "Purchase"
@@ -1145,7 +1161,7 @@ msgstr "Cotizar"
 
 msgctxt "view:purchase.purchase:"
 msgid "Shipments"
-msgstr "Envios"
+msgstr "Envíos"
 
 msgctxt "view:stock.move:"
 msgid "Moves"
diff --git a/locale/es_ES.po b/locale/es_ES.po
index 1baefde..f9bc6ef 100644
--- a/locale/es_ES.po
+++ b/locale/es_ES.po
@@ -7,10 +7,8 @@ msgid "You cannot reset to draft an invoice generated by a purchase."
 msgstr "No puede restaurar a borrador una factura generada por una compra."
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
-msgstr ""
-"Los precios de compra están basados en la UdM de compra. ¿Desea cambiarlo?"
+msgid "Purchase prices are based on the purchase uom."
+msgstr "Los precios de compra se basan en la UdM de compra."
 
 msgctxt "error:purchase.line:"
 msgid ""
@@ -36,12 +34,6 @@ msgid "A warehouse must be defined for quotation of purchase \"%s\"."
 msgstr "Se debe definir un almacén para el presupuesto de la compra \"%s\"."
 
 msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr ""
-"Se debe definir una dirección de facturación para el presupuesto de la "
-"compra \"%s\"."
-
-msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
 msgstr "Falta la \"Cuenta a pagar\" en el tercer \"%s\"."
 
@@ -429,6 +421,10 @@ msgctxt "field:purchase.product_supplier.price,rec_name:"
 msgid "Name"
 msgstr "Nombre"
 
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr "Secuencia"
+
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr "Precio unidad"
@@ -712,6 +708,14 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr "Terceros con compras"
 
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr "Proveedores de productos"
+
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr "Precios"
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr "Configuración de compras"
@@ -779,6 +783,10 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr "Configuración"
 
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr "Proveedores de productos"
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
 msgstr "Compras"
@@ -921,7 +929,7 @@ msgstr "CIF/NIF:"
 
 msgctxt "odt:purchase.purchase:"
 msgid "VAT:"
-msgstr "IVA:"
+msgstr "CIF/NIF:"
 
 msgctxt "selection:account.invoice,purchase_exception_state:"
 msgid ""
@@ -1024,6 +1032,10 @@ msgid "Draft"
 msgstr "Borrador"
 
 msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr "En proceso"
+
+msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr "Presupuesto"
 
@@ -1132,6 +1144,10 @@ msgid "Other Info"
 msgstr "Información adicional"
 
 msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr "Procesar"
+
+msgctxt "view:purchase.purchase:"
 msgid "Purchase"
 msgstr "Compra"
 
diff --git a/locale/fr_FR.po b/locale/fr_FR.po
index 2f343b1..c755d01 100644
--- a/locale/fr_FR.po
+++ b/locale/fr_FR.po
@@ -7,47 +7,39 @@ msgid "You cannot reset to draft an invoice generated by a purchase."
 msgstr "Vous ne pouvez pas réinitialiser une facture générée par un achat."
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
-msgstr ""
-"Les prix d'achat sont basé sur l'UDM d'achat, êtes-vous sûr de vouloir la "
-"modifier ?"
+msgid "Purchase prices are based on the purchase uom."
+msgstr "Les prix d'achat sont basés sur l'unité de mesure d'achat."
 
 msgctxt "error:purchase.line:"
 msgid ""
 "Product \"%(product)s\" of purchase %(purchase)s misses an expense account."
 msgstr ""
-"Le produit \"%(product)s\" de l'achat %(purchase)s n'a pas de compte de "
+"Le produit « %(product)s » de l'achat %(purchase)s n'a pas de compte de "
 "charge."
 
 msgctxt "error:purchase.line:"
 msgid "Purchase \"%(purchase)s\" misses an \"account expense\" default property."
 msgstr ""
-"La propriété par défaut \"compte de charge\" est absente de l'achat "
-"\"%(purchase)s\""
+"La propriété par défaut « compte de charge » est absente de l'achat « "
+"%(purchase)s »."
 
 msgctxt "error:purchase.line:"
 msgid "Purchase \"%(purchase)s\" misses the supplier location for line \"%(line)s\"."
 msgstr ""
-"L'emplacement fournisseur est manquant pour la ligne \"%(line)s\" de l'achat"
-" \"%(purchase)s\""
+"L'emplacement fournisseur est manquant pour la ligne « %(line)s » de l'achat"
+" « %(purchase)s »."
 
 msgctxt "error:purchase.purchase:"
 msgid "A warehouse must be defined for quotation of purchase \"%s\"."
-msgstr "Un entrepôt doit être défini pour le devis de l'achat \"%s\"."
-
-msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr ""
-"L'adresse de facturation doit être défini pour le devis de l'achat \"%s\"."
+msgstr "Un entrepôt doit être défini pour le devis de l'achat « %s »."
 
 msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
-msgstr "Le compte à payer est manquant sur le tiers \"%s\"."
+msgstr "Le compte à payer est manquant sur le tiers « %s »."
 
 msgctxt "error:purchase.purchase:"
 msgid "Purchase \"%s\" must be cancelled before deletion."
-msgstr "La commande \"%s\" doit être annulée avant suppression."
+msgstr "La commande « %s » doit être annulée avant suppression."
 
 msgctxt "error:stock.shipment.in.return:"
 msgid "You cannot reset to draft a move generated by a purchase."
@@ -58,7 +50,7 @@ msgid ""
 "You cannot reset to draft move \"%s\" because it was generated by a "
 "purchase."
 msgstr ""
-"vous ne pouvez remettre le mouvement \"%s\" en brouillon car il a été généré"
+"vous ne pouvez remettre le mouvement « %s » en brouillon car il a été généré"
 " par un achat."
 
 msgctxt "field:account.invoice,purchase_exception_state:"
@@ -429,6 +421,10 @@ msgctxt "field:purchase.product_supplier.price,rec_name:"
 msgid "Name"
 msgstr "Nom"
 
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr "Séquence"
+
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr "Prix unitaire"
@@ -567,7 +563,7 @@ msgstr "Cache du total"
 
 msgctxt "field:purchase.purchase,untaxed_amount:"
 msgid "Untaxed"
-msgstr "Non-taxé"
+msgstr "Hors taxe"
 
 msgctxt "field:purchase.purchase,untaxed_amount_cache:"
 msgid "Untaxed Cache"
@@ -712,6 +708,14 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr "Tiers associés à des achats"
 
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr "Fournisseurs du produit"
+
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr "Prix"
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr "Configuration des achats"
@@ -779,6 +783,10 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr "Configuration"
 
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr "Fournisseurs du produit"
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
 msgstr "Achats"
@@ -861,7 +869,7 @@ msgstr "Montant"
 
 msgctxt "odt:purchase.purchase:"
 msgid "Date:"
-msgstr "Date :"
+msgstr "Date :"
 
 msgctxt "odt:purchase.purchase:"
 msgid "Description"
@@ -885,7 +893,7 @@ msgstr "Téléphone"
 
 msgctxt "odt:purchase.purchase:"
 msgid "Purchase Order N°:"
-msgstr "Commande d'achat n° :"
+msgstr "Commande d'achat n° :"
 
 msgctxt "odt:purchase.purchase:"
 msgid "Quantity"
@@ -917,7 +925,7 @@ msgstr "Prix unitaire"
 
 msgctxt "odt:purchase.purchase:"
 msgid "VAT Number:"
-msgstr "Numéro TVA :"
+msgstr "Numéro TVA :"
 
 msgctxt "odt:purchase.purchase:"
 msgid "VAT:"
@@ -1024,6 +1032,10 @@ msgid "Draft"
 msgstr "Brouillon"
 
 msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr "Traitement"
+
+msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr "Devis"
 
@@ -1132,6 +1144,10 @@ msgid "Other Info"
 msgstr "Autre information"
 
 msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr "Traiter"
+
+msgctxt "view:purchase.purchase:"
 msgid "Purchase"
 msgstr "Achat"
 
diff --git a/locale/nl_NL.po b/locale/nl_NL.po
index c7da2eb..247787b 100644
--- a/locale/nl_NL.po
+++ b/locale/nl_NL.po
@@ -7,8 +7,7 @@ msgid "You cannot reset to draft an invoice generated by a purchase."
 msgstr ""
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
+msgid "Purchase prices are based on the purchase uom."
 msgstr ""
 
 msgctxt "error:purchase.line:"
@@ -29,10 +28,6 @@ msgid "A warehouse must be defined for quotation of purchase \"%s\"."
 msgstr ""
 
 msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr ""
-
-msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
 msgstr ""
 
@@ -461,6 +456,11 @@ msgid "Name"
 msgstr "Naam bijlage"
 
 #, fuzzy
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr "Reeks"
+
+#, fuzzy
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr "Eenheidsprijs"
@@ -777,6 +777,14 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr ""
 
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr ""
+
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr ""
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr ""
@@ -851,6 +859,10 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr "Instellingen"
 
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr ""
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
 msgstr ""
@@ -1133,6 +1145,11 @@ msgstr "Concept"
 
 #, fuzzy
 msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr "Verwerking"
+
+#, fuzzy
+msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr "Offerte"
 
@@ -1258,6 +1275,10 @@ msgid "Other Info"
 msgstr "Aanvullende informatie"
 
 msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr ""
+
+msgctxt "view:purchase.purchase:"
 msgid "Purchase"
 msgstr ""
 
diff --git a/locale/ru_RU.po b/locale/ru_RU.po
index 46df167..95c8b7f 100644
--- a/locale/ru_RU.po
+++ b/locale/ru_RU.po
@@ -7,10 +7,8 @@ msgid "You cannot reset to draft an invoice generated by a purchase."
 msgstr "Вы не можете сбросить в черновик инвойс созданный из покупки."
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
+msgid "Purchase prices are based on the purchase uom."
 msgstr ""
-"Цены покупки основаны на ед. измерения, вы действительно хотите изменить их?"
 
 msgctxt "error:purchase.line:"
 msgid ""
@@ -34,10 +32,6 @@ msgid "A warehouse must be defined for quotation of purchase \"%s\"."
 msgstr ""
 
 msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr ""
-
-msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
 msgstr "Отсутствует \"Счет кредиторов\" у контрагента \"%s\"."
 
@@ -425,6 +419,11 @@ msgctxt "field:purchase.product_supplier.price,rec_name:"
 msgid "Name"
 msgstr "Наименование"
 
+#, fuzzy
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr "Последовательность"
+
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr "Цена за единицу"
@@ -708,6 +707,16 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr "Контрагенты связанные с покупками."
 
+#, fuzzy
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr "Поставщики продукции"
+
+#, fuzzy
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr "Цены"
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr "Конфигурация покупок"
@@ -776,6 +785,11 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr "Конфигурация"
 
+#, fuzzy
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr "Поставщики продукции"
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
 msgstr "Покупки"
@@ -1020,6 +1034,11 @@ msgctxt "selection:purchase.purchase,state:"
 msgid "Draft"
 msgstr "Черновик"
 
+#, fuzzy
+msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr "Обслуживание"
+
 msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr "Котировка"
@@ -1128,6 +1147,11 @@ msgctxt "view:purchase.purchase:"
 msgid "Other Info"
 msgstr "Другая информация"
 
+#, fuzzy
+msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr "Обработка"
+
 msgctxt "view:purchase.purchase:"
 msgid "Purchase"
 msgstr "Покупки"
diff --git a/locale/sl_SI.po b/locale/sl_SI.po
index 14a54dd..f34a1b3 100644
--- a/locale/sl_SI.po
+++ b/locale/sl_SI.po
@@ -9,10 +9,8 @@ msgstr ""
 "priprave."
 
 msgctxt "error:product.template:"
-msgid ""
-"Purchase prices are based on the purchase uom, are you sure to change it?"
-msgstr ""
-"Nabavne cene so zasnovane na nabavni ME. Ali jo res želite spremeniti?"
+msgid "Purchase prices are based on the purchase uom."
+msgstr "Nabavne cene temeljijo na nabavni merski enoti."
 
 msgctxt "error:purchase.line:"
 msgid ""
@@ -38,10 +36,6 @@ msgid "A warehouse must be defined for quotation of purchase \"%s\"."
 msgstr "Skladišče mora biti navedeno za nabavno ponudbo \"%s\"."
 
 msgctxt "error:purchase.purchase:"
-msgid "Invoice address must be defined for quotation of purchase \"%s\"."
-msgstr "Naslov plačnika mora biti naveden za nabavno ponudbo \"%s\"."
-
-msgctxt "error:purchase.purchase:"
 msgid "Missing \"Account Payable\" on party \"%s\"."
 msgstr "Partnerju \"%s\" manjka terjatveni konto."
 
@@ -85,11 +79,11 @@ msgstr "Nabavna ME"
 
 msgctxt "field:purchase.configuration,create_date:"
 msgid "Create Date"
-msgstr "Ustvarjeno"
+msgstr "Izdelano"
 
 msgctxt "field:purchase.configuration,create_uid:"
 msgid "Create User"
-msgstr "Ustvaril"
+msgstr "Izdelal"
 
 msgctxt "field:purchase.configuration,id:"
 msgid "ID"
@@ -125,7 +119,7 @@ msgstr "ID"
 
 msgctxt "field:purchase.handle.invoice.exception.ask,recreate_invoices:"
 msgid "Recreate Invoices"
-msgstr "Poustvarjeni računi"
+msgstr "Ponovno izdelani računi"
 
 msgctxt "field:purchase.handle.shipment.exception.ask,domain_moves:"
 msgid "Domain Moves"
@@ -137,7 +131,7 @@ msgstr "ID"
 
 msgctxt "field:purchase.handle.shipment.exception.ask,recreate_moves:"
 msgid "Recreate Moves"
-msgstr "Poustvarjen promet"
+msgstr "Ponovno izdelan promet"
 
 msgctxt "field:purchase.line,amount:"
 msgid "Amount"
@@ -145,11 +139,11 @@ msgstr "Znesek"
 
 msgctxt "field:purchase.line,create_date:"
 msgid "Create Date"
-msgstr "Ustvarjeno"
+msgstr "Izdelano"
 
 msgctxt "field:purchase.line,create_uid:"
 msgid "Create User"
-msgstr "Ustvaril"
+msgstr "Izdelal"
 
 msgctxt "field:purchase.line,delivery_date:"
 msgid "Delivery Date"
@@ -189,7 +183,7 @@ msgstr "Prezrt promet"
 
 msgctxt "field:purchase.line,moves_recreated:"
 msgid "Recreated Moves"
-msgstr "Poustvarjen promet"
+msgstr "Ponovno izdelan promet"
 
 msgctxt "field:purchase.line,note:"
 msgid "Note"
@@ -253,11 +247,11 @@ msgstr "Zapisal"
 
 msgctxt "field:purchase.line-account.tax,create_date:"
 msgid "Create Date"
-msgstr "Ustvarjeno"
+msgstr "Izdelano"
 
 msgctxt "field:purchase.line-account.tax,create_uid:"
 msgid "Create User"
-msgstr "Ustvaril"
+msgstr "Izdelal"
 
 msgctxt "field:purchase.line-account.tax,id:"
 msgid "ID"
@@ -285,11 +279,11 @@ msgstr "Zapisal"
 
 msgctxt "field:purchase.line-ignored-stock.move,create_date:"
 msgid "Create Date"
-msgstr "Ustvarjeno"
+msgstr "Izdelano"
 
 msgctxt "field:purchase.line-ignored-stock.move,create_uid:"
 msgid "Create User"
-msgstr "Ustvaril"
+msgstr "Izdelal"
 
 msgctxt "field:purchase.line-ignored-stock.move,id:"
 msgid "ID"
@@ -317,11 +311,11 @@ msgstr "Zapisal"
 
 msgctxt "field:purchase.line-recreated-stock.move,create_date:"
 msgid "Create Date"
-msgstr "Ustvarjeno"
+msgstr "Izdelano"
 
 msgctxt "field:purchase.line-recreated-stock.move,create_uid:"
 msgid "Create User"
-msgstr "Ustvaril"
+msgstr "Izdelal"
 
 msgctxt "field:purchase.line-recreated-stock.move,id:"
 msgid "ID"
@@ -357,11 +351,11 @@ msgstr "Družba"
 
 msgctxt "field:purchase.product_supplier,create_date:"
 msgid "Create Date"
-msgstr "Ustvarjeno"
+msgstr "Izdelano"
 
 msgctxt "field:purchase.product_supplier,create_uid:"
 msgid "Create User"
-msgstr "Ustvaril"
+msgstr "Izdelal"
 
 msgctxt "field:purchase.product_supplier,currency:"
 msgid "Currency"
@@ -409,11 +403,11 @@ msgstr "Zapisal"
 
 msgctxt "field:purchase.product_supplier.price,create_date:"
 msgid "Create Date"
-msgstr "Ustvarjeno"
+msgstr "Izdelano"
 
 msgctxt "field:purchase.product_supplier.price,create_uid:"
 msgid "Create User"
-msgstr "Ustvaril"
+msgstr "Izdelal"
 
 msgctxt "field:purchase.product_supplier.price,id:"
 msgid "ID"
@@ -431,6 +425,10 @@ msgctxt "field:purchase.product_supplier.price,rec_name:"
 msgid "Name"
 msgstr "Ime"
 
+msgctxt "field:purchase.product_supplier.price,sequence:"
+msgid "Sequence"
+msgstr "Zap.št."
+
 msgctxt "field:purchase.product_supplier.price,unit_price:"
 msgid "Unit Price"
 msgstr "Cena"
@@ -453,11 +451,11 @@ msgstr "Družba"
 
 msgctxt "field:purchase.purchase,create_date:"
 msgid "Create Date"
-msgstr "Ustvarjeno"
+msgstr "Izdelano"
 
 msgctxt "field:purchase.purchase,create_uid:"
 msgid "Create User"
-msgstr "Ustvaril"
+msgstr "Izdelal"
 
 msgctxt "field:purchase.purchase,currency:"
 msgid "Currency"
@@ -497,7 +495,7 @@ msgstr "Prezrti računi"
 
 msgctxt "field:purchase.purchase,invoices_recreated:"
 msgid "Recreated Invoices"
-msgstr "Poustvarjeni računi"
+msgstr "Ponovno izdelani računi"
 
 msgctxt "field:purchase.purchase,lines:"
 msgid "Lines"
@@ -589,11 +587,11 @@ msgstr "Zapisal"
 
 msgctxt "field:purchase.purchase-ignored-account.invoice,create_date:"
 msgid "Create Date"
-msgstr "Ustvarjeno"
+msgstr "Izdelano"
 
 msgctxt "field:purchase.purchase-ignored-account.invoice,create_uid:"
 msgid "Create User"
-msgstr "Ustvaril"
+msgstr "Izdelal"
 
 msgctxt "field:purchase.purchase-ignored-account.invoice,id:"
 msgid "ID"
@@ -621,11 +619,11 @@ msgstr "Zapisal"
 
 msgctxt "field:purchase.purchase-recreated-account.invoice,create_date:"
 msgid "Create Date"
-msgstr "Ustvarjeno"
+msgstr "Izdelano"
 
 msgctxt "field:purchase.purchase-recreated-account.invoice,create_uid:"
 msgid "Create User"
-msgstr "Ustvaril"
+msgstr "Izdelal"
 
 msgctxt "field:purchase.purchase-recreated-account.invoice,id:"
 msgid "ID"
@@ -690,11 +688,11 @@ msgstr "Dobavitelj"
 msgctxt "help:purchase.handle.invoice.exception.ask,recreate_invoices:"
 msgid ""
 "The selected invoices will be recreated. The other ones will be ignored."
-msgstr "Izbrani računi bodo poustvarjeni, ostali bodo prezrti."
+msgstr "Izbrani računi bodo ponovno izdelani, ostali bodo prezrti."
 
 msgctxt "help:purchase.handle.shipment.exception.ask,recreate_moves:"
 msgid "The selected moves will be recreated. The other ones will be ignored."
-msgstr "Izbran promet bo poustvarjen, ostali bo prezrt."
+msgstr "Izbran promet bo ponovno izdelan, ostalo bo prezrto."
 
 msgctxt "help:purchase.product_supplier,delivery_time:"
 msgid "In number of days"
@@ -712,6 +710,14 @@ msgctxt "model:ir.action,name:act_open_supplier"
 msgid "Parties associated to Purchases"
 msgstr "Partnerji, povezani z nabavo"
 
+msgctxt "model:ir.action,name:act_product_supplier_form"
+msgid "Product Suppliers"
+msgstr "Dobavitelji izdelkov"
+
+msgctxt "model:ir.action,name:act_product_supplier_price_form"
+msgid "Prices"
+msgstr "Cene"
+
 msgctxt "model:ir.action,name:act_purchase_configuration_form"
 msgid "Purchase Configuration"
 msgstr "Nabavna konfiguracija"
@@ -779,6 +785,10 @@ msgctxt "model:ir.ui.menu,name:menu_configuration"
 msgid "Configuration"
 msgstr "Nastavitve"
 
+msgctxt "model:ir.ui.menu,name:menu_product_supplier"
+msgid "Product Suppliers"
+msgstr "Dobavitelji izdelkov"
+
 msgctxt "model:ir.ui.menu,name:menu_purchase"
 msgid "Purchase"
 msgstr "Nabava"
@@ -845,7 +855,7 @@ msgstr "Nabavni nalog - Prezrt račun"
 
 msgctxt "model:purchase.purchase-recreated-account.invoice,name:"
 msgid "Purchase - Recreated Invoice"
-msgstr "Nabavni nalog - Poustvarjeni račun"
+msgstr "Nabavni nalog - Ponovno izdelan račun"
 
 msgctxt "model:res.group,name:group_purchase"
 msgid "Purchase"
@@ -933,7 +943,7 @@ msgstr "Prezrto"
 
 msgctxt "selection:account.invoice,purchase_exception_state:"
 msgid "Recreated"
-msgstr "Poustvarjeno"
+msgstr "Ponovno izdelano"
 
 msgctxt "selection:purchase.configuration,purchase_invoice_method:"
 msgid "Based On Order"
@@ -1024,6 +1034,10 @@ msgid "Draft"
 msgstr "V pripravi"
 
 msgctxt "selection:purchase.purchase,state:"
+msgid "Processing"
+msgstr "Obdelava"
+
+msgctxt "selection:purchase.purchase,state:"
 msgid "Quotation"
 msgstr "Ponudba"
 
@@ -1037,7 +1051,7 @@ msgstr "Prezrto"
 
 msgctxt "selection:stock.move,purchase_exception_state:"
 msgid "Recreated"
-msgstr "Poustvarjeno"
+msgstr "Ponovno izdelano"
 
 msgctxt "view:product.product:"
 msgid "Products"
@@ -1053,7 +1067,7 @@ msgstr "Nabavna konfiguracija"
 
 msgctxt "view:purchase.handle.invoice.exception.ask:"
 msgid "Choose invoices to recreate"
-msgstr "Izbor računov za poustvaritev"
+msgstr "Izbor računov za ponovno izdelavo"
 
 msgctxt "view:purchase.handle.invoice.exception.ask:"
 msgid "Handle Invoice Exception"
@@ -1061,7 +1075,7 @@ msgstr "Obravnava pridržanih računov"
 
 msgctxt "view:purchase.handle.shipment.exception.ask:"
 msgid "Choose move to recreate"
-msgstr "Izbor prometa za poustvaritev"
+msgstr "Izbor prometa za ponovno izdelavo"
 
 msgctxt "view:purchase.handle.shipment.exception.ask:"
 msgid "Handle shipment Exception"
@@ -1132,6 +1146,10 @@ msgid "Other Info"
 msgstr "Drugo"
 
 msgctxt "view:purchase.purchase:"
+msgid "Process"
+msgstr "Obdelava"
+
+msgctxt "view:purchase.purchase:"
 msgid "Purchase"
 msgstr "Nabavni nalog"
 
diff --git a/product.py b/product.py
index a0b7af5..34765a4 100644
--- a/product.py
+++ b/product.py
@@ -4,7 +4,7 @@ import datetime
 from sql import Literal
 from sql.aggregate import Count
 
-from trytond.model import ModelView, ModelSQL, fields
+from trytond.model import ModelView, ModelSQL, MatchMixin, fields
 from trytond.pyson import Eval, If
 from trytond.pool import Pool, PoolMeta
 from trytond.transaction import Transaction
@@ -38,7 +38,7 @@ class Template:
         super(Template, cls).__setup__()
         cls._error_messages.update({
                 'change_purchase_uom': ('Purchase prices are based '
-                    'on the purchase uom, are you sure to change it?'),
+                    'on the purchase uom.'),
                 })
         required = ~Eval('account_category') & Eval('purchasable', False)
         if not cls.account_expense.states.get('required'):
@@ -52,15 +52,20 @@ class Template:
             cls.account_expense.depends.append('purchasable')
 
     @fields.depends('default_uom', 'purchase_uom', 'purchasable')
-    def on_change_with_purchase_uom(self):
+    def on_change_default_uom(self):
+        try:
+            changes = super(Template, self).on_change_default_uom()
+        except AttributeError:
+            changes = {}
         if self.default_uom:
             if self.purchase_uom:
                 if self.default_uom.category == self.purchase_uom.category:
-                    return self.purchase_uom.id
+                    changes['purchase_uom'] = self.purchase_uom.id
                 else:
-                    return self.default_uom.id
+                    changes['purchase_uom'] = self.default_uom.id
             else:
-                return self.default_uom.id
+                changes['purchase_uom'] = self.default_uom.id
+        return changes
 
     @classmethod
     def write(cls, *args):
@@ -99,50 +104,51 @@ class Product:
         User = pool.get('res.user')
         Currency = pool.get('currency.currency')
         Date = pool.get('ir.date')
+        ProductSupplier = pool.get('purchase.product_supplier')
+        ProductSupplierPrice = pool.get('purchase.product_supplier.price')
 
         today = Date.today()
-        res = {}
+        context = Transaction().context
+        prices = {}
 
         uom = None
-        if Transaction().context.get('uom'):
-            uom = Uom(Transaction().context['uom'])
+        if context.get('uom'):
+            uom = Uom(context['uom'])
 
         currency = None
-        if Transaction().context.get('currency'):
-            currency = Currency(Transaction().context['currency'])
+        if context.get('currency'):
+            currency = Currency(context['currency'])
 
         user = User(Transaction().user)
 
         for product in products:
-            res[product.id] = product.cost_price
+            prices[product.id] = product.cost_price
             default_uom = product.default_uom
             default_currency = (user.company.currency if user.company
                 else None)
             if not uom:
                 uom = default_uom
-            if (Transaction().context.get('supplier')
-                    and product.product_suppliers):
-                supplier_id = Transaction().context['supplier']
-                for product_supplier in product.product_suppliers:
-                    if product_supplier.party.id == supplier_id:
-                        for price in product_supplier.prices:
-                            if Uom.compute_qty(product.purchase_uom,
-                                    price.quantity, uom) <= quantity:
-                                res[product.id] = price.unit_price
-                                default_uom = product.purchase_uom
-                                default_currency = product_supplier.currency
-                        break
-            res[product.id] = Uom.compute_price(default_uom, res[product.id],
-                uom)
+            pattern = ProductSupplier.get_pattern()
+            for product_supplier in product.product_suppliers:
+                if product_supplier.match(pattern):
+                    pattern = ProductSupplierPrice.get_pattern()
+                    for price in product_supplier.prices:
+                        if price.match(quantity, uom, pattern):
+                            prices[product.id] = price.unit_price
+                            default_uom = product_supplier.uom
+                            default_currency = product_supplier.currency
+                    break
+            prices[product.id] = Uom.compute_price(
+                default_uom, prices[product.id], uom)
             if currency and default_currency:
-                date = Transaction().context.get('purchase_date') or today
+                date = context.get('purchase_date') or today
                 with Transaction().set_context(date=date):
-                    res[product.id] = Currency.compute(default_currency,
-                        res[product.id], currency, round=False)
-        return res
+                    prices[product.id] = Currency.compute(default_currency,
+                        prices[product.id], currency, round=False)
+        return prices
 
 
-class ProductSupplier(ModelSQL, ModelView):
+class ProductSupplier(ModelSQL, ModelView, MatchMixin):
     'Product Supplier'
     __name__ = 'purchase.product_supplier'
     product = fields.Many2One('product.template', 'Product', required=True,
@@ -239,6 +245,20 @@ class ProductSupplier(ModelSQL, ModelView):
                 changes['currency'], = row
         return changes
 
+    def get_rec_name(self, name):
+        return '%s @ %s' % (self.product.rec_name, self.party.rec_name)
+
+    @classmethod
+    def search_rec_name(cls, name, clause):
+        return ['OR',
+            ('product',) + tuple(clause[1:]),
+            ('party',) + tuple(clause[1:]),
+            ]
+
+    @property
+    def uom(self):
+        return self.product.purchase_uom
+
     def compute_supply_date(self, date=None):
         '''
         Compute the supply date for the Product Supplier at the given date
@@ -261,20 +281,62 @@ class ProductSupplier(ModelSQL, ModelView):
             return Date.today()
         return date - datetime.timedelta(self.delivery_time)
 
+    @staticmethod
+    def get_pattern():
+        context = Transaction().context
+        return {
+            'party': context.get('supplier'),
+            }
+
 
-class ProductSupplierPrice(ModelSQL, ModelView):
+class ProductSupplierPrice(ModelSQL, ModelView, MatchMixin):
     'Product Supplier Price'
     __name__ = 'purchase.product_supplier.price'
     product_supplier = fields.Many2One('purchase.product_supplier',
             'Supplier', required=True, ondelete='CASCADE')
     quantity = fields.Float('Quantity', required=True, help='Minimal quantity')
     unit_price = fields.Numeric('Unit Price', required=True, digits=(16, 4))
+    sequence = fields.Integer('Sequence')
 
     @classmethod
     def __setup__(cls):
         super(ProductSupplierPrice, cls).__setup__()
-        cls._order.insert(0, ('quantity', 'ASC'))
+        cls._order.insert(0, ('sequence', 'ASC'))
+
+    @classmethod
+    def __register__(cls, module_name):
+        TableHandler = backend.get('TableHandler')
+        cursor = Transaction().cursor
+        table = TableHandler(cursor, cls, module_name)
+        sql_table = cls.__table__()
+
+        fill_sequence = not table.column_exist('sequence')
+
+        super(ProductSupplierPrice, cls).__register__(module_name)
+
+        # Migration from 3.2: replace quantity by sequence for order
+        if fill_sequence:
+            cursor.execute(*sql_table.update(
+                    [sql_table.sequence], [sql_table.quantity]))
+
+    @staticmethod
+    def order_sequence(tables):
+        table, _ = tables[None]
+        return [table.sequence == None, table.sequence]
 
     @staticmethod
     def default_quantity():
         return 0.0
+
+    @staticmethod
+    def get_pattern():
+        return {}
+
+    def match(self, quantity, uom, pattern):
+        pool = Pool()
+        Uom = pool.get('product.uom')
+        test_quantity = Uom.compute_qty(
+            self.product_supplier.uom, self.quantity, uom)
+        if test_quantity > quantity:
+            return False
+        return super(ProductSupplierPrice, self).match(pattern)
diff --git a/purchase.py b/purchase.py
index 4766924..de74312 100644
--- a/purchase.py
+++ b/purchase.py
@@ -6,6 +6,7 @@ from decimal import Decimal
 from sql import Table, Literal
 from sql.functions import Overlay, Position
 from sql.aggregate import Count
+from sql.operators import Concat
 
 from trytond.model import Workflow, ModelView, ModelSQL, fields
 from trytond.modules.company import CompanyReport
@@ -51,6 +52,7 @@ class Purchase(Workflow, ModelSQL, ModelView):
         ('draft', 'Draft'),
         ('quotation', 'Quotation'),
         ('confirmed', 'Confirmed'),
+        ('processing', 'Processing'),
         ('done', 'Done'),
         ('cancel', 'Canceled'),
     ], 'State', readonly=True, required=True)
@@ -61,9 +63,17 @@ class Purchase(Workflow, ModelSQL, ModelView):
             },
         depends=['state'])
     payment_term = fields.Many2One('account.invoice.payment_term',
-        'Payment Term', required=True, states=_STATES, depends=_DEPENDS)
+        'Payment Term', states={
+            'readonly': ~Eval('state').in_(['draft', 'quotation']),
+            'required': ~Eval('state').in_(['draft', 'quotation', 'cancel']),
+            },
+        depends=['state'])
     party = fields.Many2One('party.party', 'Party', required=True,
-        states=_STATES, select=True, depends=_DEPENDS)
+        states={
+            'readonly': ((Eval('state') != 'draft')
+                | (Eval('lines', [0]) & Eval('party'))),
+            },
+        select=True, depends=['state'])
     party_lang = fields.Function(fields.Char('Party Language'),
         'on_change_with_party_lang')
     invoice_address = fields.Many2One('party.address', 'Invoice Address',
@@ -145,8 +155,6 @@ class Purchase(Workflow, ModelSQL, ModelView):
         cls._order.insert(0, ('purchase_date', 'DESC'))
         cls._order.insert(1, ('id', 'DESC'))
         cls._error_messages.update({
-                'invoice_address_required': ('Invoice address must be '
-                    'defined for quotation of purchase "%s".'),
                 'warehouse_required': ('A warehouse must be defined for '
                     'quotation of purchase "%s".'),
                 'missing_account_payable': ('Missing "Account Payable" on '
@@ -157,8 +165,10 @@ class Purchase(Workflow, ModelSQL, ModelView):
         cls._transitions |= set((
                 ('draft', 'quotation'),
                 ('quotation', 'confirmed'),
-                ('confirmed', 'confirmed'),
-                ('done', 'confirmed'),
+                ('confirmed', 'processing'),
+                ('processing', 'processing'),
+                ('processing', 'done'),
+                ('done', 'processing'),
                 ('draft', 'cancel'),
                 ('quotation', 'cancel'),
                 ('quotation', 'draft'),
@@ -174,12 +184,20 @@ class Purchase(Workflow, ModelSQL, ModelView):
                         'tryton-go-previous'),
                     },
                 'quote': {
+                    'pre_validate': [
+                        ('purchase_date', '!=', None),
+                        ('payment_term', '!=', None),
+                        ('invoice_address', '!=', None),
+                        ],
                     'invisible': Eval('state') != 'draft',
                     'readonly': ~Eval('lines', []),
                     },
                 'confirm': {
                     'invisible': Eval('state') != 'quotation',
                     },
+                'process': {
+                    'invisible': Eval('state') != 'confirmed',
+                    },
                 'handle_invoice_exception': {
                     'invisible': ((Eval('invoice_state') != 'exception')
                         | (Eval('state') == 'cancel')),
@@ -198,6 +216,10 @@ class Purchase(Workflow, ModelSQL, ModelView):
 
     @classmethod
     def __register__(cls, module_name):
+        pool = Pool()
+        PurchaseLine = pool.get('purchase.line')
+        Move = pool.get('stock.move')
+        InvoiceLine = pool.get('account.invoice.line')
         TableHandler = backend.get('TableHandler')
         cursor = Transaction().cursor
         model_data = Table('ir_model_data')
@@ -245,6 +267,34 @@ class Purchase(Workflow, ModelSQL, ModelView):
         # Migration from 2.2: purchase_date is no more required
         table.not_null_action('purchase_date', 'remove')
 
+        # Migration from 3.2
+        # state confirmed splitted into confirmed and processing
+        if (TableHandler.table_exist(cursor, PurchaseLine._table)
+                and TableHandler.table_exist(cursor, Move._table)
+                and TableHandler.table_exist(cursor, InvoiceLine._table)):
+            purchase_line = PurchaseLine.__table__()
+            move = Move.__table__()
+            invoice_line = InvoiceLine.__table__()
+            # Wrap subquery inside an other inner subquery because MySQL syntax
+            # doesn't allow update a table and select from the same table in a
+            # subquery.
+            sub_query = sql_table.join(purchase_line,
+                condition=purchase_line.purchase == sql_table.id
+                ).join(invoice_line, 'LEFT',
+                    condition=(invoice_line.origin ==
+                        Concat(PurchaseLine.__name__, purchase_line.id))
+                    ).join(move, 'LEFT',
+                        condition=(move.origin == Concat(PurchaseLine.__name__,
+                                purchase_line.id))
+                        ).select(sql_table.id,
+                            where=((sql_table.state == 'confirmed')
+                                & ((invoice_line.id != None)
+                                    | (move.id != None))))
+            cursor.execute(*sql_table.update(
+                    columns=[sql_table.state],
+                    values=['processing'],
+                    where=sql_table.id.in_(sub_query.select(sub_query.id))))
+
         # Add index on create_date
         table = TableHandler(cursor, cls, module_name)
         table.index_action('create_date', action='add')
@@ -302,7 +352,7 @@ class Purchase(Workflow, ModelSQL, ModelView):
     def default_shipment_state():
         return 'none'
 
-    @fields.depends('party', 'payment_term')
+    @fields.depends('party', 'payment_term', 'lines')
     def on_change_party(self):
         pool = Pool()
         PaymentTerm = pool.get('account.invoice.payment_term')
@@ -312,9 +362,10 @@ class Purchase(Workflow, ModelSQL, ModelView):
         changes = {
             'invoice_address': None,
             'payment_term': None,
-            'currency': self.default_currency(),
-            'currency_digits': self.default_currency_digits(),
             }
+        if not self.lines:
+            changes['currency'] = self.default_currency()
+            changes['currency_digits'] = self.default_currency_digits()
         invoice_address = None
         payment_term = None
         if self.party:
@@ -322,19 +373,20 @@ class Purchase(Workflow, ModelSQL, ModelView):
             if self.party.supplier_payment_term:
                 payment_term = self.party.supplier_payment_term
 
-            subquery = table.select(table.currency,
-                where=table.party == self.party.id,
-                order_by=table.id,
-                limit=10)
-            cursor.execute(*subquery.select(subquery.currency,
-                    group_by=subquery.currency,
-                    order_by=Count(Literal(1)).desc))
-            row = cursor.fetchone()
-            if row:
-                currency_id, = row
-                currency = Currency(currency_id)
-                changes['currency'] = currency.id
-                changes['currency_digits'] = currency.digits
+            if not self.lines:
+                subquery = table.select(table.currency,
+                    where=table.party == self.party.id,
+                    order_by=table.id,
+                    limit=10)
+                cursor.execute(*subquery.select(subquery.currency,
+                        group_by=subquery.currency,
+                        order_by=Count(Literal(1)).desc))
+                row = cursor.fetchone()
+                if row:
+                    currency_id, = row
+                    currency = Currency(currency_id)
+                    changes['currency'] = currency.id
+                    changes['currency_digits'] = currency.digits
 
         if invoice_address:
             changes['invoice_address'] = invoice_address.id
@@ -376,6 +428,9 @@ class Purchase(Workflow, ModelSQL, ModelView):
         pool = Pool()
         Tax = pool.get('account.tax')
         Invoice = pool.get('account.invoice')
+        Configuration = pool.get('account.configuration')
+
+        config = Configuration(1)
 
         changes = {
             'untaxed_amount': Decimal('0.0'),
@@ -385,6 +440,12 @@ class Purchase(Workflow, ModelSQL, ModelView):
         if self.lines:
             context = self.get_tax_context()
             taxes = {}
+
+            def round_taxes():
+                if self.currency:
+                    for key, value in taxes.iteritems():
+                        taxes[key] = self.currency.round(value)
+
             for line in self.lines:
                 if getattr(line, 'type', 'line') != 'line':
                     continue
@@ -397,13 +458,15 @@ class Purchase(Workflow, ModelSQL, ModelView):
                         getattr(line, 'quantity', None) or 0.0)
                 for tax in tax_list:
                     key, val = Invoice._compute_tax(tax, 'in_invoice')
-                    if not key in taxes:
+                    if key not in taxes:
                         taxes[key] = val['amount']
                     else:
                         taxes[key] += val['amount']
-            if self.currency:
-                for value in taxes.itervalues():
-                    changes['tax_amount'] += self.currency.round(value)
+                if config.tax_rounding == 'line':
+                    round_taxes()
+            if config.tax_rounding == 'document':
+                round_taxes()
+            changes['tax_amount'] = sum(taxes.itervalues(), Decimal('0.0'))
         if self.currency:
             changes['untaxed_amount'] = self.currency.round(
                 changes['untaxed_amount'])
@@ -419,23 +482,34 @@ class Purchase(Workflow, ModelSQL, ModelView):
         pool = Pool()
         Tax = pool.get('account.tax')
         Invoice = pool.get('account.invoice')
+        Configuration = pool.get('account.configuration')
+
+        config = Configuration(1)
 
         context = self.get_tax_context()
         taxes = {}
+
+        def round_taxes():
+            for key, value in taxes.iteritems():
+                taxes[key] = self.currency.round(value)
+
         for line in self.lines:
             if line.type != 'line':
                 continue
             with Transaction().set_context(context):
                 tax_list = Tax.compute(line.taxes, line.unit_price,
                     line.quantity)
-            # Don't round on each line to handle rounding error
             for tax in tax_list:
                 key, val = Invoice._compute_tax(tax, 'in_invoice')
-                if not key in taxes:
+                if key not in taxes:
                     taxes[key] = val['amount']
                 else:
                     taxes[key] += val['amount']
-        return sum((self.currency.round(tax) for tax in taxes.values()), _ZERO)
+            if config.tax_rounding == 'line':
+                round_taxes()
+        if config.tax_rounding == 'document':
+            round_taxes()
+        return sum(taxes.itervalues(), _ZERO)
 
     @classmethod
     def get_amount(cls, purchases, names):
@@ -588,8 +662,6 @@ class Purchase(Workflow, ModelSQL, ModelView):
         return super(Purchase, cls).copy(purchases, default=default)
 
     def check_for_quotation(self):
-        if not self.invoice_address:
-            self.raise_user_error('invoice_address_required', (self.rec_name,))
         for line in self.lines:
             if (not line.to_location
                     and line.product
@@ -659,17 +731,16 @@ class Purchase(Workflow, ModelSQL, ModelView):
         else:
             journal = None
 
-        with Transaction().set_user(0, set_context=True):
-            return Invoice(
-                company=self.company,
-                type=invoice_type,
-                journal=journal,
-                party=self.party,
-                invoice_address=self.invoice_address,
-                currency=self.currency,
-                account=self.party.account_payable,
-                payment_term=self.payment_term,
-                )
+        return Invoice(
+            company=self.company,
+            type=invoice_type,
+            journal=journal,
+            party=self.party,
+            invoice_address=self.invoice_address,
+            currency=self.currency,
+            account=self.party.account_payable,
+            payment_term=self.payment_term,
+            )
 
     def create_invoice(self, invoice_type):
         '''
@@ -693,8 +764,7 @@ class Purchase(Workflow, ModelSQL, ModelView):
         invoice.lines = list(chain.from_iterable(invoice_lines.itervalues()))
         invoice.save()
 
-        with Transaction().set_user(0, set_context=True):
-            Invoice.update_taxes([invoice])
+        Invoice.update_taxes([invoice])
         return invoice
 
     def create_move(self, move_type):
@@ -712,12 +782,11 @@ class Purchase(Workflow, ModelSQL, ModelView):
 
     def _get_return_shipment(self):
         ShipmentInReturn = Pool().get('stock.shipment.in.return')
-        with Transaction().set_user(0, set_context=True):
-            return ShipmentInReturn(
-                company=self.company,
-                from_location=self.warehouse.storage_location,
-                to_location=self.party.supplier_location,
-                )
+        return ShipmentInReturn(
+            company=self.company,
+            from_location=self.warehouse.storage_location,
+            to_location=self.party.supplier_location,
+            )
 
     def create_return_shipment(self, return_moves):
         '''
@@ -727,8 +796,7 @@ class Purchase(Workflow, ModelSQL, ModelView):
         return_shipment = self._get_return_shipment()
         return_shipment.moves = return_moves
         return_shipment.save()
-        with Transaction().set_user(0, set_context=True):
-            ShipmentInReturn.wait([return_shipment])
+        ShipmentInReturn.wait([return_shipment])
         return return_shipment
 
     def is_done(self):
@@ -774,7 +842,11 @@ class Purchase(Workflow, ModelSQL, ModelView):
     def confirm(cls, purchases):
         cls.set_purchase_date(purchases)
         cls.store_cache(purchases)
-        cls.process(purchases)
+
+    @classmethod
+    @Workflow.transition('processing')
+    def proceed(cls, purchases):
+        pass
 
     @classmethod
     @ModelView.button_action('purchase.wizard_invoice_handle_exception')
@@ -787,8 +859,9 @@ class Purchase(Workflow, ModelSQL, ModelView):
         pass
 
     @classmethod
+    @ModelView.button
     def process(cls, purchases):
-        done = []
+        process, done = [], []
         for purchase in purchases:
             purchase.create_invoice('in_invoice')
             purchase.create_invoice('in_credit_note')
@@ -800,6 +873,10 @@ class Purchase(Workflow, ModelSQL, ModelView):
             purchase.set_shipment_state()
             if purchase.is_done():
                 done.append(purchase)
+            elif purchase.state != 'processing':
+                process.append(purchase)
+        if process:
+            cls.proceed(process)
         if done:
             cls.write(done, {
                     'state': 'done',
@@ -1118,8 +1195,7 @@ class PurchaseLine(ModelSQL, ModelView):
 
     def get_amount(self, name):
         if self.type == 'line':
-            return self.purchase.currency.round(
-                Decimal(str(self.quantity)) * self.unit_price)
+            return self.on_change_with_amount()
         elif self.type == 'subtotal':
             amount = Decimal('0.0')
             for line2 in self.purchase.lines:
@@ -1171,8 +1247,7 @@ class PurchaseLine(ModelSQL, ModelView):
         Property = pool.get('ir.property')
         InvoiceLine = pool.get('account.invoice.line')
 
-        with Transaction().set_user(0, set_context=True):
-            invoice_line = InvoiceLine()
+        invoice_line = InvoiceLine()
         invoice_line.type = self.type
         invoice_line.description = self.description
         invoice_line.note = self.note
@@ -1216,10 +1291,12 @@ class PurchaseLine(ModelSQL, ModelView):
             if old_invoice_line.id not in skip_ids:
                 quantity -= Uom.compute_qty(old_invoice_line.unit,
                         old_invoice_line.quantity, self.unit)
-        invoice_line.quantity = quantity
 
-        if invoice_line.quantity <= 0.0:
+        rounding = self.unit.rounding if self.unit else 0
+        invoice_line.quantity = Uom.round(quantity, rounding)
+        if invoice_line.quantity <= 0:
             return []
+
         invoice_line.unit = self.unit
         invoice_line.product = self.product
         invoice_line.unit_price = self.unit_price
@@ -1273,15 +1350,17 @@ class PurchaseLine(ModelSQL, ModelView):
             if move not in skip:
                 quantity -= Uom.compute_qty(move.uom, move.quantity,
                     self.unit)
-        if quantity <= 0.0:
+
+        quantity = Uom.round(quantity, self.unit.rounding)
+        if quantity <= 0:
             return
+
         if not self.purchase.party.supplier_location:
             self.raise_user_error('supplier_location_required', {
                     'purchase': self.purchase.rec_name,
                     'line': self.rec_name,
                     })
-        with Transaction().set_user(0, set_context=True):
-            move = Move()
+        move = Move()
         move.quantity = quantity
         move.uom = self.unit
         move.product = self.product
diff --git a/purchase.xml b/purchase.xml
index 58eee04..71eb30b 100644
--- a/purchase.xml
+++ b/purchase.xml
@@ -353,6 +353,26 @@ this repository contains the full copyright notices and license terms. -->
             <field name="name">product_supplier_tree_sequence</field>
         </record>
 
+        <record model="ir.action.act_window" id="act_product_supplier_form">
+            <field name="name">Product Suppliers</field>
+            <field name="res_model">purchase.product_supplier</field>
+        </record>
+        <record model="ir.action.act_window.view"
+            id="act_product_supplier_list_view">
+            <field name="sequence" eval="10"/>
+            <field name="view" ref="product_supplier_view_tree"/>
+            <field name="act_window" ref="act_product_supplier_form"/>
+        </record>
+        <record model="ir.action.act_window.view"
+            id="act_product_supplier_form_view">
+            <field name="sequence" eval="20"/>
+            <field name="view" ref="product_supplier_view_form"/>
+            <field name="act_window" ref="act_product_supplier_form"/>
+        </record>
+
+        <menuitem parent="product.menu_main_product" sequence="20"
+            id="menu_product_supplier" action="act_product_supplier_form"/>
+
         <record model="ir.rule.group" id="rule_group_product_supplier">
             <field name="model" search="[('model', '=', 'purchase.product_supplier')]"/>
             <field name="global_p" eval="True"/>
@@ -362,6 +382,22 @@ this repository contains the full copyright notices and license terms. -->
             <field name="rule_group" ref="rule_group_product_supplier"/>
         </record>
 
+        <record model="ir.model.access" id="access_product_supplier">
+            <field name="model" search="[('model', '=', 'purchase.product_supplier')]"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="False"/>
+            <field name="perm_create" eval="False"/>
+            <field name="perm_delete" eval="False"/>
+        </record>
+        <record model="ir.model.access" id="access_product_supplier_admin">
+            <field name="model" search="[('model', '=', 'purchase.product_supplier')]"/>
+            <field name="group" ref="product.group_product_admin"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="True"/>
+            <field name="perm_create" eval="True"/>
+            <field name="perm_delete" eval="True"/>
+        </record>
+
         <record model="ir.ui.view" id="product_supplier_price_view_form">
             <field name="model">purchase.product_supplier.price</field>
             <field name="type">form</field>
@@ -372,6 +408,40 @@ this repository contains the full copyright notices and license terms. -->
             <field name="type">tree</field>
             <field name="name">product_supplier_price_tree</field>
         </record>
+        <record model="ir.ui.view" id="product_supplier_price_view_list_sequence">
+            <field name="model">purchase.product_supplier.price</field>
+            <field name="type">tree</field>
+            <field name="name">product_supplier_price_list_sequence</field>
+        </record>
+
+        <record model="ir.action.act_window"
+            id="act_product_supplier_price_form">
+            <field name="name">Prices</field>
+            <field name="res_model">purchase.product_supplier.price</field>
+            <field name="domain">[('product_supplier', 'in', Eval('active_ids'))]</field>
+        </record>
+        <record model="ir.action.keyword"
+            id="act_product_supplier_price_form_keyword1">
+            <field name="keyword">form_relate</field>
+            <field name="model">purchase.product_supplier,-1</field>
+            <field name="action" ref="act_product_supplier_price_form"/>
+        </record>
+
+        <record model="ir.model.access" id="access_product_supplier_price">
+            <field name="model" search="[('model', '=', 'purchase.product_supplier.price')]"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="False"/>
+            <field name="perm_create" eval="False"/>
+            <field name="perm_delete" eval="False"/>
+        </record>
+        <record model="ir.model.access" id="access_product_supplier_price_admin">
+            <field name="model" search="[('model', '=', 'purchase.product_supplier.price')]"/>
+            <field name="group" ref="product.group_product_admin"/>
+            <field name="perm_read" eval="True"/>
+            <field name="perm_write" eval="True"/>
+            <field name="perm_create" eval="True"/>
+            <field name="perm_delete" eval="True"/>
+        </record>
 
         <record model="ir.ui.view" id="template_view_form">
             <field name="model">product.template</field>
diff --git a/stock.py b/stock.py
index fed0e5d..a74e90d 100644
--- a/stock.py
+++ b/stock.py
@@ -65,7 +65,7 @@ class ShipmentIn:
                     if purchase_line.purchase not in purchases:
                         purchases.append(purchase_line.purchase)
 
-            with Transaction().set_user(0, set_context=True):
+            with Transaction().set_context(_check_access=False):
                 purchases = Purchase.browse([p.id for p in purchases])
                 Purchase.process(purchases)
 
@@ -118,7 +118,7 @@ class ShipmentInReturn:
                 for purchase_line in purchase_lines:
                     purchases.add(purchase_line.purchase)
 
-            with Transaction().set_user(0, set_context=True):
+            with Transaction().set_context(_check_access=False):
                 purchases = Purchase.browse([p.id for p in purchases])
                 Purchase.process(purchases)
 
@@ -238,11 +238,14 @@ class Move:
             elif name[9:] == 'unit_digits':
                 return 2
 
-    @fields.depends('from_location')
+    @fields.depends('from_location', 'to_location')
     def on_change_with_purchase_visible(self, name=None):
         if self.from_location:
             if self.from_location.type == 'supplier':
                 return True
+        elif self.to_location:
+            if self.to_location.type == 'supplier':
+                return True
         return False
 
     def get_supplier(self, name):
@@ -278,9 +281,8 @@ class Move:
                 ])
         if purchase_lines:
             purchase_ids = list(set(l.purchase.id for l in purchase_lines))
-            with Transaction().set_user(0, set_context=True):
-                purchases = Purchase.browse(purchase_ids)
-                Purchase.process(purchases)
+            purchases = Purchase.browse(purchase_ids)
+            Purchase.process(purchases)
 
     @classmethod
     def delete(cls, moves):
@@ -299,7 +301,7 @@ class Move:
             for purchase_line in purchase_lines:
                 purchases.add(purchase_line.purchase)
             if purchases:
-                with Transaction().set_user(0, set_context=True):
+                with Transaction().set_context(_check_access=False):
                     purchases = Purchase.browse([p.id for p in purchases])
                     Purchase.process(purchases)
 
diff --git a/tests/scenario_purchase.rst b/tests/scenario_purchase.rst
index 2f70843..4c08939 100644
--- a/tests/scenario_purchase.rst
+++ b/tests/scenario_purchase.rst
@@ -244,12 +244,11 @@ Purchase 5 products::
     >>> purchase.lines.append(purchase_line)
     >>> purchase_line.product = product
     >>> purchase_line.quantity = 3.0
-    >>> purchase.save()
-    >>> Purchase.quote([purchase.id], config.context)
-    >>> Purchase.confirm([purchase.id], config.context)
+    >>> purchase.click('quote')
+    >>> purchase.click('confirm')
+    >>> purchase.click('process')
     >>> purchase.state
-    u'confirmed'
-    >>> purchase.reload()
+    u'processing'
     >>> len(purchase.moves), len(purchase.shipment_returns), len(purchase.invoices)
     (2, 0, 1)
     >>> invoice, = purchase.invoices
@@ -302,12 +301,9 @@ Purchase 5 products with an invoice method 'on shipment'::
     >>> purchase.lines.append(purchase_line)
     >>> purchase_line.product = product
     >>> purchase_line.quantity = 3.0
-    >>> purchase.save()
-    >>> Purchase.quote([purchase.id], config.context)
-    >>> Purchase.confirm([purchase.id], config.context)
-    >>> purchase.state
-    u'confirmed'
-    >>> purchase.reload()
+    >>> purchase.click('quote')
+    >>> purchase.click('confirm')
+    >>> purchase.click('process')
     >>> len(purchase.moves), len(purchase.shipment_returns), len(purchase.invoices)
     (2, 0, 0)
 
@@ -387,11 +383,11 @@ Create a Return::
     >>> return_.lines.append(return_line)
     >>> return_line.type = 'comment'
     >>> return_line.description = 'Comment'
-    >>> return_.save()
-    >>> Purchase.quote([return_.id], config.context)
-    >>> Purchase.confirm([return_.id], config.context)
+    >>> return_.click('quote')
+    >>> return_.click('confirm')
+    >>> return_.click('process')
     >>> return_.state
-    u'confirmed'
+    u'processing'
     >>> return_.reload()
     >>> (len(return_.shipments), len(return_.shipment_returns),
     ...     len(return_.invoices))
@@ -452,11 +448,11 @@ Mixing return and purchase::
     >>> mix.lines.append(mixline2)
     >>> mixline2.product = product
     >>> mixline2.quantity = -2.
-    >>> mix.save()
-    >>> Purchase.quote([mix.id], config.context)
-    >>> Purchase.confirm([mix.id], config.context)
+    >>> mix.click('quote')
+    >>> mix.click('confirm')
+    >>> mix.click('process')
     >>> mix.state
-    u'confirmed'
+    u'processing'
     >>> mix.reload()
     >>> len(mix.moves), len(mix.shipment_returns), len(mix.invoices)
     (2, 1, 2)
@@ -532,11 +528,11 @@ Mixing stuff with an invoice method 'on shipment'::
     >>> mix.lines.append(mixline2)
     >>> mixline2.product = product
     >>> mixline2.quantity = -3.
-    >>> mix.save()
-    >>> Purchase.quote([mix.id], config.context)
-    >>> Purchase.confirm([mix.id], config.context)
+    >>> mix.click('quote')
+    >>> mix.click('confirm')
+    >>> mix.click('process')
     >>> mix.state
-    u'confirmed'
+    u'processing'
     >>> mix.reload()
     >>> len(mix.moves), len(mix.shipment_returns), len(mix.invoices)
     (2, 1, 0)
@@ -581,8 +577,9 @@ Purchase services::
     >>> service_purchase.save()
     >>> service_purchase.click('quote')
     >>> service_purchase.click('confirm')
+    >>> service_purchase.click('process')
     >>> service_purchase.state
-    u'confirmed'
+    u'processing'
     >>> service_invoice, = service_purchase.invoices
 
 Pay the service invoice::
@@ -608,3 +605,40 @@ Check service purchase states::
     u'none'
     >>> service_purchase.state
     u'done'
+
+Create a purchase to be invoiced on shipment partialy and check correctly
+linked to invoices::
+
+    >>> purchase = Purchase()
+    >>> purchase.party = supplier
+    >>> purchase.payment_term = payment_term
+    >>> purchase.invoice_method = 'shipment'
+    >>> line = purchase.lines.new()
+    >>> line.product = product
+    >>> line.quantity = 10.0
+    >>> purchase.click('quote')
+    >>> purchase.click('confirm')
+    >>> purchase.click('process')
+    >>> config.user = stock_user.id
+    >>> shipment = ShipmentIn()
+    >>> shipment.supplier = supplier
+    >>> for move in purchase.moves:
+    ...     incoming_move = Move(id=move.id)
+    ...     incoming_move.quantity = 5.0
+    ...     shipment.incoming_moves.append(incoming_move)
+    >>> shipment.save()
+    >>> for move in shipment.inventory_moves:
+    ...     move.quantity = 5.0
+    >>> shipment.click('receive')
+    >>> shipment.click('done')
+    >>> config.user = purchase_user.id
+    >>> purchase.reload()
+    >>> invoice, = purchase.invoices
+    >>> invoice_line, = invoice.lines
+    >>> invoice_line.quantity
+    5.0
+    >>> stock_move, = invoice_line.stock_moves
+    >>> stock_move.quantity
+    5.0
+    >>> stock_move.state
+    u'done'
diff --git a/tests/test_purchase.py b/tests/test_purchase.py
index b40c8c7..01f2b25 100644
--- a/tests/test_purchase.py
+++ b/tests/test_purchase.py
@@ -2,8 +2,13 @@
 #this repository contains the full copyright notices and license terms.
 import unittest
 import doctest
+from decimal import Decimal
+
 import trytond.tests.test_tryton
-from trytond.tests.test_tryton import test_view, test_depends, doctest_dropdb
+from trytond.tests.test_tryton import test_view, test_depends
+from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT
+from trytond.tests.test_tryton import doctest_setup, doctest_teardown
+from trytond.transaction import Transaction
 
 
 class PurchaseTestCase(unittest.TestCase):
@@ -20,12 +25,106 @@ class PurchaseTestCase(unittest.TestCase):
         'Test depends'
         test_depends()
 
+    def test_purchase_price(self):
+        'Test purchase price'
+        with Transaction().start(DB_NAME, USER, context=CONTEXT):
+            Company = POOL.get('company.company')
+            User = POOL.get('res.user')
+            Account = POOL.get('account.account')
+            Template = POOL.get('product.template')
+            Product = POOL.get('product.product')
+            Uom = POOL.get('product.uom')
+            ProductSupplier = POOL.get('purchase.product_supplier')
+            Party = POOL.get('party.party')
+
+            company, = Company.search([('rec_name', '=', 'Dunder Mifflin')])
+            User.write([User(USER)], {
+                    'main_company': company.id,
+                    'company': company.id,
+                    })
+
+            receivable, = Account.search([
+                    ('kind', '=', 'receivable'),
+                    ('company', '=', company.id),
+                    ])
+            payable, = Account.search([
+                    ('kind', '=', 'payable'),
+                    ('company', '=', company.id),
+                    ])
+
+            kg, = Uom.search([('name', '=', 'Kilogram')])
+            g, = Uom.search([('name', '=', 'Gram')])
+
+            template, = Template.create([{
+                        'name': 'Product',
+                        'default_uom': g.id,
+                        'purchase_uom': kg.id,
+                        'list_price': Decimal(5),
+                        'cost_price': Decimal(2),
+                        'products': [('create', [{}])],
+                        }])
+            product, = template.products
+
+            supplier, = Party.create([{
+                        'name': 'Supplier',
+                        'account_receivable': receivable.id,
+                        'account_payable': payable.id,
+                        }])
+            product_supplier, = ProductSupplier.create([{
+                        'product': template.id,
+                        'party': supplier.id,
+                        'prices': [('create', [{
+                                        'sequence': 1,
+                                        'quantity': 1,
+                                        'unit_price': Decimal(3000),
+                                        }, {
+                                        'sequence': 2,
+                                        'quantity': 2,
+                                        'unit_price': Decimal(2500),
+                                        }])],
+                        }])
+
+            prices = Product.get_purchase_price([product], quantity=100)
+            self.assertEqual(prices, {product.id: Decimal(2)})
+            prices = Product.get_purchase_price([product], quantity=1500)
+            self.assertEqual(prices, {product.id: Decimal(2)})
+
+            with Transaction().set_context(uom=kg.id):
+                prices = Product.get_purchase_price([product], quantity=0.5)
+                self.assertEqual(prices, {product.id: Decimal(2000)})
+                prices = Product.get_purchase_price([product], quantity=1.5)
+                self.assertEqual(prices, {product.id: Decimal(2000)})
+
+            with Transaction().set_context(supplier=supplier.id):
+                prices = Product.get_purchase_price([product], quantity=100)
+                self.assertEqual(prices, {product.id: Decimal(2)})
+                prices = Product.get_purchase_price([product], quantity=1500)
+                self.assertEqual(prices, {product.id: Decimal(3)})
+                prices = Product.get_purchase_price([product], quantity=3000)
+                self.assertEqual(prices, {product.id: Decimal('2.5')})
+
+            with Transaction().set_context(uom=kg.id, supplier=supplier.id):
+                prices = Product.get_purchase_price([product], quantity=0.5)
+                self.assertEqual(prices, {product.id: Decimal(2000)})
+                prices = Product.get_purchase_price([product], quantity=1.5)
+                self.assertEqual(prices, {product.id: Decimal(3000)})
+                prices = Product.get_purchase_price([product], quantity=3)
+                self.assertEqual(prices, {product.id: Decimal(2500)})
+
 
 def suite():
     suite = trytond.tests.test_tryton.suite()
+    from trytond.modules.company.tests import test_company
+    for test in test_company.suite():
+        if test not in suite:
+            suite.addTest(test)
+    from trytond.modules.account.tests import test_account
+    for test in test_account.suite():
+        if test not in suite and not isinstance(test, doctest.DocTestCase):
+            suite.addTest(test)
     suite.addTests(unittest.TestLoader().loadTestsFromTestCase(
         PurchaseTestCase))
     suite.addTests(doctest.DocFileSuite('scenario_purchase.rst',
-            setUp=doctest_dropdb, tearDown=doctest_dropdb, encoding='UTF-8',
+            setUp=doctest_setup, tearDown=doctest_teardown, encoding='UTF-8',
             optionflags=doctest.REPORT_ONLY_FIRST_FAILURE))
     return suite
diff --git a/tryton.cfg b/tryton.cfg
index 1b20ea5..1e2b20b 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -1,5 +1,5 @@
 [tryton]
-version=3.2.0
+version=3.4.0
 depends:
     account
     account_invoice
diff --git a/trytond_purchase.egg-info/PKG-INFO b/trytond_purchase.egg-info/PKG-INFO
index 41f7726..672faf5 100644
--- a/trytond_purchase.egg-info/PKG-INFO
+++ b/trytond_purchase.egg-info/PKG-INFO
@@ -1,12 +1,12 @@
 Metadata-Version: 1.1
 Name: trytond-purchase
-Version: 3.2.0
+Version: 3.4.0
 Summary: Tryton module for purchase
 Home-page: http://www.tryton.org/
 Author: Tryton
 Author-email: issue_tracker at tryton.org
 License: GPL-3
-Download-URL: http://downloads.tryton.org/3.2/
+Download-URL: http://downloads.tryton.org/3.4/
 Description: trytond_purchase
         ================
         
diff --git a/trytond_purchase.egg-info/SOURCES.txt b/trytond_purchase.egg-info/SOURCES.txt
index 67ef9c3..2a23236 100644
--- a/trytond_purchase.egg-info/SOURCES.txt
+++ b/trytond_purchase.egg-info/SOURCES.txt
@@ -15,12 +15,51 @@ stock.xml
 tryton.cfg
 ./__init__.py
 ./configuration.py
+./configuration.xml
 ./invoice.py
+./party.xml
 ./product.py
+./product.xml
+./purchase.odt
 ./purchase.py
+./purchase.xml
 ./stock.py
+./stock.xml
+./tryton.cfg
+./locale/bg_BG.po
+./locale/ca_ES.po
+./locale/cs_CZ.po
+./locale/de_DE.po
+./locale/es_AR.po
+./locale/es_CO.po
+./locale/es_EC.po
+./locale/es_ES.po
+./locale/fr_FR.po
+./locale/nl_NL.po
+./locale/ru_RU.po
+./locale/sl_SI.po
 ./tests/__init__.py
+./tests/scenario_purchase.rst
 ./tests/test_purchase.py
+./view/configuration_form.xml
+./view/handle_invoice_exception_ask_form.xml
+./view/handle_shipment_exception_ask_form.xml
+./view/move_form.xml
+./view/move_list_shipment.xml
+./view/product_list_purchase_line.xml
+./view/product_supplier_form.xml
+./view/product_supplier_price_form.xml
+./view/product_supplier_price_list_sequence.xml
+./view/product_supplier_price_tree.xml
+./view/product_supplier_tree.xml
+./view/product_supplier_tree_sequence.xml
+./view/purchase_form.xml
+./view/purchase_line_form.xml
+./view/purchase_line_tree.xml
+./view/purchase_line_tree_sequence.xml
+./view/purchase_tree.xml
+./view/template_form.xml
+./view/template_tree.xml
 doc/index.rst
 locale/bg_BG.po
 locale/ca_ES.po
@@ -28,6 +67,7 @@ locale/cs_CZ.po
 locale/de_DE.po
 locale/es_AR.po
 locale/es_CO.po
+locale/es_EC.po
 locale/es_ES.po
 locale/fr_FR.po
 locale/nl_NL.po
@@ -49,6 +89,7 @@ view/move_list_shipment.xml
 view/product_list_purchase_line.xml
 view/product_supplier_form.xml
 view/product_supplier_price_form.xml
+view/product_supplier_price_list_sequence.xml
 view/product_supplier_price_tree.xml
 view/product_supplier_tree.xml
 view/product_supplier_tree_sequence.xml
diff --git a/trytond_purchase.egg-info/requires.txt b/trytond_purchase.egg-info/requires.txt
index 4fa7d4c..354776c 100644
--- a/trytond_purchase.egg-info/requires.txt
+++ b/trytond_purchase.egg-info/requires.txt
@@ -1,11 +1,11 @@
 python-sql
-trytond_account >= 3.2, < 3.3
-trytond_account_invoice >= 3.2, < 3.3
-trytond_account_invoice_stock >= 3.2, < 3.3
-trytond_account_product >= 3.2, < 3.3
-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_stock >= 3.2, < 3.3
-trytond >= 3.2, < 3.3
\ No newline at end of file
+trytond_account >= 3.4, < 3.5
+trytond_account_invoice >= 3.4, < 3.5
+trytond_account_invoice_stock >= 3.4, < 3.5
+trytond_account_product >= 3.4, < 3.5
+trytond_company >= 3.4, < 3.5
+trytond_currency >= 3.4, < 3.5
+trytond_party >= 3.4, < 3.5
+trytond_product >= 3.4, < 3.5
+trytond_stock >= 3.4, < 3.5
+trytond >= 3.4, < 3.5
\ No newline at end of file
diff --git a/view/handle_invoice_exception_ask_form.xml b/view/handle_invoice_exception_ask_form.xml
index bb0cf4a..06a9f96 100644
--- a/view/handle_invoice_exception_ask_form.xml
+++ b/view/handle_invoice_exception_ask_form.xml
@@ -5,5 +5,5 @@ this repository contains the full copyright notices and license terms. -->
     <image name="tryton-dialog-information" xexpand="0" xfill="0"/>
     <label string="Choose invoices to recreate" id="choose"
         yalign="0.0" xalign="0.0" xexpand="1"/>
-    <field name="recreate_invoices" colspan="2"/>
+    <field name="recreate_invoices" colspan="2" widget="multiselection"/>
 </form>
diff --git a/view/handle_shipment_exception_ask_form.xml b/view/handle_shipment_exception_ask_form.xml
index 5319d45..716ec79 100644
--- a/view/handle_shipment_exception_ask_form.xml
+++ b/view/handle_shipment_exception_ask_form.xml
@@ -5,6 +5,5 @@ this repository contains the full copyright notices and license terms. -->
     <image name="tryton-dialog-information" xexpand="0" xfill="0"/>
     <label string="Choose move to recreate" id="choose"
         yalign="0.0" xalign="0.0" xexpand="1"/>
-    <field name="recreate_moves" colspan="2"
-        view_ids="stock.move_view_tree"/>
+    <field name="recreate_moves" colspan="2" widget="multiselection"/>
 </form>
diff --git a/view/product_supplier_form.xml b/view/product_supplier_form.xml
index ee69174..3309c80 100644
--- a/view/product_supplier_form.xml
+++ b/view/product_supplier_form.xml
@@ -17,5 +17,6 @@ this repository contains the full copyright notices and license terms. -->
     <newline/>
     <label name="currency"/>
     <field name="currency"/>
-    <field name="prices" colspan="4"/>
+    <field name="prices" colspan="4"
+        view_ids="purchase.product_supplier_price_view_list_sequence"/>
 </form>
diff --git a/view/product_supplier_price_form.xml b/view/product_supplier_price_form.xml
index 6237a12..85d98c1 100644
--- a/view/product_supplier_price_form.xml
+++ b/view/product_supplier_price_form.xml
@@ -1,11 +1,14 @@
 <?xml version="1.0"?>
 <!-- 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="Product Supplier Price" col="6">
+<form string="Product Supplier Price">
     <label name="product_supplier"/>
-    <field name="product_supplier" colspan="5"/>
+    <field name="product_supplier" colspan="3"/>
+    <label name="sequence"/>
+    <field name="sequence"/>
     <label name="quantity"/>
     <field name="quantity"/>
+    <newline/>
     <label name="unit_price"/>
     <field name="unit_price"/>
 </form>
diff --git a/view/product_supplier_price_list_sequence.xml b/view/product_supplier_price_list_sequence.xml
new file mode 100644
index 0000000..3e34507
--- /dev/null
+++ b/view/product_supplier_price_list_sequence.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<!-- This file is part of Tryton.  The COPYRIGHT file at the top level of
+this repository contains the full copyright notices and license terms. -->
+<tree string="Product Supplier Prices" sequence="sequence">
+    <field name="product_supplier"/>
+    <field name="quantity"/>
+    <field name="unit_price" expand="1"/>
+    <field name="sequence" tree_invisible="1"/>
+</tree>
diff --git a/view/purchase_form.xml b/view/purchase_form.xml
index 20263d1..c9eb522 100644
--- a/view/purchase_form.xml
+++ b/view/purchase_form.xml
@@ -53,6 +53,8 @@ this repository contains the full copyright notices and license terms. -->
                             icon="tryton-go-next"/>
                     <button name="confirm" string="Confirm"
                         icon="tryton-ok"/>
+                    <button name="process" string="Process"
+                        icon="tryton-go-next"/>
                 </group>
             </group>
         </page>
-- 
tryton-modules-purchase



More information about the tryton-debian-vcs mailing list