diff --git a/addons/point_of_sale/__openerp__.py b/addons/point_of_sale/__openerp__.py
index a42c2df9106..a4bd8fc247b 100644
--- a/addons/point_of_sale/__openerp__.py
+++ b/addons/point_of_sale/__openerp__.py
@@ -59,6 +59,7 @@ Main Features
'views/report_statement.xml',
'views/report_usersproduct.xml',
'views/report_userlabel.xml',
+ 'views/report_saledetails.xml',
'views/point_of_sale.xml',
'views/point_of_sale_dashboard.xml',
],
diff --git a/addons/point_of_sale/controllers/main.py b/addons/point_of_sale/controllers/main.py
index cd4d91b56c9..305e743c3f4 100644
--- a/addons/point_of_sale/controllers/main.py
+++ b/addons/point_of_sale/controllers/main.py
@@ -18,3 +18,10 @@ class PosController(http.Controller):
return werkzeug.utils.redirect('/web#action=point_of_sale.action_client_pos_menu')
pos_sessions.login()
return request.render('point_of_sale.index')
+
+ @http.route('/pos/sale_details_report', type='http', auth='user')
+ def print_sale_details(self, date_start=False, date_stop=False, **kw):
+ r = request.env['report.point_of_sale.report_saledetails']
+ pdf = request.env['report'].with_context(date_start=date_start, date_stop=date_stop).get_pdf(r, 'point_of_sale.report_saledetails')
+ pdfhttpheaders = [('Content-Type', 'application/pdf'), ('Content-Length', len(pdf))]
+ return request.make_response(pdf, headers=pdfhttpheaders)
diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py
index a8b466f1acb..fb299dae32e 100644
--- a/addons/point_of_sale/models/pos_order.py
+++ b/addons/point_of_sale/models/pos_order.py
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
+from datetime import timedelta
from functools import partial
import psycopg2
@@ -8,7 +9,7 @@ import psycopg2
from odoo import api, fields, models, tools, _
from odoo.tools import float_is_zero
from odoo.exceptions import UserError
-
+from odoo.http import request
import odoo.addons.decimal_precision as dp
_logger = logging.getLogger(__name__)
@@ -733,3 +734,104 @@ class PosOrderLine(models.Model):
def _get_tax_ids_after_fiscal_position(self):
for line in self:
line.tax_ids_after_fiscal_position = line.order_id.fiscal_position_id.map_tax(line.tax_ids)
+
+
+class ReportSaleDetails(models.AbstractModel):
+
+ _name = 'report.point_of_sale.report_saledetails'
+
+
+ @api.model
+ def get_sale_details(self, date_start=False, date_stop=False, company=False):
+ """ Serialise the orders of the day information
+
+ params: date_start, date_stop string representing the day of order
+ """
+ if not company:
+ company = self.env.user.company_id
+
+ today = fields.Datetime.from_string(fields.Date.context_today(self))
+ if date_start:
+ date_start = fields.Datetime.from_string(date_start)
+ else:
+ # start by default today 00:00:00
+ date_start = today
+
+ if date_stop:
+ # set time to 23:59:59
+ date_stop = fields.Datetime.from_string(date_stop) + timedelta(days=1, seconds=-1)
+ else:
+ # stop by default today 23:59:59
+ date_stop = today + timedelta(days=1, seconds=-1)
+
+ # avoid a date_stop smaller than date_start
+ date_stop = max(date_stop, date_start)
+
+ date_start = fields.Datetime.to_string(date_start)
+ date_stop = fields.Datetime.to_string(date_stop)
+ orders = self.env['pos.order'].search([('date_order', '>=', date_start), ('date_order', '<=', date_stop),
+ ('state', 'in', ['paid','invoiced','done']),
+ ('company_id', '=', company.id)])
+ user_currency = self.env.user.company_id.currency_id
+
+ total = 0.0
+ products_sold = {}
+ taxes = {}
+ for order in orders:
+ if user_currency != order.pricelist_id.currency_id:
+ total += order.pricelist_id.currency_id.compute(order.amount_total, user_currency)
+ else:
+ total += order.amount_total
+ currency = order.session_id.currency_id
+
+ for line in order.lines:
+ key = (line.product_id, line.price_unit, line.discount)
+ products_sold.setdefault(key, 0.0)
+ products_sold[key] += line.qty
+
+ if line.tax_ids_after_fiscal_position:
+ line_taxes = line.tax_ids_after_fiscal_position.compute_all(line.price_unit * (1-(line.discount or 0.0)/100.0), currency, line.qty, product=line.product_id, partner=line.order_id.partner_id or False)
+ for tax in line_taxes['taxes']:
+ taxes.setdefault(tax['id'], {'name': tax['name'], 'total':0.0})
+ taxes[tax['id']]['total'] += tax['amount']
+
+ st_line_ids = self.env["account.bank.statement.line"].search([('pos_statement_id', 'in', orders.ids)]).ids
+ if st_line_ids:
+ self.env.cr.execute("""
+ SELECT aj.name, sum(amount) total
+ FROM account_bank_statement_line AS absl,
+ account_bank_statement AS abs,
+ account_journal AS aj
+ WHERE absl.statement_id = abs.id
+ AND abs.journal_id = aj.id
+ AND absl.id IN %s
+ GROUP BY aj.name
+ """, (tuple(st_line_ids),))
+ payments = self.env.cr.dictfetchall()
+ else:
+ payments = []
+
+ return {
+ 'total_paid': user_currency.round(total),
+ 'payments': payments,
+ 'company_name': self.env.user.company_id.name,
+ 'taxes': taxes.values(),
+ 'products': [{
+ 'product_id': product.id,
+ 'product_name': product.name[:20],
+ 'code': product.default_code,
+ 'quantity': qty,
+ 'price_unit': price_unit,
+ 'discount': discount,
+ 'uom': product.uom_id.name
+ } for (product, price_unit, discount), qty in products_sold.items()]
+ }
+
+ @api.multi
+ def render_html(self, data=None):
+ company = request.env.user.company_id
+ date_start = self.env.context.get('date_start', False)
+ date_stop = self.env.context.get('date_stop', False)
+ data = dict(data or {}, date_start=date_start, date_stop=date_stop)
+ data.update(self.get_sale_details(date_start, date_stop, company))
+ return self.env['report'].render('point_of_sale.report_saledetails', data)
\ No newline at end of file
diff --git a/addons/point_of_sale/static/src/js/chrome.js b/addons/point_of_sale/static/src/js/chrome.js
index 926fe23eee7..f7bf1f78010 100644
--- a/addons/point_of_sale/static/src/js/chrome.js
+++ b/addons/point_of_sale/static/src/js/chrome.js
@@ -406,6 +406,23 @@ var ProxyStatusWidget = StatusWidget.extend({
},
});
+
+/* --------- The Sale Details --------- */
+
+// Generates a report to print the sales of the
+// day on a ticket
+
+var SaleDetailsButton = PosBaseWidget.extend({
+ template: 'SaleDetailsButton',
+ start: function(){
+ var self = this;
+ this.$el.click(function(){
+ self.pos.proxy.print_sale_details();
+ });
+ },
+});
+
+
/*--------------------------------------*\
| THE CHROME |
\*======================================*/
@@ -662,6 +679,11 @@ var Chrome = PosBaseWidget.extend({
'name': 'order_selector',
'widget': OrderSelectorWidget,
'replace': '.placeholder-OrderSelectorWidget',
+ },{
+ 'name': 'sale_details',
+ 'widget': SaleDetailsButton,
+ 'append': '.pos-rightheader',
+ 'condition': function(){ return this.pos.config.use_proxy; },
},{
'name': 'proxy_status',
'widget': ProxyStatusWidget,
@@ -769,6 +791,7 @@ return {
HeaderButtonWidget: HeaderButtonWidget,
OrderSelectorWidget: OrderSelectorWidget,
ProxyStatusWidget: ProxyStatusWidget,
+ SaleDetailsButton: SaleDetailsButton,
StatusWidget: StatusWidget,
SynchNotificationWidget: SynchNotificationWidget,
UsernameWidget: UsernameWidget,
diff --git a/addons/point_of_sale/static/src/js/devices.js b/addons/point_of_sale/static/src/js/devices.js
index f9dd33e0ead..cfb24bf39ed 100644
--- a/addons/point_of_sale/static/src/js/devices.js
+++ b/addons/point_of_sale/static/src/js/devices.js
@@ -2,8 +2,10 @@ odoo.define('point_of_sale.devices', function (require) {
"use strict";
var core = require('web.core');
+var Model = require('web.DataModel');
var Session = require('web.Session');
+var QWeb = core.qweb;
var _t = core._t;
// the JobQueue schedules a sequence of 'jobs'. each job is
@@ -434,6 +436,23 @@ var ProxyDevice = core.Class.extend(core.mixins.PropertiesMixin,{
send_printing_job();
},
+ print_sale_details: function() {
+ var self = this;
+ new Model('report.point_of_sale.report_saledetails').call('get_sale_details').then(function(result){
+ var env = {
+ company: self.pos.company,
+ pos: self.pos,
+ products: result.products,
+ payments: result.payments,
+ taxes: result.taxes,
+ total_paid: result.total_paid,
+ date: (new Date()).toLocaleString(),
+ };
+ var report = QWeb.render('SaleDetailsReport', env);
+ self.print_receipt(report);
+ })
+ },
+
// asks the proxy to log some information, as with the debug.log you can provide several arguments.
log: function(){
return this.message('log',{'arguments': _.toArray(arguments)});
diff --git a/addons/point_of_sale/static/src/js/report.js b/addons/point_of_sale/static/src/js/report.js
new file mode 100644
index 00000000000..783ace7f655
--- /dev/null
+++ b/addons/point_of_sale/static/src/js/report.js
@@ -0,0 +1,63 @@
+odoo.define('point_of_sale.report', function (require) {
+"use strict";
+
+var chat_manager = require('mail.chat_manager');
+var composer = require('mail.composer');
+var ChatThread = require('mail.ChatThread');
+var utils = require('mail.utils');
+
+var config = require('web.config');
+var core = require('web.core');
+var data = require('web.data');
+var Dialog = require('web.Dialog');
+var framework = require('web.framework');
+var Model = require('web.Model');
+
+var pyeval = require('web.pyeval');
+var SearchView = require('web.SearchView');
+
+var ActionManager = require('web.ActionManager');
+var ControlPanelMixin = require('web.ControlPanelMixin');
+var datepicker = require('web.datepicker');
+var Widget = require('web.Widget');
+
+var QWeb = core.qweb;
+var _t = core._t;
+
+// TODO replace in v10 with proper wizard
+var PosDetailsWidget = Widget.extend(ControlPanelMixin, {
+ template: 'WizardSaleDetailsReport',
+ events: {
+ "click .js_generate": "renderReport",
+ },
+
+ renderElement: function() {
+ this._super();
+
+ var current_date = new moment();
+ this.dp_start = new datepicker.DateWidget(this);
+ this.dp_start.insertBefore(this.$el.find('.js_date_start'));
+ this.dp_start.set_value(current_date.format('YYYY-MM-DD'));
+
+ this.dp_stop = new datepicker.DateWidget(this);
+ this.dp_stop.insertAfter(this.$el.find('.js_date_stop'));
+ this.dp_stop.set_value(current_date.format('YYYY-MM-DD'));
+
+ },
+
+ renderReport: function() {
+ var start = this.dp_start.get_value();
+ var stop = this.dp_stop.get_value();
+ var url = '/pos/sale_details_report?date_start='+start+'&date_stop='+stop;
+ window.open(url, '_blank');
+
+ },
+
+});
+
+
+core.action_registry.add('report_pos_details', PosDetailsWidget);
+
+return PosDetailsWidget;
+
+});
diff --git a/addons/point_of_sale/static/src/xml/pos.xml b/addons/point_of_sale/static/src/xml/pos.xml
index 0e54998e105..1ec188f7dfc 100644
--- a/addons/point_of_sale/static/src/xml/pos.xml
+++ b/addons/point_of_sale/static/src/xml/pos.xml
@@ -84,6 +84,14 @@
+
+
+
+