[MERGE] forward port of branch saas-6 up to be58335

This commit is contained in:
Christophe Simonis
2015-08-06 16:09:19 +02:00
57 changed files with 337 additions and 192 deletions
+1 -1
View File
@@ -1056,7 +1056,7 @@
<tree string="Journal Items" create="false">
<field name="date"/>
<field name="move_id" required="0"/>
<field name="journal_id" options='{"no_open":True}' invisible="context.get('journal_id',False)"/>
<field name="journal_id" options='{"no_open":True}'/>
<field name="name"/>
<field name="ref"/>
<field name="statement_id" invisible="1"/>
+2
View File
@@ -1,2 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import models
@@ -34,6 +34,17 @@
</field>
</record>
<record id="bank_statement_draft_form_inherit" model="ir.ui.view">
<field name="name">bank.statement.draft.form.inherit</field>
<field name="model">account.bank.statement</field>
<field name="inherit_id" ref="account.view_bank_statement_form"/>
<field name="arch" type="xml">
<xpath expr="//button[@name='button_cancel']" position="after">
<button name="button_draft" states="confirm" string="Reset to New" type="object"/>
</xpath>
</field>
</record>
<record id="bank_statement_cancel_form_inherit" model="ir.ui.view">
<field name="name">bank.statement.cancel.form.inherit</field>
<field name="model">account.bank.statement</field>
+4
View File
@@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import account_bank_statement
@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from openerp import models, api, _
from openerp.exceptions import Warning
class BankStatement(models.Model):
_inherit = 'account.bank.statement'
@api.multi
def button_draft(self):
self.state = 'draft'
class BankStatementLine(models.Model):
_inherit = 'account.bank.statement.line'
@api.multi
def cancel(self):
for line in self:
if line.statement_id.state == 'confirm':
raise Warning(_("Please set the bank statement to New before canceling."))
return super(BankStatementLine, self).cancel()
+1 -1
View File
@@ -170,7 +170,7 @@ class account_analytic_account(osv.osv):
"The type 'Analytic account' stands for usual accounts that you only want to use in accounting.\n"\
"If you select Contract or Project, it offers you the possibility to manage the validity and the invoicing options for this account.\n"\
"The special type 'Template of Contract' allows you to define a template with default data that you can reuse easily."),
'template_id': fields.many2one('account.analytic.account', 'Template of Contract'),
'template_id': fields.many2one('account.analytic.account', 'Template of Contract', ondelete='restrict'),
'description': fields.text('Description'),
'parent_id': fields.many2one('account.analytic.account', 'Parent Analytic Account', select=2),
'child_ids': fields.one2many('account.analytic.account', 'parent_id', 'Child Accounts', copy=True),
+2 -1
View File
@@ -5,7 +5,8 @@ from passlib.context import CryptContext
import openerp
from openerp.osv import fields, osv
openerp.addons.base.res.res_users.USER_PRIVATE_FIELDS.append('password_crypt')
from openerp.addons.base.res import res_users
res_users.USER_PRIVATE_FIELDS.append('password_crypt')
_logger = logging.getLogger(__name__)
+1 -1
View File
@@ -18,7 +18,7 @@ class SignupError(Exception):
def random_token():
# the token has an entropy of about 120 bits (6 bits/char * 20 chars)
chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
return ''.join(random.choice(chars) for i in xrange(20))
return ''.join(random.SystemRandom().choice(chars) for i in xrange(20))
def now(**kwargs):
dt = datetime.now() + timedelta(**kwargs)
+2 -2
View File
@@ -575,7 +575,7 @@ class calendar_alarm(osv.Model):
'type': fields.selection([('notification', 'Notification'), ('email', 'Email')], 'Type', required=True),
'duration': fields.integer('Amount', required=True),
'interval': fields.selection(list(_interval_selection.iteritems()), 'Unit', required=True),
'duration_minutes': fields.function(_get_duration, type='integer', string='Duration', store=True, help="Duration in minutes"),
'duration_minutes': fields.function(_get_duration, type='integer', string='Duration in minutes', store=True, help="Duration in minutes"),
}
_defaults = {
@@ -958,7 +958,7 @@ class calendar_event(osv.Model):
'user_id': fields.many2one('res.users', 'Responsible', states={'done': [('readonly', True)]}),
'color_partner_id': fields.related('user_id', 'partner_id', 'id', type="integer", string="Color index of creator", store=False), # Color of creator
'active': fields.boolean('Active', help="If the active field is set to true, it will allow you to hide the event alarm information without removing it."),
'active': fields.boolean('Active', help="If the active field is set to false, it will allow you to hide the event alarm information without removing it."),
'categ_ids': fields.many2many('calendar.event.type', 'meeting_category_rel', 'event_id', 'type_id', 'Tags'),
'attendee_ids': fields.one2many('calendar.attendee', 'event_id', 'Attendees', ondelete='cascade'),
'partner_ids': fields.many2many('res.partner', 'calendar_event_res_partner_rel', string='Attendees', states={'done': [('readonly', True)]}),
+1 -1
View File
@@ -1441,7 +1441,7 @@ msgstr ""
#. module: calendar
#: field:calendar.alarm,duration_minutes:0
msgid "duration_minutes"
msgid "Duration in minutes"
msgstr ""
#. module: calendar
@@ -187,7 +187,8 @@ class crm_lead(osv.osv):
# warning: point() type takes (longitude, latitude) as parameters in this order!
cr.execute("""SELECT id, distance
FROM (select id, (point(partner_longitude, partner_latitude) <-> point(%s,%s)) AS distance FROM res_partner
WHERE partner_longitude is not null
WHERE active
AND partner_longitude is not null
AND partner_latitude is not null
AND partner_weight > 0) AS d
ORDER BY distance LIMIT 1""", (longitude, latitude))
+8 -1
View File
@@ -31,7 +31,14 @@ class SaleOrder(models.Model):
@api.depends('carrier_id', 'partner_id', 'order_line')
def _compute_delivery_price(self):
for order in self:
order.delivery_price = order.carrier_id.with_context(order_id=order.id).price
if order.state != 'draft':
# we do not want to recompute the shipping price of an already validated/done SO
continue
elif order.carrier_id.delivery_type != 'grid' and not order.order_line:
# prevent SOAP call to external shipping provider when SO has no lines yet
continue
else:
order.delivery_price = order.carrier_id.with_context(order_id=order.id).price
@api.multi
def delivery_set(self):
+4 -1
View File
@@ -64,7 +64,7 @@ class stock_picking(osv.osv):
"""
carrier_obj = self.pool.get('delivery.carrier')
grid_obj = self.pool.get('delivery.grid')
fpos_obj = self.pool['account.fiscal.position']
currency_obj = self.pool.get('res.currency')
if not picking.carrier_id or \
any(inv_line.product_id.id == picking.carrier_id.product_id.id
for inv_line in invoice.invoice_line_ids):
@@ -77,6 +77,9 @@ class stock_picking(osv.osv):
price = grid_obj.get_price_from_picking(cr, uid, grid_id,
invoice.amount_untaxed, picking.weight, picking.volume,
quantity, context=context)
if invoice.company_id.currency_id.id != invoice.currency_id.id:
price = currency_obj.compute(cr, uid, invoice.company_id.currency_id.id, invoice.currency_id.id,
price, context=dict(context or {}, date=invoice.date_invoice))
account_id = picking.carrier_id.product_id.property_account_income_id.id
if not account_id:
account_id = picking.carrier_id.product_id.categ_id\
+3
View File
@@ -24,6 +24,7 @@ from openerp.exceptions import UserError
_logger = logging.getLogger(__name__)
MAX_POP_MESSAGES = 50
MAIL_TIMEOUT = 60
# Workaround for Python 2.7.8 bug https://bugs.python.org/issue23906
poplib._MAXLINE = 65536
@@ -137,6 +138,8 @@ openerp_mailgate: "|/path/to/openerp-mailgate.py --host=localhost -u %(uid)d -p
#connection.user("recent:"+server.user)
connection.user(server.user)
connection.pass_(server.password)
# Add timeout on socket
connection.sock.settimeout(MAIL_TIMEOUT)
return connection
def button_confirm_login(self, cr, uid, ids, context=None):
+3 -3
View File
@@ -163,13 +163,13 @@ class google_service(osv.osv_memory):
except:
pass
except urllib2.HTTPError, e:
if e.code in (400, 401, 410):
raise e
elif e.code in (204, 404):
if e.code in (204, 404):
status = e.code
response = ""
else:
_logger.exception("Bad google request : %s !" % e.read())
if e.code in (400, 401, 410):
raise e
raise self.pool.get('res.config.settings').get_config_warning(cr, _("Something went wrong with your request to google"), context=context)
return (status, response, ask_time)
+3 -1
View File
@@ -212,8 +212,10 @@ class google_calendar(osv.AbstractModel):
vstype = 'date'
attendee_list = []
for attendee in event.attendee_ids:
email = tools.email_split(attendee.email)
email = email[0] if email else 'NoEmail@mail.com'
attendee_list.append({
'email': attendee.email or 'NoEmail@mail.com',
'email': email,
'displayName': attendee.partner_id.name,
'responseStatus': attendee.state or 'needsAction',
})
@@ -177,16 +177,16 @@ class account_analytic_line(osv.osv):
if factor.customer_name:
factor_name += ' - ' + factor.customer_name
general_account = product.property_account_income_id or product.categ_id.property_account_income_categ_id
if not general_account:
raise UserError(_("Configuration Error!") + '\n' + _("Please define income account for product '%s'.") % product.name)
taxes = product.taxes_id or general_account.tax_ids
tax = self.pool['account.fiscal.position'].map_tax(cr, uid, account.partner_id.property_account_position_id, taxes)
curr_invoice_line.update({
'invoice_line_tax_ids': [(6, 0, tax)],
'name': factor_name,
'account_id': general_account.id,
})
general_account = product.property_account_income_id or product.categ_id.property_account_income_categ_id
if not general_account:
raise UserError(_("Configuration Error!") + '\n' + _("Please define income account for product '%s'.") % product.name)
taxes = product.taxes_id or general_account.tax_ids
tax = self.pool['account.fiscal.position'].map_tax(cr, uid, account.partner_id.property_account_position_id, taxes)
curr_invoice_line.update({
'invoice_line_tax_ids': [(6, 0, tax)],
'name': factor_name,
'account_id': general_account.id,
})
note = []
for line in analytic_line_ids:
@@ -36,7 +36,7 @@
<field name="name">Live Support Managers can see all session from live support</field>
<field name="model_id" ref="im_chat.model_im_chat_session"/>
<field name="groups" eval="[(6,0,[ref('im_livechat.im_livechat_group_manager')])]"/>
<field name="domain_force">[('to_id.channel_id', '!=', None)]</field>
<field name="domain_force">[('channel_id', '!=', None)]</field>
<field name="perm_unlink" eval="1"/>
<field name="perm_write" eval="0"/>
<field name="perm_read" eval="1"/>
+15 -15
View File
@@ -91,7 +91,7 @@
<record id="attn_VAT-OUT-21-S" model="account.tax.template">
<field name="sequence">10</field>
<field name="description">VAT-OUT-21-S</field>
<field name="name">VAT 21% - Services</field>
<field name="name">TVA 21% - Services</field>
<field name="refund_account_id" ref="a451054"/>
<field name="account_id" ref="a451054"/>
<field name="price_include" eval="0"/>
@@ -104,7 +104,7 @@
<record id="attn_VAT-OUT-21-L" model="account.tax.template">
<field name="sequence">11</field>
<field name="description">VAT-OUT-21-L</field>
<field name="name">VAT 21%</field>
<field name="name">TVA 21%</field>
<field name="refund_account_id" ref="a451054"/>
<field name="account_id" ref="a451054"/>
<field name="price_include" eval="0"/>
@@ -117,7 +117,7 @@
<record id="attn_VAT-OUT-12-S" model="account.tax.template">
<field name="sequence">20</field>
<field name="description">VAT-OUT-12-S</field>
<field name="name">VAT 12% - Services</field>
<field name="name">TVA 12% - Services</field>
<field name="refund_account_id" ref="a451054"/>
<field name="account_id" ref="a451054"/>
<field name="price_include" eval="0"/>
@@ -130,7 +130,7 @@
<record id="attn_VAT-OUT-12-L" model="account.tax.template">
<field name="sequence">21</field>
<field name="description">VAT-OUT-12-L</field>
<field name="name">VAT 12%</field>
<field name="name">TVA 12%</field>
<field name="refund_account_id" ref="a451054"/>
<field name="account_id" ref="a451054"/>
<field name="price_include" eval="0"/>
@@ -143,7 +143,7 @@
<record id="attn_VAT-OUT-06-S" model="account.tax.template">
<field name="sequence">30</field>
<field name="description">VAT-OUT-06-S</field>
<field name="name">VAT 6% - Services</field>
<field name="name">TVA 6% - Services</field>
<field name="refund_account_id" ref="a451054"/>
<field name="account_id" ref="a451054"/>
<field name="price_include" eval="0"/>
@@ -156,7 +156,7 @@
<record id="attn_VAT-OUT-06-L" model="account.tax.template">
<field name="sequence">31</field>
<field name="description">VAT-OUT-06-L</field>
<field name="name">VAT 6%</field>
<field name="name">TVA 6%</field>
<field name="refund_account_id" ref="a451054"/>
<field name="account_id" ref="a451054"/>
<field name="price_include" eval="0"/>
@@ -169,7 +169,7 @@
<record id="attn_VAT-OUT-00-S" model="account.tax.template">
<field name="sequence">40</field>
<field name="description">VAT-OUT-00-S</field>
<field name="name">VAT 0% - Services</field>
<field name="name">TVA 0% - Services</field>
<field name="price_include" eval="0"/>
<field name="amount">0</field>
<field name="amount_type">percent</field>
@@ -180,7 +180,7 @@
<record id="attn_VAT-OUT-00-L" model="account.tax.template">
<field name="sequence">41</field>
<field name="description">VAT-OUT-00-L</field>
<field name="name">VAT 0%</field>
<field name="name">TVA 0%</field>
<field name="price_include" eval="0"/>
<field name="amount">0</field>
<field name="amount_type">percent</field>
@@ -191,7 +191,7 @@
<record id="attn_VAT-OUT-00-CC" model="account.tax.template">
<field name="sequence">50</field>
<field name="description">VAT-OUT-00-CC</field>
<field name="name">VAT 0% Cocontractant</field>
<field name="name">TVA 0% Cocontractant</field>
<field name="price_include" eval="0"/>
<field name="amount">0</field>
<field name="amount_type">percent</field>
@@ -202,7 +202,7 @@
<record id="attn_VAT-OUT-00-EU-S" model="account.tax.template">
<field name="sequence">60</field>
<field name="description">VAT-OUT-00-EU-S</field>
<field name="name">Services EU</field>
<field name="name">TVA services EU</field>
<field name="price_include" eval="0"/>
<field name="amount">0</field>
<field name="amount_type">percent</field>
@@ -213,7 +213,7 @@
<record id="attn_VAT-OUT-00-EU-L" model="account.tax.template">
<field name="sequence">61</field>
<field name="description">VAT-OUT-00-EU-L</field>
<field name="name">Marchandises EU (Code L)</field>
<field name="name">TVA Marchandises EU (Code L)</field>
<field name="price_include" eval="0"/>
<field name="amount">0</field>
<field name="amount_type">percent</field>
@@ -224,7 +224,7 @@
<record id="attn_VAT-OUT-00-EU-T" model="account.tax.template">
<field name="sequence">62</field>
<field name="description">VAT-OUT-00-EU-T</field>
<field name="name">Marchandises EU (Code T)</field>
<field name="name">TVA marchandises EU (Code T)</field>
<field name="price_include" eval="0"/>
<field name="amount">0</field>
<field name="amount_type">percent</field>
@@ -235,7 +235,7 @@
<record id="attn_VAT-OUT-00-ROW" model="account.tax.template">
<field name="sequence">70</field>
<field name="description">VAT-OUT-00-ROW</field>
<field name="name">Export hors EU</field>
<field name="name">TVA export hors EU</field>
<field name="price_include" eval="0"/>
<field name="amount">0</field>
<field name="amount_type">percent</field>
@@ -818,7 +818,7 @@
<record id="attn_VAT-IN-V82-CAR-EXC-C1" model="account.tax.template">
<field name="sequence">721</field>
<field name="description">VAT-IN-V82-CAR-EXC-C1</field>
<field name="name">Frais de voiture - VAT 50% Non Deductible</field>
<field name="name">Frais de voiture - TVA 50% Non Deductible</field>
<field name="refund_account_id" ref="a64012"/>
<field name="account_id" ref="a64012"/>
<field name="price_include" eval="0"/>
@@ -831,7 +831,7 @@
<record id="attn_VAT-IN-V82-CAR-EXC-C2" model="account.tax.template">
<field name="sequence">722</field>
<field name="description">VAT-IN-V82-CAR-EXC-C2</field>
<field name="name">Frais de voiture - VAT 50% Deductible (Price Excl.)</field>
<field name="name">Frais de voiture - TVA 50% Deductible (Prix Excl.)</field>
<field name="refund_account_id" ref="a411059"/>
<field name="account_id" ref="a411059"/>
<field name="price_include" eval="0"/>
@@ -14,6 +14,7 @@
<field name="partner_id" ref="base.res_partner_9"/>
<field name="reference_type">bba</field>
<field name="reference">+++240/2838/42818+++</field>
<field name="date_invoice">2011-01-20</field>
</record>
<record id="invoice_1_line_1" model="account.invoice.line">
<field name="name">Dell Inspiron Laptop without OS</field>
-8
View File
@@ -76,23 +76,15 @@ class mrp_production(osv.osv):
for sub_product in production.bom_id.sub_products:
product_uom_factor = product_uom_obj._compute_qty(cr, uid, production.product_uom.id, production.product_qty, production.bom_id.product_uom.id)
qty1 = sub_product.product_qty
qty2 = production.product_uos and production.product_uos_qty or False
product_uos_factor = 0.0
if qty2 and production.bom_id.product_uos.id:
product_uos_factor = product_uom_obj._compute_qty(cr, uid, production.product_uos.id, production.product_uos_qty, production.bom_id.product_uos.id)
if sub_product.subproduct_type == 'variable':
if production.product_qty:
qty1 *= product_uom_factor / (production.bom_id.product_qty or 1.0)
if production.product_uos_qty:
qty2 *= product_uos_factor / (production.bom_id.product_uos_qty or 1.0)
data = {
'name': 'PROD:'+production.name,
'date': production.date_planned,
'product_id': sub_product.product_id.id,
'product_uom_qty': qty1,
'product_uom': sub_product.product_uom.id,
'product_uos_qty': qty2,
'product_uos': production.product_uos and production.product_uos.id or False,
'location_id': source,
'location_dest_id': production.location_dest_id.id,
'move_dest_id': production.move_prod_id.id,
+1 -1
View File
@@ -36,7 +36,7 @@ class pad_common(osv.osv_memory):
pad["server"] = pad["server"].rstrip('/')
# generate a salt
s = string.ascii_uppercase + string.digits
salt = ''.join([s[random.randint(0, len(s) - 1)] for i in range(10)])
salt = ''.join([s[random.SystemRandom().randint(0, len(s) - 1)] for i in range(10)])
#path
# etherpad hardcodes pad id length limit to 50
path = '-%s-%s' % (self._name, salt)
+1 -1
View File
@@ -389,7 +389,7 @@ class PaymentTransaction(osv.Model):
('done', 'Done'), ('error', 'Error'),
('cancel', 'Canceled')
], 'Status', required=True,
track_visiblity='onchange', copy=False),
track_visibility='onchange', copy=False),
'state_message': fields.text('Message',
help='Field used to store error and/or validation messages for information'),
# payment
+1 -1
View File
@@ -44,7 +44,7 @@ class OgoneController(http.Controller):
acquirer.s2s_process(post)
return werkzeug.utils.redirect(post.get('return_url', '/'))
@http.route(['/payment/ogone/s2s/feedback'])
@http.route(['/payment/ogone/s2s/feedback'], auth='none')
def feedback(self, **kwargs):
cr, uid, context = request.cr, SUPERUSER_ID, request.context
payment = request.registry.get('payment.transaction')
+3 -2
View File
@@ -373,11 +373,12 @@ class PaymentTxOgone(osv.Model):
def _ogone_s2s_validate(self, tx):
tree = self._ogone_s2s_get_tx_status(tx)
return self.ogone_s2s_validate(tx, tree)
return self._ogone_s2s_validate_tree(tx, tree)
def _ogone_s2s_validate_tree(self, tx, tree, tries=2):
if tx.state not in ('draft', 'pending'):
return True # already validated
_logger.info('Ogone: trying to validate an already validated tx (ref %s)', tx.reference)
return True
status = int(tree.get('STATUS', '0'))
if status in self._ogone_valid_tx_status:
@@ -3865,6 +3865,13 @@ msgstr ""
msgid "Unknown Barcode"
msgstr ""
#. module: point_of_sale
#. openerp-web
#: code:addons/point_of_sale/static/src/xml/pos.xml:914
#, python-format
msgid "Unknown Customer"
msgstr ""
#. module: point_of_sale
#. openerp-web
#: code:addons/point_of_sale/static/src/xml/pos.xml:845
@@ -1232,7 +1232,6 @@
</span>
</t>
</t>
</span>
<span class="order-button square neworder-button">
<i class='fa fa-plus' />
-5
View File
@@ -3264,11 +3264,6 @@ msgstr ""
msgid "lb(s)"
msgstr ""
#. module: product
#: view:product.product:product.product_normal_form_view
msgid "lst_price"
msgstr ""
#. module: product
#: model:product.uom,name:product.product_uom_mile
msgid "mile(s)"
+34 -1
View File
@@ -9,6 +9,39 @@ from openerp.osv import fields, osv
class product_product(osv.osv):
_inherit = "product.product"
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None, orderby=False, lazy=True):
"""
Inherit read_group to calculate the sum of the non-stored fields, as it is not automatically done anymore through the XML.
"""
res = super(product_product, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby, lazy=lazy)
if context is None:
context = {}
fields_list = ['turnover', 'sale_avg_price', 'sale_purchase_price', 'sale_num_invoiced', 'purchase_num_invoiced',
'sales_gap', 'purchase_gap', 'total_cost', 'sale_expected', 'normal_cost', 'total_margin',
'expected_margin', 'total_margin_rate', 'expected_margin_rate']
if any(x in fields for x in fields_list):
# Calculate first for every product in which line it needs to be applied
re_ind = 0
prod_re = {}
tot_products = []
for re in res:
if re.get('__domain'):
products = self.search(cr, uid, re['__domain'], context=context)
tot_products += products
for prod in products:
prod_re[prod] = re_ind
re_ind += 1
res_val = self._product_margin(cr, uid, tot_products, [x for x in fields if fields in fields_list], '', context=context)
for key in res_val.keys():
for l in res_val[key].keys():
re = res[prod_re[key]]
if re.get(l):
re[l] += res_val[key][l]
else:
re[l] = res_val[key][l]
return res
def _product_margin(self, cr, uid, ids, field_names, arg, context=None):
res = {}
if context is None:
@@ -47,7 +80,7 @@ class product_product(osv.osv):
from account_invoice_line l
left join account_invoice i on (l.invoice_id = i.id)
left join product_product product on (product.id=l.product_id)
left join product_template pt on (pt.id = l.product_id)
left join product_template pt on (pt.id = product.product_tmpl_id)
left join product_uom pu on (pt.uom_id = pu.id)
left join product_uom pu2 on (l.uos_id = pu2.id)
where l.product_id = %s and i.state in %s and i.type IN %s and (i.date_invoice IS NULL or (i.date_invoice>=%s and i.date_invoice<=%s and i.company_id=%s))
@@ -7,7 +7,7 @@
<field name="priority" eval="50"/>
<field name="arch" type="xml">
<graph string="Product Margins" type="bar">
<field name="name"/>
<field name="product_tmpl_id"/>
<field name="turnover" operator="+"/>
<field name="total_cost" operator="+"/>
</graph>
+1 -1
View File
@@ -88,7 +88,7 @@
<field name="model">res.partner</field>
<field name="inherit_id" ref="base.view_partner_form" />
<field name="priority" eval="20"/>
<field name="groups_id" eval="[(4, ref('account.group_account_user'))]"/>
<field name="groups_id" eval="[(4, ref('account.group_account_invoice'))]"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<button class="oe_stat_button" name="%(purchase.act_res_partner_2_supplier_invoices)d" type="action"
+30 -16
View File
@@ -998,6 +998,30 @@ class purchase_order(osv.osv):
return orders_info
def _set_po_lines_invoiced(self, cr, uid, ids, context=None):
for po in self.browse(cr, uid, ids, context=context):
is_invoiced = []
if po.invoice_method == 'picking':
# We determine the invoiced state of the PO line based on the invoiced state
# of the associated moves. This should cover all possible cases:
# - all moves are done and invoiced
# - a PO line is split into multiple moves (e.g. if multiple pickings): some
# pickings are done, some are in progress, some are cancelled
for po_line in po.order_line:
if (po_line.move_ids and
all(move.state in ('done', 'cancel') for move in po_line.move_ids) and
not all(move.state == 'cancel' for move in po_line.move_ids) and
all(move.invoice_state == 'invoiced' for move in po_line.move_ids if move.state == 'done')):
is_invoiced.append(po_line.id)
else:
for po_line in po.order_line:
if (po_line.invoice_lines and
all(line.invoice_id.state not in ['draft', 'cancel'] for line in po_line.invoice_lines)):
is_invoiced.append(po_line.id)
if is_invoiced:
self.pool['purchase.order.line'].write(cr, uid, is_invoiced, {'invoiced': True})
workflow.trg_write(uid, 'purchase.order', po.id, cr)
class purchase_order_line(osv.osv):
def _amount_line(self, cr, uid, ids, prop, arg, context=None):
@@ -1118,6 +1142,9 @@ class purchase_order_line(osv.osv):
res = {'value': {'price_unit': price_unit or 0.0, 'name': name or '', 'product_uom' : uom_id or False}}
if not product_id:
if not uom_id:
uom_id = self.default_get(cr, uid, ['product_uom'], context=context).get('product_uom', False)
res['value']['product_uom'] = uom_id
return res
product_product = self.pool.get('product.product')
@@ -1740,22 +1767,9 @@ class account_invoice(osv.Model):
else:
user_id = uid
po_ids = purchase_order_obj.search(cr, user_id, [('invoice_ids', 'in', ids)], context=context)
for order in purchase_order_obj.browse(cr, user_id, po_ids, context=context):
purchase_order_obj.message_post(cr, user_id, order.id, body=_("Invoice received"), context=context)
invoiced = []
shipped = True
# for invoice method manual or order, don't care about shipping state
# for invoices based on incoming shippment, beware of partial deliveries
if (order.invoice_method == 'picking' and
not all(picking.invoice_state in ['invoiced'] for picking in order.picking_ids)):
shipped = False
for po_line in order.order_line:
if (po_line.invoice_lines and
all(line.invoice_id.state not in ['draft', 'cancel'] for line in po_line.invoice_lines)):
invoiced.append(po_line.id)
if invoiced and shipped:
self.pool['purchase.order.line'].write(cr, user_id, invoiced, {'invoiced': True})
workflow.trg_write(user_id, 'purchase.order', order.id, cr)
for po_id in po_ids:
purchase_order_obj.message_post(cr, user_id, po_id, body=_("Invoice received"), context=context)
purchase_order_obj._set_po_lines_invoiced(cr, user_id, [po_id], context=context)
return res
def confirm_paid(self, cr, uid, ids, context=None):
+9 -1
View File
@@ -27,15 +27,23 @@ class stock_move(osv.osv):
res = super(stock_move, self).write(cr, uid, ids, vals, context=context)
from openerp import workflow
if vals.get('state') in ['done', 'cancel']:
po_to_check = []
for move in self.browse(cr, uid, ids, context=context):
if move.purchase_line_id and move.purchase_line_id.order_id:
order_id = move.purchase_line_id.order_id.id
order = move.purchase_line_id.order_id
order_id = order.id
# update linked purchase order as superuser as the warehouse
# user may not have rights to access purchase.order
if self.pool.get('purchase.order').test_moves_done(cr, uid, [order_id], context=context):
workflow.trg_validate(SUPERUSER_ID, 'purchase.order', order_id, 'picking_done', cr)
if self.pool.get('purchase.order').test_moves_except(cr, uid, [order_id], context=context):
workflow.trg_validate(SUPERUSER_ID, 'purchase.order', order_id, 'picking_cancel', cr)
if order_id not in po_to_check and vals['state'] == 'cancel' and order.invoice_method == 'picking':
po_to_check.append(order_id)
# Some moves which are cancelled might be part of a PO line which is partially
# invoiced, so we check if some PO line can be set on "invoiced = True".
if po_to_check:
self.pool.get('purchase.order')._set_po_lines_invoiced(cr, uid, po_to_check, context=context)
return res
def copy(self, cr, uid, id, default=None, context=None):
+36 -41
View File
@@ -12,6 +12,41 @@ class purchase_line_invoice(osv.osv_memory):
_name = 'purchase.order.line_invoice'
_description = 'Purchase Order Line Make Invoice'
def _make_invoice_by_partner(self, cr, uid, partner, orders, lines_ids, context=None):
"""
create a new invoice for one vendor
@param cr : Cursor
@param uid : Id of current user
@param partner : The object partner
@param orders : The set of orders to add in the invoice
@param lines : The list of line's id
"""
purchase_obj = self.pool.get('purchase.order')
account_jrnl_obj = self.pool.get('account.journal')
invoice_obj = self.pool.get('account.invoice')
name = orders and orders[0].name or ''
journal_id = account_jrnl_obj\
.search(cr, uid, [('type', '=', 'purchase')], context=None)
journal_id = journal_id and journal_id[0] or False
a = partner.property_account_payable_id.id
inv = {
'name': name,
'origin': name,
'type': 'in_invoice',
'journal_id': journal_id,
'reference': partner.ref,
'account_id': a,
'partner_id': partner.id,
'invoice_line_ids': [(6, 0, lines_ids)],
'currency_id': orders[0].currency_id.id,
'comment': " \n".join([order.notes for order in orders if order.notes]),
'payment_term_id': orders[0].payment_term_id.id,
'fiscal_position_id': partner.property_account_position_id.id
}
inv_id = invoice_obj.create(cr, uid, inv, context=context)
purchase_obj.write(cr, uid, [order.id for order in orders], {'invoice_ids': [(4, inv_id)]}, context=context)
return inv_id
def makeInvoices(self, cr, uid, ids, context=None):
"""
@@ -30,49 +65,9 @@ class purchase_line_invoice(osv.osv_memory):
if record_ids:
res = False
invoices = {}
invoice_obj = self.pool.get('account.invoice')
purchase_obj = self.pool.get('purchase.order')
purchase_line_obj = self.pool.get('purchase.order.line')
invoice_line_obj = self.pool.get('account.invoice.line')
account_jrnl_obj = self.pool.get('account.journal')
def multiple_order_invoice_notes(orders):
notes = ""
for order in orders:
notes += "%s \n" % order.notes
return notes
def make_invoice_by_partner(partner, orders, lines_ids):
"""
create a new invoice for one vendor
@param partner : The object partner
@param orders : The set of orders to add in the invoice
@param lines : The list of line's id
"""
name = orders and orders[0].name or ''
journal_id = account_jrnl_obj.search(cr, uid, [('type', '=', 'purchase')], context=None)
journal_id = journal_id and journal_id[0] or False
a = partner.property_account_payable_id.id
inv = {
'name': name,
'origin': name,
'type': 'in_invoice',
'journal_id':journal_id,
'reference' : partner.ref,
'account_id': a,
'partner_id': partner.id,
'invoice_line_ids': [(6, 0, lines_ids)],
'currency_id' : orders[0].currency_id.id,
'comment': multiple_order_invoice_notes(orders),
'payment_term_id': orders[0].payment_term_id.id,
'fiscal_position_id': partner.property_account_position_id.id
}
inv_id = invoice_obj.create(cr, uid, inv)
for order in orders:
order.write({'invoice_ids': [(4, inv_id)]})
return inv_id
for line in purchase_line_obj.browse(cr, uid, record_ids, context=context):
if (not line.invoiced) and (line.state not in ('draft', 'cancel')):
@@ -90,7 +85,7 @@ class purchase_line_invoice(osv.osv_memory):
il = map(lambda x: x[1], result)
orders = list(set(map(lambda x : x[0].order_id, result)))
res.append(make_invoice_by_partner(orders[0].partner_id, orders, il))
res.append(self._make_invoice_by_partner(cr, uid, orders[0].partner_id, orders, il, context=context))
return {
'domain': "[('id','in', ["+','.join(map(str,res))+"])]",
+2
View File
@@ -71,6 +71,8 @@ Example: 10% for retailers, promotion of 5 EUR on this product, etc."""),
return {}
def onchange_task_work(self, cr, uid, ids, task_work, context=None):
if not task_work:
return {'value': {}}
return {'value': {
'module_project_timesheet': task_work,
'module_sale_service': task_work,
+9 -1
View File
@@ -3,6 +3,7 @@
from datetime import datetime, timedelta
import time
from openerp import SUPERUSER_ID
from openerp.addons.analytic.models import analytic
from openerp.osv import fields, osv
from openerp.tools.translate import _
@@ -1057,7 +1058,14 @@ class sale_order_line(osv.osv):
else:
fpos = self.pool['account.fiscal.position'].browse(cr, uid, fiscal_position_id)
if update_tax: # The quantity only have changed
result['tax_id'] = self.pool['account.fiscal.position'].map_tax(cr, uid, fpos, product_obj.taxes_id)
# The superuser is used by website_sale in order to create a sale order. We need to make
# sure we only select the taxes related to the company of the partner. This should only
# apply if the partner is linked to a company.
if uid == SUPERUSER_ID and partner.company_id:
taxes = product_obj.taxes_id.filtered(lambda r: r.company_id == partner.company_id)
else:
taxes = product_obj.taxes_id
result['tax_id'] = self.pool['account.fiscal.position'].map_tax(cr, uid, fpos, taxes)
if not flag:
result['name'] = Product.name_get(cr, uid, [product_obj.id], context=ctx_product)[0][1]
+2
View File
@@ -401,6 +401,8 @@ class stock_move(osv.osv):
fp = move.picking_id.sale_id.fiscal_position
res = self.pool.get("account.invoice.line").product_id_change(cr, uid, [], move.product_id.id, None, partner_id=move.picking_id.partner_id.id, fposition_id=(fp and fp.id), context=context)
extra_move_tax[0, move.product_id] = [(6, 0, res['value']['invoice_line_tax_ids'])]
else:
extra_move_tax[0, move.product_id] = [(6, 0, [x.id for x in move.product_id.product_tmpl_id.taxes_id])]
return (is_extra_move, extra_move_tax)
def _get_taxes(self, cr, uid, move, context=None):
+1 -1
View File
@@ -43,7 +43,7 @@ class crm_team(osv.Model):
'complete_name': fields.function(get_full_name, type='char', size=256, readonly=True, store=True, string="Full Name"),
'code': fields.char('Code', size=8),
'active': fields.boolean('Active', help="If the active field is set to "\
"true, it will allow you to hide the sales team without removing it."),
"false, it will allow you to hide the sales team without removing it."),
'company_id': fields.many2one('res.company', 'Company'),
'user_id': fields.many2one('res.users', 'Team Leader'),
'member_ids': fields.many2many('res.users', 'sale_member_rel', 'team_id', 'member_id', 'Team Members'),
+5 -5
View File
@@ -3421,11 +3421,11 @@ class stock_warehouse(osv.osv):
seq_obj = self.pool.get('ir.sequence')
picking_type_obj = self.pool.get('stock.picking.type')
#create new sequences
in_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': warehouse.name + _(' Sequence in'), 'prefix': warehouse.code + '/IN/', 'padding': 5}, context=context)
out_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': warehouse.name + _(' Sequence out'), 'prefix': warehouse.code + '/OUT/', 'padding': 5}, context=context)
pack_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': warehouse.name + _(' Sequence packing'), 'prefix': warehouse.code + '/PACK/', 'padding': 5}, context=context)
pick_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': warehouse.name + _(' Sequence picking'), 'prefix': warehouse.code + '/PICK/', 'padding': 5}, context=context)
int_seq_id = seq_obj.create(cr, SUPERUSER_ID, values={'name': warehouse.name + _(' Sequence internal'), 'prefix': warehouse.code + '/INT/', 'padding': 5}, context=context)
in_seq_id = seq_obj.create(cr, SUPERUSER_ID, {'name': warehouse.name + _(' Sequence in'), 'prefix': warehouse.code + '/IN/', 'padding': 5}, context=context)
out_seq_id = seq_obj.create(cr, SUPERUSER_ID, {'name': warehouse.name + _(' Sequence out'), 'prefix': warehouse.code + '/OUT/', 'padding': 5}, context=context)
pack_seq_id = seq_obj.create(cr, SUPERUSER_ID, {'name': warehouse.name + _(' Sequence packing'), 'prefix': warehouse.code + '/PACK/', 'padding': 5}, context=context)
pick_seq_id = seq_obj.create(cr, SUPERUSER_ID, {'name': warehouse.name + _(' Sequence picking'), 'prefix': warehouse.code + '/PICK/', 'padding': 5}, context=context)
int_seq_id = seq_obj.create(cr, SUPERUSER_ID, {'name': warehouse.name + _(' Sequence internal'), 'prefix': warehouse.code + '/INT/', 'padding': 5}, context=context)
wh_stock_loc = warehouse.lot_stock_id
wh_input_stock_loc = warehouse.wh_input_stock_loc_id
+7 -1
View File
@@ -690,7 +690,7 @@
<button name="action_confirm" states="draft" string="Mark as Todo" type="object" class="oe_highlight" groups="base.group_user"/>
<button name="do_new_transfer" states="draft,partially_available,assigned" string="Validate" groups="stock.group_stock_user" type="object" class="oe_highlight"/>
<button name="action_assign" states="confirmed,waiting" string="Reserve" type="object" class="oe_highlight" groups="base.group_user"/>
<button name="rereserve_pick" states="waiting,partially_available" string="Recheck Reservation" type="object" class="oe_highlight" groups="base.group_user"/>
<button name="rereserve_pick" string="Recheck Availability" type="object" class="oe_highlight" groups="base.group_user" attrs="{'invisible': ['|', ('state', 'not in', ('waiting', 'partially_available')), ('pack_operation_exist','=',True)]}"/>
<button name="force_assign" states="confirmed,waiting,partially_available" string="Force Availability" type="object" groups="base.group_user"/>
<button name="do_print_picking" string="Print Picking List" groups="stock.group_stock_user" type="object" attrs="{'invisible': [('state', 'not in', ('assigned', 'partially_available'))]}"/>
<button name="%(act_stock_return_picking)d" string="Reverse Transfer" states="done" type="action" groups="base.group_user"/>
@@ -1246,6 +1246,9 @@
<group name="quants_grp" string="Reserved Quants" colspan="2" groups="base.group_no_one">
<field name="string_availability_info"/>
</group>
<group name="moved_quants_grp" string="Moved Quants" colspan="4" groups="base.group_no_one" attrs="{'invisible': [('state', '!=', 'done')]}">
<field name="quant_ids" readonly="1" nolabel="1"/>
</group>
</group>
</sheet>
</form>
@@ -1299,6 +1302,9 @@
<group name="quants_grp" string="Reserved">
<field name="string_availability_info"/>
</group>
<group name="moved_quants_grp" string="Moved Quants" colspan="4" groups="base.group_no_one" attrs="{'invisible': [('state', '!=', 'done')]}">
<field name="quant_ids" readonly="1" nolabel="1"/>
</group>
</group>
</form>
</field>
@@ -723,9 +723,9 @@ var CalendarView = View.extend({
var color_field = self.fields[self.color_field];
_.each(events, function (e) {
var key,val = null;
if (self.fields[self.color_field].type == "selection") {
if (color_field.type == "selection") {
key = e[self.color_field];
val = _.find( self.fields[self.color_field].selection, function(name){ return name[0] === key;});
val = _.find(color_field.selection, function(name){ return name[0] === key;});
} else {
key = e[self.color_field][0];
val = e[self.color_field];
@@ -750,7 +750,7 @@ var CalendarView = View.extend({
self.sidebar.filter.set_filters();
events = $.map(events, function (e) {
var key = self.fields[self.color_field].type == "selection" ? e[self.color_field] : e[self.color_field][0];
var key = color_field.type == "selection" ? e[self.color_field] : e[self.color_field][0];
if (_.contains(self.now_filter_ids, key) && self.all_filters[key].is_checked) {
return e;
}
+5
View File
@@ -365,6 +365,9 @@ class website_sale(http.Controller):
return {}
value = order._cart_update(product_id=product_id, line_id=line_id, add_qty=add_qty, set_qty=set_qty)
if not order.cart_quantity:
request.website.sale_reset()
return {}
if not display:
return None
value['cart_quantity'] = order.cart_quantity
@@ -882,6 +885,8 @@ class website_sale(http.Controller):
# clean context and session, then redirect to the confirmation page
request.website.sale_reset(context=context)
if tx and tx.state == 'draft':
return request.redirect('/shop')
return request.redirect('/shop/confirmation')
@@ -64,7 +64,7 @@ $(document).ready(function () {
}
function track_ga() {
website_ga = this._gaw || function(){};
website_ga = this.ga || function(){};
website_ga.apply(this, arguments);
}
+1 -1
View File
@@ -16,7 +16,7 @@ Delivery Costs
'security/ir.model.access.csv',
],
'demo': [
'demo/website_sale_delivery_demo.xml',
'data/website_sale_delivery_demo.xml'
],
'qweb': [],
'installable': True,
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<record id="delivery.delivery_carrier" model="delivery.carrier">
<field name="website_published" eval="True" />
</record>
<record id="delivery.normal_delivery_carrier" model="delivery.carrier">
<field name="website_published" eval="True" />
</record>
</data>
</odoo>
@@ -3,6 +3,8 @@
from openerp.osv import orm, fields
from openerp import SUPERUSER_ID
from openerp.addons import decimal_precision
from openerp.exceptions import ValidationError
from openerp.tools.translate import _
class delivery_carrier(orm.Model):
@@ -114,14 +116,22 @@ class SaleOrder(orm.Model):
# This can surely be done in a more efficient way, but at the moment, it mimics the way it's
# done in delivery_set method of sale.py, from delivery module
for delivery_id in carrier_obj.browse(cr, SUPERUSER_ID, delivery_ids, context=dict(context, order_id=order.id)):
if not delivery_id.available:
try:
if not delivery_id.available:
delivery_ids.remove(delivery_id.id)
except ValidationError:
# RIM: hack to remove in master, because available field should not depend on a SOAP call to external shipping provider
# The validation error is used in backend to display errors in fedex config, but should fail silently in frontend
delivery_ids.remove(delivery_id.id)
return delivery_ids
def _get_errors(self, cr, uid, order, context=None):
errors = super(SaleOrder, self)._get_errors(cr, uid, order, context=context)
if not self._get_delivery_methods(cr, uid, order, context=context):
errors.append(('No delivery method available', 'There is no available delivery method for your order'))
errors.append(
(_('Sorry, we are unable to ship your order'),
_('No shipping method is available for your current order and shipping address. '
'Please contact us for more information.')))
return errors
def _get_website_data(self, cr, uid, order, context=None):
+1 -1
View File
@@ -10,7 +10,7 @@ class website_config_settings(models.TransientModel):
website_slide_google_app_key = fields.Char(string='Google Doc Key')
@api.model
def get_website_slide_google_app_key(self, fields):
def get_default_website_slide_google_app_key(self, fields):
website_slide_google_app_key = False
if 'website_slide_google_app_key' in fields:
website_slide_google_app_key = self.env['ir.config_parameter'].sudo().get_param('website_slides.google_app_key')
+11
View File
@@ -0,0 +1,11 @@
France, 07/30/2015
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,
Anthony Ruhier <anthony.ruhier@gmail.com> https://github.com/anthony25
+1 -1
View File
@@ -623,7 +623,7 @@ instead of a single view its ``arch`` field is composed of any number of
<!-- improved idea categories list -->
<record id="idea_category_list2" model="ir.ui.view">
<field name="name">id.category.list2</field>
<field name="model">idea.category/field>
<field name="model">idea.category</field>
<field name="inherit_id" ref="id_category_list"/>
<field name="arch" type="xml">
<!-- find field description inside tree, and add the field
+1 -4
View File
@@ -292,7 +292,6 @@ class ir_translation(osv.osv):
def _set_ids(self, cr, uid, name, tt, lang, ids, value, src=None):
self.clear_caches()
original_module = self.pool[name.split(',')[0]]._original_module
cr.execute('update ir_translation '
'set value=%s '
' , src=%s '
@@ -300,10 +299,9 @@ class ir_translation(osv.osv):
'where lang=%s '
'and type=%s '
'and name=%s '
'and module=%s '
'and res_id IN %s '
'returning res_id',
(value,src,'translated',lang,tt,name,original_module,tuple(ids),))
(value,src,'translated',lang,tt,name,tuple(ids),))
existing_ids = [x[0] for x in cr.fetchall()]
@@ -313,7 +311,6 @@ class ir_translation(osv.osv):
'type':tt,
'name':name,
'res_id':id,
'module':original_module,
'value':value,
'src':src,
'state':'translated'
+1 -1
View File
@@ -465,7 +465,7 @@ class module(osv.osv):
ir_model_data = self.pool.get('ir.model.data')
modules_to_remove = [m.name for m in self.browse(cr, uid, ids, context)]
ir_model_data._module_data_uninstall(cr, uid, modules_to_remove, context)
self.write(cr, uid, ids, {'state': 'uninstalled'})
self.write(cr, uid, ids, {'state': 'uninstalled', 'latest_version': False})
return True
def downstream_dependencies(self, cr, uid, ids, known_dep_ids=None,
+1 -1
View File
@@ -718,7 +718,7 @@ def parse_m2m(commands):
for command in commands:
if isinstance(command, (tuple, list)):
if command[0] in (1, 4):
ids.append(command[2])
ids.append(command[1])
elif command[0] == 5:
ids = []
elif command[0] == 6:
+11 -11
View File
@@ -49,7 +49,7 @@ class test_integer_field(CreatorCase):
def test_0(self):
self.assertEqual(
self.export(0),
[[False]])
[[u'0']])
def test_basic_value(self):
self.assertEqual(
@@ -72,7 +72,7 @@ class test_float_field(CreatorCase):
def test_0(self):
self.assertEqual(
self.export(0.0),
[[False]])
[[u'0.0']])
def test_epsilon(self):
self.assertEqual(
@@ -100,14 +100,14 @@ class test_decimal_field(CreatorCase):
def test_0(self):
self.assertEqual(
self.export(0.0),
[[False]])
[[u'0.0']])
def test_epsilon(self):
""" epsilon gets sliced to 0 due to precision
"""
self.assertEqual(
self.export(0.000000000027),
[[False]])
[[u'0.0']])
def test_negative(self):
self.assertEqual(
@@ -129,7 +129,7 @@ class test_string_field(CreatorCase):
def test_empty(self):
self.assertEqual(
self.export(""),
[[False]])
[['']])
def test_within_bounds(self):
self.assertEqual(
self.export("foobar"),
@@ -148,7 +148,7 @@ class test_unbound_string_field(CreatorCase):
def test_empty(self):
self.assertEqual(
self.export(""),
[[False]])
[['']])
def test_small(self):
self.assertEqual(
self.export("foobar"),
@@ -170,7 +170,7 @@ class test_text(CreatorCase):
def test_empty(self):
self.assertEqual(
self.export(""),
[[False]])
[['']])
def test_small(self):
self.assertEqual(
self.export("foobar"),
@@ -190,7 +190,7 @@ class test_date(CreatorCase):
def test_empty(self):
self.assertEqual(
self.export(False),
[[False]])
[['']])
def test_basic(self):
self.assertEqual(
self.export('2011-11-07'),
@@ -202,7 +202,7 @@ class test_datetime(CreatorCase):
def test_empty(self):
self.assertEqual(
self.export(False),
[[False]])
[['']])
def test_basic(self):
self.assertEqual(
self.export('2011-11-07 21:05:48'),
@@ -265,7 +265,7 @@ class test_selection_function(CreatorCase):
def test_empty(self):
self.assertEqual(
self.export(False),
[[None]])
[['']])
def test_value(self):
# FIXME: selection functions export the *value* itself
@@ -278,7 +278,7 @@ class test_selection_function(CreatorCase):
# fucking hell
self.assertEqual(
self.export(0),
[[None]])
[['']])
class test_m2o(CreatorCase):
model_name = 'export.many2one'
+23 -18
View File
@@ -761,9 +761,9 @@ class Field(object):
""" convert ``value`` from the cache to a valid value for export. The
parameter ``env`` is given for managing translations.
"""
if env.context.get('export_raw_data'):
return value
return bool(value) and ustr(value)
if not value:
return ''
return value if env.context.get('export_raw_data') else ustr(value)
def convert_to_display_name(self, value, record=None):
""" convert ``value`` from the cache to a suitable display name. """
@@ -1015,6 +1015,11 @@ class Integer(Field):
# special case, when an integer field is used as inverse for a one2many
records._cache[self] = value.id or 0
def convert_to_export(self, value, env):
if value or value == 0:
return value if env.context.get('export_raw_data') else ustr(value)
return ''
class Float(Field):
""" The precision digits are given by the attribute
@@ -1062,6 +1067,11 @@ class Float(Field):
digits = self.digits
return float_round(value, precision_digits=digits[1]) if digits else value
def convert_to_export(self, value, env):
if value or value == 0.0:
return value if env.context.get('export_raw_data') else ustr(value)
return ''
class Monetary(Field):
""" The decimal precision and currency symbol are taken from the attribute
@@ -1152,11 +1162,6 @@ class _String(Field):
else:
return value
def convert_to_export(self, value, env):
if env.context.get('export_raw_data'):
return value if value else None
return bool(value) and ustr(value)
class Char(_String):
""" Basic string field, can be length-limited, usually displayed as a
@@ -1282,9 +1287,9 @@ class Date(Field):
return self.to_string(value)
def convert_to_export(self, value, env):
if value and env.context.get('export_raw_data'):
return self.from_string(value) or None
return bool(value) and ustr(value)
if not value:
return ''
return self.from_string(value) if env.context.get('export_raw_data') else ustr(value)
class Datetime(Field):
@@ -1351,9 +1356,9 @@ class Datetime(Field):
return self.to_string(value)
def convert_to_export(self, value, env):
if value and env.context.get('export_raw_data'):
return self.from_string(value) or None
return bool(value) and ustr(value)
if not value:
return ''
return self.from_string(value) if env.context.get('export_raw_data') else ustr(value)
def convert_to_display_name(self, value, record=None):
assert record, 'Record expected'
@@ -1461,7 +1466,7 @@ class Selection(Field):
def convert_to_export(self, value, env):
if not isinstance(self.selection, list):
# FIXME: this reproduces an existing buggy behavior!
return value or None
return value if value else ''
for item in self._description_selection(env):
if item[0] == value:
return item[1]
@@ -1498,7 +1503,7 @@ class Reference(Selection):
return "%s,%s" % (value._name, value.id) if value else False
def convert_to_export(self, value, env):
return value.name_get()[0][1] if value else None
return value.name_get()[0][1] if value else ''
def convert_to_display_name(self, value, record=None):
return ustr(value and value.display_name)
@@ -1638,7 +1643,7 @@ class Many2one(_Relational):
return value.id
def convert_to_export(self, value, env):
return value.name_get()[0][1] if value else None
return value.name_get()[0][1] if value else ''
def convert_to_display_name(self, value, record=None):
return ustr(value.display_name)
@@ -1744,7 +1749,7 @@ class _RelationalMulti(_Relational):
return result
def convert_to_export(self, value, env):
return ','.join(name for id, name in value.name_get()) if value else None
return ','.join(name for id, name in value.name_get()) if value else ''
def convert_to_display_name(self, value, record=None):
raise NotImplementedError()
+2 -2
View File
@@ -58,7 +58,7 @@ _logger = logging.getLogger(__name__)
_schema = logging.getLogger(__name__ + '.schema')
_unlink = logging.getLogger(__name__ + '.unlink')
regex_order = re.compile('^( *([a-z0-9:_]+|"[a-z0-9:_]+")( *desc| *asc)?( *, *|))+$', re.I)
regex_order = re.compile('^(\s*([a-z0-9:_]+|"[a-z0-9:_]+")(\s+(desc|asc))?\s*(,|$))+(?<!,)$', re.I)
regex_object_name = re.compile(r'^[a-z0-9_.]+$')
onchange_v7 = re.compile(r"^(\w+)\((.*)\)$")
@@ -3193,7 +3193,7 @@ class BaseModel(object):
result = self.read(list(fnames), load='_classic_write')
# check the cache, and update it if necessary
if not self._cache.contains(field):
if field not in self._cache:
for values in result:
record = self.browse(values.pop('id'))
record._cache.update(record._convert_to_cache(values, validate=False))
+1 -1
View File
@@ -122,7 +122,7 @@ def load_module_graph(cr, graph, status=None, perform_checks=True, skip_modules=
migrations.migrate_module(package, 'pre')
load_openerp_module(package.name)
new_install = package.installed_version is None
new_install = package.state == 'to install'
if new_install:
py_module = sys.modules['openerp.addons.%s' % (module_name,)]
pre_init = package.info.get('pre_init_hook')
-17
View File
@@ -361,23 +361,6 @@ class HttpCase(TransactionCase):
openerp.tools.misc.dumpstacks()
t0 = t1
def phantom_jsfile(self, jsfile, timeout=60, **kw):
options = {
'timeout' : timeout,
'port': PORT,
'db': get_db_name(),
'session_id': self.session_id,
}
options.update(kw)
phantomtest = os.path.join(os.path.dirname(__file__), 'phantomtest.js')
# phantom.args[0] == phantomtest path
# phantom.args[1] == options
cmd = [
'phantomjs',
jsfile, phantomtest, json.dumps(options)
]
self.phantom_run(cmd, timeout)
def phantom_js(self, url_path, code, ready="window", login=None, timeout=60, **kw):
""" Test js code running in the browser
- optionnally log as 'login'