[MERGE] forward port of branch 8.0 up to 86f98d5
This commit is contained in:
@@ -542,7 +542,8 @@ class account_bank_statement_line(osv.osv):
|
|||||||
('reconcile_id', '=', False),
|
('reconcile_id', '=', False),
|
||||||
('state', '=', 'valid'),
|
('state', '=', 'valid'),
|
||||||
('account_id.reconcile', '=', True),
|
('account_id.reconcile', '=', True),
|
||||||
('id', 'not in', excluded_ids)]
|
('id', 'not in', excluded_ids),
|
||||||
|
('partner_id', 'in', (False, st_line.partner_id.id))]
|
||||||
return domain
|
return domain
|
||||||
|
|
||||||
def get_reconciliation_proposition(self, cr, uid, st_line, excluded_ids=None, context=None):
|
def get_reconciliation_proposition(self, cr, uid, st_line, excluded_ids=None, context=None):
|
||||||
|
|||||||
@@ -742,6 +742,7 @@ class account_invoice(models.Model):
|
|||||||
else:
|
else:
|
||||||
line['currency_id'] = False
|
line['currency_id'] = False
|
||||||
line['amount_currency'] = False
|
line['amount_currency'] = False
|
||||||
|
line['price'] = self.currency_id.round(line['price'])
|
||||||
line['ref'] = ref
|
line['ref'] = ref
|
||||||
if self.type in ('out_invoice','in_refund'):
|
if self.type in ('out_invoice','in_refund'):
|
||||||
total += line['price']
|
total += line['price']
|
||||||
|
|||||||
@@ -691,6 +691,7 @@ class account_analytic_account(osv.osv):
|
|||||||
'fiscal_position': fpos_id,
|
'fiscal_position': fpos_id,
|
||||||
'payment_term': partner_payment_term,
|
'payment_term': partner_payment_term,
|
||||||
'company_id': contract.company_id.id or False,
|
'company_id': contract.company_id.id or False,
|
||||||
|
'user_id': contract.manager_id.id or uid,
|
||||||
}
|
}
|
||||||
return invoice
|
return invoice
|
||||||
|
|
||||||
|
|||||||
@@ -2,5 +2,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
|||||||
access_account_analytic_plan,account.analytic.plan,model_account_analytic_plan,account.group_account_user,1,1,1,1
|
access_account_analytic_plan,account.analytic.plan,model_account_analytic_plan,account.group_account_user,1,1,1,1
|
||||||
access_account_analytic_plan_line,account.analytic.plan.line,model_account_analytic_plan_line,account.group_account_user,1,1,1,1
|
access_account_analytic_plan_line,account.analytic.plan.line,model_account_analytic_plan_line,account.group_account_user,1,1,1,1
|
||||||
access_account_analytic_plan_instance,account.analytic.plan.instance,model_account_analytic_plan_instance,account.group_account_user,1,1,1,1
|
access_account_analytic_plan_instance,account.analytic.plan.instance,model_account_analytic_plan_instance,account.group_account_user,1,1,1,1
|
||||||
|
access_account_analytic_plan_instance_group_user,account.analytic.plan.instance,model_account_analytic_plan_instance,base.group_user,1,0,0,0
|
||||||
access_account_analytic_plan_instance_line,account.analytic.plan.instance.line,model_account_analytic_plan_instance_line,account.group_account_user,1,1,1,1
|
access_account_analytic_plan_instance_line,account.analytic.plan.instance.line,model_account_analytic_plan_instance_line,account.group_account_user,1,1,1,1
|
||||||
|
access_account_analytic_plan_instance_line_group_user,account.analytic.plan.instance.line,model_account_analytic_plan_instance_line,base.group_user,1,0,0,0
|
||||||
access_account_analytic_plan_line_invoice,account.analytic.plan.line.invoice,model_account_analytic_plan_line,account.group_account_user,1,1,1,1
|
access_account_analytic_plan_line_invoice,account.analytic.plan.line.invoice,model_account_analytic_plan_line,account.group_account_user,1,1,1,1
|
||||||
|
|||||||
|
@@ -277,7 +277,10 @@ class account_analytic_line(osv.osv):
|
|||||||
|
|
||||||
for (key_id, company_id, currency_id), analytic_lines in invoice_grouping.items():
|
for (key_id, company_id, currency_id), analytic_lines in invoice_grouping.items():
|
||||||
# key_id is an account.analytic.account
|
# key_id is an account.analytic.account
|
||||||
partner = analytic_lines[0].account_id.partner_id # will be the same for every line
|
account = analytic_lines[0].account_id
|
||||||
|
partner = account.partner_id # will be the same for every line
|
||||||
|
if (not partner) or not (currency_id):
|
||||||
|
raise UserError(_('Contract incomplete. Please fill in the Customer and Pricelist fields for %s.') % (account.name))
|
||||||
|
|
||||||
curr_invoice = self._prepare_cost_invoice(cr, uid, partner, company_id, currency_id, analytic_lines, context=context)
|
curr_invoice = self._prepare_cost_invoice(cr, uid, partner, company_id, currency_id, analytic_lines, context=context)
|
||||||
invoice_context = dict(context,
|
invoice_context = dict(context,
|
||||||
@@ -292,8 +295,6 @@ class account_analytic_line(osv.osv):
|
|||||||
invoice_lines_grouping = {}
|
invoice_lines_grouping = {}
|
||||||
for analytic_line in analytic_lines:
|
for analytic_line in analytic_lines:
|
||||||
account = analytic_line.account_id
|
account = analytic_line.account_id
|
||||||
if (not partner) or not (account.pricelist_id):
|
|
||||||
raise UserError(_('Contract incomplete. Please fill in the Customer and Pricelist fields for %s.') % (account.name))
|
|
||||||
|
|
||||||
if not analytic_line.to_invoice:
|
if not analytic_line.to_invoice:
|
||||||
raise UserError(_('Trying to invoice non invoiceable line for %s.') % (analytic_line.product_id.name))
|
raise UserError(_('Trying to invoice non invoiceable line for %s.') % (analytic_line.product_id.name))
|
||||||
|
|||||||
@@ -1,9 +1,22 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<openerp>
|
<openerp>
|
||||||
|
<data noupdate="1">
|
||||||
|
<!-- Those properties are in a noupdate section in the stock module -->
|
||||||
|
<!-- No need to create them if they have been deleted -->
|
||||||
|
<record id="stock.property_stock_account_input_categ" model="ir.property" forcecreate="False">
|
||||||
|
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_account_input_categ')]"/>
|
||||||
|
<field eval="'account.account,'+str(ref('chart2141_en'))" model="account.account" name="value"/>
|
||||||
|
<field eval="'product.category,'+str(ref('product.product_category_all'))" model="product.category" name="res_id"/>
|
||||||
|
</record>
|
||||||
|
<record id="stock.property_stock_account_output_categ" model="ir.property" forcecreate="False">
|
||||||
|
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_account_output_categ')]"/>
|
||||||
|
<field eval="'account.account,'+str(ref('chart1145_en'))" model="account.account" name="value"/>
|
||||||
|
<field eval="'product.category,'+str(ref('product.product_category_all'))" model="product.category" name="res_id"/>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
<!-- Chart template -->
|
<!-- Chart template -->
|
||||||
|
|
||||||
<record id="ca_en_chart_template_en" model="account.chart.template">
|
<record id="ca_en_chart_template_en" model="account.chart.template">
|
||||||
<field name="name">Canada - Chart of Accounts for english-speaking provinces</field>
|
<field name="name">Canada - Chart of Accounts for english-speaking provinces</field>
|
||||||
<field name="account_root_id" ref="chart0_en"/>
|
<field name="account_root_id" ref="chart0_en"/>
|
||||||
@@ -16,18 +29,6 @@
|
|||||||
<field name="currency_id" ref="base.CAD"/>
|
<field name="currency_id" ref="base.CAD"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="stock.property_stock_account_input_categ" model="ir.property">
|
|
||||||
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_account_input_categ')]"/>
|
|
||||||
<field eval="'account.account,'+str(ref('chart2141_en'))" model="account.account" name="value"/>
|
|
||||||
<field eval="'product.category,'+str(ref('product.product_category_all'))" model="product.category" name="res_id"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="stock.property_stock_account_output_categ" model="ir.property">
|
|
||||||
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_account_output_categ')]"/>
|
|
||||||
<field eval="'account.account,'+str(ref('chart1145_en'))" model="account.account" name="value"/>
|
|
||||||
<field eval="'product.category,'+str(ref('product.product_category_all'))" model="product.category" name="res_id"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="property_stock_valuation_account_id_en" model="ir.property">
|
<record id="property_stock_valuation_account_id_en" model="ir.property">
|
||||||
<field name="name">property_stock_valuation_account_id</field>
|
<field name="name">property_stock_valuation_account_id</field>
|
||||||
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_valuation_account_id')]"/>
|
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_valuation_account_id')]"/>
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<openerp>
|
<openerp>
|
||||||
|
<data noupdate="1">
|
||||||
|
<!-- Those properties are in a noupdate section in the stock module -->
|
||||||
|
<!-- No need to create them if they have been deleted -->
|
||||||
|
<record id="stock.property_stock_account_input_categ" model="ir.property" forcecreate="False">
|
||||||
|
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_account_input_categ')]"/>
|
||||||
|
<field eval="'account.account,'+str(ref('chart2171_fr'))" model="account.account" name="value"/>
|
||||||
|
<field eval="'product.category,'+str(ref('product.product_category_all'))" model="product.category" name="res_id"/>
|
||||||
|
</record>
|
||||||
|
<record id="stock.property_stock_account_output_categ" model="ir.property" forcecreate="False">
|
||||||
|
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_account_output_categ')]"/>
|
||||||
|
<field eval="'account.account,'+str(ref('chart1145_fr'))" model="account.account" name="value"/>
|
||||||
|
<field eval="'product.category,'+str(ref('product.product_category_all'))" model="product.category" name="res_id"/>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
<data>
|
<data>
|
||||||
|
|
||||||
<!-- Chart template -->
|
<!-- Chart template -->
|
||||||
@@ -15,18 +29,6 @@
|
|||||||
<field name="currency_id" ref="base.CAD"/>
|
<field name="currency_id" ref="base.CAD"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="stock.property_stock_account_input_categ" model="ir.property">
|
|
||||||
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_account_input_categ')]"/>
|
|
||||||
<field eval="'account.account,'+str(ref('chart2171_fr'))" model="account.account" name="value"/>
|
|
||||||
<field eval="'product.category,'+str(ref('product.product_category_all'))" model="product.category" name="res_id"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="stock.property_stock_account_output_categ" model="ir.property">
|
|
||||||
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_account_output_categ')]"/>
|
|
||||||
<field eval="'account.account,'+str(ref('chart1145_fr'))" model="account.account" name="value"/>
|
|
||||||
<field eval="'product.category,'+str(ref('product.product_category_all'))" model="product.category" name="res_id"/>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="property_stock_valuation_account_id" model="ir.property">
|
<record id="property_stock_valuation_account_id" model="ir.property">
|
||||||
<field name="name">property_stock_valuation_account_id</field>
|
<field name="name">property_stock_valuation_account_id</field>
|
||||||
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_valuation_account_id')]"/>
|
<field name="fields_id" search="[('model','=','product.category'),('name','=','property_stock_valuation_account_id')]"/>
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class TestMassMailing(osv.TransientModel):
|
|||||||
'body_html': '',
|
'body_html': '',
|
||||||
'notification': True,
|
'notification': True,
|
||||||
'mailing_id': mailing.id,
|
'mailing_id': mailing.id,
|
||||||
|
'attachment_ids': [(4, attachment.id) for attachment in mailing.attachment_ids],
|
||||||
}
|
}
|
||||||
mail_mail_obj = Mail.browse(cr, uid, Mail.create(cr, uid, mail_values, context=context), context=context)
|
mail_mail_obj = Mail.browse(cr, uid, Mail.create(cr, uid, mail_values, context=context), context=context)
|
||||||
unsubscribe_url = Mail._get_unsubscribe_url(cr, uid, mail_mail_obj, test_mail, context=context)
|
unsubscribe_url = Mail._get_unsubscribe_url(cr, uid, mail_mail_obj, test_mail, context=context)
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# KEYBOARD CONFIGURATION FILE
|
||||||
|
|
||||||
|
# Consult the keyboard(5) manual page.
|
||||||
|
|
||||||
|
XKBMODEL="pc105"
|
||||||
|
XKBLAYOUT="us"
|
||||||
|
XKBVARIANT=""
|
||||||
|
XKBOPTIONS=""
|
||||||
|
|
||||||
|
BACKSPACE="guess"
|
||||||
@@ -31,7 +31,7 @@ apt-get -y autoremove
|
|||||||
apt-get update
|
apt-get update
|
||||||
apt-get -y dist-upgrade
|
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"
|
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 screen"
|
||||||
|
|
||||||
apt-get -y install ${PKGS_TO_INSTALL}
|
apt-get -y install ${PKGS_TO_INSTALL}
|
||||||
|
|
||||||
@@ -48,14 +48,22 @@ pip install pyusb==1.0.0b1
|
|||||||
pip install qrcode
|
pip install qrcode
|
||||||
pip install evdev
|
pip install evdev
|
||||||
|
|
||||||
|
groupadd usbusers
|
||||||
|
usermod -a -G usbusers pi
|
||||||
usermod -a -G lp pi
|
usermod -a -G lp pi
|
||||||
|
|
||||||
sudo -u postgres createuser -s pi
|
sudo -u postgres createuser -s pi
|
||||||
mkdir /var/log/odoo
|
mkdir /var/log/odoo
|
||||||
chown pi:pi /var/log/odoo
|
chown pi:pi /var/log/odoo
|
||||||
|
|
||||||
|
echo "* * * * * rm /var/run/odoo/sessions/*" | crontab -
|
||||||
|
|
||||||
update-rc.d odoo defaults
|
update-rc.d odoo defaults
|
||||||
|
|
||||||
|
# https://www.raspberrypi.org/forums/viewtopic.php?p=79249
|
||||||
|
# to not have "setting up console font and keymap" during boot take ages
|
||||||
|
setupcon
|
||||||
|
|
||||||
# create dirs for ramdisks
|
# create dirs for ramdisks
|
||||||
create_ramdisk_dir () {
|
create_ramdisk_dir () {
|
||||||
mkdir "${1}_ram"
|
mkdir "${1}_ram"
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
SUBSYSTEM=="usb", GROUP="usbusers", MODE="0660"
|
||||||
|
SUBSYSTEMS=="usb", GROUP="usbusers", MODE="0660"
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
#
|
||||||
|
set meta-flag on
|
||||||
|
set convert-meta off
|
||||||
|
set input-meta on
|
||||||
|
set output-meta on
|
||||||
|
set show-all-if-ambiguous on
|
||||||
|
set visible-stats on
|
||||||
|
set bell-style none
|
||||||
|
# set bell-style visible
|
||||||
|
#"\M-k": kill-whole-line
|
||||||
|
#----------------------------------------------------------
|
||||||
|
# arrows left/right/up/down
|
||||||
|
"\e[C": forward-char
|
||||||
|
"\e[D": backward-char
|
||||||
|
"\e[A": previous-history
|
||||||
|
"\e[B": next-history
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# pgup/pgdn
|
||||||
|
"\e[6~": history-search-forward
|
||||||
|
"\e[5~": history-search-backward
|
||||||
|
#----------------------------------------------------------
|
||||||
|
# insert,delete
|
||||||
|
#"\e[2~": quoted-insert
|
||||||
|
"\e[3~": delete-char
|
||||||
|
# esc+delete, esc+backspace
|
||||||
|
"\e\e[3~": kill-word
|
||||||
|
"\e\C-h": backward-kill-word
|
||||||
|
#----------------------------------------------------------
|
||||||
|
# ctrl left/right (rxvt)
|
||||||
|
"\eOc": forward-word
|
||||||
|
"\eOd": backward-word
|
||||||
|
# ctrl left/right (xterm)
|
||||||
|
"\e[1;5C": forward-word
|
||||||
|
"\e[1;5D": backward-word
|
||||||
|
# ctrl left/right (unknown)
|
||||||
|
#"\e[5C": forward-word
|
||||||
|
#"\e[5D": backward-word
|
||||||
|
#"\e\e[C": forward-word
|
||||||
|
#"\e\e[D": backward-word
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# home/end (linux console)
|
||||||
|
"\e[1~": beginning-of-line
|
||||||
|
"\e[4~": end-of-line
|
||||||
|
# home/end (rxvt)
|
||||||
|
"\e[7~": beginning-of-line
|
||||||
|
"\e[8~": end-of-line
|
||||||
|
# home/end (xterm, freebsd console)
|
||||||
|
"\e[H": beginning-of-line
|
||||||
|
"\e[F": end-of-line
|
||||||
|
# home/end (non RH/Debian xterm, unknown)
|
||||||
|
"\eOH": beginning-of-line
|
||||||
|
"\eOF": end-of-line
|
||||||
|
"\eOw": end-of-line
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
set all&
|
||||||
|
set autoindent
|
||||||
|
set backspace=2
|
||||||
|
set nobackup
|
||||||
|
set nocompatible
|
||||||
|
set noerrorbells
|
||||||
|
set noexpandtab
|
||||||
|
set expandtab
|
||||||
|
set number
|
||||||
|
set hidden
|
||||||
|
set history=500
|
||||||
|
set hlsearch
|
||||||
|
set ignorecase
|
||||||
|
set modeline
|
||||||
|
set ruler
|
||||||
|
set shiftwidth=4
|
||||||
|
set scrolloff=5
|
||||||
|
set showcmd
|
||||||
|
set showmode
|
||||||
|
set tabstop=4
|
||||||
|
set textwidth=0
|
||||||
|
set visualbell
|
||||||
|
set t_vb=
|
||||||
|
set wrap
|
||||||
|
set list
|
||||||
|
set listchars=tab:~.,trail:.,extends:>,precedes:<
|
||||||
|
set viminfo="NONE"
|
||||||
@@ -737,8 +737,12 @@ class purchase_order(osv.osv):
|
|||||||
#we don't round the price_unit, as we may want to store the standard price with more digits than allowed by the currency
|
#we don't round the price_unit, as we may want to store the standard price with more digits than allowed by the currency
|
||||||
price_unit = self.pool.get('res.currency').compute(cr, uid, order.currency_id.id, order.company_id.currency_id.id, price_unit, round=False, context=context)
|
price_unit = self.pool.get('res.currency').compute(cr, uid, order.currency_id.id, order.company_id.currency_id.id, price_unit, round=False, context=context)
|
||||||
res = []
|
res = []
|
||||||
|
if order.location_id.usage == 'customer':
|
||||||
|
name = order_line.product_id.name
|
||||||
|
else:
|
||||||
|
name = order_line.name or ''
|
||||||
move_template = {
|
move_template = {
|
||||||
'name': order_line.name or '',
|
'name': name,
|
||||||
'product_id': order_line.product_id.id,
|
'product_id': order_line.product_id.id,
|
||||||
'product_uom': order_line.product_uom.id,
|
'product_uom': order_line.product_uom.id,
|
||||||
'product_uos': order_line.product_uom.id,
|
'product_uos': order_line.product_uom.id,
|
||||||
@@ -1470,6 +1474,9 @@ class procurement_order(osv.osv):
|
|||||||
|
|
||||||
return qty, price
|
return qty, price
|
||||||
|
|
||||||
|
def update_origin_po(self, cr, uid, po, proc, context=None):
|
||||||
|
pass
|
||||||
|
|
||||||
def _get_grouping_dicts(self, cr, uid, ids, context=None):
|
def _get_grouping_dicts(self, cr, uid, ids, context=None):
|
||||||
"""
|
"""
|
||||||
It will group the procurements according to the pos they should go into. That way, lines going to the same
|
It will group the procurements according to the pos they should go into. That way, lines going to the same
|
||||||
@@ -1586,6 +1593,9 @@ class procurement_order(osv.osv):
|
|||||||
self.message_post(cr, uid, [proc.id], body=_("Purchase line created and linked to an existing Purchase Order"), context=context)
|
self.message_post(cr, uid, [proc.id], body=_("Purchase line created and linked to an existing Purchase Order"), context=context)
|
||||||
po_obj.write(cr, uid, [add_purchase], {'order_line': line_values},context=context)
|
po_obj.write(cr, uid, [add_purchase], {'order_line': line_values},context=context)
|
||||||
|
|
||||||
|
for procurment in procuremnts:
|
||||||
|
self.update_origin_po(cr, uid, po, procurement, context=context)
|
||||||
|
|
||||||
|
|
||||||
# Create new purchase orders
|
# Create new purchase orders
|
||||||
partner_obj = self.pool.get("res.partner")
|
partner_obj = self.pool.get("res.partner")
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<field name="inherit_id" ref="purchase.purchase_order_line_form"/>
|
<field name="inherit_id" ref="purchase.purchase_order_line_form"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="account_analytic_id" position="replace">
|
<field name="account_analytic_id" position="replace">
|
||||||
<field name="analytics_id" context="{'journal_id':parent.journal_id, 'model': 'purchase_order'}" domain="[('plan_id','<>',False)]"/>
|
<field name="analytics_id" groups="purchase.group_analytic_accounting" context="{'journal_id':parent.journal_id, 'model': 'purchase_order'}" domain="[('plan_id','<>',False)]"/>
|
||||||
</field>
|
</field>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
<field name="inherit_id" ref="purchase.purchase_order_form"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="account_analytic_id" position="replace">
|
<field name="account_analytic_id" position="replace">
|
||||||
<field name="analytics_id" context="{'journal_id':parent.journal_id}" domain="[('plan_id','<>',False)]"/>
|
<field name="analytics_id" groups="purchase.group_analytic_accounting" context="{'journal_id':parent.journal_id}" domain="[('plan_id','<>',False)]"/>
|
||||||
</field>
|
</field>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<field name="inherit_id" ref="product.product_product_tree_view"/>
|
<field name="inherit_id" ref="product.product_product_tree_view"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree position="attributes">
|
<tree position="attributes">
|
||||||
<attribute name="colors">red:virtual_available<0;blue:virtual_available>=0 and state in ('draft', 'end', 'obsolete');black:virtual_available>=0 and state not in ('draft', 'end', 'obsolete')</attribute>
|
<attribute name="colors" translation="off">red:virtual_available<0;blue:virtual_available>=0 and state in ('draft', 'end', 'obsolete');black:virtual_available>=0 and state not in ('draft', 'end', 'obsolete')</attribute>
|
||||||
</tree>
|
</tree>
|
||||||
<field name="price" position="after">
|
<field name="price" position="after">
|
||||||
<field name="qty_available"/>
|
<field name="qty_available"/>
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<field name="inherit_id" ref="product.product_template_tree_view"/>
|
<field name="inherit_id" ref="product.product_template_tree_view"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<tree position="attributes">
|
<tree position="attributes">
|
||||||
<attribute name="colors">red:virtual_available<0;blue:virtual_available>=0 and state in ('draft', 'end', 'obsolete');black:virtual_available>=0 and state not in ('draft', 'end', 'obsolete')</attribute>
|
<attribute name="colors" translation="off">red:virtual_available<0;blue:virtual_available>=0 and state in ('draft', 'end', 'obsolete');black:virtual_available>=0 and state not in ('draft', 'end', 'obsolete')</attribute>
|
||||||
</tree>
|
</tree>
|
||||||
<field name="uom_id" position="after">
|
<field name="uom_id" position="after">
|
||||||
<field name="qty_available"/>
|
<field name="qty_available"/>
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<field name="product_manager" position="attributes">
|
<field name="product_manager" position="attributes">
|
||||||
<attribute name="context">{'default_groups_ref': ['base.group_user', 'base.group_sale_manager', 'stock.group_stock_manager']}</attribute>
|
<attribute name="context" translation="off">{'default_groups_ref': ['base.group_user', 'base.group_sale_manager', 'stock.group_stock_manager']}</attribute>
|
||||||
</field>
|
</field>
|
||||||
<group name="procurement" position="after" >
|
<group name="procurement" position="after" >
|
||||||
<group string="Supply Chain Information" attrs="{'invisible': [('type', '=', 'service')]}" groups="base.group_user">
|
<group string="Supply Chain Information" attrs="{'invisible': [('type', '=', 'service')]}" groups="base.group_user">
|
||||||
|
|||||||
@@ -43,3 +43,12 @@ class purchase_order(models.Model):
|
|||||||
if not self.env.context.get('no_invoice_policy_check'):
|
if not self.env.context.get('no_invoice_policy_check'):
|
||||||
self._check_invoice_policy()
|
self._check_invoice_policy()
|
||||||
super(purchase_order, self).wkf_confirm_order()
|
super(purchase_order, self).wkf_confirm_order()
|
||||||
|
|
||||||
|
class procurement_order(models.Model):
|
||||||
|
_inherit = 'procurement.order'
|
||||||
|
|
||||||
|
@api.model
|
||||||
|
def update_origin_po(self, po, proc):
|
||||||
|
super(procurement_order, self).update_origin_po(po, proc)
|
||||||
|
if proc.sale_line_id and not (proc.origin in po.origin):
|
||||||
|
po.sudo().write({'origin': po.origin+', '+proc.origin})
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ def login_redirect():
|
|||||||
# built the redirect url, keeping all the query parameters of the url
|
# built the redirect url, keeping all the query parameters of the url
|
||||||
redirect_url = '%s?%s' % (request.httprequest.base_url, werkzeug.urls.url_encode(request.params))
|
redirect_url = '%s?%s' % (request.httprequest.base_url, werkzeug.urls.url_encode(request.params))
|
||||||
return """<html><head><script>
|
return """<html><head><script>
|
||||||
window.location = '%sredirect=' + encodeURIComponent("%s");
|
window.location = '%sredirect=' + encodeURIComponent("%s" + location.hash);
|
||||||
</script></head></html>
|
</script></head></html>
|
||||||
""" % (url, redirect_url)
|
""" % (url, redirect_url)
|
||||||
|
|
||||||
|
|||||||
@@ -357,10 +357,6 @@ body > nav.navbar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ----- BOOTSTRAP FIX ----- */
|
/* ----- BOOTSTRAP FIX ----- */
|
||||||
.col-md-12 {
|
|
||||||
float: left;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
@-moz-document url-prefix() {
|
@-moz-document url-prefix() {
|
||||||
.table .img-responsive {
|
.table .img-responsive {
|
||||||
|
|||||||
@@ -251,10 +251,6 @@ body > nav.navbar
|
|||||||
|
|
||||||
/* ----- BOOTSTRAP FIX ----- */
|
/* ----- BOOTSTRAP FIX ----- */
|
||||||
|
|
||||||
.col-md-12
|
|
||||||
float: left
|
|
||||||
width: 100%
|
|
||||||
|
|
||||||
@-moz-document url-prefix()
|
@-moz-document url-prefix()
|
||||||
.table .img-responsive
|
.table .img-responsive
|
||||||
width: 100%
|
width: 100%
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
Russia, 2015-08-14
|
||||||
|
|
||||||
|
IT Libertas 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,
|
||||||
|
|
||||||
|
IT Libertas LLC info@itlibertas.com https://github.com/itlibertas
|
||||||
|
|
||||||
|
List of contributors:
|
||||||
|
|
||||||
|
Denis Baranov baranov@itlibertas.com https://github.com/barachka
|
||||||
|
Tatiana Deribina deribina@itlibertas.com https://github.com/Sapfiriana
|
||||||
|
Aleksandr Shevelev shevelev@itlibertas.com https://github.com/alexalv
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
France, 2015-08-18
|
||||||
|
|
||||||
|
I hereby agree to the terms of the Odoo Individual Contributor License
|
||||||
|
Agreement v1.0.
|
||||||
|
|
||||||
|
I declare that I am authorized and able to make this agreement and sign this
|
||||||
|
declaration.
|
||||||
|
|
||||||
|
Signed,
|
||||||
|
|
||||||
|
Florian Hatat github@hatat.me https://github.com/flh
|
||||||
@@ -108,11 +108,9 @@ class ir_http(osv.AbstractModel):
|
|||||||
datas = attach[0]['datas'] or ''
|
datas = attach[0]['datas'] or ''
|
||||||
name = attach[0]['name']
|
name = attach[0]['name']
|
||||||
|
|
||||||
if not datas:
|
if (not datas and name != request.httprequest.path and
|
||||||
if name.startswith(('http://', 'https://', '/')):
|
name.startswith(('http://', 'https://', '/'))):
|
||||||
return werkzeug.utils.redirect(name, 301)
|
return werkzeug.utils.redirect(name, 301)
|
||||||
else:
|
|
||||||
return werkzeug.wrappers.Response(status=204) # NO CONTENT
|
|
||||||
|
|
||||||
response = werkzeug.wrappers.Response()
|
response = werkzeug.wrappers.Response()
|
||||||
server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
|
server_format = openerp.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
|
||||||
|
|||||||
@@ -5,6 +5,18 @@ import openerp.tests.common as common
|
|||||||
|
|
||||||
class test_search(common.TransactionCase):
|
class test_search(common.TransactionCase):
|
||||||
|
|
||||||
|
def patch_order(self, model, order):
|
||||||
|
m_e = self.env[model]
|
||||||
|
m_r = self.registry(model)
|
||||||
|
|
||||||
|
old_order = m_e._order
|
||||||
|
|
||||||
|
@self.addCleanup
|
||||||
|
def cleanup():
|
||||||
|
m_r._order = type(m_e)._order = old_order
|
||||||
|
|
||||||
|
m_r._order = type(m_e)._order = order
|
||||||
|
|
||||||
def test_00_search_order(self):
|
def test_00_search_order(self):
|
||||||
|
|
||||||
registry, cr, uid = self.registry, self.cr, self.uid
|
registry, cr, uid = self.registry, self.cr, self.uid
|
||||||
@@ -96,15 +108,13 @@ class test_search(common.TransactionCase):
|
|||||||
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
||||||
|
|
||||||
# Do: order on many2one, but not by specifying in order parameter of search, but by overriding _order of res_users
|
# Do: order on many2one, but not by specifying in order parameter of search, but by overriding _order of res_users
|
||||||
old_order = users_obj._order
|
self.patch_order('res.users', 'country_id desc, name asc, login desc')
|
||||||
users_obj._order = 'country_id desc, name asc, login desc'
|
|
||||||
user_ids = users_obj.search(cr, search_user, [])
|
user_ids = users_obj.search(cr, search_user, [])
|
||||||
expected_ids = [search_user, c, b, a]
|
expected_ids = [search_user, c, b, a]
|
||||||
test_user_ids = filter(lambda x: x in expected_ids, user_ids)
|
test_user_ids = filter(lambda x: x in expected_ids, user_ids)
|
||||||
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
self.assertEqual(test_user_ids, expected_ids, 'search on res_users did not provide expected ids or expected order')
|
||||||
users_obj._order = old_order
|
|
||||||
|
|
||||||
def test_11_indirect_inherits_m2order(self):
|
def test_11_indirect_inherits_m2o_order(self):
|
||||||
registry, cr, uid = self.registry, self.cr, self.uid
|
registry, cr, uid = self.registry, self.cr, self.uid
|
||||||
Cron = registry('ir.cron')
|
Cron = registry('ir.cron')
|
||||||
Users = registry('res.users')
|
Users = registry('res.users')
|
||||||
@@ -119,6 +129,48 @@ class test_search(common.TransactionCase):
|
|||||||
expected_ids = [cron_ids[l] for l in 'ABC']
|
expected_ids = [cron_ids[l] for l in 'ABC']
|
||||||
self.assertEqual(ids, expected_ids)
|
self.assertEqual(ids, expected_ids)
|
||||||
|
|
||||||
|
def test_12_m2o_order_loop_self(self):
|
||||||
|
registry, cr, uid = self.registry, self.cr, self.uid
|
||||||
|
|
||||||
|
Cats = registry('ir.module.category')
|
||||||
|
ids = {}
|
||||||
|
def create(name, **kw):
|
||||||
|
ids[name] = Cats.create(cr, uid, dict(kw, name=name))
|
||||||
|
|
||||||
|
self.patch_order('ir.module.category', 'parent_id desc, name')
|
||||||
|
|
||||||
|
create('A')
|
||||||
|
create('B', parent_id=ids['A'])
|
||||||
|
create('C', parent_id=ids['A'])
|
||||||
|
create('D')
|
||||||
|
create('E', parent_id=ids['D'])
|
||||||
|
create('F', parent_id=ids['D'])
|
||||||
|
|
||||||
|
expected_order = [ids[x] for x in 'ADEFBC']
|
||||||
|
domain = [('id', 'in', ids.values())]
|
||||||
|
search_result = Cats.search(cr, uid, domain)
|
||||||
|
self.assertEqual(search_result, expected_order)
|
||||||
|
|
||||||
|
def test_13_m2o_order_loop_multi(self):
|
||||||
|
Users = self.env['res.users']
|
||||||
|
|
||||||
|
# will sort by login desc of the creator, then by name
|
||||||
|
self.patch_order('res.partner', 'create_uid, name')
|
||||||
|
self.patch_order('res.users', 'partner_id, login desc')
|
||||||
|
|
||||||
|
kw = dict(groups_id=[(6, 0, [self.ref('base.group_system'),
|
||||||
|
self.ref('base.group_partner_manager')])])
|
||||||
|
|
||||||
|
u1 = Users.create(dict(name='Q', login='m', **kw)).id
|
||||||
|
u2 = Users.sudo(user=u1).create(dict(name='B', login='f', **kw)).id
|
||||||
|
u3 = Users.create(dict(name='C', login='c', **kw)).id
|
||||||
|
u4 = Users.sudo(user=u2).create(dict(name='D', login='z', **kw)).id
|
||||||
|
|
||||||
|
expected_order = [u2, u4, u3, u1]
|
||||||
|
|
||||||
|
domain = [('id', 'in', [u1, u2, u3, u4])]
|
||||||
|
search_result = list(Users.search(domain)._ids)
|
||||||
|
self.assertEqual(search_result, expected_order)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest2.main()
|
unittest2.main()
|
||||||
|
|||||||
+21
-13
@@ -4536,7 +4536,7 @@ class BaseModel(object):
|
|||||||
apply_rule(rule_where_clause, rule_where_clause_params, rule_tables,
|
apply_rule(rule_where_clause, rule_where_clause_params, rule_tables,
|
||||||
parent_model=inherited_model)
|
parent_model=inherited_model)
|
||||||
|
|
||||||
def _generate_m2o_order_by(self, alias, order_field, query, reverse_direction):
|
def _generate_m2o_order_by(self, alias, order_field, query, reverse_direction, seen):
|
||||||
"""
|
"""
|
||||||
Add possibly missing JOIN to ``query`` and generate the ORDER BY clause for m2o fields,
|
Add possibly missing JOIN to ``query`` and generate the ORDER BY clause for m2o fields,
|
||||||
either native m2o fields or function/related fields that are stored, including
|
either native m2o fields or function/related fields that are stored, including
|
||||||
@@ -4546,18 +4546,18 @@ class BaseModel(object):
|
|||||||
"""
|
"""
|
||||||
if order_field not in self._columns and order_field in self._inherit_fields:
|
if order_field not in self._columns and order_field in self._inherit_fields:
|
||||||
# also add missing joins for reaching the table containing the m2o field
|
# also add missing joins for reaching the table containing the m2o field
|
||||||
qualified_field = self._inherits_join_calc(alias, order_field, query)
|
|
||||||
order_field_column = self._inherit_fields[order_field][2]
|
order_field_column = self._inherit_fields[order_field][2]
|
||||||
|
qualified_field = self._inherits_join_calc(alias, order_field, query)
|
||||||
|
alias, order_field = qualified_field.replace('"', '').split('.', 1)
|
||||||
else:
|
else:
|
||||||
qualified_field = '"%s"."%s"' % (alias, order_field)
|
|
||||||
order_field_column = self._columns[order_field]
|
order_field_column = self._columns[order_field]
|
||||||
|
|
||||||
assert order_field_column._type == 'many2one', 'Invalid field passed to _generate_m2o_order_by()'
|
assert order_field_column._type == 'many2one', 'Invalid field passed to _generate_m2o_order_by()'
|
||||||
if not order_field_column._classic_write and not getattr(order_field_column, 'store', False):
|
if not order_field_column._classic_write and not getattr(order_field_column, 'store', False):
|
||||||
_logger.debug("Many2one function/related fields must be stored " \
|
_logger.debug("Many2one function/related fields must be stored "
|
||||||
"to be used as ordering fields! Ignoring sorting for %s.%s",
|
"to be used as ordering fields! Ignoring sorting for %s.%s",
|
||||||
self._name, order_field)
|
self._name, order_field)
|
||||||
return
|
return []
|
||||||
|
|
||||||
# figure out the applicable order_by for the m2o
|
# figure out the applicable order_by for the m2o
|
||||||
dest_model = self.pool[order_field_column._obj]
|
dest_model = self.pool[order_field_column._obj]
|
||||||
@@ -4568,12 +4568,14 @@ class BaseModel(object):
|
|||||||
|
|
||||||
# Join the dest m2o table if it's not joined yet. We use [LEFT] OUTER join here
|
# Join the dest m2o table if it's not joined yet. We use [LEFT] OUTER join here
|
||||||
# as we don't want to exclude results that have NULL values for the m2o
|
# as we don't want to exclude results that have NULL values for the m2o
|
||||||
src_table, src_field = qualified_field.replace('"', '').split('.', 1)
|
join = (alias, dest_model._table, order_field, 'id', order_field)
|
||||||
dst_alias, dst_alias_statement = query.add_join((src_table, dest_model._table, src_field, 'id', src_field), implicit=False, outer=True)
|
dst_alias, dst_alias_statement = query.add_join(join, implicit=False, outer=True)
|
||||||
return dest_model._generate_order_by_inner(dst_alias, m2o_order, query,
|
return dest_model._generate_order_by_inner(dst_alias, m2o_order, query,
|
||||||
reverse_direction=reverse_direction)
|
reverse_direction=reverse_direction, seen=seen)
|
||||||
|
|
||||||
def _generate_order_by_inner(self, alias, order_spec, query, reverse_direction=False):
|
def _generate_order_by_inner(self, alias, order_spec, query, reverse_direction=False, seen=None):
|
||||||
|
if seen is None:
|
||||||
|
seen = set()
|
||||||
order_by_elements = []
|
order_by_elements = []
|
||||||
self._check_qorder(order_spec)
|
self._check_qorder(order_spec)
|
||||||
for order_part in order_spec.split(','):
|
for order_part in order_spec.split(','):
|
||||||
@@ -4594,7 +4596,10 @@ class BaseModel(object):
|
|||||||
inner_clauses = ['"%s"."%s"' % (alias, order_field)]
|
inner_clauses = ['"%s"."%s"' % (alias, order_field)]
|
||||||
add_dir = True
|
add_dir = True
|
||||||
elif order_column._type == 'many2one':
|
elif order_column._type == 'many2one':
|
||||||
inner_clauses = self._generate_m2o_order_by(alias, order_field, query, do_reverse)
|
key = (self._name, order_column._obj, order_field)
|
||||||
|
if key not in seen:
|
||||||
|
seen.add(key)
|
||||||
|
inner_clauses = self._generate_m2o_order_by(alias, order_field, query, do_reverse, seen)
|
||||||
else:
|
else:
|
||||||
continue # ignore non-readable or "non-joinable" fields
|
continue # ignore non-readable or "non-joinable" fields
|
||||||
elif order_field in self._inherit_fields:
|
elif order_field in self._inherit_fields:
|
||||||
@@ -4604,7 +4609,10 @@ class BaseModel(object):
|
|||||||
inner_clauses = [self._inherits_join_calc(alias, order_field, query)]
|
inner_clauses = [self._inherits_join_calc(alias, order_field, query)]
|
||||||
add_dir = True
|
add_dir = True
|
||||||
elif order_column._type == 'many2one':
|
elif order_column._type == 'many2one':
|
||||||
inner_clauses = self._generate_m2o_order_by(alias, order_field, query, do_reverse)
|
key = (parent_obj._name, order_column._obj, order_field)
|
||||||
|
if key not in seen:
|
||||||
|
seen.add(key)
|
||||||
|
inner_clauses = self._generate_m2o_order_by(alias, order_field, query, do_reverse, seen)
|
||||||
else:
|
else:
|
||||||
continue # ignore non-readable or "non-joinable" fields
|
continue # ignore non-readable or "non-joinable" fields
|
||||||
else:
|
else:
|
||||||
|
|||||||
Reference in New Issue
Block a user