Browse Source

Merge pull request #3 from Antiun/8.0-improve-pos-pricelist

[IMP] Show aggregated taxes detail in pos.order and when printing ticket
pull/39/head
Adil Houmadi 9 years ago
parent
commit
000655c123
  1. 80
      pos_pricelist/README.rst
  2. 4
      pos_pricelist/__openerp__.py
  3. 25
      pos_pricelist/data/pos_order.yml
  4. 141
      pos_pricelist/i18n/es.po
  5. 141
      pos_pricelist/i18n/pos_pricelist.pot
  6. 110
      pos_pricelist/models/point_of_sale.py
  7. 36
      pos_pricelist/report/report_receipt.xml
  8. 11
      pos_pricelist/views/point_of_sale_view.xml

80
pos_pricelist/README.rst

@ -1,3 +1,6 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
Dynamic Price for Odoo Point of Sale
====================================
@ -20,13 +23,31 @@ Goal of the module
The goal of this module is to bring the pricelist computation engine to the POS.
This module loads all the necessary data into the POS in order to have a coherent behaviour (offline/online/backend).
Implemented features
--------------------
Installation
============
Nothing special is needed to install this module.
Configuration
=============
You'll have new configuration parameters at Point of Sale > Configuration > Point of Sales
* Price with Taxes: Show prices with taxes in POS session or not
Usage
=====
Implemented features at POS Session
-----------------------------------
1. Attached pricelist on partner will take effect on the POS, which means that if we attach a pricelist to a partner.
The POS will recognize it and will compute the price according to the rule defined.
2. Fiscal Position of each partner will also be present so taxes will be correctly computed
2. Fiscal Position of each partner will also be present so taxes will be correctly computed
(conforming to the fiscal position).
- Implemented Rules are :
@ -44,7 +65,60 @@ The computation take in account the pricelist and the fiscal position of the cus
3x -> 70 €
5x -> 50 €
Implemented features at backend
-------------------------------
1. Tax details
- Tax details per order line
- Tax details aggregated by tax at order level
2. Ticket
- Tax details table added at end of printed ticket
Known issues / Roadmap
======================
Missing features
----------------
* As you may know, product template is not fully implemented in the POS, so I decided to drop it from this module.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/pos/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
`here <https://github.com/OCA/pos/issues/new?body=module:%20pos_pricelist%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Adil Houmadi <ah@taktik.be>
* Pablo Cayuela <pablo.cayuela@aserti.es>
* Antonio Espinosa <antonioea@antiun.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

4
pos_pricelist/__openerp__.py

@ -34,7 +34,9 @@ New feature for the Point Of Sale:
'data': [
"views/pos_pricelist_template.xml",
"views/pos_pricelist_views.xml",
"views/point_of_sale_view.xml"
"views/point_of_sale_view.xml",
"report/report_receipt.xml",
"data/pos_order.yml",
],
'demo': [
'demo/pos_pricelist_demo.yml',

25
pos_pricelist/data/pos_order.yml

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Python source code encoding : https://www.python.org/dev/peps/pep-0263/
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright :
# (c) 2015 Antiun Ingenieria, SL (Madrid, Spain, http://www.antiun.com)
# Antonio Espinosa <antonioea@antiun.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
- !function {model: pos.order, name: _install_tax_detail}

141
pos_pricelist/i18n/es.po

@ -0,0 +1,141 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * pos_pricelist
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-24 14:44+0000\n"
"PO-Revision-Date: 2015-07-24 14:44+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: pos_pricelist
#: field:pos.order.tax,amount:0
#: view:website:point_of_sale.report_receipt
msgid "Amount"
msgstr "Cuota"
#. module: pos_pricelist
#. openerp-web
#: code:addons/pos_pricelist/static/src/js/models.js:386
#, python-format
msgid "At least one pricelist has no active version ! Please create or activate one."
msgstr "¡Al menos una lista de precios no tiene ua versión activa! Por favor, cree o active una."
#. module: pos_pricelist
#: field:pos.order.tax,base:0
#: view:website:point_of_sale.report_receipt
msgid "Base"
msgstr "Base imponible"
#. module: pos_pricelist
#: field:pos.order.tax,create_uid:0
msgid "Created by"
msgstr "Creado por"
#. module: pos_pricelist
#: field:pos.order.tax,create_date:0
msgid "Created on"
msgstr "Creado en"
#. module: pos_pricelist
#: help:pos.config,display_price_with_taxes:0
msgid "Display Prices with taxes on POS"
msgstr "Mostrar los precios con impuestos incluidos en el TPV"
#. module: pos_pricelist
#: field:pos.order.tax,id:0
msgid "ID"
msgstr "ID"
#. module: pos_pricelist
#: field:pos.order.tax,write_uid:0
msgid "Last Updated by"
msgstr "Última actualización por"
#. module: pos_pricelist
#: field:pos.order.tax,write_date:0
msgid "Last Updated on"
msgstr "Última actualización en"
#. module: pos_pricelist
#: model:ir.model,name:pos_pricelist.model_pos_order_line
msgid "Lines of Point of Sale"
msgstr "Líneas del Terminal Punto de Venta"
#. module: pos_pricelist
#: field:pos.order.tax,pos_order:0
msgid "POS Order"
msgstr "Pedido"
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_1_product_template
msgid "POS Product 1"
msgstr "TPV Producto 1"
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_2_product_template
msgid "POS Product 2"
msgstr "TPV Producto 2"
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_3_product_template
msgid "POS Product 3"
msgstr "TPV Producto 3"
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_4_product_template
msgid "POS Product 4"
msgstr "TPV Producto 4"
#. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
msgid "Payments"
msgstr "Pagos"
#. module: pos_pricelist
#: model:ir.model,name:pos_pricelist.model_pos_order
msgid "Point of Sale"
msgstr "Terminal Punto de Venta"
#. module: pos_pricelist
#: field:pos.config,display_price_with_taxes:0
msgid "Price With Taxes"
msgstr "Precios con impuestos incluidos"
#. module: pos_pricelist
#. openerp-web
#: code:addons/pos_pricelist/static/src/js/models.js:385
#, python-format
msgid "Pricelist Error"
msgstr "Error en lista de precios"
#. module: pos_pricelist
#: field:pos.order.tax,tax:0
#: view:website:point_of_sale.report_receipt
msgid "Tax"
msgstr "Impuesto"
#. module: pos_pricelist
#: field:pos.order.tax,name:0
msgid "Tax Description"
msgstr "Descripción del impuesto"
#. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
#: field:pos.order,taxes:0
#: field:pos.order.line,tax_ids:0
msgid "Taxes"
msgstr "Impuestos"
#. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
msgid "Taxes detail"
msgstr "Detalle de impuestos"

141
pos_pricelist/i18n/pos_pricelist.pot

@ -0,0 +1,141 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * pos_pricelist
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-07-24 14:44+0000\n"
"PO-Revision-Date: 2015-07-24 14:44+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: pos_pricelist
#: field:pos.order.tax,amount:0
#: view:website:point_of_sale.report_receipt
msgid "Amount"
msgstr ""
#. module: pos_pricelist
#. openerp-web
#: code:addons/pos_pricelist/static/src/js/models.js:386
#, python-format
msgid "At least one pricelist has no active version ! Please create or activate one."
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,base:0
#: view:website:point_of_sale.report_receipt
msgid "Base"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,create_uid:0
msgid "Created by"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,create_date:0
msgid "Created on"
msgstr ""
#. module: pos_pricelist
#: help:pos.config,display_price_with_taxes:0
msgid "Display Prices with taxes on POS"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,id:0
msgid "ID"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,write_uid:0
msgid "Last Updated by"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,write_date:0
msgid "Last Updated on"
msgstr ""
#. module: pos_pricelist
#: model:ir.model,name:pos_pricelist.model_pos_order_line
msgid "Lines of Point of Sale"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,pos_order:0
msgid "POS Order"
msgstr ""
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_1_product_template
msgid "POS Product 1"
msgstr ""
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_2_product_template
msgid "POS Product 2"
msgstr ""
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_3_product_template
msgid "POS Product 3"
msgstr ""
#. module: pos_pricelist
#: model:product.template,name:pos_pricelist.pos_product_product_4_product_template
msgid "POS Product 4"
msgstr ""
#. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
msgid "Payments"
msgstr ""
#. module: pos_pricelist
#: model:ir.model,name:pos_pricelist.model_pos_order
msgid "Point of Sale"
msgstr ""
#. module: pos_pricelist
#: field:pos.config,display_price_with_taxes:0
msgid "Price With Taxes"
msgstr ""
#. module: pos_pricelist
#. openerp-web
#: code:addons/pos_pricelist/static/src/js/models.js:385
#, python-format
msgid "Pricelist Error"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,tax:0
#: view:website:point_of_sale.report_receipt
msgid "Tax"
msgstr ""
#. module: pos_pricelist
#: field:pos.order.tax,name:0
msgid "Tax Description"
msgstr ""
#. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
#: field:pos.order,taxes:0
#: field:pos.order.line,tax_ids:0
msgid "Taxes"
msgstr ""
#. module: pos_pricelist
#: view:pos.order:pos_pricelist.view_pos_pos_form
msgid "Taxes detail"
msgstr ""

110
pos_pricelist/models/point_of_sale.py

@ -20,19 +20,47 @@
from openerp import models, fields, api
from openerp.addons import decimal_precision as dp
import logging
_logger = logging.getLogger(__name__)
class PosOrderTax(models.Model):
_name = 'pos.order.tax'
pos_order = fields.Many2one('pos.order', string='POS Order',
ondelete='cascade', index=True)
tax = fields.Many2one('account.tax', string='Tax')
name = fields.Char(string='Tax Description', required=True)
base = fields.Float(string='Base', digits=dp.get_precision('Account'))
amount = fields.Float(string='Amount', digits=dp.get_precision('Account'))
class PosOrderLine(models.Model):
_inherit = "pos.order.line"
@api.multi
def _compute_taxes(self):
res = {
'total': 0,
'total_included': 0,
'taxes': [],
}
for line in self:
price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
taxes = line.tax_ids.compute_all(
price, line.qty, product=line.product_id,
partner=line.order_id.partner_id)
res['total'] += taxes['total']
res['total_included'] += taxes['total_included']
res['taxes'] += taxes['taxes']
return res
@api.one
@api.depends('tax_ids', 'qty', 'price_unit',
'product_id', 'discount', 'order_id.partner_id')
def _amount_line_all(self):
price = self.price_unit * (1 - (self.discount or 0.0) / 100.0)
taxes = self.tax_ids.compute_all(
price, self.qty, product=self.product_id,
partner=self.order_id.partner_id)
taxes = self._compute_taxes()
self.price_subtotal = taxes['total']
self.price_subtotal_incl = taxes['total_included']
@ -46,6 +74,9 @@ class PosOrderLine(models.Model):
class PosOrder(models.Model):
_inherit = "pos.order"
taxes = fields.One2many(comodel_name='pos.order.tax',
inverse_name='pos_order')
@api.model
def _amount_line_tax(self, line):
price = line.price_unit * (1 - (line.discount or 0.0) / 100.0)
@ -56,3 +87,74 @@ class PosOrder(models.Model):
for c in taxes:
val += c.get('amount', 0.0)
return val
@api.multi
def _tax_list_get(self):
agg_taxes = {}
tax_lines = []
for order in self:
for line in order.lines:
tax_lines.append({
'base': line.price_subtotal,
'taxes': line._compute_taxes()['taxes']
})
for tax_line in tax_lines:
base = tax_line['base']
for tax in tax_line['taxes']:
tax_id = str(tax['id'])
if tax_id in agg_taxes:
agg_taxes[tax_id]['base'] += base
agg_taxes[tax_id]['amount'] += tax['amount']
else:
agg_taxes[tax_id] = {
'tax_id': tax_id,
'name': tax['name'],
'base': base,
'amount': tax['amount'],
}
return agg_taxes
@api.multi
def compute_tax_detail(self):
taxes_to_delete = False
for order in self:
taxes_to_delete = self.env['pos.order.tax'].search(
[('pos_order', '=', order.id)])
# Update order taxes list
for key, tax in order._tax_list_get().iteritems():
current = taxes_to_delete.filtered(
lambda r: r.tax.id == tax['tax_id'])
if current:
current.write({
'base': tax['base'],
'amount': tax['amount'],
})
taxes_to_delete -= current
else:
self.env['pos.order.tax'].create({
'pos_order': order.id,
'tax': tax['tax_id'],
'name': tax['name'],
'base': tax['base'],
'amount': tax['amount'],
})
if taxes_to_delete:
taxes_to_delete.unlink()
@api.multi
def action_paid(self):
result = super(PosOrder, self).action_paid()
self.compute_tax_detail()
return result
@api.model
def _install_tax_detail(self):
"""Create tax details to pos.order's already paid, done or invoiced.
"""
# Find orders with state : paid, done or invoiced
orders = self.search([('state', 'in', ('paid', 'done', 'invoiced')),
('taxes', '=', False)])
# Compute tax detail
orders.compute_tax_detail()
_logger.info("%d orders computed installing module.", len(orders))

36
pos_pricelist/report/report_receipt.xml

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<template id="report_receipt"
inherit_id="point_of_sale.report_receipt"
name="Add taxes detail">
<xpath expr="//div[@class='page']" position="inside">
<table class="table table-condensed">
<thead>
<tr>
<th>Tax</th>
<th class="text-right">Base</th>
<th class="text-right">Amount</th>
</tr>
</thead>
<tbody>
<tr t-foreach="o.taxes" t-as="tax">
<td>
<span t-esc="tax.name"/>
</td>
<td class="text-right">
<span t-esc="formatLang(tax.base, currency_obj=res_company.currency_id)"/>
</td>
<td class="text-right">
<span t-esc="formatLang(tax.amount, currency_obj=res_company.currency_id)"/>
</td>
</tr>
</tbody>
</table>
</xpath>
</template>
</data>
</openerp>

11
pos_pricelist/views/point_of_sale_view.xml

@ -10,6 +10,17 @@
<xpath expr="//field[@name='lines']/tree/field[@name='discount']" position="after">
<field name="tax_ids" widget="many2many_tags"/>
</xpath>
<page string="Payments" position="after">
<page string="Taxes">
<field name="taxes" widget="one2many_list">
<tree string="Taxes detail">
<field name="name"/>
<field name="base"/>
<field name="amount"/>
</tree>
</field>
</page>
</page>
</field>
</record>

Loading…
Cancel
Save