Skip to content
Permalink
Browse files

[ADD] point_of_sale: add reprint button on pos order to reprint ticke…

…t from POS backend.
  • Loading branch information...
pla-odoo committed Mar 4, 2019
1 parent 5694de8 commit 31de2d26ea020842774e58547e22bc42f3cf771d
@@ -18,6 +18,7 @@
'wizard/pos_details.xml',
'wizard/pos_open_statement.xml',
'wizard/pos_payment.xml',
'wizard/pos_order_ticket.xml',
'views/pos_templates.xml',
'views/point_of_sale_template.xml',
'views/point_of_sale_report.xml',
@@ -48,6 +49,9 @@
],
'installable': True,
'application': True,
'qweb': ['static/src/xml/pos.xml'],
'qweb': [
'static/src/xml/pos.xml',
'static/src/xml/pos_order_reprint.xml',
],
'website': 'https://www.odoo.com/page/point-of-sale-shop',
}
@@ -0,0 +1,37 @@
odoo.define('web.PrintTicket', function (require) {
"use static";

var core = require('web.core');
var AbstractAction = require('web.AbstractAction');

var QWeb = core.qweb;

var PrintTicket = AbstractAction.extend({
/**
* @override
* @param {Object} parent
* @param {Object} records
*
*/
init: function (parent, records) {
this._super.apply(this, arguments);
this.receipt_data = records.params.receipt_data;
this.iot_box_url = records.params.iot_box_url;
},
/**
* @override
*
*/
start: function () {
var $receipt = QWeb.render('OrderXmlReceipt', this.receipt_data);
var def = this._rpc({
route: this.iot_box_url+'/hw_proxy/print_xml_receipt',
params:{receipt: $receipt}
});

return Promise.all([def, this._super.apply(this, arguments)]);
},
});

core.action_registry.add('print_ticket_action', PrintTicket);
});
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>

<templates>
<t t-extend="XmlReceipt" t-name="OrderXmlReceipt">
<t t-jquery="t[t-foreach='paymentlines']" t-operation="replace">
<t t-foreach='receipt.paymentlines' t-as='line'>
<line>
<left><t t-esc='line.name' /></left>
<right><value t-att-value-decimals='pos.currency.decimals'><t t-esc='line.amount'/></value></right>
</line>
</t>
</t>
</t>
</templates>
@@ -4,6 +4,7 @@
<xpath expr="." position="inside">
<link rel="stylesheet" type="text/scss" href="/point_of_sale/static/src/scss/pos_dashboard.scss"/>
<script type="text/javascript" src="/point_of_sale/static/src/js/tour.js"></script>
<script type="text/javascript" src="/point_of_sale/static/src/js/print_ticket.js"></script>
</xpath>
</template>
</odoo>
@@ -11,6 +11,7 @@
attrs="{'invisible': ['|', ('invoice_group', '=', False), ('state','!=','paid')]}"/>
<button name="refund" string="Return Products" type="object"
attrs="{'invisible':[('state','=','draft')]}"/>
<button name="%(pos_order_ticket_action)d" string="Print Ticket" type="action" context="{'default_pos_order_id': active_id}"/>
<field name="state" widget="statusbar" statusbar_visible="draft,paid,done" />
</header>
<sheet>
@@ -5,3 +5,4 @@
from . import pos_details
from . import pos_open_statement
from . import pos_payment
from . import pos_order_ticket
@@ -0,0 +1,148 @@
# -*- coding: utf-8 -*-
import base64

from odoo import api, fields, models, tools
from odoo.tools.mimetypes import guess_mimetype


class PosOrderTicket(models.TransientModel):
_name = "pos.order.ticket"

pos_name = fields.Many2one('pos.config', string="POS Name", required=True)
proxy_ip = fields.Char(related="pos_name.proxy_ip")
ip_url = fields.Char(compute="_compute_ip_url")

@api.depends('pos_name')
def _compute_ip_url(self):
for box in self:
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
if box.proxy_ip:
if base_url[:5] == "https":
box.ip_url = "https://" + box.proxy_ip
else:
box.ip_url = "http://" + box.proxy_ip + ":8069"

def _amount_by_group(self, order_line):
res = {}
for line in order_line.lines:
price_reduce = line.price_unit * (1.0 - line.discount / 100.0)
taxes = line.tax_ids_after_fiscal_position.compute_all(price_reduce, quantity=line.qty, product=line.product_id)['taxes']
for tax in line.tax_ids_after_fiscal_position:
group = tax.tax_group_id
res.setdefault(group, {'amount': 0.0, 'base': 0.0})
for t in taxes:
if t['id'] == tax.id or t['id'] in tax.children_tax_ids.ids:
res[group]['amount'] += t['amount']
res[group]['base'] += t['base']
res = sorted(res.items(), key=lambda l: l[0].sequence)
return [(l[0].name, l[1]['amount'], l[1]['base']) for l in res]

def _generate_wrapped_product_name(self, product_name):
MAX_LENGTH = 24
wrapped = []
name = product_name.split("]")[1]
current_line = ""

while (len(name) > 0):
space_index = name.find(" ")
if (space_index == -1):
space_index = len(name)

if (len(current_line) + space_index > MAX_LENGTH):
if (len(current_line)):
wrapped.append(current_line)
current_line = ""

current_line += name[0:space_index + 1]
name = name[space_index + 1:]

if (len(current_line)):
wrapped.append(current_line)
return wrapped

@api.multi
def print_ticket(self):
self.ensure_one()
rec = self.env['pos.order'].browse(self.env.context.get('active_id', False))
total = 0.0
orderlines = []
taxes = []
statement_ids = []
if rec.statement_ids:
for statement in rec.statement_ids:
if statement.amount < 0:
change = statement.amount
total = 0.0
else:
total += statement.amount
journal = statement.statement_id.journal_id.display_name
statement_ids.append({
"amount": total,
"name": journal
})
img = base64.b64decode(rec.company_id.logo)
mimetype = guess_mimetype(img, default='image/png')
company = {
"name": rec.company_id.name,
"contact_address": rec.company_id.name,
"phone": rec.company_id.phone,
"vat": rec.company_id.vat,
"email": rec.company_id.email,
"website": rec.company_id.website,
"logo": 'data:%s;base64,' % mimetype + rec.company_id.logo_web.decode('utf-8')
}
price_total = 0.0
total_disc = 0.0
for line in rec.lines:
price_total += line.price_subtotal
total_disc += line.price_unit * (line.discount/100) * line.qty
orderlines.append({
"quantity": line.qty,
"price": line.price_unit,
"discount": line.discount,
"product_name": line.product_id.display_name,
"product_name_wrapped": self._generate_wrapped_product_name(line.product_id.display_name),
"price_display": line.price_subtotal,
"price_with_tax": line.price_subtotal_incl,
"unit_name": line.product_id.uom_name,
"tax": [{
"name": tax.display_name,
"amount": tax.amount
} for tax in line.tax_ids_after_fiscal_position],
})
tax_details = self._amount_by_group(rec)
for tax in tax_details:
taxes.append({
'name': tax[0],
'amount': tax[1]
})
product_price = self.env.ref('product.decimal_price')
product_uom = self.env.ref('product.decimal_product_uom')
report_data = {
"receipt": {
"cashier": rec.user_id.display_name,
"orderlines": orderlines,
"paymentlines": statement_ids,
"total_with_tax": rec.amount_total,
"total_tax": rec.amount_tax,
"name": rec.pos_reference,
"date": {"localestring": rec.date_order},
"company": company,
"subtotal": price_total,
"discount": total_disc,
"change": abs(change) if rec.statement_ids and change else 0.0,
"tax_details": taxes
},
"pos": {
"currency": {"decimals": rec.pricelist_id.currency_id.decimal_places},
"dp": {
product_price.name: product_price.digits,
product_uom.name: product_uom.digits
}
}
}
return {
'type': 'ir.actions.client',
'tag': 'print_ticket_action',
'params': {'receipt_data': report_data, 'iot_box_url': self.ip_url},
}
@@ -0,0 +1,31 @@
<?xml version="1.0"?>
<odoo>
<record id="pos_order_ticket_view_form" model="ir.ui.view">
<field name="name">pos.order.ticket.view</field>
<field name="model">pos.order.ticket</field>
<field name="arch" type="xml">
<form string="Order Reprint">
<sheet>
<group>
<field name="pos_name"/>
<field name="proxy_ip" invisible="1"/>
<field name="ip_url" invisible="1"/>
</group>
</sheet>
<footer>
<button name="print_ticket" type="object" string="Print Ticket" class="btn-primary"/>
<button string="Cancel" class="btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>

<record id="pos_order_ticket_action" model="ir.actions.act_window">
<field name="name">Order Reprint</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">pos.order.ticket</field>
<field name="view_mode">form</field>
<field name="view_id" ref='pos_order_ticket_view_form'/>
<field name="target">new</field>
</record>
</odoo>

0 comments on commit 31de2d2

Please sign in to comment.
You can’t perform that action at this time.