Master upstream patch

This commit is contained in:
Parthiv Patel
2021-05-31 08:13:27 +00:00
parent 0c96298a5f
commit 2409bc60a8
497 changed files with 86066 additions and 42956 deletions
+3 -3
View File
@@ -49,9 +49,9 @@ class PortalAccount(CustomerPortal):
order = searchbar_sortings[sortby]['order']
searchbar_filters = {
'all': {'label': _('All'), 'domain': [('move_type', 'in', ['in_invoice', 'out_invoice'])]},
'invoices': {'label': _('Invoices'), 'domain': [('move_type', '=', 'out_invoice')]},
'bills': {'label': _('Bills'), 'domain': [('move_type', '=', 'in_invoice')]},
'all': {'label': _('All'), 'domain': []},
'invoices': {'label': _('Invoices'), 'domain': [('move_type', '=', ('out_invoice', 'out_refund'))]},
'bills': {'label': _('Bills'), 'domain': [('move_type', '=', ('in_invoice', 'in_refund'))]},
}
# default filter by value
if not filterby:
+35 -21
View File
@@ -617,16 +617,23 @@ class AccountGroup(models.Model):
"""
if not self and not account_ids:
return
self.env['account.group'].flush()
self.env['account.account'].flush()
self.env['account.group'].flush(self.env['account.group']._fields)
self.env['account.account'].flush(self.env['account.account']._fields)
query = """
UPDATE account_account account SET group_id = (
SELECT agroup.id FROM account_group agroup
WHERE agroup.code_prefix_start <= LEFT(account.code, char_length(agroup.code_prefix_start))
AND agroup.code_prefix_end >= LEFT(account.code, char_length(agroup.code_prefix_end))
AND agroup.company_id = account.company_id
ORDER BY char_length(agroup.code_prefix_start) DESC LIMIT 1
) WHERE account.company_id in %(company_ids)s {where_account};
WITH relation AS (
SELECT DISTINCT FIRST_VALUE(agroup.id) OVER (PARTITION BY account.id ORDER BY char_length(agroup.code_prefix_start) DESC, agroup.id) AS group_id,
account.id AS account_id
FROM account_group agroup
JOIN account_account account
ON agroup.code_prefix_start <= LEFT(account.code, char_length(agroup.code_prefix_start))
AND agroup.code_prefix_end >= LEFT(account.code, char_length(agroup.code_prefix_end))
AND agroup.company_id = account.company_id
WHERE account.company_id IN %(company_ids)s {where_account}
)
UPDATE account_account account
SET group_id = relation.group_id
FROM relation
WHERE relation.account_id = account.id;
""".format(
where_account=account_ids and 'AND account.id IN %(account_ids)s' or ''
)
@@ -642,21 +649,28 @@ class AccountGroup(models.Model):
"""
if not self:
return
self.env['account.group'].flush()
self.env['account.group'].flush(self.env['account.group']._fields)
query = """
UPDATE account_group agroup SET parent_id = (
SELECT parent.id FROM account_group parent
WHERE char_length(parent.code_prefix_start) < char_length(agroup.code_prefix_start)
AND parent.code_prefix_start <= LEFT(agroup.code_prefix_start, char_length(parent.code_prefix_start))
AND parent.code_prefix_end >= LEFT(agroup.code_prefix_end, char_length(parent.code_prefix_end))
AND parent.id != agroup.id
AND parent.company_id = %(company_id)s
ORDER BY char_length(parent.code_prefix_start) DESC LIMIT 1
) WHERE agroup.company_id = %(company_id)s;
WITH relation AS (
SELECT DISTINCT FIRST_VALUE(parent.id) OVER (PARTITION BY child.id ORDER BY child.id, char_length(parent.code_prefix_start) DESC) AS parent_id,
child.id AS child_id
FROM account_group parent
JOIN account_group child
ON char_length(parent.code_prefix_start) < char_length(child.code_prefix_start)
AND parent.code_prefix_start <= LEFT(child.code_prefix_start, char_length(parent.code_prefix_start))
AND parent.code_prefix_end >= LEFT(child.code_prefix_end, char_length(parent.code_prefix_end))
AND parent.id != child.id
AND parent.company_id = child.company_id
WHERE child.company_id IN %(company_ids)s
)
UPDATE account_group child
SET parent_id = relation.parent_id
FROM relation
WHERE child.id = relation.child_id;
"""
self.env.cr.execute(query, {'company_id': self.company_id.id})
self.env.cr.execute(query, {'company_ids': tuple(self.company_id.ids)})
self.env['account.group'].invalidate_cache(fnames=['parent_id'])
self.env['account.group'].search([('company_id', '=', self.company_id.id)])._parent_store_update()
self.env['account.group'].search([('company_id', 'in', self.company_id.ids)])._parent_store_update()
class AccountRoot(models.Model):
+1 -3
View File
@@ -697,9 +697,6 @@ class AccountJournal(models.Model):
''' Get the outstanding payments balance of the current journal by filtering the journal items using the
journal's accounts.
/!\ The current journal is not part of the applied domain. This is the expected behavior since we only want
a logic based on accounts.
:param domain: An additional domain to be applied on the account.move.line model.
:param date: The date to be used when performing the currency conversions.
:return: The balance expressed in the journal's currency.
@@ -722,6 +719,7 @@ class AccountJournal(models.Model):
('display_type', 'not in', ('line_section', 'line_note')),
('move_id.state', '!=', 'cancel'),
('reconciled', '=', False),
('journal_id', '=', self.id),
]
query = self.env['account.move.line']._where_calc(domain)
tables, where_clause, where_params = query.get_sql()
+91 -37
View File
@@ -194,6 +194,7 @@ class AccountMove(models.Model):
payment_reference = fields.Char(string='Payment Reference', index=True, copy=False,
help="The payment reference to set on journal items.")
payment_id = fields.Many2one(
index=True,
comodel_name='account.payment',
string="Payment", copy=False, check_company=True)
statement_line_id = fields.Many2one(
@@ -580,7 +581,7 @@ class AccountMove(models.Model):
quantity = 1.0
tax_type = base_line.tax_ids[0].type_tax_use if base_line.tax_ids else None
is_refund = (tax_type == 'sale' and base_line.debit) or (tax_type == 'purchase' and base_line.credit)
price_unit_wo_discount = base_line.balance
price_unit_wo_discount = base_line.amount_currency
balance_taxes_res = base_line.tax_ids._origin.with_context(force_sign=move._get_tax_force_sign()).compute_all(
price_unit_wo_discount,
@@ -1114,13 +1115,15 @@ class AccountMove(models.Model):
# the same counter for multiple groups that might be spread in multiple months.
final_batches = []
for journal_group in grouped.values():
journal_group_changed = True
for date_group in journal_group.values():
if (
not final_batches
journal_group_changed
or final_batches[-1]['format'] != date_group['format']
or dict(final_batches[-1]['format_values'], seq=0) != dict(date_group['format_values'], seq=0)
):
final_batches += [date_group]
journal_group_changed = False
elif date_group['reset'] == 'never':
final_batches[-1]['records'] += date_group['records']
elif (
@@ -2806,7 +2809,10 @@ class AccountMove(models.Model):
('date', '<=', fields.Date.context_today(self)),
('auto_post', '=', True),
])
records._post()
for ids in self._cr.split_for_in_conditions(records.ids, size=1000):
self.browse(ids)._post()
if not self.env.registry.in_test_mode():
self._cr.commit()
# offer the possibility to duplicate thanks to a button instead of a hidden menu, which is more visible
def action_duplicate(self):
@@ -2827,7 +2833,8 @@ class AccountMove(models.Model):
}
for line in preview_vals['items_vals']:
if 'partner_id' in line[2]:
line[2]['partner_id'] = self.env['res.partner'].browse(line[2]['partner_id']).display_name
# sudo is needed to compute display_name in a multi companies environment
line[2]['partner_id'] = self.env['res.partner'].browse(line[2]['partner_id']).sudo().display_name
line[2]['account_id'] = self.env['account.account'].browse(line[2]['account_id']).display_name or _('Destination Account')
line[2]['debit'] = currency_id and formatLang(self.env, line[2]['debit'], currency_obj=currency_id) or line[2]['debit']
line[2]['credit'] = currency_id and formatLang(self.env, line[2]['credit'], currency_obj=currency_id) or line[2]['debit']
@@ -3154,23 +3161,75 @@ class AccountMoveLine(models.Model):
return '\n'.join(values)
def _get_computed_price_unit(self):
''' Helper to get the default price unit based on the product by taking care of the taxes
set on the product and the fiscal position.
:return: The price unit.
'''
self.ensure_one()
if not self.product_id:
return self.price_unit
elif self.move_id.is_sale_document(include_receipts=True):
# Out invoice.
price_unit = self.product_id.lst_price
return 0.0
company = self.move_id.company_id
currency = self.move_id.currency_id
company_currency = company.currency_id
product_uom = self.product_id.uom_id
fiscal_position = self.move_id.fiscal_position_id
is_refund_document = self.move_id.move_type in ('out_refund', 'in_refund')
move_date = self.move_id.date or fields.Date.context_today(self)
if self.move_id.is_sale_document(include_receipts=True):
product_price_unit = self.product_id.lst_price
product_taxes = self.product_id.taxes_id
elif self.move_id.is_purchase_document(include_receipts=True):
# In invoice.
price_unit = self.product_id.standard_price
product_price_unit = self.product_id.standard_price
product_taxes = self.product_id.supplier_taxes_id
else:
return self.price_unit
return 0.0
product_taxes = product_taxes.filtered(lambda tax: tax.company_id == company)
if self.product_uom_id != self.product_id.uom_id:
price_unit = self.product_id.uom_id._compute_price(price_unit, self.product_uom_id)
# Apply unit of measure.
if self.product_uom_id and self.product_uom_id != product_uom:
product_price_unit = product_uom._compute_price(product_price_unit, self.product_uom_id)
return price_unit
# Apply fiscal position.
if product_taxes and fiscal_position:
product_taxes_after_fp = fiscal_position.map_tax(product_taxes, partner=self.partner_id)
if set(product_taxes.ids) != set(product_taxes_after_fp.ids):
flattened_taxes_before_fp = product_taxes._origin.flatten_taxes_hierarchy()
if any(tax.price_include for tax in flattened_taxes_before_fp):
taxes_res = flattened_taxes_before_fp.compute_all(
product_price_unit,
quantity=1.0,
currency=company_currency,
product=self.product_id,
partner=self.partner_id,
is_refund=is_refund_document,
)
product_price_unit = company_currency.round(taxes_res['total_excluded'])
flattened_taxes_after_fp = product_taxes_after_fp._origin.flatten_taxes_hierarchy()
if any(tax.price_include for tax in flattened_taxes_after_fp):
taxes_res = flattened_taxes_after_fp.compute_all(
product_price_unit,
quantity=1.0,
currency=company_currency,
product=self.product_id,
partner=self.partner_id,
is_refund=is_refund_document,
handle_price_include=False,
)
for tax_res in taxes_res['taxes']:
tax = self.env['account.tax'].browse(tax_res['id'])
if tax.price_include:
product_price_unit += tax_res['amount']
# Apply currency rate.
if currency and currency != company_currency:
product_price_unit = company_currency._convert(product_price_unit, currency, company, move_date)
return product_price_unit
def _get_computed_account(self):
self.ensure_one()
@@ -3471,33 +3530,21 @@ class AccountMoveLine(models.Model):
line.name = line._get_computed_name()
line.account_id = line._get_computed_account()
line.tax_ids = line._get_computed_taxes()
taxes = line._get_computed_taxes()
if taxes and line.move_id.fiscal_position_id:
taxes = line.move_id.fiscal_position_id.map_tax(taxes, partner=line.partner_id)
line.tax_ids = taxes
line.product_uom_id = line._get_computed_uom()
line.price_unit = line._get_computed_price_unit()
# price_unit and taxes may need to be adapted following Fiscal Position
line._set_price_and_tax_after_fpos()
# Convert the unit price to the invoice's currency.
company = line.move_id.company_id
line.price_unit = company.currency_id._convert(line.price_unit, line.move_id.currency_id, company, line.move_id.date, round=False)
@api.onchange('product_uom_id')
def _onchange_uom_id(self):
''' Recompute the 'price_unit' depending of the unit of measure. '''
price_unit = self._get_computed_price_unit()
# See '_onchange_product_id' for details.
taxes = self._get_computed_taxes()
if taxes and self.move_id.fiscal_position_id:
price_subtotal = self._get_price_total_and_subtotal(price_unit=price_unit, taxes=taxes)['price_subtotal']
accounting_vals = self._get_fields_onchange_subtotal(price_subtotal=price_subtotal, currency=self.move_id.company_currency_id)
amount_currency = accounting_vals['amount_currency']
price_unit = self._get_fields_onchange_balance(amount_currency=amount_currency, force_computation=True).get('price_unit', price_unit)
# Convert the unit price to the invoice's currency.
company = self.move_id.company_id
self.price_unit = company.currency_id._convert(price_unit, self.move_id.currency_id, company, self.move_id.date, round=False)
taxes = self.move_id.fiscal_position_id.map_tax(taxes, partner=self.partner_id)
self.tax_ids = taxes
self.price_unit = self._get_computed_price_unit()
@api.onchange('account_id')
def _onchange_account_id(self):
@@ -4384,10 +4431,17 @@ class AccountMoveLine(models.Model):
continue
grouping_key = self.env['account.partial.reconcile']._get_cash_basis_base_line_grouping_key_from_record(line, account=account_to_fix)
account_vals_to_fix[grouping_key] = {
**vals,
'account_id': account_to_fix.id,
}
if grouping_key not in account_vals_to_fix:
account_vals_to_fix[grouping_key] = {
**vals,
'account_id': account_to_fix.id,
}
else:
# Multiple base lines could share the same key, if the same
# cash basis tax is used alone on several lines of the invoices
account_vals_to_fix[grouping_key]['debit'] += vals['debit']
account_vals_to_fix[grouping_key]['credit'] += vals['credit']
# ==========================================================================
# Subtract the balance of all previously generated cash basis journal entries
+47 -28
View File
@@ -187,23 +187,32 @@ class AccountPayment(models.Model):
self.journal_id.display_name))
# Compute amounts.
write_off_amount = write_off_line_vals.get('amount', 0.0)
write_off_amount_currency = write_off_line_vals.get('amount', 0.0)
if self.payment_type == 'inbound':
# Receive money.
counterpart_amount = -self.amount
write_off_amount *= -1
liquidity_amount_currency = self.amount
elif self.payment_type == 'outbound':
# Send money.
counterpart_amount = self.amount
liquidity_amount_currency = -self.amount
write_off_amount_currency *= -1
else:
counterpart_amount = 0.0
write_off_amount = 0.0
liquidity_amount_currency = write_off_amount_currency = 0.0
balance = self.currency_id._convert(counterpart_amount, self.company_id.currency_id, self.company_id, self.date)
counterpart_amount_currency = counterpart_amount
write_off_balance = self.currency_id._convert(write_off_amount, self.company_id.currency_id, self.company_id, self.date)
write_off_amount_currency = write_off_amount
write_off_balance = self.currency_id._convert(
write_off_amount_currency,
self.company_id.currency_id,
self.company_id,
self.date,
)
liquidity_balance = self.currency_id._convert(
liquidity_amount_currency,
self.company_id.currency_id,
self.company_id,
self.date,
)
counterpart_amount_currency = -liquidity_amount_currency - write_off_amount_currency
counterpart_balance = -liquidity_balance - write_off_balance
currency_id = self.currency_id.id
if self.is_internal_transfer:
@@ -236,33 +245,33 @@ class AccountPayment(models.Model):
{
'name': liquidity_line_name or default_line_name,
'date_maturity': self.date,
'amount_currency': -counterpart_amount_currency,
'amount_currency': liquidity_amount_currency,
'currency_id': currency_id,
'debit': balance < 0.0 and -balance or 0.0,
'credit': balance > 0.0 and balance or 0.0,
'debit': liquidity_balance if liquidity_balance > 0.0 else 0.0,
'credit': -liquidity_balance if liquidity_balance < 0.0 else 0.0,
'partner_id': self.partner_id.id,
'account_id': self.journal_id.payment_debit_account_id.id if balance < 0.0 else self.journal_id.payment_credit_account_id.id,
'account_id': self.journal_id.payment_credit_account_id.id if liquidity_balance < 0.0 else self.journal_id.payment_debit_account_id.id,
},
# Receivable / Payable.
{
'name': self.payment_reference or default_line_name,
'date_maturity': self.date,
'amount_currency': counterpart_amount_currency + write_off_amount_currency if currency_id else 0.0,
'amount_currency': counterpart_amount_currency,
'currency_id': currency_id,
'debit': balance + write_off_balance > 0.0 and balance + write_off_balance or 0.0,
'credit': balance + write_off_balance < 0.0 and -balance - write_off_balance or 0.0,
'debit': counterpart_balance if counterpart_balance > 0.0 else 0.0,
'credit': -counterpart_balance if counterpart_balance < 0.0 else 0.0,
'partner_id': self.partner_id.id,
'account_id': self.destination_account_id.id,
},
]
if write_off_balance:
if not self.currency_id.is_zero(write_off_amount_currency):
# Write-off line.
line_vals_list.append({
'name': write_off_line_vals.get('name') or default_line_name,
'amount_currency': -write_off_amount_currency,
'amount_currency': write_off_amount_currency,
'currency_id': currency_id,
'debit': write_off_balance < 0.0 and -write_off_balance or 0.0,
'credit': write_off_balance > 0.0 and write_off_balance or 0.0,
'debit': write_off_balance if write_off_balance > 0.0 else 0.0,
'credit': -write_off_balance if write_off_balance < 0.0 else 0.0,
'partner_id': self.partner_id.id,
'account_id': write_off_line_vals.get('account_id'),
})
@@ -344,7 +353,9 @@ class AccountPayment(models.Model):
available_payment_methods = pay.journal_id.outbound_payment_method_ids
# Select the first available one by default.
if available_payment_methods:
if pay.payment_method_id in available_payment_methods:
pay.payment_method_id = pay.payment_method_id
elif available_payment_methods:
pay.payment_method_id = available_payment_methods[0]._origin
else:
pay.payment_method_id = False
@@ -678,12 +689,15 @@ class AccountPayment(models.Model):
})
payment_vals_to_write.update({
'amount': abs(liquidity_amount),
'payment_type': 'inbound' if liquidity_amount > 0.0 else 'outbound',
'partner_type': partner_type,
'currency_id': liquidity_lines.currency_id.id,
'destination_account_id': counterpart_lines.account_id.id,
'partner_id': liquidity_lines.partner_id.id,
})
if liquidity_amount > 0.0:
payment_vals_to_write.update({'payment_type': 'inbound'})
elif liquidity_amount < 0.0:
payment_vals_to_write.update({'payment_type': 'outbound'})
move.write(move._cleanup_write_orm_values(move, move_vals_to_write))
pay.write(move._cleanup_write_orm_values(pay, payment_vals_to_write))
@@ -708,16 +722,21 @@ class AccountPayment(models.Model):
# This allows to create a new payment with custom 'line_ids'.
if writeoff_lines:
counterpart_amount = sum(counterpart_lines.mapped('amount_currency'))
writeoff_amount = sum(writeoff_lines.mapped('amount_currency'))
counterpart_amount = counterpart_lines['amount_currency']
if writeoff_amount > 0.0 and counterpart_amount > 0.0:
sign = 1
else:
# To be consistent with the payment_difference made in account.payment.register,
# 'writeoff_amount' needs to be signed regarding the 'amount' field before the write.
# Since the write is already done at this point, we need to base the computation on accounting values.
if (counterpart_amount > 0.0) == (writeoff_amount > 0.0):
sign = -1
else:
sign = 1
writeoff_amount = abs(writeoff_amount) * sign
write_off_line_vals = {
'name': writeoff_lines[0].name,
'amount': writeoff_amount * sign,
'amount': writeoff_amount,
'account_id': writeoff_lines[0].account_id.id,
}
else:
@@ -30,7 +30,7 @@ class AccountReconcileModelPartnerMapping(models.Model):
re.compile(record.payment_ref_regex)
if record.narration_regex:
current_regex = record.narration_regex
re.compile(record.narration_regex)
re.compile(record.narration_regex)
except re.error:
raise ValidationError(_("The following regular expression is invalid to create a partner mapping: %s") % current_regex)
@@ -612,6 +612,7 @@ class AccountReconcileModel(models.Model):
LEFT JOIN account_move move ON move.id = aml.move_id AND move.state = 'posted'
LEFT JOIN account_account account ON account.id = aml.account_id
LEFT JOIN res_partner aml_partner ON aml.partner_id = aml_partner.id
LEFT JOIN account_payment payment ON payment.move_id = move.id
WHERE
aml.company_id = st_line_move.company_id
AND move.state = 'posted'
@@ -725,9 +726,11 @@ class AccountReconcileModel(models.Model):
st_ref_list += ['st_line_move.ref']
if not st_ref_list:
return "FALSE"
return r'''(move.payment_reference IS NOT NULL AND ({}))'''.format(
# payment_reference is not used on account.move for payments; ref is used instead
return r'''((move.payment_reference IS NOT NULL OR (payment.id IS NOT NULL AND move.ref IS NOT NULL)) AND ({}))'''.format(
' OR '.join(
rf"regexp_replace(move.payment_reference, '\s+', '', 'g') = regexp_replace({st_ref}, '\s+', '', 'g')"
rf"regexp_replace(CASE WHEN payment.id IS NULL THEN move.payment_reference ELSE move.ref END, '\s+', '', 'g') = regexp_replace({st_ref}, '\s+', '', 'g')"
for st_ref in st_ref_list
)
)
@@ -881,8 +884,7 @@ class AccountReconcileModel(models.Model):
# Statement line amount is equal to the total residual.
if line_currency.is_zero(line_residual_after_reconciliation):
return True
reconciled_percentage = (abs(line_residual) - abs(line_residual_after_reconciliation)) / abs(line_residual) * 100
reconciled_percentage = 100 - abs(line_residual_after_reconciliation) / abs(line_residual - line_residual_after_reconciliation) * 100
return reconciled_percentage >= self.match_total_amount_param
def _filter_candidates(self, candidates, aml_ids_to_exclude, reconciled_amls_ids):
+4 -3
View File
@@ -17,12 +17,13 @@ class Digest(models.Model):
for record in self:
start, end, company = record._get_kpi_compute_parameters()
self._cr.execute('''
SELECT SUM(line.debit)
SELECT -SUM(line.balance)
FROM account_move_line line
JOIN account_move move ON move.id = line.move_id
JOIN account_journal journal ON journal.id = move.journal_id
JOIN account_account account ON account.id = line.account_id
WHERE line.company_id = %s AND line.date >= %s AND line.date < %s
AND journal.type = 'sale'
AND account.internal_group = 'income'
AND move.state = 'posted'
''', [company.id, start, end])
query_res = self._cr.fetchone()
record.kpi_account_total_revenue_value = query_res and query_res[0] or 0.0
+1 -1
View File
@@ -56,7 +56,7 @@ class AccountFiscalPosition(models.Model):
return taxes
result = self.env['account.tax']
for tax in taxes:
taxes_correspondance = self.tax_ids.filtered(lambda t: t.tax_src_id == tax)
taxes_correspondance = self.tax_ids.filtered(lambda t: t.tax_src_id == tax._origin)
result |= taxes_correspondance.tax_dest_id if taxes_correspondance else tax
return result
@@ -53,7 +53,7 @@ tour.register('account_tour', {
}, {
trigger: "div[name=invoice_line_ids] textarea[name=name]",
extra_trigger: "[name=move_type][raw-value=out_invoice]",
content: _t("Fill in the details of the line.<br><i>Tip: all the details can be set automatically if you configure your <b>products</b>.</i>"),
content: _t("Fill in the details of the line."),
position: "bottom",
}, {
trigger: "div[name=invoice_line_ids] input[name=price_unit]",
+1
View File
@@ -19,6 +19,7 @@ from . import test_account_invoice_report
from . import test_account_journal_dashboard
from . import test_fiscal_position
from . import test_reconciliation
from . import test_sequence_mixin
from . import test_settings
from . import test_tax
from . import test_invoice_taxes
@@ -342,325 +342,6 @@ class TestAccountMove(AccountTestInvoicingCommon):
# You can remove journal items if the related journal entry is still balanced.
self.test_move.line_ids.unlink()
def test_sequence_change_date(self):
# Check setup
self.assertEqual(self.test_move.state, 'draft')
self.assertEqual(self.test_move.name, 'MISC/2016/01/0001')
self.assertEqual(fields.Date.to_string(self.test_move.date), '2016-01-01')
# Never posetd, the number must change if we change the date
self.test_move.date = '2020-02-02'
self.assertEqual(self.test_move.name, 'MISC/2020/02/0001')
# We don't recompute user's input when posting
self.test_move.name = 'MyMISC/2020/0000001'
self.test_move.action_post()
self.assertEqual(self.test_move.name, 'MyMISC/2020/0000001')
# Has been posted, and it doesn't change anymore
self.test_move.button_draft()
self.test_move.date = '2020-01-02'
self.test_move.action_post()
self.assertEqual(self.test_move.name, 'MyMISC/2020/0000001')
def test_journal_sequence(self):
self.assertEqual(self.test_move.name, 'MISC/2016/01/0001')
self.test_move.action_post()
self.assertEqual(self.test_move.name, 'MISC/2016/01/0001')
copy1 = self.test_move.copy({'date': self.test_move.date})
self.assertEqual(copy1.name, '/')
copy1.action_post()
self.assertEqual(copy1.name, 'MISC/2016/01/0002')
copy2 = self.test_move.copy({'date': self.test_move.date})
new_journal = self.test_move.journal_id.copy()
new_journal.code = "MISC2"
copy2.journal_id = new_journal
self.assertEqual(copy2.name, 'MISC2/2016/01/0001')
with Form(copy2) as move_form: # It is editable in the form
move_form.name = 'MyMISC/2016/0001'
move_form.journal_id = self.test_move.journal_id
self.assertEqual(move_form.name, '/')
move_form.journal_id = new_journal
self.assertEqual(move_form.name, 'MISC2/2016/01/0001')
move_form.name = 'MyMISC/2016/0001'
copy2.action_post()
self.assertEqual(copy2.name, 'MyMISC/2016/0001')
copy3 = copy2.copy({'date': copy2.date})
self.assertEqual(copy3.name, '/')
with self.assertRaises(AssertionError):
with Form(copy2) as move_form: # It is not editable in the form
move_form.name = 'MyMISC/2016/0002'
copy3.action_post()
self.assertEqual(copy3.name, 'MyMISC/2016/0002')
copy3.name = 'MISC2/2016/00002'
copy4 = copy2.copy({'date': copy2.date})
copy4.action_post()
self.assertEqual(copy4.name, 'MISC2/2016/00003')
copy5 = copy2.copy({'date': copy2.date})
copy5.date = '2021-02-02'
copy5.action_post()
self.assertEqual(copy5.name, 'MISC2/2021/00001')
copy5.name = 'N\'importe quoi?'
copy6 = copy5.copy({'date': copy5.date})
copy6.action_post()
self.assertEqual(copy6.name, 'N\'importe quoi?1')
def test_journal_sequence_format(self):
"""Test different format of sequences and what it becomes on another period"""
sequences = [
('JRNL/2016/00001', 'JRNL/2016/00002', 'JRNL/2016/00003', 'JRNL/2017/00001'),
('1234567', '1234568', '1234569', '1234570'),
('20190910', '20190911', '20190912', '20190913'),
('2016-0910', '2016-0911', '2016-0912', '2017-0001'),
('201603-10', '201603-11', '201604-01', '201703-01'),
('16-03-10', '16-03-11', '16-04-01', '17-03-01'),
('2016-10', '2016-11', '2016-12', '2017-01'),
('045-001-000002', '045-001-000003', '045-001-000004', '045-001-000005'),
('JRNL/2016/00001suffix', 'JRNL/2016/00002suffix', 'JRNL/2016/00003suffix', 'JRNL/2017/00001suffix'),
]
other_moves = self.env['account.move'].search([('journal_id', '=', self.test_move.journal_id.id)]) - self.test_move
other_moves.unlink() # Do not interfere when trying to get the highest name for new periods
init_move = self.test_move
next_move = init_move.copy()
next_move_month = init_move.copy()
next_move_year = init_move.copy()
init_move.date = '2016-03-12'
next_move.date = '2016-03-12'
next_move_month.date = '2016-04-12'
next_move_year.date = '2017-03-12'
next_moves = (next_move + next_move_month + next_move_year)
next_moves.action_post()
for sequence_init, sequence_next, sequence_next_month, sequence_next_year in sequences:
init_move.name = sequence_init
next_moves.name = False
next_moves._compute_name()
self.assertEqual(
[next_move.name, next_move_month.name, next_move_year.name],
[sequence_next, sequence_next_month, sequence_next_year],
)
def test_journal_next_sequence(self):
prefix = "TEST_ORDER/2016/"
self.test_move.name = f"{prefix}1"
for c in range(2, 25):
copy = self.test_move.copy({'date': self.test_move.date})
copy.name = "/"
copy.action_post()
self.assertEqual(copy.name, f"{prefix}{c}")
def test_journal_sequence_multiple_type(self):
entry, entry2, invoice, invoice2, refund, refund2 = (self.test_move.copy({'date': self.test_move.date}) for i in range(6))
(invoice + invoice2 + refund + refund2).write({
'journal_id': self.company_data['default_journal_sale'],
'partner_id': 1,
'invoice_date': '2016-01-01',
})
(invoice + invoice2).move_type = 'out_invoice'
(refund + refund2).move_type = 'out_refund'
all = (entry + entry2 + invoice + invoice2 + refund + refund2)
all.name = False
all.action_post()
self.assertEqual(entry.name, 'MISC/2016/01/0002')
self.assertEqual(entry2.name, 'MISC/2016/01/0003')
self.assertEqual(invoice.name, 'INV/2016/01/0001')
self.assertEqual(invoice2.name, 'INV/2016/01/0002')
self.assertEqual(refund.name, 'RINV/2016/01/0001')
self.assertEqual(refund2.name, 'RINV/2016/01/0002')
def test_journal_sequence_groupby_compute(self):
# Setup two journals with a sequence that resets yearly
journals = self.env['account.journal'].create([{
'name': f'Journal{i}',
'code': f'J{i}',
'type': 'general',
} for i in range(2)])
account = self.env['account.account'].search([], limit=1)
moves = self.env['account.move'].create([{
'journal_id': journals[i].id,
'line_ids': [(0, 0, {'account_id': account.id, 'name': 'line'})],
'date': '2010-01-01',
} for i in range(2)])._post()
for i in range(2):
moves[i].name = f'J{i}/2010/00001'
# Check that the moves are correctly batched
moves = self.env['account.move'].create([{
'journal_id': journals[journal_index].id,
'line_ids': [(0, 0, {'account_id': account.id, 'name': 'line'})],
'date': f'2010-{month}-01',
} for journal_index, month in [(1, 1), (0, 1), (1, 2), (1, 1)]])._post()
self.assertEqual(
moves.mapped('name'),
['J1/2010/00002', 'J0/2010/00002', 'J1/2010/00004', 'J1/2010/00003'],
)
def test_journal_override_sequence_regex(self):
other_moves = self.env['account.move'].search([('journal_id', '=', self.test_move.journal_id.id)]) - self.test_move
other_moves.unlink() # Do not interfere when trying to get the highest name for new periods
self.test_move.date = '2020-01-01'
self.test_move.name = '00000876-G 0002/2020'
next = self.test_move.copy({'date': self.test_move.date})
next.action_post()
self.assertEqual(next.name, '00000876-G 0002/2021') # Wait, I didn't want this!
next.button_draft()
next.name = False
next.journal_id.sequence_override_regex = r'^(?P<seq>\d*)(?P<suffix1>.*?)(?P<year>(\d{4})?)(?P<suffix2>)$'
next.action_post()
self.assertEqual(next.name, '00000877-G 0002/2020') # Pfew, better!
next = self.test_move.copy({'date': self.test_move.date})
next.action_post()
self.assertEqual(next.name, '00000878-G 0002/2020')
next = self.test_move.copy({'date': self.test_move.date})
next.date = "2017-05-02"
next.action_post()
self.assertEqual(next.name, '00000001-G 0002/2017')
def test_journal_sequence_ordering(self):
self.test_move.name = 'XMISC/2016/00001'
copies = reduce((lambda x, y: x+y), [self.test_move.copy({'date': self.test_move.date}) for i in range(6)])
copies[0].date = '2019-03-05'
copies[1].date = '2019-03-06'
copies[2].date = '2019-03-07'
copies[3].date = '2019-03-04'
copies[4].date = '2019-03-05'
copies[5].date = '2019-03-05'
# that entry is actualy the first one of the period, so it already has a name
# set it to '/' so that it is recomputed at post to be ordered correctly.
copies[0].name = '/'
copies.action_post()
# Ordered by date
self.assertEqual(copies[0].name, 'XMISC/2019/00002')
self.assertEqual(copies[1].name, 'XMISC/2019/00005')
self.assertEqual(copies[2].name, 'XMISC/2019/00006')
self.assertEqual(copies[3].name, 'XMISC/2019/00001')
self.assertEqual(copies[4].name, 'XMISC/2019/00003')
self.assertEqual(copies[5].name, 'XMISC/2019/00004')
# Can't have twice the same name
with self.assertRaises(ValidationError):
copies[0].name = 'XMISC/2019/00001'
# Lets remove the order by date
copies[0].name = 'XMISC/2019/10001'
copies[1].name = 'XMISC/2019/10002'
copies[2].name = 'XMISC/2019/10003'
copies[3].name = 'XMISC/2019/10004'
copies[4].name = 'XMISC/2019/10005'
copies[5].name = 'XMISC/2019/10006'
copies[4].button_draft()
copies[4].with_context(force_delete=True).unlink()
copies[5].button_draft()
wizard = Form(self.env['account.resequence.wizard'].with_context(active_ids=set(copies.ids) - set(copies[4].ids), active_model='account.move'))
new_values = json.loads(wizard.new_values)
self.assertEqual(new_values[str(copies[0].id)]['new_by_date'], 'XMISC/2019/10002')
self.assertEqual(new_values[str(copies[0].id)]['new_by_name'], 'XMISC/2019/10001')
self.assertEqual(new_values[str(copies[1].id)]['new_by_date'], 'XMISC/2019/10004')
self.assertEqual(new_values[str(copies[1].id)]['new_by_name'], 'XMISC/2019/10002')
self.assertEqual(new_values[str(copies[2].id)]['new_by_date'], 'XMISC/2019/10005')
self.assertEqual(new_values[str(copies[2].id)]['new_by_name'], 'XMISC/2019/10003')
self.assertEqual(new_values[str(copies[3].id)]['new_by_date'], 'XMISC/2019/10001')
self.assertEqual(new_values[str(copies[3].id)]['new_by_name'], 'XMISC/2019/10004')
self.assertEqual(new_values[str(copies[5].id)]['new_by_date'], 'XMISC/2019/10003')
self.assertEqual(new_values[str(copies[5].id)]['new_by_name'], 'XMISC/2019/10005')
wizard.save().resequence()
self.assertEqual(copies[3].state, 'posted')
self.assertEqual(copies[5].name, 'XMISC/2019/10005')
self.assertEqual(copies[5].state, 'draft')
def test_sequence_get_more_specific(self):
def test_date(date, name):
test = self.test_move.copy({'date': date})
test.action_post()
self.assertEqual(test.name, name)
def set_sequence(date, name):
return self.test_move.copy({'date': date, 'name': name})._post()
# Start with a continuous sequence
self.test_move.name = 'MISC/00001'
# Change the prefix to reset every year starting in 2017
new_year = set_sequence(self.test_move.date + relativedelta(years=1), 'MISC/2017/00001')
# Change the prefix to reset every month starting in February 2017
new_month = set_sequence(new_year.date + relativedelta(months=1), 'MISC/2017/02/00001')
test_date(self.test_move.date, 'MISC/00002') # Keep the old prefix in 2016
test_date(new_year.date, 'MISC/2017/00002') # Keep the new prefix in 2017
test_date(new_month.date, 'MISC/2017/02/00002') # Keep the new prefix in February 2017
# Change the prefix to never reset (again) year starting in 2018 (Please don't do that)
reset_never = set_sequence(self.test_move.date + relativedelta(years=2), 'MISC/00100')
test_date(reset_never.date, 'MISC/00101') # Keep the new prefix in 2018
def test_sequence_concurency(self):
with self.env.registry.cursor() as cr0,\
self.env.registry.cursor() as cr1,\
self.env.registry.cursor() as cr2:
env0 = api.Environment(cr0, SUPERUSER_ID, {})
env1 = api.Environment(cr1, SUPERUSER_ID, {})
env2 = api.Environment(cr2, SUPERUSER_ID, {})
journal = env0['account.journal'].create({
'name': 'concurency_test',
'code': 'CT',
'type': 'general',
})
account = env0['account.account'].create({
'code': 'CT',
'name': 'CT',
'user_type_id': env0.ref('account.data_account_type_fixed_assets').id,
})
moves = env0['account.move'].create([{
'journal_id': journal.id,
'date': fields.Date.from_string('2016-01-01'),
'line_ids': [(0, 0, {'name': 'name', 'account_id': account.id})]
}] * 3)
moves.name = '/'
moves[0].action_post()
self.assertEqual(moves.mapped('name'), ['CT/2016/01/0001', '/', '/'])
env0.cr.commit()
# start the transactions here on cr2 to simulate concurency with cr1
env2.cr.execute('SELECT 1')
move = env1['account.move'].browse(moves[1].id)
move.action_post()
env1.cr.commit()
move = env2['account.move'].browse(moves[2].id)
with self.assertRaises(psycopg2.OperationalError), env2.cr.savepoint(), mute_logger('flectra.sql_db'):
move.action_post()
self.assertEqual(moves.mapped('name'), ['CT/2016/01/0001', 'CT/2016/01/0002', '/'])
moves.button_draft()
moves.posted_before = False
moves.unlink()
journal.unlink()
account.unlink()
env0.cr.commit()
def test_add_followers_on_post(self):
# Add some existing partners, some from another company
company = self.env['res.company'].create({'name': 'Oopo'})
@@ -830,7 +830,7 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
'amount_total': 1730.0,
})
def test_out_invoice_line_onchange_rounding_price_subtotal(self):
def test_out_invoice_line_onchange_rounding_price_subtotal_1(self):
''' Seek for rounding issue on the price_subtotal when dealing with a price_unit having more digits than the
foreign currency one.
'''
@@ -904,6 +904,108 @@ class TestAccountMoveOutInvoiceOnchanges(AccountTestInvoicingCommon):
check_invoice_values(invoice_2)
def test_out_invoice_line_onchange_rounding_price_subtotal_2(self):
""" Ensure the cyclic computations implemented using onchanges are not leading to rounding issues when using
price-included taxes.
For example:
100 / 1.21 ~= 82.64 but 82.64 * 1.21 ~= 99.99 != 100.0.
"""
def check_invoice_values(invoice):
self.assertInvoiceValues(invoice, [
{
'price_unit': 100.0,
'price_subtotal': 82.64,
'debit': 0.0,
'credit': 82.64,
},
{
'price_unit': 17.36,
'price_subtotal': 17.36,
'debit': 0.0,
'credit': 17.36,
},
{
'price_unit': -100.0,
'price_subtotal': -100.0,
'debit': 100.0,
'credit': 0.0,
},
], {
'amount_untaxed': 82.64,
'amount_tax': 17.36,
'amount_total': 100.0,
})
tax = self.env['account.tax'].create({
'name': '21%',
'amount': 21.0,
'price_include': True,
'include_base_amount': True,
})
# == Test assigning tax directly ==
invoice_create = self.env['account.move'].create({
'move_type': 'out_invoice',
'invoice_date': '2017-01-01',
'date': '2017-01-01',
'partner_id': self.partner_a.id,
'invoice_line_ids': [(0, 0, {
'name': 'test line',
'price_unit': 100.0,
'account_id': self.company_data['default_account_revenue'].id,
'tax_ids': [(6, 0, tax.ids)],
})],
})
check_invoice_values(invoice_create)
move_form = Form(self.env['account.move'].with_context(default_move_type='out_invoice'))
move_form.invoice_date = fields.Date.from_string('2017-01-01')
move_form.partner_id = self.partner_a
with move_form.invoice_line_ids.new() as line_form:
line_form.name = 'test line'
line_form.price_unit = 100.0
line_form.account_id = self.company_data['default_account_revenue']
line_form.tax_ids.clear()
line_form.tax_ids.add(tax)
invoice_onchange = move_form.save()
check_invoice_values(invoice_onchange)
# == Test when the tax is set on a product ==
product = self.env['product.product'].create({
'name': 'product',
'lst_price': 100.0,
'property_account_income_id': self.company_data['default_account_revenue'].id,
'taxes_id': [(6, 0, tax.ids)],
})
move_form = Form(self.env['account.move'].with_context(default_move_type='out_invoice'))
move_form.invoice_date = fields.Date.from_string('2017-01-01')
move_form.partner_id = self.partner_a
with move_form.invoice_line_ids.new() as line_form:
line_form.product_id = product
invoice_onchange = move_form.save()
check_invoice_values(invoice_onchange)
# == Test with a fiscal position ==
fiscal_position = self.env['account.fiscal.position'].create({'name': 'fiscal_position'})
move_form = Form(self.env['account.move'].with_context(default_move_type='out_invoice'))
move_form.invoice_date = fields.Date.from_string('2017-01-01')
move_form.partner_id = self.partner_a
move_form.fiscal_position_id = fiscal_position
with move_form.invoice_line_ids.new() as line_form:
line_form.product_id = product
invoice_onchange = move_form.save()
check_invoice_values(invoice_onchange)
def test_out_invoice_line_onchange_taxes_2_price_unit_tax_included(self):
''' Seek for rounding issue in the price unit. Suppose a price_unit of 2300 with a 5.5% price-included tax
applied on it.
@@ -212,8 +212,11 @@ class TestAccountMoveReconcile(AccountTestInvoicingCommon):
FROM account_account_tag_account_move_line_rel rel
JOIN account_move_line line ON line.id = rel.account_move_line_id
WHERE line.tax_exigible IS TRUE
AND line.company_id IN %(company_ids)s
GROUP BY rel.account_account_tag_id
''')
''', {
'company_ids': tuple(self.env.companies.ids),
})
for tag_id, total_balance in self.cr.fetchall():
tag, expected_balance = expected_values[tag_id]
@@ -324,6 +324,206 @@ class TestAccountPayment(AccountTestInvoicingCommon):
},
])
def test_inbound_payment_sync_writeoff_debit_sign(self):
payment = self.env['account.payment'].create({
'amount': 100.0,
'payment_type': 'inbound',
'partner_type': 'customer',
})
# ==== Edit the account.move.line ====
liquidity_lines, counterpart_lines, writeoff_lines = payment._seek_for_lines()
payment.move_id.write({
'line_ids': [
(1, liquidity_lines.id, {'debit': 100.0}),
(1, counterpart_lines.id, {'credit': 125.0}),
(0, 0, {'debit': 25.0, 'account_id': self.company_data['default_account_revenue'].id}),
],
})
self.assertRecordValues(payment, [{
'payment_type': 'inbound',
'partner_type': 'customer',
'amount': 100.0,
}])
# ==== Edit the account.payment amount ====
payment.write({
'partner_type': 'supplier',
'amount': 100.1,
'destination_account_id': self.company_data['default_account_payable'].id,
})
self.assertRecordValues(payment.line_ids.sorted('balance'), [
{
'debit': 0.0,
'credit': 125.1,
'account_id': self.company_data['default_account_payable'].id,
},
{
'debit': 25.0,
'credit': 0.0,
'account_id': self.company_data['default_account_revenue'].id,
},
{
'debit': 100.1,
'credit': 0.0,
'account_id': self.payment_debit_account_id.id,
},
])
def test_inbound_payment_sync_writeoff_credit_sign(self):
payment = self.env['account.payment'].create({
'amount': 100.0,
'payment_type': 'inbound',
'partner_type': 'customer',
})
# ==== Edit the account.move.line ====
liquidity_lines, counterpart_lines, writeoff_lines = payment._seek_for_lines()
payment.move_id.write({
'line_ids': [
(1, liquidity_lines.id, {'debit': 100.0}),
(1, counterpart_lines.id, {'credit': 75.0}),
(0, 0, {'credit': 25.0, 'account_id': self.company_data['default_account_revenue'].id}),
],
})
self.assertRecordValues(payment, [{
'payment_type': 'inbound',
'partner_type': 'customer',
'amount': 100.0,
}])
# ==== Edit the account.payment amount ====
payment.write({
'partner_type': 'supplier',
'amount': 100.1,
'destination_account_id': self.company_data['default_account_payable'].id,
})
self.assertRecordValues(payment.line_ids.sorted('balance'), [
{
'debit': 0.0,
'credit': 75.1,
'account_id': self.company_data['default_account_payable'].id,
},
{
'debit': 0.0,
'credit': 25.0,
'account_id': self.company_data['default_account_revenue'].id,
},
{
'debit': 100.1,
'credit': 0.0,
'account_id': self.payment_debit_account_id.id,
},
])
def test_outbound_payment_sync_writeoff_debit_sign(self):
payment = self.env['account.payment'].create({
'amount': 100.0,
'payment_type': 'outbound',
'partner_type': 'supplier',
})
# ==== Edit the account.move.line ====
liquidity_lines, counterpart_lines, writeoff_lines = payment._seek_for_lines()
payment.move_id.write({
'line_ids': [
(1, liquidity_lines.id, {'credit': 100.0}),
(1, counterpart_lines.id, {'debit': 75.0}),
(0, 0, {'debit': 25.0, 'account_id': self.company_data['default_account_revenue'].id}),
],
})
self.assertRecordValues(payment, [{
'payment_type': 'outbound',
'partner_type': 'supplier',
'amount': 100.0,
}])
# ==== Edit the account.payment amount ====
payment.write({
'partner_type': 'customer',
'amount': 100.1,
'destination_account_id': self.company_data['default_account_receivable'].id,
})
self.assertRecordValues(payment.line_ids.sorted('balance'), [
{
'debit': 0.0,
'credit': 100.1,
'account_id': self.payment_credit_account_id.id,
},
{
'debit': 25.0,
'credit': 0.0,
'account_id': self.company_data['default_account_revenue'].id,
},
{
'debit': 75.1,
'credit': 0.0,
'account_id': self.company_data['default_account_receivable'].id,
},
])
def test_outbound_payment_sync_writeoff_credit_sign(self):
payment = self.env['account.payment'].create({
'amount': 100.0,
'payment_type': 'outbound',
'partner_type': 'supplier',
})
# ==== Edit the account.move.line ====
liquidity_lines, counterpart_lines, writeoff_lines = payment._seek_for_lines()
payment.move_id.write({
'line_ids': [
(1, liquidity_lines.id, {'credit': 100.0}),
(1, counterpart_lines.id, {'debit': 125.0}),
(0, 0, {'credit': 25.0, 'account_id': self.company_data['default_account_revenue'].id}),
],
})
self.assertRecordValues(payment, [{
'payment_type': 'outbound',
'partner_type': 'supplier',
'amount': 100.0,
}])
# ==== Edit the account.payment amount ====
payment.write({
'partner_type': 'customer',
'amount': 100.1,
'destination_account_id': self.company_data['default_account_receivable'].id,
})
self.assertRecordValues(payment.line_ids.sorted('balance'), [
{
'debit': 0.0,
'credit': 100.1,
'account_id': self.payment_credit_account_id.id,
},
{
'debit': 0.0,
'credit': 25.0,
'account_id': self.company_data['default_account_revenue'].id,
},
{
'debit': 125.1,
'credit': 0.0,
'account_id': self.company_data['default_account_receivable'].id,
},
])
def test_internal_transfer(self):
copy_receivable = self.copy_account(self.company_data['default_account_receivable'])
@@ -350,7 +350,7 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
def test_matching_fields_match_total_amount(self):
# Check match_total_amount: line amount >= total residual amount.
self.rule_1.match_total_amount_param = 90.0
self.bank_line_1.amount += 5
self.bank_line_1.amount += 10
self._check_statement_matching(self.rule_1, {
self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1, 'status': 'write_off', 'partner': self.bank_line_1.partner_id},
self.bank_line_2.id: {'aml_ids': [
@@ -361,11 +361,11 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1, 'partner': self.cash_line_1.partner_id},
})
self.rule_1.match_total_amount_param = 100.0
self.bank_line_1.amount -= 5
self.bank_line_1.amount -= 10
# Check match_total_amount: line amount <= total residual amount.
self.rule_1.match_total_amount_param = 90.0
self.bank_line_1.amount -= 5
self.bank_line_1.amount -= 10
self._check_statement_matching(self.rule_1, {
self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1, 'status': 'write_off', 'partner': self.bank_line_1.partner_id},
self.bank_line_2.id: {'aml_ids': [
@@ -376,7 +376,37 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1, 'partner': self.cash_line_1.partner_id},
})
self.rule_1.match_total_amount_param = 100.0
self.bank_line_1.amount += 5
self.bank_line_1.amount += 10
# Check match_total_amount: line amount >= total residual amount, match_total_amount_param just not matched.
self.rule_1.match_total_amount_param = 90.0
self.bank_line_1.amount += 10.01
self._check_statement_matching(self.rule_1, {
self.bank_line_1.id: {'aml_ids': []},
self.bank_line_2.id: {'aml_ids': [
self.invoice_line_1.id,
self.invoice_line_2.id,
self.invoice_line_3.id,
], 'model': self.rule_1, 'partner': self.bank_line_2.partner_id},
self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1, 'partner': self.cash_line_1.partner_id},
})
self.rule_1.match_total_amount_param = 100.0
self.bank_line_1.amount -= 10.01
# Check match_total_amount: line amount <= total residual amount, match_total_amount_param just not matched.
self.rule_1.match_total_amount_param = 90.0
self.bank_line_1.amount -= 10.01
self._check_statement_matching(self.rule_1, {
self.bank_line_1.id: {'aml_ids': []},
self.bank_line_2.id: {'aml_ids': [
self.invoice_line_1.id,
self.invoice_line_2.id,
self.invoice_line_3.id,
], 'model': self.rule_1, 'partner': self.bank_line_2.partner_id},
self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1, 'partner': self.cash_line_1.partner_id},
})
self.rule_1.match_total_amount_param = 100.0
self.bank_line_1.amount += 10.01
def test_matching_fields_match_partner_category_ids(self):
test_category = self.env['res.partner.category'].create({'name': 'Consulting Services'})
@@ -919,3 +949,39 @@ class TestReconciliationMatchingRules(AccountTestInvoicingCommon):
self.bank_line_1.id: {'aml_ids': [self.invoice_line_1.id], 'model': self.rule_1, 'status': 'write_off', 'partner': self.bank_line_1.partner_id},
self.bank_line_2.id: {'aml_ids': [self.invoice_line_2.id], 'model': second_inv_matching_rule, 'partner': self.bank_line_2.partner_id}
}, statements=self.bank_st)
def test_payment_similar_communications(self):
def create_payment_line(amount, memo, partner):
payment = self.env['account.payment'].create({
'amount': amount,
'payment_type': 'inbound',
'partner_type': 'customer',
'partner_id': partner.id,
'ref': memo,
'destination_account_id': self.company_data['default_account_receivable'].id,
})
payment.action_post()
return payment.line_ids.filtered(lambda x: x.account_id.user_type_id.type not in {'receivable', 'payable'})
payment_partner = self.env['res.partner'].create({
'name': "Bernard Gagnant",
})
self.rule_1.match_partner_ids = [(6, 0, payment_partner.ids)]
pmt_line_1 = create_payment_line(500, 'a1b2c3', payment_partner)
pmt_line_2 = create_payment_line(500, 'a1b2c3', payment_partner)
pmt_line_3 = create_payment_line(500, 'd1e2f3', payment_partner)
self.bank_line_1.write({
'amount': 1000,
'payment_ref': 'a1b2c3',
'partner_id': payment_partner.id,
})
self.bank_line_2.unlink()
self.rule_1.match_total_amount = False
self._check_statement_matching(self.rule_1, {
self.bank_line_1.id: {'aml_ids': (pmt_line_1 + pmt_line_2).ids, 'model': self.rule_1, 'partner': payment_partner},
}, statements=self.bank_line_1.statement_id)
+386
View File
@@ -0,0 +1,386 @@
# -*- coding: utf-8 -*-
from flectra.addons.account.tests.common import AccountTestInvoicingCommon
from flectra.tests import tagged
from flectra.tests.common import Form
from flectra import fields, api, SUPERUSER_ID
from flectra.exceptions import ValidationError
from flectra.tools import mute_logger
from dateutil.relativedelta import relativedelta
from functools import reduce
import json
import psycopg2
@tagged('post_install', '-at_install')
class TestSequenceMixin(AccountTestInvoicingCommon):
@classmethod
def setUpClass(cls, chart_template_ref=None):
super().setUpClass(chart_template_ref=chart_template_ref)
cls.test_move = cls.create_move()
@classmethod
def create_move(cls, move_type=None, date=None, journal=None, name=None, post=False):
move = cls.env['account.move'].create({
'move_type': move_type or 'entry',
'date': date or '2016-01-01',
'line_ids': [
(0, None, {
'name': 'line',
'account_id': cls.company_data['default_account_revenue'].id,
}),
]
})
if journal:
move.name = False
move.journal_id = journal
if name:
move.name = name
if post:
move.action_post()
return move
def test_sequence_change_date(self):
"""Change the sequence when we change the date iff it has never been posted."""
# Check setup
self.assertEqual(self.test_move.state, 'draft')
self.assertEqual(self.test_move.name, 'MISC/2016/01/0001')
self.assertEqual(fields.Date.to_string(self.test_move.date), '2016-01-01')
# Never posetd, the number must change if we change the date
self.test_move.date = '2020-02-02'
self.assertEqual(self.test_move.name, 'MISC/2020/02/0001')
# We don't recompute user's input when posting
self.test_move.name = 'MyMISC/2020/0000001'
self.test_move.action_post()
self.assertEqual(self.test_move.name, 'MyMISC/2020/0000001')
# Has been posted, and it doesn't change anymore
self.test_move.button_draft()
self.test_move.date = '2020-01-02'
self.test_move.action_post()
self.assertEqual(self.test_move.name, 'MyMISC/2020/0000001')
def test_journal_sequence(self):
self.assertEqual(self.test_move.name, 'MISC/2016/01/0001')
self.test_move.action_post()
self.assertEqual(self.test_move.name, 'MISC/2016/01/0001')
copy1 = self.create_move(date=self.test_move.date)
self.assertEqual(copy1.name, '/')
copy1.action_post()
self.assertEqual(copy1.name, 'MISC/2016/01/0002')
copy2 = self.create_move(date=self.test_move.date)
new_journal = self.test_move.journal_id.copy()
new_journal.code = "MISC2"
copy2.journal_id = new_journal
self.assertEqual(copy2.name, 'MISC2/2016/01/0001')
with Form(copy2) as move_form: # It is editable in the form
move_form.name = 'MyMISC/2016/0001'
move_form.journal_id = self.test_move.journal_id
self.assertEqual(move_form.name, '/')
move_form.journal_id = new_journal
self.assertEqual(move_form.name, 'MISC2/2016/01/0001')
move_form.name = 'MyMISC/2016/0001'
copy2.action_post()
self.assertEqual(copy2.name, 'MyMISC/2016/0001')
copy3 = self.create_move(date=copy2.date, journal=new_journal)
self.assertEqual(copy3.name, '/')
with self.assertRaises(AssertionError):
with Form(copy2) as move_form: # It is not editable in the form
move_form.name = 'MyMISC/2016/0002'
copy3.action_post()
self.assertEqual(copy3.name, 'MyMISC/2016/0002')
copy3.name = 'MISC2/2016/00002'
copy4 = self.create_move(date=copy2.date, journal=new_journal)
copy4.action_post()
self.assertEqual(copy4.name, 'MISC2/2016/00003')
copy5 = self.create_move(date=copy2.date, journal=new_journal)
copy5.date = '2021-02-02'
copy5.action_post()
self.assertEqual(copy5.name, 'MISC2/2021/00001')
copy5.name = 'N\'importe quoi?'
copy6 = self.create_move(date=copy5.date, journal=new_journal)
copy6.action_post()
self.assertEqual(copy6.name, 'N\'importe quoi?1')
def test_journal_sequence_format(self):
"""Test different format of sequences and what it becomes on another period"""
sequences = [
('JRNL/2016/00001', 'JRNL/2016/00002', 'JRNL/2016/00003', 'JRNL/2017/00001'),
('1234567', '1234568', '1234569', '1234570'),
('20190910', '20190911', '20190912', '20190913'),
('2016-0910', '2016-0911', '2016-0912', '2017-0001'),
('201603-10', '201603-11', '201604-01', '201703-01'),
('16-03-10', '16-03-11', '16-04-01', '17-03-01'),
('2016-10', '2016-11', '2016-12', '2017-01'),
('045-001-000002', '045-001-000003', '045-001-000004', '045-001-000005'),
('JRNL/2016/00001suffix', 'JRNL/2016/00002suffix', 'JRNL/2016/00003suffix', 'JRNL/2017/00001suffix'),
]
init_move = self.create_move(date='2016-03-12')
next_move = self.create_move(date='2016-03-12')
next_move_month = self.create_move(date='2016-04-12')
next_move_year = self.create_move(date='2017-03-12')
next_moves = (next_move + next_move_month + next_move_year)
next_moves.action_post()
for sequence_init, sequence_next, sequence_next_month, sequence_next_year in sequences:
init_move.name = sequence_init
next_moves.name = False
next_moves._compute_name()
self.assertEqual(
[next_move.name, next_move_month.name, next_move_year.name],
[sequence_next, sequence_next_month, sequence_next_year],
)
def test_journal_next_sequence(self):
"""Sequences behave correctly even when there is not enough padding."""
prefix = "TEST_ORDER/2016/"
self.test_move.name = f"{prefix}1"
for c in range(2, 25):
copy = self.create_move(date=self.test_move.date)
copy.name = "/"
copy.action_post()
self.assertEqual(copy.name, f"{prefix}{c}")
def test_journal_sequence_multiple_type(self):
"""Domain is computed accordingly to different types."""
entry, entry2, invoice, invoice2, refund, refund2 = (
self.create_move(date='2016-01-01')
for i in range(6)
)
(invoice + invoice2 + refund + refund2).write({
'journal_id': self.company_data['default_journal_sale'],
'partner_id': 1,
'invoice_date': '2016-01-01',
})
(invoice + invoice2).move_type = 'out_invoice'
(refund + refund2).move_type = 'out_refund'
all = (entry + entry2 + invoice + invoice2 + refund + refund2)
all.name = False
all.action_post()
self.assertEqual(entry.name, 'MISC/2016/01/0002')
self.assertEqual(entry2.name, 'MISC/2016/01/0003')
self.assertEqual(invoice.name, 'INV/2016/01/0001')
self.assertEqual(invoice2.name, 'INV/2016/01/0002')
self.assertEqual(refund.name, 'RINV/2016/01/0001')
self.assertEqual(refund2.name, 'RINV/2016/01/0002')
def test_journal_sequence_groupby_compute(self):
"""The grouping optimization is correctly done."""
# Setup two journals with a sequence that resets yearly
journals = self.env['account.journal'].create([{
'name': f'Journal{i}',
'code': f'J{i}',
'type': 'general',
} for i in range(2)])
account = self.env['account.account'].search([], limit=1)
moves = self.env['account.move'].create([{
'journal_id': journals[i].id,
'line_ids': [(0, 0, {'account_id': account.id, 'name': 'line'})],
'date': '2010-01-01',
} for i in range(2)])._post()
for i in range(2):
moves[i].name = f'J{i}/2010/00001'
# Check that the moves are correctly batched
moves = self.env['account.move'].create([{
'journal_id': journals[journal_index].id,
'line_ids': [(0, 0, {'account_id': account.id, 'name': 'line'})],
'date': f'2010-{month}-01',
} for journal_index, month in [(1, 1), (0, 1), (1, 2), (1, 1)]])._post()
self.assertEqual(
moves.mapped('name'),
['J1/2010/00002', 'J0/2010/00002', 'J1/2010/00004', 'J1/2010/00003'],
)
journals[0].code = 'OLD'
journals.flush()
journal_same_code = self.env['account.journal'].create([{
'name': 'Journal0',
'code': 'J0',
'type': 'general',
}])
moves = (
self.create_move(date='2010-01-01', journal=journal_same_code, name='J0/2010/00001')
+ self.create_move(date='2010-01-01', journal=journal_same_code)
+ self.create_move(date='2010-01-01', journal=journal_same_code)
+ self.create_move(date='2010-01-01', journal=journals[0])
)._post()
self.assertEqual(
moves.mapped('name'),
['J0/2010/00001', 'J0/2010/00002', 'J0/2010/00003', 'J0/2010/00003'],
)
def test_journal_override_sequence_regex(self):
"""There is a possibility to override the regex and change the order of the paramters."""
self.create_move(date='2020-01-01', name='00000876-G 0002/2020')
next = self.create_move(date='2020-01-01')
next.action_post()
self.assertEqual(next.name, '00000876-G 0002/2021') # Wait, I didn't want this!
next.button_draft()
next.name = False
next.journal_id.sequence_override_regex = r'^(?P<seq>\d*)(?P<suffix1>.*?)(?P<year>(\d{4})?)(?P<suffix2>)$'
next.action_post()
self.assertEqual(next.name, '00000877-G 0002/2020') # Pfew, better!
next = self.create_move(date='2020-01-01')
next.action_post()
self.assertEqual(next.name, '00000878-G 0002/2020')
next = self.create_move(date='2017-05-02')
next.action_post()
self.assertEqual(next.name, '00000001-G 0002/2017')
def test_journal_sequence_ordering(self):
"""Entries are correctly sorted when posting multiple at once."""
self.test_move.name = 'XMISC/2016/00001'
copies = reduce((lambda x, y: x+y), [
self.create_move(date=self.test_move.date)
for i in range(6)
])
copies[0].date = '2019-03-05'
copies[1].date = '2019-03-06'
copies[2].date = '2019-03-07'
copies[3].date = '2019-03-04'
copies[4].date = '2019-03-05'
copies[5].date = '2019-03-05'
# that entry is actualy the first one of the period, so it already has a name
# set it to '/' so that it is recomputed at post to be ordered correctly.
copies[0].name = '/'
copies.action_post()
# Ordered by date
self.assertEqual(copies[0].name, 'XMISC/2019/00002')
self.assertEqual(copies[1].name, 'XMISC/2019/00005')
self.assertEqual(copies[2].name, 'XMISC/2019/00006')
self.assertEqual(copies[3].name, 'XMISC/2019/00001')
self.assertEqual(copies[4].name, 'XMISC/2019/00003')
self.assertEqual(copies[5].name, 'XMISC/2019/00004')
# Can't have twice the same name
with self.assertRaises(ValidationError):
copies[0].name = 'XMISC/2019/00001'
# Lets remove the order by date
copies[0].name = 'XMISC/2019/10001'
copies[1].name = 'XMISC/2019/10002'
copies[2].name = 'XMISC/2019/10003'
copies[3].name = 'XMISC/2019/10004'
copies[4].name = 'XMISC/2019/10005'
copies[5].name = 'XMISC/2019/10006'
copies[4].button_draft()
copies[4].with_context(force_delete=True).unlink()
copies[5].button_draft()
wizard = Form(self.env['account.resequence.wizard'].with_context(
active_ids=set(copies.ids) - set(copies[4].ids),
active_model='account.move'),
)
new_values = json.loads(wizard.new_values)
self.assertEqual(new_values[str(copies[0].id)]['new_by_date'], 'XMISC/2019/10002')
self.assertEqual(new_values[str(copies[0].id)]['new_by_name'], 'XMISC/2019/10001')
self.assertEqual(new_values[str(copies[1].id)]['new_by_date'], 'XMISC/2019/10004')
self.assertEqual(new_values[str(copies[1].id)]['new_by_name'], 'XMISC/2019/10002')
self.assertEqual(new_values[str(copies[2].id)]['new_by_date'], 'XMISC/2019/10005')
self.assertEqual(new_values[str(copies[2].id)]['new_by_name'], 'XMISC/2019/10003')
self.assertEqual(new_values[str(copies[3].id)]['new_by_date'], 'XMISC/2019/10001')
self.assertEqual(new_values[str(copies[3].id)]['new_by_name'], 'XMISC/2019/10004')
self.assertEqual(new_values[str(copies[5].id)]['new_by_date'], 'XMISC/2019/10003')
self.assertEqual(new_values[str(copies[5].id)]['new_by_name'], 'XMISC/2019/10005')
wizard.save().resequence()
self.assertEqual(copies[3].state, 'posted')
self.assertEqual(copies[5].name, 'XMISC/2019/10005')
self.assertEqual(copies[5].state, 'draft')
def test_sequence_get_more_specific(self):
"""There is the ability to change the format (i.e. from yearly to montlhy)."""
def test_date(date, name):
test = self.create_move(date=date)
test.action_post()
self.assertEqual(test.name, name)
def set_sequence(date, name):
return self.create_move(date=date, name=name)._post()
# Start with a continuous sequence
self.test_move.name = 'MISC/00001'
# Change the prefix to reset every year starting in 2017
new_year = set_sequence(self.test_move.date + relativedelta(years=1), 'MISC/2017/00001')
# Change the prefix to reset every month starting in February 2017
new_month = set_sequence(new_year.date + relativedelta(months=1), 'MISC/2017/02/00001')
test_date(self.test_move.date, 'MISC/00002') # Keep the old prefix in 2016
test_date(new_year.date, 'MISC/2017/00002') # Keep the new prefix in 2017
test_date(new_month.date, 'MISC/2017/02/00002') # Keep the new prefix in February 2017
# Change the prefix to never reset (again) year starting in 2018 (Please don't do that)
reset_never = set_sequence(self.test_move.date + relativedelta(years=2), 'MISC/00100')
test_date(reset_never.date, 'MISC/00101') # Keep the new prefix in 2018
def test_sequence_concurency(self):
"""Computing the same name in concurent transactions is not allowed."""
with self.env.registry.cursor() as cr0,\
self.env.registry.cursor() as cr1,\
self.env.registry.cursor() as cr2:
env0 = api.Environment(cr0, SUPERUSER_ID, {})
env1 = api.Environment(cr1, SUPERUSER_ID, {})
env2 = api.Environment(cr2, SUPERUSER_ID, {})
journal = env0['account.journal'].create({
'name': 'concurency_test',
'code': 'CT',
'type': 'general',
})
account = env0['account.account'].create({
'code': 'CT',
'name': 'CT',
'user_type_id': env0.ref('account.data_account_type_fixed_assets').id,
})
moves = env0['account.move'].create([{
'journal_id': journal.id,
'date': fields.Date.from_string('2016-01-01'),
'line_ids': [(0, 0, {'name': 'name', 'account_id': account.id})]
}] * 3)
moves.name = '/'
moves[0].action_post()
self.assertEqual(moves.mapped('name'), ['CT/2016/01/0001', '/', '/'])
env0.cr.commit()
# start the transactions here on cr2 to simulate concurency with cr1
env2.cr.execute('SELECT 1')
move = env1['account.move'].browse(moves[1].id)
move.action_post()
env1.cr.commit()
move = env2['account.move'].browse(moves[2].id)
with self.assertRaises(psycopg2.OperationalError), env2.cr.savepoint(), mute_logger('flectra.sql_db'):
move.action_post()
self.assertEqual(moves.mapped('name'), ['CT/2016/01/0001', 'CT/2016/01/0002', '/'])
moves.button_draft()
moves.posted_before = False
moves.unlink()
journal.unlink()
account.unlink()
env0.cr.commit()
@@ -18,7 +18,7 @@
<group/> <!-- put Accounting group under Amount group -->
<group name="accounting" string="Accounting">
<field name="general_account_id" options="{'no_create': True}"/>
<field name="move_id"/>
<field name="move_id" options="{'no_create': True}"/>
</group>
</group>
</data>
+12 -12
View File
@@ -18,19 +18,19 @@
<field name="name"/>
<field name="partner_id"
domain="['|', ('parent_id', '=', False), ('is_company', '=', True)]"
attrs="{'readonly': [('parent_state', '=', 'posted')]}"/>
readonly="1"/>
</group>
<notebook colspan="4">
<page string="Information" name="information">
<group>
<group string="Amount">
<field name="account_id" options="{'no_create': True}" domain="[('company_id', '=', company_id)]" attrs="{'readonly':[('parent_state','=','posted')]}"/>
<field name="debit" attrs="{'readonly':[('parent_state','=','posted')]}"/>
<field name="credit" attrs="{'readonly':[('parent_state','=','posted')]}"/>
<field name="quantity" attrs="{'readonly':[('parent_state','=','posted')]}"/>
<field name="account_id" options="{'no_create': True}" domain="[('company_id', '=', company_id)]" readonly="1"/>
<field name="debit" readonly="1"/>
<field name="credit" readonly="1"/>
<field name="quantity" readonly="1"/>
</group>
<group string="Accounting Documents">
<field name="move_id" attrs="{'readonly':[('parent_state','=','posted')]}"/>
<field name="move_id" readonly="1"/>
<field name="statement_id" readonly="True" attrs="{'invisible': [('statement_id','=',False)]}"/>
</group>
<group string="Dates">
@@ -41,7 +41,7 @@
<group string="Taxes" attrs="{'invisible': [('tax_line_id','=',False), ('tax_ids','=',[])]}">
<field name="tax_line_id" readonly="1" attrs="{'invisible': [('tax_line_id','=',False)]}"/>
<field name="tax_ids" widget="many2many_tags" readonly="1" attrs="{'invisible': [('tax_ids','=',[])]}"/>
<field name="tax_exigible" attrs="{'readonly':[('parent_state','=','posted')]}"/>
<field name="tax_exigible" readonly="1"/>
<field name="tax_audit"/>
</group>
<group string="Matching" attrs="{'invisible':[('matched_debit_ids', '=', []),('matched_credit_ids', '=', [])]}">
@@ -63,7 +63,7 @@
<field name="amount_currency"/>
</group>
<group string="Product" attrs="{'invisible': [('product_id', '=', False)]}">
<field name="product_id"/>
<field name="product_id" readonly="1"/>
</group>
<group string="States">
<field name="blocked"/>
@@ -71,7 +71,7 @@
<group string="Analytic" groups="analytic.group_analytic_accounting,analytic.group_analytic_tags">
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"
domain="['|', ('company_id', '=', company_id), ('company_id', '=', False)]"
attrs="{'readonly':[('parent_state','=','posted')]}"/>
readonly="1"/>
<field name="analytic_tag_ids" groups="analytic.group_analytic_tags"
widget="many2many_tags"/>
</group>
@@ -660,7 +660,7 @@
<field name="payment_reference"
attrs="{'invisible': [('move_type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))], 'readonly': [('state', '!=', 'draft')]}"/>
<field name="partner_bank_id"
context="{'default_partner_id': commercial_partner_id}"
context="{'default_partner_id': bank_partner_id}"
domain="[('partner_id', '=', bank_partner_id)]"
attrs="{'invisible': [('move_type', 'not in', ('in_invoice', 'in_refund', 'in_receipt'))], 'readonly': [('state', '!=', 'draft')]}"/>
<label name="invoice_vendor_bill_id_label" for="invoice_vendor_bill_id" string="Auto-Complete" class="oe_edit_only"
@@ -895,7 +895,7 @@
</group>
<group>
<field name="analytic_tag_ids" groups="analytic.group_analytic_tags" widget="many2many_tags"/>
<field name="account_id" options="{'no_create': True}" domain="[('company_id', '=', company_id)]" attrs="{'readonly':[('parent_state','=','posted')]}"/>
<field name="account_id" options="{'no_create': True}" domain="[('company_id', '=', company_id)]" readonly="1"/>
<field name="tax_ids" widget="many2many_tags"/>
<field name="analytic_account_id" groups="analytic.group_analytic_accounting"/>
</group>
@@ -1060,7 +1060,7 @@
<field name="invoice_user_id" domain="[('share', '=', False)]" widget="many2one_avatar_user"/>
<field name="invoice_origin" string="Source Document" force_save="1" invisible="1"/>
<field name="partner_bank_id"
context="{'default_partner_id': commercial_partner_id}"
context="{'default_partner_id': bank_partner_id}"
domain="[('partner_id', '=', bank_partner_id)]"
attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="qr_code_method"
@@ -84,7 +84,7 @@ class AccountPayment(models.Model):
def _inverse_check_number(self):
for payment in self:
if payment.check_number:
sequence = payment.journal_id.check_sequence_id
sequence = payment.journal_id.check_sequence_id.sudo()
sequence.padding = len(payment.check_number)
@api.depends('payment_type', 'journal_id', 'partner_id')
@@ -98,6 +98,20 @@ class AccountEdiFormat(models.Model):
# TO OVERRIDE
return False
def _get_embedding_to_invoice_pdf_values(self, invoice):
""" Get the values to embed to pdf.
:returns: A dictionary {'name': name, 'datas': datas} or False if there are no values to embed.
* name: The name of the file.
* datas: The bytes ot the file.
"""
self.ensure_one()
attachment = invoice._get_edi_attachment(self)
if not attachment or not self._is_embedding_to_invoice_pdf_needed():
return False
datas = base64.b64decode(attachment.with_context(bin_size=False).datas)
return {'name': attachment.name, 'datas': datas}
def _support_batching(self, move=None, state=None, company=None):
""" Indicate if we can send multiple documents in the same time to the web services.
If True, the _post_%s_edi methods will get multiple documents in the same time.
@@ -247,11 +261,10 @@ class AccountEdiFormat(models.Model):
:returns: the same pdf_content with the EDI of the invoice embed in it.
"""
attachments = []
for edi_format in self:
attachment = invoice._get_edi_attachment(edi_format)
if attachment and edi_format._is_embedding_to_invoice_pdf_needed():
datas = base64.b64decode(attachment.with_context(bin_size=False).datas)
attachments.append({'name': attachment.name, 'datas': datas})
for edi_format in self.filtered(lambda edi_format: edi_format._is_embedding_to_invoice_pdf_needed()):
attach = edi_format._get_embedding_to_invoice_pdf_values(invoice)
if attach:
attachments.append(attach)
if attachments:
# Add the attachments to the pdf file
+3 -3
View File
@@ -57,7 +57,7 @@ class AccountEdiTestCommon(AccountTestInvoicingCommon):
invoice.message_post(attachment_ids=[attachment.id])
def create_invoice_from_file(self, module_name, subfolder, filename):
file_path = get_module_resource(module_name, 'test_file', filename)
file_path = get_module_resource(module_name, subfolder, filename)
file = open(file_path, 'rb').read()
attachment = self.env['ir.attachment'].create({
@@ -65,9 +65,9 @@ class AccountEdiTestCommon(AccountTestInvoicingCommon):
'datas': base64.encodebytes(file),
'res_model': 'account.move',
})
journal_id = self.company_data['default_journal_sale']
journal_id.with_context(default_move_type='in_invoice').create_invoice_from_attachment(attachment.ids)
action_vals = journal_id.with_context(default_move_type='in_invoice').create_invoice_from_attachment(attachment.ids)
return self.env['account.move'].browse(action_vals['res_id'])
def assert_generated_file_equal(self, invoice, expected_values, applied_xpath=None):
invoice.action_post()
@@ -112,7 +112,7 @@
<!-- Document Headers. -->
<rsm:ExchangedDocument>
<ram:ID t-esc="record.ref"/>
<ram:ID t-esc="record.name"/>
<ram:TypeCode t-esc="'381' if 'refund' in record.move_type else '380'"/>
<ram:IssueDateTime>
<udt:DateTimeString format="102" t-esc="format_date(record.invoice_date)"/>
@@ -45,6 +45,12 @@ class AccountEdiFormat(models.Model):
self.ensure_one()
return True if self.code == 'facturx_1_0_05' else super()._is_embedding_to_invoice_pdf_needed()
def _get_embedding_to_invoice_pdf_values(self, invoice):
values = super()._get_embedding_to_invoice_pdf_values(invoice)
if values and self.code == 'facturx_1_0_05':
values['name'] = 'factur-x.xml'
return values
def _export_facturx(self, invoice):
def format_date(dt):
@@ -66,6 +66,7 @@ class TestAccountEdiFacturx(AccountEdiTestCommon):
</GuidelineSpecifiedDocumentContextParameter>
</ExchangedDocumentContext>
<ExchangedDocument>
<ID>INV/2017/01/0001</ID>
<TypeCode>380</TypeCode>
<IssueDateTime>
<DateTimeString format="102">20170101</DateTimeString>
@@ -209,6 +210,11 @@ class TestAccountEdiFacturx(AccountEdiTestCommon):
self.assert_generated_file_equal(self.invoice, self.expected_invoice_facturx_values, applied_xpath)
def test_export_pdf(self):
self.invoice.action_post()
pdf_values = self.edi_format._get_embedding_to_invoice_pdf_values(self.invoice)
self.assertEqual(pdf_values['name'], 'factur-x.xml')
####################################################
# Test import
####################################################
@@ -119,29 +119,6 @@ class AccountEdiFormat(models.Model):
else:
invoice_form.partner_id = self.env['res.partner']
# Regenerate PDF
attachments = self.env['ir.attachment']
elements = tree.xpath('//cac:AdditionalDocumentReference', namespaces=namespaces)
for element in elements:
attachment_name = element.xpath('cbc:ID', namespaces=namespaces)
attachment_data = element.xpath('cac:Attachment//cbc:EmbeddedDocumentBinaryObject', namespaces=namespaces)
if attachment_name and attachment_data:
text = attachment_data[0].text
# Normalize the name of the file : some e-fff emitters put the full path of the file
# (Windows or Linux style) and/or the name of the xml instead of the pdf.
# Get only the filename with a pdf extension.
name = PureWindowsPath(attachment_name[0].text).stem + '.pdf'
attachments |= self.env['ir.attachment'].create({
'name': name,
'res_id': invoice.id,
'res_model': 'account.move',
'datas': text + '=' * (len(text) % 3), # Fix incorrect padding
'type': 'binary',
'mimetype': 'application/pdf',
})
if attachments:
invoice.with_context(no_new_invoice=True).message_post(attachment_ids=attachments.ids)
# Lines
lines_elements = tree.xpath('//cac:InvoiceLine', namespaces=namespaces)
for eline in lines_elements:
@@ -196,4 +173,29 @@ class AccountEdiFormat(models.Model):
if tax:
invoice_line_form.tax_ids.add(tax)
return invoice_form.save()
invoice = invoice_form.save()
# Regenerate PDF
attachments = self.env['ir.attachment']
elements = tree.xpath('//cac:AdditionalDocumentReference', namespaces=namespaces)
for element in elements:
attachment_name = element.xpath('cbc:ID', namespaces=namespaces)
attachment_data = element.xpath('cac:Attachment//cbc:EmbeddedDocumentBinaryObject', namespaces=namespaces)
if attachment_name and attachment_data:
text = attachment_data[0].text
# Normalize the name of the file : some e-fff emitters put the full path of the file
# (Windows or Linux style) and/or the name of the xml instead of the pdf.
# Get only the filename with a pdf extension.
name = PureWindowsPath(attachment_name[0].text).stem + '.pdf'
attachments |= self.env['ir.attachment'].create({
'name': name,
'res_id': invoice.id,
'res_model': 'account.move',
'datas': text + '=' * (len(text) % 3), # Fix incorrect padding
'type': 'binary',
'mimetype': 'application/pdf',
})
if attachments:
invoice.with_context(no_new_invoice=True).message_post(attachment_ids=attachments.ids)
return invoice
+1
View File
@@ -15,6 +15,7 @@ class PaymentTransaction(models.Model):
def render_invoice_button(self, invoice, submit_txt=None, render_values=None):
values = {
'partner_id': invoice.partner_id.id,
'type': self.type,
}
if render_values:
values.update(render_values)
@@ -125,6 +125,6 @@ class IrAttachment(models.Model):
for ftype in FTYPES:
buf = getattr(self, '_index_%s' % ftype)(bin_data)
if buf:
return buf
return buf.replace('\x00', '')
return super(IrAttachment, self)._index(bin_data, mimetype)
@@ -21,7 +21,7 @@
</div>
<div class="o_setting_right_pane">
<label string="Google Authentication" for="auth_oauth_google_enabled"/>
<a href="https://doc.flectrahq.com/2.0/general/auth/google.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<a href="https://doc.flectrahq.com/2.0/applications/general/auth/google.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<div class="text-muted">
Allow users to sign in with their Google account
</div>
@@ -30,7 +30,7 @@
<label for="auth_oauth_google_client_id" string="Client ID:" class="col-lg-3 o_light_label"/>
<field name="auth_oauth_google_client_id" placeholder="e.g. 1234-xyz.apps.googleusercontent.com"/>
</div>
<a href="https://www.flectrahq.com/documentation/user/online/general/auth/google.html" target="_blank"><i class="fa fa-fw fa-arrow-right"/>Tutorial</a>
<a href="https://doc.flectrahq.com/2.0/applications/general/auth/google.html" target="_blank"><i class="fa fa-fw fa-arrow-right"/>Tutorial</a>
</div>
</div>
</div>
+2 -2
View File
@@ -117,7 +117,7 @@
<span class="alert alert-info" role="status">
<i class="fa fa-warning"/>
Two-factor authentication not enabled
<a href="https://www.flectrahq.com/documentation/user/general/auth/2fa.html"
<a href="https://doc.flectrahq.com/2.0/applications/general/auth/2fa.html"
title="What is this?" class="o_doc_link" target="_blank"></a>
</span>
<button name="totp_enable_wizard" type="object" string="Enable two-factor authentication"
@@ -129,7 +129,7 @@
<span class="text-success">
<i class="fa fa-check-circle"/>
Two-factor authentication enabled
<a href="https://www.flectrahq.com/documentation/user/general/auth/2fa.html"
<a href="https://doc.flectrahq.com/2.0/applications/general/auth/2fa.html"
title="What is this?" class="o_doc_link" target="_blank"></a>
</span>
<button name="totp_disable" type="object" string="(Disable two-factor authentication)"
@@ -93,10 +93,18 @@ class Partner(models.Model):
if separator and field_name:
#maxsplit set to 1 to unpack only the first element and let the rest untouched
tmp = street_raw.split(separator, 1)
if previous_greedy in vals:
# attach part before space to preceding greedy field
append_previous, sep, tmp[0] = tmp[0].rpartition(' ')
street_raw = separator.join(tmp)
vals[previous_greedy] += sep + append_previous
if len(tmp) == 2:
field_value, street_raw = tmp
vals[field_name] = field_value
if field_value or not field_name:
previous_greedy = None
if field_name == 'street_name' and separator == ' ':
previous_greedy = field_name
# select next field to find (first pass OR field found)
# [2:-2] is used to remove the extra chars '%(' and ')s'
field_name = re_match.group()[2:-2]
@@ -35,6 +35,7 @@ class TestStreetFields(SavepointCase):
{'country_id': us_id, 'street': '40 Chaussee de Namur'},
{'country_id': us_id, 'street': 'Chaussee de Namur'},
{'country_id': mx_id, 'street': 'Av. Miguel Hidalgo y Costilla 601'},
{'country_id': mx_id, 'street': 'Av. Miguel Hidalgo y Costilla 601/40'},
{'country_id': ch_id, 'street': 'header Chaussee de Namur, 40 - 2b trailer'},
{'country_id': ch_id, 'street': 'header Chaussee de Namur, 40 trailer'},
{'country_id': ch_id, 'street': 'header Chaussee de Namur trailer'},
@@ -43,7 +44,8 @@ class TestStreetFields(SavepointCase):
{'street_name': 'Chaussee de Namur', 'street_number': '40', 'street_number2': '2b'},
{'street_name': 'Chaussee de Namur', 'street_number': '40', 'street_number2': False},
{'street_name': 'de Namur', 'street_number': 'Chaussee', 'street_number2': False},
{'street_name': 'Av.', 'street_number': 'Miguel Hidalgo y Costilla 601', 'street_number2': False},
{'street_name': 'Av. Miguel Hidalgo y Costilla', 'street_number': '601', 'street_number2': False},
{'street_name': 'Av. Miguel Hidalgo y Costilla', 'street_number': '601', 'street_number2': '40'},
{'street_name': 'Chaussee de Namur', 'street_number': '40', 'street_number2': '2b'},
{'street_name': 'Chaussee de Namur', 'street_number': '40', 'street_number2': False},
{'street_name': 'Chaussee de Namur', 'street_number': False, 'street_number2': False}
@@ -108,6 +110,7 @@ class TestStreetFields(SavepointCase):
{'country_id': us_id, 'street': '40 Chaussee de Namur'},
{'country_id': us_id, 'street': 'Chaussee de Namur'},
{'country_id': mx_id, 'street': 'Av. Miguel Hidalgo y Costilla 601'},
{'country_id': mx_id, 'street': 'Av. Miguel Hidalgo y Costilla 601/40'},
{'country_id': ch_id, 'street': 'header Chaussee de Namur, 40 - 2b trailer'},
{'country_id': ch_id, 'street': 'header Chaussee de Namur, 40 trailer'},
{'country_id': ch_id, 'street': 'header Chaussee de Namur trailer'},
@@ -116,7 +119,8 @@ class TestStreetFields(SavepointCase):
{'street_name': 'Chaussee de Namur', 'street_number': '40', 'street_number2': '2b'},
{'street_name': 'Chaussee de Namur', 'street_number': '40', 'street_number2': False},
{'street_name': 'de Namur', 'street_number': 'Chaussee', 'street_number2': False},
{'street_name': 'Av.', 'street_number': 'Miguel Hidalgo y Costilla 601', 'street_number2': False},
{'street_name': 'Av. Miguel Hidalgo y Costilla', 'street_number': '601', 'street_number2': False},
{'street_name': 'Av. Miguel Hidalgo y Costilla', 'street_number': '601', 'street_number2': '40'},
{'street_name': 'Chaussee de Namur', 'street_number': '40', 'street_number2': '2b'},
{'street_name': 'Chaussee de Namur', 'street_number': '40', 'street_number2': False},
{'street_name': 'Chaussee de Namur', 'street_number': False, 'street_number2': False}
+1 -1
View File
@@ -114,7 +114,7 @@ _map_iban_template = {
'br': 'BRkk BBBB BBBB SSSS SCCC CCCC CCCT N', # Brazil
'by': 'BYkk BBBB AAAA CCCC CCCC CCCC CCCC', # Belarus
'ch': 'CHkk BBBB BCCC CCCC CCCC C', # Switzerland
'cr': 'CRkk BBBC CCCC CCCC CCCC C', # Costa Rica
'cr': 'CRkk BBBC CCCC CCCC CCCC CC', # Costa Rica
'cy': 'CYkk BBBS SSSS CCCC CCCC CCCC CCCC', # Cyprus
'cz': 'CZkk BBBB SSSS SSCC CCCC CCCC', # Czech Republic
'de': 'DEkk BBBB BBBB CCCC CCCC CC', # Germany
@@ -114,7 +114,7 @@
<i class="fa fa-download"/> <span><t t-esc="template.label"/></span>
</a>
</div>
<a href="https://doc.flectrahq.com/2.0/general/base_import/import_faq.html" target="new">Import FAQ</a>
<a href="https://doc.flectrahq.com/2.0/applications/general/base_import/import_faq.html" target="new">Import FAQ</a>
</div>
</div>
</form>
@@ -22,7 +22,7 @@
<span class='o_form_label' attrs="{'invisible':[('active_user_count', '&lt;=', '1')]}">
Active Users
</span>
<a href="https://doc.flectrahq.com/2.0/general/flectra_basics/add_user.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<a href="https://doc.flectrahq.com/2.0/applications/general/flectra_basics/users.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<br/>
<button name="%(base.action_res_users)d" icon="fa-arrow-right" type="action" string="Manage Users" class="btn-link o_web_settings_access_rights"/>
@@ -140,7 +140,7 @@
<div class="o_setting_right_pane" id="sms_settings">
<div class="o_form_label">
Send SMS
<a href="https://doc.flectrahq.com/2.0/sms_marketing/pricing/pricing_and_faq.html" title="Documentation" class="ml-1 o_doc_link" target="_blank"></a>
<a href="https://doc.flectrahq.com/2.0/applications/marketing/sms_marketing/pricing/pricing_and_faq.html" title="Documentation" class="ml-1 o_doc_link" target="_blank"></a>
</div>
<div class="text-muted">
Send texts to your contacts
@@ -192,7 +192,7 @@
</div>
<div class="o_setting_right_pane">
<label string="Import &amp; Export" for="module_base_import"/>
<a href="https://doc.flectrahq.com/2.0/general/base_import/import_faq.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<a href="https://doc.flectrahq.com/2.0/applications/general/base_import/import_faq.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<div class="text-muted">
Allow users to import data from CSV/XLS/XLSX/ODS files
</div>
@@ -267,7 +267,7 @@
</div>
<div class="o_setting_right_pane">
<label string="Google Calendar" for="module_google_calendar"/>
<a href="https://doc.flectrahq.com/2.0/crm/optimize/google_calendar_credentials.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<a href="https://doc.flectrahq.com/2.0/applications/general/calendars/google/google_calendar_credentials.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<div class="text-muted">
Synchronize your calendar with Google Calendar
</div>
@@ -324,7 +324,7 @@
</div>
<div class="o_setting_right_pane" name="auth_ldap_right_pane">
<label string="LDAP Authentication" for="module_auth_ldap"/>
<a href="https://doc.flectrahq.com/2.0/general/auth/ldap.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<a href="https://doc.flectrahq.com/2.0/applications/general/auth/ldap.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<div class="text-muted">
Use LDAP credentials to log in
</div>
@@ -339,7 +339,7 @@
</div>
<div class="o_setting_right_pane" id="web_unsplash_settings">
<label for="module_web_unsplash"/>
<a href="https://doc.flectrahq.com/2.0/general/unsplash/unsplash_access_key.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<a href="https://doc.flectrahq.com/2.0/applications/general/unsplash/unsplash_access_key.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<div class="text-muted">
Find free high-resolution images from Unsplash
</div>
@@ -386,12 +386,12 @@
<div class="o_setting_right_pane">
<!-- FIXME Those links are defined directly in the template which means that we will have to
update the template code is the link ever changes -->
<a class="d-block mx-auto" href="https://play.google.com/store/apps/details?id=com.flectra.flectrahq" target="blank">
<a class="d-block mx-auto" href="https://play.google.com/store/apps/details?id=com.flectra.mobile" target="blank">
<img alt="On Google Play" class="d-block mx-auto img img-fluid" src="/base_setup/static/src/img/google_play.png"/>
</a>
</div>
<div>
<a class='d-block mx-auto' href="https://itunes.apple.com/us/app/flectra/id1561830563" target="blank">
<a class='d-block mx-auto' href="https://itunes.apple.com/us/app/flectra/id1272543640" target="blank">
<img alt="On Apple Store" class="d-block mx-auto img img-fluid" src="/base_setup/static/src/img/app_store.png"/>
</a>
</div>
+1 -3
View File
@@ -327,9 +327,7 @@ var CrossTabBus = Longpolling.extend({
}
// update channels
else if (key === this._generateKey('channels')) {
var channels = value;
_.each(_.difference(this._channels, channels), this.deleteChannel.bind(this));
_.each(_.difference(channels, this._channels), this.addChannel.bind(this));
this._channels = value;
}
// update options
else if (key === this._generateKey('options')) {
+77
View File
@@ -2,6 +2,7 @@ flectra.define('web.bus_tests', function (require) {
"use strict";
var BusService = require('bus.BusService');
var CrossTabBus = require('bus.CrossTab');
var AbstractStorageService = require('web.AbstractStorageService');
var RamStorage = require('web.RamStorage');
var testUtils = require('web.test_utils');
@@ -310,5 +311,81 @@ QUnit.module('Bus', {
parentMaster.destroy();
parentSlave.destroy();
});
QUnit.test('two tabs calling addChannel simultaneously', async function (assert) {
assert.expect(5);
let id = 1;
testUtils.patch(CrossTabBus, {
init: function () {
this._super.apply(this, arguments);
this.__tabId__ = id++;
},
addChannel: function (channel) {
assert.step('Tab ' + this.__tabId__ + ': addChannel ' + channel);
this._super.apply(this, arguments);
},
deleteChannel: function (channel) {
assert.step('Tab ' + this.__tabId__ + ': deleteChannel ' + channel);
this._super.apply(this, arguments);
},
});
let pollPromise;
const parentTab1 = new Widget();
await testUtils.addMockEnvironment(parentTab1, {
data: {},
services: {
local_storage: LocalStorageServiceMock,
},
mockRPC: function (route) {
if (route === '/longpolling/poll') {
pollPromise = testUtils.makeTestPromise();
pollPromise.abort = (function () {
this.reject({message: "XmlHttpRequestError abort"}, $.Event());
}).bind(pollPromise);
return pollPromise;
}
return this._super.apply(this, arguments);
}
});
const parentTab2 = new Widget();
await testUtils.addMockEnvironment(parentTab2, {
data: {},
services: {
local_storage: LocalStorageServiceMock,
},
mockRPC: function (route) {
if (route === '/longpolling/poll') {
pollPromise = testUtils.makeTestPromise();
pollPromise.abort = (function () {
this.reject({message: "XmlHttpRequestError abort"}, $.Event());
}).bind(pollPromise);
return pollPromise;
}
return this._super.apply(this, arguments);
}
});
const tab1 = new CrossTabBus(parentTab1);
const tab2 = new CrossTabBus(parentTab2);
tab1.addChannel("alpha");
tab2.addChannel("alpha");
tab1.addChannel("beta");
tab2.addChannel("beta");
assert.verifySteps([
"Tab 1: addChannel alpha",
"Tab 2: addChannel alpha",
"Tab 1: addChannel beta",
"Tab 2: addChannel beta",
]);
testUtils.unpatch(CrossTabBus);
parentTab1.destroy();
parentTab2.destroy();
});
});
});
+12 -5
View File
@@ -125,11 +125,18 @@ class Attendee(models.Model):
'mimetype': 'text/calendar',
'datas': base64.b64encode(ics_file)})
]
body = invitation_template.with_context(rendering_context)._render_field(
'body_html',
attendee.ids,
compute_lang=True,
post_process=True)[attendee.id]
try:
body = invitation_template.with_context(rendering_context)._render_field(
'body_html',
attendee.ids,
compute_lang=True,
post_process=True)[attendee.id]
except UserError: #TO BE REMOVED IN MASTER
body = invitation_template.sudo().with_context(rendering_context)._render_field(
'body_html',
attendee.ids,
compute_lang=True,
post_process=True)[attendee.id]
subject = invitation_template._render_field(
'subject',
attendee.ids,
+11 -6
View File
@@ -493,7 +493,8 @@ class Lead(models.Model):
# searching on +32485112233 should also finds 00485112233 (00 / + prefix are both valid)
# we therefore remove it from input value and search for both of them in db
if value.startswith('+') or value.startswith('00'):
value = value.replace('+', '').replace('00', '', 1)
if value.startswith('00'):
value = value[2:]
starts_with = '00|\+'
else:
starts_with = '%'
@@ -1401,21 +1402,21 @@ class Lead(models.Model):
""" Handle salesman recipients that can convert leads into opportunities
and set opportunities as won / lost. """
groups = super(Lead, self)._notify_get_groups(msg_vals=msg_vals)
msg_vals = msg_vals or {}
local_msg_vals = dict(msg_vals or {})
self.ensure_one()
if self.type == 'lead':
convert_action = self._notify_get_action_link('controller', controller='/lead/convert', **msg_vals)
convert_action = self._notify_get_action_link('controller', controller='/lead/convert', **local_msg_vals)
salesman_actions = [{'url': convert_action, 'title': _('Convert to opportunity')}]
else:
won_action = self._notify_get_action_link('controller', controller='/lead/case_mark_won', **msg_vals)
lost_action = self._notify_get_action_link('controller', controller='/lead/case_mark_lost', **msg_vals)
won_action = self._notify_get_action_link('controller', controller='/lead/case_mark_won', **local_msg_vals)
lost_action = self._notify_get_action_link('controller', controller='/lead/case_mark_lost', **local_msg_vals)
salesman_actions = [
{'url': won_action, 'title': _('Won')},
{'url': lost_action, 'title': _('Lost')}]
if self.team_id:
custom_params = dict(msg_vals, res_id=self.team_id.id, model=self.team_id._name)
custom_params = dict(local_msg_vals, res_id=self.team_id.id, model=self.team_id._name)
salesman_actions.append({
'url': self._notify_get_action_link('view', **custom_params),
'title': _('Sales Team Settings')
@@ -1515,6 +1516,10 @@ class Lead(models.Model):
break
return result
def _phone_get_number_fields(self):
""" Use mobile or phone fields to compute sanitized phone number """
return ['mobile', 'phone']
@api.model
def get_import_templates(self):
return [{
+5 -5
View File
@@ -129,12 +129,12 @@ class TestCrmCommon(TestSalesCommon, MailCase):
'philip.j.fry@test.example.com',
'turanga.leela@test.example.com',
]
cls.test_pĥone_data = [
cls.test_phone_data = [
'+1 202 555 0122', # formatted US number
'202 555 0999', # local US number
'202 555 0888', # local US number
]
cls.test_pĥone_data_sanitized = [
cls.test_phone_data_sanitized = [
'+12025550122',
'+12025550999',
'+12025550888',
@@ -153,7 +153,7 @@ class TestCrmCommon(TestSalesCommon, MailCase):
cls.contact_1 = cls.env['res.partner'].create({
'name': 'Philip J Fry',
'email': cls.test_email_data[1],
'mobile': cls.test_pĥone_data[0],
'mobile': cls.test_phone_data[0],
'title': cls.env.ref('base.res_partner_title_mister').id,
'function': 'Delivery Boy',
'phone': False,
@@ -167,8 +167,8 @@ class TestCrmCommon(TestSalesCommon, MailCase):
cls.contact_2 = cls.env['res.partner'].create({
'name': 'Turanga Leela',
'email': cls.test_email_data[2],
'mobile': cls.test_pĥone_data[1],
'phone': cls.test_pĥone_data[2],
'mobile': cls.test_phone_data[1],
'phone': cls.test_phone_data[2],
'parent_id': False,
'is_company': False,
'street': 'Cookieville Minimum-Security Orphanarium',
+46 -3
View File
@@ -217,16 +217,16 @@ class TestCRMLead(TestCrmCommon):
lead_form = Form(lead)
# reset partner phone to a local number and prepare formatted / sanitized values
partner_phone, partner_mobile = self.test_pĥone_data[2], self.test_pĥone_data[1]
partner_phone, partner_mobile = self.test_phone_data[2], self.test_phone_data[1]
partner_phone_formatted = phone_format(partner_phone, 'US', '1')
partner_phone_sanitized = phone_format(partner_phone, 'US', '1', force_format='E164')
partner_mobile_formatted = phone_format(partner_mobile, 'US', '1')
partner_mobile_sanitized = phone_format(partner_mobile, 'US', '1', force_format='E164')
partner_email, partner_email_normalized = self.test_email_data[2], self.test_email_data_normalized[2]
self.assertEqual(partner_phone_formatted, '+1 202-555-0888')
self.assertEqual(partner_phone_sanitized, self.test_pĥone_data_sanitized[2])
self.assertEqual(partner_phone_sanitized, self.test_phone_data_sanitized[2])
self.assertEqual(partner_mobile_formatted, '+1 202-555-0999')
self.assertEqual(partner_mobile_sanitized, self.test_pĥone_data_sanitized[1])
self.assertEqual(partner_mobile_sanitized, self.test_phone_data_sanitized[1])
# ensure initial data
self.assertEqual(partner.phone, partner_phone)
self.assertEqual(partner.mobile, partner_mobile)
@@ -386,3 +386,46 @@ class TestCRMLead(TestCrmCommon):
new_lead.handle_partner_assignment(create_missing=True)
self.assertEqual(new_lead.partner_id.email, 'unknown.sender@test.example.com')
self.assertEqual(new_lead.partner_id.team_id, self.sales_team_1)
@users('user_sales_manager')
def test_phone_mobile_update(self):
lead = self.env['crm.lead'].create({
'name': 'Lead 1',
'country_id': self.env.ref('base.us').id,
'phone': self.test_phone_data[0],
})
self.assertEqual(lead.phone, self.test_phone_data[0])
self.assertFalse(lead.mobile)
self.assertEqual(lead.phone_sanitized, self.test_phone_data_sanitized[0])
lead.write({'phone': False, 'mobile': self.test_phone_data[1]})
self.assertFalse(lead.phone)
self.assertEqual(lead.mobile, self.test_phone_data[1])
self.assertEqual(lead.phone_sanitized, self.test_phone_data_sanitized[1])
lead.write({'phone': self.test_phone_data[1], 'mobile': self.test_phone_data[2]})
self.assertEqual(lead.phone, self.test_phone_data[1])
self.assertEqual(lead.mobile, self.test_phone_data[2])
self.assertEqual(lead.phone_sanitized, self.test_phone_data_sanitized[2])
# updating country should trigger sanitize computation
lead.write({'country_id': self.env.ref('base.be').id})
self.assertEqual(lead.phone, self.test_phone_data[1])
self.assertEqual(lead.mobile, self.test_phone_data[2])
self.assertFalse(lead.phone_sanitized)
@users('user_sales_manager')
def test_phone_mobile_search(self):
lead_1 = self.env['crm.lead'].create({
'name': 'Lead 1',
'country_id': self.env.ref('base.be').id,
'phone': '+32485001122',
})
_lead_2 = self.env['crm.lead'].create({
'name': 'Lead 2',
'country_id': self.env.ref('base.be').id,
'phone': '+32485112233',
})
self.assertEqual(lead_1, self.env['crm.lead'].search([
('phone_mobile_search', 'like', '+32485001122')
]))
+49
View File
@@ -5,6 +5,55 @@ from flectra import SUPERUSER_ID
from flectra.addons.crm.tests import common as crm_common
from flectra.fields import Datetime
from flectra.tests.common import tagged, users
from flectra.tests.common import Form
@tagged('lead_manage')
class TestLeadConvertForm(crm_common.TestLeadConvertCommon):
@users('user_sales_manager')
def test_form_action_default(self):
""" Test Lead._find_matching_partner() """
lead = self.env['crm.lead'].browse(self.lead_1.ids)
customer = self.env['res.partner'].create({
"name": "Amy Wong",
"email": '"Amy, PhD Student, Wong" Tiny <AMY.WONG@test.example.com>'
})
wizard = Form(self.env['crm.lead2opportunity.partner'].with_context({
'active_model': 'crm.lead',
'active_id': lead.id,
'active_ids': lead.ids,
}))
self.assertEqual(wizard.name, 'convert')
self.assertEqual(wizard.action, 'exist')
self.assertEqual(wizard.partner_id, customer)
@users('user_sales_manager')
def test_form_name_onchange(self):
""" Test Lead._find_matching_partner() """
lead = self.env['crm.lead'].browse(self.lead_1.ids)
lead_dup = lead.copy({'name': 'Duplicate'})
customer = self.env['res.partner'].create({
"name": "Amy Wong",
"email": '"Amy, PhD Student, Wong" Tiny <AMY.WONG@test.example.com>'
})
wizard = Form(self.env['crm.lead2opportunity.partner'].with_context({
'active_model': 'crm.lead',
'active_id': lead.id,
'active_ids': lead.ids,
}))
self.assertEqual(wizard.name, 'merge')
self.assertEqual(wizard.action, 'exist')
self.assertEqual(wizard.partner_id, customer)
self.assertEqual(wizard.duplicated_lead_ids[:], lead + lead_dup)
wizard.name = 'convert'
wizard.action = 'create'
self.assertEqual(wizard.action, 'create', 'Should keep user input')
self.assertEqual(wizard.name, 'convert', 'Should keep user input')
@tagged('lead_manage')
@@ -5,7 +5,7 @@ from flectra.addons.crm.tests import common as crm_common
from flectra.tests.common import tagged, users
@tagged('lead_manage')
@tagged('lead_manage', 'crm_performance')
class TestLeadConvertMass(crm_common.TestLeadConvertMassCommon):
@classmethod
@@ -24,7 +24,7 @@ class TestLeadConvertMass(crm_common.TestLeadConvertMassCommon):
with self.assertQueryCount(user_sales_manager=0):
test_leads = self.env['crm.lead'].browse(test_leads.ids)
with self.assertQueryCount(user_sales_manager=254): # crm only: 251
with self.assertQueryCount(user_sales_manager=254): # often 251, sometimes +3 on runbot
test_leads.handle_salesmen_assignment(user_ids=user_ids, team_id=False)
self.assertEqual(test_leads.team_id, self.sales_team_convert | self.sales_team_1)
@@ -42,7 +42,7 @@ class TestLeadConvertMass(crm_common.TestLeadConvertMassCommon):
with self.assertQueryCount(user_sales_manager=0):
test_leads = self.env['crm.lead'].browse(test_leads.ids)
with self.assertQueryCount(user_sales_manager=220): # crm only: 215
with self.assertQueryCount(user_sales_manager=221): # crm only: 215 - generally 218, sometimes +2/+3 on runbot
test_leads.handle_salesmen_assignment(user_ids=user_ids, team_id=team_id)
self.assertEqual(test_leads.team_id, self.sales_team_convert)
@@ -166,7 +166,7 @@ class TestLeadConvertMass(crm_common.TestLeadConvertMassCommon):
test_leads = self._create_leads_batch(count=50, user_ids=[False])
user_ids = self.assign_users.ids
with self.assertQueryCount(user_sales_manager=1363): # crm only: 1352
with self.assertQueryCount(user_sales_manager=1361): # still some randomness (1360 spotted) - crm only: 1352
mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({
'active_model': 'crm.lead',
'active_ids': test_leads.ids,
@@ -135,7 +135,7 @@
<div class="o_setting_right_pane" id="crm_iap_lead_settings">
<label string="Lead Mining" for="module_crm_iap_lead"/>
<a href="https://doc.flectrahq.com/2.0/crm/acquire_leads/lead_mining.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<a href="https://doc.flectrahq.com/2.0/applications/sales/crm/acquire_leads/lead_mining.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<div class="text-muted">
Generate new leads based on their country, industry, size, etc.
</div>
@@ -148,7 +148,7 @@
<div class="o_setting_right_pane" id="mail_client_extension">
<label string="Outlook CRM Extension" for="module_mail_client_extension"/>
<a href="https://www.flectrahq.com/documentation/user/crm/optimize/outlook_extension.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<a href="https://doc.flectrahq.com/2.0/applications/sales/crm/optimize/outlook_extension.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<div class="text-muted">
Turn emails received in your Outlook mailbox into leads and log their content as internal notes.
</div>
+3 -2
View File
@@ -50,7 +50,8 @@ class Lead2OpportunityPartner(models.TransientModel):
@api.depends('duplicated_lead_ids')
def _compute_name(self):
for convert in self:
convert.name = 'merge' if convert.duplicated_lead_ids and len(convert.duplicated_lead_ids) >= 2 else 'convert'
if not convert.name:
convert.name = 'merge' if convert.duplicated_lead_ids and len(convert.duplicated_lead_ids) >= 2 else 'convert'
@api.depends('lead_id')
def _compute_action(self):
@@ -77,7 +78,7 @@ class Lead2OpportunityPartner(models.TransientModel):
convert.lead_id.partner_id.email if convert.lead_id.partner_id.email else convert.lead_id.email_from,
include_lost=True).ids
@api.depends('action')
@api.depends('action', 'lead_id')
def _compute_partner_id(self):
for convert in self:
if convert.action == 'exist':
@@ -13,6 +13,7 @@
<field name="team_id" widget="selection"/>
</group>
<group string="Opportunities" attrs="{'invisible': [('name', '!=', 'merge')]}">
<field name="lead_id" invisible="1"/>
<field name="duplicated_lead_ids" nolabel="1">
<tree>
<field name="create_date" widget="date"/>
+1 -1
View File
@@ -39,7 +39,7 @@ class MailChannel(models.Model):
# anonymous user whatever the participants. Otherwise keep only share
# partners (no user or portal user) to link to the lead.
customers = self.env['res.partner']
for customer in channel_partners.partner_id.filtered('partner_share'):
for customer in channel_partners.partner_id.filtered('partner_share').with_context(active_test=False):
if customer.user_ids and all(user._is_public() for user in customer.user_ids):
customers = self.env['res.partner']
break
@@ -44,6 +44,23 @@ class TestLivechatLead(TestCrmCommon):
self.assertEqual(lead.name, 'TestLead command')
self.assertEqual(lead.partner_id, self.env['res.partner'])
# public user: should not be set as customer
# 'base.public_user' is archived by default
self.assertFalse(self.env.ref('base.public_user').active)
channel = self.env['mail.channel'].create({
'name': 'Chat with Visitor',
'channel_partner_ids': [(4, self.env.ref('base.public_partner').id)]
})
lead = channel._convert_visitor_to_lead(self.env.user.partner_id, channel.channel_last_seen_partner_ids, '/lead TestLead command')
self.assertEqual(
channel.channel_last_seen_partner_ids.partner_id,
self.user_sales_leads.partner_id | self.env.ref('base.public_partner')
)
self.assertEqual(lead.name, 'TestLead command')
self.assertEqual(lead.partner_id, self.env['res.partner'])
# public + someone else: no customer (as he was anonymous)
channel.write({
'channel_partner_ids': [(4, self.user_sales_manager.partner_id.id)]
+1
View File
@@ -10,4 +10,5 @@ class CrmLead(models.Model):
def _sms_get_number_fields(self):
""" This method returns the fields to use to find the number to use to
send an SMS on a record. """
# TDE FIXME: to be cleaned in 14.4+ as it conflicts with _phone_get_number_fields
return ['mobile', 'phone']
+3
View File
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import test_crm_lead
+29
View File
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
from flectra.addons.crm.tests.common import TestCrmCommon
from flectra.tests.common import Form, users
class TestCRMLead(TestCrmCommon):
@users('user_sales_manager')
def test_phone_mobile_update(self):
lead = self.env['crm.lead'].create({
'name': 'Lead 1',
'country_id': self.env.ref('base.us').id,
'phone': self.test_phone_data[0],
})
self.assertEqual(lead.phone, self.test_phone_data[0])
self.assertFalse(lead.mobile)
self.assertEqual(lead.phone_sanitized, self.test_phone_data_sanitized[0])
lead.write({'phone': False, 'mobile': self.test_phone_data[1]})
self.assertFalse(lead.phone)
self.assertEqual(lead.mobile, self.test_phone_data[1])
self.assertEqual(lead.phone_sanitized, self.test_phone_data_sanitized[1])
lead.write({'phone': self.test_phone_data[1], 'mobile': self.test_phone_data[2]})
self.assertEqual(lead.phone, self.test_phone_data[1])
self.assertEqual(lead.mobile, self.test_phone_data[2])
self.assertEqual(lead.phone_sanitized, self.test_phone_data_sanitized[2])
+7 -8
View File
@@ -195,14 +195,13 @@ class StockPicking(models.Model):
delivery_lines = sale_order.order_line.filtered(lambda l: l.is_delivery and l.currency_id.is_zero(l.price_unit) and l.product_id == self.carrier_id.product_id)
carrier_price = self.carrier_price * (1.0 + (float(self.carrier_id.margin) / 100.0))
if not delivery_lines:
sale_order._create_delivery_line(self.carrier_id, carrier_price)
else:
delivery_line = delivery_lines[0]
delivery_line[0].write({
'price_unit': carrier_price,
# remove the estimated price from the description
'name': sale_order.carrier_id.with_context(lang=self.partner_id.lang).name,
})
delivery_lines = [sale_order._create_delivery_line(self.carrier_id, carrier_price)]
delivery_line = delivery_lines[0]
delivery_line[0].write({
'price_unit': carrier_price,
# remove the estimated price from the description
'name': sale_order.carrier_id.with_context(lang=self.partner_id.lang).name,
})
def open_website_url(self):
self.ensure_one()
+1 -1
View File
@@ -49,7 +49,6 @@
<field name="arch" type="xml">
<form string="Carrier">
<sheet>
<widget name="web_ribbon" text="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<div class="oe_button_box" name="button_box">
<button name="toggle_prod_environment"
attrs="{'invisible': ['|', '|', ('prod_environment', '=', False), ('delivery_type', '=', 'fixed'), ('delivery_type', '=', 'base_on_rule')]}"
@@ -87,6 +86,7 @@
</div>
</button>
</div>
<widget name="web_ribbon" text="Archived" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<div class="oe_title" name="title">
<label for="name" string="Name" class="oe_edit_only"/>
<h1>
+2 -2
View File
@@ -406,10 +406,10 @@
<div style="width: 50%; float: left;">
<p class="run_business">Run your business from anywhere with <b>Flectra Mobile</b>.</p>
<div>
<a href="https://play.google.com/store/apps/details?id=com.flectra.flectrahq" target="_blank"><img class="download_app" src="https://www.flectrahq.com/digest/static/src/img/google_play.png" /></a>
<a href="https://play.google.com/store/apps/details?id=com.flectra.mobile" target="_blank"><img class="download_app" src="https://www.flectrahq.com/digest/static/src/img/google_play.png" /></a>
</div>
<div>
<a href="https://itunes.apple.com/us/app/flectra/id1561830563" target="_blank"><img class="download_app" src="https://www.flectrahq.com/digest/static/src/img/app_store.png" /></a>
<a href="https://itunes.apple.com/us/app/flectra/id1272543640" target="_blank"><img class="download_app" src="https://www.flectrahq.com/digest/static/src/img/app_store.png" /></a>
</div>
</div>
</div>
@@ -57,20 +57,14 @@ tour.register('event_tour', {
}, {
trigger: '.o_event_form_view div[name="event_ticket_ids"] .o_field_x2many_list_row_add a',
content: _t("Ticket types allow you to distinguish your attendees. Let's <b>create</b> a new one."),
}, {
trigger: '.o_form_button_save',
extra_trigger: '.o_event_form_view',
content: _t("Awesome! Now, let's <b>save</b> your changes."),
position: 'bottom',
width: 250,
}, ...new EventAdditionalTourSteps()._get_website_event_steps(), {
trigger: '.o_event_form_view div[name="stage_id"] button:contains("Booked")',
trigger: '.o_event_form_view div[name="stage_id"]',
extra_trigger: 'div.o_form_buttons_view:not(.o_hidden)',
content: _t("Now that your event is ready, click here to move it to another stage."),
position: 'bottom',
}, {
trigger: 'ol.breadcrumb li.breadcrumb-item:first',
extra_trigger: '.o_event_form_view div[name="stage_id"] button.disabled:contains("Booked")',
extra_trigger: '.o_event_form_view div[name="stage_id"]',
content: _t("Use the <b>breadcrumbs</b> to go back to your kanban overview."),
position: 'bottom',
run: 'click',
+1 -1
View File
@@ -180,7 +180,7 @@ class EventLeadRule(models.Model):
'description': "%s\n%s" % (lead.description, additionnal_description),
'registration_ids': [(4, reg.id) for reg in group_registrations],
})
else:
elif group_registrations:
lead_vals_list.append(group_registrations._get_lead_values(rule))
return self.env['crm.lead'].create(lead_vals_list)
@@ -145,3 +145,23 @@ class TestEventCrmFlow(TestEventCrmCommon):
})
self.assertEqual(len(self.event_0.registration_ids), 4)
self.assertLeadConvertion(self.test_rule_attendee, registration, partner=None)
@users('user_eventmanager')
def test_order_rule_duplicate_lead(self):
""" Check when two rules match one event
but only one match the registration,
only one lead should be created
"""
test_rule_order_2 = self.test_rule_order.copy(default={
'event_registration_filter': [['email', 'not ilike', '@test.example.com']]
})
self.env['event.registration'].create({
'name': 'My Registration',
'partner_id': False,
'email': 'super.email@test.example.com',
'phone': False,
'mobile': '0456332211',
'event_id': self.event_0.id,
})
self.assertEqual(len(self.test_rule_order.lead_ids), 1)
self.assertEqual(len(test_rule_order_2.lead_ids), 0)
+1 -6
View File
@@ -137,11 +137,6 @@ class SaleOrderLine(models.Model):
def _get_display_price(self, product):
if self.event_ticket_id and self.event_id:
company = self.event_id.company_id or self.env.company
currency = company.currency_id
return currency._convert(
self.event_ticket_id.price, self.order_id.currency_id,
self.order_id.company_id or self.env.company.id,
self.order_id.date_order or fields.Date.today())
return self.event_ticket_id.with_context(pricelist=self.order_id.pricelist_id.id, uom=self.product_uom.id).price_reduce
else:
return super()._get_display_price(product)
@@ -50,6 +50,7 @@ class TestEventSale(TestEventSaleCommon):
'event_ticket_id': ticket1.id,
'product_id': ticket1.product_id.id,
'product_uom_qty': TICKET1_COUNT,
'price_unit': 10,
}), (0, 0, {
'event_id': self.event_0.id,
'event_ticket_id': ticket2.id,
@@ -153,3 +154,58 @@ class TestEventSale(TestEventSaleCommon):
self.assertEqual(editor_action['type'], 'ir.actions.act_window')
self.assertEqual(editor_action['res_model'], 'registration.editor')
def test_ticket_price_with_pricelist_and_tax(self):
self.env.user.partner_id.country_id = False
pricelist = self.env['product.pricelist'].search([], limit=1)
tax = self.env['account.tax'].create({
'name': "Tax 10",
'amount': 10,
})
event_product = self.env['product.template'].create({
'name': 'Event Product',
'list_price': 10.0,
})
event_product.taxes_id = tax
event = self.env['event.event'].create({
'name': 'New Event',
'date_begin': '2020-02-02',
'date_end': '2020-04-04',
})
event_ticket = self.env['event.event.ticket'].create({
'name': 'VIP',
'price': 1000.0,
'event_id': event.id,
'product_id': event_product.product_variant_id.id,
})
pricelist.item_ids = self.env['product.pricelist.item'].create({
'applied_on': "1_product",
'base': "list_price",
'compute_price': "fixed",
'fixed_price': 6.0,
'product_tmpl_id': event_product.id,
})
pricelist.discount_policy = 'without_discount'
so = self.env['sale.order'].create({
'partner_id': self.env.user.partner_id.id,
'pricelist_id': pricelist.id,
})
sol = self.env['sale.order.line'].create({
'name': event.name,
'product_id': event_product.product_variant_id.id,
'product_uom_qty': 1,
'product_uom': event_product.uom_id.id,
'price_unit': event_product.list_price,
'order_id': so.id,
'event_id': event.id,
'event_ticket_id': event_ticket.id,
})
sol.product_id_change()
self.assertEqual(so.amount_total, 660.0, "Ticket is $1000 but the event product is on a pricelist 10 -> 6. So, $600 + a 10% tax.")
+1 -1
View File
@@ -59,7 +59,7 @@ class FleetVehicleLogContract(models.Model):
def _compute_contract_name(self):
for record in self:
name = record.vehicle_id.name
if record.cost_subtype_id.name:
if name and record.cost_subtype_id.name:
name = record.cost_subtype_id.name + ' ' + name
record.name = name
+19 -8
View File
@@ -146,14 +146,25 @@ class GamificationBadge(models.Model):
self.update(defaults)
return
self.env.cr.execute("""
SELECT badge_id, count(user_id) as granted_count,
count(distinct(user_id)) as granted_users_count,
array_agg(distinct(user_id)) as unique_owner_ids
FROM gamification_badge_user
WHERE badge_id in %s
GROUP BY badge_id
""", [tuple(self.ids)])
Users = self.env["res.users"]
query = Users._where_calc([])
Users._apply_ir_rules(query)
badge_alias = query.join("res_users", "id", "gamification_badge_user", "user_id", "badges")
tables, where_clauses, where_params = query.get_sql()
self.env.cr.execute(
f"""
SELECT {badge_alias}.badge_id, count(res_users.id) as stat_count,
count(distinct(res_users.id)) as stat_count_distinct,
array_agg(distinct(res_users.id)) as unique_owner_ids
FROM {tables}
WHERE {where_clauses}
AND {badge_alias}.badge_id IN %s
GROUP BY {badge_alias}.badge_id
""",
[*where_params, tuple(self.ids)]
)
mapping = {
badge_id: {
+7 -13
View File
@@ -245,19 +245,13 @@ class Challenge(models.Model):
# exclude goals for users that did not connect since the last update
yesterday = fields.Date.to_string(date.today() - timedelta(days=1))
self.env.cr.execute("""SELECT gg.id
FROM gamification_goal as gg,
gamification_challenge as gc,
res_users as ru,
res_users_log as log
WHERE gg.challenge_id = gc.id
AND gg.user_id = ru.id
AND ru.id = log.create_uid
AND gg.write_date < log.create_date
FROM gamification_goal as gg
JOIN res_users_log as log ON gg.user_id = log.create_uid
WHERE gg.write_date < log.create_date
AND gg.closed IS NOT TRUE
AND gc.id IN %s
AND gg.challenge_id IN %s
AND (gg.state = 'inprogress'
OR (gg.state = 'reached'
AND (gg.end_date >= %s OR gg.end_date IS NULL)))
OR (gg.state = 'reached' AND gg.end_date >= %s))
GROUP BY gg.id
""", [tuple(self.ids), yesterday])
@@ -360,7 +354,7 @@ class Challenge(models.Model):
participant_user_ids = set(challenge.user_ids.ids)
user_squating_challenge_ids = user_with_goal_ids - participant_user_ids
if user_squating_challenge_ids:
# users that used to match the challenge
# users that used to match the challenge
Goals.search([
('challenge_id', '=', challenge.id),
('user_id', 'in', list(user_squating_challenge_ids))
@@ -451,7 +445,7 @@ class Challenge(models.Model):
'action': <{True,False}>,
'display_mode': <{progress,boolean}>,
'target': <challenge line target>,
'state': <gamification.goal state {draft,inprogress,reached,failed,canceled}>,
'state': <gamification.goal state {draft,inprogress,reached,failed,canceled}>,
'completeness': <percentage>,
'current': <current value>,
}
@@ -58,7 +58,7 @@ class GoogleCalendarService():
@requires_auth_token
def insert(self, values, token=None, timeout=TIMEOUT):
url = "/calendar/v3/calendars/primary/events"
url = "/calendar/v3/calendars/primary/events?sendUpdates=all"
headers = {'Content-type': 'application/json', 'Authorization': 'Bearer %s' % token}
if not values.get('id'):
values['id'] = uuid4().hex
@@ -67,13 +67,13 @@ class GoogleCalendarService():
@requires_auth_token
def patch(self, event_id, values, token=None, timeout=TIMEOUT):
url = "/calendar/v3/calendars/primary/events/%s" % event_id
url = "/calendar/v3/calendars/primary/events/%s?sendUpdates=all" % event_id
headers = {'Content-type': 'application/json', 'Authorization': 'Bearer %s' % token}
self.google_service._do_request(url, json.dumps(values), headers, method='PUT', timeout=timeout)
@requires_auth_token
def delete(self, event_id, token=None, timeout=TIMEOUT):
url = "/calendar/v3/calendars/primary/events/%s" % event_id
url = "/calendar/v3/calendars/primary/events/%s?sendUpdates=all" % event_id
headers = {'Content-type': 'application/json'}
params = {'access_token': token}
try:
@@ -13,7 +13,7 @@
<label for="cal_client_secret" string="Client Secret" class="col-3 col-lg-3 o_light_label"/>
<field name="cal_client_secret" password="True" nolabel="1"/>
</div>
<a href="https://doc.flectrahq.com/2.0/crm/optimize/google_calendar_credentials.html" class="oe-link" target="_blank"><i class="fa fa-fw fa-arrow-right"/>Tutorial</a>
<a href="https://doc.flectrahq.com/2.0/applications/general/calendars/google/google_calendar_credentials.html" class="oe-link" target="_blank"><i class="fa fa-fw fa-arrow-right"/>Tutorial</a>
</div>
</div>
</field>
+1 -1
View File
@@ -39,7 +39,7 @@ class HrAttendance(models.Model):
@api.depends('check_in', 'check_out')
def _compute_worked_hours(self):
for attendance in self:
if attendance.check_out:
if attendance.check_out and attendance.check_in:
delta = attendance.check_out - attendance.check_in
attendance.worked_hours = delta.total_seconds() / 3600.0
else:
+1 -1
View File
@@ -30,7 +30,7 @@ class Contract(models.Model):
help="End date of the trial period (if there is one).")
resource_calendar_id = fields.Many2one(
'resource.calendar', 'Working Schedule', compute='_compute_employee_contract', store=True, readonly=False,
default=lambda self: self.env.company.resource_calendar_id.id, copy=False,
default=lambda self: self.env.company.resource_calendar_id.id, copy=False, index=True,
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
wage = fields.Monetary('Wage', required=True, tracking=True, help="Employee's monthly gross wage.")
notes = fields.Text('Notes')
-26
View File
@@ -510,37 +510,11 @@ Or send your receipts at <a href="mailto:%(email)s?subject=Lunch%%20with%%20cust
move_line_values_by_expense = self._get_account_move_line_values()
for expense in self:
company_currency = expense.company_id.currency_id
different_currency = expense.currency_id != company_currency
# get the account move of the related sheet
move = move_group_by_sheet[expense.sheet_id.id]
# get move line values
move_line_values = move_line_values_by_expense.get(expense.id)
move_line_dst = move_line_values[-1]
total_amount = move_line_dst['debit'] or -move_line_dst['credit']
total_amount_currency = move_line_dst['amount_currency']
# create one more move line, a counterline for the total on payable account
if expense.payment_mode == 'company_account':
if not expense.sheet_id.bank_journal_id.default_account_id:
raise UserError(_("No account found for the %s journal, please configure one.") % (expense.sheet_id.bank_journal_id.name))
journal = expense.sheet_id.bank_journal_id
# create payment
payment_methods = journal.outbound_payment_method_ids if total_amount < 0 else journal.inbound_payment_method_ids
journal_currency = journal.currency_id or journal.company_id.currency_id
payment = self.env['account.payment'].create({
'payment_method_id': payment_methods and payment_methods[0].id or False,
'payment_type': 'outbound' if total_amount < 0 else 'inbound',
'partner_id': expense.employee_id.sudo().address_home_id.commercial_partner_id.id,
'partner_type': 'supplier',
'journal_id': journal.id,
'date': expense.date,
'currency_id': expense.currency_id.id if different_currency else journal_currency.id,
'amount': abs(total_amount_currency) if different_currency else abs(total_amount),
'ref': expense.name,
})
# link move lines to move, and move to expense sheet
move.write({'line_ids': [(0, 0, line) for line in move_line_values]})
@@ -28,13 +28,13 @@ flectra.define('hr_expense.expenses.tree', function (require) {
async _renderView() {
const self = this;
await this._super(...arguments);
const google_url = "https://play.google.com/store/apps/details?id=com.flectra.flectrahq";
const apple_url = "https://apps.apple.com/be/app/flectra/id1561830563";
const google_url = "https://play.google.com/store/apps/details?id=com.flectra.mobile";
const apple_url = "https://apps.apple.com/be/app/flectra/id1272543640";
const action_desktop = {
name: 'Download our App',
type: 'ir.actions.client',
tag: 'expense_qr_code_modal',
params: {'url': "https://apps.apple.com/be/app/flectra/id1561830563"},
params: {'url': "https://apps.apple.com/be/app/flectra/id1272543640"},
target: 'new',
};
this.$el.find('img.o_expense_apple_store').on('click', function(event) {
+4 -4
View File
@@ -398,10 +398,10 @@
</p>
<p>Snap pictures of your receipts and let Flectra<br/> automatically create expenses for you.</p>
<p>
<a href="https://apps.apple.com/be/app/flectra/id1561830563" target="_blank">
<a href="https://apps.apple.com/be/app/flectra/id1272543640" target="_blank">
<img alt="Apple App Store" class="img img-fluid h-100 o_expense_apple_store" src="/hr_expense/static/img/app_store.png"/>
</a>
<a href="https://play.google.com/store/apps/details?id=com.flectra.flectrahq" target="_blank" class="o_expense_google_store">
<a href="https://play.google.com/store/apps/details?id=com.flectra.mobile" target="_blank" class="o_expense_google_store">
<img alt="Google Play Store" class="img img-fluid h-100 o_expense_google_store" src="/hr_expense/static/img/play_store.png"/>
</a>
</p>
@@ -433,10 +433,10 @@
</p>
<p>Snap pictures of your receipts and let Flectra<br/> automatically create expenses for you.</p>
<p>
<a href="https://apps.apple.com/be/app/flectra/id1561830563" target="_blank">
<a href="https://apps.apple.com/be/app/flectra/id1272543640" target="_blank">
<img alt="Apple App Store" class="img img-fluid h-100 o_expense_apple_store" src="/hr_expense/static/img/app_store.png"/>
</a>
<a href="https://play.google.com/store/apps/details?id=com.flectra.flectrahq" target="_blank" class="o_expense_google_store">
<a href="https://play.google.com/store/apps/details?id=com.flectra.mobile" target="_blank" class="o_expense_google_store">
<img alt="Google Play Store" class="img img-fluid h-100 o_expense_google_store" src="/hr_expense/static/img/play_store.png"/>
</a>
</p>
+9 -6
View File
@@ -594,7 +594,10 @@ class HolidaysRequest(models.Model):
""" Returns a float equals to the timedelta between two dates given as string."""
if employee_id:
employee = self.env['hr.employee'].browse(employee_id)
return employee._get_work_days_data_batch(date_from, date_to)[employee.id]
result = employee._get_work_days_data_batch(date_from, date_to)[employee.id]
if self.request_unit_half:
result['days'] = 0.5
return result
today_hours = self.env.company.resource_calendar_id.get_work_hours_count(
datetime.combine(date_from.date(), time.min),
@@ -602,8 +605,8 @@ class HolidaysRequest(models.Model):
False)
hours = self.env.company.resource_calendar_id.get_work_hours_count(date_from, date_to)
return {'days': hours / (today_hours or HOURS_PER_DAY), 'hours': hours}
days = hours / (today_hours or HOURS_PER_DAY) if not self.request_unit_half else 0.5
return {'days': days, 'hours': hours}
def _adjust_date_based_on_tz(self, leave_date, hour):
""" request_date_{from,to} are local to the user's tz but hour_{from,to} are in UTC.
@@ -1220,15 +1223,15 @@ class HolidaysRequest(models.Model):
""" Handle HR users and officers recipients that can validate or refuse holidays
directly from email. """
groups = super(HolidaysRequest, self)._notify_get_groups(msg_vals=msg_vals)
msg_vals = msg_vals or {}
local_msg_vals = dict(msg_vals or {})
self.ensure_one()
hr_actions = []
if self.state == 'confirm':
app_action = self._notify_get_action_link('controller', controller='/leave/validate', **msg_vals)
app_action = self._notify_get_action_link('controller', controller='/leave/validate', **local_msg_vals)
hr_actions += [{'url': app_action, 'title': _('Approve')}]
if self.state in ['confirm', 'validate', 'validate1']:
ref_action = self._notify_get_action_link('controller', controller='/leave/refuse', **msg_vals)
ref_action = self._notify_get_action_link('controller', controller='/leave/refuse', **local_msg_vals)
hr_actions += [{'url': ref_action, 'title': _('Refuse')}]
holiday_user_group_id = self.env.ref('hr_holidays.group_hr_holidays_user').id
@@ -670,15 +670,15 @@ class HolidaysAllocation(models.Model):
""" Handle HR users and officers recipients that can validate or refuse holidays
directly from email. """
groups = super(HolidaysAllocation, self)._notify_get_groups(msg_vals=msg_vals)
msg_vals = msg_vals or {}
local_msg_vals = dict(msg_vals or {})
self.ensure_one()
hr_actions = []
if self.state == 'confirm':
app_action = self._notify_get_action_link('controller', controller='/allocation/validate', **msg_vals)
app_action = self._notify_get_action_link('controller', controller='/allocation/validate', **local_msg_vals)
hr_actions += [{'url': app_action, 'title': _('Approve')}]
if self.state in ['confirm', 'validate', 'validate1']:
ref_action = self._notify_get_action_link('controller', controller='/allocation/refuse', **msg_vals)
ref_action = self._notify_get_action_link('controller', controller='/allocation/refuse', **local_msg_vals)
hr_actions += [{'url': ref_action, 'title': _('Refuse')}]
holiday_user_group_id = self.env.ref('hr_holidays.group_hr_holidays_user').id
@@ -33,8 +33,8 @@ class TestAutomaticLeaveDates(TestHrHolidaysCommon):
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 0)
self.assertEqual(leave_form.number_of_hours_text, '0 Hours')
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '4 Hours')
def test_single_attendance_on_morning_and_afternoon(self):
calendar = self.env['resource.calendar'].create({
@@ -140,13 +140,13 @@ class TestAutomaticLeaveDates(TestHrHolidaysCommon):
# Ask for morning
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 1)
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '8 Hours')
# Ask for afternoon
leave_form.request_date_from_period = 'pm'
self.assertEqual(leave_form.number_of_days_display, 1)
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '8 Hours')
def test_attendance_next_day(self):
@@ -173,8 +173,8 @@ class TestAutomaticLeaveDates(TestHrHolidaysCommon):
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 0)
self.assertEqual(leave_form.number_of_hours_text, '0 Hours')
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '4 Hours')
self.assertEqual(leave_form.date_from, datetime(2019, 9, 2, 6, 0, 0))
self.assertEqual(leave_form.date_to, datetime(2019, 9, 2, 10, 0, 0))
@@ -202,8 +202,8 @@ class TestAutomaticLeaveDates(TestHrHolidaysCommon):
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 0)
self.assertEqual(leave_form.number_of_hours_text, '0 Hours')
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '4 Hours')
self.assertEqual(leave_form.date_from, datetime(2019, 9, 3, 6, 0, 0))
self.assertEqual(leave_form.date_to, datetime(2019, 9, 3, 10, 0, 0))
@@ -241,7 +241,7 @@ class TestAutomaticLeaveDates(TestHrHolidaysCommon):
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 1)
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '2 Hours')
self.assertEqual(leave_form.date_from, datetime(2019, 9, 2, 8, 0, 0))
self.assertEqual(leave_form.date_to, datetime(2019, 9, 2, 10, 0, 0))
@@ -254,7 +254,7 @@ class TestAutomaticLeaveDates(TestHrHolidaysCommon):
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 1)
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '4 Hours')
self.assertEqual(leave_form.date_from, datetime(2019, 9, 9, 6, 0, 0))
self.assertEqual(leave_form.date_to, datetime(2019, 9, 9, 10, 0, 0))
@@ -285,7 +285,7 @@ class TestAutomaticLeaveDates(TestHrHolidaysCommon):
leave_form.request_unit_half = True
leave_form.request_date_from_period = 'am'
self.assertEqual(leave_form.number_of_days_display, 0)
self.assertEqual(leave_form.number_of_hours_text, '0 Hours')
self.assertEqual(leave_form.number_of_days_display, 0.5)
self.assertEqual(leave_form.number_of_hours_text, '4 Hours')
self.assertEqual(leave_form.date_from, datetime(2019, 9, 2, 6, 0, 0))
self.assertEqual(leave_form.date_to, datetime(2019, 9, 2, 10, 0, 0))
@@ -313,7 +313,7 @@ class TestCompanyLeave(SavepointCase):
})
company_leave._compute_date_from_to()
count = 865
count = 732
with self.assertQueryCount(__system__=count, admin=count):
# Original query count: 1987
# Without tracking/activity context keys: 5154
+1 -1
View File
@@ -16,7 +16,7 @@ class MaintenanceEquipment(models.Model):
required=True,
default='employee')
owner_user_id = fields.Many2one(compute='_compute_owner', store=True)
assign_date = fields.Date(compute='_compute_equipement_assign', store=True, readonly=False, copy=True)
assign_date = fields.Date(compute='_compute_equipment_assign', store=True, readonly=False, copy=True)
@api.depends('employee_id', 'department_id', 'equipment_assign_to')
def _compute_owner(self):
@@ -515,7 +515,8 @@ class Applicant(models.Model):
], order='sequence asc', limit=1).id
for applicant in self:
applicant.write(
{'stage_id': default_stage[applicant.job_id.id], 'refuse_reason_id': False})
{'stage_id': applicant.job_id.id and default_stage[applicant.job_id.id],
'refuse_reason_id': False})
def toggle_active(self):
res = super(Applicant, self).toggle_active()
+1 -1
View File
@@ -152,7 +152,7 @@ class AccountAnalyticLine(models.Model):
if vals.get('project_id') and not vals.get('account_id'):
project = self.env['project.project'].browse(vals.get('project_id'))
vals['account_id'] = project.analytic_account_id.id
vals['company_id'] = project.analytic_account_id.company_id.id
vals['company_id'] = project.analytic_account_id.company_id.id or project.company_id.id
if not project.analytic_account_id.active:
raise UserError(_('The project you are timesheeting on is not linked to an active analytic account. Set one on the project configuration.'))
# employee implies user
+1 -1
View File
@@ -19,7 +19,7 @@ class HrWorkEntry(models.Model):
date_start = fields.Datetime(required=True, string='From')
date_stop = fields.Datetime(compute='_compute_date_stop', store=True, readonly=False, string='To')
duration = fields.Float(compute='_compute_duration', store=True, string="Period")
work_entry_type_id = fields.Many2one('hr.work.entry.type')
work_entry_type_id = fields.Many2one('hr.work.entry.type', index=True)
color = fields.Integer(related='work_entry_type_id.color', readonly=True)
state = fields.Selection([
('draft', 'Draft'),
+14 -3
View File
@@ -12,8 +12,6 @@ _logger = logging.getLogger(__name__)
class InterfaceMetaClass(type):
def __new__(cls, clsname, bases, attrs):
if clsname in interfaces:
return interfaces[clsname]
new_interface = super(InterfaceMetaClass, cls).__new__(cls, clsname, bases, attrs)
interfaces[clsname] = new_interface
return new_interface
@@ -38,6 +36,15 @@ class Interface(Thread, metaclass=InterfaceMetaClass):
def update_iot_devices(self, devices={}):
added = devices.keys() - self._detected_devices
removed = self._detected_devices - devices.keys()
# keys() returns a dict_keys, and the values of that stay in sync with the
# original dictionary if it changes. This means that get_devices needs to return
# a newly created dictionary every time. If it doesn't do that and reuses the
# same dictionary, this logic won't detect any changes that are made. Could be
# avoided by converting the dict_keys into a regular dict. The current logic
# also can't detect if a device is replaced by a different one with the same
# key. Also, _detected_devices starts out as a class variable but gets turned
# into an instance variable here. It would be better if it was an instance
# variable from the start to avoid confusion.
self._detected_devices = devices.keys()
for identifier in removed:
@@ -51,8 +58,12 @@ class Interface(Thread, metaclass=InterfaceMetaClass):
_logger.info('Device %s is now connected', identifier)
d = driver(identifier, devices[identifier])
d.daemon = True
d.start()
iot_devices[identifier] = d
# Start the thread after creating the iot_devices entry so the
# thread can assume the iot_devices entry will exist while it's
# running, at least until the `disconnect` above gets triggered
# when `removed` is not empty.
d.start()
break
def get_devices(self):
+1 -1
View File
@@ -137,7 +137,7 @@
</div>
<div class="footer">
<a href='https://www.flectrahq.com/help'>Help</a>
<a href='https://doc.flectrahq.com/2.0/iot.html'>Documentation</a>
<a href='https://doc.flectrahq.com/2.0/applications/productivity/iot.html'>Documentation</a>
</div>
</body>
</html>
@@ -73,7 +73,7 @@
However the preferred method to upgrade the IoTBox is to flash the sd-card with
the <a href='https://nightly.flectrahq.com/master/iotbox/iotbox-latest.zip'>latest image</a>. The upgrade
procedure is explained into to the
<a href='https://doc.flectrahq.com/2.0/iot.html'>IoTBox manual</a>
<a href='https://doc.flectrahq.com/2.0/applications/productivity/iot.html'>IoTBox manual</a>
</p>
<p>
To upgrade the IoTBox, click on the upgrade button. The upgrade will take a few minutes. <b>Do not reboot</b> the IoTBox during the upgrade.
+1 -1
View File
@@ -24,7 +24,7 @@
<div t-name="iap.buy_more_credits" class="mt-2 row">
<div class="col-sm">
<button class="btn btn-link buy_credits"><i class="fa fa-arrow-right"/> Buy credits</button>
<button class="btn btn-link buy_credits o-hidden-ios"><i class="fa fa-arrow-right"/> Buy credits</button>
</div>
</div>
</template>
+20
View File
@@ -6,14 +6,34 @@ import logging
import json
import requests
import uuid
from unittest.mock import patch
from flectra import exceptions, _
from flectra.tests.common import BaseCase
from flectra.tools import pycompat
_logger = logging.getLogger(__name__)
DEFAULT_ENDPOINT = 'https://iap.flectrahq.com'
# We need to mock iap_jsonrpc during tests as we don't want to perform real calls to RPC endpoints
def iap_jsonrpc_mocked(*args, **kwargs):
raise exceptions.AccessError("Unavailable during tests.")
iap_patch = patch('flectra.addons.iap.tools.iap_tools.iap_jsonrpc', iap_jsonrpc_mocked)
def setUp(self):
old_setup_func(self)
iap_patch.start()
self.addCleanup(iap_patch.stop)
old_setup_func = BaseCase.setUp
BaseCase.setUp = setUp
#----------------------------------------------------------
# Helpers for both clients and proxy
#----------------------------------------------------------
+2 -2
View File
@@ -24,8 +24,8 @@ if records:
<div class='o_setting_right_pane'>
<div class="o_form_label">
Flectra IAP
<a href="https://doc.flectrahq.com/2.0/general/in_app_purchase/in_app_purchase.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<a href="https://www.flectrahq.com/documentation/14.0/webservices/iap.html" title="Documentation" class="ml-1 o_doc_link" target="_blank"></a>
<a href="https://doc.flectrahq.com/2.0/applications/general/in_app_purchase/in_app_purchase.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<a href="https://doc.flectrahq.com/2.0/developer/webservices/iap.html" title="Documentation" class="ml-1 o_doc_link" target="_blank"></a>
</div>
<div class="text-muted">
View your IAP Services and recharge your credits
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<flectra>
<data>
<data noupdate="1">
<record id="im_livechat_channel_data" model="im_livechat.channel">
<field name="name">YourWebsite.com</field>
<field name="default_message">Hello, how may I help you?</field>
@@ -4,7 +4,7 @@ import base64
import random
import re
from flectra import api, fields, models, modules
from flectra import api, fields, models, modules, _
class ImLivechatChannel(models.Model):
@@ -225,6 +225,8 @@ class ImLivechatChannel(models.Model):
def get_livechat_info(self, username='Visitor'):
self.ensure_one()
if username == 'Visitor':
username = _('Visitor')
info = {}
info['available'] = len(self._get_available_users()) > 0
info['server_url'] = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
+1 -1
View File
@@ -2,7 +2,7 @@
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
{
'name': 'Argentina - Accounting',
'version': "3.2",
'version': "3.3",
'description': """
Functional
----------
+146 -20
View File
@@ -7,19 +7,79 @@ l10n_ar.base_deudores_por_ventas,l10n_ar.l10nar_base_chart_template,1.1.3.01.010
l10n_ar.base_deudores_por_ventas_pos,l10n_ar.l10nar_base_chart_template,1.1.3.01.020,account.data_account_type_receivable,Deudores por ventas (PoS),True
l10n_ar.base_ret_percepcion_tasa_municipal,l10n_ar.l10nar_base_chart_template,1.1.4.01.010,account.data_account_type_current_assets,Ret/Percepción Tasa Municipal,False
l10n_ar.base_saldo_a_favor_tasa_municipal,l10n_ar.l10nar_base_chart_template,1.1.4.01.020,account.data_account_type_current_assets,Saldo a favor Tasa Municipal,False
l10n_ar.base_saldo_favor_iibb_sf,l10n_ar.l10nar_base_chart_template,1.1.4.02.010,account.data_account_type_current_assets,Saldo a favor IIBB p. Santa Fé,False
l10n_ar.base_retencion_iibb_sf_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.020,account.data_account_type_current_assets,Retención IIBB p. Santa Fé sufrida,False
l10n_ar.base_percepcion_iibb_sf_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.030,account.data_account_type_current_assets,Percepción IIBB p. Santa Fé sufrida,False
l10n_ar.base_saldo_favor_iibb_co,l10n_ar.l10nar_base_chart_template,1.1.4.02.040,account.data_account_type_current_assets,Saldo a favor IIBB p. Córdoba,False
l10n_ar.base_retencion_iibb_co_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.050,account.data_account_type_current_assets,Retención IIBB p. Córdoba sufrida,False
l10n_ar.base_percepcion_iibb_co_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.060,account.data_account_type_current_assets,Percepción IIBB p. Córdoba sufrida,False
l10n_ar.base_saldo_favor_iibb_ba,l10n_ar.l10nar_base_chart_template,1.1.4.02.070,account.data_account_type_current_assets,Saldo a favor IIBB p. Buenos Aires,False
l10n_ar.base_retencion_iibb_ba_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.080,account.data_account_type_current_assets,Retención IIBB p. Buenos Aires sufrida,False
l10n_ar.base_percepcion_iibb_ba_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.090,account.data_account_type_current_assets,Percepción IIBB p. Buenos Aires sufrida,False
l10n_ar.base_saldo_favor_iibb_caba,l10n_ar.l10nar_base_chart_template,1.1.4.02.100,account.data_account_type_current_assets,Saldo a favor IIBB p. CABA,False
l10n_ar.base_retencion_iibb_caba_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.110,account.data_account_type_current_assets,Retención IIBB CABA sufrida,False
l10n_ar.base_percepcion_iibb_caba_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.120,account.data_account_type_current_assets,Percepción IIBB CABA sufrida,False
l10n_ar.base_sircreb,l10n_ar.l10nar_base_chart_template,1.1.4.02.130,account.data_account_type_current_assets,SIRCREB,False
l10n_ar.base_saldo_favor_iibb_caba,l10n_ar.l10nar_base_chart_template,1.1.4.02.010,account.data_account_type_current_assets,Saldo a favor IIBB CABA,False
l10n_ar.base_retencion_iibb_caba_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.020,account.data_account_type_current_assets,Retención IIBB CABA sufrida,False
l10n_ar.base_percepcion_iibb_caba_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.030,account.data_account_type_current_assets,Percepción IIBB CABA sufrida,False
l10n_ar.base_saldo_favor_iibb_ba,l10n_ar.l10nar_base_chart_template,1.1.4.02.040,account.data_account_type_current_assets,Saldo a favor IIBB Buenos Aires,False
l10n_ar.base_retencion_iibb_ba_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.050,account.data_account_type_current_assets,Retención IIBB Buenos Aires sufrida,False
l10n_ar.base_percepcion_iibb_ba_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.060,account.data_account_type_current_assets,Percepción IIBB Buenos Aires sufrida,False
l10n_ar.base_saldo_favor_iibb_ca,l10n_ar.l10nar_base_chart_template,1.1.4.02.070,account.data_account_type_current_assets,Saldo a favor IIBB Catamarca,False
l10n_ar.base_retencion_iibb_ca_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.080,account.data_account_type_current_assets,Retención IIBB Catamarca sufrida,False
l10n_ar.base_percepcion_iibb_ca_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.090,account.data_account_type_current_assets,Percepción IIBB Catamarca sufrida,False
l10n_ar.base_saldo_favor_iibb_co,l10n_ar.l10nar_base_chart_template,1.1.4.02.100,account.data_account_type_current_assets,Saldo a favor IIBB Córdoba,False
l10n_ar.base_retencion_iibb_co_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.110,account.data_account_type_current_assets,Retención IIBB Córdoba sufrida,False
l10n_ar.base_percepcion_iibb_co_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.120,account.data_account_type_current_assets,Percepción IIBB Córdoba sufrida,False
l10n_ar.base_saldo_favor_iibb_rr,l10n_ar.l10nar_base_chart_template,1.1.4.02.130,account.data_account_type_current_assets,Saldo a favor IIBB Corrientes,False
l10n_ar.base_retencion_iibb_rr_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.140,account.data_account_type_current_assets,Retención IIBB Corrientes sufrida,False
l10n_ar.base_percepcion_iibb_rr_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.150,account.data_account_type_current_assets,Percepción IIBB Corrientes sufrida,False
l10n_ar.base_saldo_favor_iibb_er,l10n_ar.l10nar_base_chart_template,1.1.4.02.160,account.data_account_type_current_assets,Saldo a favor IIBB Entre Ríos,False
l10n_ar.base_retencion_iibb_er_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.170,account.data_account_type_current_assets,Retención IIBB Entre Ríos sufrida,False
l10n_ar.base_percepcion_iibb_er_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.180,account.data_account_type_current_assets,Percepción IIBB Entre Ríos sufrida,False
l10n_ar.base_saldo_favor_iibb_ju,l10n_ar.l10nar_base_chart_template,1.1.4.02.190,account.data_account_type_current_assets,Saldo a favor IIBB Jujuy,False
l10n_ar.base_retencion_iibb_ju_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.200,account.data_account_type_current_assets,Retención IIBB Jujuy sufrida,False
l10n_ar.base_percepcion_iibb_ju_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.210,account.data_account_type_current_assets,Percepción IIBB Jujuy sufrida,False
l10n_ar.base_saldo_favor_iibb_za,l10n_ar.l10nar_base_chart_template,1.1.4.02.220,account.data_account_type_current_assets,Saldo a favor IIBB Mendoza,False
l10n_ar.base_retencion_iibb_za_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.230,account.data_account_type_current_assets,Retención IIBB Mendoza sufrida,False
l10n_ar.base_percepcion_iibb_za_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.240,account.data_account_type_current_assets,Percepción IIBB Mendoza sufrida,False
l10n_ar.base_saldo_favor_iibb_lr,l10n_ar.l10nar_base_chart_template,1.1.4.02.250,account.data_account_type_current_assets,Saldo a favor IIBB La Rioja,False
l10n_ar.base_retencion_iibb_lr_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.260,account.data_account_type_current_assets,Retención IIBB La Rioja sufrida,False
l10n_ar.base_percepcion_iibb_lr_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.270,account.data_account_type_current_assets,Percepción IIBB La Rioja sufrida,False
l10n_ar.base_saldo_favor_iibb_sa,l10n_ar.l10nar_base_chart_template,1.1.4.02.280,account.data_account_type_current_assets,Saldo a favor IIBB Salta,False
l10n_ar.base_retencion_iibb_sa_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.290,account.data_account_type_current_assets,Retención IIBB Salta sufrida,False
l10n_ar.base_percepcion_iibb_sa_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.300,account.data_account_type_current_assets,Percepción IIBB Salta sufrida,False
l10n_ar.base_saldo_favor_iibb_nn,l10n_ar.l10nar_base_chart_template,1.1.4.02.310,account.data_account_type_current_assets,Saldo a favor IIBB San Juan,False
l10n_ar.base_retencion_iibb_nn_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.320,account.data_account_type_current_assets,Retención IIBB San Juan sufrida,False
l10n_ar.base_percepcion_iibb_nn_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.330,account.data_account_type_current_assets,Percepción IIBB San Juan sufrida,False
l10n_ar.base_saldo_favor_iibb_sl,l10n_ar.l10nar_base_chart_template,1.1.4.02.340,account.data_account_type_current_assets,Saldo a favor IIBB San Luis,False
l10n_ar.base_retencion_iibb_sl_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.350,account.data_account_type_current_assets,Retención IIBB San Luis sufrida,False
l10n_ar.base_percepcion_iibb_sl_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.360,account.data_account_type_current_assets,Percepción IIBB San Luis sufrida,False
l10n_ar.base_saldo_favor_iibb_sf,l10n_ar.l10nar_base_chart_template,1.1.4.02.370,account.data_account_type_current_assets,Saldo a favor IIBB Santa Fe,False
l10n_ar.base_retencion_iibb_sf_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.380,account.data_account_type_current_assets,Retención IIBB Santa Fe sufrida,False
l10n_ar.base_percepcion_iibb_sf_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.390,account.data_account_type_current_assets,Percepción IIBB Santa Fe sufrida,False
l10n_ar.base_saldo_favor_iibb_se,l10n_ar.l10nar_base_chart_template,1.1.4.02.400,account.data_account_type_current_assets,Saldo a favor IIBB Santiago del Estero,False
l10n_ar.base_retencion_iibb_se_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.410,account.data_account_type_current_assets,Retención IIBB Santiago del Estero sufrida,False
l10n_ar.base_percepcion_iibb_se_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.420,account.data_account_type_current_assets,Percepción IIBB Santiago del Estero sufrida,False
l10n_ar.base_saldo_favor_iibb_tn,l10n_ar.l10nar_base_chart_template,1.1.4.02.430,account.data_account_type_current_assets,Saldo a favor IIBB Tucumán,False
l10n_ar.base_retencion_iibb_tn_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.440,account.data_account_type_current_assets,Retención IIBB Tucumán sufrida,False
l10n_ar.base_percepcion_iibb_tn_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.450,account.data_account_type_current_assets,Percepción IIBB Tucumán sufrida,False
l10n_ar.base_saldo_favor_iibb_ha,l10n_ar.l10nar_base_chart_template,1.1.4.02.460,account.data_account_type_current_assets,Saldo a favor IIBB Chaco,False
l10n_ar.base_retencion_iibb_ha_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.470,account.data_account_type_current_assets,Retención IIBB Chaco sufrida,False
l10n_ar.base_percepcion_iibb_ha_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.480,account.data_account_type_current_assets,Percepción IIBB Chaco sufrida,False
l10n_ar.base_saldo_favor_iibb_ct,l10n_ar.l10nar_base_chart_template,1.1.4.02.490,account.data_account_type_current_assets,Saldo a favor IIBB Chubut,False
l10n_ar.base_retencion_iibb_ct_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.500,account.data_account_type_current_assets,Retención IIBB Chubut sufrida,False
l10n_ar.base_percepcion_iibb_ct_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.510,account.data_account_type_current_assets,Percepción IIBB Chubut sufrida,False
l10n_ar.base_saldo_favor_iibb_fo,l10n_ar.l10nar_base_chart_template,1.1.4.02.520,account.data_account_type_current_assets,Saldo a favor IIBB Formosa,False
l10n_ar.base_retencion_iibb_fo_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.530,account.data_account_type_current_assets,Retención IIBB Formosa sufrida,False
l10n_ar.base_percepcion_iibb_fo_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.540,account.data_account_type_current_assets,Percepción IIBB Formosa sufrida,False
l10n_ar.base_saldo_favor_iibb_mi,l10n_ar.l10nar_base_chart_template,1.1.4.02.550,account.data_account_type_current_assets,Saldo a favor IIBB Misiones,False
l10n_ar.base_retencion_iibb_mi_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.560,account.data_account_type_current_assets,Retención IIBB Misiones sufrida,False
l10n_ar.base_percepcion_iibb_mi_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.570,account.data_account_type_current_assets,Percepción IIBB Misiones sufrida,False
l10n_ar.base_saldo_favor_iibb_ne,l10n_ar.l10nar_base_chart_template,1.1.4.02.580,account.data_account_type_current_assets,Saldo a favor IIBB Neuquén,False
l10n_ar.base_retencion_iibb_ne_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.590,account.data_account_type_current_assets,Retención IIBB Neuquén sufrida,False
l10n_ar.base_percepcion_iibb_ne_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.600,account.data_account_type_current_assets,Percepción IIBB Neuquén sufrida,False
l10n_ar.base_saldo_favor_iibb_lp,l10n_ar.l10nar_base_chart_template,1.1.4.02.610,account.data_account_type_current_assets,Saldo a favor IIBB La Pampa,False
l10n_ar.base_retencion_iibb_lp_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.620,account.data_account_type_current_assets,Retención IIBB La Pampa sufrida,False
l10n_ar.base_percepcion_iibb_lp_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.630,account.data_account_type_current_assets,Percepción IIBB La Pampa sufrida,False
l10n_ar.base_saldo_favor_iibb_rn,l10n_ar.l10nar_base_chart_template,1.1.4.02.640,account.data_account_type_current_assets,Saldo a favor IIBB Río Negro,False
l10n_ar.base_retencion_iibb_rn_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.650,account.data_account_type_current_assets,Retención IIBB Río Negro sufrida,False
l10n_ar.base_percepcion_iibb_rn_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.660,account.data_account_type_current_assets,Percepción IIBB Río Negro sufrida,False
l10n_ar.base_saldo_favor_iibb_az,l10n_ar.l10nar_base_chart_template,1.1.4.02.670,account.data_account_type_current_assets,Saldo a favor IIBB Santa Cruz,False
l10n_ar.base_retencion_iibb_az_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.680,account.data_account_type_current_assets,Retención IIBB Santa Cruz sufrida,False
l10n_ar.base_percepcion_iibb_az_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.690,account.data_account_type_current_assets,Percepción IIBB Santa Cruz sufrida,False
l10n_ar.base_saldo_favor_iibb_tf,l10n_ar.l10nar_base_chart_template,1.1.4.02.700,account.data_account_type_current_assets,Saldo a favor IIBB Tierra del Fuego,False
l10n_ar.base_retencion_iibb_tf_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.710,account.data_account_type_current_assets,Retención IIBB Tierra del Fuego sufrida,False
l10n_ar.base_percepcion_iibb_tf_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.02.720,account.data_account_type_current_assets,Percepción IIBB Tierra del Fuego sufrida,False
l10n_ar.base_sircreb,l10n_ar.l10nar_base_chart_template,1.1.4.02.730,account.data_account_type_current_assets,SIRCREB,False
l10n_ar.base_saldo_a_favor_suss,l10n_ar.l10nar_base_chart_template,1.1.4.03.010,account.data_account_type_current_assets,Saldo a favor SUSS,False
l10n_ar.base_retencion_suss_sufrida,l10n_ar.l10nar_base_chart_template,1.1.4.03.020,account.data_account_type_current_assets,Retención SUSS Sufrida,False
l10n_ar.ri_iva_credito_fiscal,l10n_ar.l10nar_ri_chart_template,1.1.4.04.010,account.data_account_type_current_assets,IVA crédito fiscal,False
@@ -62,10 +122,56 @@ l10n_ar.base_tasa_municipal_a_pagar,l10n_ar.l10nar_base_chart_template,2.1.3.01.
l10n_ar.base_plan_tasa_municipal_a_pagar,l10n_ar.l10nar_base_chart_template,2.1.3.01.020,account.data_account_type_payable,Plan Tasa Municipal a pagar,True
l10n_ar.base_iibb_a_pagar,l10n_ar.l10nar_base_chart_template,2.1.3.02.010,account.data_account_type_payable,IIBB a pagar,True
l10n_ar.ri_retencion_sicore_a_pagar,l10n_ar.l10nar_ex_chart_template,2.1.3.02.020,account.data_account_type_payable,SICORE a pagar,True
l10n_ar.ri_retencion_iibb_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.030,account.data_account_type_current_liabilities,Retención IIBB aplicada,False
l10n_ar.ri_percepcion_iibb_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.040,account.data_account_type_current_liabilities,Percepción IIBB aplicada,False
l10n_ar.ri_retencion_iibb_a_pagar,l10n_ar.l10nar_ex_chart_template,2.1.3.02.050,account.data_account_type_payable,Retención/Percepción IIBB a pagar,True
l10n_ar.base_plan_de_iibb_a_pagar,l10n_ar.l10nar_base_chart_template,2.1.3.02.060,account.data_account_type_payable,Plan de IIBB a pagar,True
l10n_ar.ri_retencion_iibb_caba_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.030,account.data_account_type_current_liabilities,Retención IIBB CABA aplicada,False
l10n_ar.ri_percepcion_iibb_caba_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.040,account.data_account_type_current_liabilities,Percepción IIBB CABA aplicada,False
l10n_ar.ri_retencion_iibb_ba_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.050,account.data_account_type_current_liabilities,Retención IIBB ARBA aplicada,False
l10n_ar.ri_percepcion_iibb_ba_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.060,account.data_account_type_current_liabilities,Percepción IIBB ARBA aplicada,False
l10n_ar.ri_retencion_iibb_ca_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.070,account.data_account_type_current_liabilities,Retención IIBB Catamarca aplicada,False
l10n_ar.ri_percepcion_iibb_ca_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.080,account.data_account_type_current_liabilities,Percepción IIBB Catamarca aplicada,False
l10n_ar.ri_retencion_iibb_co_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.090,account.data_account_type_current_liabilities,Retención IIBB Córdoba aplicada,False
l10n_ar.ri_percepcion_iibb_co_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.100,account.data_account_type_current_liabilities,Percepción IIBB Córdoba aplicada,False
l10n_ar.ri_retencion_iibb_rr_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.110,account.data_account_type_current_liabilities,Retención IIBB Corrientes aplicada,False
l10n_ar.ri_percepcion_iibb_rr_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.120,account.data_account_type_current_liabilities,Percepción IIBB Corrientes aplicada,False
l10n_ar.ri_retencion_iibb_er_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.130,account.data_account_type_current_liabilities,Retención IIBB Entre Río aplicada,False
l10n_ar.ri_percepcion_iibb_er_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.140,account.data_account_type_current_liabilities,Percepción IIBB Entre Río aplicada,False
l10n_ar.ri_retencion_iibb_ju_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.150,account.data_account_type_current_liabilities,Retención IIBB Jujuy aplicada,False
l10n_ar.ri_percepcion_iibb_ju_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.160,account.data_account_type_current_liabilities,Percepción IIBB Jujuy aplicada,False
l10n_ar.ri_retencion_iibb_za_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.170,account.data_account_type_current_liabilities,Retención IIBB Mendoza aplicada,False
l10n_ar.ri_percepcion_iibb_za_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.180,account.data_account_type_current_liabilities,Percepción IIBB Mendoza aplicada,False
l10n_ar.ri_retencion_iibb_lr_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.190,account.data_account_type_current_liabilities,Retención IIBB La Rioja aplicada,False
l10n_ar.ri_percepcion_iibb_lr_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.200,account.data_account_type_current_liabilities,Percepción IIBB La Rioja aplicada,False
l10n_ar.ri_retencion_iibb_sa_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.210,account.data_account_type_current_liabilities,Retención IIBB Salta aplicada,False
l10n_ar.ri_percepcion_iibb_sa_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.220,account.data_account_type_current_liabilities,Percepción IIBB Salta aplicada,False
l10n_ar.ri_retencion_iibb_nn_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.230,account.data_account_type_current_liabilities,Retención IIBB San Juan aplicada,False
l10n_ar.ri_percepcion_iibb_nn_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.240,account.data_account_type_current_liabilities,Percepción IIBB San Juan aplicada,False
l10n_ar.ri_retencion_iibb_sl_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.250,account.data_account_type_current_liabilities,Retención IIBB San Luis aplicada,False
l10n_ar.ri_percepcion_iibb_sl_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.260,account.data_account_type_current_liabilities,Percepción IIBB San Luis aplicada,False
l10n_ar.ri_retencion_iibb_sf_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.270,account.data_account_type_current_liabilities,Retención IIBB Santa Fe aplicada,False
l10n_ar.ri_percepcion_iibb_sf_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.280,account.data_account_type_current_liabilities,Percepción IIBB Santa Fe aplicada,False
l10n_ar.ri_retencion_iibb_se_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.290,account.data_account_type_current_liabilities,Retención IIBB Santiago del Estero aplicada,False
l10n_ar.ri_percepcion_iibb_se_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.300,account.data_account_type_current_liabilities,Percepción IIBB Santiago del Estero aplicada,False
l10n_ar.ri_retencion_iibb_tn_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.310,account.data_account_type_current_liabilities,Retención IIBB Tucumán aplicada,False
l10n_ar.ri_percepcion_iibb_tn_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.320,account.data_account_type_current_liabilities,Percepción IIBB Tucumán aplicada,False
l10n_ar.ri_retencion_iibb_ha_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.330,account.data_account_type_current_liabilities,Retención IIBB Chaco aplicada,False
l10n_ar.ri_percepcion_iibb_ha_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.340,account.data_account_type_current_liabilities,Percepción IIBB Chaco aplicada,False
l10n_ar.ri_retencion_iibb_ct_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.350,account.data_account_type_current_liabilities,Retención IIBB Chubut aplicada,False
l10n_ar.ri_percepcion_iibb_ct_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.360,account.data_account_type_current_liabilities,Percepción IIBB Chubut aplicada,False
l10n_ar.ri_retencion_iibb_fo_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.370,account.data_account_type_current_liabilities,Retención IIBB Formosa aplicada,False
l10n_ar.ri_percepcion_iibb_fo_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.380,account.data_account_type_current_liabilities,Percepción IIBB Formosa aplicada,False
l10n_ar.ri_retencion_iibb_mi_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.390,account.data_account_type_current_liabilities,Retención IIBB Misiones aplicada,False
l10n_ar.ri_percepcion_iibb_mi_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.400,account.data_account_type_current_liabilities,Percepción IIBB Misiones aplicada,False
l10n_ar.ri_retencion_iibb_ne_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.410,account.data_account_type_current_liabilities,Retención IIBB Neuquén aplicada,False
l10n_ar.ri_percepcion_iibb_ne_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.420,account.data_account_type_current_liabilities,Percepción IIBB Neuquén aplicada,False
l10n_ar.ri_retencion_iibb_lp_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.430,account.data_account_type_current_liabilities,Retención IIBB La Pampa aplicada,False
l10n_ar.ri_percepcion_iibb_lp_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.440,account.data_account_type_current_liabilities,Percepción IIBB La Pampa aplicada,False
l10n_ar.ri_retencion_iibb_rn_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.450,account.data_account_type_current_liabilities,Retención IIBB Río Negro aplicada,False
l10n_ar.ri_percepcion_iibb_rn_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.460,account.data_account_type_current_liabilities,Percepción IIBB Río Negro aplicada,False
l10n_ar.ri_retencion_iibb_az_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.470,account.data_account_type_current_liabilities,Retención IIBB Santa Cruz aplicada,False
l10n_ar.ri_percepcion_iibb_az_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.480,account.data_account_type_current_liabilities,Percepción IIBB Santa Cruz aplicada,False
l10n_ar.ri_retencion_iibb_tf_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.490,account.data_account_type_current_liabilities,Retención IIBB Tierra del Fuego aplicada,False
l10n_ar.ri_percepcion_iibb_tf_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.02.500,account.data_account_type_current_liabilities,Percepción IIBB Tierra del Fuego aplicada,False
l10n_ar.ri_retencion_iibb_a_pagar,l10n_ar.l10nar_ex_chart_template,2.1.3.02.510,account.data_account_type_payable,Retención/Percepción IIBB a pagar,True
l10n_ar.base_plan_de_iibb_a_pagar,l10n_ar.l10nar_base_chart_template,2.1.3.02.520,account.data_account_type_payable,Plan de IIBB a pagar,True
l10n_ar.ri_iva_debito_fiscal,l10n_ar.l10nar_ri_chart_template,2.1.3.03.010,account.data_account_type_current_liabilities,IVA débito fiscal,False
l10n_ar.ri_iva_saldo_a_pagar,l10n_ar.l10nar_ri_chart_template,2.1.3.03.020,account.data_account_type_payable,IVA saldo a pagar,True
l10n_ar.ri_retencion_iva_aplicada,l10n_ar.l10nar_ex_chart_template,2.1.3.03.030,account.data_account_type_current_liabilities,Retención IVA aplicada,False
@@ -151,9 +257,29 @@ l10n_ar.base_seguros_administracion,l10n_ar.l10nar_base_chart_template,5.3.1.01.
l10n_ar.base_sellados_y_certificaciones,l10n_ar.l10nar_base_chart_template,5.3.1.01.140,account.data_account_type_expenses,Sellados y Certificaciones,False
l10n_ar.base_tasa_municipal,l10n_ar.l10nar_base_chart_template,5.4.1.01.010,account.data_account_type_expenses,Tasa Municipal,False
l10n_ar.base_impuestos_iibb_caba,l10n_ar.l10nar_base_chart_template,5.4.2.01.010,account.data_account_type_expenses,IIBB CABA,False
l10n_ar.base_impuestos_iibb_ba,l10n_ar.l10nar_base_chart_template,5.4.2.01.020,account.data_account_type_expenses,IIBB Prov. Bs. As.,False
l10n_ar.base_impuestos_iibb_co,l10n_ar.l10nar_base_chart_template,5.4.2.01.030,account.data_account_type_expenses,IIBB Prov. Córdoba,False
l10n_ar.base_impuestos_iibb_sf,l10n_ar.l10nar_base_chart_template,5.4.2.01.040,account.data_account_type_expenses,IIBB Prov. Santa Fé,False
l10n_ar.base_impuestos_iibb_ba,l10n_ar.l10nar_base_chart_template,5.4.2.01.020,account.data_account_type_expenses,IIBB ARBA,False
l10n_ar.base_impuestos_iibb_ca,l10n_ar.l10nar_base_chart_template,5.4.2.01.030,account.data_account_type_expenses,IIBB Catamarca,False
l10n_ar.base_impuestos_iibb_co,l10n_ar.l10nar_base_chart_template,5.4.2.01.040,account.data_account_type_expenses,IIBB Córdoba,False
l10n_ar.base_impuestos_iibb_rr,l10n_ar.l10nar_base_chart_template,5.4.2.01.050,account.data_account_type_expenses,IIBB Corrientes,False
l10n_ar.base_impuestos_iibb_er,l10n_ar.l10nar_base_chart_template,5.4.2.01.060,account.data_account_type_expenses,IIBB Entre Ríos,False
l10n_ar.base_impuestos_iibb_ju,l10n_ar.l10nar_base_chart_template,5.4.2.01.070,account.data_account_type_expenses,IIBB Jujuy,False
l10n_ar.base_impuestos_iibb_za,l10n_ar.l10nar_base_chart_template,5.4.2.01.080,account.data_account_type_expenses,IIBB Mendoza,False
l10n_ar.base_impuestos_iibb_lr,l10n_ar.l10nar_base_chart_template,5.4.2.01.090,account.data_account_type_expenses,IIBB La Rioja,False
l10n_ar.base_impuestos_iibb_sa,l10n_ar.l10nar_base_chart_template,5.4.2.01.100,account.data_account_type_expenses,IIBB Salta,False
l10n_ar.base_impuestos_iibb_nn,l10n_ar.l10nar_base_chart_template,5.4.2.01.110,account.data_account_type_expenses,IIBB San Juan,False
l10n_ar.base_impuestos_iibb_sl,l10n_ar.l10nar_base_chart_template,5.4.2.01.120,account.data_account_type_expenses,IIBB San Luis,False
l10n_ar.base_impuestos_iibb_sf,l10n_ar.l10nar_base_chart_template,5.4.2.01.130,account.data_account_type_expenses,IIBB Santa Fe,False
l10n_ar.base_impuestos_iibb_se,l10n_ar.l10nar_base_chart_template,5.4.2.01.140,account.data_account_type_expenses,IIBB Santiago del Estero,False
l10n_ar.base_impuestos_iibb_tn,l10n_ar.l10nar_base_chart_template,5.4.2.01.150,account.data_account_type_expenses,IIBB Tucumán,False
l10n_ar.base_impuestos_iibb_ha,l10n_ar.l10nar_base_chart_template,5.4.2.01.160,account.data_account_type_expenses,IIBB Chaco,False
l10n_ar.base_impuestos_iibb_ct,l10n_ar.l10nar_base_chart_template,5.4.2.01.170,account.data_account_type_expenses,IIBB Chubut,False
l10n_ar.base_impuestos_iibb_fo,l10n_ar.l10nar_base_chart_template,5.4.2.01.180,account.data_account_type_expenses,IIBB Formosa,False
l10n_ar.base_impuestos_iibb_mi,l10n_ar.l10nar_base_chart_template,5.4.2.01.190,account.data_account_type_expenses,IIBB Misiones,False
l10n_ar.base_impuestos_iibb_ne,l10n_ar.l10nar_base_chart_template,5.4.2.01.200,account.data_account_type_expenses,IIBB Neuquén,False
l10n_ar.base_impuestos_iibb_lp,l10n_ar.l10nar_base_chart_template,5.4.2.01.210,account.data_account_type_expenses,IIBB La Pampa,False
l10n_ar.base_impuestos_iibb_rn,l10n_ar.l10nar_base_chart_template,5.4.2.01.220,account.data_account_type_expenses,IIBB Río Negro,False
l10n_ar.base_impuestos_iibb_az,l10n_ar.l10nar_base_chart_template,5.4.2.01.230,account.data_account_type_expenses,IIBB Santa Cruz,False
l10n_ar.base_impuestos_iibb_tf,l10n_ar.l10nar_base_chart_template,5.4.2.01.240,account.data_account_type_expenses,IIBB Tierra del Fuego,False
l10n_ar.base_impuestos_debitos_y_creditos,l10n_ar.l10nar_base_chart_template,5.4.3.01.010,account.data_account_type_expenses,Impuestos a los débitos y créditos bancarios,False
l10n_ar.base_impuestos_a_las_ganancias,l10n_ar.l10nar_ex_chart_template,5.5.1.01.010,account.data_account_type_expenses,Impuestos a las ganancias,False
l10n_ar.base_resultado_intereses_y_recargos,l10n_ar.l10nar_base_chart_template,5.6.1.01.020,account.data_account_type_expenses,Intereses por préstamos,False
1 id chart_template_id/id code user_type_id/id name reconcile
7 l10n_ar.base_deudores_por_ventas_pos l10n_ar.l10nar_base_chart_template 1.1.3.01.020 account.data_account_type_receivable Deudores por ventas (PoS) True
8 l10n_ar.base_ret_percepcion_tasa_municipal l10n_ar.l10nar_base_chart_template 1.1.4.01.010 account.data_account_type_current_assets Ret/Percepción Tasa Municipal False
9 l10n_ar.base_saldo_a_favor_tasa_municipal l10n_ar.l10nar_base_chart_template 1.1.4.01.020 account.data_account_type_current_assets Saldo a favor Tasa Municipal False
10 l10n_ar.base_saldo_favor_iibb_sf l10n_ar.base_saldo_favor_iibb_caba l10n_ar.l10nar_base_chart_template 1.1.4.02.010 account.data_account_type_current_assets Saldo a favor IIBB p. Santa Fé Saldo a favor IIBB CABA False
11 l10n_ar.base_retencion_iibb_sf_sufrida l10n_ar.base_retencion_iibb_caba_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.020 account.data_account_type_current_assets Retención IIBB p. Santa Fé sufrida Retención IIBB CABA sufrida False
12 l10n_ar.base_percepcion_iibb_sf_sufrida l10n_ar.base_percepcion_iibb_caba_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.030 account.data_account_type_current_assets Percepción IIBB p. Santa Fé sufrida Percepción IIBB CABA sufrida False
13 l10n_ar.base_saldo_favor_iibb_co l10n_ar.base_saldo_favor_iibb_ba l10n_ar.l10nar_base_chart_template 1.1.4.02.040 account.data_account_type_current_assets Saldo a favor IIBB p. Córdoba Saldo a favor IIBB Buenos Aires False
14 l10n_ar.base_retencion_iibb_co_sufrida l10n_ar.base_retencion_iibb_ba_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.050 account.data_account_type_current_assets Retención IIBB p. Córdoba sufrida Retención IIBB Buenos Aires sufrida False
15 l10n_ar.base_percepcion_iibb_co_sufrida l10n_ar.base_percepcion_iibb_ba_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.060 account.data_account_type_current_assets Percepción IIBB p. Córdoba sufrida Percepción IIBB Buenos Aires sufrida False
16 l10n_ar.base_saldo_favor_iibb_ba l10n_ar.base_saldo_favor_iibb_ca l10n_ar.l10nar_base_chart_template 1.1.4.02.070 account.data_account_type_current_assets Saldo a favor IIBB p. Buenos Aires Saldo a favor IIBB Catamarca False
17 l10n_ar.base_retencion_iibb_ba_sufrida l10n_ar.base_retencion_iibb_ca_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.080 account.data_account_type_current_assets Retención IIBB p. Buenos Aires sufrida Retención IIBB Catamarca sufrida False
18 l10n_ar.base_percepcion_iibb_ba_sufrida l10n_ar.base_percepcion_iibb_ca_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.090 account.data_account_type_current_assets Percepción IIBB p. Buenos Aires sufrida Percepción IIBB Catamarca sufrida False
19 l10n_ar.base_saldo_favor_iibb_caba l10n_ar.base_saldo_favor_iibb_co l10n_ar.l10nar_base_chart_template 1.1.4.02.100 account.data_account_type_current_assets Saldo a favor IIBB p. CABA Saldo a favor IIBB Córdoba False
20 l10n_ar.base_retencion_iibb_caba_sufrida l10n_ar.base_retencion_iibb_co_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.110 account.data_account_type_current_assets Retención IIBB CABA sufrida Retención IIBB Córdoba sufrida False
21 l10n_ar.base_percepcion_iibb_caba_sufrida l10n_ar.base_percepcion_iibb_co_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.120 account.data_account_type_current_assets Percepción IIBB CABA sufrida Percepción IIBB Córdoba sufrida False
22 l10n_ar.base_sircreb l10n_ar.base_saldo_favor_iibb_rr l10n_ar.l10nar_base_chart_template 1.1.4.02.130 account.data_account_type_current_assets SIRCREB Saldo a favor IIBB Corrientes False
23 l10n_ar.base_retencion_iibb_rr_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.140 account.data_account_type_current_assets Retención IIBB Corrientes sufrida False
24 l10n_ar.base_percepcion_iibb_rr_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.150 account.data_account_type_current_assets Percepción IIBB Corrientes sufrida False
25 l10n_ar.base_saldo_favor_iibb_er l10n_ar.l10nar_base_chart_template 1.1.4.02.160 account.data_account_type_current_assets Saldo a favor IIBB Entre Ríos False
26 l10n_ar.base_retencion_iibb_er_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.170 account.data_account_type_current_assets Retención IIBB Entre Ríos sufrida False
27 l10n_ar.base_percepcion_iibb_er_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.180 account.data_account_type_current_assets Percepción IIBB Entre Ríos sufrida False
28 l10n_ar.base_saldo_favor_iibb_ju l10n_ar.l10nar_base_chart_template 1.1.4.02.190 account.data_account_type_current_assets Saldo a favor IIBB Jujuy False
29 l10n_ar.base_retencion_iibb_ju_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.200 account.data_account_type_current_assets Retención IIBB Jujuy sufrida False
30 l10n_ar.base_percepcion_iibb_ju_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.210 account.data_account_type_current_assets Percepción IIBB Jujuy sufrida False
31 l10n_ar.base_saldo_favor_iibb_za l10n_ar.l10nar_base_chart_template 1.1.4.02.220 account.data_account_type_current_assets Saldo a favor IIBB Mendoza False
32 l10n_ar.base_retencion_iibb_za_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.230 account.data_account_type_current_assets Retención IIBB Mendoza sufrida False
33 l10n_ar.base_percepcion_iibb_za_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.240 account.data_account_type_current_assets Percepción IIBB Mendoza sufrida False
34 l10n_ar.base_saldo_favor_iibb_lr l10n_ar.l10nar_base_chart_template 1.1.4.02.250 account.data_account_type_current_assets Saldo a favor IIBB La Rioja False
35 l10n_ar.base_retencion_iibb_lr_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.260 account.data_account_type_current_assets Retención IIBB La Rioja sufrida False
36 l10n_ar.base_percepcion_iibb_lr_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.270 account.data_account_type_current_assets Percepción IIBB La Rioja sufrida False
37 l10n_ar.base_saldo_favor_iibb_sa l10n_ar.l10nar_base_chart_template 1.1.4.02.280 account.data_account_type_current_assets Saldo a favor IIBB Salta False
38 l10n_ar.base_retencion_iibb_sa_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.290 account.data_account_type_current_assets Retención IIBB Salta sufrida False
39 l10n_ar.base_percepcion_iibb_sa_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.300 account.data_account_type_current_assets Percepción IIBB Salta sufrida False
40 l10n_ar.base_saldo_favor_iibb_nn l10n_ar.l10nar_base_chart_template 1.1.4.02.310 account.data_account_type_current_assets Saldo a favor IIBB San Juan False
41 l10n_ar.base_retencion_iibb_nn_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.320 account.data_account_type_current_assets Retención IIBB San Juan sufrida False
42 l10n_ar.base_percepcion_iibb_nn_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.330 account.data_account_type_current_assets Percepción IIBB San Juan sufrida False
43 l10n_ar.base_saldo_favor_iibb_sl l10n_ar.l10nar_base_chart_template 1.1.4.02.340 account.data_account_type_current_assets Saldo a favor IIBB San Luis False
44 l10n_ar.base_retencion_iibb_sl_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.350 account.data_account_type_current_assets Retención IIBB San Luis sufrida False
45 l10n_ar.base_percepcion_iibb_sl_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.360 account.data_account_type_current_assets Percepción IIBB San Luis sufrida False
46 l10n_ar.base_saldo_favor_iibb_sf l10n_ar.l10nar_base_chart_template 1.1.4.02.370 account.data_account_type_current_assets Saldo a favor IIBB Santa Fe False
47 l10n_ar.base_retencion_iibb_sf_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.380 account.data_account_type_current_assets Retención IIBB Santa Fe sufrida False
48 l10n_ar.base_percepcion_iibb_sf_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.390 account.data_account_type_current_assets Percepción IIBB Santa Fe sufrida False
49 l10n_ar.base_saldo_favor_iibb_se l10n_ar.l10nar_base_chart_template 1.1.4.02.400 account.data_account_type_current_assets Saldo a favor IIBB Santiago del Estero False
50 l10n_ar.base_retencion_iibb_se_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.410 account.data_account_type_current_assets Retención IIBB Santiago del Estero sufrida False
51 l10n_ar.base_percepcion_iibb_se_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.420 account.data_account_type_current_assets Percepción IIBB Santiago del Estero sufrida False
52 l10n_ar.base_saldo_favor_iibb_tn l10n_ar.l10nar_base_chart_template 1.1.4.02.430 account.data_account_type_current_assets Saldo a favor IIBB Tucumán False
53 l10n_ar.base_retencion_iibb_tn_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.440 account.data_account_type_current_assets Retención IIBB Tucumán sufrida False
54 l10n_ar.base_percepcion_iibb_tn_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.450 account.data_account_type_current_assets Percepción IIBB Tucumán sufrida False
55 l10n_ar.base_saldo_favor_iibb_ha l10n_ar.l10nar_base_chart_template 1.1.4.02.460 account.data_account_type_current_assets Saldo a favor IIBB Chaco False
56 l10n_ar.base_retencion_iibb_ha_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.470 account.data_account_type_current_assets Retención IIBB Chaco sufrida False
57 l10n_ar.base_percepcion_iibb_ha_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.480 account.data_account_type_current_assets Percepción IIBB Chaco sufrida False
58 l10n_ar.base_saldo_favor_iibb_ct l10n_ar.l10nar_base_chart_template 1.1.4.02.490 account.data_account_type_current_assets Saldo a favor IIBB Chubut False
59 l10n_ar.base_retencion_iibb_ct_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.500 account.data_account_type_current_assets Retención IIBB Chubut sufrida False
60 l10n_ar.base_percepcion_iibb_ct_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.510 account.data_account_type_current_assets Percepción IIBB Chubut sufrida False
61 l10n_ar.base_saldo_favor_iibb_fo l10n_ar.l10nar_base_chart_template 1.1.4.02.520 account.data_account_type_current_assets Saldo a favor IIBB Formosa False
62 l10n_ar.base_retencion_iibb_fo_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.530 account.data_account_type_current_assets Retención IIBB Formosa sufrida False
63 l10n_ar.base_percepcion_iibb_fo_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.540 account.data_account_type_current_assets Percepción IIBB Formosa sufrida False
64 l10n_ar.base_saldo_favor_iibb_mi l10n_ar.l10nar_base_chart_template 1.1.4.02.550 account.data_account_type_current_assets Saldo a favor IIBB Misiones False
65 l10n_ar.base_retencion_iibb_mi_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.560 account.data_account_type_current_assets Retención IIBB Misiones sufrida False
66 l10n_ar.base_percepcion_iibb_mi_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.570 account.data_account_type_current_assets Percepción IIBB Misiones sufrida False
67 l10n_ar.base_saldo_favor_iibb_ne l10n_ar.l10nar_base_chart_template 1.1.4.02.580 account.data_account_type_current_assets Saldo a favor IIBB Neuquén False
68 l10n_ar.base_retencion_iibb_ne_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.590 account.data_account_type_current_assets Retención IIBB Neuquén sufrida False
69 l10n_ar.base_percepcion_iibb_ne_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.600 account.data_account_type_current_assets Percepción IIBB Neuquén sufrida False
70 l10n_ar.base_saldo_favor_iibb_lp l10n_ar.l10nar_base_chart_template 1.1.4.02.610 account.data_account_type_current_assets Saldo a favor IIBB La Pampa False
71 l10n_ar.base_retencion_iibb_lp_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.620 account.data_account_type_current_assets Retención IIBB La Pampa sufrida False
72 l10n_ar.base_percepcion_iibb_lp_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.630 account.data_account_type_current_assets Percepción IIBB La Pampa sufrida False
73 l10n_ar.base_saldo_favor_iibb_rn l10n_ar.l10nar_base_chart_template 1.1.4.02.640 account.data_account_type_current_assets Saldo a favor IIBB Río Negro False
74 l10n_ar.base_retencion_iibb_rn_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.650 account.data_account_type_current_assets Retención IIBB Río Negro sufrida False
75 l10n_ar.base_percepcion_iibb_rn_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.660 account.data_account_type_current_assets Percepción IIBB Río Negro sufrida False
76 l10n_ar.base_saldo_favor_iibb_az l10n_ar.l10nar_base_chart_template 1.1.4.02.670 account.data_account_type_current_assets Saldo a favor IIBB Santa Cruz False
77 l10n_ar.base_retencion_iibb_az_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.680 account.data_account_type_current_assets Retención IIBB Santa Cruz sufrida False
78 l10n_ar.base_percepcion_iibb_az_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.690 account.data_account_type_current_assets Percepción IIBB Santa Cruz sufrida False
79 l10n_ar.base_saldo_favor_iibb_tf l10n_ar.l10nar_base_chart_template 1.1.4.02.700 account.data_account_type_current_assets Saldo a favor IIBB Tierra del Fuego False
80 l10n_ar.base_retencion_iibb_tf_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.710 account.data_account_type_current_assets Retención IIBB Tierra del Fuego sufrida False
81 l10n_ar.base_percepcion_iibb_tf_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.02.720 account.data_account_type_current_assets Percepción IIBB Tierra del Fuego sufrida False
82 l10n_ar.base_sircreb l10n_ar.l10nar_base_chart_template 1.1.4.02.730 account.data_account_type_current_assets SIRCREB False
83 l10n_ar.base_saldo_a_favor_suss l10n_ar.l10nar_base_chart_template 1.1.4.03.010 account.data_account_type_current_assets Saldo a favor SUSS False
84 l10n_ar.base_retencion_suss_sufrida l10n_ar.l10nar_base_chart_template 1.1.4.03.020 account.data_account_type_current_assets Retención SUSS Sufrida False
85 l10n_ar.ri_iva_credito_fiscal l10n_ar.l10nar_ri_chart_template 1.1.4.04.010 account.data_account_type_current_assets IVA crédito fiscal False
122 l10n_ar.base_plan_tasa_municipal_a_pagar l10n_ar.l10nar_base_chart_template 2.1.3.01.020 account.data_account_type_payable Plan Tasa Municipal a pagar True
123 l10n_ar.base_iibb_a_pagar l10n_ar.l10nar_base_chart_template 2.1.3.02.010 account.data_account_type_payable IIBB a pagar True
124 l10n_ar.ri_retencion_sicore_a_pagar l10n_ar.l10nar_ex_chart_template 2.1.3.02.020 account.data_account_type_payable SICORE a pagar True
125 l10n_ar.ri_retencion_iibb_aplicada l10n_ar.ri_retencion_iibb_caba_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.030 account.data_account_type_current_liabilities Retención IIBB aplicada Retención IIBB CABA aplicada False
126 l10n_ar.ri_percepcion_iibb_aplicada l10n_ar.ri_percepcion_iibb_caba_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.040 account.data_account_type_current_liabilities Percepción IIBB aplicada Percepción IIBB CABA aplicada False
127 l10n_ar.ri_retencion_iibb_a_pagar l10n_ar.ri_retencion_iibb_ba_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.050 account.data_account_type_payable account.data_account_type_current_liabilities Retención/Percepción IIBB a pagar Retención IIBB ARBA aplicada True False
128 l10n_ar.base_plan_de_iibb_a_pagar l10n_ar.ri_percepcion_iibb_ba_aplicada l10n_ar.l10nar_base_chart_template l10n_ar.l10nar_ex_chart_template 2.1.3.02.060 account.data_account_type_payable account.data_account_type_current_liabilities Plan de IIBB a pagar Percepción IIBB ARBA aplicada True False
129 l10n_ar.ri_retencion_iibb_ca_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.070 account.data_account_type_current_liabilities Retención IIBB Catamarca aplicada False
130 l10n_ar.ri_percepcion_iibb_ca_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.080 account.data_account_type_current_liabilities Percepción IIBB Catamarca aplicada False
131 l10n_ar.ri_retencion_iibb_co_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.090 account.data_account_type_current_liabilities Retención IIBB Córdoba aplicada False
132 l10n_ar.ri_percepcion_iibb_co_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.100 account.data_account_type_current_liabilities Percepción IIBB Córdoba aplicada False
133 l10n_ar.ri_retencion_iibb_rr_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.110 account.data_account_type_current_liabilities Retención IIBB Corrientes aplicada False
134 l10n_ar.ri_percepcion_iibb_rr_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.120 account.data_account_type_current_liabilities Percepción IIBB Corrientes aplicada False
135 l10n_ar.ri_retencion_iibb_er_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.130 account.data_account_type_current_liabilities Retención IIBB Entre Río aplicada False
136 l10n_ar.ri_percepcion_iibb_er_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.140 account.data_account_type_current_liabilities Percepción IIBB Entre Río aplicada False
137 l10n_ar.ri_retencion_iibb_ju_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.150 account.data_account_type_current_liabilities Retención IIBB Jujuy aplicada False
138 l10n_ar.ri_percepcion_iibb_ju_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.160 account.data_account_type_current_liabilities Percepción IIBB Jujuy aplicada False
139 l10n_ar.ri_retencion_iibb_za_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.170 account.data_account_type_current_liabilities Retención IIBB Mendoza aplicada False
140 l10n_ar.ri_percepcion_iibb_za_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.180 account.data_account_type_current_liabilities Percepción IIBB Mendoza aplicada False
141 l10n_ar.ri_retencion_iibb_lr_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.190 account.data_account_type_current_liabilities Retención IIBB La Rioja aplicada False
142 l10n_ar.ri_percepcion_iibb_lr_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.200 account.data_account_type_current_liabilities Percepción IIBB La Rioja aplicada False
143 l10n_ar.ri_retencion_iibb_sa_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.210 account.data_account_type_current_liabilities Retención IIBB Salta aplicada False
144 l10n_ar.ri_percepcion_iibb_sa_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.220 account.data_account_type_current_liabilities Percepción IIBB Salta aplicada False
145 l10n_ar.ri_retencion_iibb_nn_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.230 account.data_account_type_current_liabilities Retención IIBB San Juan aplicada False
146 l10n_ar.ri_percepcion_iibb_nn_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.240 account.data_account_type_current_liabilities Percepción IIBB San Juan aplicada False
147 l10n_ar.ri_retencion_iibb_sl_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.250 account.data_account_type_current_liabilities Retención IIBB San Luis aplicada False
148 l10n_ar.ri_percepcion_iibb_sl_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.260 account.data_account_type_current_liabilities Percepción IIBB San Luis aplicada False
149 l10n_ar.ri_retencion_iibb_sf_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.270 account.data_account_type_current_liabilities Retención IIBB Santa Fe aplicada False
150 l10n_ar.ri_percepcion_iibb_sf_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.280 account.data_account_type_current_liabilities Percepción IIBB Santa Fe aplicada False
151 l10n_ar.ri_retencion_iibb_se_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.290 account.data_account_type_current_liabilities Retención IIBB Santiago del Estero aplicada False
152 l10n_ar.ri_percepcion_iibb_se_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.300 account.data_account_type_current_liabilities Percepción IIBB Santiago del Estero aplicada False
153 l10n_ar.ri_retencion_iibb_tn_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.310 account.data_account_type_current_liabilities Retención IIBB Tucumán aplicada False
154 l10n_ar.ri_percepcion_iibb_tn_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.320 account.data_account_type_current_liabilities Percepción IIBB Tucumán aplicada False
155 l10n_ar.ri_retencion_iibb_ha_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.330 account.data_account_type_current_liabilities Retención IIBB Chaco aplicada False
156 l10n_ar.ri_percepcion_iibb_ha_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.340 account.data_account_type_current_liabilities Percepción IIBB Chaco aplicada False
157 l10n_ar.ri_retencion_iibb_ct_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.350 account.data_account_type_current_liabilities Retención IIBB Chubut aplicada False
158 l10n_ar.ri_percepcion_iibb_ct_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.360 account.data_account_type_current_liabilities Percepción IIBB Chubut aplicada False
159 l10n_ar.ri_retencion_iibb_fo_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.370 account.data_account_type_current_liabilities Retención IIBB Formosa aplicada False
160 l10n_ar.ri_percepcion_iibb_fo_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.380 account.data_account_type_current_liabilities Percepción IIBB Formosa aplicada False
161 l10n_ar.ri_retencion_iibb_mi_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.390 account.data_account_type_current_liabilities Retención IIBB Misiones aplicada False
162 l10n_ar.ri_percepcion_iibb_mi_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.400 account.data_account_type_current_liabilities Percepción IIBB Misiones aplicada False
163 l10n_ar.ri_retencion_iibb_ne_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.410 account.data_account_type_current_liabilities Retención IIBB Neuquén aplicada False
164 l10n_ar.ri_percepcion_iibb_ne_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.420 account.data_account_type_current_liabilities Percepción IIBB Neuquén aplicada False
165 l10n_ar.ri_retencion_iibb_lp_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.430 account.data_account_type_current_liabilities Retención IIBB La Pampa aplicada False
166 l10n_ar.ri_percepcion_iibb_lp_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.440 account.data_account_type_current_liabilities Percepción IIBB La Pampa aplicada False
167 l10n_ar.ri_retencion_iibb_rn_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.450 account.data_account_type_current_liabilities Retención IIBB Río Negro aplicada False
168 l10n_ar.ri_percepcion_iibb_rn_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.460 account.data_account_type_current_liabilities Percepción IIBB Río Negro aplicada False
169 l10n_ar.ri_retencion_iibb_az_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.470 account.data_account_type_current_liabilities Retención IIBB Santa Cruz aplicada False
170 l10n_ar.ri_percepcion_iibb_az_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.480 account.data_account_type_current_liabilities Percepción IIBB Santa Cruz aplicada False
171 l10n_ar.ri_retencion_iibb_tf_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.490 account.data_account_type_current_liabilities Retención IIBB Tierra del Fuego aplicada False
172 l10n_ar.ri_percepcion_iibb_tf_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.02.500 account.data_account_type_current_liabilities Percepción IIBB Tierra del Fuego aplicada False
173 l10n_ar.ri_retencion_iibb_a_pagar l10n_ar.l10nar_ex_chart_template 2.1.3.02.510 account.data_account_type_payable Retención/Percepción IIBB a pagar True
174 l10n_ar.base_plan_de_iibb_a_pagar l10n_ar.l10nar_base_chart_template 2.1.3.02.520 account.data_account_type_payable Plan de IIBB a pagar True
175 l10n_ar.ri_iva_debito_fiscal l10n_ar.l10nar_ri_chart_template 2.1.3.03.010 account.data_account_type_current_liabilities IVA débito fiscal False
176 l10n_ar.ri_iva_saldo_a_pagar l10n_ar.l10nar_ri_chart_template 2.1.3.03.020 account.data_account_type_payable IVA saldo a pagar True
177 l10n_ar.ri_retencion_iva_aplicada l10n_ar.l10nar_ex_chart_template 2.1.3.03.030 account.data_account_type_current_liabilities Retención IVA aplicada False
257 l10n_ar.base_sellados_y_certificaciones l10n_ar.l10nar_base_chart_template 5.3.1.01.140 account.data_account_type_expenses Sellados y Certificaciones False
258 l10n_ar.base_tasa_municipal l10n_ar.l10nar_base_chart_template 5.4.1.01.010 account.data_account_type_expenses Tasa Municipal False
259 l10n_ar.base_impuestos_iibb_caba l10n_ar.l10nar_base_chart_template 5.4.2.01.010 account.data_account_type_expenses IIBB CABA False
260 l10n_ar.base_impuestos_iibb_ba l10n_ar.l10nar_base_chart_template 5.4.2.01.020 account.data_account_type_expenses IIBB Prov. Bs. As. IIBB ARBA False
261 l10n_ar.base_impuestos_iibb_co l10n_ar.base_impuestos_iibb_ca l10n_ar.l10nar_base_chart_template 5.4.2.01.030 account.data_account_type_expenses IIBB Prov. Córdoba IIBB Catamarca False
262 l10n_ar.base_impuestos_iibb_sf l10n_ar.base_impuestos_iibb_co l10n_ar.l10nar_base_chart_template 5.4.2.01.040 account.data_account_type_expenses IIBB Prov. Santa Fé IIBB Córdoba False
263 l10n_ar.base_impuestos_iibb_rr l10n_ar.l10nar_base_chart_template 5.4.2.01.050 account.data_account_type_expenses IIBB Corrientes False
264 l10n_ar.base_impuestos_iibb_er l10n_ar.l10nar_base_chart_template 5.4.2.01.060 account.data_account_type_expenses IIBB Entre Ríos False
265 l10n_ar.base_impuestos_iibb_ju l10n_ar.l10nar_base_chart_template 5.4.2.01.070 account.data_account_type_expenses IIBB Jujuy False
266 l10n_ar.base_impuestos_iibb_za l10n_ar.l10nar_base_chart_template 5.4.2.01.080 account.data_account_type_expenses IIBB Mendoza False
267 l10n_ar.base_impuestos_iibb_lr l10n_ar.l10nar_base_chart_template 5.4.2.01.090 account.data_account_type_expenses IIBB La Rioja False
268 l10n_ar.base_impuestos_iibb_sa l10n_ar.l10nar_base_chart_template 5.4.2.01.100 account.data_account_type_expenses IIBB Salta False
269 l10n_ar.base_impuestos_iibb_nn l10n_ar.l10nar_base_chart_template 5.4.2.01.110 account.data_account_type_expenses IIBB San Juan False
270 l10n_ar.base_impuestos_iibb_sl l10n_ar.l10nar_base_chart_template 5.4.2.01.120 account.data_account_type_expenses IIBB San Luis False
271 l10n_ar.base_impuestos_iibb_sf l10n_ar.l10nar_base_chart_template 5.4.2.01.130 account.data_account_type_expenses IIBB Santa Fe False
272 l10n_ar.base_impuestos_iibb_se l10n_ar.l10nar_base_chart_template 5.4.2.01.140 account.data_account_type_expenses IIBB Santiago del Estero False
273 l10n_ar.base_impuestos_iibb_tn l10n_ar.l10nar_base_chart_template 5.4.2.01.150 account.data_account_type_expenses IIBB Tucumán False
274 l10n_ar.base_impuestos_iibb_ha l10n_ar.l10nar_base_chart_template 5.4.2.01.160 account.data_account_type_expenses IIBB Chaco False
275 l10n_ar.base_impuestos_iibb_ct l10n_ar.l10nar_base_chart_template 5.4.2.01.170 account.data_account_type_expenses IIBB Chubut False
276 l10n_ar.base_impuestos_iibb_fo l10n_ar.l10nar_base_chart_template 5.4.2.01.180 account.data_account_type_expenses IIBB Formosa False
277 l10n_ar.base_impuestos_iibb_mi l10n_ar.l10nar_base_chart_template 5.4.2.01.190 account.data_account_type_expenses IIBB Misiones False
278 l10n_ar.base_impuestos_iibb_ne l10n_ar.l10nar_base_chart_template 5.4.2.01.200 account.data_account_type_expenses IIBB Neuquén False
279 l10n_ar.base_impuestos_iibb_lp l10n_ar.l10nar_base_chart_template 5.4.2.01.210 account.data_account_type_expenses IIBB La Pampa False
280 l10n_ar.base_impuestos_iibb_rn l10n_ar.l10nar_base_chart_template 5.4.2.01.220 account.data_account_type_expenses IIBB Río Negro False
281 l10n_ar.base_impuestos_iibb_az l10n_ar.l10nar_base_chart_template 5.4.2.01.230 account.data_account_type_expenses IIBB Santa Cruz False
282 l10n_ar.base_impuestos_iibb_tf l10n_ar.l10nar_base_chart_template 5.4.2.01.240 account.data_account_type_expenses IIBB Tierra del Fuego False
283 l10n_ar.base_impuestos_debitos_y_creditos l10n_ar.l10nar_base_chart_template 5.4.3.01.010 account.data_account_type_expenses Impuestos a los débitos y créditos bancarios False
284 l10n_ar.base_impuestos_a_las_ganancias l10n_ar.l10nar_ex_chart_template 5.5.1.01.010 account.data_account_type_expenses Impuestos a las ganancias False
285 l10n_ar.base_resultado_intereses_y_recargos l10n_ar.l10nar_base_chart_template 5.6.1.01.020 account.data_account_type_expenses Intereses por préstamos False
+121
View File
@@ -69,8 +69,129 @@
<field name="l10n_ar_tribute_afip_code">06</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_caba">
<field name="name">Perc IIBB CABA</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_ba">
<field name="name">Perc IIBB ARBA</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_ca">
<field name="name">Perc IIBB Catamarca</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_co">
<field name="name">Perc IIBB Córdoba</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_rr">
<field name="name">Perc IIBB Corrientes</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_er">
<field name="name">Perc IIBB Entre Ríos</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_ju">
<field name="name">Perc IIBB Jujuy</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_za">
<field name="name">Perc IIBB Mendoza</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_lr">
<field name="name">Perc IIBB La Rioja</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_sa">
<field name="name">Perc IIBB Salta</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_nn">
<field name="name">Perc IIBB San Juan</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_sl">
<field name="name">Perc IIBB San Luis</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_sf">
<field name="name">Perc IIBB Santa Fe</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_se">
<field name="name">Perc IIBB Santiago del Estero</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_tn">
<field name="name">Perc IIBB Tucumán</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_ha">
<field name="name">Perc IIBB Chaco</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_ct">
<field name="name">Perc IIBB Chubut</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_fo">
<field name="name">Perc IIBB Formosa</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_mi">
<field name="name">Perc IIBB Misiones</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_ne">
<field name="name">Perc IIBB Neuquén</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_lp">
<field name="name">Perc IIBB La Pampa</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_rn">
<field name="name">Perc IIBB Río Negro</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_az">
<field name="name">Perc IIBB Santa Cruz</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb_tf">
<field name="name">Perc IIBB Tierra del Fuego</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
<record model="account.tax.group" id="tax_group_percepcion_iibb">
<field name="name">IIBB Perceptions</field>
<field name="sequence">25</field>
<field name="l10n_ar_tribute_afip_code">07</field>
</record>
File diff suppressed because it is too large Load Diff
+7 -1
View File
@@ -88,7 +88,13 @@
<function model="account.tax" name="write" context="{'active_test': False}">
<value model="account.tax" eval="obj().search([('company_id', '=', ref('company_ri')), ('tax_group_id', 'in',
[ref('tax_group_percepcion_iva'), ref('tax_group_percepcion_ganancias'), ref('tax_group_percepcion_iibb'), ref('account.tax_group_taxes')]
[ref('tax_group_percepcion_iva'),
ref('tax_group_percepcion_ganancias'),
ref('tax_group_percepcion_iibb_caba'),
ref('tax_group_percepcion_iibb_ba'),
ref('tax_group_percepcion_iibb_co'),
ref('tax_group_percepcion_iibb_sf'),
ref('account.tax_group_taxes')]
)]).ids"/>
<value eval="{'amount': 0.1, 'active': True}"/>
</function>
-3
View File
@@ -159,9 +159,6 @@
<attribute name="t-esc">', '.join(map(lambda x: (x.description or x.name), line.l10n_latam_tax_ids.filtered(lambda x: x.tax_group_id.l10n_ar_vat_afip_code)))</attribute>
</span>
<!-- remove payment term, this is added on information section -->
<p name="payment_term" position="replace"/>
<!-- remove payment reference that is not used in Argentina -->
<xpath expr="//span[@t-field='o.payment_reference']/../.." position="replace"/>
+2 -2
View File
@@ -1,10 +1,10 @@
# Translation of Odoo Server.
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * l10n_be
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Project-Id-Version: Flectra Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-27 14:01+0000\n"
"PO-Revision-Date: 2020-01-27 14:01+0000\n"
+2 -2
View File
@@ -1,10 +1,10 @@
# Translation of Odoo Server.
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * l10n_be
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Project-Id-Version: Flectra Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-27 14:01+0000\n"
"PO-Revision-Date: 2020-01-27 14:01+0000\n"
+3 -3
View File
@@ -1,10 +1,10 @@
# Translation of Odoo Server.
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * l10n_be
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Project-Id-Version: Flectra Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-27 14:01+0000\n"
"PO-Revision-Date: 2020-01-27 14:01+0000\n"
@@ -4549,5 +4549,5 @@ msgstr ""
#: model:ir.model.fields,help:l10n_be.field_account_journal__invoice_reference_model
msgid ""
"You can choose different models for each type of reference. The default one "
"is the Odoo reference."
"is the Flectra reference."
msgstr ""
+2 -2
View File
@@ -1,10 +1,10 @@
# Translation of Odoo Server.
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * l10n_be
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Project-Id-Version: Flectra Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-01-27 14:01+0000\n"
"PO-Revision-Date: 2020-01-27 14:01+0000\n"
File diff suppressed because one or more lines are too long
+9 -1
View File
@@ -9,7 +9,7 @@ class TestUBL(AccountEdiTestCommon):
cls.partner_a.vat = 'BE0477472701'
def test_invoice_edi_xml(self):
def test_invoice_edi_xml_update(self):
invoice = self._create_empty_vendor_bill()
invoice_count = len(self.env['account.move'].search([]))
self.update_invoice_from_file('l10n_be_edi', 'test_xml_file', 'efff_test.xml', invoice)
@@ -18,3 +18,11 @@ class TestUBL(AccountEdiTestCommon):
self.assertEqual(invoice.amount_total, 666.50)
self.assertEqual(invoice.amount_tax, 115.67)
self.assertEqual(invoice.partner_id, self.partner_a)
def test_invoice_edi_xml_create(self):
invoice_count = len(self.env['account.move'].search([]))
invoice = self.create_invoice_from_file('l10n_be_edi', 'test_xml_file', 'efff_test.xml')
self.assertEqual(len(self.env['account.move'].search([])), invoice_count + 1)
self.assertEqual(invoice.amount_total, 666.50)
self.assertEqual(invoice.amount_tax, 115.67)
self.assertEqual(invoice.partner_id, self.partner_a)
+2 -2
View File
@@ -1,10 +1,10 @@
# Translation of Odoo Server.
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * l10n_ca
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 9.0\n"
"Project-Id-Version: Flectra Server 9.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-03 22:23+0000\n"
"PO-Revision-Date: 2015-11-03 17:52-0500\n"
+2 -2
View File
@@ -1,10 +1,10 @@
# Translation of Odoo Server.
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * l10n_ca
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.0c\n"
"Project-Id-Version: Flectra Server 10.0c\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-11-03 22:23+0000\n"
"PO-Revision-Date: 2015-11-03 22:23+0000\n"
+4 -4
View File
@@ -1,10 +1,10 @@
# Translation of Odoo Server.
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * l10n_ch
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0+e\n"
"Project-Id-Version: Flectra Server 2.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-11-27 07:17+0000\n"
"PO-Revision-Date: 2020-11-27 07:17+0000\n"
@@ -1789,10 +1789,10 @@ msgstr "Fahrzeuge"
#: model:ir.model.fields,help:l10n_ch.field_account_journal__invoice_reference_model
msgid ""
"You can choose different models for each type of reference. The default one "
"is the Odoo reference."
"is the Flectra reference."
msgstr ""
"Sie können für jede Art von Referenz verschiedene Modelle auswählen. Die "
"Standardeinstellung ist die Odoo-Referenz."
"Standardeinstellung ist die Flectra-Referenz."
#. module: l10n_ch
#: code:addons/l10n_ch/models/account_invoice.py:0
+3 -3
View File
@@ -1,10 +1,10 @@
# Translation of Odoo Server.
# Translation of Flectra Server.
# This file contains the translation of the following modules:
# * l10n_ch
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0+e\n"
"Project-Id-Version: Flectra Server 2.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-11-27 07:25+0000\n"
"PO-Revision-Date: 2020-11-27 07:25+0000\n"
@@ -1796,7 +1796,7 @@ msgstr "Vehicles"
#: model:ir.model.fields,help:l10n_ch.field_account_journal__invoice_reference_model
msgid ""
"You can choose different models for each type of reference. The default one "
"is the Odoo reference."
"is the Flectra reference."
msgstr ""
#. module: l10n_ch

Some files were not shown because too many files have changed in this diff Show More