mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-08-17 16:54:42 -05:00
[PATCH] Upstream patch - 11082023
This commit is contained in:
@@ -3106,11 +3106,13 @@ class AccountMove(models.Model):
|
||||
for ids in self._cr.split_for_in_conditions(records.ids, size=100):
|
||||
moves = self.browse(ids)
|
||||
try: # try posting in batch
|
||||
moves._post()
|
||||
with self.env.cr.savepoint():
|
||||
moves._post()
|
||||
except UserError: # if at least one move cannot be posted, handle moves one by one
|
||||
for move in moves:
|
||||
try:
|
||||
move._post()
|
||||
with self.env.cr.savepoint():
|
||||
move._post()
|
||||
except UserError as e:
|
||||
move.to_check = True
|
||||
msg = _('The move could not be posted for the following reason: %(error_message)s', error_message=e)
|
||||
|
||||
@@ -766,7 +766,13 @@ class HrExpenseSheet(models.Model):
|
||||
return self.env['account.journal'].search([('type', 'in', ['cash', 'bank']), ('company_id', '=', default_company_id)], limit=1)
|
||||
|
||||
name = fields.Char('Expense Report Summary', required=True, tracking=True)
|
||||
expense_line_ids = fields.One2many('hr.expense', 'sheet_id', string='Expense Lines', copy=False)
|
||||
expense_line_ids = fields.One2many(
|
||||
comodel_name='hr.expense',
|
||||
inverse_name='sheet_id',
|
||||
string='Expense Lines',
|
||||
copy=False,
|
||||
states={'post': [('readonly', True)], 'done': [('readonly', True)], 'cancel': [('readonly', True)]}
|
||||
)
|
||||
state = fields.Selection([
|
||||
('draft', 'Draft'),
|
||||
('submit', 'Submitted'),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from flectra import api, fields, models
|
||||
from flectra.tools.sql import column_exists, create_column
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
@@ -10,6 +11,18 @@ class ProductTemplate(models.Model):
|
||||
can_be_expensed = fields.Boolean(string="Can be Expensed", compute='_compute_can_be_expensed',
|
||||
store=True, readonly=False, help="Specify whether the product can be selected in an expense.")
|
||||
|
||||
def _auto_init(self):
|
||||
if not column_exists(self.env.cr, "product_template", "can_be_expensed"):
|
||||
create_column(self.env.cr, "product_template", "can_be_expensed", "boolean")
|
||||
self.env.cr.execute(
|
||||
"""
|
||||
UPDATE product_template
|
||||
SET can_be_expensed = false
|
||||
WHERE type NOT IN ('consu', 'service')
|
||||
"""
|
||||
)
|
||||
return super()._auto_init()
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
result = super(ProductTemplate, self).default_get(fields)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
from flectra import api, fields, models
|
||||
from flectra.exceptions import UserError
|
||||
from flectra.tools.translate import _
|
||||
from flectra import fields, models
|
||||
|
||||
class AccountTaxTemplate(models.Model):
|
||||
_inherit = 'account.tax.template'
|
||||
@@ -18,23 +16,6 @@ class AccountTax(models.Model):
|
||||
l10n_de_datev_code = fields.Char(size=4, help="4 digits code use by Datev")
|
||||
|
||||
|
||||
class AccountMove(models.Model):
|
||||
_inherit = 'account.move'
|
||||
|
||||
def _post(self, soft=True):
|
||||
# OVERRIDE to check the invoice lines taxes.
|
||||
for invoice in self.filtered(lambda move: move.is_invoice()):
|
||||
for line in invoice.invoice_line_ids:
|
||||
account_tax = line.account_id.tax_ids.ids
|
||||
if account_tax and invoice.company_id.country_id.code == 'DE':
|
||||
account_name = line.account_id.name
|
||||
for tax in line.tax_ids:
|
||||
if tax.id not in account_tax:
|
||||
raise UserError(_('Account %s does not authorize to have tax %s specified on the line. \
|
||||
Change the tax used in this invoice or remove all taxes from the account') % (account_name, tax.name))
|
||||
return super()._post(soft)
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = "product.template"
|
||||
|
||||
|
||||
@@ -3574,7 +3574,7 @@
|
||||
<record id="account_tax_template_s_irpf24_rdc" model="account.tax.template">
|
||||
<field name="description">Retención 24% (Rendimientos del capital)</field>
|
||||
<field name="type_tax_use">sale</field>
|
||||
<field name="name">Retenciones a cuenta IRPF 24%</field>
|
||||
<field name="name">Retenciones a cuenta IRPF 24% (Rendimientos del capital)</field>
|
||||
<field name="chart_template_id" ref="l10n_es.account_chart_template_common"/>
|
||||
<field name="amount" eval="-24"/>
|
||||
<field name="amount_type">percent</field>
|
||||
|
||||
@@ -109,6 +109,7 @@ class Partner(models.Model):
|
||||
invoice_vals_list.append({
|
||||
'move_type': 'out_invoice',
|
||||
'partner_id': partner.id,
|
||||
'invoice_payment_term_id': partner.property_payment_term_id.id,
|
||||
'invoice_line_ids': [
|
||||
(0, None, {'product_id': product.id, 'quantity': 1, 'price_unit': amount, 'tax_ids': [(6, 0, product.taxes_id.ids)]})
|
||||
]
|
||||
|
||||
@@ -158,3 +158,23 @@ class TestMembership(TestMembershipCommon):
|
||||
self.partner_1._compute_membership_state()
|
||||
self.assertEqual(invoice.state, 'cancel')
|
||||
self.assertEqual(self.partner_1.membership_state, 'canceled')
|
||||
|
||||
def test_apply_payment_term(self):
|
||||
"""
|
||||
Check if the payment term defined on the partner is applied to the invoice
|
||||
"""
|
||||
pay_term_15_days_after_today = self.env['account.payment.term'].create({
|
||||
'name': '15 days after today',
|
||||
'line_ids': [
|
||||
(0, 0, {
|
||||
'value': 'balance',
|
||||
'days': 15,
|
||||
'option': 'day_after_invoice_date',
|
||||
}),
|
||||
],
|
||||
})
|
||||
self.partner_1.write({
|
||||
'property_payment_term_id': pay_term_15_days_after_today.id,
|
||||
})
|
||||
invoice = self.partner_1.create_membership_invoice(self.membership_1, 100.0)
|
||||
self.assertEqual(invoice.invoice_payment_term_id, pay_term_15_days_after_today)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from pytz import timezone, utc
|
||||
|
||||
from flectra import api, fields, models
|
||||
@@ -73,7 +73,7 @@ class EventSponsor(models.Model):
|
||||
for sponsor in self:
|
||||
if not sponsor.event_id.is_ongoing:
|
||||
sponsor.is_in_opening_hours = False
|
||||
elif not sponsor.hour_from or not sponsor.hour_to:
|
||||
elif sponsor.hour_from is False or sponsor.hour_to is False:
|
||||
sponsor.is_in_opening_hours = True
|
||||
else:
|
||||
event_tz = timezone(sponsor.event_id.date_tz)
|
||||
@@ -86,6 +86,9 @@ class EventSponsor(models.Model):
|
||||
# compute opening hours
|
||||
opening_from_tz = event_tz.localize(datetime.combine(now_tz.date(), float_to_time(sponsor.hour_from)))
|
||||
opening_to_tz = event_tz.localize(datetime.combine(now_tz.date(), float_to_time(sponsor.hour_to)))
|
||||
if sponsor.hour_to == 0:
|
||||
# when closing 'at midnight', we consider it's at midnight the next day
|
||||
opening_to_tz = opening_to_tz + timedelta(days=1)
|
||||
|
||||
opening_from = max([dt_begin, opening_from_tz])
|
||||
opening_to = min([dt_end, opening_to_tz])
|
||||
|
||||
@@ -31,7 +31,7 @@ class TestSponsorData(TestEventTrackOnlineCommon):
|
||||
@users('user_eventmanager')
|
||||
def test_event_date_computation(self):
|
||||
""" Test date computation. Pay attention that mocks returns UTC values, meaning
|
||||
we have to take into account Europe/Brussels offset """
|
||||
we have to take into account Europe/Brussels offset (+2 in July) """
|
||||
event = self.env['event.event'].browse(self.event_0.id)
|
||||
sponsor = self.env['event.sponsor'].browse(self.sponsor_0.id)
|
||||
event.invalidate_cache(fnames=['is_ongoing'])
|
||||
@@ -85,3 +85,36 @@ class TestSponsorData(TestEventTrackOnlineCommon):
|
||||
sponsor.invalidate_cache(fnames=['is_in_opening_hours'])
|
||||
self.assertFalse(sponsor.is_in_opening_hours)
|
||||
self.assertFalse(event.is_ongoing)
|
||||
|
||||
# Use "00:00" as opening hours for sponsor -> should still work
|
||||
event.invalidate_cache(fnames=['is_ongoing'])
|
||||
sponsor.hour_from = 0.0 # 0 -> 18
|
||||
|
||||
# Inside opening hours (17 < 18)
|
||||
self.mock_wevent_dt.now.return_value = datetime(2020, 7, 6, 15, 0, 1)
|
||||
self.mock_wevent_exhib_dt.now.return_value = datetime(2020, 7, 6, 15, 0, 1)
|
||||
sponsor.invalidate_cache(fnames=['is_in_opening_hours'])
|
||||
self.assertTrue(sponsor.is_in_opening_hours)
|
||||
|
||||
# Outside opening hours (21 > 18)
|
||||
self.mock_wevent_dt.now.return_value = datetime(2020, 7, 6, 19, 0, 1)
|
||||
self.mock_wevent_exhib_dt.now.return_value = datetime(2020, 7, 6, 19, 0, 1)
|
||||
sponsor.invalidate_cache(fnames=['is_in_opening_hours'])
|
||||
self.assertFalse(sponsor.is_in_opening_hours)
|
||||
|
||||
# Use "00:00" as closing hours for sponsor -> should still work
|
||||
# (considered 'at midnight the next day')
|
||||
sponsor.hour_from = 10.0
|
||||
sponsor.hour_to = 0.0
|
||||
|
||||
# Inside opening hours (11 > 10)
|
||||
self.mock_wevent_dt.now.return_value = datetime(2020, 7, 6, 9, 0, 1)
|
||||
self.mock_wevent_exhib_dt.now.return_value = datetime(2020, 7, 6, 9, 0, 1)
|
||||
sponsor.invalidate_cache(fnames=['is_in_opening_hours'])
|
||||
self.assertTrue(sponsor.is_in_opening_hours)
|
||||
|
||||
# Outside opening hours (7 < 10)
|
||||
self.mock_wevent_dt.now.return_value = datetime(2020, 7, 6, 5, 0, 1)
|
||||
self.mock_wevent_exhib_dt.now.return_value = datetime(2020, 7, 6, 5, 0, 1)
|
||||
sponsor.invalidate_cache(fnames=['is_in_opening_hours'])
|
||||
self.assertFalse(sponsor.is_in_opening_hours)
|
||||
|
||||
@@ -9,10 +9,10 @@ from datetime import datetime
|
||||
from psycopg2 import IntegrityError
|
||||
from werkzeug.exceptions import BadRequest
|
||||
|
||||
from flectra import http, SUPERUSER_ID, _
|
||||
from flectra import http, SUPERUSER_ID
|
||||
from flectra.http import request
|
||||
from flectra.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
from flectra.tools.translate import _
|
||||
from flectra.tools.translate import _, _lt
|
||||
from flectra.exceptions import ValidationError, UserError
|
||||
from flectra.addons.base.models.ir_qweb_fields import nl2br
|
||||
|
||||
@@ -87,7 +87,7 @@ class WebsiteForm(http.Controller):
|
||||
|
||||
# Constants string to make metadata readable on a text field
|
||||
|
||||
_meta_label = "%s\n________\n\n" % _("Metadata") # Title for meta data
|
||||
_meta_label = _lt("Metadata") # Title for meta data
|
||||
|
||||
# Dict of dynamically called filters following type of field to be fault tolerent
|
||||
|
||||
@@ -218,7 +218,7 @@ class WebsiteForm(http.Controller):
|
||||
default_field_data = values.get(default_field.name, '')
|
||||
custom_content = (default_field_data + "\n\n" if default_field_data else '') \
|
||||
+ (_custom_label + custom + "\n\n" if custom else '') \
|
||||
+ (self._meta_label + meta if meta else '')
|
||||
+ (self._meta_label + "\n________\n\n" + meta if meta else '')
|
||||
|
||||
# If there is a default field configured for this model, use it.
|
||||
# If there isn't, put the custom data in a message instead
|
||||
|
||||
@@ -649,7 +649,7 @@ class WebsiteForum(WebsiteProfile):
|
||||
down_votes = rec['vote_count']
|
||||
|
||||
# Votes which given by users on others questions and answers.
|
||||
vote_ids = Vote.search([('user_id', '=', user.id)])
|
||||
vote_ids = Vote.search([('user_id', '=', user.id), ('forum_id', 'in', forums.ids)])
|
||||
|
||||
# activity by user.
|
||||
model, comment = Data.get_object_reference('mail', 'mt_comment')
|
||||
|
||||
@@ -63,7 +63,6 @@
|
||||
|
||||
<record id="product.product_product_6" model="product.product">
|
||||
<field name="is_published" eval="True"/>
|
||||
<field name="website_sequence">10010</field>
|
||||
</record>
|
||||
|
||||
<record id="product.product_product_7" model="product.product">
|
||||
@@ -183,6 +182,7 @@
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_cabinets')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_11_product_template" model="product.template">
|
||||
<field name="website_sequence">9990</field>
|
||||
<field name="public_categ_ids" eval="[(6,0,[ref('public_category_furnitures_chairs')])]"/>
|
||||
</record>
|
||||
<record id="product.product_product_12_product_template" model="product.template">
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
import logging
|
||||
|
||||
from flectra import api, fields, models, tools, _
|
||||
from flectra.exceptions import ValidationError, UserError
|
||||
@@ -7,6 +8,9 @@ from flectra.addons.http_routing.models.ir_http import slug
|
||||
from flectra.addons.website.models import ir_http
|
||||
from flectra.tools.translate import html_translate
|
||||
from flectra.osv import expression
|
||||
from psycopg2.extras import execute_values
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ProductRibbon(models.Model):
|
||||
@@ -339,6 +343,25 @@ class ProductTemplate(models.Model):
|
||||
website = self.website_id or kwargs.get('website')
|
||||
return website and website.company_id or res
|
||||
|
||||
def _init_column(self, column_name):
|
||||
# to avoid generating a single default website_sequence when installing the module,
|
||||
# we need to set the default row by row for this column
|
||||
if column_name == "website_sequence":
|
||||
_logger.debug("Table '%s': setting default value of new column %s to unique values for each row", self._table, column_name)
|
||||
self.env.cr.execute("SELECT id FROM %s WHERE website_sequence IS NULL" % self._table)
|
||||
prod_tmpl_ids = self.env.cr.dictfetchall()
|
||||
max_seq = self._default_website_sequence()
|
||||
query = """
|
||||
UPDATE {table}
|
||||
SET website_sequence = p.web_seq
|
||||
FROM (VALUES %s) AS p(p_id, web_seq)
|
||||
WHERE id = p.p_id
|
||||
""".format(table=self._table)
|
||||
values_args = [(prod_tmpl['id'], max_seq + i * 5) for i, prod_tmpl in enumerate(prod_tmpl_ids)]
|
||||
execute_values(self.env.cr._obj, query, values_args)
|
||||
else:
|
||||
super(ProductTemplate, self)._init_column(column_name)
|
||||
|
||||
def _default_website_sequence(self):
|
||||
''' We want new product to be the last (highest seq).
|
||||
Every product should ideally have an unique sequence.
|
||||
|
||||
Reference in New Issue
Block a user