[MERGE] forward port branch saas-11.3 up to b4555df336
This commit is contained in:
@@ -1370,6 +1370,8 @@ class AccountInvoice(models.Model):
|
||||
values[name] = line[name]
|
||||
elif name == 'invoice_line_tax_ids':
|
||||
values[name] = [(6, 0, line[name].ids)]
|
||||
elif name == 'analytic_tag_ids':
|
||||
values[name] = [(6, 0, line[name].ids)]
|
||||
result.append((0, 0, values))
|
||||
return result
|
||||
|
||||
|
||||
@@ -1532,15 +1532,15 @@ class AccountPartialReconcile(models.Model):
|
||||
'amount_currency': self.amount_currency and line.currency_id.round(-line.amount_currency * amount / line.balance) or 0.0,
|
||||
'partner_id': line.partner_id.id,
|
||||
})
|
||||
if newly_created_move:
|
||||
if move_date > (self.company_id.period_lock_date or '0000-00-00') and newly_created_move.date != move_date:
|
||||
# The move date should be the maximum date between payment and invoice (in case
|
||||
# of payment in advance). However, we should make sure the move date is not
|
||||
# recorded before the period lock date as the tax statement for this period is
|
||||
# probably already sent to the estate.
|
||||
newly_created_move.write({'date': move_date})
|
||||
# post move
|
||||
newly_created_move.post()
|
||||
if newly_created_move:
|
||||
if move_date > (self.company_id.period_lock_date or '0000-00-00') and newly_created_move.date != move_date:
|
||||
# The move date should be the maximum date between payment and invoice (in case
|
||||
# of payment in advance). However, we should make sure the move date is not
|
||||
# recorded before the period lock date as the tax statement for this period is
|
||||
# probably already sent to the estate.
|
||||
newly_created_move.write({'date': move_date})
|
||||
# post move
|
||||
newly_created_move.post()
|
||||
|
||||
def _create_tax_basis_move(self):
|
||||
# Check if company_journal for cash basis is set if not, raise exception
|
||||
|
||||
@@ -76,6 +76,47 @@ class Partner(models.Model):
|
||||
street_value += street_format[previous_pos:]
|
||||
partner.street = street_value
|
||||
|
||||
def _split_street_with_params(self, street_raw, street_format):
|
||||
street_fields = self.get_street_fields()
|
||||
vals = {}
|
||||
previous_pos = 0
|
||||
field_name = None
|
||||
# iter on fields in street_format, detected as '%(<field_name>)s'
|
||||
for re_match in re.finditer(r'%\(\w+\)s', street_format):
|
||||
field_pos = re_match.start()
|
||||
if not field_name:
|
||||
#first iteration: remove the heading chars
|
||||
street_raw = street_raw[field_pos:]
|
||||
|
||||
# get the substring between 2 fields, to be used as separator
|
||||
separator = street_format[previous_pos:field_pos]
|
||||
field_value = None
|
||||
if separator and field_name:
|
||||
#maxsplit set to 1 to unpack only the first element and let the rest untouched
|
||||
tmp = street_raw.split(separator, 1)
|
||||
if len(tmp) == 2:
|
||||
field_value, street_raw = tmp
|
||||
vals[field_name] = field_value
|
||||
if field_value or not field_name:
|
||||
# select next field to find (first pass OR field found)
|
||||
# [2:-2] is used to remove the extra chars '%(' and ')s'
|
||||
field_name = re_match.group()[2:-2]
|
||||
else:
|
||||
# value not found: keep looking for the same field
|
||||
pass
|
||||
if field_name not in street_fields:
|
||||
raise UserError(_("Unrecognized field %s in street format.") % field_name)
|
||||
previous_pos = re_match.end()
|
||||
|
||||
# last field value is what remains in street_raw minus trailing chars in street_format
|
||||
trailing_chars = street_format[previous_pos:]
|
||||
if trailing_chars and street_raw.endswith(trailing_chars):
|
||||
vals[field_name] = street_raw[:-len(trailing_chars)]
|
||||
else:
|
||||
vals[field_name] = street_raw
|
||||
return vals
|
||||
|
||||
|
||||
@api.multi
|
||||
@api.depends('street')
|
||||
def _split_street(self):
|
||||
@@ -90,47 +131,18 @@ class Partner(models.Model):
|
||||
|
||||
street_format = (partner.country_id.street_format or
|
||||
'%(street_number)s/%(street_number2)s %(street_name)s')
|
||||
vals = {}
|
||||
previous_pos = 0
|
||||
street_raw = partner.street
|
||||
field_name = None
|
||||
# iter on fields in street_format, detected as '%(<field_name>)s'
|
||||
for re_match in re.finditer(r'%\(\w+\)s', street_format):
|
||||
field_pos = re_match.start()
|
||||
if not field_name:
|
||||
#first iteration: remove the heading chars
|
||||
street_raw = street_raw[field_pos:]
|
||||
|
||||
# get the substring between 2 fields, to be used as separator
|
||||
separator = street_format[previous_pos:field_pos]
|
||||
field_value = None
|
||||
if separator and field_name:
|
||||
#maxsplit set to 1 to unpack only the first element and let the rest untouched
|
||||
tmp = street_raw.split(separator, 1)
|
||||
if len(tmp) == 2:
|
||||
field_value, street_raw = tmp
|
||||
vals[field_name] = field_value
|
||||
if field_value or not field_name:
|
||||
# select next field to find (first pass OR field found)
|
||||
# [2:-2] is used to remove the extra chars '%(' and ')s'
|
||||
field_name = re_match.group()[2:-2]
|
||||
else:
|
||||
# value not found: keep looking for the same field
|
||||
pass
|
||||
if field_name not in street_fields:
|
||||
raise UserError(_("Unrecognized field %s in street format.") % field_name)
|
||||
previous_pos = re_match.end()
|
||||
|
||||
# last field value is what remains in street_raw minus trailing chars in street_format
|
||||
trailing_chars = street_format[previous_pos:]
|
||||
if trailing_chars and street_raw.endswith(trailing_chars):
|
||||
vals[field_name] = street_raw[:-len(trailing_chars)]
|
||||
else:
|
||||
vals[field_name] = street_raw
|
||||
vals = self._split_street_with_params(street_raw, street_format)
|
||||
# assign the values to the fields
|
||||
for k, v in vals.items():
|
||||
partner[k] = v
|
||||
|
||||
def write(self, vals):
|
||||
res = super(Partner, self).write(vals)
|
||||
if 'country_id' in vals:
|
||||
self._set_street()
|
||||
return res
|
||||
|
||||
|
||||
class Company(models.Model):
|
||||
_inherit = 'res.company'
|
||||
|
||||
@@ -51,5 +51,5 @@ class TestStreetFields(TransactionCase):
|
||||
self.write_and_assert(p1, {'street': 'Chaussee de Namur'}, 'Chaussee de Namur', 'Chaussee de Namur', '', '')
|
||||
self.write_and_assert(p1, {'street_name': 'Chee de Namur', 'street_number': '40'}, 'Chee de Namur, 40', 'Chee de Namur', '40', '')
|
||||
self.write_and_assert(p1, {'street_number2': '4'}, 'Chee de Namur, 40/4', 'Chee de Namur', '40', '4')
|
||||
#we don't recompute the street fields when we change the country
|
||||
self.write_and_assert(p1, {'country_id': self.env.ref('base.us').id}, 'Chee de Namur, 40/4', 'Chee de Namur', '40', '4')
|
||||
#we do recompute the street fields when we change the country
|
||||
self.write_and_assert(p1, {'country_id': self.env.ref('base.us').id}, '40/4 Chee de Namur', 'Chee de Namur', '40', '4')
|
||||
|
||||
@@ -72,8 +72,8 @@ class ResPartner(models.Model):
|
||||
if len(lines) == 1:
|
||||
lines = [x.strip() for x in lines[0].split(' ') if x]
|
||||
|
||||
partner_address['street'] = lines.pop(0)
|
||||
#_set_address_field(partner, 'street', lines.pop(0))
|
||||
vals = self._split_street_with_params(', '.join(lines.pop(0).rsplit(' ', 1)), '%(street_name)s, %(street_number)s/%(street_number2)s')
|
||||
partner_address.update(vals)
|
||||
|
||||
if len(lines) > 0:
|
||||
res = _check_city(lines, result['countryCode'])
|
||||
|
||||
@@ -372,7 +372,6 @@
|
||||
<td style="padding:25px 0px;">
|
||||
<strong>Add this event to your calendar</strong>
|
||||
<a href="https://www.google.com/calendar/render?action=TEMPLATE&text=${object.event_id.name}&dates=${date_begin}/${date_end}&location=${location}" style="padding:3px 5px;border:1px solid #875A7B;color:#875A7B;text-decoration:none;border-radius:3px;" target="new"><img src="/web_editor/font_to_img/61525/rgb(135,90,123)/16" style="vertical-align:middle;" height="16"/> Google</a>
|
||||
<a href="https://bay02.calendar.live.com/calendar/calendar.aspx?rru=addevent&summary=${object.event_id.name}&dtstart=${date_begin}&dtend=${date_end}&location=${location}" style="padding:3px 5px;border:1px solid #875A7B;color:#875A7B;text-decoration:none;border-radius:3px;" target="new"><img src="/web_editor/font_to_img/61525/rgb(135,90,123)/16" style="vertical-align:middle;" height="16"/> Outlook</a>
|
||||
<a href="https://calendar.yahoo.com/?v=60&view=d&type=20&title=${object.event_id.name}&in_loc=${location}&st=${format_tz(object.event_id.date_begin, tz='UTC', format='%Y%m%dT%H%M%S')}&et=${format_tz(object.event_id.date_end, tz='UTC', format='%Y%m%dT%H%M%S')}" style="padding:3px 5px;border:1px solid #875A7B;color:#875A7B;text-decoration:none;border-radius:3px;" target="new">
|
||||
<img src="/web_editor/font_to_img/61525/rgb(135,90,123)/16" style="vertical-align:middle;" height="16"/> Yahoo</a>
|
||||
</td>
|
||||
|
||||
@@ -459,6 +459,17 @@ class EventRegistration(models.Model):
|
||||
pass
|
||||
return recipients
|
||||
|
||||
@api.multi
|
||||
def message_get_default_recipients(self):
|
||||
# Prioritize registration email over partner_id, which may be shared when a single
|
||||
# partner booked multiple seats
|
||||
return {
|
||||
r.id: {'partner_ids': [],
|
||||
'email_to': r.email,
|
||||
'email_cc': False}
|
||||
for r in self
|
||||
}
|
||||
|
||||
def _message_post_after_hook(self, message, *args, **kwargs):
|
||||
if self.email and not self.partner_id:
|
||||
# we consider that posting a message with a specified recipient (not a follower, a specific one)
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<t t-if="l.task_id"><span t-field="l.task_id.name"/></t>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<span t-esc="'%s:%02.0f' % tuple(int(round(x)) for x in divmod(l.unit_amount*60,60))"/>
|
||||
<span t-field="l.unit_amount" t-options="{'widget': 'float_time'}"/>
|
||||
</td>
|
||||
</tr>
|
||||
</t>
|
||||
@@ -53,7 +53,9 @@
|
||||
<td />
|
||||
<td t-if="show_task"/>
|
||||
<td class="text-right"><strong>Total</strong></td>
|
||||
<td class="text-right"><strong t-esc="'%s:%02.0f' % tuple(int(round(x)) for x in divmod(sum(docs.mapped('unit_amount'))*60,60))"/></td>
|
||||
<t t-set="total_value" t-value="sum(docs.mapped('unit_amount'))" />
|
||||
<t t-set="sign" t-value="'-' if total_value < 0 else ''"/>
|
||||
<td class="text-right"><strong t-esc="sign + '%s:%02.0f' % tuple(int(round(x)) for x in divmod(abs(total_value)*60,60))"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
@@ -205,6 +205,7 @@
|
||||
<field name="res_model">mail.shortcode</field>
|
||||
<field name="view_mode">tree</field>
|
||||
<field name="view_id" ref="im_livechat_canned_response_view_tree"/>
|
||||
<field name="domain">[]</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a new canned response
|
||||
|
||||
@@ -0,0 +1,155 @@
|
||||
# Translation of Odoo Server.
|
||||
# This file contains the translation of the following modules:
|
||||
# * web_planner
|
||||
#
|
||||
# Translators:
|
||||
# Mpasua Msonobari <msonobari@gmail.com>, 2018
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: Odoo Server 10.saas~18\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2017-09-20 09:54+0000\n"
|
||||
"PO-Revision-Date: 2017-09-20 09:54+0000\n"
|
||||
"Last-Translator: Mpasua Msonobari <msonobari@gmail.com>, 2018\n"
|
||||
"Language-Team: Swahili (https://www.transifex.com/odoo/teams/41243/sw/)\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: \n"
|
||||
"Language: sw\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_active
|
||||
#: model:ir.ui.view,arch_db:web_planner.web_planner_view_search
|
||||
msgid "Active"
|
||||
msgstr "Amilifu"
|
||||
|
||||
#. module: web_planner
|
||||
#. openerp-web
|
||||
#: code:addons/web_planner/static/src/js/web_planner_common.js:379
|
||||
#, python-format
|
||||
msgid "Cancel"
|
||||
msgstr "Katiza"
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_create_uid
|
||||
msgid "Created by"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_create_date
|
||||
msgid "Created on"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_data
|
||||
msgid "Data"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_display_name
|
||||
msgid "Display Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_id
|
||||
msgid "ID"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,help:web_planner.field_web_planner_active
|
||||
msgid ""
|
||||
"If the active field is set to False, it will allow you to hide the planner. "
|
||||
"This change requires a refresh of your page."
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.ui.view,arch_db:web_planner.web_planner_view_search
|
||||
msgid "Inactive"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner___last_update
|
||||
msgid "Last Modified on"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_write_uid
|
||||
msgid "Last Updated by"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_write_date
|
||||
msgid "Last Updated on"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#. openerp-web
|
||||
#: code:addons/web_planner/static/src/js/web_planner_common.js:133
|
||||
#, python-format
|
||||
msgid "Mark As Done"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_menu_id
|
||||
msgid "Menu"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_name
|
||||
msgid "Name"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#. openerp-web
|
||||
#: code:addons/web_planner/static/src/js/web_planner_common.js:141
|
||||
#, python-format
|
||||
msgid "Next Step"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#. openerp-web
|
||||
#: code:addons/web_planner/static/src/js/web_planner_common.js:388
|
||||
#, python-format
|
||||
msgid "Odoo Enterprise"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model,name:web_planner.model_web_planner
|
||||
#: model:ir.ui.view,arch_db:web_planner.web_planner_view_search
|
||||
#: model:ir.ui.view,arch_db:web_planner.web_planner_view_tree
|
||||
msgid "Planner"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_planner_application
|
||||
msgid "Planner Application"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_tooltip_planner
|
||||
msgid "Planner Tooltips"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.actions.act_window,name:web_planner.web_planner_action
|
||||
#: model:ir.ui.menu,name:web_planner.web_planner_menu
|
||||
msgid "Planners"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_progress
|
||||
msgid "Progress Percentage"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#: model:ir.model.fields,field_description:web_planner.field_web_planner_view_id
|
||||
msgid "Template"
|
||||
msgstr ""
|
||||
|
||||
#. module: web_planner
|
||||
#. openerp-web
|
||||
#: code:addons/web_planner/static/src/js/web_planner_common.js:365
|
||||
#, python-format
|
||||
msgid "Upgrade now"
|
||||
msgstr ""
|
||||
@@ -1,185 +1,185 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<odoo>
|
||||
<!-- Account Tax Tags -->
|
||||
|
||||
<record id="tag_de_41" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 41</field>
|
||||
<field name="name">Ust-VA KZ 41</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_44" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 44</field>
|
||||
<field name="name">Ust-VA KZ 44</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_49" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 49</field>
|
||||
<field name="name">Ust-VA KZ 49</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_43" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 43</field>
|
||||
<field name="name">Ust-VA KZ 43</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_48" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 48</field>
|
||||
<field name="name">Ust-VA KZ 48</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_81" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 81</field>
|
||||
<field name="name">Ust-VA KZ 81</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_86" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 86</field>
|
||||
<field name="name">Ust-VA KZ 86</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_35" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 35</field>
|
||||
<field name="name">Ust-VA KZ 35</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_77" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 77</field>
|
||||
<field name="name">Ust-VA KZ 77</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_76" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 76</field>
|
||||
<field name="name">Ust-VA KZ 76</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_91" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 91</field>
|
||||
<field name="name">Ust-VA KZ 91</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_89" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 89</field>
|
||||
<field name="name">Ust-VA KZ 89</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_93" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 93</field>
|
||||
<field name="name">Ust-VA KZ 93</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_95" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 95</field>
|
||||
<field name="name">Ust-VA KZ 95</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_94" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 94</field>
|
||||
<field name="name">Ust-VA KZ 94</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_42" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 42</field>
|
||||
<field name="name">Ust-VA KZ 42</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_68" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 68</field>
|
||||
<field name="name">Ust-VA KZ 68</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_60" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 60</field>
|
||||
<field name="name">Ust-VA KZ 60</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_21" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 21</field>
|
||||
<field name="name">Ust-VA KZ 21</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_45" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 45</field>
|
||||
<field name="name">Ust-VA KZ 45</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_46" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 46</field>
|
||||
<field name="name">Ust-VA KZ 46</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_52" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 52</field>
|
||||
<field name="name">Ust-VA KZ 52</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_73" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 73</field>
|
||||
<field name="name">Ust-VA KZ 73</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_78" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 78</field>
|
||||
<field name="name">Ust-VA KZ 78</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_84" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 84</field>
|
||||
<field name="name">Ust-VA KZ 84</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_36" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 36</field>
|
||||
<field name="name">Ust-VA KZ 36</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_80" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 80</field>
|
||||
<field name="name">Ust-VA KZ 80</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_98" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 98</field>
|
||||
<field name="name">Ust-VA KZ 98</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_96" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 96</field>
|
||||
<field name="name">Ust-VA KZ 96</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_47" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 47</field>
|
||||
<field name="name">Ust-VA KZ 47</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_53" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 53</field>
|
||||
<field name="name">Ust-VA KZ 53</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_74" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 74</field>
|
||||
<field name="name">Ust-VA KZ 74</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_79" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 79</field>
|
||||
<field name="name">Ust-VA KZ 79</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_85" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 85</field>
|
||||
<field name="name">Ust-VA KZ 85</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_65" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 65</field>
|
||||
<field name="name">Ust-VA KZ 65</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_66" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 66</field>
|
||||
<field name="name">Ust-VA KZ 66</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_61" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 61</field>
|
||||
<field name="name">Ust-VA KZ 61</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_62" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 62</field>
|
||||
<field name="name">Ust-VA KZ 62</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_67" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 67</field>
|
||||
<field name="name">Ust-VA KZ 67</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_63" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 63</field>
|
||||
<field name="name">Ust-VA KZ 63</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_64" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 64</field>
|
||||
<field name="name">Ust-VA KZ 64</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_59" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 59</field>
|
||||
<field name="name">Ust-VA KZ 59</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_69" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 69</field>
|
||||
<field name="name">Ust-VA KZ 69</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_39" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 39</field>
|
||||
<field name="name">Ust-VA KZ 39</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_83" model="account.account.tag">
|
||||
<field name="name">Umsatzsteuer-Voranmeldung Code 83</field>
|
||||
<field name="name">Ust-VA KZ 83</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
|
||||
@@ -188,300 +188,300 @@
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_intracom_community_supplies" model="account.account.tag">
|
||||
<field name="name">Sonstige leistungen</field>
|
||||
<field name="name">Sonstige Leistungen</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
<record id="tag_de_intracom_ABC" model="account.account.tag">
|
||||
<field name="name">Dreiecksgecshäfte</field>
|
||||
<field name="name">Dreiecksgeschäfte</field>
|
||||
<field name="applicability">taxes</field>
|
||||
</record>
|
||||
|
||||
<!-- Profit and loss tags -->
|
||||
<record id="tag_de_pl_01" model="account.account.tag">
|
||||
<field name="name">P&L: 1-Umsatzerlöse</field>
|
||||
<field name="name">G&V: 1-Umsatzerlöse</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_02" model="account.account.tag">
|
||||
<field name="name">P&L: 2-Erhöhung oder Verminderung des Bestands an fertigen und unfertigen Erzeugnissen</field>
|
||||
<field name="name">G&V: 2-Erhöhung oder Verminderung des Bestands an fertigen und unfertigen Erzeugnissen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_03" model="account.account.tag">
|
||||
<field name="name">P&L: 3-Andere aktivierte eigenleistungen</field>
|
||||
<field name="name">G&V: 3-Andere aktivierte Eigenleistungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_04" model="account.account.tag">
|
||||
<field name="name">P&L: 4-Sonstige betrieliche erträge</field>
|
||||
<field name="name">G&V: 4-Sonstige betrieliche Erträge</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_05" model="account.account.tag">
|
||||
<field name="name">P&L: 5-Materialaufwand</field>
|
||||
<field name="name">G&V: 5-Materialaufwand</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_06" model="account.account.tag">
|
||||
<field name="name">P&L: 6-Personalaufwand</field>
|
||||
<field name="name">G&V: 6-Personalaufwand</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_07" model="account.account.tag">
|
||||
<field name="name">P&L: 7-Abschreibungen</field>
|
||||
<field name="name">G&V: 7-Abschreibungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_08_1" model="account.account.tag">
|
||||
<field name="name">P&L: 8.1-Raumkosten</field>
|
||||
<field name="name">G&V: 8.1-Raumkosten</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_08_2" model="account.account.tag">
|
||||
<field name="name">P&L: 8.2-Versicherungen, Beiträge und Abgaben</field>
|
||||
<field name="name">G&V: 8.2-Versicherungen, Beiträge und Abgaben</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_08_3" model="account.account.tag">
|
||||
<field name="name">P&L: 8.3-eparaturen und Instandhaltungen</field>
|
||||
<field name="name">G&V: 8.3-Reparaturen und Instandhaltungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_08_4" model="account.account.tag">
|
||||
<field name="name">P&L: 8.4-Fahrzeugkosten</field>
|
||||
<field name="name">G&V: 8.4-Fahrzeugkosten</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_08_5" model="account.account.tag">
|
||||
<field name="name">P&L: 8.5-Werbe- und Reisekosten</field>
|
||||
<field name="name">G&V: 8.5-Werbe- und Reisekosten</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_08_6" model="account.account.tag">
|
||||
<field name="name">P&L: 8.6-Kosten der Warenabgabe</field>
|
||||
<field name="name">G&V: 8.6-Kosten der Warenabgabe</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_08_7" model="account.account.tag">
|
||||
<field name="name">P&L: 8.7-verschiedene betriebliche Kosten</field>
|
||||
<field name="name">G&V: 8.7-verschiedene betriebliche Kosten</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_09" model="account.account.tag">
|
||||
<field name="name">P&L: 9-Erträge aus beteiligungen</field>
|
||||
<field name="name">G&V: 9-Erträge aus Beteiligungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_10" model="account.account.tag">
|
||||
<field name="name">P&L: 10-Erträge aus anderen wertpapieren und ausleihungen des finanzanlagevermögens</field>
|
||||
<field name="name">G&V: 10-Erträge aus anderen Wertpapieren und Ausleihungen des Finanzanlagevermögens</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_11" model="account.account.tag">
|
||||
<field name="name">P&L: 11-Sonstige zinsen und ähnliche erträge</field>
|
||||
<field name="name">G&V: 11-Sonstige Zinsen und ähnliche Erträge</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_12" model="account.account.tag">
|
||||
<field name="name">P&L: 12-Abschreibungen auf Finanzanlagen und auf Wertpapiere des Umlaufvermögens</field>
|
||||
<field name="name">G&V: 12-Abschreibungen auf Finanzanlagen und auf Wertpapiere des Umlaufvermögens</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_13" model="account.account.tag">
|
||||
<field name="name">P&L: 13-Zinsen und ähnliche Aufwendungen</field>
|
||||
<field name="name">G&V: 13-Zinsen und ähnliche Aufwendungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_14" model="account.account.tag">
|
||||
<field name="name">P&L: 14-Steuern vom einkommen und ertrag</field>
|
||||
<field name="name">G&V: 14-Steuern vom Einkommen und Ertrag</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_pl_15" model="account.account.tag">
|
||||
<field name="name">P&L: 15-Sonstige steuern</field>
|
||||
<field name="name">G&V: 15-Sonstige Steuern</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
|
||||
<!-- Balance sheet tags -->
|
||||
<record id="tag_de_asset_bs_A_I_1" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A I 1-Selbst geschaffene gewerbliche Schutzrechte und ähnliche Rechte und Werte</field>
|
||||
<field name="name">Bilanz-Aktiva: A I 1-Selbst geschaffene gewerbliche Schutzrechte und ähnliche Rechte und Werte</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_I_2" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A I 2-Konzessionen, Lizenzen und ähnliche Rechte und Werte</field>
|
||||
<field name="name">Bilanz-Aktiva: A I 2-Konzessionen, Lizenzen und ähnliche Rechte und Werte</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_I_3" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A I 3-Geschäfts- oder Firmenwert</field>
|
||||
<field name="name">Bilanz-Aktiva: A I 3-Geschäfts- oder Firmenwert</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_I_4" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A I 4-geleistete Anzahlungen</field>
|
||||
<field name="name">Bilanz-Aktiva: A I 4-geleistete Anzahlungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_II_1" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A II 1-Grundstücke. grundstücksgleiche Rechte und Bauten</field>
|
||||
<field name="name">Bilanz-Aktiva: A II 1-Grundstücke. grundstücksgleiche Rechte und Bauten</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_II_2" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A II 2-Technische Anlagen und Maschinen</field>
|
||||
<field name="name">Bilanz-Aktiva: A II 2-Technische Anlagen und Maschinen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_II_3" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A II 3-Andere Anlagen. Betriebs- und Geschäftsausstattung</field>
|
||||
<field name="name">Bilanz-Aktiva: A II 3-Andere Anlagen. Betriebs- und Geschäftsausstattung</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_II_4" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A II 4-Geleistete Anzahlungen und Anlagen im Bau</field>
|
||||
<field name="name">Bilanz-Aktiva: A II 4-Geleistete Anzahlungen und Anlagen im Bau</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_III_1" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A III 1-Anteile an verbundenen Unternehmen</field>
|
||||
<field name="name">Bilanz-Aktiva: A III 1-Anteile an verbundenen Unternehmen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_III_2" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A III 2-Ausleihungen an verbundene Unternehmen</field>
|
||||
<field name="name">Bilanz-Aktiva: A III 2-Ausleihungen an verbundene Unternehmen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_III_3" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A III 3-Beteiligungen</field>
|
||||
<field name="name">Bilanz-Aktiva: A III 3-Beteiligungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_III_4" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A III 4-Ausleihungen an Unternehmen, mit denen ein Beteiligungsverhältnis besteht</field>
|
||||
<field name="name">Bilanz-Aktiva: A III 4-Ausleihungen an Unternehmen, mit denen ein Beteiligungsverhältnis besteht</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_III_5" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A III 5-Wertpapiere des Anlagevermögens</field>
|
||||
<field name="name">Bilanz-Aktiva: A III 5-Wertpapiere des Anlagevermögens</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_A_III_6" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: A III 6-sonstige Ausleihungen</field>
|
||||
<field name="name">Bilanz-Aktiva: A III 6-sonstige Ausleihungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_B_I_1" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: B I 1-Roh-, Hilfs- und Betriebsstoffe</field>
|
||||
<field name="name">Bilanz-Aktiva: B I 1-Roh-, Hilfs- und Betriebsstoffe</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_B_I_2" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: B I 2-Unfertige Erzeugnisse, unfertige Leistungen</field>
|
||||
<field name="name">Bilanz-Aktiva: B I 2-Unfertige Erzeugnisse, unfertige Leistungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_B_I_3" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: B I 3-Fertige Erzeugnisse und Waren</field>
|
||||
<field name="name">Bilanz-Aktiva: B I 3-Fertige Erzeugnisse und Waren</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_B_I_4" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: B I 4-Geleistete Anzahlungen</field>
|
||||
<field name="name">Bilanz-Aktiva: B I 4-Geleistete Anzahlungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_B_II_1" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: B II 1-Forderungen aus Lieferungen und Leistungen</field>
|
||||
<field name="name">Bilanz-Aktiva: B II 1-Forderungen aus Lieferungen und Leistungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_B_II_2" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: B II 2-Forderungen gegen verbundene Unternehmen</field>
|
||||
<field name="name">Bilanz-Aktiva: B II 2-Forderungen gegen verbundene Unternehmen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_B_II_3" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: B II 3-Forderungen gegen Unternehmen, mit denen ein Beteiligungsverhältnis besteht</field>
|
||||
<field name="name">Bilanz-Aktiva: B II 3-Forderungen gegen Unternehmen, mit denen ein Beteiligungsverhältnis besteht</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_B_II_4" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: B II 4-Sonstige Vermögensgegenstände</field>
|
||||
<field name="name">Bilanz-Aktiva: B II 4-Sonstige Vermögensgegenstände</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_B_III_1" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: B III 1-Anteile an verbundenen Unternehmen</field>
|
||||
<field name="name">Bilanz-Aktiva: B III 1-Anteile an verbundenen Unternehmen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_B_III_2" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: B III 2-sonstige Wertpapiere</field>
|
||||
<field name="name">Bilanz-Aktiva: B III 2-sonstige Wertpapiere</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_B_IV" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: B IV-Kassenbestand, Bundesbankguthaben, Guthaben bei Kreditinstituten und Schecks</field>
|
||||
<field name="name">Bilanz-Aktiva: B IV-Kassenbestand, Bundesbankguthaben, Guthaben bei Kreditinstituten und Schecks</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_C" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: C-Rechnungsabgrenzungsposten</field>
|
||||
<field name="name">Bilanz-Aktiva: C-Rechnungsabgrenzungsposten</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_D" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: D-Aktive latente Steuern</field>
|
||||
<field name="name">Bilanz-Aktiva: D-Aktive latente Steuern</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_asset_bs_E" model="account.account.tag">
|
||||
<field name="name">BS-Aktivseite: E-Aktiver Unterschiedsbetrag aus der Vermögensverrechnung</field>
|
||||
<field name="name">Bilanz-Aktiva: E-Aktiver Unterschiedsbetrag aus der Vermögensverrechnung</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
|
||||
<record id="tag_de_liabilities_bs_A_I" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: A I-Gezeichnetes Kapital</field>
|
||||
<field name="name">Bilanz-Passiva: A I-Gezeichnetes Kapital</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_A_II" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: A II-Kapitalrücklage</field>
|
||||
<field name="name">Bilanz-Passiva: A II-Kapitalrücklage</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_A_III_1" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: A III 1-Gesetzliche Rücklage</field>
|
||||
<field name="name">Bilanz-Passiva: A III 1-Gesetzliche Rücklage</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_A_III_2" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: A III 2-Rücklage für Anteile an einem herrschenden oder mehrheitlich beteiligten Unternehmen</field>
|
||||
<field name="name">Bilanz-Passiva: A III 2-Rücklage für Anteile an einem herrschenden oder mehrheitlich beteiligten Unternehmen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_A_III_3" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: A III 3-Satzungsmäßige Rücklagen</field>
|
||||
<field name="name">Bilanz-Passiva: A III 3-Satzungsmäßige Rücklagen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_A_III_4" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: A III 4-Andere Gewinnrücklagen</field>
|
||||
<field name="name">Bilanz-Passiva: A III 4-Andere Gewinnrücklagen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_A_IV" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: A IV-Gewinnvortrag/Verlustvortrag</field>
|
||||
<field name="name">Bilanz-Passiva: A IV-Gewinnvortrag/Verlustvortrag</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_A_V" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: A V-Jahresüberschuß/Jahresfehlbetrag</field>
|
||||
<field name="name">Bilanz-Passiva: A V-Jahresüberschuß/Jahresfehlbetrag</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_B" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: B Sonderposten mit Rücklageanteil</field>
|
||||
<field name="name">Bilanz-Passiva: B Sonderposten mit Rücklageanteil</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_C_1" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: C 1-Rückstellungen für Pensionen und ähnliche Verpflichtungen</field>
|
||||
<field name="name">Bilanz-Passiva: C 1-Rückstellungen für Pensionen und ähnliche Verpflichtungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_C_2" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: C 2-Steuerrückstellungen</field>
|
||||
<field name="name">Bilanz-Passiva: C 2-Steuerrückstellungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_C_3" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: C 3-Sonstige Rückstellungen</field>
|
||||
<field name="name">Bilanz-Passiva: C 3-Sonstige Rückstellungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_D_1" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: D 1-Anleihen, davon konvertibeln</field>
|
||||
<field name="name">Bilanz-Passiva: D 1-Anleihen, davon konvertibeln</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_D_2" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: D 2-Verbindlichkeiten gegenüber Kreditinstituten</field>
|
||||
<field name="name">Bilanz-Passiva: D 2-Verbindlichkeiten gegenüber Kreditinstituten</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_D_3" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: D 3-Erhaltene Anzahlungen auf Bestellungen</field>
|
||||
<field name="name">Bilanz-Passiva: D 3-Erhaltene Anzahlungen auf Bestellungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_D_4" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: D 4-Verbindlichkeiten aus Lieferungen und Leistungen</field>
|
||||
<field name="name">Bilanz-Passiva: D 4-Verbindlichkeiten aus Lieferungen und Leistungen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_D_5" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: D 5-Verbindlichkeiten aus der Annahme gezogener Wechsel und der Ausstellung eigener Wechsel</field>
|
||||
<field name="name">Bilanz-Passiva: D 5-Verbindlichkeiten aus der Annahme gezogener Wechsel und der Ausstellung eigener Wechsel</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_D_6" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: D 6-Verbindlichkeiten gegenüber verbundenen Unternehmen</field>
|
||||
<field name="name">Bilanz-Passiva: D 6-Verbindlichkeiten gegenüber verbundenen Unternehmen</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_D_7" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: D 7-Verbindlichkeiten gegenüber Unternehmen, mit denen ein Beteiligungsverhältnis besteht</field>
|
||||
<field name="name">Bilanz-Passiva: D 7-Verbindlichkeiten gegenüber Unternehmen, mit denen ein Beteiligungsverhältnis besteht</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_D_8" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: D 8-Sonstige Verbindlichkeiten, davon aus Steuern, davon im Rahmen der sozialen Sicherheit</field>
|
||||
<field name="name">Bilanz-Passiva: D 8-Sonstige Verbindlichkeiten, davon aus Steuern, davon im Rahmen der sozialen Sicherheit</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_E" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: E-Rechnungsabgrenzungsposten</field>
|
||||
<field name="name">Bilanz-Passiva: E-Rechnungsabgrenzungsposten</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
<record id="tag_de_liabilities_bs_F" model="account.account.tag">
|
||||
<field name="name">BS-Passivseite: F-Passive latente Steuern</field>
|
||||
<field name="name">Bilanz-Passiva: F-Passive latente Steuern</field>
|
||||
<field name="applicability">accounts</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
from odoo import fields, models
|
||||
from odoo import api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.tools.translate import _
|
||||
|
||||
class AccountTaxTemplate(models.Model):
|
||||
_inherit = 'account.tax.template'
|
||||
@@ -14,3 +16,18 @@ class AccountTax(models.Model):
|
||||
_inherit = "account.tax"
|
||||
|
||||
l10n_de_datev_code = fields.Char(size=2, help="2 digits code use by Datev")
|
||||
|
||||
class AccountInvoice(models.Model):
|
||||
_inherit = "account.invoice"
|
||||
|
||||
def invoice_validate(self):
|
||||
for invoice in self:
|
||||
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.invoice_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(AccountInvoice, self).invoice_validate()
|
||||
@@ -5,22 +5,24 @@
|
||||
# =====
|
||||
|
||||
# Dieses Modul bietet Ihnen einen deutschen Kontenplan basierend auf dem SKR03.
|
||||
# Gemäss der aktuellen Einstellungen ist die Firma nicht Umsatzsteuerpflichtig.
|
||||
# Diese Grundeinstellung ist sehr einfach zu ändern und bedarf in der Regel
|
||||
# grundsätzlich eine initiale Zuweisung von Steuerkonten zu Produkten und / oder
|
||||
# Sachkonten oder zu Partnern.
|
||||
# Die Umsatzsteuern (voller Steuersatz, reduzierte Steuer und steuerfrei)
|
||||
# sollten bei den Produktstammdaten hinterlegt werden (in Abhängigkeit der
|
||||
# Steuervorschriften). Die Zuordnung erfolgt auf dem Aktenreiter Finanzbuchhaltung
|
||||
# (Kategorie: Umsatzsteuer).
|
||||
# Die Vorsteuern (voller Steuersatz, reduzierte Steuer und steuerfrei)
|
||||
# sollten ebenso bei den Produktstammdaten hinterlegt werden (in Abhängigkeit
|
||||
# der Steuervorschriften). Die Zuordnung erfolgt auf dem Aktenreiter
|
||||
# Finanzbuchhaltung (Kategorie: Vorsteuer).
|
||||
# Gemäss der aktuellen Einstellungen ist ein neues Unternehmen in Odoo
|
||||
# Umsatzsteuerpflichtig. Zahlreiche Erlös- und Aufwandskonten enthalten
|
||||
# bereits eine zugeordnete Steuer. Hierdurch wird für diese Konten bereits
|
||||
# die richtige Vorsteuer (Eingangsrechnungen) bzw. Umsatzsteuer
|
||||
# (Ausgangsrechnungen) automatisch ausgewählt.
|
||||
#
|
||||
# Die Zuordnung von Steuerkonten zu Produkten und / oder Sachkonten kann
|
||||
# für den jeweiligen betrieblichen Anwendungszweck überarbeitet oder
|
||||
# auch erweitert werden.
|
||||
# Die mit diesem Kontenrahmen installierten Steuerschlüssel (z.B. 19%, 7%,
|
||||
# steuerfrei) können hierzu bei den Produktstammdaten hinterlegt werden
|
||||
# (in Abhängigkeit der Steuervorschriften). Die Zuordnung erfolgt auf
|
||||
# dem Aktenreiter Finanzbuchhaltung (Kategorie: Umsatzsteuer / Vorsteuer).
|
||||
|
||||
# Die Zuordnung der Steuern für Ein- und Ausfuhren aus EU Ländern, sowie auch
|
||||
# für den Ein- und Verkauf aus und in Drittländer sollten beim Partner
|
||||
# (Lieferant/Kunde)hinterlegt werden (in Anhängigkeit vom Herkunftsland
|
||||
# des Lieferanten/Kunden). Die Zuordnung beim Kunden ist 'höherwertig' als
|
||||
# (Lieferant / Kunde) hinterlegt werden (in Anhängigkeit vom Herkunftsland
|
||||
# des Lieferanten/Kunden). Diese Zuordnung ist 'höherwertig' als
|
||||
# die Zuordnung bei Produkten und überschreibt diese im Einzelfall.
|
||||
#
|
||||
# Zur Vereinfachung der Steuerausweise und Buchung bei Auslandsgeschäften
|
||||
@@ -28,32 +30,10 @@
|
||||
# (z.B. Zuordnung 'Umsatzsteuer 19%' zu 'steuerfreie Einfuhren aus der EU')
|
||||
# zwecks Zuordnung dieses Mappings zum ausländischen Partner (Kunde/Lieferant).
|
||||
|
||||
# Die Rechnungsbuchung beim Einkauf bewirkt folgendes:
|
||||
# Die Steuerbemessungsgrundlage (exklusive Steuer) wird ausgewiesen bei den
|
||||
# jeweiligen Kategorien für den Vorsteuer Steuermessbetrag (z.B. Vorsteuer
|
||||
# Steuermessbetrag Voller Steuersatz 19%).
|
||||
# Der Steuerbetrag erscheint unter der Kategorie 'Vorsteuern' (z.B. Vorsteuer
|
||||
# 19%). Durch multidimensionale Hierachien können verschiedene Positionen
|
||||
# zusammengefasst werden und dann in Form eines Reports ausgegeben werden.
|
||||
#
|
||||
# Die Rechnungsbuchung beim Verkauf bewirkt folgendes:
|
||||
# Die Steuerbemessungsgrundlage (exklusive Steuer) wird ausgewiesen bei den
|
||||
# jeweiligen Kategorien für den Umsatzsteuer Steuermessbetrag
|
||||
# (z.B. Umsatzsteuer Steuermessbetrag Voller Steuersatz 19%).
|
||||
# Der Steuerbetrag erscheint unter der Kategorie 'Umsatzsteuer'
|
||||
# (z.B. Umsatzsteuer 19%). Durch multidimensionale Hierachien können
|
||||
# verschiedene Positionen zusammengefasst werden.
|
||||
# Die zugewiesenen Steuerausweise können auf Ebene der einzelnen
|
||||
# Rechnung (Eingangs- und Ausgangsrechnung) nachvollzogen werden,
|
||||
# und dort gegebenenfalls angepasst werden.
|
||||
|
||||
# Rechnungsgutschriften führen zu einer Korrektur (Gegenposition)
|
||||
# der Steuerbuchung, in Form einer spiegelbildlichen Buchung.
|
||||
|
||||
|
||||
{
|
||||
'name': 'Deutschland SKR03 - Accounting',
|
||||
'version': '2.0',
|
||||
'version': '3.0',
|
||||
'author': 'openbig.org',
|
||||
'website': 'http://www.openbig.org',
|
||||
'category': 'Localization',
|
||||
@@ -68,6 +48,7 @@ German accounting chart and localization.
|
||||
'data/l10n_de_skr03_chart_data.xml',
|
||||
'data/account_data.xml',
|
||||
'data/account_tax_fiscal_position_data.xml',
|
||||
'data/account_reconcile_model_template.xml',
|
||||
'data/account_chart_template_data.xml',
|
||||
],
|
||||
'auto_install': True
|
||||
|
||||
@@ -4,13 +4,22 @@
|
||||
|
||||
<!-- Account Tax Group -->
|
||||
<record id="tax_group_0" model="account.tax.group">
|
||||
<field name="name">Tax 0%</field>
|
||||
<field name="name">USt 0%</field>
|
||||
</record>
|
||||
<record id="tax_group_7" model="account.tax.group">
|
||||
<field name="name">Tax 7%</field>
|
||||
<field name="name">USt 7%</field>
|
||||
</record>
|
||||
<record id="tax_group_55" model="account.tax.group">
|
||||
<field name="name">USt 5,5%</field>
|
||||
</record>
|
||||
<record id="tax_group_107" model="account.tax.group">
|
||||
<field name="name">USt 10,7%</field>
|
||||
</record>
|
||||
<record id="tax_group_x" model="account.tax.group">
|
||||
<field name="name">USt x%</field>
|
||||
</record>
|
||||
<record id="tax_group_19" model="account.tax.group">
|
||||
<field name="name">Tax 19%</field>
|
||||
<field name="name">USt 19%</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="reconcile_3731" model="account.reconcile.model.template">
|
||||
<field name="name">Skonto-EK-7%</field>
|
||||
<field name="account_id" ref="account_3731"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_vst_7_taxinclusive_skr03"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Skonto-EK-7%</field>
|
||||
<field name="chart_template_id" ref="l10n_de_chart_template"/>
|
||||
</record>
|
||||
<record id="reconcile_3736" model="account.reconcile.model.template">
|
||||
<field name="name">Skonto-EK-19%</field>
|
||||
<field name="account_id" ref="account_3736"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_vst_19_taxinclusive_skr03"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Skonto-EK-19%</field>
|
||||
<field name="chart_template_id" ref="l10n_de_chart_template"/>
|
||||
</record>
|
||||
<record id="reconcile_8731" model="account.reconcile.model.template">
|
||||
<field name="name">Skonto-VK-7%</field>
|
||||
<field name="account_id" ref="account_8731"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_ust_7_taxinclusive_skr03"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Skonto-VK-7%</field>
|
||||
<field name="chart_template_id" ref="l10n_de_chart_template"/>
|
||||
</record>
|
||||
<record id="reconcile_8736" model="account.reconcile.model.template">
|
||||
<field name="name">Skonto-VK-19%</field>
|
||||
<field name="account_id" ref="account_8736"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_ust_19_taxinclusive_skr03"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Skonto-VK-19%</field>
|
||||
<field name="chart_template_id" ref="l10n_de_chart_template"/>
|
||||
</record>
|
||||
<record id="reconcile_2401" model="account.reconcile.model.template">
|
||||
<field name="name">Forderungsverlust-7%</field>
|
||||
<field name="account_id" ref="account_2401"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_ust_7_taxinclusive_skr03"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Forderungsverlust-7%</field>
|
||||
<field name="chart_template_id" ref="l10n_de_chart_template"/>
|
||||
</record>
|
||||
<record id="reconcile_2406" model="account.reconcile.model.template">
|
||||
<field name="name">Forderungsverlust-19%</field>
|
||||
<field name="account_id" ref="account_2406"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_ust_19_taxinclusive_skr03"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Forderungsverlust-19%</field>
|
||||
<field name="chart_template_id" ref="l10n_de_chart_template"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,26 +3,25 @@
|
||||
|
||||
# SKR04
|
||||
# =====
|
||||
# Dieses Modul bietet Ihnen einen deutschen Kontenplan basierend auf dem SKR03.
|
||||
# Gemäss der aktuellen Einstellungen ist ein neues Unternehmen in Odoo
|
||||
# Umsatzsteuerpflichtig. Zahlreiche Erlös- und Aufwandskonten enthalten
|
||||
# bereits eine zugeordnete Steuer. Hierdurch wird für diese Konten bereits
|
||||
# die richtige Vorsteuer (Eingangsrechnungen) bzw. Umsatzsteuer
|
||||
# (Ausgangsrechnungen) automatisch ausgewählt.
|
||||
#
|
||||
# Die Zuordnung von Steuerkonten zu Produkten und / oder Sachkonten kann
|
||||
# für den jeweiligen betrieblichen Anwendungszweck überarbeitet oder
|
||||
# auch erweitert werden.
|
||||
# Die mit diesem Kontenrahmen installierten Steuerschlüssel (z.B. 19%, 7%,
|
||||
# steuerfrei) können hierzu bei den Produktstammdaten hinterlegt werden
|
||||
# (in Abhängigkeit der Steuervorschriften). Die Zuordnung erfolgt auf
|
||||
# dem Aktenreiter Finanzbuchhaltung (Kategorie: Umsatzsteuer / Vorsteuer).
|
||||
|
||||
# Dieses Modul bietet Ihnen einen deutschen Kontenplan basierend auf dem SKR04.
|
||||
# Gemäss der aktuellen Einstellungen ist die Firma nicht Umsatzsteuerpflichtig,
|
||||
# d.h. im Standard existiert keine Zuordnung von Produkten und Sachkonten zu
|
||||
# Steuerschlüsseln.
|
||||
# Diese Grundeinstellung ist sehr einfach zu ändern und bedarf in der Regel
|
||||
# grundsätzlich eine initiale Zuweisung von Steuerschlüsseln zu Produkten und / oder
|
||||
# Sachkonten oder zu Partnern.
|
||||
# Die Umsatzsteuern (voller Steuersatz, reduzierte Steuer und steuerfrei)
|
||||
# sollten bei den Produktstammdaten hinterlegt werden (in Abhängigkeit der
|
||||
# Steuervorschriften). Die Zuordnung erfolgt auf dem Aktenreiter Finanzbuchhaltung
|
||||
# (Kategorie: Umsatzsteuer).
|
||||
# Die Vorsteuern (voller Steuersatz, reduzierte Steuer und steuerfrei)
|
||||
# sollten ebenso bei den Produktstammdaten hinterlegt werden (in Abhängigkeit
|
||||
# der Steuervorschriften). Die Zuordnung erfolgt auf dem Aktenreiter
|
||||
# Finanzbuchhaltung (Kategorie: Vorsteuer).
|
||||
# Die Zuordnung der Steuern für Ein- und Ausfuhren aus EU Ländern, sowie auch
|
||||
# für den Ein- und Verkauf aus und in Drittländer sollten beim Partner
|
||||
# (Lieferant/Kunde) hinterlegt werden (in Anhängigkeit vom Herkunftsland
|
||||
# des Lieferanten/Kunden). Die Zuordnung beim Kunden ist 'höherwertig' als
|
||||
# (Lieferant / Kunde) hinterlegt werden (in Anhängigkeit vom Herkunftsland
|
||||
# des Lieferanten/Kunden). Diese Zuordnung ist 'höherwertig' als
|
||||
# die Zuordnung bei Produkten und überschreibt diese im Einzelfall.
|
||||
#
|
||||
# Zur Vereinfachung der Steuerausweise und Buchung bei Auslandsgeschäften
|
||||
@@ -30,32 +29,10 @@
|
||||
# (z.B. Zuordnung 'Umsatzsteuer 19%' zu 'steuerfreie Einfuhren aus der EU')
|
||||
# zwecks Zuordnung dieses Mappings zum ausländischen Partner (Kunde/Lieferant).
|
||||
|
||||
# Die Rechnungsbuchung beim Einkauf bewirkt folgendes:
|
||||
# Die Steuerbemessungsgrundlage (exklusive Steuer) wird ausgewiesen bei den
|
||||
# jeweiligen Kategorien für den Vorsteuer Steuermessbetrag (z.B. Vorsteuer
|
||||
# Steuermessbetrag Voller Steuersatz 19%).
|
||||
# Der Steuerbetrag erscheint unter der Kategorie 'Vorsteuern' (z.B. Vorsteuer
|
||||
# 19%). Durch multidimensionale Hierachien können verschiedene Positionen
|
||||
# zusammengefasst werden und dann in Form eines Reports ausgegeben werden.
|
||||
#
|
||||
# Die Rechnungsbuchung beim Verkauf bewirkt folgendes:
|
||||
# Die Steuerbemessungsgrundlage (exklusive Steuer) wird ausgewiesen bei den
|
||||
# jeweiligen Kategorien für den Umsatzsteuer Steuermessbetrag
|
||||
# (z.B. Umsatzsteuer Steuermessbetrag Voller Steuersatz 19%).
|
||||
# Der Steuerbetrag erscheint unter der Kategorie 'Umsatzsteuer'
|
||||
# (z.B. Umsatzsteuer 19%). Durch multidimensionale Hierachien können
|
||||
# verschiedene Positionen zusammengefasst werden.
|
||||
# Die zugewiesenen Steuerausweise können auf Ebene der einzelnen
|
||||
# Rechnung (Eingangs- und Ausgangsrechnung) nachvollzogen werden,
|
||||
# und dort gegebenenfalls angepasst werden.
|
||||
|
||||
# Rechnungsgutschriften führen zu einer Korrektur (Gegenposition)
|
||||
# der Steuerbuchung, in Form einer spiegelbildlichen Buchung.
|
||||
|
||||
|
||||
{
|
||||
'name': 'Deutschland SKR04 - Accounting',
|
||||
'version': '2.0',
|
||||
'version': '3.0',
|
||||
'author': 'openbig.org',
|
||||
'website': 'http://www.openbig.org',
|
||||
'category': 'Localization',
|
||||
@@ -70,6 +47,7 @@ German accounting chart and localization.
|
||||
'data/l10n_de_skr04_chart_data.xml',
|
||||
'data/account_data.xml',
|
||||
'data/account_tax_fiscal_position_data.xml',
|
||||
'data/account_reconcile_model_template.xml',
|
||||
'data/account_chart_template_data.xml',
|
||||
],
|
||||
}
|
||||
|
||||
@@ -4,13 +4,22 @@
|
||||
|
||||
<!-- Account Tax Group -->
|
||||
<record id="tax_group_0" model="account.tax.group">
|
||||
<field name="name">Tax 0%</field>
|
||||
<field name="name">USt 0%</field>
|
||||
</record>
|
||||
<record id="tax_group_7" model="account.tax.group">
|
||||
<field name="name">Tax 7%</field>
|
||||
<field name="name">USt 7%</field>
|
||||
</record>
|
||||
<record id="tax_group_55" model="account.tax.group">
|
||||
<field name="name">USt 5,5%</field>
|
||||
</record>
|
||||
<record id="tax_group_107" model="account.tax.group">
|
||||
<field name="name">USt 10,7%</field>
|
||||
</record>
|
||||
<record id="tax_group_x" model="account.tax.group">
|
||||
<field name="name">USt x%</field>
|
||||
</record>
|
||||
<record id="tax_group_19" model="account.tax.group">
|
||||
<field name="name">Tax 19%</field>
|
||||
<field name="name">USt 19%</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="reconcile_5731" model="account.reconcile.model.template">
|
||||
<field name="name">Skonto-EK-7%</field>
|
||||
<field name="account_id" ref="chart_skr04_5731"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_vst_7_taxinclusive_skr04"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Skonto-EK-7%</field>
|
||||
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
|
||||
</record>
|
||||
<record id="reconcile_5736" model="account.reconcile.model.template">
|
||||
<field name="name">Skonto-EK-19%</field>
|
||||
<field name="account_id" ref="chart_skr04_5736"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_vst_19_taxinclusive_skr04"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Skonto-EK-19%</field>
|
||||
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
|
||||
</record>
|
||||
<record id="reconcile_4731" model="account.reconcile.model.template">
|
||||
<field name="name">Skonto-VK-7%</field>
|
||||
<field name="account_id" ref="chart_skr04_4731"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_ust_7_taxinclusive_skr04"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Skonto-VK-7%</field>
|
||||
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
|
||||
</record>
|
||||
<record id="reconcile_4736" model="account.reconcile.model.template">
|
||||
<field name="name">Skonto-VK-19%</field>
|
||||
<field name="account_id" ref="chart_skr04_4736"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_ust_19_taxinclusive_skr04"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Skonto-VK-19%</field>
|
||||
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
|
||||
</record>
|
||||
<record id="reconcile_6931" model="account.reconcile.model.template">
|
||||
<field name="name">Forderungsverlust-7%</field>
|
||||
<field name="account_id" ref="chart_skr04_6931"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_ust_7_taxinclusive_skr04"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Forderungsverlust-7%</field>
|
||||
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
|
||||
</record>
|
||||
<record id="reconcile_6936" model="account.reconcile.model.template">
|
||||
<field name="name">Forderungsverlust-19%</field>
|
||||
<field name="account_id" ref="chart_skr04_6936"/>
|
||||
<field name="amount_type">percentage</field>
|
||||
<field name="tax_id" ref="tax_ust_19_taxinclusive_skr04"/>
|
||||
<field name="amount">100</field>
|
||||
<field name="label">Forderungsverlust-19%</field>
|
||||
<field name="chart_template_id" ref="l10n_chart_de_skr04"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+3053
-539
File diff suppressed because it is too large
Load Diff
@@ -63,7 +63,7 @@ def format_amount(env, amount, currency):
|
||||
lang = env['res.lang']._lang_get(env.context.get('lang') or 'en_US')
|
||||
|
||||
formatted_amount = lang.format(fmt, currency.round(amount), grouping=True, monetary=True)\
|
||||
.replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'\u2011')
|
||||
.replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'-\N{ZERO WIDTH NO-BREAK SPACE}')
|
||||
|
||||
pre = post = u''
|
||||
if currency.position == 'before':
|
||||
|
||||
@@ -249,6 +249,11 @@ class PosConfig(models.Model):
|
||||
if any(self.journal_ids.mapped(lambda journal: journal.currency_id and journal.currency_id != self.currency_id)):
|
||||
raise ValidationError(_("All payment methods must be in the same currency as the Sales Journal or the company currency if that is not set."))
|
||||
|
||||
@api.constrains('company_id', 'available_pricelist_ids')
|
||||
def _check_companies(self):
|
||||
if any(self.available_pricelist_ids.mapped(lambda pl: pl.company_id.id not in (False, self.company_id.id))):
|
||||
raise ValidationError(_("The selected pricelists must belong to no company or the company of the point of sale."))
|
||||
|
||||
@api.onchange('iface_print_via_proxy')
|
||||
def _onchange_iface_print_via_proxy(self):
|
||||
self.iface_print_auto = self.iface_print_via_proxy
|
||||
|
||||
@@ -228,7 +228,7 @@ class ProductProduct(models.Model):
|
||||
def _compute_partner_ref(self):
|
||||
for supplier_info in self.seller_ids:
|
||||
if supplier_info.name.id == self._context.get('partner_id'):
|
||||
product_name = supplier_info.product_name or self.default_code
|
||||
product_name = supplier_info.product_name or self.default_code or self.name
|
||||
self.partner_ref = '%s%s' % (self.code and '[%s] ' % self.code or '', product_name)
|
||||
break
|
||||
else:
|
||||
|
||||
@@ -180,6 +180,9 @@ class CustomerPortal(CustomerPortal):
|
||||
@http.route(['/my/task/<int:task_id>'], type='http', auth="user", website=True)
|
||||
def portal_my_task(self, task_id=None, **kw):
|
||||
task = request.env['project.task'].browse(task_id)
|
||||
task.check_access_rights('read')
|
||||
task.check_access_rule('read')
|
||||
|
||||
vals = {
|
||||
'task': task,
|
||||
'user': request.env.user
|
||||
|
||||
@@ -154,8 +154,8 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<label string="Request for Quotation " attrs="{'invisible': [('state','not in',('draft','sent','bid'))]}"/>
|
||||
<label string="Purchase Order " attrs="{'invisible': [('state','in',('draft','sent','bid'))]}"/>
|
||||
<label string="Request for Quotation " attrs="{'invisible': [('state','not in',('draft','sent'))]}"/>
|
||||
<label string="Purchase Order " attrs="{'invisible': [('state','in',('draft','sent'))]}"/>
|
||||
<h1>
|
||||
<field name="name" readonly="1"/>
|
||||
</h1>
|
||||
|
||||
@@ -209,3 +209,12 @@ class Orderpoint(models.Model):
|
||||
result['domain'] = "[('id','in',%s)]" % (purchase_ids.ids)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class PushedFlow(models.Model):
|
||||
_inherit = "stock.location.path"
|
||||
|
||||
def _prepare_move_copy_values(self, move_to_copy, new_date):
|
||||
res = super()._prepare_move_copy_values(move_to_copy, new_date)
|
||||
res['purchase_line_id'] = None
|
||||
return res
|
||||
|
||||
@@ -236,12 +236,13 @@
|
||||
</div>
|
||||
<t t-foreach="order.order_line" t-as="ol">
|
||||
<div class="row orders_vertical_align">
|
||||
<div class="visible-lg col-lg-1 text-center">
|
||||
<div t-if="not request.env.user._is_public()" class="visible-lg col-lg-1 text-center">
|
||||
<span t-field="ol.product_image" t-options="{'widget': 'image', 'class': 'img-rounded', 'style':'width: 48px;height:48px'}" />
|
||||
</div>
|
||||
<div id='product_name' t-att-class="'col-lg-3 col-sm-5 col-xs-4' if display_discount else 'col-lg-4 col-sm-6 col-xs-3'">
|
||||
<span t-esc="ol.product_id.name"/>
|
||||
</div>
|
||||
<div t-if="request.env.user._is_public()" class="visible-lg col-lg-1 text-center" /> <!-- Just for alignment -->
|
||||
<div class="col-sm-3 hidden-xs text-right">
|
||||
<span t-field="ol.price_unit" t-options='{"widget": "monetary", "display_currency": order.pricelist_id.currency_id}'/>
|
||||
</div>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<record id="account_analytic_line_rule_billing_user" model="ir.rule">
|
||||
<field name="name">account.analytic.line.billing.user</field>
|
||||
<field name="model_id" ref="analytic.model_account_analytic_line"/>
|
||||
<field name="domain_force">[('project_id', '=', False)]</field>
|
||||
<field name="domain_force">[(1, '=', 1)]</field>
|
||||
<field name="groups" eval="[(4, ref('account.group_account_invoice'))]"/>
|
||||
<field name="perm_create" eval="1"/>
|
||||
<field name="perm_write" eval="1"/>
|
||||
|
||||
@@ -28,11 +28,11 @@ class Company(models.Model):
|
||||
location.sudo().write({'company_id': company.id})
|
||||
company.write({'internal_transit_location_id': location.id})
|
||||
|
||||
warehouses = self.env['stock.warehouse'].search([('partner_id', '=', self.partner_id.id)])
|
||||
warehouses.mapped('partner_id').with_context(force_company=self.id).write({
|
||||
'property_stock_customer': location.id,
|
||||
'property_stock_supplier': location.id,
|
||||
})
|
||||
warehouses = self.env['stock.warehouse'].search([('partner_id', '=', company.partner_id.id)])
|
||||
warehouses.mapped('partner_id').with_context(force_company=company.id).write({
|
||||
'property_stock_customer': location.id,
|
||||
'property_stock_supplier': location.id,
|
||||
})
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
|
||||
@@ -262,12 +262,12 @@ class StockQuant(models.Model):
|
||||
# if we want to reserve
|
||||
available_quantity = self._get_available_quantity(product_id, location_id, lot_id=lot_id, package_id=package_id, owner_id=owner_id, strict=strict)
|
||||
if float_compare(quantity, available_quantity, precision_rounding=rounding) > 0:
|
||||
raise UserError(_('It is not possible to reserve more products of %s than you have in stock.') % (', '.join(quants.mapped('product_id').mapped('display_name'))))
|
||||
raise UserError(_('It is not possible to reserve more products of %s than you have in stock.') % product_id.display_name)
|
||||
elif float_compare(quantity, 0, precision_rounding=rounding) < 0:
|
||||
# if we want to unreserve
|
||||
available_quantity = sum(quants.mapped('reserved_quantity'))
|
||||
if float_compare(abs(quantity), available_quantity, precision_rounding=rounding) > 0:
|
||||
raise UserError(_('It is not possible to unreserve more products of %s than you have in stock.') % (', '.join(quants.mapped('product_id').mapped('display_name'))))
|
||||
raise UserError(_('It is not possible to unreserve more products of %s than you have in stock.') % product_id.display_name)
|
||||
else:
|
||||
return reserved_quants
|
||||
|
||||
|
||||
@@ -695,11 +695,31 @@ class Warehouse(models.Model):
|
||||
|
||||
def _get_sequence_values(self):
|
||||
return {
|
||||
'in_type_id': {'name': self.name + ' ' + _('Sequence in'), 'prefix': self.code + '/IN/', 'padding': 5},
|
||||
'out_type_id': {'name': self.name + ' ' + _('Sequence out'), 'prefix': self.code + '/OUT/', 'padding': 5},
|
||||
'pack_type_id': {'name': self.name + ' ' + _('Sequence packing'), 'prefix': self.code + '/PACK/', 'padding': 5},
|
||||
'pick_type_id': {'name': self.name + ' ' + _('Sequence picking'), 'prefix': self.code + '/PICK/', 'padding': 5},
|
||||
'int_type_id': {'name': self.name + ' ' + _('Sequence internal'), 'prefix': self.code + '/INT/', 'padding': 5},
|
||||
'in_type_id': {
|
||||
'name': self.name + ' ' + _('Sequence in'),
|
||||
'prefix': self.code + '/IN/', 'padding': 5,
|
||||
'company_id': self.company_id.id,
|
||||
},
|
||||
'out_type_id': {
|
||||
'name': self.name + ' ' + _('Sequence out'),
|
||||
'prefix': self.code + '/OUT/', 'padding': 5,
|
||||
'company_id': self.company_id.id,
|
||||
},
|
||||
'pack_type_id': {
|
||||
'name': self.name + ' ' + _('Sequence packing'),
|
||||
'prefix': self.code + '/PACK/', 'padding': 5,
|
||||
'company_id': self.company_id.id,
|
||||
},
|
||||
'pick_type_id': {
|
||||
'name': self.name + ' ' + _('Sequence picking'),
|
||||
'prefix': self.code + '/PICK/', 'padding': 5,
|
||||
'company_id': self.company_id.id,
|
||||
},
|
||||
'int_type_id': {
|
||||
'name': self.name + ' ' + _('Sequence internal'),
|
||||
'prefix': self.code + '/INT/', 'padding': 5,
|
||||
'company_id': self.company_id.id,
|
||||
},
|
||||
}
|
||||
|
||||
def _format_rulename(self, from_loc, dest_loc, suffix):
|
||||
|
||||
@@ -107,7 +107,7 @@ class LandedCost(models.Model):
|
||||
'landed_cost_value': new_landed_cost_value,
|
||||
'value': line.move_id.value + cost_to_add,
|
||||
'remaining_value': line.move_id.remaining_value + cost_to_add,
|
||||
'price_unit': (line.move_id.value + new_landed_cost_value) / line.move_id.product_qty,
|
||||
'price_unit': (line.move_id.value + cost_to_add) / line.move_id.product_qty,
|
||||
})
|
||||
# `remaining_qty` is negative if the move is out and delivered proudcts that were not
|
||||
# in stock.
|
||||
|
||||
@@ -25,7 +25,7 @@ class Http(models.AbstractModel):
|
||||
return {
|
||||
"session_id": request.session.sid,
|
||||
"uid": request.session.uid,
|
||||
"is_system": user._is_system(),
|
||||
"is_system": user._is_system() if request.session.uid else False,
|
||||
"is_superuser": user._is_superuser() if request.session.uid else False,
|
||||
"user_context": request.session.get_context() if request.session.uid else {},
|
||||
"db": request.session.db,
|
||||
|
||||
+1
@@ -48,6 +48,7 @@ ol {
|
||||
|
||||
ul {
|
||||
list-style: disc;
|
||||
padding-left: 40px;
|
||||
}
|
||||
|
||||
ul ul {
|
||||
|
||||
@@ -704,7 +704,7 @@ ActionManager.include({
|
||||
var env = ev.data.env;
|
||||
var context = new Context(env.context, actionData.context || {});
|
||||
var recordID = env.currentID || null; // pyeval handles null value, not undefined
|
||||
var def;
|
||||
var def = $.Deferred();
|
||||
|
||||
// determine the action to execute according to the actionData
|
||||
if (actionData.special) {
|
||||
|
||||
@@ -1843,7 +1843,7 @@ var StatInfo = AbstractField.extend({
|
||||
*/
|
||||
_render: function () {
|
||||
var options = {
|
||||
value: this.value || 0,
|
||||
value: this._formatValue(this.value || 0),
|
||||
};
|
||||
if (! this.attrs.nolabel) {
|
||||
if (this.nodeOptions.label_field && this.recordData[this.nodeOptions.label_field]) {
|
||||
|
||||
@@ -141,6 +141,7 @@ var KanbanColumnProgressBar = Widget.extend({
|
||||
}
|
||||
|
||||
// Display and animate the progress bars
|
||||
var barNumber = 0;
|
||||
_.each(self.colors, function (val, key) {
|
||||
var $bar = self.$bars[val];
|
||||
var count = self.subgroupCounts && self.subgroupCounts[key] || 0;
|
||||
@@ -165,7 +166,14 @@ var KanbanColumnProgressBar = Widget.extend({
|
||||
window.getComputedStyle($bar[0]).getPropertyValue('width'); // Force reflow so that animations work
|
||||
if (count > 0) {
|
||||
$bar.addClass('o_bar_has_records');
|
||||
// Make sure every bar that has records has some space
|
||||
// and that everything adds up to 100%
|
||||
var minWidth = 6*barNumber;
|
||||
var maxWidth = 100 - minWidth;
|
||||
self.$('.progress-bar.o_bar_has_records').css('max-width', maxWidth + '%');
|
||||
self.$('.progress-bar.o_bar_has_records').css('min-width', minWidth + '%');
|
||||
$bar.css('width', (count * 100 / self.groupCount) + '%');
|
||||
barNumber++;
|
||||
} else {
|
||||
$bar.css('width', '');
|
||||
}
|
||||
|
||||
@@ -72,18 +72,16 @@
|
||||
max-width: 70%;
|
||||
line-height: 1.2;
|
||||
|
||||
.o_stat_value {
|
||||
> .o_stat_value, > .o_stat_text {
|
||||
@include o-text-overflow(block);
|
||||
}
|
||||
|
||||
.o_stat_value {
|
||||
font-weight: 700;
|
||||
color: $o-brand-primary;
|
||||
}
|
||||
.o_stat_text {
|
||||
@include o-text-overflow(block);
|
||||
font-size: small;
|
||||
|
||||
.o_stat_value {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
}
|
||||
> span {
|
||||
|
||||
@@ -72,11 +72,6 @@
|
||||
margin-bottom: 0;
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
|
||||
// Be sure that a bar with data has a minimun width
|
||||
&.o_bar_has_records {
|
||||
min-width: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.o_kanban_counter_label {
|
||||
|
||||
@@ -4074,6 +4074,40 @@ QUnit.module('basic_fields', {
|
||||
|
||||
QUnit.module('StatInfo');
|
||||
|
||||
QUnit.test('statinfo widget formats decimal precision', function (assert) {
|
||||
// sometimes the round method can return numbers such as 14.000001
|
||||
// when asked to round a number to 2 decimals, as such is the behaviour of floats.
|
||||
// we check that even in that eventuality, only two decimals are displayed
|
||||
assert.expect(2);
|
||||
|
||||
this.data.partner.fields.monetary = {string: "Monetary", type: 'monetary'};
|
||||
this.data.partner.records[0].monetary = 9.999999;
|
||||
this.data.partner.records[0].currency_id = 1;
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<button class="oe_stat_button" name="items" icon="fa-gear">' +
|
||||
'<field name="qux" widget="statinfo"/>' +
|
||||
'</button>' +
|
||||
'<button class="oe_stat_button" name="money" icon="fa-money">' +
|
||||
'<field name="monetary" widget="statinfo"/>' +
|
||||
'</button>' +
|
||||
'</form>',
|
||||
res_id: 1,
|
||||
});
|
||||
|
||||
// formatFloat renders according to this.field.digits
|
||||
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').eq(0).text(),
|
||||
'0.4', "Default precision should be [16,1]");
|
||||
assert.strictEqual(form.$('.oe_stat_button .o_field_widget.o_stat_info .o_stat_value').eq(1).text(),
|
||||
'10.00', "Currency decimal precision should be 2");
|
||||
|
||||
form.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('statinfo widget in form view', function (assert) {
|
||||
assert.expect(9);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ var Widget = require('web.Widget');
|
||||
var weContext = require('web_editor.context');
|
||||
var rte = require('web_editor.rte');
|
||||
var weWidgets = require('web_editor.widget');
|
||||
var Dialog = require('web.Dialog');
|
||||
|
||||
var _t = core._t;
|
||||
|
||||
@@ -26,6 +27,7 @@ var RTETranslatorWidget = rte.Class.extend({
|
||||
* @override
|
||||
*/
|
||||
_saveElement: function ($el, context, withLang) {
|
||||
var self = this;
|
||||
if ($el.data('oe-translation-id')) {
|
||||
return this._rpc({
|
||||
model: 'ir.translation',
|
||||
@@ -35,7 +37,9 @@ var RTETranslatorWidget = rte.Class.extend({
|
||||
this._getEscapedElement($el).html(),
|
||||
context || weContext.get()
|
||||
],
|
||||
});
|
||||
}).fail(function (error) {
|
||||
Dialog.alert(null, error.data.message);
|
||||
});
|
||||
}
|
||||
return this._super($el, context, withLang === undefined ? true : withLang);
|
||||
},
|
||||
|
||||
@@ -1528,7 +1528,7 @@ var LinkDialog = Dialog.extend({
|
||||
+ ((size && size.length) ? (' btn-' + size) : '');
|
||||
var isNewWindow = this.$('input[name="is_new_window"]').prop('checked');
|
||||
|
||||
if (url.indexOf('@') >= 0 && url.indexOf('mailto:') < 0) {
|
||||
if (url.indexOf('@') >= 0 && url.indexOf('mailto:') < 0 && !url.match(/^http[s]?/i)) {
|
||||
url = ('mailto:' + url);
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -72,7 +72,8 @@ class WebsiteHrRecruitment(http.Controller):
|
||||
|
||||
@http.route('/jobs/add', type='http', auth="user", website=True)
|
||||
def jobs_add(self, **kwargs):
|
||||
job = request.env['hr.job'].create({
|
||||
# avoid branding of website_description by setting rendering_bundle in context
|
||||
job = request.env['hr.job'].with_context(rendering_bundle=True).create({
|
||||
'name': _('Job Title'),
|
||||
})
|
||||
return request.redirect("/jobs/detail/%s?enable_editor=1" % slug(job))
|
||||
|
||||
@@ -76,4 +76,4 @@ class WebsiteSaleDelivery(WebsiteSale):
|
||||
lang = request.env['res.lang']._lang_get(request.env.context.get('lang') or 'en_US')
|
||||
|
||||
return lang.format(fmt, currency.round(amount), grouping=True, monetary=True)\
|
||||
.replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'\u2011')
|
||||
.replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'-\N{ZERO WIDTH NO-BREAK SPACE}')
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
France, 2018-07-20
|
||||
|
||||
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,
|
||||
|
||||
tducasse 11507599+tducasse@users.noreply.github.com https://github.com/tducasse
|
||||
@@ -113,6 +113,10 @@ Running the server
|
||||
|
||||
runs tests after installing modules
|
||||
|
||||
.. option:: --test-tags 'tag_1,tag_2,...,-tag_n'
|
||||
|
||||
select the tests to run by using tags.
|
||||
|
||||
.. option:: --dev <feature,feature,...,feature>
|
||||
|
||||
* ``all``: all the features below are activated
|
||||
@@ -305,6 +309,13 @@ customize the amount of logging output
|
||||
enables `log rotation <https://docs.python.org/2/library/logging.handlers.html#timedrotatingfilehandler>`_
|
||||
daily, keeping 30 backups. Log rotation frequency and number of backups is
|
||||
not configurable.
|
||||
|
||||
.. danger::
|
||||
|
||||
Built-in log rotation is not reliable in multi-workers scenarios
|
||||
and may incur significant data loss. It is *strongly recommended* to
|
||||
use an external log rotation utility or use system loggers (--syslog)
|
||||
instead.
|
||||
|
||||
.. option:: --syslog
|
||||
|
||||
|
||||
@@ -71,8 +71,6 @@ This means the first *group rule* restricts access, but any further
|
||||
.. warning:: record rules do not apply to the Administrator user
|
||||
:class: aphorism
|
||||
|
||||
although access rules do
|
||||
|
||||
.. _reference/security/fields:
|
||||
|
||||
Field Access
|
||||
|
||||
+144
-1
@@ -64,6 +64,8 @@ related to testing Odoo content (modules, mainly):
|
||||
.. autoclass:: odoo.tests.common.HttpCase
|
||||
:members: browse_ref, ref, url_open, phantom_js
|
||||
|
||||
.. autofunction:: odoo.tests.common.tagged
|
||||
|
||||
By default, tests are run once right after the corresponding module has been
|
||||
installed. Test cases can also be configured to run after all modules have
|
||||
been installed, and not run right after the module installation:
|
||||
@@ -111,6 +113,147 @@ supported.
|
||||
|
||||
.. _unittest documentation: https://docs.python.org/2/library/unittest.html
|
||||
|
||||
Test selection
|
||||
--------------
|
||||
|
||||
In Odoo, Python tests can be tagged to facilitate the test selection when
|
||||
running tests.
|
||||
|
||||
Subclasses of :class:`odoo.tests.common.BaseCase` (usually through
|
||||
:class:`~odoo.tests.common.TransactionCase`,
|
||||
:class:`~odoo.tests.common.SavepointCase` or
|
||||
:class:`~odoo.tests.common.HttpCase`) are automatically tagged with
|
||||
``standard``, ``at_install`` and their source module's name by default.
|
||||
|
||||
Invocation
|
||||
^^^^^^^^^^
|
||||
|
||||
:option:`--test-tags <odoo-bin --test-tags>` can be used to select/filter tests
|
||||
to run on the command-line.
|
||||
|
||||
This option defaults to ``+standard`` meaning tests tagged ``standard``
|
||||
(explicitly or implicitly) will be run by default when starting Odoo
|
||||
with :option:`--test-enable <odoo-bin --test-enable>`.
|
||||
|
||||
When writing tests, the :func:`~odoo.tests.common.tagged` decorator can be
|
||||
used on **test classes** to add or remove tags.
|
||||
|
||||
The decorator's arguments are tag names, as strings.
|
||||
|
||||
.. danger:: :func:`~odoo.tests.common.tagged` is a class decorator, it has no
|
||||
effect on functions or methods
|
||||
|
||||
Tags can be prefixed with the minus (``-``) sign, to *remove* them instead of
|
||||
add or select them e.g. if you don't want your test to be executed by
|
||||
default you can remove the ``standard`` tag:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from odoo.tests import TransactionCase, tagged
|
||||
|
||||
@tagged('-standard', 'nice')
|
||||
class NiceTest(TransactionCase):
|
||||
...
|
||||
|
||||
This test will not be selected by default, to run it the relevant tag will
|
||||
have to be selected explicitely:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ odoo-bin --test-enable --test-tags nice
|
||||
|
||||
Note that only the tests tagged ``nice`` are going to be executed. To run
|
||||
*both* ``nice`` and ``standard`` tests, provide multiple values to
|
||||
:option:`--test-tags <odoo-bin --test-tags>`: on the command-line, values
|
||||
are *additive* (you're selecting all tests with *any* of the specified tags)
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ odoo-bin --test-enable --test-tags nice,standard
|
||||
|
||||
The config switch parameter also accepts the ``+`` and ``-`` prefixes. The
|
||||
``+`` prefix is implied and therefore, totaly optional. The ``-`` (minus)
|
||||
prefix is made to deselect tests tagged with the prefixed tags, even if they
|
||||
are selected by other specified tags e.g. if there are ``standard`` tests which
|
||||
are also tagged as ``slow`` you can run all standard tests *except* the slow
|
||||
ones:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ odoo-bin --test-enable --test-tags 'standard,-slow'
|
||||
|
||||
When you write a test that does not inherit from the
|
||||
:class:`~odoo.tests.common.BaseCase`, this test will not have the default tags,
|
||||
you have to add them explicitely to have the test included in the default test
|
||||
suite. This is a common issue when using a simple ``unittest.TestCase`` as
|
||||
they're not going to get run:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import unittest
|
||||
from odoo.tests import tagged
|
||||
|
||||
@tagged('standard', 'at_install')
|
||||
class SmallTest(unittest.TestCase):
|
||||
...
|
||||
|
||||
Special tags
|
||||
^^^^^^^^^^^^
|
||||
|
||||
- ``standard``: All Odoo tests that inherit from
|
||||
:class:`~odoo.tests.common.BaseCase` are implicitely tagged standard.
|
||||
:option:`--test-tags <odoo-bin --test-tags>` also defaults to ``standard``.
|
||||
|
||||
That means untagged test will be executed by default when tests are enabled.
|
||||
- ``at_install``: Means that the test will be executed right after the module
|
||||
installation and before other modules are installed. This is a default
|
||||
implicit tag.
|
||||
- ``post_install``: Means that the test will be executed after all the modules
|
||||
are installed. This is what you want for HttpCase tests most of the time.
|
||||
|
||||
Note that this is *not exclusive* with ``at_install``, however since you
|
||||
will generally not want both ``post_install`` is usually paired with
|
||||
``-at_install`` when tagging a test class.
|
||||
- *module_name*: Odoo tests classes extending
|
||||
:class:`~odoo.tests.common.BaseCase` are implicitely tagged with the
|
||||
technical name of their module. This allows easily selecting or excluding
|
||||
specific modules when testing e.g. if you want to only run tests from
|
||||
``stock_account``:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ odoo-bin --test-enable --test-tags stock_account
|
||||
|
||||
Examples
|
||||
^^^^^^^^
|
||||
|
||||
.. important::
|
||||
|
||||
Tests will be executed only in the installed or updated modules. So
|
||||
modules have to be selected with the :option:`-u <odoo-bin -u>` or
|
||||
:option:`-i <odoo-bin -i>` switches. For simplicity, those switches are
|
||||
not specified in the examples below.
|
||||
|
||||
Run only the tests from the sale module:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ odoo-bin --test-enable --test-tags sale
|
||||
|
||||
Run the tests from the sale module but not the ones tagged as slow:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ odoo-bin --test-enable --test-tags 'sale,-slow'
|
||||
|
||||
Run only the tests from stock or tagged as slow:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ odoo-bin --test-enable --test-tags '-standard, slow, stock'
|
||||
|
||||
.. note:: ``-standard`` is implicit (not required), and present for clarity
|
||||
|
||||
Testing JS code
|
||||
===============
|
||||
|
||||
@@ -153,4 +296,4 @@ that the web client and the server work together. In order to do that, we can
|
||||
write another kind of test: tours. A tour is a mini scenario of some interesting
|
||||
business flow. It explains a sequence of steps that should be followed. The
|
||||
test runner will then create a phantom_js browser, point it to the proper url
|
||||
and simulate the click and inputs, according to the scenario.
|
||||
and simulate the click and inputs, according to the scenario.
|
||||
|
||||
@@ -564,23 +564,29 @@ class IrModelFields(models.Model):
|
||||
This method prevents the modification/deletion of many2one fields
|
||||
that have an inverse one2many, for instance.
|
||||
"""
|
||||
failed_dependencies = []
|
||||
for rec in self:
|
||||
model = self.env[rec.model]
|
||||
field = model._fields[rec.name]
|
||||
for dependant, path in model._field_triggers.get(field, ()):
|
||||
if dependant.manual:
|
||||
failed_dependencies.append((field, dependant))
|
||||
for inverse in model._field_inverses.get(field, ()):
|
||||
if inverse.manual and inverse.type == 'one2many':
|
||||
failed_dependencies.append((field, inverse))
|
||||
|
||||
if not self._context.get(MODULE_UNINSTALL_FLAG) and failed_dependencies:
|
||||
msg = _("The field '%s' cannot be removed because the field '%s' depends on it.")
|
||||
raise UserError(msg % failed_dependencies[0])
|
||||
elif failed_dependencies:
|
||||
dependants = {rel[1] for rel in failed_dependencies}
|
||||
to_unlink = [self._get(field.model_name, field.name) for field in dependants]
|
||||
self.browse().union(*to_unlink).unlink()
|
||||
|
||||
self = self.filtered(lambda record: record.state == 'manual')
|
||||
if not self:
|
||||
return
|
||||
|
||||
for record in self:
|
||||
model = self.env[record.model]
|
||||
field = model._fields[record.name]
|
||||
if field.type == 'many2one' and model._field_inverses.get(field):
|
||||
if self._context.get(MODULE_UNINSTALL_FLAG):
|
||||
# automatically unlink the corresponding one2many field(s)
|
||||
inverses = self.search([('relation', '=', field.model_name),
|
||||
('relation_field', '=', field.name)])
|
||||
inverses.unlink()
|
||||
continue
|
||||
msg = _("The field '%s' cannot be removed because the field '%s' depends on it.")
|
||||
raise UserError(msg % (field, model._field_inverses[field][0]))
|
||||
|
||||
# remove fields from registry, and check that views are not broken
|
||||
fields = [self.env[record.model]._pop_field(record.name) for record in self]
|
||||
domain = expression.OR([('arch_db', 'like', record.name)] for record in self)
|
||||
|
||||
@@ -7,6 +7,7 @@ from odoo import api, fields, models, _
|
||||
from PIL import Image
|
||||
import babel
|
||||
from lxml import etree
|
||||
import math
|
||||
|
||||
from odoo.tools import html_escape as escape, posix_to_ldml, safe_eval, float_utils, format_date, pycompat
|
||||
|
||||
@@ -125,7 +126,7 @@ class IntegerConverter(models.AbstractModel):
|
||||
|
||||
@api.model
|
||||
def value_to_html(self, value, options):
|
||||
return pycompat.to_text(self.user_lang().format('%d', value, grouping=True).replace(r'-', u'\u2011'))
|
||||
return pycompat.to_text(self.user_lang().format('%d', value, grouping=True).replace(r'-', u'-\N{ZERO WIDTH NO-BREAK SPACE}'))
|
||||
|
||||
|
||||
class FloatConverter(models.AbstractModel):
|
||||
@@ -145,7 +146,7 @@ class FloatConverter(models.AbstractModel):
|
||||
value = float_utils.float_round(value, precision_digits=precision)
|
||||
fmt = '%.{precision}f'.format(precision=precision)
|
||||
|
||||
formatted = self.user_lang().format(fmt, value, grouping=True).replace(r'-', u'\u2011')
|
||||
formatted = self.user_lang().format(fmt, value, grouping=True).replace(r'-', u'-\N{ZERO WIDTH NO-BREAK SPACE}')
|
||||
|
||||
# %f does not strip trailing zeroes. %g does but its precision causes
|
||||
# it to switch to scientific notation starting at a million *and* to
|
||||
@@ -327,7 +328,7 @@ class MonetaryConverter(models.AbstractModel):
|
||||
|
||||
lang = self.user_lang()
|
||||
formatted_amount = lang.format(fmt, display_currency.round(value),
|
||||
grouping=True, monetary=True).replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'\u2011')
|
||||
grouping=True, monetary=True).replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'-\N{ZERO WIDTH NO-BREAK SPACE}')
|
||||
|
||||
pre = post = u''
|
||||
if display_currency.position == 'before':
|
||||
@@ -373,9 +374,9 @@ class FloatTimeConverter(models.AbstractModel):
|
||||
|
||||
@api.model
|
||||
def value_to_html(self, value, options):
|
||||
factor = -1 if value < 0 else 1
|
||||
sign = math.copysign(1.0, value)
|
||||
hours, minutes = divmod(abs(value) * 60, 60)
|
||||
return '%02d:%02d' % (hours * factor, minutes)
|
||||
return '%02d:%02d' % (sign * hours, minutes)
|
||||
|
||||
|
||||
class DurationConverter(models.AbstractModel):
|
||||
|
||||
@@ -616,6 +616,14 @@ class IrTranslation(models.Model):
|
||||
SELECT 1 FROM ir_translation
|
||||
WHERE lang=l.code AND type='model' AND name=%(name)s AND res_id=%(res_id)s
|
||||
);
|
||||
|
||||
DELETE FROM ir_translation dup
|
||||
WHERE type='model' AND name=%(name)s AND res_id=%(res_id)s
|
||||
AND dup.id NOT IN (SELECT MAX(t.id)
|
||||
FROM ir_translation t
|
||||
WHERE t.lang=dup.lang AND type='model' AND name=%(name)s AND res_id=%(res_id)s
|
||||
);
|
||||
|
||||
UPDATE ir_translation SET src=%(src)s
|
||||
WHERE type='model' AND name=%(name)s AND res_id=%(res_id)s;
|
||||
"""
|
||||
|
||||
@@ -136,6 +136,9 @@ class Partner(models.Model):
|
||||
def _default_company(self):
|
||||
return self.env['res.company']._company_default_get('res.partner')
|
||||
|
||||
def _split_street_with_params(self, street_raw, street_format):
|
||||
return {'street': street_raw}
|
||||
|
||||
name = fields.Char(index=True)
|
||||
display_name = fields.Char(compute='_compute_display_name', store=True, index=True)
|
||||
date = fields.Date(index=True)
|
||||
|
||||
@@ -246,9 +246,6 @@ class TestCustomFields(common.TransactionCase):
|
||||
self.registry.enter_test_mode(self.cr)
|
||||
self.addCleanup(self.registry.leave_test_mode)
|
||||
|
||||
# do not reload the registry after removing a field
|
||||
self.env = self.env(context={'_force_unlink': True})
|
||||
|
||||
def create_field(self, name):
|
||||
""" create a custom field and return it """
|
||||
model = self.env['ir.model'].search([('model', '=', self.MODEL)])
|
||||
@@ -274,48 +271,6 @@ class TestCustomFields(common.TransactionCase):
|
||||
with self.assertRaises(ValidationError):
|
||||
self.create_field('foo')
|
||||
|
||||
def test_create_custom_o2m(self):
|
||||
""" try creating a custom o2m and then deleting its m2o inverse """
|
||||
model = self.env['ir.model'].search([('model', '=', self.MODEL)])
|
||||
comodel = self.env['ir.model'].search([('model', '=', self.COMODEL)])
|
||||
|
||||
m2o_field = self.env['ir.model.fields'].create({
|
||||
'model_id': comodel.id,
|
||||
'name': 'x_my_m2o',
|
||||
'field_description': 'my_m2o',
|
||||
'ttype': 'many2one',
|
||||
'relation': self.MODEL,
|
||||
})
|
||||
|
||||
o2m_field = self.env['ir.model.fields'].create({
|
||||
'model_id': model.id,
|
||||
'name': 'x_my_o2m',
|
||||
'field_description': 'my_o2m',
|
||||
'ttype': 'one2many',
|
||||
'relation': self.COMODEL,
|
||||
'relation_field': m2o_field.name,
|
||||
})
|
||||
|
||||
m2o_field.unlink()
|
||||
self.assertFalse(o2m_field.exists())
|
||||
|
||||
def test_create_custom_related(self):
|
||||
""" try creating a custom related then deleting its inverse """
|
||||
comodel = self.env['ir.model'].search([('model', '=', self.COMODEL)])
|
||||
|
||||
field = self.create_field('x_my_char')
|
||||
|
||||
related_field = self.env['ir.model.fields'].create({
|
||||
'model_id': comodel.id,
|
||||
'name': 'x_oh_boy',
|
||||
'field_description': 'x_oh_boy',
|
||||
'ttype': 'char',
|
||||
'related': 'partner_id.x_my_char',
|
||||
})
|
||||
|
||||
field.unlink()
|
||||
self.assertFalse(related_field.exists())
|
||||
|
||||
def test_rename_custom(self):
|
||||
""" custom field names must be start with 'x_' """
|
||||
field = self.create_field('x_foo')
|
||||
@@ -375,3 +330,56 @@ class TestCustomFields(common.TransactionCase):
|
||||
with self.assertRaises(UserError):
|
||||
field.name = 'x_bar'
|
||||
self.assertIn('x_foo', self.env[self.MODEL]._fields)
|
||||
|
||||
def test_unlink_with_inverse(self):
|
||||
""" create a custom o2m and then delete its m2o inverse """
|
||||
model = self.env['ir.model']._get(self.MODEL)
|
||||
comodel = self.env['ir.model']._get(self.COMODEL)
|
||||
|
||||
m2o_field = self.env['ir.model.fields'].create({
|
||||
'model_id': comodel.id,
|
||||
'name': 'x_my_m2o',
|
||||
'field_description': 'my_m2o',
|
||||
'ttype': 'many2one',
|
||||
'relation': self.MODEL,
|
||||
})
|
||||
|
||||
o2m_field = self.env['ir.model.fields'].create({
|
||||
'model_id': model.id,
|
||||
'name': 'x_my_o2m',
|
||||
'field_description': 'my_o2m',
|
||||
'ttype': 'one2many',
|
||||
'relation': self.COMODEL,
|
||||
'relation_field': m2o_field.name,
|
||||
})
|
||||
|
||||
# normal mode: you cannot break dependencies
|
||||
with self.assertRaises(UserError):
|
||||
m2o_field.unlink()
|
||||
|
||||
# uninstall mode: unlink dependant fields
|
||||
m2o_field.with_context(_force_unlink=True).unlink()
|
||||
self.assertFalse(o2m_field.exists())
|
||||
|
||||
def test_unlink_with_dependant(self):
|
||||
""" create a computed field, then delete its dependency """
|
||||
# Also applies to compute fields
|
||||
comodel = self.env['ir.model'].search([('model', '=', self.COMODEL)])
|
||||
|
||||
field = self.create_field('x_my_char')
|
||||
|
||||
dependant = self.env['ir.model.fields'].create({
|
||||
'model_id': comodel.id,
|
||||
'name': 'x_oh_boy',
|
||||
'field_description': 'x_oh_boy',
|
||||
'ttype': 'char',
|
||||
'related': 'partner_id.x_my_char',
|
||||
})
|
||||
|
||||
# normal mode: you cannot break dependencies
|
||||
with self.assertRaises(UserError):
|
||||
field.unlink()
|
||||
|
||||
# uninstall mode: unlink dependant fields
|
||||
field.with_context(_force_unlink=True).unlink()
|
||||
self.assertFalse(dependant.exists())
|
||||
|
||||
@@ -275,6 +275,37 @@ class TestTranslation(TransactionCase):
|
||||
self.assertEqual(categories.ids, [padawans.id, self.customers.id],
|
||||
"Search ordered by translated name should return Padawans (Apprentis) before Customers (Clients)")
|
||||
|
||||
def test_105_duplicated_translation(self):
|
||||
""" Test synchronizing translations with duplicated source """
|
||||
# create a category with a French translation
|
||||
padawans = self.env['res.partner.category'].create({'name': 'Padawan'})
|
||||
self.env['ir.translation'].create({
|
||||
'type': 'model',
|
||||
'name': 'res.partner.category,name',
|
||||
'module':'base',
|
||||
'lang': 'fr_FR',
|
||||
'res_id': padawans.id,
|
||||
'value': 'Apprenti',
|
||||
'state': 'translated',
|
||||
})
|
||||
# change name and insert a duplicate manually
|
||||
padawans.write({'name': 'Padawans'})
|
||||
self.env['ir.translation'].create({
|
||||
'type': 'model',
|
||||
'name': 'res.partner.category,name',
|
||||
'module':'base',
|
||||
'lang': 'fr_FR',
|
||||
'res_id': padawans.id,
|
||||
'value': 'Apprentis',
|
||||
'state': 'translated',
|
||||
})
|
||||
self.env['ir.translation'].translate_fields('res.partner.category', padawans.id, 'name')
|
||||
translations = self.env['ir.translation'].search([
|
||||
('res_id', '=', padawans.id), ('name', '=', 'res.partner.category,name')
|
||||
])
|
||||
self.assertEqual(len(translations), 1, "Translations were not merged after `translate_fields` call")
|
||||
self.assertEqual(translations.value, "Apprentis", "The most recent translation must stay")
|
||||
|
||||
|
||||
class TestXMLTranslation(TransactionCase):
|
||||
def setUp(self):
|
||||
|
||||
@@ -73,7 +73,7 @@ class TestFloatExport(TestBasicExport):
|
||||
converter = self.get_converter('float')
|
||||
|
||||
value = converter(-42.0)
|
||||
self.assertEqual(value, u"\u201142.0")
|
||||
self.assertEqual(value, u"-\N{ZERO WIDTH NO-BREAK SPACE}42.0")
|
||||
|
||||
value = converter(42.0100)
|
||||
self.assertEqual(value, "42.01")
|
||||
@@ -120,7 +120,7 @@ class TestCurrencyExport(TestExport):
|
||||
converted = self.convert(obj, dest=currency)
|
||||
|
||||
self.assertEqual(
|
||||
converted, u'<span class="oe_currency_value">\u20110.12</span>'
|
||||
converted, u'<span class="oe_currency_value">-\N{ZERO WIDTH NO-BREAK SPACE}0.12</span>'
|
||||
u'\N{NO-BREAK SPACE}{symbol}'.format(
|
||||
obj=obj,
|
||||
symbol=currency.symbol
|
||||
|
||||
@@ -139,14 +139,10 @@ class TestOnChange(common.TransactionCase):
|
||||
self.env.cache.invalidate()
|
||||
result = self.Discussion.onchange(values, 'name', field_onchange)
|
||||
self.assertIn('messages', result['value'])
|
||||
self.assertItemsEqual(result['value']['messages'], [
|
||||
self.assertEqual(result['value']['messages'], [
|
||||
(5,),
|
||||
(1, message.id, {
|
||||
'name': "[%s] %s" % ("Foo", USER.name),
|
||||
'body': message.body,
|
||||
'author': message.author.name_get()[0],
|
||||
'size': message.size,
|
||||
'important': message.important,
|
||||
}),
|
||||
(0, 0, {
|
||||
'name': "[%s] %s" % ("Foo", USER.name),
|
||||
@@ -157,6 +153,17 @@ class TestOnChange(common.TransactionCase):
|
||||
}),
|
||||
])
|
||||
|
||||
# ensure onchange changing one2many without subfield works
|
||||
one_level_fields = {k: v for k, v in field_onchange.items() if k.count('.') < 1}
|
||||
values = dict(values, name='{generate_dummy_message}')
|
||||
result = self.Discussion.with_context(generate_dummy_message=True).onchange(values, 'name', one_level_fields)
|
||||
self.assertEqual(result['value']['messages'], [
|
||||
(5,),
|
||||
(4, message.id),
|
||||
(0, 0, {}),
|
||||
(0, 0, {}),
|
||||
])
|
||||
|
||||
def test_onchange_one2many_reference(self):
|
||||
""" test the effect of onchange() on one2many fields with line references """
|
||||
BODY = "What a beautiful day!"
|
||||
@@ -245,8 +252,7 @@ class TestOnChange(common.TransactionCase):
|
||||
'lines': [
|
||||
(5,),
|
||||
(1, line1.id, {'name': partner2.name,
|
||||
'partner': (partner2.id, partner2.name),
|
||||
'tags': [(5,)]}),
|
||||
'partner': (partner2.id, partner2.name)}),
|
||||
(0, 0, {'name': partner2.name,
|
||||
'partner': (partner2.id, partner2.name),
|
||||
'tags': [(5,)]}),
|
||||
@@ -254,6 +260,17 @@ class TestOnChange(common.TransactionCase):
|
||||
})
|
||||
|
||||
# do it again, but this time with a new tag on the second line
|
||||
expected_new_tag_result = {
|
||||
'name': partner2.name,
|
||||
'lines': [
|
||||
(5,),
|
||||
(1, line1.id, {'name': partner2.name,
|
||||
'partner': (partner2.id, partner2.name)}),
|
||||
(0, 0, {'name': partner2.name,
|
||||
'partner': (partner2.id, partner2.name),
|
||||
'tags': [(5,), (0, 0, {'name': 'Tag'})]}),
|
||||
],
|
||||
}
|
||||
values = {
|
||||
'name': partner1.name,
|
||||
'partner': partner2.id, # this one just changed
|
||||
@@ -265,18 +282,13 @@ class TestOnChange(common.TransactionCase):
|
||||
self.env.cache.invalidate()
|
||||
|
||||
result = multi.onchange(values, 'partner', field_onchange)
|
||||
self.assertEqual(result['value'], {
|
||||
'name': partner2.name,
|
||||
'lines': [
|
||||
(5,),
|
||||
(1, line1.id, {'name': partner2.name,
|
||||
'partner': (partner2.id, partner2.name),
|
||||
'tags': [(5,)]}),
|
||||
(0, 0, {'name': partner2.name,
|
||||
'partner': (partner2.id, partner2.name),
|
||||
'tags': [(5,), (0, 0, {'name': 'Tag'})]}),
|
||||
],
|
||||
})
|
||||
self.assertEqual(result['value'], expected_new_tag_result)
|
||||
|
||||
# ensure ID is not returned when asked and a many2many record is set to be created
|
||||
self.env.cache.invalidate()
|
||||
|
||||
result = multi.onchange(values, 'partner', dict(field_onchange, **{'lines.tags.id': None}))
|
||||
self.assertEqual(result['value'], expected_new_tag_result)
|
||||
|
||||
def test_onchange_specific(self):
|
||||
""" test the effect of field-specific onchange method """
|
||||
@@ -308,8 +320,7 @@ class TestOnChange(common.TransactionCase):
|
||||
self.assertIn('participants', result['value'])
|
||||
self.assertItemsEqual(
|
||||
result['value']['participants'],
|
||||
[(5,)] + [(1, user.id, {'display_name': user.display_name})
|
||||
for user in discussion.participants + demo],
|
||||
[(5,)] + [(4, user.id) for user in discussion.participants + demo],
|
||||
)
|
||||
|
||||
def test_onchange_default(self):
|
||||
@@ -345,6 +356,8 @@ class TestOnChange(common.TransactionCase):
|
||||
self.assertEqual(len(discussion.messages), 3)
|
||||
messages = [(4, msg.id) for msg in discussion.messages]
|
||||
messages[0] = (1, messages[0][1], {'body': 'test onchange'})
|
||||
lines = ["%s:%s" % (m.name, m.body) for m in discussion.messages]
|
||||
lines[0] = "%s:%s" % (discussion.messages[0].name, 'test onchange')
|
||||
values = {
|
||||
'name': discussion.name,
|
||||
'moderator': demo.id,
|
||||
@@ -355,8 +368,7 @@ class TestOnChange(common.TransactionCase):
|
||||
}
|
||||
result = discussion.onchange(values, 'messages', field_onchange)
|
||||
self.assertIn('message_concat', result['value'])
|
||||
self.assertEqual(result['value']['message_concat'],
|
||||
"\n".join(["%s:%s" % (m.name, m.body) for m in discussion.messages]))
|
||||
self.assertEqual(result['value']['message_concat'], "\n".join(lines))
|
||||
|
||||
def test_onchange_one2many_with_domain_on_related_field(self):
|
||||
""" test the value of the one2many field when defined with a domain on a related field"""
|
||||
@@ -402,28 +414,15 @@ class TestOnChange(common.TransactionCase):
|
||||
'categories': [(4, cat.id) for cat in discussion.categories],
|
||||
'messages': [(4, msg.id) for msg in discussion.messages],
|
||||
'participants': [(4, usr.id) for usr in discussion.participants],
|
||||
'message_changes': 0,
|
||||
'important_messages': [(4, msg.id) for msg in discussion.important_messages],
|
||||
'important_emails': [(4, eml.id) for eml in discussion.important_emails],
|
||||
}
|
||||
self.env.cache.invalidate()
|
||||
result = discussion.onchange(values, 'name', field_onchange)
|
||||
|
||||
# When one2many domain contains non-computed field, things are ok
|
||||
self.assertEqual(result['value']['important_messages'],
|
||||
[(5,)] + [(4, msg.id) for msg in discussion.important_messages])
|
||||
|
||||
# But here with commit 5676d81, we get value of: [(2, email.id)]
|
||||
self.assertEqual(
|
||||
result['value']['important_emails'],
|
||||
[(5,),
|
||||
(1, email.id, {
|
||||
'name': u'[Foo Bar] %s' % USER.name,
|
||||
'body': email.body,
|
||||
'author': USER.name_get()[0],
|
||||
'important': True,
|
||||
'email_to': demo.email,
|
||||
'size': email.size,
|
||||
})]
|
||||
[(5,), (1, email.id, {'name': u'[Foo Bar] %s' % USER.name})],
|
||||
)
|
||||
|
||||
def test_onchange_related(self):
|
||||
|
||||
+106
-29
@@ -4982,28 +4982,114 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
if not all(name in self._fields for name in names):
|
||||
return {}
|
||||
|
||||
# filter out keys in field_onchange that do not refer to actual fields
|
||||
dotnames = []
|
||||
for dotname in field_onchange:
|
||||
try:
|
||||
model = self.browse()
|
||||
for name in dotname.split('.'):
|
||||
model = model[name]
|
||||
dotnames.append(dotname)
|
||||
except Exception:
|
||||
pass
|
||||
class PrefixTree(OrderedDict):
|
||||
""" A prefix tree for sequences of field names. The tree is a
|
||||
dictionary that associates each given field name to its
|
||||
corresponding subtree (in fields order)::
|
||||
|
||||
# tree corresponding to dotnames
|
||||
# ['name', 'line_ids.product_id', 'line_ids.tags_ids.name']
|
||||
{
|
||||
'name': {},
|
||||
'line_ids': {
|
||||
'product_id': {},
|
||||
'tags_ids': {
|
||||
'name': {},
|
||||
},
|
||||
},
|
||||
}
|
||||
"""
|
||||
def __init__(self, model, dotnames):
|
||||
super(PrefixTree, self).__init__()
|
||||
if not dotnames:
|
||||
return
|
||||
# group dotnames by prefix
|
||||
suffixes = defaultdict(list)
|
||||
for dotname in dotnames:
|
||||
names = dotname.split('.', 1)
|
||||
name_suffixes = suffixes[names[0]]
|
||||
if len(names) > 1:
|
||||
name_suffixes.append(names[1])
|
||||
# fill in self in fields order
|
||||
for name in model._fields:
|
||||
if name in suffixes:
|
||||
self[name] = PrefixTree(model[name], suffixes[name])
|
||||
|
||||
def dotnames(self):
|
||||
""" Iterate over the sequences of field names. """
|
||||
for name, subnames in self.items():
|
||||
yield name
|
||||
for dotname in subnames.dotnames():
|
||||
yield "%s.%s" % (name, dotname)
|
||||
|
||||
nametree = PrefixTree(self.browse(), field_onchange)
|
||||
dotnames = list(nametree.dotnames())
|
||||
|
||||
def snapshot(record, tree=nametree):
|
||||
""" Return a dict with the values of record, following nametree. """
|
||||
vals = {}
|
||||
for name, subnames in tree.items():
|
||||
if subnames:
|
||||
# x2many fields as {line: snapshot(line), ...}
|
||||
vals[name] = OrderedDict(
|
||||
(line, snapshot(line, subnames))
|
||||
for line in record[name]
|
||||
)
|
||||
else:
|
||||
vals[name] = record[name]
|
||||
return vals
|
||||
|
||||
def diff(record, old, new, tree=nametree):
|
||||
""" Return the values that differ between snapshots.
|
||||
The snapshot ``old`` may be empty (for new records).
|
||||
"""
|
||||
result = {}
|
||||
for name, subnames in tree.items():
|
||||
if name == 'id':
|
||||
continue
|
||||
if old and old[name] == new[name]:
|
||||
continue
|
||||
field = record._fields[name]
|
||||
if not subnames:
|
||||
result[name] = field.convert_to_onchange(new[name], record, {})
|
||||
continue
|
||||
# x2many fields: serialize value as commands
|
||||
result[name] = commands = [(5,)]
|
||||
old_val = old.get(name) or {}
|
||||
for line, vals in new[name].items():
|
||||
vals0 = (old_val.get(line) or snapshot(line, subnames)) if line.id else {}
|
||||
line_diff = diff(line, vals0, vals, subnames)
|
||||
if not line.id:
|
||||
commands.append((0, line.id.ref or 0, line_diff))
|
||||
elif line_diff:
|
||||
commands.append((1, line.id, line_diff))
|
||||
else:
|
||||
commands.append((4, line.id))
|
||||
return result
|
||||
|
||||
# prefetch x2many lines without data (for the initial snapshot)
|
||||
for name, subnames in nametree.items():
|
||||
if subnames and values.get(name):
|
||||
# retrieve all ids in commands, and read the expected fields
|
||||
line_ids = []
|
||||
for cmd in values[name]:
|
||||
if cmd[0] in (1, 4):
|
||||
line_ids.append(cmd[1])
|
||||
elif cmd[0] == 6:
|
||||
line_ids.extend(cmd[2])
|
||||
lines = self.browse()[name].browse(line_ids)
|
||||
lines.read(list(subnames), load='_classic_write')
|
||||
|
||||
# create a new record with values, and attach ``self`` to it
|
||||
with env.do_in_onchange():
|
||||
record = self.new(values)
|
||||
values = {name: record[name] for name in record._cache}
|
||||
values = {name: record[name] for name in nametree}
|
||||
# attach ``self`` with a different context (for cache consistency)
|
||||
record._origin = self.with_context(__onchange=True)
|
||||
|
||||
# load fields on secondary records, to avoid false changes
|
||||
# make a snapshot based on the initial values of record
|
||||
with env.do_in_onchange():
|
||||
for dotname in dotnames:
|
||||
record.mapped(dotname)
|
||||
before = snapshot(record)
|
||||
|
||||
# determine which field(s) should be triggered an onchange
|
||||
todo = list(names) or list(values)
|
||||
@@ -5022,7 +5108,6 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
record[name] = value
|
||||
|
||||
result = {}
|
||||
dirty = set()
|
||||
|
||||
# process names in order (or the keys of values if no name given)
|
||||
while todo:
|
||||
@@ -5048,22 +5133,14 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
|
||||
field.type in ('one2many', 'many2many') and newval._is_dirty()
|
||||
):
|
||||
todo.append(name)
|
||||
dirty.add(name)
|
||||
|
||||
# determine subfields for field.convert_to_onchange() below
|
||||
Tree = lambda: defaultdict(Tree)
|
||||
subnames = Tree()
|
||||
for dotname in dotnames:
|
||||
subtree = subnames
|
||||
for name in dotname.split('.'):
|
||||
subtree = subtree[name]
|
||||
|
||||
# collect values from dirty fields
|
||||
# make a snapshot based on the final values of record
|
||||
with env.do_in_onchange():
|
||||
result['value'] = {
|
||||
name: self._fields[name].convert_to_onchange(record[name], record, subnames[name])
|
||||
for name in dirty
|
||||
}
|
||||
after = snapshot(record)
|
||||
|
||||
# determine values that have changed by comparing snapshots
|
||||
self.invalidate_cache()
|
||||
result['value'] = diff(record, before, after)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -390,7 +390,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
||||
cr.execute("""select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)""")
|
||||
for (model, name) in cr.fetchall():
|
||||
if model in registry and not registry[model]._abstract and not registry[model]._transient:
|
||||
_logger.warning('The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,,1,0,0,0',
|
||||
_logger.warning('The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,base.group_user,1,0,0,0',
|
||||
model, model.replace('.', '_'), model.replace('.', '_'), model.replace('.', '_'))
|
||||
|
||||
# Temporary warning while we remove access rights on osv_memory objects, as they have
|
||||
|
||||
@@ -131,7 +131,7 @@ class FSWatcher(object):
|
||||
if isinstance(event, (FileCreatedEvent, FileModifiedEvent, FileMovedEvent)):
|
||||
if not event.is_directory:
|
||||
path = getattr(event, 'dest_path', event.src_path)
|
||||
if path.endswith('.py'):
|
||||
if path.endswith('.py') and not os.path.basename(path).startswith('.~'):
|
||||
try:
|
||||
source = open(path, 'rb').read() + b'\n'
|
||||
compile(source, path, 'exec')
|
||||
|
||||
@@ -80,6 +80,11 @@ def at_install(flag):
|
||||
|
||||
By default, tests are run right after installing the module, before
|
||||
starting the installation of the next module.
|
||||
|
||||
.. deprecated:: 12.0
|
||||
|
||||
``at_install`` is now a flag, you can use :func:`tagged` to
|
||||
add/remove it, although ``tagged`` only works on test classes
|
||||
"""
|
||||
def decorator(obj):
|
||||
obj.at_install = flag
|
||||
@@ -93,6 +98,11 @@ def post_install(flag):
|
||||
|
||||
By default, tests are *not* run after installation of all modules in the
|
||||
current installation set.
|
||||
|
||||
.. deprecated:: 12.0
|
||||
|
||||
``post_install`` is now a flag, you can use :func:`tagged` to
|
||||
add/remove it, although ``tagged`` only works on test classes
|
||||
"""
|
||||
def decorator(obj):
|
||||
obj.post_install = flag
|
||||
|
||||
@@ -107,8 +107,8 @@ _SAFE_OPCODES = _EXPR_OPCODES.union(set(opmap[x] for x in [
|
||||
'JUMP_FORWARD', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE', 'JUMP_ABSOLUTE',
|
||||
# New in Python 2.7 - http://bugs.python.org/issue4715 :
|
||||
'JUMP_IF_FALSE_OR_POP', 'JUMP_IF_TRUE_OR_POP', 'POP_JUMP_IF_FALSE',
|
||||
'POP_JUMP_IF_TRUE', 'SETUP_EXCEPT', 'END_FINALLY', 'RAISE_VARARGS',
|
||||
'LOAD_NAME', 'STORE_NAME', 'DELETE_NAME', 'LOAD_ATTR',
|
||||
'POP_JUMP_IF_TRUE', 'SETUP_EXCEPT', 'SETUP_FINALLY', 'END_FINALLY',
|
||||
'RAISE_VARARGS', 'LOAD_NAME', 'STORE_NAME', 'DELETE_NAME', 'LOAD_ATTR',
|
||||
'LOAD_FAST', 'STORE_FAST', 'DELETE_FAST', 'UNPACK_SEQUENCE',
|
||||
'LOAD_GLOBAL', # Only allows access to restricted globals
|
||||
] if x in opmap))
|
||||
|
||||
Reference in New Issue
Block a user