[MERGE] forward port of branch 8.0 up to 02954ba
This commit is contained in:
@@ -399,7 +399,7 @@
|
||||
<field name="reconciled" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="payment_term" class="oe_inline" on_change="onchange_payment_term_date_invoice(payment_term,date_invoice)"/>
|
||||
<field name="payment_term" class="oe_inline" on_change="onchange_payment_term_date_invoice(payment_term, date_invoice)"/>
|
||||
</group>
|
||||
<field name="comment" class="oe_inline" placeholder="Additional notes..."/>
|
||||
</page>
|
||||
|
||||
@@ -885,6 +885,7 @@
|
||||
<field name="priority">100</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Account Tax Code" toolbar="1">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="sum_period"/>
|
||||
@@ -904,6 +905,7 @@
|
||||
<field name="code"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
<field name="sequence"/>
|
||||
</group>
|
||||
<group string="Reporting Configuration">
|
||||
<field name="notprintable"/>
|
||||
@@ -2154,6 +2156,7 @@
|
||||
<field name="field_parent">child_ids</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Account Tax Code Template" toolbar="1">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="name"/>
|
||||
<field name="code"/>
|
||||
<field name="parent_id" invisible="1"/>
|
||||
@@ -2183,6 +2186,7 @@
|
||||
<field name="code"/>
|
||||
<field name="parent_id"/>
|
||||
<field name="sign"/>
|
||||
<field name="sequence"/>
|
||||
</group>
|
||||
<separator string="Description"/>
|
||||
<field name="info"/>
|
||||
|
||||
@@ -375,7 +375,7 @@ class account_analytic_account(osv.osv):
|
||||
inv_ids = []
|
||||
for account in self.browse(cr, uid, ids, context=context):
|
||||
res[account.id] = 0.0
|
||||
line_ids = lines_obj.search(cr, uid, [('account_id','=', account.id), ('invoice_id','!=',False), ('to_invoice','!=', False), ('journal_id.type', '=', 'general'), ('invoice_id.type', 'in', ['out_invoice', 'out_refund'])], context=context)
|
||||
line_ids = lines_obj.search(cr, uid, [('account_id','=', account.id), ('invoice_id','!=',False), ('invoice_id.state', 'not in', ['draft', 'cancel']), ('to_invoice','!=', False), ('journal_id.type', '=', 'general'), ('invoice_id.type', 'in', ['out_invoice', 'out_refund'])], context=context)
|
||||
for line in lines_obj.browse(cr, uid, line_ids, context=context):
|
||||
if line.invoice_id not in inv_ids:
|
||||
inv_ids.append(line.invoice_id)
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
<record id="provider_facebook" model="auth.oauth.provider">
|
||||
<field name="name">Facebook Graph</field>
|
||||
<field name="auth_endpoint">https://www.facebook.com/dialog/oauth</field>
|
||||
<field name="scope"></field>
|
||||
<field name="validation_endpoint">https://graph.facebook.com/me/permissions</field>
|
||||
<field name="scope">public_profile,email</field>
|
||||
<field name="validation_endpoint">https://graph.facebook.com/me</field>
|
||||
<field name="data_endpoint"></field>
|
||||
<field name="css_class">fa fa-facebook-square</field>
|
||||
<field name="body">Log in with facebook</field>
|
||||
|
||||
@@ -101,7 +101,12 @@ class res_users(osv.Model):
|
||||
validation = self._auth_oauth_validate(cr, uid, provider, access_token)
|
||||
# required check
|
||||
if not validation.get('user_id'):
|
||||
raise openerp.exceptions.AccessDenied()
|
||||
# Workaround: facebook does not send 'user_id' in Open Graph Api
|
||||
if validation.get('id'):
|
||||
validation['user_id'] = validation['id']
|
||||
else:
|
||||
raise openerp.exceptions.AccessDenied()
|
||||
|
||||
# retrieve and sign in user
|
||||
login = self._auth_oauth_signin(cr, uid, provider, validation, params, context=context)
|
||||
if not login:
|
||||
|
||||
@@ -63,19 +63,15 @@ class res_users(osv.osv):
|
||||
cr.commit()
|
||||
return res[0] if res else False
|
||||
|
||||
def check(self, db, uid, passwd):
|
||||
def check_credentials(self, cr, uid, password):
|
||||
try:
|
||||
return super(res_users, self).check(db, uid, passwd)
|
||||
return super(res_users, self).check_credentials(cr, uid, password)
|
||||
except openerp.exceptions.AccessDenied:
|
||||
if not passwd:
|
||||
cr.execute('''SELECT COUNT(1)
|
||||
FROM res_users
|
||||
WHERE id=%s
|
||||
AND openid_key=%s
|
||||
AND active=%s''',
|
||||
(int(uid), password, True))
|
||||
if not cr.fetchone()[0]:
|
||||
raise
|
||||
with RegistryManager.get(db).cursor() as cr:
|
||||
cr.execute('''SELECT COUNT(1)
|
||||
FROM res_users
|
||||
WHERE id=%s
|
||||
AND openid_key=%s
|
||||
AND active=%s''',
|
||||
(int(uid), passwd, True))
|
||||
if not cr.fetchone()[0]:
|
||||
raise
|
||||
self._uid_cache.setdefault(db, {})[uid] = passwd
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<?xml version='1.0' encoding='UTF-8' ?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
@@ -25,17 +26,27 @@
|
||||
<filter domain="[('state','in',('confirm','validate1'))]" string="To Approve" name="approve"/>
|
||||
<filter domain="[('state','=','validate')]" string="Validated" name="validated"/>
|
||||
<separator/>
|
||||
<filter name="active_types" string="Active Types" domain="[('holiday_status_id.active', '=', True)]" help="Filters only on allocations and requests that belong to an holiday type that is 'active' (active field is True)"/>
|
||||
<separator/>
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator/>
|
||||
<filter string="Approved Leaves" name="validated" domain="[('state','=','validate')]"/>
|
||||
<separator/>
|
||||
<filter string="To Report in Payslip" name="gray" domain="[('payslip_status', '=', False)]" groups="base.group_hr_manager"/>
|
||||
<separator/>
|
||||
<filter name="year" string="Year" domain="[('holiday_status_id.active','=',True)]" help="Filters only on allocations and requests that belong to an holiday type that is 'active' (active field is True)"/>
|
||||
<separator/>
|
||||
<filter string="To Do" name="todo" domain="[('payslip_status', '=', False), ('holiday_status_id.active', '=', True)]"/>
|
||||
<separator/>
|
||||
<filter string="My Department Leaves" help="My Department Leaves" domain="[('department_id.manager_id','=',uid)]"/>
|
||||
<filter name="year" string="Year"
|
||||
domain="['|','&',('date_to', '<=', time.strftime('%%Y-12-31')),
|
||||
('date_to', '>=', time.strftime('%%Y-01-01')),
|
||||
'&',('date_from', '<=', time.strftime('%%Y-12-31')),
|
||||
('date_from', '>=', time.strftime('%%Y-01-01'))]"
|
||||
help="Current Year Leaves"/>
|
||||
<separator/>
|
||||
<filter string="My Requests" name="my_leaves" domain="[('user_id', '=', uid)]" help="My Leave Requests"/>
|
||||
<separator/>
|
||||
<filter string="My Department Leaves" name="my_department_leaves" domain="[('department_id.manager_id.user_id', '=', uid)]"/>
|
||||
<field name="employee_id"/>
|
||||
<field name="department_id"/>
|
||||
<field name="holiday_status_id"/>
|
||||
|
||||
@@ -255,6 +255,7 @@ class account_analytic_line(osv.osv):
|
||||
def invoice_cost_create(self, cr, uid, ids, data=None, context=None):
|
||||
invoice_obj = self.pool.get('account.invoice')
|
||||
invoice_line_obj = self.pool.get('account.invoice.line')
|
||||
analytic_line_obj = self.pool.get('account.analytic.line')
|
||||
invoices = []
|
||||
if context is None:
|
||||
context = {}
|
||||
@@ -303,13 +304,15 @@ class account_analytic_line(osv.osv):
|
||||
analytic_line.to_invoice.id,
|
||||
analytic_line.account_id,
|
||||
analytic_line.journal_id.type)
|
||||
# We want to retrieve the data in the partner language for the invoice creation
|
||||
analytic_line = analytic_line_obj.browse(cr, uid , [line.id for line in analytic_line], context=invoice_context)
|
||||
invoice_lines_grouping.setdefault(key, []).append(analytic_line)
|
||||
|
||||
# finally creates the invoice line
|
||||
for (product_id, uom, user_id, factor_id, account, journal_type), lines_to_invoice in invoice_lines_grouping.items():
|
||||
curr_invoice_line = self._prepare_cost_invoice_line(cr, uid, last_invoice,
|
||||
product_id, uom, user_id, factor_id, account, lines_to_invoice,
|
||||
journal_type, data, context=context)
|
||||
journal_type, data, context=invoice_context)
|
||||
|
||||
invoice_line_obj.create(cr, uid, curr_invoice_line, context=context)
|
||||
self.write(cr, uid, [l.id for l in analytic_lines], {'invoice_id': last_invoice}, context=context)
|
||||
|
||||
@@ -40,6 +40,10 @@ from openerp.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
# workaround https://bugs.launchpad.net/openobject-server/+bug/947231
|
||||
# related to http://bugs.python.org/issue7980
|
||||
from datetime import datetime
|
||||
datetime.strptime('2012-01-01', '%Y-%m-%d')
|
||||
|
||||
class EscposDriver(Thread):
|
||||
def __init__(self):
|
||||
@@ -146,7 +150,7 @@ class EscposDriver(Thread):
|
||||
_logger.warning('ESC/POS Device Disconnected: '+message)
|
||||
|
||||
def run(self):
|
||||
|
||||
printer = None
|
||||
if not escpos:
|
||||
_logger.error('ESC/POS cannot initialize, please verify system dependencies.')
|
||||
return
|
||||
@@ -192,7 +196,7 @@ class EscposDriver(Thread):
|
||||
errmsg = str(e) + '\n' + '-'*60+'\n' + traceback.format_exc() + '-'*60 + '\n'
|
||||
_logger.error(errmsg);
|
||||
finally:
|
||||
if error:
|
||||
if error:
|
||||
self.queue.put((timestamp, task, data))
|
||||
if printer:
|
||||
printer.close()
|
||||
|
||||
@@ -36,16 +36,16 @@ index_template = """
|
||||
</p>
|
||||
<p>
|
||||
For more information on how to setup the Point of Sale with
|
||||
the PosBox, please refer to <a href='/hw_proxy/static/doc/manual.pdf'>the manual</a>
|
||||
the PosBox, please refer to <a href='/hw_proxy/static/doc/manual.pdf'>the manual</a>.
|
||||
</p>
|
||||
<p>
|
||||
To see the status of the connected hardware, please refer
|
||||
to the <a href='/hw_proxy/status'>hardware status page</a>
|
||||
to the <a href='/hw_proxy/status'>hardware status page</a>.
|
||||
</p>
|
||||
<p>
|
||||
The PosBox software installed on this posbox is <b>version 6</b>,
|
||||
The PosBox software installed on this posbox is <b>version 13</b>,
|
||||
the posbox version number is independent from Odoo. You can upgrade
|
||||
the software on the <a href='/hw_proxy/upgrade/'>upgrade page</a>
|
||||
the software on the <a href='/hw_proxy/upgrade/'>upgrade page</a>.
|
||||
</p>
|
||||
<p>For any other question, please contact the Odoo support at <a href='mailto:support@odoo.com'>support@odoo.com</a>
|
||||
</p>
|
||||
|
||||
@@ -29,17 +29,8 @@ upgrade_template = """
|
||||
$.ajax({
|
||||
url:'/hw_proxy/perform_upgrade/'
|
||||
}).then(function(status){
|
||||
$('#upgrade').html('Upgrade Successful<br \\>Click to Restart the PosBox');
|
||||
$('#upgrade').html('Upgrade successful, restarting the posbox...');
|
||||
$('#upgrade').off('click');
|
||||
$('#upgrade').click(function(){
|
||||
$.ajax({ url:'/hw_proxy/perform_restart' })
|
||||
$('#upgrade').text('Restarting');
|
||||
$('#upgrade').off('click');
|
||||
setTimeout(function(){
|
||||
window.location = '/'
|
||||
},30*1000);
|
||||
});
|
||||
|
||||
},function(){
|
||||
$('#upgrade').text('Upgrade Failed');
|
||||
});
|
||||
@@ -73,9 +64,11 @@ upgrade_template = """
|
||||
<body>
|
||||
<h1>PosBox Software Upgrade</h1>
|
||||
<p>
|
||||
This tool will help you perform an upgrade of the PosBox's software.
|
||||
This tool will help you perform an upgrade of the PosBox's software over the
|
||||
internet.
|
||||
<p></p>
|
||||
However the preferred method to upgrade the posbox is to flash the sd-card with
|
||||
the <a href='http://nightly.openerp.com/trunk/posbox/'>latest image</a>. The upgrade
|
||||
the <a href='http://nightly.odoo.com/trunk/posbox/'>latest image</a>. The upgrade
|
||||
procedure is explained into to the <a href='/hw_proxy/static/doc/manual.pdf'>PosBox manual</a>
|
||||
</p>
|
||||
<p>
|
||||
@@ -93,7 +86,6 @@ class PosboxUpgrader(hw_proxy.Proxy):
|
||||
def __init__(self):
|
||||
super(PosboxUpgrader,self).__init__()
|
||||
self.upgrading = threading.Lock()
|
||||
self.last_upgrade = 0
|
||||
|
||||
@http.route('/hw_proxy/upgrade', type='http', auth='none', )
|
||||
def upgrade(self):
|
||||
@@ -102,25 +94,8 @@ class PosboxUpgrader(hw_proxy.Proxy):
|
||||
@http.route('/hw_proxy/perform_upgrade', type='http', auth='none')
|
||||
def perform_upgrade(self):
|
||||
self.upgrading.acquire()
|
||||
if time.time() - self.last_upgrade < 30:
|
||||
self.upgrading.release()
|
||||
return 'UPTODATE'
|
||||
else:
|
||||
os.system('/bin/bash /home/pi/openerp/update.sh')
|
||||
self.last_upgrade = time.time()
|
||||
self.upgrading.release()
|
||||
return 'SUCCESS'
|
||||
|
||||
@http.route('/hw_proxy/perform_restart', type='http', auth='none')
|
||||
def perform_restart(self):
|
||||
self.upgrading.acquire()
|
||||
if time.time() - self.last_upgrade < 30:
|
||||
self.upgrading.release()
|
||||
return 'RESTARTED'
|
||||
else:
|
||||
os.system('/bin/bash /home/pi/openerp/restart.sh')
|
||||
self.last_upgrade = time.time()
|
||||
self.upgrading.release()
|
||||
return 'SUCCESS'
|
||||
|
||||
os.system('/home/pi/posbox_update.sh')
|
||||
|
||||
self.upgrading.release()
|
||||
return 'SUCCESS'
|
||||
|
||||
@@ -17,6 +17,14 @@ _logger = logging.getLogger(__name__)
|
||||
from openerp import http
|
||||
from openerp.http import request
|
||||
|
||||
# Those are the builtin raspberry pi USB modules, they should
|
||||
# not appear in the list of connected devices.
|
||||
BANNED_DEVICES = set([
|
||||
"0424:9514", # Standard Microsystem Corp. Builtin Ethernet module
|
||||
"1d6b:0002", # Linux Foundation 2.0 root hub
|
||||
"0424:ec00", # Standard Microsystem Corp. Other Builtin Ethernet module
|
||||
])
|
||||
|
||||
|
||||
# drivers modules must add to drivers an object with a get_status() method
|
||||
# so that 'status' can return the status of all active drivers
|
||||
@@ -88,10 +96,18 @@ class Proxy(http.Controller):
|
||||
<p>The list of connected USB devices as seen by the posbox</p>
|
||||
"""
|
||||
devices = commands.getoutput("lsusb").split('\n')
|
||||
count = 0
|
||||
resp += "<div class='devices'>\n"
|
||||
for device in devices:
|
||||
device_name = device[device.find('ID')+2:]
|
||||
resp+= "<div class='device' data-device='"+device+"'>"+device_name+"</div>\n"
|
||||
device_id = device_name.split()[0]
|
||||
if not (device_id in BANNED_DEVICES):
|
||||
resp+= "<div class='device' data-device='"+device+"'>"+device_name+"</div>\n"
|
||||
count += 1
|
||||
|
||||
if count == 0:
|
||||
resp += "<div class='device'>No USB Device Found</div>"
|
||||
|
||||
resp += "</div>\n"
|
||||
resp += """
|
||||
<h2>Add New Printer</h2>
|
||||
|
||||
@@ -44,6 +44,11 @@ class Scale(Thread):
|
||||
if status == self.status['status']:
|
||||
if message != None and message != self.status['messages'][-1]:
|
||||
self.status['messages'].append(message)
|
||||
|
||||
if status == 'error' and message:
|
||||
_logger.error('Scale Error: '+message)
|
||||
elif status == 'disconnected' and message:
|
||||
_logger.warning('Disconnected Scale: '+message)
|
||||
else:
|
||||
self.status['status'] = status
|
||||
if message:
|
||||
@@ -51,13 +56,16 @@ class Scale(Thread):
|
||||
else:
|
||||
self.status['messages'] = []
|
||||
|
||||
if status == 'error' and message:
|
||||
_logger.error('Scale Error: '+message)
|
||||
elif status == 'disconnected' and message:
|
||||
_logger.info('Disconnected Scale: %s', message)
|
||||
if status == 'error' and message:
|
||||
_logger.error('Scale Error: '+message)
|
||||
elif status == 'disconnected' and message:
|
||||
_logger.info('Disconnected Scale: %s', message)
|
||||
|
||||
def get_device(self):
|
||||
try:
|
||||
if not os.path.exists(self.input_dir):
|
||||
self.set_status('disconnected','Scale Not Found')
|
||||
return None
|
||||
devices = [ device for device in listdir(self.input_dir)]
|
||||
scales = [ device for device in devices if ('mettler' in device.lower()) or ('toledo' in device.lower()) ]
|
||||
if len(scales) > 0:
|
||||
@@ -69,8 +77,8 @@ class Scale(Thread):
|
||||
stopbits = serial.STOPBITS_ONE,
|
||||
parity = serial.PARITY_EVEN,
|
||||
#xonxoff = serial.XON,
|
||||
timeout = 0.01,
|
||||
writeTimeout= 0.01)
|
||||
timeout = 0.02,
|
||||
writeTimeout= 0.02)
|
||||
else:
|
||||
self.set_status('disconnected','Scale Not Found')
|
||||
return None
|
||||
@@ -95,7 +103,7 @@ class Scale(Thread):
|
||||
if self.device:
|
||||
try:
|
||||
self.device.write('W')
|
||||
time.sleep(0.1)
|
||||
time.sleep(0.2)
|
||||
answer = []
|
||||
|
||||
while True:
|
||||
@@ -171,7 +179,7 @@ class Scale(Thread):
|
||||
while True:
|
||||
if self.device:
|
||||
self.read_weight()
|
||||
time.sleep(0.05)
|
||||
time.sleep(0.15)
|
||||
else:
|
||||
with self.scalelock:
|
||||
self.device = self.get_device()
|
||||
|
||||
@@ -111,6 +111,8 @@ class Scanner(Thread):
|
||||
|
||||
def get_device(self):
|
||||
try:
|
||||
if not evdev:
|
||||
return None
|
||||
devices = [ device for device in listdir(self.input_dir)]
|
||||
keyboards = [ device for device in devices if ('kbd' in device) and ('keyboard' not in device.lower())]
|
||||
scanners = [ device for device in devices if ('barcode' in device.lower()) or ('scanner' in device.lower())]
|
||||
@@ -133,6 +135,7 @@ class Scanner(Thread):
|
||||
been returned before. This is necessary to catch barcodes scanned while the POS is
|
||||
busy reading another barcode
|
||||
"""
|
||||
|
||||
self.lockedstart()
|
||||
|
||||
while True:
|
||||
@@ -164,10 +167,13 @@ class Scanner(Thread):
|
||||
try:
|
||||
device.ungrab()
|
||||
except Exception as e:
|
||||
device = None
|
||||
self.set_status('error',str(e))
|
||||
else:
|
||||
time.sleep(5) # wait until a suitable device is plugged
|
||||
device = self.get_device()
|
||||
if not device:
|
||||
continue
|
||||
|
||||
try:
|
||||
device.grab()
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
import urllib
|
||||
import urlparse
|
||||
import werkzeug.urls
|
||||
|
||||
from openerp import tools
|
||||
from openerp import SUPERUSER_ID
|
||||
@@ -55,7 +55,7 @@ class MailMail(osv.Model):
|
||||
track_url = urlparse.urljoin(
|
||||
base_url, 'mail/track/%(mail_id)s/blank.gif?%(params)s' % {
|
||||
'mail_id': mail.id,
|
||||
'params': urllib.urlencode({'db': cr.dbname})
|
||||
'params': werkzeug.url_encode({'db': cr.dbname})
|
||||
}
|
||||
)
|
||||
return '<img src="%s" alt=""/>' % track_url
|
||||
@@ -65,7 +65,7 @@ class MailMail(osv.Model):
|
||||
url = urlparse.urljoin(
|
||||
base_url, 'mail/mailing/%(mailing_id)s/unsubscribe?%(params)s' % {
|
||||
'mailing_id': mail.mailing_id.id,
|
||||
'params': urllib.urlencode({'db': cr.dbname, 'res_id': mail.res_id, 'email': email_to})
|
||||
'params': werkzeug.url_encode({'db': cr.dbname, 'res_id': mail.res_id, 'email': email_to})
|
||||
}
|
||||
)
|
||||
return url
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
kernel-qemu
|
||||
posbox.img
|
||||
raspbian.img
|
||||
@@ -0,0 +1,4 @@
|
||||
proc /proc proc defaults 0 0
|
||||
/dev/mmcblk0p1 /boot vfat defaults 0 2
|
||||
/dev/mmcblk0p2 / ext4 defaults,noatime,ro 0 1
|
||||
# a swapfile is not a swap partition, so no using swapon|off from here on, use dphys-swapfile swap[on|off] for that
|
||||
@@ -0,0 +1,10 @@
|
||||
#! /bin/sh
|
||||
#
|
||||
# rcS
|
||||
#
|
||||
# Call all S??* scripts in /etc/rcS.d/ in numerical/alphabetical order
|
||||
#
|
||||
|
||||
/etc/setup_ramdisks.sh
|
||||
|
||||
exec /etc/init.d/rc S
|
||||
@@ -0,0 +1,3 @@
|
||||
# needed for postgresql
|
||||
auto lo
|
||||
iface lo inet loopback
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# rc.local
|
||||
#
|
||||
# This script is executed at the end of each multiuser runlevel.
|
||||
# Make sure that the script will "exit 0" on success or any other
|
||||
# value on error.
|
||||
#
|
||||
# In order to enable or disable this script just change the execution
|
||||
# bits.
|
||||
#
|
||||
# By default this script does nothing.
|
||||
|
||||
# Print the IP address
|
||||
_IP=$(hostname -I) || true
|
||||
if [ "$_IP" ]; then
|
||||
printf "My IP address is %s\n" "$_IP"
|
||||
fi
|
||||
|
||||
mkdir -p /var/run/odoo
|
||||
chown pi:pi /var/run/odoo
|
||||
|
||||
/home/pi/led_status.sh &
|
||||
|
||||
exit 0
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace
|
||||
|
||||
create_ramdisk () {
|
||||
ORIGINAL="${1}"
|
||||
RAMDISK="${ORIGINAL}_ram"
|
||||
SIZE="${2}"
|
||||
echo "Creating ramdisk for ${1} of size ${SIZE}..."
|
||||
|
||||
mount -t tmpfs -o size="${SIZE}" tmpfs "${RAMDISK}"
|
||||
rsync -a --exclude="swap" --exclude="apt" --exclude="dpkg" "${ORIGINAL}/" "${RAMDISK}/"
|
||||
mount --bind "${RAMDISK}" "${ORIGINAL}"
|
||||
}
|
||||
|
||||
# check /proc/cmdline
|
||||
|
||||
# bind mount / so that we can get to the real /var and /etc
|
||||
mount --bind / /root_bypass_ramdisks
|
||||
|
||||
echo "Creating ramdisks..."
|
||||
create_ramdisk "/var" "128M"
|
||||
create_ramdisk "/etc" "16M"
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/bin/bash
|
||||
### BEGIN INIT INFO
|
||||
# Provides: odoo.py
|
||||
# Required-Start: $remote_fs $syslog postgresql
|
||||
# Required-Stop: $remote_fs $syslog
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop: 0 1 6
|
||||
# Short-Description: Start odoo daemon at boot time
|
||||
# Description: Enable service provided by daemon.
|
||||
# X-Interactive: true
|
||||
### END INIT INFO
|
||||
## more info: http://wiki.debian.org/LSBInitScripts
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin
|
||||
DAEMON=/home/pi/odoo/odoo.py
|
||||
NAME=odoo
|
||||
DESC=odoo
|
||||
CONFIG=/home/pi/odoo.conf
|
||||
LOGFILE=/var/log/odoo/odoo-server.log
|
||||
PIDFILE=/var/run/${NAME}.pid
|
||||
USER=pi
|
||||
|
||||
test -x $DAEMON || exit 0
|
||||
set -e
|
||||
|
||||
function _start() {
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$USER --background --make-pidfile --exec $DAEMON -- --config $CONFIG --logfile $LOGFILE --load=web,hw_proxy,hw_posbox_homepage,hw_posbox_upgrade,hw_scale,hw_scanner,hw_escpos
|
||||
}
|
||||
|
||||
function _stop() {
|
||||
start-stop-daemon --stop --quiet --pidfile $PIDFILE --oknodo --retry 3
|
||||
rm -f $PIDFILE
|
||||
}
|
||||
|
||||
function _status() {
|
||||
start-stop-daemon --status --quiet --pidfile $PIDFILE
|
||||
return $?
|
||||
}
|
||||
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Starting $DESC: "
|
||||
_start
|
||||
echo "ok"
|
||||
;;
|
||||
stop)
|
||||
echo -n "Stopping $DESC: "
|
||||
_stop
|
||||
echo "ok"
|
||||
;;
|
||||
restart|force-reload)
|
||||
echo -n "Restarting $DESC: "
|
||||
_stop
|
||||
sleep 1
|
||||
_start
|
||||
echo "ok"
|
||||
;;
|
||||
status)
|
||||
echo -n "Status of $DESC: "
|
||||
_status && echo "running" || echo "stopped"
|
||||
;;
|
||||
*)
|
||||
N=/etc/init.d/$NAME
|
||||
echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename ${__file} .sh)"
|
||||
|
||||
# Recommends: antiword, graphviz, ghostscript, postgresql, python-gevent, poppler-utils
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# GUI-related packages
|
||||
PKGS_TO_DELETE="xserver-xorg-video-fbdev xserver-xorg xinit gstreamer1.0-x gstreamer1.0-omx gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-alsa gstreamer1.0-libav epiphany-browser lxde lxtask menu-xdg gksu xserver-xorg-video-fbturbo xpdf gtk2-engines alsa-utils netsurf-gtk zenity desktop-base lxpolkit weston omxplayer raspberrypi-artwork lightdm gnome-themes-standard-data gnome-icon-theme qt50-snapshot qt50-quick-particle-examples idle python-pygame python-tk idle3 python-serial python-picamera debian-reference-en dillo x2x scratch nuscratch raspberrypi-ui-mods timidity smartsim penguinspuzzle pistore sonic-pi python-pifacecommon python-pifacedigitalio oracle-java8-jdk minecraft-pi python-minecraftpi wolfram-engine raspi-config libgl1-mesa-dri libicu48 pypy-upstream lxde-icon-theme python3"
|
||||
INSTALLED_PKGS_TO_DELETE=""
|
||||
set +o errexit
|
||||
for CURRENT_PKG in $(echo $PKGS_TO_DELETE); do
|
||||
$(dpkg --status $CURRENT_PKG &> /dev/null)
|
||||
if [[ $? -eq 0 ]]; then
|
||||
INSTALLED_PKGS_TO_DELETE="$INSTALLED_PKGS_TO_DELETE $CURRENT_PKG"
|
||||
fi
|
||||
done
|
||||
set -o errexit
|
||||
|
||||
apt-get -y remove --purge ${INSTALLED_PKGS_TO_DELETE}
|
||||
|
||||
# Remove automatically installed dependency packages
|
||||
apt-get -y autoremove
|
||||
|
||||
apt-get update
|
||||
apt-get -y dist-upgrade
|
||||
|
||||
PKGS_TO_INSTALL="adduser postgresql-client python python-dateutil python-decorator python-docutils python-feedparser python-imaging python-jinja2 python-ldap python-libxslt1 python-lxml python-mako python-mock python-openid python-passlib python-psutil python-psycopg2 python-pybabel python-pychart python-pydot python-pyparsing python-pypdf python-reportlab python-requests python-simplejson python-tz python-unittest2 python-vatnumber python-vobject python-werkzeug python-xlwt python-yaml postgresql python-gevent python-serial python-pip python-dev localepurge vim mc mg"
|
||||
|
||||
apt-get -y install ${PKGS_TO_INSTALL}
|
||||
|
||||
apt-get clean
|
||||
localepurge
|
||||
rm -rf /usr/share/doc || true
|
||||
rm -rf /home/pi/python_games || true
|
||||
|
||||
# python-usb in wheezy is too old
|
||||
# the latest pyusb from pip does not work either, usb.core.find() never returns
|
||||
# this may be fixed with libusb>2:1.0.11-1, but that's the most recent one in raspbian
|
||||
# so we install the latest pyusb that works with this libusb
|
||||
pip install pyusb==1.0.0b1
|
||||
pip install qrcode
|
||||
pip install evdev
|
||||
|
||||
usermod -a -G lp pi
|
||||
|
||||
sudo -u postgres createuser -s pi
|
||||
mkdir /var/log/odoo
|
||||
chown pi:pi /var/log/odoo
|
||||
|
||||
update-rc.d odoo defaults
|
||||
|
||||
# create dirs for ramdisks
|
||||
create_ramdisk_dir () {
|
||||
mkdir "${1}_ram"
|
||||
}
|
||||
|
||||
create_ramdisk_dir "/var"
|
||||
create_ramdisk_dir "/etc"
|
||||
mkdir /root_bypass_ramdisks
|
||||
|
||||
reboot
|
||||
@@ -0,0 +1,2 @@
|
||||
# the used qemu-kernel doesn't work well with this library, so get rid of it
|
||||
#/usr/lib/arm-linux-gnueabihf/libcofi_rpi.so
|
||||
@@ -0,0 +1,32 @@
|
||||
# see "man logrotate" for details
|
||||
# rotate log files daily
|
||||
daily
|
||||
|
||||
# keep 2 days worth of backlogs
|
||||
rotate 2
|
||||
|
||||
# create new (empty) log files after rotating old ones
|
||||
create
|
||||
|
||||
# uncomment this if you want your log files compressed
|
||||
#compress
|
||||
|
||||
# packages drop log rotation information into this directory
|
||||
include /etc/logrotate.d
|
||||
|
||||
# no packages own wtmp, or btmp -- we'll rotate them here
|
||||
/var/log/wtmp {
|
||||
missingok
|
||||
monthly
|
||||
create 0664 root utmp
|
||||
rotate 1
|
||||
}
|
||||
|
||||
/var/log/btmp {
|
||||
missingok
|
||||
monthly
|
||||
create 0660 root utmp
|
||||
rotate 1
|
||||
}
|
||||
|
||||
# system-specific logs may be configured here
|
||||
@@ -0,0 +1,5 @@
|
||||
/var/log/odoo/*.log {
|
||||
copytruncate
|
||||
missingok
|
||||
notifempty
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#!/bin/sh -e
|
||||
#
|
||||
# rc.local
|
||||
#
|
||||
# This script is executed at the end of each multiuser runlevel.
|
||||
# Make sure that the script will "exit 0" on success or any other
|
||||
# value on error.
|
||||
#
|
||||
# In order to enable or disable this script just change the execution
|
||||
# bits.
|
||||
#
|
||||
# By default this script does nothing.
|
||||
|
||||
# Print the IP address
|
||||
_IP=$(hostname -I) || true
|
||||
if [ "$_IP" ]; then
|
||||
printf "My IP address is %s\n" "$_IP"
|
||||
fi
|
||||
|
||||
/etc/init_posbox_image.sh
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,3 @@
|
||||
KERNEL=="sda", SYMLINK+="mmcblk0"
|
||||
KERNEL=="sda?", SYMLINK+="mmcblk0p%n"
|
||||
KERNEL=="sda2", SYMLINK+="root"
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set_brightness() {
|
||||
echo "${1}" > /sys/class/leds/led0/brightness
|
||||
}
|
||||
|
||||
check_status_loop() {
|
||||
while true ; do
|
||||
if wget --quiet localhost:8069/hw_proxy/hello -O /dev/null ; then
|
||||
set_brightness 255
|
||||
else
|
||||
set_brightness 0
|
||||
fi
|
||||
sleep 5
|
||||
done
|
||||
}
|
||||
|
||||
echo none > /sys/class/leds/led0/trigger
|
||||
check_status_loop
|
||||
@@ -0,0 +1,6 @@
|
||||
[options]
|
||||
data_dir = /var/run/odoo
|
||||
log_level = error
|
||||
logfile = /var/log/odoo/odoo-server.log
|
||||
pidfile = /var/run/odoo/odoo.pid
|
||||
server_wide_modules = web,hw_proxy,hw_posbox_homepage,hw_posbox_upgrade,hw_scale,hw_scanner,hw_escpos
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
sudo mount -o remount,rw /
|
||||
sudo git --work-tree=/home/pi/odoo/ --git-dir=/home/pi/odoo/.git pull
|
||||
sudo mount -o remount,ro /
|
||||
(sleep 5 && sudo reboot) &
|
||||
@@ -0,0 +1,75 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o errexit
|
||||
set -o nounset
|
||||
set -o pipefail
|
||||
# set -o xtrace
|
||||
|
||||
if [[ $EUID -ne 0 ]]; then
|
||||
echo "This script must be run as root"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
file_exists() {
|
||||
[[ -f $1 ]];
|
||||
}
|
||||
|
||||
__dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
__file="${__dir}/$(basename "${BASH_SOURCE[0]}")"
|
||||
__base="$(basename ${__file} .sh)"
|
||||
|
||||
MOUNT_POINT="${__dir}/root_mount"
|
||||
OVERWRITE_FILES_BEFORE_INIT_DIR="${__dir}/overwrite_before_init"
|
||||
OVERWRITE_FILES_AFTER_INIT_DIR="${__dir}/overwrite_after_init"
|
||||
|
||||
if [ ! -f kernel-qemu ] || ! file_exists *raspbian*.img ; then
|
||||
./posbox_download_images.sh
|
||||
fi
|
||||
|
||||
cp -a *raspbian*.img posbox.img
|
||||
|
||||
CLONE_DIR="${OVERWRITE_FILES_BEFORE_INIT_DIR}/home/pi/odoo"
|
||||
mkdir "${CLONE_DIR}"
|
||||
git clone -b 8.0 --no-checkout --depth 1 https://github.com/odoo/odoo.git "${CLONE_DIR}"
|
||||
cd "${CLONE_DIR}"
|
||||
git config core.sparsecheckout true
|
||||
echo "addons/web
|
||||
addons/web_kanban
|
||||
addons/hw_*
|
||||
openerp/
|
||||
odoo.py" | tee --append .git/info/sparse-checkout > /dev/null
|
||||
git read-tree -mu HEAD
|
||||
cd "${__dir}"
|
||||
|
||||
# rc.local
|
||||
LOOP_MAPPER_PATH=$(kpartx -av posbox.img | tail -n 1 | cut -d ' ' -f 3)
|
||||
LOOP_MAPPER_PATH="/dev/mapper/${LOOP_MAPPER_PATH}"
|
||||
mkdir "${MOUNT_POINT}"
|
||||
mount "${LOOP_MAPPER_PATH}" "${MOUNT_POINT}"
|
||||
|
||||
# 'overlay' the overwrite directory onto the mounted image filesystem
|
||||
cp -a "${OVERWRITE_FILES_BEFORE_INIT_DIR}"/* "${MOUNT_POINT}"
|
||||
|
||||
# get rid of the git clone
|
||||
rm -rf "${CLONE_DIR}"
|
||||
|
||||
# get rid of the mount, we have to remount it anyway because we have
|
||||
# to "refresh" the filesystem after qemu modified it
|
||||
sleep 2
|
||||
umount "${MOUNT_POINT}"
|
||||
|
||||
# from http://paulscott.co.za/blog/full-raspberry-pi-raspbian-emulation-with-qemu/
|
||||
# ssh pi@localhost -p10022
|
||||
qemu-system-arm -kernel kernel-qemu -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -hda posbox.img -net user,hostfwd=tcp::10022-:22,hostfwd=tcp::18069-:8069 -net nic
|
||||
|
||||
mount "${LOOP_MAPPER_PATH}" "${MOUNT_POINT}"
|
||||
cp -av "${OVERWRITE_FILES_AFTER_INIT_DIR}"/* "${MOUNT_POINT}"
|
||||
|
||||
# cleanup
|
||||
sleep 2
|
||||
umount "${MOUNT_POINT}"
|
||||
rm -r "${MOUNT_POINT}"
|
||||
|
||||
echo "Running zerofree..."
|
||||
zerofree -v "${LOOP_MAPPER_PATH}" || true
|
||||
|
||||
kpartx -d posbox.img
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
wget 'http://downloads.raspberrypi.org/raspbian_latest' -O raspbian.img.zip
|
||||
unzip raspbian.img.zip
|
||||
wget 'https://github.com/dhruvvyas90/qemu-rpi-kernel/raw/master/kernel-qemu'
|
||||
@@ -79,7 +79,8 @@ class sale_advance_payment_inv(osv.osv_memory):
|
||||
result = []
|
||||
for sale in sale_obj.browse(cr, uid, sale_ids, context=context):
|
||||
val = inv_line_obj.product_id_change(cr, uid, [], wizard.product_id.id,
|
||||
False, partner_id=sale.partner_id.id, fposition_id=sale.fiscal_position.id)
|
||||
False, partner_id=sale.partner_id.id, fposition_id=sale.fiscal_position.id,
|
||||
company_id=sale.company_id.id)
|
||||
res = val['value']
|
||||
|
||||
# determine and check income account
|
||||
@@ -143,7 +144,7 @@ class sale_advance_payment_inv(osv.osv_memory):
|
||||
'partner_id': sale.partner_invoice_id.id,
|
||||
'invoice_line': [(0, 0, inv_line_values)],
|
||||
'currency_id': sale.pricelist_id.currency_id.id,
|
||||
'comment': '',
|
||||
'comment': sale.note,
|
||||
'payment_term': sale.payment_term.id,
|
||||
'fiscal_position': sale.fiscal_position.id or sale.partner_id.property_account_position.id,
|
||||
'team_id': sale.team_id.id,
|
||||
|
||||
@@ -993,7 +993,8 @@ class stock_picking(osv.osv):
|
||||
move_obj = self.pool.get("stock.move")
|
||||
move_obj.write(cr, uid, backorder_move_ids, {'picking_id': backorder_id}, context=context)
|
||||
|
||||
self.write(cr, uid, [picking.id], {'date_done': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
|
||||
if not picking.date_done:
|
||||
self.write(cr, uid, [picking.id], {'date_done': time.strftime(DEFAULT_SERVER_DATETIME_FORMAT)}, context=context)
|
||||
self.action_confirm(cr, uid, [backorder_id], context=context)
|
||||
return backorder_id
|
||||
return False
|
||||
@@ -1744,12 +1745,14 @@ class stock_move(osv.osv):
|
||||
settings_obj = self.pool.get('stock.config.settings')
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
res = dict.fromkeys(ids, '')
|
||||
precision = self.pool['decimal.precision'].precision_get(cr, uid, 'Product Unit of Measure')
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
if move.state in ('draft', 'done', 'cancel') or move.location_id.usage != 'internal':
|
||||
res[move.id] = '' # 'not applicable' or 'n/a' could work too
|
||||
continue
|
||||
total_available = min(move.product_qty, move.reserved_availability + move.availability)
|
||||
total_available = uom_obj._compute_qty_obj(cr, uid, move.product_id.uom_id, total_available, move.product_uom, context=context)
|
||||
total_available = uom_obj._compute_qty_obj(cr, uid, move.product_id.uom_id, total_available, move.product_uom, round=False, context=context)
|
||||
total_available = float_round(total_available, precision_digits=precision)
|
||||
info = str(total_available)
|
||||
#look in the settings if we need to display the UoM name or not
|
||||
config_ids = settings_obj.search(cr, uid, [], limit=1, order='id DESC', context=context)
|
||||
@@ -1760,7 +1763,8 @@ class stock_move(osv.osv):
|
||||
if move.reserved_availability:
|
||||
if move.reserved_availability != total_available:
|
||||
#some of the available quantity is assigned and some are available but not reserved
|
||||
reserved_available = uom_obj._compute_qty_obj(cr, uid, move.product_id.uom_id, move.reserved_availability, move.product_uom, context=context)
|
||||
reserved_available = uom_obj._compute_qty_obj(cr, uid, move.product_id.uom_id, move.reserved_availability, move.product_uom, round=False, context=context)
|
||||
reserved_available = float_round(reserved_available, precision_digits=precision)
|
||||
info += _(' (%s reserved)') % str(reserved_available)
|
||||
else:
|
||||
#all available quantity is assigned
|
||||
|
||||
@@ -315,9 +315,15 @@ class stock_picking(osv.osv):
|
||||
invoices[key] = invoice_id
|
||||
else:
|
||||
invoice = invoice_obj.browse(cr, uid, invoices[key], context=context)
|
||||
merge_vals = {}
|
||||
if not invoice.origin or invoice_vals['origin'] not in invoice.origin.split(', '):
|
||||
invoice_origin = filter(None, [invoice.origin, invoice_vals['origin']])
|
||||
invoice.write({'origin': ', '.join(invoice_origin)})
|
||||
merge_vals['origin'] = ', '.join(invoice_origin)
|
||||
if not invoice.name or invoice_vals['name'] not in invoice.name.split(', '):
|
||||
invoice_name = filter(None, [invoice.name, invoice_vals['name']])
|
||||
merge_vals['name'] = ', '.join(invoice_name)
|
||||
if merge_vals:
|
||||
invoice.write(merge_vals)
|
||||
|
||||
invoice_line_vals = move_obj._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context)
|
||||
invoice_line_vals['invoice_id'] = invoices[key]
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
<record id="survey_input_users_access" model="ir.rule">
|
||||
<field name="name">Access to user_input for regular users</field>
|
||||
<field name="model_id" ref="survey.model_survey_user_input"/>
|
||||
<field name="domain_force">[('create_uid', '=', user.id)]</field>
|
||||
<field name="domain_force">['|', ('create_uid', '=', user.id), ('partner_id', '=', user.partner_id.id)]</field>
|
||||
<field name="groups" eval="[(4, ref('base.group_survey_user'))]"/>
|
||||
<field eval="0" name="perm_unlink"/>
|
||||
<field eval="0" name="perm_write"/>
|
||||
|
||||
@@ -24,9 +24,6 @@
|
||||
}
|
||||
|
||||
/** web_kanban */
|
||||
:root .openerp .oe_kanban_view .oe_kanban_group_title_vertical {
|
||||
writing-mode: lr-tb;
|
||||
}
|
||||
.openerp .oe_kanban_column_cards {
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,6 @@
|
||||
.openerp .oe_kanban_view .oe_kanban_group_title_undefined {
|
||||
color: #666666; }
|
||||
.openerp .oe_kanban_view .oe_kanban_group_title_vertical {
|
||||
writing-mode: vertical-rl;
|
||||
-webkit-transform: rotate(90deg);
|
||||
-moz-transform: rotate(90deg);
|
||||
-o-transform: rotate(90deg);
|
||||
@@ -483,7 +482,6 @@
|
||||
.openerp_ie .oe_kanban_view .oe_kanban_group_header.oe_kanban_group_folded .oe_kanban_group_title_vertical {
|
||||
display: inline-block !important; }
|
||||
.openerp_ie .oe_kanban_view .oe_kanban_group_title_vertical {
|
||||
-ms-writing-mode: lr-tb !important;
|
||||
background: #f0eeee; }
|
||||
.openerp_ie .oe_kanban_view.oe_kanban_grouped .oe_kanban_group_header {
|
||||
height: 1%; }
|
||||
|
||||
@@ -203,7 +203,6 @@
|
||||
.oe_kanban_group_title_undefined
|
||||
color: #666666
|
||||
.oe_kanban_group_title_vertical
|
||||
writing-mode: vertical-rl
|
||||
-webkit-transform: rotate(90deg)
|
||||
-moz-transform: rotate(90deg)
|
||||
-o-transform: rotate(90deg)
|
||||
@@ -515,7 +514,6 @@
|
||||
.oe_kanban_group_header.oe_kanban_group_folded .oe_kanban_group_title_vertical
|
||||
display: inline-block !important
|
||||
.oe_kanban_group_title_vertical
|
||||
-ms-writing-mode: lr-tb !important
|
||||
background: rgb(240, 238, 238)
|
||||
&.oe_kanban_grouped
|
||||
.oe_kanban_group_header
|
||||
|
||||
@@ -369,8 +369,8 @@
|
||||
// retrieve the hash before the redirect
|
||||
var redirect = {
|
||||
lang: self.data('lang'),
|
||||
url: self.attr('href'),
|
||||
hash: location.hash
|
||||
url: encodeURIComponent(self.attr('href')),
|
||||
hash: encodeURIComponent(location.hash)
|
||||
};
|
||||
location.href = _.str.sprintf("/website/lang/%(lang)s?r=%(url)s%(hash)s", redirect);
|
||||
});
|
||||
|
||||
@@ -84,7 +84,7 @@ $('.oe_website_sale').each(function () {
|
||||
return;
|
||||
}
|
||||
if (!data.quantity) {
|
||||
location.reload();
|
||||
location.reload(true);
|
||||
return;
|
||||
}
|
||||
var $q = $(".my_cart_quantity");
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
Lithuania, Macedonia, 2015-07-31
|
||||
|
||||
HBEE agrees to the terms of the Odoo Corporate Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Paulius Sladkevičius paulius@hbee.eu https://github.com/komsas
|
||||
|
||||
List of contributors:
|
||||
|
||||
Darko Nikolovski darko@hbee.eu https://github.com/DarkoNikolovski
|
||||
Ignas Karpiejus ignas@hbee.eu https://github.com/ignask
|
||||
Karolis Kalantojus karolis@hbee.eu https://github.com/kkarolis
|
||||
Kiril Vangelovski kiril@hbee.eu https://github.com/kirca
|
||||
Naglis Jonaitis naglis@hbee.eu https://github.com/naglis
|
||||
Paulius Sladkevičius paulius@hbee.eu https://github.com/komsas
|
||||
Tomas Račys tomas@hbee.eu https://github.com/taezaz
|
||||
@@ -0,0 +1,14 @@
|
||||
Paraguay, 2015-07-09
|
||||
|
||||
Rossa S.A. agrees to the terms of the Odoo Corporate Contributor License Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Rossa S.A. emaildarossa@gmail.com https://github.com/rossasa
|
||||
|
||||
List of contributors:
|
||||
|
||||
Marcelo Pickler marcelo@rossa.com.py https://github.com/loxamir
|
||||
Alan R. S. Pieske alan@rossa.com.py https://github.com/alanpy
|
||||
@@ -0,0 +1,18 @@
|
||||
Australia, 2015-07-20
|
||||
|
||||
Willow IT agrees to the terms of the Odoo Corporate Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Richard deMeester richard@willowit.com.au https://github.com/richard-willowit
|
||||
|
||||
List of contributors:
|
||||
|
||||
Richard deMeester richard@willowit.com.au https://github.com/richard-willowit
|
||||
Douglas Parker doug@willowit.com.au https://github.com/doug-willowit
|
||||
Bhavya Malik bhavya@willowit.com.au https://github.com/bhavya-willowit
|
||||
Jon Wilson jon@willowit.com.au https://github.com/jon-willowit
|
||||
@@ -730,7 +730,7 @@ class view(osv.osv):
|
||||
orm.transfer_field_to_modifiers(field, modifiers)
|
||||
|
||||
elif node.tag in ('form', 'tree'):
|
||||
result = Model.view_header_get(cr, user, False, node.tag, context)
|
||||
result = Model.view_header_get(cr, user, False, node.tag, context=context)
|
||||
if result:
|
||||
node.set('string', result)
|
||||
in_tree_view = node.tag == 'tree'
|
||||
@@ -869,17 +869,17 @@ class view(osv.osv):
|
||||
if node.tag == 'diagram':
|
||||
if node.getchildren()[0].tag == 'node':
|
||||
node_model = self.pool[node.getchildren()[0].get('object')]
|
||||
node_fields = node_model.fields_get(cr, user, None, context)
|
||||
node_fields = node_model.fields_get(cr, user, None, context=context)
|
||||
fields.update(node_fields)
|
||||
if not node.get("create") and \
|
||||
not node_model.check_access_rights(cr, user, 'create', raise_exception=False) or \
|
||||
not context.get("create", True):
|
||||
node.set("create", 'false')
|
||||
if node.getchildren()[1].tag == 'arrow':
|
||||
arrow_fields = self.pool[node.getchildren()[1].get('object')].fields_get(cr, user, None, context)
|
||||
arrow_fields = self.pool[node.getchildren()[1].get('object')].fields_get(cr, user, None, context=context)
|
||||
fields.update(arrow_fields)
|
||||
else:
|
||||
fields = Model.fields_get(cr, user, None, context)
|
||||
fields = Model.fields_get(cr, user, None, context=context)
|
||||
|
||||
node = self.add_on_change(cr, user, model, node)
|
||||
fields_def = self.postprocess(cr, user, model, node, view_id, False, fields, context=context)
|
||||
|
||||
@@ -142,7 +142,7 @@ class res_users(osv.osv):
|
||||
avatar, ... The user model is now dedicated to technical data.
|
||||
"""
|
||||
__admin_ids = {}
|
||||
_uid_cache = {}
|
||||
__uid_cache = {}
|
||||
_inherits = {
|
||||
'res.partner': 'partner_id',
|
||||
}
|
||||
@@ -307,6 +307,24 @@ class res_users(osv.osv):
|
||||
|
||||
return result
|
||||
|
||||
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True):
|
||||
if uid != SUPERUSER_ID:
|
||||
groupby_fields = set([groupby] if isinstance(groupby, basestring) else groupby)
|
||||
if groupby_fields.intersection(USER_PRIVATE_FIELDS):
|
||||
raise openerp.exceptions.AccessError('Invalid groupby')
|
||||
return super(res_users, self).read_group(
|
||||
cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby, lazy=lazy)
|
||||
|
||||
def _search(self, cr, user, args, offset=0, limit=None, order=None, context=None, count=False, access_rights_uid=None):
|
||||
if user != SUPERUSER_ID and args:
|
||||
domain_terms = [term for term in args if isinstance(term, (tuple, list))]
|
||||
domain_fields = set(left for (left, op, right) in domain_terms)
|
||||
if domain_fields.intersection(USER_PRIVATE_FIELDS):
|
||||
raise openerp.exceptions.AccessError('Invalid search criterion')
|
||||
return super(res_users, self)._search(
|
||||
cr, user, args, offset=offset, limit=limit, order=order, context=context, count=count,
|
||||
access_rights_uid=access_rights_uid)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
user_id = super(res_users, self).create(cr, uid, vals, context=context)
|
||||
user = self.browse(cr, uid, user_id, context=context)
|
||||
@@ -341,10 +359,10 @@ class res_users(osv.osv):
|
||||
clear = partial(self.pool['ir.rule'].clear_cache, cr)
|
||||
map(clear, ids)
|
||||
db = cr.dbname
|
||||
if db in self._uid_cache:
|
||||
if db in self.__uid_cache:
|
||||
for id in ids:
|
||||
if id in self._uid_cache[db]:
|
||||
del self._uid_cache[db][id]
|
||||
if id in self.__uid_cache[db]:
|
||||
del self.__uid_cache[db][id]
|
||||
self._context_get.clear_cache(self)
|
||||
self.has_group.clear_cache(self)
|
||||
return res
|
||||
@@ -353,10 +371,10 @@ class res_users(osv.osv):
|
||||
if 1 in ids:
|
||||
raise UserError(_('You can not remove the admin user as it is used internally for resources created by Odoo (updates, module installation, ...)'))
|
||||
db = cr.dbname
|
||||
if db in self._uid_cache:
|
||||
if db in self.__uid_cache:
|
||||
for id in ids:
|
||||
if id in self._uid_cache[db]:
|
||||
del self._uid_cache[db][id]
|
||||
if id in self.__uid_cache[db]:
|
||||
del self.__uid_cache[db][id]
|
||||
return super(res_users, self).unlink(cr, uid, ids, context=context)
|
||||
|
||||
def name_search(self, cr, user, name='', args=None, operator='ilike', context=None, limit=100):
|
||||
@@ -495,15 +513,12 @@ class res_users(osv.osv):
|
||||
if not passwd:
|
||||
# empty passwords disallowed for obvious security reasons
|
||||
raise openerp.exceptions.AccessDenied()
|
||||
if self._uid_cache.get(db, {}).get(uid) == passwd:
|
||||
if self.__uid_cache.setdefault(db, {}).get(uid) == passwd:
|
||||
return
|
||||
cr = self.pool.cursor()
|
||||
try:
|
||||
self.check_credentials(cr, uid, passwd)
|
||||
if self._uid_cache.has_key(db):
|
||||
self._uid_cache[db][uid] = passwd
|
||||
else:
|
||||
self._uid_cache[db] = {uid:passwd}
|
||||
self.__uid_cache[db][uid] = passwd
|
||||
finally:
|
||||
cr.close()
|
||||
|
||||
|
||||
@@ -334,6 +334,7 @@ class HttpCase(TransactionCase):
|
||||
phantom.terminate()
|
||||
phantom.wait()
|
||||
self._wait_remaining_requests()
|
||||
# we ignore phantomjs return code as we kill it as soon as we have ok
|
||||
_logger.info("phantom_run execution finished")
|
||||
|
||||
def _wait_remaining_requests(self):
|
||||
|
||||
Reference in New Issue
Block a user