[MERGE] forward port branch 10.0 up to c0fa5228d8
This commit is contained in:
@@ -7,7 +7,8 @@ from odoo import fields, models
|
||||
class AccountConfigSettings(models.TransientModel):
|
||||
_inherit = 'account.config.settings'
|
||||
|
||||
fiscalyear_last_day = fields.Integer(related='company_id.fiscalyear_last_day', default=31)
|
||||
fiscalyear_last_day = fields.Integer(related='company_id.fiscalyear_last_day',
|
||||
default=lambda self: self._default_fiscalyear_last_day())
|
||||
fiscalyear_last_month = fields.Selection([
|
||||
(1, 'January'),
|
||||
(2, 'February'),
|
||||
@@ -20,8 +21,10 @@ class AccountConfigSettings(models.TransientModel):
|
||||
(9, 'September'),
|
||||
(10, 'October'),
|
||||
(11, 'November'),
|
||||
(12, 'December')
|
||||
], related='company_id.fiscalyear_last_month', default=12)
|
||||
(12, 'December')],
|
||||
related='company_id.fiscalyear_last_month',
|
||||
default=lambda self: self._default_fiscalyear_last_month())
|
||||
|
||||
period_lock_date = fields.Date(related='company_id.period_lock_date')
|
||||
fiscalyear_lock_date = fields.Date(related='company_id.fiscalyear_lock_date')
|
||||
use_anglo_saxon = fields.Boolean(string='Anglo-Saxon Accounting', related='company_id.anglo_saxon_accounting')
|
||||
@@ -33,3 +36,9 @@ class AccountConfigSettings(models.TransientModel):
|
||||
'account.journal',
|
||||
related='company_id.tax_cash_basis_journal_id',
|
||||
string="Tax Cash Basis Journal",)
|
||||
|
||||
def _default_fiscalyear_last_day(self):
|
||||
return self.env.user.company_id.fiscalyear_last_day or 31
|
||||
|
||||
def _default_fiscalyear_last_month(self):
|
||||
return self.env.user.company_id.fiscalyear_last_month or 12
|
||||
|
||||
@@ -339,15 +339,22 @@ class PosOrder(models.Model):
|
||||
for order in self:
|
||||
aml = order.statement_ids.mapped('journal_entry_ids') | order.account_move.line_ids | order.invoice_id.move_id.line_ids
|
||||
aml = aml.filtered(lambda r: not r.reconciled and r.account_id.internal_type == 'receivable' and r.partner_id == order.partner_id.commercial_partner_id)
|
||||
|
||||
# Reconcile returns first
|
||||
# to avoid mixing up the credit of a payment and the credit of a return
|
||||
# in the receivable account
|
||||
aml_returns = aml.filtered(lambda l: (l.journal_id.type == 'sale' and l.credit) or (l.journal_id.type != 'sale' and l.debit))
|
||||
try:
|
||||
aml.reconcile()
|
||||
aml_returns.reconcile()
|
||||
(aml - aml_returns).reconcile()
|
||||
except Exception:
|
||||
# There might be unexpected situations where the automatic reconciliation won't
|
||||
# work. We don't want the user to be blocked because of this, since the automatic
|
||||
# reconciliation is introduced for convenience, not for mandatory accounting
|
||||
# reasons.
|
||||
_logger.error('Reconciliation did not work for order %s', order.name)
|
||||
continue
|
||||
# It may be interesting to have the Traceback logged anyway
|
||||
# for debugging and support purposes
|
||||
_logger.exception('Reconciliation did not work for order %s', order.name)
|
||||
|
||||
def _default_session(self):
|
||||
return self.env['pos.session'].search([('state', '=', 'opened'), ('user_id', '=', self.env.uid)], limit=1)
|
||||
|
||||
@@ -27,7 +27,7 @@ access_product_category_manager,product.category manager,product.model_product_c
|
||||
access_product_pricelist_manager,product.pricelist manager,product.model_product_pricelist,group_pos_manager,1,0,0,0
|
||||
access_pos_session_user,pos.session user,model_pos_session,group_pos_user,1,1,1,0
|
||||
access_pos_config_user,pos.config user,model_pos_config,group_pos_user,1,1,0,0
|
||||
access_pos_config_manager,pos.config user,model_pos_config,group_pos_manager,1,1,1,0
|
||||
access_pos_config_manager,pos.config manager,model_pos_config,group_pos_manager,1,1,1,1
|
||||
access_product_category_pos_manager,pos.category manager,model_pos_category,group_pos_manager,1,1,1,1
|
||||
access_product_category_pos_user,pos.category user,model_pos_category,group_pos_user,1,0,0,0
|
||||
access_barcode_nomenclature_pos_user,barcode.nomenclature.pos.user,barcodes.model_barcode_nomenclature,group_pos_user,1,0,0,0
|
||||
|
||||
|
@@ -454,9 +454,9 @@ class InventoryLine(models.Model):
|
||||
continue
|
||||
diff = line.theoretical_qty - line.product_qty
|
||||
if diff < 0: # found more than expected
|
||||
vals = self._get_move_values(abs(diff), line.product_id.property_stock_inventory.id, line.location_id.id)
|
||||
vals = line._get_move_values(abs(diff), line.product_id.property_stock_inventory.id, line.location_id.id)
|
||||
else:
|
||||
vals = self._get_move_values(abs(diff), line.location_id.id, line.product_id.property_stock_inventory.id)
|
||||
vals = line._get_move_values(abs(diff), line.location_id.id, line.product_id.property_stock_inventory.id)
|
||||
move = moves.create(vals)
|
||||
|
||||
if diff > 0:
|
||||
|
||||
@@ -15,7 +15,7 @@ class WebsiteEventTrackController(http.Controller):
|
||||
|
||||
@http.route(['''/event/<model("event.event"):event>/track/<model("event.track", "[('event_id','=',event[0])]"):track>'''], type='http', auth="public", website=True)
|
||||
def event_track_view(self, event, track, **post):
|
||||
track = track.sudo()
|
||||
track = track.sudo().with_context(tz=event.date_tz or 'UTC')
|
||||
values = {'track': track, 'event': track.event_id, 'main_object': track}
|
||||
return request.render("website_event_track.track_view", values)
|
||||
|
||||
@@ -67,6 +67,7 @@ class WebsiteEventTrackController(http.Controller):
|
||||
|
||||
@http.route(['''/event/<model("event.event", "[('show_tracks','=',1)]"):event>/agenda'''], type='http', auth="public", website=True)
|
||||
def event_agenda(self, event, tag=None, **post):
|
||||
event = event.with_context(tz=event.date_tz or 'UTC')
|
||||
local_tz = pytz.timezone(event.date_tz or 'UTC')
|
||||
days_tracks = collections.defaultdict(lambda: [])
|
||||
for track in event.track_ids.sorted(lambda track: (track.date, bool(track.location_id))):
|
||||
@@ -99,6 +100,7 @@ class WebsiteEventTrackController(http.Controller):
|
||||
'''/event/<model("event.event", "[('show_tracks','=',1)]"):event>/track/tag/<model("event.track.tag"):tag>'''
|
||||
], type='http', auth="public", website=True)
|
||||
def event_tracks(self, event, tag=None, **post):
|
||||
event = event.with_context(tz=event.date_tz or 'UTC')
|
||||
searches = {}
|
||||
if tag:
|
||||
searches.update(tag=tag.id)
|
||||
|
||||
@@ -250,7 +250,9 @@
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<b>Date</b><br/>
|
||||
<span t-field="track.date" t-options='{"hide_seconds":"True"}'/><br/>
|
||||
<span t-field="track.date" t-options='{"hide_seconds":"True"}'/>
|
||||
<t t-if="event.date_tz">(<span t-field="event.date_tz"/>)</t>
|
||||
<br/>
|
||||
<b>Duration</b><br/>
|
||||
<span t-field="track.duration" t-options='{"widget": "duration", "unit": "hour", "round": "minute"}'/><br/>
|
||||
<b>Location</b><br/>
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
Belarus, 2017-01-17
|
||||
|
||||
I hereby agree to the terms of the Odoo Individual Contributor License
|
||||
Agreement v1.0.
|
||||
|
||||
I declare that I am authorized and able to make this agreement and sign this
|
||||
declaration.
|
||||
|
||||
Signed,
|
||||
|
||||
Sergei Ruzki sergei.ruzki@icode.by https://github.com/sergeiruzkiicode
|
||||
@@ -258,8 +258,8 @@
|
||||
<field name="name">Belarus</field>
|
||||
<field name="code">by</field>
|
||||
<field file="base/static/img/country_flags/by.png" name="image" type="base64" />
|
||||
<field name="currency_id" ref="BYR" />
|
||||
<field eval="0" name="phone_code" />
|
||||
<field name="currency_id" ref="BYN" />
|
||||
<field eval="375" name="phone_code" />
|
||||
</record>
|
||||
<record id="bz" model="res.country">
|
||||
<field name="name">Belize</field>
|
||||
|
||||
@@ -408,6 +408,13 @@
|
||||
<field name="active" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record id="BYN" model="res.currency">
|
||||
<field name="name">BYN</field>
|
||||
<field name="symbol">Br</field>
|
||||
<field name="rounding">0.01</field>
|
||||
<field name="active" eval="False"/>
|
||||
</record>
|
||||
|
||||
<record id="BZD" model="res.currency">
|
||||
<field name="name">BZD</field>
|
||||
<field name="symbol">BZ$</field>
|
||||
|
||||
@@ -349,6 +349,12 @@
|
||||
<field name="rate">10228.19</field>
|
||||
</record>
|
||||
|
||||
<record forcecreate="0" id="rateBYN" model="res.currency.rate">
|
||||
<field name="currency_id" ref="BYN" />
|
||||
<field name="name">2016-07-01</field>
|
||||
<field name="rate">2.23151</field>
|
||||
</record>
|
||||
|
||||
<record forcecreate="0" id="rateBZD" model="res.currency.rate">
|
||||
<field name="currency_id" ref="BZD" />
|
||||
<field name="name">2010-01-01</field>
|
||||
|
||||
@@ -14,6 +14,7 @@ from odoo.exceptions import AccessDenied, AccessError, UserError, ValidationErro
|
||||
from odoo.osv import expression
|
||||
from odoo.service.db import check_super
|
||||
from odoo.tools import partition
|
||||
from odoo.http import root
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -372,6 +373,8 @@ class Users(models.Model):
|
||||
if any(key.startswith('context_') or key in ('lang', 'tz') for key in values):
|
||||
self.context_get.clear_cache(self)
|
||||
if any(key in values for key in ['active'] + USER_PRIVATE_FIELDS):
|
||||
# force deletion of all sessions for these users
|
||||
root.session_store.delete_sessions_for_uids(self.ids)
|
||||
db = self._cr.dbname
|
||||
for id in self.ids:
|
||||
self.__uid_cache[db].pop(id, None)
|
||||
@@ -385,7 +388,10 @@ class Users(models.Model):
|
||||
db = self._cr.dbname
|
||||
for id in self.ids:
|
||||
self.__uid_cache[db].pop(id, None)
|
||||
return super(Users, self).unlink()
|
||||
res = super(Users, self).unlink()
|
||||
# force deletion of all sessions for these users
|
||||
root.session_store.delete_sessions_for_uids(self.ids)
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def name_search(self, name='', args=None, operator='ilike', limit=100):
|
||||
|
||||
+12
-4
@@ -1040,7 +1040,6 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
|
||||
self.db = db
|
||||
self.uid = uid
|
||||
self.login = login
|
||||
self.password = password
|
||||
request.uid = uid
|
||||
request.disable_db = False
|
||||
|
||||
@@ -1055,7 +1054,6 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
|
||||
"""
|
||||
if not self.db or not self.uid:
|
||||
raise SessionExpiredException("Session expired")
|
||||
security.check(self.db, self.uid, self.password)
|
||||
|
||||
def logout(self, keep_db=False):
|
||||
for k in self.keys():
|
||||
@@ -1068,7 +1066,6 @@ class OpenERPSession(werkzeug.contrib.sessions.Session):
|
||||
self.setdefault("db", None)
|
||||
self.setdefault("uid", None)
|
||||
self.setdefault("login", None)
|
||||
self.setdefault("password", None)
|
||||
self.setdefault("context", {})
|
||||
|
||||
def get_context(self):
|
||||
@@ -1281,6 +1278,17 @@ class DisableCacheMiddleware(object):
|
||||
start_response(status, new_headers)
|
||||
return self.app(environ, start_wrapped)
|
||||
|
||||
class OdooSessionStore(werkzeug.contrib.sessions.FilesystemSessionStore):
|
||||
def delete_sessions_for_uids(self, uids):
|
||||
# pretty expensive on large session stores, especially non-local!
|
||||
uids = set(uids)
|
||||
_logger.info('Deleting all HTTP sessions for UIDs %s', uids)
|
||||
for sid in self.list():
|
||||
s = self.get(sid)
|
||||
if s.uid and s.uid in uids:
|
||||
_logger.debug('Deleting session %s', sid)
|
||||
self.delete(s)
|
||||
|
||||
class Root(object):
|
||||
"""Root WSGI application for the OpenERP Web Client.
|
||||
"""
|
||||
@@ -1292,7 +1300,7 @@ class Root(object):
|
||||
# Setup http sessions
|
||||
path = odoo.tools.config.session_dir
|
||||
_logger.debug('HTTP sessions stored in: %s', path)
|
||||
return werkzeug.contrib.sessions.FilesystemSessionStore(path, session_class=OpenERPSession)
|
||||
return OdooSessionStore(path, session_class=OpenERPSession)
|
||||
|
||||
@lazy_property
|
||||
def nodb_routing_map(self):
|
||||
|
||||
Reference in New Issue
Block a user