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

This commit is contained in:
Christophe Simonis
2015-07-22 16:17:54 +02:00
493 changed files with 18887 additions and 14489 deletions
+2
View File
@@ -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
+1
View File
@@ -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,
+3 -1
View File
@@ -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,
+5 -3
View File
@@ -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"
+2 -4
View File
@@ -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):
+2
View File
@@ -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.
+8 -3
View File
@@ -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)
+2 -1
View File
@@ -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()
+15 -12
View File
@@ -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
-2
View File
@@ -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')])]"/>
+1 -1
View File
@@ -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;
+7 -6
View File
@@ -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):
+1 -7
View File
@@ -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'):
+3
View File
@@ -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'
+3 -2
View File
@@ -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.
-
+3 -4
View File
@@ -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'),
+4 -1
View File
@@ -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 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
6 access_delivery_grid_manager delivery.grid model_delivery_grid base.group_sale_manager 1 1 1 1
7 access_delivery_grid_line_manager delivery.grid.line model_delivery_grid_line base.group_sale_manager 1 1 1 1
8 access_delivery_carrier_partner_manager delivery.carrier partner_manager model_delivery_carrier base.group_partner_manager 1 0 0 0
9 access_delivery_carrier_stock_user delivery.carrier stock_user model_delivery_carrier stock.group_stock_user 1 0 0 0
10 access_delivery_carrier_stock_manager delivery.carrier model_delivery_carrier stock.group_stock_manager 1 1 1 1
11 access_delivery_grid_stock_manager delivery.grid model_delivery_grid stock.group_stock_manager 1 1 1 1
12 access_delivery_grid_line_stock_manager delivery.grid.line model_delivery_grid_line stock.group_stock_manager 1 1 1 1
+1 -1
View File
@@ -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>
-2
View File
@@ -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.
+4
View File
@@ -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'
+10 -8
View File
@@ -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>
-3
View File
@@ -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.
-
+1 -1
View File
@@ -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"/>
+1 -1
View File
@@ -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() + """,
+1
View File
@@ -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
+1
View File
@@ -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,
+3
View File
@@ -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>
+231 -17
View File
@@ -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&amp;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&amp;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&amp;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>
+2 -1
View File
@@ -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>)
+2 -1
View File
@@ -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 -1
View File
@@ -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">
+43 -43
View File
@@ -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"
1 id country_id/id code name
2 RO_AB base.ro AB Alba
3 RO_AG base.ro AG Argeș
4 RO_AR base.ro AR Arad
5 RO_B base.ro B București
6 RO_BC base.ro BC Bacău
7 RO_BH base.ro BH Bihor
8 RO_BN base.ro BN Bistrița-Năsăud
9 RO_BR base.ro BR Brăila
10 RO_BT base.ro BT Botoșani
11 RO_BV base.ro BV Brașov
12 RO_BZ base.ro BZ Buzău
13 RO_CJ base.ro CJ Cluj
14 RO_CL base.ro CL Călărași
15 RO_CS base.ro CS Caraș Severin
16 RO_CT base.ro CT Constanța
17 RO_CV base.ro CV Covasna
18 RO_DB base.ro DB Dâmbovița
19 RO_DJ base.ro DJ Dolj
20 RO_GJ base.ro GJ Gorj
21 RO_GL base.ro GL Galați
22 RO_GR base.ro GR Giurgiu
23 RO_HD base.ro HD Hunedoara
24 RO_HR base.ro HR Harghita
25 RO_IF base.ro IF Ilfov
26 RO_IL base.ro IL Ialomița
27 RO_IS base.ro IS Iași
28 RO_MH base.ro MH Mehedinți
29 RO_MM base.ro MM Maramureș
30 RO_MS base.ro MS Mureș
31 RO_NT base.ro NT Neamț
32 RO_OT base.ro OT Olt
33 RO_PH base.ro PH Prahova
34 RO_SB base.ro SB Sibiu
35 RO_SJ base.ro SJ Sălaj
36 RO_SM base.ro SM Satu Mare
37 RO_SV base.ro SV Suceava
38 RO_TL base.ro TL Tulcea
39 RO_TM base.ro TM Timiș
40 RO_TR base.ro TR Teleorman
41 RO_VL base.ro VL Vâlcea
42 RO_VN base.ro VN Vrancea
43 RO_VS base.ro VS Vaslui
+19 -11
View File
@@ -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')):
+3 -1
View File
@@ -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();
});
},
+1 -1
View File
@@ -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'>
+40 -40
View File
@@ -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'
+16 -13
View File
@@ -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
View File
@@ -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
View File
@@ -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):
+1 -3
View File
@@ -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
+21 -6
View File
@@ -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'}
+2 -1
View File
@@ -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.
+1 -1
View File
@@ -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
+1 -3
View File
@@ -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
+1 -1
View File
@@ -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):
+2 -2
View File
@@ -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',
+1 -1
View File
@@ -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)
+11 -10
View File
@@ -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({
+28 -9
View File
@@ -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,
}
+1 -1
View File
@@ -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 [];
+2 -4
View File
@@ -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">
+1 -1
View File
@@ -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"),
+11 -3
View File
@@ -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
+6 -6
View File
@@ -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)
+2 -3
View File
@@ -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:
+1 -1
View File
@@ -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,
+1 -3
View File
@@ -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
-
+11 -3
View File
@@ -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})
+15 -3
View File
@@ -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,
+10 -3
View File
@@ -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,
+1 -1
View File
@@ -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
+2
View File
@@ -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:
+3
View File
@@ -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;
}
+14 -1
View File
@@ -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
View File
@@ -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}
+2 -2
View File
@@ -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','&lt;&gt;', 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"/>
-2
View File
@@ -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.
-5
View File
@@ -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 ""
+7 -6
View File
@@ -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):
+29 -20
View File
@@ -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
View File
@@ -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:
+3 -3
View File
@@ -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
View File
@@ -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,
+1 -1
View File
@@ -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"/>
-2
View File
@@ -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.
+1 -1
View File
@@ -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