[tryton-debian-vcs] tryton-modules-sale branch debian updated. debian/3.4.1-1-2-g8cf3c63

Mathias Behrle tryton-debian-vcs at alioth.debian.org
Thu Apr 23 16:05:54 UTC 2015


The following commit has been merged in the debian branch:
https://alioth.debian.org/plugins/scmgit/cgi-bin/gitweb.cgi/?p=tryton/tryton-modules-sale.git;a=commitdiff;h=debian/3.4.1-1-2-g8cf3c63

commit 8cf3c6335feffd13a202e7038e9eef17ec2817ab
Author: Mathias Behrle <mathiasb at m9s.biz>
Date:   Thu Apr 23 17:00:04 2015 +0200

    Merging upstream version 3.6.0.

diff --git a/CHANGELOG b/CHANGELOG
index cee8c6d..932573a 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,9 @@
-Version 3.4.1 - 2015-02-21
+Version 3.6.0 - 2015-04-20
 * Bug fixes (see mercurial logs for details)
+* Add support for PyPy
+* Add origin on sale
+* Support mixed invoice type by line in invoiced quantity calculation
+* Use TaxableMixin
 
 Version 3.4.0 - 2014-10-20
 * Bug fixes (see mercurial logs for details)
diff --git a/INSTALL b/INSTALL
index f34c7d4..eaa1781 100644
--- a/INSTALL
+++ b/INSTALL
@@ -6,7 +6,7 @@ Prerequisites
 
  * Python 2.7 or later (http://www.python.org/)
  * trytond (http://www.tryton.org/)
- * python-sql (http://code.google.com/p/python-sql/)
+ * python-sql 0.4 or later (http://code.google.com/p/python-sql/)
  * trytond_company (http://www.tryton.org/)
  * trytond_party (http://www.tryton.org/)
  * trytond_stock (http://www.tryton.org/)
diff --git a/PKG-INFO b/PKG-INFO
index 05cbca1..727f1da 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,12 @@
 Metadata-Version: 1.1
 Name: trytond_sale
-Version: 3.4.1
+Version: 3.6.0
 Summary: Tryton module for sale
 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.4/
+Download-URL: http://downloads.tryton.org/3.6/
 Description: trytond_sale
         ============
         
@@ -64,5 +64,7 @@ Classifier: Natural Language :: Slovenian
 Classifier: Natural Language :: Spanish
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Office/Business
 Classifier: Topic :: Office/Business :: Financial :: Accounting
diff --git a/__init__.py b/__init__.py
index 0b4e671..c6d2562 100644
--- a/__init__.py
+++ b/__init__.py
@@ -1,5 +1,5 @@
-#This file is part of Tryton.  The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
 
 from trytond.pool import Pool
 from .sale import *
diff --git a/configuration.py b/configuration.py
index 905b65a..c301a03 100644
--- a/configuration.py
+++ b/configuration.py
@@ -1,5 +1,5 @@
-#This file is part of Tryton.  The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
 from trytond.model import ModelView, ModelSQL, ModelSingleton, fields
 from trytond.pyson import Eval, Bool
 
diff --git a/invoice.py b/invoice.py
index bfd5937..39578ce 100644
--- a/invoice.py
+++ b/invoice.py
@@ -1,5 +1,5 @@
-#This file is part of Tryton.  The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
 from functools import wraps
 from sql import Table
 
diff --git a/locale/bg_BG.po b/locale/bg_BG.po
index c81a465..02f9813 100644
--- a/locale/bg_BG.po
+++ b/locale/bg_BG.po
@@ -409,6 +409,11 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr "Движения"
 
+#, fuzzy
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr "Източник"
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr "Партньор"
@@ -1065,7 +1070,7 @@ msgid "Cancel"
 msgstr "Отказ"
 
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Добре"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,end:"
@@ -1073,7 +1078,7 @@ msgid "Cancel"
 msgstr "Отказ"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Добре"
 
 #, fuzzy
diff --git a/locale/ca_ES.po b/locale/ca_ES.po
index 3606428..c3c3ecb 100644
--- a/locale/ca_ES.po
+++ b/locale/ca_ES.po
@@ -9,7 +9,8 @@ msgstr "No podeu restaurar a esborrany una factura generada per una venda."
 msgctxt "error:sale.line:"
 msgid "Product \"%(product)s\" of sale %(sale)s misses a revenue account."
 msgstr ""
-"Falta el compte a cobrar del producte \"%(product)s\" de la venda %(sale)s."
+"Falta el compte d'ingressos del producte \"%(product)s\" de la venda "
+"%(sale)s."
 
 msgctxt "error:sale.line:"
 msgid "Sale \"%(sale)s\" is missing the customer location in line \"%(line)s\"."
@@ -19,7 +20,9 @@ msgstr ""
 
 msgctxt "error:sale.line:"
 msgid "Sale \"%(sale)s\" misses an \"account revenue\" default property."
-msgstr "Falta la propietat \"Compte a cobrar\" per defecte de les vendes."
+msgstr ""
+"Falta la propietat \"Compte d'ingressos\" per defecte de la venda "
+"\"%(sale)s\"."
 
 msgctxt "error:sale.sale:"
 msgid "Invalid combination of shipment and invoicing methods on sale \"%s\"."
@@ -125,7 +128,7 @@ msgstr "Recrea factures"
 
 msgctxt "field:sale.handle.shipment.exception.ask,domain_moves:"
 msgid "Domain Moves"
-msgstr "Domini moviments"
+msgstr "Domini dels moviments"
 
 msgctxt "field:sale.handle.shipment.exception.ask,id:"
 msgid "ID"
@@ -415,6 +418,10 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr "Moviments"
 
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr "Origen"
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr "Tercer"
@@ -635,12 +642,12 @@ msgstr "Gestiona excepció d'enviament"
 
 msgctxt "model:ir.action.act_window.domain,name:act_sale_form_domain_all"
 msgid "All"
-msgstr "Tot"
+msgstr "Totes"
 
 msgctxt ""
 "model:ir.action.act_window.domain,name:act_sale_form_domain_confirmed"
 msgid "Confirmed"
-msgstr "Confirmat"
+msgstr "Confirmada"
 
 msgctxt "model:ir.action.act_window.domain,name:act_sale_form_domain_draft"
 msgid "Draft"
@@ -966,7 +973,7 @@ msgstr "Configuració comades de venda"
 
 msgctxt "view:sale.handle.invoice.exception.ask:"
 msgid "Choose invoices to recreate"
-msgstr "Tria una factura a refer"
+msgstr "Seleccioneu les factures a recrear"
 
 msgctxt "view:sale.handle.invoice.exception.ask:"
 msgid "Handle Invoice Exception"
@@ -974,7 +981,7 @@ msgstr "Gestiona excepció de factura"
 
 msgctxt "view:sale.handle.shipment.exception.ask:"
 msgid "Choose move to recreate"
-msgstr "Tria un moviment a refer"
+msgstr "Seleccioneu els moviments a recrear"
 
 msgctxt "view:sale.handle.shipment.exception.ask:"
 msgid "Handle shipment Exception"
@@ -996,6 +1003,10 @@ msgctxt "view:sale.line:"
 msgid "Sale Lines"
 msgstr "Línies de venda"
 
+msgctxt "view:sale.line:"
+msgid "Taxes"
+msgstr "Impostos"
+
 msgctxt "view:sale.return_sale.start:"
 msgid "Are you sure to return those/this sale(s)?"
 msgstr "Esteu segur de retornar aquestes comandes de venda?"
@@ -1061,7 +1072,7 @@ msgid "Cancel"
 msgstr "Cancel·la"
 
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Accepta"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,end:"
@@ -1069,7 +1080,7 @@ msgid "Cancel"
 msgstr "Cancel·la"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Accepta"
 
 msgctxt "wizard_button:sale.return_sale,start,end:"
diff --git a/locale/cs_CZ.po b/locale/cs_CZ.po
index 489994c..612de9d 100644
--- a/locale/cs_CZ.po
+++ b/locale/cs_CZ.po
@@ -408,6 +408,10 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr ""
 
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr ""
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr ""
@@ -1053,7 +1057,7 @@ msgid "Cancel"
 msgstr ""
 
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr ""
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,end:"
@@ -1061,7 +1065,7 @@ msgid "Cancel"
 msgstr ""
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr ""
 
 msgctxt "wizard_button:sale.return_sale,start,end:"
diff --git a/locale/de_DE.po b/locale/de_DE.po
index 50c9336..1e0c513 100644
--- a/locale/de_DE.po
+++ b/locale/de_DE.po
@@ -42,7 +42,7 @@ msgstr ""
 
 msgctxt "error:sale.sale:"
 msgid "It misses an \"Account Receivable\" on the party \"%s\"."
-msgstr "Fehlendes \"Forderungskonto\" für Partei \"%s\"."
+msgstr "Fehlendes Forderungskonto für Partei \"%s\""
 
 msgctxt "error:sale.sale:"
 msgid "Sale \"%s\" must be cancelled before deletion."
@@ -426,6 +426,10 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr "Bewegungen"
 
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr "Herkunft"
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr "Partei"
@@ -1008,6 +1012,10 @@ msgctxt "view:sale.line:"
 msgid "Sale Lines"
 msgstr "Verkaufspositionen"
 
+msgctxt "view:sale.line:"
+msgid "Taxes"
+msgstr "Steuern"
+
 msgctxt "view:sale.return_sale.start:"
 msgid "Are you sure to return those/this sale(s)?"
 msgstr ""
@@ -1074,7 +1082,7 @@ msgid "Cancel"
 msgstr "Abbrechen"
 
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "OK"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,end:"
@@ -1082,7 +1090,7 @@ msgid "Cancel"
 msgstr "Abbrechen"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "OK"
 
 msgctxt "wizard_button:sale.return_sale,start,end:"
diff --git a/locale/es_AR.po b/locale/es_AR.po
index fe9b838..2def8da 100644
--- a/locale/es_AR.po
+++ b/locale/es_AR.po
@@ -232,7 +232,7 @@ msgstr "Unidad"
 
 msgctxt "field:sale.line,unit_digits:"
 msgid "Unit Digits"
-msgstr "Dígitos de unidad"
+msgstr "Decimales de unidad"
 
 msgctxt "field:sale.line,unit_price:"
 msgid "Unit Price"
@@ -240,7 +240,7 @@ msgstr "Precio unitario"
 
 msgctxt "field:sale.line,warehouse:"
 msgid "Warehouse"
-msgstr "Depósito"
+msgstr "Almacén"
 
 msgctxt "field:sale.line,write_date:"
 msgid "Write Date"
@@ -372,7 +372,7 @@ msgstr "Moneda"
 
 msgctxt "field:sale.sale,currency_digits:"
 msgid "Currency Digits"
-msgstr "Dígitos de moneda"
+msgstr "Decimales de moneda"
 
 msgctxt "field:sale.sale,description:"
 msgid "Description"
@@ -414,6 +414,10 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr "Movimientos"
 
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr "Origen"
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr "Entidad"
@@ -995,6 +999,10 @@ msgctxt "view:sale.line:"
 msgid "Sale Lines"
 msgstr "Líneas de venta"
 
+msgctxt "view:sale.line:"
+msgid "Taxes"
+msgstr "Impuestos"
+
 msgctxt "view:sale.return_sale.start:"
 msgid "Are you sure to return those/this sale(s)?"
 msgstr "¿Está seguro de devolver estos pedidos?"
@@ -1060,7 +1068,7 @@ msgid "Cancel"
 msgstr "Cancelar"
 
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Aceptar"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,end:"
@@ -1068,7 +1076,7 @@ msgid "Cancel"
 msgstr "Cancelar"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Aceptar"
 
 msgctxt "wizard_button:sale.return_sale,start,end:"
diff --git a/locale/es_CO.po b/locale/es_CO.po
index cff685c..0777ec3 100644
--- a/locale/es_CO.po
+++ b/locale/es_CO.po
@@ -417,6 +417,10 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr "Movimientos"
 
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr "Origen"
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr "Tercero"
@@ -998,6 +1002,10 @@ msgctxt "view:sale.line:"
 msgid "Sale Lines"
 msgstr "Líneas de Venta"
 
+msgctxt "view:sale.line:"
+msgid "Taxes"
+msgstr "Impuestos"
+
 msgctxt "view:sale.return_sale.start:"
 msgid "Are you sure to return those/this sale(s)?"
 msgstr "Esta seguro que desea devolver esta(s) venta(s)?"
@@ -1008,7 +1016,7 @@ msgstr "Crear Devolución de Venta"
 
 msgctxt "view:sale.sale:"
 msgid "Cancel"
-msgstr "Cancelar"
+msgstr "Anular"
 
 msgctxt "view:sale.sale:"
 msgid "Confirm"
@@ -1063,7 +1071,7 @@ msgid "Cancel"
 msgstr "Cancelar"
 
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Aceptar"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,end:"
@@ -1071,7 +1079,7 @@ msgid "Cancel"
 msgstr "Cancelar"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Aceptar"
 
 msgctxt "wizard_button:sale.return_sale,start,end:"
diff --git a/locale/es_EC.po b/locale/es_EC.po
index df48961..2bc547c 100644
--- a/locale/es_EC.po
+++ b/locale/es_EC.po
@@ -4,12 +4,12 @@ msgstr "Content-Type: text/plain; charset=utf-8\n"
 
 msgctxt "error:account.invoice:"
 msgid "You cannot reset to draft an invoice generated by a sale."
-msgstr "No puede restaurar a borrador una factura generada por una venta."
+msgstr "No puede restablecer a borrador una factura generada por una venta."
 
 msgctxt "error:sale.line:"
 msgid "Product \"%(product)s\" of sale %(sale)s misses a revenue account."
 msgstr ""
-"Al producto \"%(product)s\" de la venta \"%(sale)s\" le falta definir una "
+"Al producto \"%(product)s\" de la venta \"%(sale)s\" le falta definir la "
 "cuenta de ingresos."
 
 msgctxt "error:sale.line:"
@@ -27,15 +27,15 @@ msgstr ""
 msgctxt "error:sale.sale:"
 msgid "Invalid combination of shipment and invoicing methods on sale \"%s\"."
 msgstr ""
-"La combinación de métodos de envío y facturación en la venta \"%s\" no es "
-"válida."
+"La combinación de los métodos de envío y facturación en la venta \"%s\" no "
+"es válida."
 
 msgctxt "error:sale.sale:"
 msgid ""
 "Invoice and Shipment addresses must be defined for the quotation of sale "
 "\"%s\"."
 msgstr ""
-"Las direcciones de facturación y envío se deben definir para la cotización "
+"Las direcciones de Envío y Facturación se deben definir para la cotización "
 "de venta \"%s\"."
 
 msgctxt "error:sale.sale:"
@@ -52,15 +52,15 @@ msgstr "Se debe definir el depósito para la cotización de la venta \"%s\"."
 
 msgctxt "error:stock.shipment.out.return:"
 msgid "You cannot reset to draft a move generated by a sale."
-msgstr "No puede restaurar a borrador un movimiento generado por una venta."
+msgstr "No puede restablecer a borrador un movimiento generado por una venta."
 
 msgctxt "error:stock.shipment.out:"
 msgid "You cannot reset to draft a move generated by a sale."
-msgstr "No puede restaurar a borrador un movimiento generado por una venta."
+msgstr "No puede restablecer a borrador un movimiento generado por una venta."
 
 msgctxt "field:account.invoice,sale_exception_state:"
 msgid "Exception State"
-msgstr "Estado Excepción"
+msgstr "Estado excepción"
 
 msgctxt "field:account.invoice,sales:"
 msgid "Sales"
@@ -68,7 +68,7 @@ msgstr "Ventas"
 
 msgctxt "field:product.template,delivery_time:"
 msgid "Delivery Time"
-msgstr "Tiempo de Entrega"
+msgstr "Tiempo de entrega"
 
 msgctxt "field:product.template,salable:"
 msgid "Salable"
@@ -76,15 +76,15 @@ msgstr "Vendible"
 
 msgctxt "field:product.template,sale_uom:"
 msgid "Sale UOM"
-msgstr "UdM de Venta"
+msgstr "UdM de venta"
 
 msgctxt "field:sale.configuration,create_date:"
 msgid "Create Date"
-msgstr "Fecha de Creación"
+msgstr "Fecha de creación"
 
 msgctxt "field:sale.configuration,create_uid:"
 msgid "Create User"
-msgstr "Creado por Usuario"
+msgstr "Creado por usuario"
 
 msgctxt "field:sale.configuration,id:"
 msgid "ID"
@@ -96,27 +96,27 @@ msgstr "Nombre"
 
 msgctxt "field:sale.configuration,sale_invoice_method:"
 msgid "Sale Invoice Method"
-msgstr "Método de Facturación"
+msgstr "Método de facturación"
 
 msgctxt "field:sale.configuration,sale_sequence:"
 msgid "Sale Reference Sequence"
-msgstr "Secuencia de Pedidos de Venta"
+msgstr "Secuencia de pedidos de venta"
 
 msgctxt "field:sale.configuration,sale_shipment_method:"
 msgid "Sale Shipment Method"
-msgstr "Método de Envío"
+msgstr "Método de envío"
 
 msgctxt "field:sale.configuration,write_date:"
 msgid "Write Date"
-msgstr "Fecha de Modificación"
+msgstr "Fecha de modificación"
 
 msgctxt "field:sale.configuration,write_uid:"
 msgid "Write User"
-msgstr "Modificado por Usuario"
+msgstr "Modificado por usuario"
 
 msgctxt "field:sale.handle.invoice.exception.ask,domain_invoices:"
 msgid "Domain Invoices"
-msgstr "Dominio de Facturas"
+msgstr "Dominio de facturas"
 
 msgctxt "field:sale.handle.invoice.exception.ask,id:"
 msgid "ID"
@@ -124,11 +124,11 @@ msgstr "ID"
 
 msgctxt "field:sale.handle.invoice.exception.ask,recreate_invoices:"
 msgid "Recreate Invoices"
-msgstr "Recrear Facturas"
+msgstr "Recrear facturas"
 
 msgctxt "field:sale.handle.shipment.exception.ask,domain_moves:"
 msgid "Domain Moves"
-msgstr "Dominio de Movimientos"
+msgstr "Dominio de movimientos"
 
 msgctxt "field:sale.handle.shipment.exception.ask,id:"
 msgid "ID"
@@ -136,7 +136,7 @@ msgstr "ID"
 
 msgctxt "field:sale.handle.shipment.exception.ask,recreate_moves:"
 msgid "Recreate Moves"
-msgstr "Recrear Movimientos"
+msgstr "Recrear movimientos"
 
 msgctxt "field:sale.line,amount:"
 msgid "Amount"
@@ -144,15 +144,15 @@ msgstr "Subtotal"
 
 msgctxt "field:sale.line,create_date:"
 msgid "Create Date"
-msgstr "Fecha de Creación"
+msgstr "Fecha de creación"
 
 msgctxt "field:sale.line,create_uid:"
 msgid "Create User"
-msgstr "Creado por Usuario"
+msgstr "Creado por usuario"
 
 msgctxt "field:sale.line,delivery_date:"
 msgid "Delivery Date"
-msgstr "Fecha de Entrega"
+msgstr "Fecha de entrega"
 
 msgctxt "field:sale.line,description:"
 msgid "Description"
@@ -160,7 +160,7 @@ msgstr "Descripción"
 
 msgctxt "field:sale.line,from_location:"
 msgid "From Location"
-msgstr "Desde Ubicación"
+msgstr "Desde ubicación"
 
 msgctxt "field:sale.line,id:"
 msgid "ID"
@@ -168,15 +168,15 @@ msgstr "ID"
 
 msgctxt "field:sale.line,invoice_lines:"
 msgid "Invoice Lines"
-msgstr "Líneas de Factura"
+msgstr "Líneas de factura"
 
 msgctxt "field:sale.line,move_done:"
 msgid "Moves Done"
-msgstr "Movimientos Realizados"
+msgstr "Movimientos realizados"
 
 msgctxt "field:sale.line,move_exception:"
 msgid "Moves Exception"
-msgstr "Excepción de Movimientos"
+msgstr "Excepción de movimientos"
 
 msgctxt "field:sale.line,moves:"
 msgid "Moves"
@@ -184,11 +184,11 @@ msgstr "Movimientos"
 
 msgctxt "field:sale.line,moves_ignored:"
 msgid "Ignored Moves"
-msgstr "Movimientos Ignorados"
+msgstr "Movimientos ignorados"
 
 msgctxt "field:sale.line,moves_recreated:"
 msgid "Recreated Moves"
-msgstr "Movimientos Recreados"
+msgstr "Movimientos recreados"
 
 msgctxt "field:sale.line,note:"
 msgid "Note"
@@ -200,7 +200,7 @@ msgstr "Producto"
 
 msgctxt "field:sale.line,product_uom_category:"
 msgid "Product Uom Category"
-msgstr "Categoría UdM de Producto"
+msgstr "Categoría de UdM de producto"
 
 msgctxt "field:sale.line,quantity:"
 msgid "Quantity"
@@ -224,7 +224,7 @@ msgstr "Impuestos"
 
 msgctxt "field:sale.line,to_location:"
 msgid "To Location"
-msgstr "A Bodega"
+msgstr "A bodega"
 
 msgctxt "field:sale.line,type:"
 msgid "Type"
@@ -236,11 +236,11 @@ msgstr "Unidad"
 
 msgctxt "field:sale.line,unit_digits:"
 msgid "Unit Digits"
-msgstr "Decimales de Unidad"
+msgstr "Decimales de unidad"
 
 msgctxt "field:sale.line,unit_price:"
 msgid "Unit Price"
-msgstr "Precio Unitario"
+msgstr "Precio unitario"
 
 msgctxt "field:sale.line,warehouse:"
 msgid "Warehouse"
@@ -248,19 +248,19 @@ msgstr "Depósito"
 
 msgctxt "field:sale.line,write_date:"
 msgid "Write Date"
-msgstr "Fecha de Modificación"
+msgstr "Fecha de modificación"
 
 msgctxt "field:sale.line,write_uid:"
 msgid "Write User"
-msgstr "Modificado por Usuario"
+msgstr "Modificado por usuario"
 
 msgctxt "field:sale.line-account.tax,create_date:"
 msgid "Create Date"
-msgstr "Fecha de Creación"
+msgstr "Fecha de creación"
 
 msgctxt "field:sale.line-account.tax,create_uid:"
 msgid "Create User"
-msgstr "Creado por Usuario"
+msgstr "Creado por usuario"
 
 msgctxt "field:sale.line-account.tax,id:"
 msgid "ID"
@@ -268,7 +268,7 @@ msgstr "ID"
 
 msgctxt "field:sale.line-account.tax,line:"
 msgid "Sale Line"
-msgstr "Línea de Venta"
+msgstr "Línea de venta"
 
 msgctxt "field:sale.line-account.tax,rec_name:"
 msgid "Name"
@@ -280,19 +280,19 @@ msgstr "Impuesto"
 
 msgctxt "field:sale.line-account.tax,write_date:"
 msgid "Write Date"
-msgstr "Fecha de Modificación"
+msgstr "Fecha de modificación"
 
 msgctxt "field:sale.line-account.tax,write_uid:"
 msgid "Write User"
-msgstr "Modificado por Usuario"
+msgstr "Modificado por usuario"
 
 msgctxt "field:sale.line-ignored-stock.move,create_date:"
 msgid "Create Date"
-msgstr "Fecha de Creación"
+msgstr "Fecha de creación"
 
 msgctxt "field:sale.line-ignored-stock.move,create_uid:"
 msgid "Create User"
-msgstr "Creado por Usuario"
+msgstr "Creado por usuario"
 
 msgctxt "field:sale.line-ignored-stock.move,id:"
 msgid "ID"
@@ -312,19 +312,19 @@ msgstr "Línea de Venta"
 
 msgctxt "field:sale.line-ignored-stock.move,write_date:"
 msgid "Write Date"
-msgstr "Fecha de Modificación"
+msgstr "Fecha de modificación"
 
 msgctxt "field:sale.line-ignored-stock.move,write_uid:"
 msgid "Write User"
-msgstr "Modificado por Usuario"
+msgstr "Modificado por usuario"
 
 msgctxt "field:sale.line-recreated-stock.move,create_date:"
 msgid "Create Date"
-msgstr "Fecha de Creación"
+msgstr "Fecha de creación"
 
 msgctxt "field:sale.line-recreated-stock.move,create_uid:"
 msgid "Create User"
-msgstr "Creado por Usuario"
+msgstr "Creado por usuario"
 
 msgctxt "field:sale.line-recreated-stock.move,id:"
 msgid "ID"
@@ -340,15 +340,15 @@ msgstr "Nombre"
 
 msgctxt "field:sale.line-recreated-stock.move,sale_line:"
 msgid "Sale Line"
-msgstr "Línea de Venta"
+msgstr "Línea de venta"
 
 msgctxt "field:sale.line-recreated-stock.move,write_date:"
 msgid "Write Date"
-msgstr "Fecha de Modificación"
+msgstr "Fecha de modificación"
 
 msgctxt "field:sale.line-recreated-stock.move,write_uid:"
 msgid "Write User"
-msgstr "Modificado por Usuario"
+msgstr "Modificado por usuario"
 
 msgctxt "field:sale.return_sale.start,id:"
 msgid "ID"
@@ -364,11 +364,11 @@ msgstr "Empresa"
 
 msgctxt "field:sale.sale,create_date:"
 msgid "Create Date"
-msgstr "Fecha de Creación"
+msgstr "Fecha de creación"
 
 msgctxt "field:sale.sale,create_uid:"
 msgid "Create User"
-msgstr "Creado por Usuario"
+msgstr "Creado por usuario"
 
 msgctxt "field:sale.sale,currency:"
 msgid "Currency"
@@ -376,7 +376,7 @@ msgstr "Moneda"
 
 msgctxt "field:sale.sale,currency_digits:"
 msgid "Currency Digits"
-msgstr "Decimales de Moneda"
+msgstr "Decimales de moneda"
 
 msgctxt "field:sale.sale,description:"
 msgid "Description"
@@ -388,15 +388,15 @@ msgstr "ID"
 
 msgctxt "field:sale.sale,invoice_address:"
 msgid "Invoice Address"
-msgstr "Dirección de Facturación"
+msgstr "Dirección de facturación"
 
 msgctxt "field:sale.sale,invoice_method:"
 msgid "Invoice Method"
-msgstr "Método de Facturación"
+msgstr "Método de facturación"
 
 msgctxt "field:sale.sale,invoice_state:"
 msgid "Invoice State"
-msgstr "Estado de Factura"
+msgstr "Estado de factura"
 
 msgctxt "field:sale.sale,invoices:"
 msgid "Invoices"
@@ -404,11 +404,11 @@ msgstr "Facturas"
 
 msgctxt "field:sale.sale,invoices_ignored:"
 msgid "Ignored Invoices"
-msgstr "Facturas Ignoradas"
+msgstr "Facturas ignoradas"
 
 msgctxt "field:sale.sale,invoices_recreated:"
 msgid "Recreated Invoices"
-msgstr "Facturas Recreadas"
+msgstr "Facturas recreadas"
 
 msgctxt "field:sale.sale,lines:"
 msgid "Lines"
@@ -418,17 +418,21 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr "Movimientos"
 
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr "Origen"
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr "Tercero"
 
 msgctxt "field:sale.sale,party_lang:"
 msgid "Party Language"
-msgstr "Idioma del Tercero"
+msgstr "Idioma del tercero"
 
 msgctxt "field:sale.sale,payment_term:"
 msgid "Payment Term"
-msgstr "Plazo de Pago"
+msgstr "Término de pago"
 
 msgctxt "field:sale.sale,rec_name:"
 msgid "Name"
@@ -440,23 +444,23 @@ msgstr "Referencia"
 
 msgctxt "field:sale.sale,sale_date:"
 msgid "Sale Date"
-msgstr "Fecha de Venta"
+msgstr "Fecha de venta"
 
 msgctxt "field:sale.sale,shipment_address:"
 msgid "Shipment Address"
-msgstr "Dirección de Envío"
+msgstr "Dirección de envío"
 
 msgctxt "field:sale.sale,shipment_method:"
 msgid "Shipment Method"
-msgstr "Método de Envío"
+msgstr "Método de envío"
 
 msgctxt "field:sale.sale,shipment_returns:"
 msgid "Shipment Returns"
-msgstr "Devolución de Envío"
+msgstr "Devolución de envío"
 
 msgctxt "field:sale.sale,shipment_state:"
 msgid "Shipment State"
-msgstr "Estado de Envío"
+msgstr "Estado de envío"
 
 msgctxt "field:sale.sale,shipments:"
 msgid "Shipments"
@@ -472,7 +476,7 @@ msgstr "Impuesto"
 
 msgctxt "field:sale.sale,tax_amount_cache:"
 msgid "Tax Cache"
-msgstr "Impuestos Precalculado"
+msgstr "Impuestos precalculado"
 
 msgctxt "field:sale.sale,total_amount:"
 msgid "Total"
@@ -484,11 +488,11 @@ msgstr "Total Impuestos"
 
 msgctxt "field:sale.sale,untaxed_amount:"
 msgid "Untaxed"
-msgstr "Base Sin Impuesto"
+msgstr "Base sin impuesto"
 
 msgctxt "field:sale.sale,untaxed_amount_cache:"
 msgid "Untaxed Cache"
-msgstr "Base Sin Impuesto Precalculada"
+msgstr "Base sin impuesto precalculada"
 
 msgctxt "field:sale.sale,warehouse:"
 msgid "Warehouse"
@@ -496,19 +500,19 @@ msgstr "Depósito"
 
 msgctxt "field:sale.sale,write_date:"
 msgid "Write Date"
-msgstr "Fecha de Modificación"
+msgstr "Fecha de modificación"
 
 msgctxt "field:sale.sale,write_uid:"
 msgid "Write User"
-msgstr "Modificado por Usuario"
+msgstr "Modificado por usuario"
 
 msgctxt "field:sale.sale-ignored-account.invoice,create_date:"
 msgid "Create Date"
-msgstr "Fecha de Creación"
+msgstr "Fecha de creación"
 
 msgctxt "field:sale.sale-ignored-account.invoice,create_uid:"
 msgid "Create User"
-msgstr "Creado por Usuario"
+msgstr "Creado por usuario"
 
 msgctxt "field:sale.sale-ignored-account.invoice,id:"
 msgid "ID"
@@ -528,19 +532,19 @@ msgstr "Venta"
 
 msgctxt "field:sale.sale-ignored-account.invoice,write_date:"
 msgid "Write Date"
-msgstr "Fecha de Modificación"
+msgstr "Fecha de modificación"
 
 msgctxt "field:sale.sale-ignored-account.invoice,write_uid:"
 msgid "Write User"
-msgstr "Modificado por Usuario"
+msgstr "Modificado por usuario"
 
 msgctxt "field:sale.sale-recreated-account.invoice,create_date:"
 msgid "Create Date"
-msgstr "Fecha de Creación"
+msgstr "Fecha de creación"
 
 msgctxt "field:sale.sale-recreated-account.invoice,create_uid:"
 msgid "Create User"
-msgstr "Creado por Usuario"
+msgstr "Creado por creación"
 
 msgctxt "field:sale.sale-recreated-account.invoice,id:"
 msgid "ID"
@@ -560,11 +564,11 @@ msgstr "Venta"
 
 msgctxt "field:sale.sale-recreated-account.invoice,write_date:"
 msgid "Write Date"
-msgstr "Fecha de Modificación"
+msgstr "Fecha de modificación"
 
 msgctxt "field:sale.sale-recreated-account.invoice,write_uid:"
 msgid "Write User"
-msgstr "Modificado por Usuario"
+msgstr "Modificado por usuario"
 
 msgctxt "field:stock.move,sale:"
 msgid "Sale"
@@ -572,7 +576,7 @@ msgstr "Venta"
 
 msgctxt "field:stock.move,sale_exception_state:"
 msgid "Exception State"
-msgstr "Estado Excepción"
+msgstr "Estado de excepción"
 
 msgctxt "help:product.template,delivery_time:"
 msgid "In number of days"
@@ -598,7 +602,7 @@ msgstr "Devolución"
 
 msgctxt "model:ir.action,name:act_sale_configuration_form"
 msgid "Sales Configuration"
-msgstr "Configuración de Ventas"
+msgstr "Configuración de ventas"
 
 msgctxt "model:ir.action,name:act_sale_form"
 msgid "Sales"
@@ -626,15 +630,15 @@ msgstr "Venta"
 
 msgctxt "model:ir.action,name:wizard_invoice_handle_exception"
 msgid "Handle Invoice Exception"
-msgstr "Gestionar Excepción de Factura"
+msgstr "Gestionar excepción de factura"
 
 msgctxt "model:ir.action,name:wizard_return_sale"
 msgid "Return Sale"
-msgstr "Crear Devolución de Venta"
+msgstr "Crear devolución de venta"
 
 msgctxt "model:ir.action,name:wizard_shipment_handle_exception"
 msgid "Handle Shipment Exception"
-msgstr "Gestionar Excepción de Envío"
+msgstr "Gestionar excepción de envío"
 
 msgctxt "model:ir.action.act_window.domain,name:act_sale_form_domain_all"
 msgid "All"
@@ -697,19 +701,19 @@ msgstr "Administrador de Ventas"
 
 msgctxt "model:sale.configuration,name:"
 msgid "Sale Configuration"
-msgstr "Configuración Ventas"
+msgstr "Configuración de ventas"
 
 msgctxt "model:sale.handle.invoice.exception.ask,name:"
 msgid "Handle Invoice Exception"
-msgstr "Gestionar Excepción de Factura"
+msgstr "Gestionar excepción de factura"
 
 msgctxt "model:sale.handle.shipment.exception.ask,name:"
 msgid "Handle Shipment Exception"
-msgstr "Gestionar Excepción de Envío"
+msgstr "Gestionar excepción de envío"
 
 msgctxt "model:sale.line,name:"
 msgid "Sale Line"
-msgstr "Línea de Venta"
+msgstr "Línea de venta"
 
 msgctxt "model:sale.line-account.tax,name:"
 msgid "Sale Line - Tax"
@@ -717,15 +721,15 @@ msgstr "Línea de Venta - Impuesto"
 
 msgctxt "model:sale.line-ignored-stock.move,name:"
 msgid "Sale Line - Ignored Move"
-msgstr "Línea de Venta - Movimiento Ignorado"
+msgstr "Línea de venta - Movimiento ignorado"
 
 msgctxt "model:sale.line-recreated-stock.move,name:"
 msgid "Sale Line - Recreated Move"
-msgstr "Línea de Venta - Movimiento Recreado"
+msgstr "Línea de venta - Movimiento recreado"
 
 msgctxt "model:sale.return_sale.start,name:"
 msgid "Return Sale"
-msgstr "Crear Devolución de Venta"
+msgstr "Crear devolución de venta"
 
 msgctxt "model:sale.sale,name:"
 msgid "Sale"
@@ -733,11 +737,11 @@ msgstr "Venta"
 
 msgctxt "model:sale.sale-ignored-account.invoice,name:"
 msgid "Sale - Ignored Invoice"
-msgstr "Venta - Factura Ignorada"
+msgstr "Venta - Factura ignorada"
 
 msgctxt "model:sale.sale-recreated-account.invoice,name:"
 msgid "Sale - Recreated Invoice"
-msgstr "Venta - Factura Recreada"
+msgstr "Venta - Factura recreada"
 
 msgctxt "odt:sale.sale:"
 msgid "Amount"
@@ -757,7 +761,7 @@ msgstr "Descripción:"
 
 msgctxt "odt:sale.sale:"
 msgid "Draft Sale Order"
-msgstr "Pedido de Venta en Borrador"
+msgstr "Pedido de venta en borrador"
 
 msgctxt "odt:sale.sale:"
 msgid "E-Mail:"
@@ -777,7 +781,7 @@ msgstr "Cotización Nº:"
 
 msgctxt "odt:sale.sale:"
 msgid "Sale Order N°:"
-msgstr "Orden de Venta Nº:"
+msgstr "Orden de venta Nº:"
 
 msgctxt "odt:sale.sale:"
 msgid "Taxes"
@@ -797,7 +801,7 @@ msgstr "Total:"
 
 msgctxt "odt:sale.sale:"
 msgid "Unit Price"
-msgstr "Precio Unitario"
+msgstr "Precio unitario"
 
 msgctxt "odt:sale.sale:"
 msgid "VAT Number:"
@@ -813,7 +817,7 @@ msgstr ""
 
 msgctxt "selection:account.invoice,sale_exception_state:"
 msgid "Ignored"
-msgstr "Ignorado"
+msgstr "Ignorada"
 
 msgctxt "selection:account.invoice,sale_exception_state:"
 msgid "Recreated"
@@ -825,11 +829,11 @@ msgstr "Manual"
 
 msgctxt "selection:sale.configuration,sale_invoice_method:"
 msgid "On Order Processed"
-msgstr "Al Procesar Pedido"
+msgstr "Al procesar pedido"
 
 msgctxt "selection:sale.configuration,sale_invoice_method:"
 msgid "On Shipment Sent"
-msgstr "Al Enviar"
+msgstr "Al enviar"
 
 msgctxt "selection:sale.configuration,sale_shipment_method:"
 msgid "Manual"
@@ -837,11 +841,11 @@ msgstr "Manual"
 
 msgctxt "selection:sale.configuration,sale_shipment_method:"
 msgid "On Invoice Paid"
-msgstr "Al Pagar la Factura"
+msgstr "Al pagar la factura"
 
 msgctxt "selection:sale.configuration,sale_shipment_method:"
 msgid "On Order Processed"
-msgstr "Al Procesar Pedido"
+msgstr "Al procesar el pedido"
 
 msgctxt "selection:sale.line,type:"
 msgid "Comment"
@@ -865,11 +869,11 @@ msgstr "Manual"
 
 msgctxt "selection:sale.sale,invoice_method:"
 msgid "On Order Processed"
-msgstr "Al Procesar el Pedido"
+msgstr "Al procesar el pedido"
 
 msgctxt "selection:sale.sale,invoice_method:"
 msgid "On Shipment Sent"
-msgstr "Al Enviar"
+msgstr "Al enviar"
 
 msgctxt "selection:sale.sale,invoice_state:"
 msgid "Exception"
@@ -893,11 +897,11 @@ msgstr "Manual"
 
 msgctxt "selection:sale.sale,shipment_method:"
 msgid "On Invoice Paid"
-msgstr "Al Pagar la Factura"
+msgstr "Al pagar la factura"
 
 msgctxt "selection:sale.sale,shipment_method:"
 msgid "On Order Processed"
-msgstr "Al Procesar Pedido"
+msgstr "Al procesar el pedido"
 
 msgctxt "selection:sale.sale,shipment_state:"
 msgid "Exception"
@@ -913,7 +917,7 @@ msgstr "Enviada"
 
 msgctxt "selection:sale.sale,shipment_state:"
 msgid "Waiting"
-msgstr "En Espera"
+msgstr "En espera"
 
 msgctxt "selection:sale.sale,state:"
 msgid "Canceled"
@@ -933,7 +937,7 @@ msgstr "Borrador"
 
 msgctxt "selection:sale.sale,state:"
 msgid "Processing"
-msgstr "En Proceso"
+msgstr "En proceso"
 
 msgctxt "selection:sale.sale,state:"
 msgid "Quotation"
@@ -945,11 +949,11 @@ msgstr ""
 
 msgctxt "selection:stock.move,sale_exception_state:"
 msgid "Ignored"
-msgstr "Ignorado"
+msgstr "Ignorada"
 
 msgctxt "selection:stock.move,sale_exception_state:"
 msgid "Recreated"
-msgstr "Recreado"
+msgstr "Recreada"
 
 msgctxt "view:party.party:"
 msgid "Sale"
@@ -965,7 +969,7 @@ msgstr "Clientes"
 
 msgctxt "view:sale.configuration:"
 msgid "Sale Configuration"
-msgstr "Configuración de Venta"
+msgstr "Configuración de venta"
 
 msgctxt "view:sale.handle.invoice.exception.ask:"
 msgid "Choose invoices to recreate"
@@ -973,7 +977,7 @@ msgstr "Seleccione las facturas a recrear"
 
 msgctxt "view:sale.handle.invoice.exception.ask:"
 msgid "Handle Invoice Exception"
-msgstr "Gestionar Excepción de Factura"
+msgstr "Gestionar excepción de factura"
 
 msgctxt "view:sale.handle.shipment.exception.ask:"
 msgid "Choose move to recreate"
@@ -981,7 +985,7 @@ msgstr "Seleccione los movimientos a recrear"
 
 msgctxt "view:sale.handle.shipment.exception.ask:"
 msgid "Handle shipment Exception"
-msgstr "Gestionar Excepción de Envío"
+msgstr "Gestionar excepción de envío"
 
 msgctxt "view:sale.line:"
 msgid "General"
@@ -993,11 +997,15 @@ msgstr "Notas"
 
 msgctxt "view:sale.line:"
 msgid "Sale Line"
-msgstr "Línea de Venta"
+msgstr "Línea de venta"
 
 msgctxt "view:sale.line:"
 msgid "Sale Lines"
-msgstr "Líneas de Venta"
+msgstr "Líneas de venta"
+
+msgctxt "view:sale.line:"
+msgid "Taxes"
+msgstr "Impuestos"
 
 msgctxt "view:sale.return_sale.start:"
 msgid "Are you sure to return those/this sale(s)?"
@@ -1005,7 +1013,7 @@ msgstr "¿Está seguro que desea devolver esta(s) venta(s)?"
 
 msgctxt "view:sale.return_sale.start:"
 msgid "Return Sale"
-msgstr "Crear Devolución de Venta"
+msgstr "Crear devolución de venta"
 
 msgctxt "view:sale.sale:"
 msgid "Cancel"
@@ -1021,11 +1029,11 @@ msgstr "Borrador"
 
 msgctxt "view:sale.sale:"
 msgid "Handle Invoice Exception"
-msgstr "Gestionar Excepción de Factura"
+msgstr "Gestionar excepción de factura"
 
 msgctxt "view:sale.sale:"
 msgid "Handle Shipment Exception"
-msgstr "Gestionar Excepción de Envío"
+msgstr "Gestionar excepción de envío"
 
 msgctxt "view:sale.sale:"
 msgid "Invoices"
@@ -1033,7 +1041,7 @@ msgstr "Facturas"
 
 msgctxt "view:sale.sale:"
 msgid "Other Info"
-msgstr "Información Adicional"
+msgstr "Información adicional"
 
 msgctxt "view:sale.sale:"
 msgid "Process"
@@ -1064,7 +1072,7 @@ msgid "Cancel"
 msgstr "Cancelar"
 
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Aceptar"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,end:"
@@ -1072,7 +1080,7 @@ msgid "Cancel"
 msgstr "Cancelar"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Aceptar"
 
 msgctxt "wizard_button:sale.return_sale,start,end:"
diff --git a/locale/es_ES.po b/locale/es_ES.po
index 6e5724c..3f93637 100644
--- a/locale/es_ES.po
+++ b/locale/es_ES.po
@@ -9,7 +9,8 @@ msgstr "No puede restaurar a borrador una factura generada por una venta."
 msgctxt "error:sale.line:"
 msgid "Product \"%(product)s\" of sale %(sale)s misses a revenue account."
 msgstr ""
-"Falta la cuenta a cobrar del producto \"%(product)s\" de la venta %(sale)s."
+"Falta la cuenta de ingresos del producto \"%(product)s\" de la venta "
+"%(sale)s."
 
 msgctxt "error:sale.line:"
 msgid "Sale \"%(sale)s\" is missing the customer location in line \"%(line)s\"."
@@ -19,7 +20,9 @@ msgstr ""
 
 msgctxt "error:sale.line:"
 msgid "Sale \"%(sale)s\" misses an \"account revenue\" default property."
-msgstr "Falta la propiedad \"Cuenta a cobrar\" por defecto de las ventas."
+msgstr ""
+"Falta la propiedad \"Cuenta de ingresos\" por defecto en la venta "
+"\"%(sale)s\"."
 
 msgctxt "error:sale.sale:"
 msgid "Invalid combination of shipment and invoicing methods on sale \"%s\"."
@@ -169,7 +172,7 @@ msgstr "Líneas de factura"
 
 msgctxt "field:sale.line,move_done:"
 msgid "Moves Done"
-msgstr "Movimientos realizados"
+msgstr "Movimientos finalizados"
 
 msgctxt "field:sale.line,move_exception:"
 msgid "Moves Exception"
@@ -415,6 +418,10 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr "Movimientos"
 
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr "Origen"
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr "Tercero"
@@ -640,7 +647,7 @@ msgstr "Todo"
 msgctxt ""
 "model:ir.action.act_window.domain,name:act_sale_form_domain_confirmed"
 msgid "Confirmed"
-msgstr "Confirmado"
+msgstr "Confirmada"
 
 msgctxt "model:ir.action.act_window.domain,name:act_sale_form_domain_draft"
 msgid "Draft"
@@ -922,7 +929,7 @@ msgstr "Confirmada"
 
 msgctxt "selection:sale.sale,state:"
 msgid "Done"
-msgstr "Realizada"
+msgstr "Finalizada"
 
 msgctxt "selection:sale.sale,state:"
 msgid "Draft"
@@ -966,7 +973,7 @@ msgstr "Configuración de venta"
 
 msgctxt "view:sale.handle.invoice.exception.ask:"
 msgid "Choose invoices to recreate"
-msgstr "Seleccione facturas a recrear"
+msgstr "Seleccione las facturas a recrear"
 
 msgctxt "view:sale.handle.invoice.exception.ask:"
 msgid "Handle Invoice Exception"
@@ -974,7 +981,7 @@ msgstr "Gestionar excepción de factura"
 
 msgctxt "view:sale.handle.shipment.exception.ask:"
 msgid "Choose move to recreate"
-msgstr "Seleccione movimientos a recrear"
+msgstr "Seleccione los movimientos a recrear"
 
 msgctxt "view:sale.handle.shipment.exception.ask:"
 msgid "Handle shipment Exception"
@@ -996,6 +1003,10 @@ msgctxt "view:sale.line:"
 msgid "Sale Lines"
 msgstr "Líneas de venta"
 
+msgctxt "view:sale.line:"
+msgid "Taxes"
+msgstr "Impuestos"
+
 msgctxt "view:sale.return_sale.start:"
 msgid "Are you sure to return those/this sale(s)?"
 msgstr "¿Está seguro de devolver estos pedidos de venta?"
@@ -1061,7 +1072,7 @@ msgid "Cancel"
 msgstr "Cancelar"
 
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Aceptar"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,end:"
@@ -1069,7 +1080,7 @@ msgid "Cancel"
 msgstr "Cancelar"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Aceptar"
 
 msgctxt "wizard_button:sale.return_sale,start,end:"
diff --git a/locale/fr_FR.po b/locale/fr_FR.po
index 11629af..c15eb5e 100644
--- a/locale/fr_FR.po
+++ b/locale/fr_FR.po
@@ -39,7 +39,7 @@ msgstr ""
 
 msgctxt "error:sale.sale:"
 msgid "It misses an \"Account Receivable\" on the party \"%s\"."
-msgstr "Le compte à recevoir est manquant sur le tiers « %s »."
+msgstr "Le « compte client » est manquant sur le tiers « %s »."
 
 msgctxt "error:sale.sale:"
 msgid "Sale \"%s\" must be cancelled before deletion."
@@ -417,6 +417,10 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr "Mouvements"
 
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr "Origine"
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr "Tiers"
@@ -998,6 +1002,10 @@ msgctxt "view:sale.line:"
 msgid "Sale Lines"
 msgstr "Lignes de vente"
 
+msgctxt "view:sale.line:"
+msgid "Taxes"
+msgstr "Taxes"
+
 msgctxt "view:sale.return_sale.start:"
 msgid "Are you sure to return those/this sale(s)?"
 msgstr "Êtes-vous sûr de retourner ces/cette vente(s) ?"
@@ -1063,16 +1071,16 @@ msgid "Cancel"
 msgstr "Annuler"
 
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
-msgstr "Ok"
+msgid "OK"
+msgstr "OK"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,end:"
 msgid "Cancel"
 msgstr "Annuler"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
-msgstr "Ok"
+msgid "OK"
+msgstr "OK"
 
 msgctxt "wizard_button:sale.return_sale,start,end:"
 msgid "Cancel"
diff --git a/locale/nl_NL.po b/locale/nl_NL.po
index e638807..6a2d4ae 100644
--- a/locale/nl_NL.po
+++ b/locale/nl_NL.po
@@ -414,6 +414,10 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr "Boekingen"
 
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr ""
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr "Relatie"
@@ -1098,7 +1102,7 @@ msgstr "Annuleren"
 
 #, fuzzy
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Oké"
 
 #, fuzzy
@@ -1108,7 +1112,7 @@ msgstr "Annuleren"
 
 #, fuzzy
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Oké"
 
 #, fuzzy
diff --git a/locale/ru_RU.po b/locale/ru_RU.po
index 0e62430..d091623 100644
--- a/locale/ru_RU.po
+++ b/locale/ru_RU.po
@@ -415,6 +415,11 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr "Перемещения"
 
+#, fuzzy
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr "Первоисточник"
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr "Контрагент"
@@ -1067,7 +1072,7 @@ msgid "Cancel"
 msgstr "Отменить"
 
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Ок"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,end:"
@@ -1075,7 +1080,7 @@ msgid "Cancel"
 msgstr "Отменить"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "Ок"
 
 #, fuzzy
diff --git a/locale/sl_SI.po b/locale/sl_SI.po
index 1fb6359..b38384c 100644
--- a/locale/sl_SI.po
+++ b/locale/sl_SI.po
@@ -422,6 +422,10 @@ msgctxt "field:sale.sale,moves:"
 msgid "Moves"
 msgstr "Promet"
 
+msgctxt "field:sale.sale,origin:"
+msgid "Origin"
+msgstr "Poreklo"
+
 msgctxt "field:sale.sale,party:"
 msgid "Party"
 msgstr "Partner"
@@ -1002,6 +1006,10 @@ msgctxt "view:sale.line:"
 msgid "Sale Lines"
 msgstr "Prodajne postavke"
 
+msgctxt "view:sale.line:"
+msgid "Taxes"
+msgstr "Davki"
+
 msgctxt "view:sale.return_sale.start:"
 msgid "Are you sure to return those/this sale(s)?"
 msgstr "Ali res želite vrniti to/te prodajo/e?"
@@ -1067,7 +1075,7 @@ msgid "Cancel"
 msgstr "Prekliči"
 
 msgctxt "wizard_button:sale.handle.invoice.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "V redu"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,end:"
@@ -1075,7 +1083,7 @@ msgid "Cancel"
 msgstr "Prekliči"
 
 msgctxt "wizard_button:sale.handle.shipment.exception,ask,handle:"
-msgid "Ok"
+msgid "OK"
 msgstr "V redu"
 
 msgctxt "wizard_button:sale.return_sale,start,end:"
diff --git a/party.xml b/party.xml
index 67e6d3c..ffb8e70 100644
--- a/party.xml
+++ b/party.xml
@@ -6,7 +6,8 @@ this repository contains the full copyright notices and license terms. -->
         <record model="ir.action.act_window" id="act_sale_form2">
             <field name="name">Sales</field>
             <field name="res_model">sale.sale</field>
-            <field name="domain">[('party', 'in', Eval('active_ids'))]</field>
+            <field name="domain"
+                eval="[('party', 'in', Eval('active_ids'))]" pyson="1"/>
         </record>
         <record model="ir.action.keyword"
                 id="act_open_sale_keyword1">
diff --git a/product.py b/product.py
index 8cf9086..6452c2e 100644
--- a/product.py
+++ b/product.py
@@ -1,5 +1,5 @@
-#This file is part of Tryton.  The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
 import datetime
 
 from trytond.model import fields
@@ -54,18 +54,22 @@ class Template:
     @fields.depends('default_uom', 'sale_uom', 'salable')
     def on_change_default_uom(self):
         try:
-            changes = super(Template, self).on_change_default_uom()
+            super(Template, self).on_change_default_uom()
         except AttributeError:
-            changes = {}
+            pass
         if self.default_uom:
             if self.sale_uom:
-                if self.default_uom.category == self.sale_uom.category:
-                    changes['sale_uom'] = self.sale_uom.id
-                else:
-                    changes['sale_uom'] = self.default_uom.id
+                if self.default_uom.category != self.sale_uom.category:
+                    self.sale_uom = self.default_uom
             else:
-                changes['sale_uom'] = self.default_uom.id
-        return changes
+                self.sale_uom = self.default_uom
+
+    @classmethod
+    def view_attributes(cls):
+        return super(Template, cls).view_attributes() + [
+            ('//page[@id="customers"]', 'states', {
+                    'invisible': ~Eval('salable'),
+                    })]
 
 
 class Product:
diff --git a/sale.odt b/sale.odt
index 0a64610..c1c82ae 100644
Binary files a/sale.odt and b/sale.odt differ
diff --git a/sale.py b/sale.py
index 2a72dfd..f4dce4e 100644
--- a/sale.py
+++ b/sale.py
@@ -1,9 +1,10 @@
-#This file is part of Tryton.  The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
 from decimal import Decimal
 from itertools import groupby, chain
 from functools import partial
-from sql import Table
+
+from sql import Table, Null
 from sql.functions import Overlay, Position
 from sql.operators import Concat
 
@@ -16,6 +17,9 @@ from trytond.pyson import If, Eval, Bool, PYSONEncoder, Id
 from trytond.transaction import Transaction
 from trytond.pool import Pool, PoolMeta
 
+from trytond.modules.account.tax import TaxableMixin
+from trytond.modules.product import price_digits
+
 __all__ = ['Sale', 'SaleIgnoredInvoice', 'SaleRecreatedInvoice',
     'SaleLine', 'SaleLineTax', 'SaleLineIgnoredMove',
     'SaleLineRecreatedMove', 'SaleReport', 'OpenCustomer',
@@ -27,7 +31,7 @@ __metaclass__ = PoolMeta
 _ZERO = Decimal(0)
 
 
-class Sale(Workflow, ModelSQL, ModelView):
+class Sale(Workflow, ModelSQL, ModelView, TaxableMixin):
     'Sale'
     __name__ = 'sale.sale'
     _rec_name = 'reference'
@@ -91,8 +95,8 @@ class Sale(Workflow, ModelSQL, ModelView):
         depends=['state'])
     currency = fields.Many2One('currency.currency', 'Currency', required=True,
         states={
-            'readonly': (Eval('state') != 'draft') |
-                (Eval('lines', [0]) & Eval('currency', 0)),
+            'readonly': ((Eval('state') != 'draft')
+                | (Eval('lines', [0]) & Eval('currency', 0))),
             },
         depends=['state'])
     currency_digits = fields.Function(fields.Integer('Currency Digits'),
@@ -167,12 +171,19 @@ class Sale(Workflow, ModelSQL, ModelView):
         'get_shipment_returns', searcher='search_shipment_returns')
     moves = fields.Function(fields.One2Many('stock.move', None, 'Moves'),
         'get_moves')
+    origin = fields.Reference('Origin', selection='get_origin', select=True,
+        states={
+            'readonly': Eval('state') != 'draft',
+            },
+        depends=['state'])
 
     @classmethod
     def __setup__(cls):
         super(Sale, cls).__setup__()
-        cls._order.insert(0, ('sale_date', 'DESC'))
-        cls._order.insert(1, ('id', 'DESC'))
+        cls._order = [
+            ('sale_date', 'DESC'),
+            ('id', 'DESC'),
+            ]
         cls._error_messages.update({
                 'invalid_method': ('Invalid combination of shipment and '
                     'invoicing methods on sale "%s".'),
@@ -305,8 +316,8 @@ class Sale(Workflow, ModelSQL, ModelView):
                                 sale_line.id))
                         ).select(sql_table.id,
                             where=(sql_table.state == 'confirmed')
-                            & ((sale_line_invoice_line.id != None)
-                                | (move.id != None)))
+                            & ((sale_line_invoice_line.id != Null)
+                                | (move.id != Null)))
             cursor.execute(*sql_table.update(
                     columns=[sql_table.state],
                     values=['processing'],
@@ -375,32 +386,14 @@ class Sale(Workflow, ModelSQL, ModelView):
 
     @fields.depends('party', 'payment_term')
     def on_change_party(self):
-        invoice_address = None
-        shipment_address = None
-        payment_term = None
+        self.invoice_address = None
+        self.shipment_address = None
+        self.payment_term = self.default_payment_term()
         if self.party:
-            invoice_address = self.party.address_get(type='invoice')
-            shipment_address = self.party.address_get(type='delivery')
+            self.invoice_address = self.party.address_get(type='invoice')
+            self.shipment_address = self.party.address_get(type='delivery')
             if self.party.customer_payment_term:
-                payment_term = self.party.customer_payment_term
-
-        changes = {}
-        if invoice_address:
-            changes['invoice_address'] = invoice_address.id
-            changes['invoice_address.rec_name'] = invoice_address.rec_name
-        else:
-            changes['invoice_address'] = None
-        if shipment_address:
-            changes['shipment_address'] = shipment_address.id
-            changes['shipment_address.rec_name'] = shipment_address.rec_name
-        else:
-            changes['shipment_address'] = None
-        if payment_term:
-            changes['payment_term'] = payment_term.id
-            changes['payment_term.rec_name'] = payment_term.rec_name
-        else:
-            changes['payment_term'] = self.default_payment_term()
-        return changes
+                self.payment_term = self.party.customer_payment_term
 
     @fields.depends('currency')
     def on_change_with_currency_digits(self, name=None):
@@ -408,7 +401,7 @@ class Sale(Workflow, ModelSQL, ModelView):
             return self.currency.digits
         return 2
 
-    def get_tax_context(self):
+    def _get_tax_context(self):
         res = {}
         if self.party and self.party.lang:
             res['language'] = self.party.lang.code
@@ -423,92 +416,47 @@ class Sale(Workflow, ModelSQL, ModelView):
 
     @fields.depends('lines', 'currency', 'party')
     def on_change_lines(self):
-        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'),
-            'tax_amount': Decimal('0.0'),
-            'total_amount': Decimal('0.0'),
-            }
+        self.untaxed_amount = Decimal('0.0')
+        self.tax_amount = Decimal('0.0')
+        self.total_amount = Decimal('0.0')
 
+        taxes = {}
         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
-                changes['untaxed_amount'] += (getattr(line, 'amount', None)
-                    or Decimal(0))
-
-                with Transaction().set_context(context):
-                    tax_list = Tax.compute(getattr(line, 'taxes', []),
-                        getattr(line, 'unit_price', None) or Decimal('0.0'),
-                        getattr(line, 'quantity', None) or 0.0)
-                for tax in tax_list:
-                    key, val = Invoice._compute_tax(tax, 'out_invoice')
-                    if key not in taxes:
-                        taxes[key] = val['amount']
-                    else:
-                        taxes[key] += val['amount']
-                if config.tax_rounding == 'line':
-                    round_taxes()
-            if config.tax_rounding == 'document':
-                round_taxes()
-            changes['tax_amount'] = sum(taxes.itervalues(), Decimal('0.0'))
+                self.untaxed_amount += getattr(line, 'amount', None) or 0
+            taxes = self._get_taxes()
+            self.tax_amount = sum(v['amount'] for v in taxes.itervalues())
         if self.currency:
-            changes['untaxed_amount'] = self.currency.round(
-                changes['untaxed_amount'])
-            changes['tax_amount'] = self.currency.round(changes['tax_amount'])
-        changes['total_amount'] = (changes['untaxed_amount']
-            + changes['tax_amount'])
+            self.untaxed_amount = self.currency.round(self.untaxed_amount)
+            self.tax_amount = self.currency.round(self.tax_amount)
+        self.total_amount = self.untaxed_amount + self.tax_amount
         if self.currency:
-            changes['total_amount'] = self.currency.round(
-                changes['total_amount'])
-        return changes
-
-    def get_tax_amount(self):
-        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)
+            self.total_amount = self.currency.round(self.total_amount)
 
+    @property
+    def taxable_lines(self):
+        taxable_lines = []
+        # In case we're called from an on_change we have to use some sensible
+        # defaults
         for line in self.lines:
-            if line.type != 'line':
+            if getattr(line, 'type', None) != 'line':
                 continue
-            with Transaction().set_context(context):
-                tax_list = Tax.compute(line.taxes, line.unit_price,
-                    line.quantity)
-            for tax in tax_list:
-                key, val = Invoice._compute_tax(tax, 'out_invoice')
-                if key not in taxes:
-                    taxes[key] = val['amount']
-                else:
-                    taxes[key] += val['amount']
-            if config.tax_rounding == 'line':
-                round_taxes()
-        if config.tax_rounding == 'document':
-            round_taxes()
-        return sum(taxes.itervalues(), _ZERO)
+            taxable_lines.append(tuple())
+            for attribute, default_value in (
+                    ('taxes', []),
+                    ('unit_price', Decimal(0)),
+                    ('quantity', 0.0)):
+                value = getattr(line, attribute, None)
+                taxable_lines[-1] += (value
+                    if value is not None else default_value,)
+        return taxable_lines
+
+    @property
+    def tax_type(self):
+        return 'invoice'
+
+    def get_tax_amount(self):
+        return sum(v['amount'] for v in self._get_taxes().itervalues())
 
     @classmethod
     def get_amount(cls, sales, names):
@@ -645,6 +593,20 @@ class Sale(Workflow, ModelSQL, ModelView):
                     })
 
     @classmethod
+    def _get_origin(cls):
+        'Return list of Model names for origin Reference'
+        return ['sale.sale']
+
+    @classmethod
+    def get_origin(cls):
+        Model = Pool().get('ir.model')
+        models = cls._get_origin()
+        models = Model.search([
+                ('model', 'in', models),
+                ])
+        return [(None, '')] + [(m.model, m.name) for m in models]
+
+    @classmethod
     def validate(cls, sales):
         super(Sale, cls).validate(sales)
         for sale in sales:
@@ -667,13 +629,21 @@ class Sale(Workflow, ModelSQL, ModelView):
 
     @classmethod
     def search_rec_name(cls, name, clause):
+        if clause[1].startswith('!') or clause[1].startswith('not '):
+            bool_op = 'AND'
+        else:
+            bool_op = 'OR'
         names = clause[2].split(' - ', 1)
-        res = [('reference', clause[1], names[0])]
+        res = [bool_op, ('reference', clause[1], names[0])]
         if len(names) != 1 and names[1]:
             res.append(('party', clause[1], names[1]))
         return res
 
     @classmethod
+    def view_attributes(cls):
+        return [('//field[@name="comment"]', 'spell', Eval('party_lang'))]
+
+    @classmethod
     def copy(cls, sales, default=None):
         if default is None:
             default = {}
@@ -1029,7 +999,7 @@ class SaleLine(ModelSQL, ModelView):
     product_uom_category = fields.Function(
         fields.Many2One('product.uom.category', 'Product Uom Category'),
         'on_change_with_product_uom_category')
-    unit_price = fields.Numeric('Unit Price', digits=(16, 4),
+    unit_price = fields.Numeric('Unit Price', digits=price_digits,
         states={
             'invisible': Eval('type') != 'line',
             'required': Eval('type') == 'line',
@@ -1044,9 +1014,12 @@ class SaleLine(ModelSQL, ModelView):
     description = fields.Text('Description', size=None, required=True)
     note = fields.Text('Note')
     taxes = fields.Many2Many('sale.line-account.tax', 'line', 'tax', 'Taxes',
+        order=[('tax.sequence', 'ASC'), ('tax.id', 'ASC')],
         domain=[('parent', '=', None), ['OR',
                 ('group', '=', None),
                 ('group.kind', 'in', ['sale', 'both'])],
+                ('company', '=',
+                    Eval('_parent_sale', {}).get('company', -1)),
             ],
         states={
             'invisible': Eval('type') != 'line',
@@ -1111,7 +1084,7 @@ class SaleLine(ModelSQL, ModelView):
     @staticmethod
     def order_sequence(tables):
         table, _ = tables[None]
-        return [table.sequence == None, table.sequence]
+        return [table.sequence == Null, table.sequence]
 
     @staticmethod
     def default_type():
@@ -1176,6 +1149,7 @@ class SaleLine(ModelSQL, ModelView):
             context['uom'] = self.unit.id
         else:
             context['uom'] = self.product.sale_uom.id
+        context['taxes'] = [t.id for t in self.taxes]
         return context
 
     @fields.depends('product', 'unit', 'quantity', 'description',
@@ -1185,8 +1159,7 @@ class SaleLine(ModelSQL, ModelView):
         Product = Pool().get('product.product')
 
         if not self.product:
-            return {}
-        res = {}
+            return
 
         party = None
         party_context = {}
@@ -1195,71 +1168,70 @@ class SaleLine(ModelSQL, ModelView):
             if party.lang:
                 party_context['language'] = party.lang.code
 
-        category = self.product.sale_uom.category
-        if not self.unit or self.unit not in category.uoms:
-            res['unit'] = self.product.sale_uom.id
-            self.unit = self.product.sale_uom
-            res['unit.rec_name'] = self.product.sale_uom.rec_name
-            res['unit_digits'] = self.product.sale_uom.digits
-
-        with Transaction().set_context(self._get_context_sale_price()):
-            res['unit_price'] = Product.get_sale_price([self.product],
-                    self.quantity or 0)[self.product.id]
-            if res['unit_price']:
-                res['unit_price'] = res['unit_price'].quantize(
-                    Decimal(1) / 10 ** self.__class__.unit_price.digits[1])
-        res['taxes'] = []
+        # Set taxes before unit_price to have taxes in context of sale price
+        taxes = []
         pattern = self._get_tax_rule_pattern()
         for tax in self.product.customer_taxes_used:
             if party and party.customer_tax_rule:
                 tax_ids = party.customer_tax_rule.apply(tax, pattern)
                 if tax_ids:
-                    res['taxes'].extend(tax_ids)
+                    taxes.extend(tax_ids)
                 continue
-            res['taxes'].append(tax.id)
+            taxes.append(tax.id)
         if party and party.customer_tax_rule:
             tax_ids = party.customer_tax_rule.apply(None, pattern)
             if tax_ids:
-                res['taxes'].extend(tax_ids)
+                taxes.extend(tax_ids)
+        self.taxes = taxes
+
+        category = self.product.sale_uom.category
+        if not self.unit or self.unit not in category.uoms:
+            self.unit = self.product.sale_uom
+            self.unit_digits = self.product.sale_uom.digits
+
+        with Transaction().set_context(self._get_context_sale_price()):
+            self.unit_price = Product.get_sale_price([self.product],
+                    self.quantity or 0)[self.product.id]
+            if self.unit_price:
+                self.unit_price = self.unit_price.quantize(
+                    Decimal(1) / 10 ** self.__class__.unit_price.digits[1])
 
         if not self.description:
             with Transaction().set_context(party_context):
-                res['description'] = Product(self.product.id).rec_name
+                self.description = Product(self.product.id).rec_name
 
-        self.unit_price = res['unit_price']
         self.type = 'line'
-        res['amount'] = self.on_change_with_amount()
-        return res
+        self.amount = self.on_change_with_amount()
 
     @fields.depends('product')
     def on_change_with_product_uom_category(self, name=None):
         if self.product:
             return self.product.default_uom_category.id
 
-    @fields.depends('product', 'quantity', 'unit',
+    @fields.depends('product', 'quantity', 'unit', 'taxes',
         '_parent_sale.currency', '_parent_sale.party',
         '_parent_sale.sale_date')
     def on_change_quantity(self):
         Product = Pool().get('product.product')
 
         if not self.product:
-            return {}
-        res = {}
+            return
 
         with Transaction().set_context(
                 self._get_context_sale_price()):
-            res['unit_price'] = Product.get_sale_price([self.product],
+            self.unit_price = Product.get_sale_price([self.product],
                 self.quantity or 0)[self.product.id]
-            if res['unit_price']:
-                res['unit_price'] = res['unit_price'].quantize(
+            if self.unit_price:
+                self.unit_price = self.unit_price.quantize(
                     Decimal(1) / 10 ** self.__class__.unit_price.digits[1])
-        return res
 
-    @fields.depends('product', 'quantity', 'unit',
-        '_parent_sale.currency', '_parent_sale.party',
-        '_parent_sale.sale_date')
+    @fields.depends(methods=['quantity'])
     def on_change_unit(self):
-        return self.on_change_quantity()
+        self.on_change_quantity()
+
+    @fields.depends(methods=['quantity'])
+    def on_change_taxes(self):
+        self.on_change_quantity()
 
     @fields.depends('type', 'quantity', 'unit_price', 'unit',
         '_parent_sale.currency')
@@ -1365,8 +1337,15 @@ class SaleLine(ModelSQL, ModelView):
             if old_invoice_line.type != 'line':
                 continue
             if old_invoice_line.id not in skip_ids:
+                if old_invoice_line.invoice:
+                    old_invoice_type = old_invoice_line.invoice.type
+                else:
+                    old_invoice_type = old_invoice_line.invoice_type
+
+                sign = 1 if old_invoice_type == invoice_type else -1
+
                 quantity -= Uom.compute_qty(old_invoice_line.unit,
-                    old_invoice_line.quantity, self.unit)
+                    sign * old_invoice_line.quantity, self.unit)
 
         rounding = self.unit.rounding if self.unit else 0.01
         invoice_line.quantity = Uom.round(quantity, rounding)
@@ -1397,6 +1376,11 @@ class SaleLine(ModelSQL, ModelView):
         return [invoice_line]
 
     @classmethod
+    def view_attributes(cls):
+        return [('//field[@name="note"]|//field[@name="description"]',
+                'spell', Eval('_parent_sale', {}).get('party_lang'))]
+
+    @classmethod
     def copy(cls, lines, default=None):
         if default is None:
             default = {}
@@ -1566,7 +1550,7 @@ class HandleShipmentException(Wizard):
     ask = StateView('sale.handle.shipment.exception.ask',
         'sale.handle_shipment_exception_ask_view_form', [
             Button('Cancel', 'end', 'tryton-cancel'),
-            Button('Ok', 'handle', 'tryton-ok', default=True),
+            Button('OK', 'handle', 'tryton-ok', default=True),
             ])
     handle = StateTransition()
 
@@ -1622,7 +1606,7 @@ class HandleInvoiceExceptionAsk(ModelView):
         domain=[('id', 'in', Eval('domain_invoices'))],
         depends=['domain_invoices'],
         help='The selected invoices will be recreated. '
-            'The other ones will be ignored.')
+        'The other ones will be ignored.')
     domain_invoices = fields.Many2Many(
         'account.invoice', None, None, 'Domain Invoices')
 
@@ -1634,7 +1618,7 @@ class HandleInvoiceException(Wizard):
     ask = StateView('sale.handle.invoice.exception.ask',
         'sale.handle_invoice_exception_ask_view_form', [
             Button('Cancel', 'end', 'tryton-cancel'),
-            Button('Ok', 'handle', 'tryton-ok', default=True),
+            Button('OK', 'handle', 'tryton-ok', default=True),
             ])
     handle = StateTransition()
 
@@ -1698,11 +1682,14 @@ class ReturnSale(Wizard):
 
         sales = Sale.browse(Transaction().context['active_ids'])
         return_sales = Sale.copy(sales)
-        for sale in return_sales:
-            for line in sale.lines:
+        for return_sale, sale in zip(return_sales, sales):
+            return_sale.origin = sale
+            for line in return_sale.lines:
                 if line.type == 'line':
                     line.quantity *= -1
-                    line.save()
+            return_sale.lines = return_sale.lines  # Force saving
+        Sale.save(return_sales)
+
         data = {'res_id': [s.id for s in return_sales]}
         if len(return_sales) == 1:
             action['views'].reverse()
diff --git a/sale.xml b/sale.xml
index 41237b4..4f6e9e9 100644
--- a/sale.xml
+++ b/sale.xml
@@ -71,7 +71,9 @@ this repository contains the full copyright notices and license terms. -->
         <record model="ir.action.act_window" id="act_shipment_form">
             <field name="name">Shipments</field>
             <field name="res_model">stock.shipment.out</field>
-            <field name="domain">[('moves.sale', 'in', Eval('active_ids'))]</field>
+            <field name="domain"
+                eval="[('moves.sale', 'in', Eval('active_ids'))]"
+                pyson="1"/>
         </record>
         <record model="ir.action.keyword"
                 id="act_open_shipment_keyword1">
@@ -82,7 +84,9 @@ this repository contains the full copyright notices and license terms. -->
         <record model="ir.action.act_window" id="act_return_form">
             <field name="name">Returns</field>
             <field name="res_model">stock.shipment.out.return</field>
-            <field name="domain">[('moves.sale', 'in', Eval('active_ids'))]</field>
+            <field name="domain"
+                eval="[('moves.sale', 'in', Eval('active_ids'))]"
+                pyson="1"/>
         </record>
         <record model="ir.action.keyword" id="act_open_shipment_return_keyword1">
             <field name="keyword">form_relate</field>
@@ -92,7 +96,9 @@ this repository contains the full copyright notices and license terms. -->
         <record model="ir.action.act_window" id="act_invoice_form">
             <field name="name">Invoices</field>
             <field name="res_model">account.invoice</field>
-            <field name="domain">[('lines.origin.sale.id', 'in', Eval('active_ids'), 'sale.line')]</field>
+            <field name="domain"
+                eval="[('lines.origin.sale.id', 'in', Eval('active_ids'), 'sale.line')]"
+                pyson="1"/>
         </record>
         <record model="ir.action.keyword"
                 id="act_open_invoice_keyword1">
@@ -119,25 +125,33 @@ this repository contains the full copyright notices and license terms. -->
         <record model="ir.action.act_window.domain" id="act_sale_form_domain_draft">
             <field name="name">Draft</field>
             <field name="sequence" eval="10"/>
-            <field name="domain">[('state', '=', 'draft')]</field>
+            <field name="domain"
+                eval="[('state', '=', 'draft')]"
+                pyson="1"/>
             <field name="act_window" ref="act_sale_form"/>
         </record>
         <record model="ir.action.act_window.domain" id="act_sale_form_domain_quotation">
             <field name="name">Quotation</field>
             <field name="sequence" eval="20"/>
-            <field name="domain">[('state', '=', 'quotation')]</field>
+            <field name="domain"
+                eval="[('state', '=', 'quotation')]"
+                pyson="1"/>
             <field name="act_window" ref="act_sale_form"/>
         </record>
         <record model="ir.action.act_window.domain" id="act_sale_form_domain_confirmed">
             <field name="name">Confirmed</field>
             <field name="sequence" eval="30"/>
-            <field name="domain">[('state', '=', 'confirmed')]</field>
+            <field name="domain"
+                eval="[('state', '=', 'confirmed')]"
+                pyson="1"/>
             <field name="act_window" ref="act_sale_form"/>
         </record>
         <record model="ir.action.act_window.domain" id="act_sale_form_domain_processing">
             <field name="name">Processing</field>
             <field name="sequence" eval="40"/>
-            <field name="domain">[('state', '=', 'processing')]</field>
+            <field name="domain"
+                eval="[('state', '=', 'processing')]"
+                pyson="1"/>
             <field name="act_window" ref="act_sale_form"/>
         </record>
         <record model="ir.action.act_window.domain" id="act_sale_form_domain_all">
@@ -157,7 +171,9 @@ this repository contains the full copyright notices and license terms. -->
         <record model="ir.action.act_window" id="act_sale_invoice_relate">
             <field name="name">Sales</field>
             <field name="res_model">sale.sale</field>
-            <field name="domain">[('invoices', 'in', Eval('active_ids'))]</field>
+            <field name="domain"
+                eval="[('invoices', 'in', Eval('active_ids'))]"
+                pyson="1"/>
         </record>
         <record model="ir.action.act_window.view"
             id="act_sale_invoice_relate_view1">
@@ -181,7 +197,9 @@ this repository contains the full copyright notices and license terms. -->
         <record model="ir.action.act_window" id="act_sale_shipments_relate">
             <field name="name">Sales</field>
             <field name="res_model">sale.sale</field>
-            <field name="domain">[('shipments', 'in', Eval('active_ids'))]</field>
+            <field name="domain"
+                eval="[('shipments', 'in', Eval('active_ids'))]"
+                pyson="1"/>
         </record>
         <record model="ir.action.act_window.view"
             id="act_sale_shipments_relate_view1">
@@ -380,7 +398,9 @@ this repository contains the full copyright notices and license terms. -->
             <field name="global_p" eval="True"/>
         </record>
         <record model="ir.rule" id="rule_sale1">
-            <field name="domain">[('company', '=', user.company.id if user.company else None)]</field>
+            <field name="domain"
+                eval="[('company', '=', Eval('user', {}).get('company', None))]"
+                pyson="1"/>
             <field name="rule_group" ref="rule_group_sale"/>
         </record>
 
diff --git a/setup.py b/setup.py
index b6bddfd..554f434 100644
--- a/setup.py
+++ b/setup.py
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
-#This file is part of Tryton.  The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
 
 from setuptools import setup
 import re
@@ -41,7 +41,7 @@ if minor_version % 2:
         'hg+http://hg.tryton.org/modules/%s#egg=%s-%s' % (
             name[8:], name, version))
 
-requires = ['python-sql']
+requires = ['python-sql >= 0.4']
 for dep in info.get('depends', []):
     if not re.match(r'(ir|res|webdav)(\W|$)', dep):
         requires.append(get_require_version('trytond_%s' % dep))
@@ -92,6 +92,8 @@ setup(name=name,
         'Natural Language :: Spanish',
         'Operating System :: OS Independent',
         'Programming Language :: Python :: 2.7',
+        'Programming Language :: Python :: Implementation :: CPython',
+        'Programming Language :: Python :: Implementation :: PyPy',
         'Topic :: Office/Business',
         'Topic :: Office/Business :: Financial :: Accounting',
         ],
diff --git a/stock.py b/stock.py
index 3226e32..bc291ea 100644
--- a/stock.py
+++ b/stock.py
@@ -1,5 +1,6 @@
-#This file is part of Tryton.  The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
+from sql import Null
 from sql.operators import Concat
 
 from trytond.model import Workflow, ModelView, fields
@@ -18,9 +19,9 @@ class ShipmentOut:
     def __setup__(cls):
         super(ShipmentOut, cls).__setup__()
         cls._error_messages.update({
-                'reset_move': 'You cannot reset to draft a move generated '
-                    'by a sale.',
-            })
+                'reset_move': ('You cannot reset to draft a move generated '
+                    'by a sale.'),
+                })
 
     @classmethod
     def write(cls, *args):
@@ -68,9 +69,9 @@ class ShipmentOutReturn:
     def __setup__(cls):
         super(ShipmentOutReturn, cls).__setup__()
         cls._error_messages.update({
-                'reset_move': 'You cannot reset to draft a move generated '
-                    'by a sale.',
-            })
+                'reset_move': ('You cannot reset to draft a move generated '
+                    'by a sale.'),
+                })
 
     @classmethod
     def write(cls, *args):
@@ -140,7 +141,7 @@ class Move:
             cursor.execute(*sql_table.update(
                     columns=[sql_table.origin],
                     values=[Concat('sale.line,', sql_table.sale_line)],
-                    where=sql_table.sale_line != None))
+                    where=sql_table.sale_line != Null))
             table.drop_column('sale_line')
 
     @classmethod
diff --git a/tests/__init__.py b/tests/__init__.py
index 479d61c..daf50d7 100644
--- a/tests/__init__.py
+++ b/tests/__init__.py
@@ -1,5 +1,5 @@
-#This file is part of Tryton.  The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
 
 from .test_sale import suite
 
diff --git a/tests/scenario_sale.rst b/tests/scenario_sale.rst
index d459bba..711b9ed 100644
--- a/tests/scenario_sale.rst
+++ b/tests/scenario_sale.rst
@@ -8,7 +8,13 @@ Imports::
     >>> from dateutil.relativedelta import relativedelta
     >>> from decimal import Decimal
     >>> from operator import attrgetter
-    >>> from proteus import config, Model, Wizard
+    >>> from proteus import config, Model, Wizard, Report
+    >>> from trytond.modules.company.tests.tools import create_company, \
+    ...     get_company
+    >>> from trytond.modules.account.tests.tools import create_fiscalyear, \
+    ...     create_chart, get_accounts, create_tax
+    >>> from.trytond.modules.account_invoice.tests.tools import \
+    ...     set_fiscalyear_invoice_sequences, create_payment_term
     >>> today = datetime.date.today()
 
 Create database::
@@ -20,34 +26,13 @@ Install sale::
 
     >>> Module = Model.get('ir.module.module')
     >>> sale_module, = Module.find([('name', '=', 'sale')])
-    >>> Module.install([sale_module.id], config.context)
+    >>> sale_module.click('install')
     >>> Wizard('ir.module.module.install_upgrade').execute('upgrade')
 
 Create company::
 
-    >>> Currency = Model.get('currency.currency')
-    >>> CurrencyRate = Model.get('currency.currency.rate')
-    >>> currencies = Currency.find([('code', '=', 'USD')])
-    >>> if not currencies:
-    ...     currency = Currency(name='U.S. Dollar', symbol='$', code='USD',
-    ...         rounding=Decimal('0.01'), mon_grouping='[3, 3, 0]',
-    ...         mon_decimal_point='.', mon_thousands_sep=',')
-    ...     currency.save()
-    ...     CurrencyRate(date=today + relativedelta(month=1, day=1),
-    ...         rate=Decimal('1.0'), currency=currency).save()
-    ... else:
-    ...     currency, = currencies
-    >>> Company = Model.get('company.company')
-    >>> Party = Model.get('party.party')
-    >>> company_config = Wizard('company.company.config')
-    >>> company_config.execute('company')
-    >>> company = company_config.form
-    >>> party = Party(name='Dunder Mifflin')
-    >>> party.save()
-    >>> company.party = party
-    >>> company.currency = currency
-    >>> company_config.execute('add')
-    >>> company, = Company.find([])
+    >>> _ = create_company()
+    >>> company = get_company()
 
 Reload the context::
 
@@ -87,67 +72,29 @@ Create account user::
 
 Create fiscal year::
 
-    >>> FiscalYear = Model.get('account.fiscalyear')
-    >>> Sequence = Model.get('ir.sequence')
-    >>> SequenceStrict = Model.get('ir.sequence.strict')
-    >>> fiscalyear = FiscalYear(name=str(today.year))
-    >>> fiscalyear.start_date = today + relativedelta(month=1, day=1)
-    >>> fiscalyear.end_date = today + relativedelta(month=12, day=31)
-    >>> fiscalyear.company = company
-    >>> post_move_seq = Sequence(name=str(today.year), code='account.move',
-    ...     company=company)
-    >>> post_move_seq.save()
-    >>> fiscalyear.post_move_sequence = post_move_seq
-    >>> invoice_seq = SequenceStrict(name=str(today.year),
-    ...     code='account.invoice', company=company)
-    >>> invoice_seq.save()
-    >>> fiscalyear.out_invoice_sequence = invoice_seq
-    >>> fiscalyear.in_invoice_sequence = invoice_seq
-    >>> fiscalyear.out_credit_note_sequence = invoice_seq
-    >>> fiscalyear.in_credit_note_sequence = invoice_seq
-    >>> fiscalyear.save()
-    >>> FiscalYear.create_period([fiscalyear.id], config.context)
+    >>> fiscalyear = set_fiscalyear_invoice_sequences(
+    ...     create_fiscalyear(company))
+    >>> fiscalyear.click('create_period')
 
 Create chart of accounts::
 
-    >>> AccountTemplate = Model.get('account.account.template')
-    >>> Account = Model.get('account.account')
+    >>> _ = create_chart(company)
+    >>> accounts = get_accounts(company)
+    >>> revenue = accounts['revenue']
+    >>> expense = accounts['expense']
+    >>> cash = accounts['cash']
+
     >>> Journal = Model.get('account.journal')
-    >>> account_template, = AccountTemplate.find([('parent', '=', None)])
-    >>> create_chart = Wizard('account.create_chart')
-    >>> create_chart.execute('account')
-    >>> create_chart.form.account_template = account_template
-    >>> create_chart.form.company = company
-    >>> create_chart.execute('create_account')
-    >>> receivable, = Account.find([
-    ...         ('kind', '=', 'receivable'),
-    ...         ('company', '=', company.id),
-    ...         ])
-    >>> payable, = Account.find([
-    ...         ('kind', '=', 'payable'),
-    ...         ('company', '=', company.id),
-    ...         ])
-    >>> revenue, = Account.find([
-    ...         ('kind', '=', 'revenue'),
-    ...         ('company', '=', company.id),
-    ...         ])
-    >>> expense, = Account.find([
-    ...         ('kind', '=', 'expense'),
-    ...         ('company', '=', company.id),
-    ...         ])
-    >>> create_chart.form.account_receivable = receivable
-    >>> create_chart.form.account_payable = payable
-    >>> create_chart.execute('create_properties')
-    >>> cash, = Account.find([
-    ...         ('kind', '=', 'other'),
-    ...         ('name', '=', 'Main Cash'),
-    ...         ('company', '=', company.id),
-    ...         ])
     >>> cash_journal, = Journal.find([('type', '=', 'cash')])
     >>> cash_journal.credit_account = cash
     >>> cash_journal.debit_account = cash
     >>> cash_journal.save()
 
+Create tax::
+
+    >>> tax = create_tax(Decimal('.10'))
+    >>> tax.save()
+
 Create parties::
 
     >>> Party = Model.get('party.party')
@@ -181,6 +128,7 @@ Create product::
     >>> template.cost_price_method = 'fixed'
     >>> template.account_expense = expense
     >>> template.account_revenue = revenue
+    >>> template.customer_taxes.append(tax)
     >>> template.save()
     >>> product.template = template
     >>> product.save()
@@ -202,31 +150,23 @@ Create product::
 
 Create payment term::
 
-    >>> PaymentTerm = Model.get('account.invoice.payment_term')
-    >>> PaymentTermLine = Model.get('account.invoice.payment_term.line')
-    >>> payment_term = PaymentTerm(name='Direct')
-    >>> payment_term_line = PaymentTermLine(type='remainder', days=0)
-    >>> payment_term.lines.append(payment_term_line)
+    >>> payment_term = create_payment_term()
     >>> payment_term.save()
 
 Create an Inventory::
 
     >>> config.user = stock_user.id
     >>> Inventory = Model.get('stock.inventory')
-    >>> InventoryLine = Model.get('stock.inventory.line')
     >>> Location = Model.get('stock.location')
     >>> storage, = Location.find([
     ...         ('code', '=', 'STO'),
     ...         ])
     >>> inventory = Inventory()
     >>> inventory.location = storage
-    >>> inventory.save()
-    >>> inventory_line = InventoryLine(product=product, inventory=inventory)
+    >>> inventory_line = inventory.lines.new(product=product)
     >>> inventory_line.quantity = 100.0
     >>> inventory_line.expected_quantity = 0.0
-    >>> inventory.save()
-    >>> inventory_line.save()
-    >>> Inventory.confirm([inventory.id], config.context)
+    >>> inventory.click('confirm')
     >>> inventory.state
     u'done'
 
@@ -251,13 +191,17 @@ Sale 5 products::
     >>> sale.lines.append(sale_line)
     >>> sale_line.product = product
     >>> sale_line.quantity = 3.0
-    >>> sale.save()
-    >>> Sale.quote([sale.id], config.context)
-    >>> Sale.confirm([sale.id], config.context)
-    >>> Sale.process([sale.id], config.context)
+    >>> sale.click('quote')
+    >>> sale.untaxed_amount, sale.tax_amount, sale.total_amount
+    (Decimal('50.00'), Decimal('5.00'), Decimal('55.00'))
+    >>> sale.click('confirm')
+    >>> sale.untaxed_amount, sale.tax_amount, sale.total_amount
+    (Decimal('50.00'), Decimal('5.00'), Decimal('55.00'))
+    >>> sale.click('process')
+    >>> sale.untaxed_amount, sale.tax_amount, sale.total_amount
+    (Decimal('50.00'), Decimal('5.00'), Decimal('55.00'))
     >>> sale.state
     u'processing'
-    >>> sale.reload()
     >>> len(sale.shipments), len(sale.shipment_returns), len(sale.invoices)
     (1, 0, 1)
     >>> invoice, = sale.invoices
@@ -287,12 +231,22 @@ Post invoice and check no new invoices::
 
     >>> config.user = account_user.id
     >>> Invoice = Model.get('account.invoice')
-    >>> Invoice.post([i.id for i in sale.invoices], config.context)
+    >>> for invoice in sale.invoices:
+    ...     invoice.click('post')
     >>> config.user = sale_user.id
     >>> sale.reload()
     >>> len(sale.shipments), len(sale.shipment_returns), len(sale.invoices)
     (1, 0, 1)
 
+Testing the report::
+
+    >>> sale_report = Report('sale.sale')
+    >>> ext, _, _, name = sale_report.execute([sale], {})
+    >>> ext
+    u'odt'
+    >>> name
+    u'Sale'
+
 Sale 5 products with an invoice method 'on shipment'::
 
     >>> config.user = sale_user.id
@@ -314,10 +268,9 @@ Sale 5 products with an invoice method 'on shipment'::
     >>> sale.lines.append(sale_line)
     >>> sale_line.product = product
     >>> sale_line.quantity = 3.0
-    >>> sale.save()
-    >>> Sale.quote([sale.id], config.context)
-    >>> Sale.confirm([sale.id], config.context)
-    >>> Sale.process([sale.id], config.context)
+    >>> sale.click('quote')
+    >>> sale.click('confirm')
+    >>> sale.click('process')
     >>> sale.state
     u'processing'
     >>> sale.reload()
@@ -337,11 +290,10 @@ Not yet linked to invoice lines::
 
 Validate Shipments::
 
-    >>> ShipmentOut = Model.get('stock.shipment.out')
-    >>> ShipmentOut.assign_try([shipment.id], config.context)
+    >>> shipment.click('assign_try')
     True
-    >>> ShipmentOut.pack([shipment.id], config.context)
-    >>> ShipmentOut.done([shipment.id], config.context)
+    >>> shipment.click('pack')
+    >>> shipment.click('done')
 
 Open customer invoice::
 
@@ -358,7 +310,7 @@ Open customer invoice::
     >>> for line in invoice.lines:
     ...     line.quantity = 1
     ...     line.save()
-    >>> Invoice.post([invoice.id], config.context)
+    >>> invoice.click('post')
 
 Invoice lines must be linked to each stock moves::
 
@@ -431,7 +383,7 @@ Stock moves must be linked to invoice line::
     >>> sale.reload()
     >>> shipment, = sale.shipments
     >>> config.user = stock_user.id
-    >>> shipment = ShipmentOut(shipment.id)
+    >>> shipment.reload()
     >>> stock_move, = shipment.outgoing_moves
     >>> stock_move.quantity
     4.0
@@ -481,10 +433,9 @@ Create a Return::
     >>> return_.lines.append(return_line)
     >>> return_line.type = 'comment'
     >>> return_line.description = 'Comment'
-    >>> return_.save()
-    >>> Sale.quote([return_.id], config.context)
-    >>> Sale.confirm([return_.id], config.context)
-    >>> Sale.process([return_.id], config.context)
+    >>> return_.click('quote')
+    >>> return_.click('confirm')
+    >>> return_.click('process')
     >>> return_.state
     u'processing'
     >>> return_.reload()
@@ -497,8 +448,7 @@ Check Return Shipments::
     >>> config.user = sale_user.id
     >>> ship_return, = return_.shipment_returns
     >>> config.user = stock_user.id
-    >>> ShipmentReturn = Model.get('stock.shipment.out.return')
-    >>> ShipmentReturn.receive([ship_return.id], config.context)
+    >>> ship_return.click('receive')
     >>> move_return, = ship_return.incoming_moves
     >>> move_return.product.rec_name
     u'product'
@@ -518,7 +468,7 @@ Open customer credit note::
     1
     >>> sum(l.quantity for l in credit_note.lines)
     4.0
-    >>> Invoice.post([credit_note.id], config.context)
+    >>> credit_note.click('post')
 
 Mixing return and sale::
 
@@ -539,10 +489,9 @@ Mixing return and sale::
     >>> mix.lines.append(mixline2)
     >>> mixline2.product = product
     >>> mixline2.quantity = -2.
-    >>> mix.save()
-    >>> Sale.quote([mix.id], config.context)
-    >>> Sale.confirm([mix.id], config.context)
-    >>> Sale.process([mix.id], config.context)
+    >>> mix.click('quote')
+    >>> mix.click('confirm')
+    >>> mix.click('process')
     >>> mix.state
     u'processing'
     >>> mix.reload()
@@ -552,20 +501,20 @@ Mixing return and sale::
 Checking Shipments::
 
     >>> config.user = sale_user.id
-    >>> mix_returns, = mix.shipment_returns
-    >>> mix_shipments, = mix.shipments
+    >>> mix_return, = mix.shipment_returns
+    >>> mix_shipment, = mix.shipments
     >>> config.user = stock_user.id
-    >>> ShipmentReturn.receive([mix_returns.id], config.context)
-    >>> move_return, = mix_returns.incoming_moves
+    >>> mix_return.click('receive')
+    >>> move_return, = mix_return.incoming_moves
     >>> move_return.product.rec_name
     u'product'
     >>> move_return.quantity
     2.0
-    >>> ShipmentOut.assign_try([mix_shipments.id], config.context)
+    >>> mix_shipment.click('assign_try')
     True
-    >>> ShipmentOut.pack([mix_shipments.id], config.context)
-    >>> ShipmentOut.done([mix_shipments.id], config.context)
-    >>> move_shipment, = mix_shipments.outgoing_moves
+    >>> mix_shipment.click('pack')
+    >>> mix_shipment.click('done')
+    >>> move_shipment, = mix_shipment.outgoing_moves
     >>> move_shipment.product.rec_name
     u'product'
     >>> move_shipment.quantity
@@ -588,8 +537,8 @@ Checking the invoice::
     7.0
     >>> sum(l.quantity for l in mix_credit_note.lines)
     2.0
-    >>> Invoice.post([mix_invoice.id], config.context)
-    >>> Invoice.post([mix_credit_note.id], config.context)
+    >>> mix_invoice.click('post')
+    >>> mix_credit_note.click('post')
 
 Mixing stuff with an invoice method 'on shipment'::
 
@@ -610,32 +559,30 @@ Mixing stuff with an invoice method 'on shipment'::
     >>> mix.lines.append(mixline2)
     >>> mixline2.product = product
     >>> mixline2.quantity = -3.
-    >>> mix.save()
-    >>> Sale.quote([mix.id], config.context)
-    >>> Sale.confirm([mix.id], config.context)
-    >>> Sale.process([mix.id], config.context)
+    >>> mix.click('quote')
+    >>> mix.click('confirm')
+    >>> mix.click('process')
     >>> mix.state
     u'processing'
-    >>> mix.reload()
     >>> len(mix.shipments), len(mix.shipment_returns), len(mix.invoices)
     (1, 1, 0)
 
 Checking Shipments::
 
     >>> config.user = sale_user.id
-    >>> mix_returns, = mix.shipment_returns
-    >>> mix_shipments, = mix.shipments
+    >>> mix_return, = mix.shipment_returns
+    >>> mix_shipment, = mix.shipments
     >>> config.user = stock_user.id
-    >>> ShipmentReturn.receive([mix_returns.id], config.context)
-    >>> move_return, = mix_returns.incoming_moves
+    >>> mix_return.click('receive')
+    >>> move_return, = mix_return.incoming_moves
     >>> move_return.product.rec_name
     u'product'
     >>> move_return.quantity
     3.0
-    >>> ShipmentOut.assign_try([mix_shipments.id], config.context)
+    >>> mix_shipment.click('assign_try')
     True
-    >>> ShipmentOut.pack([mix_shipments.id], config.context)
-    >>> move_shipment, = mix_shipments.outgoing_moves
+    >>> mix_shipment.click('pack')
+    >>> move_shipment, = mix_shipment.outgoing_moves
     >>> move_shipment.product.rec_name
     u'product'
     >>> move_shipment.quantity
@@ -702,6 +649,8 @@ Return sales using the wizard::
     >>> returned_sale, = Sale.find([
     ...     ('state', '=', 'draft'),
     ...     ])
+    >>> returned_sale.origin == sale_to_return
+    True
     >>> sorted([x.quantity for x in returned_sale.lines])
     [None, -1.0]
 
diff --git a/tests/test_sale.py b/tests/test_sale.py
index 87fd72f..54fd92c 100644
--- a/tests/test_sale.py
+++ b/tests/test_sale.py
@@ -1,25 +1,15 @@
-#This file is part of Tryton.  The COPYRIGHT file at the top level of
-#this repository contains the full copyright notices and license terms.
+# This file is part of Tryton.  The COPYRIGHT file at the top level of
+# this repository contains the full copyright notices and license terms.
 import unittest
 import doctest
 import trytond.tests.test_tryton
-from trytond.tests.test_tryton import test_view, test_depends
+from trytond.tests.test_tryton import ModuleTestCase
 from trytond.tests.test_tryton import doctest_setup, doctest_teardown
 
 
-class SaleTestCase(unittest.TestCase):
+class SaleTestCase(ModuleTestCase):
     'Test Sale module'
-
-    def setUp(self):
-        trytond.tests.test_tryton.install_module('sale')
-
-    def test0005views(self):
-        'Test views'
-        test_view('sale')
-
-    def test0006depends(self):
-        'Test depends'
-        test_depends()
+    module = 'sale'
 
 
 def suite():
diff --git a/tryton.cfg b/tryton.cfg
index f2faccb..0e9e427 100644
--- a/tryton.cfg
+++ b/tryton.cfg
@@ -1,5 +1,5 @@
 [tryton]
-version=3.4.1
+version=3.6.0
 depends:
     account
     account_invoice
diff --git a/trytond_sale.egg-info/PKG-INFO b/trytond_sale.egg-info/PKG-INFO
index e35f5b8..1d74e02 100644
--- a/trytond_sale.egg-info/PKG-INFO
+++ b/trytond_sale.egg-info/PKG-INFO
@@ -1,12 +1,12 @@
 Metadata-Version: 1.1
 Name: trytond-sale
-Version: 3.4.1
+Version: 3.6.0
 Summary: Tryton module for sale
 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.4/
+Download-URL: http://downloads.tryton.org/3.6/
 Description: trytond_sale
         ============
         
@@ -64,5 +64,7 @@ Classifier: Natural Language :: Slovenian
 Classifier: Natural Language :: Spanish
 Classifier: Operating System :: OS Independent
 Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
 Classifier: Topic :: Office/Business
 Classifier: Topic :: Office/Business :: Financial :: Accounting
diff --git a/trytond_sale.egg-info/requires.txt b/trytond_sale.egg-info/requires.txt
index 354776c..a18bded 100644
--- a/trytond_sale.egg-info/requires.txt
+++ b/trytond_sale.egg-info/requires.txt
@@ -1,11 +1,11 @@
-python-sql
-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
+python-sql >= 0.4
+trytond_account >= 3.6, < 3.7
+trytond_account_invoice >= 3.6, < 3.7
+trytond_account_invoice_stock >= 3.6, < 3.7
+trytond_account_product >= 3.6, < 3.7
+trytond_company >= 3.6, < 3.7
+trytond_currency >= 3.6, < 3.7
+trytond_party >= 3.6, < 3.7
+trytond_product >= 3.6, < 3.7
+trytond_stock >= 3.6, < 3.7
+trytond >= 3.6, < 3.7
\ No newline at end of file
diff --git a/view/sale_form.xml b/view/sale_form.xml
index 2f8d2dd..7a62fdb 100644
--- a/view/sale_form.xml
+++ b/view/sale_form.xml
@@ -24,7 +24,7 @@ this repository contains the full copyright notices and license terms. -->
             <field name="currency"/>
             <field name="lines" colspan="4"
                 view_ids="sale.sale_line_view_tree_sequence"/>
-            <group col="2" colspan="2" id="states">
+            <group col="2" colspan="2" id="states" yfill="1">
                 <label name="invoice_state"/>
                 <field name="invoice_state"/>
                 <label name="shipment_state"/>
@@ -32,7 +32,7 @@ this repository contains the full copyright notices and license terms. -->
                 <label name="state"/>
                 <field name="state"/>
             </group>
-            <group col="2" colspan="2" id="amount_buttons">
+            <group col="2" colspan="2" id="amount_buttons" yfill="1">
                 <label name="untaxed_amount" xalign="1.0" xexpand="1"/>
                 <field name="untaxed_amount" xalign="1.0" xexpand="0"/>
                 <label name="tax_amount" xalign="1.0" xexpand="1"/>
@@ -61,13 +61,14 @@ this repository contains the full copyright notices and license terms. -->
         <page string="Other Info" id="other">
             <label name="company"/>
             <field name="company"/>
-            <newline/>
+            <label name="origin"/>
+            <field name="origin"/>
             <label name="invoice_method"/>
             <field name="invoice_method"/>
             <label name="shipment_method"/>
             <field name="shipment_method"/>
             <separator name="comment" colspan="4"/>
-            <field name="comment" colspan="4" spell="Eval('party_lang')"/>
+            <field name="comment" colspan="4"/>
         </page>
         <page string="Invoices" id="invoices">
             <field name="invoices" colspan="4"/>
diff --git a/view/sale_line_form.xml b/view/sale_line_form.xml
index f0f9a35..949b1dc 100644
--- a/view/sale_line_form.xml
+++ b/view/sale_line_form.xml
@@ -4,19 +4,18 @@ this repository contains the full copyright notices and license terms. -->
 <form string="Sale Line" cursor="product">
     <label name="sale"/>
     <field name="sale" colspan="3"/>
+    <label name="type"/>
+    <field name="type"/>
+    <label name="sequence"/>
+    <field name="sequence"/>
     <notebook colspan="4">
         <page string="General" id="general">
-            <label name="type"/>
-            <field name="type"/>
-            <label name="sequence"/>
-            <field name="sequence"/>
             <label name="product"/>
             <field name="product"
                 view_ids="sale.product_view_list_sale_line"/>
             <newline/>
             <label name="description"/>
-            <field name="description" colspan="3"
-                spell="Get(Eval('_parent_sale', {}), 'party_lang')"/>
+            <field name="description" colspan="3" yexpand="0"/>
             <label name="quantity"/>
             <field name="quantity"/>
             <label name="unit"/>
@@ -27,13 +26,13 @@ this repository contains the full copyright notices and license terms. -->
             <field name="amount"/>
             <label name="delivery_date"/>
             <field name="delivery_date"/>
+        </page>
+        <page string="Taxes" id="taxes">
             <field name="taxes" colspan="4"/>
         </page>
         <page string="Notes" id="notes">
             <separator name="note" colspan="4"/>
-            <field name="note" colspan="4"
-                spell="Get(Eval('_parent_sale', {}), 'party_lang')"/>
+            <field name="note" colspan="4"/>
         </page>
     </notebook>
-    <field name="unit_digits" invisible="1" colspan="4"/>
 </form>
diff --git a/view/template_form.xml b/view/template_form.xml
index cd702ff..dde1d0a 100644
--- a/view/template_form.xml
+++ b/view/template_form.xml
@@ -8,9 +8,7 @@ this repository contains the full copyright notices and license terms. -->
         <field name="salable"/>
     </xpath>
     <xpath expr="/form/notebook/page[@id='general']" position="after">
-        <page string="Customers"
-            states="{'invisible': Not(Bool(Eval('salable')))}"
-            id="customers">
+        <page string="Customers" id="customers">
             <label name="salable"/>
             <field name="salable"/>
             <label name="sale_uom"/>
-- 
tryton-modules-sale



More information about the tryton-debian-vcs mailing list