[MERGE] forward port branch saas-11 up to b844d93889
This commit is contained in:
@@ -588,11 +588,11 @@ class AccountTax(models.Model):
|
||||
def unlink(self):
|
||||
company_id = self.env.user.company_id.id
|
||||
ir_values = self.env['ir.values']
|
||||
supplier_taxes_id = set(ir_values.get_default('product.template', 'supplier_taxes_id', company_id=company_id))
|
||||
supplier_taxes_id = set(ir_values.get_default('product.template', 'supplier_taxes_id', company_id=company_id) or [])
|
||||
deleted_sup_tax = self.filtered(lambda tax: tax.id in supplier_taxes_id)
|
||||
if deleted_sup_tax:
|
||||
ir_values.sudo().set_default('product.template', "supplier_taxes_id", list(supplier_taxes_id - set(deleted_sup_tax.ids)), for_all_users=True, company_id=company_id)
|
||||
taxes_id = set(self.env['ir.values'].get_default('product.template', 'taxes_id', company_id=company_id))
|
||||
taxes_id = set(self.env['ir.values'].get_default('product.template', 'taxes_id', company_id=company_id) or [])
|
||||
deleted_tax = self.filtered(lambda tax: tax.id in taxes_id)
|
||||
if deleted_tax:
|
||||
ir_values.sudo().set_default('product.template', "taxes_id", list(taxes_id - set(deleted_tax.ids)), for_all_users=True, company_id=company_id)
|
||||
|
||||
@@ -685,9 +685,10 @@ class AccountInvoice(models.Model):
|
||||
for line in invoice_move_lines:
|
||||
if self.currency_id != company_currency:
|
||||
currency = self.currency_id.with_context(date=self.date_invoice or fields.Date.context_today(self))
|
||||
line['currency_id'] = currency.id
|
||||
line['amount_currency'] = currency.round(line['price'])
|
||||
line['price'] = currency.compute(line['price'], company_currency)
|
||||
if not (line.get('currency_id') and line.get('amount_currency')):
|
||||
line['currency_id'] = currency.id
|
||||
line['amount_currency'] = currency.round(line['price'])
|
||||
line['price'] = currency.compute(line['price'], company_currency)
|
||||
else:
|
||||
line['currency_id'] = False
|
||||
line['amount_currency'] = False
|
||||
|
||||
@@ -921,6 +921,14 @@ class AccountMoveLine(models.Model):
|
||||
if 'analytic_account_id' in first_line_dict:
|
||||
del first_line_dict['analytic_account_id']
|
||||
if 'tax_ids' in first_line_dict:
|
||||
tax_ids = []
|
||||
#vals['tax_ids'] is a list of commands [[4, tax_id, None], ...]
|
||||
for tax_id in vals['tax_ids']:
|
||||
tax_ids.append(tax_id[1])
|
||||
amount = first_line_dict['credit'] - first_line_dict['debit']
|
||||
amount_tax = self.env['account.tax'].browse(tax_ids).compute_all(amount)['total_included']
|
||||
first_line_dict['credit'] = amount_tax > 0 and amount_tax or 0.0
|
||||
first_line_dict['debit'] = amount_tax < 0 and abs(amount_tax) or 0.0
|
||||
del first_line_dict['tax_ids']
|
||||
|
||||
# Writeoff line in specified writeoff account
|
||||
|
||||
@@ -206,15 +206,17 @@ class ResPartner(models.Model):
|
||||
def _credit_debit_get(self):
|
||||
tables, where_clause, where_params = self.env['account.move.line']._query_get()
|
||||
where_params = [tuple(self.ids)] + where_params
|
||||
self._cr.execute("""SELECT l.partner_id, act.type, SUM(l.amount_residual)
|
||||
FROM account_move_line l
|
||||
LEFT JOIN account_account a ON (l.account_id=a.id)
|
||||
if where_clause:
|
||||
where_clause = 'AND ' + where_clause
|
||||
self._cr.execute("""SELECT account_move_line.partner_id, act.type, SUM(account_move_line.amount_residual)
|
||||
FROM account_move_line
|
||||
LEFT JOIN account_account a ON (account_move_line.account_id=a.id)
|
||||
LEFT JOIN account_account_type act ON (a.user_type_id=act.id)
|
||||
WHERE act.type IN ('receivable','payable')
|
||||
AND l.partner_id IN %s
|
||||
AND l.reconciled IS FALSE
|
||||
AND account_move_line.partner_id IN %s
|
||||
AND account_move_line.reconciled IS FALSE
|
||||
""" + where_clause + """
|
||||
GROUP BY l.partner_id, act.type
|
||||
GROUP BY account_move_line.partner_id, act.type
|
||||
""", where_params)
|
||||
for pid, type, val in self._cr.fetchall():
|
||||
partner = self.browse(pid)
|
||||
|
||||
@@ -1343,6 +1343,7 @@
|
||||
<field name="currency_id" options="{'no_create': True}" groups="base.group_multi_currency"/>
|
||||
<field name="debit" sum="Total Debit"/>
|
||||
<field name="credit" sum="Total Credit"/>
|
||||
<field name="date_maturity" required="0"/>
|
||||
</tree>
|
||||
</field>
|
||||
<field name="narration" colspan="4" placeholder="Add an internal note..." nolabel="1" height="50"/>
|
||||
|
||||
@@ -11,5 +11,7 @@ class IrConfigParameter(models.Model):
|
||||
super(IrConfigParameter, self).init(force=force)
|
||||
if force:
|
||||
oauth_oe = self.env.ref('auth_oauth.provider_openerp')
|
||||
if not oauth_oe:
|
||||
return
|
||||
dbuuid = self.sudo().get_param('database.uuid')
|
||||
oauth_oe.write({'client_id': dbuuid})
|
||||
|
||||
@@ -552,15 +552,15 @@ class Meeting(models.Model):
|
||||
def _get_recurrency_end_date(self):
|
||||
""" Return the last date a recurring event happens, according to its end_type. """
|
||||
self.ensure_one()
|
||||
data = self.read(['final_date', 'recurrency', 'rrule_type', 'count', 'end_type', 'stop'])[0]
|
||||
data = self.read(['final_date', 'recurrency', 'rrule_type', 'count', 'end_type', 'stop', 'interval'])[0]
|
||||
|
||||
if not data.get('recurrency'):
|
||||
return False
|
||||
|
||||
end_type = data.get('end_type')
|
||||
final_date = data.get('final_date')
|
||||
if end_type == 'count' and all(data.get(key) for key in ['count', 'rrule_type', 'stop']):
|
||||
count = data['count'] + 1
|
||||
if end_type == 'count' and all(data.get(key) for key in ['count', 'rrule_type', 'stop', 'interval']):
|
||||
count = (data['count'] + 1) * data['interval']
|
||||
delay, mult = {
|
||||
'daily': ('days', 1),
|
||||
'weekly': ('days', 7),
|
||||
@@ -1134,7 +1134,7 @@ class Meeting(models.Model):
|
||||
data['rrule_type'] = 'monthly'
|
||||
|
||||
if rule._bymonthday:
|
||||
data['day'] = rule._bymonthday[0]
|
||||
data['day'] = list(rule._bymonthday)[0]
|
||||
data['month_by'] = 'date'
|
||||
data['rrule_type'] = 'monthly'
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@ class EventTicket(models.Model):
|
||||
name = fields.Char(string='Name', required=True, translate=True)
|
||||
event_id = fields.Many2one('event.event', string="Event", required=True, ondelete='cascade')
|
||||
product_id = fields.Many2one('product.product', string='Product',
|
||||
required=True, domain=[("event_ok", "=", True)], default=_default_product_id)
|
||||
required=True, domain=["|", ("event_type_id", "!=", False), ("event_ok", "=", True)],
|
||||
default=_default_product_id)
|
||||
registration_ids = fields.One2many('event.registration', 'event_ticket_id', string='Registrations')
|
||||
price = fields.Float(string='Price', digits=dp.get_precision('Product Price'))
|
||||
deadline = fields.Date(string="Sales End")
|
||||
|
||||
@@ -194,8 +194,8 @@ class GoogleCalendar(models.AbstractModel):
|
||||
|
||||
def generate_data(self, event, isCreating=False):
|
||||
if event.allday:
|
||||
start_date = fields.Datetime.context_timestamp(self, fields.Datetime.from_string(event.start)).isoformat('T').split('T')[0]
|
||||
final_date = fields.Datetime.context_timestamp(self, fields.Datetime.from_string(event.stop) + timedelta(days=1)).isoformat('T').split('T')[0]
|
||||
start_date = event.start_date
|
||||
final_date = (datetime.strptime(event.stop_date, tools.DEFAULT_SERVER_DATE_FORMAT) + timedelta(days=1)).strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
|
||||
type = 'date'
|
||||
vstype = 'dateTime'
|
||||
else:
|
||||
|
||||
@@ -10,6 +10,7 @@ from werkzeug import url_encode
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import UserError, AccessError, ValidationError
|
||||
from openerp.tools import float_compare
|
||||
from odoo.tools.translate import _
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -249,7 +250,8 @@ class Holidays(models.Model):
|
||||
if holiday.holiday_type != 'employee' or holiday.type != 'remove' or not holiday.employee_id or holiday.holiday_status_id.limit:
|
||||
continue
|
||||
leave_days = holiday.holiday_status_id.get_days(holiday.employee_id.id)[holiday.holiday_status_id.id]
|
||||
if leave_days['remaining_leaves'] < 0 or leave_days['virtual_remaining_leaves'] < 0:
|
||||
if float_compare(leave_days['remaining_leaves'], 0, precision_digits=2) == -1 or \
|
||||
float_compare(leave_days['virtual_remaining_leaves'], 0, precision_digits=2) == -1:
|
||||
raise ValidationError(_('The number of remaining leaves is not sufficient for this leave type.\n'
|
||||
'Please verify also the leaves waiting for validation.'))
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import time
|
||||
from datetime import datetime, timedelta
|
||||
from dateutil import relativedelta
|
||||
|
||||
import babel
|
||||
|
||||
from odoo import api, fields, models, tools, _
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
@@ -545,9 +547,10 @@ class HrPayslip(models.Model):
|
||||
return res
|
||||
ttyme = datetime.fromtimestamp(time.mktime(time.strptime(date_from, "%Y-%m-%d")))
|
||||
employee = self.env['hr.employee'].browse(employee_id)
|
||||
locale = self.env.context.get('lang', 'en_US')
|
||||
res['value'].update({
|
||||
'name': _('Salary Slip of %s for %s') % (employee.name, tools.ustr(ttyme.strftime('%B-%Y'))),
|
||||
'company_id': employee.company_id.id
|
||||
'name': _('Salary Slip of %s for %s') % (employee.name, tools.ustr(babel.dates.format_date(date=ttyme, format='MMMM-y', locale=locale))),
|
||||
'company_id': employee.company_id.id,
|
||||
})
|
||||
|
||||
if not self.env.context.get('contract'):
|
||||
@@ -593,7 +596,8 @@ class HrPayslip(models.Model):
|
||||
date_to = self.date_to
|
||||
|
||||
ttyme = datetime.fromtimestamp(time.mktime(time.strptime(date_from, "%Y-%m-%d")))
|
||||
self.name = _('Salary Slip of %s for %s') % (employee.name, tools.ustr(ttyme.strftime('%B-%Y')))
|
||||
locale = self.env.context.get('lang', 'en_US')
|
||||
self.name = _('Salary Slip of %s for %s') % (employee.name, tools.ustr(babel.dates.format_date(date=ttyme, format='MMMM-y', locale=locale)))
|
||||
self.company_id = employee.company_id
|
||||
|
||||
if not self.env.context.get('contract') or not self.contract_id:
|
||||
|
||||
@@ -21,12 +21,11 @@ class Task(models.Model):
|
||||
task.subtask_count = self.search_count([('id', 'child_of', task.id), ('id', '!=', task.id)])
|
||||
|
||||
@api.depends('timesheet_ids.unit_amount', 'planned_hours', 'child_ids.stage_id',
|
||||
'child_ids.planned_hours', 'child_ids.effective_hours', 'child_ids.children_hours')
|
||||
'child_ids.planned_hours', 'child_ids.effective_hours', 'child_ids.children_hours', 'child_ids.timesheet_ids.unit_amount')
|
||||
def _hours_get(self):
|
||||
for task in self:
|
||||
|
||||
for task in self.sorted(key='id', reverse=True):
|
||||
for child_task in task.child_ids:
|
||||
if child_task.stage_id and child_task.stage_id.fold:
|
||||
if child_task.stage_id and not child_task.stage_id.fold:
|
||||
task.children_hours += child_task.effective_hours + child_task.children_hours
|
||||
else:
|
||||
task.children_hours += max(child_task.planned_hours, child_task.effective_hours + child_task.children_hours)
|
||||
|
||||
+401
-398
File diff suppressed because it is too large
Load Diff
@@ -27,12 +27,14 @@ class AccountTax(models.Model):
|
||||
_inherit = 'account.tax'
|
||||
|
||||
name = fields.Char(translate=True)
|
||||
description = fields.Char(translate=True)
|
||||
|
||||
|
||||
class AccountTaxTemplate(models.Model):
|
||||
_inherit = 'account.tax.template'
|
||||
|
||||
name = fields.Char(translate=True)
|
||||
description = fields.Char(translate=True)
|
||||
|
||||
|
||||
class AccountChartTemplate(models.Model):
|
||||
|
||||
@@ -63,8 +63,10 @@ class AccountChartTemplate(models.Model):
|
||||
for company in company_ids:
|
||||
# write account.account translations in the real COA
|
||||
chart_template_id._process_accounts_translations(company.id, langs, 'name')
|
||||
# copy account.tax translations
|
||||
# copy account.tax name translations
|
||||
chart_template_id._process_taxes_translations(company.id, langs, 'name')
|
||||
# copy account.tax description translations
|
||||
chart_template_id._process_taxes_translations(company.id, langs, 'description')
|
||||
# copy account.fiscal.position translations
|
||||
chart_template_id._process_fiscal_pos_translations(company.id, langs, 'name')
|
||||
return True
|
||||
@@ -109,8 +111,10 @@ class BaseLanguageInstall(models.TransientModel):
|
||||
for company in self.env['res.company'].search([('chart_template_id', '=', coa.id)]):
|
||||
# write account.account translations in the real COA
|
||||
coa._process_accounts_translations(company.id, [self.lang], 'name')
|
||||
# copy account.tax translations
|
||||
# copy account.tax name translations
|
||||
coa._process_taxes_translations(company.id, [self.lang], 'name')
|
||||
# copy account.tax description translations
|
||||
coa._process_taxes_translations(company.id, [self.lang], 'description')
|
||||
# copy account.fiscal.position translations
|
||||
coa._process_fiscal_pos_translations(company.id, [self.lang], 'name')
|
||||
return res
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tax_tag_ut8" model="account.account.tag">
|
||||
<field name="name">Utgående 8% mva</field>
|
||||
<field name="name">Utgående 10% mva</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tax_tag_in25" model="account.account.tag">
|
||||
@@ -24,7 +24,7 @@
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tax_tag_in8" model="account.account.tag">
|
||||
<field name="name">Inngående 8% mva</field>
|
||||
<field name="name">Inngående 10% mva</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
|
||||
@@ -63,9 +63,9 @@
|
||||
</record>
|
||||
<record id="tax3" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="no_chart_template"/>
|
||||
<field name="name">Utgående 8% mva</field>
|
||||
<field name="description">Utgående 8% mva</field>
|
||||
<field name="amount">8</field>
|
||||
<field name="name">Utgående 10% mva</field>
|
||||
<field name="description">Utgående 10% mva</field>
|
||||
<field name="amount">10</field>
|
||||
<field name="amount_type">percent</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="account_id" ref="chart2704"/>
|
||||
@@ -96,9 +96,9 @@
|
||||
</record>
|
||||
<record id="tax6" model="account.tax.template">
|
||||
<field name="chart_template_id" ref="no_chart_template"/>
|
||||
<field name="name">Inngående 8% mva</field>
|
||||
<field name="description">Inngående 8% mva</field>
|
||||
<field name="amount">8</field>
|
||||
<field name="name">Inngående 10% mva</field>
|
||||
<field name="description">Inngående 10% mva</field>
|
||||
<field name="amount">10</field>
|
||||
<field name="amount_type">percent</field>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_id" ref="chart2714"/>
|
||||
|
||||
@@ -114,7 +114,10 @@ class MailController(http.Controller):
|
||||
is_editable = request.env.user.has_group('base.group_no_one')
|
||||
partner_id = request.env.user.partner_id
|
||||
follower_id = None
|
||||
for follower in request.env['mail.followers'].browse(follower_ids):
|
||||
follower_recs = request.env['mail.followers'].sudo().browse(follower_ids)
|
||||
res_ids = follower_recs.mapped('res_id')
|
||||
request.env[res_model].browse(res_ids).check_access_rule("write")
|
||||
for follower in follower_recs:
|
||||
is_uid = partner_id == follower.partner_id
|
||||
follower_id = follower.id if is_uid else follower_id
|
||||
followers.append({
|
||||
|
||||
@@ -351,7 +351,7 @@ snippets_editor.Class.include({
|
||||
|
||||
var callback = window ? window["callback"] : undefined;
|
||||
odoo_top[callback+"_updown"] = function (value, fields_values, field_name) {
|
||||
if (!window) {
|
||||
if (!window || window.closed) {
|
||||
delete odoo_top[callback+"_updown"];
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import json
|
||||
import logging
|
||||
import pprint
|
||||
import urllib
|
||||
import urllib2
|
||||
import werkzeug
|
||||
|
||||
@@ -26,7 +27,7 @@ class PaypalController(http.Controller):
|
||||
return return_url
|
||||
|
||||
def _parse_pdt_response(self, response):
|
||||
""" Parse a text reponse for a PDT verification .
|
||||
""" Parse a text response for a PDT verification .
|
||||
|
||||
:param response str: text response, structured in the following way:
|
||||
STATUS\nkey1=value1\nkey2=value2...\n
|
||||
@@ -37,6 +38,9 @@ class PaypalController(http.Controller):
|
||||
lines = filter(None, response.split('\n'))
|
||||
status = lines.pop(0)
|
||||
pdt_post = dict(line.split('=', 1) for line in lines)
|
||||
# html unescape
|
||||
for post in pdt_post:
|
||||
pdt_post[post] = urllib.unquote_plus(pdt_post[post]).decode('utf8')
|
||||
return status, pdt_post
|
||||
|
||||
def paypal_validate_data(self, **post):
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<field name="paypal_api_enabled" invisible="1"/>
|
||||
<field name="paypal_api_username" invisible="1"/>
|
||||
<field name="paypal_api_password" invisible="1"/>
|
||||
<a colspan="2" href="https://www.paypal.com/in/cgi-bin/webscr?cmd=xpt/Marketing/general/how-to-set-up-a-paypal-account-outside" target="_blank">How to configure your paypal account?</a>
|
||||
<a colspan="2" href="https://www.odoo.com/documentation/user/online/ecommerce/shopper_experience/paypal.html" target="_blank">How to configure your paypal account?</a>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
|
||||
@@ -47,7 +47,7 @@ class PosOrderReport(models.Model):
|
||||
MIN(l.id) AS id,
|
||||
COUNT(*) AS nbr_lines,
|
||||
s.date_order AS date,
|
||||
SUM(l.qty * u.factor) AS product_qty,
|
||||
SUM(l.qty) AS product_qty,
|
||||
SUM(l.qty * l.price_unit) AS price_sub_total,
|
||||
SUM((l.qty * l.price_unit) * (100 - l.discount) / 100) AS price_total,
|
||||
SUM((l.qty * l.price_unit) * (l.discount / 100)) AS total_discount,
|
||||
|
||||
@@ -75,7 +75,7 @@ class PortalWizardUser(models.TransientModel):
|
||||
_description = 'Portal User Config'
|
||||
|
||||
wizard_id = fields.Many2one('portal.wizard', string='Wizard', required=True, ondelete='cascade')
|
||||
partner_id = fields.Many2one('res.partner', string='Contact', required=True, readonly=True)
|
||||
partner_id = fields.Many2one('res.partner', string='Contact', required=True, readonly=True, ondelete='cascade')
|
||||
email = fields.Char('Email')
|
||||
in_portal = fields.Boolean('In Portal')
|
||||
user_id = fields.Many2one('res.users', string='Login User')
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
cost_method: average
|
||||
property_stock_account_input: o_expense
|
||||
property_stock_account_output: o_income
|
||||
supplier_taxes_id: []
|
||||
description: Average Ice Cream can be mass-produced and thus is widely available in developed parts of the world. Ice cream can be purchased in large cartons (vats and squrounds) from supermarkets and grocery stores, in smaller quantities from ice cream shops, convenience stores, and milk bars, and in individual servings from small carts or vans at public events.
|
||||
-
|
||||
I create a draft Purchase Order for first incoming shipment for 10 pieces at 60€
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
-
|
||||
Set the company currency as EURO for the sake of repeatibility
|
||||
-
|
||||
!record {model: res.company, id: base.main_company}:
|
||||
currency_id: base.EUR
|
||||
!python {model: res.company}: |
|
||||
company = self.browse(cr, uid, ref('base.main_company'))
|
||||
company.currency_id = company.env['res.currency'].browse(ref('base.EUR'))
|
||||
-
|
||||
Set a product as using fifo price
|
||||
-
|
||||
@@ -19,13 +20,13 @@
|
||||
valuation: real_time
|
||||
property_stock_account_input: o_expense
|
||||
property_stock_account_output: o_income
|
||||
supplier_taxes_id: []
|
||||
description: FIFO Ice Cream can be mass-produced and thus is widely available in developed parts of the world. Ice cream can be purchased in large cartons (vats and squrounds) from supermarkets and grocery stores, in smaller quantities from ice cream shops, convenience stores, and milk bars, and in individual servings from small carts or vans at public events.
|
||||
-
|
||||
I create a draft Purchase Order for first in move for 10 kg at 50 euro
|
||||
-
|
||||
!record {model: purchase.order, id: purchase_order_fifo1}:
|
||||
partner_id: base.res_partner_3
|
||||
currency_id: base.EUR
|
||||
order_line:
|
||||
- product_id: product_fifo_icecream
|
||||
product_qty: 10.0
|
||||
@@ -264,6 +265,7 @@
|
||||
valuation: real_time
|
||||
property_stock_account_input: o_expense
|
||||
property_stock_account_output: o_income
|
||||
supplier_taxes_id: []
|
||||
description:
|
||||
-
|
||||
Create outpicking. We create delivery order of 100 kg.
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
valuation: real_time
|
||||
property_stock_account_input: o_expense
|
||||
property_stock_account_output: o_income
|
||||
supplier_taxes_id: []
|
||||
description: FIFO Ice Cream can be mass-produced and thus is widely available in developed parts of the world. Ice cream can be purchased in large cartons (vats and squrounds) from supermarkets and grocery stores, in smaller quantities from ice cream shops, convenience stores, and milk bars, and in individual servings from small carts or vans at public events.
|
||||
-
|
||||
I create a draft Purchase Order for first in move for 10 kg at 50 euro
|
||||
|
||||
@@ -17,6 +17,11 @@ class SaleOrderLine(models.Model):
|
||||
domain,
|
||||
['so_line', 'unit_amount', 'product_uom_id'], ['product_uom_id', 'so_line'], lazy=False
|
||||
)
|
||||
# If the unlinked analytic line was the last one on the SO line, the qty was not updated.
|
||||
force_so_lines = self.env.context.get("force_so_lines")
|
||||
if force_so_lines:
|
||||
for line in force_so_lines:
|
||||
lines.setdefault(line, 0.0)
|
||||
for d in data:
|
||||
if not d['product_uom_id']:
|
||||
continue
|
||||
@@ -48,6 +53,12 @@ class AccountAnalyticLine(models.Model):
|
||||
).price
|
||||
if self.unit_amount == 0.0:
|
||||
return 0.0
|
||||
|
||||
# Prevent unnecessary currency conversion that could be impacted by exchange rate
|
||||
# fluctuations
|
||||
if self.currency_id and self.amount_currency and self.currency_id == order.currency_id:
|
||||
return abs(self.amount_currency / self.unit_amount)
|
||||
|
||||
price_unit = abs(self.amount / self.unit_amount)
|
||||
currency_id = self.company_id.currency_id
|
||||
if currency_id and currency_id != order.currency_id:
|
||||
@@ -122,3 +133,10 @@ class AccountAnalyticLine(models.Model):
|
||||
line.with_context(create=True).write(res)
|
||||
line.mapped('so_line').sudo()._compute_analytic()
|
||||
return line
|
||||
|
||||
@api.multi
|
||||
def unlink(self):
|
||||
so_lines = self.mapped('so_line')
|
||||
res = super(AccountAnalyticLine, self).unlink()
|
||||
so_lines.with_context(force_so_lines=so_lines).sudo()._compute_analytic()
|
||||
return res
|
||||
|
||||
@@ -124,6 +124,11 @@ class Inventory(models.Model):
|
||||
if self.filter == 'product':
|
||||
self.exhausted = True
|
||||
|
||||
@api.onchange('location_id')
|
||||
def onchange_location_id(self):
|
||||
if self.location_id.company_id:
|
||||
self.company_id = self.location_id.company_id
|
||||
|
||||
@api.one
|
||||
@api.constrains('filter', 'product_id', 'lot_id', 'partner_id', 'package_id')
|
||||
def _check_filter_product(self):
|
||||
@@ -204,6 +209,11 @@ class Inventory(models.Model):
|
||||
# Empty recordset of products to filter
|
||||
products_to_filter = self.env['product.product']
|
||||
|
||||
# case 0: Filter on company
|
||||
if self.company_id:
|
||||
domain += ' AND company_id = %s'
|
||||
args += (self.company_id.id,)
|
||||
|
||||
#case 1: Filter on One owner only or One product for a specific owner
|
||||
if self.partner_id:
|
||||
domain += ' AND owner_id = %s'
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Stock Location" decoration-info="usage=='view'" decoration-danger="usage=='internal'">
|
||||
<field name="active" invisible="1"/>
|
||||
<field name="complete_name"/>
|
||||
<field name="display_name"/>
|
||||
<field name="usage"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</tree>
|
||||
@@ -287,4 +287,4 @@
|
||||
<menuitem action="action_routes_form" id="menu_stock_routes"
|
||||
parent="stock.menu_routes_config" sequence="1" />
|
||||
|
||||
</odoo>
|
||||
</odoo>
|
||||
|
||||
@@ -38,13 +38,21 @@ class AccountInvoice(models.Model):
|
||||
cacc = accounts['expense'].id
|
||||
if dacc and cacc:
|
||||
price_unit = i_line._get_anglo_saxon_price_unit()
|
||||
if inv.currency_id.id != company_currency:
|
||||
currency_id = inv.currency_id.id
|
||||
amount_currency = i_line._get_price(company_currency, price_unit)
|
||||
else:
|
||||
currency_id = False
|
||||
amount_currency = False
|
||||
return [
|
||||
{
|
||||
'type': 'src',
|
||||
'name': i_line.name[:64],
|
||||
'price_unit': price_unit,
|
||||
'quantity': i_line.quantity,
|
||||
'price': i_line._get_price(company_currency, price_unit),
|
||||
'price': price_unit * i_line.quantity,
|
||||
'currency_id': currency_id,
|
||||
'amount_currency': amount_currency,
|
||||
'account_id':dacc,
|
||||
'product_id':i_line.product_id.id,
|
||||
'uom_id':i_line.uom_id.id,
|
||||
@@ -57,7 +65,9 @@ class AccountInvoice(models.Model):
|
||||
'name': i_line.name[:64],
|
||||
'price_unit': price_unit,
|
||||
'quantity': i_line.quantity,
|
||||
'price': -1 * i_line._get_price(company_currency, price_unit),
|
||||
'price': -1 * price_unit * i_line.quantity,
|
||||
'currency_id': currency_id,
|
||||
'amount_currency': -1 * amount_currency,
|
||||
'account_id':cacc,
|
||||
'product_id':i_line.product_id.id,
|
||||
'uom_id':i_line.uom_id.id,
|
||||
|
||||
@@ -295,7 +295,9 @@ var ImageDialog = Widget.extend({
|
||||
self.display_attachments();
|
||||
});
|
||||
this.fetch_existing().then(function () {
|
||||
self.set_image(_.find(self.records, function (record) { return record.url === o.url;}) || o);
|
||||
if (o.url) {
|
||||
self.set_image(_.find(self.records, function (record) { return record.url === o.url;}) || o);
|
||||
}
|
||||
});
|
||||
return res;
|
||||
},
|
||||
|
||||
@@ -371,7 +371,8 @@ class PageConverter(werkzeug.routing.PathConverter):
|
||||
query = query and query.startswith('website.') and query[8:] or query
|
||||
if query:
|
||||
domain += [('key', 'like', query)]
|
||||
domain += ['|', ('website_id', '=', request.website.id), ('website_id', '=', False)]
|
||||
website_id = request.context.get('website_id') or request.registry['website'].search(cr, uid, [], limit=1)[0]
|
||||
domain += ['|', ('website_id', '=', website_id), ('website_id', '=', False)]
|
||||
|
||||
views = View.search_read(domain, fields=['key', 'priority', 'write_date'], order='name')
|
||||
for view in views:
|
||||
|
||||
@@ -526,6 +526,7 @@ class Website(models.Model):
|
||||
of the same.
|
||||
:rtype: list({name: str, url: str})
|
||||
"""
|
||||
request.context = dict(request.context, **context)
|
||||
router = request.httprequest.app.get_db_router(request.db)
|
||||
# Force enumeration to be performed as public user
|
||||
url_set = set()
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
</div>
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="subtitle"/>
|
||||
</group>
|
||||
</sheet>
|
||||
<div class="oe_chatter">
|
||||
|
||||
@@ -343,7 +343,7 @@ class Website(models.Model):
|
||||
else:
|
||||
salesperson_id = request.website.salesperson_id.id
|
||||
addr = partner.address_get(['delivery', 'invoice'])
|
||||
sale_order = self.env['sale.order'].sudo().create({
|
||||
so_data = {
|
||||
'partner_id': partner.id,
|
||||
'pricelist_id': pricelist_id,
|
||||
'payment_term_id': self.sale_get_payment_term(partner),
|
||||
@@ -351,7 +351,12 @@ class Website(models.Model):
|
||||
'partner_invoice_id': addr['invoice'],
|
||||
'partner_shipping_id': addr['delivery'],
|
||||
'user_id': salesperson_id or self.salesperson_id.id,
|
||||
})
|
||||
}
|
||||
company = self.company_id or self.env['product.pricelist'].browse(pricelist_id).sudo().company_id
|
||||
if company:
|
||||
so_data['company_id'] = company.id
|
||||
|
||||
sale_order = self.env['sale.order'].sudo().create(so_data)
|
||||
|
||||
# set fiscal position
|
||||
if request.website.partner_id.id != partner.id:
|
||||
|
||||
@@ -262,9 +262,12 @@ odoo.define('website_sale.website_sale', function (require) {
|
||||
}
|
||||
|
||||
$(oe_website_sale).on('change', 'input.js_product_change', function () {
|
||||
var self = this;
|
||||
var $parent = $(this).closest('.js_product');
|
||||
$parent.find(".oe_default_price:first .oe_currency_value").html( price_to_str(+$(this).data('lst_price')) );
|
||||
$parent.find(".oe_price:first .oe_currency_value").html(price_to_str(+$(this).data('price')) );
|
||||
$.when(base.ready()).then(function() {
|
||||
$parent.find(".oe_default_price:first .oe_currency_value").html( price_to_str(+$(self).data('lst_price')) );
|
||||
$parent.find(".oe_price:first .oe_currency_value").html(price_to_str(+$(self).data('price')) );
|
||||
});
|
||||
update_product_image(this, +$(this).val());
|
||||
});
|
||||
|
||||
@@ -286,8 +289,10 @@ odoo.define('website_sale.website_sale', function (require) {
|
||||
var product_id = false;
|
||||
for (var k in variant_ids) {
|
||||
if (_.isEmpty(_.difference(variant_ids[k][1], values))) {
|
||||
$price.html(price_to_str(variant_ids[k][2]));
|
||||
$default_price.html(price_to_str(variant_ids[k][3]));
|
||||
$.when(base.ready()).then(function() {
|
||||
$price.html(price_to_str(variant_ids[k][2]));
|
||||
$default_price.html(price_to_str(variant_ids[k][3]));
|
||||
});
|
||||
if (variant_ids[k][3]-variant_ids[k][2]>0.01) {
|
||||
$default_price.closest('.oe_website_sale').addClass("discount");
|
||||
$optional_price.closest('.oe_optional').show().css('text-decoration', 'line-through');
|
||||
|
||||
@@ -41,7 +41,7 @@ $('.oe_website_sale #add_to_cart, .oe_website_sale #products_grid .a-submit')
|
||||
data: {lang: base.get_context().lang},
|
||||
success: function (quantity) {
|
||||
if (!$a.hasClass('js_goto_shop')) {
|
||||
window.location.href = window.location.href.replace(/shop([\/?].*)?$/, "shop/cart");
|
||||
window.location.pathname = window.location.pathname.replace(/shop([\/?].*)?$/, "shop/cart");
|
||||
}
|
||||
var $q = $(".my_cart_quantity");
|
||||
$q.parent().parent().removeClass("hidden", !quantity);
|
||||
|
||||
@@ -29,3 +29,5 @@ Ferdinand Gassauer ferdinand.gassauer@camptocamp.com https://github.com/ferdiga
|
||||
Jean-Baptiste Aubort jean-baptiste.aubort@camptocamp.com
|
||||
Cyril Gaudin cyril.gaudin@camptocamp.com https://github.com/cyrilgdn
|
||||
Denis Leemann denis.leemann@camptocamp.com https://github.com/leemannd
|
||||
Akim Juillerat akim.juillerat@camptocamp.com https://github.com/grindtildeath
|
||||
Damien Crier damien.crier@camptocamp.com https://github.com/damdam-s
|
||||
|
||||
@@ -16,5 +16,6 @@ List of contributors:
|
||||
- Stéphane Le Cornec stephane.lecornec@gmail.com https://github.com/coleste
|
||||
- Eric Lemire elemire@users.noreply.github.com https://github.com/elemire
|
||||
- Martin Malorni mmalorni@gmail.com https://github.com/mmalorni
|
||||
- Gregory Savoie gs.microcom@gmail.com https://github.com/gregsavoie
|
||||
- Samuel Chamberland sc.microcom@gmail.com https://github.com/sc-microcom
|
||||
- Noreddine Ben Jillali nbj.microcom@gmail.com https://github.com/nbj-microcom
|
||||
- Rim Ben Dhaou rbd.microcom@gmail.com https://github.com/rbd-microcom
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
United States, 2016-03-28
|
||||
|
||||
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,
|
||||
|
||||
César Castillo ceaucari@gmail.com https://github.com/ceaucari
|
||||
@@ -0,0 +1,11 @@
|
||||
Ecuador, 2016-10-02
|
||||
|
||||
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,
|
||||
|
||||
Daniel A. Mendieta P. damendieta@gmail.com https://github.com/damendieta
|
||||
@@ -0,0 +1,11 @@
|
||||
Taiwan, 2016-08-09
|
||||
|
||||
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,
|
||||
|
||||
JasonWu Tingyuan Wu jaronemo@msn.com https://github.com/jaronemo
|
||||
@@ -0,0 +1,11 @@
|
||||
Spain, 2016-04-15
|
||||
|
||||
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,
|
||||
|
||||
Javier Colmenero Fernández javierjcf@gmail.com https://github.com/javierjcf
|
||||
@@ -0,0 +1,11 @@
|
||||
Ecuador, 2016-12-13
|
||||
|
||||
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,
|
||||
|
||||
Juan Cristobal Lopez Arrieta juancristobal@gmail.com https://github.com/jclopezar
|
||||
@@ -0,0 +1,11 @@
|
||||
Algeria, 2016-08-11
|
||||
|
||||
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,
|
||||
|
||||
Noureddine LOUAHEDJ n.louahedj@gmail.com https://github.com/noureddineme
|
||||
@@ -0,0 +1,11 @@
|
||||
Cuba, 2016-12-01
|
||||
|
||||
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,
|
||||
|
||||
Rigoberto Martínez rigo1985@gmail.com https://github.com/rigo1985
|
||||
@@ -0,0 +1,11 @@
|
||||
China, 20160118
|
||||
|
||||
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,
|
||||
|
||||
LIN Yu yu_lin@me.com https://github.com/uynil
|
||||
Reference in New Issue
Block a user