@ -0,0 +1,21 @@ |
|||
================= |
|||
Pos Discounts v19 |
|||
================= |
|||
|
|||
This module adds a feature to provide several types of discounts in point of sale. |
|||
|
|||
Installation |
|||
============ |
|||
|
|||
Just select it from available modules to install it, there is no need to extra installations. |
|||
|
|||
Configuration |
|||
============= |
|||
|
|||
We need to specify a discount account when we create the point of sale. This account will be used to record the discount amount. |
|||
|
|||
Credits |
|||
======= |
|||
Developer: Linto CT @ cybrosys, linto@cybrosys.in |
|||
|
|||
|
@ -0,0 +1,4 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import models |
|||
|
@ -0,0 +1,52 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
############################################################################## |
|||
# |
|||
# Cybrosys Technologies Pvt. Ltd. |
|||
# Copyright (C) 2017-TODAY Cybrosys Technologies(<https://www.cybrosys.com>). |
|||
# Author: LINTO C T(<https://www.cybrosys.com>) |
|||
# you can modify it under the terms of the GNU LESSER |
|||
# GENERAL PUBLIC LICENSE (LGPL v3), Version 3. |
|||
# |
|||
# It is forbidden to publish, distribute, sublicense, or sell copies |
|||
# of the Software or modified copies of the Software. |
|||
# |
|||
# 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. |
|||
# |
|||
# You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE |
|||
# GENERAL PUBLIC LICENSE (LGPL v3) along with this program. |
|||
# If not, see <https://www.gnu.org/licenses/>. |
|||
# |
|||
############################################################################## |
|||
{ |
|||
'name': 'Point of Sale Discounts', |
|||
'version': '9.0.1.0.0', |
|||
'category': 'Point of Sale', |
|||
'summary': 'Discounts in the Point of Sale(Fixed and Percentage) ', |
|||
'author': 'Cybrosys Techno Solutions', |
|||
'company': 'Cybrosys Techno Solutions', |
|||
'images': ['static/description/banner.jpg'], |
|||
'website': 'https://www.cybrosys.com', |
|||
'depends': ['base', 'point_of_sale', 'account', 'report', 'account_accountant'], |
|||
'data': [ |
|||
'views/report_paperformat_new.xml', |
|||
'views/templates.xml', |
|||
'views/report_payment_new.xml', |
|||
'views/pos_reports_new_invoice.xml', |
|||
'views/report_saleslines_new.xml', |
|||
'views/report_receipt_new.xml', |
|||
'views/account_invoice_view_pos.xml', |
|||
'views/pos_reports_account_invoice.xml', |
|||
'views/pos_view.xml', |
|||
], |
|||
'qweb': [ |
|||
'static/src/xml/discount.xml' |
|||
], |
|||
'license': 'AGPL-3', |
|||
'installable': True, |
|||
'auto_install': False, |
|||
} |
|||
|
@ -0,0 +1,7 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import pos_order_lines_new |
|||
import pos_payment_report_new |
|||
import pos_lines_new |
|||
import pos_invoice_new |
|||
import pos_receipt_new |
@ -0,0 +1,49 @@ |
|||
import time |
|||
from openerp.osv import osv |
|||
from openerp.report import report_sxw |
|||
|
|||
|
|||
class pos_payment_report(report_sxw.rml_parse): |
|||
|
|||
def __init__(self, cr, uid, name, context): |
|||
super(pos_payment_report, self).__init__(cr, uid, name, context=context) |
|||
self.total = 0.0 |
|||
self.localcontext.update({ |
|||
'time': time, |
|||
'pos_payment': self._pos_payment, |
|||
'pos_payment_total':self._pos_payment_total, |
|||
}) |
|||
|
|||
def _pos_payment(self, obj): |
|||
self.total = 0 |
|||
data={} |
|||
sql = """ select id from pos_order where id = %d"""%(obj.id) |
|||
self.cr.execute(sql) |
|||
if self.cr.fetchone(): |
|||
self.cr.execute ("select pt.name,pp.default_code as code,pol.qty,pu.name as uom,pol.discount,pol.price_unit, " \ |
|||
"(pol.price_unit * pol.qty * (1 - (pol.discount) / 100.0)) as total " \ |
|||
"from pos_order as po,pos_order_line as pol,product_product as pp,product_template as pt, product_uom as pu " \ |
|||
"where pt.id=pp.product_tmpl_id and pp.id=pol.product_id and po.id = pol.order_id and pu.id=pt.uom_id " \ |
|||
"and po.state IN ('paid','invoiced') and to_char(date_trunc('day',po.date_order),'YYYY-MM-DD')::date = current_date and po.id=%d"%(obj.id)) |
|||
data=self.cr.dictfetchall() |
|||
else: |
|||
self.cr.execute ("select pt.name,pp.default_code as code,pol.qty,pu.name as uom,pol.discount,pol.price_unit, " \ |
|||
"(pol.price_unit * pol.qty * (1 - (pol.discount) / 100.0)) as total " \ |
|||
"from pos_order as po,pos_order_line as pol,product_product as pp,product_template as pt, product_uom as pu " \ |
|||
"where pt.id=pp.product_tmpl_id and pp.id=pol.product_id and po.id = pol.order_id and pu.id=pt.uom_id " \ |
|||
"and po.state IN ('paid','invoiced') and to_char(date_trunc('day',po.date_order),'YYYY-MM-DD')::date = current_date") |
|||
data=self.cr.dictfetchall() |
|||
|
|||
for d in data: |
|||
self.total += d['price_unit'] * d['qty'] |
|||
return data |
|||
|
|||
def _pos_payment_total(self, o): |
|||
return self.total |
|||
|
|||
|
|||
class report_pos_payment(osv.AbstractModel): |
|||
_name = 'report.point_of_sale.report_payment' |
|||
_inherit = 'report.abstract_report' |
|||
_template = 'point_of_sale.report_payment' |
|||
_wrapped_report_class = pos_payment_report |
@ -0,0 +1,166 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from openerp import SUPERUSER_ID |
|||
from openerp.osv import osv |
|||
from openerp.tools import float_is_zero |
|||
|
|||
from openerp.exceptions import UserError |
|||
from openerp import api, fields, models, _ |
|||
import openerp.addons.decimal_precision as dp |
|||
|
|||
|
|||
class PosInvoiceReportNew(osv.AbstractModel): |
|||
_name = 'report.discounts_in_pos.report_invoice' |
|||
|
|||
def render_html(self, cr, uid, ids, data=None, context=None): |
|||
report_obj = self.pool['report'] |
|||
posorder_obj = self.pool['pos.order'] |
|||
report = report_obj._get_report_from_name(cr, uid, 'discounts_in_pos.report_invoice') |
|||
selected_orders = posorder_obj.browse(cr, uid, ids, context=context) |
|||
ids_to_print = [] |
|||
invoiced_posorders_ids = [] |
|||
for order in selected_orders: |
|||
if order.invoice_id: |
|||
ids_to_print.append(order.invoice_id.id) |
|||
invoiced_posorders_ids.append(order.id) |
|||
|
|||
not_invoiced_orders_ids = list(set(ids) - set(invoiced_posorders_ids)) |
|||
if not_invoiced_orders_ids: |
|||
not_invoiced_posorders = posorder_obj.browse(cr, uid, not_invoiced_orders_ids, context=context) |
|||
not_invoiced_orders_names = list(map(lambda a: a.name, not_invoiced_posorders)) |
|||
raise UserError(_('No link to an invoice for %s.') % ', '.join(not_invoiced_orders_names)) |
|||
|
|||
docargs = { |
|||
'docs': self.pool['account.invoice'].browse(cr, uid, ids_to_print, context=context) |
|||
} |
|||
|
|||
return report_obj.render(cr, SUPERUSER_ID, ids, 'discounts_in_pos.report_invoice', docargs, context=context) |
|||
|
|||
|
|||
class POSInvoiceNew(models.Model): |
|||
_inherit = 'account.invoice.line' |
|||
|
|||
discount_fixed = fields.Float(string='Discount.Fixed', digits=dp.get_precision('DiscountFixed'), |
|||
default=0.0) |
|||
|
|||
@api.one |
|||
@api.depends('price_unit', 'discount', 'invoice_line_tax_ids', 'quantity', |
|||
'product_id', 'invoice_id.partner_id', 'invoice_id.currency_id', 'invoice_id.company_id') |
|||
def _compute_price(self): |
|||
super(POSInvoiceNew, self)._compute_price() |
|||
|
|||
currency = self.invoice_id and self.invoice_id.currency_id or None |
|||
|
|||
price = self.price_unit * (1 - (self.discount or 0.0) / 100.0) |
|||
|
|||
if self.discount != 0: |
|||
price = self.price_unit * (1 - (self.discount or 0.0) / 100.0) |
|||
if self.discount_fixed != 0: |
|||
price = self.price_unit |
|||
taxes = False |
|||
if self.invoice_line_tax_ids: |
|||
taxes = self.invoice_line_tax_ids.compute_all(price, currency, self.quantity, product=self.product_id, |
|||
partner=self.invoice_id.partner_id) |
|||
|
|||
self.price_subtotal = price_subtotal_signed = taxes['total_excluded'] if taxes else self.quantity * price |
|||
|
|||
if self.discount != 0: |
|||
self.price_subtotal = price_subtotal_signed = taxes['total_excluded'] if taxes else self.quantity * price |
|||
|
|||
if self.discount_fixed != 0: |
|||
self.price_subtotal = price_subtotal_signed = taxes[ |
|||
'total_excluded'] if taxes else self.quantity * price - self.discount_fixed |
|||
if self.invoice_id.currency_id and self.invoice_id.currency_id != self.invoice_id.company_id.currency_id: |
|||
price_subtotal_signed = self.invoice_id.currency_id.compute(price_subtotal_signed, |
|||
self.invoice_id.company_id.currency_id) |
|||
sign = self.invoice_id.type in ['in_refund', 'out_refund'] and -1 or 1 |
|||
self.price_subtotal_signed = price_subtotal_signed * sign |
|||
|
|||
|
|||
class POSInvoiceTotalDisc(models.Model): |
|||
_inherit = 'account.invoice' |
|||
|
|||
discount_total = fields.Float(string='Total Discount', default=0.0) |
|||
discount_percent = fields.Float(string='Total Discount(%)', default=0.0) |
|||
|
|||
@api.one |
|||
@api.depends('invoice_line_ids.price_subtotal', 'tax_line_ids.amount', 'currency_id', 'company_id') |
|||
def _compute_amount(self): |
|||
super(POSInvoiceTotalDisc, self)._compute_amount() |
|||
self.amount_total = self.amount_untaxed + self.amount_tax |
|||
if self.discount_total > 0: |
|||
self.amount_total -= self.discount_total |
|||
if self.discount_percent > 0: |
|||
self.amount_total -= ((self.amount_untaxed + self.amount_tax) * self.discount_percent / 100) |
|||
|
|||
def _compute_residual(self): |
|||
super(POSInvoiceTotalDisc, self)._compute_residual() |
|||
residual = 0.0 |
|||
residual_company_signed = 0.0 |
|||
sign = self.type in ['in_refund', 'out_refund'] and -1 or 1 |
|||
for line in self.sudo().move_id.line_ids: |
|||
if line.account_id.internal_type in ('receivable', 'payable'): |
|||
residual_company_signed += line.amount_residual |
|||
if line.currency_id == self.currency_id: |
|||
residual += line.amount_residual_currency if line.currency_id else line.amount_residual |
|||
else: |
|||
from_currency = (line.currency_id and line.currency_id.with_context(date=line.date)) or line.company_id.currency_id.with_context(date=line.date) |
|||
residual += from_currency.compute(line.amount_residual, self.currency_id) |
|||
|
|||
if self.discount_total > 0: |
|||
residual -= self.discount_total |
|||
if self.discount_percent > 0: |
|||
residual -= self.amount_untaxed * self.discount_percent / 100 |
|||
|
|||
self.residual_company_signed = abs(residual_company_signed) * sign |
|||
self.residual_signed = abs(residual) * sign |
|||
self.residual = abs(residual) |
|||
digits_rounding_precision = self.currency_id.rounding |
|||
if float_is_zero(self.residual, precision_rounding=digits_rounding_precision): |
|||
self.reconciled = True |
|||
else: |
|||
self.reconciled = False |
|||
|
|||
@api.multi |
|||
def action_move_create(self): |
|||
res = super(POSInvoiceTotalDisc, self).action_move_create() |
|||
order = self.env['pos.order'].search([('invoice_id', '=', self.id)]) |
|||
session = None |
|||
if order: |
|||
if order.discount_total > 0 or order.discount_percent > 0: |
|||
session = order.session_id |
|||
discount_ac = None |
|||
if session: |
|||
if session.config_id.discount_account: |
|||
discount_ac = session.config_id.discount_account |
|||
else: |
|||
raise UserError(_('Please set a discount account for this session')) |
|||
lines = self.env['account.move.line'].search([('move_id', '=', self.move_id.id), ('debit', '>', 0)], limit=1) |
|||
if order.discount_total > 0: |
|||
discount = order.discount_total |
|||
elif order.discount_percent > 0: |
|||
move_lines = self.env['account.move.line'].search([('move_id', '=', self.move_id.id), ('credit', '>', 0)]) |
|||
sum = 0 |
|||
for i in move_lines: |
|||
sum += i.credit |
|||
discount = sum - order.amount_total |
|||
lines.write({ |
|||
'debit': lines.debit - discount |
|||
}) |
|||
temp2 = { |
|||
'partner_id': self.partner_id.id, |
|||
'name': "Discount", |
|||
'credit': 0, |
|||
'debit': discount, |
|||
'account_id': discount_ac.id, |
|||
'quantity': 1, |
|||
'move_id': self.move_id.id, |
|||
} |
|||
self.env['account.move.line'].create(temp2) |
|||
return res |
|||
|
|||
|
|||
class PosConfigNew(models.Model): |
|||
_inherit = 'pos.config' |
|||
# discount account is used to enter the total discount values |
|||
discount_account = fields.Many2one('account.account', string="Discount Account", required=True) |
@ -0,0 +1,42 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import time |
|||
from openerp.osv import osv |
|||
from openerp.report import report_sxw |
|||
|
|||
|
|||
class pos_lines(report_sxw.rml_parse): |
|||
|
|||
def __init__(self, cr, uid, name, context): |
|||
super(pos_lines, self).__init__(cr, uid, name, context=context) |
|||
self.total = 0.0 |
|||
self.localcontext.update({ |
|||
'time': time, |
|||
'total_quantity': self.__total_quantity__, |
|||
'taxes':self.__taxes__, |
|||
|
|||
}) |
|||
|
|||
def __total_quantity__(self, obj): |
|||
tot = 0 |
|||
for line in obj.lines: |
|||
tot += line.qty |
|||
self.total = tot |
|||
return self.total |
|||
|
|||
def __taxes__(self, obj): |
|||
self.cr.execute ( " Select acct.name from pos_order as po " \ |
|||
" LEFT JOIN pos_order_line as pol ON po.id = pol.order_id " \ |
|||
" LEFT JOIN product_product as pp ON pol.product_id = pp.id" |
|||
" LEFT JOIN product_taxes_rel as ptr ON pp.product_tmpl_id = ptr.prod_id " \ |
|||
" LEFT JOIN account_tax as acct ON acct.id = ptr.tax_id " \ |
|||
" WHERE pol.id = %s", (obj.id,)) |
|||
res=self.cr.fetchone()[0] |
|||
return res |
|||
|
|||
|
|||
class report_pos_lines(osv.AbstractModel): |
|||
_name = 'report.discounts_in_pos.report_saleslines' |
|||
_inherit = 'report.abstract_report' |
|||
_template = 'discounts_in_pos.report_saleslines' |
|||
_wrapped_report_class = pos_lines |
@ -0,0 +1,503 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import logging |
|||
|
|||
from openerp import SUPERUSER_ID |
|||
from openerp.osv import fields, osv |
|||
from openerp.tools.translate import _ |
|||
from openerp.exceptions import UserError |
|||
import openerp.addons.decimal_precision as dp |
|||
|
|||
from openerp import api, models, fields as Fields |
|||
|
|||
_logger = logging.getLogger(__name__) |
|||
|
|||
|
|||
class NewPosOrder(osv.osv): |
|||
_inherit = "pos.order" |
|||
|
|||
discount_total = Fields.Float(string='Total Discount(Fixed)', default=0.0) |
|||
discount_percent = Fields.Float(string='Total Discount(%)', default=0.0) |
|||
|
|||
_defaults = { |
|||
'discount_total': lambda *a: 0.0, |
|||
'discount_percent': lambda *a: 0.0, |
|||
} |
|||
|
|||
@api.onchange('discount_percent') |
|||
def change_discount_fixed(self): |
|||
if self.discount_percent: |
|||
self.discount_total = 0.0 |
|||
|
|||
@api.onchange('discount_total') |
|||
def change_discount_percent(self): |
|||
if self.discount_total: |
|||
self.discount_percent = 0.0 |
|||
|
|||
@api.depends('statement_ids', 'lines.price_subtotal_incl', 'lines.discount', 'lines.discount_fixed','discount_total','discount_percent') |
|||
def _compute_amount_all(self): |
|||
super(NewPosOrder, self)._compute_amount_all() |
|||
|
|||
for order in self: |
|||
|
|||
currency = order.pricelist_id.currency_id |
|||
amount_untaxed = currency.round(sum(line.price_subtotal for line in order.lines)) |
|||
|
|||
order.amount_total = order.amount_tax + amount_untaxed |
|||
if order.discount_total > 0: |
|||
order.amount_total -= order.discount_total |
|||
if order.discount_percent > 0: |
|||
order.amount_total -= ((order.amount_tax + amount_untaxed) * order.discount_percent / 100) |
|||
|
|||
def _order_fields(self, cr, uid, ui_order, context=None): |
|||
new_discount = super(NewPosOrder, self)._order_fields(cr, uid, ui_order) |
|||
new_discount['discount_total'] = ui_order['discount_total'] |
|||
new_discount['discount_percent'] = ui_order['discount_percent'] |
|||
return new_discount |
|||
|
|||
def action_invoice(self, cr, uid, ids, context=None): |
|||
|
|||
inv_ref = self.pool.get('account.invoice') |
|||
inv_line_ref = self.pool.get('account.invoice.line') |
|||
product_obj = self.pool.get('product.product') |
|||
inv_ids = [] |
|||
|
|||
for order in self.pool.get('pos.order').browse(cr, uid, ids, context=context): |
|||
# Force company for all SUPERUSER_ID action |
|||
company_id = order.company_id.id |
|||
local_context = dict(context or {}, force_company=company_id, company_id=company_id) |
|||
if order.invoice_id: |
|||
inv_ids.append(order.invoice_id.id) |
|||
continue |
|||
|
|||
if not order.partner_id: |
|||
raise UserError(_('Please provide a partner for the sale.')) |
|||
|
|||
acc = order.partner_id.property_account_receivable_id.id |
|||
|
|||
# =============adding 'discount_total' to invoice================================================================ |
|||
inv = { |
|||
'name': order.name, |
|||
'origin': order.name, |
|||
'account_id': acc, |
|||
'journal_id': order.sale_journal.id or None, |
|||
'type': 'out_invoice', |
|||
'reference': order.name, |
|||
'partner_id': order.partner_id.id, |
|||
'comment': order.note or '', |
|||
'currency_id': order.pricelist_id.currency_id.id, # considering partner's sale pricelist's currency |
|||
'company_id': company_id, |
|||
'user_id': uid, |
|||
'discount_total': order.discount_total, |
|||
'discount_percent': order.discount_percent, |
|||
|
|||
} |
|||
invoice = inv_ref.new(cr, uid, inv) |
|||
invoice._onchange_partner_id() |
|||
invoice.fiscal_position_id = order.fiscal_position_id |
|||
|
|||
inv = invoice._convert_to_write(invoice._cache) |
|||
if not inv.get('account_id', None): |
|||
inv['account_id'] = acc |
|||
inv_id = inv_ref.create(cr, SUPERUSER_ID, inv, context=local_context) |
|||
|
|||
self.write(cr, uid, [order.id], {'invoice_id': inv_id, 'state': 'invoiced'}, context=local_context) |
|||
inv_ids.append(inv_id) |
|||
for line in order.lines: |
|||
inv_name = product_obj.name_get(cr, uid, [line.product_id.id], context=local_context)[0][1] |
|||
|
|||
# ===============adding 'discount fixed' to invoice lines========================================== |
|||
inv_line = { |
|||
'invoice_id': inv_id, |
|||
'product_id': line.product_id.id, |
|||
'quantity': line.qty, |
|||
'account_analytic_id': self._prepare_analytic_account(cr, uid, line, context=local_context), |
|||
'name': inv_name, |
|||
'discount_fixed': line.discount_fixed, |
|||
} |
|||
|
|||
#Oldlin trick |
|||
invoice_line = inv_line_ref.new(cr, SUPERUSER_ID, inv_line, context=local_context) |
|||
invoice_line._onchange_product_id() |
|||
invoice_line.invoice_line_tax_ids = [tax.id for tax in invoice_line.invoice_line_tax_ids if tax.company_id.id == company_id] |
|||
fiscal_position_id = line.order_id.fiscal_position_id |
|||
if fiscal_position_id: |
|||
invoice_line.invoice_line_tax_ids = fiscal_position_id.map_tax(invoice_line.invoice_line_tax_ids) |
|||
invoice_line.invoice_line_tax_ids = [tax.id for tax in invoice_line.invoice_line_tax_ids] |
|||
# We convert a new id object back to a dictionary to write to bridge between old and new api |
|||
inv_line = invoice_line._convert_to_write(invoice_line._cache) |
|||
inv_line.update(price_unit=line.price_unit, discount=line.discount, discount_fixed=line.discount_fixed) |
|||
inv_line_ref.create(cr, SUPERUSER_ID, inv_line, context=local_context) |
|||
inv_ref.compute_taxes(cr, SUPERUSER_ID, [inv_id], context=local_context) |
|||
self.signal_workflow(cr, uid, [order.id], 'invoice') |
|||
inv_ref.signal_workflow(cr, SUPERUSER_ID, [inv_id], 'validate') |
|||
|
|||
if not inv_ids: return {} |
|||
|
|||
mod_obj = self.pool.get('ir.model.data') |
|||
res = mod_obj.get_object_reference(cr, uid, 'account', 'invoice_form') |
|||
res_id = res and res[1] or False |
|||
return { |
|||
'name': _('Customer Invoice'), |
|||
'view_type': 'form', |
|||
'view_mode': 'form', |
|||
'view_id': [res_id], |
|||
'res_model': 'account.invoice', |
|||
'context': "{'type':'out_invoice'}", |
|||
'type': 'ir.actions.act_window', |
|||
'target': 'current', |
|||
'res_id': inv_ids and inv_ids[0] or False, |
|||
} |
|||
|
|||
def _create_account_move_line(self, cr, uid, ids, session=None, move_id=None, context=None): |
|||
# Tricky, via the workflow, we only have one id in the ids variable |
|||
"""Create a account move line of order grouped by products or not.""" |
|||
account_move_obj = self.pool.get('account.move') |
|||
account_tax_obj = self.pool.get('account.tax') |
|||
property_obj = self.pool.get('ir.property') |
|||
cur_obj = self.pool.get('res.currency') |
|||
|
|||
# session_ids = set(order.session_id for order in self.browse(cr, uid, ids, context=context)) |
|||
|
|||
if session and not all( |
|||
session.id == order.session_id.id for order in self.browse(cr, uid, ids, context=context)): |
|||
raise UserError(_('Selected orders do not have the same session!')) |
|||
|
|||
grouped_data = {} |
|||
have_to_group_by = session and session.config_id.group_by or False |
|||
rounding_method = session and session.config_id.company_id.tax_calculation_rounding_method |
|||
|
|||
for order in self.browse(cr, uid, ids, context=context): |
|||
if order.account_move: |
|||
continue |
|||
if order.state != 'paid': |
|||
continue |
|||
|
|||
current_company = order.sale_journal.company_id |
|||
|
|||
group_tax = {} |
|||
account_def = property_obj.get(cr, uid, 'property_account_receivable_id', 'res.partner', |
|||
context=context) |
|||
|
|||
order_account = order.partner_id and \ |
|||
order.partner_id.property_account_receivable_id and \ |
|||
order.partner_id.property_account_receivable_id.id or \ |
|||
account_def and account_def.id |
|||
|
|||
if move_id is None: |
|||
# Create an entry for the sale |
|||
# FORWARD-PORT UP TO SAAS-12 |
|||
journal_id = self.pool['ir.config_parameter'].get_param(cr, SUPERUSER_ID, |
|||
'pos.closing.journal_id_%s' % ( |
|||
current_company.id), |
|||
default=order.sale_journal.id, |
|||
context=context) |
|||
move_id = self._create_account_move(cr, uid, order.session_id.start_at, order.name, int(journal_id), |
|||
order.company_id.id, context=context) |
|||
|
|||
move = account_move_obj.browse(cr, SUPERUSER_ID, move_id, context=context) |
|||
|
|||
def insert_data(data_type, values): |
|||
# if have_to_group_by: |
|||
|
|||
# 'quantity': line.qty, |
|||
# 'product_id': line.product_id.id, |
|||
values.update({ |
|||
'partner_id': order.partner_id and self.pool.get("res.partner")._find_accounting_partner( |
|||
order.partner_id).id or False, |
|||
'move_id': move_id, |
|||
}) |
|||
|
|||
if data_type == 'product': |
|||
key = ('product', values['partner_id'], |
|||
(values['product_id'], tuple(values['tax_ids'][0][2]), values['name']), |
|||
values['analytic_account_id'], values['debit'] > 0) |
|||
elif data_type == 'tax': |
|||
key = ('tax', values['partner_id'], values['tax_line_id'], values['debit'] > 0) |
|||
elif data_type == 'counter_part': |
|||
key = ('counter_part', values['partner_id'], values['account_id'], values['debit'] > 0) |
|||
else: |
|||
return |
|||
|
|||
grouped_data.setdefault(key, []) |
|||
|
|||
# if not have_to_group_by or (not grouped_data[key]): |
|||
# grouped_data[key].append(values) |
|||
# else: |
|||
# pass |
|||
|
|||
if have_to_group_by: |
|||
if not grouped_data[key]: |
|||
grouped_data[key].append(values) |
|||
else: |
|||
for line in grouped_data[key]: |
|||
if line.get('tax_code_id') == values.get('tax_code_id'): |
|||
current_value = line |
|||
current_value['quantity'] = current_value.get('quantity', 0.0) + values.get( |
|||
'quantity', 0.0) |
|||
current_value['credit'] = current_value.get('credit', 0.0) + values.get('credit', |
|||
0.0) |
|||
current_value['debit'] = current_value.get('debit', 0.0) + values.get('debit', 0.0) |
|||
break |
|||
else: |
|||
grouped_data[key].append(values) |
|||
else: |
|||
grouped_data[key].append(values) |
|||
|
|||
# because of the weird way the pos order is written, we need to make sure there is at least one line, |
|||
# because just after the 'for' loop there are references to 'line' and 'income_account' variables (that |
|||
# are set inside the for loop) |
|||
# TOFIX: a deep refactoring of this method (and class!) is needed in order to get rid of this stupid hack |
|||
assert order.lines, _('The POS order must have lines when calling this method') |
|||
# Create an move for each order line |
|||
|
|||
cur = order.pricelist_id.currency_id |
|||
for line in order.lines: |
|||
amount = line.price_subtotal |
|||
|
|||
# Search for the income account |
|||
if line.product_id.property_account_income_id.id: |
|||
income_account = line.product_id.property_account_income_id.id |
|||
elif line.product_id.categ_id.property_account_income_categ_id.id: |
|||
income_account = line.product_id.categ_id.property_account_income_categ_id.id |
|||
else: |
|||
raise UserError(_('Please define income ' \ |
|||
'account for this product: "%s" (id:%d).') \ |
|||
% (line.product_id.name, line.product_id.id)) |
|||
|
|||
name = line.product_id.name |
|||
if line.notice: |
|||
# add discount reason in move |
|||
name = name + ' (' + line.notice + ')' |
|||
|
|||
# Create a move for the line for the order line |
|||
insert_data('product', { |
|||
'name': name, |
|||
'quantity': line.qty, |
|||
'product_id': line.product_id.id, |
|||
'account_id': income_account, |
|||
'analytic_account_id': self._prepare_analytic_account(cr, uid, line, context=context), |
|||
'credit': ((amount > 0) and amount) or 0.0, |
|||
'debit': ((amount < 0) and -amount) or 0.0, |
|||
'tax_ids': [(6, 0, line.tax_ids_after_fiscal_position.ids)], |
|||
'partner_id': order.partner_id and self.pool.get("res.partner")._find_accounting_partner( |
|||
order.partner_id).id or False |
|||
}) |
|||
|
|||
# Create the tax lines |
|||
taxes = [] |
|||
for t in line.tax_ids_after_fiscal_position: |
|||
if t.company_id.id == current_company.id: |
|||
taxes.append(t.id) |
|||
if not taxes: |
|||
continue |
|||
for tax in account_tax_obj.browse(cr, uid, taxes, context=context).compute_all( |
|||
line.price_unit * (100.0 - line.discount) / 100.0, cur, line.qty)['taxes']: |
|||
insert_data('tax', { |
|||
'name': _('Tax') + ' ' + tax['name'], |
|||
'product_id': line.product_id.id, |
|||
'quantity': line.qty, |
|||
'account_id': tax['account_id'] or income_account, |
|||
'credit': ((tax['amount'] > 0) and tax['amount']) or 0.0, |
|||
'debit': ((tax['amount'] < 0) and -tax['amount']) or 0.0, |
|||
'tax_line_id': tax['id'], |
|||
'partner_id': order.partner_id and self.pool.get("res.partner")._find_accounting_partner( |
|||
order.partner_id).id or False |
|||
}) |
|||
|
|||
# round tax lines per order |
|||
if rounding_method == 'round_globally': |
|||
for group_key, group_value in grouped_data.iteritems(): |
|||
if group_key[0] == 'tax': |
|||
for line in group_value: |
|||
line['credit'] = cur.round(line['credit']) |
|||
line['debit'] = cur.round(line['debit']) |
|||
|
|||
if order.discount_total: |
|||
insert_data('counter_part', { |
|||
'name': 'Discount', |
|||
'account_id': order.session_id.config_id.discount_account.id, |
|||
'credit': ((order.discount_total < 0) and -order.discount_total) or 0.0, |
|||
'debit': ((order.discount_total > 0) and order.discount_total) or 0.0, |
|||
'partner_id': order.partner_id and self.pool.get("res.partner")._find_accounting_partner( |
|||
order.partner_id).id or False |
|||
}) |
|||
elif order.discount_percent: |
|||
discount = (100 * order.amount_total) / (100 - order.discount_percent) |
|||
discount -= order.amount_total |
|||
print discount, "--------------" |
|||
insert_data('counter_part', { |
|||
'name': 'Discount', |
|||
'account_id': order.session_id.config_id.discount_account.id, |
|||
'credit': ((discount < 0) and -discount) or 0.0, |
|||
'debit': ((discount > 0) and discount) or 0.0, |
|||
'partner_id': order.partner_id and self.pool.get("res.partner")._find_accounting_partner( |
|||
order.partner_id).id or False |
|||
}) |
|||
# counterpart |
|||
insert_data('counter_part', { |
|||
'name': _("Trade Receivables"), # order.name, |
|||
'account_id': order_account, |
|||
'credit': ((order.amount_total < 0) and -order.amount_total) or 0.0, |
|||
'debit': ((order.amount_total > 0) and order.amount_total) or 0.0, |
|||
'partner_id': order.partner_id and self.pool.get("res.partner")._find_accounting_partner( |
|||
order.partner_id).id or False |
|||
}) |
|||
|
|||
order.write({'state': 'done', 'account_move': move_id}) |
|||
|
|||
all_lines = [] |
|||
for group_key, group_data in grouped_data.iteritems(): |
|||
for value in group_data: |
|||
all_lines.append((0, 0, value), ) |
|||
if move_id: # In case no order was changed |
|||
self.pool.get("account.move").write(cr, SUPERUSER_ID, [move_id], {'line_ids': all_lines}, |
|||
context=dict(context or {}, dont_create_taxes=True)) |
|||
self.pool.get("account.move").post(cr, SUPERUSER_ID, [move_id], context=context) |
|||
|
|||
return True |
|||
|
|||
|
|||
class NewPosLines(osv.osv): |
|||
_inherit = "pos.order.line" |
|||
|
|||
_columns = { |
|||
'price_unit': fields.float(string='Unit Price', digits=0), |
|||
'qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure')), |
|||
'discount_fixed': fields.float('Discount Fixed'), |
|||
'discountStr': fields.char('discountStr'), |
|||
|
|||
} |
|||
|
|||
_defaults = { |
|||
'discount_fixed': lambda *a: 0.0, |
|||
} |
|||
|
|||
@api.onchange('discount_fixed') |
|||
def change_discount_fixed_line(self): |
|||
if self.discount_fixed: |
|||
self.discount = 0.0 |
|||
|
|||
@api.onchange('discount') |
|||
def change_discount_line(self): |
|||
if self.discount: |
|||
self.discount_fixed = 0.0 |
|||
|
|||
@api.onchange('qty') |
|||
def change_qty_line(self): |
|||
self._compute_amount_line_all() |
|||
|
|||
@api.onchange('price_unit') |
|||
def change_price_unit_line(self): |
|||
self._compute_amount_line_all() |
|||
|
|||
@api.depends('price_unit', 'tax_ids', 'qty', 'discount', 'discount_fixed', 'product_id') |
|||
def _compute_amount_line_all(self): |
|||
for line in self: |
|||
currency = line.order_id.pricelist_id.currency_id |
|||
taxes = line.tax_ids.filtered(lambda tax: tax.company_id.id == line.order_id.company_id.id) |
|||
fiscal_position_id = line.order_id.fiscal_position_id |
|||
if fiscal_position_id: |
|||
taxes = fiscal_position_id.map_tax(taxes) |
|||
# =============== finding subtotal for each orderline========================================================= |
|||
if line.discount_fixed != 0: |
|||
price = line.price_unit |
|||
line.price_subtotal = line.price_subtotal_incl = price * line.qty - line.discount_fixed |
|||
else: |
|||
price = line.price_unit |
|||
line.price_subtotal = line.price_subtotal_incl = (price * line.qty) - (price * line.qty * (line.discount or 0.0) / 100) |
|||
if taxes: |
|||
taxes = taxes.compute_all(price, currency, line.qty, product=line.product_id, partner=line.order_id.partner_id or False) |
|||
line.price_subtotal = taxes['total_excluded'] |
|||
line.price_subtotal_incl = taxes['total_included'] |
|||
line.price_subtotal = currency.round(line.price_subtotal) |
|||
line.price_subtotal_incl = currency.round(line.price_subtotal_incl) |
|||
|
|||
|
|||
class AccountMoveLineExtra(models.Model): |
|||
_inherit = 'account.move.line' |
|||
|
|||
_sql_constraints = [ |
|||
('credit_debit1', 'CHECK (credit*debit=0)', 'Wrong credit or debit value in accounting entry !'), |
|||
('credit_debit2', 'CHECK (credit*debit=0)', 'Wrong credit or debit value in accounting entry !'), |
|||
] |
|||
|
|||
@api.multi |
|||
def _update_check(self): |
|||
""" This module is overwritten, to avoid the warning raised when we edit the journal entries""" |
|||
move_ids = set() |
|||
for line in self: |
|||
err_msg = _('Move name (id): %s (%s)') % (line.move_id.name, str(line.move_id.id)) |
|||
if line.move_id.id not in move_ids: |
|||
move_ids.add(line.move_id.id) |
|||
self.env['account.move'].browse(list(move_ids))._check_lock_date() |
|||
return True |
|||
|
|||
@api.multi |
|||
def reconcile(self, writeoff_acc_id=False, writeoff_journal_id=False): |
|||
""" This function is overwritten to remove some warnings""" |
|||
# Perform all checks on lines |
|||
company_ids = set() |
|||
all_accounts = [] |
|||
partners = set() |
|||
for line in self: |
|||
company_ids.add(line.company_id.id) |
|||
all_accounts.append(line.account_id) |
|||
if (line.account_id.internal_type in ('receivable', 'payable')): |
|||
partners.add(line.partner_id.id) |
|||
if line.reconciled: |
|||
raise UserError(_('You are trying to reconcile some entries that are already reconciled!')) |
|||
if len(company_ids) > 1: |
|||
raise UserError(_('To reconcile the entries company should be the same for all entries!')) |
|||
if not all_accounts[0].reconcile: |
|||
raise UserError(_('The account %s (%s) is not marked as reconciliable !') % ( |
|||
all_accounts[0].name, all_accounts[0].code)) |
|||
# reconcile everything that can be |
|||
remaining_moves = self.auto_reconcile_lines() |
|||
|
|||
# if writeoff_acc_id specified, then create write-off move with value the remaining amount from move in self |
|||
if writeoff_acc_id and writeoff_journal_id and remaining_moves: |
|||
all_aml_share_same_currency = all([x.currency_id == self[0].currency_id for x in self]) |
|||
writeoff_vals = { |
|||
'account_id': writeoff_acc_id.id, |
|||
'journal_id': writeoff_journal_id.id |
|||
} |
|||
if not all_aml_share_same_currency: |
|||
writeoff_vals['amount_currency'] = False |
|||
writeoff_to_reconcile = remaining_moves._create_writeoff(writeoff_vals) |
|||
# add writeoff line to reconcile algo and finish the reconciliation |
|||
remaining_moves = (remaining_moves + writeoff_to_reconcile).auto_reconcile_lines() |
|||
return writeoff_to_reconcile |
|||
return True |
|||
|
|||
|
|||
class AccountMoveNew(models.Model): |
|||
_inherit = 'account.move' |
|||
|
|||
@api.multi |
|||
def assert_balanced(self): |
|||
"""Overwritten to remove the warning raised.(For editing the journal entry)""" |
|||
if not self.ids: |
|||
return True |
|||
prec = self.env['decimal.precision'].precision_get('Account') |
|||
|
|||
self._cr.execute("""\ |
|||
SELECT move_id |
|||
FROM account_move_line |
|||
WHERE move_id in %s |
|||
GROUP BY move_id |
|||
HAVING abs(sum(debit) - sum(credit)) > %s |
|||
""", (tuple(self.ids), 10 ** (-max(5, prec)))) |
|||
return True |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
@ -0,0 +1,70 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import time |
|||
from openerp.osv import osv |
|||
from openerp.report import report_sxw |
|||
|
|||
|
|||
class pos_payment_report_new(report_sxw.rml_parse): |
|||
|
|||
def __init__(self, cr, uid, name, context): |
|||
super(pos_payment_report_new, self).__init__(cr, uid, name, context=context) |
|||
self.total = 0.0 |
|||
self.localcontext.update({ |
|||
'time': time, |
|||
'pos_payment': self._pos_payment, |
|||
'pos_payment_total':self._pos_payment_total, |
|||
'pos_fixed_discount':self._pos_fixed_discount, |
|||
'pos_percent_discount': self._pos_percent_discount, |
|||
}) |
|||
|
|||
def _pos_payment(self, obj): |
|||
self.total = 0 |
|||
self.discount_total = 0 |
|||
self.discount_percent = 0 |
|||
data={} |
|||
new_data={} |
|||
sql = """ select id from pos_order where id = %d"""%(obj.id) |
|||
self.cr.execute(sql) |
|||
if self.cr.fetchone(): |
|||
self.cr.execute ("select pol.id,pt.name,pp.default_code as code,pol.qty,pu.name as uom,pol.discount,pol.discount_fixed,pol.price_unit, " \ |
|||
"(pol.price_unit * pol.qty) as total " \ |
|||
"from pos_order as po,pos_order_line as pol,product_product as pp,product_template as pt, product_uom as pu " \ |
|||
"where pt.id=pp.product_tmpl_id and pp.id=pol.product_id and po.id = pol.order_id and pu.id=pt.uom_id " \ |
|||
"and po.state IN ('paid','invoiced') and to_char(date_trunc('day',po.date_order),'YYYY-MM-DD')::date = current_date and po.id=%d"%(obj.id)) |
|||
data = self.cr.dictfetchall() |
|||
|
|||
else: |
|||
self.cr.execute ("select pt.name,pp.default_code as code,pol.qty,pu.name as uom,pol.discount,pol.discount_fixed,pol.price_unit, " \ |
|||
"(pol.price_unit * pol.qty) as total " \ |
|||
"from pos_order as po,pos_order_line as pol,product_product as pp,product_template as pt, product_uom as pu " \ |
|||
"where pt.id=pp.product_tmpl_id and pp.id=pol.product_id and po.id = pol.order_id and pu.id=pt.uom_id " \ |
|||
"and po.state IN ('paid','invoiced') and to_char(date_trunc('day',po.date_order),'YYYY-MM-DD')::date = current_date") |
|||
data = self.cr.dictfetchall() |
|||
|
|||
for d in data: |
|||
if d['discount_fixed'] != 0: |
|||
d['total'] = d['price_unit'] * d['qty'] - d['discount_fixed'] |
|||
else: |
|||
d['total'] = d['price_unit'] * d['qty'] * (1 - (d['discount'] / 100)) |
|||
|
|||
self.total = obj.amount_total |
|||
self.discount_total += obj.discount_total |
|||
self.discount_percent += obj.discount_percent |
|||
return data |
|||
|
|||
def _pos_payment_total(self, o): |
|||
return self.total |
|||
|
|||
def _pos_fixed_discount(self, o): |
|||
return self.discount_total |
|||
|
|||
def _pos_percent_discount(self, o): |
|||
return self.discount_percent |
|||
|
|||
|
|||
class report_pos_payment(osv.AbstractModel): |
|||
_name = 'report.discounts_in_pos.report_payment' |
|||
_inherit = 'report.abstract_report' |
|||
_template = 'discounts_in_pos.report_payment' |
|||
_wrapped_report_class = pos_payment_report_new |
@ -0,0 +1,65 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
import time |
|||
from openerp.osv import osv |
|||
from openerp.report import report_sxw |
|||
|
|||
|
|||
def titlize(journal_name): |
|||
words = journal_name.split() |
|||
while words.pop() != 'journal': |
|||
continue |
|||
return ' '.join(words) |
|||
|
|||
|
|||
class order(report_sxw.rml_parse): |
|||
|
|||
def __init__(self, cr, uid, name, context): |
|||
super(order, self).__init__(cr, uid, name, context=context) |
|||
|
|||
user = self.pool['res.users'].browse(cr, uid, uid, context=context) |
|||
partner = user.company_id.partner_id |
|||
|
|||
self.localcontext.update({ |
|||
'time': time, |
|||
'disc': self.discount, |
|||
'net': self.netamount, |
|||
'get_journal_amt': self._get_journal_amt, |
|||
'address': partner or False, |
|||
'titlize': titlize |
|||
}) |
|||
|
|||
def netamount(self, order_line_id): |
|||
sql = 'select (qty*price_unit) as net_price from pos_order_line where id = %s' |
|||
self.cr.execute(sql, (order_line_id,)) |
|||
res = self.cr.fetchone() |
|||
return res[0] |
|||
|
|||
def discount(self, order_id): |
|||
sql = 'select discount, discount_fixed, price_unit, qty from pos_order_line where order_id = %s ' |
|||
self.cr.execute(sql, (order_id,)) |
|||
res = self.cr.fetchall() |
|||
dsum = 0 |
|||
for line in res: |
|||
if line[1] != 0: |
|||
dsum = dsum + (line[1]) |
|||
else: |
|||
dsum = dsum + (line[3] * (line[0] * line[2] / 100)) |
|||
return dsum |
|||
|
|||
def _get_journal_amt(self, order_id): |
|||
data={} |
|||
sql = """ select aj.name,absl.amount as amt from account_bank_statement as abs |
|||
LEFT JOIN account_bank_statement_line as absl ON abs.id = absl.statement_id |
|||
LEFT JOIN account_journal as aj ON aj.id = abs.journal_id |
|||
WHERE absl.pos_statement_id =%d"""%(order_id) |
|||
self.cr.execute(sql) |
|||
data = self.cr.dictfetchall() |
|||
return data |
|||
|
|||
|
|||
class report_order_receipt(osv.AbstractModel): |
|||
_name = 'report.discounts_in_pos.report_receipt' |
|||
_inherit = 'report.abstract_report' |
|||
_template = 'discounts_in_pos.report_receipt' |
|||
_wrapped_report_class = order |
After Width: | Height: | Size: 91 KiB |
After Width: | Height: | Size: 128 KiB |
After Width: | Height: | Size: 50 KiB |
After Width: | Height: | Size: 253 KiB |
After Width: | Height: | Size: 16 KiB |
@ -0,0 +1,169 @@ |
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<h2 class="oe_slogan">POS Discount Total</h2> |
|||
<h3 class="oe_slogan">POS Discount Total(Fixed and Percentage)</h3> |
|||
<h4 class="oe_slogan">Cybrosys Technologies , www.cybrosys.com</h4> |
|||
<div> |
|||
<h4><p>Features:</p></h4> |
|||
<ul> |
|||
<li style="list-style:none !important;"><span style="color:green;"> ☑</span> Percentage discount on order lines.</li> |
|||
<li style="list-style:none !important;"><span style="color:green;"> ☑</span> Fixed discount on order lines.</li> |
|||
<li style="list-style:none !important;"><span style="color:green;"> ☑</span> Percentage discount on order.</li> |
|||
<li style="list-style:none !important;"><span style="color:green;"> ☑</span> Fixed discount on order.</li> |
|||
</ul> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container oe_dark"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<center> |
|||
<p class="oe_mt32"> |
|||
This module allows us to provide different types of discounts in point of sale. |
|||
Possible discounts are, fixed discounts and percentage discounts(Order lines and Order). |
|||
</p> |
|||
</center> |
|||
|
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<h3 class="oe_slogan">Fixed discount on order lines.</h3> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<center> |
|||
<div class="oe_row_img oe_centered"> |
|||
<img class="oe_picture oe_screenshot" src="discount-button.png"> |
|||
</div> |
|||
</center> |
|||
|
|||
</div> |
|||
<div class="oe_span12"> |
|||
<p class="oe_mt32"> |
|||
A new button 'Disc.Fixed' is added for providing fixed discounts on orderlines. By clicking on this |
|||
button, we can enter the fixed discount. After we have entered the discount, |
|||
it will be shown under the product name of the orderline to which we have applied the discount. |
|||
</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container oe_dark"> |
|||
<div class="oe_row oe_spaced"> |
|||
<h3 class="oe_slogan">Percentage discount on order.</h3> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<center> |
|||
<p class="oe_mt32"> |
|||
If we need to provide discount on the total amount of an order, it can be done using this module. |
|||
The button 'Disc(Total%)' can be used to provide percentage discounts to an order. |
|||
</p> |
|||
</center> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<h3 class="oe_slogan">Fixed discount on order.</h3> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<p class="oe_mt32"> |
|||
This feature can be used to apply a fixed amount discount to an order. The button 'Dis.Fixed(Total)' |
|||
can be used for this purpose.</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container oe_dark"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<p class="oe_mt32"> |
|||
We can have either one type of discount at a time for an order and order line. i.e, it is |
|||
not possible to provide percentage discount and fixed discount at the same time. |
|||
Suppose we have applied fixed discount on an order or orderline, then if we try to apply |
|||
percentage discount, the existing discount will be removed and new one will be applied. |
|||
</p> |
|||
<p> |
|||
The applied discounts will be shown in the receipts and the reports. |
|||
</p> |
|||
</div> |
|||
<div class="oe_span6"> |
|||
<div class="oe_row_img oe_centered"> |
|||
<img class="oe_picture oe_screenshot" src="receipt.png"> |
|||
</div> |
|||
</div> |
|||
<div class="oe_span6"> |
|||
<center> |
|||
<div class="oe_row_img oe_centered"> |
|||
<img class="oe_picture oe_screenshot" src="receipt-percentage.png"> |
|||
</div> |
|||
</center> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<img class="oe_picture oe_screenshot" src="total-disc.png"> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container oe_dark"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_row oe_spaced"> |
|||
<div class="oe_span12"> |
|||
<p class="oe_mt32"> |
|||
Before providing discounts we need to set an account for recording the discount amount. It can be |
|||
created when we are creating the point of sale. |
|||
</p> |
|||
</div> |
|||
<div class="oe_span12"> |
|||
<img class="oe_picture oe_screenshot" src="account.png"> |
|||
</div> |
|||
|
|||
</div> |
|||
</div> |
|||
</section> |
|||
|
|||
<section class="oe_container"> |
|||
<h2 class="oe_slogan" style="margin-top:20px;" >Need Any Help?</h2> |
|||
<div class="oe_slogan" style="margin-top:10px !important;"> |
|||
<div> |
|||
<a class="btn btn-primary btn-lg mt8" |
|||
style="color: #FFFFFF !important;border-radius: 0;" href="https://www.cybrosys.com"><i |
|||
class="fa fa-envelope"></i> Email </a> <a |
|||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
|||
href="https://www.cybrosys.com/contact/"><i |
|||
class="fa fa-phone"></i> Contact Us </a> <a |
|||
class="btn btn-primary btn-lg mt8" style="color: #FFFFFF !important;border-radius: 0;" |
|||
href="https://www.cybrosys.com/odoo-customization-and-installation/"><i |
|||
class="fa fa-check-square"></i> Request Customization </a> |
|||
</div> |
|||
<br> |
|||
<img src="cybro_logo.png" style="width: 190px; margin-bottom: 20px;" class="center-block"> |
|||
<div> |
|||
<a href="https://twitter.com/cybrosys" target="_blank"><i class="fa fa-2x fa-twitter" style="color:white;background: #00a0d1;width:35px;"></i></a></td> |
|||
<a href="https://www.linkedin.com/company/cybrosys-technologies-pvt-ltd" target="_blank"><i class="fa fa-2x fa-linkedin" style="color:white;background: #31a3d6;width:35px;padding-left: 3px;"></i></a></td> |
|||
<a href="https://www.facebook.com/cybrosystechnologies" target="_blank"><i class="fa fa-2x fa-facebook" style="color:white;background: #3b5998;width:35px;padding-left: 8px;"></i></a></td> |
|||
<a href="https://plus.google.com/106641282743045431892/about" target="_blank"><i class="fa fa-2x fa-google-plus" style="color:white;background: #c53c2c;width:35px;padding-left: 3px;"></i></a></td> |
|||
<a href="https://in.pinterest.com/cybrosys" target="_blank"><i class="fa fa-2x fa-pinterest" style="color:white;background: #ac0f18;width:35px;padding-left: 3px;"></i></a></td> |
|||
</div> |
|||
</div> |
|||
</section> |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 41 KiB |
@ -0,0 +1,486 @@ |
|||
odoo.define('discounts_in_pos', function (require) { |
|||
"use strict"; |
|||
|
|||
var screens = require('point_of_sale.screens'); |
|||
var models = require('point_of_sale.models'); |
|||
var core = require('web.core'); |
|||
var formats = require('web.formats'); |
|||
var utils = require('web.utils'); |
|||
|
|||
var QWeb = core.qweb; |
|||
var round_di = utils.round_decimals; |
|||
var round_pr = utils.round_precision; |
|||
|
|||
screens.OrderWidget.include({ |
|||
|
|||
set_value: function(val) { |
|||
var order = this.pos.get_order(); |
|||
if (order.get_selected_orderline()) { |
|||
var mode = this.numpad_state.get('mode'); |
|||
if( mode === 'quantity'){ |
|||
order.get_selected_orderline().set_quantity(val); |
|||
}else if( mode === 'discount'){ |
|||
order.get_selected_orderline().set_discount(val); |
|||
}else if( mode === 'price'){ |
|||
order.get_selected_orderline().set_unit_price(val); |
|||
} |
|||
// for the new button 'DiscFix'
|
|||
else if( mode === 'discount_fixed'){ |
|||
console.log(order) |
|||
console.log(order.get_selected_orderline()) |
|||
order.get_selected_orderline().set_discount_fixed(val); |
|||
} |
|||
else if( mode === 'discount_total'){ |
|||
order.get_selected_orderline().set_discount_total(val); |
|||
order.set_discount_total_order(val); |
|||
} |
|||
else if( mode === 'discount_percent'){ |
|||
order.get_selected_orderline().set_discount_percent(val); |
|||
order.set_discount_percent_order(val); |
|||
} |
|||
} |
|||
}, |
|||
// ============================updates total discount(fixed and percentage) on order ==========================================
|
|||
update_summary: function(){ |
|||
var order = this.pos.get_order(); |
|||
if (!order.get_orderlines().length) { |
|||
return; |
|||
} |
|||
var total = order ? order.get_total_with_tax() : 0; |
|||
var taxes = order ? total - order.get_total_without_tax() : 0; |
|||
var discount_total = (order && order.get_discount_total_order() > 0) ? order.get_discount_total_order() : 0; |
|||
var discount_percent = (order && order.get_discount_percent_order() > 0) ? order.get_discount_percent_order() : 0; |
|||
|
|||
this.el.querySelector('.summary .total > .value').textContent = this.format_currency(total); |
|||
this.el.querySelector('.summary .total .subentry .value').textContent = this.format_currency(taxes); |
|||
|
|||
if (discount_total > 0) { |
|||
this.el.querySelector('.summary .total .subentry .value_discount_percent').textContent = ""; |
|||
this.el.querySelector('.summary .total .subentry .value_discount_total').textContent = "Discount(Total Fixed)" +this.format_currency(discount_total); |
|||
} |
|||
else { |
|||
this.el.querySelector('.summary .total .subentry .value_discount_total').textContent = ""; |
|||
} |
|||
if (discount_percent > 0) { |
|||
this.el.querySelector('.summary .total .subentry .value_discount_total').textContent = ""; |
|||
this.el.querySelector('.summary .total .subentry .value_discount_percent').textContent = "Discount(Total %)" + discount_percent; |
|||
} |
|||
else { |
|||
this.el.querySelector('.summary .total .subentry .value_discount_percent').textContent = ""; |
|||
} |
|||
}, |
|||
}); |
|||
var OrderlineSuper = models.Orderline; |
|||
models.Orderline = models.Orderline.extend({ |
|||
initialize: function(attr,options){ |
|||
OrderlineSuper.prototype.initialize.call(this, attr,options); |
|||
this.discount_fixed = 0; |
|||
this.discount_total = 0; |
|||
this.discount_percent = 0; |
|||
}, |
|||
init_from_JSON: function(json) { |
|||
OrderlineSuper.prototype.init_from_JSON.call(this, json); |
|||
if(json.discount_fixed > 0) { |
|||
this.set_discount_fixed(json.discount_fixed); |
|||
} |
|||
else { |
|||
this.set_discount(json.discount); |
|||
} |
|||
}, |
|||
clone: function(){ |
|||
var orderline = OrderlineSuper.prototype.clone.call(this); |
|||
orderline.discount_fixed = this.discount_fixed; |
|||
return orderline; |
|||
}, |
|||
set_discount: function(discount){ |
|||
OrderlineSuper.prototype.set_discount.call(this, discount); |
|||
this.discount_fixed = 0.0; |
|||
this.discount_total = 0.0; |
|||
this.discount_percent = 0.0; |
|||
this.discountStr = 'percentage'; |
|||
this.trigger('change',this); |
|||
}, |
|||
set_discount_fixed: function(discount){ |
|||
this.discount_fixed = discount; |
|||
this.discount = 0.0; |
|||
this.discount_total = 0.0; |
|||
this.discount_percent = 0.0; |
|||
this.discountStr = 'fixed' ; |
|||
this.trigger('change',this); |
|||
}, |
|||
set_discount_total: function(discount){ |
|||
this.discount_total = discount; |
|||
this.discount_percent = 0.0; |
|||
}, |
|||
set_discount_percent: function(discount){ |
|||
var disc = Math.min(Math.max(parseFloat(discount) || 0, 0),100); |
|||
this.discount_percent = disc; |
|||
this.discount_total = 0.0; |
|||
}, |
|||
get_discount_total: function(){ |
|||
return this.discount_total; |
|||
}, |
|||
get_discount_percent: function(){ |
|||
return this.discount_percent; |
|||
}, |
|||
get_discount_fixed: function(){ |
|||
return this.discount_fixed; |
|||
}, |
|||
set_quantity: function(quantity){ |
|||
var order = this.pos.get_order(); |
|||
if (order) { |
|||
if(order.selected_orderline == undefined) { |
|||
order.set_discount_total_order(0); |
|||
order.set_discount_percent_order(0); |
|||
} |
|||
} |
|||
|
|||
this.order.assert_editable(); |
|||
if(quantity === 'remove'){ |
|||
this.order.remove_orderline(this); |
|||
return; |
|||
}else{ |
|||
var quant = parseFloat(quantity) || 0; |
|||
|
|||
var unit = this.get_unit(); |
|||
if(unit){ |
|||
if (unit.rounding) { |
|||
this.quantity = round_pr(quant, unit.rounding); |
|||
var decimals = this.pos.dp['Product Unit of Measure']; |
|||
this.quantityStr = formats.format_value(round_di(this.quantity, decimals), { type: 'float', digits: [69, decimals]}); |
|||
} else { |
|||
this.quantity = round_pr(quant, 1); |
|||
this.quantityStr = this.quantity.toFixed(0); |
|||
} |
|||
}else{ |
|||
this.quantity = quant; |
|||
this.quantityStr = '' + this.quantity; |
|||
} |
|||
} |
|||
this.trigger('change',this); |
|||
}, |
|||
can_be_merged_with: function(orderline){ |
|||
if( this.get_product().id !== orderline.get_product().id){ //only orderline of the same product can be merged
|
|||
return false; |
|||
}else if(!this.get_unit() || !this.get_unit().groupable){ |
|||
return false; |
|||
}else if(this.get_product_type() !== orderline.get_product_type()){ |
|||
return false; |
|||
}else if(this.get_discount() > 0){ // we don't merge discounted orderlines
|
|||
return false; |
|||
}else if(this.get_discount_fixed() > 0){ // we don't merge discounted orderlines
|
|||
return false; |
|||
}else if(this.price !== orderline.price){ |
|||
return false; |
|||
}else{ |
|||
return true; |
|||
} |
|||
}, |
|||
export_as_JSON: function() { |
|||
return { |
|||
qty: this.get_quantity(), |
|||
price_unit: this.get_unit_price(), |
|||
discount: this.get_discount(), |
|||
discount_fixed: this.get_discount_fixed(), |
|||
discount_total: this.get_discount_total(), |
|||
discount_percent: this.get_discount_percent(), |
|||
discountStr:this.get_discount_str(), |
|||
product_id: this.get_product().id, |
|||
tax_ids: [[6, false, _.map(this.get_applicable_taxes(), function(tax){ return tax.id; })]], |
|||
id: this.id, |
|||
}; |
|||
}, |
|||
export_for_printing: function(){ |
|||
return { |
|||
quantity: this.get_quantity(), |
|||
unit_name: this.get_unit().name, |
|||
price: this.get_unit_display_price(), |
|||
discount: this.get_discount(), |
|||
discount_fixed: this.get_discount_fixed(), |
|||
discount_total: this.get_discount_total(), |
|||
discount_percent: this.get_discount_percent(), |
|||
discountStr: this.get_discount_str(), |
|||
product_name: this.get_product().display_name, |
|||
price_display : this.get_display_price(), |
|||
price_with_tax : this.get_price_with_tax(), |
|||
price_without_tax: this.get_price_without_tax(), |
|||
tax: this.get_tax(), |
|||
product_description: this.get_product().description, |
|||
product_description_sale: this.get_product().description_sale, |
|||
}; |
|||
}, |
|||
get_base_price: function(){ |
|||
var rounding = this.pos.currency.rounding; |
|||
if(this.discount_fixed !== 0){ |
|||
return round_pr(this.get_unit_price() * this.get_quantity() - this.get_discount_fixed(), rounding); |
|||
} |
|||
|
|||
return round_pr(this.get_unit_price() * this.get_quantity() * (1 - this.get_discount()/100), rounding); |
|||
}, |
|||
get_all_prices: function(){ |
|||
|
|||
if(this.discount_fixed > 0) |
|||
{ |
|||
var price_unit = this.get_unit_price() * this.get_quantity() - this.get_discount_fixed(); |
|||
} |
|||
else { |
|||
var price_unit = this.get_unit_price() * (1.0 - (this.get_discount() / 100.0)); |
|||
} |
|||
var taxtotal = 0; |
|||
|
|||
var product = this.get_product(); |
|||
var taxes_ids = product.taxes_id; |
|||
var taxes = this.pos.taxes; |
|||
var taxdetail = {}; |
|||
var product_taxes = []; |
|||
|
|||
_(taxes_ids).each(function(el){ |
|||
product_taxes.push(_.detect(taxes, function(t){ |
|||
return t.id === el; |
|||
})); |
|||
}); |
|||
|
|||
var all_taxes = this.compute_all(product_taxes, price_unit, this.get_quantity(), this.pos.currency.rounding); |
|||
_(all_taxes.taxes).each(function(tax) { |
|||
taxtotal += tax.amount; |
|||
taxdetail[tax.id] = tax.amount; |
|||
}); |
|||
if(this.get_discount_fixed() != 0) { |
|||
all_taxes.total_excluded = price_unit; |
|||
} |
|||
return { |
|||
"priceWithTax": all_taxes.total_included, |
|||
"priceWithoutTax": all_taxes.total_excluded, |
|||
"tax": taxtotal, |
|||
"taxDetails": taxdetail, |
|||
}; |
|||
}, |
|||
}); |
|||
|
|||
var OrderSuper = models.Order; |
|||
models.Order = models.Order.extend({ |
|||
initialize: function(attributes,options){ |
|||
var order = OrderSuper.prototype.initialize.call(this, attributes,options); |
|||
order.discount_total = 0; |
|||
order.discount_percent = 0; |
|||
return order; |
|||
}, |
|||
init_from_JSON: function(json) { |
|||
OrderSuper.prototype.init_from_JSON.call(this, json); |
|||
this.discount_total = json.discount_total; |
|||
this.discount_percent = json.discount_percent; |
|||
}, |
|||
export_as_JSON: function() { |
|||
var json_new = OrderSuper.prototype.export_as_JSON.call(this); |
|||
json_new.discount_total = this.get_discount_total_order(); |
|||
json_new.discount_percent = this.get_discount_percent_order(); |
|||
return json_new; |
|||
}, |
|||
export_for_printing: function(){ |
|||
var orderlines = []; |
|||
var self = this; |
|||
|
|||
this.orderlines.each(function(orderline){ |
|||
orderlines.push(orderline.export_for_printing()); |
|||
}); |
|||
|
|||
var paymentlines = []; |
|||
this.paymentlines.each(function(paymentline){ |
|||
paymentlines.push(paymentline.export_for_printing()); |
|||
}); |
|||
var client = this.get('client'); |
|||
var cashier = this.pos.cashier || this.pos.user; |
|||
var company = this.pos.company; |
|||
var shop = this.pos.shop; |
|||
var date = new Date(); |
|||
|
|||
function is_xml(subreceipt){ |
|||
return subreceipt ? (subreceipt.split('\n')[0].indexOf('<!DOCTYPE QWEB') >= 0) : false; |
|||
} |
|||
|
|||
function render_xml(subreceipt){ |
|||
if (!is_xml(subreceipt)) { |
|||
return subreceipt; |
|||
} else { |
|||
subreceipt = subreceipt.split('\n').slice(1).join('\n'); |
|||
var qweb = new QWeb2.Engine(); |
|||
qweb.debug = core.debug; |
|||
qweb.default_dict = _.clone(QWeb.default_dict); |
|||
qweb.add_template('<templates><t t-name="subreceipt">'+subreceipt+'</t></templates>'); |
|||
|
|||
return qweb.render('subreceipt',{'pos':self.pos,'widget':self.pos.chrome,'order':self, 'receipt': receipt}) ; |
|||
} |
|||
} |
|||
|
|||
var receipt = { |
|||
orderlines: orderlines, |
|||
paymentlines: paymentlines, |
|||
subtotal: this.get_subtotal(), |
|||
total_with_tax: this.get_total_with_tax(), |
|||
total_without_tax: this.get_total_without_tax(), |
|||
total_tax: this.get_total_tax(), |
|||
total_paid: this.get_total_paid(), |
|||
discount_total_fixed: this.get_discount_total_order(), |
|||
discount_total_percent: this.get_discount_percent_order(), |
|||
total_discount: this.get_total_discount(), |
|||
tax_details: this.get_tax_details(), |
|||
change: this.get_change(), |
|||
name : this.get_name(), |
|||
client: client ? client.name : null , |
|||
invoice_id: null, //TODO
|
|||
cashier: cashier ? cashier.name : null, |
|||
precision: { |
|||
price: 2, |
|||
money: 2, |
|||
quantity: 3, |
|||
}, |
|||
date: { |
|||
year: date.getFullYear(), |
|||
month: date.getMonth(), |
|||
date: date.getDate(), // day of the month
|
|||
day: date.getDay(), // day of the week
|
|||
hour: date.getHours(), |
|||
minute: date.getMinutes() , |
|||
isostring: date.toISOString(), |
|||
localestring: date.toLocaleString(), |
|||
}, |
|||
company:{ |
|||
email: company.email, |
|||
website: company.website, |
|||
company_registry: company.company_registry, |
|||
contact_address: company.partner_id[1], |
|||
vat: company.vat, |
|||
name: company.name, |
|||
phone: company.phone, |
|||
logo: this.pos.company_logo_base64, |
|||
}, |
|||
shop:{ |
|||
name: shop.name, |
|||
}, |
|||
currency: this.pos.currency, |
|||
}; |
|||
|
|||
if (is_xml(this.pos.config.receipt_header)){ |
|||
receipt.header = ''; |
|||
receipt.header_xml = render_xml(this.pos.config.receipt_header); |
|||
} else { |
|||
receipt.header = this.pos.config.receipt_header || ''; |
|||
} |
|||
|
|||
if (is_xml(this.pos.config.receipt_footer)){ |
|||
receipt.footer = ''; |
|||
receipt.footer_xml = render_xml(this.pos.config.receipt_footer); |
|||
} else { |
|||
receipt.footer = this.pos.config.receipt_footer || ''; |
|||
} |
|||
|
|||
return receipt; |
|||
}, |
|||
set_discount_total_order: function(discount){ |
|||
this.discount_total = discount; |
|||
this.discount_percent = 0; |
|||
this.trigger('change',this); |
|||
}, |
|||
get_discount_total_order: function(){ |
|||
return this.discount_total; |
|||
}, |
|||
set_discount_percent_order: function(discount){ |
|||
var disc = Math.min(Math.max(parseFloat(discount) || 0, 0),100); |
|||
this.discount_percent = disc; |
|||
this.discount_total = 0.0; |
|||
this.trigger('change',this); |
|||
}, |
|||
get_discount_percent_order: function(){ |
|||
return this.discount_percent; |
|||
}, |
|||
get_total_without_tax: function() { |
|||
var total_fixed_disc = this.get_discount_total_order(); |
|||
var total_percent_disc = this.get_discount_percent_order(); |
|||
if (total_fixed_disc) { |
|||
return round_pr(this.orderlines.reduce((function(sum, orderLine) { |
|||
return sum + orderLine.get_price_without_tax(); |
|||
}), 0), this.pos.currency.rounding) - total_fixed_disc ; |
|||
} |
|||
if (total_percent_disc) { |
|||
var temp = round_pr(this.orderlines.reduce((function(sum, orderLine) { |
|||
return sum + orderLine.get_price_without_tax(); |
|||
}), 0), this.pos.currency.rounding); |
|||
return (temp - (temp * total_percent_disc / 100)) |
|||
} |
|||
return round_pr(this.orderlines.reduce((function(sum, orderLine) { |
|||
return sum + orderLine.get_price_without_tax(); |
|||
}), 0), this.pos.currency.rounding); |
|||
}, |
|||
get_total_discount: function() { |
|||
var sum = OrderSuper.prototype.get_total_discount.call(this); |
|||
sum = 0.0; |
|||
var disc = 0.0; |
|||
for (var i = 0; i < this.orderlines.length; i++) { |
|||
var NewOrder = this.orderlines.models[i]; |
|||
disc += (NewOrder.quantity * NewOrder.price); |
|||
if (NewOrder.discountStr == 'fixed') { |
|||
sum += parseFloat(NewOrder.discount_fixed); |
|||
} |
|||
else { |
|||
sum += NewOrder.quantity * NewOrder.price * (parseFloat(NewOrder.discount) / 100); |
|||
} |
|||
} |
|||
if (this.discount_total) { sum += parseFloat(this.discount_total); } |
|||
disc -= parseFloat(this.get_total_without_tax() + sum); |
|||
if (this.discount_percent) { sum += disc; } |
|||
|
|||
return sum; |
|||
|
|||
}, |
|||
}); |
|||
models.PosModel = models.PosModel.extend({ |
|||
push_and_invoice_order: function(order){ |
|||
var self = this; |
|||
var invoiced = new $.Deferred(); |
|||
|
|||
if(!order.get_client()){ |
|||
invoiced.reject({code:400, message:'Missing Customer', data:{}}); |
|||
return invoiced; |
|||
} |
|||
|
|||
var order_id = this.db.add_order(order.export_as_JSON()); |
|||
|
|||
this.flush_mutex.exec(function(){ |
|||
var done = new $.Deferred(); // holds the mutex
|
|||
|
|||
// send the order to the server
|
|||
// we have a 30 seconds timeout on this push.
|
|||
// FIXME: if the server takes more than 30 seconds to accept the order,
|
|||
// the client will believe it wasn't successfully sent, and very bad
|
|||
// things will happen as a duplicate will be sent next time
|
|||
// so we must make sure the server detects and ignores duplicated orders
|
|||
|
|||
var transfer = self._flush_orders([self.db.get_order(order_id)], {timeout:30000, to_invoice:true}); |
|||
|
|||
transfer.fail(function(error){ |
|||
invoiced.reject(error); |
|||
done.reject(); |
|||
}); |
|||
|
|||
// on success, get the order id generated by the server
|
|||
transfer.pipe(function(order_server_id){ |
|||
|
|||
// generate the pdf and download it
|
|||
self.chrome.do_action('discounts_in_pos.pos_invoice_report',{additional_context:{ |
|||
active_ids:order_server_id, |
|||
}}); |
|||
|
|||
invoiced.resolve(); |
|||
done.resolve(); |
|||
}); |
|||
|
|||
return done; |
|||
|
|||
}); |
|||
|
|||
return invoiced; |
|||
}, |
|||
}); |
|||
}); |
|||
|
|||
|
@ -0,0 +1,223 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<templates id="pos_extend_template" inherit_id="point_of_sale.template"> |
|||
|
|||
<t t-extend="NumpadWidget"> |
|||
|
|||
<t t-jquery="div.numpad" t-operation="inner"> |
|||
|
|||
<button class="input-button number-char">1</button> |
|||
<button class="input-button number-char">2</button> |
|||
<button class="input-button number-char">3</button> |
|||
<button class="mode-button" data-mode='quantity'>Qty</button> |
|||
<br /> |
|||
<button class="input-button number-char">4</button> |
|||
<button class="input-button number-char">5</button> |
|||
<button class="input-button number-char">6</button> |
|||
<button class="mode-button" data-mode='discount'>Disc</button> |
|||
<br /> |
|||
<button class="input-button number-char">7</button> |
|||
<button class="input-button number-char">8</button> |
|||
<button class="input-button number-char">9</button> |
|||
<button class="mode-button" data-mode='price'>Price</button> |
|||
<br /> |
|||
<button class="input-button numpad-minus" >+/-</button> |
|||
<button class="input-button number-char">0</button> |
|||
<button class="input-button number-char">.</button> |
|||
<button class="input-button numpad-backspace"> |
|||
<img style="pointer-events: none;" src="/point_of_sale/static/src/img/backspace.png" width="24" height="21" /> |
|||
</button> |
|||
<br /> |
|||
<button class="mode-button" data-mode='discount_fixed' style="width:100%;height:45px;">Disc.Fixed</button> |
|||
<button class="mode-button" data-mode='discount_percent' style="width:40%;height:45px;">Disc(Total %)</button> |
|||
<br /> |
|||
<button class="mode-button" data-mode='discount_total' style="width:60%;height:45px;">Dis.Fixed(Total)</button> |
|||
</t> |
|||
|
|||
</t> |
|||
|
|||
<t t-name="Orderline"> |
|||
<li t-attf-class="orderline #{ line.selected ? 'selected' : '' }"> |
|||
<span class="product-name"> |
|||
<t t-esc="line.get_product().display_name"/> |
|||
</span> |
|||
<span class="price"> |
|||
<t t-esc="widget.format_currency(line.get_display_price())"/> |
|||
</span> |
|||
<ul class="info-list"> |
|||
<t t-if="line.get_quantity_str() !== '1' || line.selected "> |
|||
<li class="info"> |
|||
<em> |
|||
<t t-esc="line.get_quantity_str()" /> |
|||
</em> |
|||
<t t-esc="line.get_unit().name" /> |
|||
at |
|||
<t t-esc="widget.format_currency(line.get_unit_display_price(),'Product Price')" /> |
|||
/ |
|||
<t t-esc="line.get_unit().name" /> |
|||
</li> |
|||
</t> |
|||
<t t-if="line.get_discount()"> |
|||
<li class="info"> |
|||
With a |
|||
<em> |
|||
<t t-esc="line.get_discount()" />% |
|||
</em> |
|||
discount |
|||
</li> |
|||
</t> |
|||
<t t-if="line.get_discount_fixed()"> |
|||
<li class="info"> |
|||
With a |
|||
<em> |
|||
<t t-esc="widget.format_currency(line.get_discount_fixed())"/> |
|||
</em> |
|||
discount |
|||
</li> |
|||
</t> |
|||
</ul> |
|||
</li> |
|||
</t> |
|||
|
|||
<t t-name="OrderWidget"> |
|||
<div class="order-container"> |
|||
<div class="order-scroller touch-scrollable"> |
|||
<div class="order"> |
|||
<t t-if="orderlines.length === 0" > |
|||
<div class='order-empty'> |
|||
<i class='fa fa-shopping-cart' /> |
|||
<h1>Your shopping cart is empty</h1> |
|||
</div> |
|||
</t> |
|||
<t t-if="orderlines.length > 0"> |
|||
<ul class="orderlines"></ul> |
|||
<div class="summary clearfix"> |
|||
<div class="line"> |
|||
<div class='entry total'> |
|||
<span class="label">Total: </span> <span class="value">0.00 €</span> |
|||
<div class='subentry'>Taxes: <span class="value">0.00€</span></div> |
|||
|
|||
<div class='subentry'><span class="value_discount_total"></span></div> |
|||
<div class='subentry'><span class="value_discount_percent"></span></div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
|
|||
<t t-name="PosTicket"> |
|||
<div class="pos-sale-ticket"> |
|||
|
|||
<div class="pos-center-align"><t t-esc="moment().format('L LT')"/> <t t-esc="order.name"/></div> |
|||
<br /> |
|||
<t t-esc="widget.pos.company.name"/><br /> |
|||
Phone: <t t-esc="widget.pos.company.phone || ''"/><br /> |
|||
User: <t t-esc="widget.pos.cashier ? widget.pos.cashier.name : widget.pos.user.name"/><br /> |
|||
Shop: <t t-esc="widget.pos.shop.name"/><br /> |
|||
<br /> |
|||
<t t-if="receipt.header"> |
|||
<div style='text-align:center'> |
|||
<t t-esc="receipt.header" /> |
|||
</div> |
|||
<br /> |
|||
</t> |
|||
<table class='receipt-orderlines'> |
|||
<colgroup> |
|||
<col width='50%' /> |
|||
<col width='25%' /> |
|||
<col width='25%' /> |
|||
</colgroup> |
|||
<tr t-foreach="orderlines" t-as="orderline"> |
|||
<td> |
|||
<t t-esc="orderline.get_product().display_name"/> |
|||
<t t-if="orderline.get_discount() > 0"> |
|||
<div class="pos-disc-font"> |
|||
With a <t t-esc="orderline.get_discount()"/>% discount |
|||
</div> |
|||
</t> |
|||
<t t-if="orderline.get_discount_fixed() > 0"> |
|||
<div class="pos-disc-font"> |
|||
With a <t t-esc="widget.format_currency(orderline.get_discount_fixed())"/> discount |
|||
</div> |
|||
</t> |
|||
</td> |
|||
<td class="pos-right-align"> |
|||
<t t-esc="orderline.get_quantity_str_with_unit()"/> |
|||
</td> |
|||
<td class="pos-right-align"> |
|||
<t t-esc="widget.format_currency(orderline.get_display_price())"/> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
<br /> |
|||
<table class='receipt-total'> |
|||
<tr> |
|||
<td>Subtotal:</td> |
|||
<td class="pos-right-align"> |
|||
<t t-esc="widget.format_currency(order.get_total_without_tax())"/> |
|||
</td> |
|||
</tr> |
|||
<t t-foreach="order.get_tax_details()" t-as="taxdetail"> |
|||
<tr> |
|||
<td><t t-esc="taxdetail.name" /></td> |
|||
<td class="pos-right-align"> |
|||
<t t-esc="widget.format_currency(taxdetail.amount)" /> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
<tr> |
|||
<td>Disc.Fixed(Total):</td> |
|||
<td class="pos-right-align"> |
|||
<t t-esc="widget.format_currency(order.get_discount_total_order())"/> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td>Disc.Percent(Total):</td> |
|||
<td class="pos-right-align"> |
|||
<t t-esc="order.get_discount_percent_order()"/> % |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td>Total Discount:</td> |
|||
<td class="pos-right-align"> |
|||
<t t-esc="widget.format_currency(order.get_total_discount())"/> |
|||
</td> |
|||
</tr> |
|||
<tr class="emph"> |
|||
<td>Total:</td> |
|||
<td class="pos-right-align"> |
|||
<t t-esc="widget.format_currency(order.get_total_with_tax())"/> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
<br /> |
|||
<table class='receipt-paymentlines'> |
|||
<t t-foreach="paymentlines" t-as="line"> |
|||
<tr> |
|||
<td> |
|||
<t t-esc="line.name"/> |
|||
</td> |
|||
<td class="pos-right-align"> |
|||
<t t-esc="widget.format_currency(line.get_amount())"/> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
</table> |
|||
<br /> |
|||
<table class='receipt-change'> |
|||
<tr><td>Change:</td><td class="pos-right-align"> |
|||
<t t-esc="widget.format_currency(order.get_change())"/> |
|||
</td></tr> |
|||
</table> |
|||
<t t-if="receipt.footer"> |
|||
<br /> |
|||
<div style='text-align:center'> |
|||
<t t-esc="receipt.footer" /> |
|||
</div> |
|||
</t> |
|||
</div> |
|||
</t> |
|||
|
|||
</templates> |
@ -0,0 +1,21 @@ |
|||
<?xml version="1.0"?> |
|||
<openerp> |
|||
<data> |
|||
|
|||
<record model="ir.ui.view" id="view_pos_invoice_new_extended"> |
|||
<field name="name">pos.order.invoice.extend</field> |
|||
<field name="model">account.invoice</field> |
|||
<field name="inherit_id" ref="account.invoice_form"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//field[@name='discount']" position="after"> |
|||
<field name="discount_fixed" groups="sale.group_discount_per_so_line"/> |
|||
</xpath> |
|||
|
|||
<xpath expr="//field[@name='amount_tax']" position="after"> |
|||
<field name="discount_total"/> |
|||
<field name="discount_percent"/> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
</data> |
|||
</openerp> |
@ -0,0 +1,186 @@ |
|||
<?xml version="1.0" encoding="iso-8859-1"?> |
|||
<openerp> |
|||
<data> |
|||
<template id="report_invoice_document_new"> |
|||
<t t-call="report.external_layout"> |
|||
<t t-set="o" t-value="o.with_context({'lang':o.partner_id.lang})" /> |
|||
<div class="page"> |
|||
<div class="row"> |
|||
<div class="col-xs-5 col-xs-offset-7"> |
|||
<address t-field="o.partner_id" |
|||
t-field-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": true}' /> |
|||
<span t-if="o.partner_id.vat">TIN: <span t-field="o.partner_id.vat"/></span> |
|||
</div> |
|||
</div> |
|||
|
|||
<h2> |
|||
<span t-if="o.type == 'out_invoice' and (o.state == 'open' or o.state == 'paid')">Invoice</span> |
|||
<span t-if="o.type == 'out_invoice' and o.state == 'proforma2'">PRO-FORMA</span> |
|||
<span t-if="o.type == 'out_invoice' and o.state == 'draft'">Draft Invoice</span> |
|||
<span t-if="o.type == 'out_invoice' and o.state == 'cancel'">Cancelled Invoice</span> |
|||
<span t-if="o.type == 'out_refund'">Refund</span> |
|||
<span t-if="o.type == 'in_refund'">Vendor Refund</span> |
|||
<span t-if="o.type == 'in_invoice'">Vendor Bill</span> |
|||
<span t-field="o.number"/> |
|||
</h2> |
|||
|
|||
<div class="row mt32 mb32"> |
|||
<div class="col-xs-2" t-if="o.name"> |
|||
<strong>Description:</strong> |
|||
<p t-field="o.name"/> |
|||
</div> |
|||
<div class="col-xs-2" t-if="o.date_invoice"> |
|||
<strong>Invoice Date:</strong> |
|||
<p t-field="o.date_invoice"/> |
|||
</div> |
|||
<div class="col-xs-2" t-if="o.date_due and o.type == 'out_invoice' and (o.state == 'open' or o.state == 'paid')"> |
|||
<strong>Due Date:</strong> |
|||
<p t-field="o.date_due"/> |
|||
</div> |
|||
<div class="col-xs-2" t-if="o.origin"> |
|||
<strong>Source:</strong> |
|||
<p t-field="o.origin"/> |
|||
</div> |
|||
<div class="col-xs-2" t-if="o.partner_id.ref"> |
|||
<strong>Customer Code:</strong> |
|||
<p t-field="o.partner_id.ref"/> |
|||
</div> |
|||
<div name="reference" class="col-xs-2" t-if="o.reference"> |
|||
<strong>Reference:</strong> |
|||
<p t-field="o.reference"/> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Is there a discount on at least one line? --> |
|||
<t t-set="display_discount" t-value="any([l.discount_fixed for l in o.invoice_line_ids])"/> |
|||
<!--<t t-set="display_discount_fixed" t-value="any([l.discount_fixed for l in o.invoice_line_ids])"/>--> |
|||
<table class="table table-condensed"> |
|||
<thead> |
|||
<tr> |
|||
<th>Description</th> |
|||
<th class="text-right">Quantity</th> |
|||
<th class="text-right">Unit Price</th> |
|||
<th class="text-right" groups="sale.group_discount_per_so_line">Disc.(%)</th> |
|||
<th class="text-right" groups="sale.group_discount_per_so_line">Disc.Fixed</th> |
|||
<th class="text-right">Taxes</th> |
|||
<th class="text-right">Price</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody class="invoice_tbody"> |
|||
<tr t-foreach="o.invoice_line_ids" t-as="l"> |
|||
<td><span t-field="l.name"/></td> |
|||
<td class="text-right"> |
|||
<span t-field="l.quantity"/> |
|||
<span t-field="l.uom_id" groups="product.group_uom"/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-field="l.price_unit"/> |
|||
</td> |
|||
<td class="text-right" groups="sale.group_discount_per_so_line"> |
|||
<span t-field="l.discount"/> |
|||
</td> |
|||
<td class="text-right" groups="sale.group_discount_per_so_line"> |
|||
<span t-field="l.discount_fixed"/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-esc="', '.join(map(lambda x: (x.description or x.name), l.invoice_line_tax_ids))"/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-field="l.price_subtotal" |
|||
t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
|
|||
<div class="row"> |
|||
<div class="col-xs-4 pull-right"> |
|||
<table class="table table-condensed"> |
|||
<tr class="border-black"> |
|||
<td><strong>Subtotal</strong></td> |
|||
<td class="text-right"> |
|||
<span t-field="o.amount_untaxed" t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
<tr class="border-black"> |
|||
<td><strong>Discount Fixed(Total)</strong></td> |
|||
<td class="text-right"> |
|||
<span t-field="o.discount_total" t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
<tr class="border-black"> |
|||
<td><strong>Discount Percent(Total)</strong></td> |
|||
<td class="text-right"> |
|||
<span t-field="o.discount_percent"/>% |
|||
</td> |
|||
</tr> |
|||
<t t-foreach="o._get_tax_amount_by_group()" t-as="amount_by_group"> |
|||
<tr> |
|||
<td><span t-esc="amount_by_group[0]"/></td> |
|||
<td class="text-right"> |
|||
<span t-esc="amount_by_group[1]"/> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
<tr class="border-black"> |
|||
<td><strong>Total</strong></td> |
|||
<td class="text-right"> |
|||
<span t-field="o.amount_total" t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row" t-if="o.tax_line_ids"> |
|||
<div class="col-xs-6"> |
|||
<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.tax_line_ids" t-as="t"> |
|||
<td><span t-field="t.name"/></td> |
|||
<td class="text-right"> |
|||
<span t-field="t.base" |
|||
t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-field="t.amount" |
|||
t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
|
|||
<p t-if="o.comment"> |
|||
<strong>Comment:</strong> |
|||
<span t-field="o.comment"/> |
|||
</p> |
|||
<p t-if="o.payment_term_id"> |
|||
<span t-field="o.payment_term_id.note"/> |
|||
</p> |
|||
<p t-if="o.fiscal_position_id.note"> |
|||
<strong>Fiscal Position Remark:</strong> |
|||
<span t-field="o.fiscal_position_id.note"/> |
|||
</p> |
|||
</div> |
|||
</t> |
|||
</template> |
|||
|
|||
|
|||
<template id="report_invoice_new"> |
|||
<t t-call="report.html_container"> |
|||
<t t-foreach="docs" t-as="o"> |
|||
<t t-call="discounts_in_pos.report_invoice_document_new" t-lang="o.partner_id.lang"/> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
</data> |
|||
</openerp> |
@ -0,0 +1,186 @@ |
|||
<?xml version="1.0" encoding="iso-8859-1"?> |
|||
<openerp> |
|||
<data> |
|||
<template id="report_invoice_document"> |
|||
<t t-call="report.external_layout"> |
|||
<t t-set="o" t-value="o.with_context({'lang':o.partner_id.lang})" /> |
|||
<div class="page"> |
|||
<div class="row"> |
|||
<div class="col-xs-5 col-xs-offset-7"> |
|||
<address t-field="o.partner_id" |
|||
t-field-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": true}' /> |
|||
<span t-if="o.partner_id.vat">TIN: <span t-field="o.partner_id.vat"/></span> |
|||
</div> |
|||
</div> |
|||
|
|||
<h2> |
|||
<span t-if="o.type == 'out_invoice' and (o.state == 'open' or o.state == 'paid')">Invoice</span> |
|||
<span t-if="o.type == 'out_invoice' and o.state == 'proforma2'">PRO-FORMA</span> |
|||
<span t-if="o.type == 'out_invoice' and o.state == 'draft'">Draft Invoice</span> |
|||
<span t-if="o.type == 'out_invoice' and o.state == 'cancel'">Cancelled Invoice</span> |
|||
<span t-if="o.type == 'out_refund'">Refund</span> |
|||
<span t-if="o.type == 'in_refund'">Vendor Refund</span> |
|||
<span t-if="o.type == 'in_invoice'">Vendor Bill</span> |
|||
<span t-field="o.number"/> |
|||
</h2> |
|||
|
|||
<div class="row mt32 mb32"> |
|||
<div class="col-xs-2" t-if="o.name"> |
|||
<strong>Description:</strong> |
|||
<p t-field="o.name"/> |
|||
</div> |
|||
<div class="col-xs-2" t-if="o.date_invoice"> |
|||
<strong>Invoice Date:</strong> |
|||
<p t-field="o.date_invoice"/> |
|||
</div> |
|||
<div class="col-xs-2" t-if="o.date_due and o.type == 'out_invoice' and (o.state == 'open' or o.state == 'paid')"> |
|||
<strong>Due Date:</strong> |
|||
<p t-field="o.date_due"/> |
|||
</div> |
|||
<div class="col-xs-2" t-if="o.origin"> |
|||
<strong>Source:</strong> |
|||
<p t-field="o.origin"/> |
|||
</div> |
|||
<div class="col-xs-2" t-if="o.partner_id.ref"> |
|||
<strong>Customer Code:</strong> |
|||
<p t-field="o.partner_id.ref"/> |
|||
</div> |
|||
<div name="reference" class="col-xs-2" t-if="o.reference"> |
|||
<strong>Reference:</strong> |
|||
<p t-field="o.reference"/> |
|||
</div> |
|||
</div> |
|||
|
|||
<!-- Is there a discount on at least one line? --> |
|||
<t t-set="display_discount" t-value="any([l.discount_fixed for l in o.invoice_line_ids])"/> |
|||
<!--<t t-set="display_discount_fixed" t-value="any([l.discount_fixed for l in o.invoice_line_ids])"/>--> |
|||
<table class="table table-condensed"> |
|||
<thead> |
|||
<tr> |
|||
<th>Description</th> |
|||
<th class="text-right">Quantity</th> |
|||
<th class="text-right">Unit Price</th> |
|||
<th class="text-right" groups="sale.group_discount_per_so_line">Disc.(%)</th> |
|||
<th class="text-right" groups="sale.group_discount_per_so_line">Disc.Fixed</th> |
|||
<th class="text-right">Taxes</th> |
|||
<th class="text-right">Price</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody class="invoice_tbody"> |
|||
<tr t-foreach="o.invoice_line_ids" t-as="l"> |
|||
<td><span t-field="l.name"/></td> |
|||
<td class="text-right"> |
|||
<span t-field="l.quantity"/> |
|||
<span t-field="l.uom_id" groups="product.group_uom"/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-field="l.price_unit"/> |
|||
</td> |
|||
<td class="text-right" groups="sale.group_discount_per_so_line"> |
|||
<span t-field="l.discount"/> |
|||
</td> |
|||
<td class="text-right" groups="sale.group_discount_per_so_line"> |
|||
<span t-field="l.discount_fixed"/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-esc="', '.join(map(lambda x: (x.description or x.name), l.invoice_line_tax_ids))"/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-field="l.price_subtotal" |
|||
t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
|
|||
<div class="row"> |
|||
<div class="col-xs-4 pull-right"> |
|||
<table class="table table-condensed"> |
|||
<tr class="border-black"> |
|||
<td><strong>Subtotal</strong></td> |
|||
<td class="text-right"> |
|||
<span t-field="o.amount_untaxed" t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
<tr class="border-black"> |
|||
<td><strong>Discount Fixed(Total)</strong></td> |
|||
<td class="text-right"> |
|||
<span t-field="o.discount_total" t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
<tr class="border-black"> |
|||
<td><strong>Discount Percent(Total)</strong></td> |
|||
<td class="text-right"> |
|||
<span t-field="o.discount_percent"/>% |
|||
</td> |
|||
</tr> |
|||
<t t-foreach="o._get_tax_amount_by_group()" t-as="amount_by_group"> |
|||
<tr> |
|||
<td><span t-esc="amount_by_group[0]"/></td> |
|||
<td class="text-right"> |
|||
<span t-esc="amount_by_group[1]"/> |
|||
</td> |
|||
</tr> |
|||
</t> |
|||
<tr class="border-black"> |
|||
<td><strong>Total</strong></td> |
|||
<td class="text-right"> |
|||
<span t-field="o.amount_total" t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row" t-if="o.tax_line_ids"> |
|||
<div class="col-xs-6"> |
|||
<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.tax_line_ids" t-as="t"> |
|||
<td><span t-field="t.name"/></td> |
|||
<td class="text-right"> |
|||
<span t-field="t.base" |
|||
t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-field="t.amount" |
|||
t-field-options='{"widget": "monetary", "display_currency": "o.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
|
|||
<p t-if="o.comment"> |
|||
<strong>Comment:</strong> |
|||
<span t-field="o.comment"/> |
|||
</p> |
|||
<p t-if="o.payment_term_id"> |
|||
<span t-field="o.payment_term_id.note"/> |
|||
</p> |
|||
<p t-if="o.fiscal_position_id.note"> |
|||
<strong>Fiscal Position Remark:</strong> |
|||
<span t-field="o.fiscal_position_id.note"/> |
|||
</p> |
|||
</div> |
|||
</t> |
|||
</template> |
|||
|
|||
<template id="report_invoice"> |
|||
<t t-call="report.html_container"> |
|||
<t t-foreach="docs" t-as="o"> |
|||
<t t-call="discounts_in_pos.report_invoice_document" t-lang="o.partner_id.lang"/> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
|
|||
</data> |
|||
</openerp> |
@ -0,0 +1,89 @@ |
|||
<?xml version="1.0" encoding="iso-8859-1"?> |
|||
<openerp> |
|||
<data> |
|||
<record model="ir.ui.view" id="view_pos_config_form_extended"> |
|||
<field name="name">pos.config.extend</field> |
|||
<field name="model">pos.config</field> |
|||
<field name="inherit_id" ref="point_of_sale.view_pos_config_form"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//field[@name='sequence_id']" position="after"> |
|||
<field name="discount_account"/> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
<record model="ir.ui.view" id="view_pos_new_form_extended"> |
|||
<field name="name">pos.order.extend</field> |
|||
<field name="model">pos.order</field> |
|||
<field name="inherit_id" ref="point_of_sale.view_pos_pos_form"/> |
|||
<field name="arch" type="xml"> |
|||
<xpath expr="//field[@name='qty']" position="replace"> |
|||
<field name="qty"/> |
|||
</xpath> |
|||
<xpath expr="//field[@name='price_unit']" position="replace"> |
|||
<field name="price_unit"/> |
|||
</xpath> |
|||
<xpath expr="//field[@name='discount']" position="replace"> |
|||
<field name="discount" widget="monetary"/> |
|||
</xpath> |
|||
<xpath expr="//field[@name='discount']" position="after"> |
|||
<field name="discount_fixed" widget="monetary"/> |
|||
</xpath> |
|||
|
|||
<xpath expr="//field[@name='amount_tax']" position="after"> |
|||
<field name="discount_total" /> |
|||
<field name="discount_percent" /> |
|||
</xpath> |
|||
</field> |
|||
</record> |
|||
|
|||
<report |
|||
id="pos_invoice_report" |
|||
string="Invoice" |
|||
model="pos.order" |
|||
report_type="qweb-pdf" |
|||
name="discounts_in_pos.report_invoice" |
|||
file="discounts_in_pos.report_invoice" |
|||
/> |
|||
|
|||
<!--in account.invoice --> |
|||
<report |
|||
id="account_invoices" |
|||
model="account.invoice" |
|||
string="Invoices" |
|||
report_type="qweb-pdf" |
|||
name="discounts_in_pos.report_invoice_new" |
|||
file="discounts_in_pos.report_invoice_new" |
|||
attachment_use="True" |
|||
attachment="(object.state in ('open','paid')) and ('INV'+(object.number or '').replace('/','')+'.pdf')" |
|||
/> |
|||
|
|||
<report |
|||
id="pos_payment_report" |
|||
string="Today's Payment" |
|||
model="pos.order" |
|||
report_type="qweb-pdf" |
|||
name="discounts_in_pos.report_payment" |
|||
file="discounts_in_pos.report_payment" |
|||
/> |
|||
|
|||
<report |
|||
id="action_report_pos_receipt" |
|||
string="Receipt" |
|||
model="pos.order" |
|||
report_type="qweb-pdf" |
|||
name="discounts_in_pos.report_receipt" |
|||
file="discounts_in_pos.report_receipt" |
|||
paperformat="discounts_in_pos.paperformat_posreceipt" |
|||
/> |
|||
<report |
|||
id="pos_lines_report" |
|||
string="Sales Lines" |
|||
model="pos.order" |
|||
report_type="qweb-pdf" |
|||
name="discounts_in_pos.report_saleslines" |
|||
file="discounts_in_pos.report_saleslines" |
|||
auto="False" |
|||
/> |
|||
|
|||
</data> |
|||
</openerp> |
@ -0,0 +1,20 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<openerp> |
|||
<data> |
|||
<record id="paperformat_posreceipt" model="report.paperformat"> |
|||
<field name="name">Point Of Sale Receipt</field> |
|||
<field name="default" eval="True"/> |
|||
<field name="format">custom</field> |
|||
<field name="page_height">150</field> |
|||
<field name="page_width">90</field> |
|||
<field name="orientation">Portrait</field> |
|||
<field name="margin_top">3</field> |
|||
<field name="margin_bottom">3</field> |
|||
<field name="margin_left">3</field> |
|||
<field name="margin_right">3</field> |
|||
<field name="header_line" eval="False" /> |
|||
<field name="header_spacing">3</field> |
|||
<field name="dpi">130</field> |
|||
</record> |
|||
</data> |
|||
</openerp> |
@ -0,0 +1,113 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<openerp> |
|||
<data> |
|||
<template id="report_payment"> |
|||
<t t-call="report.html_container"> |
|||
<t t-foreach="docs" t-as="o"> |
|||
<t t-call="report.internal_layout"> |
|||
<div class="page"> |
|||
<h2>Today's Payments</h2> |
|||
<div class="row mt32 mb32"> |
|||
<div class="col-xs-3"> |
|||
<strong>Company</strong>: |
|||
<br/> |
|||
<span t-field="res_company.name"/> |
|||
</div> |
|||
<div class="col-xs-3"> |
|||
<strong>Print date</strong>: |
|||
<br/> |
|||
<t t-esc="formatLang(time.strftime('%Y-%m-%d'), date='True')"/> |
|||
</div> |
|||
</div> |
|||
<t t-set="pos_payment" t-value="pos_payment(o)"/> |
|||
<table class="table table-condensed" t-if="pos_payment"> |
|||
<thead> |
|||
<tr> |
|||
<td> |
|||
<strong>Product</strong> |
|||
</td> |
|||
<td class="text-center"> |
|||
<strong>Qty</strong> |
|||
</td> |
|||
<td class="text-center"> |
|||
<strong>Disc.(%)</strong> |
|||
</td> |
|||
<td class="text-center"> |
|||
<strong>Disc.Fixed</strong> |
|||
</td> |
|||
<td class="text-right"> |
|||
<strong>Unit Price</strong> |
|||
</td> |
|||
<td class="text-right"> |
|||
<strong>Total</strong> |
|||
</td> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<tr t-foreach="pos_payment" t-as="line_ids"> |
|||
<td> |
|||
<t t-if="line_ids['code']"> |
|||
<span t-esc="line_ids['code']"/> |
|||
</t> |
|||
<t t-if="line_ids['name']"> |
|||
<span t-esc="line_ids['name']"/> |
|||
</t> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-esc="formatLang(line_ids['qty'])"/> |
|||
<t t-if="line_ids['uom']"> |
|||
<span t-esc="line_ids['uom']"/> |
|||
</t> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-esc="formatLang(line_ids['discount'])"/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-esc="formatLang(line_ids['discount_fixed'], currency_obj=res_company.currency_id)"/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-esc="formatLang(line_ids['price_unit'])"/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-esc="formatLang(line_ids['total'], currency_obj=res_company.currency_id)"/> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
<div class="row" t-if="pos_payment_total(o)"> |
|||
<div class="col-xs-4 pull-right"> |
|||
<table class="table table-condensed"> |
|||
<tr class="border-black"> |
|||
<td> |
|||
<strong>Discount Fixed(Total)</strong> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-esc="formatLang(pos_fixed_discount(o), currency_obj=res_company.currency_id)"/> |
|||
</td> |
|||
</tr> |
|||
<tr class="border-black"> |
|||
<td> |
|||
<strong>Discount Percent(Total)</strong> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-esc="pos_percent_discount(o)"/> % |
|||
</td> |
|||
</tr> |
|||
<tr class="border-black"> |
|||
<td> |
|||
<strong>Net Total</strong> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-esc="formatLang(pos_payment_total(o), currency_obj=res_company.currency_id)"/> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
</data> |
|||
</openerp> |
@ -0,0 +1,112 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<openerp> |
|||
<data> |
|||
<template id="report_receipt"> |
|||
<t t-call="report.html_container"> |
|||
<t t-foreach="docs" t-as="o"> |
|||
<div class="page"> |
|||
<div class="row"> |
|||
<div class="col-xs-12 text-center"> |
|||
<h2 t-esc="o.user_id.company_id.name"/> |
|||
<div t-field="o.partner_id" |
|||
t-field-options='{"widget": "contact", "fields": ["address", "name", "phone", "fax"], "no_marker": true, "phone_icons": true}'/> |
|||
User: <span t-field="o.user_id"/><br/> |
|||
Date: <span t-field="o.date_order"/><br/> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="row"> |
|||
</div> |
|||
|
|||
<table class="table table-condensed"> |
|||
<thead> |
|||
<tr> |
|||
<th>Description</th> |
|||
<th class="text-right">Quantity</th> |
|||
<th class="text-right">Price</th> |
|||
<th class="text-right">Discount</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<tr t-foreach="o.lines" t-as="line"> |
|||
<td><span t-field="line.product_id"/></td> |
|||
<td class="text-right"> |
|||
<t t-if="o.state != 'cancel' and o.statement_ids"> |
|||
<span t-field="line.qty"/> |
|||
</t> |
|||
</td> |
|||
<td class="text-right"> |
|||
<t t-if="o.state != 'cancel' and o.statement_ids"> |
|||
<span t-esc="formatLang(net(line.id), currency_obj=res_company.currency_id)"/> |
|||
</t> |
|||
</td> |
|||
<td> |
|||
<t t-if="line.discount != 0.0"> |
|||
<span t-esc="line.discount"/>% |
|||
</t> |
|||
<t t-if="line.discount_fixed != 0.0"> |
|||
<span t-esc="formatLang(line.discount_fixed, currency_obj=res_company.currency_id)"/> |
|||
</t> |
|||
<t t-if="line.discount == 0.0 and line.discount_fixed == 0.0"> |
|||
0 |
|||
</t> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
|
|||
<div class="row"> |
|||
<div class="col-xs-6 pull-right"> |
|||
<table class="table table-condensed"> |
|||
<tr class="border-black"> |
|||
<td><strong>Taxes</strong></td> |
|||
<td class="text-right"> |
|||
<strong t-esc="formatLang(o.amount_tax, currency_obj=res_company.currency_id)"/> |
|||
</td> |
|||
</tr> |
|||
<tr class="border-black"> |
|||
<td><strong>Discount Fixed(Total)</strong></td> |
|||
<td class="text-right"> |
|||
<strong t-esc="formatLang(o.discount_total, currency_obj=res_company.currency_id)"/> |
|||
</td> |
|||
</tr> |
|||
<tr class="border-black"> |
|||
<td><strong>Discount Percent(Total)</strong></td> |
|||
<td class="text-right"> |
|||
<strong t-esc="o.discount_percent"/> % |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td><strong>Total</strong></td> |
|||
<td class="text-right"> |
|||
<strong t-esc="formatLang(o.amount_total, currency_obj=res_company.currency_id)"/> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
|
|||
<table class="table table-condensed"> |
|||
<thead> |
|||
<tr> |
|||
<th>Payment Mode</th> |
|||
<th>Amount</th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<tr t-foreach="get_journal_amt(o)" t-as="d"> |
|||
<td> |
|||
<span t-esc="d['name']"/> |
|||
</td> |
|||
<td> |
|||
<span t-esc="formatLang(d['amt'], currency_obj=res_company.currency_id)"/> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
</data> |
|||
</openerp> |
@ -0,0 +1,125 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<openerp> |
|||
<data> |
|||
<template id="report_saleslines"> |
|||
<t t-call="report.html_container"> |
|||
<t t-foreach="docs" t-as="o"> |
|||
<t t-call="report.internal_layout"> |
|||
<div class="page"> |
|||
<h2>POS Lines</h2> |
|||
|
|||
<div class="row mt32 mb32"> |
|||
<div class="col-xs-3"> |
|||
<strong>Company</strong>:<br/> |
|||
<span t-field="res_company.name"/> |
|||
</div> |
|||
<div class="col-xs-3"> |
|||
<strong>Print date</strong>:<br/> |
|||
<t t-esc="formatLang(time.strftime('%Y-%m-%d'), date=True)"/> |
|||
</div> |
|||
<div class="col-xs-3"> |
|||
<strong>No. Of Articles</strong>:<br/> |
|||
<t t-esc="total_quantity(o)"/> |
|||
</div> |
|||
</div> |
|||
|
|||
<table class="table table-condensed"> |
|||
<thead> |
|||
<tr> |
|||
<th><strong>Description</strong></th> |
|||
<th><strong>Tax</strong></th> |
|||
<th class="text-right"><strong>Quantity</strong></th> |
|||
<th class="text-right"><strong>Unit Price</strong></th> |
|||
<th class="text-right" groups="sale.group_discount_per_so_line"><strong>Disc. (%)</strong></th> |
|||
<th class="text-right" groups="sale.group_discount_per_so_line"><strong>Disc.Fixed</strong></th> |
|||
<th class="text-right"><strong>Price</strong></th> |
|||
</tr> |
|||
</thead> |
|||
<tbody> |
|||
<tr t-foreach="o.lines" t-as="l"> |
|||
<td> |
|||
<t t-if="l.product_id and l.product_id.code"> |
|||
[<span t-field="l.product_id.code"/>] |
|||
</t> |
|||
<span t-field="l.product_id.name"/> |
|||
</td> |
|||
<td> |
|||
<t t-esc="taxes(l)"/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-field="l.qty"/> |
|||
<span t-field="l.product_id.uom_id.name" groups="product.group_uom"/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-field="l.price_unit"/> |
|||
</td> |
|||
<td class="text-right" groups="sale.group_discount_per_so_line"> |
|||
<span t-field="l.discount"/> |
|||
</td> |
|||
<td class="text-right" groups="sale.group_discount_per_so_line"> |
|||
<span t-field="l.discount_fixed" t-field-options='{"widget": "monetary", "display_currency": "o.pricelist_id.currency_id"}'/> |
|||
</td> |
|||
<td class="text-right"> |
|||
<span t-field="l.price_subtotal" t-field-options='{"widget": "monetary", "display_currency": "o.pricelist_id.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
|
|||
<div class="row"> |
|||
<div class="col-xs-4 pull-right"> |
|||
<table class="table table-condensed"> |
|||
<tr class="border-black"> |
|||
<td><strong>Total Without Taxes</strong></td> |
|||
<td class="text-right"> |
|||
<t t-if="o.discount_percent > 0"> |
|||
<span t-esc="(o.amount_total - o.amount_tax)*100/(100 - o.discount_percent)" |
|||
t-esc-options='{"widget": "monetary", "display_currency": "o.pricelist_id.currency_id"}'/> |
|||
</t> |
|||
<t t-if="o.discount_total > 0"> |
|||
<span t-esc="(o.amount_total - o.amount_tax) + o.discount_total" |
|||
t-esc-options='{"widget": "monetary", "display_currency": "o.pricelist_id.currency_id"}'/> |
|||
</t> |
|||
<t t-if="o.discount_total == 0 and o.discount_percent == 0"> |
|||
<span t-esc="(o.amount_total - o.amount_tax)" |
|||
t-esc-options='{"widget": "monetary", "display_currency": "o.pricelist_id.currency_id"}'/> |
|||
</t> |
|||
</td> |
|||
</tr> |
|||
<tr> |
|||
<td>Taxes</td> |
|||
<td class="text-right"> |
|||
<span t-field="o.amount_tax" |
|||
t-field-options='{"widget": "monetary", "display_currency": "o.pricelist_id.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
<tr groups="sale.group_discount_per_so_line"> |
|||
<td>Discount Fixed(Total)</td> |
|||
<td class="text-right"> |
|||
<span t-field="o.discount_total" |
|||
t-field-options='{"widget": "monetary", "display_currency": "o.pricelist_id.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
<tr groups="sale.group_discount_per_so_line"> |
|||
<td>Discount Percent(Total)</td> |
|||
<td class="text-right"> |
|||
<span t-field="o.discount_percent"/> % |
|||
</td> |
|||
</tr> |
|||
<tr class="border-black"> |
|||
<td><strong>Total</strong></td> |
|||
<td class="text-right"> |
|||
<span t-field="o.amount_total" |
|||
t-field-options='{"widget": "monetary", "display_currency": "o.pricelist_id.currency_id"}'/> |
|||
</td> |
|||
</tr> |
|||
</table> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</t> |
|||
</t> |
|||
</t> |
|||
</template> |
|||
</data> |
|||
</openerp> |
@ -0,0 +1,12 @@ |
|||
<?xml version="1.0" encoding="utf-8"?> |
|||
<openerp> |
|||
<data> |
|||
|
|||
<template id="assets_frontend" inherit_id="web.assets_common"> |
|||
<xpath expr="." position="inside"> |
|||
<script type="text/javascript" src="/discounts_in_pos/static/src/js/discount.js"></script> |
|||
</xpath> |
|||
</template> |
|||
|
|||
</data> |
|||
</openerp> |