[MERGE] forward port of branch saas-6 up to be58335
This commit is contained in:
@@ -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"/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
@@ -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),
|
||||
|
||||
@@ -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__)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)]}),
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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\
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"/>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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' />
|
||||
|
||||
@@ -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)"
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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))+"])]",
|
||||
|
||||
@@ -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
@@ -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]
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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))
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user