Browse Source

Initial Commit

pull/81/head
SHEREEF PT 8 years ago
parent
commit
88430aaa9e
  1. 21
      discounts_in_pos/README.rst
  2. 4
      discounts_in_pos/__init__.py
  3. 52
      discounts_in_pos/__openerp__.py
  4. 7
      discounts_in_pos/models/__init__.py
  5. 49
      discounts_in_pos/models/p.py~
  6. 166
      discounts_in_pos/models/pos_invoice_new.py
  7. 42
      discounts_in_pos/models/pos_lines_new.py
  8. 503
      discounts_in_pos/models/pos_order_lines_new.py
  9. 70
      discounts_in_pos/models/pos_payment_report_new.py
  10. 65
      discounts_in_pos/models/pos_receipt_new.py
  11. BIN
      discounts_in_pos/static/description/account.png
  12. BIN
      discounts_in_pos/static/description/banner.jpg
  13. BIN
      discounts_in_pos/static/description/cybro_logo.png
  14. BIN
      discounts_in_pos/static/description/discount-button.png
  15. BIN
      discounts_in_pos/static/description/icon.png
  16. 169
      discounts_in_pos/static/description/index.html
  17. BIN
      discounts_in_pos/static/description/receipt-percentage.png
  18. BIN
      discounts_in_pos/static/description/receipt.png
  19. BIN
      discounts_in_pos/static/description/total-disc.png
  20. 486
      discounts_in_pos/static/src/js/discount.js
  21. 223
      discounts_in_pos/static/src/xml/discount.xml
  22. 21
      discounts_in_pos/views/account_invoice_view_pos.xml
  23. 186
      discounts_in_pos/views/pos_reports_account_invoice.xml
  24. 186
      discounts_in_pos/views/pos_reports_new_invoice.xml
  25. 89
      discounts_in_pos/views/pos_view.xml
  26. 20
      discounts_in_pos/views/report_paperformat_new.xml
  27. 113
      discounts_in_pos/views/report_payment_new.xml
  28. 112
      discounts_in_pos/views/report_receipt_new.xml
  29. 125
      discounts_in_pos/views/report_saleslines_new.xml
  30. 12
      discounts_in_pos/views/templates.xml

21
discounts_in_pos/README.rst

@ -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

4
discounts_in_pos/__init__.py

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
import models

52
discounts_in_pos/__openerp__.py

@ -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,
}

7
discounts_in_pos/models/__init__.py

@ -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

49
discounts_in_pos/models/p.py~

@ -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

166
discounts_in_pos/models/pos_invoice_new.py

@ -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)

42
discounts_in_pos/models/pos_lines_new.py

@ -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

503
discounts_in_pos/models/pos_order_lines_new.py

@ -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

70
discounts_in_pos/models/pos_payment_report_new.py

@ -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

65
discounts_in_pos/models/pos_receipt_new.py

@ -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

BIN
discounts_in_pos/static/description/account.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

BIN
discounts_in_pos/static/description/banner.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

BIN
discounts_in_pos/static/description/cybro_logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

BIN
discounts_in_pos/static/description/discount-button.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

BIN
discounts_in_pos/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

169
discounts_in_pos/static/description/index.html

@ -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;"> &#9745;</span>&nbsp;&nbsp; Percentage discount on order lines.</li>
<li style="list-style:none !important;"><span style="color:green;"> &#9745;</span>&nbsp;&nbsp; Fixed discount on order lines.</li>
<li style="list-style:none !important;"><span style="color:green;"> &#9745;</span>&nbsp;&nbsp; Percentage discount on order.</li>
<li style="list-style:none !important;"><span style="color:green;"> &#9745;</span>&nbsp;&nbsp; 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>

BIN
discounts_in_pos/static/description/receipt-percentage.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
discounts_in_pos/static/description/receipt.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
discounts_in_pos/static/description/total-disc.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

486
discounts_in_pos/static/src/js/discount.js

@ -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;
},
});
});

223
discounts_in_pos/static/src/xml/discount.xml

@ -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>

21
discounts_in_pos/views/account_invoice_view_pos.xml

@ -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>

186
discounts_in_pos/views/pos_reports_account_invoice.xml

@ -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>

186
discounts_in_pos/views/pos_reports_new_invoice.xml

@ -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>

89
discounts_in_pos/views/pos_view.xml

@ -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>

20
discounts_in_pos/views/report_paperformat_new.xml

@ -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>

113
discounts_in_pos/views/report_payment_new.xml

@ -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>

112
discounts_in_pos/views/report_receipt_new.xml

@ -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>

125
discounts_in_pos/views/report_saleslines_new.xml

@ -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>

12
discounts_in_pos/views/templates.xml

@ -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>
Loading…
Cancel
Save