diff options
| author | Christophe Simonis <chs@odoo.com> | 2017-03-28 18:05:31 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2017-03-28 18:05:31 +0200 |
| commit | 2df5faa551112d0bde9c30a8e6f0536fb7bf21d3 (patch) | |
| tree | e0b09fe7efc2f983075ba742aed97daa5245dd39 | |
| parent | ad811b19a0b88366cfe2cd28c2cd871d27107408 (diff) | |
| parent | 2f68e9e93a11f37241c1be2835e74ff8be95db1d (diff) | |
[MERGE] forward port branch saas-14 up to 2f68e9e93a1
146 files changed, 2511 insertions, 593 deletions
diff --git a/addons/account/models/account.py b/addons/account/models/account.py index 976f6106b2f..32e90d115eb 100644 --- a/addons/account/models/account.py +++ b/addons/account/models/account.py @@ -327,6 +327,15 @@ class AccountJournal(models.Model): if 'bank_acc_number' in vals: for journal in self.filtered(lambda r: r.type == 'bank' and not r.bank_account_id): journal.set_bank_account(vals.get('bank_acc_number'), vals.get('bank_id')) + # create the relevant refund sequence + if vals.get('refund_sequence'): + for journal in self.filtered(lambda j: j.type in ('sale', 'purchase') and not j.refund_sequence_id): + journal_vals = { + 'name': journal.name, + 'company_id': journal.company_id.id, + 'code': journal.code + } + journal.refund_sequence_id = self.sudo()._create_sequence(journal_vals, refund=True).id return result @@ -342,7 +351,7 @@ class AccountJournal(models.Model): """ Create new no_gap entry sequence for every new Journal""" prefix = self._get_sequence_prefix(vals['code'], refund) seq = { - 'name': vals['name'], + 'name': refund and vals['name'] + _(': Refund') or vals['name'], 'implementation': 'no_gap', 'prefix': prefix, 'padding': 4, diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 2b3b9a83e60..0915e4c9f90 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -560,7 +560,7 @@ class AccountBankStatementLine(models.Model): domain_reconciliation = ['&', '&', ('statement_line_id', '=', False), ('account_id', 'in', reconciliation_aml_accounts), ('payment_id','<>', False)] # Black lines = unreconciled & (not linked to a payment or open balance created by statement - domain_matching = ['&', ('reconciled', '=', False), '|', ('payment_id','=',False), ('statement_id', '<>', False)] + domain_matching = [('reconciled', '=', False)] if self.partner_id.id or overlook_partner: domain_matching = expression.AND([domain_matching, [('account_id.internal_type', 'in', ['payable', 'receivable'])]]) else: diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index 4503e6ce96f..50a6102b0c8 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -312,7 +312,7 @@ class AccountInvoice(models.Model): default=lambda self: self.env.user) fiscal_position_id = fields.Many2one('account.fiscal.position', string='Fiscal Position', oldname='fiscal_position', readonly=True, states={'draft': [('readonly', False)]}) - commercial_partner_id = fields.Many2one('res.partner', string='Commercial Entity', + commercial_partner_id = fields.Many2one('res.partner', string='Commercial Entity', compute_sudo=True, related='partner_id.commercial_partner_id', store=True, readonly=True, help="The commercial entity that will be used on Journal Entries for this invoice") diff --git a/addons/account/models/account_journal_dashboard.py b/addons/account/models/account_journal_dashboard.py index 3498b71fe7f..d45f61fe50d 100644 --- a/addons/account/models/account_journal_dashboard.py +++ b/addons/account/models/account_journal_dashboard.py @@ -307,6 +307,8 @@ class account_journal(models.Model): [action] = self.env.ref('account.%s' % action_name).read() action['context'] = ctx action['domain'] = self._context.get('use_domain', []) + action['views'] = False + action['view_id'] = False return action @api.multi diff --git a/addons/account/models/company.py b/addons/account/models/company.py index 6d49b37728e..a87e906c074 100644 --- a/addons/account/models/company.py +++ b/addons/account/models/company.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from odoo import fields, models, api, _ +from odoo.exceptions import ValidationError from datetime import timedelta @@ -79,6 +80,14 @@ Best Regards,''') @api.multi def write(self, values): + #restrict the closing of FY if there are still unposted entries + if values.get('fiscalyear_lock_date'): + nb_draft_entries = self.env['account.move'].search([ + ('company_id', 'in', [c.id for c in self]), + ('state', '=', 'draft'), + ('date', '<=', values['fiscalyear_lock_date'])]) + if nb_draft_entries: + raise ValidationError(_('There are still unposted entries in the period you want to lock. You should either post or delete them.')) # Reflect the change on accounts for company in self: digits = values.get('accounts_code_digits') or company.accounts_code_digits diff --git a/addons/account/tests/test_account_move_closed_period.py b/addons/account/tests/test_account_move_closed_period.py index 120b7cbb556..f0b700247f8 100644 --- a/addons/account/tests/test_account_move_closed_period.py +++ b/addons/account/tests/test_account_move_closed_period.py @@ -10,10 +10,15 @@ class TestPeriodState(AccountingTestCase): def setUp(self): super(TestPeriodState, self).setUp() + self.user_id = self.env.user self.day_before_yesterday = datetime.now() - timedelta(2) self.yesterday = datetime.now() - timedelta(1) - self.user_id = self.env.user - self.user_id.company_id.write({'fiscalyear_lock_date': self.yesterday.strftime(DEFAULT_SERVER_DATE_FORMAT)}) + self.yesterday_str = self.yesterday.strftime(DEFAULT_SERVER_DATE_FORMAT) + #make sure there is no unposted entry + draft_entries = self.env['account.move'].search([('date', '<=', self.yesterday_str), ('state', '=', 'draft')]) + if draft_entries: + draft_entries.post() + self.user_id.company_id.write({'fiscalyear_lock_date': self.yesterday_str}) self.sale_journal_id = self.env['account.journal'].search([('type', '=', 'sale')])[0] self.account_id = self.env['account.account'].search([('internal_type', '=', 'receivable')])[0] diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml index 8fd2f020003..ab4a3c75587 100644 --- a/addons/account/views/account_view.xml +++ b/addons/account/views/account_view.xml @@ -261,7 +261,7 @@ <field name="code"/> <field name="refund_sequence" attrs="{'invisible': [('type', 'not in', ['sale', 'purchase'])]}" groups="base.group_no_one"/> <field name="sequence_id" required="0" attrs="{'readonly': 1}" groups="base.group_no_one"/> - <field name="refund_sequence_id" attrs="{'invisible': ['|',('type', 'not in', ['sale', 'purchase']), ('refund_sequence', '!=', True)], 'required': [('type', 'in', ['sale', 'purchase']), ('refund_sequence', '=', True)]}"/> + <field name="refund_sequence_id" required="0" attrs="{'readonly': 1, 'invisible': ['|',('type', 'not in', ['sale', 'purchase']), ('refund_sequence', '!=', True)]}" groups="base.group_no_one"/> </group> <group> <field name="default_debit_account_id" domain="[('deprecated', '=', False)]" /> diff --git a/addons/account/views/res_config_view.xml b/addons/account/views/res_config_view.xml index fa2074c39a8..b7ee84bbdda 100644 --- a/addons/account/views/res_config_view.xml +++ b/addons/account/views/res_config_view.xml @@ -21,7 +21,6 @@ <sheet> <field name="company_id" invisible="1"/> <field name="has_chart_of_accounts" invisible="1"/> - <span attrs="{'invisible': [('has_chart_of_accounts','!=',False)]}"> <h2>Fiscal Localization</h2> <div class="row mt16 o_settings_container"> <div class="col-xs-12 col-md-6 o_setting_box"> @@ -33,13 +32,15 @@ Taxes, fiscal positions, chart of accounts & legal statements for your country </div> <div class="content-group"> - <div class="row mt16"> - <label string="Package" class="col-md-3 o_light_label"/> - <field name="chart_template_id" widget="selection"/> - </div> - <div> - <button name="%(account.open_account_charts_modules)d" icon="fa-arrow-right" type="action" string="Install More Packages" class="btn-link" attrs="{'invisible': [('has_chart_of_accounts','!=',False)]}"/> - </div> + <span attrs="{'invisible': [('has_chart_of_accounts','!=',False)]}"> + <div class="row mt16"> + <label string="Package" class="col-md-3 o_light_label"/> + <field name="chart_template_id" widget="selection"/> + </div> + <div> + <button name="%(account.open_account_charts_modules)d" icon="fa-arrow-right" type="action" string="Install More Packages" class="btn-link" attrs="{'invisible': [('has_chart_of_accounts','!=',False)]}"/> + </div> + </span> <div class="row mt16" groups="base.group_no_one"> <label string="# of digits" class="col-md-3 o_light_label"/> <field name="code_digits"/> @@ -48,7 +49,6 @@ </div> </div> </div> - </span> <h2>Taxes</h2> <div class="row mt16 o_settings_container"> <div class="col-xs-12 col-md-6 o_setting_box" title="These taxes are set in any new product created."> diff --git a/addons/account_asset/models/account_invoice.py b/addons/account_asset/models/account_invoice.py index d6fb00358c9..4d6e3590037 100644 --- a/addons/account_asset/models/account_invoice.py +++ b/addons/account_asset/models/account_invoice.py @@ -80,8 +80,6 @@ class AccountInvoiceLine(models.Model): @api.onchange('asset_category_id') def onchange_asset_category_id(self): - if not self.asset_category_id: - self.account_id = self.get_invoice_line_account(self.invoice_id.type, self.product_id, self.invoice_id.fiscal_position_id, self.invoice_id.company_id) if self.invoice_id.type == 'out_invoice' and self.asset_category_id: self.account_id = self.asset_category_id.account_asset_id.id elif self.invoice_id.type == 'in_invoice' and self.asset_category_id: diff --git a/addons/account_check_printing/models/account_payment.py b/addons/account_check_printing/models/account_payment.py index 8ee9a40a11f..13b9e39cb22 100644 --- a/addons/account_check_printing/models/account_payment.py +++ b/addons/account_check_printing/models/account_payment.py @@ -123,7 +123,6 @@ class AccountPayment(models.Model): } else: self.filtered(lambda r: r.state == 'draft').post() - self.write({'state': 'sent'}) return self.do_print_checks() @api.multi diff --git a/addons/auth_signup/controllers/main.py b/addons/auth_signup/controllers/main.py index 804642ac8c2..0ddca4cc626 100644 --- a/addons/auth_signup/controllers/main.py +++ b/addons/auth_signup/controllers/main.py @@ -65,7 +65,9 @@ class AuthSignupHome(Home): except Exception, e: qcontext['error'] = e.message or e.name - return request.render('auth_signup.reset_password', qcontext) + response = request.render('auth_signup.reset_password', qcontext) + response.headers['X-Frame-Options'] = 'DENY' + return response def get_auth_signup_config(self): """retrieve the module config (which features are enabled) for the login page""" diff --git a/addons/barcodes/static/src/js/barcode_events.js b/addons/barcodes/static/src/js/barcode_events.js index 3c5cb289232..0adff5f8e1b 100644 --- a/addons/barcodes/static/src/js/barcode_events.js +++ b/addons/barcodes/static/src/js/barcode_events.js @@ -113,6 +113,7 @@ var BarcodeEvents = core.Class.extend(mixins.PropertiesMixin, { if (e.key === "ArrowLeft" || e.key === "ArrowRight" || e.key === "ArrowUp" || e.key === "ArrowDown" || e.key === "Escape" || e.key === "Tab" || + e.key === "Backspace" || e.key === "Delete" || /F\d\d?/.test(e.key)) { return true; } else { diff --git a/addons/barcodes/static/src/js/field_float_scannable.js b/addons/barcodes/static/src/js/field_float_scannable.js index 79022362251..801cf32b5e2 100644 --- a/addons/barcodes/static/src/js/field_float_scannable.js +++ b/addons/barcodes/static/src/js/field_float_scannable.js @@ -23,6 +23,10 @@ var FieldFloatScannable = form_widgets.FieldFloat.extend({ }, simulateKeypress: function (e) { + /* only simulate a keypress if it has been previously prevented */ + if (e.originalEvent.dispatched_by_barcode_reader !== true) { + return; + } var character = String.fromCharCode(e.which); var current_str = e.target.value; var str_before_carret = current_str.substring(0, e.target.selectionStart); diff --git a/addons/base_automation/data/base_automation_demo.xml b/addons/base_automation/data/base_automation_demo.xml index d8bedc07020..246320ecf4a 100644 --- a/addons/base_automation/data/base_automation_demo.xml +++ b/addons/base_automation/data/base_automation_demo.xml @@ -35,6 +35,19 @@ <field name="filter_domain">[('customer', '=', True)]</field> </record> + <record id="test_rule_recursive" model="base.automation"> + <field name="name">Base Automation: test recursive rule</field> + <field name="model_id" ref="base_automation.model_base_automation_lead_test"/> + <field name="trigger">on_write</field> + <field name="active" eval="True"/> + <field name="state">code</field> + <field name="code"> +record = model.browse(env.context['active_id']) +if 'partner_id' in env.context['old_values'][record.id]: + record.write({'state': 'draft'}) + </field> + </record> + <record id="test_rule_on_line" model="base.automation"> <field name="name">Base Automation: test rule on secondary model</field> <field name="model_id" ref="base_automation.model_base_automation_line_test"/> @@ -44,4 +57,18 @@ <field name="active" eval="True"/> <field name="model_id" ref="base_automation.model_base_automation_line_test"/> </record> + + <record id="test_rule_on_write_check_context" model="base.automation"> + <field name="name">Base Automation: test rule on write check context</field> + <field name="model_id" ref="base_automation.model_base_automation_lead_test"/> + <field name="trigger">on_write</field> + <field name="active" eval="True"/> + <field name="state">code</field> + <field name="code"> +record = model.browse(env.context['active_id']) +if 'user_id' in env.context['old_values'][record.id]: + record.write({'is_assigned_to_admin': (record.user_id.id == 1)}) + </field> + </record> + </odoo> diff --git a/addons/base_automation/models/base_automation.py b/addons/base_automation/models/base_automation.py index 24267f72821..af8363b92fa 100644 --- a/addons/base_automation/models/base_automation.py +++ b/addons/base_automation/models/base_automation.py @@ -156,13 +156,18 @@ class BaseAutomation(models.Model): def _process(self, records): """ Process action ``self`` on the ``records`` that have not been done yet. """ - # filter out the records on which self has already been done, then mark - # remaining records as done (to avoid recursive processing) + # filter out the records on which self has already been done action_done = self._context['__action_done'] - records -= action_done.setdefault(self, records.browse()) + records_done = action_done.get(self, records.browse()) + records -= records_done if not records: return - action_done[self] |= records + + # mark the remaining records as done (to avoid recursive processing) + action_done = dict(action_done) + action_done[self] = records_done + records + self = self.with_context(__action_done=action_done) + records = records.with_context(__action_done=action_done) # modify records values = {} diff --git a/addons/base_automation/tests/test_base_automation.py b/addons/base_automation/tests/test_base_automation.py index 9fddfad983d..2bea32ec57c 100644 --- a/addons/base_automation/tests/test_base_automation.py +++ b/addons/base_automation/tests/test_base_automation.py @@ -92,6 +92,30 @@ class base_automation_test(common.TransactionCase): self.assertTrue(lead.customer, "Customer field should updated to True") self.assertEqual(lead.user_id, self.user_demo, "Responsible should be change on write of Lead when Customer becomes True.") + def test_11_recomputed_field(self): + """ + Check that a rule is executed whenever a field is recomputed and the + context contains the target field + """ + partner = self.env.ref('base.res_partner_1') + lead = self.create_lead(state='draft', partner_id=partner.id) + self.assertFalse(lead.deadline, 'There should not be a deadline defined') + # change priority and user; this triggers deadline recomputation, and + # the server action should set the boolean field to True + lead.write({'priority': True, 'user_id': self.user_admin.id}) + self.assertTrue(lead.deadline, 'Deadline should be defined') + self.assertTrue(lead.is_assigned_to_admin, 'Lead should be assigned to admin') + + def test_12_recursive(self): + """ Check that a rule is executed recursively by a secondary change. """ + lead = self.create_lead(state='open') + self.assertEqual(lead.state, 'open') + self.assertEqual(lead.user_id, self.user_admin) + # change partner; this should trigger the rule that modifies the state + partner = self.env.ref('base.res_partner_1') + lead.write({'partner_id': partner.id}) + self.assertEqual(lead.state, 'draft') + def test_20_direct_line(self): """ Check that a rule is executed after creating a line record. diff --git a/addons/base_automation/tests/test_models.py b/addons/base_automation/tests/test_models.py index 36893e37447..fd2255dff6f 100644 --- a/addons/base_automation/tests/test_models.py +++ b/addons/base_automation/tests/test_models.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import fields, models +from dateutil import relativedelta +from odoo import fields, models, api class LeadTest(models.Model): @@ -19,6 +20,17 @@ class LeadTest(models.Model): customer = fields.Boolean(related='partner_id.customer', readonly=True, store=True) line_ids = fields.One2many('base.automation.line.test', 'lead_id') + priority = fields.Boolean() + deadline = fields.Boolean(compute='_compute_deadline', store=True) + is_assigned_to_admin = fields.Boolean(string='Assigned to admin user') + + @api.depends('priority') + def _compute_deadline(self): + for record in self: + if not record.priority: + record.deadline = False + else: + record.deadline = fields.Datetime.from_string(record.create_date) + relativedelta.relativedelta(days=3) class LineTest(models.Model): _name = "base.automation.line.test" diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py index 2c3fa12fa5e..c543f5ea830 100644 --- a/addons/calendar/models/calendar.py +++ b/addons/calendar/models/calendar.py @@ -1066,7 +1066,7 @@ class Meeting(models.Model): if [True for item in new_pile if not item]: continue - result_data.append(meeting.get_search_fields(order_fields, r_date=r_date)) + result_data.append(meeting.get_search_fields(order_fields, r_date=r_start_date)) if order_fields: uniq = lambda it: collections.OrderedDict((id(x), x) for x in it).values() diff --git a/addons/calendar/tests/test_calendar_recurrent_event_case2.py b/addons/calendar/tests/test_calendar_recurrent_event_case2.py index e05428593ae..892c0ffe2aa 100644 --- a/addons/calendar/tests/test_calendar_recurrent_event_case2.py +++ b/addons/calendar/tests/test_calendar_recurrent_event_case2.py @@ -2,6 +2,7 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.tests import common +from odoo.addons.calendar.models.calendar import calendar_id2real_id class TestRecurrentEvent(common.TransactionCase): @@ -145,3 +146,26 @@ class TestRecurrentEvent(common.TransactionCase): ('start', '>=', '2017-06-30 08:00:00'), ('name', '=', 'Review code with programmer') ]) self.assertEqual(meetings_count, 1, "Last recurrent weekly meetings are not found without stop filter !") + + def test_recurrent_meeting5(self): + # I create a recurrent event and I check if the virtual_id are correct + self.CalendarEvent.create({ + 'count': 5, + 'start': '2012-04-13 11:00:00', + 'stop': '2012-04-13 12:00:00', + 'duration': 1.0, + 'name': 'Test Meeting', + 'recurrency': True, + 'rrule_type': 'daily' + }) + # I search for the first recurrent meeting + meeting = self.CalendarEvent.with_context({'virtual_id': True}).search([ + ('start', '=', '2012-04-13 11:00:00'), ('stop', '=', '2012-04-13 12:00:00') + ]) + virutal_dates = calendar_id2real_id(meeting.id, with_date=True) + + # virtual_dates are used by the calendar view and I check if the start date for the first virtual event is correct. + self.assertEqual(virutal_dates[1], '2012-04-13 11:00:00', "The virtual event doesn't have the correct start date !") + + # virtual_dates are used by the calendar view and I check if the stop date for the first virtual event is correct. + self.assertEqual(virutal_dates[2], '2012-04-13 12:00:00', "The virtual event doesn't have the correct stop date !") diff --git a/addons/crm/data/crm_data.xml b/addons/crm/data/crm_data.xml index 1f27dcb6256..ddfb2fe40ae 100644 --- a/addons/crm/data/crm_data.xml +++ b/addons/crm/data/crm_data.xml @@ -10,7 +10,7 @@ <!--default alias for leads--> <record id="mail_alias_lead_info" model="mail.alias"> - <field name="alias_name">info</field> + <field name="alias_name"></field> <field name="alias_model_id" ref="model_crm_lead"/> <field name="alias_user_id" ref="base.user_root"/> <field name="alias_parent_model_id" ref="model_crm_team"/> diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index 50b20b94fd8..df134ff6c4b 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -1045,6 +1045,15 @@ class Lead(models.Model): return view_id @api.multi + def message_get_default_recipients(self): + return { + r.id : {'partner_ids': [], + 'email_to': r.email_from, + 'email_cc': False} + for r in self.sudo() + } + + @api.multi def message_get_suggested_recipients(self): recipients = super(Lead, self).message_get_suggested_recipients() try: diff --git a/addons/crm/models/res_config.py b/addons/crm/models/res_config.py index a786f1e2c0b..b3bed2ba043 100644 --- a/addons/crm/models/res_config.py +++ b/addons/crm/models/res_config.py @@ -11,7 +11,8 @@ class CRMSettings(models.TransientModel): help="Odoo will generate an email alias based on the sales channel name") alias_prefix = fields.Char('Default Alias Name for Leads') alias_domain = fields.Char('Alias Domain', default=lambda self: self.env["ir.config_parameter"].sudo().get_param("mail.catchall.domain")) - default_generate_lead_from_alias = fields.Boolean() + # TDE TODO: as it is not linked to ir.values anymore, it should be renamed, but not in stable + default_generate_lead_from_alias = fields.Boolean('Manual Assignation of Emails') group_use_lead = fields.Boolean(string="Leads", implied_group='crm.group_use_lead') module_crm_voip = fields.Boolean("Asterisk (VoIP)") @@ -41,6 +42,26 @@ class CRMSettings(models.TransientModel): IrValues.set_default('sale.config.settings', 'generate_sales_team_alias', self.generate_sales_team_alias) @api.model + def get_default_default_generate_lead_from_alias(self, fields): + return { + 'default_generate_lead_from_alias': self.env['ir.config_parameter'].sudo().get_param('sale_config_settings.default_generate_lead_from_alias') + } + + @api.multi + def set_default_default_generate_lead_from_alias(self): + self.env['ir.config_parameter'].sudo().set_param('sale_config_settings.default_generate_lead_from_alias', self.default_generate_lead_from_alias) + + @api.onchange('group_use_lead') + def _onchange_group_use_lead(self): + """ Reset alias / leads configuration if leads are not used """ + if not self.group_use_lead: + self.default_generate_lead_from_alias = False + + @api.onchange('default_generate_lead_from_alias') + def _onchange_default_generate_lead_from_alias(self): + self.alias_prefix = 'info' if self.default_generate_lead_from_alias else False + + @api.model def get_default_alias_prefix(self, fields): alias = self._find_default_lead_alias_id() return {'alias_prefix': alias.alias_name if alias else False} diff --git a/addons/crm/views/crm_team_views.xml b/addons/crm/views/crm_team_views.xml index 7b007b8a531..23698ecc36c 100644 --- a/addons/crm/views/crm_team_views.xml +++ b/addons/crm/views/crm_team_views.xml @@ -242,4 +242,8 @@ </field> </record> + <record id="sales_team.mail_activity_type_action_config_sales" model="ir.actions.act_window"> + <field name="domain">['|', ('res_model_id', '=', False), ('res_model_id.model', 'in', ['crm.lead', 'res.partner'])]</field> + </record> + </odoo> diff --git a/addons/crm/views/res_config_views.xml b/addons/crm/views/res_config_views.xml index 69df0c5a712..745b5e2b5ed 100644 --- a/addons/crm/views/res_config_views.xml +++ b/addons/crm/views/res_config_views.xml @@ -20,19 +20,24 @@ </div> </div> </div> - <div class="col-xs-12 col-md-6 o_setting_box" id="crm_lead" attrs="{'invisible': [('group_use_lead','=',False)]}" title="Emails received to that address generate new leads not assigned to any sales channel yet. This can be made when converting them into opportunities. Incoming emails can be automatically assigned to specific sales channels. To do so, set an email alias on the sales channel."> + <div class="col-xs-12 col-md-6 o_setting_box" id="crm_lead" + attrs="{'invisible': [('group_use_lead','=',False)]}" + title="Emails received to that address generate new leads not assigned to any sales channel yet. This can be made when converting them into opportunities. Incoming emails can be automatically assigned to specific sales channels. To do so, set an email alias on the sales channel." + groups="base.group_no_one"> <div class="o_setting_left_pane"> <field name="default_generate_lead_from_alias"/> </div> <div class="o_setting_right_pane"> - <label string="Emails"/> + <label string="Manually Assignation of Incoming Emails"/> <div class="text-muted"> - Generate leads from incoming emails + Generate unassigned leads from incoming emails. Leads coming from + that email will be assigned manually. </div> <div class="content-group" attrs="{'invisible': [('default_generate_lead_from_alias','=',False)]}"> <div class="mt16"> <label string="Alias" class="o_light_label"/> - <field name="alias_prefix" class="oe_inline"/> + <field name="alias_prefix" class="oe_inline" + attrs="{'required': [('default_generate_lead_from_alias', '=', True)]}"/> <span>@</span> <field name="alias_domain" readonly="1" class="oe_inline"/> </div> diff --git a/addons/hr_attendance/models/hr_attendance.py b/addons/hr_attendance/models/hr_attendance.py index 9ad4ef499e7..c8728ec0e31 100644 --- a/addons/hr_attendance/models/hr_attendance.py +++ b/addons/hr_attendance/models/hr_attendance.py @@ -26,15 +26,15 @@ class HrAttendance(models.Model): result = [] for attendance in self: if not attendance.check_out: - result.append((self.id, _("%(empl_name)s from %(check_in)s") % { - 'empl_name': self.employee_id.name, - 'check_in': fields.Datetime.to_string(fields.Datetime.context_timestamp(self, fields.Datetime.from_string(self.check_in))), + result.append((attendance.id, _("%(empl_name)s from %(check_in)s") % { + 'empl_name': attendance.employee_id.name, + 'check_in': fields.Datetime.to_string(fields.Datetime.context_timestamp(attendance, fields.Datetime.from_string(attendance.check_in))), })) else: - result.append((self.id, _("%(empl_name)s from %(check_in)s to %(check_out)s") % { - 'empl_name': self.employee_id.name, - 'check_in': fields.Datetime.to_string(fields.Datetime.context_timestamp(self, fields.Datetime.from_string(self.check_in))), - 'check_out': fields.Datetime.to_string(fields.Datetime.context_timestamp(self, fields.Datetime.from_string(self.check_out))), + result.append((attendance.id, _("%(empl_name)s from %(check_in)s to %(check_out)s") % { + 'empl_name': attendance.employee_id.name, + 'check_in': fields.Datetime.to_string(fields.Datetime.context_timestamp(attendance, fields.Datetime.from_string(attendance.check_in))), + 'check_out': fields.Datetime.to_string(fields.Datetime.context_timestamp(attendance, fields.Datetime.from_string(attendance.check_out))), })) return result diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py index cb36a790ecf..b6e25c34f51 100644 --- a/addons/hr_expense/models/hr_expense.py +++ b/addons/hr_expense/models/hr_expense.py @@ -172,19 +172,24 @@ class HrExpense(models.Model): ''' main function that is called when trying to create the accounting entries related to an expense ''' + move_group_by_sheet = {} for expense in self: journal = expense.sheet_id.bank_journal_id if expense.payment_mode == 'company_account' else expense.sheet_id.journal_id #create the move that will contain the accounting entries acc_date = expense.sheet_id.accounting_date or expense.date - move = self.env['account.move'].create({ - 'journal_id': journal.id, - 'company_id': self.env.user.company_id.id, - 'date': acc_date, - 'ref': expense.sheet_id.name, - # force the name to the default value, to avoid an eventual 'default_name' in the context - # to set it to '' which cause no number to be given to the account.move when posted. - 'name': '/', - }) + if not expense.sheet_id.id in move_group_by_sheet: + move = self.env['account.move'].create({ + 'journal_id': journal.id, + 'company_id': self.env.user.company_id.id, + 'date': acc_date, + 'ref': expense.sheet_id.name, + # force the name to the default value, to avoid an eventual 'default_name' in the context + # to set it to '' which cause no number to be given to the account.move when posted. + 'name': '/', + }) + move_group_by_sheet[expense.sheet_id.id] = move + else: + move = move_group_by_sheet[expense.sheet_id.id] company_currency = expense.company_id.currency_id diff_currency_p = expense.currency_id != company_currency #one account.move.line per expense (+taxes..) @@ -235,9 +240,10 @@ class HrExpense(models.Model): lines = map(lambda x: (0, 0, expense._prepare_move_line(x)), move_lines) move.with_context(dont_create_taxes=True).write({'line_ids': lines}) expense.sheet_id.write({'account_move_id': move.id}) - move.post() if expense.payment_mode == 'company_account': expense.sheet_id.paid_expense_sheets() + for move in move_group_by_sheet.values(): + move.post() return True @api.multi @@ -272,7 +278,7 @@ class HrExpense(models.Model): # Calculate tax lines and adjust base line taxes = expense.tax_ids.compute_all(expense.unit_amount, expense.currency_id, expense.quantity, expense.product_id) account_move[-1]['price'] = taxes['total_excluded'] - account_move[-1]['tax_ids'] = expense.tax_ids.ids + account_move[-1]['tax_ids'] = [(6, 0, expense.tax_ids.ids)] for tax in taxes['taxes']: account_move.append({ 'type': 'tax', @@ -511,14 +517,14 @@ class HrExpenseSheet(models.Model): if any(not sheet.journal_id for sheet in self): raise UserError(_("Expenses must have an expense journal specified to generate accounting entries.")) - res = self.mapped('expense_line_ids')\ - .filtered(lambda r: not float_is_zero(r.total_amount, precision_rounding=(r.currency_id or self.env.user.company_id.currency_id).rounding))\ - .action_move_create() + expense_line_ids = self.mapped('expense_line_ids')\ + .filtered(lambda r: not float_is_zero(r.total_amount, precision_rounding=(r.currency_id or self.env.user.company_id.currency_id).rounding)) + res = expense_line_ids.action_move_create() if not self.accounting_date: self.accounting_date = self.account_move_id.date - if self.payment_mode=='own_account': + if self.payment_mode == 'own_account' and expense_line_ids: self.write({'state': 'post'}) else: self.write({'state': 'done'}) diff --git a/addons/hr_holidays/models/hr_holidays.py b/addons/hr_holidays/models/hr_holidays.py index 1569a91a73a..61af9bd1dbb 100644 --- a/addons/hr_holidays/models/hr_holidays.py +++ b/addons/hr_holidays/models/hr_holidays.py @@ -243,6 +243,7 @@ class Holidays(models.Model): ('date_to', '>=', holiday.date_from), ('employee_id', '=', holiday.employee_id.id), ('id', '!=', holiday.id), + ('type', '=', holiday.type), ('state', 'not in', ['cancel', 'refuse']), ] nholidays = self.search_count(domain) diff --git a/addons/hr_maintenance/views/maintenance_views.xml b/addons/hr_maintenance/views/maintenance_views.xml index 58dec50bc2f..2c56a9f2538 100644 --- a/addons/hr_maintenance/views/maintenance_views.xml +++ b/addons/hr_maintenance/views/maintenance_views.xml @@ -79,6 +79,12 @@ <xpath expr="//img[@t-att-title='record.owner_user_id.value']" position='replace'> <img t-att-src="kanban_image('hr.employee', 'image_small', record.employee_id.raw_value)" t-att-title="record.employee_id.value" width="27" height="27" class="oe_kanban_avatar"/> </xpath> + <div t-if="!record.owner_user_id.raw_value" position='replace'/> + <div t-if="record.owner_user_id.raw_value" position='replace'> + <div t-if="record.employee_id.value"><field name="employee_id"/></div> + <div t-if="record.department_id.value"><field name="department_id"/> + </div> + </div> </field> </record> diff --git a/addons/hr_timesheet_attendance/report/hr_timesheet_attendance_report_view.xml b/addons/hr_timesheet_attendance/report/hr_timesheet_attendance_report_view.xml index ba48dceb8f2..a307bd47ddd 100644 --- a/addons/hr_timesheet_attendance/report/hr_timesheet_attendance_report_view.xml +++ b/addons/hr_timesheet_attendance/report/hr_timesheet_attendance_report_view.xml @@ -29,6 +29,8 @@ <field name="user_id" type="row"/> <field name="date" interval="day" type="col"/> <field name="total_difference" type="measure" widget="float_time"/> + <field name="total_timesheet" type="measure" widget="float_time"/> + <field name="total_attendance" type="measure" widget="float_time"/> </pivot> </field> </record> diff --git a/addons/hw_posbox_homepage/controllers/main.py b/addons/hw_posbox_homepage/controllers/main.py index 09ba008d430..f43e585fcba 100644 --- a/addons/hw_posbox_homepage/controllers/main.py +++ b/addons/hw_posbox_homepage/controllers/main.py @@ -56,7 +56,10 @@ index_template = """ If you need to grant remote debugging access to a developer, you can do it <a href='/remote_connect'>here</a>. </p> <p> - The PosBox software installed on this posbox is <b>version 15</b>, + If you need to display the current customer basket on another device, you can do it <a href='/point_of_sale/display'>here</a>. + </p> + <p> + The PosBox software installed on this posbox is <b>version 16</b>, the posbox version number is independent from Odoo. You can upgrade the software on the <a href='/hw_proxy/upgrade/'>upgrade page</a>. </p> diff --git a/addons/hw_screen/__init__.py b/addons/hw_screen/__init__.py new file mode 100644 index 00000000000..bf7fb7b45c1 --- /dev/null +++ b/addons/hw_screen/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import controllers diff --git a/addons/hw_screen/__openerp__.py b/addons/hw_screen/__openerp__.py new file mode 100644 index 00000000000..8ed5711b836 --- /dev/null +++ b/addons/hw_screen/__openerp__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. +{ + 'name': 'Screen Driver', + 'version': '1.0', + 'category': 'Hardware Drivers', + 'sequence': 6, + 'summary': 'Provides support for customer facing displays', + 'website': 'https://www.odoo.com/page/point-of-sale', + 'description': """ +Screen Driver +============= + +This module allows the POS client to send rendered HTML to a remotely +installed screen. This module then displays this HTML using a web +browser. +""", + 'depends': ['hw_proxy'], + 'installable': False, + 'auto_install': False, +} diff --git a/addons/hw_screen/controllers/__init__.py b/addons/hw_screen/controllers/__init__.py new file mode 100644 index 00000000000..f48716d3a69 --- /dev/null +++ b/addons/hw_screen/controllers/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import main diff --git a/addons/hw_screen/controllers/main.py b/addons/hw_screen/controllers/main.py new file mode 100644 index 00000000000..f6101e7c8ca --- /dev/null +++ b/addons/hw_screen/controllers/main.py @@ -0,0 +1,166 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import http +from odoo.tools import config +from odoo.addons.web.controllers import main as web + +import logging +import netifaces as ni +import os +from subprocess import call +import time +import threading + +self_port = str(config['xmlrpc_port'] or 8069) + +_logger = logging.getLogger(__name__) + + +class HardwareScreen(web.Home): + + event_data = threading.Event() + pos_client_data = {'rendered_html': False, + 'ip_from': False} + display_in_use = '' + failure_count = {} + + def _call_xdotools(self, keystroke): + os.environ['DISPLAY'] = ":0.0" + os.environ['XAUTHORITY'] = "/run/lightdm/pi/xauthority" + try: + call(['xdotool', 'key', keystroke]) + return "xdotool succeeded in stroking " + keystroke + except: + return "xdotool threw an error, maybe it is not installed on the posbox" + + @http.route('/hw_proxy/display_refresh', type='json', auth='none', cors='*') + def display_refresh(self): + return self._call_xdotools('F5') + + # POS CASHIER'S ROUTES + @http.route('/hw_proxy/customer_facing_display', type='json', auth='none', cors='*') + def update_user_facing_display(self, html=None): + request_ip = http.request.httprequest.remote_addr + if request_ip == HardwareScreen.pos_client_data.get('ip_from', ''): + HardwareScreen.pos_client_data['rendered_html'] = html + HardwareScreen.event_data.set() + + return {'status': 'updated'} + else: + return {'status': 'failed'} + + @http.route('/hw_proxy/take_control', type='json', auth='none', cors='*') + def take_control(self, html=None): + # ALLOW A CASHIER TO TAKE CONTROL OVER THE POSBOX, IN CASE OF MULTIPLE CASHIER PER POSBOX + HardwareScreen.pos_client_data['rendered_html'] = html + HardwareScreen.pos_client_data['ip_from'] = http.request.httprequest.remote_addr + HardwareScreen.event_data.set() + + return {'status': 'success', + 'message': 'You now have access to the display'} + + @http.route('/hw_proxy/test_ownership', type='json', auth='none', cors='*') + def test_ownership(self): + if HardwareScreen.pos_client_data.get('ip_from') == http.request.httprequest.remote_addr: + return {'status': 'OWNER'} + else: + return {'status': 'NOWNER'} + + # POSBOX ROUTES (SELF) + @http.route('/point_of_sale/display', type='http', auth='none') + def render_main_display(self): + return self._get_html() + + @http.route('/point_of_sale/get_serialized_order', type='json', auth='none') + def get_serialized_order(self): + request_addr = http.request.httprequest.remote_addr + result = HardwareScreen.pos_client_data + if HardwareScreen.display_in_use and request_addr != HardwareScreen.display_in_use: + if not HardwareScreen.failure_count.get(request_addr): + HardwareScreen.failure_count[request_addr] = 0 + if HardwareScreen.failure_count[request_addr] > 0: + time.sleep(10) + HardwareScreen.failure_count[request_addr] += 1 + return {'rendered_html': """<div class="pos-customer_facing_display"><p>Not Authorized. Another browser is in use to display for the client. Please refresh.</p></div> """, + 'stop_longpolling': True, + 'ip_from': request_addr} + + # IMPLEMENTATION OF LONGPOLLING + # Times out 2 seconds before the JS request does + if HardwareScreen.event_data.wait(28): + HardwareScreen.event_data.clear() + HardwareScreen.failure_count[request_addr] = 0 + return result + return {'rendered_html': False, + 'ip_from': HardwareScreen.pos_client_data['ip_from']} + + def _get_html(self): + cust_js = None + interfaces = ni.interfaces() + my_ip = '127.0.0.1' + HardwareScreen.display_in_use = http.request.httprequest.remote_addr + + with open(os.path.join(os.path.dirname(__file__), "../static/src/js/worker.js")) as js: + cust_js = js.read() + + with open(os.path.join(os.path.dirname(__file__), "../static/src/css/cust_css.css")) as css: + cust_css = css.read() + + display_ifaces = "" + for iface_id in interfaces: + iface_obj = ni.ifaddresses(iface_id) + ifconfigs = iface_obj.get(ni.AF_INET, []) + for conf in ifconfigs: + if conf.get('addr'): + display_ifaces += "<tr><td>" + iface_id + "</td>" + display_ifaces += "<td>" + conf.get('addr') + "</td>" + display_ifaces += "<td>" + conf.get('netmask') + "</td></tr>" + # What is my external IP ? + if iface_id != 'lo': + my_ip = conf.get('addr') + + my_ip_port = my_ip + ":" + self_port + + html = """ + <!DOCTYPE html> + <html> + <head> + <title class="origin">Odoo -- Point of Sale</title> + <script type="text/javascript" class="origin" src="http://""" + my_ip_port + """/web/static/lib/jquery/jquery.js" > + </script> + <script type="text/javascript" class="origin"> + """ + cust_js + """ + </script> + <link rel="stylesheet" class="origin" href="http://""" + my_ip_port + """/web/static/lib/bootstrap/css/bootstrap.css" > + </link> + <script class="origin" src="http://""" + my_ip_port + """/web/static/lib/bootstrap/js/bootstrap.min.js"></script> + <style class="origin"> + """ + cust_css + """ + </style> + </head> + <body class="original_body"> + <div hidden class="shadow"></div> + <div class="container"> + <div class="row"> + <div class="col-md-4 col-md-offset-4"> + <h1>Odoo Point of Sale</h1> + <h2>POSBox Client display</h2> + <h3>My IPs</h3> + <table id="table_ip" class="table table-condensed"> + <tr> + <th>Interface</th> + <th>IP</th> + <th>Netmask</th> + </tr> + """ + display_ifaces + """ + </table> + <p>The customer cart will be displayed here once a Point of Sale session is started.</p> + <p>Odoo version 11 or above is required.</p> + </div> + </div> + </div> + </body> + </html> + """ + return html diff --git a/addons/hw_screen/static/src/css/cust_css.css b/addons/hw_screen/static/src/css/cust_css.css new file mode 100644 index 00000000000..69fddb25457 --- /dev/null +++ b/addons/hw_screen/static/src/css/cust_css.css @@ -0,0 +1,21 @@ +html { + width: 100%; + height: 100%; + font-size: 11px; +} + +body { + width: 100%; + height: 100%; + font-size: 14px; + margin: 0; +} + +.original_body { + background-color: #797083; + color: white; +} + +.ajax_got_body { + color: black; +}
\ No newline at end of file diff --git a/addons/hw_screen/static/src/js/worker.js b/addons/hw_screen/static/src/js/worker.js new file mode 100644 index 00000000000..55e389e78ab --- /dev/null +++ b/addons/hw_screen/static/src/js/worker.js @@ -0,0 +1,60 @@ + $(function() { + "use strict"; + // mergedHead will be turned to true the first time we receive something from a new host + // It allows to transform the <head> only once + var mergedHead = false; + var current_client_url = ""; + var stop_longpolling = false; + + function longpolling() { + $.ajax({ + type: 'POST', + url: 'http://'+window.location.host+'/point_of_sale/get_serialized_order', + dataType: 'json', + beforeSend: function(xhr){xhr.setRequestHeader('Content-Type', 'application/json');}, + data: JSON.stringify({jsonrpc: '2.0'}), + + success: function(data) { + if (typeof data.result.stop_longpolling !== 'undefined') { + stop_longpolling = data.result.stop_longpolling; + } + if (data.result.ip_from && data.result.rendered_html) { + var trimmed = $.trim(data.result.rendered_html); + var $parsedHTML = $('<div>').html($.parseHTML(trimmed,true)); // WARNING: the true here will executes any script present in the string to parse + var new_client_url = $parsedHTML.find(".resources > base").attr('href'); + + if (!mergedHead || (current_client_url !== new_client_url)) { + + mergedHead = true; + current_client_url = new_client_url; + $("body").removeClass('original_body').addClass('ajax_got_body'); + $("head").children().not('.origin').remove(); + $("head").append($parsedHTML.find(".resources").html()); + } + + $(".container").html($parsedHTML.find('.pos-customer_facing_display').html()); + $(".container").attr('class', 'container').addClass($parsedHTML.find('.pos-customer_facing_display').attr('class')); + + var d = $('.pos_orderlines_list'); + d.scrollTop(d.prop("scrollHeight")); + + // Here we execute the code coming from the pos, apparently $.parseHTML() executes scripts right away, + // Since we modify the dom afterwards, the script might not have any effect + if (typeof foreign_js !== 'undefined' && $.isFunction(foreign_js)) { + foreign_js(); + } + } + }, + + complete: function(jqXHR,err) { + if (!stop_longpolling) { + longpolling(); + } + }, + + timeout: 30000, + }); + }; + + longpolling(); + });
\ No newline at end of file diff --git a/addons/l10n_be/data/account_tax_template_data.xml b/addons/l10n_be/data/account_tax_template_data.xml index 587ffea2a38..05a5a0cb31a 100644 --- a/addons/l10n_be/data/account_tax_template_data.xml +++ b/addons/l10n_be/data/account_tax_template_data.xml @@ -278,7 +278,7 @@ <field name="price_include" eval="0"/> <field name="amount">0</field> <field name="amount_type">percent</field> - <field name="type_tax_use">none</field> + <field name="type_tax_use">sale</field> <field name="chart_template_id" ref="l10nbe_chart_template"/> <field name="tag_ids" eval="[(6,0,[ref('tax_tag_46L'), ref('tax_tag_48s46L')])]"/> </record> @@ -291,7 +291,7 @@ <field name="account_id" ref="a451054"/> <field name="amount">0</field> <field name="amount_type">percent</field> - <field name="type_tax_use">none</field> + <field name="type_tax_use">sale</field> <field name="chart_template_id" ref="l10nbe_chart_template"/> <field name="tag_ids" eval="[(6,0,[ref('tax_tag_46T'), ref('tax_tag_48s46T')])]"/> </record> @@ -369,7 +369,7 @@ <field name="price_include" eval="1"/> <field name="amount">21</field> <field name="amount_type">percent</field> - <field name="type_tax_use">none</field> + <field name="type_tax_use">purchase</field> <field name="chart_template_id" ref="l10nbe_chart_template"/> <field name="tag_ids" eval="[(6,0,[ref('tax_tag_82'), ref('tax_tag_85'), ref('tax_tag_63'), ref('tax_tag_59')])]"/> </record> diff --git a/addons/l10n_ch/i18n_extra/de_CH.po b/addons/l10n_ch/i18n_extra/de_CH.po index 57696de267f..23e7511b472 100644 --- a/addons/l10n_ch/i18n_extra/de_CH.po +++ b/addons/l10n_ch/i18n_extra/de_CH.po @@ -8,7 +8,7 @@ msgstr "" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-03-14 15:52+0000\n" "PO-Revision-Date: 2016-12-15 14:35+0100\n" -"Last-Translator: <>\n" +"Last-Translator: <didier.donze@camptocamp.com>\n" "Language-Team: \n" "Language: de\n" "MIME-Version: 1.0\n" @@ -74,7 +74,7 @@ msgstr "2.5% Invest." #: model:account.tax,description:l10n_ch.1_vat_25_invest_incl #: model:account.tax.template,description:l10n_ch.vat_25_invest_incl msgid "2.5% invest. Incl." -msgstr "2.5% Invest. Incl." +msgstr "2.5% Invest. Inkl." #. module: l10n_ch #: model:account.tax,description:l10n_ch.1_vat_38 @@ -104,13 +104,13 @@ msgstr "3.8% Einkauf Inkl." #: model:account.tax,description:l10n_ch.1_vat_38_invest #: model:account.tax.template,description:l10n_ch.vat_38_invest msgid "3.8% invest" -msgstr "3.8% Invest" +msgstr "3.8% Invest." #. module: l10n_ch #: model:account.tax,description:l10n_ch.1_vat_38_invest_incl #: model:account.tax.template,description:l10n_ch.vat_38_invest_incl msgid "3.8% invest Incl." -msgstr "3.8% Invest Incl." +msgstr "3.8% Invest. Inkl." #. module: l10n_ch #: model:account.tax,description:l10n_ch.1_vat_80 @@ -164,13 +164,13 @@ msgstr "Erhaltene Anzahlungen" #: model:account.account,name:l10n_ch.1_ch_coa_1208 #: model:account.account.template,name:l10n_ch.ch_coa_1208 msgid "Acomptes sur les marchandises commerciales" -msgstr "" +msgstr "Akonto auf Zwischenhandelswaren" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1218 #: model:account.account.template,name:l10n_ch.ch_coa_1218 msgid "Acomptes sur matières premières" -msgstr "" +msgstr "Akonto auf Rohstoffe" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1149 @@ -229,7 +229,7 @@ msgstr "Abschreibungen auf Mobiliar und Einrichtungen" #: model:account.account,name:l10n_ch.1_ch_coa_1599 #: model:account.account.template,name:l10n_ch.ch_coa_1599 msgid "Amortissements sur les autres immobilisations corporelles meubles" -msgstr "" +msgstr "Abschreibungen andere Sachanlagen" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1709 @@ -247,7 +247,7 @@ msgstr "Abschreibungen auf Geschäftsliegenschaften" #: model:account.account,name:l10n_ch.1_ch_coa_1559 #: model:account.account.template,name:l10n_ch.ch_coa_1559 msgid "Amortissements sur les installations de stockage" -msgstr "" +msgstr "Abschreibungen und Wertberichtigungen Lagereinrichtungen" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1529 @@ -278,7 +278,7 @@ msgstr "Abschreibungen auf Fahrzeuge" #: model:account.account,name:l10n_ch.1_ch_coa_1579 #: model:account.account.template,name:l10n_ch.ch_coa_1579 msgid "Amortissements sur les Ă©quipements et installations" -msgstr "" +msgstr "Abschreibungen und Wertberichtigungen feste Einrichtungen und Installationen" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_2270 @@ -349,12 +349,12 @@ msgstr "VorschĂĽsse und Darlehen" #. module: l10n_ch #: model:ir.model,name:l10n_ch.model_res_bank msgid "Bank" -msgstr "" +msgstr "Bank" #. module: l10n_ch #: model:ir.model,name:l10n_ch.model_res_partner_bank msgid "Bank Accounts" -msgstr "" +msgstr "Bankkonten" #. module: l10n_ch #: model:ir.model.fields,help:l10n_ch.field_account_config_settings_l10n_ch_isr_print_bank_location @@ -398,7 +398,7 @@ msgstr "Gewinnvortrag oder Verlustvortrag" #. module: l10n_ch #: model:ir.model.fields,field_description:l10n_ch.field_res_bank_l10n_ch_postal_chf msgid "CHF ISR reference" -msgstr "" +msgstr "CHF ESR Referenznummer" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1850 @@ -418,7 +418,7 @@ msgstr "Aktien-, Stamm-, Anteilschein- oder Stiftungskapital" #: model:account.account,name:l10n_ch.1_ch_coa_4521 #: model:account.account.template,name:l10n_ch.ch_coa_4521 msgid "Charbon, briquettes, bois" -msgstr "" +msgstr "Kohle, Briketts, Holz" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_7010 @@ -514,30 +514,30 @@ msgstr "Noch nicht bezahlter Aufwand" #: model:account.account,name:l10n_ch.1_ch_coa_3803 #: model:account.account.template,name:l10n_ch.ch_coa_3803 msgid "Commissions de tiers" -msgstr "" +msgstr "Provisionen an Dritte" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_4903 #: model:account.account.template,name:l10n_ch.ch_coa_4903 msgid "Commissions obtenues sur achats" -msgstr "" +msgstr "Einkaufsprovisionen" #. module: l10n_ch #: model:ir.model,name:l10n_ch.model_res_company msgid "Companies" -msgstr "" +msgstr "Unternehmen" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1099 #: model:account.account.template,name:l10n_ch.ch_coa_1099 msgid "Compte d'attente autre" -msgstr "" +msgstr "Unklare Beträge" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1091 #: model:account.account.template,name:l10n_ch.ch_coa_1091 msgid "Compte d'attente pour salaires" -msgstr "" +msgstr "Lohndurchlaufkonto" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_3710 @@ -549,31 +549,31 @@ msgstr "Eigenverbrauch" #: model:account.account,name:l10n_ch.1_ch_coa_1269 #: model:account.account.template,name:l10n_ch.ch_coa_1269 msgid "Correction de la valeur de stocks de produits finis" -msgstr "" +msgstr "Wertberichtigungen fertige Erzeugnisse" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1279 #: model:account.account.template,name:l10n_ch.ch_coa_1279 msgid "Corrections de la valeur des stock produits semi-ouvrĂ©s" -msgstr "" +msgstr "Wertberichtigungen unfertige Erzeugnisse" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1209 #: model:account.account.template,name:l10n_ch.ch_coa_1209 msgid "Corrections de la valeur des stocks de marchandises" -msgstr "" +msgstr "Wertberichtigungen Handelswaren" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1289 #: model:account.account.template,name:l10n_ch.ch_coa_1289 msgid "Corrections de la valeur des travaux en cours" -msgstr "" +msgstr "Wertberichtigungen nicht fakturierte Dienstleistungen" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1219 #: model:account.account.template,name:l10n_ch.ch_coa_1219 msgid "Corrections de la valeur sur matières premières" -msgstr "" +msgstr "Wertberichtigungen Rohstoffe" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_1180 @@ -590,7 +590,7 @@ msgstr "Verbindlichkeiten aus Lieferungen und Leistungen (Kreditoren)" #. module: l10n_ch #: model:ir.model.fields,field_description:l10n_ch.field_account_invoice_l10n_ch_currency_name msgid "Currency" -msgstr "" +msgstr "Währung" #. module: l10n_ch #: model:account.account,name:l10n_ch.1_ch_coa_2100 diff --git a/addons/l10n_do/__init__.py b/addons/l10n_do/__init__.py index 67dee8c60db..dc5e6b693d1 100644 --- a/addons/l10n_do/__init__.py +++ b/addons/l10n_do/__init__.py @@ -1,2 +1,4 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import models diff --git a/addons/l10n_do/__manifest__.py b/addons/l10n_do/__manifest__.py index ba049cf6f99..cf4af681219 100644 --- a/addons/l10n_do/__manifest__.py +++ b/addons/l10n_do/__manifest__.py @@ -1,37 +1,103 @@ # -*- coding: utf-8 -*- -# Part of Odoo. See LICENSE file for full copyright and licensing details. -# First author: Jose Ernesto Mendez <tecnologia@obsdr.com> (Open Business Solutions SRL.) -# Copyright (c) 2012 -TODAY Open Business Solutions, SRL. (http://obsdr.com). All rights reserved. -# This is a fork to upgrade to odoo 8.0 -# by Marcos Organizador de Negocios - Eneldo Serrata - www.marcos.org.do +# Author: Gustavo Valverde <gvalverde@iterativo.do> iterativo | Consultores +# Contributors: Edser Solis - iterativo + +# Odoo 8.0 author: Eneldo Serrata <eneldo@marcos.do> +# (Marcos Organizador de Negocios SRL..) +# Odoo 7.0 author: Jose Ernesto Mendez <tecnologia@obsdr.com> +# (Open Business Solutions SRL.) + +# Copyright (c) 2016 - Present | iterativo, SRL. - http://iterativo.do +# All rights reserved. { 'name': 'Dominican Republic - Accounting', - 'version': '1.0', + 'version': '2.0', 'category': 'Localization', 'description': """ -This is the base module to manage the accounting chart for Dominican Republic. -============================================================================== - -* Chart of Accounts. -* The Tax Code Chart for Domincan Republic -* The main taxes used in Domincan Republic -* Fiscal position for local """, - 'author': 'Eneldo Serrata - Marcos Organizador de Negocios, SRL.', - 'website': 'http://marcos.do', - 'depends': ['account', 'base_iban'], + +Localization Module for Dominican Republic +=========================================== + +Catálogo de Cuentas e Impuestos para RepĂşblica Dominicana, Compatible para +**InternacionalizaciĂłn** con **NIIF** y alineado a las normas y regulaciones +de la DirecciĂłn General de Impuestos Internos (**DGII**). + +**Este mĂłdulo consiste de:** + +- Catálogo de Cuentas Estándar (alineado a DGII y NIIF) +- Catálogo de Impuestos con la mayorĂa de Impuestos Preconfigurados + - ITBIS para compras y ventas + - Retenciones de ITBIS + - Retenciones de ISR + - Grupos de Impuestos y Retenciones: + - Telecomunicaiones + - Proveedores de Materiales de ConstrucciĂłn + - Personas FĂsicas Proveedoras de Servicios + - Otros impuestos +- Secuencias Preconfiguradas para manejo de todos los NCF + - Facturas con Valor Fiscal (para Ventas) + - Facturas para Consumidores Finales + - Notas de DĂ©bito y CrĂ©dito + - Registro de Proveedores Informales + - Registro de Ingreso Ăšnico + - Registro de Gastos Menores + - Gubernamentales +- Posiciones Fiscales para automatizaciĂłn de impuestos y retenciones + - Cambios de Impuestos a Exenciones (Ej. Ventas al Estado) + - Cambios de Impuestos a Retenciones (Ej. Compra Servicios al Exterior) + - Entre otros + +**Nota:** +Esta localizaciĂłn, aunque posee las secuencias para NCF, las mismas no pueden +ser utilizadas sin la instalaciĂłn de mĂłdulos de terceros o desarrollo +adicional. + +Estructura de CodificaciĂłn del Catálogo de Cuentas: +=================================================== + +**Un dĂgito** representa la categorĂa/tipo de cuenta del del estado financiero. +**1** - Activo **4** - Cuentas de Ingresos y Ganancias +**2** - Pasivo **5** - Costos, Gastos y PĂ©rdidas +**3** - Capital **6** - Cuentas Liquidadoras de Resultados + +**Dos dĂgitos** representan los rubros de agrupaciĂłn: +11- Activo Corriente +21- Pasivo Corriente +31- Capital Contable + +**Cuatro dĂgitos** se asignan a las cuentas de mayor: cuentas de primer orden +1101- Efectivo y Equivalentes de Efectivo +2101- Cuentas y Documentos por pagar +3101- Capital Social + +**Seis dĂgitos** se asignan a las sub-cuentas: cuentas de segundo orden +110101 - Caja +210101 - Proveedores locales + +**Ocho dĂgitos** son para las cuentas de tercer orden (las visualizadas +en Odoo): +1101- Efectivo y Equivalentes +110101- Caja +11010101 Caja General + """, + 'author': 'Gustavo Valverde - iterativo | Consultores de Odoo', + 'website': 'http://iterativo.do', + 'depends': ['account', + 'base_iban' + ], 'data': [ - # basic accounting data + # Basic accounting data 'data/l10n_do_chart_data.xml', 'data/account.account.template.csv', 'data/account_chart_template_data.xml', 'data/account_account_tag_data.xml', - 'data/account.tax.template.csv', + 'data/account.tax.template.xml', + # Country States 'data/l10n_do_state_data.xml', # Adds fiscal position - 'data/account.fiscal.position.template.csv', - 'data/account.fiscal.position.tax.template.csv', + 'data/fiscal_position_template.xml', # configuration wizard, views, reports... 'data/account_chart_template_data.yml', ], diff --git a/addons/l10n_do/data/account.account.template.csv b/addons/l10n_do/data/account.account.template.csv index ed6b2ba91a8..2879acc2e86 100644 --- a/addons/l10n_do/data/account.account.template.csv +++ b/addons/l10n_do/data/account.account.template.csv @@ -1,198 +1,254 @@ id,code,name,user_type_id/id,reconcile,chart_template_id/id -default_chart_a_account_528,61121,"Agua, Luz y Basura",account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_529,61122,Telecomunicaciones,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_721,61123,Otros Gastos Administrativos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_531,61131,DepreciaciĂłn Edificio,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_532,61132,DepreciaciĂłn Mobiliario y Equipos de Oficina,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_533,61133,DepreciaciĂłn Equipos de CĂłmputos y Telecomunicaciones,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_534,61134,DepreciaciĂłn Equipos de Transporte,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_535,61135,DepreciaciĂłn Maquinarias y Equipos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_536,61136,DepreciaciĂłn Otros Activos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_537,61137,AmortizaciĂłn Mejoras en Propiedad Arrendada,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_538,61138,AmortizaciĂłn Gastos de OrganizaciĂłn y ConstituciĂłn,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_539,61139,AmortizaciĂłn Patentes y Derechos de ExplotaciĂłn,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_542,61141,Alquiler de Locales ,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_543,61142,Alquiler de Equipos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_544,61143,Alquiler de VehĂculos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_545,61144,Alquileres Generales,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_722,61160,Otras Deducciones Admitidas,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_586,61161,Impuesto de FiscalizaciĂłn,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_587,61162,Retenciones de Impuesto sobre la Rentas Asumidas,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_588,61163,"Penalidades, Mora e InterĂ©s Indemnizatorios",account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_589,61164,Gastos Sin Comprobantes No Admitidos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_590,61165,Gastos de Años Anteriores No Admitidos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_591,61166,Otros Gastos No Deducible ISR,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_592,61167,Otros Gastos Generales y Administrativos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_594,61171,Cargos Bancarios,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_595,61172,Cargos Carnet,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_596,61173,PĂ©rdida en Ajuste por Tipo de Cambio,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_597,61174,Intereses sobre Prestamos Bancarios,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_598,61175,Intereses sobre Prestamos Particulares,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_600,61181,Impuestos sobre la Renta Corrientes,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_601,61182,Impuestos sobre Activos Corrientes,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_602,61183,Impuestos Sobre la Renta Diferidos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_603,61184,CrĂ©dito Fiscal por RetenciĂłn de Dividendos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_604,61185,Impuestos de años anteriores,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_605,61186,Impuestos sobre Activos de años anteriores,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_152,112050,Efectivo en transito,account.data_account_type_current_assets,true,l10n_do.default_chart_a -default_chart_a_account_13,113010,Cuentas por Cobrar Clientes,account.data_account_type_receivable,true,l10n_do.default_chart_a -default_chart_a_account_14,113020,Cuentas por Cobrar Funcionarios y Empleados,account.data_account_type_receivable,true,l10n_do.default_chart_a -default_chart_a_account_15,113030,Otras Cuentas por Cobrar,account.data_account_type_receivable,true,l10n_do.default_chart_a -default_chart_a_account_707,113040,Pendientes de conciliar,account.data_account_type_current_assets,true,l10n_do.default_chart_a -default_chart_a_account_709,113050,Operaciones bancarias en transito,account.data_account_type_current_assets,true,l10n_do.default_chart_a -default_chart_a_account_716,113060,Gastos Pagados Por Adelantado,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_17,114010,Mercancias,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_18,114020,Materia Prima,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_19,114030,Productos en procesos,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_20,114040,Productos terminados,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_22,115010,Seguros,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_23,115020,Placas y Patentes,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_24,115030,I.S.R.,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_25,115040,Intereses cobrados por adelantados,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_26,115050,Otros,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_182,123100,Mobiliario y Equipos de Oficina,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_183,123200,Deprec. Acumulada Mobiliario y Equipos de Oficina,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_184,124100,Equipos de CĂłmputos y Telecomunicaciones,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_185,124200,Deprec. Acumulada Equipos de CĂłmputos y Telecomunicaciones,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_187,125100,Equipos de Transporte Livianos,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_188,125200,Deprec. Acumulada Equipos de Transporte Livianos,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_190,125300,Equipos de Transporte Pesados,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_191,125400,Deprec. Acumulada Equipos de Transporte Pesados,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_194,127100,Otros Activos Depreciables,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_195,127200,Deprec. Acumulada Otros Activos Depreciables,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_197,128100,Mejoras en Propiedad Arrendada,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_198,128200,AmortizaciĂłn Mejoras en Propiedad Arrendada,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_200,129100,Terreno en Proceso de CapitalizaciĂłn,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_201,129200,Edificio en Proceso de CapitalizaciĂłn,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_203,129400,Equipos de CĂłmputos y Telecom. en Proceso de InstalaciĂłn,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_204,129500,Equipos de Transporte en Proceso de LiquidaciĂłn,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_205,129700,Otros Activos Depreciables en Proceso de InstalaciĂłn,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_38,131000,Mejoras Propiedad Arrendadas,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_39,132000,Gastos de Organizacion,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_40,133000,Gastos Legales,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_42,141000,Acciones,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_43,142000,bonos,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_44,143000,Bienes Muebles e Inmuebles,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_46,151000,Fianzas,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_47,152000,Depositos,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_48,153000,Codetel,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_49,154000,CDEEE,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_50,155000,CAASD,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_51,156000,Telecable Nacional,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_719,157000,Obras de Arte,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_53,161000,ITBIS Pagado en compras,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_54,162000,Anticipos ISR,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_55,163000,ITBIS retenido cobros con tarjetas,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_56,164000,ITBIS Pagado en importaciones,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_57,165000,ITBIS por servicios deducibles,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_70,201050,Retencion Empleados SFS,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_61,211010,Suplidores,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_62,211020,Proveedores,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_63,211030,Instituciones Estatales,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_64,211040,Prestamos por Pagar,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_713,211050,Cheques popular en transito,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_714,211060,Caja Chica por pagar,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_715,211070,Sueldo y Salarios por Pagar,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_717,211080,Otras Cuentas Por Pagar,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_718,211090,Cobros anticipados,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_66,212010,RetenciĂłn Empleados SVDS,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_67,212020,I.S.R.,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_723,212021,I.S.R. RETENCIONES DE ASALARIADOS,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_68,212030,Infotep,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_69,212040,TSS,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_71,212060,ITBIS,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_163,212061,ITBIS 18% retenido a personas fisicas,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_712,212062,ISR 10% retenido a personas fisicas,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_72,212070,Otras Retenciones,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_720,212080,Otros Impuestos Por Pagar,account.data_account_type_payable,true,l10n_do.default_chart_a -default_chart_a_account_75,311000,Capital Autorizado,account.data_account_type_equity,false,l10n_do.default_chart_a -default_chart_a_account_76,312000,Acciones no emitidas,account.data_account_type_equity,false,l10n_do.default_chart_a -default_chart_a_account_77,313000,Capital Social,account.data_account_type_equity,false,l10n_do.default_chart_a -default_chart_a_account_79,321000,Reserva Legal,account.data_account_type_equity,false,l10n_do.default_chart_a -default_chart_a_account_80,322000,Reservas para Contingencias,account.data_account_type_equity,false,l10n_do.default_chart_a -default_chart_a_account_82,331000,Ganancias retenidas años anteriores,account.data_account_type_equity,false,l10n_do.default_chart_a -default_chart_a_account_83,332000,Ajustes años anteriores,account.data_account_type_equity,false,l10n_do.default_chart_a -default_chart_a_account_84,333000,Ganancia del periodo,account.data_account_type_equity,false,l10n_do.default_chart_a -default_chart_a_account_87,411000,Ventas,account.data_account_type_revenue,false,l10n_do.default_chart_a -default_chart_a_account_89,421000,Ingresos por Servicios,account.data_account_type_revenue,false,l10n_do.default_chart_a -default_chart_a_account_90,422000,Intereses Cobrados,account.data_account_type_revenue,false,l10n_do.default_chart_a -default_chart_a_account_91,423000,Donaciones,account.data_account_type_revenue,false,l10n_do.default_chart_a -default_chart_a_account_92,424000,Ingresos en Ventas de Activos Fijos,account.data_account_type_revenue,false,l10n_do.default_chart_a -default_chart_a_account_93,430000,Devoluciones en Ventas,account.data_account_type_revenue,false,l10n_do.default_chart_a -default_chart_a_account_94,440000,Descuentos en Ventas,account.data_account_type_revenue,false,l10n_do.default_chart_a -default_chart_a_account_148,450000,Ingresos por diferencia de cambio,account.data_account_type_revenue,false,l10n_do.default_chart_a -default_chart_a_account_724,460000,Otros Ingresos,account.data_account_type_revenue,false,l10n_do.default_chart_a -default_chart_a_account_97,511000,Materiales Directos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_98,512000,Mano de Obra Directa,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_99,513000,Costos Indirectos de Fabricacion,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_101,521000,Compras de mercancias,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_162,522000,Compras de mercancĂas en US,account.data_account_type_expenses,true,l10n_do.default_chart_a -default_chart_a_account_102,523000,Devoluciones en compras,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_103,524000,Descuentos en Compras,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_104,525000,Transporte en Compras,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_150,526000,Costo en ventas,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_507,611110,Salarios,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_516,611111,Infotep,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_517,611112,Aporte Plan Básico de Salud (SFS),account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_518,611113,Aporte Plan de Pensiones (AFP),account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_519,611114,Aporte Riesgos Laborales (ARL) ,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_520,611115,Seguro Medico y de Vida Privado,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_521,611116,Uniforme,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_522,611117,Dietas y Viáticos a Empleados,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_523,611118,Actividades Sociales Empleados,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_525,611120,Impuesto de Retribuciones Complementarias,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_508,611121,Comisiones Funcionarios y Empleados,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_526,611122,Otros Beneficios Empleados,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_509,611123,Incentivos y Horas Extras,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_510,611124,BonificaciĂłn,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_511,611125,Salario de Navidad,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_512,611126,Vacaciones,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_513,611127,Preaviso y CesantĂa,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_514,611128,CompensaciĂłn uso de vehĂculos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_515,611129,Entrenamiento y CapacitaciĂłn,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_524,611130,Gasto de Retribuciones Complementarias,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_547,611501,Honorarios por Servicios Profesionales Sociedades,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_548,611502,Honorarios por Servicios Profesionales Personas FĂsicas,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_549,611503,Comisiones por Venta a Terceros Personas FĂsicas,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_550,611504,Transporte y Acarreo,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_551,611505,Combustible y Lubricantes VehĂculos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_552,611506,Combustible Planta ElĂ©ctrica,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_553,611507,EstadĂa Hoteles,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_554,611508,Gastos por Cuentas Malas,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_555,611509,Reparaciones de Edificio,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_556,611510,Reparaciones de Activos Fijos CategorĂa 2 y 3,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_557,611511,Mantenimiento de Activos Fijos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_558,611512,Promociones,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_559,611513,Publicidad,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_560,611514,Viáticos y RepresentaciĂłn,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_561,611515,Patrocinio y aportes,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_562,611516,ParticipaciĂłn en concursos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_563,611517,Material Gastable y PapelerĂa,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_564,611518,Material de Limpieza,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_565,611519,Atenciones a Clientes,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_566,611520,Gastos de Correo y EnvĂos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_567,611521,Gastos Legales,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_568,611522,Seguridad ElectrĂłnica,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_569,611523,Guardianes y Vigilancia,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_570,611524,FumigaciĂłn y Control de Plagas,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_571,611525,Suscripciones y MembresĂas,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_572,611526,Donaciones,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_573,611527,Gastos de RepresentaciĂłn,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_574,611528,PĂ©rdida por Obsolescencia de Inventarios,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_575,611529,PĂ©rdida en Venta de Inversiones,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_576,611530,PĂ©rdida en Venta de Activos Fijos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_577,611531,PĂ©rdida en Venta de Terreno,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_578,611532,PĂ©rdida en Venta de Edificio,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_579,611533,PĂ©rdida en Venta de Mobiliario y Equipos de Oficina,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_580,611534,PĂ©rdida en Venta de Maquinarias y Equipos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_581,611535,PĂ©rdida en Venta de Otros Activos Fijos,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_582,611536,PĂ©rdida en ParticipaciĂłn Patrimonial en Subsidiarias,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_583,611537,PĂ©rdida en IndemnizaciĂłn de Seguros,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_584,611538,Consulta de Datos e FormaciĂłn Crediticia,account.data_account_type_expenses,false,l10n_do.default_chart_a -default_chart_a_account_143,711000,"Beneficio en retiro de Propiedad, Planta y Equipos",account.data_account_type_current_assets,true,l10n_do.default_chart_a -default_chart_a_account_144,712000,"Perdida en retiro de Propiedad, Planta y Equipos",account.data_account_type_current_assets,true,l10n_do.default_chart_a -default_chart_a_account_145,720000,Resumen de Ganancias y Perdidas,account.data_account_type_current_assets,true,l10n_do.default_chart_a -default_chart_a_account_173,11103002,Cheques en caja,account.data_account_type_current_assets,true,l10n_do.default_chart_a -default_chart_a_account_174,11103003,Diferencia en caja,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_175,11103004,Sobrante en caja,account.data_account_type_current_assets,false,l10n_do.default_chart_a -default_chart_a_account_176,11103005,Caja en transito,account.data_account_type_current_assets,true,l10n_do.default_chart_a +do_niif_11010301,11010301,Depósitos a Corto Plazo,account.data_account_type_liquidity,FALSE,do_chart_template +do_niif_11020100,11020100,Bonos y Acciones Temporales,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11020200,11020200,Operaciones en Bolsa,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11020300,11020300,Otros Valores Negociables,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11030101,11030101,Cheques Devueltos por Cobrar,account.data_account_type_receivable,TRUE,do_chart_template +do_niif_11030102,11030102,Intereses por Cobrar,account.data_account_type_receivable,TRUE,do_chart_template +do_niif_11030201,11030201,Cuenta por Cobrar a Clientes,account.data_account_type_receivable,TRUE,do_chart_template +do_niif_11030202,11030202,Cuenta por Cobrar a Funcionarios y Empleados,account.data_account_type_receivable,TRUE,do_chart_template +do_niif_11030203,11030203,Cuenta por Cobrar a Afiliadas,account.data_account_type_receivable,TRUE,do_chart_template +do_niif_11030204,11030204,Cuenta por Cobrar a Accionistas,account.data_account_type_receivable,TRUE,do_chart_template +do_niif_11030205,11030205,Otras Cuentas por Cobrar,account.data_account_type_receivable,TRUE,do_chart_template +do_niif_11040100,11040100,Provisión Incobrables a Clientes,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11040200,11040200,Provisión Incobrables a Funcionarios y Empleados,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11040300,11040300,Provisión Incobrables a Afiliadas,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11040400,11040400,Provisión Incobrables a Accionistas,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11040500,11040500,Provisión Otras Cuentas Incobrables,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11050100,11050100,Inventario de Mercancías o Productos Terminados,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11050200,11050200,Inventario de Materia Prima,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11050300,11050300,Inventario en Tránsito,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11050400,11050400,Materiales y Suministros en Inventario,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11050500,11050500,Combustibles en Inventario,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11060100,11060100,Deterioro Acum. de Inventario en Almacen,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11060200,11060200,Deterioro Acum. de Materiales y Suministros,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11060300,11060300,Deterioro Acum. de Combustibles,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11070100,11070100,Obsolescencia Inventario en Almacen,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11070200,11070200,Obsolescencia Materiales y Suministros,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11070300,11070300,Obsolescencia Combustibles,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11080101,11080101,ITBIS Pagado en Compras Locales,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11080102,11080102,ITBIS Pagado en Servicios Locales,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11080103,11080103,ITBIS Pagado por Importaciones,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11080301,11080301,ITBIS Pagado en Ventas con Tarjeta de Crédito (Norma 08-04),account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11080302,11080302,Saldo a Favor ITBIS,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11080303,11080303,Saldo a Favor ISR,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11090100,11090100,Acciones Temporales,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11090200,11090200,Depósitos a Plazo Temporales,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11090300,11090300,Bonos Temporales,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_11100100,11100100,Gastos Pagados por Anticipado,account.data_account_type_prepayments,FALSE,do_chart_template +do_niif_11100200,11100200,Renta Pagada por Anticipado,account.data_account_type_prepayments,FALSE,do_chart_template +do_niif_11100300,11100300,Seguros Pagados por Anticipado,account.data_account_type_prepayments,FALSE,do_chart_template +do_niif_11100400,11100400,Anticipos ISR,account.data_account_type_prepayments,FALSE,do_chart_template +do_niif_11100500,11100500,Anticipos Gastos,account.data_account_type_prepayments,FALSE,do_chart_template +do_niif_12010101,12010101,Terrenos,account.data_account_type_fixed_assets,FALSE,do_chart_template +do_niif_12010102,12010102,Edificaciones,account.data_account_type_fixed_assets,FALSE,do_chart_template +do_niif_12010201,12010201,Equipo de Transporte,account.data_account_type_fixed_assets,FALSE,do_chart_template +do_niif_12010202,12010202,Mobiliario y Equipos,account.data_account_type_fixed_assets,FALSE,do_chart_template +do_niif_12010301,12010301,Maquinaria,account.data_account_type_fixed_assets,FALSE,do_chart_template +do_niif_12010302,12010302,Herramientas,account.data_account_type_fixed_assets,FALSE,do_chart_template +do_niif_12010303,12010303,Instalaciones,account.data_account_type_fixed_assets,FALSE,do_chart_template +do_niif_12010304,12010304,Misceláneos u otros activos,account.data_account_type_fixed_assets,FALSE,do_chart_template +do_niif_12020100,12020100,Depreciación Acum. de Edificios,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12020200,12020200,Depreciación Acum. de Equipo de Transporte,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12020300,12020300,Depreciación Acum. de Mobiliario y Equipos,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12020400,12020400,Depreciación Acum. de Maquinaria,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12020500,12020500,Depreciación Acum. de Herramientas,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12020600,12020600,Depreciación Acum. de Instalaciones,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12040100,12040100,Marcas y Patentes,account.data_account_type_fixed_assets,FALSE,do_chart_template +do_niif_12040200,12040200,Programas Informáticos,account.data_account_type_fixed_assets,FALSE,do_chart_template +do_niif_12050100,12050100,Edificios y Locales Arrendados,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_12050200,12050200,Maquinaria y Equipo Arrendados,account.data_account_type_current_assets,FALSE,do_chart_template +do_niif_12050300,12050300,Instalaciones Arrendadas,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12060100,12060100,Depreciación Acum. Edificios y Locales,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12060200,12060200,Depreciación Acum. Maquinaria y Equipo,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12060300,12060300,Depreciación Acum. Instalaciones,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12070100,12070100,Deterioro Valor Acum. Edificios y Locales,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12070200,12070200,Deterioro Valor Acum. Maquinaria y Equipo,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12070300,12070300,Deterioro Valor Acum. Instalaciones,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12080100,12080100,Acciones en otras sociedades,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12090100,12090100,Diferencias temporales deducibles,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12090200,12090200,Gastos Organizacionales Diferidos,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_12090300,12090300,ISR Deducible,account.data_account_type_non_current_assets,FALSE,do_chart_template +do_niif_21010100,21010100,Préstamos Bancarios por Pagar,account.data_account_type_payable,TRUE,do_chart_template +do_niif_21010200,21010200,Cuenta por Pagar Proveedores Locales,account.data_account_type_payable,TRUE,do_chart_template +do_niif_21010300,21010300,Cuenta por Pagar Proveedores del Exterior,account.data_account_type_payable,TRUE,do_chart_template +do_niif_21010400,21010400,Nóminas por Pagar,account.data_account_type_payable,TRUE,do_chart_template +do_niif_21010500,21010500,Intereses por Pagar,account.data_account_type_payable,TRUE,do_chart_template +do_niif_21010600,21010600,Otras Cuentas por Pagar,account.data_account_type_payable,TRUE,do_chart_template +do_niif_21020100,21020100,Dividendos por Pagar,account.data_account_type_payable,TRUE,do_chart_template +do_niif_21020200,21020200,Comisiones por Pagar,account.data_account_type_payable,TRUE,do_chart_template +do_niif_21020300,21020300,Bonificaciones por Pagar,account.data_account_type_payable,TRUE,do_chart_template +do_niif_21020400,21020400,Regalía Pascual por Pagar,account.data_account_type_payable,TRUE,do_chart_template +do_niif_21030101,21030101,ITBIS por Venta Servicios,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030102,21030102,ITBIS por Venta Bienes,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030103,21030103,ITBIS por Venta Bienes - al Exterior,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030201,21030201,ITBIS Retenido Persona Jurídica (N 02-05),account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030202,21030202,ITBIS Retenido Persona Física (R 293-11),account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030203,21030203,ITBIS Retenido a Entidades No Lucrativas (N 01-2011),account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030204,21030204,ITBIS Retenido por Servicios Profesionales Liberales (N 02-05),account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030205,21030205,ITBIS Retenido a Proveedores Informales de Bienes (N 08-10),account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030301,21030301,ISR Retenido por Honorarios Profesionales de Personas Físicas,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030302,21030302,ISR Retenido por Alquileres Pagados a Personas Físicas,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030303,21030303,ISR Retenido por Dividendos Pagados,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030304,21030304,ISR Retenido por Intereses Pagados al Exterior,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030305,21030305,ISR Retenido por Intereses Pagados,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030306,21030306,ISR Retenido por Transferencias de Títulos y Propiedades,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030307,21030307,ISR Retenido por Remesas al Exterior (Ley 253-12),account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030308,21030308,Otras Retenciones (N 07-07),account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030309,21030309,Otras Retenciones,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030401,21030401,Retención de Seguro Familiar de Salud (SFS),account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030402,21030402,"Seguro de vejez, Discapacidad y Sobre Vivencia (AFP)",account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030404,21030404,Impuesto al Salario (ISR),account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030501,21030501,ISR por Pagar,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030502,21030502,Anticipos ISR por Pagar,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030503,21030503,Seguro de Riesgo Laboral (SRL),account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030504,21030504,INFOTEP,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21030505,21030505,Otros Impuestos por Pagar,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21040100,21040100,Provisión Pago Alquileres,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21040200,21040200,Provisión Arrendamiento Financiero,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21040300,21040300,Provisión Gastos Fijos,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21050100,21050100,Tarjeta de Crédito Empresarial,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_21050200,21050200,Prima de Tarjetas de Crédito,account.data_account_type_current_liabilities,FALSE,do_chart_template +do_niif_22010100,22010100,Préstamos Bancarios Largo Plazo,account.data_account_type_non_current_liabilities,FALSE,do_chart_template +do_niif_22010200,22010200,Préstamos Hipotecarios LP,account.data_account_type_non_current_liabilities,FALSE,do_chart_template +do_niif_22012300,22012300,Otros Préstamos LP,account.data_account_type_non_current_liabilities,FALSE,do_chart_template +do_niif_22020100,22020100,Provisión Beneficios de Empleados LP,account.data_account_type_non_current_liabilities,FALSE,do_chart_template +do_niif_22020200,22020200,Provisión Prestaciones Laborales,account.data_account_type_non_current_liabilities,FALSE,do_chart_template +do_niif_22020300,22020300,Provisión Indemnizaciones,account.data_account_type_non_current_liabilities,FALSE,do_chart_template +do_niif_22030100,22030100,Anticipos de Clientes,account.data_account_type_non_current_liabilities,FALSE,do_chart_template +do_niif_22030200,22030200,Garantías de Clientes,account.data_account_type_non_current_liabilities,FALSE,do_chart_template +do_niif_22040100,22040100,Provisión Arrendamiento Financiero LP,account.data_account_type_non_current_liabilities,FALSE,do_chart_template +do_niif_31010100,31010100,Capital Social Autorizado,account.data_account_type_equity,FALSE,do_chart_template +do_niif_31010200,31010200,Capital Social en Acciones no Emitidas,account.data_account_type_equity,FALSE,do_chart_template +do_niif_31010300,31010300,Capital Social Pagado,account.data_account_type_equity,FALSE,do_chart_template +do_niif_31010400,31010400,Capital Social No Pagado,account.data_account_type_equity,FALSE,do_chart_template +do_niif_31010500,31010500,Acciones o Participaciones en Tesorería,account.data_account_type_equity,FALSE,do_chart_template +do_niif_31020100,31020100,Superávit por Revaluación de Terrenos,account.data_account_type_equity,FALSE,do_chart_template +do_niif_31020200,31020200,Superávit por Revaluación de Edificaciones,account.data_account_type_equity,FALSE,do_chart_template +do_niif_31020300,31020300,Superávit por Revaluación de Instalaciones,account.data_account_type_equity,FALSE,do_chart_template +do_niif_31020400,31020400,Superávit por Revaluación de Mobiliario y Equipo,account.data_account_type_equity,FALSE,do_chart_template +do_niif_32010100,32010100,Reserva Legal,account.data_account_type_equity,FALSE,do_chart_template +do_niif_33010100,33010100,Utilidades de Ejercicios Anteriores,account.data_account_type_equity,FALSE,do_chart_template +do_niif_33010200,33010200,Pérdidas de Ejercicios Anteriores,account.data_account_type_equity,FALSE,do_chart_template +do_niif_33020100,33020100,Utilidad del Ejercicio,account.data_account_type_equity,FALSE,do_chart_template +do_niif_33020200,33020200,Pérdidas del Ejercicio,account.data_account_type_equity,FALSE,do_chart_template +do_niif_33040100,33040100,Superávit en Reserva,account.data_account_type_equity,FALSE,do_chart_template +do_niif_33040200,33040200,Déficit en Reserva,account.data_account_type_equity,FALSE,do_chart_template +do_niif_41010100,41010100,Ventas Bienes,account.data_account_type_revenue,FALSE,do_chart_template +do_niif_41010200,41010200,Ventas Bienes - Al Exterior,account.data_account_type_revenue,FALSE,do_chart_template +do_niif_41020100,41020100,Ventas Servicios,account.data_account_type_revenue,FALSE,do_chart_template +do_niif_41020200,41020200,Ventas Servicios - Al Exterior,account.data_account_type_revenue,FALSE,do_chart_template +do_niif_41030100,41030100,Devoluciones de Bienes,account.data_account_type_revenue,FALSE,do_chart_template +do_niif_41030200,41030200,Devoluciones por Servicios,account.data_account_type_revenue,FALSE,do_chart_template +do_niif_41040100,41040100,Descuentos por Ventas (por NC),account.data_account_type_revenue,FALSE,do_chart_template +do_niif_42010100,42010100,Intereses sobre Certificados,account.data_account_type_revenue,FALSE,do_chart_template +do_niif_42010200,42010200,Intereses en Cuentas Bancarias,account.data_account_type_revenue,FALSE,do_chart_template +do_niif_42010300,42010300,Intereses por Financiamientos,account.data_account_type_revenue,FALSE,do_chart_template +do_niif_42020100,42020100,Ingresos por Ventas de Activos,account.data_account_type_revenue,FALSE,do_chart_template +do_niif_42030100,42030100,Ingresos por Dividendos Ganados,account.data_account_type_revenue,FALSE,do_chart_template +do_niif_42040100,42040100,Ingresos por Diferencia Cambiaria,account.data_account_type_other_income,FALSE,do_chart_template +do_niif_42040200,42040200,Cobro de Cuentas Incobrables,account.data_account_type_other_income,FALSE,do_chart_template +do_niif_42040300,42040300,Otros Ingresos,account.data_account_type_other_income,FALSE,do_chart_template +do_niif_51010100,51010100,Costos de Bienes,account.data_account_type_direct_costs,FALSE,do_chart_template +do_niif_51010200,51010200,Otros Costos de Venta,account.data_account_type_direct_costs,FALSE,do_chart_template +do_niif_51020100,51020100,Materia Prima,account.data_account_type_direct_costs,FALSE,do_chart_template +do_niif_51020200,51020200,Mano de Obra,account.data_account_type_direct_costs,FALSE,do_chart_template +do_niif_51020300,51020300,Costos Indirectos,account.data_account_type_direct_costs,FALSE,do_chart_template +do_niif_52010100,52010100,Sueldos y Salarios,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010200,52010200,Regalía Pascual,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010300,52010300,Retribuciones Complementarias,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010400,52010400,Bono Vacacional,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010500,52010500,Bono por Desempeńo,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010600,52010600,Comisiones,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010700,52010700,Indemnizaciones,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010800,52010800,Bonificaciones y Gratificaciones,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010900,52010900,Dietas al Personal,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52011000,52011000,Cursos y Entrenamientos,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52011100,52011100,Prestaciones Laborales (Preaviso y Cesantia),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52011200,52011200,Incentivos,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52011300,52011300,Horas Extras,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52011400,52011400,Otros Gastos de Personal,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010102,52010102,Aportes a la Administradora de Fondos de Pensiones (AFP),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010103,52010103,Aportes al Seguro Riesgo Laboral (SRL),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010104,52010104,Seguro Familiar de Salud (SFS),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010201,52010201,Aportes a la Administradora de Riesgos de Salud (ARS),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010202,52010202,Seguros al Personal,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010203,52010203,Planes Complementarios de Salud,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010204,52010204,Seguros de Vida,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52010205,52010205,Aportes al Infotep,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52020100,52020100,Energía Eléctrica,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52020200,52020200,Comunicaciones,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52020300,52020300,Papelería y útiles,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52020400,52020400,Útiles de Aseo y Limpieza,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52020500,52020500,Material de Empaque,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52020600,52020600,Seguro de Edificio,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52020700,52020700,Combustibles y Lubricantes,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52020800,52020800,Alquileres,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52020900,52020900,Franquicias,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52021000,52021000,Inducción a Vendedores,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52021100,52021100,Seguros,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52021200,52021200,Servicios de Mensajería,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52021300,52021300,Flete y Carga,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52021400,52021400,Cuotas y Suscripciones,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52021500,52021500,Otros Gastos de Administración,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030101,52030101,Legales (P. Física),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030102,52030102,Contabilidad y Auditoría (P. Física),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030103,52030103,Tecnología (P. Física),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030104,52030104,Mantenimiento de Planta (P. Física),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030105,52030105,Mantenimiento del Local (P. Física),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030106,52030106,Mantenimiento Mobiliario y Equipos (P. Física),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030107,52030107,Asesorías (P. Física),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030108,52030108,Fumigaciones (P. Física),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030109,52030109,Copias y Escaneos (P. Física),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030110,52030110,Servicios de Vigilancia (P. Física),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030111,52030111,Otros Servicios Profesionales (P. Física),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030201,52030201,Legales (P. Jurídica),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030202,52030202,Contabilidad y Auditoría (P. Jurídica),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030203,52030203,Tecnología (P. Jurídica),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030204,52030204,Mantenimiento de Planta (P. Jurídica),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030205,52030205,Mantenimiento del Local (P. Jurídica),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030206,52030206,Mantenimiento Mobiliario y Equipos (P. Jurídica),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030207,52030207,Asesorías (P. Jurídica),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030208,52030208,Fumigaciones (P. Jurídica),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030209,52030209,Copias y Escaneos (P. Jurídica),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030210,52030210,Servicios de Vigilancia (P. Jurídica),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030211,52030211,Otros Servicios Profesionales (P. Jurídica),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030301,52030301,Honorarios por Servicios del Exterior - Relacionadas,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52030302,52030302,Honorarios por Servicios del Exterior - Terceros,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52040100,52040100,Gastos por Depreciación de Edificios,account.data_account_type_depreciation,FALSE,do_chart_template +do_niif_52040200,52040200,Gastos por Depreciación de Equipo de Transporte,account.data_account_type_depreciation,FALSE,do_chart_template +do_niif_52040300,52040300,Gastos por Depreciación de Mobiliario y Equipos,account.data_account_type_depreciation,FALSE,do_chart_template +do_niif_52040400,52040400,Gastos por Depreciación de Maquinaria,account.data_account_type_depreciation,FALSE,do_chart_template +do_niif_52040500,52040500,Gastos por Depreciación de Herramientas,account.data_account_type_depreciation,FALSE,do_chart_template +do_niif_52040600,52040600,Gastos por Depreciación de Instalaciones,account.data_account_type_depreciation,FALSE,do_chart_template +do_niif_52050100,52050100,Gastos por Reparación de Edificios,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52050200,52050200,Gastos por Reparación de Equipo de Transporte,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52050300,52050300,Gastos por Reparación de Mobiliario y Equipos,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52050400,52050400,Gastos por Reparación de Maquinaria,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52050500,52050500,Gastos por Reparación de Herramientas,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52050600,52050600,Gastos por Reparación de Instalaciones,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52060100,52060100,Relaciones Públicas,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52060200,52060200,Publicidad,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52060300,52060300,Viajes,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52060400,52060400,Donaciones,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52060500,52060500,Donaciones a ProIndustria (Ley 392-07),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52060600,52060600,Promociones,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52060700,52060700,Otros Gastos de Representación,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52070100,52070100,Gastos por Préstamos Bancarios,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52070200,52070200,Retención por Cheques y Transacciones Electrónicas (0.015%),account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52070300,52070300,Intereses Bancarios,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52070400,52070400,Comisiones Bancarias,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52070500,52070500,Comisión de Tarjeta de Crédito,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52070600,52070600,Nota de Cargos por Banco,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52070700,52070700,Seguro sobre Préstamos Bancarios,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52070800,52070800,Diferencia Negativa Cambiaria,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52070900,52070900,Otro Gastos Financieros,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52080100,52080100,Gastos por Siniestros,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52080200,52080200,Pérdidas por Ventas de Activos Fijos,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52080300,52080300,Pérdidas por Cuentas Incobrables,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52080400,52080400,Gastos por ISR,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52080500,52080500,Impuestos a los Activos,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52080600,52080600,Penalidades/Recargos de DGII,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52080700,52080700,Penalidades/Recargos de TSS,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_52080800,52080800,Gastos Sin Comprobante,account.data_account_type_expenses,FALSE,do_chart_template +do_niif_61010100,61010100,Pérdidas y Ganancias,account.data_unaffected_earnings,FALSE,do_chart_template diff --git a/addons/l10n_do/data/account.account.type.csv b/addons/l10n_do/data/account.account.type.csv deleted file mode 100644 index ecc5c031e9e..00000000000 --- a/addons/l10n_do/data/account.account.type.csv +++ /dev/null @@ -1,17 +0,0 @@ -id,name,report_type -default_chart_a_type_1,Root/View,none -default_chart_a_type_2,Receivable,asset -default_chart_a_type_3,Payable,liability -default_chart_a_type_4,Bank,asset -default_chart_a_type_5,Cash,asset -default_chart_a_type_6,Asset,asset -default_chart_a_type_7,Liability,liability -default_chart_a_type_8,Income,income -default_chart_a_type_9,Expense,expense -default_chart_a_type_10,Income View,income -default_chart_a_type_11,Expense View,expense -default_chart_a_type_12,Asset View,asset -default_chart_a_type_13,Liability View,liability -default_chart_a_type_14,Tax,expense -default_chart_a_type_15,Equity,liability -default_chart_a_type_16,Check,asset diff --git a/addons/l10n_do/data/account.fiscal.position.tax.template.csv b/addons/l10n_do/data/account.fiscal.position.tax.template.csv deleted file mode 100644 index 8d0f2b6590d..00000000000 --- a/addons/l10n_do/data/account.fiscal.position.tax.template.csv +++ /dev/null @@ -1,4 +0,0 @@ -id,position_id:id,tax_src_id:id,tax_dest_id:id -default_chart_a_position_tax_1,default_chart_a_position_4,default_chart_a_tax_14,default_chart_a_tax_7 -default_chart_a_position_tax_2,default_chart_a_position_17,default_chart_a_tax_8,default_chart_a_tax_15 -default_chart_a_position_tax_3,default_chart_a_position_13,default_chart_a_tax_15, diff --git a/addons/l10n_do/data/account.fiscal.position.template.csv b/addons/l10n_do/data/account.fiscal.position.template.csv deleted file mode 100644 index 926f8f2f915..00000000000 --- a/addons/l10n_do/data/account.fiscal.position.template.csv +++ /dev/null @@ -1,18 +0,0 @@ -id,name,chart_template_id:id -default_chart_a_position_1,"Para CrĂ©dito Fiscal",default_chart_a, -default_chart_a_position_2,"Cosumidor Final",default_chart_a, -default_chart_a_position_3,Gubernamental,default_chart_a, -default_chart_a_position_4,"RegĂmenes Especiales",default_chart_a, -default_chart_a_position_5,"Gastos de personal",default_chart_a, -default_chart_a_position_6,"Gastos por trabajo, suministros y servicios",default_chart_a, -default_chart_a_position_7,Arrendamientos,default_chart_a, -default_chart_a_position_8,"Gastos de Activos Fijos",default_chart_a, -default_chart_a_position_9,"Gastos de RepresentaciĂłn",default_chart_a, -default_chart_a_position_10,"Otras Deducciones Admitidas",default_chart_a, -default_chart_a_position_11,"Gastos Financieros",default_chart_a, -default_chart_a_position_12,"Gastos Extraordinarios",default_chart_a, -default_chart_a_position_13,"Proveedores de mercancĂa impuesto no incluido",default_chart_a, -default_chart_a_position_14,"Adquisiciones de Activos",default_chart_a, -default_chart_a_position_15,"Gastos Menores",default_chart_a, -default_chart_a_position_16,"Gastos de Seguro",default_chart_a, -default_chart_a_position_17,"Proveedores de mercancĂa impuesto incluido",default_chart_a, diff --git a/addons/l10n_do/data/account.tax.template.csv b/addons/l10n_do/data/account.tax.template.csv deleted file mode 100644 index cd144c6b56c..00000000000 --- a/addons/l10n_do/data/account.tax.template.csv +++ /dev/null @@ -1,19 +0,0 @@ -id,name,description,type_tax_use,amount_type,amount,sequence,refund_account_id:id,account_id:id,chart_template_id:id,tag_ids:id -default_chart_a_tax_1,10% Honorarios por Servicios Independientes,R-ISR 10%,purchase,percent,-10,1,default_chart_a_account_712,default_chart_a_account_712,default_chart_a,tag_R_ISR_10 -default_chart_a_tax_2,ITBIS Exento en compras,C-EXENTA,purchase,percent,0,1,,,default_chart_a,tag_C_EXENTA -default_chart_a_tax_3,ITBIS 8% Ventas,V-ITBIS 8%,sale,percent,11,1,,,default_chart_a,tag_V_ITBIS_8 -default_chart_a_tax_4,ITBIS 8% Compras,C-ITBIS 8%,purchase,percent,11,1,,,default_chart_a,tag_C_ITBIS_8 -default_chart_a_tax_5,ITBIS 11% Ventas,V-ITBIS 11%,sale,percent,11,1,,,default_chart_a,tag_V_ITBIS_11 -default_chart_a_tax_6,ITBIS 11% Compras,C-ITBIS 11%,purchase,percent,11,1,,,default_chart_a,tag_C_ITBIS_11 -default_chart_a_tax_7,ITBIS Exento en ventas,V-EXENTA,sale,percent,18,1,,,default_chart_a,tag_V_EXENTA -default_chart_a_tax_8,ITBIS 18% Compras,C-ITBIS 18%,purchase,percent,18,1,default_chart_a_account_53,default_chart_a_account_53,default_chart_a,tag_C_ITBIS_18 -default_chart_a_tax_9,ITBIS 18% Compras Servicios,CS-ITBIS 18%,purchase,percent,18,1,default_chart_a_account_57,default_chart_a_account_57,default_chart_a,tag_CS_ITBIS_18 -default_chart_a_tax_10,ITBIS 18% Compras Importaciones,IMP-ITBIS 18%,purchase,percent,18,1,default_chart_a_account_56,default_chart_a_account_56,default_chart_a,tag_IMP_ITBIS_18 -default_chart_a_tax_12,2% Otras Retenciones (Norma 07-2007),R-ISR 2%,purchase,percent,-2,1,,,default_chart_a,tag_R_ISR_2 -default_chart_a_tax_13,18% ITBIS Retenido,R-ITBIS 18%,purchase,percent,-18,1,default_chart_a_account_163,default_chart_a_account_163,default_chart_a,tag_R_ITBIS_18 -default_chart_a_tax_14,ITBIS 18% Ventas,V-ITBIS 18%,sale,percent,18,10,default_chart_a_account_71,default_chart_a_account_71,default_chart_a,tag_V_ITBIS_18 -default_chart_a_tax_15,ITBIS 18% Compras Includo,C-ITBIS 18% Incluido,purchase,percent,18,1,default_chart_a_account_53,default_chart_a_account_53,default_chart_a,tag_C_ITBIS_18_Incluido -default_chart_a_tax_16,ITBIS 18% Compras Servicios Incluido,CS-ITBIS 18% Incluido,purchase,percent,18,1,default_chart_a_account_57,,default_chart_a,tag_CS_ITBIS_18_Incluido -default_chart_a_tax_19,ISC Telecomunicacones,TELE-ISC,purchase,percent,10,1,default_chart_a_account_529,,default_chart_a,tag_TELE_ISC -default_chart_a_tax_20,CDT Telecomunicacones,TELE-CDT,purchase,percent,2,1,default_chart_a_account_529,,default_chart_a,tag_TELE_CDT -default_chart_a_tax_23,10% Retencion por alquileres,R-Alquileres 10%,purchase,percent,-10,1,default_chart_a_account_712,default_chart_a_account_712,default_chart_a,tag_R_Alquileres_10 diff --git a/addons/l10n_do/data/account.tax.template.xml b/addons/l10n_do/data/account.tax.template.xml new file mode 100644 index 00000000000..166bb85294b --- /dev/null +++ b/addons/l10n_do/data/account.tax.template.xml @@ -0,0 +1,364 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <data noupdate="1"> + <!-- Chart template for Taxes --> + <!-- Taxes Groups --> + <record id="group_itbis" model="account.tax.group"> + <field name="name">ITBIS</field> + </record> + <record id="group_ret" model="account.tax.group"> + <field name="name">Retenciones</field> + </record> + <record id="group_tax" model="account.tax.group"> + <field name="name">Otros Impuestos</field> + </record> + <!-- Taxes Template --> + <record id="tax_0_sale" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">50</field> + <field name="name">Exento ITBIS Ventas</field> + <field name="description">Exento</field> + <field name="amount">0</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">sale</field> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_V_EXENTA')])]" name="tag_ids"/> + </record> + <record id="tax_0_purch" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">50</field> + <field name="name">Exento ITBIS Compras</field> + <field name="description">Exento</field> + <field name="amount">0</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_C_EXENTA')])]" name="tag_ids"/> + </record> + <record id="tax_18_sale" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">1</field> + <field name="name">18% ITBIS Ventas</field> + <field name="description">18%</field> + <field name="amount">18</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">sale</field> + <field name="account_id" ref="do_niif_21030102"/> + <field name="refund_account_id" ref="do_niif_21030102"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_V_ITBIS_18')])]" name="tag_ids"/> + </record> + <record id="tax_18_sale_incl" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">10</field> + <field name="name">18% ITBIS Incl. Ventas</field> + <field name="description">18% Incl</field> + <field name="amount">18</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">sale</field> + <field name="account_id" ref="do_niif_21030102"/> + <field name="refund_account_id" ref="do_niif_21030102"/> + <field eval="1" name="price_include"/> + <field eval="[(6,0,[ref('tag_V_ITBIS_18')])]" name="tag_ids"/> + </record> + <record id="tax_18_purch" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">18% ITBIS Compras</field> + <field name="sequence">2</field> + <field name="description">18%</field> + <field name="amount">18</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_11080101"/> + <field name="refund_account_id" ref="do_niif_11080302"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_C_ITBIS_18')])]" name="tag_ids"/> + </record> + <record id="tax_18_purch_incl" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">20</field> + <field name="name">18% ITBIS Incl. Compras</field> + <field name="description">18%</field> + <field name="amount">18</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_11080101"/> + <field name="refund_account_id" ref="do_niif_11080302"/> + <field eval="1" name="price_include"/> + <field eval="[(6,0,[ref('tag_C_ITBIS_18_Incluido')])]" name="tag_ids"/> + </record> + <record id="tax_18_purch_serv" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">20</field> + <field name="name">18% ITBIS Compras - Servicios</field> + <field name="description">18%</field> + <field name="amount">18</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_11080102"/> + <field name="refund_account_id" ref="do_niif_11080302"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_C_ITBIS_18')])]" name="tag_ids"/> + </record> + <record id="tax_18_purch_serv_incl" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">20</field> + <field name="name">18% ITBIS Incl. Compras - Servicios</field> + <field name="description">18%</field> + <field name="amount">18</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_11080102"/> + <field name="refund_account_id" ref="do_niif_11080302"/> + <field eval="1" name="price_include"/> + <field eval="[(6,0,[ref('tag_C_ITBIS_18_Incluido')])]" name="tag_ids"/> + </record> + <record id="tax_18_importation" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">20</field> + <field name="name">18% ITBIS - Importaciones</field> + <field name="description">18%</field> + <field name="amount">18</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_11080103"/> + <field name="refund_account_id" ref="do_niif_11080302"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_IMP_ITBIS_18')])]" name="tag_ids"/> + </record> + <record id="tax_18_of_10" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">20</field> + <field name="name">18% ITBIS sobre el 10% del Monto Total</field> + <field name="description">18% del 10%</field> + <field name="amount">1.8</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_11080101"/> + <field name="refund_account_id" ref="do_niif_11080302"/> + <field eval="0" name="price_include"/> + </record> + <record id="tax_0015_bank" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">30</field> + <field name="name">Impuesto 0.15% Transferencia Bancaria</field> + <field name="description">0.15%</field> + <field name="amount">0.0015</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_52070200"/> + <field name="refund_account_id" ref="do_niif_11080303"/> + <field eval="1" name="price_include"/> + </record> + <record id="tax_10_telco" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">30</field> + <field name="name">Impuesto 10% Telecomunicaciones (ISC)</field> + <field name="description">ISC</field> + <field name="amount">10</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_52020200"/> + <field name="refund_account_id" ref="do_niif_52020200"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_TELE_ISC')])]" name="tag_ids"/> + </record> + <record id="tax_2_telco" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">30</field> + <field name="name">Impuesto 2% Telecomunicaciones (CDT)</field> + <field name="description">CDT</field> + <field name="amount">2</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_52020200"/> + <field name="refund_account_id" ref="do_niif_52020200"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_TELE_CDT')])]" name="tag_ids"/> + </record> + <record id="tax_group_telco" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">30</field> + <field name="name">Impuestos a las Telecomunicaciones</field> + <field eval="0" name="amount"/> + <field name="amount_type">group</field> + <field name="type_tax_use">purchase</field> + <field eval="[(6, 0, [ref('tax_10_telco'), ref('tax_2_telco')])]" name="children_tax_ids"/> + </record> + <record id="ret_100_tax_nonprofit" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">40</field> + <field name="name">RetenciĂłn ITBIS 100% a No Lucrativas (Servicios)</field> + <field name="description">100% del ITBIS</field> + <field name="amount">-18</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_21030203"/> + <field name="refund_account_id" ref="do_niif_21030203"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_R_ITBIS_18')])]" name="tag_ids"/> + </record> + <record id="ret_100_tax_person" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">40</field> + <field name="name">RetenciĂłn ITBIS 100% a Persona FĂsica</field> + <field name="description">100% del ITBIS</field> + <field name="amount">-18</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_21030202"/> + <field name="refund_account_id" ref="do_niif_21030202"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_R_ITBIS_18')])]" name="tag_ids"/> + </record> + <record id="ret_30_tax_moral" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">40</field> + <field name="name">RetenciĂłn ITBIS 30% a Persona JurĂdica (ConstrucciĂłn)</field> + <field name="description">30% del ITBIS</field> + <field name="amount">-5.4</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_21030201"/> + <field name="refund_account_id" ref="do_niif_21030201"/> + <field eval="0" name="price_include"/> + </record> + <record id="ret_30_tax_freelance" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">40</field> + <field name="name">RetenciĂłn ITBIS 30% a Profesionales Liberales (Servicios)</field> + <field name="description">30% del ITBIS</field> + <field name="amount">-5.4</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_21030204"/> + <field name="refund_account_id" ref="do_niif_21030204"/> + <field eval="0" name="price_include"/> + </record> + <record id="ret_75_tax_nonformal" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">40</field> + <field name="name">RetenciĂłn ITBIS 75% a Proveedores Informales (Bienes)</field> + <field name="description">75% del ITBIS</field> + <field name="amount">-13.5</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_21030205"/> + <field name="refund_account_id" ref="do_niif_21030205"/> + <field eval="0" name="price_include"/> + </record> + <record id="ret_10_income_person" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">40</field> + <field name="name">RetenciĂłn ISR 10% Honorarios a Persona FĂsica (Servicios)</field> + <field name="description">10% ISR</field> + <field name="amount">-10</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_21030301"/> + <field name="refund_account_id" ref="do_niif_11080303"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_R_ISR_10')])]" name="tag_ids"/> + </record> + <record id="ret_10_income_rent" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">40</field> + <field name="name">RetenciĂłn ISR 10% a Persona FĂsica (Alquiler)</field> + <field name="description">10% ISR</field> + <field name="amount">-10</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_21030302"/> + <field name="refund_account_id" ref="do_niif_11080303"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_R_ISR_10')])]" name="tag_ids"/> + </record> + <record id="ret_10_income_dividend" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">40</field> + <field name="name">RetenciĂłn ISR 10% por Dividendos</field> + <field name="description">10% ISR</field> + <field name="amount">-10</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_21030303"/> + <field name="refund_account_id" ref="do_niif_11080303"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_R_ISR_10')])]" name="tag_ids"/> + </record> + <record id="ret_2_income_person" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">40</field> + <field name="name">RetenciĂłn ISR 2% a Persona FĂsica (Servicios)</field> + <field name="description">2% ISR (N 07-07)</field> + <field name="amount">-2</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_21030308"/> + <field name="refund_account_id" ref="do_niif_11080303"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_R_ISR_2')])]" name="tag_ids"/> + </record> + <record id="ret_2_income_transfer" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">40</field> + <field name="name">RetenciĂłn ISR 2% por Transferencia de TĂtulos</field> + <field name="description">2% ISR</field> + <field name="amount">-2</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_21030306"/> + <field name="refund_account_id" ref="do_niif_11080303"/> + <field eval="0" name="price_include"/> + <field eval="[(6,0,[ref('tag_R_ISR_2')])]" name="tag_ids"/> + </record> + <record id="ret_27_income_remittance" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">40</field> + <field name="name">RetenciĂłn ISR 27% por Remesas al Exterior</field> + <field name="description">27% ISR</field> + <field name="amount">-27</field> + <field name="amount_type">percent</field> + <field name="type_tax_use">purchase</field> + <field name="account_id" ref="do_niif_21030307"/> + <field name="refund_account_id" ref="do_niif_11080303"/> + <field eval="0" name="price_include"/> + </record> + <record id="tax_group_nonformal" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">60</field> + <field name="name">RetenciĂłn a Proveedores Informales (Bienes)</field> + <field name="amount_type">group</field> + <field eval="0" name="amount"/> + <field name="type_tax_use">purchase</field> + <field eval="[(6, 0, [ref('ret_75_tax_nonformal'), ref('tax_18_purch')])]" name="children_tax_ids"/> + </record> + <record id="tax_group_person_construction" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">60</field> + <field name="name">RetenciĂłn a Persona FĂsica (Servicios ConstrucciĂłn con Materiales)</field> + <field name="amount_type">group</field> + <field eval="0" name="amount"/> + <field name="type_tax_use">purchase</field> + <field eval="[(6, 0, [ref('tax_18_of_10'), ref('ret_2_income_person'), ref('ret_100_tax_person')])]" name="children_tax_ids"/> + </record> + <record id="tax_group_moral_construction" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">60</field> + <field name="name">RetenciĂłn a JurĂdica (Servicios ConstrucciĂłn con Materiales)</field> + <field name="amount_type">group</field> + <field eval="0" name="amount"/> + <field name="type_tax_use">purchase</field> + <field eval="[(6, 0, [ref('ret_30_tax_moral'), ref('tax_18_of_10')])]" name="children_tax_ids"/> + </record> + <record id="tax_group_person_services" model="account.tax.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="sequence">60</field> + <field name="name">RetenciĂłn a Persona FĂsica por Servicios Profesionales</field> + <field name="amount_type">group</field> + <field eval="0" name="amount"/> + <field name="type_tax_use">purchase</field> + <field eval="[(6, 0, [ref('ret_2_income_person'), ref('ret_100_tax_person')])]" name="children_tax_ids"/> + </record> + </data> +</odoo> diff --git a/addons/l10n_do/data/account_chart_template_data.xml b/addons/l10n_do/data/account_chart_template_data.xml index 3cfff934abb..0123c1d897b 100644 --- a/addons/l10n_do/data/account_chart_template_data.xml +++ b/addons/l10n_do/data/account_chart_template_data.xml @@ -1,11 +1,16 @@ <?xml version="1.0" encoding="utf-8"?> <odoo> - <record id="default_chart_a" model="account.chart.template"> - <field name="property_account_receivable_id" ref="default_chart_a_account_13"/> - <field name="property_account_payable_id" ref="default_chart_a_account_61"/> - <field name="property_account_expense_categ_id" ref="default_chart_a_account_101"/> - <field name="property_account_income_categ_id" ref="default_chart_a_account_87"/> - <field name="income_currency_exchange_account_id" ref="default_chart_a_account_148"/> - <field name="expense_currency_exchange_account_id" ref="default_chart_a_account_596"/> - </record> + <!-- Chart Template for Defaults --> + <record id="do_chart_template" model="account.chart.template"> + <field name="property_account_receivable_id" ref="do_niif_11030201"/> + <field name="property_account_payable_id" ref="do_niif_21010200"/> + <field name="property_account_expense_categ_id" ref="do_niif_52021500"/> + <field name="property_account_income_categ_id" ref="do_niif_41010100"/> + <field eval="False" name="use_anglo_saxon"/> + <field name="property_stock_account_input_categ_id" ref="do_niif_11050300"/> + <field name="property_stock_account_output_categ_id" ref="do_niif_11050300"/> + <field name="property_stock_valuation_account_id" ref="do_niif_11060100"/> + <field name="expense_currency_exchange_account_id" ref="do_niif_52070800"/> + <field name="income_currency_exchange_account_id" ref="do_niif_42040100"/> + </record> </odoo> diff --git a/addons/l10n_do/data/account_chart_template_data.yml b/addons/l10n_do/data/account_chart_template_data.yml index bbae47a8ee6..bfea5da2ff5 100644 --- a/addons/l10n_do/data/account_chart_template_data.yml +++ b/addons/l10n_do/data/account_chart_template_data.yml @@ -1,3 +1,3 @@ - - !python {model: account.chart.template, id: default_chart_a}: | + !python {model: account.chart.template, id: do_chart_template}: | self[0].try_loading_for_current_company() diff --git a/addons/l10n_do/data/fiscal_position_template.xml b/addons/l10n_do/data/fiscal_position_template.xml new file mode 100644 index 00000000000..7179966d999 --- /dev/null +++ b/addons/l10n_do/data/fiscal_position_template.xml @@ -0,0 +1,146 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo> + <data noupdate="1"> + <!-- = = = = = = = = = = = = = = = --> + <!-- Fiscal Position Templates --> + <!-- = = = = = = = = = = = = = = = --> + <!-- Principal Fiscal Position for Dominican Republic internally --> + <record id="position_buyer_final" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">Consumidor Final</field> + </record> + <record id="position_buyer_moral" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">CrĂ©dito Fiscal</field> + </record> + <record id="position_provider_moral" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">Proveedor Fiscal</field> + </record> + <record id="position_construction_moral" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">Proveedor Fiscal (ConstrucciĂłn)</field> + </record> + <record id="position_construction_person" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">Persona FĂsica (ConstrucciĂłn)</field> + </record> + <record id="position_person" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">Persona FĂsica</field> + </record> + <record id="position_nonformal" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">Proveedor Informal (Bienes)</field> + </record> + <record id="position_exterior" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">Proveedor del Exterior</field> + </record> + <record id="position_expenses" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">Gastos Menores</field> + </record> + <record id="position_gov" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">Gubernamental</field> + </record> + <record id="position_nonprofit" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">No lucrativas</field> + </record> + <record id="position_especial" model="account.fiscal.position.template"> + <field name="chart_template_id" ref="do_chart_template"/> + <field name="name">RegĂmenes Especiales</field> + </record> + <!-- = = = = = = = = = = = = = = = --> + <!-- Fiscal Position Tax Templates --> + <!-- = = = = = = = = = = = = = = = --> + <!-- Locales --> + <!-- Proveedor Informal Bienes --> + <record id="fiscal_position_tax_3" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_purch"/> + <field name="position_id" ref="position_nonformal"/> + <field name="tax_dest_id" ref="tax_group_nonformal"/> + </record> + <record id="fiscal_position_tax_4" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_purch_incl"/> + <field name="position_id" ref="position_nonformal"/> + <field name="tax_dest_id" ref="tax_group_nonformal"/> + </record> + <!-- Persona FĂsica>--> + <record id="fiscal_position_tax_9" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_purch"/> + <field name="position_id" ref="position_person"/> + <field name="tax_dest_id" ref="tax_group_person_services"/> + </record> + <record id="fiscal_position_tax_10" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_purch_serv"/> + <field name="position_id" ref="position_person"/> + <field name="tax_dest_id" ref="tax_group_person_services"/> + </record> + <!-- Gubernamental --> + <record id="fiscal_position_tax_1" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_sale"/> + <field name="position_id" ref="position_gov"/> + <field name="tax_dest_id" ref="tax_0_sale"/> + </record> + <record id="fiscal_position_tax_2" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_purch"/> + <field name="position_id" ref="position_gov"/> + <field name="tax_dest_id" ref="tax_0_purch"/> + </record> + <!-- No Lucrativas --> + <record id="fiscal_position_tax_12" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_purch"/> + <field name="position_id" ref="position_nonprofit"/> + <field name="tax_dest_id" ref="tax_0_purch"/> + </record> + <record id="fiscal_position_tax_13" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_purch_serv"/> + <field name="position_id" ref="position_nonprofit"/> + <field name="tax_dest_id" ref="ret_100_tax_nonprofit"/> + </record> + <!-- Proveedor Moral ConstrucciĂłn --> + <record id="fiscal_position_tax_8" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_purch"/> + <field name="position_id" ref="position_construction_moral"/> + <field name="tax_dest_id" ref="tax_group_moral_construction"/> + </record> + <!-- Persona FĂsica ConstrucciĂłn --> + <record id="fiscal_position_tax_7" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_purch"/> + <field name="position_id" ref="position_construction_person"/> + <field name="tax_dest_id" ref="tax_group_person_construction"/> + </record> + <!-- ImportaciĂłn / ExportaciĂłn --> + <!-- Proveedo del Exterior --> + <record id="fiscal_position_tax_5" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_purch_serv"/> + <field name="position_id" ref="position_exterior"/> + <field name="tax_dest_id" ref="ret_27_income_remittance"/> + </record> + <record id="fiscal_position_tax_6" model="account.fiscal.position.tax.template"> + <field name="tax_src_id" ref="tax_18_purch"/> + <field name="position_id" ref="position_exterior"/> + <field name="tax_dest_id" ref="tax_0_purch"/> + </record> + <!-- = = = = = = = = = = = = = = = = = --> + <!-- Fiscal Position Accounts Template --> + <!-- = = = = = = = = = = = = = = = = = --> + <!-- Locales --> + <!-- Persona FĂsica de Servicios --> + <record id="fiscal_position_account_2" model="account.fiscal.position.account.template"> + <field name="position_id" ref="position_person"/> + <field name="account_dest_id" ref="do_niif_52030111"/> + <field name="account_src_id" ref="do_niif_52021500"/> + </record> + <!-- ImportaciĂłn / ExportaciĂłn --> + <!-- Proveedor del Exterior --> + <record id="fiscal_position_account_1" model="account.fiscal.position.account.template"> + <field name="position_id" ref="position_exterior"/> + <field name="account_dest_id" ref="do_niif_21010300"/> + <field name="account_src_id" ref="do_niif_21010200"/> + </record> + </data> +</odoo> diff --git a/addons/l10n_do/data/l10n_do_chart_data.xml b/addons/l10n_do/data/l10n_do_chart_data.xml index 300fada848a..9075d92a621 100644 --- a/addons/l10n_do/data/l10n_do_chart_data.xml +++ b/addons/l10n_do/data/l10n_do_chart_data.xml @@ -1,25 +1,25 @@ <?xml version="1.0" encoding="utf-8"?> <odoo> <menuitem id="account_reports_do_statements_menu" name="Dominican Statements" parent="account.menu_finance_reports" sequence="3" groups="account.group_account_user"/> - - <record model="account.account.template" id="default_chart_a_account_152"> - <field name="name">Efectivo en transito</field> - <field name="code">112050</field> - <field name="reconcile" eval="True"/> - <field name="user_type_id" ref="account.data_account_type_current_assets"/> - </record> - - - <record id="default_chart_a" model="account.chart.template"> - <field name="name">Catálogo de Cuentas Empresas Privadas</field> - <field name="currency_id" ref="base.DOP"/> - <field name="code_digits" eval="8"/> - <field name="transfer_account_id" ref="default_chart_a_account_152"/> - <field name="bank_account_code_prefix">112</field> - <field name="cash_account_code_prefix">111</field> - </record> - - <record model="account.account.template" id="default_chart_a_account_152"> - <field name="chart_template_id" ref="default_chart_a"/> - </record> + <data noupdate="1"> + <!-- Chart of Accounts Template --> + <record id="cash_transfer_account" model="account.account.template"> + <field name="name">Transferencias de Efectivo</field> + <field name="code">11010100</field> + <field eval="True" name="reconcile"/> + <field name="user_type_id" ref="account.data_account_type_current_assets"/> + </record> + <record id="do_chart_template" model="account.chart.template"> + <field name="name">Catálogo de Cuentas Dominicano (NIIF)</field> + <field name="code_digits">8</field> + <field name="cash_account_code_prefix">110101</field> + <field name="bank_account_code_prefix">110102</field> + <field name="transfer_account_id" ref="cash_transfer_account"/> + <field name="currency_id" ref="base.DOP"/> + <field name="spoken_languages" eval="'es_DO'"/> + </record> + <record id="cash_transfer_account" model="account.account.template"> + <field name="chart_template_id" ref="do_chart_template"/> + </record> + </data> </odoo> diff --git a/addons/l10n_do/data/l10n_do_state_data.xml b/addons/l10n_do/data/l10n_do_state_data.xml index 63c061e8749..322e27b3b4c 100644 --- a/addons/l10n_do/data/l10n_do_state_data.xml +++ b/addons/l10n_do/data/l10n_do_state_data.xml @@ -1,173 +1,177 @@ <?xml version="1.0" encoding="utf-8"?> <odoo> + <data noupdate="1"> <!-- - Resource: res.country.state - Update states using ISO 3166-2:DO codes - --> + Resource: res.country.state + Update states. This one is not using ISO 3166-2:DO codes, + as those codes are not used or known in Dominican Republic. + The new codes are more friendly and easier to identify by + the users. + --> <record id="state_DO_01" model="res.country.state"> - <field name="code">01</field> + <field name="code">DN</field> <field name="name">Distrito Nacional</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_02" model="res.country.state"> - <field name="code">02</field> + <field name="code">AZU</field> <field name="name">Azua</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_03" model="res.country.state"> - <field name="code">03</field> + <field name="code">BAH</field> <field name="name">Bahoruco</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_4" model="res.country.state"> - <field name="code">04</field> + <field name="code">BAR</field> <field name="name">Barahona</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_05" model="res.country.state"> - <field name="code">05</field> - <field name="name">Dajabon</field> + <field name="code">DAJ</field> + <field name="name">DajabĂłn</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_06" model="res.country.state"> - <field name="code">06</field> + <field name="code">DUA</field> <field name="name">Duarte</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_07" model="res.country.state"> - <field name="code">07</field> - <field name="name">Elias Piña</field> + <field name="code">ELP</field> + <field name="name">ElĂas Piña</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_08" model="res.country.state"> - <field name="code">08</field> - <field name="name">El Seybo</field> + <field name="code">ELS</field> + <field name="name">El Seibo</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_09" model="res.country.state"> - <field name="code">09</field> + <field name="code">ESP</field> <field name="name">Espaillat</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_10" model="res.country.state"> - <field name="code">10</field> + <field name="code">IND</field> <field name="name">Independencia</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_11" model="res.country.state"> - <field name="code">11</field> + <field name="code">LA</field> <field name="name">La Altagracia</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_12" model="res.country.state"> - <field name="code">12</field> + <field name="code">LR</field> <field name="name">La Romana</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_13" model="res.country.state"> - <field name="code">13</field> + <field name="code">LV</field> <field name="name">La Vega</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_14" model="res.country.state"> - <field name="code">14</field> - <field name="name">Maria Trinidad Sanchez</field> + <field name="code">MTS</field> + <field name="name">MarĂa Trinidad Sánchez</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_15" model="res.country.state"> - <field name="code">15</field> + <field name="code">MC</field> <field name="name">Monte Cristi</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_16" model="res.country.state"> - <field name="code">16</field> + <field name="code">PED</field> <field name="name">Pedernales</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_17" model="res.country.state"> - <field name="code">17</field> + <field name="code">PER</field> <field name="name">Peravia</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_18" model="res.country.state"> - <field name="code">18</field> + <field name="code">PP</field> <field name="name">Puerto Plata</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_19" model="res.country.state"> - <field name="code">19</field> + <field name="code">HEM</field> <field name="name">Hermanas Mirabal</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_20" model="res.country.state"> - <field name="code">20</field> - <field name="name">Samana</field> + <field name="code">SAM</field> + <field name="name">Samaná</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_21" model="res.country.state"> - <field name="code">21</field> - <field name="name">San Cristobal</field> + <field name="code">SC</field> + <field name="name">San CristĂłbal</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_22" model="res.country.state"> - <field name="code">22</field> - <field name="name">San Juan de la Maguana</field> + <field name="code">SJ</field> + <field name="name">San Juan</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_23" model="res.country.state"> - <field name="code">23</field> - <field name="name">San Pedro de Macoris</field> + <field name="code">SPM</field> + <field name="name">San Pedro de MacorĂs</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_24" model="res.country.state"> - <field name="code">24</field> - <field name="name">Sanchez Ramirez</field> + <field name="code">SRA</field> + <field name="name">Sánchez RamĂrez</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_25" model="res.country.state"> - <field name="code">25</field> + <field name="code">STGO</field> <field name="name">Santiago</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_26" model="res.country.state"> - <field name="code">26</field> - <field name="name">Santiago Rodriguez</field> + <field name="code">SRO</field> + <field name="name">Santiago RodrĂguez</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_27" model="res.country.state"> - <field name="code">27</field> + <field name="code">VAL</field> <field name="name">Valverde</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_28" model="res.country.state"> - <field name="code">28</field> + <field name="code">MON</field> <field name="name">Monseñor Nouel</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_29" model="res.country.state"> - <field name="code">29</field> + <field name="code">MP</field> <field name="name">Monte Plata</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_30" model="res.country.state"> - <field name="code">30</field> + <field name="code">HAM</field> <field name="name">Hato Mayor</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_31" model="res.country.state"> - <field name="code">31</field> - <field name="name">San Jose de Ocoa</field> + <field name="code">SJO</field> + <field name="name">San JosĂ© de Ocoa</field> <field name="country_id" ref="base.do"/> </record> <record id="state_DO_32" model="res.country.state"> - <field name="code">32</field> + <field name="code">SD</field> <field name="name">Santo Domingo</field> <field name="country_id" ref="base.do"/> </record> <!-- - Resource: res.partner.title - Update partner titles - --> + Resource: res.partner.title + Update partner titles + --> <record id="base.res_partner_title_dra" model="res.partner.title"> <field name="name">Doctora</field> <field name="shortcut">Dra.</field> @@ -192,4 +196,5 @@ <field name="name">Ingeniero/a</field> <field name="shortcut">Ing.</field> </record> + </data> </odoo> diff --git a/addons/l10n_do/models/__init__.py b/addons/l10n_do/models/__init__.py new file mode 100644 index 00000000000..88065f98bba --- /dev/null +++ b/addons/l10n_do/models/__init__.py @@ -0,0 +1,4 @@ +# coding: utf-8 +# Copyright 2016 iterativo (https://www.iterativo.do) <info@iterativo.do> + +from . import chart_template diff --git a/addons/l10n_do/models/chart_template.py b/addons/l10n_do/models/chart_template.py new file mode 100644 index 00000000000..ddbc17b8f92 --- /dev/null +++ b/addons/l10n_do/models/chart_template.py @@ -0,0 +1,18 @@ +# coding: utf-8 +# Copyright 2016 iterativo (https://www.iterativo.do) <info@iterativo.do> + +from openerp import models, api, _ + + +class WizardMultiChartsAccounts(models.TransientModel): + _inherit = 'wizard.multi.charts.accounts' + + @api.model + def _get_default_bank_account_ids(self): + if self.env.user.company_id.country_id and self.env.user.company_id.country_id.code.upper() == 'DO': + return [ + {'acc_name': _('Cash'), 'account_type': 'cash'}, + {'acc_name': _('Caja Chica'), 'account_type': 'cash'}, + {'acc_name': _('Bank'), 'account_type': 'bank'} + ] + return super(WizardMultiChartsAccounts, self)._get_default_bank_account_ids() diff --git a/addons/l10n_mx/models/chart_template.py b/addons/l10n_mx/models/chart_template.py index b02eafdaa69..155877b2761 100644 --- a/addons/l10n_mx/models/chart_template.py +++ b/addons/l10n_mx/models/chart_template.py @@ -66,14 +66,14 @@ class AccountChartTemplate(models.Model): acc_template_ref, company, journals_dict=journals_dict) if not self == self.env.ref('l10n_mx.mx_coa'): return res - account = self.env.ref('l10n_mx.1_cuenta118_01') + account = acc_template_ref.get(self.env.ref('l10n_mx.cuenta118_01').id) res.append({ 'type': 'general', 'name': _('Effectively Paid'), 'code': 'CBMX', 'company_id': company.id, - 'default_credit_account_id': account.id, - 'default_debit_account_id': account.id, + 'default_credit_account_id': account, + 'default_debit_account_id': account, 'show_on_dashboard': True, }) return res diff --git a/addons/mail/models/mail_mail.py b/addons/mail/models/mail_mail.py index 6fcae69b21b..ff25c60f04a 100644 --- a/addons/mail/models/mail_mail.py +++ b/addons/mail/models/mail_mail.py @@ -255,6 +255,10 @@ class MailMail(models.Model): for mail_id in self.ids: try: mail = self.browse(mail_id) + if mail.state != 'outgoing': + if mail.state != 'exception' and mail.auto_delete: + mail.sudo().unlink() + continue # TDE note: remove me when model_id field is present on mail.message - done here to avoid doing it multiple times in the sub method if mail.model: model = self.env['ir.model']._get(mail.model)[0] diff --git a/addons/mail/static/src/js/client_action.js b/addons/mail/static/src/js/client_action.js index 99c7567a069..2b3a1f242f5 100644 --- a/addons/mail/static/src/js/client_action.js +++ b/addons/mail/static/src/js/client_action.js @@ -563,7 +563,7 @@ var ChatAction = Widget.extend(ControlPanelMixin, { var self = this; var options = this.selected_message ? {} : {channel_id: this.channel.id}; if (this.selected_message) { - message.subtype = 'mail.mt_comment'; + message.subtype = this.selected_message.is_note ? 'mail.mt_note': 'mail.mt_comment'; message.subtype_id = false; message.message_type = 'comment'; message.content_subtype = 'html'; diff --git a/addons/mail/static/src/js/many2many_tags_email.js b/addons/mail/static/src/js/many2many_tags_email.js index bd3957cd5d3..5e7c0f4e8b2 100644 --- a/addons/mail/static/src/js/many2many_tags_email.js +++ b/addons/mail/static/src/js/many2many_tags_email.js @@ -5,6 +5,7 @@ var core = require('web.core'); var form_common = require('web.form_common'); var form_relational = require('web.form_relational'); var Model = require('web.DataModel'); +var utils = require('web.utils'); var _t = core._t; @@ -16,50 +17,48 @@ var _t = core._t; var FieldMany2ManyTagsEmail = form_relational.FieldMany2ManyTags.extend({ start: function() { - this.values = []; - this.values_checking = []; + this.mutex = new utils.Mutex(); - this.on("change:value", this, this.on_change_value_check); - this.trigger("change:value"); + // This widget will indirectly trigger a change:value to it's parent widget + // when setting the value of valid partners. For this reason we have to keep an + // internal state of the last value in order to compute the effective value changes. + this.last_processed_value = []; + this.on("change:value", this, this.on_change_value_check); this._super.apply(this, arguments); }, on_change_value_check : function () { - this.values = _.uniq(this.values); - - // filter for removed values - var values_removed = _.difference(this.values, this.get('value')); - if (values_removed.length) { - this.values = _.difference(this.values, values_removed); - this.set({'value': this.values}); - return false; - } + var self = this; + var values = this.get('value').slice(0); // Clone the array - // find not checked values that are not currently on checking - var not_checked = _.difference(this.get('value'), this.values, this.values_checking); - if (not_checked.length) { - // remember values on checking for cheked only one time - this.values_checking = this.values_checking.concat(not_checked); - // check values - this._check_email_popup(not_checked); + // We only validate partners emails in case the value is not empty + // and is different from the last processed value + var effective_change = _.difference(values, self.last_processed_value).length; + if (values.length && effective_change) { + this.mutex.exec(function() { + return self._check_email_popup(values); + }); } }, _check_email_popup: function (ids) { var self = this; - new Model('res.partner').call("search", [[ - ["id", "in", ids], + var valid_partners; + + return new Model('res.partner').call("search", [[ + ["id", "in", ids], ["email", "=", false] ]], {context: this.build_context()}) .then(function (record_ids) { - // valid partner - var valid_partner = _.difference(ids, record_ids); - self.values = self.values.concat(valid_partner); - self.values_checking = _.difference(self.values_checking, valid_partner); + var popups_deferreds = []; + self.valid_partners = _.difference(ids, record_ids); - // unvalid partner + // Propose the user to correct invalid partners _.each(record_ids, function (id) { + var popup_def = $.Deferred(); + popups_deferreds.push(popup_def); + var pop = new form_common.FormViewDialog(self, { res_model: 'res.partner', res_id: id, @@ -67,15 +66,19 @@ var FieldMany2ManyTagsEmail = form_relational.FieldMany2ManyTags.extend({ title: _t("Please complete partner's informations and Email"), }).open(); pop.on('write_completed', self, function () { - this.values.push(id); - this.values_checking = _.without(this.values_checking, id); - this.set({'value': this.values}); + self.valid_partners.push(id); }); pop.on('closed', self, function () { - this.values_checking = _.without(this.values_checking, id); - this.set({'value': this.values}); + popup_def.resolve(); }); }); + return $.when.apply($, popups_deferreds).then(function() { + // All popups have been processed for the given ids + // It is now time to set the final value with valid partners ids. + var filtered_value = _.uniq(self.valid_partners); + self.last_processed_value = filtered_value; + self.set({'value': filtered_value}); + }); }); }, }); diff --git a/addons/mail/views/mail_activity_views.xml b/addons/mail/views/mail_activity_views.xml index 388f64e1b16..74e9185a534 100644 --- a/addons/mail/views/mail_activity_views.xml +++ b/addons/mail/views/mail_activity_views.xml @@ -12,7 +12,7 @@ </div> <group> <group> - <field name="res_model_id"/> + <field name="res_model_id" groups="base.group_no_one"/> <field name="icon" groups="base.group_no_one"/> <field name="days"/> </group> diff --git a/addons/mail/views/res_config_views.xml b/addons/mail/views/res_config_views.xml index ea8ebacf725..732b7df0497 100644 --- a/addons/mail/views/res_config_views.xml +++ b/addons/mail/views/res_config_views.xml @@ -7,8 +7,22 @@ <field name="inherit_id" ref="base_setup.base_config_settings_view_form"/> <field name="arch" type="xml"> <div id="emails" position='replace'> - <h2>Emails</h2> + <h2>Discuss</h2> <div class="row mt16 o_settings_container" id="emails"> + <div class="col-xs-12 col-md-6 o_setting_box"> + <div class="o_setting_left_pane"/> + <div class="o_setting_right_pane"> + <label string="Activities"/> + <div class="text-muted"> + Configure your activity types + </div> + <div class="content-group"> + <div class="mt16"> + <button name="%(mail.mail_activity_type_action)d" string="Activity Types" type="action" class="oe_link" icon="fa-arrow-right"/> + </div> + </div> + </div> + </div> <div class="col-xs-12 col-md-6 o_setting_box" title="Using your own email server is required to send/receive emails in Community and Enterprise versions. Online users already benefit from a ready-to-use email server (@mycompany.odoo.com)."> <div class="o_setting_left_pane"> <field name="default_external_email_server"/> diff --git a/addons/mass_mailing/models/mass_mailing.py b/addons/mass_mailing/models/mass_mailing.py index 2673fcc8106..86ded7246b9 100644 --- a/addons/mass_mailing/models/mass_mailing.py +++ b/addons/mass_mailing/models/mass_mailing.py @@ -4,6 +4,7 @@ import hashlib import hmac from datetime import datetime +import logging import random from odoo import api, fields, models, tools, _ @@ -11,6 +12,7 @@ from odoo.exceptions import UserError from odoo.tools.safe_eval import safe_eval from odoo.tools.translate import html_translate +_logger = logging.getLogger(__name__) class MassMailingTag(models.Model): """Model of categories of mass mailing, i.e. marketing, newsletter, ... """ @@ -567,6 +569,69 @@ class MassMailing(models.Model): # Email Sending #------------------------------------------------------ + def _get_blacklist(self): + """Returns a set of emails opted-out in target model""" + # TODO: implement a global blacklist table, to easily share + # it and update it. + self.ensure_one() + blacklist = {} + target = self.env[self.mailing_model_real] + mail_field = 'email' if 'email' in target._fields else 'email_from' + if 'opt_out' in target._fields: + # avoid loading a large number of records in memory + # + use a basic heuristic for extracting emails + query = """ + SELECT lower(substring(%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)')) + FROM %(target)s + WHERE opt_out AND + substring(%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)') IS NOT NULL; + """ + query = query % {'target': target._table, 'mail_field': mail_field} + self._cr.execute(query) + blacklist = set(m[0] for m in self._cr.fetchall()) + _logger.info( + "Mass-mailing %s targets %s, blacklist: %s emails", + self, target._name, len(blacklist)) + else: + _logger.info("Mass-mailing %s targets %s, no blacklist available", self, target._name) + return blacklist + + def _get_seen_list(self): + """Returns a set of emails already targeted by current mailing/campaign (no duplicates)""" + self.ensure_one() + target = self.env[self.mailing_model_real] + mail_field = 'email' if 'email' in target._fields else 'email_from' + # avoid loading a large number of records in memory + # + use a basic heuristic for extracting emails + query = """ + SELECT lower(substring(%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)')) + FROM mail_mail_statistics s + JOIN %(target)s t ON (s.res_id = t.id) + WHERE substring(%(mail_field)s, '([^ ,;<@]+@[^> ,;]+)') IS NOT NULL + """ + if self.mass_mailing_campaign_id.unique_ab_testing: + query +=""" + AND s.mass_mailing_campaign_id = %%(mailing_campaign_id)s; + """ + else: + query +=""" + AND s.mass_mailing_id = %%(mailing_id)s; + """ + query = query % {'target': target._table, 'mail_field': mail_field} + params = {'mailing_id': self.id, 'mailing_campaign_id': self.mass_mailing_campaign_id.id} + self._cr.execute(query, params) + seen_list = set(m[0] for m in self._cr.fetchall()) + _logger.info( + "Mass-mailing %s has already reached %s %s emails", self, len(seen_list), target._name) + return seen_list + + def _get_mass_mailing_context(self): + """Returns extra context items with pre-filled blacklist and seen list for massmailing""" + return { + 'mass_mailing_blacklist': self._get_blacklist(), + 'mass_mailing_seen_list': self._get_seen_list(), + } + def get_recipients(self): if self.mailing_domain: domain = safe_eval(self.mailing_domain) @@ -625,7 +690,9 @@ class MassMailing(models.Model): composer_values['reply_to'] = mailing.reply_to composer = self.env['mail.compose.message'].with_context(active_ids=res_ids).create(composer_values) - composer.with_context(active_ids=res_ids).send_mail(auto_commit=True) + extra_context = self._get_mass_mailing_context() + composer = composer.with_context(active_ids=res_ids, **extra_context) + composer.send_mail(auto_commit=True) mailing.state = 'done' return True diff --git a/addons/mass_mailing/wizard/mail_compose_message.py b/addons/mass_mailing/wizard/mail_compose_message.py index 82566623d19..c8b1e54f316 100644 --- a/addons/mass_mailing/wizard/mail_compose_message.py +++ b/addons/mass_mailing/wizard/mail_compose_message.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, fields, models +from odoo import api, fields, models, tools class MailComposeMessage(models.TransientModel): @@ -40,14 +40,28 @@ class MailComposeMessage(models.TransientModel): 'mailing_model': self.model, 'mailing_domain': self.active_domain, }) + blacklist = self._context.get('mass_mailing_blacklist') + seen_list = self._context.get('mass_mailing_seen_list') for res_id in res_ids: - res[res_id].update({ + mail_values = res[res_id] + recips = tools.email_split(mail_values.get('email_to')) + mail_to = recips[0].lower() if recips else False + if (blacklist and mail_to in blacklist) or (seen_list and mail_to in seen_list): + # prevent sending to blocked addresses that were included by mistake + mail_values['state'] = 'cancel' + elif seen_list is not None: + seen_list.add(mail_to) + stat_vals = { + 'model': self.model, + 'res_id': res_id, + 'mass_mailing_id': mass_mailing.id + } + # propagate exception state to stat when still-born + if mail_values.get('state') == 'cancel': + stat_vals['exception'] = fields.Datetime.now() + mail_values.update({ 'mailing_id': mass_mailing.id, - 'statistics_ids': [(0, 0, { - 'model': self.model, - 'res_id': res_id, - 'mass_mailing_id': mass_mailing.id, - })], + 'statistics_ids': [(0, 0, stat_vals)], # email-mode: keep original message for routing 'notification': mass_mailing.reply_to_mode == 'thread', 'auto_delete': not mass_mailing.keep_archives, diff --git a/addons/mass_mailing/wizard/test_mailing.py b/addons/mass_mailing/wizard/test_mailing.py index 130827e1fe4..24b395c7c53 100644 --- a/addons/mass_mailing/wizard/test_mailing.py +++ b/addons/mass_mailing/wizard/test_mailing.py @@ -30,6 +30,7 @@ class TestMassMailing(models.TransientModel): 'notification': True, 'mailing_id': mailing.id, 'attachment_ids': [(4, attachment.id) for attachment in mailing.attachment_ids], + 'auto_delete': True, } mail = self.env['mail.mail'].create(mail_values) mails |= mail diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 03755965b3b..7d7e4beecb6 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -126,6 +126,9 @@ class MrpProduction(models.Model): ('none', 'None')], string='Availability', compute='_compute_availability', store=True) + unreserve_visible = fields.Boolean( + 'Inventory Unreserve Visible', compute='_compute_unreserve_visible', + help='Technical field to check when we can unreserve') post_visible = fields.Boolean( 'Inventory Post Visible', compute='_compute_post_visible', help='Technical field to check when we can post') @@ -193,6 +196,14 @@ class MrpProduction(models.Model): assigned_list = [x.state in ('assigned', 'done', 'cancel') for x in order.move_raw_ids] order.availability = (all(assigned_list) and 'assigned') or (any(partial_list) and 'partially_available') or 'waiting' + @api.depends('state', 'move_raw_ids.reserved_quant_ids') + def _compute_unreserve_visible(self): + for order in self: + if order.state in ['done', 'cancel'] or not order.move_raw_ids.mapped('reserved_quant_ids'): + order.unreserve_visible = False + else: + order.unreserve_visible = True + @api.multi @api.depends('move_raw_ids.quantity_done', 'move_finished_ids.quantity_done') def _compute_post_visible(self): diff --git a/addons/mrp/models/product.py b/addons/mrp/models/product.py index c3f457adb56..7ecc6274636 100644 --- a/addons/mrp/models/product.py +++ b/addons/mrp/models/product.py @@ -37,8 +37,15 @@ class ProductTemplate(models.Model): class ProductProduct(models.Model): _inherit = "product.product" + bom_count = fields.Integer('# Bill of Material', compute='_compute_bom_count') mo_count = fields.Integer('# Manufacturing Orders', compute='_compute_mo_count') + def _compute_bom_count(self): + read_group_res = self.env['mrp.bom'].read_group([('product_id', 'in', self.ids)], ['product_id'], ['product_id']) + mapped_data = dict([(data['product_id'][0], data['product_id_count']) for data in read_group_res]) + for product in self: + product.bom_count = mapped_data.get(product.id, 0) + def _compute_mo_count(self): read_group_res = self.env['mrp.production'].read_group([('product_id', 'in', self.ids)], ['product_id'], ['product_id']) mapped_data = dict([(data['product_id'][0], data['product_id_count']) for data in read_group_res]) diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py index a9066344b53..150f9cd562e 100644 --- a/addons/mrp/models/stock_move.py +++ b/addons/mrp/models/stock_move.py @@ -29,13 +29,15 @@ class StockMoveLots(models.Model): plus_visible = fields.Boolean("Plus Visible", compute='_compute_plus') @api.one - @api.constrains('lot_id') + @api.constrains('lot_id', 'quantity_done') def _check_lot_id(self): if self.move_id.product_id.tracking == 'serial': lots = set([]) for move_lot in self.move_id.move_lot_ids.filtered(lambda r: not r.lot_produced_id): if move_lot.lot_id in lots: raise exceptions.UserError(_('You cannot use the same serial number in two different lines.')) + if float_compare(move_lot.quantity_done, 1.0, precision_rounding=move_lot.product_id.uom_id.rounding) == 1: + raise exceptions.UserError(_('You can only produce 1.0 %s for products with unique serial number.') % move_lot.product_id.uom_id.name) lots.add(move_lot.lot_id) def _compute_plus(self): diff --git a/addons/mrp/security/ir.model.access.csv b/addons/mrp/security/ir.model.access.csv index 7a384a01b2e..47a7e677285 100644 --- a/addons/mrp/security/ir.model.access.csv +++ b/addons/mrp/security/ir.model.access.csv @@ -57,5 +57,6 @@ access_resource_calendar_manufacturinguser,resource.calendar manufacturing.user, access_mrp_unbuild,mrp.unbuild,model_mrp_unbuild,group_mrp_user,1,0,0,0 access_mrp_unbuild_manager,mrp.unbuild manager,model_mrp_unbuild,group_mrp_manager,1,1,1,1 access_mrp_message_mrp_user,mrp.message,model_mrp_message,group_mrp_user,1,0,0,0 +access_mrp_message_mrp_manager,mrp.message,model_mrp_message,group_mrp_manager,1,1,1,1 access_stock_move_lots,stock.move.lots,model_stock_move_lots,group_mrp_user,1,1,1,0 access_stock_move_lots_manager,stock.move.lots,model_stock_move_lots,group_mrp_manager,1,1,1,1 diff --git a/addons/mrp/views/mrp_production_views.xml b/addons/mrp/views/mrp_production_views.xml index 3d645e5136b..40a30df4bad 100644 --- a/addons/mrp/views/mrp_production_views.xml +++ b/addons/mrp/views/mrp_production_views.xml @@ -51,12 +51,13 @@ <button name="post_inventory" string="Post Inventory" type="object" attrs="{'invisible': [('post_visible', '=', False)]}"/> <button name="action_cancel" type="object" string="Cancel" attrs="{'invisible': ['|', ('state', 'in', ('done','cancel')), ('check_to_done', '=', True)]}"/> <button name="button_scrap" type="object" string="Scrap" attrs="{'invisible': ['|', ('availability', '=', 'none'), ('state', 'in', ('cancel'))]}"/> - <button name="button_unreserve" type="object" string="Unreserve" attrs="{'invisible': ['|', ('state', 'in', ['done', 'cancel']), ('availability', 'in', ['none', 'waiting'])]}"/> + <button name="button_unreserve" type="object" string="Unreserve" attrs="{'invisible': [('unreserve_visible', '=', False)]}"/> <span class="label label-danger" attrs="{'invisible': ['|', ('availability', 'in', ('assigned', 'none')), ('state', 'not in', ('confirmed','progress'))]}">Raw materials not available!</span> <field name="state" widget="statusbar" statusbar_visible="confirmed,progress,done"/> </header> <sheet> <field name="post_visible" invisible="1"/> + <field name="unreserve_visible" invisible="1"/> <div class="oe_button_box" name="button_box"> <button name="%(action_mrp_workorder_production_specific)d" type="action" attrs="{'invisible': [('workorder_count', '=', 0)]}" class="oe_stat_button" icon="fa-play-circle-o"> <div class="o_form_field o_stat_info"> @@ -265,7 +266,7 @@ <separator/> <filter string="No Routing" domain="[('routing_id','=', False)]" name="norouting" groups="mrp.group_mrp_routings"/> <field name="product_id"/> - <field name="product_id" string="Raw Material" filter_domain="[('move_raw_ids.product_id','ilike',self)]"/> + <field name="move_raw_ids" string="Raw Material" filter_domain="[('move_raw_ids.product_id','ilike',self)]"/> <field name="name" string="Work Center" filter_domain="[('routing_id.operation_ids.workcenter_id','ilike',self)]"/> <field name="routing_id" groups="mrp.group_mrp_routings"/> <separator/> diff --git a/addons/point_of_sale/models/pos_order.py b/addons/point_of_sale/models/pos_order.py index 85cd571c709..a72c87cef52 100644 --- a/addons/point_of_sale/models/pos_order.py +++ b/addons/point_of_sale/models/pos_order.py @@ -751,7 +751,7 @@ class PosOrder(models.Model): class PosOrderLine(models.Model): _name = "pos.order.line" - _description = "Lines of Point of Sale" + _description = "Lines of Point of Sale Orders" _rec_name = "product_id" def _order_line_fields(self, line, session_id=None): diff --git a/addons/point_of_sale/static/src/js/gui.js b/addons/point_of_sale/static/src/js/gui.js index 87cb30caf78..6107d3a979e 100644 --- a/addons/point_of_sale/static/src/js/gui.js +++ b/addons/point_of_sale/static/src/js/gui.js @@ -184,12 +184,22 @@ var Gui = core.Class.extend({ close_other_tabs: function() { var self = this; + // avoid closing itself + var now = Date.now(); + localStorage['message'] = ''; localStorage['message'] = JSON.stringify({ 'message':'close_tabs', 'session': this.pos.pos_session.id, + 'window_uid': now, }); + // storage events are (most of the time) triggered only when the + // localstorage is updated in a different tab. + // some browsers (e.g. IE) does trigger an event in the same tab + // This may be a browser bug or a different interpretation of the HTML spec + // cf https://connect.microsoft.com/IE/feedback/details/774798/localstorage-event-fired-in-source-window + // Use window_uid parameter to exclude the current window window.addEventListener("storage", function(event) { var msg = event.data; @@ -197,7 +207,8 @@ var Gui = core.Class.extend({ var msg = JSON.parse(event.newValue); if ( msg.message === 'close_tabs' && - msg.session == self.pos.pos_session.id ) { + msg.session == self.pos.pos_session.id && + msg.window_uid != now) { console.info('POS / Session opened in another window. EXITING POS') self._close(); diff --git a/addons/point_of_sale/tools/posbox/configuration/setup_ramdisks.sh b/addons/point_of_sale/tools/posbox/configuration/setup_ramdisks.sh index ce2f2e633e6..618c4b1fd48 100755 --- a/addons/point_of_sale/tools/posbox/configuration/setup_ramdisks.sh +++ b/addons/point_of_sale/tools/posbox/configuration/setup_ramdisks.sh @@ -11,7 +11,7 @@ create_ramdisk () { echo "Creating ramdisk for ${1} of size ${SIZE}..." mount -t tmpfs -o size="${SIZE}" tmpfs "${RAMDISK}" - rsync -a --exclude="swap" --exclude="apt" --exclude="dpkg" "${ORIGINAL}/" "${RAMDISK}/" + rsync -a --exclude="swap" --exclude="apt" --exclude="dpkg" --exclude=".mozilla" "${ORIGINAL}/" "${RAMDISK}/" mount --bind "${RAMDISK}" "${ORIGINAL}" } diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/lightdm/lightdm.conf b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/lightdm/lightdm.conf new file mode 100644 index 00000000000..977903c1c90 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/lightdm/lightdm.conf @@ -0,0 +1,8 @@ + +[LightDM] +user-authority-in-system-dir=true + +[SeatDefaults] +xserver-command=/usr/bin/X -s 0 dpms -nolisten tcp +greeter-hide-users=false +autologin-user=pi
\ No newline at end of file diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart new file mode 100755 index 00000000000..e2b61e2f591 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/etc/xdg/openbox/autostart @@ -0,0 +1,6 @@ +#!/bin/bash +xset s off +xset -dpms + +export HOME=/tmp +/usr/bin/firefox http://localhost:8069/point_of_sale/display & diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/manifest.mf b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/manifest.mf new file mode 100644 index 00000000000..63a9098e00d --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/manifest.mf @@ -0,0 +1,32 @@ +Manifest-Version: 1.0 + +Name: install.rdf +Digest-Algorithms: MD5 SHA1 +MD5-Digest: xnFKNbJgc33dy/FJ+4cmHA== +SHA1-Digest: 4YLgHgdgCw4lGCfsX7+r4zVmKJ4= + +Name: chrome.manifest +Digest-Algorithms: MD5 SHA1 +MD5-Digest: O5ce4bajAqUxG6iVul0K2w== +SHA1-Digest: wb6VleWnV5GgLypmg1ij9TfmPLE= + +Name: content/rkioskbrowser.js +Digest-Algorithms: MD5 SHA1 +MD5-Digest: /cF15tfVnbkfbxRVTL5N+g== +SHA1-Digest: lvbY92PbsjwY+0TguEYoXWw0lxQ= + +Name: content/rkioskbrowser.xul +Digest-Algorithms: MD5 SHA1 +MD5-Digest: NFOIpAmZtn20Y+XfTo4cpw== +SHA1-Digest: VVIo7GdG+4mvAOtgR0DJUsSc/yg= + +Name: content/rkioskunknownContentType.xul +Digest-Algorithms: MD5 SHA1 +MD5-Digest: 6cNGoHJS9Xvm+wmvo4IesQ== +SHA1-Digest: T8i1MkMKjmn5HICqWv+iXSPRKIU= + +Name: content/rkioskxpinstallConfirm.xul +Digest-Algorithms: MD5 SHA1 +MD5-Digest: SxN1YnRJiuood2WhU85v9g== +SHA1-Digest: Msj21u4bTAKUi496xld5YCGdjiA= + diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.rsa b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.rsa Binary files differnew file mode 100644 index 00000000000..521b08d182a --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.rsa diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.sf b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.sf new file mode 100644 index 00000000000..37eae3e21fb --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/META-INF/mozilla.sf @@ -0,0 +1,4 @@ +Signature-Version: 1.0 +MD5-Digest-Manifest: 7hFyhNW67+H+rf9OhWGDkA== +SHA1-Digest-Manifest: HvfAQQLXphSZ9m8KBorJMX8MUnE= + diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/README b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/README new file mode 100644 index 00000000000..c8c1ce58823 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/README @@ -0,0 +1,3 @@ +The R-kiosk module has been downloaded from https://addons.mozilla.org/en-US/firefox/addon/r-kiosk/ +It is in the public domain as stated on https://addons.mozilla.org/en-US/firefox/addon/r-kiosk/eula/ +This mozilla module is shipped by Odoo to provide out of the box Client facing display to Odoo's Posbox
\ No newline at end of file diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/chrome.manifest b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/chrome.manifest new file mode 100644 index 00000000000..e4957b8d5e8 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/chrome.manifest @@ -0,0 +1,4 @@ +content RKiosk content/
+overlay chrome://browser/content/browser.xul chrome://rkiosk/content/rkioskbrowser.xul
+overlay chrome://mozapps/content/xpinstall/xpinstallConfirm.xul chrome://rkiosk/content/rkioskxpinstallConfirm.xul
+overlay chrome://mozapps/content/downloads/unknownContentType.xul chrome://rkiosk/content/rkioskunknownContentType.xul
diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.js b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.js new file mode 100644 index 00000000000..5ece9a9e06b --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.js @@ -0,0 +1,34 @@ +function Rkiosk_donothing()
+{
+
+
+}
+
+function rkioskclose()
+{
+ close();
+}
+
+function Rkiosk_navbar_setting()
+{
+ var rkiosk_navbar_enable="true";
+ var prefs = Components.classes["@mozilla.org/preferences-service;1"].
+ getService(Components.interfaces.nsIPrefBranch);
+ if (prefs.getPrefType("rkiosk.navbar") == prefs.PREF_BOOL){
+ if (prefs.getBoolPref("rkiosk.navbar")) rkiosk_navbar_enable = "false";
+ }
+ var rkiosk_element = document.getElementById("navigator-toolbox");
+ rkiosk_element.setAttribute("hidden", rkiosk_navbar_enable);
+}
+
+function RkioskBrowserStartup()
+{
+ Rkiosk_navbar_setting();
+ BrowserStartup();
+ setTimeout(RkioskdelayedStartup, 1000);
+}
+
+function RkioskdelayedStartup()
+{
+ window.fullScreen = true;
+}
diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.xul b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.xul new file mode 100644 index 00000000000..d5fb0c140d1 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskbrowser.xul @@ -0,0 +1,175 @@ +<?xml version="1.0"?>
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+<window id="main-window"
+ onload="RkioskBrowserStartup()">
+</window>
+
+<script type="application/x-javascript" src="rkioskbrowser.js"/>
+
+ <menubar id="main-menubar" hidden="true" fullscreentoolbar="false" disabled="true">
+ <menuitem id="menu_preferences" disabled="true"/>
+ </menubar>
+
+ <popup id="contentAreaContextMenu"
+ onpopupshowing="if (event.target != this) return true; return false;"
+ onpopuphiding="if (event.target == this) gContextMenu = null;">
+ </popup>
+
+ <commandset id="mainCommandSet">
+ <command id="cmd_newNavigator" disabled="true"/>
+ <command id="cmd_handleBackspace" disabled="true"/>
+ <command id="cmd_handleShiftBackspace" disabled="true"/>
+ <command id="cmd_newNavigatorTab" disabled="true"/>
+ <command id="Browser:OpenFile" disabled="true"/>
+ <command id="Browser:SavePage" disabled="true"/>
+ <command id="Browser:SaveFrame" disabled="true"/>
+ <command id="Browser:SendLink" disabled="true"/>
+ <command id="cmd_pageSetup" disabled="true"/>
+ <command id="cmd_print" oncommand="PrintUtils.print();"/>
+ <command id="cmd_printPreview" disabled="true"/>
+ <command id="cmd_close" disabled="true"/>
+ <command id="cmd_closeWindow" disabled="true"/>
+ <command id="cmd_ToggleTabsOnTop" disabled="true"/>
+ <command id="cmd_quitApplication" disabled="true"/>
+ <command id="cmd_toggleTaskbar" disabled="true"/>
+ <command id="cmd_CustomizeToolbars" disabled="true"/>
+ <commandset id="editMenuCommands"/>
+ <command id="View:PageSource" disabled="true"/>
+ <command id="View:PageInfo" disabled="true"/>
+ <command id="View:FullScreen" disabled="true"/>
+ <command id="cmd_find" disabled="true"/>
+ <command id="cmd_findAgain" disabled="true"/>
+ <command id="cmd_findPrevious" disabled="true"/>
+ <command id="Browser:AddBookmarkAs" disabled="true"/>
+ <command id="Browser:BookmarkAllTabs" disabled="true"/>
+ <command id="Browser:Home" oncommand="BrowserHome();"/>
+ <command id="Browser:Back" disabled="true"/>
+ <command id="Browser:Forward" disabled="true"/>
+ <command id="Browser:Stop" disabled="true"/>
+ <command id="Browser:Reload" disabled="true"/>
+ <command id="Browser:ReloadSkipCache" disabled="true"/>
+ <command id="Browser:BackOrBackDuplicate" disabled="true"/>
+ <command id="Browser:Forward" disabled="true"/>
+ <command id="Browser:ForwardOrForwardDuplicate" disabled="true"/>
+ <command id="Browser:ReloadOrDuplicate" disabled="true"/>
+ <command id="Browser:NextTab" disabled="true"/>
+ <command id="Browser:PrevTab" disabled="true"/>
+ <command id="Browser:ShowAllTabs" disabled="true"/>
+ <command id="Browser:ToggleTabView" disabled="true"/>
+ <command id="Browser:ToggleAddonBar" disabled="true"/>
+ <command id="cmd_fullZoomReduce" disabled="true"/>
+ <command id="cmd_fullZoomEnlarge" disabled="true"/>
+ <command id="cmd_fullZoomReset" disabled="true"/>
+ <command id="cmd_fullZoomToggle" disabled="true"/>
+ <command id="Browser:OpenLocation" disabled="true"/>
+ <command id="Tools:Search" disabled="true"/>
+ <command id="Tools:Downloads" disabled="true"/>
+ <command id="Tools:Addons" disabled="true"/>
+ <command id="Tools:Sanitize" disabled="true"/>
+ <command id="Tools:Inspect" disabled="true"/>
+ <command id="Tools:PrivateBrowsing" disabled="true"/>
+ <command id="History:UndoCloseTab" disabled="true"/>
+ <command id="History:UndoCloseWindow" disabled="true"/>
+ <command id="cmd_bm_open" disabled="true"/>
+ <command id="cmd_bm_openinnewwindow" disabled="true"/>
+ <command id="cmd_bm_openinnewtab" disabled="true"/>
+ <command id="cmd_bm_openfolder" disabled="true"/>
+ <command id="cmd_bm_managefolder" disabled="true"/>
+ <command id="cmd_bm_newfolder" disabled="true"/>
+ <command id="cmd_bm_newbookmark" disabled="true"/>
+ <command id="cmd_bm_newseparator" disabled="true"/>
+ <command id="cmd_bm_properties" disabled="true"/>
+ <command id="cmd_bm_refreshlivemark" disabled="true"/>
+ <command id="cmd_bm_refreshmicrosummary" disabled="true"/>
+ <command id="cmd_bm_rename" disabled="true"/>
+ <command id="cmd_bm_moveBookmark" disabled="true"/>
+ <command id="cmd_bm_sortbyname" disabled="true"/>
+ <command id="cmd_copyLink" disabled="true"/>
+ <command id="cmd_copyImageLocation" disabled="true"/>
+ <command id="cmd_copyImageContents" disabled="true"/>
+ <command id="cmd_undo" disabled="true"/>
+ <command id="cmd_redo" disabled="true"/>
+ <command id="cmd_cut" disabled="true"/>
+ <command id="cmd_copy" disabled="true"/>
+ <command id="cmd_paste" disabled="true"/>
+ <command id="cmd_delete" disabled="true"/>
+ <command id="cmd_selectAll" disabled="true"/>
+ <command id="cmd_switchTextDirection" disabled="true"/>
+ <command id="cmd_textZoomReduce" disabled="true"/>
+ <command id="cmd_textZoomEnlarge" disabled="true"/>
+ <command id="cmd_textZoomReset" disabled="true"/>
+ </commandset>
+ <commandset id="placesCommands">
+ <command id="Browser:ShowAllBookmarks" disabled="true"/>
+ <command id="Browser:ShowAllHistory" disabled="true"/>
+ </commandset>
+
+ <keyset id="mainKeyset">
+ <key id="rkiosk_f1" keycode="VK_F1" oncommand="Rkiosk_donothing();"/>
+ <key id="key_newNavigator" disabled="true"/>
+ <key id="key_newNavigatorTab" disabled="true"/>
+ <key id="focusURLBar" disabled="true"/>
+ <key id="focusURLBar2" disabled="true"/>
+ <key id="key_search" disabled="true"/>
+ <key id="key_search2" disabled="true"/>
+ <key id="key_openDownloads" disabled="true"/>
+ <key id="openFileKb" disabled="true"/>
+ <key id="key_savePage" disabled="true"/>
+ <key id="printKb" disabled="true"/>
+ <key id="key_close" disabled="true"/>
+ <key id="key_closeWindow" disabled="true"/>
+ <key id="key_undo" disabled="true"/>
+ <key id="key_redo" disabled="true"/>
+ <key id="key_cut" disabled="true"/>
+ <key id="key_copy" disabled="true"/>
+ <key id="key_paste" disabled="true"/>
+ <key id="key_delete" disabled="true"/>
+ <key id="key_selectAll" disabled="true"/>
+ <key id="goBackKb" disabled="true"/>
+ <key id="goForwardKb" disabled="true"/>
+ <key id="goHome" keycode="VK_HOME" command="Browser:Home" modifiers="alt"/>
+ <key id="key_viewSource" disabled="true"/>
+ <key id="key_find" disabled="true"/>
+ <key id="key_findAgain" disabled="true"/>
+ <key id="key_findPrevious" disabled="true"/>
+ <key id="addBookmarkAsKb" disabled="true"/>
+ <key id="bookmarkAllTabsKb" disabled="true"/>
+ <key id="key_stop" disabled="true"/>
+ <key id="key_gotoHistory" command="Rkiosk_donothing();"/>
+ <key id="key_switchTextDirection" disabled="true"/>
+ <key id="key_sanitize" disabled="true"/>
+ <key id="key_undoCloseTab" disabled="true"/>
+ <key id="viewBookmarksSidebarKb" command="Rkiosk_donothing();"/>
+ <key id="viewBookmarksSidebarWinKb" command="Rkiosk_donothing();"/>
+ <key id="key_fullScreen" disabled="true"/>
+ <key id="key_textZoomReduce" disabled="true"/>
+ <key id="key_textZoomEnlarge" disabled="true"/>
+ <key id="key_textZoomReset" disabled="true"/>
+ <key id="showAllHistoryKb" disabled="true"/>
+ <key id="key_errorConsole" disabled="true"/>
+ <key id="manBookmarkKb" disabled="true"/>
+ <key id="key_fullZoomReduce" disabled="true"/>
+ <key id="key_fullZoomEnlarge" disabled="true"/>
+ <key id="key_fullZoomReset" disabled="true"/>
+ <key id="key_openAddons" disabled="true"/>
+ <key id="key_webConsole" disabled="true"/>
+ <key id="key_inspect" disabled="true"/>
+ <key id="key_scratchpad" disabled="true"/>
+ <key id="key_showAllTabs" disabled="true"/>
+ <key id="key_tabview" disabled="true"/>
+ <key id="key_privatebrowsing" disabled="true"/>
+ <key id="key_undoCloseWindow" disabled="true"/>
+ <key id="key_selectTab1" disabled="true"/>
+ <key id="key_selectTab2" disabled="true"/>
+ <key id="key_selectTab3" disabled="true"/>
+ <key id="key_selectTab4" disabled="true"/>
+ <key id="key_selectTab5" disabled="true"/>
+ <key id="key_selectTab6" disabled="true"/>
+ <key id="key_selectTab7" disabled="true"/>
+ <key id="key_selectTab8" disabled="true"/>
+ <key id="key_selectLastTab" disabled="true"/>
+ <key id="key_toggleAddonBar" disabled="true"/>
+ </keyset>
+</overlay>
\ No newline at end of file diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskunknownContentType.xul b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskunknownContentType.xul new file mode 100644 index 00000000000..faf2381d1fa --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskunknownContentType.xul @@ -0,0 +1,9 @@ +<?xml version="1.0"?>
+
+<overlay>
+ <dialog id="unknownContentType"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="rkioskclose();">
+ <script src="rkioskbrowser.js"/>
+ </dialog>
+</overlay>
diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskxpinstallConfirm.xul b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskxpinstallConfirm.xul new file mode 100644 index 00000000000..b96deadeee6 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/content/rkioskxpinstallConfirm.xul @@ -0,0 +1,9 @@ +<?xml version="1.0"?>
+
+<overlay>
+ <dialog id="xpinstallConfirm"
+ xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+ onload="rkioskclose();">
+ <script src="rkioskbrowser.js"/>
+ </dialog>
+</overlay>
diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/install.rdf b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/install.rdf new file mode 100644 index 00000000000..5be400e52e8 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/lib/firefox-esr/browser/extensions/{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}/install.rdf @@ -0,0 +1,19 @@ +<?xml version='1.0' encoding='utf-8'?> +<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:em="http://www.mozilla.org/2004/em-rdf#"> + + <Description about="urn:mozilla:install-manifest"> + + <em:id>{4D498D0A-05AD-4fdb-97B5-8A0AABC1FC5B}</em:id> + <em:name>R-kiosk</em:name> + <em:version>0.9.0.1-signed.1-signed</em:version> + <em:description>RKiosk (Real Kiosk), fullscreen kiosk mode: all menus, keys etc. disabled</em:description> + <em:creator>Kimmo Heinaaro</em:creator> + <em:targetApplication> + <Description> + <em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id> + <em:minVersion>2.0</em:minVersion> + <em:maxVersion>6.*</em:maxVersion> + </Description> + </em:targetApplication> + </Description> +</RDF>
\ No newline at end of file diff --git a/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/share/firefox-esr/browser/defaults/preferences/all-posbox.js b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/share/firefox-esr/browser/defaults/preferences/all-posbox.js new file mode 100644 index 00000000000..8de5d5d60a4 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_after_init/usr/share/firefox-esr/browser/defaults/preferences/all-posbox.js @@ -0,0 +1,7 @@ +// Preferences to allow unattended install of R-Kiosk extension +// Needed for Odoo posbox Client display +pref("app.update.checkInstallTime", false); +pref("devtools.webide.widget.autoinstall", false); +pref("xpinstall.customConfirmationUI", false); +pref("xpinstall.signatures.required", false); +pref("browser.shell.checkDefaultBrowser",false) diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo index 30be4bd26d3..4ab50a456a1 100755 --- a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo +++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init.d/odoo @@ -26,7 +26,7 @@ test -x $DAEMON || exit 0 set -e function _start() { - start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$USER --background --make-pidfile --exec $DAEMON -- --config $CONFIG --logfile $LOGFILE --load=web,hw_proxy,hw_posbox_homepage,hw_posbox_upgrade,hw_scale,hw_scanner,hw_escpos,hw_blackbox_be + start-stop-daemon --start --quiet --pidfile $PIDFILE --chuid $USER:$USER --background --make-pidfile --exec $DAEMON -- --config $CONFIG --logfile $LOGFILE --load=web,hw_proxy,hw_posbox_homepage,hw_posbox_upgrade,hw_scale,hw_scanner,hw_escpos,hw_blackbox_be,hw_screen } function _stop() { diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh index a05dfc897ae..00058bef68c 100755 --- a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh +++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/init_posbox_image.sh @@ -8,17 +8,25 @@ __dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" __file="${__dir}/$(basename "${BASH_SOURCE[0]}")" __base="$(basename ${__file} .sh)" +# Since we are emulating, the real /boot is not mounted, +# leading to mismatch between kernel image and modules. +mount /dev/sda1 /boot + # Recommends: antiword, graphviz, ghostscript, postgresql, python-gevent, poppler-utils export DEBIAN_FRONTEND=noninteractive +echo "nameserver 8.8.8.8" >> /etc/resolv.conf -mount /dev/sda1 /boot apt-get update apt-get -y dist-upgrade +# Do not be too fast to upgrade to more recent firmware and kernel than 4.38 +# Firmware 4.44 seems to prevent the LED mechanism from working -PKGS_TO_INSTALL="adduser postgresql-client python python-dateutil python-decorator python-docutils python-feedparser python-imaging python-jinja2 python-ldap python-libxslt1 python-lxml python-mako python-mock python-openid python-passlib python-psutil python-psycopg2 python-pybabel python-pychart python-pydot python-pyparsing python-pypdf python-reportlab python-requests python-tz python-vatnumber python-vobject python-werkzeug python-xlwt python-yaml postgresql python-gevent python-serial python-pip python-dev localepurge vim mc mg screen iw hostapd isc-dhcp-server git rsync console-data" +PKGS_TO_INSTALL="adduser postgresql-client python python-dateutil python-decorator python-docutils python-feedparser python-imaging python-jinja2 python-ldap python-libxslt1 python-lxml python-mako python-mock python-openid python-passlib python-psutil python-psycopg2 python-pybabel python-pychart python-pydot python-pyparsing python-pypdf python-reportlab python-requests python-tz python-vatnumber python-vobject python-werkzeug python-xlwt python-yaml postgresql python-gevent python-serial python-pip python-dev localepurge vim mc mg screen iw hostapd isc-dhcp-server git rsync console-data lightdm xserver-xorg-video-fbdev xserver-xorg-input-evdev iceweasel xdotool unclutter x11-utils openbox python-netifaces rpi-update" -apt-get -y install ${PKGS_TO_INSTALL} +# KEEP OWN CONFIG FILES DURING PACKAGE CONFIGURATION +# http://serverfault.com/questions/259226/automatically-keep-current-version-of-config-files-when-apt-get-install +apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" --force-yes install ${PKGS_TO_INSTALL} apt-get clean localepurge @@ -32,13 +40,20 @@ pip install pyusb==1.0.0b1 pip install qrcode pip install evdev +# --upgrade because websocket_client in wheezy is bad: +# https://github.com/docker/compose/issues/1288 +pip install --upgrade websocket_client + groupadd usbusers usermod -a -G usbusers pi usermod -a -G lp pi +usermod -a -G input lightdm sudo -u postgres createuser -s pi mkdir /var/log/odoo chown pi:pi /var/log/odoo +chown pi:pi -R /home/pi/odoo/ +chmod 770 -R /home/pi/odoo/ # logrotate is very picky when it comes to file permissions chown -R root:root /etc/logrotate.d/ @@ -54,6 +69,31 @@ update-rc.d -f isc-dhcp-server remove systemctl daemon-reload systemctl enable ramdisks.service systemctl disable dphys-swapfile.service +systemctl enable ssh + +# USER PI AUTO LOGIN (from nano raspi-config) +# We take the whole algorithm from raspi-config in order to stay compatible with raspbian infrastructure +if command -v systemctl > /dev/null && systemctl | grep -q '\-\.mount'; then + SYSTEMD=1 +elif [ -f /etc/init.d/cron ] && [ ! -h /etc/init.d/cron ]; then + SYSTEMD=0 +else + echo "Unrecognised init system" + return 1 +fi +if [ $SYSTEMD -eq 1 ]; then + systemctl set-default graphical.target + ln -fs /etc/systemd/system/autologin@.service /etc/systemd/system/getty.target.wants/getty@tty1.service +else + update-rc.d lightdm enable 2 +fi + +# disable overscan in /boot/config.txt, we can't use +# overwrite_after_init because it's on a different device +# (/dev/mmcblk0p1) and we don't mount that afterwards. +# This option disables any black strips around the screen +# cf: https://www.raspberrypi.org/documentation/configuration/raspi-config.md +echo "disable_overscan=1" >> /boot/config.txt # https://www.raspberrypi.org/forums/viewtopic.php?p=79249 # to not have "setting up console font and keymap" during boot take ages @@ -68,5 +108,6 @@ create_ramdisk_dir "/var" create_ramdisk_dir "/etc" create_ramdisk_dir "/tmp" mkdir /root_bypass_ramdisks +umount /dev/sda1 reboot diff --git a/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/udev/rules.d/99-z-input.rules b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/udev/rules.d/99-z-input.rules new file mode 100644 index 00000000000..aab19f2d1c7 --- /dev/null +++ b/addons/point_of_sale/tools/posbox/overwrite_before_init/etc/udev/rules.d/99-z-input.rules @@ -0,0 +1,2 @@ +SUBSYSTEM=="input", GROUP="input", MODE="0660" +KERNEL=="tty[0-9]*", GROUP="tty", MODE="0660"
\ No newline at end of file diff --git a/addons/point_of_sale/tools/posbox/posbox_create_image.sh b/addons/point_of_sale/tools/posbox/posbox_create_image.sh index 1e4c9d1277c..a9ec8bc102d 100755 --- a/addons/point_of_sale/tools/posbox/posbox_create_image.sh +++ b/addons/point_of_sale/tools/posbox/posbox_create_image.sh @@ -36,20 +36,25 @@ fi cp -a *raspbian*.img posbox.img CLONE_DIR="${OVERWRITE_FILES_BEFORE_INIT_DIR}/home/pi/odoo" + rm -rf "${CLONE_DIR}" -mkdir "${CLONE_DIR}" -git clone -b 8.0 --no-checkout --depth 1 https://github.com/odoo/odoo.git "${CLONE_DIR}" -cd "${CLONE_DIR}" -git config core.sparsecheckout true -echo "addons/web + +if [ ! -d $CLONE_DIR ]; then + echo "Clone Github repo" + mkdir -p "${CLONE_DIR}" + git clone -b 8.0 --no-local --no-checkout --depth 1 https://github.com/odoo/odoo.git "${CLONE_DIR}" + cd "${CLONE_DIR}" + git config core.sparsecheckout true + echo "addons/web addons/web_kanban addons/hw_* addons/point_of_sale/tools/posbox/configuration openerp/ odoo.py" | tee --append .git/info/sparse-checkout > /dev/null -git read-tree -mu HEAD -cd "${__dir}" + git read-tree -mu HEAD +fi +cd "${__dir}" USR_BIN="${OVERWRITE_FILES_BEFORE_INIT_DIR}/usr/bin/" mkdir -p "${USR_BIN}" cd "/tmp" @@ -60,9 +65,11 @@ cd "${__dir}" mv /tmp/ngrok "${USR_BIN}" # zero pad the image to be around 3.5 GiB, by default the image is only ~1.3 GiB +echo "Enlarging the image..." dd if=/dev/zero bs=1M count=2048 >> posbox.img # resize partition table +echo "Fdisking" START_OF_ROOT_PARTITION=$(fdisk -l posbox.img | tail -n 1 | awk '{print $2}') (echo 'p'; # print echo 'd'; # delete @@ -75,7 +82,7 @@ START_OF_ROOT_PARTITION=$(fdisk -l posbox.img | tail -n 1 | awk '{print $2}') echo 'p'; # print echo 'w') | fdisk posbox.img # write and quit -LOOP_MAPPER_PATH=$(kpartx -av posbox.img | tail -n 1 | cut -d ' ' -f 3) +LOOP_MAPPER_PATH=$(kpartx -avs posbox.img | tail -n 1 | cut -d ' ' -f 3) LOOP_MAPPER_PATH="/dev/mapper/${LOOP_MAPPER_PATH}" sleep 5 diff --git a/addons/product/models/product.py b/addons/product/models/product.py index a14a60c46a3..bc1d0837fde 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -48,7 +48,7 @@ class ProductCategory(models.Model): def get_names(cat): """ Return the list [cat.name, cat.parent_id.name, ...] """ res = [] - while cat: + while cat and cat.id: res.append(cat.name) cat = cat.parent_id return res diff --git a/addons/project/views/project_views.xml b/addons/project/views/project_views.xml index 08f3b80c8c7..eeba7d224cc 100644 --- a/addons/project/views/project_views.xml +++ b/addons/project/views/project_views.xml @@ -631,6 +631,18 @@ action = model.activate_sample_project() action="project_task_action_activity" sequence="25"/> + <!-- Activity types config --> + <record id="mail_activity_type_action_config_project_types" model="ir.actions.act_window"> + <field name="name">Activity Types</field> + <field name="res_model">mail.activity.type</field> + <field name="view_type">form</field> + <field name="view_mode">tree,form</field> + <field name="domain">['|', ('res_model_id', '=', False), ('res_model_id.model', '=', 'project.task')]</field> + </record> + <menuitem id="project_menu_config_activity_type" + action="mail_activity_type_action_config_project_types" + parent="menu_project_config"/> + <record id="action_view_task_overpassed_draft" model="ir.actions.act_window"> <field name="name">Overpassed Tasks</field> <field name="res_model">project.task</field> diff --git a/addons/project_issue/views/project_issue_views.xml b/addons/project_issue/views/project_issue_views.xml index 5eb5e5b7170..78e04595e22 100644 --- a/addons/project_issue/views/project_issue_views.xml +++ b/addons/project_issue/views/project_issue_views.xml @@ -372,4 +372,8 @@ parent="project.menu_project_management" action="project_issue_action_activity" sequence="25"/> + + <record id="project.mail_activity_type_action_config_project_types" model="ir.actions.act_window"> + <field name="domain">['|', ('res_model_id', '=', False), ('res_model_id.model', 'in', ['project.task', 'project.issue'])]</field> + </record> </odoo> diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index d440841e918..87559c4913c 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -42,7 +42,7 @@ class PurchaseOrder(models.Model): if min_date: order.date_planned = min_date - @api.depends('state', 'order_line.qty_invoiced', 'order_line.product_qty') + @api.depends('state', 'order_line.qty_invoiced', 'order_line.qty_received', 'order_line.product_qty') def _get_invoiced(self): precision = self.env['decimal.precision'].precision_get('Product Unit of Measure') for order in self: @@ -50,9 +50,9 @@ class PurchaseOrder(models.Model): order.invoice_status = 'no' continue - if any(float_compare(line.qty_invoiced, line.product_qty, precision_digits=precision) == -1 for line in order.order_line): + if any(float_compare(line.qty_invoiced, line.product_qty if line.product_id.purchase_method == 'purchase' else line.qty_received, precision_digits=precision) == -1 for line in order.order_line): order.invoice_status = 'to invoice' - elif all(float_compare(line.qty_invoiced, line.product_qty, precision_digits=precision) >= 0 for line in order.order_line): + elif all(float_compare(line.qty_invoiced, line.product_qty if line.product_id.purchase_method == 'purchase' else line.qty_received, precision_digits=precision) >= 0 for line in order.order_line): order.invoice_status = 'invoiced' else: order.invoice_status = 'no' @@ -524,7 +524,10 @@ class PurchaseOrderLine(models.Model): qty = 0.0 for inv_line in line.invoice_lines: if inv_line.invoice_id.state not in ['cancel']: - qty += inv_line.uom_id._compute_quantity(inv_line.quantity, line.product_uom) + if inv_line.invoice_id.type == 'in_invoice': + qty += inv_line.uom_id._compute_quantity(inv_line.quantity, line.product_uom) + elif inv_line.invoice_id.type == 'in_refund': + qty -= inv_line.uom_id._compute_quantity(inv_line.quantity, line.product_uom) line.qty_invoiced = qty @api.depends('order_id.state', 'move_ids.state') @@ -582,8 +585,8 @@ class PurchaseOrderLine(models.Model): invoice_lines = fields.One2many('account.invoice.line', 'purchase_line_id', string="Bill Lines", readonly=True, copy=False) # Replace by invoiced Qty - qty_invoiced = fields.Float(compute='_compute_qty_invoiced', string="Billed Qty", store=True) - qty_received = fields.Float(compute='_compute_qty_received', string="Received Qty", store=True) + qty_invoiced = fields.Float(compute='_compute_qty_invoiced', string="Billed Qty", digits=dp.get_precision('Product Unit of Measure'), store=True) + qty_received = fields.Float(compute='_compute_qty_received', string="Received Qty", digits=dp.get_precision('Product Unit of Measure'), store=True) partner_id = fields.Many2one('res.partner', related='order_id.partner_id', string='Partner', readonly=True, store=True) currency_id = fields.Many2one(related='order_id.currency_id', store=True, string='Currency', readonly=True) @@ -1050,7 +1053,7 @@ class ProductTemplate(models.Model): @api.model def _get_buy_route(self): - buy_route = self.env.ref('purchase.route_warehouse0_buy') + buy_route = self.env.ref('purchase.route_warehouse0_buy', raise_if_not_found=False) if buy_route: return buy_route.ids return [] diff --git a/addons/purchase/tests/test_purchase_order.py b/addons/purchase/tests/test_purchase_order.py index 5f1c1f3f645..a7b83a0e237 100644 --- a/addons/purchase/tests/test_purchase_order.py +++ b/addons/purchase/tests/test_purchase_order.py @@ -22,6 +22,7 @@ class TestPurchaseOrder(AccountingTestCase): self.product_id_1 = self.env.ref('product.product_product_8') self.product_id_2 = self.env.ref('product.product_product_11') + (self.product_id_1 | self.product_id_2).write({'purchase_method': 'purchase'}) # Ensure product_id_2 doesn't have res_partner_1 as supplier if self.partner_id in self.product_id_2.seller_ids.mapped('name'): id_to_remove = self.product_id_2.seller_ids.filtered(lambda r: r.name == self.partner_id).ids[0] if self.product_id_2.seller_ids.filtered(lambda r: r.name == self.partner_id) else False @@ -80,6 +81,7 @@ class TestPurchaseOrder(AccountingTestCase): 'partner_id': self.partner_id.id, 'purchase_id': self.po.id, 'account_id': self.partner_id.property_account_payable_id.id, + 'type': 'in_invoice', }) self.invoice.purchase_order_change() self.assertEqual(self.po.order_line.mapped('qty_invoiced'), [5.0, 5.0], 'Purchase: all products should be invoiced"') diff --git a/addons/rating_project/data/project_data.xml b/addons/rating_project/data/project_data.xml index e7c5e5a7cbc..b238f9c17f7 100644 --- a/addons/rating_project/data/project_data.xml +++ b/addons/rating_project/data/project_data.xml @@ -88,7 +88,7 @@ </tr> </table> </td></tr> - <tr><td style="padding:15px 20px 10px 20px;">${object.user_id.signature or ''| safe}</td></tr> + <tr><td style="padding:15px 20px 10px 20px;">${(object.user_id.signature or '')| safe}</td></tr> </tbody> </table> <table style="width:600px;margin:auto;text-align:center;font-size:12px;"> diff --git a/addons/report/static/src/js/report.editor.js b/addons/report/static/src/js/report.editor.js index 5b58793bbf5..57942f9b79c 100644 --- a/addons/report/static/src/js/report.editor.js +++ b/addons/report/static/src/js/report.editor.js @@ -1,6 +1,8 @@ odoo.define('report.editor', function (require) { 'use strict'; +var ajax = require('web.ajax'); +var core = require('web.core'); var utils = require('report.utils'); var editor = require('web_editor.editor'); var options = require('web_editor.snippets.options'); @@ -10,6 +12,8 @@ var trusted_host = utils.get_host_from_url(web_base_url); var trusted_protocol = utils.get_protocol_from_url(web_base_url); var trusted_origin = utils.build_origin(trusted_protocol, trusted_host); +ajax.loadXML('/web/static/src/xml/base_common.xml', core.qweb); + // Patch the editor's behavior when it is launched inside an iframe. if (window.self !== window.top) { $(document.body).addClass('o_in_iframe'); // in order to apply css rules diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py index 42e6228a3df..22d4c0747d1 100644 --- a/addons/sale/models/sale.py +++ b/addons/sale/models/sale.py @@ -824,6 +824,7 @@ class SaleOrderLine(models.Model): @api.multi def _get_display_price(self, product): + # TO DO: move me in master/saas-16 on sale.order if self.order_id.pricelist_id.discount_policy == 'without_discount': from_currency = self.order_id.company_id.currency_id return from_currency.compute(product.lst_price, self.order_id.pricelist_id.currency_id) diff --git a/addons/sale/views/sales_team_views.xml b/addons/sale/views/sales_team_views.xml index b10d6b55764..c1fec1d76d4 100644 --- a/addons/sale/views/sales_team_views.xml +++ b/addons/sale/views/sales_team_views.xml @@ -137,4 +137,8 @@ </field> </record> + <record id="sales_team.mail_activity_type_action_config_sales" model="ir.actions.act_window"> + <field name="domain">['|', ('res_model_id', '=', False), ('res_model_id.model', 'in', ['sale.order', 'res.partner', 'product.template', 'product.product'])]</field> + </record> + </odoo> diff --git a/addons/sale_crm/views/crm_lead_views.xml b/addons/sale_crm/views/crm_lead_views.xml index a85f89b796a..2f3f7883fe7 100644 --- a/addons/sale_crm/views/crm_lead_views.xml +++ b/addons/sale_crm/views/crm_lead_views.xml @@ -45,4 +45,8 @@ <field name="context">{'default_type': 'opportunity', 'default_user_id': uid, 'needaction_menu_ref': 'sale.menu_sale_quotations'}</field> </record> + <record id="sales_team.mail_activity_type_action_config_sales" model="ir.actions.act_window"> + <field name="domain">['|', ('res_model_id', '=', False), ('res_model_id.model', 'in', ['crm.lead', 'sale.order', 'res.partner', 'product.template', 'product.product'])]</field> + </record> + </odoo> diff --git a/addons/sales_team/views/crm_team_views.xml b/addons/sales_team/views/crm_team_views.xml index 88521f84c23..5294e3b4bf8 100644 --- a/addons/sales_team/views/crm_team_views.xml +++ b/addons/sales_team/views/crm_team_views.xml @@ -197,5 +197,18 @@ action="sales_team_config_action" sequence="2"/> + <record id="mail_activity_type_action_config_sales" model="ir.actions.act_window"> + <field name="name">Activity Types</field> + <field name="res_model">mail.activity.type</field> + <field name="view_type">form</field> + <field name="view_mode">tree,form</field> + <field name="domain">['|', ('res_model_id', '=', False), ('res_model_id.model', '=', 'res.partner')]</field> + </record> + <menuitem name="Activity Types" + id="sales_team_menu_config_activity_types" + sequence="2" + action="mail_activity_type_action_config_sales" + parent="sales_team.menu_sale_config"/> + </data> </odoo> diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 35ac5630f68..020a25ac276 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -561,6 +561,7 @@ class StockMove(models.Model): moves_to_assign = self.env['stock.move'] moves_to_do = self.env['stock.move'] operations = self.env['stock.pack.operation'] + ancestors_list = {} # work only on in progress moves moves = self.filtered(lambda move: move.state in ['confirmed', 'waiting', 'assigned']) @@ -583,6 +584,7 @@ class StockMove(models.Model): # we always search for yet unassigned quants main_domain[move.id] = [('reservation_id', '=', False), ('qty', '>', 0)] + ancestors_list[move.id] = True if ancestors else False if move.state == 'waiting' and not ancestors: # if the waiting move hasn't yet any ancestor (PO/MO not confirmed yet), don't find any quant available in stock main_domain[move.id] += [('id', '=', False)] @@ -626,7 +628,9 @@ class StockMove(models.Model): lot_qty[lot] -= qty move_qty -= qty - for move in moves_to_do: + # Sort moves to reserve first the ones with ancestors, in case the same product is listed in + # different stock moves. + for move in sorted(moves_to_do, key=lambda x: -1 if ancestors_list.get(x.id) else 0): # then if the move isn't totally assigned, try to find quants without any specific domain if move.state != 'assigned' and not self.env.context.get('reserve_only_ops'): qty_already_assigned = move.reserved_availability diff --git a/addons/stock/security/ir.model.access.csv b/addons/stock/security/ir.model.access.csv index 090c74ab74c..17993221052 100644 --- a/addons/stock/security/ir.model.access.csv +++ b/addons/stock/security/ir.model.access.csv @@ -74,4 +74,4 @@ access_barcode_rule_stock_user,barcode.rule.stock.user,barcodes.model_barcode_ru access_barcode_rule_stock_manager,barcode.rule.stock.manager,barcodes.model_barcode_rule,stock.group_stock_manager,1,1,1,1 access_stock_forecast_user,report.stock.forecast.user,model_report_stock_forecast,stock.group_stock_user,1,0,0,0 access_stock_forecast_manager,report.stock.forecast.manager,model_report_stock_forecast,stock.group_stock_manager,1,1,1,1 -access_stock_scrap_user,stock.scrap.user,model_stock_scrap,stock.group_stock_user,1,0,0,0 +access_stock_scrap_user,stock.scrap.user,model_stock_scrap,stock.group_stock_user,1,1,1,0 diff --git a/addons/theme_default/static/src/less/option_layout_boxed.less b/addons/theme_default/static/src/less/option_layout_boxed.less index db449d79b4d..4e258175923 100644 --- a/addons/theme_default/static/src/less/option_layout_boxed.less +++ b/addons/theme_default/static/src/less/option_layout_boxed.less @@ -1,4 +1,6 @@ #wrapwrap { - width: 85%; - margin: 0 auto; -}
\ No newline at end of file + @media (min-width: @screen-sm-min){ + width: 85%; + margin: 0 auto; + } +} diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 11e92be6ac7..4db03e463eb 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -440,7 +440,9 @@ class Home(http.Controller): request.uid = request.session.uid context = request.env['ir.http'].webclient_rendering_context() - return request.render('web.webclient_bootstrap', qcontext=context) + response = request.render('web.webclient_bootstrap', qcontext=context) + response.headers['X-Frame-Options'] = 'DENY' + return response @http.route('/web/dbredirect', type='http', auth="none") def web_db_redirect(self, redirect='/', **kw): @@ -473,7 +475,9 @@ class Home(http.Controller): return http.redirect_with_hash(redirect) request.uid = old_uid values['error'] = _("Wrong login/password") - return request.render('web.login', values) + response = request.render('web.login', values) + response.headers['X-Frame-Options'] = 'DENY' + return response class WebClient(http.Controller): diff --git a/addons/web/static/src/js/framework/pyeval.js b/addons/web/static/src/js/framework/pyeval.js index d0708bdf356..bcab0b0717f 100644 --- a/addons/web/static/src/js/framework/pyeval.js +++ b/addons/web/static/src/js/framework/pyeval.js @@ -850,31 +850,62 @@ function eval_contexts (contexts, evaluation_context) { function eval_domains (domains, evaluation_context) { evaluation_context = _.extend(pycontext(), evaluation_context || {}); var result_domain = []; + // Normalize only if the first domain is the array ["|"] or ["!"] + var need_normalization = ( + domains && + domains.length > 0 && + domains[0].length === 1 && + (domains[0][0] === "|" || domains[0][0] === "!") + ); _(domains).each(function (domain) { if (_.isString(domain)) { // wrap raw strings in domain domain = { __ref: 'domain', __debug: domain }; } + var domain_array_to_combine; switch(domain.__ref) { case 'domain': evaluation_context.context = evaluation_context; - result_domain.push.apply( - result_domain, py.eval(domain.__debug, wrap_context(evaluation_context))); + domain_array_to_combine = py.eval(domain.__debug, wrap_context(evaluation_context)); break; case 'compound_domain': var eval_context = eval_contexts([domain.__eval_context]); - result_domain.push.apply( - result_domain, eval_domains( - domain.__domains, _.extend( - {}, evaluation_context, eval_context))); + domain_array_to_combine = eval_domains( + domain.__domains, _.extend({}, evaluation_context, eval_context) + ); break; default: - result_domain.push.apply(result_domain, domain); + domain_array_to_combine = domain; + } + if (need_normalization) { + domain_array_to_combine = get_normalized_domain(domain_array_to_combine); } + result_domain.push.apply(result_domain, domain_array_to_combine); }); return result_domain; } +/** + * Returns a normalized copy of the given domain array. Normalization is + * is making the implicit "&" at the start of the domain explicit, e.g. + * [A, B, C] would become ["&", "&", A, B, C]. + * + * @param {Array} domain_array + * @returns {Array} normalized copy of the given array + */ +function get_normalized_domain(domain_array) { + var expected = 1; // Holds the number of expected domain expressions + _.each(domain_array, function (item) { + if (item === "&" || item === "|") { + expected++; + } else if (item !== "!") { + expected--; + } + }); + var new_explicit_ands = _.times(-expected, _.constant("&")); + return new_explicit_ands.concat(domain_array); +} + function eval_groupbys (contexts, evaluation_context) { evaluation_context = _.extend(pycontext(), evaluation_context || {}); var result_group = []; diff --git a/addons/web/static/src/js/views/form_relational_widgets.js b/addons/web/static/src/js/views/form_relational_widgets.js index c44806d6bb8..63d04aaeef3 100644 --- a/addons/web/static/src/js/views/form_relational_widgets.js +++ b/addons/web/static/src/js/views/form_relational_widgets.js @@ -959,7 +959,8 @@ var X2ManyListView = ListView.extend({ field.no_rerender = true; current_values[field.name] = field.get('value'); }); - var cached_records = _.filter(this.dataset.cache, function(item){return !_.isEmpty(item.values) && !item.to_delete;}); + var ids = _.map(this.records.records, function (item) { return item.attributes.id; }); + var cached_records = _.filter(this.dataset.cache, function(item){return _.contains(ids, item.id) && !_.isEmpty(item.values) && !item.to_delete;}); var valid = _.every(cached_records, function(record){ _.each(fields, function(field){ var value = record.values[field.name]; diff --git a/addons/web/static/src/js/views/form_view.js b/addons/web/static/src/js/views/form_view.js index dc4df281c4d..0471f6d3156 100644 --- a/addons/web/static/src/js/views/form_view.js +++ b/addons/web/static/src/js/views/form_view.js @@ -55,7 +55,6 @@ var FormView = View.extend(common.FieldManagerMixin, { this.fields = {}; this.fields_order = []; this.datarecord = {}; - this._onchange_specs = {}; this.onchanges_mutex = new utils.Mutex(); this.default_focus_field = null; this.default_focus_button = null; @@ -75,7 +74,6 @@ var FormView = View.extend(common.FieldManagerMixin, { this.rendering_engine = new FormRenderingEngine(this); this.set({actual_mode: this.options.initial_mode}); this.has_been_loaded.done(function() { - self._build_onchange_specs(); self.on("change:actual_mode", self, self.toggle_buttons); self.on("change:actual_mode", self, self.toggle_sidebar); }); @@ -318,8 +316,11 @@ var FormView = View.extend(common.FieldManagerMixin, { this.update_pager(); // the mode must be actualized before updating the pager return $.when.apply(null, set_values).then(function() { if (!record.id) { - // trigger onchanges - self.do_onchange(null); + // trigger onchange for new record after x2many with non-embedded views are loaded + var fields_loaded = _.pluck(self.fields, 'is_loaded'); + $.when.apply(null, fields_loaded).done(function() { + self.do_onchange(null); + }); } self.on_form_changed(); self.rendering_engine.init_fields().then(function() { @@ -381,7 +382,24 @@ var FormView = View.extend(common.FieldManagerMixin, { _.each(this.fields, function(field, name) { self._onchange_fields.push(name); self._onchange_specs[name] = find(name, field.node); - _.each(field.field.views, function(view) { + + // we get the list of first-level fields of x2many firstly by + // getting them from the field embedded views, then if no embedded + // view is present for a loaded view, we get them from the default + // view that has been loaded + + // gather embedded view objects + var views = _.clone(field.field.views); + // also gather default view objects + if (field.viewmanager) { + _.each(field.viewmanager.views, function(view, view_type) { + // add default view if it was not embedded and it is loaded + if (views[view_type] === undefined && view.controller) { + views[view_type] = view.controller.fields_view; + } + }); + } + _.each(views, function(view) { _.each(view.fields, function(_, subname) { self._onchange_specs[name + '.' + subname] = find(subname, view.arch); }); @@ -410,6 +428,9 @@ var FormView = View.extend(common.FieldManagerMixin, { do_onchange: function(widget) { var self = this; + if (self._onchange_specs === undefined) { + self._build_onchange_specs(); + } var onchange_specs = self._onchange_specs; try { var def = $.when({}); diff --git a/addons/web/static/src/js/views/list_view.js b/addons/web/static/src/js/views/list_view.js index b02c91ed147..83e1b7bf900 100644 --- a/addons/web/static/src/js/views/list_view.js +++ b/addons/web/static/src/js/views/list_view.js @@ -948,9 +948,11 @@ ListView.List = Class.extend({ $row = self.$current.children( '[data-id=' + record.get('id') + ']'); } - var $newRow = $(self.render_record(record)); - $newRow.find('.o_list_record_selector input').prop('checked', !!$row.find('.o_list_record_selector input').prop('checked')); - $row.replaceWith($newRow); + if ($row.length) { + var $newRow = $(self.render_record(record)); + $newRow.find('.o_list_record_selector input').prop('checked', !!$row.find('.o_list_record_selector input').prop('checked')); + $row.replaceWith($newRow); + } }, 'add': function (ev, records, record, index) { var $new_row = $(self.render_record(record)); diff --git a/addons/web/static/src/js/views/list_view_editable.js b/addons/web/static/src/js/views/list_view_editable.js index c3b2209c477..6beb6a7a044 100644 --- a/addons/web/static/src/js/views/list_view_editable.js +++ b/addons/web/static/src/js/views/list_view_editable.js @@ -828,6 +828,10 @@ ListView.List.include(/** @lends instance.web.ListView.List# */{ if (!this.view.editable() || !this.view.is_action_enabled('edit')) { return this._super.apply(this, arguments); } + if (this.__is_starting_edition) { + return; + } + this.__is_starting_edition = true; var self = this; var args = arguments; @@ -839,6 +843,8 @@ ListView.List.include(/** @lends instance.web.ListView.List# */{ focus_field: $(event.target).not(".o_readonly").data('field'), }).fail(function() { return _super.apply(self, args); // The record can't be edited so open it in a modal (use-case: readonly mode) + }).always(function () { + self.__is_starting_edition = false; }); }, /** diff --git a/addons/web/static/src/less/tooltip.less b/addons/web/static/src/less/tooltip.less index dad63e374fa..e071bf04a40 100644 --- a/addons/web/static/src/less/tooltip.less +++ b/addons/web/static/src/less/tooltip.less @@ -5,6 +5,8 @@ opacity: 1; .tooltip-inner { + max-width: 300px; // fallback for browsers which do not support "vw" unit + max-width: 100vw; background-color: @odoo-tooltip-background-color; color: @odoo-tooltip-color; border-radius: @border-radius-base; diff --git a/addons/web/static/test/evals.js b/addons/web/static/test/evals.js index df58cab75d2..b6a3b4177e8 100644 --- a/addons/web/static/test/evals.js +++ b/addons/web/static/test/evals.js @@ -534,7 +534,7 @@ odoo.define_section('eval.edc.nonliterals', ['web.pyeval', 'web.session'], funct var result = pyeval.sync_eval_domains_and_contexts({ domains: [ [['type', '=', 'contract']], - { "__domains": [["|"], [["state", "in", ["open", "draft"]]], [["state", "=", "pending"]]], + { "__domains": [["|"], [["state", "in", ["open", "draft"]]], [["type", "=", "contract"], ["state", "=", "pending"]]], "__eval_context": null, "__ref": "compound_domain" }, @@ -550,7 +550,8 @@ odoo.define_section('eval.edc.nonliterals', ['web.pyeval', 'web.session'], funct assert.deepEqual(result.domain, [ ["type", "=", "contract"], "|", ["state", "in", ["open", "draft"]], - ["state", "=", "pending"], + "&", ["type", "=", "contract"], + ["state", "=", "pending"], "|", "&", ["date", "!=", false], ["date", "<=", today], diff --git a/addons/web_calendar/static/src/js/web_calendar.js b/addons/web_calendar/static/src/js/web_calendar.js index 7aed6e10860..f4995462698 100644 --- a/addons/web_calendar/static/src/js/web_calendar.js +++ b/addons/web_calendar/static/src/js/web_calendar.js @@ -332,7 +332,7 @@ var CalendarView = View.extend({ self.proxy('update_record')(event._id, data); }, eventRender: function (event, element, view) { - element.find('.fc-event-title').html(event.title); + element.find('.fc-event-title').html(event.title + event.attendee_avatars); }, eventAfterRender: function (event, element, view) { if ((view.name !== 'month') && (((event.end-event.start)/60000)<=30)) { @@ -633,7 +633,6 @@ var CalendarView = View.extend({ if (attendee_other.length>2) { the_title_avatar += '<span class="o_attendee_head" title="' + attendee_other.slice(0, -2) + '">+</span>'; } - the_title = the_title_avatar + the_title; } } @@ -642,9 +641,10 @@ var CalendarView = View.extend({ date_stop = m_start.toDate(); } var r = { - 'start': moment(date_start).toISOString(), - 'end': moment(date_stop).toISOString(), + 'start': moment(date_start).toString(), + 'end': moment(date_stop).toString(), 'title': the_title, + 'attendee_avatars': the_title_avatar, 'allDay': (this.fields[this.date_start].type == 'date' || (this.all_day && evt[this.all_day]) || false), 'id': evt.id, 'attendees':attendees diff --git a/addons/web_editor/models/ir_ui_view.py b/addons/web_editor/models/ir_ui_view.py index 955f2496860..98d8fd8bf6e 100644 --- a/addons/web_editor/models/ir_ui_view.py +++ b/addons/web_editor/models/ir_ui_view.py @@ -182,4 +182,4 @@ class IrUiView(models.Model): """ user_groups = set(self.env.user.groups_id) views = self.with_context(active_test=False)._views_get(key, bundles=bundles) - return views.filtered(lambda v: user_groups.issuperset(v.groups_id)) + return views.filtered(lambda v: not v.groups_id or len(user_groups.intersection(v.groups_id)) diff --git a/addons/web_editor/static/src/js/transcoder.js b/addons/web_editor/static/src/js/transcoder.js index fa7b4023377..05068972532 100644 --- a/addons/web_editor/static/src/js/transcoder.js +++ b/addons/web_editor/static/src/js/transcoder.js @@ -131,7 +131,7 @@ var font_to_img = function ($editable) { var icon, content; _.find(widget.fontIcons, function (font) { return _.find(widget.getCssSelectors(font.parser), function (css) { - if ($font.is(css[0].replace(/::?before$/, ''))) { + if ($font.is(css[0].replace(/::?before/g, ''))) { icon = css[2].split("-").shift(); content = css[1].match(/content:\s*['"]?(.)['"]?/)[1]; return true; diff --git a/addons/web_editor/static/src/js/widgets.js b/addons/web_editor/static/src/js/widgets.js index e5b4c825786..e0ecc658110 100644 --- a/addons/web_editor/static/src/js/widgets.js +++ b/addons/web_editor/static/src/js/widgets.js @@ -563,6 +563,7 @@ var getCssSelectors = function (filter) { if (!data) { data = [match[1], rules[r].cssText.replace(/(^.*\{\s*)|(\s*\}\s*$)/g, ''), clean, [clean]]; } else { + data[0] += (", " + match[1]); data[3].push(clean); } } diff --git a/addons/web_kanban/static/src/js/kanban_view.js b/addons/web_kanban/static/src/js/kanban_view.js index 8c382caacf4..9cd35c687c9 100644 --- a/addons/web_kanban/static/src/js/kanban_view.js +++ b/addons/web_kanban/static/src/js/kanban_view.js @@ -230,7 +230,7 @@ var KanbanView = View.extend({ // fetch group data (display information) var group_ids = _.without(_.map(groups, function (elem) { return elem.attributes.value[0];}), undefined); - if (options.grouped_by_m2o && group_ids.length) { + if (options.grouped_by_m2o && group_ids.length && group_by_fields_to_read.length) { return new data.DataSet(self, options.relation) .read_ids(group_ids, _.union(['display_name'], group_by_fields_to_read)) .then(function(results) { diff --git a/addons/website_crm_partner_assign/models/res_partner.py b/addons/website_crm_partner_assign/models/res_partner.py index 87b55e4df29..40babddea73 100644 --- a/addons/website_crm_partner_assign/models/res_partner.py +++ b/addons/website_crm_partner_assign/models/res_partner.py @@ -53,9 +53,9 @@ class ResPartner(models.Model): implemented_count = fields.Integer(compute='_compute_implemented_partner_count', store=True) @api.one - @api.depends('implemented_partner_ids') + @api.depends('implemented_partner_ids', 'implemented_partner_ids.website_published', 'implemented_partner_ids.active') def _compute_implemented_partner_count(self): - self.implemented_count = len(self.implemented_partner_ids.filtered(lambda x: x.website_published)) + self.implemented_count = len(self.implemented_partner_ids.filtered('website_published')) @api.onchange('grade_id') def _onchange_grade_id(self): diff --git a/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml b/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml index 668848908ab..37b99d87760 100644 --- a/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml +++ b/addons/website_crm_partner_assign/views/website_crm_partner_assign_templates.xml @@ -99,7 +99,7 @@ <div t-field="partner.website_short_description"/> <t t-if="any([p.website_published for p in partner.implemented_partner_ids])"> <small><a t-attf-href="/partners/#{slug(partner)}#right_column"> - <t t-raw="len([p for p in partner.implemented_partner_ids if p.website_published])"/> reference(s) + <t t-esc="partner.implemented_count"/> reference(s) </a></small> </t> </div> diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml index 05faca8c2f6..74df06b10cb 100644 --- a/addons/website_forum/views/website_forum.xml +++ b/addons/website_forum/views/website_forum.xml @@ -566,9 +566,11 @@ <ul> <li>Set a clear, explicit and concise question title (check - <a href="#" data-placement="top" data-trigger="focus" data-toggle="popover" data-content="Inventory Date Problem, Task remaining hours, Can you help solve solve my tax computation problem in Canada?" title="Click to get bad question samples">bad examples</a> + <t t-set="message_content_01">Inventory Date Problem, Task remaining hours, Can you help solve solve my tax computation problem in Canada?</t> + <a href="#" data-placement="top" data-trigger="focus" data-toggle="popover" t-att-data-content="message_content_01" title="Click to get bad question samples">bad examples</a> and - <a href="#" data-placement="bottom" data-trigger="focus" data-toggle="popover" data-content="How to create a physical inventory at an anterior date?, How is the 'remaining hours' field computed on tasks?, How to configure TPS and TVQ's canadian taxes?" title="Click to get good question titles">good examples</a> + <t t-set="message_content_02">How to create a physical inventory at an anterior date?, How is the 'remaining hours' field computed on tasks?, How to configure TPS and TVQ's canadian taxes?</t> + <a href="#" data-placement="bottom" data-trigger="focus" data-toggle="popover" t-att-data-content="message_content_02" title="Click to get good question titles">good examples</a> ), </li> <li>Avoid unnecessary introductions (Hi,... Please... Thanks...),</li> diff --git a/addons/website_mass_mailing/views/unsubscribe_templates.xml b/addons/website_mass_mailing/views/unsubscribe_templates.xml index dc9668d4869..ae0a10a9674 100644 --- a/addons/website_mass_mailing/views/unsubscribe_templates.xml +++ b/addons/website_mass_mailing/views/unsubscribe_templates.xml @@ -52,7 +52,7 @@ <h1 class="page-header">Mailing Subscriptions</h1> <div class="alert alert-success text-center"> - <p>Your changes have been saved.</p> + <p>You have been successfully <strong>unsubscribed</strong>!</p> </div> </div> </div> diff --git a/addons/website_portal/controllers/main.py b/addons/website_portal/controllers/main.py index 1912dae43c7..4a9a8cb78bb 100644 --- a/addons/website_portal/controllers/main.py +++ b/addons/website_portal/controllers/main.py @@ -99,7 +99,9 @@ class website_account(http.Controller): 'redirect': redirect, }) - return request.render("website_portal.details", values) + response = request.render("website_portal.details", values) + response.headers['X-Frame-Options'] = 'DENY' + return response def details_form_validate(self, data): error = dict() diff --git a/addons/website_project/views/project_templates.xml b/addons/website_project/views/project_templates.xml index a7e527d9f5a..3bbdd0f2d88 100644 --- a/addons/website_project/views/project_templates.xml +++ b/addons/website_project/views/project_templates.xml @@ -32,7 +32,7 @@ <span class='badge'><t t-esc="task_count"/></span> </t> <t t-if="not task_count"> - There are currently no quotes. + There are currently no tasks. </t> </small> </a> diff --git a/addons/website_quote/models/sale_quote.py b/addons/website_quote/models/sale_quote.py index 817df1e087c..e65f6ed905f 100644 --- a/addons/website_quote/models/sale_quote.py +++ b/addons/website_quote/models/sale_quote.py @@ -58,7 +58,7 @@ class SaleQuoteLine(models.Model): def _onchange_product_id(self): self.ensure_one() if self.product_id: - name = self.product_id.name + name = self.product_id.name_get()[0][1] if self.product_id.description_sale: name += '\n' + self.product_id.description_sale self.name = name diff --git a/addons/website_sale/controllers/main.py b/addons/website_sale/controllers/main.py index 39a72c2700d..407a2e7cd11 100644 --- a/addons/website_sale/controllers/main.py +++ b/addons/website_sale/controllers/main.py @@ -536,17 +536,18 @@ class WebsiteSale(http.Controller): @http.route(['/shop/address'], type='http', methods=['GET', 'POST'], auth="public", website=True) def address(self, **kw): Partner = request.env['res.partner'].with_context(show_address=1).sudo() - order = request.website.sale_get_order(force_create=1) + order = request.website.sale_get_order() + + redirection = self.checkout_redirection(order) + if redirection: + return redirection + mode = (False, False) def_country_id = order.partner_id.country_id values, errors = {}, {} partner_id = int(kw.get('partner_id', -1)) - redirection = self.checkout_redirection(order) - if redirection: - return redirection - # IF PUBLIC ORDER if order.partner_id.id == request.website.user_id.sudo().partner_id.id: mode = ('new', 'billing') diff --git a/addons/website_sale/models/sale_order.py b/addons/website_sale/models/sale_order.py index 7af22085041..7be62cd91d1 100644 --- a/addons/website_sale/models/sale_order.py +++ b/addons/website_sale/models/sale_order.py @@ -68,12 +68,18 @@ class SaleOrder(models.Model): }) product = self.env['product.product'].with_context(product_context).browse(product_id) + pu = product.price + if order.pricelist_id and order.partner_id: + order_line = order._cart_find_product_line(product.id) + if order_line: + pu = self.env['account.tax']._fix_tax_included_price(order_line._get_display_price(product), product.taxes_id, order_line.tax_id) + return { 'product_id': product_id, 'product_uom_qty': qty, 'order_id': order_id, 'product_uom': product.uom_id.id, - 'price_unit': product.price, + 'price_unit': pu, } @api.multi @@ -144,10 +150,12 @@ class SaleOrder(models.Model): # update line values = self._website_product_id_change(self.id, product_id, qty=quantity) - - if self.pricelist_id.discount_policy == 'with_discount' and not self.env.context.get('fixed_price'): - values['price_unit'] = order_line._get_display_price(order_line.product_id) + values['price_unit'] = self.env['account.tax']._fix_tax_included_price( + order_line._get_display_price(order_line.product_id), + order_line.product_id.taxes_id, + order_line.tax_id + ) order_line.write(values) diff --git a/doc/cla/corporate/vauxoo.md b/doc/cla/corporate/vauxoo.md index a8fc2a644b2..d651412fb9d 100644 --- a/doc/cla/corporate/vauxoo.md +++ b/doc/cla/corporate/vauxoo.md @@ -32,3 +32,4 @@ Leonardo Astros leonardo@vauxoo.com https://github.com/Codemaker83 Jose Angel Fentanez Delfin joseangel@vauxoo.com https://github.com/Angelfentanez Osval Reyes osval@vauxoo.com https://github.com/osvalr Jose Suniaga josemiguel@vauxoo.com https://github.com/suniagajose +Luis González lgonzalez@vauxoo.com https://github.com/luisg123v diff --git a/doc/cla/individual/beuss.md b/doc/cla/individual/beuss.md new file mode 100644 index 00000000000..aefea1e7a9d --- /dev/null +++ b/doc/cla/individual/beuss.md @@ -0,0 +1,11 @@ +France, 2017-03-24 + +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, + +Sébastien Le Ray <sebastien-github@orniz.org> https://github.com/beuss diff --git a/doc/cla/individual/cgenie.md b/doc/cla/individual/cgenie.md new file mode 100644 index 00000000000..833bf7d38ad --- /dev/null +++ b/doc/cla/individual/cgenie.md @@ -0,0 +1,11 @@ +London, 2017-03-18 + +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, + +Przemyslaw Kaminski cgenie@gmail.com https://github.com/cgenie diff --git a/doc/cla/individual/gustavovalverde.md b/doc/cla/individual/gustavovalverde.md new file mode 100644 index 00000000000..2aa43f39456 --- /dev/null +++ b/doc/cla/individual/gustavovalverde.md @@ -0,0 +1,11 @@ +Dominican Republic, 10-13-2016 + +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, + +Gustavo Valverde g.valverde02@gmail.com https://github.com/gustavovalverde diff --git a/doc/cla/individual/sylnsr.md b/doc/cla/individual/sylnsr.md new file mode 100644 index 00000000000..358bf370043 --- /dev/null +++ b/doc/cla/individual/sylnsr.md @@ -0,0 +1,11 @@ +United States, 2017-03-17 + +I hereby agree to the terms of the Odoo Individual Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Mike Mugge github@muggeltd.com.com https://github.com/sylnsr diff --git a/doc/howtos/backend.rst b/doc/howtos/backend.rst index 3c5070494da..4d48a6d7de3 100644 --- a/doc/howtos/backend.rst +++ b/doc/howtos/backend.rst @@ -643,7 +643,7 @@ instead of a single view its ``arch`` field is composed of any number of ``inside`` appends ``xpath``'s body at the end of the matched element ``replace`` - replaces the matched element with the ``xpath``'s body, replacing any `$0` node occurrence + replaces the matched element with the ``xpath``'s body, replacing any ``$0`` node occurrence in the new body with the original element ``before`` inserts the ``xpath``'s body as a sibling before the matched element diff --git a/doc/reference/views.rst b/doc/reference/views.rst index 186ab4eedf8..853104bfaa6 100644 --- a/doc/reference/views.rst +++ b/doc/reference/views.rst @@ -97,7 +97,7 @@ how the matched node should be altered: the content of the inheritance spec is appended to the matched node ``replace`` the content of the inheritance spec replaces the matched node. - Any text node containing only `$0` within the contents of the spec will + Any text node containing only ``$0`` within the contents of the spec will be replaced by a complete copy of the matched node, effectively wrapping the matched node. ``after`` diff --git a/doc/setup/deploy.rst b/doc/setup/deploy.rst index 68e5e41e928..ec1a31e0a3c 100644 --- a/doc/setup/deploy.rst +++ b/doc/setup/deploy.rst @@ -34,8 +34,8 @@ accessible Odoo needs a rule to know which one it should use. That is one of the purposes of :option:`--db-filter <odoo-bin --db-filter>`: it specifies how the database should be selected based on the hostname (domain) that is being requested. The value is a `regular expression`_, possibly -including the dynamically injected hostname (`%h`) or the first subdomain (`%d`) -through which the system is being accessed. +including the dynamically injected hostname (``%h``) or the first subdomain +(``%d``) through which the system is being accessed. For servers hosting multiple databases in production, especially if ``website`` is used, dbfilter **must** be set, otherwise a number of features will not work @@ -70,7 +70,7 @@ in ``/etc/odoo.conf`` set: of securing your deployment. Once it is correctly working and only matching a single database per hostname, it is strongly recommended to block access to the database manager screens, - and to use the `--no-database-list` startup paramater to prevent listing + and to use the ``--no-database-list`` startup paramater to prevent listing your databases. See also security_. diff --git a/odoo/addons/base/ir/ir_attachment.py b/odoo/addons/base/ir/ir_attachment.py index 0e7e9284f44..b6bd9a08ee7 100644 --- a/odoo/addons/base/ir/ir_attachment.py +++ b/odoo/addons/base/ir/ir_attachment.py @@ -26,7 +26,7 @@ class IrAttachment(models.Model): The computed field ``datas`` is implemented using ``_file_read``, ``_file_write`` and ``_file_delete``, which can be overridden to implement other storage engines. Such methods should check for other location pseudo - uri (example: hdfs://hadoppserver). + uri (example: hdfs://hadoopserver). The default implementation is the file:dirname location that stores files on the local filesystem using name based on their sha1 hash diff --git a/odoo/addons/base/ir/ir_model.py b/odoo/addons/base/ir/ir_model.py index 9cd07f64386..b2918fef887 100644 --- a/odoo/addons/base/ir/ir_model.py +++ b/odoo/addons/base/ir/ir_model.py @@ -78,11 +78,16 @@ class IrModel(models.Model): _description = "Models" _order = 'model' + def _default_field_id(self): + if self.env.context.get('install_mode'): + return [] # no default field when importing + return [(0, 0, {'name': 'x_name', 'field_description': 'Name', 'ttype': 'char'})] + name = fields.Char(string='Model Description', translate=True, required=True) model = fields.Char(default='x_', required=True, index=True) info = fields.Text(string='Information') field_id = fields.One2many('ir.model.fields', 'model_id', string='Fields', required=True, copy=True, - default=lambda self: [(0, 0, {'name': 'x_name', 'field_description': 'Name', 'ttype': 'char'})]) + default=_default_field_id) inherited_model_ids = fields.Many2many('ir.model', compute='_inherited_models', string="Inherited models", help="The list of models that extends the current model.") state = fields.Selection([('manual', 'Custom Object'), ('base', 'Base Object')], string='Type', default='manual', readonly=True) diff --git a/odoo/addons/base/ir/ir_values.py b/odoo/addons/base/ir/ir_values.py index 866cb8a8504..00564b440e1 100644 --- a/odoo/addons/base/ir/ir_values.py +++ b/odoo/addons/base/ir/ir_values.py @@ -7,6 +7,10 @@ from odoo import api, fields, models, tools, _ from odoo.exceptions import AccessError, MissingError, ValidationError from odoo.tools import pickle +import logging +_logger = logging.getLogger(__name__) + + EXCLUDED_FIELDS = set(('code', 'report_sxw_content', 'report_rml_content', 'report_sxw', 'report_rml', 'report_sxw_content_data', 'report_rml_content_data', 'search_view', )) @@ -223,7 +227,7 @@ class IrValues(models.Model): field = self.env[model]._fields[field_name] field.convert_to_cache(value, self.browse()) except KeyError: - raise ValidationError(_("Invalid field %s.%s") % (model, field_name)) + _logger.warning("Invalid field %s.%s", model, field_name) except Exception: raise ValidationError(_("Invalid value for %s.%s: %s") % (model, field_name, value)) diff --git a/odoo/addons/base/res/res_lang.py b/odoo/addons/base/res/res_lang.py index e19d5175f90..446565ada13 100644 --- a/odoo/addons/base/res/res_lang.py +++ b/odoo/addons/base/res/res_lang.py @@ -216,8 +216,17 @@ class Lang(models.Model): lang_codes = self.mapped('code') if 'code' in vals and any(code != vals['code'] for code in lang_codes): raise UserError(_("Language code cannot be modified.")) - if vals.get('active') == False and self.env['res.users'].search([('lang', 'in', lang_codes)]): - raise UserError(_("Cannot unactivate a language that is currently used by users.")) + if vals.get('active') == False: + if self.env['res.users'].search([('lang', 'in', lang_codes)]): + raise UserError(_("Cannot unactivate a language that is currently used by users.")) + # delete linked ir.value specifying default partner's language + default_lang = self.env['ir.values'].search([ + ('key', '=', 'default'), + ('name', '=', 'lang'), + ('model', '=', 'res.partner')]) + if default_lang and default_lang.value_unpickle in lang_codes: + default_lang.unlink() + res = super(Lang, self).write(vals) self.clear_caches() return res diff --git a/odoo/addons/base/tests/test_ir_values.py b/odoo/addons/base/tests/test_ir_values.py index b8aa0cdb331..e7d04359e92 100644 --- a/odoo/addons/base/tests/test_ir_values.py +++ b/odoo/addons/base/tests/test_ir_values.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from odoo import tools from odoo.exceptions import ValidationError from odoo.tests.common import TransactionCase @@ -41,11 +42,12 @@ class TestIrValues(TransactionCase): self.assertTrue(d, "At least one value should be retrieved for this model.") self.assertEqual(d[2], '007', "Can't retrieve the created default value.") - # create invalid defaults - with self.assertRaises(ValidationError): + # create valid but unusable defaults, a ValidationError should not be thrown + with tools.mute_logger('odoo.addons.base.ir.ir_values'): ir_values.set_default('unknown_model', 'unknown_field', 42) - with self.assertRaises(ValidationError): ir_values.set_default('res.partner', 'unknown_field', 42) + + # create invalid defaults with self.assertRaises(ValidationError): ir_values.set_default('res.partner', 'lang', 'some_LANG') with self.assertRaises(ValidationError): diff --git a/odoo/addons/test_new_api/ir.model.access.csv b/odoo/addons/test_new_api/ir.model.access.csv index 9c35118a5a1..4f05bc6dae3 100644 --- a/odoo/addons/test_new_api/ir.model.access.csv +++ b/odoo/addons/test_new_api/ir.model.access.csv @@ -14,4 +14,5 @@ access_test_new_api_foo,access_test_new_api_foo,model_test_new_api_foo,,1,1,1,1 access_test_new_api_bar,access_test_new_api_bar,model_test_new_api_bar,,1,1,1,1 access_test_new_api_related,access_test_new_api_related,model_test_new_api_related,,1,1,1,1 access_test_new_api_company,access_test_new_api_company,model_test_new_api_company,,1,1,1,1 +access_test_new_api_company_attr,access_test_new_api_company_attr,model_test_new_api_company_attr,,1,1,1,1 access_test_new_api_compute_inverse,access_test_new_api_compute_inverse,model_test_new_api_compute_inverse,,1,1,1,1 diff --git a/odoo/addons/test_new_api/models.py b/odoo/addons/test_new_api/models.py index 1d3d5ab404b..d0871a51dcf 100644 --- a/odoo/addons/test_new_api/models.py +++ b/odoo/addons/test_new_api/models.py @@ -4,7 +4,7 @@ import datetime from odoo import models, fields, api, _ -from odoo.exceptions import AccessError +from odoo.exceptions import AccessError, ValidationError class Category(models.Model): @@ -82,6 +82,20 @@ class Discussion(models.Model): """Ensure computed O2M domains work as expected.""" return [("important", "=", True)] + @api.onchange('name') + def _onchange_name(self): + # test onchange modifying one2many field values + if self.env.context.get('generate_dummy_message') and self.name == '{generate_dummy_message}': + # update body of existings messages and emails + for message in self.messages: + message.body = 'not last dummy message' + for message in self.important_messages: + message.body = 'not last dummy message' + # add new dummy message + message_vals = self.messages._add_missing_default_values({'body': 'dummy message', 'important': True}) + self.messages |= self.messages.new(message_vals) + self.important_messages |= self.messages.new(message_vals) + @api.onchange('moderator') def _onchange_moderator(self): self.participants |= self.moderator @@ -154,7 +168,7 @@ class Message(models.Model): @api.one @api.depends('author', 'author.partner_id') def _compute_author_partner(self): - self.author_partner = author.partner_id + self.author_partner = self.author.partner_id @api.model def _search_author_partner(self, operator, value): @@ -323,3 +337,15 @@ class CompanyDependent(models.Model): _name = 'test_new_api.company' foo = fields.Char(company_dependent=True) + +class CompanyDependentAttribute(models.Model): + _name = 'test_new_api.company.attr' + + company = fields.Many2one('test_new_api.company') + quantity = fields.Integer() + bar = fields.Char(compute='_compute_bar', store=True) + + @api.depends('quantity', 'company.foo') + def _compute_bar(self): + for record in self: + record.bar = (record.company.foo or '') * record.quantity
\ No newline at end of file diff --git a/odoo/addons/test_new_api/static/test/x2many.js b/odoo/addons/test_new_api/static/test/x2many.js index d26eedcd0f6..4d63b226c36 100644 --- a/odoo/addons/test_new_api/static/test/x2many.js +++ b/odoo/addons/test_new_api/static/test/x2many.js @@ -454,5 +454,71 @@ odoo.define('web.test.x2many', function (require) { trigger: '.tab-pane:eq(0) .o_form_field.o_view_manager_content tbody tr[data-id]:eq(2)', extra_trigger: 'body:not(:has(.tab-pane:eq(0) .o_form_field.o_view_manager_content tbody tr[data-id]:eq(3)))', run: function () {}, // it's a check + }, + + ///////////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////////////////////// + + { + content: "switch to the third form view to test onchange changing one2many (toggle menu dropdown)", + trigger: '.o_sub_menu .oe_secondary_submenu .oe_menu_leaf .oe_menu_text:containsExact(Discussions)', + extra_trigger: '.tab-pane:eq(0) .o_form_field.o_view_manager_content tbody tr[data-id]:eq(2)', + edition: 'community' + }, { + content: "switch to the third form view to test onchange changing one2many (toggle menu dropdown)", + trigger: 'nav .o_menu_sections li a:containsExact(Discussions)', + extra_trigger: '.tab-pane:eq(0) .o_form_field.o_view_manager_content tbody tr[data-id]:eq(2)', + edition: 'enterprise' + }, { + content: "switch to the thied form view to test onchange changing one2many (open submenu)", + trigger: '.o_sub_menu .oe_secondary_submenu .oe_menu_leaf .oe_menu_text:contains(Discussions 3)', + edition: 'community' + }, { + content: "switch to the thied form view to test onchange changing one2many (open submenu)", + trigger: 'nav .o_menu_sections ul li a:contains(Discussions 3)', + edition: 'enterprise' + }, { + content: "wait web client", + trigger: '.breadcrumb:contains(Discussions 3)', + }, { + content: "create new discussion", + trigger: 'button.o_list_button_add', + }, { + content: "set discussion title to generate dummy message", + trigger: 'input.o_form_required', + run: 'text {generate_dummy_message}', + }, { + content: "check new dummy message happened", + trigger: '.o_group tr:first-child td[data-field="size"]:containsExact(13)', + extra_trigger: '.o_group tr:last-child td[data-field="size"]:containsExact(13)', + run: function () {}, // it's a check + }, { + content: "check field not in embedded view received correctly", + trigger: 'td[data-field="important"] input[type="checkbox"]:propChecked', + run: function () {}, // it's a check + }, { + content: "empty discussion title", + trigger: 'input.o_form_required', + run: 'text removed_title', + }, { + content: "onchange happened", + trigger: 'td[data-field="name"]:contains([removed_title])', + run: function () {}, // it's a check + }, { + content: "set discussion title to generate dummy message", + trigger: 'input.o_form_required', + run: 'text {generate_dummy_message}', + }, { + content: "chuck update and new dummy message happened", + trigger: '.o_group tr:first-child td[data-field="size"]:containsExact(22)', + extra_trigger: '.o_group tr:last-child td[data-field="size"]:containsExact(22)', + run: function () {}, // it's a check + }, { // cancel + content: "cancel change", + trigger: '.o_cp_buttons .o_form_button_cancel', + run: 'click', + }, { + content: "confirm cancel change", + trigger: '.modal-footer button:contains(Ok)', }]); }); diff --git a/odoo/addons/test_new_api/tests/test_new_fields.py b/odoo/addons/test_new_api/tests/test_new_fields.py index 9247d32370f..ca61afa413a 100644 --- a/odoo/addons/test_new_api/tests/test_new_fields.py +++ b/odoo/addons/test_new_api/tests/test_new_fields.py @@ -498,6 +498,25 @@ class TestFields(common.TransactionCase): self.assertEqual(record.sudo(user1).foo, 'alpha') self.assertEqual(record.sudo(user2).foo, 'default') + # create company record and attribute + company_record = self.env['test_new_api.company'].create({'foo': 'ABC'}) + attribute_record = self.env['test_new_api.company.attr'].create({ + 'company': company_record.id, + 'quantity': 1, + }) + self.assertEqual(attribute_record.bar, 'ABC') + + # change quantity, 'bar' should recompute to 'ABCABC' + attribute_record.quantity = 2 + self.assertEqual(attribute_record.bar, 'ABCABC') + self.assertFalse(self.env.has_todo()) + + # change company field 'foo', 'bar' should recompute to 'DEFDEF' + company_record.foo = 'DEF' + self.assertEqual(attribute_record.company.foo, 'DEF') + self.assertEqual(attribute_record.bar, 'DEFDEF') + self.assertFalse(self.env.has_todo()) + def test_30_read(self): """ test computed fields as returned by read(). """ discussion = self.env.ref('test_new_api.discussion_0') diff --git a/odoo/addons/test_new_api/tests/test_onchange.py b/odoo/addons/test_new_api/tests/test_onchange.py index 0301ca2b3e4..a6e2bff1b35 100644 --- a/odoo/addons/test_new_api/tests/test_onchange.py +++ b/odoo/addons/test_new_api/tests/test_onchange.py @@ -307,12 +307,7 @@ class TestOnChange(common.TransactionCase): # When one2many domain contains non-computed field, things are ok self.assertEqual(result['value']['important_messages'], - [(5,)] + [(1, msg.id, { - 'name': msg.name, - 'body': msg.body, - 'author': (msg.author.id, msg.author.display_name), - 'size': msg.size - }) for msg in discussion.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( diff --git a/odoo/addons/test_new_api/views.xml b/odoo/addons/test_new_api/views.xml index 0b053635319..0916144467a 100644 --- a/odoo/addons/test_new_api/views.xml +++ b/odoo/addons/test_new_api/views.xml @@ -152,6 +152,41 @@ </record> <menuitem id="menu_discussions_2" action="action_discussions_2" parent="menu_sub" sequence="10"/> + <!-- Discussion form view with embedded list --> + <record id="discussion_form_3" model="ir.ui.view"> + <field name="name">discussion form view</field> + <field name="model">test_new_api.discussion</field> + <field name="priority" eval="11"/> + <field name="arch" type="xml"> + <form string="Discussion" version="7.0"> + <sheet> + <group> + <field name="name" context="{'generate_dummy_message': True}"/> + </group> + <group> + <field name="messages" /> + <field name="important_messages"> + <tree string="Important messages"> + <field name="name"/> + <field name="author"/> + <field name="size"/> + </tree> + </field> + </group> + </sheet> + </form> + </field> + </record> + + <record id="action_discussions_3" model="ir.actions.act_window"> + <field name="name">Discussions 3</field> + <field name="res_model">test_new_api.discussion</field> + <field name="view_ids" eval="[(5,0,0), + (0,0,{'view_mode':'tree'}), + (0,0,{'view_mode':'form', 'view_id': ref('discussion_form_3')})]"/> + </record> + <menuitem id="menu_discussions_3" action="action_discussions_3" parent="menu_sub" sequence="11"/> + <!-- Message tree view --> <record id="message_tree" model="ir.ui.view"> @@ -159,7 +194,10 @@ <field name="model">test_new_api.message</field> <field name="arch" type="xml"> <tree string="Messages"> - <field name="display_name"/> + <field name="name"/> + <field name="author"/> + <field name="size"/> + <field name="important"/> </tree> </field> </record> diff --git a/odoo/fields.py b/odoo/fields.py index 4d1f16fd68d..d1d25edf05e 100644 --- a/odoo/fields.py +++ b/odoo/fields.py @@ -2217,7 +2217,7 @@ class One2many(_RelationalMulti): _description_relation_field = property(attrgetter('inverse_name')) def convert_to_onchange(self, value, record, fnames=()): - fnames = set(fnames or value.fields_view_get()['fields']) + fnames = set(fnames or ()) fnames.discard(self.inverse_name) return super(One2many, self).convert_to_onchange(value, record, fnames) diff --git a/odoo/http.py b/odoo/http.py index ae7e2ae5e2b..cef63e8f639 100644 --- a/odoo/http.py +++ b/odoo/http.py @@ -1366,9 +1366,16 @@ class Root(object): httprequest.session.db = db_monodb(httprequest) def setup_lang(self, httprequest): - if not "lang" in httprequest.session.context: - lang = httprequest.accept_languages.best or "en_US" - lang = babel.core.LOCALE_ALIASES.get(lang, lang).replace('-', '_') + if "lang" not in httprequest.session.context: + alang = httprequest.accept_languages.best or "en-US" + try: + code, territory, _, _ = babel.core.parse_locale(alang, sep='-') + if territory: + lang = '%s_%s' % (code, territory) + else: + lang = babel.core.LOCALE_ALIASES[code] + except (ValueError, KeyError): + lang = 'en_US' httprequest.session.context["lang"] = lang def get_request(self, httprequest): diff --git a/odoo/models.py b/odoo/models.py index 70aecb39ee3..f0a5cb16786 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -2311,7 +2311,7 @@ class BaseModel(object): self._add_magic_fields() cls._proper_fields = set(cls._fields) - cls.pool.model_cache[cls._model_cache_key] = cls + cls.pool.model_cache[cls._model_cache_key] = cls # 2. add custom fields self._add_manual_fields(partial) @@ -3018,12 +3018,17 @@ class BaseModel(object): if new_vals: # put the values of pure new-style fields into cache, and inverse them + self.modified(set(new_vals) - set(old_vals)) for record in self: record._cache.update(record._convert_to_cache(new_vals, update=True)) for key in new_vals: self._fields[key].determine_inverse(self) + self.modified(set(new_vals) - set(old_vals)) # check Python constraints for inversed fields self._validate_fields(set(new_vals) - set(old_vals)) + # recompute new-style fields + if self.env.recompute and self._context.get('recompute', True): + self.recompute() return True @@ -3276,14 +3281,19 @@ class BaseModel(object): # create record with old-style fields record = self.browse(self._create(old_vals)) - # put the values of pure new-style fields into cache, and inverse them - record._cache.update(record._convert_to_cache(new_vals)) protected_fields = map(self._fields.get, new_vals) with self.env.protecting(protected_fields, record): + # put the values of pure new-style fields into cache, and inverse them + record.modified(set(new_vals) - set(old_vals)) + record._cache.update(record._convert_to_cache(new_vals)) for key in new_vals: self._fields[key].determine_inverse(record) + record.modified(set(new_vals) - set(old_vals)) # check Python constraints for inversed fields record._validate_fields(set(new_vals) - set(old_vals)) + # recompute new-style fields + if self.env.recompute and self._context.get('recompute', True): + self.recompute() return record diff --git a/odoo/modules/registry.py b/odoo/modules/registry.py index a6ab4ead1b4..8ff70b84eb1 100644 --- a/odoo/modules/registry.py +++ b/odoo/modules/registry.py @@ -8,6 +8,7 @@ from collections import Mapping, defaultdict, deque from contextlib import closing from functools import partial from operator import attrgetter +from weakref import WeakValueDictionary import logging import os import threading @@ -31,6 +32,9 @@ class Registry(Mapping): _lock = threading.RLock() _saved_lock = None + # a cache for model classes, indexed by their base classes + model_cache = WeakValueDictionary() + @lazy_classproperty def registries(cls): """ A mapping from database names to registries. """ @@ -180,12 +184,6 @@ class Registry(Mapping): """ Add or replace a model in the registry.""" self.models[model_name] = model - @lazy_classproperty - def model_cache(cls): - """ A cache for model classes, indexed by their base classes. """ - # we cache 256 classes per registry on average - return LRU(cls.registries.count * 256) - @lazy_property def field_sequence(self): """ Return a function mapping a field to an integer. The value of a |
