[MERGE] forward port of branch saas-6 up to 63e92cb
This commit is contained in:
@@ -10,6 +10,8 @@ recursive-include openerp *.jpg
|
||||
recursive-include openerp *.js
|
||||
recursive-include openerp *.less
|
||||
recursive-include openerp *.md
|
||||
recursive-include openerp *.mp3
|
||||
recursive-include openerp *.ogg
|
||||
recursive-include openerp *.png
|
||||
recursive-include openerp *.po
|
||||
recursive-include openerp *.rml
|
||||
|
||||
@@ -57,6 +57,7 @@ You could use this simplified accounting in case you work with an (external) acc
|
||||
"static/src/xml/account_reconciliation.xml",
|
||||
"static/src/xml/account_payment.xml",
|
||||
"static/src/xml/account_report_backend.xml",
|
||||
'test/analytic_hierarchy.yml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
|
||||
@@ -738,7 +738,9 @@ class AccountInvoice(models.Model):
|
||||
ctx['company_id'] = inv.company_id.id
|
||||
ctx['dont_create_taxes'] = True
|
||||
ctx['invoice_id'] = inv.move_name and inv or False
|
||||
move = account_move.with_context(ctx).create(move_vals)
|
||||
ctx_nolang = ctx.copy()
|
||||
ctx_nolang.pop('lang', None)
|
||||
move = account_move.with_context(ctx_nolang).create(move_vals)
|
||||
# make the invoice point to that move
|
||||
vals = {
|
||||
'move_id': move.id,
|
||||
|
||||
@@ -177,13 +177,15 @@ class AccountMove(models.Model):
|
||||
def assert_balanced(self):
|
||||
if not self.ids:
|
||||
return True
|
||||
prec = self.env['decimal.precision'].precision_get('Account')
|
||||
|
||||
self._cr.execute("""\
|
||||
SELECT move_id
|
||||
FROM account_move_line
|
||||
WHERE move_id in %s
|
||||
GROUP BY move_id
|
||||
HAVING abs(sum(debit) - sum(credit)) > 0.00001
|
||||
""", (tuple(self.ids),))
|
||||
HAVING abs(sum(debit) - sum(credit)) > %s
|
||||
""", (tuple(self.ids), 10 ** (-max(5, prec))))
|
||||
if len(self._cr.fetchall()) != 0:
|
||||
raise UserError(_("Cannot create unbalanced journal entry."))
|
||||
return True
|
||||
@@ -1086,7 +1088,7 @@ class AccountMoveLine(models.Model):
|
||||
'journal_id': self.journal_id.analytic_journal_id.id,
|
||||
'ref': self.ref,
|
||||
'move_id': self.id,
|
||||
'user_id': self._uid,
|
||||
'user_id': self.invoice_id.user_id.id or self._uid,
|
||||
}
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
-
|
||||
We create a simple hierarchy like this
|
||||
Toplevel view account
|
||||
├ Real analytic account 1
|
||||
└ Real analytic account 2
|
||||
-
|
||||
!record {model: account.analytic.account, id: analytic_account_view1}:
|
||||
name: 'Toplevel view account'
|
||||
type: 'view'
|
||||
-
|
||||
!record {model: account.analytic.account, id: analytic_account1}:
|
||||
name: 'Real analytic account 1'
|
||||
type: 'normal'
|
||||
parent_id: analytic_account_view1
|
||||
-
|
||||
!record {model: account.analytic.account, id: analytic_account2}:
|
||||
name: 'Real analytic account 2'
|
||||
type: 'normal'
|
||||
parent_id: analytic_account_view1
|
||||
-
|
||||
We add analytic lines in real accounts and journal
|
||||
-
|
||||
!record {model: account.analytic.journal, id: analytic_journal1}:
|
||||
name: 'Analytic journal'
|
||||
-
|
||||
!record {model: account.analytic.line, id: analytic_line1}:
|
||||
name: 'Analytic line 1'
|
||||
account_id: analytic_account1
|
||||
journal_id: analytic_journal1
|
||||
general_account_id: account.a_expense
|
||||
-
|
||||
!record {model: account.analytic.line, id: analytic_line2}:
|
||||
name: 'Analytic line 2'
|
||||
account_id: analytic_account2
|
||||
journal_id: analytic_journal1
|
||||
general_account_id: account.a_expense
|
||||
-
|
||||
Now we copy the toplevel account
|
||||
-
|
||||
!function {model: account.analytic.account, name: copy, id: analytic_account_view1}:
|
||||
- eval: "ref('analytic_account_view1')"
|
||||
-
|
||||
!python {model: account.analytic.account}: |
|
||||
# the toplevel account has been copied with the (copy) suffix
|
||||
accounts = self.search(cr, uid, [('name', 'like', '%Toplevel view account%')])
|
||||
assert len(accounts) == 2, 'The toplevel account has not been copied'
|
||||
accounts = self.search(cr, uid, [('name', '=', 'Toplevel view account')])
|
||||
assert len(accounts) == 1, 'The toplevel account copy has a bad name'
|
||||
# the sub-accounts and sub-accounts have been copied without the (copy) suffix
|
||||
accounts = self.search(cr, uid, [('name', '=', 'Real analytic account 1')])
|
||||
assert len(accounts) == 2, 'The sub-account has not been copied'
|
||||
accounts = self.search(cr, uid, [('name', '=', 'Real analytic account 2')])
|
||||
assert len(accounts) == 2, 'The sub-account has not been copied'
|
||||
# the analytic lines should not be duplicated
|
||||
lines = self.pool.get('account.analytic.line').search(cr, uid, [('name', 'like', '%Analytic line %')])
|
||||
assert len(lines) == 2, "The analytic lines shouldn't have been copied"
|
||||
@@ -19,19 +19,17 @@ class AccountTestUsers(AccountingTestCase):
|
||||
self.account_type_model = self.env['account.account.type']
|
||||
self.currency_euro = self.env.ref('base.EUR')
|
||||
|
||||
self.account_user = self.res_user_model.create(dict(
|
||||
self.account_user = self.res_user_model.with_context({'no_reset_password': True}).create(dict(
|
||||
name="Accountant",
|
||||
company_id=self.main_company.id,
|
||||
login="acc",
|
||||
password="acc",
|
||||
email="accountuser@yourcompany.com",
|
||||
groups_id=[(6, 0, [res_users_account_user.id, partner_manager.id])]
|
||||
))
|
||||
self.account_manager = self.res_user_model.create(dict(
|
||||
self.account_manager = self.res_user_model.with_context({'no_reset_password': True}).create(dict(
|
||||
name="Adviser",
|
||||
company_id=self.main_company.id,
|
||||
login="fm",
|
||||
password="fm",
|
||||
email="accountmanager@yourcompany.com",
|
||||
groups_id=[(6, 0, [res_users_account_manager.id, partner_manager.id])]
|
||||
))
|
||||
|
||||
@@ -684,6 +684,28 @@ class account_analytic_account(osv.osv):
|
||||
}
|
||||
return invoice
|
||||
|
||||
def _prepare_invoice_line(self, cr, uid, line, fiscal_position, context=None):
|
||||
fpos_obj = self.pool.get('account.fiscal.position')
|
||||
res = line.product_id
|
||||
account_id = res.property_account_income_id.id
|
||||
if not account_id:
|
||||
account_id = res.categ_id.property_account_income_categ_id.id
|
||||
account_id = fpos_obj.map_account(cr, uid, fiscal_position, account_id)
|
||||
|
||||
taxes = res.taxes_id or False
|
||||
tax_id = fpos_obj.map_tax(cr, uid, fiscal_position, taxes)
|
||||
values = {
|
||||
'name': line.name,
|
||||
'account_id': account_id,
|
||||
'account_analytic_id': line.analytic_account_id.id,
|
||||
'price_unit': line.price_unit or 0.0,
|
||||
'quantity': line.quantity,
|
||||
'uos_id': line.uom_id.id or False,
|
||||
'product_id': line.product_id.id or False,
|
||||
'invoice_line_tax_ids': [(6, 0, tax_id)],
|
||||
}
|
||||
return values
|
||||
|
||||
def _prepare_invoice_lines(self, cr, uid, contract, fiscal_position_id, context=None):
|
||||
fpos_obj = self.pool.get('account.fiscal.position')
|
||||
fiscal_position = None
|
||||
@@ -691,26 +713,8 @@ class account_analytic_account(osv.osv):
|
||||
fiscal_position = fpos_obj.browse(cr, uid, fiscal_position_id, context=context)
|
||||
invoice_lines = []
|
||||
for line in contract.recurring_invoice_line_ids:
|
||||
|
||||
res = line.product_id
|
||||
account_id = res.property_account_income_id.id
|
||||
if not account_id:
|
||||
account_id = res.categ_id.property_account_income_categ_id.id
|
||||
account_id = fpos_obj.map_account(cr, uid, fiscal_position, account_id)
|
||||
|
||||
taxes = res.taxes_id or False
|
||||
tax_id = fpos_obj.map_tax(cr, uid, fiscal_position, taxes)
|
||||
|
||||
invoice_lines.append((0, 0, {
|
||||
'name': line.name,
|
||||
'account_id': account_id,
|
||||
'account_analytic_id': contract.id,
|
||||
'price_unit': line.price_unit or 0.0,
|
||||
'quantity': line.quantity,
|
||||
'uos_id': line.uom_id.id or False,
|
||||
'product_id': line.product_id.id or False,
|
||||
'invoice_line_tax_ids': [(6, 0, tax_id)],
|
||||
}))
|
||||
values = self._prepare_invoice_line(cr, uid, line, fiscal_position, context=context)
|
||||
invoice_lines.append((0, 0, values))
|
||||
return invoice_lines
|
||||
|
||||
def _prepare_invoice(self, cr, uid, contract, context=None):
|
||||
|
||||
@@ -99,10 +99,12 @@ class crossovered_budget_lines(osv.osv):
|
||||
result = 0.0
|
||||
if context is None:
|
||||
context = {}
|
||||
account_obj = self.pool.get('account.account')
|
||||
for line in self.browse(cr, uid, ids, context=context):
|
||||
acc_ids = [x.id for x in line.general_budget_id.account_ids]
|
||||
if not acc_ids:
|
||||
raise UserError(_("The Budget '%s' has no accounts!") % ustr(line.general_budget_id.name))
|
||||
acc_ids = account_obj._get_children_and_consol(cr, uid, acc_ids, context=context)
|
||||
date_to = line.date_to
|
||||
date_from = line.date_from
|
||||
if line.analytic_account_id.id:
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: Voucher Accountant
|
||||
login: vacc
|
||||
password: acc
|
||||
email: accountant@yourcompany.com
|
||||
-
|
||||
I added groups to Accountant for account voucher.
|
||||
@@ -21,7 +20,6 @@
|
||||
company_id: base.main_company
|
||||
name: Financial Manager for voucher
|
||||
login: fmv
|
||||
password: fmv
|
||||
email: finmanager@yourcompany.com
|
||||
-
|
||||
I added groups to Financial Manager for account voucher.
|
||||
|
||||
@@ -168,9 +168,9 @@ class account_analytic_account(osv.osv):
|
||||
'template_id': fields.many2one('account.analytic.account', 'Template of Contract'),
|
||||
'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'),
|
||||
'child_ids': fields.one2many('account.analytic.account', 'parent_id', 'Child Accounts', copy=True),
|
||||
'child_complete_ids': fields.function(_child_compute, relation='account.analytic.account', string="Account Hierarchy", type='many2many'),
|
||||
'line_ids': fields.one2many('account.analytic.line', 'account_id', 'Analytic Entries'),
|
||||
'line_ids': fields.one2many('account.analytic.line', 'account_id', 'Analytic Entries', copy=False),
|
||||
'balance': fields.function(_debit_credit_bal_qtty, type='float', string='Balance', multi='debit_credit_bal_qtty', digits=0),
|
||||
'debit': fields.function(_debit_credit_bal_qtty, type='float', string='Debit', multi='debit_credit_bal_qtty', digits=0),
|
||||
'credit': fields.function(_debit_credit_bal_qtty, type='float', string='Credit', multi='debit_credit_bal_qtty', digits=0),
|
||||
@@ -263,6 +263,8 @@ class account_analytic_account(osv.osv):
|
||||
raise UserError(_("Quick account creation disallowed."))
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
""" executed only on the toplevel copied object of the hierarchy.
|
||||
Subobject are actually copied with copy_data"""
|
||||
if not default:
|
||||
default = {}
|
||||
analytic = self.browse(cr, uid, id, context=context)
|
||||
@@ -299,9 +301,12 @@ class account_analytic_account(osv.osv):
|
||||
dom = []
|
||||
for name2 in name.split('/'):
|
||||
name = name2.strip()
|
||||
account_ids = self.search(cr, uid, dom + [('name', operator, name)] + args, limit=limit, context=context)
|
||||
account_ids = self.search(cr, uid, dom + [('name', operator, name)], limit=limit, context=context)
|
||||
if not account_ids: break
|
||||
dom = [('parent_id','in',account_ids)]
|
||||
if account_ids and args:
|
||||
# final filtering according to domain (args)
|
||||
account_ids = self.search(cr, uid, [('id', 'in', account_ids)] + args, limit=limit, context=context)
|
||||
else:
|
||||
account_ids = self.search(cr, uid, args, limit=limit, context=context)
|
||||
return self.name_get(cr, uid, account_ids, context=context)
|
||||
|
||||
@@ -123,7 +123,8 @@ class CompanyLDAP(osv.osv):
|
||||
try:
|
||||
conn = self.connect(conf)
|
||||
ldap_password = conf['ldap_password'] or ''
|
||||
conn.simple_bind_s(conf['ldap_binddn'] or '', ldap_password.encode('utf-8'))
|
||||
ldap_binddn = conf['ldap_binddn'] or ''
|
||||
conn.simple_bind_s(ldap_binddn.encode('utf-8'), ldap_password.encode('utf-8'))
|
||||
results = conn.search_st(conf['ldap_base'], ldap.SCOPE_SUBTREE,
|
||||
filter, retrieve_attributes, timeout=60)
|
||||
conn.unbind()
|
||||
|
||||
@@ -46,6 +46,20 @@ class res_users(osv.Model):
|
||||
validation.update(data)
|
||||
return validation
|
||||
|
||||
def _generate_signup_values(self, cr, uid, provider, validation, params, context=None):
|
||||
oauth_uid = validation['user_id']
|
||||
email = validation.get('email', 'provider_%s_user_%s' % (provider, oauth_uid))
|
||||
name = validation.get('name', email)
|
||||
return {
|
||||
'name': name,
|
||||
'login': email,
|
||||
'email': email,
|
||||
'oauth_provider_id': provider,
|
||||
'oauth_uid': oauth_uid,
|
||||
'oauth_access_token': params['access_token'],
|
||||
'active': True,
|
||||
}
|
||||
|
||||
def _auth_oauth_signin(self, cr, uid, provider, validation, params, context=None):
|
||||
""" retrieve and sign in the user corresponding to provider and validated access token
|
||||
:param provider: oauth provider id (int)
|
||||
@@ -70,18 +84,7 @@ class res_users(osv.Model):
|
||||
return None
|
||||
state = simplejson.loads(params['state'])
|
||||
token = state.get('t')
|
||||
oauth_uid = validation['user_id']
|
||||
email = validation.get('email', 'provider_%s_user_%s' % (provider, oauth_uid))
|
||||
name = validation.get('name', email)
|
||||
values = {
|
||||
'name': name,
|
||||
'login': email,
|
||||
'email': email,
|
||||
'oauth_provider_id': provider,
|
||||
'oauth_uid': oauth_uid,
|
||||
'oauth_access_token': params['access_token'],
|
||||
'active': True,
|
||||
}
|
||||
values = self._generate_signup_values(cr, uid, provider, validation, params, context=context)
|
||||
try:
|
||||
_, login, _ = self.signup(cr, uid, values, token, context=context)
|
||||
return login
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
<record id="default_template_user" model="res.users">
|
||||
<field name="name">Template User</field>
|
||||
<field name="login">portaltemplate</field>
|
||||
<!-- No password: this template user doesn't need to log in -->
|
||||
<field name="password"></field>
|
||||
<field name="active" eval="False"/>
|
||||
<!-- Avoid auto-including this user in any default group, just like a typical portal member -->
|
||||
<field name="groups_id" eval="[(6, 0, [ref('base.group_portal')])]"/>
|
||||
|
||||
@@ -247,7 +247,7 @@ class res_users(osv.Model):
|
||||
if not user_ids:
|
||||
user_ids = self.search(cr, uid, [('email', '=', login)], context=context)
|
||||
if len(user_ids) != 1:
|
||||
raise Exception('Reset password: invalid username or email')
|
||||
raise Exception(_('Reset password: invalid username or email'))
|
||||
return self.action_reset_password(cr, uid, user_ids, context=context)
|
||||
|
||||
def action_reset_password(self, cr, uid, ids, context=None):
|
||||
|
||||
@@ -118,7 +118,7 @@ var BarcodeParser = Class.extend({
|
||||
// - value: the numerical value encoded in the barcode (0 if no value encoded)
|
||||
// - base_code: the barcode in which numerical content is replaced by 0's
|
||||
// - match: boolean
|
||||
match_pattern: function (barcode, pattern){
|
||||
match_pattern: function (barcode, pattern, encoding){
|
||||
var match = {
|
||||
value: 0,
|
||||
base_code: barcode,
|
||||
@@ -156,6 +156,16 @@ var BarcodeParser = Class.extend({
|
||||
.replace("\{", "{")
|
||||
.replace("\}","}")
|
||||
.replace("\.",".");
|
||||
|
||||
var base_code = match.base_code.split('')
|
||||
if (encoding === 'ean13') {
|
||||
base_code[12] = '' + this.ean_checksum(match.base_code);
|
||||
} else if (encoding === 'ean8') {
|
||||
base_code[7] = '' + this.ean8_checksum(match.base_code);
|
||||
} else if (encoding === 'upca') {
|
||||
base_code[11] = '' + this.ean_checksum('0' + match.base_code);
|
||||
}
|
||||
match.base_code = base_code.join('')
|
||||
}
|
||||
|
||||
if (base_pattern[0] !== '^') {
|
||||
@@ -208,7 +218,7 @@ var BarcodeParser = Class.extend({
|
||||
continue;
|
||||
}
|
||||
|
||||
var match = this.match_pattern(cur_barcode,rules[i].pattern);
|
||||
var match = this.match_pattern(cur_barcode, rules[i].pattern, rule.encoding);
|
||||
if (match.match) {
|
||||
if(rules[i].type === 'alias') {
|
||||
barcode = rules[i].alias;
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from collections import defaultdict
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import time
|
||||
import logging
|
||||
|
||||
@@ -16,11 +17,11 @@ from openerp.tools.safe_eval import safe_eval as eval
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
DATE_RANGE_FUNCTION = {
|
||||
'minutes': lambda interval: timedelta(minutes=interval),
|
||||
'hour': lambda interval: timedelta(hours=interval),
|
||||
'day': lambda interval: timedelta(days=interval),
|
||||
'month': lambda interval: timedelta(months=interval),
|
||||
False: lambda interval: timedelta(0),
|
||||
'minutes': lambda interval: relativedelta(minutes=interval),
|
||||
'hour': lambda interval: relativedelta(hours=interval),
|
||||
'day': lambda interval: relativedelta(days=interval),
|
||||
'month': lambda interval: relativedelta(months=interval),
|
||||
False: lambda interval: relativedelta(0),
|
||||
}
|
||||
|
||||
def get_datetime(date_str):
|
||||
|
||||
@@ -96,7 +96,7 @@ class calendar_attendee(osv.Model):
|
||||
'email': fields.char('Email', help="Email of Invited Person"),
|
||||
'availability': fields.selection([('free', 'Free'), ('busy', 'Busy')], 'Free/Busy', readonly="True"),
|
||||
'access_token': fields.char('Invitation Token'),
|
||||
'event_id': fields.many2one('calendar.event', 'Meeting linked'),
|
||||
'event_id': fields.many2one('calendar.event', 'Meeting linked', ondelete='cascade'),
|
||||
}
|
||||
_defaults = {
|
||||
'state': 'needsAction',
|
||||
@@ -1674,12 +1674,6 @@ class calendar_event(osv.Model):
|
||||
virtual_id = context.get('virtual_id', True)
|
||||
context.update({'virtual_id': False})
|
||||
res = super(calendar_event, self).read_group(cr, uid, domain, fields, groupby, offset=offset, limit=limit, context=context, orderby=orderby, lazy=lazy)
|
||||
for result in res:
|
||||
#remove the count, since the value is not consistent with the result of the search when expand the group
|
||||
for groupname in groupby:
|
||||
if result.get(groupname + "_count"):
|
||||
del result[groupname + "_count"]
|
||||
result.get('__context', {}).update({'virtual_id': virtual_id})
|
||||
return res
|
||||
|
||||
def read(self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
|
||||
|
||||
@@ -86,6 +86,9 @@
|
||||
type='object'
|
||||
attrs="{'invisible': [('state', 'in', ('option', 'finished' ))]}"
|
||||
/>
|
||||
<button name='next_cb' string='Skip these contacts'
|
||||
type='object' class='oe_link'
|
||||
attrs="{'invisible': [('state', '!=', 'selection')]}" />
|
||||
<button name='start_process_cb'
|
||||
string='Merge with Manual Check'
|
||||
type='object' class='oe_highlight'
|
||||
|
||||
@@ -269,9 +269,10 @@ class crm_lead(format_address, osv.osv):
|
||||
values = {}
|
||||
if partner_id:
|
||||
partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
|
||||
partner_name = (partner.parent_id and partner.parent_id.name) or (partner.is_company and partner.name) or False
|
||||
values = {
|
||||
'partner_name': partner.parent_id.name if partner.parent_id else partner.name,
|
||||
'contact_name': partner.name if partner.parent_id else False,
|
||||
'partner_name': partner_name,
|
||||
'contact_name': (not partner.is_company and partner.name) or False,
|
||||
'title': partner.title and partner.title.id or False,
|
||||
'street': partner.street,
|
||||
'street2': partner.street2,
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: Crm Sales manager
|
||||
login: csm
|
||||
password: csm
|
||||
email: crmmanager@yourcompany.com
|
||||
-
|
||||
I added groups for Crm Salesmanager.
|
||||
@@ -20,7 +19,6 @@
|
||||
company_id: base.main_company
|
||||
name: Crm Salesman
|
||||
login: csu
|
||||
password: csu
|
||||
email: crmuser@yourcompany.com
|
||||
-
|
||||
I added groups for Crm Salesman.
|
||||
|
||||
@@ -4,22 +4,18 @@
|
||||
!record {model: res.users, id: test_res_user_01}:
|
||||
name: 'Test user A'
|
||||
login: 'tua@example.com'
|
||||
new_password: 'tua'
|
||||
-
|
||||
!record {model: res.users, id: test_res_user_02}:
|
||||
name: 'Test user B'
|
||||
login: 'tub@example.com'
|
||||
new_password: 'tub'
|
||||
-
|
||||
!record {model: res.users, id: test_res_user_03}:
|
||||
name: 'Test user C'
|
||||
login: 'tuc@example.com'
|
||||
new_password: 'tuc'
|
||||
-
|
||||
!record {model: res.users, id: test_res_user_04}:
|
||||
name: 'Test user D'
|
||||
login: 'tud@example.com'
|
||||
new_password: 'tud'
|
||||
-
|
||||
Salesman also creates lead so giving access rights of salesman.
|
||||
-
|
||||
|
||||
@@ -98,12 +98,11 @@ class delivery_carrier(osv.osv):
|
||||
|
||||
# not using advanced pricing per destination: override grid
|
||||
grid_id = grid_pool.search(cr, uid, [('carrier_id', '=', record.id)], context=context)
|
||||
if grid_id and not (record.normal_price or record.free_if_more_than):
|
||||
if grid_id and not (record.normal_price is not False or record.free_if_more_than):
|
||||
grid_pool.unlink(cr, uid, grid_id, context=context)
|
||||
grid_id = None
|
||||
|
||||
# Check that float, else 0.0 is False
|
||||
if not (isinstance(record.normal_price,float) or record.free_if_more_than):
|
||||
if not (record.normal_price is not False or record.free_if_more_than):
|
||||
continue
|
||||
|
||||
if not grid_id:
|
||||
@@ -130,7 +129,7 @@ class delivery_carrier(osv.osv):
|
||||
'list_base_price': 0.0,
|
||||
}
|
||||
grid_line_pool.create(cr, uid, line_data, context=context)
|
||||
if isinstance(record.normal_price,float):
|
||||
if record.normal_price is not False:
|
||||
line_data = {
|
||||
'grid_id': grid_id and grid_id[0],
|
||||
'name': _('Default price'),
|
||||
|
||||
@@ -49,6 +49,7 @@ class sale_order(osv.Model):
|
||||
acc_fp_obj = self.pool.get('account.fiscal.position')
|
||||
self._delivery_unset(cr, uid, ids, context=context)
|
||||
currency_obj = self.pool.get('res.currency')
|
||||
line_ids = []
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
grid_id = carrier_obj.grid_get(cr, uid, [order.carrier_id.id], order.partner_shipping_id.id)
|
||||
if not grid_id:
|
||||
@@ -67,7 +68,7 @@ class sale_order(osv.Model):
|
||||
price_unit = currency_obj.compute(cr, uid, order.company_id.currency_id.id, order.pricelist_id.currency_id.id,
|
||||
price_unit, context=dict(context or {}, date=order.date_order))
|
||||
#create the sale order line
|
||||
line_obj.create(cr, uid, {
|
||||
line_id = line_obj.create(cr, uid, {
|
||||
'order_id': order.id,
|
||||
'name': grid.carrier_id.name,
|
||||
'product_uom_qty': 1,
|
||||
@@ -77,3 +78,5 @@ class sale_order(osv.Model):
|
||||
'tax_id': [(6, 0, taxes_ids)],
|
||||
'is_delivery': True
|
||||
}, context=context)
|
||||
line_ids.append(line_id)
|
||||
return line_ids
|
||||
|
||||
@@ -6,6 +6,7 @@ access_delivery_carrier_manager,delivery.carrier,model_delivery_carrier,base.gro
|
||||
access_delivery_grid_manager,delivery.grid,model_delivery_grid,base.group_sale_manager,1,1,1,1
|
||||
access_delivery_grid_line_manager,delivery.grid.line,model_delivery_grid_line,base.group_sale_manager,1,1,1,1
|
||||
access_delivery_carrier_partner_manager,delivery.carrier partner_manager,model_delivery_carrier,base.group_partner_manager,1,0,0,0
|
||||
access_delivery_carrier_stock_user,delivery.carrier stock_user,model_delivery_carrier,stock.group_stock_user,1,0,0,0
|
||||
access_delivery_carrier_stock_manager,delivery.carrier,model_delivery_carrier,stock.group_stock_manager,1,1,1,1
|
||||
access_delivery_grid_stock_manager,delivery.grid,model_delivery_grid,stock.group_stock_manager,1,1,1,1
|
||||
access_delivery_grid_line_stock_manager,delivery.grid.line,model_delivery_grid_line,stock.group_stock_manager,1,1,1,1
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="event_registration_mail_template_badge" model="mail.template">
|
||||
<field name="name">Event: Registration Badge</field>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: Event manager
|
||||
login: em
|
||||
password: em
|
||||
email: eventmanager@yourcompany.com
|
||||
-
|
||||
I added groups for Event manager.
|
||||
@@ -20,7 +19,6 @@
|
||||
company_id: base.main_company
|
||||
name: User
|
||||
login: eu
|
||||
password: eu
|
||||
email: eventuser@yourcompany.com
|
||||
-
|
||||
I added groups for Event user.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import logging
|
||||
import poplib
|
||||
import time
|
||||
from imaplib import IMAP4
|
||||
from imaplib import IMAP4_SSL
|
||||
@@ -24,6 +25,9 @@ from openerp.exceptions import UserError
|
||||
_logger = logging.getLogger(__name__)
|
||||
MAX_POP_MESSAGES = 50
|
||||
|
||||
# Workaround for Python 2.7.8 bug https://bugs.python.org/issue23906
|
||||
poplib._MAXLINE = 65536
|
||||
|
||||
class fetchmail_server(osv.osv):
|
||||
"""Incoming POP/IMAP mail server account"""
|
||||
_name = 'fetchmail.server'
|
||||
|
||||
@@ -198,6 +198,8 @@ class google_calendar(osv.AbstractModel):
|
||||
_name = 'google.%s' % STR_SERVICE
|
||||
|
||||
def generate_data(self, cr, uid, event, isCreating=False, context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
if event.allday:
|
||||
start_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.start, tools.DEFAULT_SERVER_DATETIME_FORMAT), context=context).isoformat('T').split('T')[0]
|
||||
final_date = fields.datetime.context_timestamp(cr, uid, datetime.strptime(event.start, tools.DEFAULT_SERVER_DATETIME_FORMAT) + timedelta(hours=event.duration) + timedelta(days=isCreating and 1 or 0), context=context).isoformat('T').split('T')[0]
|
||||
@@ -222,19 +224,18 @@ class google_calendar(osv.AbstractModel):
|
||||
"method": "email" if alarm.type == "email" else "popup",
|
||||
"minutes": alarm.duration_minutes
|
||||
})
|
||||
|
||||
data = {
|
||||
"summary": event.name or '',
|
||||
"description": event.description or '',
|
||||
"start": {
|
||||
type: start_date,
|
||||
vstype: None,
|
||||
'timeZone': 'UTC'
|
||||
'timeZone': context.get('tz', 'UTC'),
|
||||
},
|
||||
"end": {
|
||||
type: final_date,
|
||||
vstype: None,
|
||||
'timeZone': 'UTC'
|
||||
'timeZone': context.get('tz', 'UTC'),
|
||||
},
|
||||
"attendees": attendee_list,
|
||||
"reminders": {
|
||||
@@ -360,7 +361,7 @@ class google_calendar(osv.AbstractModel):
|
||||
|
||||
url = "/calendar/v3/calendars/%s/events/%s?fields=%s&access_token=%s" % ('primary', google_event['id'], 'id,updated', self.get_token(cr, uid, context))
|
||||
headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
|
||||
data = self.generate_data(cr, uid, oe_event, context)
|
||||
data = self.generate_data(cr, uid, oe_event, context=context)
|
||||
data['sequence'] = google_event.get('sequence', 0)
|
||||
data_json = simplejson.dumps(data)
|
||||
|
||||
@@ -416,9 +417,10 @@ class google_calendar(osv.AbstractModel):
|
||||
|
||||
if self.get_need_synchro_attendee(cr, uid, context=context):
|
||||
for google_attendee in single_event_dict.get('attendees', []):
|
||||
partner_email = google_attendee.get('email', False)
|
||||
if type == "write":
|
||||
for oe_attendee in event['attendee_ids']:
|
||||
if oe_attendee.email == google_attendee['email']:
|
||||
if oe_attendee.email == partner_email:
|
||||
calendar_attendee_obj.write(cr, uid, [oe_attendee.id], {'state': google_attendee['responseStatus'], 'google_internal_event_id': single_event_dict.get('id')}, context=context)
|
||||
google_attendee['found'] = True
|
||||
continue
|
||||
@@ -426,12 +428,12 @@ class google_calendar(osv.AbstractModel):
|
||||
if google_attendee.get('found'):
|
||||
continue
|
||||
|
||||
attendee_id = res_partner_obj.search(cr, uid, [('email', '=', google_attendee['email'])], context=context)
|
||||
attendee_id = res_partner_obj.search(cr, uid, [('email', '=', partner_email)], context=context)
|
||||
if not attendee_id:
|
||||
data = {
|
||||
'email': google_attendee['email'],
|
||||
'email': partner_email,
|
||||
'customer': False,
|
||||
'name': google_attendee.get("displayName", False) or google_attendee['email']
|
||||
'name': google_attendee.get("displayName", False) or partner_email
|
||||
}
|
||||
attendee_id = [res_partner_obj.create(cr, uid, data, context=context)]
|
||||
attendee = res_partner_obj.read(cr, uid, attendee_id[0], ['email'], context=context)
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<record id="google_spreadsheet_template" model="google.drive.config">
|
||||
<field name="name">Base Spreadsheet Template</field>
|
||||
<field name="model_id" ref="base.model_res_partner"/>
|
||||
<field name="google_drive_template_url">https://docs.google.com/spreadsheet/ccc?key=0ApGVjjwUC-ygdDZ0TG5EQnRlLVFQNlFGdFN5b1ZrY1E</field>
|
||||
<field name="google_drive_template_url">https://docs.google.com/spreadsheet/ccc?key=1KUlSSzZMzkEEzyroyZ2NerRt1RVCspkG9VQIh2V6dnM</field>
|
||||
<field name="name_template">Reporting %(name)s</field>
|
||||
<field name="active" eval="0" />
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
</openerp>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: HR manager
|
||||
login: hrm
|
||||
password: hrm
|
||||
-
|
||||
I added groups for HR Manager.
|
||||
-
|
||||
@@ -19,7 +18,6 @@
|
||||
company_id: base.main_company
|
||||
name: HR Officer
|
||||
login: hro
|
||||
password: hro
|
||||
email: hro@example.com
|
||||
-
|
||||
I added groups for HR Officer.
|
||||
@@ -34,7 +32,6 @@
|
||||
company_id: base.main_company
|
||||
name: Employee
|
||||
login: emp
|
||||
password: emp
|
||||
-
|
||||
I added groups for Employee.
|
||||
-
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: HR Officer
|
||||
login: ao
|
||||
password: ao
|
||||
-
|
||||
I added groups for HR Attendance Officer.
|
||||
-
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
<field name="product_id" on_change="onchange_product_id(product_id, context)" context="{'default_hr_expense_ok':1}"/>
|
||||
<field name="name"/>
|
||||
<field name="ref"/>
|
||||
<field domain="[('type','=','normal')]" name="analytic_account" groups="analytic.group_analytic_accounting"/>
|
||||
<field domain="[('type','in',['normal','contract'])]" name="analytic_account" groups="analytic.group_analytic_accounting"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="unit_amount"/>
|
||||
|
||||
@@ -13,7 +13,7 @@ class hr_grant_badge_wizard(osv.TransientModel):
|
||||
'employee_id': fields.many2one("hr.employee", string='Employee', required=True),
|
||||
'user_id': fields.related("employee_id", "user_id",
|
||||
type="many2one", relation="res.users",
|
||||
store=True, string='User', required=True)
|
||||
store=True, string='User')
|
||||
}
|
||||
|
||||
def action_grant_badge(self, cr, uid, ids, context=None):
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: HR Recruitment Officer
|
||||
login: hrro
|
||||
password: hrro
|
||||
email: hrofcr@yourcompany.com
|
||||
-
|
||||
I added groups for HR Recruitment Officer.
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: HR timesheet manager
|
||||
login: hrtm
|
||||
password: hrtm
|
||||
-
|
||||
I added groups for HR timesheet Manager.
|
||||
-
|
||||
@@ -19,7 +18,6 @@
|
||||
company_id: base.main_company
|
||||
name: HR timesheet Officer
|
||||
login: hrto
|
||||
password: hrto
|
||||
-
|
||||
I added groups for HR timesheet Officer.
|
||||
-
|
||||
@@ -33,7 +31,6 @@
|
||||
company_id: base.main_company
|
||||
name: Timesheet Employee
|
||||
login: empt
|
||||
password: empt
|
||||
-
|
||||
I added groups for Timesheet Employee.
|
||||
-
|
||||
|
||||
@@ -158,7 +158,7 @@ class account_analytic_line(osv.osv):
|
||||
unit_price = total_price*-1.0 / total_qty
|
||||
|
||||
factor = self.pool['hr_timesheet_invoice.factor'].browse(cr, uid, factor_id, context=uom_context)
|
||||
factor_name = factor.customer_name
|
||||
factor_name = factor.customer_name or ''
|
||||
curr_invoice_line = {
|
||||
'price_unit': unit_price,
|
||||
'quantity': total_qty,
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
</page>
|
||||
<page string="Details">
|
||||
<field context="{'employee_id': employee_id, 'user_id':user_id, 'timesheet_date_from': date_from, 'timesheet_date_to': date_to, 'default_is_timesheet' : 1}" name="timesheet_ids" nolabel="1">
|
||||
<tree editable="top" string="Timesheet Activities">
|
||||
<tree editable="bottom" string="Timesheet Activities">
|
||||
<field name="date"/>
|
||||
<field domain="[('type','in',['normal', 'contract']), ('state', '!=', 'close'),('invoice_on_timesheets','=',1)]" name="account_id" on_change="on_change_account_id(account_id, user_id, unit_amount, is_timesheet, context)" options="{'no_open': True, 'no_create': True}" context="{'default_use_timesheets': 1}"/>
|
||||
<field name="name"/>
|
||||
|
||||
@@ -55,7 +55,7 @@ class hr_timesheet_report(osv.osv):
|
||||
htss.state"""
|
||||
|
||||
def _from(self):
|
||||
return super(hr_timesheet_report, self)._from() + "left join hr_timesheet_sheet_sheet as htss ON (aal.sheet_id=htss.id) join totals as t on (t.sheet_id = aal.sheet_id and t.date = aal.date)"
|
||||
return super(hr_timesheet_report, self)._from() + "left join hr_timesheet_sheet_sheet as htss ON (aal.sheet_id=htss.id) left join totals as t on (t.sheet_id = aal.sheet_id and t.date = aal.date)"
|
||||
|
||||
def _group_by(self):
|
||||
return super(hr_timesheet_report, self)._group_by() + """,
|
||||
|
||||
@@ -75,6 +75,7 @@ TXT_ENC_PC861 = '\x1b\x74\x23' # PC861 Icelandic
|
||||
TXT_ENC_PC862 = '\x1b\x74\x24' # PC862 Hebrew
|
||||
TXT_ENC_PC864 = '\x1b\x74\x25' # PC864 Arabic
|
||||
TXT_ENC_PC869 = '\x1b\x74\x26' # PC869 Greek
|
||||
TXT_ENC_PC936 = '\x1C\x21\x00' # PC936 GBK(Guobiao Kuozhan)
|
||||
TXT_ENC_8859_2 = '\x1b\x74\x27' # ISO8859-2 Latin2
|
||||
TXT_ENC_8859_9 = '\x1b\x74\x28' # ISO8859-2 Latin9
|
||||
TXT_ENC_PC1098 = '\x1b\x74\x29' # PC1098 Farsi
|
||||
|
||||
@@ -748,6 +748,7 @@ class Escpos:
|
||||
'cp866': TXT_ENC_PC866,
|
||||
'cp862': TXT_ENC_PC862,
|
||||
'cp720': TXT_ENC_PC720,
|
||||
'cp936': TXT_ENC_PC936,
|
||||
'iso8859_2': TXT_ENC_8859_2,
|
||||
'iso8859_7': TXT_ENC_8859_7,
|
||||
'iso8859_9': TXT_ENC_8859_9,
|
||||
|
||||
@@ -514,6 +514,7 @@
|
||||
<field name="user_type_id" ref="account.data_account_type_payable"/>
|
||||
<field name="chart_template_id" ref="l10nbe_chart_template"/>
|
||||
<field eval="True" name="reconcile"/>
|
||||
<field name="financial_report_ids" eval="[(4,ref('account_financial_report_fournisseurs4'))]"/>
|
||||
</record>
|
||||
<record id="a446" model="account.account.template">
|
||||
<field name="name">Acomptes reçus</field>
|
||||
@@ -521,6 +522,7 @@
|
||||
<field name="user_type_id" ref="account.data_account_type_payable"/>
|
||||
<field name="chart_template_id" ref="l10nbe_chart_template"/>
|
||||
<field eval="True" name="reconcile"/>
|
||||
<field name="financial_report_ids" eval="[(4,ref('account_financial_report_fournisseurs4'))]"/>
|
||||
</record>
|
||||
<record id="a448" model="account.account.template">
|
||||
<field name="name">Compensations fournisseurs</field>
|
||||
@@ -528,6 +530,7 @@
|
||||
<field name="user_type_id" ref="account.data_account_type_payable"/>
|
||||
<field name="chart_template_id" ref="l10nbe_chart_template"/>
|
||||
<field eval="True" name="reconcile"/>
|
||||
<field name="financial_report_ids" eval="[(4,ref('account_financial_report_fournisseurs4'))]"/>
|
||||
</record>
|
||||
<record id="a4500" model="account.account.template">
|
||||
<field name="name">Dettes fiscales estimées</field>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# TVA - Taxe sur la Valeur Ajoutée
|
||||
-->
|
||||
<record model="account.tax.template" id="vat_25">
|
||||
<field name="name">TVA due a 2.5% (TR)</field>
|
||||
<field name="name">TVA due a 2.5%</field>
|
||||
<field name="description">2.5%</field>
|
||||
<field name="amount" eval="0.025"/>
|
||||
<field name="type">percent</field>
|
||||
@@ -14,8 +14,27 @@
|
||||
<field name="account_paid_id" ref="ch_coa_2200"/>
|
||||
<field name="type_tax_use">sale</field>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_25_ttc">
|
||||
<field name="name">TVA due a 2.5% TTC</field>
|
||||
<field name="description">2.5% TTC</field>
|
||||
<field name="price_include" eval="1"/>
|
||||
<field name="amount" eval="0.025"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="base_code_id" ref="vat_code_due_25"/>
|
||||
<field name="tax_code_id" ref="vat_code_due_tva25"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_due_25"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_due_tva25"/>
|
||||
<field name="base_sign" eval="1.0"/>
|
||||
<field name="tax_sign" eval="1.0"/>
|
||||
<field name="ref_base_sign" eval="-1.0"/>
|
||||
<field name="ref_tax_sign" eval="-1.0"/>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
<field name="account_collected_id" ref="ch_coa_2200"/>
|
||||
<field name="account_paid_id" ref="ch_coa_2200"/>
|
||||
<field name="type_tax_use">sale</field>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_25_purchase">
|
||||
<field name="name">TVA 2.5% sur achat B&S (TR)</field>
|
||||
<field name="name">TVA 2.5% sur achats, biens et services</field>
|
||||
<field name="description">2.5% achat</field>
|
||||
<field name="amount" eval="0.025"/>
|
||||
<field name="type">percent</field>
|
||||
@@ -25,9 +44,30 @@
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="ch_coa_1170"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1170"/>
|
||||
</record>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_25_purchase_ttc">
|
||||
<field name="name">TVA 2.5% sur achats, biens et services TTC</field>
|
||||
<field name="description">2.5% achat TTC</field>
|
||||
<field name="price_include" eval="1"/>
|
||||
<field name="amount" eval="0.025"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="base_code_id" ref="vat_code_receivable_base_25"/>
|
||||
<field name="tax_code_id" ref="vat_code_payable_bs"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_receivable_base_25"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_payable_bs"/>
|
||||
<field name="python_compute">result = round((price_unit * 0.025) / 0.05) * 0.05</field>
|
||||
<field name="python_compute_inv">result = round((price_unit * ( 1 - (1 / 1.025))) /0.05) * 0.05</field>
|
||||
<field name="base_sign" eval="-1.0"/>
|
||||
<field name="tax_sign" eval="-1.0"/>
|
||||
<field name="ref_base_sign" eval="1.0"/>
|
||||
<field name="ref_tax_sign" eval="1.0"/>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="ch_coa_1170"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1170"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_25_invest">
|
||||
<field name="name">TVA 2.5% sur invest. et autres ch. (TR)</field>
|
||||
<field name="name">TVA 2.5% sur invest. et autres ch.</field>
|
||||
<field name="description">2.5% invest.</field>
|
||||
<field name="amount" eval="0.025"/>
|
||||
<field name="type">percent</field>
|
||||
@@ -38,9 +78,29 @@
|
||||
<field name="account_collected_id" ref="ch_coa_1171"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1171"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.template" id="vat_25_invest_ttc">
|
||||
<field name="name">TVA 2.5% sur invest. et autres ch. TTC</field>
|
||||
<field name="description">2.5% invest.TTC</field>
|
||||
<field name="price_include" eval="1"/>
|
||||
<field name="amount" eval="0.025"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="base_code_id" ref="vat_code_receivable_base_invest25"/>
|
||||
<field name="tax_code_id" ref="vat_code_payable_invest"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_receivable_base_invest25"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_payable_invest"/>
|
||||
<field name="python_compute">result = round((price_unit * 0.025) / 0.05) * 0.05</field>
|
||||
<field name="python_compute_inv">result = round((price_unit * ( 1 - (1 / 1.025))) /0.05) * 0.05</field>
|
||||
<field name="base_sign" eval="-1.0"/>
|
||||
<field name="tax_sign" eval="-1.0"/>
|
||||
<field name="ref_base_sign" eval="1.0"/>
|
||||
<field name="ref_tax_sign" eval="1.0"/>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="ch_coa_1171"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1171"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_38">
|
||||
<field name="name">TVA due a 3.8% (TS)</field>
|
||||
<field name="name">TVA due a 3.8%</field>
|
||||
<field name="description">3.8%</field>
|
||||
<field name="amount" eval="0.038"/>
|
||||
<field name="type">percent</field>
|
||||
@@ -51,8 +111,29 @@
|
||||
<field name="account_collected_id" ref="ch_coa_2200"/>
|
||||
<field name="account_paid_id" ref="ch_coa_2200"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_38_ttc">
|
||||
<field name="name">TVA due a 3.8% TTC</field>
|
||||
<field name="description">3.8% TTC</field>
|
||||
<field name="price_include" eval="1"/>
|
||||
<field name="amount" eval="0.038"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="base_code_id" ref="vat_code_due_38"/>
|
||||
<field name="tax_code_id" ref="vat_code_due_tva38"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_due_38"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_due_tva38"/>
|
||||
<field name="python_compute">result = round((price_unit * 0.038) / 0.05) * 0.05</field>
|
||||
<field name="python_compute_inv">result = round((price_unit * ( 1 - (1 / 1.038))) /0.05) * 0.05</field>
|
||||
<field name="base_sign" eval="1.0"/>
|
||||
<field name="tax_sign" eval="1.0"/>
|
||||
<field name="ref_base_sign" eval="-1.0"/>
|
||||
<field name="ref_tax_sign" eval="-1.0"/>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="account_collected_id" ref="ch_coa_2200"/>
|
||||
<field name="account_paid_id" ref="ch_coa_2200"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_38_purchase">
|
||||
<field name="name">TVA 3.8% sur achat B&S (TS)</field>
|
||||
<field name="name">TVA 3.8% sur achats, biens et services</field>
|
||||
<field name="description">3.8% achat</field>
|
||||
<field name="amount" eval="0.038"/>
|
||||
<field name="type">percent</field>
|
||||
@@ -63,8 +144,29 @@
|
||||
<field name="account_collected_id" ref="ch_coa_1170"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1170"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_38_purchase_ttc">
|
||||
<field name="name">TVA 3.8% sur achats, biens et services TTC</field>
|
||||
<field name="description">3.8% achat TTC</field>
|
||||
<field name="price_include" eval="1"/>
|
||||
<field name="amount" eval="0.038"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="base_code_id" ref="vat_code_receivable_base_38"/>
|
||||
<field name="tax_code_id" ref="vat_code_payable_bs"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_receivable_base_38"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_payable_bs"/>
|
||||
<field name="python_compute">result = round((price_unit * 0.038) / 0.05) * 0.05</field>
|
||||
<field name="python_compute_inv">result = round((price_unit * ( 1 - (1 / 1.038))) /0.05) * 0.05</field>
|
||||
<field name="base_sign" eval="-1.0"/>
|
||||
<field name="tax_sign" eval="-1.0"/>
|
||||
<field name="ref_base_sign" eval="1.0"/>
|
||||
<field name="ref_tax_sign" eval="1.0"/>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="ch_coa_1170"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1170"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_38_invest">
|
||||
<field name="name">TVA 3.8% sur invest. et autres ch. (TS)</field>
|
||||
<field name="name">TVA 3.8% sur invest. et autres ch.</field>
|
||||
<field name="description">3.8% invest</field>
|
||||
<field name="amount" eval="0.038"/>
|
||||
<field name="type">percent</field>
|
||||
@@ -75,8 +177,29 @@
|
||||
<field name="account_collected_id" ref="ch_coa_1171"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1171"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_38_invest_ttc">
|
||||
<field name="name">TVA 3.8% sur invest. et autres ch. TTC</field>
|
||||
<field name="description">3.8% invest TTC</field>
|
||||
<field name="price_include" eval="1"/>
|
||||
<field name="amount" eval="0.038"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="base_code_id" ref="vat_code_receivable_base_invest38"/>
|
||||
<field name="tax_code_id" ref="vat_code_payable_invest"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_receivable_base_invest38"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_payable_invest"/>
|
||||
<field name="python_compute">result = round((price_unit * 0.038) / 0.05) * 0.05</field>
|
||||
<field name="python_compute_inv">result = round((price_unit * ( 1 - (1 / 1.038))) /0.05) * 0.05</field>
|
||||
<field name="base_sign" eval="-1.0"/>
|
||||
<field name="tax_sign" eval="-1.0"/>
|
||||
<field name="ref_base_sign" eval="1.0"/>
|
||||
<field name="ref_tax_sign" eval="1.0"/>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="ch_coa_1171"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1171"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_80">
|
||||
<field name="name">TVA due a 8.0% (TN)</field>
|
||||
<field name="name">TVA due a 8.0%</field>
|
||||
<field name="description">8.0%</field>
|
||||
<field name="amount" eval="0.080"/>
|
||||
<field name="sequence" eval="0"/>
|
||||
@@ -89,7 +212,7 @@
|
||||
<field name="account_paid_id" ref="ch_coa_2200"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_80_purchase">
|
||||
<field name="name">TVA 8.0% sur achat B&S (TN)</field>
|
||||
<field name="name">TVA 8.0% sur achats, biens et services</field>
|
||||
<field name="description">8.0% achat</field>
|
||||
<field name="amount" eval="0.080"/>
|
||||
<field name="type">percent</field>
|
||||
@@ -100,9 +223,52 @@
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="ch_coa_1170"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1170"/>
|
||||
</record>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_80_ttc">
|
||||
<field name="name">TVA due a 8.0% TTC</field>
|
||||
<field name="description">8.0% TTC</field>
|
||||
<field name="price_include" eval="1"/>
|
||||
<field name="amount" eval="0.080"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="base_code_id" ref="vat_code_due_80"/>
|
||||
<field name="tax_code_id" ref="vat_code_due_tva80"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_due_80"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_due_tva80"/>
|
||||
<field name="python_compute">result = round((price_unit * 0.080) / 0.05) * 0.05</field>
|
||||
<field name="python_compute_inv">result = round((price_unit * ( 1 - (1 / 1.080))) /0.05) * 0.05</field>
|
||||
<field name="base_sign" eval="1.0"/>
|
||||
<field name="tax_sign" eval="1.0"/>
|
||||
<field name="ref_base_sign" eval="-1.0"/>
|
||||
<field name="ref_tax_sign" eval="-1.0"/>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="account_collected_id" ref="ch_coa_2200"/>
|
||||
<field name="account_paid_id" ref="ch_coa_2200"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_80_purchase_ttc">
|
||||
<field name="name">TVA 8.0% sur achats, biens et services TTC</field>
|
||||
<field name="description">8.0% achat TTC</field>
|
||||
<field name="price_include" eval="1"/>
|
||||
<field name="amount" eval="0.080"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="base_code_id" ref="vat_code_receivable_base_80"/>
|
||||
<field name="tax_code_id" ref="vat_code_payable_bs"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_receivable_base_80"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_payable_bs"/>
|
||||
<field name="python_compute">result = round((price_unit * 0.080) / 0.05) * 0.05</field>
|
||||
<field name="python_compute_inv">result = round((price_unit * ( 1 - (1 / 1.080))) /0.05) * 0.05</field>
|
||||
<field name="base_sign" eval="-1.0"/>
|
||||
<field name="tax_sign" eval="-1.0"/>
|
||||
<field name="ref_base_sign" eval="1.0"/>
|
||||
<field name="ref_tax_sign" eval="1.0"/>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="ch_coa_1170"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1170"/>
|
||||
</record>
|
||||
|
||||
<record model="account.tax.template" id="vat_80_invest">
|
||||
<field name="name">TVA 8.0% sur invest. et autres ch. (TN)</field>
|
||||
<field name="name">TVA 8.0% sur invest. et autres ch.</field>
|
||||
<field name="description">8.0% invest.</field>
|
||||
<field name="amount" eval="0.080"/>
|
||||
<field name="type">percent</field>
|
||||
@@ -113,6 +279,27 @@
|
||||
<field name="account_collected_id" ref="ch_coa_1171"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1171"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_80_invest_ttc">
|
||||
<field name="name">TVA 8.0% sur invest. et autres ch.TTC</field>
|
||||
<field name="description">8.0% invest.TTC</field>
|
||||
<field name="price_include" eval="1"/>
|
||||
<field name="amount" eval="0.080"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="base_code_id" ref="vat_code_receivable_base_invest80"/>
|
||||
<field name="tax_code_id" ref="vat_code_payable_invest"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_receivable_base_invest80"/>
|
||||
<field name="ref_tax_code_id" ref="vat_code_payable_invest"/>
|
||||
<field name="python_compute">result = round((price_unit * 0.080) / 0.05) * 0.05</field>
|
||||
<field name="python_compute_inv">result = round((price_unit * ( 1 - (1 / 1.080))) /0.05) * 0.05</field>
|
||||
<field name="base_sign" eval="-1.0"/>
|
||||
<field name="tax_sign" eval="-1.0"/>
|
||||
<field name="ref_base_sign" eval="1.0"/>
|
||||
<field name="ref_tax_sign" eval="1.0"/>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="ch_coa_1171"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1171"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_XO">
|
||||
<field name="name">TVA due a 0% (Exportations)</field>
|
||||
<field name="amount" eval="0.00"/>
|
||||
@@ -124,8 +311,8 @@
|
||||
<field name="account_paid_id" ref="ch_coa_2200"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_O_exclude">
|
||||
<field name="name">TVA 0% exclue</field>
|
||||
<field name="description">0% excl.</field>
|
||||
<field name="name">TVA exclue/ventes</field>
|
||||
<field name="description">exclue</field>
|
||||
<field name="amount" eval="0.00"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
@@ -133,8 +320,24 @@
|
||||
<field name="account_collected_id" ref="ch_coa_2200"/>
|
||||
<field name="account_paid_id" ref="ch_coa_2200"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_O_exclude_purch">
|
||||
<field name="name">TVA exclue/achats</field>
|
||||
<field name="description">0% excl.ach.</field>
|
||||
<field name="amount" eval="0.00"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="base_code_id" ref="vat_code_receivable_base_excl"/>
|
||||
<field name="ref_base_code_id" ref="vat_code_receivable_base_excl"/>
|
||||
<field name="base_sign" eval="-1.0"/>
|
||||
<field name="tax_sign" eval="-1.0"/>
|
||||
<field name="ref_base_sign" eval="1.0"/>
|
||||
<field name="ref_tax_sign" eval="1.0"/>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="ch_coa_1170"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1170"/>
|
||||
</record>
|
||||
<record model="account.tax.template" id="vat_O_import">
|
||||
<field name="name">TVA 0% Importations de biens et services</field>
|
||||
<field name="name">TVA 0% Importations</field>
|
||||
<field name="description">0% import.</field>
|
||||
<field name="amount" eval="0.00"/>
|
||||
<field name="type">percent</field>
|
||||
@@ -145,8 +348,8 @@
|
||||
</record>
|
||||
<!--# 100% on import !! the tax percentage is 00-->
|
||||
<record model="account.tax.template" id="vat_100_import">
|
||||
<field name="name">100% dédouanement TVA</field>
|
||||
<field name="description">100% imp.</field>
|
||||
<field name="name">100% dédouanement TVA sur invest. et autres ch.</field>
|
||||
<field name="description">100% imp.invest.</field>
|
||||
<field name="amount" eval="0.0"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
@@ -154,5 +357,16 @@
|
||||
<field name="account_collected_id" ref="ch_coa_1171"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1171"/>
|
||||
</record>
|
||||
<!--# 100% on import !! the tax percentage is 00-->
|
||||
<record model="account.tax.template" id="vat_100_import_abs8">
|
||||
<field name="name">100% dédouanement TVA sur achats, biens et services </field>
|
||||
<field name="description">100% imp.abs.</field>
|
||||
<field name="amount" eval="0.0"/>
|
||||
<field name="type">percent</field>
|
||||
<field name="chart_template_id" ref="l10nch_chart_template"/>
|
||||
<field name="type_tax_use">purchase</field>
|
||||
<field name="account_collected_id" ref="ch_coa_1170"/>
|
||||
<field name="account_paid_id" ref="ch_coa_1170"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
# @author - Fekete Mihai <feketemihai@gmail.com>
|
||||
# @author - Fekete Mihai <feketemihai@gmail.com>, Tatár Attila <atta@nvm.ro>
|
||||
# Copyright (C) 2015 Tatár Attila
|
||||
# Copyright (C) 2015 Forest and Biomass Services Romania (http://www.forbiom.eu).
|
||||
# Copyright (C) 2011 TOTAL PC SYSTEMS (http://www.erpsystems.ro).
|
||||
# Copyright (C) 2009 (<http://www.filsystem.ro>)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
# @author - Fekete Mihai <feketemihai@gmail.com>
|
||||
# @author - Fekete Mihai <feketemihai@gmail.com>, Tatár Attila <atta@nvm.ro>
|
||||
# Copyright (C) 2015 Tatár Attila
|
||||
# Copyright (C) 2015 Forest and Biomass Services Romania (http://www.forbiom.eu).
|
||||
# Copyright (C) 2011 TOTAL PC SYSTEMS (http://www.erpsystems.ro).
|
||||
# Copyright (C) 2009 (<http://www.filsystem.ro>)
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<data>
|
||||
<record model="ir.ui.view" id="res_partner_form_ro">
|
||||
<field name="name">res.partner.form.ro</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="inherit_id" ref="account.view_partner_property_form"/>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="arch" type="xml">
|
||||
<field name="property_account_position_id" position="after">
|
||||
|
||||
@@ -1,43 +1,43 @@
|
||||
"id","country_id/id","code","name"
|
||||
"RO_AB","base.ro","AB","Alba"
|
||||
"RO_AG","base.ro","AG","Argeș"
|
||||
"RO_AR","base.ro","AR","Arad"
|
||||
"RO_B","base.ro","B","București"
|
||||
"RO_BC","base.ro","BC","Bacău"
|
||||
"RO_BH","base.ro","BH","Bihor"
|
||||
"RO_BN","base.ro","BN","Bistrița-Năsăud"
|
||||
"RO_BR","base.ro","BR","Brăila"
|
||||
"RO_BT","base.ro","BT","Botoșani"
|
||||
"RO_BV","base.ro","BV","Brașov"
|
||||
"RO_BZ","base.ro","BZ","Buzău"
|
||||
"RO_CJ","base.ro","CJ","Cluj"
|
||||
"RO_CL","base.ro","CL","Călărași"
|
||||
"RO_CS","base.ro","CS","Caraș Severin"
|
||||
"RO_CT","base.ro","CT","Constanța"
|
||||
"RO_CV","base.ro","CV","Covasna"
|
||||
"RO_DB","base.ro","DB","Dâmbovița"
|
||||
"RO_DJ","base.ro","DJ","Dolj"
|
||||
"RO_GJ","base.ro","GJ","Gorj"
|
||||
"RO_GL","base.ro","GL","Galați"
|
||||
"RO_GR","base.ro","GR","Giurgiu"
|
||||
"RO_HD","base.ro","HD","Hunedoara"
|
||||
"RO_HR","base.ro","HR","Harghita"
|
||||
"RO_IF","base.ro","IF","Ilfov"
|
||||
"RO_IL","base.ro","IL","Ialomița"
|
||||
"RO_IS","base.ro","IS","Iași"
|
||||
"RO_MH","base.ro","MH","Mehedinți"
|
||||
"RO_MM","base.ro","MM","Maramureș"
|
||||
"RO_MS","base.ro","MS","Mureș"
|
||||
"RO_NT","base.ro","NT","Neamț"
|
||||
"RO_OT","base.ro","OT","Olt"
|
||||
"RO_PH","base.ro","PH","Prahova"
|
||||
"RO_SB","base.ro","SB","Sibiu"
|
||||
"RO_SJ","base.ro","SJ","Sălaj"
|
||||
"RO_SM","base.ro","SM","Satu Mare"
|
||||
"RO_SV","base.ro","SV","Suceava"
|
||||
"RO_TL","base.ro","TL","Tulcea"
|
||||
"RO_TM","base.ro","TM","Timiș"
|
||||
"RO_TR","base.ro","TR","Teleorman"
|
||||
"RO_VL","base.ro","VL","Vâlcea"
|
||||
"RO_VN","base.ro","VN","Vrancea"
|
||||
"RO_VS","base.ro","VS","Vaslui"
|
||||
"id","country_id/id","code","name"
|
||||
"RO_AB","base.ro","AB","Alba"
|
||||
"RO_AG","base.ro","AG","Argeș"
|
||||
"RO_AR","base.ro","AR","Arad"
|
||||
"RO_B","base.ro","B","București"
|
||||
"RO_BC","base.ro","BC","Bacău"
|
||||
"RO_BH","base.ro","BH","Bihor"
|
||||
"RO_BN","base.ro","BN","Bistrița-Năsăud"
|
||||
"RO_BR","base.ro","BR","Brăila"
|
||||
"RO_BT","base.ro","BT","Botoșani"
|
||||
"RO_BV","base.ro","BV","Brașov"
|
||||
"RO_BZ","base.ro","BZ","Buzău"
|
||||
"RO_CJ","base.ro","CJ","Cluj"
|
||||
"RO_CL","base.ro","CL","Călărași"
|
||||
"RO_CS","base.ro","CS","Caraș Severin"
|
||||
"RO_CT","base.ro","CT","Constanța"
|
||||
"RO_CV","base.ro","CV","Covasna"
|
||||
"RO_DB","base.ro","DB","Dâmbovița"
|
||||
"RO_DJ","base.ro","DJ","Dolj"
|
||||
"RO_GJ","base.ro","GJ","Gorj"
|
||||
"RO_GL","base.ro","GL","Galați"
|
||||
"RO_GR","base.ro","GR","Giurgiu"
|
||||
"RO_HD","base.ro","HD","Hunedoara"
|
||||
"RO_HR","base.ro","HR","Harghita"
|
||||
"RO_IF","base.ro","IF","Ilfov"
|
||||
"RO_IL","base.ro","IL","Ialomița"
|
||||
"RO_IS","base.ro","IS","Iași"
|
||||
"RO_MH","base.ro","MH","Mehedinți"
|
||||
"RO_MM","base.ro","MM","Maramureș"
|
||||
"RO_MS","base.ro","MS","Mureș"
|
||||
"RO_NT","base.ro","NT","Neamț"
|
||||
"RO_OT","base.ro","OT","Olt"
|
||||
"RO_PH","base.ro","PH","Prahova"
|
||||
"RO_SB","base.ro","SB","Sibiu"
|
||||
"RO_SJ","base.ro","SJ","Sălaj"
|
||||
"RO_SM","base.ro","SM","Satu Mare"
|
||||
"RO_SV","base.ro","SV","Suceava"
|
||||
"RO_TL","base.ro","TL","Tulcea"
|
||||
"RO_TM","base.ro","TM","Timiș"
|
||||
"RO_TR","base.ro","TR","Teleorman"
|
||||
"RO_VL","base.ro","VL","Vâlcea"
|
||||
"RO_VN","base.ro","VN","Vrancea"
|
||||
"RO_VS","base.ro","VS","Vaslui"
|
||||
|
||||
|
@@ -709,7 +709,7 @@ class MailThread(models.AbstractModel):
|
||||
if not message_dict.get('parent_id'):
|
||||
raise ValueError('Routing: posting a message without model should be with a parent_id (private mesage).')
|
||||
_warn('posting a message without model should be with a parent_id (private mesage), skipping')
|
||||
return ()
|
||||
return False
|
||||
|
||||
if model and thread_id:
|
||||
record_set = self.env[model].browse(thread_id)
|
||||
@@ -726,7 +726,7 @@ class MailThread(models.AbstractModel):
|
||||
assert record_set.exists(), 'Routing: reply to missing document (%s,%s)' % (model, thread_id)
|
||||
else:
|
||||
_warn('reply to missing document (%s,%s), skipping' % (model, thread_id))
|
||||
return ()
|
||||
return False
|
||||
|
||||
# Existing Document: check model accepts the mailgateway
|
||||
if thread_id and model and not hasattr(record_set, 'message_update'):
|
||||
@@ -737,7 +737,7 @@ class MailThread(models.AbstractModel):
|
||||
assert hasattr(record_set, 'message_update'), 'Routing: model %s does not accept document update, crashing' % model
|
||||
else:
|
||||
_warn('model %s does not accept document update, skipping' % model)
|
||||
return ()
|
||||
return False
|
||||
|
||||
# New Document: check model accepts the mailgateway
|
||||
if not thread_id and model and not hasattr(record_set, 'message_new'):
|
||||
@@ -747,7 +747,7 @@ class MailThread(models.AbstractModel):
|
||||
'Model %s does not accept document creation, crashing' % model
|
||||
)
|
||||
_warn('model %s does not accept document creation, skipping' % model)
|
||||
return ()
|
||||
return False
|
||||
|
||||
# Update message author if asked
|
||||
# We do it now because we need it for aliases (contact settings)
|
||||
@@ -766,16 +766,16 @@ class MailThread(models.AbstractModel):
|
||||
if not author_id or author_id not in [fol.id for fol in obj.message_follower_ids]:
|
||||
_warn('alias %s restricted to internal followers, skipping' % alias.alias_name)
|
||||
_create_bounce_email()
|
||||
return ()
|
||||
return False
|
||||
elif alias and alias.alias_contact == 'partners' and not author_id:
|
||||
_warn('alias %s does not accept unknown author, skipping' % alias.alias_name)
|
||||
_create_bounce_email()
|
||||
return ()
|
||||
return False
|
||||
|
||||
if not model and not thread_id and not alias and not allow_private:
|
||||
return ()
|
||||
|
||||
return (model, thread_id, route[2], route[3], route[4])
|
||||
return (model, thread_id, route[2], route[3], None if context.get('drop_alias', False) else route[4])
|
||||
|
||||
@api.model
|
||||
def message_route(self, message, message_dict, model=None, thread_id=None, custom_values=None):
|
||||
@@ -815,6 +815,7 @@ class MailThread(models.AbstractModel):
|
||||
if not isinstance(message, Message):
|
||||
raise TypeError('message must be an email.message.Message at this point')
|
||||
MailMessage = self.env['mail.message']
|
||||
Alias = self.env['mail.alias']
|
||||
fallback_model = model
|
||||
|
||||
# Get email.message.Message variables for future processing
|
||||
@@ -841,15 +842,19 @@ class MailThread(models.AbstractModel):
|
||||
mail_messages = MailMessage.sudo().search([('message_id', 'in', msg_references)], limit=1)
|
||||
if ref_match and mail_messages:
|
||||
model, thread_id = mail_messages.model, mail_messages.res_id
|
||||
alias = Alias.search(cr, uid, [('alias_name', '=', (tools.email_split(email_to) or [''])[0].split('@', 1)[0].lower())])
|
||||
alias = alias[0] if alias else None
|
||||
route = self.message_route_verify(
|
||||
message, message_dict,
|
||||
(model, thread_id, custom_values, self._uid, None),
|
||||
update_author=True, assert_model=False, create_fallback=True)
|
||||
(model, thread_id, custom_values, self._uid, alias),
|
||||
update_author=True, assert_model=False, create_fallback=True, context=dict(context, drop_alias=True))
|
||||
if route:
|
||||
_logger.info(
|
||||
'Routing mail from %s to %s with Message-Id %s: direct reply to msg: model: %s, thread_id: %s, custom_values: %s, uid: %s',
|
||||
email_from, email_to, message_id, model, thread_id, custom_values, self._uid)
|
||||
return [route]
|
||||
elif route is False:
|
||||
return []
|
||||
|
||||
# 2. message is a reply to an existign thread (6.1 compatibility)
|
||||
if ref_match:
|
||||
@@ -876,6 +881,8 @@ class MailThread(models.AbstractModel):
|
||||
'Routing mail from %s to %s with Message-Id %s: direct thread reply (compat-mode) to model: %s, thread_id: %s, custom_values: %s, uid: %s',
|
||||
email_from, email_to, message_id, model, thread_id, custom_values, self._uid)
|
||||
return [route]
|
||||
elif route is False:
|
||||
return []
|
||||
|
||||
# 3. Reply to a private message
|
||||
if in_reply_to:
|
||||
@@ -893,6 +900,8 @@ class MailThread(models.AbstractModel):
|
||||
'Routing mail from %s to %s with Message-Id %s: direct reply to a private message: %s, custom_values: %s, uid: %s',
|
||||
email_from, email_to, message_id, mail_message_ids.id, custom_values, self._uid)
|
||||
return [route]
|
||||
elif route is False:
|
||||
return []
|
||||
|
||||
# 4. Look for a matching mail.alias entry
|
||||
# Delivered-To is a safe bet in most modern MTAs, but we have to fallback on To + Cc values
|
||||
@@ -905,7 +914,6 @@ class MailThread(models.AbstractModel):
|
||||
decode_header(message, 'Resent-Cc')])
|
||||
local_parts = [e.split('@')[0] for e in tools.email_split(rcpt_tos)]
|
||||
if local_parts:
|
||||
Alias = self.env['mail.alias']
|
||||
aliases = Alias.search([('alias_name', 'in', local_parts)])
|
||||
if aliases:
|
||||
routes = []
|
||||
@@ -962,7 +970,7 @@ class MailThread(models.AbstractModel):
|
||||
# postpone setting message_dict.partner_ids after message_post, to avoid double notifications
|
||||
partner_ids = message_dict.pop('partner_ids', [])
|
||||
thread_id = False
|
||||
for model, thread_id, custom_values, user_id, alias in routes:
|
||||
for model, thread_id, custom_values, user_id, alias in routes or ():
|
||||
if model:
|
||||
Model = self.env[model]
|
||||
if not (thread_id and hasattr(Model, 'message_update') or hasattr(Model, 'message_new')):
|
||||
|
||||
@@ -1365,7 +1365,9 @@ var ComposeMessage = Attachment.extend ({
|
||||
target: 'new',
|
||||
context: context,
|
||||
};
|
||||
self.do_action(action);
|
||||
self.do_action(action, {
|
||||
'on_close': function(){ self.is_log && self.parent_thread.message_fetch() }
|
||||
});
|
||||
self.on_cancel();
|
||||
});
|
||||
},
|
||||
|
||||
@@ -194,7 +194,7 @@
|
||||
<t t-if="attachment.file_type_icon !== 'webimage'">
|
||||
<div t-attf-class="oe_attachment #{attachment.upload ? 'oe_uploading' : ''}">
|
||||
<a t-att-href='attachment.url' target="_blank">
|
||||
<img t-att-src="'/mail/static/src/img/mimetypes/' + attachment.file_type_icon + '.png'"></img>
|
||||
<img t-att-src="'/mail/static/src/img/mimetypes/' + (attachment.file_type_icon or 'unknown') + '.png'"></img>
|
||||
<div class='oe_name'><t t-raw='attachment.name' /></div>
|
||||
</a>
|
||||
<div class='oe_delete oe_e'>
|
||||
|
||||
@@ -25,6 +25,46 @@ class MassMailingTag(osv.Model):
|
||||
}
|
||||
|
||||
|
||||
class MassMailingList(osv.Model):
|
||||
"""Model of a contact list. """
|
||||
_name = 'mail.mass_mailing.list'
|
||||
_order = 'name'
|
||||
_description = 'Mailing List'
|
||||
|
||||
def _get_contact_nbr(self, cr, uid, ids, name, arg, context=None):
|
||||
result = dict.fromkeys(ids, 0)
|
||||
Contacts = self.pool.get('mail.mass_mailing.contact')
|
||||
for group in Contacts.read_group(cr, uid, [('list_id', 'in', ids), ('opt_out', '!=', True)], ['list_id'], ['list_id'], context=context):
|
||||
result[group['list_id'][0]] = group['list_id_count']
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Mailing List', required=True),
|
||||
'create_date': fields.datetime('Creation Date'),
|
||||
'contact_nbr': fields.function(
|
||||
_get_contact_nbr, type='integer',
|
||||
string='Number of Contacts',
|
||||
),
|
||||
'popup_content': fields.html("Website Popup Content", translate=True, required=True, sanitize=False),
|
||||
'popup_redirect_url': fields.char("Website Popup Redirect URL"),
|
||||
}
|
||||
|
||||
def _get_default_popup_content(self, cr, uid, context=None):
|
||||
return """<div class="o_popup_modal_header text-center">
|
||||
<h3 class="o_popup_modal_title mt8">Odoo Presents</h3>
|
||||
</div>
|
||||
<div class="o_popup_message">
|
||||
<font>7</font>
|
||||
<strong>Business Hacks</strong>
|
||||
<span> to<br/>boost your marketing</span>
|
||||
</div>
|
||||
<p class="o_message_paragraph">Join our Marketing newsletter and get <strong>this white paper instantly</strong></p>"""
|
||||
|
||||
_defaults = {
|
||||
'popup_content': _get_default_popup_content,
|
||||
}
|
||||
|
||||
|
||||
class MassMailingContact(osv.Model):
|
||||
"""Model of a contact. This model is different from the partner model
|
||||
because it holds only some basic information: name, email. The purpose is to
|
||||
@@ -105,46 +145,6 @@ class MassMailingContact(osv.Model):
|
||||
self.write(cr, uid, [obj.id], {'message_bounce': obj.message_bounce + 1}, context=context)
|
||||
|
||||
|
||||
class MassMailingList(osv.Model):
|
||||
"""Model of a contact list. """
|
||||
_name = 'mail.mass_mailing.list'
|
||||
_order = 'name'
|
||||
_description = 'Mailing List'
|
||||
|
||||
def _get_contact_nbr(self, cr, uid, ids, name, arg, context=None):
|
||||
result = dict.fromkeys(ids, 0)
|
||||
Contacts = self.pool.get('mail.mass_mailing.contact')
|
||||
for group in Contacts.read_group(cr, uid, [('list_id', 'in', ids), ('opt_out', '!=', True)], ['list_id'], ['list_id'], context=context):
|
||||
result[group['list_id'][0]] = group['list_id_count']
|
||||
return result
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Mailing List', required=True),
|
||||
'create_date': fields.datetime('Creation Date'),
|
||||
'contact_nbr': fields.function(
|
||||
_get_contact_nbr, type='integer',
|
||||
string='Number of Contacts',
|
||||
),
|
||||
'popup_content': fields.html("Website Popup Content", translate=True, required=True, sanitize=False),
|
||||
'popup_redirect_url': fields.char("Website Popup Redirect URL"),
|
||||
}
|
||||
|
||||
def _get_default_popup_content(self, cr, uid, context=None):
|
||||
return """<div class="o_popup_modal_header text-center">
|
||||
<h3 class="o_popup_modal_title mt8">Odoo Presents</h3>
|
||||
</div>
|
||||
<div class="o_popup_message">
|
||||
<font>7</font>
|
||||
<strong>Business Hacks</strong>
|
||||
<span> to<br/>boost your marketing</span>
|
||||
</div>
|
||||
<p class="o_message_paragraph">Join our Marketing newsletter and get <strong>this white paper instantly</strong></p>"""
|
||||
|
||||
_defaults = {
|
||||
'popup_content': _get_default_popup_content,
|
||||
}
|
||||
|
||||
|
||||
class MassMailingStage(osv.Model):
|
||||
"""Stage for mass mailing campaigns. """
|
||||
_name = 'mail.mass_mailing.stage'
|
||||
|
||||
@@ -26,17 +26,16 @@
|
||||
<field name="mail_mail_id_int"/>
|
||||
<field name="message_id"/>
|
||||
<field name="mass_mailing_id"/>
|
||||
<filter help="Sent" domain="[('sent', '!=', False)]"/>
|
||||
<filter help="Opened" domain="[('opened', '!=', False)]"/>
|
||||
<filter help="Replied" domain="[('replied', '!=', False)]"/>
|
||||
<filter help="Bounced" domain="[('bounced', '!=', False)]"/>
|
||||
<filter string="Received" name="filter_received" domain="[('sent', '!=', False), ('bounced', '=', False)]"/>
|
||||
<filter string="Opened" name="filter_opened" domain="[('opened', '!=', False)]"/>
|
||||
<filter string="Replied" name="filter_replied" domain="[('replied', '!=', False)]"/>
|
||||
<filter string="Bounced" name="filter_bounced" domain="[('bounced', '!=', False)]"/>
|
||||
<group expand="0" string="Group By">
|
||||
<filter string="State" domain="[]"
|
||||
context="{'group_by':'state'}"/>
|
||||
<filter string="Last State Update" domain="[]"
|
||||
context="{'group_by':'state_update'}"/>
|
||||
<filter string="Mass Mailing" domain="[]"
|
||||
context="{'group_by':'mass_mailing_id'}"/>
|
||||
<filter string="State" domain="[]" context="{'group_by':'state'}"/>
|
||||
<filter string="Open Date" name="group_open_date" context="{'group_by': 'opened:day'}"/>
|
||||
<filter string="Reply Date" name="group_reply_date" context="{'group_by': 'replied:day'}"/>
|
||||
<filter string="Last State Update" domain="[]" context="{'group_by':'state_update'}"/>
|
||||
<filter string="Mass Mailing" domain="[]" context="{'group_by':'mass_mailing_id'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
@@ -399,15 +398,18 @@
|
||||
<field name="sent" string="Emails Sent" widget="statinfo"/>
|
||||
</button>
|
||||
<button name="%(action_view_mail_mail_statistics_mailing)d"
|
||||
type="action" class="oe_stat_button">
|
||||
context="{'search_default_filter_received': True}"
|
||||
type="action" class="oe_stat_button">
|
||||
<field name="received_ratio" string="Received" widget="percentpie"/>
|
||||
</button>
|
||||
<button name="%(action_view_mail_mail_statistics_mailing)d"
|
||||
type="action" class="oe_stat_button">
|
||||
context="{'search_default_filter_opened': True}"
|
||||
type="action" class="oe_stat_button">
|
||||
<field name="opened_ratio" string="Opened" widget="percentpie"/>
|
||||
</button>
|
||||
<button name="%(action_view_mail_mail_statistics_mailing)d"
|
||||
type="action" class="oe_stat_button">
|
||||
context="{'search_default_filter_replied': True}"
|
||||
type="action" class="oe_stat_button">
|
||||
<field name="replied_ratio" string="Replied" widget="percentpie"/>
|
||||
</button>
|
||||
<button name="%(action_view_mass_mailing_links_statistics)d"
|
||||
@@ -415,6 +417,7 @@
|
||||
<field name="clicks_ratio" string="Clicks" widget="percentpie"/>
|
||||
</button>
|
||||
<button name="%(action_view_mail_mail_statistics_mailing)d"
|
||||
context="{'search_default_filter_bounced': True}"
|
||||
type="action" class="oe_stat_button">
|
||||
<field name="bounced_ratio" string="Bounced" widget="percentpie"/>
|
||||
</button>
|
||||
|
||||
+14
-2
@@ -490,6 +490,12 @@ class mrp_production(osv.osv):
|
||||
result[prod.id]['cycle_total'] += wc.cycle
|
||||
return result
|
||||
|
||||
def _get_workcenter_line(self, cr, uid, ids, context=None):
|
||||
result = {}
|
||||
for line in self.pool['mrp.production.workcenter.line'].browse(cr, uid, ids, context=context):
|
||||
result[line.production_id.id] = True
|
||||
return result.keys()
|
||||
|
||||
def _src_id_default(self, cr, uid, ids, context=None):
|
||||
try:
|
||||
location_model, location_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'stock', 'stock_location_stock')
|
||||
@@ -588,8 +594,14 @@ class mrp_production(osv.osv):
|
||||
"If the stock is available then the status is set to 'Ready to Produce.\n"
|
||||
"When the production gets started then the status is set to 'In Production.\n"
|
||||
"When the production is over, the status is set to 'Done'."),
|
||||
'hour_total': fields.function(_production_calc, type='float', string='Total Hours', multi='workorder', store=True),
|
||||
'cycle_total': fields.function(_production_calc, type='float', string='Total Cycles', multi='workorder', store=True),
|
||||
'hour_total': fields.function(_production_calc, type='float', string='Total Hours', multi='workorder', store={
|
||||
_name: (lambda self, cr, uid, ids, c={}: ids, ['workcenter_lines'], 40),
|
||||
'mrp.production.workcenter.line': (_get_workcenter_line, ['hour', 'cycle'], 40),
|
||||
}),
|
||||
'cycle_total': fields.function(_production_calc, type='float', string='Total Cycles', multi='workorder', store={
|
||||
_name: (lambda self, cr, uid, ids, c={}: ids, ['workcenter_lines'], 40),
|
||||
'mrp.production.workcenter.line': (_get_workcenter_line, ['hour', 'cycle'], 40),
|
||||
}),
|
||||
'user_id': fields.many2one('res.users', 'Responsible'),
|
||||
'company_id': fields.many2one('res.company', 'Company', required=True),
|
||||
'ready_production': fields.function(_moves_assigned, type='boolean', string="Ready for production", store={'stock.move': (_mrp_from_move, ['state'], 10)}),
|
||||
|
||||
+6
-4
@@ -14,7 +14,7 @@ class StockMove(osv.osv):
|
||||
_inherit = 'stock.move'
|
||||
|
||||
_columns = {
|
||||
'production_id': fields.many2one('mrp.production', 'Production Order for Produced Products', select=True),
|
||||
'production_id': fields.many2one('mrp.production', 'Production Order for Produced Products', select=True, copy=False),
|
||||
'raw_material_production_id': fields.many2one('mrp.production', 'Production Order for Raw Materials', select=True),
|
||||
'consumed_for': fields.many2one('stock.move', 'Consumed for', help='Technical field used to make the traceability of produced products'),
|
||||
}
|
||||
@@ -156,6 +156,8 @@ class StockMove(osv.osv):
|
||||
quantity_rest_uom = move.product_uom_qty - self.pool.get("product.uom")._compute_qty_obj(cr, uid, move.product_id.uom_id, product_qty, move.product_uom)
|
||||
if float_compare(quantity_rest_uom, 0, precision_rounding=move.product_uom.rounding) != 0:
|
||||
new_mov = self.split(cr, uid, move, quantity_rest, context=context)
|
||||
if move.production_id:
|
||||
self.write(cr, uid, [new_mov], {'production_id': move.production_id.id}, context=context)
|
||||
res.append(new_mov)
|
||||
vals = {'restrict_lot_id': restrict_lot_id,
|
||||
'restrict_partner_id': restrict_partner_id,
|
||||
@@ -187,9 +189,9 @@ class StockMove(osv.osv):
|
||||
production_ids = production_obj.search(cr, uid, [('move_lines', 'in', [move.id])])
|
||||
for prod_id in production_ids:
|
||||
production_obj.signal_workflow(cr, uid, [prod_id], 'button_produce')
|
||||
for new_move in new_moves:
|
||||
production_obj.write(cr, uid, production_ids, {'move_lines': [(4, new_move)]})
|
||||
res.append(new_move)
|
||||
if move.production_id.id:
|
||||
self.write(cr, uid, new_moves, {'production_id': move.production_id.id}, context=context)
|
||||
res.append(new_moves)
|
||||
return res
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: MRP Manager
|
||||
login: mam
|
||||
password: mam
|
||||
email: mrp_manager@yourcompany.com
|
||||
-
|
||||
I added groups for MRP Manager.
|
||||
@@ -21,11 +20,10 @@
|
||||
company_id: base.main_company
|
||||
name: MRP User
|
||||
login: mau
|
||||
password: mau
|
||||
email: mrp_user@yourcompany.com
|
||||
-
|
||||
I added groups for MRP User.
|
||||
-
|
||||
!record {model: res.users, id: res_users_mrp_user}:
|
||||
groups_id:
|
||||
- mrp.group_mrp_user
|
||||
- mrp.group_mrp_user
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools import float_compare
|
||||
from openerp.tools.translate import _
|
||||
import openerp.addons.decimal_precision as dp
|
||||
|
||||
@@ -40,12 +41,26 @@ class stock_move_consume(osv.osv_memory):
|
||||
context = {}
|
||||
move_obj = self.pool.get('stock.move')
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
production_obj = self.pool.get('mrp.production')
|
||||
move_ids = context['active_ids']
|
||||
move = move_obj.browse(cr, uid, move_ids[0], context=context)
|
||||
production_id = move.raw_material_production_id.id
|
||||
production = production_obj.browse(cr, uid, production_id, context=context)
|
||||
precision = self.pool['decimal.precision'].precision_get(cr, uid, 'Product Unit of Measure')
|
||||
|
||||
for data in self.browse(cr, uid, ids, context=context):
|
||||
if move_ids and move_ids[0]:
|
||||
move = move_obj.browse(cr, uid, move_ids[0], context=context)
|
||||
qty = uom_obj._compute_qty(cr, uid, data['product_uom'].id, data.product_qty, data.product_id.uom_id.id)
|
||||
move_obj.action_consume(cr, uid, move_ids,
|
||||
qty, data.location_id.id, restrict_lot_id=data.restrict_lot_id.id,
|
||||
context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
remaining_qty = move.product_qty - qty
|
||||
#check for product quantity is less than previously planned
|
||||
if float_compare(remaining_qty, 0, precision_digits=precision) >= 0:
|
||||
move_obj.action_consume(cr, uid, move_ids, qty, data.location_id.id, restrict_lot_id=data.restrict_lot_id.id, context=context)
|
||||
else:
|
||||
consumed_qty = min(move.product_qty, qty)
|
||||
new_moves = move_obj.action_consume(cr, uid, move_ids, consumed_qty, data.location_id.id, restrict_lot_id=data.restrict_lot_id.id, context=context)
|
||||
#consumed more in wizard than previously planned
|
||||
extra_more_qty = qty - consumed_qty
|
||||
#create new line for a remaining qty of the product
|
||||
extra_move_id = production_obj._make_consume_line_from_data(cr, uid, production, data.product_id, data.product_id.uom_id.id, extra_more_qty, False, 0, context=context)
|
||||
move_obj.write(cr, uid, [extra_move_id], {'restrict_lot_id': data.restrict_lot_id.id}, context=context)
|
||||
move_obj.action_done(cr, uid, [extra_move_id], context=context)
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
@@ -278,7 +278,8 @@ class mrp_production(osv.osv):
|
||||
if l.state in ('done','cancel','draft'):
|
||||
continue
|
||||
todo += l.move_dest_id_lines
|
||||
if l.production_id and (l.production_id.date_finished > dt):
|
||||
date_end = l.production_id.date_finished
|
||||
if date_end and datetime.strptime(date_end, '%Y-%m-%d %H:%M:%S') > dt:
|
||||
if l.production_id.state not in ('done','cancel'):
|
||||
for wc in l.production_id.workcenter_lines:
|
||||
i = self.pool.get('resource.calendar').interval_min_get(
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: MRP User
|
||||
login: maou
|
||||
password: maou
|
||||
email: mrp_operation_user@yourcompany.com
|
||||
-
|
||||
I added groups for MRP User.
|
||||
|
||||
@@ -268,7 +268,7 @@ class mrp_repair(osv.osv):
|
||||
else:
|
||||
self.write(cr, uid, [o.id], {'state': 'confirmed'})
|
||||
for line in o.operations:
|
||||
if line.product_id.tracking != 'none':
|
||||
if line.product_id.tracking != 'none' and not line.lot_id:
|
||||
raise UserError(_("Serial number is required for operation line with product '%s'") % (line.product_id.name))
|
||||
mrp_line_obj.write(cr, uid, [l.id for l in o.operations], {'state': 'confirmed'})
|
||||
return True
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: MRP Manager
|
||||
login: marm
|
||||
password: marm
|
||||
email: mrp_repair_manager@yourcompany.com
|
||||
-
|
||||
I added groups for MRP Repair Manager.
|
||||
@@ -20,11 +19,10 @@
|
||||
company_id: base.main_company
|
||||
name: MRP User
|
||||
login: maru
|
||||
password: maru
|
||||
email: mrp_repair_user@yourcompany.com
|
||||
-
|
||||
I added groups for MRP Repair User.
|
||||
-
|
||||
!record {model: res.users, id: res_mrp_repair_user}:
|
||||
groups_id:
|
||||
- mrp.group_mrp_user
|
||||
- mrp.group_mrp_user
|
||||
|
||||
@@ -13,7 +13,7 @@ def _partner_format_address(address1=False, address2=False):
|
||||
|
||||
|
||||
def _partner_split_name(partner_name):
|
||||
return [' '.join(partner_name.split()[-1:]), ' '.join(partner_name.split()[:-1])]
|
||||
return [' '.join(partner_name.split()[:-1]), ' '.join(partner_name.split()[-1:])]
|
||||
|
||||
|
||||
class ValidationError(ValueError):
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr='//group[@name="purchase"]' position="after">
|
||||
<group string="Payment" colspan="2">
|
||||
<field name="payment_method_ids" groups="base.group_sale_salesman">
|
||||
<group string="Payment Methods" colspan="2">
|
||||
<field name="payment_method_ids" groups="base.group_sale_salesman" nolabel="1">
|
||||
<tree editable="bottom" create="false">
|
||||
<field name="name"/>
|
||||
<field name="acquirer_id" readonly="1"/>
|
||||
|
||||
@@ -62,8 +62,8 @@ class AuthorizeForm(AuthorizeCommon):
|
||||
'return_url': None,
|
||||
'x_currency_code': 'USD',
|
||||
'x_invoice_num': 'SO004',
|
||||
'x_first_name': 'Buyer',
|
||||
'x_last_name': 'Norbert',
|
||||
'x_first_name': 'Norbert',
|
||||
'x_last_name': 'Buyer',
|
||||
'x_address': 'Huge Street 2/543',
|
||||
'x_city': 'Sin City',
|
||||
'x_zip': '1000',
|
||||
|
||||
@@ -31,7 +31,7 @@ class OgoneController(http.Controller):
|
||||
|
||||
@http.route(['/payment/ogone/s2s/create_json'], type='json', auth='public')
|
||||
def ogone_s2s_create_json(self, **kwargs):
|
||||
data = kwargs['params']
|
||||
data = kwargs
|
||||
acquirer_id = int(data.get('acquirer_id'))
|
||||
acquirer = request.env['payment.acquirer'].browse(acquirer_id)
|
||||
new_id = acquirer.s2s_process(data)
|
||||
|
||||
@@ -17,7 +17,7 @@ from openerp.addons.payment_ogone.controllers.main import OgoneController
|
||||
from openerp.addons.payment_ogone.data import ogone
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.tools import float_round, DEFAULT_SERVER_DATE_FORMAT
|
||||
from openerp.tools.float_utils import float_compare
|
||||
from openerp.tools.float_utils import float_compare, float_repr
|
||||
from openerp.tools.safe_eval import safe_eval
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
@@ -148,12 +148,11 @@ class PaymentAcquirerOgone(osv.Model):
|
||||
def ogone_form_generate_values(self, cr, uid, id, partner_values, tx_values, context=None):
|
||||
base_url = self.pool['ir.config_parameter'].get_param(cr, uid, 'web.base.url')
|
||||
acquirer = self.browse(cr, uid, id, context=context)
|
||||
|
||||
ogone_tx_values = dict(tx_values)
|
||||
temp_ogone_tx_values = {
|
||||
'PSPID': acquirer.ogone_pspid,
|
||||
'ORDERID': tx_values['reference'],
|
||||
'AMOUNT': '%d' % int(float_round(tx_values['amount'], 2) * 100),
|
||||
'AMOUNT': float_repr(float_round(tx_values['amount'], 2) * 100, 0),
|
||||
'CURRENCY': tx_values['currency'] and tx_values['currency'].name or '',
|
||||
'LANGUAGE': partner_values['lang'],
|
||||
'CN': partner_values['name'],
|
||||
@@ -289,9 +288,11 @@ class PaymentTxOgone(osv.Model):
|
||||
if status in self._ogone_valid_tx_status:
|
||||
tx.write({
|
||||
'state': 'done',
|
||||
'date_validate': data['TRXDATE'],
|
||||
'date_validate': datetime.datetime.strptime(data['TRXDATE'],'%m/%d/%y').strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
'acquirer_reference': data['PAYID'],
|
||||
})
|
||||
if tx.s2s_cb_eval:
|
||||
safe_eval(tx.s2s_cb_eval, {'self': tx})
|
||||
return True
|
||||
elif status in self._ogone_cancel_tx_status:
|
||||
tx.write({
|
||||
@@ -305,9 +306,9 @@ class PaymentTxOgone(osv.Model):
|
||||
})
|
||||
else:
|
||||
error = 'Ogone: feedback error: %(error_str)s\n\n%(error_code)s: %(error_msg)s' % {
|
||||
'error_str': data.get('NCERROR'),
|
||||
'error_code': data.get('NCERRORPLUS'),
|
||||
'error_msg': ogone.OGONE_ERROR_MAP.get(data.get('NCERRORPLUS')),
|
||||
'error_str': data.get('NCERRORPLUS'),
|
||||
'error_code': data.get('NCERROR'),
|
||||
'error_msg': ogone.OGONE_ERROR_MAP.get(data.get('NCERROR')),
|
||||
}
|
||||
_logger.info(error)
|
||||
tx.write({
|
||||
@@ -406,9 +407,9 @@ class PaymentTxOgone(osv.Model):
|
||||
return self.ogone_s2s_validate(tx, tree, tries - 1)
|
||||
else:
|
||||
error = 'Ogone: feedback error: %(error_str)s\n\n%(error_code)s: %(error_msg)s' % {
|
||||
'error_str': tree.get('NCERROR'),
|
||||
'error_code': tree.get('NCERRORPLUS'),
|
||||
'error_msg': ogone.OGONE_ERROR_MAP.get(tree.get('NCERRORPLUS')),
|
||||
'error_str': tree.get('NCERRORPLUS'),
|
||||
'error_code': tree.get('NCERROR'),
|
||||
'error_msg': ogone.OGONE_ERROR_MAP.get(tree.get('NCERROR')),
|
||||
}
|
||||
_logger.info(error)
|
||||
tx.write({
|
||||
|
||||
@@ -604,26 +604,37 @@ class pos_order(osv.osv):
|
||||
order['pos_session_id'] = rescue_session_id
|
||||
session = self.pool['pos.session'].browse(cr, uid, rescue_session_id, context=context)
|
||||
order_id = self.create(cr, uid, self._order_fields(cr, uid, order, context=context),context)
|
||||
|
||||
journal_ids = set()
|
||||
for payments in order['statement_ids']:
|
||||
self.add_payment(cr, uid, order_id, self._payment_fields(cr, uid, payments[2], context=context), context=context)
|
||||
journal_ids.add(payments[2]['journal_id'])
|
||||
|
||||
if session.sequence_number <= order['sequence_number']:
|
||||
session.write({'sequence_number': order['sequence_number'] + 1})
|
||||
session.refresh()
|
||||
|
||||
if not float_is_zero(order['amount_return'], self.pool.get('decimal.precision').precision_get(cr, uid, 'Account')):
|
||||
cash_journal = session.cash_journal_id
|
||||
cash_journal = session.cash_journal_id.id
|
||||
if not cash_journal:
|
||||
cash_journal_ids = filter(lambda st: st.journal_id.type=='cash', session.statement_ids)
|
||||
if not len(cash_journal_ids):
|
||||
raise UserError(_("No cash statement found for this session. Unable to record returned cash."))
|
||||
cash_journal = cash_journal_ids[0].journal_id
|
||||
# Select for change one of the cash journals used in this payment
|
||||
cash_journal_ids = self.pool['account.journal'].search(cr, uid, [
|
||||
('type', '=', 'cash'),
|
||||
('id', 'in', list(journal_ids)),
|
||||
], limit=1, context=context)
|
||||
if not cash_journal_ids:
|
||||
# If none, select for change one of the cash journals of the POS
|
||||
# This is used for example when a customer pays by credit card
|
||||
# an amount higher than total amount of the order and gets cash back
|
||||
cash_journal_ids = [statement.journal_id.id for statement in session.statement_ids
|
||||
if statement.journal_id.type == 'cash']
|
||||
if not cash_journal_ids:
|
||||
raise UserError(_("No cash statement found for this session. Unable to record returned cash."))
|
||||
cash_journal = cash_journal_ids[0]
|
||||
self.add_payment(cr, uid, order_id, {
|
||||
'amount': -order['amount_return'],
|
||||
'payment_date': time.strftime('%Y-%m-%d %H:%M:%S'),
|
||||
'payment_name': _('return'),
|
||||
'journal': cash_journal.id,
|
||||
'journal': cash_journal,
|
||||
}, context=context)
|
||||
return order_id
|
||||
|
||||
@@ -703,7 +714,8 @@ class pos_order(osv.osv):
|
||||
val1 += self._amount_line_tax(cr, uid, line, context=context)
|
||||
val2 += line.price_subtotal
|
||||
res[order.id]['amount_tax'] = cur_obj.round(cr, uid, cur, val1)
|
||||
res[order.id]['amount_total'] = cur_obj.round(cr, uid, cur, val1+val2)
|
||||
amount_untaxed = cur_obj.round(cr, uid, cur, val2)
|
||||
res[order.id]['amount_total'] = res[order.id]['amount_tax'] + amount_untaxed
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
@@ -804,6 +816,8 @@ class pos_order(osv.osv):
|
||||
move_obj = self.pool.get('stock.move')
|
||||
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
if all(t == 'service' for t in order.lines.mapped('product_id.type')):
|
||||
continue
|
||||
addr = order.partner_id and partner_obj.address_get(cr, uid, [order.partner_id.id], ['delivery']) or {}
|
||||
picking_type = order.picking_type_id
|
||||
picking_id = False
|
||||
@@ -878,9 +892,14 @@ class pos_order(osv.osv):
|
||||
statement_line_obj = self.pool.get('account.bank.statement.line')
|
||||
property_obj = self.pool.get('ir.property')
|
||||
order = self.browse(cr, uid, order_id, context=context)
|
||||
date = data.get('payment_date', time.strftime('%Y-%m-%d'))
|
||||
if len(date) > 10:
|
||||
timestamp = datetime.strptime(date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
ts = fields.datetime.context_timestamp(cr, uid, timestamp, context)
|
||||
date = ts.strftime(tools.DEFAULT_SERVER_DATE_FORMAT)
|
||||
args = {
|
||||
'amount': data['amount'],
|
||||
'date': data.get('payment_date', time.strftime('%Y-%m-%d')),
|
||||
'date': date,
|
||||
'name': order.name + ': ' + (data.get('payment_name', '') or ''),
|
||||
'partner_id': order.partner_id and self.pool.get("res.partner")._find_accounting_partner(order.partner_id).id or False,
|
||||
}
|
||||
|
||||
@@ -382,7 +382,7 @@ var PosDB = core.Class.extend({
|
||||
search_product_in_category: function(category_id, query){
|
||||
try {
|
||||
query = query.replace(/[\[\]\(\)\+\*\?\.\-\!\&\^\$\|\~\_\{\}\:\,\\\/]/g,'.');
|
||||
query = query.replace(' ','.+');
|
||||
query = query.replace(/ /g,'.+');
|
||||
var re = RegExp("([0-9]+):.*?"+query,"gi");
|
||||
}catch(e){
|
||||
return [];
|
||||
|
||||
@@ -287,7 +287,7 @@ exports.PosModel = Backbone.Model.extend({
|
||||
loaded: function(self, pricelists){ self.pricelist = pricelists[0]; },
|
||||
},{
|
||||
model: 'res.currency',
|
||||
fields: ['symbol','position','rounding','accuracy'],
|
||||
fields: ['name','symbol','position','rounding','accuracy'],
|
||||
ids: function(self){ return [self.pricelist.currency_id[0]]; },
|
||||
loaded: function(self, currencies){
|
||||
self.currency = currencies[0];
|
||||
@@ -1826,9 +1826,7 @@ exports.Order = Backbone.Model.extend({
|
||||
}), 0), this.pos.currency.rounding);
|
||||
},
|
||||
get_total_with_tax: function() {
|
||||
return round_pr(this.orderlines.reduce((function(sum, orderLine) {
|
||||
return sum + orderLine.get_price_with_tax();
|
||||
}), 0), this.pos.currency.rounding);
|
||||
return this.get_total_without_tax() + this.get_total_tax();
|
||||
},
|
||||
get_total_without_tax: function() {
|
||||
return round_pr(this.orderlines.reduce((function(sum, orderLine) {
|
||||
|
||||
@@ -1508,7 +1508,9 @@ var PaymentScreenWidget = ScreenWidget.extend({
|
||||
if (event.type === "keypress") {
|
||||
if (event.keyCode === 13) { // Enter
|
||||
self.validate_order();
|
||||
} else if (event.keyCode === 46) { // Period
|
||||
} else if ( event.keyCode === 190 || // Dot
|
||||
event.keyCode === 110 || // Decimal point (numpad)
|
||||
event.keyCode === 188 ) { // Comma
|
||||
key = '.';
|
||||
} else if (event.keyCode >= 48 && event.keyCode <= 57) { // Numbers
|
||||
key = '' + (event.keyCode - 48);
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<td><span t-field="line.product_id"/></td>
|
||||
<td class="text-right">
|
||||
<t t-if="o.state != 'cancel' and o.statement_ids">
|
||||
<span t-esc="'%.f' % line.qty"/>
|
||||
<span t-field="line.qty"/>
|
||||
</t>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
|
||||
@@ -63,7 +63,7 @@ class procurement_rule(osv.osv):
|
||||
return []
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name', required=True,
|
||||
'name': fields.char('Name', required=True, translate=True,
|
||||
help="This field will fill the packing origin and the name of its moves"),
|
||||
'active': fields.boolean('Active', help="If unchecked, it will allow you to hide the rule without removing it."),
|
||||
'group_propagation_option': fields.selection([('none', 'Leave Empty'), ('propagate', 'Propagate'), ('fixed', 'Fixed')], string="Propagation of Procurement Group"),
|
||||
|
||||
@@ -15,12 +15,20 @@ class procurement_order(osv.osv):
|
||||
self.check(cr, uid, [procurement_id], context=context)
|
||||
return procurement_id
|
||||
|
||||
def run(self, cr, uid, ids, context=None):
|
||||
def run(self, cr, uid, ids, autocommit=False, context=None):
|
||||
context = dict(context or {}, procurement_autorun_defer=True)
|
||||
res = super(procurement_order, self).run(cr, uid, ids, context=context)
|
||||
res = super(procurement_order, self).run(cr, uid, ids, autocommit=autocommit, context=context)
|
||||
|
||||
procurement_ids = self.search(cr, uid, [('move_dest_id.procurement_id', 'in', ids)], order='id', context=context)
|
||||
|
||||
if procurement_ids:
|
||||
return self.run(cr, uid, procurement_ids, context=context)
|
||||
return self.run(cr, uid, procurement_ids, autocommit=autocommit, context=context)
|
||||
return res
|
||||
|
||||
class stock_move(osv.osv):
|
||||
_inherit = "stock.move"
|
||||
|
||||
def _create_procurements(self, cr, uid, moves, context=None):
|
||||
res = super(stock_move, self)._create_procurements(cr, uid, moves, context=dict(context or {}, procurement_autorun_defer=True))
|
||||
self.pool['procurement.order'].run(cr, uid, res, context=context)
|
||||
return res
|
||||
|
||||
@@ -697,7 +697,7 @@ class product_template(osv.osv):
|
||||
# unlink or inactive product
|
||||
for variant_id in map(int,variants_inactive):
|
||||
try:
|
||||
with cr.savepoint():
|
||||
with cr.savepoint(), tools.mute_logger('openerp.sql_db'):
|
||||
product_obj.unlink(cr, uid, [variant_id], context=ctx)
|
||||
#We catch all kind of exception to be sure that the operation doesn't fail.
|
||||
except (psycopg2.Error, except_orm):
|
||||
@@ -931,12 +931,12 @@ class product_product(osv.osv):
|
||||
|
||||
def _set_image_variant(self, cr, uid, id, name, value, args, context=None):
|
||||
image = tools.image_resize_image_big(value)
|
||||
res = self.write(cr, uid, [id], {'image_variant': image}, context=context)
|
||||
|
||||
product = self.browse(cr, uid, id, context=context)
|
||||
if not product.product_tmpl_id.image:
|
||||
product.write({'image_variant': None})
|
||||
product.product_tmpl_id.write({'image': image})
|
||||
return res
|
||||
if product.product_tmpl_id.image:
|
||||
product.image_variant = image
|
||||
else:
|
||||
product.product_tmpl_id.image = image
|
||||
|
||||
def _get_price_extra(self, cr, uid, ids, name, args, context=None):
|
||||
result = dict.fromkeys(ids, False)
|
||||
|
||||
@@ -56,11 +56,10 @@ class product_template(osv.osv):
|
||||
uom_obj = self.pool.get("product.uom")
|
||||
tmpl_obj = self.pool.get('product.template')
|
||||
for sbom in bom.bom_line_ids:
|
||||
my_qty = sbom.product_qty
|
||||
my_qty = sbom.product_qty / sbom.product_efficiency
|
||||
if not sbom.attribute_value_ids:
|
||||
bom_product = sbom.product_id
|
||||
# No attribute_value_ids means the bom line is not variant specific
|
||||
price += uom_obj._compute_price(cr, uid, bom_product.uom_po_id and bom_product.uom_po_id.id or bom_product.uom_id.id, bom_product.standard_price, sbom.product_uom.id) * my_qty
|
||||
price += uom_obj._compute_price(cr, uid, sbom.product_id.uom_id.id, sbom.product_id.standard_price, sbom.product_uom.id) * my_qty
|
||||
|
||||
if bom.routing_id:
|
||||
for wline in bom.routing_id.workcenter_lines:
|
||||
|
||||
@@ -248,7 +248,7 @@
|
||||
<field name="res_model">project.issue</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="name">Issues</field>
|
||||
<field name="view_mode">kanban,tree,form,calendar,graph</field>
|
||||
<field name="view_mode">kanban,tree,form,calendar,graph,pivot</field>
|
||||
<field name="context">{
|
||||
'search_default_project_id': [active_id],
|
||||
'default_project_id': active_id,
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: Project Manager
|
||||
login: prim
|
||||
password: prim
|
||||
email: issuemanager@yourcompany.com
|
||||
-
|
||||
I added groups for Project manager.
|
||||
@@ -20,11 +19,10 @@
|
||||
company_id: base.main_company
|
||||
name: Project User
|
||||
login: priu
|
||||
password: priu
|
||||
email: issueuser@yourcompany.com
|
||||
-
|
||||
I added groups for Project user.
|
||||
-
|
||||
!record {model: res.users, id: res_users_project_issue_user}:
|
||||
groups_id:
|
||||
- project.group_project_user
|
||||
- project.group_project_user
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: HR Manager
|
||||
login: hr
|
||||
password: hr
|
||||
groups_id:
|
||||
- base.group_hr_manager
|
||||
-
|
||||
|
||||
@@ -860,6 +860,7 @@ class purchase_order(osv.osv):
|
||||
}
|
||||
picking_id = self.pool.get('stock.picking').create(cr, uid, picking_vals, context=context)
|
||||
self._create_stock_moves(cr, uid, order, order.order_line, picking_id, context=context)
|
||||
return picking_id
|
||||
|
||||
def picking_done(self, cr, uid, ids, context=None):
|
||||
self.write(cr, uid, ids, {'shipped':1,'state':'approved'}, context=context)
|
||||
@@ -1372,7 +1373,11 @@ class procurement_order(osv.osv):
|
||||
names_dict[id] = name
|
||||
for procurement in procurements:
|
||||
taxes_ids = procurement.product_id.supplier_taxes_id
|
||||
taxes = acc_pos_obj.map_tax(cr, uid, partner.property_account_position_id, taxes_ids)
|
||||
# It is necessary to have the appropriate fiscal position to get the right tax mapping
|
||||
fp = acc_pos_obj.get_fiscal_position(cr, uid, None, partner.id, context=context)
|
||||
if fp:
|
||||
fp = acc_pos_obj.browse(cr, uid, fp, context=context)
|
||||
taxes = acc_pos_obj.map_tax(cr, uid, fp, taxes_ids)
|
||||
name = names_dict[procurement.product_id.id]
|
||||
if procurement.product_id.description_purchase:
|
||||
name += '\n' + procurement.product_id.description_purchase
|
||||
@@ -1493,6 +1498,7 @@ class procurement_order(osv.osv):
|
||||
po_line_obj = self.pool.get('purchase.order.line')
|
||||
seq_obj = self.pool.get('ir.sequence')
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
acc_pos_obj = self.pool.get('account.fiscal.position')
|
||||
add_purchase_procs, create_purchase_procs = self._get_grouping_dicts(cr, uid, ids, context=context)
|
||||
procs_done = []
|
||||
|
||||
@@ -1580,6 +1586,7 @@ class procurement_order(osv.osv):
|
||||
name = seq_obj.next_by_code(cr, uid, 'purchase.order') or _('PO: %s') % procurement.name
|
||||
gpo = procurement.rule_id.group_propagation_option
|
||||
group = (gpo == 'fixed' and procurement.rule_id.group_id.id) or (gpo == 'propagate' and procurement.group_id.id) or False
|
||||
fp = acc_pos_obj.get_fiscal_position(cr, uid, None, partner.id, context=context)
|
||||
po_vals = {
|
||||
'name': name,
|
||||
'origin': procurement.origin,
|
||||
@@ -1589,7 +1596,7 @@ class procurement_order(osv.osv):
|
||||
'pricelist_id': partner.property_product_pricelist_purchase.id,
|
||||
'date_order': purchase_date.strftime(DEFAULT_SERVER_DATETIME_FORMAT),
|
||||
'company_id': procurement.company_id.id,
|
||||
'fiscal_position_id': partner.property_account_position_id.id,
|
||||
'fiscal_position_id': fp,
|
||||
'payment_term_id': partner.property_supplier_payment_term_id.id,
|
||||
'dest_address_id': procurement.partner_dest_id.id,
|
||||
'group_id': group,
|
||||
@@ -1719,7 +1726,8 @@ class account_invoice(osv.Model):
|
||||
not all(picking.invoice_state in ['invoiced'] for picking in order.picking_ids)):
|
||||
shipped = False
|
||||
for po_line in order.order_line:
|
||||
if all(line.invoice_id.state not in ['draft', 'cancel'] for line in po_line.invoice_lines):
|
||||
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})
|
||||
|
||||
@@ -52,6 +52,15 @@ class purchase_report(osv.osv):
|
||||
tools.sql.drop_view_if_exists(cr, 'purchase_report')
|
||||
cr.execute("""
|
||||
create or replace view purchase_report as (
|
||||
WITH currency_rate (currency_id, rate, date_start, date_end) AS (
|
||||
SELECT r.currency_id, r.rate, r.name AS date_start,
|
||||
(SELECT name FROM res_currency_rate r2
|
||||
WHERE r2.name > r.name AND
|
||||
r2.currency_id = r.currency_id
|
||||
ORDER BY r2.name ASC
|
||||
LIMIT 1) AS date_end
|
||||
FROM res_currency_rate r
|
||||
)
|
||||
select
|
||||
min(l.id) as id,
|
||||
s.date_order as date,
|
||||
@@ -75,10 +84,10 @@ class purchase_report(osv.osv):
|
||||
extract(epoch from age(s.date_approve,s.date_order))/(24*60*60)::decimal(16,2) as delay,
|
||||
extract(epoch from age(l.date_planned,s.date_order))/(24*60*60)::decimal(16,2) as delay_pass,
|
||||
count(*) as nbr,
|
||||
sum(l.price_unit*l.product_qty)::decimal(16,2) as price_total,
|
||||
avg(100.0 * (l.price_unit*l.product_qty) / NULLIF(ip.value_float*l.product_qty/u.factor*u2.factor, 0.0))::decimal(16,2) as negociation,
|
||||
sum(l.price_unit*cr.rate*l.product_qty)::decimal(16,2) as price_total,
|
||||
avg(100.0 * (l.price_unit*cr.rate*l.product_qty) / NULLIF(ip.value_float*l.product_qty/u.factor*u2.factor, 0.0))::decimal(16,2) as negociation,
|
||||
sum(ip.value_float*l.product_qty/u.factor*u2.factor)::decimal(16,2) as price_standard,
|
||||
(sum(l.product_qty*l.price_unit)/NULLIF(sum(l.product_qty/u.factor*u2.factor),0.0))::decimal(16,2) as price_average,
|
||||
(sum(l.product_qty*cr.rate*l.price_unit)/NULLIF(sum(l.product_qty/u.factor*u2.factor),0.0))::decimal(16,2) as price_average,
|
||||
partner.country_id as country_id,
|
||||
partner.commercial_partner_id as commercial_partner_id,
|
||||
analytic_account.id as account_analytic_id
|
||||
@@ -92,6 +101,9 @@ class purchase_report(osv.osv):
|
||||
left join product_uom u2 on (u2.id=t.uom_id)
|
||||
left join stock_picking_type spt on (spt.id=s.picking_type_id)
|
||||
left join account_analytic_account analytic_account on (l.account_analytic_id = analytic_account.id)
|
||||
join currency_rate cr on (cr.currency_id = s.currency_id and
|
||||
cr.date_start <= coalesce(s.date_order, now()) and
|
||||
(cr.date_end is null or cr.date_end > coalesce(s.date_order, now())))
|
||||
group by
|
||||
s.company_id,
|
||||
s.create_uid,
|
||||
|
||||
@@ -76,9 +76,12 @@ class stock_move(osv.osv):
|
||||
return invoice_line_id
|
||||
|
||||
def _get_master_data(self, cr, uid, move, company, context=None):
|
||||
if context.get('inv_type') in ('in_invoice', 'in_refund') and move.purchase_line_id:
|
||||
if context.get('inv_type') == 'in_invoice' and move.purchase_line_id:
|
||||
purchase_order = move.purchase_line_id.order_id
|
||||
return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.currency_id.id
|
||||
if context.get('inv_type') == 'in_refund' and move.origin_returned_move_id.purchase_line_id:
|
||||
purchase_order = move.origin_returned_move_id.purchase_line_id.order_id
|
||||
return purchase_order.partner_id, purchase_order.create_uid.id, purchase_order.currency_id.id
|
||||
elif context.get('inv_type') in ('in_invoice', 'in_refund') and move.picking_id:
|
||||
# In case of an extra move, it is better to use the data from the original moves
|
||||
for purchase_move in move.picking_id.move_lines:
|
||||
@@ -96,10 +99,14 @@ class stock_move(osv.osv):
|
||||
|
||||
def _get_invoice_line_vals(self, cr, uid, move, partner, inv_type, context=None):
|
||||
res = super(stock_move, self)._get_invoice_line_vals(cr, uid, move, partner, inv_type, context=context)
|
||||
if inv_type in ('in_invoice', 'in_refund') and move.purchase_line_id:
|
||||
if inv_type == 'in_invoice' and move.purchase_line_id:
|
||||
purchase_line = move.purchase_line_id
|
||||
res['invoice_line_tax_ids'] = [(6, 0, [x.id for x in purchase_line.taxes_id])]
|
||||
res['price_unit'] = purchase_line.price_unit
|
||||
elif inv_type == 'in_refund' and move.origin_returned_move_id.purchase_line_id:
|
||||
purchase_line = move.origin_returned_move_id.purchase_line_id
|
||||
res['invoice_line_tax_id'] = [(6, 0, [x.id for x in purchase_line.taxes_id])]
|
||||
res['price_unit'] = purchase_line.price_unit
|
||||
return res
|
||||
|
||||
def _get_moves_taxes(self, cr, uid, moves, inv_type, context=None):
|
||||
@@ -203,7 +210,7 @@ class stock_warehouse(osv.osv):
|
||||
_columns = {
|
||||
'buy_to_resupply': fields.boolean('Purchase to resupply this warehouse',
|
||||
help="When products are bought, they can be delivered to this warehouse"),
|
||||
'buy_pull_id': fields.many2one('procurement.rule', 'BUY rule'),
|
||||
'buy_pull_id': fields.many2one('procurement.rule', 'Buy rule'),
|
||||
}
|
||||
_defaults = {
|
||||
'buy_to_resupply': True,
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
<field name="inherit_id" ref="stock.view_picking_internal_search"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='product_id']" position="before">
|
||||
<filter name="reception_to_invoice" string="Incoming Shipments to Invoice" domain="[('reception_to_invoice', '=', True)]"/>
|
||||
<filter name="reception_to_invoice" string="Incoming Shipments to Invoice" domain="[('reception_to_invoice', '=', True), ('invoice_state', '!=', 'invoiced')]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: Purchase Manager
|
||||
login: pm
|
||||
password: pm
|
||||
email: purchasemanager@yourcompany.com
|
||||
-
|
||||
I added groups for Purchase manager.
|
||||
@@ -20,7 +19,6 @@
|
||||
company_id: base.main_company
|
||||
name: Purchase User
|
||||
login: pu
|
||||
password: pu
|
||||
email: purchaseuser@yourcompany.com
|
||||
-
|
||||
I added groups for Purchase user.
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: Purchase requisition Manager
|
||||
login: prm
|
||||
password: prm
|
||||
email: requisition_manager@yourcompany.com
|
||||
-
|
||||
I added groups for Purchase Requisition Manager.
|
||||
@@ -20,11 +19,10 @@
|
||||
company_id: base.main_company
|
||||
name: Purchase requisition User
|
||||
login: pru
|
||||
password: pru
|
||||
email: requisition_user@yourcompany.com
|
||||
-
|
||||
I added groups for Purchase Requisition User.
|
||||
-
|
||||
!record {model: res.users, id: res_users_purchase_requisition_user}:
|
||||
groups_id:
|
||||
- purchase_requisition.group_purchase_requisition_user
|
||||
- purchase_requisition.group_purchase_requisition_user
|
||||
|
||||
@@ -330,6 +330,8 @@ class Report(osv.Model):
|
||||
:returns: Content of the pdf as a string
|
||||
"""
|
||||
command_args = []
|
||||
if wkhtmltopdf_state == "ok":
|
||||
command_args.extend(['--viewport-size', '1024x768'])
|
||||
|
||||
# Passing the cookie to wkhtmltopdf in order to resolve internal links.
|
||||
try:
|
||||
|
||||
@@ -5,6 +5,9 @@ body {
|
||||
.border-black td {
|
||||
border-top: 1px solid black !important;
|
||||
}
|
||||
.table-condensed > tbody > tr {
|
||||
page-break-inside: avoid !important;
|
||||
}
|
||||
.table-condensed > thead > tr > th {
|
||||
border-bottom: 1px solid black !important;
|
||||
}
|
||||
|
||||
@@ -47,11 +47,20 @@ class sale_report(osv.osv):
|
||||
|
||||
def _select(self):
|
||||
select_str = """
|
||||
WITH currency_rate (currency_id, rate, date_start, date_end) AS (
|
||||
SELECT r.currency_id, r.rate, r.name AS date_start,
|
||||
(SELECT name FROM res_currency_rate r2
|
||||
WHERE r2.name > r.name AND
|
||||
r2.currency_id = r.currency_id
|
||||
ORDER BY r2.name ASC
|
||||
LIMIT 1) AS date_end
|
||||
FROM res_currency_rate r
|
||||
)
|
||||
SELECT min(l.id) as id,
|
||||
l.product_id as product_id,
|
||||
t.uom_id as product_uom,
|
||||
sum(l.product_uom_qty / u.factor * u2.factor) as product_uom_qty,
|
||||
sum(l.product_uom_qty * l.price_unit * (100.0-l.discount) / 100.0) as price_total,
|
||||
sum(l.product_uom_qty * cr.rate * l.price_unit * (100.0-l.discount) / 100.0) as price_total,
|
||||
count(*) as nbr,
|
||||
s.date_order as date,
|
||||
s.date_confirm as date_confirm,
|
||||
@@ -81,6 +90,10 @@ class sale_report(osv.osv):
|
||||
left join product_template t on (p.product_tmpl_id=t.id)
|
||||
left join product_uom u on (u.id=l.product_uom)
|
||||
left join product_uom u2 on (u2.id=t.uom_id)
|
||||
left join product_pricelist pp on (s.pricelist_id = pp.id)
|
||||
join currency_rate cr on (cr.currency_id = pp.currency_id and
|
||||
cr.date_start <= coalesce(s.date_order, now()) and
|
||||
(cr.date_end is null or cr.date_end > coalesce(s.date_order, now())))
|
||||
"""
|
||||
return from_str
|
||||
|
||||
|
||||
+36
-5
@@ -218,7 +218,7 @@ class sale_order(osv.osv):
|
||||
|
||||
def _track_subtype(self, cr, uid, ids, init_values, context=None):
|
||||
record = self.browse(cr, uid, ids[0], context=context)
|
||||
if 'state' in init_values and record.state == 'manual':
|
||||
if 'state' in init_values and record.state in ['manual', 'progress']:
|
||||
return 'sale.mt_order_confirmed'
|
||||
elif 'state' in init_values and record.state == 'sent':
|
||||
return 'sale.mt_order_sent'
|
||||
@@ -524,8 +524,12 @@ class sale_order(osv.osv):
|
||||
return True
|
||||
|
||||
def action_button_confirm(self, cr, uid, ids, context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
assert len(ids) == 1, 'This option should only be used for a single id at a time.'
|
||||
self.signal_workflow(cr, uid, ids, 'order_confirm')
|
||||
if context.get('send_email'):
|
||||
self.force_quotation_send(cr, uid, ids, context=context)
|
||||
return True
|
||||
|
||||
def action_wait(self, cr, uid, ids, context=None):
|
||||
@@ -575,6 +579,29 @@ class sale_order(osv.osv):
|
||||
'context': ctx,
|
||||
}
|
||||
|
||||
def force_quotation_send(self, cr, uid, ids, context=None):
|
||||
for order_id in ids:
|
||||
email_act = self.action_quotation_send(cr, uid, [order_id], context=context)
|
||||
if email_act and email_act.get('context'):
|
||||
composer_obj = self.pool['mail.compose.message']
|
||||
composer_values = {}
|
||||
email_ctx = email_act['context']
|
||||
template_values = [
|
||||
email_ctx.get('default_template_id'),
|
||||
email_ctx.get('default_composition_mode'),
|
||||
email_ctx.get('default_model'),
|
||||
email_ctx.get('default_res_id'),
|
||||
]
|
||||
composer_values.update(composer_obj.onchange_template_id(cr, uid, None, *template_values, context=context).get('value', {}))
|
||||
if not composer_values.get('email_from'):
|
||||
composer_values['email_from'] = self.browse(cr, uid, order_id, context=context).company_id.email
|
||||
for key in ['attachment_ids', 'partner_ids']:
|
||||
if composer_values.get(key):
|
||||
composer_values[key] = [(6, 0, composer_values[key])]
|
||||
composer_id = composer_obj.create(cr, uid, composer_values, context=email_ctx)
|
||||
composer_obj.send_mail(cr, uid, [composer_id], context=email_ctx)
|
||||
return True
|
||||
|
||||
def action_done(self, cr, uid, ids, context=None):
|
||||
for order in self.browse(cr, uid, ids, context=context):
|
||||
self.pool.get('sale.order.line').write(cr, uid, [line.id for line in order.order_line if line.state != 'cancel'], {'state': 'done'}, context=context)
|
||||
@@ -1069,13 +1096,17 @@ class sale_order_line(osv.osv):
|
||||
uom2 = product_obj.uom_id
|
||||
|
||||
if pricelist and partner_id:
|
||||
ctx = dict(
|
||||
context,
|
||||
uom=uom or result.get('product_uom'),
|
||||
date=date_order,
|
||||
)
|
||||
price = self.pool['product.pricelist'].price_get(cr, uid, [pricelist],
|
||||
product, qty or 1.0, partner_id, {
|
||||
'uom': uom or result.get('product_uom'),
|
||||
'date': date_order,
|
||||
})[pricelist]
|
||||
product, qty or 1.0, partner_id, ctx)[pricelist]
|
||||
else:
|
||||
price = Product.price_get(cr, uid, [product], ptype='list_price', context=ctx_product)[product] or False
|
||||
if context.get('uom_qty_change', False):
|
||||
result, domain = {}, {}
|
||||
result.update({'price_unit': price})
|
||||
return {'value': result, 'domain': domain}
|
||||
|
||||
|
||||
@@ -193,7 +193,7 @@
|
||||
<label for="product_uom_qty"/>
|
||||
<div>
|
||||
<field
|
||||
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
|
||||
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom, 'uom_qty_change':True}"
|
||||
name="product_uom_qty" class="oe_inline"
|
||||
on_change="product_id_change(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,product_uos,name,parent.partner_id, False, False, parent.date_order, False, parent.fiscal_position_id, True, context)"/>
|
||||
<field name="product_uom" groups="product.group_uom" class="oe_inline oe_no_button"
|
||||
@@ -510,7 +510,7 @@
|
||||
<search string="Search Sales Order">
|
||||
<filter icon="terp-dolar_ok!" string="To Invoice" domain="[('invoiced','<>', 1),('state','=','done')]" help="Sales Order Lines ready to be invoiced"/>
|
||||
<separator/>
|
||||
<filter string="Confirmed" domain="[('state', 'in', ['waiting_date','progress','manual', 'shipping_except', 'invoice_except', 'confirmed', 'done'])]" name="confirmed"/>
|
||||
<filter string="Confirmed" domain="[('state', 'in', ['confirmed', 'done'])]" name="confirmed"/>
|
||||
<separator/>
|
||||
<filter string="My Sales Order Lines" icon="terp-personnal" domain="[('salesman_id','=',uid)]" help="Sales Order Lines related to a Sales Order of mine"/>
|
||||
<field name="order_id"/>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: Sales manager
|
||||
login: sm
|
||||
password: sm
|
||||
email: salesmanager@yourcompany.com
|
||||
-
|
||||
I added groups for Salesmanager.
|
||||
@@ -20,7 +19,6 @@
|
||||
company_id: base.main_company
|
||||
name: Salesman
|
||||
login: su
|
||||
password: su
|
||||
email: salesman@yourcompany.com
|
||||
-
|
||||
I added groups for Salesman.
|
||||
|
||||
@@ -360,8 +360,3 @@ msgstr ""
|
||||
msgid "days"
|
||||
msgstr ""
|
||||
|
||||
#. module: sale_stock
|
||||
#: view:sale.order:sale_stock.view_order_form_inherit
|
||||
msgid "{\"shipping_except\":\"red\",\"invoice_except\":\"red\",\"waiting_date\":\"blue\"}"
|
||||
msgstr ""
|
||||
|
||||
|
||||
@@ -191,7 +191,7 @@ class product_product(osv.osv):
|
||||
#when sale/product is installed alone, there is no need to create procurements, but with sale_stock
|
||||
#we must create a procurement for each product that is not a service.
|
||||
for product in self.browse(cr, uid, ids, context=context):
|
||||
if product.type != 'service':
|
||||
if product.id and product.type != 'service':
|
||||
return True
|
||||
return super(product_product, self).need_procurement(cr, uid, ids, context=context)
|
||||
|
||||
@@ -440,11 +440,12 @@ class stock_picking(osv.osv):
|
||||
""" Inherit the original function of the 'stock' module
|
||||
We select the partner of the sales order as the partner of the customer invoice
|
||||
"""
|
||||
saleorder_ids = self.pool['sale.order'].search(cr, uid, [('procurement_group_id' ,'=', picking.group_id.id)], context=context)
|
||||
saleorders = self.pool['sale.order'].browse(cr, uid, saleorder_ids, context=context)
|
||||
if saleorders and saleorders[0] and saleorders[0].order_policy == 'picking':
|
||||
saleorder = saleorders[0]
|
||||
return saleorder.partner_invoice_id.id
|
||||
if picking.sale_id:
|
||||
saleorder_ids = self.pool['sale.order'].search(cr, uid, [('procurement_group_id' ,'=', picking.group_id.id)], context=context)
|
||||
saleorders = self.pool['sale.order'].browse(cr, uid, saleorder_ids, context=context)
|
||||
if saleorders and saleorders[0] and saleorders[0].order_policy == 'picking':
|
||||
saleorder = saleorders[0]
|
||||
return saleorder.partner_invoice_id.id
|
||||
return super(stock_picking, self)._get_partner_to_invoice(cr, uid, picking, context=context)
|
||||
|
||||
def _get_sale_id(self, cr, uid, ids, name, args, context=None):
|
||||
|
||||
@@ -38,27 +38,36 @@
|
||||
<field name="picking_policy" required="True"/>
|
||||
</group>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/form//field[@name='product_id']" position="replace">
|
||||
<field name="product_id"
|
||||
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
|
||||
groups="base.group_user"
|
||||
on_change="product_id_change_with_wh(parent.pricelist_id,product_id,product_uom_qty,False,product_uos_qty,False,name,parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position_id, False, parent.warehouse_id, context)"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/tree//field[@name='product_id']" position="replace">
|
||||
<field name="product_id"
|
||||
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
|
||||
groups="base.group_user"
|
||||
on_change="product_id_change_with_wh(parent.pricelist_id,product_id,product_uom_qty,False,product_uos_qty,False,name,parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position_id, False, parent.warehouse_id, context)"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/form//field[@name='product_id']" position="replace">
|
||||
<field name="product_id"
|
||||
context="{'partner_id':parent.partner_id, 'quantity':product_uom_qty, 'pricelist':parent.pricelist_id, 'uom':product_uom}"
|
||||
groups="base.group_user"
|
||||
on_change="product_id_change_with_wh(parent.pricelist_id,product_id,product_uom_qty,False,product_uos_qty,False,name,parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position_id, False, parent.warehouse_id, context)"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/tree//field[@name='product_uom_qty']" position="attributes">
|
||||
<attribute name="on_change">product_id_change_with_wh(parent.pricelist_id,product_id,product_uom_qty,product_uom,product_uos_qty,False,name,parent.partner_id, False, False, parent.date_order, product_packaging, parent.fiscal_position_id, True, parent.warehouse_id, context)</attribute>
|
||||
<xpath expr="//field[@name='order_line']/form//field[@name='product_id']" position="attributes">
|
||||
<!-- no product_uos to force reset of product_uom, product_uos and product_uos_qty in porduct_id_change -->
|
||||
<attribute name="on_change">product_id_change_with_wh(
|
||||
parent.pricelist_id, product_id, product_uom_qty, False, product_uos_qty, False, name,
|
||||
parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position_id,
|
||||
False, parent.warehouse_id, context)
|
||||
</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/tree//field[@name='product_id']" position="attributes">
|
||||
<attribute name="on_change">product_id_change_with_wh(
|
||||
parent.pricelist_id, product_id, product_uom_qty, False, product_uos_qty, False, name,
|
||||
parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position_id,
|
||||
False, parent.warehouse_id, context)
|
||||
</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/form//field[@name='product_uos_qty']" position="attributes">
|
||||
<!-- keep product_uos to force update of product_uom and product_uom_qty in porduct_id_change -->
|
||||
<attribute name="on_change">product_id_change_with_wh(
|
||||
parent.pricelist_id, product_id, product_uom_qty, False, product_uos_qty, product_uos, name,
|
||||
parent.partner_id, False, True, parent.date_order, product_packaging, parent.fiscal_position_id,
|
||||
False, parent.warehouse_id, context)
|
||||
</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='order_line']/form//field[@name='product_uom_qty']" position="attributes">
|
||||
<attribute name="on_change">product_id_change_with_wh(
|
||||
parent.pricelist_id, product_id, product_uom_qty, product_uom, product_uos_qty, False, name,
|
||||
parent.partner_id, False, False, parent.date_order, product_packaging, parent.fiscal_position_id,
|
||||
True, parent.warehouse_id, context)
|
||||
</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//group[@name='technical']" position="inside">
|
||||
<field name="shipped" groups="base.group_no_one"/>
|
||||
</xpath>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
!record {model: product.product, id: product_onchange1}:
|
||||
name: 'Devil Worship Book'
|
||||
lst_price: 66.6
|
||||
default_code: 'DWB00001'
|
||||
-
|
||||
In sale order to test process of onchange of Sale Order with access rights of saleman.
|
||||
-
|
||||
@@ -28,5 +29,5 @@
|
||||
!python {model: sale.order}: |
|
||||
from openerp.tools import float_compare
|
||||
order_line = self.browse(cr, uid, ref('sale_order_onchange1')).order_line
|
||||
assert order_line[0].name == u'Devil Worship Book', "The onchange function of product was not correctly triggered"
|
||||
assert order_line[0].name == u'[DWB00001] Devil Worship Book', "The onchange function of product was not correctly triggered"
|
||||
assert float_compare(order_line[0].price_unit, 66.6, precision_digits=2) == 0, "The onchange function of product was not correctly triggered"
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: Stock Sales manager
|
||||
login: ssm
|
||||
password: ssm
|
||||
email: ss_salesmanager@yourcompany.com
|
||||
-
|
||||
I added groups for Salesmanager.
|
||||
@@ -20,7 +19,6 @@
|
||||
company_id: base.main_company
|
||||
name: Stock Salesman
|
||||
login: ssu
|
||||
password: ssu
|
||||
email: ss_salesman@yourcompany.com
|
||||
-
|
||||
I added groups for Stock Salesman.
|
||||
@@ -36,7 +34,6 @@
|
||||
company_id: base.main_company
|
||||
name: Stock User
|
||||
login: sau
|
||||
password: sau
|
||||
email: stock_user@yourcompany.com
|
||||
-
|
||||
I added groups for Stock User.
|
||||
@@ -51,8 +48,6 @@
|
||||
company_id: base.main_company
|
||||
name: Stock Manager
|
||||
login: sam
|
||||
password: sam
|
||||
email: admin@portal.example.com
|
||||
email: stock_manager@yourcompany.com
|
||||
-
|
||||
I added groups for Stock Manager.
|
||||
|
||||
+12
-4
@@ -56,9 +56,9 @@ class product_product(osv.osv):
|
||||
|
||||
location_ids = []
|
||||
if context.get('location', False):
|
||||
if type(context['location']) == type(1):
|
||||
if isinstance(context['location'], (int, long)):
|
||||
location_ids = [context['location']]
|
||||
elif type(context['location']) in (type(''), type(u'')):
|
||||
elif isinstance(context['location'], basestring):
|
||||
domain = [('complete_name','ilike',context['location'])]
|
||||
if context.get('force_company', False):
|
||||
domain += [('company_id', '=', context['force_company'])]
|
||||
@@ -67,7 +67,15 @@ class product_product(osv.osv):
|
||||
location_ids = context['location']
|
||||
else:
|
||||
if context.get('warehouse', False):
|
||||
wids = [context['warehouse']]
|
||||
if isinstance(context['warehouse'], (int, long)):
|
||||
wids = [context['warehouse']]
|
||||
elif isinstance(context['warehouse'], basestring):
|
||||
domain = [('name', 'ilike', context['warehouse'])]
|
||||
if context.get('force_company', False):
|
||||
domain += [('company_id', '=', context['force_company'])]
|
||||
wids = warehouse_obj.search(cr, uid, domain, context=context)
|
||||
else:
|
||||
wids = context['warehouse']
|
||||
else:
|
||||
wids = warehouse_obj.search(cr, uid, [], context=context)
|
||||
|
||||
@@ -279,7 +287,7 @@ class product_product(osv.osv):
|
||||
toolbar=toolbar, submenu=submenu)
|
||||
if context is None:
|
||||
context = {}
|
||||
if ('location' in context) and context['location']:
|
||||
if context.get('location') and isinstance(context['location'], int):
|
||||
location_info = self.pool.get('stock.location').browse(cr, uid, context['location'])
|
||||
fields=res.get('fields',{})
|
||||
if fields:
|
||||
|
||||
@@ -91,10 +91,10 @@ This installs the module product_expiry."""),
|
||||
'group_uom': fields.boolean("Manage different units of measure for products",
|
||||
implied_group='product.group_uom',
|
||||
help="""Allows you to select and maintain different units of measure for products."""),
|
||||
'group_uos': fields.boolean("Invoice products in a different unit of measure than the sales order",
|
||||
'group_uos': fields.boolean("Store products in a different unit of measure than the sales order",
|
||||
implied_group='product.group_uos',
|
||||
help='Allows you to sell units of a product, but invoice based on a different unit of measure.\n'
|
||||
'For instance, you can sell pieces of meat that you invoice based on their weight.'),
|
||||
help='Allows you to store units of a product, but sell and invoice based on a different unit of measure.\n'
|
||||
'For instance, you can store pieces of meat that you sell and invoice based on their weight.'),
|
||||
'group_stock_packaging': fields.boolean("Allow to define several packaging methods on products",
|
||||
implied_group='product.group_stock_packaging',
|
||||
help="""Allows you to create and manage your packaging dimensions and types you want to be maintained in your system."""),
|
||||
|
||||
+38
-16
@@ -195,7 +195,7 @@ class stock_location_route(osv.osv):
|
||||
_order = 'sequence'
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Route Name', required=True),
|
||||
'name': fields.char('Route Name', required=True, translate=True),
|
||||
'sequence': fields.integer('Sequence'),
|
||||
'pull_ids': fields.one2many('procurement.rule', 'route_id', 'Procurement Rules', copy=True),
|
||||
'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the route without removing it."),
|
||||
@@ -787,6 +787,13 @@ class stock_picking(models.Model):
|
||||
res.add(move.picking_id.id)
|
||||
return list(res)
|
||||
|
||||
def _get_pickings_dates_priority(self, cr, uid, ids, context=None):
|
||||
res = set()
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
if move.picking_id and (not (move.picking_id.min_date < move.date_expected < move.picking_id.max_date) or move.priority > move.picking_id.priority):
|
||||
res.add(move.picking_id.id)
|
||||
return list(res)
|
||||
|
||||
def _get_pack_operation_exist(self, cr, uid, ids, field_name, arg, context=None):
|
||||
res = {}
|
||||
for pick in self.browse(cr, uid, ids, context=context):
|
||||
@@ -871,12 +878,12 @@ class stock_picking(models.Model):
|
||||
'picking_type_code': fields.related('picking_type_id', 'code', type='selection', selection=[('incoming', 'Suppliers'), ('outgoing', 'Customers'), ('internal', 'Internal')]),
|
||||
'picking_type_entire_packs': fields.related('picking_type_id', 'show_entire_packs', type='boolean'),
|
||||
'priority': fields.function(get_min_max_date, multi="min_max_date", fnct_inv=_set_priority, type='selection', selection=procurement.PROCUREMENT_PRIORITIES, string='Priority',
|
||||
store={'stock.move': (_get_pickings, ['priority', 'picking_id'], 20)}, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, select=1, help="Priority for this picking. Setting manually a value here would set it as priority for all the moves",
|
||||
store={'stock.move': (_get_pickings_dates_priority, ['priority', 'picking_id'], 20)}, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, select=1, help="Priority for this picking. Setting manually a value here would set it as priority for all the moves",
|
||||
track_visibility='onchange', required=True),
|
||||
'min_date': fields.function(get_min_max_date, multi="min_max_date", fnct_inv=_set_min_date,
|
||||
store={'stock.move': (_get_pickings, ['date_expected', 'picking_id'], 20)}, type='datetime', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, string='Scheduled Date', select=1, help="Scheduled time for the first part of the shipment to be processed. Setting manually a value here would set it as expected date for all the stock moves.", track_visibility='onchange'),
|
||||
store={'stock.move': (_get_pickings_dates_priority, ['date_expected', 'picking_id'], 20)}, type='datetime', states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, string='Scheduled Date', select=1, help="Scheduled time for the first part of the shipment to be processed. Setting manually a value here would set it as expected date for all the stock moves.", track_visibility='onchange'),
|
||||
'max_date': fields.function(get_min_max_date, multi="min_max_date",
|
||||
store={'stock.move': (_get_pickings, ['date_expected', 'picking_id'], 20)}, type='datetime', string='Max. Expected Date', select=2, help="Scheduled time for the last part of the shipment to be processed"),
|
||||
store={'stock.move': (_get_pickings_dates_priority, ['date_expected', 'picking_id'], 20)}, type='datetime', string='Max. Expected Date', select=2, help="Scheduled time for the last part of the shipment to be processed"),
|
||||
'date': fields.datetime('Creation Date', help="Creation Date, usually the time of the order", select=True, states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}, track_visibility='onchange'),
|
||||
'date_done': fields.datetime('Date of Transfer', help="Completion Date of Transfer", readonly=True, copy=False),
|
||||
'quant_reserved_exist': fields.function(_get_quant_reserved_exist, type='boolean', string='Has quants already reserved', help='Check the existance of quants linked to this picking'),
|
||||
@@ -1747,7 +1754,9 @@ class stock_move(osv.osv):
|
||||
'date': fields.datetime('Date', required=True, select=True, help="Move date: scheduled date until move is done, then date of actual move processing", states={'done': [('readonly', True)]}),
|
||||
'date_expected': fields.datetime('Expected Date', states={'done': [('readonly', True)]}, required=True, select=True, help="Scheduled date for the processing of this move"),
|
||||
'product_id': fields.many2one('product.product', 'Product', required=True, select=True, domain=[('type', '<>', 'service')], states={'done': [('readonly', True)]}),
|
||||
'product_qty': fields.function(_quantity_normalize, fnct_inv=_set_product_qty, type='float', digits=0, store=True, string='Quantity',
|
||||
'product_qty': fields.function(_quantity_normalize, fnct_inv=_set_product_qty, type='float', digits=0, store={
|
||||
_name: (lambda self, cr, uid, ids, c={}: ids, ['product_id', 'product_uom', 'product_uom_qty'], 10),
|
||||
}, string='Quantity',
|
||||
help='Quantity in the default UoM of the product'),
|
||||
'product_uom_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure'),
|
||||
required=True, states={'done': [('readonly', True)]},
|
||||
@@ -1760,7 +1769,7 @@ class stock_move(osv.osv):
|
||||
"the product reservation, and should be done with care."
|
||||
),
|
||||
'product_uom': fields.many2one('product.uom', 'Unit of Measure', required=True, states={'done': [('readonly', True)]}),
|
||||
'product_uos_qty': fields.float('Quantity (UOS)', digits_compute=dp.get_precision('Product Unit of Measure'), states={'done': [('readonly', True)]}),
|
||||
'product_uos_qty': fields.float('Quantity (UOS)', digits_compute=dp.get_precision('Product UoS'), states={'done': [('readonly', True)]}),
|
||||
'product_uos': fields.many2one('product.uom', 'Product UOS', states={'done': [('readonly', True)]}),
|
||||
'product_tmpl_id': fields.related('product_id', 'product_tmpl_id', type='many2one', relation='product.template', string='Product Template'),
|
||||
|
||||
@@ -1940,6 +1949,12 @@ class stock_move(osv.osv):
|
||||
""" This will create a procurement order """
|
||||
return self.pool.get("procurement.order").create(cr, uid, self._prepare_procurement_from_move(cr, uid, move, context=context), context=context)
|
||||
|
||||
def _create_procurements(self, cr, uid, moves, context=None):
|
||||
res = []
|
||||
for move in moves:
|
||||
res.append(self._create_procurement(cr, uid, move, context=context))
|
||||
return res
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
@@ -2018,7 +2033,8 @@ class stock_move(osv.osv):
|
||||
break
|
||||
|
||||
if product_uos and product_uom and (product_uom != product_uos):
|
||||
result['product_uos_qty'] = product_qty * uos_coeff['uos_coeff']
|
||||
precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Product UoS')
|
||||
result['product_uos_qty'] = float_round(product_qty * uos_coeff['uos_coeff'], precision_digits=precision)
|
||||
else:
|
||||
result['product_uos_qty'] = product_qty
|
||||
|
||||
@@ -2048,7 +2064,8 @@ class stock_move(osv.osv):
|
||||
# The clients should call onchange_quantity too anyway
|
||||
|
||||
if product_uos and product_uom and (product_uom != product_uos):
|
||||
result['product_uom_qty'] = product_uos_qty / uos_coeff['uos_coeff']
|
||||
precision = self.pool.get('decimal.precision').precision_get(cr, uid, 'Product Unit of Measure')
|
||||
result['product_uom_qty'] = float_round(product_uos_qty / uos_coeff['uos_coeff'], precision_digits=precision)
|
||||
else:
|
||||
result['product_uom_qty'] = product_uos_qty
|
||||
return {'value': result}
|
||||
@@ -2142,6 +2159,8 @@ class stock_move(osv.osv):
|
||||
""" Confirms stock move or put it in waiting if it's linked to another move.
|
||||
@return: List of ids.
|
||||
"""
|
||||
if not context:
|
||||
context = {}
|
||||
if isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
states = {
|
||||
@@ -2169,12 +2188,11 @@ class stock_move(osv.osv):
|
||||
if key not in to_assign:
|
||||
to_assign[key] = []
|
||||
to_assign[key].append(move.id)
|
||||
|
||||
for move in self.browse(cr, uid, states['confirmed'], context=context):
|
||||
if move.procure_method == 'make_to_order':
|
||||
self._create_procurement(cr, uid, move, context=context)
|
||||
states['waiting'].append(move.id)
|
||||
states['confirmed'].remove(move.id)
|
||||
moves = [move for move in self.browse(cr, uid, states['confirmed'], context=context) if move.procure_method == 'make_to_order']
|
||||
self._create_procurements(cr, uid, moves, context=context)
|
||||
for move in moves:
|
||||
states['waiting'].append(move.id)
|
||||
states['confirmed'].remove(move.id)
|
||||
|
||||
for state, write_ids in states.items():
|
||||
if len(write_ids):
|
||||
@@ -3322,7 +3340,10 @@ class stock_warehouse(osv.osv):
|
||||
output_loc = warehouse.lot_stock_id
|
||||
picking_type_obj.write(cr, uid, warehouse.in_type_id.id, {'default_location_dest_id': input_loc.id}, context=context)
|
||||
picking_type_obj.write(cr, uid, warehouse.out_type_id.id, {'default_location_src_id': output_loc.id}, context=context)
|
||||
picking_type_obj.write(cr, uid, warehouse.pick_type_id.id, {'active': new_delivery_step != 'ship_only'}, context=context)
|
||||
picking_type_obj.write(cr, uid, warehouse.pick_type_id.id, {
|
||||
'active': new_delivery_step != 'ship_only',
|
||||
'default_location_dest_id': output_loc.id if new_delivery_step == 'pick_ship' else warehouse.wh_pack_stock_loc_id.id,
|
||||
}, context=context)
|
||||
picking_type_obj.write(cr, uid, warehouse.pack_type_id.id, {'active': new_delivery_step == 'pick_pack_ship'}, context=context)
|
||||
|
||||
routes_dict = self.get_routes_dict(cr, uid, ids, warehouse, context=context)
|
||||
@@ -3454,7 +3475,7 @@ class stock_warehouse(osv.osv):
|
||||
'use_existing_lots': True,
|
||||
'sequence_id': pick_seq_id,
|
||||
'default_location_src_id': wh_stock_loc.id,
|
||||
'default_location_dest_id': wh_pack_stock_loc.id,
|
||||
'default_location_dest_id': output_loc.id if warehouse.delivery_steps == 'pick_ship' else wh_pack_stock_loc.id,
|
||||
'active': warehouse.delivery_steps != 'ship_only',
|
||||
'sequence': max_sequence + 2,
|
||||
'color': color}, context=context)
|
||||
@@ -3757,6 +3778,7 @@ class stock_location_path(osv.osv):
|
||||
def _prepare_push_apply(self, cr, uid, rule, move, context=None):
|
||||
newdate = (datetime.strptime(move.date_expected, DEFAULT_SERVER_DATETIME_FORMAT) + relativedelta.relativedelta(days=rule.delay or 0)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
return {
|
||||
'origin': move.origin or move.picking_id.name or "/",
|
||||
'location_id': move.location_dest_id.id,
|
||||
'location_dest_id': rule.location_dest_id.id,
|
||||
'date': newdate,
|
||||
|
||||
@@ -689,7 +689,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="partially_available" string="Recheck Reservation" 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="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"/>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
company_id: base.main_company
|
||||
name: Stock Manager
|
||||
login: sam
|
||||
password: sam
|
||||
email: stockmanager@yourcompany.com
|
||||
-
|
||||
I added groups for Stock Manager.
|
||||
@@ -20,7 +19,6 @@
|
||||
company_id: base.main_company
|
||||
name: Stock User
|
||||
login: sau
|
||||
password: sau
|
||||
email: stockuser@yourcompany.com
|
||||
-
|
||||
I added groups for Stock User.
|
||||
|
||||
@@ -179,7 +179,7 @@ class stock_picking(osv.osv):
|
||||
def __get_picking_move(self, cr, uid, ids, context={}):
|
||||
res = []
|
||||
for move in self.pool.get('stock.move').browse(cr, uid, ids, context=context):
|
||||
if move.picking_id:
|
||||
if move.picking_id and move.invoice_state != move.picking_id.invoice_state:
|
||||
res.append(move.picking_id.id)
|
||||
return res
|
||||
|
||||
|
||||
@@ -56,15 +56,19 @@ class stock_history(osv.osv):
|
||||
for product_id in ids:
|
||||
line_ids.add(product_id)
|
||||
line_ids = list(line_ids)
|
||||
cr.execute('SELECT id, product_id, price_unit_on_quant, company_id, quantity FROM stock_history WHERE id in %s', (tuple(line_ids),))
|
||||
lines_rec = cr.dictfetchall()
|
||||
lines_rec = {}
|
||||
if line_ids:
|
||||
cr.execute('SELECT id, product_id, price_unit_on_quant, company_id, quantity FROM stock_history WHERE id in %s', (tuple(line_ids),))
|
||||
lines_rec = cr.dictfetchall()
|
||||
lines_dict = dict((line['id'], line) for line in lines_rec)
|
||||
product_ids = list(set(line_rec['product_id'] for line_rec in lines_rec))
|
||||
products_rec = self.pool['product.product'].read(cr, uid, product_ids, ['cost_method', 'product_tmpl_id'], context=context)
|
||||
products_dict = dict((product['id'], product) for product in products_rec)
|
||||
cost_method_product_tmpl_ids = list(set(product['product_tmpl_id'][0] for product in products_rec if product['cost_method'] != 'real'))
|
||||
cr.execute('SELECT DISTINCT ON (product_template_id, company_id) product_template_id, company_id, cost FROM product_price_history WHERE product_template_id in %s AND datetime <= %s ORDER BY product_template_id, company_id, datetime DESC', (tuple(cost_method_product_tmpl_ids), date))
|
||||
histories = cr.dictfetchall()
|
||||
histories = []
|
||||
if cost_method_product_tmpl_ids:
|
||||
cr.execute('SELECT DISTINCT ON (product_template_id, company_id) product_template_id, company_id, cost FROM product_price_history WHERE product_template_id in %s AND datetime <= %s ORDER BY product_template_id, company_id, datetime DESC', (tuple(cost_method_product_tmpl_ids), date))
|
||||
histories = cr.dictfetchall()
|
||||
histories_dict = {}
|
||||
for history in histories:
|
||||
histories_dict[(history['product_template_id'], history['company_id'])] = history['cost']
|
||||
@@ -158,8 +162,11 @@ class stock_history(osv.osv):
|
||||
LEFT JOIN
|
||||
product_template ON product_template.id = product_product.product_tmpl_id
|
||||
WHERE quant.qty>0 AND stock_move.state = 'done' AND dest_location.usage in ('internal', 'transit')
|
||||
AND ((source_location.company_id is null and dest_location.company_id is not null) or
|
||||
(source_location.company_id is not null and dest_location.company_id is null) or source_location.company_id != dest_location.company_id)
|
||||
AND (
|
||||
(source_location.company_id is null and dest_location.company_id is not null) or
|
||||
(source_location.company_id is not null and dest_location.company_id is null) or
|
||||
source_location.company_id != dest_location.company_id or
|
||||
source_location.usage not in ('internal', 'transit'))
|
||||
) UNION
|
||||
(SELECT
|
||||
'-' || stock_move.id::text || '-' || quant.id::text AS id,
|
||||
@@ -192,8 +199,11 @@ class stock_history(osv.osv):
|
||||
LEFT JOIN
|
||||
product_template ON product_template.id = product_product.product_tmpl_id
|
||||
WHERE quant.qty>0 AND stock_move.state = 'done' AND source_location.usage in ('internal', 'transit')
|
||||
AND ((dest_location.company_id is null and source_location.company_id is not null) or
|
||||
(dest_location.company_id is not null and source_location.company_id is null) or dest_location.company_id != source_location.company_id)
|
||||
AND (
|
||||
(dest_location.company_id is null and source_location.company_id is not null) or
|
||||
(dest_location.company_id is not null and source_location.company_id is null) or
|
||||
dest_location.company_id != source_location.company_id or
|
||||
dest_location.usage not in ('internal', 'transit'))
|
||||
))
|
||||
AS foo
|
||||
GROUP BY move_id, location_id, company_id, product_id, product_categ_id, date, price_unit_on_quant, source, product_template_id, serial_number
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user