[MERGE] forward port branch saas-12.5 up to 197474e5b9

This commit is contained in:
Christophe Simonis
2019-09-13 18:07:59 +02:00
5627 changed files with 1224516 additions and 791813 deletions
+269 -224
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -24,6 +24,7 @@ You could use this simplified accounting in case you work with an (external) acc
'data/digest_data.xml',
'views/account_menuitem.xml',
'views/account_payment_view.xml',
'wizard/account_accrual_accounting_view.xml',
'wizard/account_unreconcile_view.xml',
'wizard/account_move_reversal_view.xml',
'views/account_move_views.xml',
+96 -4
View File
@@ -11,7 +11,7 @@
<field name="context" eval="{'module': 'general_settings'}"/>
</record>
<!-- TAGS FOR CASH FLOW STATEMENT -->
<!-- TAGS FOR CASH FLOW STATEMENT DIRECT METHOD-->
<record id="account_tag_operating" model="account.account.tag">
<field name="name">Operating Activities</field>
@@ -26,6 +26,79 @@
<field name="applicability">accounts</field>
</record>
<!-- TAGS FOR CASH FLOW STATEMENT INDIRECT METHOD-->
<!-- CHANGE TAGS FOR ALL THIS RECORDS -->
<record id="account_tag_cf_im_005" model="account.account.tag">
<field name="name">CF-IM: Income Tax Expense</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_010" model="account.account.tag">
<field name="name">CF-IM: Finance Costs</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_015" model="account.account.tag">
<field name="name">CF-IM: Inventories</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_020" model="account.account.tag">
<field name="name">CF-IM: Trade Accounts Receivable</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_025" model="account.account.tag">
<field name="name">CF-IM: Other Operating Receivables</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_030" model="account.account.tag">
<field name="name">CF-IM: Trade Accounts Payable</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_035" model="account.account.tag">
<field name="name">CF-IM: Other Operating Payables</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_040" model="account.account.tag">
<field name="applicability">accounts</field>
<field name="name">CF-IM: Depreciation and Amortization Expense</field>
</record>
<record id="account_tag_cf_im_045" model="account.account.tag">
<field name="name">CF-IM: Impairment Recognized as Profit/Loss</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_050" model="account.account.tag">
<field name="name">CF-IM: Provisions</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_055" model="account.account.tag">
<field name="name">CF-IM: Unrealized Forex losses/gains</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_060" model="account.account.tag">
<field name="name">CF-IM: Shared-based Payments</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_065" model="account.account.tag">
<field name="name">CF-IM: Fair Value Adjustments</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_070" model="account.account.tag">
<field name="name">CF-IM: Undistributed Profits</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_075" model="account.account.tag">
<field name="name">CF-IM: Non-cash Items</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_080" model="account.account.tag">
<field name="name">CF-IM: Disposal of Non-current Assets</field>
<field name="applicability">accounts</field>
</record>
<record id="account_tag_cf_im_085" model="account.account.tag">
<field name="name">CF-IM: Cash Effects are investing or financial cash flow</field>
<field name="applicability">accounts</field>
</record>
<!--
Payment terms
-->
@@ -51,9 +124,15 @@
<field name="digits">6</field>
</record>
<record id="account_payment_term_net" model="account.payment.term">
<field name="name">30 Net Days</field>
<field name="note">Payment terms: 30 Net Days</field>
<record id="account_payment_term_21days" model="account.payment.term">
<field name="name">21 Days</field>
<field name="note">Payment terms: 21 Days</field>
<field name="line_ids" eval="[(5, 0), (0, 0, {'value': 'balance', 'value_amount': 0.0, 'sequence': 500, 'days': 21, 'option': 'day_after_invoice_date'})]"/>
</record>
<record id="account_payment_term_30days" model="account.payment.term">
<field name="name">30 Days</field>
<field name="note">Payment terms: 30 Days</field>
<field name="line_ids" eval="[(5, 0), (0, 0, {'value': 'balance', 'value_amount': 0.0, 'sequence': 500, 'days': 30, 'option': 'day_after_invoice_date'})]"/>
</record>
@@ -69,6 +148,19 @@
<field name="line_ids" eval="[(5, 0), (0, 0, {'value': 'balance', 'value_amount': 0.0, 'sequence': 500, 'days': 60, 'option': 'day_after_invoice_date'})]"/>
</record>
<record id="account_payment_term_end_following_month" model="account.payment.term">
<field name="name">End of Following Month</field>
<field name="note">Payment terms: End of Following Month</field>
<field name="line_ids" eval="[(5, 0), (0, 0, {'value': 'balance', 'value_amount': 0.0, 'sequence': 500, 'days': 31, 'option': 'day_following_month'})]"/>
</record>
<record id="account_payment_term_advance_60days" model="account.payment.term">
<field name="name">30% Now, Balance 60 Days</field>
<field name="note">Payment terms: 30% Now, Balance 60 Days</field>
<field name="line_ids" eval="[(5, 0), (0, 0, {'value': 'percent', 'value_amount': 30.0, 'sequence': 400, 'days': 0, 'option': 'day_after_invoice_date'}),
(0, 0, {'value': 'balance', 'value_amount': 0.0, 'sequence': 500, 'days': 60, 'option': 'day_after_invoice_date'})]"/>
</record>
<!--
Account Statement Sequences
-->
@@ -69,6 +69,7 @@
</record>
<record model="account.account.type" id="data_unaffected_earnings">
<field name="name">Current Year Earnings</field>
<field name="internal_group">equity</field>
<field name="include_initial_balance" eval="True"/>
</record>
<record model="account.account.type" id="data_account_type_other_income">
+5 -11
View File
@@ -21,12 +21,6 @@
</record>
<!-- Payment Terms -->
<record id="account_payment_term" model="account.payment.term">
<field name="name">End of Following Month</field>
<field name="note">Payment terms: End of Following Month</field>
<field name="line_ids" eval="[(5, 0), (0, 0, {'value': 'balance', 'value_amount': 0.0, 'sequence': 500, 'days': 31, 'option': 'day_following_month'})]"/>
</record>
<record id="account_payment_term_advance" model="account.payment.term">
<field name="name">30% Advance End of Following Month</field>
<field name="note">Payment terms: 30% Advance End of Following Month</field>
@@ -40,17 +34,17 @@
<!-- Add Payment terms on some demo partners -->
<record id="base.res_partner_2" model="res.partner">
<field name="property_payment_term_id" ref="account.account_payment_term_net"/>
<field name="property_payment_term_id" ref="account.account_payment_term_30days"/>
</record>
<record id="base.res_partner_12" model="res.partner">
<field name="property_payment_term_id" ref="account_payment_term"/>
<field name="property_supplier_payment_term_id" ref="account_payment_term"/>
<field name="property_payment_term_id" ref="account.account_payment_term_end_following_month"/>
<field name="property_supplier_payment_term_id" ref="account.account_payment_term_end_following_month"/>
</record>
<record id="base.res_partner_4" model="res.partner">
<field name="property_supplier_payment_term_id" ref="account.account_payment_term_net"/>
<field name="property_supplier_payment_term_id" ref="account.account_payment_term_30days"/>
</record>
<record id="base.res_partner_1" model="res.partner">
<field name="property_supplier_payment_term_id" ref="account_payment_term"/>
<field name="property_supplier_payment_term_id" ref="account.account_payment_term_end_following_month"/>
</record>
</data>
</odoo>
File diff suppressed because it is too large Load Diff
+3810 -3638
View File
File diff suppressed because it is too large Load Diff
+3419 -3539
View File
File diff suppressed because it is too large Load Diff
+2969 -2841
View File
File diff suppressed because it is too large Load Diff
+2971 -2850
View File
File diff suppressed because it is too large Load Diff
+2812 -2791
View File
File diff suppressed because it is too large Load Diff
+2738 -2634
View File
File diff suppressed because it is too large Load Diff
+2667 -2606
View File
File diff suppressed because it is too large Load Diff
+3395 -3393
View File
File diff suppressed because it is too large Load Diff
+6898 -6075
View File
File diff suppressed because it is too large Load Diff
+3241 -3280
View File
File diff suppressed because it is too large Load Diff
+2580 -2464
View File
File diff suppressed because it is too large Load Diff
+2936 -2973
View File
File diff suppressed because it is too large Load Diff
+2620 -2567
View File
File diff suppressed because it is too large Load Diff
+2634 -2642
View File
File diff suppressed because it is too large Load Diff
+2602 -2571
View File
File diff suppressed because it is too large Load Diff
+2752 -2658
View File
File diff suppressed because it is too large Load Diff
+3370 -3049
View File
File diff suppressed because it is too large Load Diff
+3476 -3255
View File
File diff suppressed because it is too large Load Diff
+3109 -3051
View File
File diff suppressed because it is too large Load Diff
+3260 -3213
View File
File diff suppressed because it is too large Load Diff
+87 -35
View File
@@ -8,7 +8,7 @@ from odoo.osv import expression
from odoo.tools.float_utils import float_round as round, float_compare
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.exceptions import UserError, ValidationError
from odoo import api, fields, models, _
from odoo import api, fields, models, _, tools
from odoo.tests.common import Form
TYPE_TAX_USE = [
@@ -41,7 +41,8 @@ class AccountAccountType(models.Model):
('expense', 'Expense'),
('off_balance', 'Off Balance'),
], string="Internal Group",
help="The 'Internal Group' is used to filter accounts based on the internal group set on the account type.")
required=True,
help="The 'Internal Group' is used to filter accounts based on the internal group set on the account type.")
note = fields.Text(string='Description')
@@ -54,7 +55,7 @@ class AccountAccountTag(models.Model):
color = fields.Integer('Color Index')
active = fields.Boolean(default=True, help="Set active to false to hide the Account Tag without removing it.")
tax_report_line_ids = fields.Many2many(string="Tax Report Lines", comodel_name='account.tax.report.line', relation='account_tax_report_line_tags_rel', help="The tax report lines using this tag")
tax_negate = fields.Boolean(string="Negate Tax Balance", help="Check this boox to negate the absolute value of the balance of the lines associated with this tag in tax report computation.")
tax_negate = fields.Boolean(string="Negate Tax Balance", help="Check this box to negate the absolute value of the balance of the lines associated with this tag in tax report computation.")
country_id = fields.Many2one(string="Country", comodel_name='res.country', help="Country for which this tag is available, when applied on taxes.")
@@ -70,7 +71,8 @@ class AccountTaxReportLine(models.Model):
report_action_id = fields.Many2one(string="Report Action", comodel_name='ir.actions.act_window', help="The optional action to call when clicking on this line in accounting reports.")
children_line_ids = fields.One2many(string="Children Lines", comodel_name='account.tax.report.line', inverse_name='parent_id', help="Lines that should be rendered as children of this one")
parent_id = fields.Many2one(string="Parent Line", comodel_name='account.tax.report.line')
sequence = fields.Integer(string='Sequence', required=True, help="Sequence determining the order of the lines in the report (smaller ones come first). This order is applied locally per section (so, chilldren of the same line are always rendered one after the other).")
sequence = fields.Integer(string='Sequence', required=True,
help="Sequence determining the order of the lines in the report (smaller ones come first). This order is applied locally per section (so, children of the same line are always rendered one after the other).")
parent_path = fields.Char(index=True)
#helper to create tags (positive and negative) on report line creation
@@ -224,6 +226,7 @@ class AccountAccount(models.Model):
default=lambda self: self.env.company)
tag_ids = fields.Many2many('account.account.tag', 'account_account_account_tag', string='Tags', help="Optional tags you may want to assign for custom reporting")
group_id = fields.Many2one('account.group')
root_id = fields.Many2one('account.root', compute='_compute_account_root', store=True)
opening_debit = fields.Monetary(string="Opening debit", compute='_compute_opening_debit_credit', inverse='_set_opening_debit', help="Opening debit value for this account.")
opening_credit = fields.Monetary(string="Opening credit", compute='_compute_opening_debit_credit', inverse='_set_opening_credit', help="Opening credit value for this account.")
@@ -241,6 +244,14 @@ class AccountAccount(models.Model):
if record.tax_ids:
raise UserError(_('An Off-Balance account can not have taxes'))
@api.depends('code')
def _compute_account_root(self):
# this computes the first 2 digits of the account.
# This field should have been a char, but the aim is to use it in a side panel view with hierarchy, and it's only supported by many2one fields so far.
# So instead, we make it a many2one to a psql view with what we need as records.
for record in self:
record.root_id = record.code and (ord(record.code[0]) * 1000 + ord(record.code[1])) or False
@api.model
def _search_new_account_code(self, company, digits, prefix):
for num in range(1, 10000):
@@ -542,13 +553,38 @@ class AccountGroup(models.Model):
return self.browse(group_ids).name_get()
class AccountRoot(models.Model):
_name = 'account.root'
_description = 'Account codes first 2 digits'
_auto = False
name = fields.Char()
parent_id = fields.Many2one('account.root')
def init(self):
tools.drop_view_if_exists(self.env.cr, self._table)
self.env.cr.execute('''
CREATE OR REPLACE VIEW %s AS (
SELECT DISTINCT ASCII(code) * 1000 + ASCII(SUBSTRING(code,2,1)) AS id,
LEFT(code,2) AS name,
ASCII(code) AS parent_id
FROM account_account WHERE code IS NOT NULL
UNION ALL
SELECT DISTINCT ASCII(code) AS id,
LEFT(code,1) AS name,
NULL::int AS parent_id
FROM account_account WHERE code IS NOT NULL
)''' % (self._table,)
)
class AccountJournalGroup(models.Model):
_name = 'account.journal.group'
_description = "Account Journal Group"
name = fields.Char("Group Name", required=True, translate=True)
name = fields.Char("Journal Group", required=True, translate=True)
company_id = fields.Many2one('res.company', required=True, default=lambda self: self.env.company)
account_journal_ids = fields.Many2many('account.journal', string="Journals", domain="[('company_id', '=', company_id)]")
excluded_journal_ids = fields.Many2many('account.journal', string="Excluded Journals", domain="[('company_id', '=', company_id)]")
sequence = fields.Integer(default=10)
@@ -608,7 +644,7 @@ class AccountJournal(models.Model):
compute='_compute_refund_seq_number_next',
inverse='_inverse_refund_seq_number_next')
invoice_reference_type = fields.Selection(string='Communication Type', required=True, selection=[('none', 'Free'), ('partner', 'Based on Partner'), ('invoice', 'Based on Invoice')], default='invoice', help='You can set here the default communication that will appear on customer invoices, once validated, to help the customer to refer to that particular invoice when making the payment.')
invoice_reference_type = fields.Selection(string='Communication Type', required=True, selection=[('none', 'Free'), ('partner', 'Based on Customer'), ('invoice', 'Based on Invoice')], default='invoice', help='You can set here the default communication that will appear on customer invoices, once validated, to help the customer to refer to that particular invoice when making the payment.')
invoice_reference_model = fields.Selection(string='Communication Standard', required=True, selection=[('odoo', 'Odoo'),('euro', 'European')], default='odoo', help="You can choose different models for each type of reference. The default one is the Odoo reference.")
#groups_id = fields.Many2many('res.groups', 'account_journal_group_rel', 'journal_id', 'group_id', string='Groups')
@@ -639,7 +675,7 @@ class AccountJournal(models.Model):
bank_statements_source = fields.Selection(selection=_get_bank_statements_available_sources, string='Bank Feeds', default='undefined', help="Defines how the bank statements will be registered")
bank_acc_number = fields.Char(related='bank_account_id.acc_number', readonly=False)
bank_id = fields.Many2one('res.bank', related='bank_account_id.bank_id', readonly=False)
post_at_bank_rec = fields.Boolean(string="Post At Bank Reconciliation", help="Whether or not the payments made in this journal should be generated in draft state, so that the related journal entries are only posted when performing bank reconciliation.")
post_at = fields.Selection([('pay_val', 'Payment Validation'), ('bank_rec', 'Bank Reconciliation')], string="Post At", default='pay_val')
# alias configuration for journals
alias_id = fields.Many2one('mail.alias', string='Alias', copy=False)
@@ -830,8 +866,8 @@ class AccountJournal(models.Model):
'refund_sequence_number_next': vals.get('refund_sequence_number_next', journal.refund_sequence_number_next),
}
journal.refund_sequence_id = self.sudo()._create_sequence(journal_vals, refund=True).id
# Changing the 'post_at_bank_rec' option will post the draft payment moves and change the related invoices' state.
if 'post_at_bank_rec' in vals and not vals['post_at_bank_rec']:
# Changing the 'post_at' option will post the draft payment moves and change the related invoices' state.
if 'post_at' in vals and vals['post_at'] != 'bank_rec':
draft_moves = self.env['account.move'].search([('journal_id', 'in', self.ids), ('state', '=', 'draft')])
pending_payments = draft_moves.mapped('line_ids.payment_id')
pending_payments.mapped('move_line_ids.move_id').post()
@@ -1009,7 +1045,7 @@ class AccountJournal(models.Model):
invoices = self.env['account.move']
for attachment in attachments:
invoice = self.env['account.move'].create({})
attachment.write({'res_model': 'account.move', 'res_id': invoice.id})
attachment.write({'res_model': 'mail.compose.message'})
invoice.message_post(attachment_ids=[attachment.id])
invoices += invoice
@@ -1019,6 +1055,7 @@ class AccountJournal(models.Model):
'res_model': 'account.move',
'views': [[False, "tree"], [False, "form"]],
'type': 'ir.actions.act_window',
'context': self._context
}
if len(invoices) == 1:
action_vals.update({'res_id': invoices[0].id, 'view_mode': 'form'})
@@ -1405,20 +1442,27 @@ class AccountTax(models.Model):
cached_tax_amounts = {}
if handle_price_include:
for tax in reversed(taxes):
tax_repartition_lines = (
is_refund
and tax.refund_repartition_line_ids
or tax.invoice_repartition_line_ids
).filtered(lambda x: x.repartition_type == "tax")
sum_repartition_factor = sum(tax_repartition_lines.mapped("factor"))
if tax.include_base_amount:
base = recompute_base(base, incl_fixed_amount, incl_percent_amount, incl_division_amount)
incl_fixed_amount = incl_percent_amount = incl_division_amount = 0
store_included_tax_total = True
if tax.price_include or self._context.get('force_price_include'):
if tax.amount_type == 'percent':
incl_percent_amount += tax.amount
incl_percent_amount += tax.amount * sum_repartition_factor
elif tax.amount_type == 'division':
incl_division_amount += tax.amount
incl_division_amount += tax.amount * sum_repartition_factor
elif tax.amount_type == 'fixed':
incl_fixed_amount += quantity * tax.amount
incl_fixed_amount += quantity * tax.amount * sum_repartition_factor
else:
# tax.amount_type == other (python)
tax_amount = tax._compute_amount(base, price_unit, quantity, product, partner)
tax_amount = tax._compute_amount(base, price_unit, quantity, product, partner) * sum_repartition_factor
incl_fixed_amount += tax_amount
# Avoid unecessary re-computation
cached_tax_amounts[i] = tax_amount
@@ -1437,6 +1481,9 @@ class AccountTax(models.Model):
i = 0
cumulated_tax_included_amount = 0
for tax in taxes:
tax_repartition_lines = (is_refund and tax.refund_repartition_line_ids or tax.invoice_repartition_line_ids).filtered(lambda x: x.repartition_type == 'tax')
sum_repartition_factor = sum(tax_repartition_lines.mapped('factor'))
#compute the tax_amount
if (self._context.get('force_price_include') or tax.price_include) and total_included_checkpoints.get(i):
# We know the total to reach for that tax, so we make a substraction to avoid any rounding issues
@@ -1444,13 +1491,14 @@ class AccountTax(models.Model):
cumulated_tax_included_amount = 0
else:
tax_amount = tax.with_context(force_price_include=False)._compute_amount(
base, price_unit, quantity, product, partner)
base, sign * price_unit, quantity, product, partner)
# Round the tax_amount
# Round the tax_amount multiplied by the computed repartition lines factor.
tax_amount = round(tax_amount, prec)
factorized_tax_amount = round(tax_amount * sum_repartition_factor, prec)
if tax.price_include and not total_included_checkpoints.get(i):
cumulated_tax_included_amount += tax_amount
cumulated_tax_included_amount += factorized_tax_amount
# If the tax affects the base of subsequent taxes, its tax move lines must
# receive the base tags and tag_ids of these taxes, so that the tax report computes
@@ -1461,18 +1509,24 @@ class AccountTax(models.Model):
subsequent_taxes = taxes[i+1:]
subsequent_tags = subsequent_taxes.get_tax_tags(is_refund, 'base')
# Compute the tax lines
tax_repartition_lines = (is_refund and tax.refund_repartition_line_ids or tax.invoice_repartition_line_ids).filtered(lambda x: x.repartition_type == 'tax')
sum_factor = sum(tax_repartition_lines.mapped('factor'))
repartition_lines_to_treat = len(tax_repartition_lines)
total_amount = 0
for repartition_line in tax_repartition_lines:
if repartition_lines_to_treat != 1 or sum_factor != 1.0:
line_amount = round(tax_amount * repartition_line.factor, prec)
else:
# When the sum of the repartition lines factor is 100%, we need to ensure the whole tax amount has
# been spread into the repartition lines.
line_amount = round(tax_amount - total_amount, prec)
# Compute the tax line amounts by multiplying each factor with the tax amount.
# Then, spread the tax rounding to ensure the consistency of each line independently with the factorized
# amount. E.g:
#
# Suppose a tax having 4 x 50% repartition line applied on a tax amount of 0.03 with 2 decimal places.
# The factorized_tax_amount will be 0.06 (200% x 0.03). However, each line taken independently will compute
# 50% * 0.03 = 0.01 with rounding. It means there is 0.06 - 0.04 = 0.02 as total_rounding_error to dispatch
# in lines as 2 x 0.01.
repartition_line_amounts = [round(tax_amount * line.factor, prec) for line in tax_repartition_lines]
total_rounding_error = round(factorized_tax_amount - sum(repartition_line_amounts), prec)
nber_rounding_steps = int(abs(total_rounding_error / currency.rounding))
rounding_error = round(nber_rounding_steps and total_rounding_error / nber_rounding_steps or 0.0, prec)
for repartition_line, line_amount in zip(tax_repartition_lines, repartition_line_amounts):
if nber_rounding_steps:
line_amount += rounding_error
nber_rounding_steps -= 1
taxes_vals.append({
'id': tax.id,
@@ -1489,16 +1543,14 @@ class AccountTax(models.Model):
'tax_ids': subsequent_taxes.ids,
})
total_amount += line_amount
if not repartition_line.account_id:
total_void += line_amount
repartition_lines_to_treat -= 1
# Affect subsequent taxes
if tax.include_base_amount:
base += tax_amount
base += factorized_tax_amount
total_included += tax_amount
total_included += factorized_tax_amount
i += 1
return {
@@ -1538,7 +1590,7 @@ class AccountTaxRepartitionLine(models.Model):
factor = fields.Float(string="Factor Ratio", compute="_compute_factor", help="Factor to apply on the account move lines generated from this repartition line")
repartition_type = fields.Selection(string="Based On", selection=[('base', 'Base'), ('tax', 'of tax')], required=True, default='tax', help="Base on which the factor will be applied.")
account_id = fields.Many2one(string="Account", comodel_name='account.account', help="Account on which to post the tax amount")
tag_ids = fields.Many2many(string="Tax Grid", comodel_name='account.account.tag', domain=[('applicability', '=', 'taxes')], copy=True)
tag_ids = fields.Many2many(string="Tax Grids", comodel_name='account.account.tag', domain=[('applicability', '=', 'taxes')], copy=True)
invoice_tax_id = fields.Many2one(comodel_name='account.tax', help="The tax set to apply this repartition on invoices. Mutually exclusive with refund_tax_id")
refund_tax_id = fields.Many2one(comodel_name='account.tax', help="The tax set to apply this repartition on refund invoices. Mutually exclusive with invoice_tax_id")
tax_id = fields.Many2one(comodel_name='account.tax', compute='_compute_tax_id')
@@ -722,7 +722,7 @@ class AccountBankStatementLine(models.Model):
total -= aml_currency._convert(balance, currency, aml_rec.company_id, aml_rec.date)
aml_rec.with_context(check_move_validity=False).write({'statement_line_id': self.id})
counterpart_moves = (counterpart_moves | aml_rec.move_id)
if aml_rec.journal_id.post_at_bank_rec and aml_rec.payment_id and aml_rec.move_id.state == 'draft':
if aml_rec.journal_id.post_at == 'bank_rec' and aml_rec.payment_id and aml_rec.move_id.state == 'draft':
# In case the journal is set to only post payments when performing bank
# reconciliation, we modify its date and post it.
aml_rec.move_id.date = self.date
@@ -843,3 +843,6 @@ class AccountBankStatementLine(models.Model):
def _check_invoice_state(self, invoice):
invoice._compute_amount()
def button_confirm_bank(self):
self.statement_id.button_confirm_bank()
@@ -40,6 +40,7 @@ class account_journal(models.Model):
act_type.name as act_type_name,
act_type.category as activity_category,
act.date_deadline,
m.date,
CASE WHEN act.date_deadline < CURRENT_DATE THEN 'late' ELSE 'future' END as status
FROM account_move m
LEFT JOIN mail_activity act ON act.res_id = m.id
@@ -54,7 +55,7 @@ class account_journal(models.Model):
'res_id': activity.get('res_id'),
'res_model': activity.get('res_model'),
'status': activity.get('status'),
'name': activity.get('summary') or activity.get('act_type_name'),
'name': (activity.get('summary') or activity.get('act_type_name')) + '(' + format_date(activity.get('date'), 'MMM', locale=self._context.get('lang') or 'en_US') + ')',
'activity_category': activity.get('activity_category'),
'date': odoo_format_date(self.env, activity.get('date_deadline'))
})
@@ -276,10 +277,10 @@ class account_journal(models.Model):
(number_waiting, sum_waiting) = self._count_results_and_sum_amounts(query_results_to_pay, currency, curr_cache=curr_cache)
(number_draft, sum_draft) = self._count_results_and_sum_amounts(query_results_drafts, currency, curr_cache=curr_cache)
(number_late, sum_late) = self._count_results_and_sum_amounts(late_query_results, currency, curr_cache=curr_cache)
read = self.env['account.move'].read_group([('journal_id', '=', self.id), ('to_check', '=', True)], ['amount'], 'journal_id', lazy=False)
read = self.env['account.move'].read_group([('journal_id', '=', self.id), ('to_check', '=', True)], ['amount_total'], 'journal_id', lazy=False)
if read:
number_to_check = read[0]['__count']
to_check_balance = read[0]['amount']
to_check_balance = read[0]['amount_total']
difference = currency.round(last_balance-account_sum) + 0.0
+227 -141
View File
@@ -14,6 +14,7 @@ from itertools import zip_longest
import json
import re
import logging
import psycopg2
_logger = logging.getLogger(__name__)
@@ -82,7 +83,7 @@ class AccountMove(models.Model):
ref = fields.Char(string='Reference', copy=False)
narration = fields.Text(string='Internal Note')
state = fields.Selection(selection=[
('draft', 'Unposted'),
('draft', 'Draft'),
('posted', 'Posted'),
('cancel', 'Cancelled')
], string='Status', required=True, readonly=True, copy=False, tracking=True,
@@ -103,6 +104,7 @@ class AccountMove(models.Model):
states={'draft': [('readonly', False)]},
domain="[('company_id', '=', company_id)]",
default=_get_default_journal)
user_id = fields.Many2one(related='invoice_user_id', string='User')
company_id = fields.Many2one(string='Company', store=True, readonly=True,
related='journal_id.company_id')
company_currency_id = fields.Many2one(string='Company Currency', readonly=True,
@@ -116,7 +118,7 @@ class AccountMove(models.Model):
partner_id = fields.Many2one('res.partner', readonly=True, tracking=True,
states={'draft': [('readonly', False)]},
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",
string='Customer/Vendor')
string='Partner')
commercial_partner_id = fields.Many2one('res.partner', string='Commercial Entity', store=True, readonly=True,
compute='_compute_commercial_partner_id')
@@ -170,22 +172,18 @@ class AccountMove(models.Model):
states={'draft': [('readonly', False)]},
string='Salesperson',
default=lambda self: self.env.user)
user_id = fields.Many2one(string='User', related='invoice_user_id',
help='Technical field used to fit the generic behavior in mail templates.')
invoice_payment_state = fields.Selection(selection=[
('not_paid', 'Not Paid'),
('in_payment', 'In Payment'),
('paid', 'Paid')],
string='Payment Status', store=True, readonly=True, copy=False, tracking=True,
string='Payment', store=True, readonly=True, copy=False, tracking=True,
compute='_compute_amount')
invoice_date = fields.Date(string='Invoice/Bill Date', readonly=True, index=True, copy=False,
states={'draft': [('readonly', False)]},
help="Keep empty to use the current date")
states={'draft': [('readonly', False)]})
invoice_date_due = fields.Date(string='Due Date', readonly=True, index=True, copy=False,
states={'draft': [('readonly', False)]},
help="If you use payment terms, the due date will be computed automatically at the generation "
"of accounting entries. The Payment terms may compute several due dates, for example 50% "
"now and 50% in one month, but if you want to force a due date, make sure that the payment "
"term is not set on the invoice. If you keep the Payment terms and the due date empty, it "
"means direct payment.")
states={'draft': [('readonly', False)]})
invoice_payment_ref = fields.Char(string='Payment Reference', index=True, copy=False, readonly=True,
states={'draft': [('readonly', False)]},
help="The payment reference to set on journal items.")
@@ -194,11 +192,8 @@ class AccountMove(models.Model):
invoice_origin = fields.Char(string='Origin', readonly=True, tracking=True,
help="The document(s) that generated the invoice.")
invoice_payment_term_id = fields.Many2one('account.payment.term', string='Payment Terms',
readonly=True, states={'draft': [('readonly', False)]},
domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]",
help="If you use payment terms, the due date will be computed automatically at the generation "
"of accounting entries. If you keep the payment terms and the due date empty, it means direct payment. "
"The payment terms may compute several due dates, for example 50% now, 50% in one month.")
readonly=True, states={'draft': [('readonly', False)]})
# /!\ invoice_line_ids is just a subset of line_ids.
invoice_line_ids = fields.One2many('account.move.line', 'move_id', string='Invoice lines',
copy=False, readonly=True,
@@ -433,25 +428,50 @@ class AccountMove(models.Model):
:param base_line: The account.move.line owning the taxes.
:return: The result of the compute_all method.
'''
move = base_line.move_id
if move.is_invoice():
sign = -1 if move.is_inbound() else 1
quantity = base_line.quantity
if base_line.currency_id:
price_unit_foreign_curr = sign * base_line.price_unit * (1 - (base_line.discount / 100.0))
price_unit_comp_curr = base_line.currency_id._convert(price_unit_foreign_curr, move.company_id.currency_id, move.company_id, move.date)
else:
price_unit_foreign_curr = 0.0
price_unit_comp_curr = sign * base_line.price_unit * (1 - (base_line.discount / 100.0))
else:
quantity = 1.0
price_unit_foreign_curr = base_line.amount_currency
price_unit_comp_curr = base_line.balance
balance_taxes_res = base_line.tax_ids._origin.compute_all(
base_line.balance,
price_unit_comp_curr,
currency=base_line.company_currency_id,
quantity=quantity,
product=base_line.product_id,
partner=base_line.partner_id,
is_refund=self.type in ('out_refund', 'in_refund'),
handle_price_include=False,
)
if base_line.currency_id:
# Multi-currencies mode: Taxes are computed both in company's currency / foreign currency.
amount_currency_taxes_res = base_line.tax_ids._origin.compute_all(
base_line.amount_currency,
price_unit_foreign_curr,
currency=base_line.currency_id,
quantity=quantity,
product=base_line.product_id,
partner=base_line.partner_id,
is_refund=self.type in ('out_refund', 'in_refund'),
handle_price_include=False,
)
for b_tax_res, ac_tax_res in zip(balance_taxes_res['taxes'], amount_currency_taxes_res['taxes']):
tax = self.env['account.tax'].browse(b_tax_res['id'])
b_tax_res['amount_currency'] = ac_tax_res['amount']
# A tax having a fixed amount must be converted into the company currency when dealing with a
# foreign currency.
if tax.amount_type == 'fixed':
b_tax_res['amount'] = base_line.currency_id._convert(b_tax_res['amount'], move.company_id.currency_id, move.company_id, move.date)
return balance_taxes_res
taxes_map = {}
@@ -889,7 +909,7 @@ class AccountMove(models.Model):
JOIN account_payment payment ON payment.id = rec_line.payment_id
JOIN account_journal journal ON journal.id = rec_line.journal_id
WHERE payment.state IN ('posted', 'sent')
AND journal.post_at_bank_rec IS TRUE
AND journal.post_at = 'bank_rec'
AND move.id IN %s
''', [tuple(invoice_ids)]
)
@@ -904,35 +924,43 @@ class AccountMove(models.Model):
total_tax_currency = 0.0
total_residual = 0.0
total_residual_currency = 0.0
total = 0.0
total_currency = 0.0
currencies = set()
for line in move.line_ids:
if line.currency_id:
currencies.add(line.currency_id)
# Untaxed amount.
if (move.is_invoice(include_receipts=True) and not line.exclude_from_invoice_tab)\
or (move.type == 'entry' and line.debit and not line.tax_line_id):
total_untaxed += line.balance
total_untaxed_currency += line.amount_currency
if move.is_invoice(include_receipts=True):
# === Invoices ===
# Tax amount.
if line.tax_line_id:
total_tax += line.balance
total_tax_currency += line.amount_currency
if not line.exclude_from_invoice_tab:
# Untaxed amount.
total_untaxed += line.balance
total_untaxed_currency += line.amount_currency
total += line.balance
total_currency += line.amount_currency
elif line.tax_line_id:
# Tax amount.
total_tax += line.balance
total_tax_currency += line.amount_currency
total += line.balance
total_currency += line.amount_currency
elif line.account_id.user_type_id.type in ('receivable', 'payable'):
# Residual amount.
total_residual += line.amount_residual
total_residual_currency += line.amount_residual_currency
else:
# === Miscellaneous journal entry ===
if line.debit:
total += line.balance
total_currency += line.amount_currency
# Residual amount.
if move.type == 'entry' or line.account_id.user_type_id.type in ('receivable', 'payable'):
total_residual += line.amount_residual
total_residual_currency += line.amount_residual_currency
total = total_untaxed + total_tax
total_currency = total_untaxed_currency + total_tax_currency
if (move.type == 'entry' and total < 0.0) or move.is_inbound():
sign = -1
else:
if move.type == 'entry' or move.is_outbound():
sign = 1
else:
sign = -1
move.amount_untaxed = sign * (total_untaxed_currency if len(currencies) == 1 else total_untaxed)
move.amount_tax = sign * (total_tax_currency if len(currencies) == 1 else total_tax)
move.amount_total = sign * (total_currency if len(currencies) == 1 else total)
@@ -969,11 +997,12 @@ class AccountMove(models.Model):
amount_currency = 0.0
for line in move.line_ids:
to_write.append((1, line.id, {
'debit': line.balance > 0.0 and balance or 0.0,
'credit': line.balance < 0.0 and balance or 0.0,
'amount_currency': line.balance > 0.0 and amount_currency or -amount_currency,
}))
if abs(line.balance) != balance:
to_write.append((1, line.id, {
'debit': line.balance > 0.0 and balance or 0.0,
'credit': line.balance < 0.0 and balance or 0.0,
'amount_currency': line.balance > 0.0 and amount_currency or -amount_currency,
}))
move.write({'line_ids': to_write})
@@ -1120,7 +1149,7 @@ class AccountMove(models.Model):
'id': line.id,
'position': currency_id.position,
'digits': [69, move.currency_id.decimal_places],
'payment_date': fields.Date.to_string(line.date),
'payment_date': fields.Date.to_string(line.date),
})
info['title'] = type_payment
move.invoice_outstanding_credits_debits_widget = json.dumps(info)
@@ -1159,6 +1188,7 @@ class AccountMove(models.Model):
'date': counterpart_line.date,
'payment_id': counterpart_line.id,
'account_payment_id': counterpart_line.payment_id.id,
'payment_method_name': counterpart_line.payment_id.payment_method_id.name if counterpart_line.journal_id.type == 'bank' else None,
'move_id': counterpart_line.move_id.id,
'ref': ref,
})
@@ -1214,27 +1244,25 @@ class AccountMove(models.Model):
if 'posted' in self.mapped('line_ids.payment_id.state'):
raise ValidationError(_("You cannot modify a journal entry linked to a posted payment."))
@api.constrains('name', 'journal_id')
@api.constrains('name', 'journal_id', 'state')
def _check_unique_sequence_number(self):
if not self:
moves = self.filtered(lambda move: move.state == 'posted')
if not moves:
return
self.flush()
# /!\ Computed stored fields are not yet inside the database.
self._cr.execute('''
WITH current_moves (id, name, state, company_id, journal_id, type) as ( values {} )
SELECT move2.id
FROM ( SELECT id, name, state, company_id, journal_id, type from account_move
UNION ALL SELECT id, name, state, company_id, journal_id, type from current_moves
) move
FROM account_move move
INNER JOIN account_move move2 ON
move2.name = move.name
AND move2.company_id = move.company_id
AND move2.journal_id = move.journal_id
AND move2.type = move.type
AND move2.id != move.id
WHERE move.id IN %s
AND move.state = 'posted'
AND move2.state = 'posted'
'''.format(", ".join(["(%s, %s, %s, %s, %s, %s)"] * len(self))), list(chain(*self.mapped(lambda r: [r.id, r.name, r.state, r.company_id.id, r.journal_id.id, r.type]))) + [tuple(self.ids)])
WHERE move.id IN %s AND move2.state = 'posted'
''', [tuple(moves.ids)])
res = self._cr.fetchone()
if res:
raise ValidationError(_('Posted journal entry must have an unique sequence number per company.'))
@@ -1245,23 +1273,28 @@ class AccountMove(models.Model):
if not moves:
return
self.env["account.move"].flush([
"ref", "type", "invoice_date", "journal_id",
"company_id", "partner_id", "commercial_partner_id",
])
self.env["account.journal"].flush(["company_id"])
self.env["res.partner"].flush(["commercial_partner_id"])
# /!\ Computed stored fields are not yet inside the database.
self._cr.execute('''
WITH current_moves (id, ref, company_id, commercial_partner_id, type, invoice_date) as ( values {} )
SELECT move2.id
FROM ( SELECT id, ref, company_id, commercial_partner_id, type, invoice_date from account_move
UNION ALL SELECT id, ref, company_id, commercial_partner_id, type, invoice_date from current_moves
) move
FROM account_move move
JOIN account_journal journal ON journal.id = move.journal_id
JOIN res_partner partner ON partner.id = move.partner_id
INNER JOIN account_move move2 ON
move2.ref = move.ref
AND move2.company_id = move.company_id
AND move2.commercial_partner_id = move.commercial_partner_id
AND move2.company_id = journal.company_id
AND move2.commercial_partner_id = partner.commercial_partner_id
AND move2.type = move.type
AND (move2.invoice_date = move.invoice_date OR move.invoice_date is NULL)
AND (move.invoice_date is NULL OR move2.invoice_date = move.invoice_date)
AND move2.id != move.id
WHERE move.id IN %s
AND move.type in ('in_invoice', 'in_refund')
AND move.ref IS NOT NULL
'''.format(", ".join(["(%s, %s, %s, %s, %s, CAST(%s as DATE))"] * len(self))), list(chain(*self.mapped(lambda r: [r.id, r.ref, r.company_id.id, r.commercial_partner_id.id, r.type, r.invoice_date or None]))) + [tuple(moves.ids)])
''', [tuple(moves.ids)])
if self._cr.fetchone():
raise ValidationError(_('Duplicated vendor reference detected. You probably encoded twice the same vendor bill/credit note.'))
@@ -1309,24 +1342,22 @@ class AccountMove(models.Model):
return True
def _check_tax_lock_date(self):
if not self:
return
self._cr.execute('''
SELECT move.id, company.tax_lock_date
FROM account_move move
JOIN account_journal journal ON journal.id = move.journal_id
JOIN res_company company ON company.id = journal.company_id
WHERE move.id IN %s
AND move.date < company.tax_lock_date
''', [tuple(self.ids)])
query_res = self._cr.fetchone()
if query_res:
raise UserError(_('''
The operation is refused as it would impact an already issued tax statement.
Please change the journal entry date or the tax lock date set in the settings (%s) to proceed
''' % query_res[1]))
for move in self:
if (
move.company_id.tax_lock_date
and move.date <= move.company_id.tax_lock_date
and any(
line.tax_ids
or line.tax_line_id
or line.tag_ids.filtered(lambda x: x.applicability == "taxes")
for line in move.line_ids
)
):
raise UserError(
_(
"The operation is refused as it would impact an already issued tax statement. Please change the journal entry date or the tax lock date set in the settings ({}) to proceed"
).format(move.company_id.tax_lock_date or date.min)
)
def _check_move_consistency(self):
for move in self:
@@ -1335,6 +1366,7 @@ class AccountMove(models.Model):
raise UserError(_("Cannot create moves for different companies."))
self._check_balanced()
self._check_tax_lock_date()
self._check_fiscalyear_lock_date()
# -------------------------------------------------------------------------
@@ -1369,6 +1401,8 @@ class AccountMove(models.Model):
line.account_id = self.journal_id.default_credit_account_id
elif self.is_purchase_document(include_receipts=True):
line.account_id = self.journal_id.default_debit_account_id
if line.product_id and not line._cache.get('name'):
line.name = line._get_computed_name()
self.line_ids._onchange_price_subtotal()
self._recompute_dynamic_lines(recompute_all_taxes=True)
@@ -1487,7 +1521,11 @@ class AccountMove(models.Model):
result = []
for move in self:
if self._context.get('name_groupby') and not (move.type == 'entry' and move.state == 'draft'):
name = '**%s**, %s %s' % (format_date(self.env, move.date), move.name, move.partner_id.name or '')
name = '**%s**, %s' % (format_date(self.env, move.date), move.name or '')
if move.ref:
name += ' (%s)' % move.ref
if move.partner_id.name:
name += ' - %s' % move.partner_id.name
elif move.type == 'entry':
# Miscellaneous operation.
if move.state == 'draft':
@@ -1693,6 +1731,13 @@ class AccountMove(models.Model):
else:
return abs(total_reconciled / total_amount)
def _get_reconciled_payments(self):
"""Helper used to retrieve the reconciled payments on this journal entry"""
pay_term_line_ids = self.line_ids.filtered(lambda line: line.account_id.user_type_id.type in ('receivable', 'payable'))
reconciled_amls = pay_term_line_ids.mapped('matched_debit_ids.debit_move_id') + \
pay_term_line_ids.mapped('matched_credit_ids.credit_move_id')
return reconciled_amls.mapped('payment_id')
def _reverse_move_vals(self, default_values, cancel=True):
''' Reverse values passed as parameter being the copied values of the original journal entry.
For example, debit / credit must be switched. The tax lines must be edited in case of refunds.
@@ -1819,7 +1864,16 @@ class AccountMove(models.Model):
'reversed_entry_id': move.id,
})
move_vals_list.append(move._reverse_move_vals(default_values, cancel=cancel))
reverse_moves = self.env['account.move'].create(move_vals_list)
for move, reverse_move in zip(self, reverse_moves.with_context(check_move_validity=False)):
# Update amount_currency if the date has changed.
if move.date != reverse_move.date:
for line in reverse_move.line_ids:
if line.currency_id:
line._onchange_currency()
reverse_move._recompute_dynamic_lines(recompute_all_taxes=False)
reverse_moves._check_balanced()
# Reconcile moves together to cancel the previous one.
if cancel:
@@ -1860,7 +1914,6 @@ class AccountMove(models.Model):
move.invoice_date = fields.Date.context_today(self)
move.with_context(check_move_validity=False)._onchange_invoice_date()
self._check_tax_lock_date()
self._check_move_consistency()
# Create the analytic lines in batch is faster as it leads to less cache invalidation.
self.mapped('line_ids').create_analytic_lines()
@@ -1900,6 +1953,26 @@ class AccountMove(models.Model):
# installing Accounting- with bank statements)
move.company_id.account_bank_reconciliation_start = move.date
for move in self:
if not move.partner_id: continue
if move.type.startswith('out_'):
field='customer_rank'
elif move.type.startswith('in_'):
field='supplier_rank'
else:
continue
try:
with self.env.cr.savepoint():
self.env.cr.execute("SELECT "+field+" FROM res_partner WHERE ID=%s FOR UPDATE NOWAIT", (move.partner_id.id,))
self.env.cr.execute("UPDATE res_partner SET "+field+"="+field+"+1 WHERE ID=%s", (move.partner_id.id,))
self.env.cache.remove(move.partner_id, move.partner_id._fields[field])
except psycopg2.DatabaseError as e:
if e.pgcode == '55P03':
_logger.debug('Another transaction already locked partner rows. Cannot update partner ranks.')
continue
else:
raise e
def action_reverse(self):
action = self.env.ref('account.action_view_account_move_reversal').read()[0]
@@ -1909,7 +1982,7 @@ class AccountMove(models.Model):
return action
def action_post(self):
if self.mapped('line_ids.payment_id') and any(self.mapped('journal_id.post_at_bank_rec')):
if self.mapped('line_ids.payment_id') and any(post_at == 'bank_rec' for post_at in self.mapped('journal_id.post_at')):
raise UserError(_("A payment journal entry generated in a journal configured to post entries only when payments are reconciled with a bank statement cannot be manually posted. Those will be posted automatically after performing the bank reconciliation."))
return self.post()
@@ -1925,6 +1998,7 @@ class AccountMove(models.Model):
self.write({'state': 'draft'})
def button_cancel(self):
self._check_tax_lock_date()
AccountMoveLine = self.env['account.move.line']
excluded_move_ids = []
@@ -1932,6 +2006,10 @@ class AccountMove(models.Model):
excluded_move_ids = AccountMoveLine.search(AccountMoveLine._get_suspense_moves_domain() + [('move_id', 'in', self.ids)]).mapped('move_id').ids
for move in self:
if move in move.line_ids.mapped('full_reconcile_id.exchange_move_id'):
raise UserError(_('You cannot cancel an exchange difference journal entry.'))
if move.tax_cash_basis_rec_id:
raise UserError(_('You cannot cancel a tax cash basis journal entry.'))
if not move.journal_id.update_posted and move.id not in excluded_move_ids:
raise UserError(_('You cannot modify a posted entry of this journal.\nFirst you should set the journal to allow cancelling entries.'))
# We remove all the analytics entries for this journal
@@ -1981,6 +2059,7 @@ class AccountMove(models.Model):
"""
if any(not move.is_invoice(include_receipts=True) for move in self):
raise UserError(_("Only invoices could be printed."))
self._check_tax_lock_date()
self.filtered(lambda inv: not inv.invoice_sent).write({'invoice_sent': True})
if self.user_has_groups('account.group_account_invoice'):
@@ -2015,9 +2094,9 @@ class AccountMove(models.Model):
def action_switch_invoice_into_refund_credit_note(self):
if any(move.type not in ('in_invoice', 'out_invoice') for move in self):
raise ValidationError(_("This action isn't available for this document."))
for move in self:
move.type = move.type.replace('invoice', 'refund')
move.type = move.type.replace('invoice', 'refund')
reversed_move = move._reverse_move_vals({}, False)
new_invoice_line_ids = []
for cmd, virtualid, line_vals in reversed_move['line_ids']:
@@ -2108,14 +2187,14 @@ class AccountMove(models.Model):
class AccountMoveLine(models.Model):
_name = "account.move.line"
_description = "Journal Item"
_order = "sequence, date desc, move_name desc, id"
_order = "date desc, move_name desc, id"
# ==== Business fields ====
move_id = fields.Many2one('account.move', string='Journal Entry',
index=True, required=True, auto_join=True, ondelete="cascade",
help="The move of this entry line.")
move_name = fields.Char(string='Number', related='move_id.name', store=True, index=True)
date = fields.Date(related='move_id.date', store=True, readonly=True, index=True, copy=False)
date = fields.Date(related='move_id.date', store=True, readonly=True, index=True, copy=False, group_operator='min')
ref = fields.Char(related='move_id.ref', store=True, copy=False, index=True, readonly=False)
parent_state = fields.Selection(related='move_id.state', store=True, readonly=True)
journal_id = fields.Many2one(related='move_id.journal_id', store=True, readonly=False, index=True, copy=False)
@@ -2127,6 +2206,7 @@ class AccountMoveLine(models.Model):
index=True, ondelete="cascade",
domain=[('deprecated', '=', False)])
account_internal_type = fields.Selection(related='account_id.user_type_id.type', string="Internal Type", store=True, readonly=True)
account_root_id = fields.Many2one(related='account_id.root_id', string="Account Root", store=True, readonly=True)
sequence = fields.Integer(default=10)
name = fields.Char(string='Label')
quantity = fields.Float(string='Quantity',
@@ -2141,7 +2221,7 @@ class AccountMoveLine(models.Model):
currency_field='company_currency_id',
compute='_compute_balance',
help="Technical field holding the debit - credit in order to open meaningful graph views from reports")
amount_currency = fields.Monetary(string='Balance in Currency', store=True, copy=True,
amount_currency = fields.Monetary(string='Amount in Currency', store=True, copy=True,
help="The amount expressed in an optional other currency if it is a multi-currency entry.")
price_subtotal = fields.Monetary(string='Subtotal', store=True, readonly=True,
currency_field='always_set_currency_id')
@@ -2150,7 +2230,7 @@ class AccountMoveLine(models.Model):
reconciled = fields.Boolean(compute='_amount_residual', store=True)
blocked = fields.Boolean(string='No Follow-up', default=False,
help="You can check this box to mark this journal item as a litigation with the associated partner")
date_maturity = fields.Date(string='Due date', index=True,
date_maturity = fields.Date(string='Due Date', index=True,
help="This field is used for payable and receivable journal entries. You can put the limit date for the payment of this line.")
currency_id = fields.Many2one('res.currency', string='Currency')
partner_id = fields.Many2one('res.partner', string='Partner', ondelete='restrict')
@@ -2174,14 +2254,14 @@ class AccountMoveLine(models.Model):
tax_group_id = fields.Many2one(related='tax_line_id.tax_group_id', string='Originator tax group',
readonly=True, store=True,
help='technical field for widget tax-group-custom-field')
tax_base_amount = fields.Monetary(string="Base Amount", store=True,
tax_base_amount = fields.Monetary(string="Base Amount", store=True, readonly=True,
currency_field='company_currency_id')
tax_exigible = fields.Boolean(string='Appears in VAT report', default=True,
tax_exigible = fields.Boolean(string='Appears in VAT report', default=True, readonly=True,
help="Technical field used to mark a tax line as exigible in the vat report or not (only exigible journal items"
" are displayed). By default all new journal items are directly exigible, but with the feature cash_basis"
" on taxes, some will become exigible only when the payment is recorded.")
tax_repartition_line_id = fields.Many2one(comodel_name='account.tax.repartition.line',
string="Originator Tax Repartition Line", ondelete='restrict',
string="Originator Tax Repartition Line", ondelete='restrict', readonly=True,
help="Tax repartition line that caused the creation of this move line, if any")
tag_ids = fields.Many2many(string="Tags", comodel_name='account.account.tag', ondelete='restrict',
help="Tags assigned to this line by the tax creating it, if any. It determines its impact on financial reports.")
@@ -2196,7 +2276,7 @@ class AccountMoveLine(models.Model):
amount_residual_currency = fields.Monetary(string='Residual Amount in Currency', store=True,
compute='_amount_residual',
help="The residual amount on a journal item expressed in its currency (possibly not the company currency).")
full_reconcile_id = fields.Many2one('account.full.reconcile', string="Matching Number", copy=False, index=True)
full_reconcile_id = fields.Many2one('account.full.reconcile', string="Matching #", copy=False, index=True)
matched_debit_ids = fields.One2many('account.partial.reconcile', 'credit_move_id', string='Matched Debits',
help='Debit journal items that are matched with this journal item.')
matched_credit_ids = fields.One2many('account.partial.reconcile', 'debit_move_id', string='Matched Credits',
@@ -2673,7 +2753,7 @@ class AccountMoveLine(models.Model):
else:
date = partial_line.credit_move_id.date if partial_line.debit_move_id == line else partial_line.debit_move_id.date
rate = line.currency_id.with_context(date=date).rate
amount_residual_currency += sign_partial_line * partial_line.amount * rate
amount_residual_currency += sign_partial_line * line.currency_id.round(partial_line.amount * rate)
#computing the `reconciled` field.
reconciled = False
@@ -2756,36 +2836,21 @@ class AccountMoveLine(models.Model):
if line.reconciled:
raise UserError(_('Lines from "Off-Balance Sheet" accounts cannot be reconciled'))
@api.constrains('tax_ids', 'tax_line_id')
def _check_tax_lock_date1(self):
for line in self:
if line.date <= (line.company_id.tax_lock_date or date.min):
raise ValidationError(
_("The operation is refused as it would impact an already issued tax statement. " +
"Please change the journal entry date or the tax lock date set in the settings ({}) to proceed").format(
line.company_id.tax_lock_date or date.min))
@api.constrains('credit', 'debit', 'date')
def _check_tax_lock_date2(self):
for line in self:
if (line.tax_ids or line.tax_line_id) and line.date <= (line.company_id.tax_lock_date or date.min):
raise ValidationError(
_("The operation is refused as it would impact an already issued tax statement. " +
"Please change the journal entry date or the tax lock date set in the settings ({}) to proceed").format(
line.company_id.tax_lock_date or date.min))
def _update_check(self):
""" Raise Warning to cause rollback if the move is posted, some entries are reconciled or the move is older than the lock date"""
move_ids = set()
for line in self:
err_msg = _('Move name (id): %s (%s)') % (line.move_id.name, str(line.move_id.id))
if line.move_id.state != 'draft':
if line.move_id.state == 'posted':
raise UserError(_('You cannot do this modification on a posted journal entry, you can just change some non legal fields. You must revert the journal entry to cancel it.\n%s.') % err_msg)
if line.reconciled and not (line.debit == 0 and line.credit == 0):
raise UserError(_('You cannot do this modification on a reconciled entry. You can just change some non legal fields or you must unreconcile first.\n%s.') % err_msg)
if line.move_id.id not in move_ids:
move_ids.add(line.move_id.id)
self.env['account.move'].browse(list(move_ids))._check_fiscalyear_lock_date()
if move_ids:
moves = self.env['account.move'].browse(list(move_ids))
moves._check_fiscalyear_lock_date()
moves._check_tax_lock_date()
return True
# -------------------------------------------------------------------------
@@ -2941,7 +3006,6 @@ class AccountMoveLine(models.Model):
def unlink(self):
self._update_check()
self._check_tax_lock_date2()
move_ids = set()
for line in self:
if line.move_id.id not in move_ids:
@@ -2975,6 +3039,11 @@ class AccountMoveLine(models.Model):
# Suggest default value for debit / credit to balance the journal entry.
balance = sum(line['debit'] - line['credit'] for line in move.line_ids)
# if we are here, line_ids is in context, so journal_id should also be.
journal = self.env['account.journal'].browse(self._context.get('default_journal_id') or self._context['journal_id'])
currency = journal.exists() and journal.company_id.currency_id
if currency:
balance = currency.round(balance)
if balance < 0.0:
values.update({'debit': -balance})
if balance > 0.0:
@@ -3083,26 +3152,31 @@ class AccountMoveLine(models.Model):
):
exchange_move_id = False
missing_exchange_difference = False
# Eventually create a journal entry to book the difference due to foreign currency's exchange rate that fluctuates
if to_balance and any([not float_is_zero(residual, precision_rounding=digits_rounding_precision) for aml, residual in to_balance.values()]):
exchange_move = self.env['account.move'].with_context(default_type='entry').create(
self.env['account.full.reconcile']._prepare_exchange_diff_move(move_date=maxdate, company=amls[0].company_id))
part_reconcile = self.env['account.partial.reconcile']
for aml_to_balance, total in to_balance.values():
if total:
rate_diff_amls, rate_diff_partial_rec = part_reconcile.create_exchange_rate_entry(aml_to_balance, exchange_move)
amls += rate_diff_amls
partial_rec_ids += rate_diff_partial_rec.ids
else:
aml_to_balance.reconcile()
exchange_move.post()
exchange_move_id = exchange_move.id
#mark the reference of the full reconciliation on the exchange rate entries and on the entries
self.env['account.full.reconcile'].create({
'partial_reconcile_ids': [(6, 0, partial_rec_ids)],
'reconciled_line_ids': [(6, 0, amls.ids)],
'exchange_move_id': exchange_move_id,
})
if not self.env.context.get('no_exchange_difference'):
exchange_move = self.env['account.move'].with_context(default_type='entry').create(
self.env['account.full.reconcile']._prepare_exchange_diff_move(move_date=maxdate, company=amls[0].company_id))
part_reconcile = self.env['account.partial.reconcile']
for aml_to_balance, total in to_balance.values():
if total:
rate_diff_amls, rate_diff_partial_rec = part_reconcile.create_exchange_rate_entry(aml_to_balance, exchange_move)
amls += rate_diff_amls
partial_rec_ids += rate_diff_partial_rec.ids
else:
aml_to_balance.reconcile()
exchange_move.post()
exchange_move_id = exchange_move.id
else:
missing_exchange_difference = True
if not missing_exchange_difference:
#mark the reference of the full reconciliation on the exchange rate entries and on the entries
self.env['account.full.reconcile'].create({
'partial_reconcile_ids': [(6, 0, partial_rec_ids)],
'reconciled_line_ids': [(6, 0, amls.ids)],
'exchange_move_id': exchange_move_id,
})
def _reconcile_lines(self, debit_moves, credit_moves, field):
""" This function loops on the 2 recordsets given as parameter as long as it
@@ -3174,7 +3248,11 @@ class AccountMoveLine(models.Model):
for after_rec_dict in cash_basis_subjected:
new_rec = part_rec.create(after_rec_dict)
# if the pair belongs to move being reverted, do not create CABA entry
if cash_basis and not (new_rec.debit_move_id + new_rec.credit_move_id).mapped('move_id.reversed_entry_id'):
if cash_basis and not (
new_rec.debit_move_id.move_id == new_rec.credit_move_id.move_id.reversed_entry_id
or
new_rec.credit_move_id.move_id == new_rec.debit_move_id.move_id.reversed_entry_id
):
new_rec.create_tax_cash_basis_entry(cash_basis_percentage_before_rec)
return debit_moves+credit_moves
@@ -3342,8 +3420,11 @@ class AccountMoveLine(models.Model):
def copy_data(self, default=None):
res = super(AccountMoveLine, self).copy_data(default=default)
if self._context.get('include_business_fields'):
for line, values in zip(self, res):
for line, values in zip(self, res):
# Don't copy the name of a payment term line.
if line.move_id.is_invoice() and line.account_id.user_type_id.type in ('receivable', 'payable'):
values['name'] = ''
if self._context.get('include_business_fields'):
line._copy_data_extend_business_fields(values)
return res
@@ -3547,6 +3628,11 @@ class AccountMoveLine(models.Model):
action['domain'] = [('id', 'in', ids)]
return action
def action_accrual_entry(self):
[action] = self.env.ref('account.account_accrual_accounting_wizard_action').read()
action['context'] = self.env.context
return action
@api.model
def _get_suspense_moves_domain(self):
return [
+10 -7
View File
@@ -47,13 +47,14 @@ class account_payment(models.Model):
as it can have been generated first, and reconciled later""")
reconciled_invoice_ids = fields.Many2many('account.move', string='Reconciled Invoices', compute='_compute_reconciled_invoice_ids', help="Invoices whose journal items have been reconciled with these payments.")
has_invoices = fields.Boolean(compute="_compute_reconciled_invoice_ids", help="Technical field used for usability purposes")
reconciled_invoices_count = fields.Integer(compute="_compute_reconciled_invoice_ids")
move_line_ids = fields.One2many('account.move.line', 'payment_id', readonly=True, copy=False, ondelete='restrict')
move_reconciled = fields.Boolean(compute="_get_move_reconciled", readonly=True)
state = fields.Selection([('draft', 'Draft'), ('posted', 'Posted'), ('sent', 'Sent'), ('reconciled', 'Reconciled'), ('cancelled', 'Cancelled')], readonly=True, default='draft', copy=False, string="Status")
state = fields.Selection([('draft', 'Draft'), ('posted', 'Validated'), ('sent', 'Sent'), ('reconciled', 'Reconciled'), ('cancelled', 'Cancelled')], readonly=True, default='draft', copy=False, string="Status")
payment_type = fields.Selection([('outbound', 'Send Money'), ('inbound', 'Receive Money'), ('transfer', 'Internal Transfer')], string='Payment Type', required=True, readonly=True, states={'draft': [('readonly', False)]})
payment_method_id = fields.Many2one('account.payment.method', string='Payment Method Type', required=True, readonly=True, states={'draft': [('readonly', False)]},
payment_method_id = fields.Many2one('account.payment.method', string='Payment Method', required=True, readonly=True, states={'draft': [('readonly', False)]},
help="Manual: Get paid by cash, check or any other method outside of Odoo.\n"\
"Electronic: Get paid automatically through a payment acquirer by requesting a transaction on a card saved by the customer when buying or subscribing online (payment token).\n"\
"Check: Pay bill by check and print it from Odoo.\n"\
@@ -65,11 +66,11 @@ class account_payment(models.Model):
partner_type = fields.Selection([('customer', 'Customer'), ('supplier', 'Vendor')], tracking=True, readonly=True, states={'draft': [('readonly', False)]})
partner_id = fields.Many2one('res.partner', string='Partner', tracking=True, readonly=True, states={'draft': [('readonly', False)]}, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]")
amount = fields.Monetary(string='Payment Amount', required=True, readonly=True, states={'draft': [('readonly', False)]}, tracking=True)
amount = fields.Monetary(string='Amount', required=True, readonly=True, states={'draft': [('readonly', False)]}, tracking=True)
currency_id = fields.Many2one('res.currency', string='Currency', required=True, readonly=True, states={'draft': [('readonly', False)]}, default=lambda self: self.env.company.currency_id)
payment_date = fields.Date(string='Payment Date', default=fields.Date.context_today, required=True, readonly=True, states={'draft': [('readonly', False)]}, copy=False, tracking=True)
payment_date = fields.Date(string='Date', default=fields.Date.context_today, required=True, readonly=True, states={'draft': [('readonly', False)]}, copy=False, tracking=True)
communication = fields.Char(string='Memo', readonly=True, states={'draft': [('readonly', False)]})
journal_id = fields.Many2one('account.journal', string='Payment Journal', required=True, readonly=True, states={'draft': [('readonly', False)]}, tracking=True, domain="[('type', 'in', ('bank', 'cash')), ('company_id', '=', company_id)]")
journal_id = fields.Many2one('account.journal', string='Journal', required=True, readonly=True, states={'draft': [('readonly', False)]}, tracking=True, domain="[('type', 'in', ('bank', 'cash')), ('company_id', '=', company_id)]")
company_id = fields.Many2one('res.company', related='journal_id.company_id', string='Company', readonly=True)
hide_payment_method = fields.Boolean(compute='_compute_hide_payment_method',
@@ -389,6 +390,7 @@ class account_payment(models.Model):
+ record.move_line_ids.mapped('matched_credit_ids.credit_move_id.move_id')
record.reconciled_invoice_ids = reconciled_moves.filtered(lambda move: move.is_invoice())
record.has_invoices = bool(record.reconciled_invoice_ids)
record.reconciled_invoices_count = len(record.reconciled_invoice_ids)
def action_register_payment(self):
active_ids = self.env.context.get('active_ids')
@@ -441,7 +443,8 @@ class account_payment(models.Model):
for move in rec.move_line_ids.mapped('move_id'):
if rec.reconciled_invoice_ids:
move.line_ids.remove_move_reconcile()
move.button_cancel()
if move.state != 'draft':
move.button_cancel()
move.unlink()
rec.write({
'state': 'cancelled',
@@ -671,7 +674,7 @@ class account_payment(models.Model):
raise UserError(_("You have to define a sequence for %s in your company.") % (sequence_code,))
moves = AccountMove.create(rec._prepare_payment_moves())
moves.filtered(lambda move: not move.journal_id.post_at_bank_rec).post()
moves.filtered(lambda move: move.journal_id.post_at != 'bank_rec').post()
# Update the state / move before performing any reconciliation.
rec.write({'state': 'posted', 'move_name': moves[0].name})
@@ -4,6 +4,8 @@ from odoo import api, fields, models, _
from odoo.tools import float_compare, float_is_zero
from odoo.exceptions import UserError
import re
class AccountReconcileModel(models.Model):
_name = 'account.reconcile.model'
@@ -92,12 +94,15 @@ class AccountReconcileModel(models.Model):
label = fields.Char(string='Journal Item Label')
amount_type = fields.Selection([
('fixed', 'Fixed'),
('percentage', 'Percentage of balance')
('percentage', 'Percentage of balance'),
('regex', 'From label'),
], required=True, default='percentage')
show_force_tax_included = fields.Boolean(store=False, help='Technical field used to show the force tax included button')
force_tax_included = fields.Boolean(string='Tax Included in Price',
help='Force the tax to be managed as a price included tax.')
amount = fields.Float(string='Write-off Amount', digits=0, required=True, default=100.0, help="Fixed amount will count as a debit if it is negative, as a credit if it is positive.")
amount_from_label_regex = fields.Char(string="Amount from Label (regex)", default=r"([\d\.,]+)", help="There is no need for regex delimiter, only the regex is needed. For instance if you want to extract the amount from\nR:9672938 10/07 AX 9415126318 T:5L:NA BRT: 3358,07 C:\nYou could enter\nBRT: ([\d,]+)")
decimal_separator = fields.Char(default=lambda self: self.env['res.lang']._lang_get(self.env.user.lang).decimal_point, help="Every character that is nor a digit nor this separator will be removed from the matching string")
tax_ids = fields.Many2many('account.tax', string='Taxes', ondelete='restrict')
analytic_account_id = fields.Many2one('account.analytic.account', string='Analytic Account', ondelete='set null')
analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Analytic Tags',
@@ -110,12 +115,14 @@ class AccountReconcileModel(models.Model):
second_label = fields.Char(string='Second Journal Item Label')
second_amount_type = fields.Selection([
('fixed', 'Fixed'),
('percentage', 'Percentage of amount')
('percentage', 'Percentage of balance'),
('regex', 'From label'),
], string="Second Amount type",required=True, default='percentage')
show_second_force_tax_included = fields.Boolean(store=False, help='Technical field used to show the force tax included button')
force_second_tax_included = fields.Boolean(string='Second Tax Included in Price',
help='Force the second tax to be managed as a price included tax.')
second_amount = fields.Float(string='Second Write-off Amount', digits=0, required=True, default=100.0, help="Fixed amount will count as a debit if it is negative, as a credit if it is positive.")
second_amount_from_label_regex = fields.Char(string="Second Amount from Label (regex)", default=r"([\d\.,]+)")
second_tax_ids = fields.Many2many('account.tax', relation='account_reconcile_model_account_tax_bis_rel', string='Second Taxes', ondelete='restrict')
second_analytic_account_id = fields.Many2one('account.analytic.account', string='Second Analytic Account', ondelete='set null')
second_analytic_tag_ids = fields.Many2many('account.analytic.tag', string='Second Analytic Tags',
@@ -231,6 +238,12 @@ class AccountReconcileModel(models.Model):
if self.amount_type == 'percentage':
line_balance = balance * (self.amount / 100.0)
elif self.amount_type == "regex":
match = re.search(self.amount_from_label_regex, st_line.name)
if match:
line_balance = float(re.sub(r'\D' + self.decimal_separator, '', match.group(1)).replace(self.decimal_separator, '.')) * (1 if balance > 0.0 else -1)
else:
line_balance = 0
else:
line_balance = self.amount * (1 if balance > 0.0 else -1)
@@ -258,7 +271,18 @@ class AccountReconcileModel(models.Model):
# Second write-off line.
if self.has_second_line and self.second_account_id:
line_balance = balance - sum(aml['debit'] - aml['credit'] for aml in new_aml_dicts)
remaining_balance = balance - sum(aml['debit'] - aml['credit'] for aml in new_aml_dicts)
if self.second_amount_type == 'percentage':
line_balance = remaining_balance * (self.second_amount / 100.0)
elif self.second_amount_type == "regex":
match = re.search(self.second_amount_from_label_regex, st_line.name)
if match:
line_balance = float(re.sub(r'\D' + self.decimal_separator, '', match.group(1)).replace(self.decimal_separator, '.'))
else:
line_balance = 0
else:
line_balance = self.second_amount * (1 if remaining_balance > 0.0 else -1)
second_writeoff_line = {
'name': self.second_label or st_line.name,
'account_id': self.second_account_id.id,
@@ -375,7 +399,7 @@ class AccountReconcileModel(models.Model):
query += ' AND st_line.name NOT ILIKE %s'
params += ['%%%s%%' % rule['match_' + field + '_param']]
elif rule['match_' + field] == 'match_regex':
query += ' AND st_line.name ~ %s'
query += ' AND st_line.name ~* %s'
params += [rule['match_' + field + '_param']]
# Filter on partners.
@@ -445,12 +469,23 @@ class AccountReconcileModel(models.Model):
aml.amount_currency AS aml_amount_currency,
account.internal_type AS account_internal_type,
-- Determine a matching or not with the statement line communication using the move.name or move.ref.
regexp_split_to_array(TRIM(REGEXP_REPLACE(move.name, '[^0-9|^\s]', '', 'g')),'\s+')
&& regexp_split_to_array(TRIM(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g')), '\s+')
-- Determine a matching or not with the statement line communication using the aml.name, move.name or move.ref.
(
aml.name IS NOT NULL
AND
TRIM(REGEXP_REPLACE(aml.name, '[^0-9|^\s]', '', 'g')) != ''
AND
regexp_split_to_array(TRIM(REGEXP_REPLACE(aml.name, '[^0-9|^\s]', '', 'g')),'\s+')
&& regexp_split_to_array(TRIM(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g')), '\s+')
)
OR
regexp_split_to_array(TRIM(REGEXP_REPLACE(move.name, '[^0-9|^\s]', '', 'g')),'\s+')
&& regexp_split_to_array(TRIM(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g')), '\s+')
OR
(
move.ref IS NOT NULL
AND
TRIM(REGEXP_REPLACE(move.ref, '[^0-9|^\s]', '', 'g')) != ''
AND
regexp_split_to_array(TRIM(REGEXP_REPLACE(move.ref, '[^0-9|^\s]', '', 'g')),'\s+')
&& regexp_split_to_array(TRIM(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g')), '\s+')
@@ -494,11 +529,22 @@ class AccountReconcileModel(models.Model):
TRIM(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g')) != ''
AND
(
regexp_split_to_array(TRIM(REGEXP_REPLACE(move.name, '[^0-9|^\s]', '', 'g')),'\s+')
&& regexp_split_to_array(TRIM(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g')), '\s+')
(
aml.name IS NOT NULL
AND
TRIM(REGEXP_REPLACE(aml.name, '[^0-9|^\s]', '', 'g')) != ''
AND
regexp_split_to_array(TRIM(REGEXP_REPLACE(aml.name, '[^0-9|^\s]', '', 'g')),'\s+')
&& regexp_split_to_array(TRIM(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g')), '\s+')
)
OR
regexp_split_to_array(TRIM(REGEXP_REPLACE(move.name, '[^0-9|^\s]', '', 'g')),'\s+')
&& regexp_split_to_array(TRIM(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g')), '\s+')
OR
(
move.ref IS NOT NULL
AND
TRIM(REGEXP_REPLACE(move.ref, '[^0-9|^\s]', '', 'g')) != ''
AND
regexp_split_to_array(TRIM(REGEXP_REPLACE(move.ref, '[^0-9|^\s]', '', 'g')),'\s+')
&& regexp_split_to_array(TRIM(REGEXP_REPLACE(st_line.name, '[^0-9|^\s]', '', 'g')), '\s+')
@@ -609,8 +655,10 @@ class AccountReconcileModel(models.Model):
if line_residual > total_residual:
amount_percentage = (total_residual / line_residual) * 100
else:
elif total_residual:
amount_percentage = (line_residual / total_residual) * 100 if total_residual else 0
else:
return False
return amount_percentage >= self.match_total_amount_param
def _apply_rules(self, st_lines, excluded_ids=None, partner_map=None):
@@ -681,8 +729,6 @@ class AccountReconcileModel(models.Model):
if not grouped_candidates.get(line.id) or not grouped_candidates[line.id].get(model.id):
continue
excluded_lines_found = False
if model.rule_type == 'invoice_matching':
candidates = grouped_candidates[line.id][model.id]
@@ -690,18 +736,26 @@ class AccountReconcileModel(models.Model):
# Otherwise, suggest all invoices having the same partner.
# N.B: The only way to match a line without a partner is through the communication.
first_batch_candidates = []
first_batch_candidates_proposed = []
second_batch_candidates = []
second_batch_candidates_proposed = []
for c in candidates:
# Don't take into account already reconciled lines.
if c['aml_id'] in reconciled_amls_ids:
continue
# Dispatch candidates between lines matching invoices with the communication or only the partner.
if c['communication_flag']:
first_batch_candidates.append(c)
elif c['communication_flag']:
if c['aml_id'] in amls_ids_to_exclude:
first_batch_candidates_proposed.append(c)
else:
first_batch_candidates.append(c)
elif not first_batch_candidates:
second_batch_candidates.append(c)
available_candidates = first_batch_candidates or second_batch_candidates
if c['aml_id'] in amls_ids_to_exclude:
second_batch_candidates_proposed.append(c)
else:
second_batch_candidates.append(c)
available_candidates = first_batch_candidates + first_batch_candidates_proposed or second_batch_candidates + second_batch_candidates_proposed
# Special case: the amount are the same, submit the line directly.
for c in available_candidates:
@@ -717,20 +771,9 @@ class AccountReconcileModel(models.Model):
# Add candidates to the result.
for candidate in available_candidates:
# Special case: the propositions match the rule but some of them are already consumed by
# another one. Then, suggest the remaining propositions to the user but don't make any
# automatic reconciliation.
if candidate['aml_id'] in amls_ids_to_exclude:
excluded_lines_found = True
continue
results[line.id]['aml_ids'].append(candidate['aml_id'])
amls_ids_to_exclude.add(candidate['aml_id'])
if excluded_lines_found:
break
# Create write-off lines.
move_lines = self.env['account.move.line'].browse(results[line.id]['aml_ids'])
partner = partner_map and partner_map.get(line.id) and self.env['res.partner'].browse(partner_map[line.id])
+13 -7
View File
@@ -57,6 +57,7 @@ class AccountAccountTemplate(models.Model):
"to define chart templates that extend another and complete it with few new accounts (You don't need to define the whole structure that is common to both several times).")
tag_ids = fields.Many2many('account.account.tag', 'account_account_template_account_tag', string='Account tag', help="Optional tags you may want to assign for custom reporting")
group_id = fields.Many2one('account.group')
root_id = fields.Many2one('account.root')
@api.depends('name', 'code')
def name_get(self):
@@ -652,10 +653,10 @@ class AccountChartTemplate(models.Model):
sale_tax = self.env['account.tax.template'].search([('type_tax_use', '=', 'sale'), ('chart_template_id', 'in', all_parents)], limit=1)
purchase_tax = self.env['account.tax.template'].search([('type_tax_use', '=', 'purchase'), ('chart_template_id', 'in', all_parents)], limit=1)
for account_template in acc_template:
# Adding a tax by default on each income or expense account.
if account_template.user_type_id.internal_group == 'income':
# Adding a tax by default on each income or expense account, if they are not used for exchange difference.
if account_template.user_type_id.internal_group == 'income' and account_template != self.income_currency_exchange_account_id:
account_template.tax_ids = sale_tax
elif account_template.user_type_id.internal_group == 'expense':
elif account_template.user_type_id.internal_group == 'expense' and account_template != self.expense_currency_exchange_account_id:
account_template.tax_ids = purchase_tax
code_main = account_template.code and len(account_template.code) or 0
code_acc = account_template.code or ''
@@ -1046,8 +1047,8 @@ class AccountFiscalPositionTemplate(models.Model):
country_group_id = fields.Many2one('res.country.group', string='Country Group',
help="Apply only if delivery or invoicing country match the group.")
state_ids = fields.Many2many('res.country.state', string='Federal States')
zip_from = fields.Integer(string='Zip Range From', default=0)
zip_to = fields.Integer(string='Zip Range To', default=0)
zip_from = fields.Char(string='Zip Range From')
zip_to = fields.Char(string='Zip Range To')
class AccountFiscalPositionTaxTemplate(models.Model):
@@ -1154,9 +1155,12 @@ class AccountReconcileModelTemplate(models.Model):
label = fields.Char(string='Journal Item Label')
amount_type = fields.Selection([
('fixed', 'Fixed'),
('percentage', 'Percentage of balance')
('percentage', 'Percentage of balance'),
('regex', 'From label'),
], required=True, default='percentage')
amount = fields.Float(string='Write-off Amount', digits=0, required=True, default=100.0, help="Fixed amount will count as a debit if it is negative, as a credit if it is positive.")
amount_from_label_regex = fields.Char(string="Amount from Label (regex)", default=r"([\d\.,]+)")
decimal_separator = fields.Char(help="Every character that is nor a digit nor this separator will be removed from the matching string")
force_tax_included = fields.Boolean(string='Tax Included in Price',
help='Force the tax to be managed as a price included tax.')
# Second part fields.
@@ -1166,9 +1170,11 @@ class AccountReconcileModelTemplate(models.Model):
second_label = fields.Char(string='Second Journal Item Label')
second_amount_type = fields.Selection([
('fixed', 'Fixed'),
('percentage', 'Percentage of amount')
('percentage', 'Percentage of amount'),
('regex', 'From label'),
], string="Second Amount type",required=True, default='percentage')
second_amount = fields.Float(string='Second Write-off Amount', digits=0, required=True, default=100.0, help="Fixed amount will count as a debit if it is negative, as a credit if it is positive.")
second_amount_from_label_regex = fields.Char(string="Second Amount from Label (regex)", default=r"([\d\.,]+)")
force_second_tax_included = fields.Boolean(string='Second Tax Included in Price',
help='Force the second tax to be managed as a price included tax.')
number_entries = fields.Integer(string='Number of entries related to this model', compute='_compute_number_entries')
+14 -11
View File
@@ -63,15 +63,6 @@ class ResCompany(models.Model):
property_stock_account_output_categ_id = fields.Many2one('account.account', string="Output Account for Stock Valuation")
property_stock_valuation_account_id = fields.Many2one('account.account', string="Account Template for Stock Valuation")
bank_journal_ids = fields.One2many('account.journal', 'company_id', domain=[('type', '=', 'bank')], string='Bank Journals')
overdue_msg = fields.Text(string='Overdue Payments Message', translate=True,
default=lambda s: _('''Dear Sir/Madam,
Our records indicate that some payments on your account are still due. Please find details below.
If the amount has already been paid, please disregard this notice. Otherwise, please forward us the total amount stated below.
If you have any queries regarding your account, Please contact us.
Thank you in advance for your cooperation.
Best Regards,'''))
tax_exigibility = fields.Boolean(string='Use Cash Basis')
account_bank_reconciliation_start = fields.Date(string="Bank Reconciliation Threshold", help="""The bank reconciliation widget won't ask to reconcile payments older than this date.
This is useful if you install accounting after having used invoicing for some time and
@@ -107,6 +98,11 @@ Best Regards,'''))
# Needed in the Point of Sale
account_default_pos_receivable_account_id = fields.Many2one('account.account', string="Default PoS Receivable Account")
# Accrual Accounting
expense_accrual_account_id = fields.Many2one('account.account', help="Account used to move the period of an expense", domain=[('internal_group', '=', 'liability'), ('reconcile', '=', True)])
revenue_accrual_account_id = fields.Many2one('account.account', help="Account used to move the period of a revenue", domain=[('internal_group', '=', 'asset'), ('reconcile', '=', True)])
accrual_default_journal_id = fields.Many2one('account.journal', help="Journal used by default for moving the period of an entry", domain="[('type', '=', 'general')]")
@api.constrains('account_opening_move_id', 'fiscalyear_last_day', 'fiscalyear_last_month')
def _check_fiscalyear_last_day(self):
# if the user explicitly chooses the 29th of February we allow it:
@@ -143,12 +139,19 @@ Best Regards,'''))
def get_and_update_account_dashboard_onboarding_state(self):
""" This method is called on the controller rendering method and ensures that the animations
are displayed only one time. """
return self.get_and_update_onbarding_state('account_dashboard_onboarding_state', [
return self.get_and_update_onbarding_state(
'account_dashboard_onboarding_state',
self.get_account_dashboard_onboarding_steps_states_names()
)
def get_account_dashboard_onboarding_steps_states_names(self):
""" Necessary to add/edit steps from other modules (account_winbooks_import in this case). """
return [
'base_onboarding_company_state',
'account_setup_bank_data_state',
'account_setup_fy_data_state',
'account_setup_coa_state',
])
]
def _check_lock_dates(self, vals):
'''Check the lock dates for the current companies. This can't be done in a api.constrains because we need
+2 -81
View File
@@ -2,7 +2,6 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import time
import psycopg2
import logging
from odoo import api, fields, models, _
@@ -10,8 +9,6 @@ from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.exceptions import ValidationError
from odoo.addons.base.models.res_partner import WARNING_MESSAGE, WARNING_HELP
_logger = logging.getLogger(__name__)
class AccountFiscalPosition(models.Model):
_name = 'account.fiscal.position'
_description = 'Fiscal Position'
@@ -330,21 +327,6 @@ class ResPartner(models.Model):
for partner in self:
partner.journal_item_count = AccountMoveLine.search_count([('partner_id', '=', partner.id)])
def get_followup_lines_domain(self, date, overdue_only=False, only_unblocked=False):
domain = [('reconciled', '=', False), ('account_id.deprecated', '=', False), ('account_id.internal_type', '=', 'receivable'), '|', ('debit', '!=', 0), ('credit', '!=', 0), ('company_id', '=', self.env.company.id)]
if only_unblocked:
domain += [('blocked', '=', False)]
if self.ids:
if 'exclude_given_ids' in self._context:
domain += [('partner_id', 'not in', self.ids)]
else:
domain += [('partner_id', 'in', self.ids)]
#adding the overdue lines
overdue_domain = ['|', '&', ('date_maturity', '!=', False), ('date_maturity', '<', date), '&', ('date_maturity', '=', False), ('date', '<', date)]
if overdue_only:
domain += overdue_domain
return domain
def _compute_has_unreconciled_entries(self):
for partner in self:
# Avoid useless work if has_unreconciled_entries is not relevant for this partner
@@ -439,8 +421,8 @@ class ResPartner(models.Model):
invoice_warn_msg = fields.Text('Message for Invoice')
# Computed fields to order the partners as suppliers/customers according to the
# amount of their generated incoming/outgoing account moves
supplier_rank = fields.Integer(compute='_compute_rank', store=True)
customer_rank = fields.Integer(compute='_compute_rank', store=True)
supplier_rank = fields.Integer(default=0)
customer_rank = fields.Integer(default=0)
def _get_name_search_order_by_fields(self):
res = super()._get_name_search_order_by_fields()
@@ -456,67 +438,6 @@ class ResPartner(models.Model):
order_by_field = order_by_field % field
return '%s, %s' % (res, order_by_field % field) if res else order_by_field
@api.depends('invoice_ids', 'invoice_ids.state')
def _compute_rank(self):
"""
The two field values may not be exact in the database!
To avoid any concurrent update failure while writing on the partner,
the count is not updated if the lock cannot be directly acquired.
The count will eventually be correctly computed, at the next successfull try.
"""
types_in = ('in_invoice', 'in_refund', 'in_receipt')
types_out = ('out_invoice', 'out_refund', 'out_receipt')
partner_ids = tuple(self.ids)
queries_params = {
'supplier_rank': {
'partner_id': partner_ids,
'move_types': types_in
},
'customer_rank': {
'partner_id': partner_ids,
'move_types': types_out
},
}
# Update database in case an invoice is just created
self.flush()
for field, params in queries_params.items():
try:
with self.env.cr.savepoint():
# Check if rows are not locked
# Take this opportunity to retrieve the current partner ranks
# If a customer has been created from the "Customer" menuitem
# his rank should be equal to 1, even if no invoice has been
# created for him yet
self.env.cr.execute("""
SELECT id, COALESCE({}, 0)
FROM res_partner
WHERE id IN %(partner_id)s
FOR UPDATE NOWAIT
""".format(field), params, log_exceptions=False)
current_counts = dict(self.env.cr.fetchall())
# Compute the real ranks, based on the posted
# account moves generated from the invoices
self.env.cr.execute("""
SELECT m.partner_id, COUNT(*) AS move_count
FROM account_move AS m
WHERE
type in %(move_types)s
AND state = 'posted'
AND partner_id IN %(partner_id)s
GROUP BY m.partner_id
""", params)
counts = dict(self.env.cr.fetchall())
# Update all ranks
for partner in self:
partner[field] = max(counts.get(partner.id, 0), current_counts.get(partner.id, 0))
except psycopg2.DatabaseError as e:
if e.pgcode == '55P03':
_logger.debug('Another transaction already locked partner rows. Cannot update partner ranks now.')
continue
else:
raise e
def _compute_bank_count(self):
bank_data = self.env['res.partner.bank'].read_group([('partner_id', 'in', self.ids)], ['partner_id'], ['partner_id'])
mapped_data = dict([(bank['partner_id'][0], bank['partner_id_count']) for bank in bank_data])
+4 -4
View File
@@ -9,11 +9,11 @@ class ProductCategory(models.Model):
property_account_income_categ_id = fields.Many2one('account.account', company_dependent=True,
string="Income Account",
domain=[('deprecated', '=', False)],
domain="['&', ('deprecated', '=', False), ('company_id', '=', current_company_id)]",
help="This account will be used when validating a customer invoice.")
property_account_expense_categ_id = fields.Many2one('account.account', company_dependent=True,
string="Expense Account",
domain=[('deprecated', '=', False)],
domain="['&', ('deprecated', '=', False), ('company_id', '=', current_company_id)]",
help="The expense is accounted for when a vendor bill is validated, except in anglo-saxon accounting with perpetual inventory valuation in which case the expense (Cost of Goods Sold account) is recognized at the customer invoice validation.")
#----------------------------------------------------------
@@ -28,11 +28,11 @@ class ProductTemplate(models.Model):
domain=[('type_tax_use', '=', 'purchase')], default=lambda self: self.env.company.account_purchase_tax_id)
property_account_income_id = fields.Many2one('account.account', company_dependent=True,
string="Income Account",
domain=[('deprecated', '=', False)],
domain="['&', ('deprecated', '=', False), ('company_id', '=', current_company_id)]",
help="Keep this field empty to use the default value from the product category.")
property_account_expense_id = fields.Many2one('account.account', company_dependent=True,
string="Expense Account",
domain=[('deprecated', '=', False)],
domain="['&', ('deprecated', '=', False), ('company_id', '=', current_company_id)]",
help="Keep this field empty to use the default value from the product category. If anglo-saxon accounting with automated valuation method is configured, the expense account on the product category will be used.")
def _get_product_accounts(self):
+90 -57
View File
@@ -3,7 +3,7 @@
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.osv import expression
from odoo.tools.misc import formatLang
from odoo.tools.misc import formatLang, format_date, parse_date
class AccountReconciliation(models.AbstractModel):
@@ -47,10 +47,10 @@ class AccountReconciliation(models.AbstractModel):
payment_aml_rec,
datum.get('new_aml_dicts', []))
processed_moves = (processed_moves | moves)
return {'moves': processed_moves}
return {'moves': processed_moves.ids, 'statement_line_ids': processed_moves.mapped('line_ids.statement_line_id').ids}
@api.model
def get_move_lines_for_bank_statement_line(self, st_line_id, partner_id=None, excluded_ids=None, search_str=False, offset=0, limit=None):
def get_move_lines_for_bank_statement_line(self, st_line_id, partner_id=None, excluded_ids=None, search_str=False, offset=0, limit=None, mode=None):
""" Returns move lines for the bank statement reconciliation widget,
formatted as a list of dicts
@@ -63,6 +63,7 @@ class AccountReconciliation(models.AbstractModel):
partner name, move line name)
:param offset: offset of the search result (to display pager)
:param limit: number of the result to search
:param mode: 'rp' for receivable/payable or 'other'
"""
st_line = self.env['account.bank.statement.line'].browse(st_line_id)
@@ -75,9 +76,33 @@ class AccountReconciliation(models.AbstractModel):
if partner_id is None:
partner_id = st_line.partner_id.id
domain = self._domain_move_lines_for_reconciliation(st_line, aml_accounts, partner_id, excluded_ids=excluded_ids, search_str=search_str)
domain = self._domain_move_lines_for_reconciliation(st_line, aml_accounts, partner_id, excluded_ids=excluded_ids, search_str=search_str, mode=mode)
recs_count = self.env['account.move.line'].search_count(domain)
aml_recs = self.env['account.move.line'].search(domain, offset=offset, limit=limit, order="date_maturity desc, id desc")
from_clause, where_clause, where_clause_params = self.env['account.move.line']._where_calc(domain).get_sql()
query_str = '''
SELECT "account_move_line".id FROM {from_clause}
{where_str}
ORDER BY ("account_move_line".debit - "account_move_line".credit) = {amount} DESC,
"account_move_line".date_maturity ASC,
"account_move_line".id ASC
{limit_str}
{offset_str}
'''.format(
from_clause=from_clause,
where_str=where_clause and (" WHERE %s" % where_clause) or '',
amount=st_line.amount,
limit_str=limit and ' LIMIT %s' or '',
offset_str=offset and ' OFFSET %s' or '',
)
params = where_clause_params + (limit and [limit] or []) + (offset and [offset] or [])
self.env['account.move'].flush()
self.env['account.move.line'].flush()
self.env['account.bank.statement'].flush()
self._cr.execute(query_str, params)
res = self._cr.fetchall()
aml_recs = self.env['account.move.line'].browse([i[0] for i in res])
target_currency = st_line.currency_id or st_line.journal_id.currency_id or st_line.journal_id.company_id.currency_id
return self._prepare_move_lines(aml_recs, target_currency=target_currency, target_date=st_line.date, recs_count=recs_count)
@@ -116,7 +141,8 @@ class AccountReconciliation(models.AbstractModel):
query += 'LEFT JOIN res_partner_bank bank ON bank.id = st_line.bank_account_id OR bank.acc_number = st_line.account_number %s\n' % (where_bank)
query += 'LEFT JOIN res_partner p1 ON st_line.partner_id=p1.id \n'
query += 'LEFT JOIN res_partner p2 ON bank.partner_id=p2.id \n'
query += 'LEFT JOIN res_partner p3 ON p3.name ILIKE st_line.partner_name %s\n' % (where_partner)
# By definition the commercial partner_id doesn't have a parent_id set
query += 'LEFT JOIN res_partner p3 ON p3.name ILIKE st_line.partner_name %s AND p3.parent_id is NULL \n' % (where_partner)
query += 'WHERE st_line.id IN %s'
params += [tuple(st_lines.ids)]
@@ -189,7 +215,7 @@ class AccountReconciliation(models.AbstractModel):
return results
@api.model
def get_bank_statement_data(self, bank_statement_line_ids, search_str=False):
def get_bank_statement_data(self, bank_statement_line_ids, srch_domain=[]):
""" Get statement lines of the specified statements or all unreconciled
statement lines and try to automatically reconcile them / find them
a partner.
@@ -203,12 +229,6 @@ class AccountReconciliation(models.AbstractModel):
suspense_moves_mode = self._context.get('suspense_moves_mode')
bank_statements = self.env['account.bank.statement.line'].browse(bank_statement_line_ids).mapped('statement_id')
search_sql = '''
AND (p.name ILIKE CONCAT('%%',%(search_str)s,'%%')
OR line.ref ILIKE CONCAT('%%',%(search_str)s,'%%')
OR line.name ILIKE CONCAT('%%',%(search_str)s,'%%')
OR CAST(line.amount AS TEXT) ILIKE CONCAT('%%',%(search_str)s,'%%'))
'''
query = '''
SELECT line.id
FROM account_bank_statement_line line
@@ -217,15 +237,14 @@ class AccountReconciliation(models.AbstractModel):
AND line.amount != 0.0
AND line.id IN %(ids)s
{cond}
{srch}
GROUP BY line.id
'''.format(
cond=not suspense_moves_mode and "AND NOT EXISTS (SELECT 1 from account_move_line aml WHERE aml.statement_line_id = line.id)" or "",
srch=search_str and search_sql or "",
)
self.env.cr.execute(query, {'ids':tuple(bank_statement_line_ids), 'search_str':search_str})
self.env.cr.execute(query, {'ids': tuple(bank_statement_line_ids)})
bank_statement_lines = self.env['account.bank.statement.line'].browse([line.get('id') for line in self.env.cr.dictfetchall()])
domain = [['id', 'in', [line.get('id') for line in self.env.cr.dictfetchall()]]] + srch_domain
bank_statement_lines = self.env['account.bank.statement.line'].search(domain)
results = self.get_bank_statement_line_data(bank_statement_lines.ids)
bank_statement_lines_left = self.env['account.bank.statement.line'].browse([line['st_line']['id'] for line in results['lines']])
@@ -330,10 +349,9 @@ class AccountReconciliation(models.AbstractModel):
aml_ids = self._context.get('active_ids') and self._context.get('active_model') == 'account.move.line' and tuple(self._context.get('active_ids'))
query = ("""
SELECT {0} account_id, account_name, account_code, max_date {10}
SELECT {select} account_id, account_name, account_code, max_date
FROM (
SELECT {1}
{11}
SELECT {inner_select}
a.id AS account_id,
a.name AS account_name,
a.code AS account_code,
@@ -342,50 +360,50 @@ class AccountReconciliation(models.AbstractModel):
account_move_line l
RIGHT JOIN account_account a ON (a.id = l.account_id)
RIGHT JOIN account_account_type at ON (at.id = a.user_type_id)
{2}
{inner_from}
WHERE
a.reconcile IS TRUE
AND l.full_reconcile_id is NULL
{3}
{4}
{5}
AND l.company_id = {6}
{where1}
{where2}
{where3}
AND l.company_id = {company_id}
AND EXISTS (
SELECT NULL
FROM account_move_line l
WHERE l.account_id = a.id
{7}
{inner_where}
AND l.amount_residual > 0
)
AND EXISTS (
SELECT NULL
FROM account_move_line l
WHERE l.account_id = a.id
{7}
{inner_where}
AND l.amount_residual < 0
)
{8}
GROUP BY {9} a.id, a.name, a.code {12}
{13}
{where4}
GROUP BY {group_by1} a.id, a.name, a.code {group_by2}
{order_by}
) as s
{14}
{outer_where}
""".format(
is_partner and 'partner_id, partner_name,' or ' ',
is_partner and 'p.id AS partner_id, p.name AS partner_name,' or ' ',
is_partner and 'RIGHT JOIN res_partner p ON (l.partner_id = p.id)' or ' ',
is_partner and ' ' or "AND at.type <> 'payable' AND at.type <> 'receivable'",
account_type and "AND at.type = %(account_type)s" or '',
res_ids and 'AND ' + res_alias + '.id in %(res_ids)s' or '',
self.env.company.id,
is_partner and 'AND l.partner_id = p.id' or ' ',
aml_ids and 'AND l.id IN %(aml_ids)s' or '',
is_partner and 'l.partner_id, p.id,' or ' ',
res_type == 'partner' and ", to_char(last_time_entries_checked, 'YYYY-MM-DD') AS last_time_entries_checked" or ' ',
res_type == 'partner' and 'p.last_time_entries_checked AS last_time_entries_checked,' or ' ',
res_type == 'partner' and ', p.last_time_entries_checked' or ' ',
res_type == 'partner' and 'ORDER BY p.last_time_entries_checked' or 'ORDER BY a.code',
res_type == 'partner' and 'WHERE (last_time_entries_checked IS NULL OR max_date > last_time_entries_checked)' or ' ',
select=is_partner and "partner_id, partner_name, to_char(last_time_entries_checked, 'YYYY-MM-DD') AS last_time_entries_checked," or ' ',
inner_select=is_partner and 'p.id AS partner_id, p.name AS partner_name, p.last_time_entries_checked AS last_time_entries_checked,' or ' ',
inner_from=is_partner and 'RIGHT JOIN res_partner p ON (l.partner_id = p.id)' or ' ',
where1=is_partner and ' ' or "AND ((at.type <> 'payable' AND at.type <> 'receivable') OR l.partner_id IS NULL)",
where2=account_type and "AND at.type = %(account_type)s" or '',
where3=res_ids and 'AND ' + res_alias + '.id in %(res_ids)s' or '',
company_id=self.env.company.id,
inner_where=is_partner and 'AND l.partner_id = p.id' or ' ',
where4=aml_ids and 'AND l.id IN %(aml_ids)s' or '',
group_by1=is_partner and 'l.partner_id, p.id,' or ' ',
group_by2=is_partner and ', p.last_time_entries_checked' or ' ',
order_by=is_partner and 'ORDER BY p.last_time_entries_checked' or 'ORDER BY a.code',
outer_where=is_partner and 'WHERE (last_time_entries_checked IS NULL OR max_date > last_time_entries_checked)' or ' ',
))
self.env['account.move.line'].flush()
self.env['account.account'].flush()
self.env.cr.execute(query, locals())
# Apply ir_rules by filtering out
@@ -449,7 +467,7 @@ class AccountReconciliation(models.AbstractModel):
'|', ('account_id.code', 'ilike', search_str),
'|', ('move_id.name', 'ilike', search_str),
'|', ('move_id.ref', 'ilike', search_str),
'|', ('date_maturity', 'like', search_str),
'|', ('date_maturity', 'like', parse_date(self.env, search_str)),
'&', ('name', '!=', '/'), ('name', 'ilike', search_str)
]
@@ -492,13 +510,14 @@ class AccountReconciliation(models.AbstractModel):
return str_domain
@api.model
def _domain_move_lines_for_reconciliation(self, st_line, aml_accounts, partner_id, excluded_ids=[], search_str=False):
def _domain_move_lines_for_reconciliation(self, st_line, aml_accounts, partner_id, excluded_ids=[], search_str=False, mode='rp'):
""" Return the domain for account.move.line records which can be used for bank statement reconciliation.
:param aml_accounts:
:param partner_id:
:param excluded_ids:
:param search_str:
:param mode: 'rp' for receivable/payable or 'other'
"""
AccountMoveLine = self.env['account.move.line']
@@ -520,17 +539,30 @@ class AccountReconciliation(models.AbstractModel):
])
domain = expression.OR([domain_reconciliation, domain_matching])
partner_domain = []
if partner_id:
domain = expression.AND([domain, [('partner_id', '=', partner_id)]])
partner_domain = [('partner_id', '=', partner_id)]
domain = expression.AND([domain, partner_domain])
if mode == 'rp':
domain = expression.AND([domain,
[('account_id.internal_type', 'in', ['receivable', 'payable', 'liquidity'])]
])
else:
domain = expression.AND([domain,
[('account_id.internal_type', 'not in', ['receivable', 'payable', 'liquidity'])]
])
# Domain factorized for all reconciliation use cases
if search_str:
str_domain = self._domain_move_lines(search_str=search_str)
if not partner_id:
str_domain = expression.OR([
str_domain,
[('partner_id.name', 'ilike', search_str)]
])
partner_domain = [('partner_id.name', 'ilike', search_str)]
str_domain = expression.OR([
str_domain,
partner_domain,
])
domain = expression.AND([
domain,
str_domain
@@ -543,6 +575,7 @@ class AccountReconciliation(models.AbstractModel):
])
# filter on account.move.line having the same company as the statement line
domain = expression.AND([domain, [('company_id', '=', st_line.company_id.id)]])
domain = expression.AND([domain, [('move_id.state', '!=', 'draft')]])
if st_line.company_id.account_bank_reconciliation_start:
domain = expression.AND([domain, [('date', '>=', st_line.company_id.account_bank_reconciliation_start)]])
@@ -581,7 +614,7 @@ class AccountReconciliation(models.AbstractModel):
line_currency = (line.currency_id and line.amount_currency) and line.currency_id or company_currency
ret_line = {
'id': line.id,
'name': line.name and line.name != '/' and line.move_id.name + ': ' + line.name or line.move_id.name,
'name': line.name and line.name != '/' and line.move_id.name != line.name and line.move_id.name + ': ' + line.name or line.move_id.name,
'ref': line.move_id.ref or '',
# For reconciliation between statement transactions and already registered payments (eg. checks)
# NB : we don't use the 'reconciled' field because the line we're selecting is not the one that gets reconciled
@@ -590,8 +623,8 @@ class AccountReconciliation(models.AbstractModel):
'account_code': line.account_id.code,
'account_name': line.account_id.name,
'account_type': line.account_id.internal_type,
'date_maturity': line.date_maturity,
'date': line.date,
'date_maturity': format_date(self.env, line.date_maturity),
'date': format_date(self.env, line.date),
'journal_id': [line.journal_id.id, line.journal_id.display_name],
'partner_id': line.partner_id.id,
'partner_name': line.partner_id.name,
@@ -686,7 +719,7 @@ class AccountReconciliation(models.AbstractModel):
'ref': st_line.ref,
'note': st_line.note or "",
'name': st_line.name,
'date': st_line.date,
'date': format_date(self.env, st_line.date),
'amount': amount,
'amount_str': amount_str, # Amount in the statement line currency
'currency_id': st_line.currency_id.id or statement_currency.id,
+2 -4
View File
@@ -17,7 +17,7 @@ class ResConfigSettings(models.TransientModel):
domain="[('company_id', '=', company_id), ('type', '=', 'general')]",
help='The accounting journal where automatic exchange differences will be registered')
has_chart_of_accounts = fields.Boolean(compute='_compute_has_chart_of_accounts', string='Company has a chart of accounts')
chart_template_id = fields.Many2one('account.chart.template', string='Template',
chart_template_id = fields.Many2one('account.chart.template', string='Template', default=lambda self: self.env.company.chart_template_id,
domain="[('visible','=', True)]")
sale_tax_id = fields.Many2one('account.tax', string="Default Sale Tax", related='company_id.account_sale_tax_id', readonly=False)
purchase_tax_id = fields.Many2one('account.tax', string="Default Purchase Tax", related='company_id.account_purchase_tax_id', readonly=False)
@@ -51,7 +51,6 @@ class ResConfigSettings(models.TransientModel):
module_account_budget = fields.Boolean(string='Budget Management')
module_account_payment = fields.Boolean(string='Invoice Online Payment')
module_account_reports = fields.Boolean("Dynamic Reports")
module_account_reports_followup = fields.Boolean("Follow-up Levels")
module_account_check_printing = fields.Boolean("Allow check printing and deposits")
module_account_batch_payment = fields.Boolean(string='Use batch payments',
help='This allows you grouping payments into a single batch and eases the reconciliation process.\n'
@@ -92,14 +91,13 @@ class ResConfigSettings(models.TransientModel):
super(ResConfigSettings, self).set_values()
if self.group_multi_currency:
self.env.ref('base.group_user').write({'implied_ids': [(4, self.env.ref('product.group_sale_pricelist').id)]})
""" install a chart of accounts for the given company (if required) """
# install a chart of accounts for the given company (if required)
if self.chart_template_id and self.chart_template_id != self.company_id.chart_template_id:
self.chart_template_id._load(15.0, 15.0, self.env.company)
@api.depends('company_id')
def _compute_has_chart_of_accounts(self):
self.has_chart_of_accounts = bool(self.company_id.chart_template_id)
self.chart_template_id = self.company_id.chart_template_id or False
self.has_accounting_entries = self.env['account.chart.template'].existing_accounting(self.company_id)
@api.onchange('show_line_subtotals_tax_selection')
@@ -7,7 +7,6 @@ from odoo.tools import float_is_zero
from datetime import datetime
from dateutil.relativedelta import relativedelta
class ReportAgedPartnerBalance(models.AbstractModel):
_name = 'report.account.report_agedpartnerbalance'
@@ -70,9 +69,13 @@ class ReportAgedPartnerBalance(models.AbstractModel):
partner_ids = self.env['res.partner'].search([('category_id', 'in', ctx['partner_categories'].ids)]).ids
arg_list += (tuple(partner_ids or [0]),)
arg_list += (date_from, tuple(company_ids))
query = '''
SELECT DISTINCT l.partner_id, UPPER(res_partner.name)
FROM account_move_line AS l left join res_partner on l.partner_id = res_partner.id, account_account, account_move am
SELECT DISTINCT l.partner_id, res_partner.name AS name, UPPER(res_partner.name) AS UPNAME, CASE WHEN prop.value_text IS NULL THEN 'normal' ELSE prop.value_text END AS trust
FROM account_move_line AS l
LEFT JOIN res_partner ON l.partner_id = res_partner.id
LEFT JOIN ir_property prop ON (prop.res_id = 'res.partner,'||res_partner.id AND prop.name='trust' AND prop.company_id=%s),
account_account, account_move am
WHERE (l.account_id = account_account.id)
AND (l.move_id = am.id)
AND (am.state IN %s)
@@ -81,6 +84,7 @@ class ReportAgedPartnerBalance(models.AbstractModel):
AND (l.date <= %s)
AND l.company_id IN %s
ORDER BY UPPER(res_partner.name)'''
arg_list = (self.env.company.id,) + arg_list
cr.execute(query, arg_list)
partners = cr.dictfetchall()
@@ -211,21 +215,18 @@ class ReportAgedPartnerBalance(models.AbstractModel):
if not float_is_zero(values[str(i)], precision_rounding=self.env.company.currency_id.rounding):
at_least_one_amount = True
values['total'] = sum([values['direction']] + [values[str(i)] for i in range(5)])
## Add for total
# Add for total
total[(i + 1)] += values['total']
values['partner_id'] = partner['partner_id']
if partner['partner_id']:
#browse the partner name and trust field in sudo, as we may not have full access to the record (but we still have to see it in the report)
browsed_partner = self.env['res.partner'].sudo().browse(partner['partner_id'])
values['name'] = browsed_partner.name and len(browsed_partner.name) >= 45 and browsed_partner.name[0:40] + '...' or browsed_partner.name
values['trust'] = browsed_partner.trust
values['name'] = len(partner['name']) >= 45 and partner['name'][0:40] + '...' or partner['name']
values['trust'] = partner['trust']
else:
values['name'] = _('Unknown Partner')
values['trust'] = False
if at_least_one_amount or (self._context.get('include_nullified_amount') and lines[partner['partner_id']]):
res.append(values)
return res, total, lines
@api.model
@@ -87,7 +87,6 @@
<filter string="Partner" name="partner_id" context="{'group_by':'partner_id','residual_visible':True}"/>
<filter string="Product Category" name="category_product" context="{'group_by':'product_categ_id','residual_invisible':True}"/>
<filter string="Status" name="status" context="{'group_by':'state'}"/>
<filter string="Analytic Account" name="analytic_account_id" context="{'group_by':'analytic_account_id'}" groups="analytic.group_analytic_accounting" />
<filter string="Company" name="company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
<separator orientation="vertical" />
<filter string="Date" name="invoice_date" context="{'group_by':'invoice_date'}"/>
@@ -97,6 +96,18 @@
</field>
</record>
<record id="view_account_invoice_report_search_analytic_accounting" model="ir.ui.view">
<field name="name">account.invoice.report.search_analytic_accounting</field>
<field name="model">account.invoice.report</field>
<field name="inherit_id" ref="account.view_account_invoice_report_search"/>
<field name="groups_id" eval="[(4, ref('analytic.group_analytic_accounting'))]"/>
<field name="arch" type="xml">
<filter name="status" position="after">
<filter string="Analytic Account" name="analytic_account_id" context="{'group_by':'analytic_account_id'}"/>
</filter>
</field>
</record>
<record id="action_account_invoice_report_all_supp" model="ir.actions.act_window">
<field name="name">Invoices Analysis</field>
<field name="res_model">account.invoice.report</field>
@@ -13,6 +13,8 @@ access_account_account_user,account.account user,model_account_account,base.grou
access_account_account_partner_manager,account.account partner manager,model_account_account,base.group_partner_manager,1,0,0,0
access_account_group_manager,account.group,model_account_group,account.group_account_manager,1,1,1,1
access_account_group,account.group,model_account_group,account.group_account_user,1,0,0,0
access_account_root_manager,account.root,model_account_root,account.group_account_manager,1,0,0,0
access_account_root,account.root,model_account_root,account.group_account_user,1,0,0,0
access_account_tax,account.tax,model_account_tax,account.group_account_invoice,1,0,0,0
access_account_account_template,account.account.template,model_account_account_template,account.group_account_manager,1,1,1,1
access_account_chart_template,account.chart.template,model_account_chart_template,account.group_account_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
13 access_account_account_partner_manager account.account partner manager model_account_account base.group_partner_manager 1 0 0 0
14 access_account_group_manager account.group model_account_group account.group_account_manager 1 1 1 1
15 access_account_group account.group model_account_group account.group_account_user 1 0 0 0
16 access_account_root_manager account.root model_account_root account.group_account_manager 1 0 0 0
17 access_account_root account.root model_account_root account.group_account_user 1 0 0 0
18 access_account_tax account.tax model_account_tax account.group_account_invoice 1 0 0 0
19 access_account_account_template account.account.template model_account_account_template account.group_account_manager 1 1 1 1
20 access_account_chart_template account.chart.template model_account_chart_template account.group_account_manager 1 1 1 1
@@ -66,6 +66,7 @@ var ShowPaymentLineWidget = AbstractField.extend({
currency: content.currency,
position: content.position,
payment_id: content.payment_id,
payment_method_name: content.payment_method_name,
move_id: content.move_id,
ref: content.ref,
account_payment_id: content.account_payment_id,
@@ -0,0 +1,72 @@
odoo.define('account.hierarchy.selection', function (require) {
"use strict";
var core = require('web.core');
var relational_fields = require('web.relational_fields');
var _t = core._t;
var registry = require('web.field_registry');
var FieldSelection = relational_fields.FieldSelection;
var qweb = core.qweb;
var HierarchySelection = FieldSelection.extend({
_renderEdit: function () {
var self = this;
var prom = Promise.resolve()
if (!self.hierarchy_groups) {
prom = this._rpc({
model: 'account.account.type',
method: 'read',
args: [
_.filter(_.map(this.values, v => v[0]), v => typeof v == 'number'),
['internal_group'],
],
}).then(function(arg) {
self.hierarchy_groups = [
{
'name': _('Balance Sheet'),
'children': [
{'name': _t('Assets'), 'ids': _.map(_.filter(arg, v => v['internal_group'] == 'asset'), v => v['id'])},
{'name': _t('Liabilities'), 'ids': _.map(_.filter(arg, v => v['internal_group'] == 'liability' || v['internal_group'] == 'equity'), v => v['id'])},
]
},
{'name': _t('Profit & Loss'), 'ids': _.map(_.filter(arg, v => v['internal_group'] == 'income' || v['internal_group'] == 'expense'), v => v['id'])},
{'name': _t('Other'), 'ids': _.map(_.filter(arg, v => !['asset', 'liability', 'equity', 'income', 'expense'].includes(v['internal_group'])), v => v['id'])},
]
});
}
Promise.resolve(prom).then(function() {
self.$el.empty();
self._addHierarchy(self.$el, self.hierarchy_groups, 0);
var value = self.value;
if (self.field.type === 'many2one' && value) {
value = value.data.id;
}
self.$el.val(JSON.stringify(value));
});
},
_addHierarchy: function(el, group, level) {
var self = this;
_.each(group, function(item) {
var optgroup = $('<optgroup/>').attr(({
'label': $('<div/>').html('&nbsp;&nbsp;'.repeat(3 * level) + item['name']).text(),
}))
_.each(item['ids'], function(id) {
var value = _.find(self.values, v => v[0] == id)
optgroup.append($('<option/>', {
value: JSON.stringify(value[0]),
text: value[1],
}));
})
el.append(optgroup)
if (item['children']) {
self._addHierarchy(el, item['children'], level + 1);
}
})
}
});
registry.add("account_hierarchy_selection", HierarchySelection);
});
@@ -99,6 +99,22 @@ odoo.define('account.dashboard.kanban', function (require) {
'click .o_button_upload_bill': '_onUpload',
'change .o_vendor_bill_upload .o_form_binary_form': '_onAddAttachment',
}),
/**
* We override _onUpload (from the upload bill mixin) to pass default_journal_id
* and default_type in context.
*
* @override
*/
_onUpload: function (event) {
var kanbanRecord = $(event.currentTarget).closest('.o_kanban_record').data('record');
this.initialState.context['default_journal_id'] = kanbanRecord.id;
if ($(event.currentTarget).attr('journal_type') == 'sale') {
this.initialState.context['default_type'] = 'out_invoice'
} else if ($(event.currentTarget).attr('journal_type') == 'purchase') {
this.initialState.context['default_type'] = 'in_invoice'
}
UploadBillMixin._onUpload.apply(this, arguments);
}
});
var DashboardKanbanView = KanbanView.extend({
@@ -5,6 +5,7 @@ var AbstractAction = require('web.AbstractAction');
var ReconciliationModel = require('account.ReconciliationModel');
var ReconciliationRenderer = require('account.ReconciliationRenderer');
var core = require('web.core');
var QWeb = core.qweb;
/**
@@ -12,6 +13,8 @@ var core = require('web.core');
*/
var StatementAction = AbstractAction.extend({
hasControlPanel: true,
withSearchBar: true,
loadControlPanel: true,
title: core._t('Bank Reconciliation'),
contentTemplate: 'reconciliation',
custom_events: {
@@ -27,13 +30,11 @@ var StatementAction = AbstractAction.extend({
quick_create_proposition: '_onAction',
partial_reconcile: '_onAction',
validate: '_onValidate',
change_name: '_onChangeName',
close_statement: '_onCloseStatement',
load_more: '_onLoadMore',
reload: 'reload',
},
events: {
'change .reconciliation_search_input': '_onSearch',
search: '_onSearch',
navigation_move:'_onNavigationMove',
},
config: _.extend({}, AbstractAction.prototype.config, {
// used to instantiate the model
@@ -50,6 +51,25 @@ var StatementAction = AbstractAction.extend({
limitMoveLines: 15,
}),
_onNavigationMove: function (ev) {
var non_reconciled_keys = _.keys(_.pick(this.model.lines, function(value, key, object) {return !value.reconciled}));
var currentIndex = _.indexOf(non_reconciled_keys, ev.data.handle);
var widget = false;
switch (ev.data.direction) {
case 'up':
case 'previous':
ev.stopPropagation();
widget = this._getWidget(non_reconciled_keys[currentIndex-1]);
break;
case 'down':
case 'next':
ev.stopPropagation();
widget = this._getWidget(non_reconciled_keys[currentIndex+1]);
break;
}
if (widget) widget.$el.focus();
},
/**
* @override
* @param {Object} params
@@ -60,6 +80,7 @@ var StatementAction = AbstractAction.extend({
this._super.apply(this, arguments);
this.action_manager = parent;
this.params = params;
this.controlPanelParams.modelName = 'account.bank.statement.line';
this.model = new this.config.Model(this, {
modelName: "account.reconciliation.widget",
defaultDisplayQty: params.params && params.params.defaultDisplayQty || this.config.defaultDisplayQty,
@@ -88,31 +109,71 @@ var StatementAction = AbstractAction.extend({
var self = this;
var def = this.model.load(this.params.context).then(this._super.bind(this));
return def.then(function () {
var title = self.model.bank_statement_id && self.model.bank_statement_id.display_name;
self._setTitle(title);
self.renderer = new self.config.ActionRenderer(self, self.model, {
'bank_statement_id': self.model.bank_statement_id,
'valuenow': self.model.valuenow,
'valuemax': self.model.valuemax,
'defaultDisplayQty': self.model.defaultDisplayQty,
'title': title,
});
if (!self.model.context || !self.model.context.active_id) {
self.model.context = {'active_id': self.params.context.active_id};
}
if (self.params.context.journal_id) {
self.model.context.active_id = self.params.context.journal_id;
}
if (self.model.context.active_id) {
var promise = self._rpc({
model: 'account.journal',
method: 'read',
args: [self.model.context.active_id, ['display_name']],
});
} else {
var promise = Promise.resolve();
}
return promise.then(function (result) {
var title = result && result[0] ? result[0]['display_name'] : self.params.display_name || ''
self._setTitle(title);
self.renderer = new self.config.ActionRenderer(self, self.model, {
'bank_statement_line_id': self.model.bank_statement_line_id,
'valuenow': self.model.valuenow,
'valuemax': self.model.valuemax,
'defaultDisplayQty': self.model.defaultDisplayQty,
'title': title,
});
});
});
},
reload: function() {
// On reload destroy all rendered line widget, reload data and then rerender widget
var self = this;
self.$('.o_reconciliation_lines').addClass('d-none'); // prevent the browser from recomputing css after each destroy for HUGE perf improvement on a lot of lines
_.each(this.widgets, function(widget) {
widget.destroy();
});
this.widgets = [];
this.model.reload()
.then(function() {
self.$('.o_reconciliation_lines').html('');
self._renderLines();
self.$('.o_reconciliation_lines').removeClass('d-none');
return this.model.reload().then(function() {
return self._renderLinesOrRainbow();
});
},
_renderLinesOrRainbow: function() {
var self = this;
return self._renderLines().then(function() {
var initialState = self.renderer._initialState;
var valuenow = self.model.statement ? self.model.statement.value_min : initialState.valuenow;
var valuemax = self.model.statement ? self.model.statement.value_max : initialState.valuemax;
// No more lines to reconcile, trigger the rainbowman.
if(valuenow === valuemax){
initialState.valuenow = valuenow;
initialState.context = self.model.getContext();
self.renderer.showRainbowMan(initialState);
self.remove_cp();
}else{
// Create a notification if some lines have been reconciled automatically.
if(initialState.valuenow > 0)
self.renderer._renderNotifications(self.model.statement.notifications);
self._openFirstLine();
});
self.renderer.$('[data-toggle="tooltip"]').tooltip();
self.do_show();
}
});
},
/**
@@ -126,19 +187,8 @@ var StatementAction = AbstractAction.extend({
var sup = this._super;
return this.renderer.prependTo(self.$('.o_form_sheet')).then(function() {
return self._renderLines().then(function() {
// No more lines to reconcile, trigger the rainbowman.
var initialState = self.renderer._initialState;
if(initialState.valuenow === initialState.valuemax){
initialState.context = self.model.getContext();
self.renderer.showRainbowMan(initialState);
}else{
// Create a notification if some lines has been reconciled automatically.
if(initialState.valuenow > 0)
self.renderer._renderNotifications(self.model.statement.notifications);
self._openFirstLine();
}
return self._renderLinesOrRainbow().then(function() {
self.do_show();
return sup.apply(self, args);
});
});
@@ -152,14 +202,24 @@ var StatementAction = AbstractAction.extend({
do_show: function () {
this._super.apply(this, arguments);
if (this.action_manager) {
this.updateControlPanel({clear: true});
this.action_manager.do_push_state({
action: this.params.tag,
active_id: this.params.res_id,
this.$pager = $(QWeb.render('reconciliation.control.pager', {widget: this.renderer}));
this.updateControlPanel({
clear: true,
cp_content: {
$pager: this.$pager,
},
});
this.renderer.$progress = this.$pager;
$(this.renderer.$progress).parent().css('width', '100%').css('padding-left', '0');
}
},
remove_cp: function() {
this.updateControlPanel({
clear: true,
});
},
//--------------------------------------------------------------------------
// Private
//--------------------------------------------------------------------------
@@ -195,7 +255,7 @@ var StatementAction = AbstractAction.extend({
}))[0];
if (handle) {
var line = this.model.getLine(handle);
this.model.changeMode(handle, 'match').then(function () {
this.model.changeMode(handle, 'default').then(function () {
self._getWidget(handle).update(line);
}).guardedCatch(function(){
self._getWidget(handle).update(line);
@@ -203,6 +263,17 @@ var StatementAction = AbstractAction.extend({
}
return handle;
},
_forceUpdate: function() {
var self = this;
_.each(this.model.lines, function(handle) {
var widget = self._getWidget(handle['handle']);
if (widget && handle.need_update) {
widget.update(handle);
widget.need_update = false;
}
})
},
/**
* render line widget and append to view
*
@@ -234,7 +305,8 @@ var StatementAction = AbstractAction.extend({
/**
* dispatch on the camelcased event name to model method then update the
* line renderer with the new state. If the mode was switched from 'inactive'
* to 'create' or 'match', the other lines switch to 'inactive' mode
* to 'create' or 'match_rp' or 'match_other', the other lines switch to
* 'inactive' mode
*
* @private
* @param {OdooEvent} event
@@ -242,11 +314,13 @@ var StatementAction = AbstractAction.extend({
_onAction: function (event) {
var self = this;
var handle = event.target.handle;
var line = this.model.getLine(handle);
var mode = line.mode;
var current_line = this.model.getLine(handle);
this.model[_.str.camelize(event.name)](handle, event.data.data).then(function () {
self._getWidget(handle).update(line);
if (mode === 'inactive' && line.mode !== 'inactive') {
var widget = self._getWidget(handle);
if (widget) {
widget.update(current_line);
}
if (current_line.mode !== 'inactive') {
_.each(self.model.lines, function (line, _handle) {
if (line.mode !== 'inactive' && _handle !== handle) {
self.model.changeMode(_handle, 'inactive');
@@ -267,7 +341,14 @@ var StatementAction = AbstractAction.extend({
_onSearch: function (ev) {
var self = this;
ev.stopPropagation();
this.reload();
this.model.domain = ev.data.domain;
this.model.display_context = 'search';
self.reload().then(function() {
self.renderer._updateProgressBar({
'valuenow': self.model.valuenow,
'valuemax': self.model.valuemax,
});
});
},
_onActionPartialAmount: function(event) {
@@ -278,25 +359,6 @@ var StatementAction = AbstractAction.extend({
self._getWidget(handle).updatePartialAmount(event.data.data, amount);
},
/**
* call 'changeName' model method
*
* @private
* @param {OdooEvent} event
*/
_onChangeName: function (event) {
var self = this;
var title = event.data.data;
this.model.changeName(title).then(function () {
self.title = title;
self.set("title", title);
self.renderer.update({
'valuenow': self.model.valuenow,
'valuemax': self.model.valuemax,
'title': title,
});
});
},
/**
* call 'closeStatement' model method
*
@@ -314,6 +376,7 @@ var StatementAction = AbstractAction.extend({
type: 'ir.actions.act_window',
view_mode: 'form',
});
$('.o_reward').remove();
});
},
/**
@@ -344,6 +407,7 @@ var StatementAction = AbstractAction.extend({
'notifications': result.notifications,
'context': self.model.getContext(),
});
self._forceUpdate();
_.each(result.handles, function (handle) {
var widget = self._getWidget(handle);
if (widget) {
@@ -370,6 +434,7 @@ var StatementAction = AbstractAction.extend({
*/
var ManualAction = StatementAction.extend({
title: core._t('Journal Items to Reconcile'),
withSearchBar: false,
config: _.extend({}, StatementAction.prototype.config, {
Model: ReconciliationModel.ManualModel,
ActionRenderer: ReconciliationRenderer.ManualRenderer,
@@ -19,7 +19,7 @@ var _t = core._t;
* {
* valuenow: integer
* valuenow: valuemax
* [bank_statement_id]: {
* [bank_statement_line_id]: {
* id: integer
* display_name: string
* }
@@ -40,7 +40,7 @@ var _t = core._t;
* partner_id: integer
* partner_name: string
* }
* mode: string ('inactive', 'match', 'create')
* mode: string ('inactive', 'match_rp', 'match_other', 'create')
* reconciliation_proposition: {
* id: number|string
* partial_amount: number
@@ -65,7 +65,8 @@ var _t = core._t;
* [to_check]: boolean
* [amount_currency_str]: string|false (amount in record currency)
* }
* mv_lines: object - idem than reconciliation_proposition
* mv_lines_match_rp: object - idem than reconciliation_proposition
* mv_lines_match_other: object - idem than reconciliation_proposition
* offset: integer
* limitMoveLines: integer
* filter: string
@@ -97,6 +98,9 @@ var StatementModel = BasicModel.extend({
avoidCreate: false,
quickCreateFields: ['account_id', 'amount', 'analytic_account_id', 'label', 'tax_ids', 'force_tax_included', 'analytic_tag_ids', 'to_check'],
// overridden in ManualModel
modes: ['create', 'match_rp', 'match_other'],
/**
* @override
*
@@ -110,8 +114,10 @@ var StatementModel = BasicModel.extend({
this.valuenow = 0;
this.valuemax = 0;
this.alreadyDisplayed = [];
this.domain = [];
this.defaultDisplayQty = options && options.defaultDisplayQty || 10;
this.limitMoveLines = options && options.limitMoveLines || 15;
this.display_context = 'init';
},
//--------------------------------------------------------------------------
@@ -130,20 +136,23 @@ var StatementModel = BasicModel.extend({
addProposition: function (handle, mv_line_id) {
var self = this;
var line = this.getLine(handle);
var prop = _.clone(_.find(line.mv_lines, {'id': mv_line_id}));
var prop = _.clone(_.find(line['mv_lines_'+line.mode], {'id': mv_line_id}));
this._addProposition(line, prop);
line.limit_override = (line.offset + 1) * this.limitMoveLines;
line.limit_override = (line.offset + 1) + this.limitMoveLines;
// remove all non valid lines
line.reconciliation_proposition = _.filter(line.reconciliation_proposition, function (prop) {return !prop.invalid;});
// Onchange the partner if not already set on the statement line.
if(!line.st_line.partner_id && line.reconciliation_proposition
&& line.reconciliation_proposition.length == 1 && prop.partner_id && line.type === undefined){
return this.changePartner(handle, {'id': prop.partner_id, 'display_name': prop.partner_name}, true)
.then(function () {
return Promise.all([self._computeLine(line), self._performMoveLine(handle)]);
return Promise.all([self._computeLine(line), self._performMoveLine(handle, 'match_rp'), self._performMoveLine(handle, 'match_other')]);
});
}
return Promise.all([this._computeLine(line), this._performMoveLine(handle)]);
return Promise.all([this._computeLine(line), this._performMoveLine(handle, 'match_rp'), self._performMoveLine(handle, 'match_other')]);
},
/**
* change the filter for the target line and fetch the new matched lines
@@ -154,56 +163,54 @@ var StatementModel = BasicModel.extend({
*/
changeFilter: function (handle, filter) {
var line = this.getLine(handle);
line.filter = filter;
line['filter_'+line.mode] = filter;
line.offset = 0;
return this._performMoveLine(handle);
return this._performMoveLine(handle, line.mode);
},
/**
* change the mode line ('inactive', 'match', 'create'), and fetch the new
* matched lines or prepare to create a new line
* change the mode line ('inactive', 'match_rp', 'match_other', 'create'),
* and fetch the new matched lines or prepare to create a new line
*
* ``match``
* display the matched lines, the user can select the lines to apply
* ``match_rp``
* display the matched lines from receivable/payable accounts, the user
* can select the lines to apply there as proposition
* ``match_other``
* display the other matched lines, the user can select the lines to apply
* there as proposition
* ``create``
* display fields and quick create button to create a new proposition
* for the reconciliation
*
* @param {string} handle
* @param {'inactive' | 'match' | 'create'} mode
* @param {'inactive' | 'match_rp' | 'create'} mode
* @returns {Promise}
*/
changeMode: function (handle, mode) {
var self = this;
var line = this.getLine(handle);
if (line.mode === 'create') {
this._blurProposition(handle);
line.createForm = null;
if (mode === 'default') {
var match_requests = self.modes.filter(x => x.startsWith('match')).map(x => this._performMoveLine(handle, x))
return Promise.all(match_requests).then(function() {
return self.changeMode(handle, self._getDefaultMode(handle));
});
}
if (mode === 'create' && this.avoidCreate) {
mode = 'match';
if (mode === 'next') {
var available_modes = self._getAvailableModes(handle)
mode = available_modes[(available_modes.indexOf(line.mode) + 1) % available_modes.length];
}
line.mode = mode;
if (mode === 'match') {
return this._performMoveLine(handle);
if (['match_rp', 'match_other'].includes(line.mode)) {
if (!(line['mv_lines_' + line.mode] && line['mv_lines_' + line.mode].length)) {
return this._performMoveLine(handle, line.mode);
} else {
return this._formatMoveLine(handle, line.mode, line['mv_lines_' + line.mode]);
}
}
if (line.mode === 'create') {
return this.createProposition(handle);
}
return Promise.resolve();
},
/**
* call 'write' method on the 'account.bank.statement'
*
* @param {string} name
* @returns {Promise}
*/
changeName: function (name) {
return this._rpc({
model: 'account.bank.statement',
method: 'write',
args: [this.bank_statement_id.id, {name: name}],
});
},
/**
* change the offset for the matched lines, and fetch the new matched lines
*
@@ -212,8 +219,9 @@ var StatementModel = BasicModel.extend({
* @returns {Promise}
*/
changeOffset: function (handle, offset) {
this.getLine(handle).offset += (offset > 0 ? 1 : -1) * this.limitMoveLines;
return this._performMoveLine(handle);
var line = this.getLine(handle);
line.offset += (offset > 0 ? 1 : -1) * this.limitMoveLines;
return this._performMoveLine(handle, line.mode);
},
/**
* change the partner on the line and fetch the new matched lines
@@ -243,13 +251,8 @@ var StatementModel = BasicModel.extend({
return self._computeLine(line);
})
.then(function () {
if (!preserveMode)
return self.changeMode(handle, 'match');
return false;
return self.changeMode(handle, preserveMode ? line.mode : 'default', true);
})
.then(function () {
return line.mode === 'create' ? self.createProposition(handle) : false;
});
},
/**
@@ -259,12 +262,12 @@ var StatementModel = BasicModel.extend({
closeStatement: function () {
var self = this;
return this._rpc({
model: 'account.bank.statement',
model: 'account.bank.statement.line',
method: 'button_confirm_bank',
args: [self.bank_statement_id.id],
args: [self.bank_statement_line_id.id],
})
.then(function () {
return self.bank_statement_id.id;
return self.bank_statement_line_id.id;
});
},
/**
@@ -277,10 +280,6 @@ var StatementModel = BasicModel.extend({
createProposition: function (handle) {
var line = this.getLine(handle);
var prop = _.filter(line.reconciliation_proposition, '__focus');
var last = prop[prop.length-1];
if (last && !this._isValid(last)) {
return Promise.resolve(false);
}
prop = this._formatQuickCreate(line);
line.reconciliation_proposition.push(prop);
line.createForm = _.pick(prop, this.quickCreateFields);
@@ -310,6 +309,7 @@ var StatementModel = BasicModel.extend({
},
/**
* Return a boolean telling if load button needs to be displayed or not
* overridden in ManualModel
*
* @returns {boolean} true if load more button needs to be displayed
*/
@@ -337,18 +337,29 @@ var StatementModel = BasicModel.extend({
* - 'account.account' fetch all account code
* - 'account.reconciliation.widget' fetch each line data
*
* overridden in ManualModel
* @param {Object} context
* @param {number[]} context.statement_line_ids
* @returns {Promise}
*/
load: function (context) {
var self = this;
this.statement_line_ids = context.statement_line_ids;
if (!this.statement_line_ids) {
return Promise.resolve();
}
this.context = context;
return self.reload();
this.statement_line_ids = context.statement_line_ids;
if (this.statement_line_ids === undefined) {
// This could be undefined if the user pressed F5, take everything as fallback instead of rainbowman
return self._rpc({
model: 'account.bank.statement.line',
method: 'search_read',
fields: ['id'],
domain: [['journal_id', '=?', context.active_id]],
}).then(function (result) {
self.statement_line_ids = result.map(r => r.id);
return self.reload()
})
} else {
return self.reload();
}
},
/**
@@ -368,6 +379,7 @@ var StatementModel = BasicModel.extend({
},
/**
* RPC method to load informations on lines
* overridden in ManualModel
*
* @param {Array} ids ids of bank statement line passed to rpc call
* @param {Array} excluded_ids list of move_line ids that needs to be excluded from search
@@ -391,17 +403,15 @@ var StatementModel = BasicModel.extend({
self.alreadyDisplayed = [];
self.lines = {};
self.pagerIndex = 0;
// FIXME: model should not be tied to the DOM !
self.search_str = $('.reconciliation_search_input').val();
var def_statement = this._rpc({
model: 'account.reconciliation.widget',
method: 'get_bank_statement_data',
kwargs: {"bank_statement_line_ids":self.statement_line_ids, "search_str":self.search_str},
kwargs: {"bank_statement_line_ids":self.statement_line_ids, "srch_domain":self.domain},
context: self.context,
})
.then(function (statement) {
self.statement = statement;
self.bank_statement_id = self.statement_line_ids.length === 1 ? {id: self.statement_line_ids[0], display_name: statement.statement_name} : false;
self.bank_statement_line_id = self.statement_line_ids.length === 1 ? {id: self.statement_line_ids[0], display_name: statement.statement_name} : false;
self.valuenow = self.valuenow || statement.value_min;
self.valuemax = self.valuemax || statement.value_max;
self.context.journal_id = statement.journal_id;
@@ -413,9 +423,11 @@ var StatementModel = BasicModel.extend({
handle: handle,
reconciled: false,
mode: 'inactive',
mv_lines: [],
mv_lines_match_rp: [],
mv_lines_match_other: [],
offset: 0,
filter: "",
filter_match_rp: "",
filter_match_other: "",
reconciliation_proposition: [],
reconcileModels: [],
};
@@ -531,28 +543,35 @@ var StatementModel = BasicModel.extend({
* @returns {Promise}
*/
quickCreateProposition: function (handle, reconcileModelId) {
var self = this;
var line = this.getLine(handle);
var reconcileModel = _.find(this.reconcileModels, function (r) {return r.id === reconcileModelId;});
var fields = ['account_id', 'amount', 'amount_type', 'analytic_account_id', 'journal_id', 'label', 'force_tax_included', 'tax_ids', 'analytic_tag_ids', 'to_check'];
var fields = ['account_id', 'amount', 'amount_type', 'analytic_account_id', 'journal_id', 'label', 'force_tax_included', 'tax_ids', 'analytic_tag_ids', 'to_check', 'amount_from_label_regex', 'decimal_separator'];
this._blurProposition(handle);
var focus = this._formatQuickCreate(line, _.pick(reconcileModel, fields));
focus.reconcileModelId = reconcileModelId;
line.reconciliation_proposition.push(focus);
var defs = [];
if (reconcileModel.has_second_line) {
var second = {};
_.each(fields, function (key) {
second[key] = ("second_"+key) in reconcileModel ? reconcileModel["second_"+key] : reconcileModel[key];
});
focus = this._formatQuickCreate(line, second);
focus.reconcileModelId = reconcileModelId;
line.reconciliation_proposition.push(focus);
this._computeReconcileModels(handle, reconcileModelId);
defs.push(self._computeLine(line).then(function() {
var second = {};
_.each(fields, function (key) {
second[key] = ("second_"+key) in reconcileModel ? reconcileModel["second_"+key] : reconcileModel[key];
});
var second_focus = self._formatQuickCreate(line, second);
second_focus.reconcileModelId = reconcileModelId;
line.reconciliation_proposition.push(second_focus);
self._computeReconcileModels(handle, reconcileModelId);
}))
}
line.createForm = _.pick(focus, this.quickCreateFields);
return this._computeLine(line);
return Promise.all(defs).then(function() {
line.createForm = _.pick(focus, self.quickCreateFields);
return self._computeLine(line);
})
},
/**
* Remove a proposition and switch to an active mode ('create' or 'match')
* Remove a proposition and switch to an active mode ('create' or 'match_rp' or 'match_other')
* overridden in ManualModel
*
* @param {string} handle
* @param {number} id (move line id)
@@ -563,29 +582,29 @@ var StatementModel = BasicModel.extend({
var line = this.getLine(handle);
var defs = [];
// new limit = previous limit + 1, the one put back
line.limit_override = (line.offset + 1) * this.limitMoveLines;
line.limit_override = (line.offset + 1) + this.limitMoveLines;
var prop = _.find(line.reconciliation_proposition, {'id' : id});
if (prop) {
line.reconciliation_proposition = _.filter(line.reconciliation_proposition, function (p) {
return p.id !== prop.id && p.id !== prop.link && p.link !== prop.id && (!p.link || p.link !== prop.link);
});
if (prop['reconcileModelId'] === undefined) {
if (['receivable', 'payable', 'liquidity'].includes(prop.account_type)) {
line.mv_lines_match_rp.unshift(prop);
} else {
line.mv_lines_match_other.unshift(prop);
}
}
// No proposition left and then, reset the st_line partner.
if(line.reconciliation_proposition.length == 0 && line.st_line.has_no_partner)
defs.push(self.changePartner(line.handle));
}
line.mode = (id || line.mode !== "create") && isNaN(id) && !this.avoidCreate ? 'create' : 'match';
line.mode = (id || line.mode !== "create") && isNaN(id) ? 'create' : 'match_rp';
defs.push(this._computeLine(line));
if (line.mode === 'create') {
return Promise.all(defs).then(function () {
return self.createProposition(handle);
});
} else if (line.mode === 'match') {
return Promise.all(defs).then(function () {
return self._performMoveLine(handle);
});
}
return Promise.all(defs);
return Promise.all(defs).then(function() {
return self.changeMode(handle, line.mode, true);
})
},
getPartialReconcileAmount: function(handle, data) {
var line = this.getLine(handle);
@@ -730,6 +749,7 @@ var StatementModel = BasicModel.extend({
/**
* Format the value and send it to 'account.reconciliation.widget' model
* Update the number of validated lines
* overridden in ManualModel
*
* @param {(string|string[])} handle
* @returns {Promise<Object>} resolved with an object who contains
@@ -737,6 +757,7 @@ var StatementModel = BasicModel.extend({
*/
validate: function (handle) {
var self = this;
this.display_context = 'validate';
var handles = [];
if (handle) {
handles = [handle];
@@ -799,6 +820,17 @@ var StatementModel = BasicModel.extend({
line.reconciled = true;
self.valuenow++;
}));
_.each(self.lines, function(other_line) {
if (other_line != line) {
var filtered_prop = other_line.reconciliation_proposition.filter(p => !line.reconciliation_proposition.map(l => l.id).includes(p.id));
if (filtered_prop.length != other_line.reconciliation_proposition.length) {
other_line.need_update = true;
other_line.reconciliation_proposition = filtered_prop;
}
self._computeLine(line);
}
})
});
return Promise.all(handlesPromises).then(function() {
@@ -874,6 +906,7 @@ var StatementModel = BasicModel.extend({
* Calculates the balance; format each proposition amount_str and mark as
* invalid the line with empty account_id, amount or label
* Check the taxes server side for each updated propositions with tax_ids
* extended by ManualModel
*
* @private
* @param {Object} line
@@ -1036,6 +1069,7 @@ var StatementModel = BasicModel.extend({
},
/**
* Format each propositions (amount, label, account_id)
* extended in ManualModel
*
* @private
* @param {Object} line
@@ -1055,6 +1089,7 @@ var StatementModel = BasicModel.extend({
},
/**
* Format each server lines and propositions and compute all lines
* overridden in ManualModel
*
* @see '_computeLine'
*
@@ -1119,6 +1154,7 @@ var StatementModel = BasicModel.extend({
},
/**
* Format the server value then compute the line
* overridden in ManualModel
*
* @see '_computeLine'
*
@@ -1127,20 +1163,20 @@ var StatementModel = BasicModel.extend({
* @param {Object[]} mv_lines
* @returns {Promise}
*/
_formatMoveLine: function (handle, mv_lines) {
_formatMoveLine: function (handle, mode, mv_lines) {
var self = this;
var line = this.getLine(handle);
if (line.offset === 0 || line.limit_override) {
line.mv_lines = mv_lines;
line['mv_lines_'+mode] = mv_lines;
delete line.limit_override;
} else {
line.mv_lines = line.mv_lines.concat(mv_lines);
line['mv_lines_'+mode] = line['mv_lines_'+mode].concat(mv_lines);
}
this._formatLineProposition(line, mv_lines);
if (line.mode !== 'create' && !line.mv_lines.length && !line.filter.length) {
line.mode = this.avoidCreate || !line.balance.amount ? 'inactive' : 'create';
if (line.mode === 'create') {
if ((line.mode == 'match_other' || line.mode == "match_rp") && !line['mv_lines_'+mode].length && !line['filter_'+mode].length) {
line.mode = self._getDefaultMode(handle);
if (line.mode !== 'match_rp' && line.mode !== 'match_other' && line.mode !== 'inactive') {
return this._computeLine(line).then(function () {
return self.createProposition(handle);
});
@@ -1149,9 +1185,40 @@ var StatementModel = BasicModel.extend({
return this._computeLine(line);
}
},
/**
* overridden in ManualModel
*/
_getDefaultMode: function(handle) {
var line = this.getLine(handle);
if (line.balance.amount === 0
&& (!line.st_line.mv_lines_match_rp || line.st_line.mv_lines_match_rp.length === 0)
&& (!line.st_line.mv_lines_match_other || line.st_line.mv_lines_match_other.length === 0)) {
return 'inactive';
}
if (line.mv_lines_match_rp && line.mv_lines_match_rp.length) {
return 'match_rp';
}
if (line.mv_lines_match_other && line.mv_lines_match_other.length) {
return 'match_other';
}
return 'create';
},
_getAvailableModes: function(handle) {
var line = this.getLine(handle);
var modes = []
if (line.mv_lines_match_rp && line.mv_lines_match_rp.length) {
modes.push('match_rp')
}
if (line.mv_lines_match_other && line.mv_lines_match_other.length) {
modes.push('match_other')
}
modes.push('create')
return modes
},
/**
* Apply default values for the proposition, format datas and format the
* base_amount with the decimal number from the currency
* extended in ManualModel
*
* @private
* @param {Object} line
@@ -1165,7 +1232,28 @@ var StatementModel = BasicModel.extend({
var formatOptions = {
currency_id: line.st_line.currency_id,
};
var amount = values.amount !== undefined ? values.amount : line.balance.amount;
var amount;
switch(values.amount_type) {
case 'percentage':
amount = line.balance.amount * values.amount / 100;
break;
case 'regex':
var matching = line.st_line.name.match(new RegExp(values.amount_from_label_regex))
amount = null;
if (matching && matching.length == 2) {
matching = matching[1].replace(new RegExp('\\D' + values.decimal_separator, 'g'), '');
matching = matching.replace(values.decimal_separator, '.');
amount = parseFloat(matching);
}
break;
case 'fixed':
amount = values.amount;
break;
default:
amount = values.amount !== undefined ? values.amount : line.balance.amount;
}
var prop = {
'id': _.uniqueId('createLine'),
'label': values.label || line.st_line.name,
@@ -1179,8 +1267,7 @@ var StatementModel = BasicModel.extend({
'credit': 0,
'date': values.date ? values.date : field_utils.parse.date(today, {}, {isUTC: true}),
'force_tax_included': values.force_tax_included || false,
'base_amount': values.amount_type !== "percentage" ?
(amount) : line.balance.amount * values.amount / 100,
'base_amount': amount,
'percent': values.amount_type === "percentage" ? values.amount : null,
'link': values.link,
'display': true,
@@ -1224,6 +1311,7 @@ var StatementModel = BasicModel.extend({
* Defined whether the line is to be displayed or not. Here, we only display
* the line if it comes from the server or if an account is defined when it
* is created
* extended in ManualModel
*
* @private
* @param {object} prop
@@ -1233,6 +1321,7 @@ var StatementModel = BasicModel.extend({
return !isNaN(prop.id) || !!prop.account_id;
},
/**
* extended in ManualModel
* @private
* @param {object} prop
* @returns {Boolean}
@@ -1242,6 +1331,7 @@ var StatementModel = BasicModel.extend({
},
/**
* Fetch 'account.reconciliation.widget' propositions.
* overridden in ManualModel
*
* @see '_formatMoveLine'
*
@@ -1249,14 +1339,12 @@ var StatementModel = BasicModel.extend({
* @param {string} handle
* @returns {Promise}
*/
_performMoveLine: function (handle) {
_performMoveLine: function (handle, mode) {
var line = this.getLine(handle);
var excluded_ids = _.compact(_.flatten(_.map(this.lines, function (line) {
return _.map(line.reconciliation_proposition, function (prop) {
return _.isNumber(prop.id) ? prop.id : null;
});
})));
var filter = line.filter || "";
var excluded_ids = _.map(line.reconciliation_proposition, function (prop) {
return _.isNumber(prop.id) ? prop.id : null;
}).filter(id => id != null);
var filter = line['filter_'+mode] || "";
var limit = this.limitMoveLines;
var offset = line.offset;
if (line.limit_override) {
@@ -1270,13 +1358,14 @@ var StatementModel = BasicModel.extend({
return this._rpc({
model: 'account.reconciliation.widget',
method: 'get_move_lines_for_bank_statement_line',
args: [line.id, line.st_line.partner_id, excluded_ids, filter, offset, limit],
args: [line.id, line.st_line.partner_id, excluded_ids, filter, offset, limit, mode === 'match_rp' ? 'rp' : 'other'],
context: this.context,
})
.then(this._formatMoveLine.bind(this, handle));
.then(this._formatMoveLine.bind(this, handle, mode));
},
/**
* format the proposition to send information server side
* extended in ManualModel
*
* @private
* @param {object} line
@@ -1320,6 +1409,7 @@ var StatementModel = BasicModel.extend({
* @returns {Deferred}
*/
_validatePostProcess: function (data) {
var self = this;
return Promise.resolve();
},
});
@@ -1332,6 +1422,8 @@ var StatementModel = BasicModel.extend({
var ManualModel = StatementModel.extend({
quickCreateFields: ['account_id', 'journal_id', 'amount', 'analytic_account_id', 'label', 'tax_ids', 'force_tax_included', 'analytic_tag_ids', 'date', 'to_check'],
modes: ['create', 'match'],
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
@@ -1445,6 +1537,7 @@ var ManualModel = StatementModel.extend({
},
/**
* Load more partners/accounts
* overridden in ManualModel
*
* @param {integer} qty quantity to load
* @returns {Promise}
@@ -1541,8 +1634,8 @@ var ManualModel = StatementModel.extend({
}
line.filter = "";
line.offset = 0;
defs.push(self._performMoveLine(handle).then(function () {
if(!line.mv_lines.length) {
defs.push(self._performMoveLine(handle, 'match').then(function () {
if(!line.mv_lines_match.length) {
self.valuenow++;
reconciled.push(handle);
line.reconciled = true;
@@ -1566,6 +1659,28 @@ var ManualModel = StatementModel.extend({
});
});
},
removeProposition: function (handle, id) {
var self = this;
var line = this.getLine(handle);
var defs = [];
// new limit = previous limit + 1, the one put back
var prop = _.find(line.reconciliation_proposition, {'id' : id});
if (prop) {
line.reconciliation_proposition = _.filter(line.reconciliation_proposition, function (p) {
return p.id !== prop.id && p.id !== prop.link && p.link !== prop.id && (!p.link || p.link !== prop.link);
});
line.mv_lines_match.unshift(prop);
// No proposition left and then, reset the st_line partner.
if(line.reconciliation_proposition.length == 0 && line.st_line.has_no_partner)
defs.push(self.changePartner(line.handle));
}
line.mode = (id || line.mode !== "create") && isNaN(id) ? 'create' : 'match';
defs.push(this._computeLine(line));
return Promise.all(defs).then(function() {
return self.changeMode(handle, line.mode, true);
})
},
//--------------------------------------------------------------------------
// Private
@@ -1686,13 +1801,11 @@ var ManualModel = StatementModel.extend({
* @param {string} handle
* @returns {Promise}
*/
_performMoveLine: function (handle) {
_performMoveLine: function (handle, mode) {
var line = this.getLine(handle);
var excluded_ids = _.compact(_.flatten(_.map(this.lines, function (line) {
return _.map(line.reconciliation_proposition, function (prop) {
return _.isNumber(prop.id) ? prop.id : null;
});
})));
var excluded_ids = _.map(line.reconciliation_proposition, function (prop) {
return _.isNumber(prop.id) ? prop.id : null;
}).filter(id => id != null);
var filter = line.filter || "";
var limit = this.limitMoveLines;
var offset = line.offset;
@@ -1707,7 +1820,7 @@ var ManualModel = StatementModel.extend({
args: args,
context: this.context,
})
.then(this._formatMoveLine.bind(this, handle));
.then(this._formatMoveLine.bind(this, handle, ''));
},
_formatToProcessReconciliation: function (line, prop) {
@@ -1715,6 +1828,35 @@ var ManualModel = StatementModel.extend({
result['date'] = prop.date;
return result;
},
_getDefaultMode: function(handle) {
var line = this.getLine(handle);
if (line.balance.amount === 0 && (!line.st_line.mv_lines_match || line.st_line.mv_lines_match.length === 0)) {
return 'inactive';
}
return line.mv_lines_match.length > 0 ? 'match' : 'create';
},
_formatMoveLine: function (handle, mode, mv_lines) {
var self = this;
var line = this.getLine(handle);
if (line.offset === 0 || line.limit_override) {
line.mv_lines_match = mv_lines;
delete line.limit_override;
} else {
line.mv_lines_match = line.mv_lines_match.concat(mv_lines);
}
this._formatLineProposition(line, mv_lines);
if (line.mode !== 'create' && !line.mv_lines_match.length && !line.filter.length) {
line.mode = this.avoidCreate || !line.balance.amount ? 'inactive' : 'create';
if (line.mode === 'create') {
return this._computeLine(line).then(function () {
return self.createProposition(handle);
});
}
} else {
return this._computeLine(line);
}
},
});
return {
@@ -19,11 +19,8 @@ var _t = core._t;
var StatementRenderer = Widget.extend(FieldManagerMixin, {
template: 'reconciliation.statement',
events: {
'click div:first h1.statement_name': '_onClickStatementName',
"click *[rel='do_action']": "_onDoAction",
'click *[rel="do_action"]': '_onDoAction',
'click button.js_load_more': '_onLoadMore',
'blur .statement_name_edition > input': '_onValidateName',
'keyup .statement_name_edition > input': '_onKeyupInput'
},
/**
* @override
@@ -42,42 +39,11 @@ var StatementRenderer = Widget.extend(FieldManagerMixin, {
var self = this;
var defs = [this._super.apply(this, arguments)];
this.time = Date.now();
this.$progress = this.$('.progress');
this.clickStatementName = this._initialState.bank_statement_id ? true : false;
this.$progress = $('');
if (this._initialState.bank_statement_id) {
var def = this.model.makeRecord("account.bank.statement", [{
type: 'char',
name: 'name',
attrs: {string: ""},
value: this._initialState.bank_statement_id.display_name
}]).then(function (recordID) {
self.handleNameRecord = recordID;
self.name = new basic_fields.FieldChar(self,
'name', self.model.get(self.handleNameRecord),
{mode: 'edit'});
self.name.appendTo(self.$('.statement_name_edition')).then(function () {
self.name.$el.addClass('o_required_modifier');
});
self.$('.statement_name').text(self._initialState.bank_statement_id.display_name);
});
defs.push(def);
}
this.$('h1.statement_name').text(this._initialState.title || _t('No Title'));
if (this.model.context && this.model.context.args && this.model.context.args.search) {
this.$('.reconciliation_search_input').val(self.model.context.args.search);
}
return Promise.all(defs);
},
/**
* @override
*/
destroy: function () {
this._super();
$('body').off('keyup', this.enterHandler);
},
//--------------------------------------------------------------------------
// Public
//--------------------------------------------------------------------------
@@ -93,6 +59,9 @@ var StatementRenderer = Widget.extend(FieldManagerMixin, {
}
},
showRainbowMan: function (state) {
if (this.model.display_context !== 'validate') {
return
}
var dt = Date.now()-this.time;
var $done = $(qweb.render("reconciliation.done", {
'duration': moment(dt).utc().format(time.getLangTimeFormat()),
@@ -100,9 +69,9 @@ var StatementRenderer = Widget.extend(FieldManagerMixin, {
'timePerTransaction': Math.round(dt/1000/state.valuemax),
'context': state.context,
}));
$done.find('*').addClass('o_reward_subcontent');
$done.find('.button_close_statement').click(this._onCloseBankStatement.bind(this));
$done.find('.button_back_to_statement').click(this._onGoToBankStatement.bind(this));
this.$el.children().hide();
// display rainbowman after full reconciliation
if (session.show_effect) {
this.trigger_up('show_effect', {
@@ -126,12 +95,7 @@ var StatementRenderer = Widget.extend(FieldManagerMixin, {
*/
update: function (state) {
var self = this;
this.$progress.find('.valuenow').text(state.valuenow);
this.$progress.find('.valuemax').text(state.valuemax);
this.$progress.find('.progress-bar')
.attr('aria-valuenow', state.valuenow)
.attr('aria-valuemax', state.valuemax)
.css('width', (state.valuenow/state.valuemax*100) + '%');
this._updateProgressBar(state);
if (state.valuenow === state.valuemax && !this.$('.done_message').length) {
this.showRainbowMan(state);
@@ -140,9 +104,14 @@ var StatementRenderer = Widget.extend(FieldManagerMixin, {
if (state.notifications) {
this._renderNotifications(state.notifications);
}
this.$('.statement_name, .statement_name_edition').toggle();
this.$('h1.statement_name').text(state.title || _t('No Title'));
},
_updateProgressBar: function(state) {
this.$progress.find('.valuenow').text(state.valuenow);
this.$progress.find('.valuemax').text(state.valuemax);
this.$progress.find('.progress-bar')
.attr('aria-valuenow', state.valuenow)
.attr('aria-valuemax', state.valuemax)
.css('width', (state.valuenow/state.valuemax*100) + '%');
},
//--------------------------------------------------------------------------
@@ -165,15 +134,6 @@ var StatementRenderer = Widget.extend(FieldManagerMixin, {
// Handlers
//--------------------------------------------------------------------------
/**
* @private
*/
_onClickStatementName: function () {
if (this._initialState.bank_statement_id) {
this.$('.statement_name, .statement_name_edition').toggle();
this.$('.statement_name_edition input').focus();
}
},
/**
* @private
* Click on close bank statement button, this will
@@ -191,15 +151,31 @@ var StatementRenderer = Widget.extend(FieldManagerMixin, {
e.preventDefault();
var name = e.currentTarget.dataset.action_name;
var model = e.currentTarget.dataset.model;
var ids = e.currentTarget.dataset.ids.split(",").map(Number);
this.do_action({
name: name,
res_model: model,
domain: [['id', 'in', ids]],
views: [[false, 'list'], [false, 'form']],
type: 'ir.actions.act_window',
view_mode: "list"
});
if (e.currentTarget.dataset.ids) {
var ids = e.currentTarget.dataset.ids.split(",").map(Number);
var domain = [['id', 'in', ids]];
} else {
var domain = e.currentTarget.dataset.domain;
}
var context = e.currentTarget.dataset.context;
var tag = e.currentTarget.dataset.tag;
if (tag) {
this.do_action({
type: 'ir.actions.client',
tag: tag,
context: context,
})
} else {
this.do_action({
name: name,
res_model: model,
domain: domain,
context: context,
views: [[false, 'list'], [false, 'form']],
type: 'ir.actions.act_window',
view_mode: "list"
});
}
},
/**
* Open the list view for account.bank.statement model
@@ -211,6 +187,7 @@ var StatementRenderer = Widget.extend(FieldManagerMixin, {
if (journalId) {
journalId = parseInt(journalId);
}
$('.o_reward').remove();
this.do_action({
name: 'Bank Statements',
res_model: 'account.bank.statement',
@@ -228,24 +205,6 @@ var StatementRenderer = Widget.extend(FieldManagerMixin, {
_onLoadMore: function (e) {
this.trigger_up('load_more');
},
/**
* @private
*/
_onValidateName: function () {
var name = this.$('.statement_name_edition input').val().trim();
this.trigger_up('change_name', {'data': name});
},
/**
* Save title on enter key pressed
*
* @private
* @param {KeyboardEvent} event
*/
_onKeyupInput: function (event) {
if (event.which === $.ui.keyCode.ENTER) {
this.$('.statement_name_edition input').blur();
}
},
});
@@ -257,8 +216,10 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
template: "reconciliation.line",
events: {
'click .accounting_view caption .o_buttons button': '_onValidate',
'click .accounting_view thead td': '_onTogglePanel',
'click .accounting_view tfoot td:not(.cell_left,.cell_right)': '_onShowPanel',
'click .accounting_view tfoot': '_onChangeTab',
'click': '_onTogglePanel',
'click .o_field_widget': '_onStopPropagation',
'click .o_notebook li a': '_onChangeTab',
'click .cell': '_onEditAmount',
'change input.filter': '_onFilterChange',
'click .match .load-more a': '_onLoadMore',
@@ -270,6 +231,7 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
'click .reconcile_model_edit': '_onEditReconcileModel',
'keyup input': '_onInputKeyup',
'blur input': '_onInputKeyup',
'keydown': '_onKeydown',
},
custom_events: _.extend({}, FieldManagerMixin.custom_events, {
'field_changed': '_onFieldChanged',
@@ -277,6 +239,45 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
_avoidFieldUpdate: {},
MV_LINE_DEBOUNCE: 200,
_onKeydown: function (ev) {
switch (ev.which) {
case $.ui.keyCode.TAB:
var event = this.trigger_up('navigation_move', {
direction: ev.shiftKey ? 'previous' : 'next',
handle: this.handle,
});
if (event.is_stopped()) {
ev.preventDefault();
ev.stopPropagation();
}
break;
case $.ui.keyCode.ENTER:
this.trigger_up('navigation_move', {direction: 'next_line', handle: this.handle});
break;
case $.ui.keyCode.ESCAPE:
this.trigger_up('navigation_move', {direction: 'cancel', handle: this.handle, originalEvent: ev});
break;
case $.ui.keyCode.UP:
ev.stopPropagation();
ev.preventDefault();
this.trigger_up('navigation_move', {direction: 'up', handle: this.handle});
break;
case $.ui.keyCode.RIGHT:
ev.stopPropagation();
this.trigger_up('navigation_move', {direction: 'right', handle: this.handle});
break;
case $.ui.keyCode.DOWN:
ev.stopPropagation();
ev.preventDefault();
this.trigger_up('navigation_move', {direction: 'down', handle: this.handle});
break;
case $.ui.keyCode.LEFT:
ev.stopPropagation();
this.trigger_up('navigation_move', {direction: 'left', handle: this.handle});
break;
}
},
/**
* create partner_id field in editable mode
*
@@ -306,7 +307,7 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
self.model.get(recordID), {
mode: 'edit',
attrs: {
placeholder: self._initialState.st_line.communication_partner_name || '',
placeholder: self._initialState.st_line.communication_partner_name || _t('Select Partner'),
}
}
)
@@ -321,7 +322,7 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
'placement': 'left',
'container': this.$el,
'html': true,
// disable bootstrap sanitizer because we use a table that has been
// disable bootstrap sanitizer because we use a table that has been
// rendered using qweb.render so it is safe and also because sanitizer escape table by default.
'sanitize': false,
'trigger': 'hover',
@@ -357,19 +358,13 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
});
// mode
this.$('.create, .match').each(function () {
var $panel = $(this);
$panel.css('-webkit-transition', 'none');
$panel.css('-moz-transition', 'none');
$panel.css('-o-transition', 'none');
$panel.css('transition', 'none');
$panel.css('max-height', $panel.height());
$panel.css('-webkit-transition', '');
$panel.css('-moz-transition', '');
$panel.css('-o-transition', '');
$panel.css('transition', '');
});
this.$el.data('mode', state.mode).attr('data-mode', state.mode);
this.$('.o_notebook li a').attr('aria-selected', false);
this.$('.o_notebook li a').removeClass('active');
this.$('.o_notebook .tab-content .tab-pane').removeClass('active');
this.$('.o_notebook li a[href*="notebook_page_' + state.mode + '"]').attr('aria-selected', true);
this.$('.o_notebook li a[href*="notebook_page_' + state.mode + '"]').addClass('active');
this.$('.o_notebook .tab-content .tab-pane[id*="notebook_page_' + state.mode + '"]').addClass('active');
this.$('.create, .match').each(function () {
$(this).removeAttr('style');
});
@@ -397,33 +392,31 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
});
// mv_lines
var stateMvLines = state.mv_lines || [];
var recs_count = stateMvLines.length > 0 ? stateMvLines[0].recs_count : 0;
var remaining = recs_count - stateMvLines.length;
var $mv_lines = this.$('.match table tbody').empty();
var matching_modes = self.model.modes.filter(x => x.startsWith('match'));
for (let i = 0; i < matching_modes.length; i++) {
var stateMvLines = state['mv_lines_'+matching_modes[i]] || [];
var recs_count = stateMvLines.length > 0 ? stateMvLines[0].recs_count : 0;
var remaining = recs_count - stateMvLines.length;
var $mv_lines = this.$('div[id*="notebook_page_' + matching_modes[i] + '"] .match table tbody').empty();
this.$('.o_notebook li a[href*="notebook_page_' + matching_modes[i] + '"]').parent().toggleClass('d-none', stateMvLines.length === 0 && !state['filter_'+matching_modes[i]]);
_.each(stateMvLines, function (line) {
var $line = $(qweb.render("reconciliation.line.mv_line", {'line': line, 'state': state}));
if (!isNaN(line.id)) {
$('<span class="line_info_button fa fa-info-circle"/>')
_.each(stateMvLines, function (line) {
var $line = $(qweb.render("reconciliation.line.mv_line", {'line': line, 'state': state}));
if (!isNaN(line.id)) {
$('<span class="line_info_button fa fa-info-circle"/>')
.appendTo($line.find('.cell_info_popover'))
.attr("data-content", qweb.render('reconciliation.line.mv_line.details', {'line': line}));
}
$mv_lines.append($line);
});
this.$('.match div.load-more').toggle(remaining > 0);
this.$('.match div.load-more span').text(remaining);
this.$('.match').css('max-height', !stateMvLines.length && !state.filter.length ? '0px' : '');
}
$mv_lines.append($line);
});
this.$('div[id*="notebook_page_' + matching_modes[i] + '"] .match div.load-more').toggle(remaining > 0);
this.$('div[id*="notebook_page_' + matching_modes[i] + '"] .match div.load-more span').text(remaining);
}
// balance
this.$('.popover').remove();
this.$('table tfoot').html(qweb.render("reconciliation.line.balance", {'state': state}));
// filter
if (_.str.strip(this.$('input.filter').val()) !== state.filter) {
this.$('input.filter').val(state.filter);
}
// create form
if (state.createForm) {
var createPromise;
@@ -469,7 +462,8 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
else {
$('.create_force_tax_included').removeClass('d-none');
var price_include = state.createForm[fieldName][0].price_include;
self.$('.create_force_tax_included input').prop('checked', price_include);
var force_tax_included = state.createForm[fieldName][0].force_tax_included;
self.$('.create_force_tax_included input').prop('checked', force_tax_included);
self.$('.create_force_tax_included input').prop('disabled', price_include);
}
}
@@ -483,10 +477,16 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
});
}
this.$('.create .add_line').toggle(!!state.balance.amount_currency);
if (this.$el.is(':focus-within')) {
this.$('caption .o_buttons button:not(:disabled):visible').attr('accesskey', 'V');
} else {
this.$('caption .o_buttons button').attr('accesskey', '');
}
},
updatePartialAmount: function(line_id, amount) {
var $line = $('.mv_line[data-line-id='+line_id+']');
var $line = this.$('.mv_line[data-line-id='+line_id+']');
$line.find('.edit_amount').addClass('d-none');
$line.find('.edit_amount_input').removeClass('d-none');
$line.find('.edit_amount_input').focus();
@@ -592,7 +592,7 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
var record = self.model.get(self.handleCreateRecord);
self.fields.account_id = new relational_fields.FieldMany2One(self,
'account_id', record, {mode: 'edit'});
'account_id', record, {mode: 'edit', attrs: {can_create:false}});
self.fields.journal_id = new relational_fields.FieldMany2One(self,
'journal_id', record, {mode: 'edit'});
@@ -646,6 +646,16 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
//--------------------------------------------------------------------------
// Handlers
//--------------------------------------------------------------------------
/**
* The event on the partner m2o widget was propagated to the bank statement
* line widget, causing it to expand and the others to collapse. This caused
* the dropdown to be poorly placed and an unwanted update of this widget.
*
* @private
*/
_onStopPropagation: function(ev) {
ev.stopPropagation();
},
/**
* @private
@@ -718,15 +728,22 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
* @private
*/
_onTogglePanel: function () {
var mode = this.$el.data('mode') === 'inactive' ? 'match' : 'inactive';
this.trigger_up('change_mode', {'data': mode});
if (this.$el[0].getAttribute('data-mode') == 'inactive')
this.trigger_up('change_mode', {'data': 'default'});
},
/**
* @private
*/
_onShowPanel: function () {
var mode = (this.$el.data('mode') === 'inactive' || this.$el.data('mode') === 'match') ? 'create' : 'match';
this.trigger_up('change_mode', {'data': mode});
_onChangeTab: function(event) {
if (event.currentTarget.nodeName === 'TFOOT') {
this.trigger_up('change_mode', {'data': 'next'});
} else {
var modes = this.model.modes;
var selected_mode = modes.find(function(e) {return event.target.getAttribute('href').includes(e)});
if (selected_mode) {
this.trigger_up('change_mode', {'data': selected_mode});
}
}
},
/**
* @private
@@ -746,7 +763,7 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
}
if(event.keyCode === 13) {
if ($(event.target).hasClass('edit_amount_input')) {
this.$(event.target).blur();
$(event.target).blur();
return;
}
var created_lines = _.findWhere(this.model.lines, {mode: 'create'});
@@ -847,13 +864,6 @@ var LineRenderer = Widget.extend(FieldManagerMixin, {
var ManualRenderer = StatementRenderer.extend({
template: "reconciliation.manual.statement",
/**
* avoid statement name edition
*
* @override
* @private
*/
_onClickStatementName: function () {}
});
@@ -912,10 +922,10 @@ var ManualLineRenderer = LineRenderer.extend({
return Promise.all(defs).then(function () {
if (!self.fields.title_account_id) {
return self.fields.partner_id.prependTo(self.$('.accounting_view thead td:eq(1) span:first'));
return self.fields.partner_id.prependTo(self.$('.accounting_view thead td:eq(0) span:first'));
} else {
self.fields.partner_id.destroy();
return self.fields.title_account_id.appendTo(self.$('.accounting_view thead td:eq(1) span:first'));
return self.fields.title_account_id.appendTo(self.$('.accounting_view thead td:eq(0) span:first'));
}
});
});
@@ -1,30 +1,20 @@
.o_reconciliation {
h1 {
margin: 0 0 25px 0;
float: left;
font-size: 2em;
height: 1.5em;
line-height: 1.5em;
&.statement_name {
@include o-text-overflow;
&.editable:hover {
outline: 1px dashed $o-brand-primary;
outline-offset: -1px;
cursor: pointer;
}
}
&.statement_name_edition input {
width: 85%;
.progress-reconciliation {
.progress-bar {
font-size: 1.08333333rem;
height: 14px;
background-color: $o-enterprise-color;
span {
display: contents;
}
}
}
.o_reconciliation {
.o_filter_input_wrapper {
position: relative;
float: right;
width: 150px;
margin-top: 0px;
margin-bottom: 20px;
float: right;
margin: 0.5rem !important;
.searchIcon {
position: absolute;
right: 10px;
@@ -34,27 +24,9 @@
border-bottom: 1px black solid;
}
}
.progress {
width: 100%;
margin: 10px 0 2px 0;
float: right;
position: relative;
display: inline-block;
.progress-bar {
background-color: $o-community-color; // FIXME probably supposed to be primary to be auto-adapted in enterprise ?
}
.progress-text {
text-align: center;
position: absolute;
width: 100%;
}
}
h1, .progress {
@media screen and (min-width: 480px) { // FIXME
width: 48%;
}
.import_to_suspense {
margin: 0.5rem !important;
}
.notification_area {
@@ -85,6 +57,15 @@
.strike_amount {
text-decoration: line-through;
}
tbody tr:hover .cell_account_code::before {
content: "\f068";
font-family: FontAwesome;
position: relative;
margin-left: -17px;
left: -4px;
line-height: 0;
padding: 3px 2px 5px 5px;
}
}
@@ -122,7 +103,7 @@
width: 100%;
vertical-align: top;
}
tr {
tbody tr {
cursor: pointer;
}
tr.already_reconciled {
@@ -165,6 +146,7 @@
}
.cell_account_code {
width: 80px;
padding-left: 5px;
}
.cell_due_date {
width: 100px;
@@ -232,24 +214,25 @@
}
/* Match view & Create view */
> .match, > .create {
> .o_notebook {
display: none;
max-height: 0px;
overflow: hidden;
margin-bottom: 5px;
transition: max-height 250ms ease 0s;
}
&[data-mode="match"] > .match {
display: block;
max-height: none;
overflow: visible;
transition: max-height 400ms ease 0s;
> .o_notebook > .tab-content > div {
border: 1px solid #ddd;
border-top: 0;
}
&[data-mode="create"] > .create {
> .o_notebook .match table tr:hover {
background-color: #eee;
}
&:not([data-mode="inactive"]) > .o_notebook {
display: block;
max-height: 210px;
transition: max-height 400ms ease 0s;
}
&:not(:focus-within) .o_web_accesskey_overlay {
display: none;
}
}
@@ -260,12 +243,6 @@
/* Match view */
.match {
> div {
padding: 5px 6px 10px;
border: 1px solid #eee;
border-radius: 5px;
margin: 5px 0 0 0;
}
.cell_action .fa-add-remove:before {
content: "";
}
@@ -303,38 +280,21 @@
/* Create view */
.create {
> div {
margin: 0 0 0 $o-account-action-col-width;
padding: 5px 10px;
> div > div.quick_add > .o_reconcile_models {
max-height: 54px;
overflow: auto;
border: 1px solid #ddd;
border-radius: 0 0 5px 5px;
> div.quick_add > .o_reconcile_models {
max-height: 54px;
overflow: auto;
}
}
.quick_add {
margin-bottom: 7px;
padding: 0 8px;
}
table {
.o_group table.o_group_col_6 {
width: 49%;
margin: 0;
vertical-align: top;
}
td {
width: 99%;
padding-left: 8px;
}
tr .o_td_label {
vertical-align: top;
line-height: 26px;
font-weight: bold;
padding-right: 8px;
min-width: 100px;
border-right: 1px solid #ddd;
white-space: nowrap;
width: 1%;
.o_group table.o_group_col_6:first-child {
margin-left: 8px;
}
.btn {
padding-top: 0;
@@ -343,17 +303,21 @@
.add_line_container {
text-align: center;
clear: both;
color: $o-account-info-color;
color: $o-enterprise-primary-color;
cursor: pointer;
}
}
.o_notebook .tab-content > .tab-pane {
padding: 5px 0;
}
}
/*Manual Reconciliation*/
.o_manual_statement {
.accounting_view {
td[colspan="3"] span:first-child {
width: 50%;
width: 100%;
display: inline-block;
}
td[colspan="2"] {
@@ -0,0 +1,21 @@
.o_search_panel.account_root {
flex: 0 0 48px;
padding: 6px;
scrollbar-width: thin;
.o_search_panel_section_header {
display: none;
}
.list-group-item span.o_search_panel_label_title {
display: contents;
}
.o_search_panel_category_value header {
margin-left: 0;
padding-left: 0;
}
&::-webkit-scrollbar {
width: 4px;
}
&::-webkit-scrollbar-thumb {
background: lightgray;
}
}
@@ -22,7 +22,7 @@
</t>
<t t-if="!outstanding">
<td>
<a role="button" tabindex="0" class="js_payment_info fa fa-info-circle" t-att-index="line.index" style="margin-right:5px;" aria-label="Info" title="Info" data-toggle="tooltip"></a>
<a role="button" tabindex="0" class="js_payment_info fa fa-info-circle" t-att-index="line.index" style="margin-right:5px;" aria-label="Info" title="Payment Info" data-toggle="tooltip"></a>
</td>
<td>
<i class="o_field_widget text-right o_payment_label">Paid on <t t-esc="line.date"></t></i>
@@ -48,25 +48,9 @@
<t t-name="PaymentPopOver">
<div>
<table>
<tr>
<td><strong>Name: </strong></td>
<td style="text-align:right;"><t t-esc="name"/></td>
</tr>
<tr>
<td><strong>Date: </strong></td>
<td style="text-align:right;"><t t-esc="date"/></td>
</tr>
<tr>
<td><strong>Payment Method: </strong></td>
<td style="text-align:right;"><t t-esc="journal_name"/></td>
</tr>
<tr>
<td><strong>Memo: </strong></td>
<td style="text-align:right;"><t t-esc="ref"/></td>
</tr>
<tr>
<td><strong>Amount: </strong></td>
<td style="text-align:right;">
<td>
<t t-if="position === 'before'">
<t t-esc="currency"/>
</t>
@@ -76,6 +60,18 @@
</t>
</td>
</tr>
<tr>
<td><strong>Memo: </strong></td>
<td><t t-esc="ref"/></td>
</tr>
<tr>
<td><strong>Date: </strong></td>
<td><t t-esc="date"/></td>
</tr>
<tr>
<td><strong>Payment Journal: </strong></td>
<td><t t-esc="journal_name"/><span t-if="payment_method_name"> (<t t-esc="payment_method_name"/>)</span></td>
</tr>
</table>
</div>
<button class="btn btn-sm btn-primary js_unreconcile_payment float-left" t-att-payment-id="payment_id" style="margin-top:5px; margin-bottom:5px;">Unreconcile</button>
@@ -10,28 +10,15 @@
</div>
</div>
<t t-name="reconciliation.control.pager">
<div class="progress progress-reconciliation">
<div aria-valuemin="0" t-att-aria-valuenow="widget._initialState.valuenow" t-att-aria-valuemax="widget._initialState.valuemax" class="progress-bar" role="progressbar" style="width: 0%;"><span class="valuenow"><t t-esc="widget._initialState.valuenow"/></span> / <span class="valuemax"><t t-esc="widget._initialState.valuemax"/></span></div>
</div>
</t>
<t t-name="reconciliation.statement">
<div t-if="widget._initialState.valuemax">
<div>
<t t-if="widget._initialState.bank_statement_id">
<h1 class="statement_name editable" title="Click to Rename" />
</t>
<t t-else="">
<h1 class="statement_name" />
</t>
<div class="o_filter_input_wrapper">
<span class="searchIcon"><i class="fa fa-search" role="img" aria-label="Search" title="Search"></i></span>
<input class="reconciliation_search_input o_filter_input" type="text" placeholder="Search..." />
</div>
<h1 class="statement_name_edition" style="display: none;"/>
<div class="progress progress-striped">
<div class="progress-text">
<span class="valuenow"><t t-esc="widget._initialState.valuenow"/></span> / <span class="valuemax"><t t-esc="widget._initialState.valuemax"/></span>
</div>
<div aria-valuemin="0" t-att-aria-valuenow="widget._initialState.valuenow" class="progress-bar" role="progressbar" style="width: 0%;" t-att-aria-valuemax="widget._initialState.valuemax"></div>
</div>
<div class="notification_area"/>
</div>
<div class="notification_area"/>
<div class="o_reconciliation_lines"/>
<div t-if="widget._initialState.valuemax &gt; widget._initialState.defaultDisplayQty">
<button class="btn btn-secondary js_load_more">Load more</button>
@@ -52,6 +39,31 @@
<t t-jquery=".o_view_noreconciliation" t-operation="append">
<p><b>Good Job!</b> There is nothing to reconcile.</p>
<p>All invoices and payments have been matched, your accounts' balances are clean.</p>
<p>
From now on, you may want to:
<ul>
<li>Check that you have no bank statement lines to <a href="#"
rel="do_action"
data-tag="bank_statement_reconciliation_view">reconcile</a></li>
<li>Verify <a href="#"
rel="do_action"
data-action_name="Unpaid Customer Invoices"
data-model="account.move"
data-domain="[('type', 'in', ('out_invoice', 'out_refund'))]"
data-context="{'search_default_unpaid': 1}">unpaid invoices</a> and follow-up customers</li>
<li>Pay your <a href="#"
rel="do_action"
data-action_name="Unpaid Vendor Bills"
data-model="account.move"
data-domain="[('type', 'in', ('in_invoice', 'in_refund'))]"
data-context="{'search_default_unpaid': 1}">vendor bills</a></li>
<li>Check all <a href="#"
rel="do_action"
data-action_name="Unreconciled Entries"
data-model="account.move.line"
data-context="{'search_default_unreconciled': 1}">unreconciled entries</a></li>
</ul>
</p>
</t>
</t>
@@ -67,7 +79,7 @@
<t t-if="context.journal_id">
<button class="button_back_to_statement btn btn-secondary" t-att-data_journal_id='context.journal_id'>Go to bank statement(s)</button>
</t>
<t t-if="context['active_model'] === 'account.bank.statement.line'">
<t t-if="context['active_model'] === 'account.bank.statement'">
<button class="button_close_statement btn btn-primary" style="display: inline-block;">Close statement</button>
</t>
</p>
@@ -76,18 +88,17 @@
<t t-name="reconciliation.line">
<t t-set="state" t-value="widget._initialState"/>
<div class="o_reconciliation_line" t-att-data-mode="state.mode">
<div class="o_reconciliation_line" t-att-data-mode="state.mode" tabindex="0">
<table class="accounting_view">
<caption style="caption-side: top;">
<div class="float-right o_buttons">
<button t-attf-class="o_validate btn btn-secondary #{!state.balance.type ? '' : 'd-none'}">Validate</button>
<button t-attf-class="o_reconcile btn btn-primary #{state.balance.type &gt; 0 ? '' : 'd-none'}">Reconcile</button>
<span t-attf-class="o_no_valid text-danger #{state.balance.type &lt; 0 ? '' : 'd-none'}">Select a partner or choose a counterpart</span>
<button t-attf-class="o_no_valid btn btn-secondary #{state.balance.type &lt; 0 ? '' : 'd-none'}" disabled="disabled" data-toggle="tooltip" title="Select a partner or choose a counterpart" accesskey="">Validate</button>
<button t-attf-class="o_validate btn btn-secondary #{!state.balance.type ? '' : 'd-none'}" accesskey="">Validate</button>
<button t-attf-class="o_reconcile btn btn-primary #{state.balance.type &gt; 0 ? '' : 'd-none'}" accesskey="">Validate</button>
</div>
</caption>
<thead>
<tr>
<td class="cell_action"><span class="toggle_match fa fa-cog" aria-label="Settings" role="img" title="Settings"></span></td>
<td class="cell_account_code"><t t-esc="state.st_line.account_code"/></td>
<td class="cell_due_date"><t t-esc="state.st_line.date"/></td>
<td class="cell_label"><t t-if="state.st_line.name" t-esc="state.st_line.name"/> <t t-if="state.st_line.amount_currency_str"> (<t t-esc="state.st_line.amount_currency_str"/>)</t></td>
@@ -103,10 +114,28 @@
<t t-call="reconciliation.line.balance"/>
</tfoot>
</table>
<div class="match">
<t t-call="reconciliation.line.match"/>
<div class="o_notebook">
<ul class="nav nav-tabs ml-0 mr-0">
<li class="nav-item" t-attf-title="{{'Match statement with existing lines on receivable/payable accounts&lt;br&gt;* Black line: existing journal entry that should be matched&lt;br&gt;* Blue lines: existing payment that should be matched'}}" data-toggle="tooltip"><a data-toggle="tab" disable_anchor="true" t-attf-href="#notebook_page_match_rp_#{state.st_line.id}" class="nav-link active nav-match_rp" role="tab" aria-selected="true">Customer/Vendor Matching</a></li>
<li class="nav-item" title="Match with entries that are not from receivable/payable accounts" data-toggle="tooltip"><a data-toggle="tab" disable_anchor="true" t-attf-href="#notebook_page_match_other_#{state.st_line.id}" class="nav-link nav-match_other" role="tab" aria-selected="false">Miscellaneous Matching</a></li>
<li class="nav-item" title="Create a counterpart" data-toggle="tooltip"><a data-toggle="tab" disable_anchor="true" t-attf-href="#notebook_page_create_#{state.st_line.id}" class="nav-link nav-create" role="tab" aria-selected="false">Manual Operations</a></li>
</ul>
<div class="tab-content">
<div class="tab-pane active" t-attf-id="notebook_page_match_rp_#{state.st_line.id}">
<div class="match">
<t t-call="reconciliation.line.match"/>
</div>
</div>
<div class="tab-pane" t-attf-id="notebook_page_match_other_#{state.st_line.id}">
<div class="match">
<t t-call="reconciliation.line.match"/>
</div>
</div>
<div class="tab-pane" t-attf-id="notebook_page_create_#{state.st_line.id}">
<div class="create"></div>
</div>
</div>
</div>
<div class="create"></div>
</div>
</t>
@@ -126,17 +155,17 @@
</t>
<t t-jquery=".accounting_view thead tr" t-operation="replace">
<tr>
<td class="cell_action"><span class="toggle_match fa fa-cog" aria-label="Settings" role="img" title="Settings"></span></td>
<td colspan="3"><span/><span t-if="state.last_time_entries_checked">Last Reconciliation: <t t-esc="state.last_time_entries_checked"/></span></td>
<td colspan="2"><t t-esc="state.st_line.account_code"/></td>
<td class="cell_info_popover"></td>
</tr>
</t>
<t t-jquery='div[t-attf-id*="notebook_page_match_rp"]' t-operation="replace"/>
<t t-jquery='a[t-attf-href*="notebook_page_match_rp"]' t-operation="replace"/>
</t>
<t t-name="reconciliation.line.balance">
<tr t-if="state.balance.show_balance">
<td class="cell_action"><span role="img" class="toggle_create fa fa-play" aria-label="Run" title="Run"></span></td>
<td class="cell_account_code"><t t-esc="state.balance.account_code"/></td>
<td class="cell_due_date"></td>
<td class="cell_label"><t t-if="state.st_line.partner_id">Open balance</t><t t-else="">Choose counterpart or Create Write-off</t></td>
@@ -149,7 +178,7 @@
<div t-name="reconciliation.line.match">
<div class="match_controls">
<input class="filter o_input" placeholder="Filter..." type="text" value=""/>
<span><input class="filter o_input" placeholder="Filter on account, label, partner, amount,..." type="text" t-att-value="state['filter_{{state.mode}}']"/></span>
<button class="btn btn-secondary btn-sm fa fa-search" type="button"></button>
</div>
<table>
@@ -182,52 +211,58 @@
</div>
</div>
</div>
<table class="float-left">
<tr class="create_account_id">
<td class="o_td_label">Account</td>
<td class="o_td_field"></td>
</tr>
<tr class="create_tax_id">
<td class="o_td_label">Taxes</td>
<td class="o_td_field"></td>
</tr>
<tr class="create_analytic_account_id" groups="analytic.group_analytic_accounting">
<td class="o_td_label">Analytic Acc.</td>
<td class="o_td_field"></td>
</tr>
<tr class="create_analytic_tag_ids" groups="analytic.group_analytic_tags">
<td class="o_td_label">Analytic Tags.</td>
<td class="o_td_field"></td>
</tr>
</table>
<table class="float-right">
<tbody>
<tr class="create_journal_id" style="display: none;">
<td class="o_td_label">Journal</td>
<td class="o_td_field"></td>
</tr>
<tr class="create_label">
<td class="o_td_label">Label</td>
<td class="o_td_field"></td>
</tr>
<tr class="create_amount">
<td class="o_td_label">Amount</td>
<td class="o_td_field"></td>
</tr>
<tr class="create_force_tax_included d-none">
<td class="o_td_label">Tax Included in Price</td>
<td class="o_td_field"></td>
</tr>
<tr class="create_date d-none">
<td class="o_td_label">Writeoff Date</td>
<td class="o_td_field"></td>
</tr>
<tr class="create_to_check"> <!--TODO d-none maybe see with avw-->
<td class="o_td_label">To Check</td>
<td class="o_td_field"></td>
</tr>
</tbody>
</table>
<div class="clearfix o_form_sheet">
<div class="o_group">
<table class="o_group o_inner_group o_group_col_6">
<tbody>
<tr class="create_account_id">
<td class="o_td_label"><label class="o_form_label">Account</label></td>
<td class="o_td_field"></td>
</tr>
<tr class="create_tax_id">
<td class="o_td_label"><label class="o_form_label">Taxes</label></td>
<td class="o_td_field"></td>
</tr>
<tr class="create_analytic_account_id" groups="analytic.group_analytic_accounting">
<td class="o_td_label"><label class="o_form_label">Analytic Acc.</label></td>
<td class="o_td_field"></td>
</tr>
<tr class="create_analytic_tag_ids" groups="analytic.group_analytic_tags">
<td class="o_td_label"><label class="o_form_label">Analytic Tags.</label></td>
<td class="o_td_field"></td>
</tr>
</tbody>
</table>
<table class="o_group o_inner_group o_group_col_6">
<tbody>
<tr class="create_journal_id" style="display: none;">
<td class="o_td_label"><label class="o_form_label">Journal</label></td>
<td class="o_td_field"></td>
</tr>
<tr class="create_label">
<td class="o_td_label"><label class="o_form_label">Label</label></td>
<td class="o_td_field"></td>
</tr>
<tr class="create_amount">
<td class="o_td_label"><label class="o_form_label">Amount</label></td>
<td class="o_td_field"></td>
</tr>
<tr class="create_force_tax_included d-none">
<td class="o_td_label"><label class="o_form_label">Tax Included in Price</label></td>
<td class="o_td_field"></td>
</tr>
<tr class="create_date d-none">
<td class="o_td_label"><label class="o_form_label">Writeoff Date</label></td>
<td class="o_td_field"></td>
</tr>
<tr class="create_to_check">
<td class="o_td_label"><label class="o_form_label">To Check</label></td>
<td class="o_td_field"></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="add_line_container">
<a class="add_line" t-att-style="!state.balance.amout ? 'display: none;' : null"><i class="fa fa-plus-circle"/> Save and New</a>
</div>
@@ -236,7 +271,6 @@
<t t-name="reconciliation.line.mv_line.amount">
<span t-att-class="(line.is_move_line &amp;&amp; proposition == true) ? 'cell' : ''">
<span class="line_amount">
<span t-if="line.amount_currency_str"
t-attf-class="o_multi_currency o_multi_currency_color_#{line.currency_id%8} line_info_button fa fa-money"
@@ -260,18 +294,17 @@
<t t-name="reconciliation.line.mv_line">
<tr t-if="line.display !== false" t-attf-class="mv_line #{line.already_paid ? ' already_reconciled' : ''} #{line.__invalid ? 'invalid' : ''} #{line.is_tax ? 'is_tax' : ''}" t-att-data-line-id="line.id" t-att-data-selected="selected">
<td class="cell_action"><span class="fa fa-add-remove" role="img" aria-label="Set" title="Set"/></td>
<td class="cell_account_code"><t t-esc="line.account_code"/></td>
<td class="cell_account_code"><t t-esc="line.account_code"/>&#8203;</td> <!-- zero width space to make empty lines the height of the text -->
<td class="cell_due_date">
<t t-if="typeof(line.id) != 'number' &amp;&amp; line.amount">
<span class="badge badge-secondary">New</span>
</t>
<t t-else="" t-esc="line.date_maturity === false ? line.date : line.date_maturity"/>
<t t-else="" t-esc="line.date_maturity || line.date"/>
</td>
<td class="cell_label">
<t t-if="line.partner_id &amp;&amp; line.partner_id !== state.st_line.partner_id">
<t t-if="line.partner_name.length">
<t t-esc="line.partner_name"/>:
<span class="font-weight-bold" t-esc="line.partner_name"/>:
</t>
</t>
<t t-esc="line.label || line.name"/>
@@ -296,12 +329,12 @@
<t t-name="reconciliation.line.mv_line.details">
<table class='details'>
<tr t-if="line.account_code"><td>Account</td><td><t t-esc="line.account_code"/> <t t-esc="line.account_name"/></td></tr>
<tr><td>Date</td><td><t t-esc="line.date"/></td></tr>
<tr><td>Due Date</td><td><t t-esc="line.date_maturity || line.date"/></td></tr>
<tr><td>Journal</td><td><t t-esc="line.journal_id[1]"/></td></tr>
<tr t-if="line.partner_id"><td>Partner</td><td><t t-esc="line.partner_name"/></td></tr>
<tr><td>Label</td><td><t t-esc="line.label"/></td></tr>
<tr t-if="line.ref"><td>Ref</td><td><t t-esc="line.ref"/></td></tr>
<tr t-if="line.partner_id"><td>Partner</td><td><t t-esc="line.partner_name"/></td></tr>
<tr><td>Date</td><td><t t-esc="line.date"/></td></tr>
<tr><td>Due Date</td><td><t t-esc="line.date_maturity === false ? line.date : line.date_maturity"/></td></tr>
<tr><td>Amount</td><td><t t-raw="line.total_amount_str"/><t t-if="line.total_amount_currency_str"> (<t t-esc="line.total_amount_currency_str"/>)</t></td></tr>
<tr t-if="line.is_partially_reconciled"><td>Residual</td><td>
<t t-raw="line.amount_str"/><t t-if="line.amount_currency_str"> (<t t-esc="line.amount_currency_str"/>)</t>
@@ -192,8 +192,8 @@ var db = {
{'second_analytic_account_id': false, 'second_amount_type': "percentage", 'second_journal_id': false, 'id': 2, 'analytic_account_id': false, 'display_name': "Perte et Profit", 'rule_type': 'writeoff_button', 'second_tax_ids': [], 'has_second_line': false, 'journal_id': false, 'label': false, 'second_label': false, 'second_account_id': false, 'account_id': 283, 'company_id': [1, "Demo SPRL"], 'tax_ids': [], 'amount_type': "percentage", 'name': "Perte et Profit", 'amount': 100.0, 'second_amount': 100.0, 'match_journal_ids': []},
{'second_analytic_account_id': false, 'second_amount_type': "percentage", 'second_journal_id': false, 'id': 5, 'analytic_account_id': false, 'display_name': "Fs bank", 'rule_type': 'writeoff_button', 'second_tax_ids': [], 'has_second_line': false, 'journal_id': false, 'label': false, 'second_label': false, 'second_account_id': false, 'account_id': 284, 'company_id': [1, "Demo SPRL"], 'tax_ids': [], 'amount_type': "percentage", 'name': "Fs bank", 'amount': 100.0, 'second_amount': 100.0},
{'second_analytic_account_id': false, 'second_amount_type': "percentage", 'second_journal_id': false, 'id': 8, 'analytic_account_id': false, 'display_name': "Caisse Sand.", 'rule_type': 'writeoff_button', 'second_tax_ids': [], 'has_second_line': false, 'journal_id': false, 'label': "Caisse Sand.", 'second_label': false, 'second_account_id': false, 'account_id': 308, 'company_id': [1, "Demo SPRL"], 'tax_ids': [], 'amount_type': "percentage", 'name': "Caisse Sand.", 'amount': 100.0, 'second_amount': 100.0, 'match_journal_ids': []},
{'second_analytic_account_id': false, 'second_amount_type': "percentage", 'second_journal_id': false, 'id': 3, 'analytic_account_id': false, 'display_name': "ATOS", 'rule_type': 'writeoff_button', 'second_tax_ids': [7], 'has_second_line': true, 'journal_id': false, 'label': "ATOS Banque", 'second_label': "ATOS Frais", 'second_account_id': 286, 'account_id': 285, 'company_id': [1, "Demo SPRL"], 'tax_ids': [6], 'amount_type': "percentage", 'name': "ATOS", 'amount': 97.5, 'second_amount': 2.5},
{'second_analytic_account_id': false, 'second_amount_type': "percentage", 'second_journal_id': false, 'id': 10, 'analytic_account_id': false, 'display_name': "Double", 'rule_type': 'writeoff_button', 'second_tax_ids': [], 'has_second_line': true, 'journal_id': false, 'label': "Double Banque", 'second_label': "Double Frais", 'second_account_id': 286, 'account_id': 285, 'company_id': [1, "Demo SPRL"], 'tax_ids': [], 'amount_type': "percentage", 'name': "Double", 'amount': 97.5, 'second_amount': 2.5, 'match_journal_ids': [], 'analytic_tag_ids': [1,2]},
{'second_analytic_account_id': false, 'second_amount_type': "percentage", 'second_journal_id': false, 'id': 3, 'analytic_account_id': false, 'display_name': "ATOS", 'rule_type': 'writeoff_button', 'second_tax_ids': [7], 'has_second_line': true, 'journal_id': false, 'label': "ATOS Banque", 'second_label': "ATOS Frais", 'second_account_id': 286, 'account_id': 285, 'company_id': [1, "Demo SPRL"], 'tax_ids': [6], 'amount_type': "percentage", 'name': "ATOS", 'amount': 97.5, 'second_amount': -14.75},
{'second_analytic_account_id': false, 'second_amount_type': "percentage", 'second_journal_id': false, 'id': 10, 'analytic_account_id': false, 'display_name': "Double", 'rule_type': 'writeoff_button', 'second_tax_ids': [], 'has_second_line': true, 'journal_id': false, 'label': "Double Banque", 'second_label': "Double Frais", 'second_account_id': 286, 'account_id': 285, 'company_id': [1, "Demo SPRL"], 'tax_ids': [], 'amount_type': "percentage", 'name': "Double", 'amount': 97.5, 'second_amount': 100, 'match_journal_ids': [], 'analytic_tag_ids': [1,2]},
]
},
'account.reconciliation.widget': {
@@ -217,6 +217,9 @@ var db = {
get_move_lines_for_bank_statement_line: function (args) {
var partner_id = args.splice(1, 1)[0];
var excluded_ids = args.splice(1, 1)[0];
var mode = args.splice(-1, 1) [0]
if (mode === 'other') return Promise.resolve([])
args.splice(-1,1); // ignore limit
var key = JSON.stringify(args);
if (!Datas.used.mv_lines[key]) {
throw new Error("Unknown parameters for get_move_lines_for_bank_statement_line: '"+ key + "'");
@@ -248,6 +251,7 @@ var db = {
},
get_move_lines_for_manual_reconciliation: function (args) {
var excluded_ids = args.splice(2, 1)[0];
args.splice(-1,1); // ignore limit
var key = JSON.stringify(args);
if (!Datas.used.move_lines_for_manual_reconciliation[key]) {
throw new Error("Unknown parameters for get_move_lines_for_manual_reconciliation: '"+ key + "'");
@@ -417,18 +421,18 @@ var data_widget = [
var mv_lines = {
'[]': [],
'[5,"",0,5]': [
'[5,"",0]': [
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-07", 'date': "2017-01-08", 'total_amount_str': "$ 650.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0002", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 109, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 650.00", 'debit': 650.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-07", 'date': "2017-01-08", 'total_amount_str': "$ 525.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0003", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 112, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 525.00", 'debit': 525.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-07", 'date': "2017-01-08", 'total_amount_str': "$ 650.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0012", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 134, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 650.00", 'debit': 650.0, 'account_id': [287, "101200 Account Receivable"], 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 4,610.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 106, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 4,610.00", 'debit': 4610.0, 'account_id': [287, "101200 Account Receivable"], 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "payable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 10,000.00", 'partner_id': 12, 'account_name': "Account Payable", 'name': "BILL/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 114, 'credit': 10000.0, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 10,000.00", 'debit': 0.0, 'account_id': [284, "101110 Stock Valuation Account"], 'account_code': "111100", 'ref': "", 'already_paid': false}
],
'[5,"b",0,5]': [
'[5,"b",0]': [
{'account_type': "liquidity", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-01-23", 'date': "2017-01-23", 'total_amount_str': "$ 100.00", 'partner_id': 8, 'account_name': "Bank", 'name': "BNK1/2017/0003: CUST.IN/2017/0001", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 394, 'credit': 0.0, 'journal_id': "Bank", 'amount_str': "$ 100.00", 'debit': 100.0, 'account_code': "101401", 'ref': "", 'already_paid': true},
{'account_type': "liquidity", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-01-23", 'date': "2017-01-23", 'total_amount_str': "$ 525.50", 'partner_id': 8, 'account_name': "Bank", 'name': "BNK1/2017/0004: CUST.IN/2017/0002", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 396, 'credit': 0.0, 'journal_id': "Bank", 'amount_str': "$ 525.50", 'debit': 525.5, 'account_code': "101401", 'ref': "INV/2017/0003", 'already_paid': true},
],
'[6,"",0,5]': [
'[6,"",0]': [
{'account_type': "liquidity", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-01-23", 'date': "2017-01-23", 'total_amount_str': "$ 376.00", 'partner_id': 7, 'account_name': "Bank", 'name': "BNK1/2017/0002: SUPP.OUT/2017/0002", 'partner_name': "ASUSTeK", 'total_amount_currency_str': "", 'id': 392, 'credit': 376.0, 'journal_id': "Bank", 'amount_str': "$ 376.00", 'debit': 0.0, 'account_code': "101401", 'ref': "BILL/2017/0003", 'already_paid': true},
{'account_type': "liquidity", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-01-23", 'date': "2017-01-23", 'total_amount_str': "$ 100.00", 'partner_id': 8, 'account_name': "Bank", 'name': "BNK1/2017/0003: CUST.IN/2017/0001", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 394, 'credit': 0.0, 'journal_id': "Bank", 'amount_str': "$ 100.00", 'debit': 100.0, 'account_code': "101401", 'ref': "", 'already_paid': true},
{'account_type': "payable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 10,000.00", 'partner_id': 12, 'account_name': "Account Payable", 'name': "BILL/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 114, 'credit': 10000.0, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 10,000.00", 'debit': 0.0, 'account_code': "111100", 'ref': "", 'already_paid': false},
@@ -438,12 +442,12 @@ var mv_lines = {
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 4,610.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 106, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 4,610.00", 'debit': 4610.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "payable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-15", 'total_amount_str': "$ 5,749.99", 'partner_id': 7, 'account_name': "Account Payable", 'name': "BILL/2017/0002", 'partner_name': "ASUSTeK", 'total_amount_currency_str': "", 'id': 117, 'credit': 5749.99, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 5,749.99", 'debit': 0.0, 'account_code': "111100", 'ref': "", 'already_paid': false}
],
'[6,"",5,5]': [
'[6,"",5]': [
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 4,610.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 106, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 4,610.00", 'debit': 4610.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "payable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 10,000.00", 'partner_id': 12, 'account_name': "Account Payable", 'name': "BILL/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 114, 'credit': 10000.0, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 10,000.00", 'debit': 0.0, 'account_code': "111100", 'ref': "", 'already_paid': false},
{'account_type': "payable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-15", 'total_amount_str': "$ 5,749.99", 'partner_id': 7, 'account_name': "Account Payable", 'name': "BILL/2017/0002", 'partner_name': "ASUSTeK", 'total_amount_currency_str': "", 'id': 117, 'credit': 5749.99, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 5,749.99", 'debit': 0.0, 'account_code': "111100", 'ref': "", 'already_paid': false}
],
'[7,"",0,5]': [
'[7,"",0]': [
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-07", 'date': "2017-01-08", 'total_amount_str': "$ 650.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0012", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 133, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 650.00", 'debit': 650.0, 'account_id': [287, "101200 Account Receivable"], 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 4,610.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 106, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 4,610.00", 'debit': 4610.0, 'account_id': [287, "101200 Account Receivable"], 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "payable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 10,000.00", 'partner_id': 12, 'account_name': "Account Payable", 'name': "BILL/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 114, 'credit': 10000.0, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 10,000.00", 'debit': 0.0, 'account_id': [284, "101110 Stock Valuation Account"], 'account_code': "111100", 'ref': "", 'already_paid': false},
@@ -453,17 +457,7 @@ var mv_lines = {
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-07", 'date': "2017-01-08", 'total_amount_str': "$ 650.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0002", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 109, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 650.00", 'debit': 650.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-22", 'date': "2017-01-23", 'total_amount_str': "$ 525.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0004", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 399, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 525.00", 'debit': 525.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
],
'[7,"",0,6]': [
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-07", 'date': "2017-01-08", 'total_amount_str': "$ 650.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0012", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 133, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 650.00", 'debit': 650.0, 'account_id': [287, "101200 Account Receivable"], 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 4,610.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 106, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 4,610.00", 'debit': 4610.0, 'account_id': [287, "101200 Account Receivable"], 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "payable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-28", 'date': "2017-01-01", 'total_amount_str': "$ 10,000.00", 'partner_id': 12, 'account_name': "Account Payable", 'name': "BILL/2017/0001", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 114, 'credit': 10000.0, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 10,000.00", 'debit': 0.0, 'account_id': [284, "101110 Stock Valuation Account"], 'account_code': "111100", 'ref': "", 'already_paid': false},
{'account_type': "liquidity", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-01-23", 'date': "2017-01-23", 'total_amount_str': "$ 376.00", 'partner_id': 7, 'account_name': "Bank", 'name': "BNK1/2017/0002: SUPP.OUT/2017/0002", 'partner_name': "ASUSTeK", 'total_amount_currency_str': "", 'id': 392, 'credit': 376.0, 'journal_id': "Bank", 'amount_str': "$ 376.00", 'debit': 0.0, 'account_code': "101401", 'ref': "BILL/2017/0003", 'already_paid': true},
{'account_type': "liquidity", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-01-23", 'date': "2017-01-23", 'total_amount_str': "$ 100.00", 'partner_id': 8, 'account_name': "Bank", 'name': "BNK1/2017/0003: CUST.IN/2017/0001", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 394, 'credit': 0.0, 'journal_id': "Bank", 'amount_str': "$ 100.00", 'debit': 100.0, 'account_code': "101401", 'ref': "", 'already_paid': true},
{'account_type': "liquidity", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-01-23", 'date': "2017-01-23", 'total_amount_str': "$ 525.50", 'partner_id': 8, 'account_name': "Bank", 'name': "BNK1/2017/0004: CUST.IN/2017/0002", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 396, 'credit': 0.0, 'journal_id': "Bank", 'amount_str': "$ 525.50", 'debit': 525.5, 'account_code': "101401", 'ref': "INV/2017/0003", 'already_paid': true},
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-07", 'date': "2017-01-08", 'total_amount_str': "$ 650.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0002", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 109, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 650.00", 'debit': 650.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-22", 'date': "2017-01-23", 'total_amount_str': "$ 525.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0004", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 399, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 525.00", 'debit': 525.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
],
'[8,"",0,5]': [],
'[8,"",0]': [],
};
var auto_reconciliation = {
@@ -521,7 +515,7 @@ var data_for_manual_reconciliation_widget = {
};
var move_lines_for_manual_reconciliation = {
'[287,8,"",0,5]': [
'[287,8,"",0]': [
{'account_type': "receivable", 'account_id': [287, "101200 Account Receivable"], 'amount_currency_str': "10,222.00 €", 'currency_id': 1, 'date_maturity': "2017-02-08", 'date': "2017-02-08", 'total_amount_str': "$ 11,000.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0004: Customer Payment", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 17, 'credit': 11000.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 11,000.00", 'debit': 0.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'account_id': [7, "101200 Account Receivable"], 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-09", 'date': "2017-02-09", 'total_amount_str': "$ 1,000.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0005: Customer Payment", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 19, 'credit': 1000.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 1,000.00", 'debit': 0.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'account_id': [287, "101200 Account Receivable"], 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-09", 'date': "2017-02-09", 'total_amount_str': "$ 180.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "BILL/2017/0003: Customer Payment", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 21, 'credit': 180.0, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 180.00", 'debit': 0.0, 'account_code': "101200", 'ref': "fddfgfdgfdgsdfg", 'already_paid': false},
@@ -529,7 +523,7 @@ var move_lines_for_manual_reconciliation = {
{'account_type': "receivable", 'account_id': [287, "101200 Account Receivable"], 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-03-10", 'date': "2017-02-08", 'total_amount_str': "$ 650.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0012", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 6, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 1000.00", 'debit': 1000.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'account_id': [287, "101200 Account Receivable"], 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-03-10", 'date': "2017-02-08", 'total_amount_str': "$ 525.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0003", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 9, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 525.00", 'debit': 525.0, 'account_code': "101200", 'ref': "", 'already_paid': false}
],
'[7,12,"",0,5]': [
'[7,12,"",0]': [
{'account_type': "receivable", 'account_id': [287, "101200 Account Receivable"], 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-08", 'date': "2017-02-08", 'total_amount_str': "$ 11,000.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0004: Customer Payment", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 17, 'credit': 11000.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 11,000.00", 'debit': 0.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'account_id': [7, "101200 Account Receivable"], 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-09", 'date': "2017-02-09", 'total_amount_str': "$ 1,000.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0005: Customer Payment", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 19, 'credit': 1000.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 1,000.00", 'debit': 0.0, 'account_code': "101200", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'account_id': [287, "101200 Account Receivable"], 'amount_currency': 100, 'amount_currency_str': "100.00 €", 'currency_id': 1, 'date_maturity': "2017-02-09", 'date': "2017-02-09", 'total_amount_str': "$ 170.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0003: Customer Payment", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 21, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 170.00", 'debit': 170.0, 'account_code': "101200", 'ref': "INV fddfgfdgfdgsdfg", 'already_paid': false},
@@ -537,16 +531,16 @@ var move_lines_for_manual_reconciliation = {
{'account_type': "receivable", 'account_id': [287, "101200 Account Receivable"], 'amount_currency': 170, 'amount_currency_str': "170.00 €", 'currency_id': 1, 'date_maturity': "2017-02-09", 'date': "2017-02-09", 'total_amount_str': "$ 100.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0003: Customer Payment", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 23, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 100.00", 'debit': 100.0, 'account_code': "101200", 'ref': "INV fddfgfdgfdgsdfg", 'already_paid': false},
{'account_type': "receivable", 'account_id': [287, "101200 Account Receivable"], 'amount_currency': 180, 'amount_currency_str': "180.00 €", 'currency_id': 1, 'date_maturity': "2017-02-10", 'date': "2017-02-10", 'total_amount_str': "$ 100.00", 'partner_id': 12, 'account_name': "101200 Account Receivable", 'name': "BILL/2017/0003: Customer Payment", 'partner_name': "Camptocamp", 'total_amount_currency_str': "", 'id': 24, 'credit': 100.0, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 100.00", 'debit': 0.0, 'account_code': "101200", 'ref': "fddfgfdgfdgsdfg", 'already_paid': false},
],
'[284,8,"",0,6]': [
'[284,8,"",0]': [
{'account_type': "receivable", 'account_id': [284, "111100 Account Payable"], 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-08", 'date': "2017-02-08", 'total_amount_str': "$ 11,000.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0004: Customer Payment", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 17, 'credit': 11000.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 11,000.00", 'debit': 0.0, 'account_code': "111100", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'account_id': [284, "111100 Account Payable"], 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-09", 'date': "2017-02-09", 'total_amount_str': "$ 1,000.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "INV/2017/0005: Customer Payment", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 19, 'credit': 1000.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 1,000.00", 'debit': 0.0, 'account_code': "111100", 'ref': "", 'already_paid': false},
{'account_type': "receivable", 'account_id': [284, "111100 Account Payable"], 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-09", 'date': "2017-02-09", 'total_amount_str': "$ 180.00", 'partner_id': 8, 'account_name': "101200 Account Receivable", 'name': "BILL/2017/0003: Customer Payment", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 21, 'credit': 180.0, 'journal_id': [2, "Vendor Bills"], 'amount_str': "$ 180.00", 'debit': 0.0, 'account_code': "111100", 'ref': "fddfgfdgfdgsdfg", 'already_paid': false},
],
'[283,null,"",0,5]': [
'[283,null,"",0]': [
{'account_type': "other", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-02-16", 'date': "2017-02-16", 'total_amount_str': "$ 1,000.00", 'partner_id': 8, 'account_name': "101000 Current Assets", 'name': "BNK1/2017/0006: Customer Payment", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 399, 'credit': 1000.0, 'journal_id': [3, "Bank"], 'amount_str': "$ 1,000.00", 'debit': 0.0, 'account_code': "101000", 'ref': "", 'already_paid': false},
{'account_type': "other", 'amount_currency_str': "", 'currency_id': false, 'date_maturity': "2017-03-18", 'date': "2017-02-16", 'total_amount_str': "$ 1,000.00", 'partner_id': 8, 'account_name': "101000 Current Assets", 'name': "INV/2017/0006", 'partner_name': "Agrolait", 'total_amount_currency_str': "", 'id': 402, 'credit': 0.0, 'journal_id': [1, "Customer Invoices"], 'amount_str': "$ 1,000.00", 'debit': 1000.0, 'account_code': "101000", 'ref': "", 'already_paid': false}
],
'[284,12,"",0,6]': [],
'[284,12,"",0]': [],
};
var session = {
@@ -610,11 +604,14 @@ QUnit.module('account', {
QUnit.module('Reconciliation');
QUnit.test('Reconciliation basic rendering', async function (assert) {
assert.expect(11);
assert.expect(10);
var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options);
testUtils.mock.addMockEnvironment(clientAction, {
'data': this.params.data,
data: this.params.data,
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
@@ -622,22 +619,20 @@ QUnit.module('account', {
assert.hasClass(widget.$el,'o_reconciliation_line', "should instance of widget reconciliation");
assert.containsOnce(widget, '.accounting_view', "should have one view");
assert.containsOnce(widget, '.match', "should have 'match' panel");
assert.containsN(widget, '[id*="notebook_page_match"]', 2, "should have 'match_rp' and 'match_other' panel");
assert.containsOnce(widget, '.create', "should have 'create' panel");
assert.strictEqual(widget.$('thead').text().replace(/[\n\r\s]+/g, ' '), " 101401 2017-01-01 SAJ/2014/002 and SAJ/2014/003 $ 1,175.00 ", "should display the line information");
assert.ok(widget.$('caption .o_field_many2one').length, "should display the many2one with to select a partner");
assert.containsN(clientAction, '[data-mode="inactive"]', 3, "should be as 'inactive' mode by default");
assert.strictEqual(widget.$el.data('mode'), 'match', "the first one should automatically switch to match mode");
assert.strictEqual(widget.$el.data('mode'), 'match_rp', "the first one should automatically switch to match_rp mode");
await testUtils.dom.click(widget.$('.accounting_view thead td:first'));
assert.strictEqual(widget.$el.data('mode'), 'inactive', "should switch to 'inactive' mode");
await testUtils.dom.click(widget.$('.accounting_view tfoot td:first'));
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_create"]'));
assert.strictEqual(widget.$el.data('mode'), 'create', "should switch to 'create' mode");
await testUtils.dom.click(widget.$('.accounting_view tfoot td:first'));
assert.strictEqual(widget.$el.data('mode'), 'match', "should switch to 'match' mode");
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_match_rp"]'));
assert.strictEqual(widget.$el.data('mode'), 'match_rp', "should switch to 'match_rp' mode");
clientAction.destroy();
});
@@ -657,6 +652,9 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
@@ -666,6 +664,7 @@ QUnit.module('account', {
assert.strictEqual(widget.$('.o_input_dropdown input').val(), "Agrolait", "the partner many2one should display agrolait");
assert.strictEqual(clientAction.widgets[2].$('.o_input_dropdown input').val(), "Camptocamp", "the partner many2one should display Camptocamp");
await testUtils.dom.click(widget.$('.accounting_view tfoot td:first'));
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_create"]'));
assert.containsN(widget, '.create input.o_input', 8,
"create panel should contain 8 fields (account_id, tax_id, journal_id, analytic_account_id, analytic_tag_ids, label, amount, date)");
assert.containsN(widget, '.create .create_account_id .o_required_modifier, .create .create_label .o_required_modifier, .create .create_amount .o_required_modifier', 3,
@@ -693,72 +692,80 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
var widget = clientAction.widgets[0];
assert.containsN(widget, '.mv_line', 2, "should display 2 account move lines");
assert.strictEqual(widget.$('.mv_line').text().replace(/[\n\r\s]+/g, ' '),
assert.containsN(widget, '.match:first .mv_line', 2, "should display 2 account move lines");
assert.strictEqual(widget.$('.match:first .mv_line').text().replace(/[\n\r\s]+/g, ' ').replace(/[\u200B]/g, ''),
" 101200 2017-02-07 INV/2017/0002 $ 650.00 101200 2017-02-07 INV/2017/0003 $ 525.00 ",
"should display 4 account move lines who contains the account_code, due_date, label and the credit");
assert.strictEqual(widget.$('.mv_line .cell_right:contains(".")').length, 2, "should display only the credit account move lines (hide the debit)");
assert.strictEqual(widget.$('.match:first .mv_line .cell_right:contains(".")').length, 2, "should display only the credit account move lines (hide the debit)");
await testUtils.dom.click(clientAction.widgets[1].$('.accounting_view thead td:first'));
assert.containsN(clientAction.widgets[1], '.mv_line', 5, "should display 5 account move lines");
assert.strictEqual(clientAction.widgets[1].$('.mv_line .cell_right:contains(".")').length, 3, "should display only the credit account move lines (hide the debit)");
assert.containsN(clientAction.widgets[1], '.mv_line.already_reconciled', 3, "should display 3 already reconciled account move lines");
assert.strictEqual(clientAction.widgets[1].$('.mv_line').text().replace(/[\n\r\s]+/g, ' '),
assert.strictEqual(clientAction.widgets[1].$('.mv_line').text().replace(/[\n\r\s]+/g, ' ').replace(/[\u200B]/g, ''),
" 101401 2017-01-23 ASUSTeK: BNK1/2017/0002: SUPP.OUT/2017/0002 : BILL/2017/0003 $ 376.00 101401 2017-01-23 Agrolait: BNK1/2017/0003: CUST.IN/2017/0001 $ 100.00 111100 2017-02-28 Camptocamp: BILL/2017/0001 $ 10,000.00 101401 2017-01-23 Agrolait: BNK1/2017/0004: CUST.IN/2017/0002 : INV/2017/0003 $ 525.50 101200 2017-02-07 Agrolait: INV/2017/0002 $ 650.00 ",
"should display 4 account move lines who contains the account_code, due_date, label and the credit");
assert.strictEqual(clientAction.widgets[1].$('.mv_line .cell_left:contains(".")').length, 2, "should display only 2 debit account move lines");
// load more
assert.ok(clientAction.widgets[1].$('.match div.load-more a:visible').length, "should display the 'load more' button");
assert.equal(clientAction.widgets[1].$('.match div.load-more span').text(), 3, "should display 3 items remaining");
await testUtils.dom.click(clientAction.widgets[1].$('.match div.load-more a'));
assert.ok(clientAction.widgets[1].$('.match:first div.load-more a:visible').length, "should display the 'load more' button");
assert.equal(clientAction.widgets[1].$('.match:first div.load-more span').text(), 3, "should display 3 items remaining");
await testUtils.dom.click(clientAction.widgets[1].$('.match:first div.load-more a'));
assert.containsN(clientAction.widgets[1], '.mv_line', 8, "should load 3 more records");
assert.notOk(clientAction.widgets[1].$('.match div.load-more a:visible').length, "should not display the 'load more' button anymore");
assert.notOk(clientAction.widgets[1].$('.match:first div.load-more a:visible').length, "should not display the 'load more' button anymore");
assert.ok(clientAction.widgets[0].$('caption button.btn-secondary:visible').length, "should display the 'validate' button");
assert.ok(clientAction.widgets[1].$('caption .text-danger:visible').length, "should display the 'Select a partner or choose a counterpart' message");
assert.ok(clientAction.widgets[2].$('caption button.btn-primary:visible').length, "should display the 'Reconcile' button");
assert.ok(clientAction.widgets[0].$('caption button.btn-secondary:visible').length, "should display the secondary 'Validate' button");
assert.equal(clientAction.widgets[1].$('caption button:disabled:visible').length, 1,"button should be disabled");
assert.ok(clientAction.widgets[2].$('caption button.btn-primary:visible').length, "should display the primary 'Validate' button");
await testUtils.dom.click(clientAction.widgets[3].$('.accounting_view thead td:first'));
assert.strictEqual(clientAction.widgets[3].$el.data('mode'), 'create', "should switch to 'create' mode instead 'match' mode when 'match' mode is empty");
assert.strictEqual(clientAction.widgets[3].$el.data('mode'), 'create', "should switch to 'create' mode instead of 'match_rp' mode when 'match_rp' mode is empty");
// open the first line
await testUtils.dom.click(widget.$('.accounting_view thead td:first'));
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_match_rp"]'));
// select propositions
await testUtils.dom.click( widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
// await testUtils.dom.click(widget.$('caption')); //why is it inactive?
testUtils.mock.intercept(clientAction, 'call_service', function (event) {
assert.deepEqual(event.data.args[1].args,
[[5],[{partner_id: 8, counterpart_aml_dicts: [{
"counterpart_aml_id": 109,
"credit": 650,
"debit": 0,
"name": "INV/2017/0002",
"analytic_tag_ids": [[6, null, []]]
},
{
"counterpart_aml_id": 112,
"credit": 525,
"debit": 0,
"name": "INV/2017/0003",
"analytic_tag_ids": [[6, null, []]]
}],
payment_aml_ids: [], new_aml_dicts: [], to_check: false}]],
"Should call process_bank_statement_line with ids");
var def = testUtils.makeTestPromise();
def.abort = function () {};
event.data.callback(def);
if (event.data.args[1].method == 'process_bank_statement_line') {
assert.deepEqual(event.data.args[1].args,
[[5],[{partner_id: 8, counterpart_aml_dicts: [{
"counterpart_aml_id": 109,
"credit": 650,
"debit": 0,
"name": "INV/2017/0002",
"analytic_tag_ids": [[6, null, []]]
},
{
"counterpart_aml_id": 112,
"credit": 525,
"debit": 0,
"name": "INV/2017/0003",
"analytic_tag_ids": [[6, null, []]]
}],
payment_aml_ids: [], new_aml_dicts: [], to_check: false}]],
"Should call process_bank_statement_line with args");
var def = testUtils.makeTestPromise();
def.abort = function () {};
event.data.callback(def);
}
});
// click on reconcile button
await testUtils.dom.click( widget.$('button.o_reconcile:not(:hidden)'));
await testUtils.dom.click(widget.$('.o_reconcile:visible'));
clientAction.destroy();
});
@@ -778,6 +785,9 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
@@ -825,6 +835,9 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
@@ -835,7 +848,7 @@ QUnit.module('account', {
await testUtils.dom.click(widget.$('.accounting_view thead td:first'),{allowInvisible:true});
await testUtils.nextTick();
// select propositions
await testUtils.dom.click(widget.$('.match .cell_account_code:first'),{allowInvisible:true});
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'),{allowInvisible:true});
await testUtils.nextTick();
// Ensure that when we validate a line with propositions and that there is a remaining balance
@@ -869,7 +882,7 @@ QUnit.module('account', {
});
QUnit.test('Reconciliation partial [REQUIRE FOCUS]', async function (assert) {
assert.expect(9);
assert.expect(8);
var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options);
testUtils.mock.addMockEnvironment(clientAction, {
@@ -907,20 +920,23 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
var widget = clientAction.widgets[0];
await testUtils.dom.click(widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
assert.equal( widget.$('.cell_right .edit_amount').length, 1, "should display the edition pencil");
widget = clientAction.widgets[1];
await testUtils.dom.click(widget.$('.accounting_view thead td:first'));
assert.strictEqual(widget.$('.match .mv_line[data-line-id=114] .cell_account_code:first()').length, 1, 'Should have line')
await testUtils.dom.click(widget.$('.match .mv_line[data-line-id=114] .cell_account_code'));
assert.strictEqual(widget.$('.match:first .mv_line[data-line-id=114] .cell_account_code:first()').length, 1, 'Should have line')
await testUtils.dom.click(widget.$('.match:first .mv_line[data-line-id=114] .cell_account_code'));
assert.equal( widget.$('.accounting_view tbody .cell_left .edit_amount').length, 1, "should display the edition pencil");
@@ -928,8 +944,7 @@ QUnit.module('account', {
await testUtils.dom.click(widget.$('.o_input_dropdown input'));
await testUtils.fields.editAndTrigger(widget.$('.o_input_dropdown input'),'',['keyup','blur']);
assert.strictEqual(widget.$('button.btn-primary:visible').length, 0, "should display the reconcile model buttons");
assert.strictEqual(widget.$('.text-danger:visible').length, 1, "should display counterpart alert");
assert.equal(clientAction.widgets[1].$('caption button:disabled:visible').length, 1,"button should be disabled");
await testUtils.dom.click(widget.$('.accounting_view .cell_left .edit_amount'));
assert.strictEqual(widget.$('.accounting_view .cell_left .edit_amount_input:not(.d-none)').length, 1, "should display the input field to edit amount");
// Edit amount
@@ -942,35 +957,13 @@ QUnit.module('account', {
clientAction.destroy();
});
QUnit.test('Reconciliation title', async function (assert) {
assert.expect(6);
var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options);
testUtils.mock.addMockEnvironment(clientAction, {
'data': this.params.data,
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
assert.strictEqual(clientAction.$('h1.statement_name:visible').text(), "BNK/2014/001", "Should display the statement name");
await testUtils.dom.click(clientAction.$('h1.statement_name'));
assert.containsNone(clientAction, 'h1.statement_name:visible', "Should hide the statement name title to edit the content");
assert.containsOnce(clientAction, 'h1.statement_name_edition:visible', "Should show the edition field of statement name");
await testUtils.fields.editAndTrigger(clientAction.$('h1.statement_name_edition input'), 'BNK/2014/001-BB', ['input', 'blur']);
assert.containsNone(clientAction, 'h1.statement_name_edition:visible', "Should hide the edition field of statement name");
assert.containsOnce(clientAction, 'h1.statement_name:visible', "Should show the statement name");
assert.strictEqual(clientAction.$('h1.statement_name:visible').text(), "BNK/2014/001-BB", "Should update the statement name");
clientAction.destroy();
});
QUnit.test('Reconciliation currencies', async function (assert) {
assert.expect(2);
var clientAction = new ReconciliationClientAction.StatementAction(null, this.params.options);
testUtils.mock.addMockEnvironment(clientAction, {
'data': this.params.data,
data: this.params.data,
session: this.params.session,
translateParameters: {
date_format: "%m/%d/%Y",
@@ -981,7 +974,10 @@ QUnit.module('account', {
decimal_point: ".",
id:1,
grouping: [3,0],
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
@@ -992,7 +988,7 @@ QUnit.module('account', {
"$ 1,175.00$ 32.58$ 2,000.00", "should display the different amounts with the currency");
// await testUtils.dom.click(widget.$('.accounting_view thead .mv_line td:first'));
assert.strictEqual(clientAction.$('.accounting_view tbody').text().replace(/[\n\r\s]+/g, ' '),
assert.strictEqual(clientAction.$('.accounting_view tbody').text().replace(/[\n\r\s]+/g, ' ').replace(/[\u200B]/g, ''),
" 101200 2017-02-07 INV/2017/0012 $ 650.00 ", "should display the created reconciliation line with the currency");
clientAction.destroy();
@@ -1010,6 +1006,7 @@ QUnit.module('account', {
'res.partner,false,search': '<search string="Partners">' +
'<field name="display_name" string="Name"/>' +
'</search>',
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
@@ -1017,12 +1014,12 @@ QUnit.module('account', {
await testUtils.nextTick();
var widget = clientAction.widgets[0];
assert.strictEqual(widget.$('.o_input_dropdown input').val(), "Agrolait", "the partner many2one should display agrolait");
assert.containsN(widget, '.match table tr', 2, "agrolait should have 2 propositions for reconciliation");
assert.containsN(widget, '.match:first table tr', 2, "agrolait should have 2 propositions for reconciliation");
// Adding the two propositions
// This is in order to try that after changing partner the propositions are emptied
await testUtils.dom.click(widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
assert.containsN(widget, '.accounting_view tbody tr', 2, "Both proposition should be selected");
// Similate changing partner to one that does not have propositions to see if create mode is open after
@@ -1032,7 +1029,7 @@ QUnit.module('account', {
clientAction._onAction({target: widget, name: 'change_partner', data: {data: {display_name: 'partner 1', id: 1}}, stopped: false});
await testUtils.nextTick();
assert.strictEqual(widget.$('.o_input_dropdown input').val(), "partner 1", "the partner many2one should display partner 1");
assert.containsNone(widget, '.match table tr.mv_line', "partner 1 should have 0 propositions for reconciliation");
assert.containsNone(widget, '.match:first table tr.mv_line', "partner 1 should have 0 propositions for reconciliation");
assert.strictEqual(widget.$el.data('mode'), 'create', "widget should be in create mode");
// Simulate changing partner
@@ -1041,7 +1038,7 @@ QUnit.module('account', {
clientAction._onAction({target: widget, name: 'change_partner', data: {data: {display_name: 'Camptocamp', id: 12}}, stopped: false});
await testUtils.nextTick();
assert.strictEqual(widget.$('.o_input_dropdown input').val(), "Camptocamp", "the partner many2one should display Camptocamp");
assert.containsN(widget, '.match table tr.mv_line', 3, "camptocamp should have 3 propositions for reconciliation");
assert.containsN(widget, '.match:first table tr.mv_line', 3, "camptocamp should have 3 propositions for reconciliation");
// Simulate changing partner with SelectCreateDialog
widget = clientAction.widgets[1];
@@ -1057,16 +1054,16 @@ QUnit.module('account', {
await testUtils.dom.click(widget.$('.accounting_view thead td:first'));
await testUtils.dom.click(widget.$('.accounting_view .mv_line .cell_label'));
assert.strictEqual(widget.$('.o_input_dropdown input').val(), "Camptocamp", "the partner many2one should display agrolait");
assert.containsN(widget, '.match table tr', 3, "Camptocamp should have 3 propositions for reconciliation");
assert.notOk(widget.$('.match div.load-more a:visible').length, "should not display the load more button");
assert.containsN(widget, '.match:first table tr', 3, "Camptocamp should have 3 propositions for reconciliation");
assert.notOk(widget.$('.match:first div.load-more a:visible').length, "should not display the load more button");
// Simulate remove partner
await testUtils.dom.click(widget.$('.o_input_dropdown input'));
await testUtils.fields.editAndTrigger(widget.$('.o_input_dropdown input'),'',['keyup','blur']);
assert.strictEqual(widget.$('.o_input_dropdown input').val(), "", "the partner many2one should be empty");
assert.containsN(widget, '.match table tr.mv_line', 5, "should have 5 propositions for reconciliation if partner is false");
assert.ok(widget.$('.match div.load-more a:visible').length, "should display the load more button");
assert.containsN(widget, '.match:first table tr.mv_line', 5, "should have 5 propositions for reconciliation if partner is false");
assert.ok(widget.$('.match:first div.load-more a:visible').length, "should display the load more button");
clientAction.destroy();
});
@@ -1087,6 +1084,9 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
@@ -1097,14 +1097,14 @@ QUnit.module('account', {
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), 'Open balance', "should display 'Open Balance' line with the rest to reconcile");
await testUtils.dom.click(widget.$('.accounting_view tfoot td:first'));
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_create"]'));
await testUtils.dom.click(widget.$('.create .create_account_id input'));
$('.ui-autocomplete .ui-menu-item a:contains(101200 Account Receivable)').trigger('mouseenter').trigger('click');
await testUtils.nextTick();
assert.notOk(widget.$('.accounting_view tfoot .cell_label').text(), "should not display 'Open Balance' line because the rest to reconcile is null");
assert.containsOnce(widget, '.accounting_view tbody tr', "should have only the created reconcile line");
assert.strictEqual(widget.$('.accounting_view tbody tr').text().replace(/[\n\r\s$,]+/g, ' '), " 101200 New SAJ/2014/002 and SAJ/2014/003 1175.00 ",
assert.strictEqual(widget.$('.accounting_view tbody tr').text().replace(/[\n\r\s$,]+/g, ' ').replace(/[\u200B]/g, ''), " 101200 New SAJ/2014/002 and SAJ/2014/003 1175.00 ",
"the new line should have the selected account, name and amout");
assert.ok(widget.$('caption button.btn-primary:visible').length, "should display the 'Reconcile' button");
@@ -1127,7 +1127,7 @@ QUnit.module('account', {
assert.strictEqual(widget.$('.accounting_view tbody .cell_right').text().trim().replace(/[\n\r\s\u00a0]+/g, ' '), "$ 1100.00", "should display the value 1100.00 in right column");
assert.strictEqual(widget.$('.accounting_view tfoot .cell_right').text(), "$ 75.00", "should display 'Open Balance' line because the rest to reconcile is 75.00");
assert.containsOnce(widget, '.accounting_view tbody tr', "should have ever only the created reconcile line");
assert.strictEqual(widget.$('.accounting_view tbody tr').text().replace(/[\n\r\s$,]+/g, ' '), " 101200 New SAJ/2014/002 and SAJ/2014/003 1100.00 ",
assert.strictEqual(widget.$('.accounting_view tbody tr').text().replace(/[\n\r\s$,]+/g, ' ').replace(/[\u200B]/g, ''), " 101200 New SAJ/2014/002 and SAJ/2014/003 1100.00 ",
"the new line should be update the amout");
assert.ok(widget.$('caption button.btn-secondary:visible').length, "should display the 'validate' button");
@@ -1142,11 +1142,10 @@ QUnit.module('account', {
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label').text(), "Open balance", "should display 'Open Balance'");
assert.strictEqual(widget.$('.accounting_view tfoot .cell_right').text(), "$ 175.00", "should display 'Open Balance' line because the rest to reconcile is 175.00");
assert.containsN(widget, '.accounting_view tbody tr', 2, "should have 2 created reconcile lines");
assert.strictEqual(widget.$('.accounting_view tbody tr:eq(1)').text().replace(/[\n\r\s$,]+/g, ' '), " 101000 New test0 100.00 ",
assert.strictEqual(widget.$('.accounting_view tbody tr:eq(1)').text().replace(/[\n\r\s$,]+/g, ' ').replace(/[\u200B]/g, ''), " 101000 New test0 100.00 ",
"the new line should have the selected account, name and amout");
await testUtils.dom.click(widget.$('.accounting_view tfoot td:first'));
await testUtils.dom.click(widget.$('.accounting_view tfoot td:first'));
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_create"]'));
assert.strictEqual(widget.$('.create .create_amount input').val(), "175.00", "should have '175.00' as default amount value");
@@ -1184,6 +1183,7 @@ QUnit.module('account', {
archs: {
"account.account,false,list": '<tree string="Account"><field name="code"/><field name="name"/></tree>',
"account.account,false,search": '<search string="Account"><field name="code"/></search>',
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
mockRPC: function (route, args) {
if (args.method === 'name_get') {
@@ -1199,14 +1199,14 @@ QUnit.module('account', {
var widget = clientAction.widgets[0];
// open the first line in write-off mode
await testUtils.dom.click(widget.$('.accounting_view tfoot td:first'));
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_create"]'));
// select an account with the many2one (drop down)
await testUtils.dom.click(widget.$('.create .create_account_id input'));
$('.ui-autocomplete .ui-menu-item a:contains(101200)').trigger('mouseenter').trigger('click');
await testUtils.nextTick();
assert.strictEqual(widget.$('.create .create_account_id input').val(), "101200 Account Receivable", "Display the selected account");
assert.strictEqual(widget.$('tbody:first .cell_account_code').text(), "101200", "Display the code of the selected account");
assert.strictEqual(widget.$('tbody:first .cell_account_code').text().replace(/[\u200B]/g, ''), "101200", "Display the code of the selected account");
// use the many2one select dialog to change the account
await testUtils.dom.click(widget.$('.create .create_account_id input'));
@@ -1219,7 +1219,7 @@ QUnit.module('account', {
def.resolve();
await testUtils.nextTick();
assert.strictEqual(widget.$('.create .create_account_id input').val(), "502 Account", "Display the selected account");
assert.strictEqual(widget.$('tbody:first .cell_account_code').text(), "502", "Display the code of the selected account");
assert.strictEqual(widget.$('tbody:first .cell_account_code').text().replace(/[\u200B]/g, ''), "502", "Display the code of the selected account");
clientAction.destroy();
});
@@ -1239,13 +1239,16 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
var widget = clientAction.widgets[0];
await testUtils.dom.click(widget.$('.accounting_view tfoot td:first'));
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_create"]'));
await testUtils.dom.click(widget.$('.create .create_account_id input'));
$('.ui-autocomplete .ui-menu-item a:contains(101000 Current Assets)').trigger('mouseenter').trigger('click');
await testUtils.nextTick();
@@ -1287,27 +1290,30 @@ QUnit.module('account', {
testUtils.mock.addMockEnvironment(clientAction, {
data: this.params.data,
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
var widget = clientAction.widgets[0];
await testUtils.dom.click(widget.$('.accounting_view tfoot td:first'));
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_create"]'));
await testUtils.dom.click(widget.$('.create .quick_add button:contains(ATOS)'));
assert.strictEqual(widget.$('.accounting_view tbody .cell_label, .accounting_view tbody .cell_right').text().replace(/[\n\r\s$,]+/g, ' '),
" ATOS Banque 1145.62 ATOS Frais 26.71 ATOS Banque Tax 20.00% 229.12 ATOS Frais Tax 10.00% include 2.67 ", "should display 4 lines");
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label, .accounting_view tfoot .cell_left').text().replace(/[\n\r\s$,]+/g, ' '),
"Open balance229.12", "should display the 'Open balance' line with value in left column");
" ATOS Banque 1145.63 ATOS Banque Tax 20.00% 229.13 ATOS Frais 26.78 ATOS Frais Tax 10.00% include 2.68 ", "should display 4 lines");
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label, .accounting_view tfoot .cell_left').text().replace(/[\n\r\s$,]+/g, ''),
"Openbalance229.22", "should display the 'Open balance' line with value in left column");
await testUtils.fields.editAndTrigger(widget.$('.create .create_amount input'), '100',['input']);
assert.strictEqual(widget.$('.accounting_view tbody').text().replace(/[\n\r\s$,]+/g, ' '),
" 101120 New ATOS Banque 1075.00 101130 New ATOS Frais 90.91 101120 New ATOS Banque Tax 20.00% 215.00 101300 New ATOS Frais Tax 10.00% include 9.09 ",
"should update the value of the 4 lines (because the line must have 100% of the value)");
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label, .accounting_view tfoot .cell_left').text().replace(/[\n\r\s$,]+/g, ' '),
"Open balance215.00", "should change the 'Open balance' line because the 20.00% tax is not an include tax");
assert.strictEqual(widget.$('.accounting_view tbody').text().replace(/[\n\r\s$,]+/g, ' ').replace(/[\u200B]/g, ''),
" 101120 New ATOS Banque 1145.63 101120 New ATOS Banque Tax 20.00% 229.13 101130 New ATOS Frais 90.91 101300 New ATOS Frais Tax 10.00% include 9.09 ",
"should update the value of the 2 lines (because the line + its tax must have 100% of the value)");
assert.strictEqual(widget.$('.accounting_view tfoot .cell_label, .accounting_view tfoot .cell_left').text().replace(/[\n\r\s$,]+/g, ''),
"Openbalance299.76", "should change the 'Open balance' line because the 20.00% tax is not an include tax");
await testUtils.dom.click(widget.$('.accounting_view tbody .cell_account_code:first'));
await testUtils.dom.click(widget.$('.accounting_view tbody .cell_label:first'));
@@ -1316,8 +1322,8 @@ QUnit.module('account', {
await testUtils.dom.click(widget.$('.create .quick_add button:contains(Double)'));
assert.strictEqual(widget.$('.accounting_view tbody').text().replace(/[\n\r\s$,]+/g, ' '),
" 101120 New Double Banque 1145.62 101130 New Double Frais 29.38 ",
assert.strictEqual(widget.$('.accounting_view tbody').text().replace(/[\n\r\s$,]+/g, ' ').replace(/[\u200B]/g, ''),
" 101120 New Double Banque 1145.63 101130 New Double Frais 29.37 ",
"should have a sum of reconciliation proposition amounts equal to the line amount");
clientAction.destroy();
@@ -1331,6 +1337,9 @@ QUnit.module('account', {
testUtils.mock.addMockEnvironment(clientAction, {
data: this.params.data,
session: this.params.session,
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
@@ -1348,13 +1357,14 @@ QUnit.module('account', {
" Agrolait 101200 ",
"should display the partner and the account code as title");
assert.strictEqual(clientAction.$('.o_reconciliation_line:first .match tr:first .cell_right').text().trim().replace(/[\n\r\s\u00a0]+/g, ' '),
assert.strictEqual(clientAction.$('.o_reconciliation_line:first .match:first tr:first .cell_right').text().trim().replace(/[\n\r\s\u00a0]+/g, ' '),
"$ 11,000.00", "sould display the line in $");
assert.strictEqual(clientAction.$('.o_reconciliation_line:first .match tr:first .cell_right .o_multi_currency').data('content'),
assert.strictEqual(clientAction.$('.o_reconciliation_line:first .match:first tr:first .cell_right .o_multi_currency').data('content'),
"10,222.00 €", "sould display the monetary information in €");
assert.containsOnce(clientAction, '.accounting_view:first .o_no_valid:visible', "should display the skip button");
await testUtils.dom.click(clientAction.$('.o_reconciliation_line:eq(1) .accounting_view'))
await testUtils.dom.click(clientAction.$('.accounting_view:eq(1) thead td:first'));
await testUtils.dom.click(clientAction.$('.o_reconciliation_line:eq(1) [data-line-id="21"] .cell_label'));
await testUtils.dom.click(clientAction.$('.o_reconciliation_line:eq(1) [data-line-id="22"] .cell_label'));
@@ -1386,8 +1396,8 @@ QUnit.module('account', {
*/
// modify the second line that is already in db to put it at $999
var indexModif = _.findIndex(this.params.mv_lines['[5,"",0,5]'], function (line) {return line.id === 112});
this.params.mv_lines['[5,"",0,5]'][indexModif] =
var indexModif = _.findIndex(this.params.mv_lines['[5,"",0]'], function (line) {return line.id === 112});
this.params.mv_lines['[5,"",0]'][indexModif] =
{account_type: "receivable", amount_currency_str: "", currency_id: false, date_maturity: "2017-02-07", date: "2017-01-08",
total_amount_str: "$ 999.00", partner_id: 8, account_name: "101200 Account Receivable", name: "INV/2017/0003",
partner_name: "Agrolait", total_amount_currency_str: "", id: 112, credit: 0.0, journal_id: [1, "Customer Invoices"],
@@ -1432,6 +1442,9 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
@@ -1440,12 +1453,12 @@ QUnit.module('account', {
var widget = clientAction.widgets[0];
// Add first invoice to reconcile fully
await testUtils.dom.click(widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
assert.ok( widget.$('.cell_right .edit_amount').length,
"should display the pencil to edit amount");
// Add second invoice to reconcile partially
await testUtils.dom.click( widget.$('.match .cell_account_code:first'));
await testUtils.dom.click( widget.$('.match:first .cell_account_code:first'));
// Edit amount on last invoice
await testUtils.dom.click(widget.$('.edit_amount:last()'));
@@ -1472,15 +1485,15 @@ QUnit.module('account', {
*/
// modify the invoice line to have their amount > payment
var indexInv1 = _.findIndex(this.params.mv_lines['[5,"",0,5]'], function (line) {return line.id === 109});
this.params.mv_lines['[5,"",0,5]'][indexInv1] =
var indexInv1 = _.findIndex(this.params.mv_lines['[5,"",0]'], function (line) {return line.id === 109});
this.params.mv_lines['[5,"",0]'][indexInv1] =
{account_type: "receivable", amount_currency_str: "", currency_id: false, date_maturity: "2017-02-07", date: "2017-01-08",
total_amount_str: "$ 1200.00", partner_id: 8, account_name: "101200 Account Receivable", name: "INV/2017/0002", partner_name: "Agrolait",
total_amount_currency_str: "", id: 109, credit: 0.0, journal_id: [1, "Customer Invoices"], amount_str: "$ 1200.00", debit: 1200.0,
account_code: "101200", ref: "", already_paid: false};
var indexInv2 = _.findIndex(this.params.mv_lines['[5,"",0,5]'], function (line) {return line.id === 112});
this.params.mv_lines['[5,"",0,5]'][indexInv2] =
var indexInv2 = _.findIndex(this.params.mv_lines['[5,"",0]'], function (line) {return line.id === 112});
this.params.mv_lines['[5,"",0]'][indexInv2] =
{account_type: "receivable", amount_currency_str: "", currency_id: false, date_maturity: "2017-02-07", date: "2017-01-08",
total_amount_str: "$ 1200.00", partner_id: 8, account_name: "101200 Account Receivable", name: "INV/2017/0003",
partner_name: "Agrolait", total_amount_currency_str: "", id: 112, credit: 0.0, journal_id: [1, "Customer Invoices"],
@@ -1532,6 +1545,9 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
@@ -1541,12 +1557,12 @@ QUnit.module('account', {
// Add first invoice
// There should be the opportunity to reconcile partially
await testUtils.dom.click(widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
assert.ok(widget.$('.cell_right .edit_amount').length,
"should display the pencil to edit amount");
// Add second invoice
await testUtils.dom.click(widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
assert.ok(widget.$('.cell_right .edit_amount').length,
"should display the pencil to edit amount");
@@ -1582,15 +1598,15 @@ QUnit.module('account', {
*/
// modify the invoice line to have their amount > payment
var indexInv1 = _.findIndex(this.params.mv_lines['[5,"",0,5]'], function (line) {return line.id === 109});
this.params.mv_lines['[5,"",0,5]'][indexInv1] =
var indexInv1 = _.findIndex(this.params.mv_lines['[5,"",0]'], function (line) {return line.id === 109});
this.params.mv_lines['[5,"",0]'][indexInv1] =
{account_type: "receivable", amount_currency_str: "", currency_id: false, date_maturity: "2017-02-07", date: "2017-01-08",
total_amount_str: "$ 1200.00", partner_id: 8, account_name: "101200 Account Receivable", name: "INV/2017/0002", partner_name: "Agrolait",
total_amount_currency_str: "", id: 109, credit: 0.0, journal_id: [1, "Customer Invoices"], amount_str: "$ 1200.00", debit: 1200.0,
account_code: "101200", ref: "", already_paid: false};
var indexInv2 = _.findIndex(this.params.mv_lines['[5,"",0,5]'], function (line) {return line.id === 112});
this.params.mv_lines['[5,"",0,5]'][indexInv2] =
var indexInv2 = _.findIndex(this.params.mv_lines['[5,"",0]'], function (line) {return line.id === 112});
this.params.mv_lines['[5,"",0]'][indexInv2] =
{account_type: "receivable", amount_currency_str: "", currency_id: false, date_maturity: "2017-02-07", date: "2017-01-08",
total_amount_str: "$ 1200.00", partner_id: 8, account_name: "101200 Account Receivable", name: "INV/2017/0003",
partner_name: "Agrolait", total_amount_currency_str: "", id: 112, credit: 0.0, journal_id: [1, "Customer Invoices"],
@@ -1636,6 +1652,9 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
@@ -1645,12 +1664,12 @@ QUnit.module('account', {
// Add first invoice
// There should be the opportunity to reconcile partially
await testUtils.dom.click(widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
assert.ok(widget.$('.cell_right .edit_amount').length,
"should display the pencil to edit amount");
// Add second invoice
await testUtils.dom.click(widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
assert.ok(widget.$('.cell_right .edit_amount').length,
"should display the pencil to edit amount");
@@ -1707,6 +1726,9 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
@@ -1716,12 +1738,14 @@ QUnit.module('account', {
var widget = clientAction.widgets[0];
// Add first prop
await testUtils.dom.click(widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
assert.equal( widget.$('.cell_right .edit_amount').length, 0, "should not display the pencil to edit amount");
// Add second prop
await testUtils.dom.click(widget.$('.match .cell_account_code:first'));
await testUtils.dom.click(widget.$('.match:first .cell_account_code:first'));
// Check that a create form is here
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_create"]'));
var writeOffCreate = widget.$('div.create');
assert.equal(writeOffCreate.length, 1,
@@ -1733,7 +1757,7 @@ QUnit.module('account', {
// remove the first line, the other two will balance one another
await testUtils.dom.click(widget.$('tr[data-line-id="999"] td:first'));
var $buttonReconcile = widget.$('button.o_reconcile:not(hidden)');
var $buttonReconcile = widget.$('button.o_reconcile:visible');
assert.equal($buttonReconcile.length, 1,
'The reconcile button must be visible');
@@ -1757,6 +1781,9 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
@@ -1839,7 +1866,10 @@ QUnit.module('account', {
);
}
return this._super.apply(this, arguments);
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
@@ -1856,7 +1886,7 @@ QUnit.module('account', {
assert.verifySteps([], "No rpc done");
// Store the money in excess to the "account receivable" account with 20% taxes
await testUtils.dom.click(widget.$("table tfoot tr td:first"));
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_create"]'));
var $reconcileForm = widget.$(".create");
await testUtils.dom.click($reconcileForm.find('.create_account_id input'));
$('.ui-autocomplete .ui-menu-item a:contains(101200 Account Receivable)').trigger('mouseover').trigger('click');
@@ -1879,28 +1909,28 @@ QUnit.module('account', {
var $newLines = widget.$('tr.mv_line[data-line-id^=createLine]');
var idx = ($($($newLines[0]).find("td")[3]).text().trim() === "dummy text") ? 0 : 1;
var $newLineGiftTds = $($newLines[idx]).find("td");
assert.equal($($newLineGiftTds[1]).text().trim(), "101200",
var $newLineGiftTds = $($newLines[1 - idx]).find("td");
assert.equal($($newLineGiftTds[0]).text().trim().replace(/[\u200B]/g, ''), "101200",
"Gift line account number is valid");
assert.equal($($newLineGiftTds[2]).text().trim(), "New",
assert.equal($($newLineGiftTds[1]).text().trim(), "New",
"Gift line is flagged as new");
assert.equal($($newLineGiftTds[3]).text().trim(), "dummy text",
assert.equal($($newLineGiftTds[2]).text().trim(), "dummy text",
"Gift line has the correct label");
assert.equal($($newLineGiftTds[4]).text().trim(), "180.00",
assert.equal($($newLineGiftTds[3]).text().trim(), "180.00",
"Gift line has the correct left amount");
assert.equal($($newLineGiftTds[5]).text().trim(), "",
assert.equal($($newLineGiftTds[4]).text().trim(), "",
"Gift line has the correct right amount");
var $newLineTaxeTds = $($newLines[1 - idx]).find("td");
assert.equal($($newLineTaxeTds[1]).text().trim(), "101200",
var $newLineTaxeTds = $($newLines[idx]).find("td");
assert.equal($($newLineTaxeTds[0]).text().trim().replace(/[\u200B]/g, ''), "101200",
"Tax line account number is valid");
assert.equal($($newLineTaxeTds[2]).text().trim(), "New",
assert.equal($($newLineTaxeTds[1]).text().trim(), "New",
"Tax line is flagged as new");
assert.equal($($newLineTaxeTds[3]).text().trim(), "Tax 20.00%",
assert.equal($($newLineTaxeTds[2]).text().trim(), "Tax 20.00%",
"Tax line has the correct label");
assert.equal($($newLineTaxeTds[4]).text().trim(), "36.00",
assert.equal($($newLineTaxeTds[3]).text().trim(), "36.00",
"Tax line has the correct left amount");
assert.equal($($newLineTaxeTds[5]).text().trim(), "",
assert.equal($($newLineTaxeTds[4]).text().trim(), "",
"Tax line has the correct right amount");
// Reconcile
@@ -1926,14 +1956,18 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
// await clientAction.appendTo(document.body); // for debug purpose
var widget = clientAction.widgets[0];
// Add a line as proposition
// open the first line
await testUtils.nextTick();
await testUtils.dom.click(widget.$('.accounting_view tfoot td.cell_label'));
await testUtils.dom.click(widget.$('.o_notebook .nav-link[href*="notebook_page_create"]'));
var $reconcileForm = widget.$(".create");
$reconcileForm.find('.create_account_id input').val('499001 Suspense Account').keydown().keyup();
@@ -1966,7 +2000,7 @@ QUnit.module('account', {
event.data.callback(def);
});
await testUtils.dom.click(widget.$("button.o_reconcile.btn.btn-primary:first"), {allowInvisible: true});
await testUtils.dom.click(widget.$("button.o_validate.btn.btn-secondary:first"));
assert.ok(true, "No error in reconciliation");
clientAction.destroy();
@@ -1998,14 +2032,18 @@ QUnit.module('account', {
}
}
},
archs: {
'account.bank.statement.line,false,search': '<search string="Statement Line"><field name="display_name"/></search>',
},
});
await clientAction.appendTo($('#qunit-fixture'));
await testUtils.nextTick();
// The first reconciliation "line" is where it happens
var widget = clientAction.widgets[0];
await testUtilsDom.click(widget.$('.toggle_create'));
await testUtilsDom.click(widget.$('.nav-create:visible'));
await testUtilsDom.click(widget.$('.quick_add button:contains("Double")'));
assert.containsN(widget, '.create_analytic_tag_ids .o_field_many2manytags .badge', 2,
'Two tags are loaded');
@@ -2016,7 +2054,7 @@ QUnit.module('account', {
await testUtilsDom.click(widget.$('.create_analytic_tag_ids .o_field_many2manytags .badge a.o_delete:first()'));
await testUtilsDom.click(widget.$('.o_reconcile'));
await testUtilsDom.click(widget.$('.o_reconcile:visible'));
clientAction.destroy();
});
@@ -21,31 +21,31 @@ Tour.register('bank_statement_reconciliation', {
// Make a partial reconciliation
{
content: "open the last line in match mode to test the partial reconciliation",
extra_trigger: '.o_reconciliation_line:first[data-mode="match"]',
trigger: '.o_reconciliation_line:last .cell_label:contains("First")'
content: "open the 4th line in match_rp mode to test the partial reconciliation",
extra_trigger: '.o_reconciliation_line:first[data-mode="match_rp"]',
trigger: '.o_reconciliation_line:nth-child(4) .cell_label:contains("First")'
},
{
content: "click on partial reconcile",
trigger: '.o_reconciliation_line:last .accounting_view .edit_amount',
trigger: '.o_reconciliation_line:nth-child(4) .accounting_view .edit_amount',
},
{
content: "Edit amount",
trigger: '.o_reconciliation_line:last .accounting_view .edit_amount_input:not(.d-none)',
trigger: '.o_reconciliation_line:nth-child(4) .accounting_view .edit_amount_input:not(.d-none)',
run: 'text 2000'
},
{
content: "Press enter to validate amount",
trigger: '.o_reconciliation_line:last .accounting_view .edit_amount_input:not(.d-none)',
run: 'keydown 13'
trigger: '.o_reconciliation_line:nth-child(4) .accounting_view .edit_amount_input:not(.d-none)',
run: 'keydown 13' // requires focus
},
{
content: "Check that amount has changed",
trigger: '.o_reconciliation_line:last .accounting_view .line_amount:contains("2,000.00")'
trigger: '.o_reconciliation_line:nth-child(4) .accounting_view .line_amount:contains("2,000.00")'
},
{
content: "reconcile the line",
trigger: '.o_reconciliation_line:last .o_reconcile:visible',
trigger: '.o_reconciliation_line:nth-child(4) .o_reconcile:visible',
},
// Reconciliation of 'Prepayment'
@@ -53,7 +53,7 @@ Tour.register('bank_statement_reconciliation', {
{
content: "change the partner of the second line",
trigger: '.o_reconciliation_line:nth-child(2) .o_field_many2one input',
trigger: '.o_reconciliation_line:nth-child(2) .o_field_many2one[name="partner_id"] input',
run: 'text Deco'
},
{
@@ -63,24 +63,25 @@ Tour.register('bank_statement_reconciliation', {
},
{
content: "use filter",
trigger: '.o_reconciliation_line:nth-child(2) .match .match_controls .filter',
trigger: '.o_reconciliation_line:nth-child(1) .match .match_controls .filter',
run: 'text 4610'
},
{
content: "select a line linked to Deco Addict ",
trigger: ".o_reconciliation_line:nth-child(2) .match .line_info_button[data-content*='Deco Addict']"
extra_trigger: ".o_reconciliation_line:nth-child(1) .match .line_info_button:last[data-content*='4,610']",
trigger: ".o_reconciliation_line:nth-child(1) .match .line_info_button[data-content*='Deco Addict']"
},
{
content: "deselect the line",
trigger: '.o_reconciliation_line:nth-child(2) .accounting_view tbody .cell_label:first',
trigger: '.o_reconciliation_line:nth-child(1) .accounting_view tbody .cell_label:first',
run: function() {
$('.o_reconciliation_line:nth-child(2) .accounting_view tbody .cell_label:first').trigger('click');
$('.o_reconciliation_line:nth-child(1) .accounting_view tbody .cell_label:first').trigger('click');
}
},
{
content: "create a write-off",
extra_trigger: '.o_reconciliation_line:nth-child(2) .accounting_view tbody:not(:has(.cell_label))',
trigger: '.o_reconciliation_line:nth-child(2) .accounting_view tfoot .cell_label'
extra_trigger: '.o_reconciliation_line:nth-child(2) .accounting_view tfoot .cell_left:visible:contains(32.58)',
trigger: '.o_reconciliation_line:nth-child(2) .o_notebook .nav-link[href*="notebook_page_create"]'
},
{
content: "enter an account",
@@ -89,8 +90,7 @@ Tour.register('bank_statement_reconciliation', {
},
{
content: "select the first account",
extra_trigger: '.ui-autocomplete:visible li:eq(1):contains(Create "100000")',
trigger: '.ui-autocomplete:visible li:contains(100000)',
trigger: '.ui-autocomplete:visible li:last:contains(100000)',
},
{
content: "reconcile the line with the write-off",
@@ -100,7 +100,7 @@ Tour.register('bank_statement_reconciliation', {
// Be done
{
content: "check the number off validate lines",
trigger: '.o_reconciliation .progress-text:contains(3 / 5)'
trigger: '.o_control_panel .progress-reconciliation:contains(3 / 6)'
},
]
);
+1
View File
@@ -20,5 +20,6 @@ from . import test_templates_consistency
from . import test_account_fiscal_year
from . import test_account_all_l10n
from . import test_reconciliation_matching_rules
from . import test_account_move_tax_lock_date
from . import test_account_onboarding
from . import test_portal_attachment
@@ -25,12 +25,7 @@ class TestAllL10n(SingleTransactionCase):
('state', '=', 'uninstalled'),
])
_logger.info("Modules to install: %s" % [x.name for x in l10n_mods])
for mod in l10n_mods:
_logger.info('Installing l10n module %s' % mod.name)
try:
mod.button_immediate_install()
except Exception:
_logger.error('Failure during installation of module "%s"', mod.name)
l10n_mods.button_immediate_install()
# Now that new modules are installed, we have to reset the environment
api.Environment.reset()
cls.env = api.Environment(cls.cr, odoo.SUPERUSER_ID, {})
+17 -14
View File
@@ -69,34 +69,27 @@ class TestAccountMove(InvoiceTestCommon):
# lines[3] = 'revenue line 2'
lines = self.test_move.line_ids.sorted('debit')
# Writing not affecting a tax is allowed.
self.test_move.write({
'line_ids': [
(1, lines[0].id, {'credit': 1750.0}), # counterpart line
(1, lines[2].id, {'debit': 600.0}), # revenue line 1
],
})
self.test_move.flush()
self.cr.execute('SAVEPOINT test_misc_tax_lock_date_1')
# Writing something affecting a tax is not allowed.
with self.assertRaises(ValidationError):
with self.assertRaises(UserError):
self.test_move.write({
'line_ids': [
(1, lines[0].id, {'credit': 2750.0}),
(1, lines[3].id, {'debit': 2000.0}),
(1, lines[3].id, {'debit': 2100.0}),
],
})
with self.assertRaises(ValidationError):
with self.assertRaises(UserError):
self.test_move.write({
'line_ids': [
(1, lines[3].id, {'tax_ids': [(6, 0, self.company_data['default_tax_purchase'].ids)]}),
],
})
with self.assertRaises(ValidationError):
with self.assertRaises(UserError):
self.test_move.write({
'line_ids': [
(1, lines[0].id, {'credit': 1900.0}),
@@ -104,12 +97,22 @@ class TestAccountMove(InvoiceTestCommon):
],
})
with self.assertRaises(ValidationError):
with self.assertRaises(UserError):
self.test_move.unlink()
self.test_move.flush()
self.test_move.invalidate_cache()
self.cr.execute('ROLLBACK TO SAVEPOINT test_misc_tax_lock_date_1')
with self.assertRaises(UserError):
self.test_move.post()
def test_misc_unique_sequence_number(self):
''' Ensure two journal entries can't share the same name when using the same sequence. '''
self.test_move.post()
# Edit the sequence to force the next move to get the same name.
self.test_move.journal_id\
.sequence_id.date_range_ids\
.filtered(lambda seq: seq.date_from == fields.Date.from_string('2016-01-01')).number_next -= 1
test_move2 = self.test_move.copy()
with self.assertRaises(ValidationError):
test_move2.post()
@@ -3,6 +3,7 @@ from odoo.addons.account.tests.invoice_test_common import InvoiceTestCommon
from odoo.tests.common import Form
from odoo.tests import tagged
from odoo import fields
from odoo.exceptions import ValidationError
@tagged('post_install', '-at_install')
@@ -851,7 +852,7 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon):
self.term_line_vals_1,
], self.move_vals)
def test_in_invoice_create_draft_refund(self):
def test_in_invoice_create_refund(self):
self.invoice.post()
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
@@ -885,8 +886,10 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon):
},
{
**self.term_line_vals_1,
'name': '',
'debit': 1128.0,
'credit': 0.0,
'date_maturity': move_reversal.date,
},
], {
**self.move_vals,
@@ -898,7 +901,7 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon):
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
'date': fields.Date.from_string('2019-02-01'),
'reason': 'because',
'reason': 'no reason again',
'refund_method': 'cancel',
})
reversal = move_reversal.reverse_moves()
@@ -927,8 +930,10 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon):
},
{
**self.term_line_vals_1,
'name': '',
'debit': 1128.0,
'credit': 0.0,
'date_maturity': move_reversal.date,
},
], {
**self.move_vals,
@@ -938,6 +943,128 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon):
'invoice_payment_state': 'paid',
})
def test_in_invoice_create_refund_multi_currency(self):
''' Test the account.move.reversal takes care about the currency rates when setting
a custom reversal date.
'''
move_form = Form(self.invoice)
move_form.date = '2016-01-01'
move_form.currency_id = self.currency_data['currency']
move_form.save()
self.invoice.post()
# The currency rate changed from 1/3 to 1/2.
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
'date': fields.Date.from_string('2017-01-01'),
'reason': 'no reason',
'refund_method': 'refund',
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
self.assertInvoiceValues(reverse_move, [
{
**self.product_line_vals_1,
'amount_currency': -800.0,
'currency_id': self.currency_data['currency'].id,
'debit': 0.0,
'credit': 400.0,
},
{
**self.product_line_vals_2,
'amount_currency': -160.0,
'currency_id': self.currency_data['currency'].id,
'debit': 0.0,
'credit': 80.0,
},
{
**self.tax_line_vals_1,
'amount_currency': -144.0,
'currency_id': self.currency_data['currency'].id,
'debit': 0.0,
'credit': 72.0,
},
{
**self.tax_line_vals_2,
'amount_currency': -24.0,
'currency_id': self.currency_data['currency'].id,
'debit': 0.0,
'credit': 12.0,
},
{
**self.term_line_vals_1,
'name': '',
'amount_currency': 1128.0,
'currency_id': self.currency_data['currency'].id,
'debit': 564.0,
'credit': 0.0,
'date_maturity': move_reversal.date,
},
], {
**self.move_vals,
'currency_id': self.currency_data['currency'].id,
'date': move_reversal.date,
'state': 'draft',
'ref': 'Reversal of: %s, %s' % (self.invoice.name, move_reversal.reason),
'invoice_payment_state': 'not_paid',
})
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
'date': fields.Date.from_string('2017-01-01'),
'reason': 'no reason again',
'refund_method': 'cancel',
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
self.assertInvoiceValues(reverse_move, [
{
**self.product_line_vals_1,
'amount_currency': -800.0,
'currency_id': self.currency_data['currency'].id,
'debit': 0.0,
'credit': 400.0,
},
{
**self.product_line_vals_2,
'amount_currency': -160.0,
'currency_id': self.currency_data['currency'].id,
'debit': 0.0,
'credit': 80.0,
},
{
**self.tax_line_vals_1,
'amount_currency': -144.0,
'currency_id': self.currency_data['currency'].id,
'debit': 0.0,
'credit': 72.0,
},
{
**self.tax_line_vals_2,
'amount_currency': -24.0,
'currency_id': self.currency_data['currency'].id,
'debit': 0.0,
'credit': 12.0,
},
{
**self.term_line_vals_1,
'name': '',
'amount_currency': 1128.0,
'currency_id': self.currency_data['currency'].id,
'debit': 564.0,
'credit': 0.0,
'date_maturity': move_reversal.date,
},
], {
**self.move_vals,
'currency_id': self.currency_data['currency'].id,
'date': move_reversal.date,
'state': 'posted',
'ref': 'Reversal of: %s, %s' % (self.invoice.name, move_reversal.reason),
'invoice_payment_state': 'paid',
})
def test_in_invoice_create_1(self):
# Test creating an account_move with the least information.
move = self.env['account.move'].create({
@@ -1042,6 +1169,14 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon):
'currency_id': self.currency_data['currency'].id,
})
def test_in_invoice_duplicate_supplier_reference(self):
''' Ensure two vendor bills can't share the same vendor reference. '''
self.invoice.ref = 'a supplier reference'
invoice2 = self.invoice.copy()
with self.assertRaises(ValidationError):
invoice2.ref = 'a supplier reference'
def test_in_invoice_switch_in_refund_1(self):
# Test creating an account_move with an in_invoice_type and switch it in an in_refund.
move = self.env['account.move'].create({
@@ -1193,3 +1328,47 @@ class TestAccountMoveInInvoiceOnchanges(InvoiceTestCommon):
'amount_total' : self.move_vals['amount_total'],
'amount_untaxed' : self.move_vals['amount_untaxed'],
})
def test_in_invoice_accrual(self):
self.env.company.accrual_default_journal_id = self.company_data['default_journal_misc']
self.env.company.expense_accrual_account_id = self.env['account.account'].create({
'name': 'Accrual Expense Account',
'code': '234567',
'user_type_id': self.env.ref('account.data_account_type_expenses').id,
'reconcile': True,
})
self.env.company.revenue_accrual_account_id = self.env['account.account'].create({
'name': 'Accrual Revenue Account',
'code': '765432',
'user_type_id': self.env.ref('account.data_account_type_expenses').id,
'reconcile': True,
})
invoice_line = self.invoice.line_ids.filtered(lambda l: l.account_id == self.product_a.property_account_expense_id)
self.env['account.accrual.accounting.wizard'].with_context(
active_model='account.move.line',
active_ids=invoice_line.ids
).create({
'date': '2016-01-01',
'percentage': 60,
}).amend_entries()
# Nothing changed except the account
self.assertInvoiceValues(self.invoice, [
{
**self.product_line_vals_1,
'account_id': self.env.company.expense_accrual_account_id.id,
},
self.product_line_vals_2,
self.tax_line_vals_1,
self.tax_line_vals_2,
self.term_line_vals_1,
], self.move_vals)
accrual_moves = self.env['account.move'].search([('journal_id', '=', self.env.company.accrual_default_journal_id.id)])
accrual_other_date = accrual_moves.filtered(lambda m: m.date == fields.Date.to_date('2016-01-01'))
accrual_same_date = accrual_moves.filtered(lambda m: m.date == invoice_line.date)
self.assertEqual(accrual_same_date.amount_total, 0.4 * invoice_line.balance)
self.assertEqual(accrual_other_date.amount_total, 0.6 * invoice_line.balance)
self.assertTrue(accrual_other_date.line_ids.full_reconcile_id)
@@ -836,7 +836,7 @@ class TestAccountMoveOutInvoiceOnchanges(InvoiceTestCommon):
self.assertRecordValues(invoice_copy, [{'name': 'INV/2019/0043'}])
def test_out_invoice_create_draft_refund(self):
def test_out_invoice_create_refund(self):
self.invoice.post()
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
@@ -870,12 +870,14 @@ class TestAccountMoveOutInvoiceOnchanges(InvoiceTestCommon):
},
{
**self.term_line_vals_1,
'name': self.invoice.name,
'name': '',
'debit': 0.0,
'credit': 1410.0,
'date_maturity': move_reversal.date,
},
], {
**self.move_vals,
'name': '/',
'date': move_reversal.date,
'state': 'draft',
'ref': 'Reversal of: %s, %s' % (self.invoice.name, move_reversal.reason),
@@ -913,9 +915,10 @@ class TestAccountMoveOutInvoiceOnchanges(InvoiceTestCommon):
},
{
**self.term_line_vals_1,
'name': self.invoice.name,
'name': '',
'debit': 0.0,
'credit': 1410.0,
'date_maturity': move_reversal.date,
},
], {
**self.move_vals,
@@ -925,6 +928,128 @@ class TestAccountMoveOutInvoiceOnchanges(InvoiceTestCommon):
'invoice_payment_state': 'paid',
})
def test_out_invoice_create_refund_multi_currency(self):
''' Test the account.move.reversal takes care about the currency rates when setting
a custom reversal date.
'''
move_form = Form(self.invoice)
move_form.date = '2016-01-01'
move_form.currency_id = self.currency_data['currency']
move_form.save()
self.invoice.post()
# The currency rate changed from 1/3 to 1/2.
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
'date': fields.Date.from_string('2017-01-01'),
'reason': 'no reason',
'refund_method': 'refund',
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
self.assertInvoiceValues(reverse_move, [
{
**self.product_line_vals_1,
'amount_currency': 1000.0,
'currency_id': self.currency_data['currency'].id,
'debit': 500.0,
'credit': 0.0,
},
{
**self.product_line_vals_2,
'amount_currency': 200.0,
'currency_id': self.currency_data['currency'].id,
'debit': 100.0,
'credit': 0.0,
},
{
**self.tax_line_vals_1,
'amount_currency': 180.0,
'currency_id': self.currency_data['currency'].id,
'debit': 90.0,
'credit': 0.0,
},
{
**self.tax_line_vals_2,
'amount_currency': 30.0,
'currency_id': self.currency_data['currency'].id,
'debit': 15.0,
'credit': 0.0,
},
{
**self.term_line_vals_1,
'name': '',
'amount_currency': -1410.0,
'currency_id': self.currency_data['currency'].id,
'debit': 0.0,
'credit': 705.0,
'date_maturity': move_reversal.date,
},
], {
**self.move_vals,
'currency_id': self.currency_data['currency'].id,
'date': move_reversal.date,
'state': 'draft',
'ref': 'Reversal of: %s, %s' % (self.invoice.name, move_reversal.reason),
'invoice_payment_state': 'not_paid',
})
move_reversal = self.env['account.move.reversal'].with_context(active_ids=self.invoice.ids).create({
'date': fields.Date.from_string('2017-01-01'),
'reason': 'no reason',
'refund_method': 'cancel',
})
reversal = move_reversal.reverse_moves()
reverse_move = self.env['account.move'].browse(reversal['res_id'])
self.assertInvoiceValues(reverse_move, [
{
**self.product_line_vals_1,
'amount_currency': 1000.0,
'currency_id': self.currency_data['currency'].id,
'debit': 500.0,
'credit': 0.0,
},
{
**self.product_line_vals_2,
'amount_currency': 200.0,
'currency_id': self.currency_data['currency'].id,
'debit': 100.0,
'credit': 0.0,
},
{
**self.tax_line_vals_1,
'amount_currency': 180.0,
'currency_id': self.currency_data['currency'].id,
'debit': 90.0,
'credit': 0.0,
},
{
**self.tax_line_vals_2,
'amount_currency': 30.0,
'currency_id': self.currency_data['currency'].id,
'debit': 15.0,
'credit': 0.0,
},
{
**self.term_line_vals_1,
'name': '',
'amount_currency': -1410.0,
'currency_id': self.currency_data['currency'].id,
'debit': 0.0,
'credit': 705.0,
'date_maturity': move_reversal.date,
},
], {
**self.move_vals,
'currency_id': self.currency_data['currency'].id,
'date': move_reversal.date,
'state': 'posted',
'ref': 'Reversal of: %s, %s' % (self.invoice.name, move_reversal.reason),
'invoice_payment_state': 'paid',
})
def test_out_invoice_create_1(self):
# Test creating an account_move with the least information.
move = self.env['account.move'].create({
@@ -1267,4 +1392,48 @@ class TestAccountMoveOutInvoiceOnchanges(InvoiceTestCommon):
'amount_tax' : self.move_vals['amount_tax'],
'amount_total' : self.move_vals['amount_total'],
'amount_untaxed' : self.move_vals['amount_untaxed'],
})
})
def test_out_invoice_accrual(self):
self.env.company.accrual_default_journal_id = self.company_data['default_journal_misc']
self.env.company.expense_accrual_account_id = self.env['account.account'].create({
'name': 'Accrual Expense Account',
'code': '234567',
'user_type_id': self.env.ref('account.data_account_type_expenses').id,
'reconcile': True,
})
self.env.company.revenue_accrual_account_id = self.env['account.account'].create({
'name': 'Accrual Revenue Account',
'code': '765432',
'user_type_id': self.env.ref('account.data_account_type_expenses').id,
'reconcile': True,
})
invoice_line = self.invoice.line_ids.filtered(lambda l: l.account_id == self.product_a.property_account_income_id)
self.env['account.accrual.accounting.wizard'].with_context(
active_model='account.move.line',
active_ids=invoice_line.ids
).create({
'date': '2016-01-01',
'percentage': 60,
}).amend_entries()
# Nothing changed except the account
self.assertInvoiceValues(self.invoice, [
{
**self.product_line_vals_1,
'account_id': self.env.company.revenue_accrual_account_id.id,
},
self.product_line_vals_2,
self.tax_line_vals_1,
self.tax_line_vals_2,
self.term_line_vals_1,
], self.move_vals)
accrual_moves = self.env['account.move'].search([('journal_id', '=', self.env.company.accrual_default_journal_id.id)])
accrual_other_date = accrual_moves.filtered(lambda m: m.date == fields.Date.to_date('2016-01-01'))
accrual_same_date = accrual_moves.filtered(lambda m: m.date == invoice_line.date)
self.assertEqual(accrual_same_date.amount_total, 0.4 * -invoice_line.balance)
self.assertEqual(accrual_other_date.amount_total, 0.6 * -invoice_line.balance)
self.assertTrue(accrual_other_date.line_ids.full_reconcile_id)
@@ -0,0 +1,98 @@
from odoo.addons.account.tests.account_test_classes import AccountingTestCase
from odoo.exceptions import UserError
from datetime import date
from calendar import monthrange
# from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
from odoo.tests import tagged
@tagged('post_install', '-at_install')
class TestTaxBlockDate(AccountingTestCase):
"""
Forbid creation, edition and deletion of Journal Items related to taxes with
a date prior to the Tax Block Date.
"""
def setUp(self):
super(TestTaxBlockDate, self).setUp()
self.user_id = self.env.user
self.company = self.env.company
company_id = self.company.id
last_day_month = date.today()
self.last_day_month = last_day_month.replace(day=monthrange(last_day_month.year, last_day_month.month)[1])
first_day_month = date.today()
self.first_day_month = first_day_month.replace(day=1)
middle_day_month = date.today()
middle_day_month = middle_day_month.replace(day=15)
self.sale_journal_id = self.env['account.journal'].search([('type', '=', 'sale'), ('company_id', '=', company_id)], limit=1)[0]
self.account_id = self.env['account.account'].search([('internal_type', '=', 'receivable'), ('company_id', '=', company_id)], limit=1)[0]
self.other_account_id = self.env['account.account'].search([('internal_type', '!=', 'receivable'), ('company_id', '=', company_id)], limit=1)[0]
self.tax_id = self.env['account.tax'].search([('company_id', '=', company_id)], limit=1)[0]
self.move = {
'name': '/',
'journal_id': self.sale_journal_id.id,
'date': middle_day_month,
'line_ids': [(0, 0, {
'name': 'foo',
'debit': 10,
'account_id': self.account_id.id,
'tax_ids': [(6, False, [self.tax_id.id])]
}), (0, 0, {
'name': 'bar',
'credit': 10,
'account_id': self.account_id.id,
})]
}
self.move_no_tax = {
'name': '/',
'journal_id': self.sale_journal_id.id,
'date': middle_day_month,
'line_ids': [(0, 0, {
'name': 'foo',
'debit': 10,
'account_id': self.account_id.id,
}), (0, 0, {
'name': 'bar',
'credit': 10,
'account_id': self.account_id.id,
})]
}
def test_tax_lock_date_post(self):
""" Checks that it is impossible to post an entry
before the tax lock date.
"""
# Posting after the lock date is always allowed
self.company.tax_lock_date = self.first_day_month
# copy() because mail.thread modifies the dictionary given to create
move_after_lock = self.env['account.move'].create(self.move.copy())
move_after_lock.post()
# Posting before the tax lock date is allowed only if the move doesn't contain any tax
self.user_id.company_id.tax_lock_date = self.last_day_month
move_before_lock_no_tax = self.env['account.move'].create(self.move_no_tax)
move_before_lock_no_tax.post()
# Posting before the tax lock date is not allowed for moves impacting the tax report
self.user_id.company_id.tax_lock_date = self.last_day_month
with self.assertRaises(UserError):
self.env['account.move'].create(self.move.copy())
def test_tax_lock_date_cancel(self):
""" Checks that it is not possible to cancel an entry posted before the
tax lock date if it impacts the tax report. """
self.sale_journal_id.update_posted = True
move = self.env['account.move'].create(self.move)
move.post()
move_no_tax = self.env['account.move'].create(self.move_no_tax)
move_no_tax.post()
self.user_id.company_id.tax_lock_date = self.last_day_month
move_no_tax.button_cancel()
with self.assertRaises(UserError):
move.button_cancel()
@@ -26,19 +26,19 @@ class TestBankStatementReconciliation(AccountingTestCase):
self.assertEqual(prop[0]['id'], rcv_mv_line.id)
def test_full_reconcile(self):
self._reconcile_invoice_with_statement(False)
self._reconcile_invoice_with_statement('pay_val')
def test_post_at_bank_rec_full_reconcile(self):
""" Test the full reconciliation of a bank statement directly with an invoice.
"""
self._reconcile_invoice_with_statement(True)
self._reconcile_invoice_with_statement('bank_rec')
def _reconcile_invoice_with_statement(self, post_at_bank_rec):
def _reconcile_invoice_with_statement(self, post_at):
""" Tests the reconciliation of an invoice with a bank statement, using
the provided 'post at bank reconciliation' value for the bank journal
where to generate the statement.
"""
self.bs_model.with_context(journal_type='bank')._default_journal().post_at_bank_reconciliation = post_at_bank_rec
self.bs_model.with_context(journal_type='bank')._default_journal().post_at_bank_reconciliation = post_at == 'bank_rec'
rcv_mv_line = self.create_invoice(100)
st_line = self.create_statement_line(100)
# reconcile
+1 -1
View File
@@ -369,7 +369,7 @@ class TestPayment(AccountingTestCase):
'name': 'Bank',
'type': 'bank',
'code': 'COUCOU',
'post_at_bank_rec': True,
'post_at': 'bank_rec',
})
payment_one = self.payment_model.create({'payment_type': 'inbound',
'payment_method_id': self.env.ref('account.account_payment_method_manual_in').id,
+80 -16
View File
@@ -149,6 +149,24 @@ class TestReconciliation(AccountingTestCase):
invoice.post()
return invoice
def create_invoice_partner(self, type='out_invoice', invoice_amount=50, currency_id=None, partner_id=False, payment_term_id=False):
move = self.env['account.move'].with_context(default_type=type).create({
'type': type,
'partner_id': partner_id,
'invoice_date': time.strftime('%Y') + '-07-01',
'date': time.strftime('%Y') + '-07-01',
'currency_id': currency_id,
'invoice_payment_term_id': payment_term_id,
'invoice_line_ids': [(0, 0, {
'quantity': 1,
'price_unit': invoice_amount,
'name': 'product that cost ' + str(invoice_amount),
})],
})
move.post()
return move
def make_payment(self, invoice_record, bank_journal, amount=0.0, amount_currency=0.0, currency_id=None):
bank_stmt = self.acc_bank_stmt_model.create({
'journal_id': bank_journal.id,
@@ -895,22 +913,6 @@ class TestReconciliationExec(TestReconciliation):
self.assertEqual(reversed_bank_line.full_reconcile_id.id, bank_line.full_reconcile_id.id)
self.assertEqual(reversed_customer_line.full_reconcile_id.id, customer_line.full_reconcile_id.id)
def create_invoice_partner(self, type='out_invoice', invoice_amount=50, currency_id=None, partner_id=False, payment_term_id=False):
move = self.env['account.move'].with_context(default_type=type).create({
'type': type,
'partner_id': partner_id,
'invoice_date': time.strftime('%Y') + '-07-01',
'date': time.strftime('%Y') + '-07-01',
'currency_id': currency_id,
'invoice_payment_term_id': payment_term_id,
'invoice_line_ids': [(0, 0, {
'quantity': 1,
'price_unit': invoice_amount,
'name': 'product that cost ' + str(invoice_amount),
})],
})
move.post()
return move
def test_aged_report(self):
AgedReport = self.env['report.account.report_agedpartnerbalance'].with_context(include_nullified_amount=True)
@@ -1169,6 +1171,68 @@ class TestReconciliationExec(TestReconciliation):
# because they owe us still 50 CC.
self.assertEqual(invoice_cust_1.invoice_payment_state, 'not_paid', 'Invoice is in status %s' % invoice_cust_1.state)
def test_inv_refund_foreign_payment_writeoff_domestic(self):
company = self.env.ref('base.main_company')
self.env['res.currency.rate'].search([]).unlink()
self.env['res.currency.rate'].create({
'name': time.strftime('%Y') + '-07-01',
'rate': 1.0,
'currency_id': self.currency_euro_id,
'company_id': company.id
})
self.env['res.currency.rate'].create({
'name': time.strftime('%Y') + '-07-01',
'rate': 1.113900, # Don't change this !
'currency_id': self.currency_usd_id,
'company_id': self.env.ref('base.main_company').id
})
inv1 = self.create_invoice(invoice_amount=480, currency_id=self.currency_usd_id)
inv2 = self.create_invoice(type="out_refund", invoice_amount=140, currency_id=self.currency_usd_id)
payment = self.env['account.payment'].create({
'payment_method_id': self.inbound_payment_method.id,
'payment_type': 'inbound',
'partner_type': 'customer',
'partner_id': inv1.partner_id.id,
'amount': 287.20,
'journal_id': self.bank_journal_euro.id,
'company_id': company.id,
})
payment.post()
inv1_receivable = inv1.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
inv2_receivable = inv2.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
pay_receivable = payment.move_line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
data_for_reconciliation = [
{
'type': 'partner',
'id': inv1.partner_id.id,
'mv_line_ids': (inv1_receivable + inv2_receivable + pay_receivable).ids,
'new_mv_line_dicts': [
{
'credit': 18.04,
'debit': 0.00,
'journal_id': self.bank_journal_euro.id,
'name': 'Total WriteOff (Fees)',
'account_id': self.diff_expense_account.id
}
]
}
]
self.env["account.reconciliation.widget"].process_move_lines(data_for_reconciliation)
self.assertTrue(inv1_receivable.full_reconcile_id.exists())
self.assertEquals(inv1_receivable.full_reconcile_id, inv2_receivable.full_reconcile_id)
self.assertEquals(inv1_receivable.full_reconcile_id, pay_receivable.full_reconcile_id)
self.assertTrue(all(l.reconciled for l in inv1_receivable))
self.assertTrue(all(l.reconciled for l in inv2_receivable))
self.assertEquals(inv1.invoice_payment_state, 'paid')
self.assertEquals(inv2.invoice_payment_state, 'paid')
def test_multiple_term_reconciliation_opw_1906665(self):
'''Test that when registering a payment to an invoice with multiple
payment term lines the reconciliation happens against the line
@@ -47,7 +47,7 @@ class TestReconciliationMatchingRules(AccountingTestCase):
current_assets_account = self.env['account.account'].search(
[('user_type_id', '=', self.env.ref('account.data_account_type_current_assets').id)], limit=1)
self.rule_0 = self.env['account.reconcile.model'].search([('company_id', '=', self.env.company.id)])
self.rule_0 = self.env['account.reconcile.model'].search([('company_id', '=', self.env.company.id), ('rule_type', '=', 'invoice_matching')])
self.rule_1 = self.rule_0.copy()
self.rule_1.account_id = current_assets_account
self.rule_1.match_partner = True
@@ -109,6 +109,7 @@ class TestReconciliationMatchingRules(AccountingTestCase):
self.bank_line_2.id: {'aml_ids': [
self.invoice_line_2.id,
self.invoice_line_3.id,
self.invoice_line_1.id,
], 'model': self.rule_1},
self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},
})
@@ -129,6 +130,7 @@ class TestReconciliationMatchingRules(AccountingTestCase):
self.bank_line_2.id: {'aml_ids': [
self.invoice_line_2.id,
self.invoice_line_3.id,
self.invoice_line_1.id,
], 'model': self.rule_1},
self.cash_line_1.id: {'aml_ids': []},
})
@@ -209,6 +211,7 @@ class TestReconciliationMatchingRules(AccountingTestCase):
self.bank_line_2.id: {'aml_ids': [
self.invoice_line_2.id,
self.invoice_line_3.id,
self.invoice_line_1.id,
], 'model': self.rule_1},
self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},
})
@@ -223,6 +226,7 @@ class TestReconciliationMatchingRules(AccountingTestCase):
self.bank_line_2.id: {'aml_ids': [
self.invoice_line_2.id,
self.invoice_line_3.id,
self.invoice_line_1.id,
], 'model': self.rule_1},
self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},
})
@@ -252,6 +256,7 @@ class TestReconciliationMatchingRules(AccountingTestCase):
self.bank_line_2.id: {'aml_ids': [
self.invoice_line_2.id,
self.invoice_line_3.id,
self.invoice_line_1.id,
], 'model': self.rule_1},
self.cash_line_1.id: {'aml_ids': [self.invoice_line_4.id], 'model': self.rule_1},
})
@@ -20,7 +20,7 @@ class TestUi(odoo.tests.HttpCase):
# To be able to test reconciliation, admin user must have access to accounting features, so we give him the right group for that
self.env.ref('base.user_admin').write({'groups_id': [(4, self.env.ref('account.group_account_user').id)]})
payload = {'action':'bank_statement_reconciliation_view', 'statement_line_ids[]': bank_stmt_line.ids}
prep = requests.models.PreparedRequest()
prep.prepare_url(url="http://localhost/web#", params=payload)
@@ -53,3 +53,82 @@ class TestReconciliationWidget(TestReconciliation):
result = self.env['account.reconciliation.widget'].get_bank_statement_line_data(bank_stmt_line.ids)
self.assertEqual(result['lines'][0]['reconciliation_proposition'][0]['amount_str'], '$ 50.00')
def test_filter_partner1(self):
inv1 = self.create_invoice(currency_id=self.currency_euro_id)
inv2 = self.create_invoice(currency_id=self.currency_euro_id)
receivable1 = inv1.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
receivable2 = inv2.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
bank_stmt = self.acc_bank_stmt_model.create({
'company_id': self.env.ref('base.main_company').id,
'journal_id': self.bank_journal_euro.id,
'date': time.strftime('%Y-07-15'),
'name': 'test',
})
bank_stmt_line = self.acc_bank_stmt_line_model.create({
'name': 'testLine',
'statement_id': bank_stmt.id,
'amount': 100,
'date': time.strftime('%Y-07-15'),
})
# This is like opening the widget, and type "deco" in the filter
mv_lines_rec = self.env['account.reconciliation.widget'].get_move_lines_for_bank_statement_line(
bank_stmt_line.id,
partner_id=False,
excluded_ids=[],
search_str="deco",
mode="rp",
)
mv_lines_ids = [l['id'] for l in mv_lines_rec]
self.assertIn(receivable1.id, mv_lines_ids)
self.assertIn(receivable2.id, mv_lines_ids)
# This is like clicking on the first receivable
partner = inv1.partner_id
mv_lines_rec = self.env['account.reconciliation.widget'].get_move_lines_for_bank_statement_line(
bank_stmt_line.id,
partner_id=partner.id,
excluded_ids=[receivable1.id],
search_str="deco",
mode="rp",
)
mv_lines_ids = [l['id'] for l in mv_lines_rec]
self.assertNotIn(receivable1.id, mv_lines_ids)
self.assertIn(receivable2.id, mv_lines_ids)
def test_partner_name_with_parent(self):
parent_partner = self.env['res.partner'].create({
'name': 'test',
})
child_partner = self.env['res.partner'].create({
'name': 'test',
'parent_id': parent_partner.id,
'type': 'delivery',
})
self.create_invoice_partner(currency_id=self.currency_euro_id, partner_id=child_partner.id)
bank_stmt = self.acc_bank_stmt_model.create({
'company_id': self.env.ref('base.main_company').id,
'journal_id': self.bank_journal_euro.id,
'date': time.strftime('%Y-07-15'),
'name': 'test',
})
bank_stmt_line = self.acc_bank_stmt_line_model.create({
'name': 'testLine',
'statement_id': bank_stmt.id,
'amount': 100,
'date': time.strftime('%Y-07-15'),
'partner_name': 'test',
})
bkstmt_data = self.env['account.reconciliation.widget'].get_bank_statement_line_data(bank_stmt_line.ids)
self.assertEqual(len(bkstmt_data['lines']), 1)
self.assertEqual(bkstmt_data['lines'][0]['partner_id'], parent_partner.id)
+255 -7
View File
@@ -348,12 +348,32 @@ class TestTax(AccountTestUsers):
'price_include': True,
'include_base_amount': True,
'sequence': 1,
'invoice_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
'refund_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
})
tax_2 = self.env['account.tax'].create({
'name': 'test_advanced_taxes_computation_0_2',
'amount_type': 'percent',
'amount': 10,
'sequence': 2,
'invoice_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
'refund_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
})
tax_3 = self.env['account.tax'].create({
'name': 'test_advanced_taxes_computation_0_3',
@@ -361,12 +381,32 @@ class TestTax(AccountTestUsers):
'amount': 10,
'price_include': True,
'sequence': 3,
'invoice_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
'refund_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
})
tax_4 = self.env['account.tax'].create({
'name': 'test_advanced_taxes_computation_0_4',
'amount_type': 'percent',
'amount': 10,
'sequence': 4,
'invoice_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
'refund_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
})
tax_5 = self.env['account.tax'].create({
'name': 'test_advanced_taxes_computation_0_5',
@@ -374,21 +414,229 @@ class TestTax(AccountTestUsers):
'amount': 10,
'price_include': True,
'sequence': 5,
'invoice_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
'refund_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
})
taxes = tax_1 + tax_2 + tax_3 + tax_4 + tax_5
res = taxes.compute_all(132.0)
# Test with positive amount.
self._check_compute_all_results(
154, # 'total_included'
100, # 'total_excluded'
[
# base , amount | seq | amount | incl | incl_base
# ---------------------------------------------------
(100.0, 10.0), # | 1 | 10% | t | t
(110.0, 11.0), # | 2 | 10% | |
(110.0, 11.0), # | 3 | 10% | t |
(110.0, 11.0), # | 4 | 10% | |
(110.0, 11.0), # | 5 | 10% | t |
(100.0, 5.0), # | 1 | 10% | t | t
(100.0, 5.0), # | 1 | 10% | t | t
(110.0, 5.5), # | 2 | 10% | |
(110.0, 5.5), # | 2 | 10% | |
(110.0, 5.5), # | 3 | 10% | t |
(110.0, 5.5), # | 3 | 10% | t |
(110.0, 5.5), # | 4 | 10% | |
(110.0, 5.5), # | 4 | 10% | |
(110.0, 5.5), # | 5 | 10% | t |
(110.0, 5.5), # | 5 | 10% | t |
# ---------------------------------------------------
],
res
taxes.compute_all(132.0)
)
# Test with negative amount.
self._check_compute_all_results(
-154, # 'total_included'
-100, # 'total_excluded'
[
# base , amount | seq | amount | incl | incl_base
# ---------------------------------------------------
(-100.0, -5.0), # | 1 | 10% | t | t
(-100.0, -5.0), # | 1 | 10% | t | t
(-110.0, -5.5), # | 2 | 10% | |
(-110.0, -5.5), # | 2 | 10% | |
(-110.0, -5.5), # | 3 | 10% | t |
(-110.0, -5.5), # | 3 | 10% | t |
(-110.0, -5.5), # | 4 | 10% | |
(-110.0, -5.5), # | 4 | 10% | |
(-110.0, -5.5), # | 5 | 10% | t |
(-110.0, -5.5), # | 5 | 10% | t |
# ---------------------------------------------------
],
taxes.compute_all(-132.0)
)
def test_intracomm_taxes_computation_0(self):
''' Test usage of intracomm taxes having e.g.+100%, -100% as repartition lines. '''
intracomm_tax = self.env['account.tax'].create({
'name': 'test_intracomm_taxes_computation_0_1',
'amount_type': 'percent',
'amount': 21,
'invoice_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': -100.0}),
],
'refund_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': -100.0}),
],
})
# Test with positive amount.
self._check_compute_all_results(
100, # 'total_included'
100, # 'total_excluded'
[
# base , amount
# ---------------
(100.0, 21.0),
(100.0, -21.0),
# ---------------
],
intracomm_tax.compute_all(100.0)
)
# Test with negative amount.
self._check_compute_all_results(
-100, # 'total_included'
-100, # 'total_excluded'
[
# base , amount
# ---------------
(-100.0, -21.0),
(-100.0, 21.0),
# ---------------
],
intracomm_tax.compute_all(-100.0)
)
def test_rounding_issues_0(self):
''' Test taxes having a complex setup of repartition lines. '''
tax = self.env['account.tax'].create({
'name': 'test_rounding_issues_0',
'amount_type': 'percent',
'amount': 3,
'invoice_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
'refund_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
],
})
# Test with positive amount.
self._check_compute_all_results(
1.09, # 'total_included'
1, # 'total_excluded'
[
# base , amount
# ---------------
(1.0, 0.01),
(1.0, 0.01),
(1.0, 0.01),
(1.0, 0.02),
(1.0, 0.02),
(1.0, 0.02),
# ---------------
],
tax.compute_all(1.0)
)
# Test with negative amount.
self._check_compute_all_results(
-1.09, # 'total_included'
-1, # 'total_excluded'
[
# base , amount
# ---------------
(-1.0, -0.01),
(-1.0, -0.01),
(-1.0, -0.01),
(-1.0, -0.02),
(-1.0, -0.02),
(-1.0, -0.02),
# ---------------
],
tax.compute_all(-1.0)
)
def test_rounding_issues_1(self):
''' Test taxes having a complex setup of repartition lines. '''
tax = self.env['account.tax'].create({
'name': 'test_advanced_taxes_repartition_lines_computation_1',
'amount_type': 'percent',
'amount': 3,
'invoice_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': -50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 25.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 25.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': -25.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': -25.0}),
],
'refund_repartition_line_ids': [
(0, 0, {'repartition_type': 'base', 'factor_percent': 100.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': -50.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 25.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': 25.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': -25.0}),
(0, 0, {'repartition_type': 'tax', 'factor_percent': -25.0}),
],
})
# Test with positive amount.
self._check_compute_all_results(
1, # 'total_included'
1, # 'total_excluded'
[
# base , amount
# ---------------
(1.0, 0.02),
(1.0, -0.02),
(1.0, 0.01),
(1.0, 0.01),
(1.0, -0.01),
(1.0, -0.01),
# ---------------
],
tax.compute_all(1.0)
)
# Test with negative amount.
self._check_compute_all_results(
-1, # 'total_included'
-1, # 'total_excluded'
[
# base , amount
# ---------------
(-1.0, -0.02),
(-1.0, 0.02),
(-1.0, -0.01),
(-1.0, -0.01),
(-1.0, 0.01),
(-1.0, 0.01),
# ---------------
],
tax.compute_all(-1.0)
)
+2
View File
@@ -14,6 +14,7 @@
<link rel="stylesheet" type="text/scss" href="/account/static/src/scss/account_reconciliation.scss"/>
<link rel="stylesheet" type="text/scss" href="/account/static/src/scss/account_journal_dashboard.scss"/>
<link rel="stylesheet" type="text/scss" href="/account/static/src/scss/account_dashboard.scss"/>
<link rel="stylesheet" type="text/scss" href="/account/static/src/scss/account_searchpanel.scss"/>
<link rel="stylesheet" href="/account/static/src/scss/section_and_note_backend.scss"/>
<link rel="stylesheet" type="text/scss" href="/account/static/src/scss/account_activity.scss"/>
@@ -30,6 +31,7 @@
<script type="text/javascript" src="/account/static/src/js/section_and_note_fields_backend.js"></script>
<script type="text/javascript" src="/account/static/src/js/tours/account.js"></script>
<script type="text/javascript" src="/account/static/src/js/bills_tree_upload.js"/>
<script type="text/javascript" src="/account/static/src/js/account_selection.js"/>
</xpath>
</template>
@@ -57,6 +57,6 @@
</record>
<menuitem action="action_incoterms_tree" id="menu_action_incoterm_open"
parent="account.account_account_menu" sequence="10" groups="account.group_account_manager"/>
parent="account.account_invoicing_menu" sequence="4" groups="account.group_account_manager"/>
</data>
</odoo>
@@ -294,9 +294,15 @@
<button type="object" name="action_create_new" class="btn btn-primary o_invoice_new">
<span>New Invoice</span>
</button>
<button class="btn btn-primary d-block o_button_upload_bill" journal_type="sale">
<span>Upload Invoices</span>
</button>
</t>
<t t-if="journal_type == 'purchase'">
<button class="btn btn-primary o_button_upload_bill" journal_type="purchase">
<button type="object" name="action_create_new" class="btn btn-primary o_invoice_new">
<span>New Bill</span>
</button>
<button class="btn btn-primary d-block o_button_upload_bill" journal_type="purchase">
<span>Upload Bills</span>
</button>
</t>
+5 -5
View File
@@ -27,12 +27,12 @@
<menuitem id="menu_finance_configuration" name="Configuration" parent="menu_finance" sequence="35" groups="account.group_account_manager"/>
<!-- Configuration Sub-Menu -->
<menuitem id="account_account_menu" name="Accounting" parent="account.menu_finance_configuration" sequence="2" groups="account.group_account_invoice"/>
<menuitem id="account_management_menu" name="Management" parent="account.menu_finance_configuration" sequence="3" groups="account.group_account_manager"/>
<menuitem id="menu_analytic_accounting" name="Analytic Accounting" parent="menu_finance_configuration" groups="analytic.group_analytic_accounting,analytic.group_analytic_tags" sequence="5"/>
<menuitem id="account_invoicing_menu" name="Invoicing" parent="account.menu_finance_configuration" sequence="1" groups="account.group_account_invoice"/>
<menuitem id="root_payment_menu" name="Payments" parent="account.menu_finance_configuration" sequence="2" groups="account.group_account_manager"/>
<menuitem id="account_account_menu" name="Accounting" parent="account.menu_finance_configuration" sequence="3" groups="account.group_account_manager"/>
<menuitem id="menu_action_currency_form" action="base.action_currency_form" name="Currencies" parent="account_account_menu" sequence="1" groups="base.group_multi_currency"/>
<menuitem id="account_management_menu" name="Management" parent="account.menu_finance_configuration" sequence="4" groups="account.group_account_manager"/>
<menuitem id="menu_analytic_accounting" name="Analytic Accounting" parent="menu_finance_configuration" groups="analytic.group_analytic_accounting,analytic.group_analytic_tags" sequence="5"/>
</data>
</odoo>
+126 -83
View File
@@ -61,6 +61,9 @@
<field name="currency_id" invisible="1"/>
<field name="amount_currency"/>
</group>
<group string="Product" attrs="{'invisible': [('product_id', '=', False)]}">
<field name="product_id"/>
</group>
<group string="States">
<field name="blocked"/>
</group>
@@ -130,7 +133,7 @@
<field name="model">account.move.line</field>
<field eval="100" name="priority"/>
<field name="arch" type="xml">
<tree string="Journal Items" create="false" editable="bottom">
<tree string="Journal Items" create="false">
<field name="date" optional="show"/>
<field name="journal_id" options='{"no_open":True}'/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
@@ -146,7 +149,7 @@
<field name="reconcile_model_id" invisible="1"/>
<field name="debit" sum="Total Debit"/>
<field name="credit" sum="Total Credit"/>
<field name="amount_currency" readonly="True" groups="base.group_multi_currency"/>
<field name="amount_currency" readonly="True" groups="base.group_multi_currency" optional="hide"/>
<field name="currency_id" readonly="True" invisible="1" />
<field name="date_maturity" optional="hide"/>
<field name="company_currency_id" invisible="1"/>
@@ -207,7 +210,7 @@
<field name="full_reconcile_id" position="attributes"><attribute name="optional">hide</attribute></field>
<field name="tag_ids" position="attributes">
<attribute name="optional">show</attribute>
<attribute name="string">Tax Grid</attribute>
<attribute name="string">Tax Grids</attribute>
<attribute name="domain">[('applicability', '=', 'taxes')]</attribute>
<attribute name="readonly">1</attribute>
</field>
@@ -311,6 +314,8 @@
('name', 'ilike', self), ('ref', 'ilike', self), ('account_id', 'ilike', self), ('partner_id', 'ilike', self)]"/>
<field name="date"/>
<field name="account_id"/>
<field name="account_root_id"/>
<field name="account_internal_type"/>
<field name="partner_id"/>
<field name="journal_id"/>
<field name="move_id" string="Journal Entry" filter_domain="[
@@ -347,6 +352,20 @@
</search>
</field>
</record>
<record id="view_account_move_line_filter_with_root_selection" model="ir.ui.view">
<field name="name">account.move.line.search</field>
<field name="model">account.move.line</field>
<field name="mode">primary</field>
<field name="priority">20</field>
<field name="inherit_id" ref="account.view_account_move_line_filter"/>
<field name="arch" type="xml">
<xpath expr="//group" position="after">
<searchpanel class="account_root">
<field name="account_root_id" icon="fa-filter"/>
</searchpanel>
</xpath>
</field>
</record>
<!-- account.move (Journal Entry) -->
@@ -379,12 +398,13 @@
<field name="invoice_partner_icon" string=" "/>
<field name="invoice_partner_display_name" invisible="context.get('default_type') not in ('in_invoice', 'in_refund','in_receipt')" groups="base.group_user" string="Vendor" />
<field name="invoice_partner_display_name" invisible="context.get('default_type') not in ('out_invoice', 'out_refund','out_receipt')" groups="base.group_user" string="Customer" />
<field name="invoice_date" optional="show"/>
<field name="invoice_payment_ref" optional="hide"/>
<field name="invoice_date" optional="show" invisible="context.get('default_type') not in ('in_invoice', 'in_refund','in_receipt')" string="Bill Date"/>
<field name="invoice_date" optional="show" invisible="context.get('default_type') not in ('out_invoice', 'out_refund','out_receipt')" string="Invoice Date"/>
<field name="invoice_origin" optional="show" string="Source Document"/>
<field name="invoice_payment_ref" optional="hide" invisible="context.get('default_type') in ('out_invoice', 'out_refund','out_receipt')"/>
<field name="invoice_user_id" optional="show" invisible="context.get('default_type') not in ('out_invoice', 'out_refund','out_receipt')" string="Sales Person"/>
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}" optional="show"/>
<field name="invoice_date_due" optional="show"/>
<field name="invoice_origin" optional="show" string="Source Document"/>
<field name="amount_untaxed_signed" string="Tax Excluded" sum="Total" optional="show"/>
<field name="amount_tax_signed" string="Tax" sum="Total" optional="hide"/>
<field name="amount_total_signed" string="Total" sum="Total" optional="show"/>
@@ -450,10 +470,7 @@
<!-- Post -->
<button name="action_post" string="Post" class="oe_highlight"
type="object" groups="account.group_account_invoice"
attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('type', 'in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}"/>
<button name="action_post" string="Validate" class="oe_highlight"
type="object" groups="account.group_account_invoice"
attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}"/>
attrs="{'invisible': [('state', '!=', 'draft')]}"/>
<!-- Send (only invoices) -->
<button name="action_invoice_sent"
type="object"
@@ -540,26 +557,28 @@
<div>
<!-- Invoice draft header -->
<span class="o_form_label"><field name="type" attrs="{'invisible': ['|', ('type', '=', 'entry'), ('state', '=', 'draft')]}" readonly="1" nolabel="1"/></span>
<span class="o_form_label" attrs="{'invisible': ['|', '|', ('type', '!=', 'out_invoice'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Invoice</span>
<span class="o_form_label" attrs="{'invisible': ['|', '|', ('type', '!=', 'out_refund'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Credit Note</span>
<span class="o_form_label" attrs="{'invisible': ['|', '|', ('type', '!=', 'in_invoice'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Bill</span>
<span class="o_form_label" attrs="{'invisible': ['|', '|', ('type', '!=', 'in_refund'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Refund</span>
<span class="o_form_label" attrs="{'invisible': ['|', '|', ('type', '!=', 'out_receipt'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Sales Receipt</span>
<span class="o_form_label" attrs="{'invisible': ['|', '|', ('type', '!=', 'in_receipt'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Purchase Receipt</span>
<h1>
<span attrs="{'invisible': ['|', '|', ('type', '!=', 'out_invoice'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Invoice</span>
<span attrs="{'invisible': ['|', '|', ('type', '!=', 'out_refund'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Credit Note</span>
<span attrs="{'invisible': ['|', '|', ('type', '!=', 'in_invoice'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Bill</span>
<span attrs="{'invisible': ['|', '|', ('type', '!=', 'in_refund'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Refund</span>
<span attrs="{'invisible': ['|', '|', ('type', '!=', 'out_receipt'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Sales Receipt</span>
<span attrs="{'invisible': ['|', '|', ('type', '!=', 'in_receipt'), ('state', '!=', 'draft'), ('name', '!=', '/')]}">Draft Purchase Receipt</span>
</h1>
<!-- Select next number header (only invoices) -->
<span class="o_form_label" attrs="{'invisible': [('invoice_sequence_number_next_prefix', '=', False)]}">- First Number:</span>
<span class="o_form_label" attrs="{'invisible': [('invoice_sequence_number_next_prefix', '=', False)]}">First Number:</span>
<!-- Number -->
<h1 class="mt0">
<field name="name" readonly="True" attrs="{'invisible':[('name', '=', '/')]}"/>
<!-- Select next number header (only invoices) -->
<div attrs="{'invisible': [('invoice_sequence_number_next_prefix', '=', False)]}">
<field name="invoice_sequence_number_next_prefix" class="oe_inline"/>
<field name="invoice_sequence_number_next" class="oe_inline"/>
</div>
</h1>
<!-- Select next number header (only invoices) -->
<div attrs="{'invisible': [('invoice_sequence_number_next_prefix', '=', False)]}">
<field name="invoice_sequence_number_next_prefix" class="oe_inline"/>
<field name="invoice_sequence_number_next" class="oe_inline"/>
</div>
</div>
<group>
<group id="header_left_group">
@@ -579,20 +598,6 @@
'required': [('type', 'in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]
}"/>
<!-- Invoice payment terms (only invoices) + due date (only invoices / receipts) -->
<label for="invoice_payment_term_id"
attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}"/>
<div attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}">
<field name="invoice_payment_term_id"
class="oe_inline"
attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}"/>
<span class="o_form_label oe_edit_only"
attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('invoice_payment_term_id', '!=', False), '|', ('invoice_date_due', '!=', False), '|', ('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}"> or </span>
<field name="invoice_date_due" force_save="1"
class="oe_inline"
attrs="{'invisible': ['|', ('invoice_payment_term_id', '!=', False), ('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}"/>
</div>
<field name="ref"
attrs="{'invisible': [('type', '=', 'out_invoice')]}"/>
<field name="invoice_vendor_bill_id"
@@ -602,14 +607,6 @@
options="{'no_create': True}" context="{'show_total_amount': True}"/>
</group>
<group id="header_right_group">
<field name="journal_id"
invisible="context.get('default_journal_id') and context.get('type', 'entry') != 'entry'"
groups="account.group_account_user"
options="{'no_create': True}"
domain="[('type', '=?', invoice_filter_type_domain)]"/>
<field name="date" string="Accounting Date"
attrs="{'invisible': [('type', 'in', ('out_invoice', 'out_refund', 'out_receipt')), ('state', '=', 'draft')]}"/>
<!-- Invoice date (only invoices / receipts) -->
<div class="o_td_label">
<label for="invoice_date" string="Invoice Date" style="font-weight:bold;"
@@ -617,9 +614,32 @@
<label for="invoice_date" string="Bill Date" style="font-weight:bold;"
attrs="{'invisible': [('type', 'not in', ('in_invoice', 'in_refund', 'in_receipt'))]}"/>
</div>
<field name="invoice_date" nolabel="1"
<field name="invoice_date" nolabel="1" options="{'datepicker': {'warn_future': true}}"
attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}"/>
<field name="date" string="Accounting Date"
attrs="{'invisible': [('type', 'in', ('out_invoice', 'out_refund', 'out_receipt'))]}"/>
<!-- Invoice payment terms (only invoices) + due date (only invoices / receipts) -->
<label for="invoice_payment_term_id"
attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}"/>
<div class="d-flex" attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}">
<field name="invoice_payment_term_id"
placeholder="Terms"
attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}"/>
<span class="o_form_label mx-3 oe_edit_only"
attrs="{'invisible': [ '|', '|', '|', ('state', '!=', 'draft'), ('invoice_payment_term_id', '!=', False), ('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}"> or </span>
<field name="invoice_date_due" force_save="1"
placeholder="Date"
attrs="{'invisible': ['|', ('invoice_payment_term_id', '!=', False), ('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt'))]}"/>
</div>
<field name="journal_id"
invisible="context.get('default_journal_id') and context.get('type', 'entry') != 'entry'"
groups="account.group_account_user"
options="{'no_create': True}"
domain="[('type', '=?', invoice_filter_type_domain)]"/>
<field name="currency_id"
groups="base.group_multi_currency"
attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund'))]}"/>
@@ -633,7 +653,7 @@
widget="section_and_note_one2many"
mode="tree,kanban"
context="{'journal_id': journal_id, 'default_partner_id': commercial_partner_id, 'default_currency_id': currency_id != company_currency_id and currency_id or False}">
<tree editable="bottom" string="Journal Items">
<tree editable="bottom" string="Journal Items" default_order="sequence, date desc, move_name desc, id">
<control>
<create name="add_line_control" string="Add a line"/>
<create name="add_section_control" string="Add a section" context="{'default_display_type': 'line_section'}"/>
@@ -642,27 +662,31 @@
<!-- Displayed fields -->
<field name="sequence" widget="handle"/>
<field name="product_id" domain="['|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"/>
<field name="name" widget="section_and_note_text" required="1"/>
<field name="move_name" invisible="1"/>
<field name="product_id" optional="show" domain="['|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"/>
<field name="name" widget="section_and_note_text" attrs="{'required': [('parent.type', 'not in', ('in_invoice', 'in_refund','in_receipt'))]}"/>
<field name="account_id"
groups="account.group_account_user"
domain="[('deprecated', '=', False), ('user_type_id.type', 'not in', ('receivable', 'payable')), ('company_id', '=', parent.company_id)]"
attrs="{'required': [('display_type', '=', False)]}"/>
<field name="analytic_account_id"
domain="['|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"
groups="analytic.group_analytic_accounting"/>
groups="analytic.group_analytic_accounting"
optional="show"/>
<field name="analytic_tag_ids"
domain="['|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"
groups="analytic.group_analytic_tags"
optional="show"
widget="many2many_tags"/>
<field name="quantity"/>
<field name="product_uom_id" string="UoM" groups="uom.group_uom"/>
<field name="product_uom_id" string="UoM" groups="uom.group_uom" optional="show"/>
<field name="price_unit" string="Price"/>
<field name="discount" string="Disc.%" groups="base.group_no_one"/>
<field name="discount" string="Disc.%" groups="base.group_no_one" optional="show"/>
<field name="tax_ids" widget="many2many_tags"
domain="[('type_tax_use', '=?', parent.invoice_filter_type_domain), ('company_id', '=', parent.company_id)]"
context="{'append_type_to_tax_name': not parent.invoice_filter_type_domain}"
options="{'no_create': True}"/>
options="{'no_create': True}"
optional="show"/>
<field name="price_subtotal"
string="Subtotal"
groups="account.group_show_line_subtotals_tax_excluded"/>
@@ -676,6 +700,7 @@
<field name="currency_id" invisible="1"/>
<field name="debit" invisible="1"/>
<field name="credit" invisible="1"/>
<field name="date" invisible="1"/>
<field name="date_maturity" invisible="1"/>
<field name="tax_line_id" invisible="1"/>
@@ -719,7 +744,7 @@
<page id="aml_tab" string="Journal Items" groups="account.group_account_user">
<field name="line_ids"
context="{'line_ids': line_ids, 'journal_id': journal_id, 'default_partner_id': commercial_partner_id, 'default_currency_id': currency_id != company_currency_id and currency_id or False}">
<tree editable="bottom" string="Journal Items" decoration-muted="display_type in ('line_section', 'line_note')">
<tree editable="bottom" string="Journal Items" decoration-muted="display_type in ('line_section', 'line_note')" default_order="sequence, date desc, move_name desc, id">
<!-- Displayed fields -->
<field name="account_id"
attrs="{
@@ -729,26 +754,28 @@
<field name="partner_id"
domain="['|', ('parent_id', '=', False), ('is_company', '=', True)]"
attrs="{'column_invisible': [('parent.type', '!=', 'entry')]}"/>
<field name="name" widget="section_and_note_text"/>
<field name="name" widget="section_and_note_text" optional="show"/>
<field name="analytic_account_id"
optional="hide"
groups="analytic.group_analytic_accounting"
attrs="{'invisible': [('display_type', 'in', ('line_section', 'line_note'))]}"/>
<field name="analytic_tag_ids"
optional="show"
groups="analytic.group_analytic_tags"
widget="many2many_tags"
attrs="{'invisible': [('display_type', 'in', ('line_section', 'line_note'))]}"/>
<field name="date_maturity"
optional="hide"
invisible="context.get('view_no_maturity')"
attrs="{'invisible': [('display_type', 'in', ('line_section', 'line_note'))]}"/>
<field name="amount_currency"
groups="base.group_multi_currency"/>
groups="base.group_multi_currency"
optional="hide"/>
<field name="currency_id" options="{'no_create': True}"
groups="base.group_multi_currency"
attrs="{'column_invisible': [('parent.type', '!=', 'entry')]}"/>
<field name="debit"
sum="Total Debit"
attrs="{'invisible': [('display_type', 'in', ('line_section', 'line_note'))]}"/>
<field name="credit"
sum="Total Credit"
attrs="{'invisible': [('display_type', 'in', ('line_section', 'line_note'))]}"/>
<field name="tax_ids" string="Taxes Applied" widget="many2many_tags"
<field name="tax_ids" widget="many2many_tags"
optional="hide"
domain="[('type_tax_use', '=?', parent.invoice_filter_type_domain)]"
context="{'append_type_to_tax_name': not parent.invoice_filter_type_domain}"
options="{'no_create': True}"
@@ -761,9 +788,13 @@
('parent.type', 'in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund', 'out_receipt', 'in_receipt')),
('account_internal_type', 'in', ('receivable', 'payable')),
]}"/>
<field name="date_maturity"
invisible="context.get('view_no_maturity')"
<field name="debit"
sum="Total Debit"
attrs="{'invisible': [('display_type', 'in', ('line_section', 'line_note'))]}"/>
<field name="credit"
sum="Total Credit"
attrs="{'invisible': [('display_type', 'in', ('line_section', 'line_note'))]}"/>
<field name="tag_ids" widget="many2many_tags" string="Tax Grids" optional="show"/>
<!-- Others fields -->
<field name="payment_id" invisible="1"/>
@@ -777,12 +808,13 @@
<field name="price_total" invisible="1"/>
<field name="sequence" invisible="1"/>
<field name="move_name" invisible="1"/>
<field name="date" invisible="1"/>
<field name="tax_line_id" invisible="1"/>
<field name="tax_group_id" invisible="1"/>
<field name="tax_repartition_line_id" invisible="1"/>
<field name="tag_ids" invisible="1"/>
<field name="tax_base_amount" invisible="1"/>
<field name="tax_exigible" invisible="1"/>
<field name="tax_repartition_line_id" invisible="1" force_save="1"/>
<field name="tax_base_amount" invisible="1" force_save="1"/>
<field name="tax_exigible" invisible="1" force_save="1"/>
<field name="company_id" invisible="1"/>
<field name="company_currency_id" invisible="1"/>
<field name="recompute_tax_line" invisible="1" force_save="1"/>
@@ -816,7 +848,7 @@
<page id="other_tab" string="Other Info" name="other_info"
attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund'))]}">
<group id="other_tab_group">
<group string="Sales Information"
<group string="Invoice"
name="sale_info_group"
attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund'))]}">
<field name="company_id" groups="base.group_multi_company"/>
@@ -824,7 +856,7 @@
<field name="invoice_origin" string="Source Document"
attrs="{'invisible': [('type', '=', 'entry')]}"/>
</group>
<group string="Accounting Information"
<group string="Accounting"
name="accounting_info_group"
attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund'))]}">
<field name="invoice_incoterm_id"/>
@@ -834,7 +866,7 @@
widget="email"
attrs="{'invisible': ['|', ('type', 'not in', ('in_invoice', 'in_refund')), ('invoice_source_email', '=', False)]}"/>
</group>
<group string="Payments Information"
<group string="Payments"
name="payments_info_group"
attrs="{'invisible': [('type', 'not in', ('out_invoice', 'out_refund', 'in_invoice', 'in_refund'))]}">
<field name="invoice_payment_ref"/>
@@ -851,6 +883,8 @@
attrs="{'invisible': [('type', '!=', 'entry')], 'readonly': [('reversed_entry_id', '!=', False)]}"/>
<field name="reversed_entry_id"
attrs="{'invisible': [('type', '!=', 'entry')]}"/>
<field name="to_check"
attrs="{'invisible': [('type', '!=', 'entry')]}" />
</group>
<group>
<field name="company_id" groups="base.group_multi_company" required="1"/>
@@ -924,8 +958,9 @@
<field name="date" string="Period"/>
<filter domain="[('invoice_user_id', '=', uid)]" name="myinvoices" help="My Invoices"/>
<separator/>
<filter name="draft" string="Draft" domain="[('state', '=', 'draft')]"/>
<filter name="unpaid" string="Open" domain="[('state', '=', 'posted'), ('invoice_payment_state', '=', 'not_paid')]"/>
<filter name="draft" string="Draft" domain="[('state','=','draft')]"/>
<filter name="unpaid" string="Posted" domain="[('state', '=', 'posted'), ('invoice_payment_state', '=', 'not_paid')]"/>
<separator/>
<filter name="in_payment" string="In Payment" domain="[('invoice_payment_state', '=', 'in_payment')]"/>
<filter name="paid" string="Paid" domain="[('invoice_payment_state', '=', 'paid')]"/>
<filter name="late" string="Overdue" domain="['&amp;', ('invoice_date_due', '&lt;', time.strftime('%%Y-%%m-%%d')), ('state', '=', 'posted'), ('invoice_payment_state', '=', 'not_paid')]" help="Overdue invoices, maturity date passed"/>
@@ -933,8 +968,6 @@
<filter name="invoice_date" string="Invoice Date" date="invoice_date"/>
<filter name="due_date" string="Due Date" date="invoice_date_due"/>
<separator/>
<filter string="My Activities" name="activities_my" domain="[('activity_ids.user_id', '=', uid)]"/>
<separator/>
<filter invisible="1" string="Late Activities" name="activities_overdue"
domain="[('activity_ids.date_deadline', '&lt;', context_today().strftime('%Y-%m-%d'))]"
help="Show all records which has next action date is before today"/>
@@ -983,6 +1016,14 @@
<field name="tag">manual_reconciliation_view</field>
</record>
<record id="action_accrual_entry" model="ir.actions.server">
<field name="name">Change Period</field>
<field name="model_id" ref="account.model_account_move_line"/>
<field name="binding_model_id" ref="account.model_account_move_line"/>
<field name="state">code</field>
<field name="code">action = records.action_accrual_entry()</field>
</record>
<act_window
id="action_move_line_select_tax_audit"
name="Journal Items for Tax Audit"
@@ -1005,16 +1046,16 @@
<field name="res_model">account.move.line</field>
<field name="domain">[('display_type', 'not in', ('line_section', 'line_note'))]</field>
<field name="view_id" ref="view_move_line_tree_grouped_sales_purchases"/>
<field name="view_mode">tree,pivot,graph,form,kanban</field>
<field name="view_mode">tree,pivot,graph</field>
</record>
<record id="action_account_moves_journal_purchase" model="ir.actions.act_window">
<field name="context">{'journal_type':'purchase', 'search_default_group_by_move': 1, 'search_default_posted':1, 'search_default_purchases':1, 'name_groupby':1, 'expand': 1}</field>
<field name="name">Purchase</field>
<field name="name">Purchases</field>
<field name="res_model">account.move.line</field>
<field name="domain">[('display_type', 'not in', ('line_section', 'line_note'))]</field>
<field name="view_id" ref="view_move_line_tree_grouped_sales_purchases"/>
<field name="view_mode">tree,pivot,graph,form,kanban</field>
<field name="view_mode">tree,pivot,graph</field>
</record>
<record id="action_account_moves_journal_bank_cash" model="ir.actions.act_window">
@@ -1023,7 +1064,7 @@
<field name="res_model">account.move.line</field>
<field name="domain">[('display_type', 'not in', ('line_section', 'line_note'))]</field>
<field name="view_id" ref="view_move_line_tree_grouped_bank_cash"/>
<field name="view_mode">tree,pivot,graph,form,kanban</field>
<field name="view_mode">tree,pivot,graph</field>
</record>
<record id="action_account_moves_journal_misc" model="ir.actions.act_window">
@@ -1032,7 +1073,7 @@
<field name="res_model">account.move.line</field>
<field name="domain">[('display_type', 'not in', ('line_section', 'line_note'))]</field>
<field name="view_id" ref="view_move_line_tree_grouped_misc"/>
<field name="view_mode">tree,pivot,graph,form,kanban</field>
<field name="view_mode">tree,pivot,graph</field>
</record>
<record id="action_account_moves_ledger_general" model="ir.actions.act_window">
@@ -1041,7 +1082,8 @@
<field name="res_model">account.move.line</field>
<field name="domain">[('display_type', 'not in', ('line_section', 'line_note'))]</field>
<field name="view_id" ref="view_move_line_tree_grouped_general"/>
<field name="view_mode">tree,pivot,graph,form,kanban</field>
<field name="search_view_id" ref="view_account_move_line_filter_with_root_selection"/>
<field name="view_mode">tree,pivot,graph</field>
</record>
<record id="action_account_moves_ledger_partner" model="ir.actions.act_window">
@@ -1050,7 +1092,8 @@
<field name="res_model">account.move.line</field>
<field name="domain">[('display_type', 'not in', ('line_section', 'line_note'))]</field>
<field name="view_id" ref="view_move_line_tree_grouped_partner"/>
<field name="view_mode">tree,pivot,graph,form,kanban</field>
<field name="search_view_id" ref="view_account_move_line_filter_with_root_selection"/>
<field name="view_mode">tree,pivot,graph</field>
</record>
<record id="action_account_moves_all_tree" model="ir.actions.act_window">
+19 -16
View File
@@ -127,7 +127,7 @@
<header>
<button name="post" class="oe_highlight" states="draft" string="Confirm" type="object"/>
<button name="action_draft" class="oe_highlight" states="cancelled" string="Set To Draft" type="object"/>
<field name="state" widget="statusbar" statusbar_visible="draft,posted,reconciled,cancelled"/>
<field name="state" widget="statusbar" statusbar_visible="draft,posted,reconciled"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
@@ -136,9 +136,11 @@
groups="account.group_account_user"
attrs="{'invisible':[('move_line_ids','=',[])]}" icon="fa-bars"/>
<field name="move_line_ids" invisible="1"/>
<button class="oe_stat_button" name="button_invoices"
string="Invoices" type="object"
attrs="{'invisible':[('has_invoices','=',False)]}" icon="fa-bars"/>
<button class="oe_stat_button" name="button_invoices" type="object" icon="fa-bars">
<field name="reconciled_invoices_count"/>
<span attrs="{'invisible':[('reconciled_invoices_count','&gt;',1)]}">Invoice</span>
<span attrs="{'invisible':[('reconciled_invoices_count','&lt;=',1)]}">Invoices</span>
</button>
<button class="oe_stat_button" name="open_payment_matching_screen"
string="Payment Matching" type="object"
groups="account.group_account_user"
@@ -156,17 +158,10 @@
<field name="payment_type" widget="radio"/>
<field name="partner_type" widget="selection" attrs="{'required': [('state', '=', 'draft'), ('payment_type', 'in', ('inbound', 'outbound'))], 'invisible': [('payment_type', 'not in', ('inbound', 'outbound'))]}"/>
<field name="partner_id" attrs="{'required': [('state', '=', 'draft'), ('payment_type', 'in', ('inbound', 'outbound'))], 'invisible': [('payment_type', 'not in', ('inbound', 'outbound'))]}" context="{'default_is_company': True}"/>
</group>
<group name="right_column">
<field name="communication"/>
<field name="payment_date"/>
<field name="company_id" groups="base.group_multi_company" required="1"/>
</group>
<group>
<label for="amount"/>
<div name="amount_div" class="o_row">
<field name="amount"/>
<field name="currency_id" options="{'no_create': True, 'no_open': True}" groups="base.group_multi_currency"/>
</div>
<field name="amount" invisible="1"/>
<field name="journal_id" widget="selection" attrs="{'invisible': [('amount', '=', 0), ('state', '!=', 'draft')]}"/>
<field name="destination_journal_id" widget="selection" attrs="{'required': [('payment_type', '=', 'transfer')], 'invisible': [('payment_type', '!=', 'transfer')]}"/>
<field name="hide_payment_method" invisible="1"/>
@@ -176,10 +171,16 @@
<field name="require_partner_bank_account" invisible="1"/>
<field name="payment_method_code" invisible="1"/>
</group>
<group>
<field name="company_id" groups="base.group_multi_company" required="1"/>
<group name="right_column">
<label for="amount"/>
<div name="amount_div" class="o_row">
<field name="amount"/>
<field name="currency_id" options="{'no_create': True, 'no_open': True}" groups="base.group_multi_currency"/>
</div>
<field name="payment_date"/>
<field name="communication"/>
</group>
<group attrs="{'invisible': [('payment_difference', '=', 0.0)]}">
<group name="payment_difference" attrs="{'invisible': [('payment_difference', '=', 0.0)]}" groups="account.group_account_user">
<label for="payment_difference"/>
<div>
<field name="payment_difference"/>
@@ -194,6 +195,7 @@
</group>
</group>
</sheet>
<div class="o_attachment_preview"/>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers" groups="base.group_user"/>
<field name="activity_ids" widget="mail_activity"/>
@@ -304,6 +306,7 @@
<field name="mode">primary</field>
<field name="arch" type="xml">
<xpath expr="//header" position='replace'></xpath>
<xpath expr="//div[@name='button_box']" position='replace'></xpath>
<xpath expr="//sheet" position='after'>
<footer>
<field name="state" invisible="1"/>
@@ -74,7 +74,7 @@
<template id="portal_invoice_page" name="Invoice Portal Template" inherit_id="portal.portal_sidebar" primary="True">
<xpath expr="//div[hasclass('o_portal_sidebar')]" position="inside">
<t t-set="o_portal_fullwidth_alert" groups="sales_team.group_sale_salesman">
<t t-set="o_portal_fullwidth_alert" groups="sales_team.group_sale_salesman,account.group_account_invoice">
<t t-call="portal.portal_back_in_edit_mode">
<t t-set="backend_url" t-value="'/web#return_label=Website&amp;model=%s&amp;id=%s&amp;action=%s&amp;view_type=form' % (invoice._name, invoice.id, invoice.env.ref('account.action_move_out_invoice_type').id)"/>
</t>
+13 -12
View File
@@ -9,21 +9,22 @@
report_type="qweb-pdf"
name="account.report_invoice_with_payments"
file="account.report_invoice_with_payments"
attachment="(object.state == 'posted') and ('INV'+(object.name or '').replace('/','')+'.pdf')"
attachment="(object.state == 'posted') and ((object.name or 'INV').replace('/','_')+'.pdf')"
print_report_name="(object._get_report_base_filename())"
groups="account.group_account_invoice"
/>
<report
id="action_account_original_vendor_bill"
model="account.move"
string="Original vendor bills"
report_type="qweb-pdf"
name="account.report_original_vendor_bill"
file="account.report_original_vendor_bill"
attachment="'original_vendor_bill.pdf'"
attachment_use="True"
/>
<record id="action_account_original_vendor_bill" model="ir.actions.report">
<field name="name">Original Bills</field>
<field name="model">account.move</field>
<field name="binding_model_id" ref="model_account_move"/>
<field name="report_type">qweb-pdf</field>
<field name="report_name">account.report_original_vendor_bill</field>
<field name="report_file">account.report_original_vendor_bill</field>
<field name="attachment">'original_vendor_bill.pdf'</field>
<field name="attachment_use">True</field>
<field name="binding_view_types">list</field>
</record>
<report
id="account_invoices_without_payment"
@@ -32,7 +33,7 @@
report_type="qweb-pdf"
name="account.report_invoice"
file="account.report_invoice"
attachment="(object.state == 'posted') and ('INV'+(object.name or '').replace('/','')+'.pdf')"
attachment="(object.state == 'posted') and ((object.name or 'INV').replace('/','_')+'.pdf')"
print_report_name="(object._get_report_base_filename())"
/>
+126 -51
View File
@@ -15,7 +15,7 @@
<group>
<field name="code" placeholder="code"/>
<field name="name"/>
<field name="user_type_id" widget="selection"/>
<field name="user_type_id" widget="account_hierarchy_selection"/>
<field name="tax_ids" widget="many2many_tags" domain="[('company_id','=',company_id)]" attrs="{'invisible': [('internal_group', '=', 'off_balance')]}"/>
<field name="tag_ids" widget="many2many_tags" domain="[('applicability', '!=', 'taxes')]" context="{'default_applicability': 'accounts'}" options="{'no_create_edit': True}"/>
<field name="group_id"/>
@@ -96,6 +96,9 @@
<group expand="0" string="Group By">
<filter string="Account Type" name="accounttype" domain="" context="{'group_by':'user_type_id'}"/>
</group>
<searchpanel class="account_root">
<field name="root_id" icon="fa-filter"/>
</searchpanel>
</search>
</field>
</record>
@@ -120,7 +123,7 @@
</field>
</record>
<menuitem action="action_account_form" id="menu_action_account_form" parent="account.account_account_menu" groups="account.group_account_user" sequence="2"/>
<menuitem action="action_account_form" id="menu_action_account_form" parent="account.account_account_menu" groups="account.group_account_user" sequence="1"/>
<record id="action_duplicate_account" model="ir.actions.server">
<field name="name">Duplicate</field>
@@ -172,7 +175,7 @@
</kanban>
</field>
</record>
<record id="view_account_journal_search" model="ir.ui.view">
<field name="name">account.journal.search</field>
<field name="model">account.journal</field>
@@ -200,7 +203,7 @@
<tree editable="bottom">
<field name="sequence" widget="handle"/>
<field name="name"/>
<field name="account_journal_ids" widget="many2many_tags" options="{'no_create': True}"/>
<field name="excluded_journal_ids" widget="many2many_tags" options="{'no_create': True}"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
@@ -214,9 +217,9 @@
<form string="Journal Groups">
<sheet>
<group>
<field name="name"/>
<field name="account_journal_ids" widget="many2many_tags" options="{'no_create': True}"/>
<field name="sequence"/>
<field name="name" placeholder="e.g. GAAP, IFRS, ..."/>
<field name="excluded_journal_ids" widget="many2many_tags" options="{'no_create': True}"/>
<field name="sequence" groups="base.group_no_one"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
</sheet>
@@ -240,13 +243,24 @@
<group>
<field name="active" invisible="1"/>
<field name="type"/>
<field name="journal_group_ids" widget="many2many_tags" domain="['|', ('company_id', '=', company_id), ('company_id', '=', False)]" options="{'no_create': True}"/>
</group>
<group>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
</group>
</group>
<notebook>
<page name="bank_account" string="Bank Account" attrs="{'invisible': [('type', '!=', 'bank')]}">
<group>
<group>
<field name="company_partner_id" invisible="1"/>
<field name="bank_account_id" context="{'default_partner_id': company_partner_id, 'form_view_ref': 'account.view_company_partner_bank_form'}"/>
<field name="bank_id"/>
</group>
<group >
<field name="bank_statements_source" widget="radio" attrs="{'required': [('type', '=', 'bank')]}" groups="account.group_account_user"/>
</group>
</group>
</page>
<page name="journal_entries" string="Journal Entries">
<group>
<group>
@@ -275,38 +289,12 @@
</group>
</group>
</page>
<page name="bank_account" string="Bank Account" attrs="{'invisible': [('type', '!=', 'bank')]}">
<group>
<group>
<field name="company_partner_id" invisible="1"/>
<field name="bank_account_id" context="{'default_partner_id': company_partner_id, 'form_view_ref': 'account.view_company_partner_bank_form'}"/>
<field name="bank_id"/>
</group>
<group >
<field name="bank_statements_source" widget="radio" attrs="{'required': [('type', '=', 'bank')]}" groups="account.group_account_user"/>
</group>
</group>
</page>
<page name="advanced_settings" string="Advanced Settings">
<group>
<group string="Control-Access" groups="base.group_no_one">
<div class="text-muted" colspan="2">Keep empty for no control</div>
<field name="type_control_ids" widget="many2many_tags"/>
<field name="account_control_ids" widget="many2many_tags"/>
</group>
<group string="Payment Method Types" attrs="{'invisible': [('type', 'not in', ['bank', 'cash'])]}">
<field name="inbound_payment_method_ids" widget="many2many_checkboxes"/>
<field name="outbound_payment_method_ids" widget="many2many_checkboxes"/>
</group>
<group string="Invoice References" attrs="{'invisible': [('type', '!=', 'sale')]}">
<group string="Payment References" attrs="{'invisible': [('type', '!=', 'sale')]}">
<field name="invoice_reference_type"/>
<field name="invoice_reference_model" attrs="{'invisible': [('invoice_reference_type', '=', 'none')]}"/>
</group>
<group string="Accounting App Options" attrs="{'invisible': [('type', 'not in', ['bank', 'cash', 'sale', 'purchase'])]}">
<field name="profit_account_id" options="{'no_create': True}" attrs="{'invisible': [('type', '!=', 'cash')]}"/>
<field name="loss_account_id" options="{'no_create': True}" attrs="{'invisible': [('type', '!=', 'cash')]}"/>
<field name="post_at_bank_rec" attrs="{'invisible': [('type', 'not in', ['bank', 'cash'])]}"/>
</group>
<group name="group_alias" string="Email your Invoices/Bills" attrs="{'invisible': [('type', 'not in', ('sale' ,'purchase'))]}">
<label string="Email Alias" attrs="{'invisible': [('alias_domain', '=', False)]}" for="alias_id"/>
<div name="alias_def" attrs="{'invisible': [('alias_domain', '=', False)]}">
@@ -319,6 +307,20 @@
<a type='action' name='%(action_open_settings)d' class="btn btn-link" role="button"><i class="fa fa-fw o_button_icon fa-arrow-right"/> Configure Email Servers</a>
</div>
</group>
<group string="Posting" name="column_posting" groups="account.group_account_user,account.group_account_manager" attrs="{'invisible': [('type', 'not in', ['bank', 'cash'])]}">
<field name="profit_account_id" options="{'no_create': True}" attrs="{'invisible': [('type', '!=', 'cash')]}"/>
<field name="loss_account_id" options="{'no_create': True}" attrs="{'invisible': [('type', '!=', 'cash')]}"/>
<field name="post_at" widget="radio" attrs="{'invisible': [('type', 'not in', ['bank', 'cash'])]}"/>
</group>
<group string="Control-Access" groups="account.group_account_manager">
<div class="text-muted" colspan="2">Keep empty for no control</div>
<field name="type_control_ids" widget="many2many_tags"/>
<field name="account_control_ids" widget="many2many_tags"/>
</group>
<group string="Payment Method Types" attrs="{'invisible': [('type', 'not in', ['bank', 'cash'])]}">
<field name="inbound_payment_method_ids" widget="many2many_checkboxes"/>
<field name="outbound_payment_method_ids" widget="many2many_checkboxes"/>
</group>
</group>
</page>
</notebook>
@@ -332,6 +334,76 @@
</field>
</record>
<record id="view_account_bank_journal_tree" model="ir.ui.view">
<field name="name">account.bank.journal.tree</field>
<field name="model">account.journal</field>
<field name="priority">10</field>
<field name="arch" type="xml">
<tree string="Account Journal">
<field name='sequence' widget='handle'/>
<field name="name"/>
<field name="bank_acc_number"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<record id="account_bank_journal_view_kanban" model="ir.ui.view">
<field name="name">account.bank.journal.kanban</field>
<field name="model">account.journal</field>
<field name="priority">10</field>
<field name="arch" type="xml">
<kanban class="o_kanban_mobile">
<templates>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_content oe_kanban_global_click">
<div class="row">
<div class="col-12">
<strong><field name="name"/></strong>
</div>
</div>
</div>
</t>
</templates>
</kanban>
</field>
</record>
<record id="view_account_bank_journal_form" model="ir.ui.view">
<field name="name">account.bank.journal.form</field>
<field name="model">account.journal</field>
<field name="priority">10</field>
<field name="arch" type="xml">
<form string="Bank Account">
<sheet>
<field name="type" invisible="1"/>
<div class="oe_title">
<label for="name" class="oe_edit_only" string="Bank Account Name"/>
<h1><field name="name"/></h1>
</div>
<group>
<field name="bank_id"/>
</group>
</sheet>
</form>
</field>
</record>
<record id="action_account_bank_journal_form" model="ir.actions.act_window">
<field name="name">Bank Accounts</field>
<field name="res_model">account.journal</field>
<field name="view_mode">tree,kanban,form</field>
<field name="view_ids" eval="[(5, 0, 0),
(0, 0, {'view_mode': 'tree', 'view_id': ref('view_account_bank_journal_tree')}),
(0, 0, {'view_mode': 'kanban', 'view_id': ref('account_bank_journal_view_kanban')}),
(0, 0, {'view_mode': 'form', 'view_id': ref('view_account_bank_journal_form')})]"/>
<field name="domain">[('type', '=', 'bank')]</field>
<field name="context">{'default_type': 'bank'}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a bank account
</p>
</field>
</record>
<menuitem action="action_account_bank_journal_form" id="menu_action_account_invoice_bank_journal_form" parent="root_payment_menu" groups="account.group_account_invoice" sequence="2"/>
<record id="view_company_partner_bank_form" model="ir.ui.view">
<field name="name">company.res.partner.bank.form</field>
<field name="model">res.partner.bank</field>
@@ -354,7 +426,7 @@ action = model.setting_init_bank_account_action()
</field>
</record>
<menuitem action="action_new_bank_setting" id="menu_action_account_bank_journal_form" parent="account_account_menu" groups="account.group_account_manager" sequence="8"/>
<menuitem action="action_new_bank_setting" id="menu_action_account_bank_journal_form" parent="root_payment_menu" groups="account.group_account_manager" sequence="1"/>
<record id="action_account_journal_form" model="ir.actions.act_window">
<field name="name">Journals</field>
@@ -373,7 +445,7 @@ action = model.setting_init_bank_account_action()
</p>
</field>
</record>
<menuitem action="action_account_journal_form" id="menu_action_account_journal_form" parent="account_account_menu" groups="account.group_account_manager"/>
<menuitem action="action_account_journal_form" id="menu_action_account_journal_form" parent="account_invoicing_menu" sequence="5" groups="account.group_account_manager"/>
<record id="action_account_journal_group_list" model="ir.actions.act_window">
<field name="name">Journal Groups</field>
@@ -386,7 +458,7 @@ action = model.setting_init_bank_account_action()
</p>
</field>
</record>
<menuitem action="action_account_journal_group_list" id="menu_action_account_journal_group_list" parent="account_account_menu"/>
<menuitem action="action_account_journal_group_list" id="menu_action_account_journal_group_list" parent="account_account_menu" sequence="2" groups="account.group_account_manager"/>
<!-- Tags -->
<record id="account_tag_view_form" model="ir.ui.view">
@@ -724,7 +796,7 @@ action = model.setting_init_bank_account_action()
<field name="journal_id" invisible="1" />
<field name="date"/>
<field name="name"/>
<field name="ref"/>
<field name="ref" groups="base.group_no_one"/>
<field name="partner_id"/>
<field name="amount"/>
<field name="transaction_type" optional="hidden"/>
@@ -833,8 +905,8 @@ action = model.setting_init_bank_account_action()
</div>
<field name="match_same_currency" attrs="{'invisible': [('rule_type', '!=', 'invoice_matching')]}"/>
<label for="match_total_amount"
attrs="{'invisible': ['|', ('rule_type', '!=', 'invoice_matching'), ('match_same_currency', '=', False)]}"/>
<div attrs="{'invisible': ['|', ('rule_type', '!=', 'invoice_matching'), ('match_same_currency', '=', False)]}">
attrs="{'invisible': ['|', '|', ('rule_type', '!=', 'invoice_matching'), ('match_same_currency', '=', False), ('match_partner', '=', False)]}"/>
<div attrs="{'invisible': ['|', '|', ('rule_type', '!=', 'invoice_matching'), ('match_same_currency', '=', False), ('match_partner', '=', False)]}">
<field name="match_total_amount" class="oe_inline"/>
<field name="match_total_amount_param" class="oe_inline"
attrs="{'invisible': [('match_total_amount', '=', False)]}"/>
@@ -882,11 +954,13 @@ action = model.setting_init_bank_account_action()
</group>
<group>
<field name="label"/>
<label for="amount"/>
<div>
<label for="amount" attrs="{'invisible': [('amount_type','=','regex')]}"/>
<div attrs="{'invisible': [('amount_type','=','regex')]}">
<field name="amount" class="oe_inline"/>
<span class="o_form_label oe_inline" attrs="{'invisible':[('amount_type','!=','percentage')]}">%</span>
</div>
<field name="amount_from_label_regex" attrs="{'invisible': [('amount_type','!=','regex')]}"/>
<field name="decimal_separator" attrs="{'invisible': [('amount_type','!=','regex')]}"/>
<field name="journal_id" domain="[('type', '!=', 'general'), ('company_id', '=', company_id)]" widget="selection"
attrs="{'invisible': [('rule_type', '!=', 'writeoff_button')]}"/>
</group>
@@ -914,11 +988,12 @@ action = model.setting_init_bank_account_action()
</group>
<group>
<field name="second_label" string="Journal Item Label"/>
<label for="second_amount" string="Amount"/>
<div>
<label for="second_amount" string="Amount" attrs="{'invisible': [('second_amount_type', '=', 'regex')]}"/>
<div attrs="{'invisible': [('second_amount_type', '=', 'regex')]}">
<field name="second_amount" class="oe_inline"/>
<span class="o_form_label oe_inline" attrs="{'invisible':[('amount_type','!=','percentage')]}">%</span>
<span class="o_form_label oe_inline" attrs="{'invisible':[('second_amount_type','!=','percentage')]}">%</span>
</div>
<field name="second_amount_from_label_regex" attrs="{'invisible': [('second_amount_type','!=','regex')]}"/>
<field name="second_journal_id" string="Journal" domain="[('type', '!=', 'general'), ('company_id', '=', company_id)]" widget="selection"
attrs="{'invisible': [('rule_type', '!=', 'writeoff_button')]}"/>
</group>
@@ -966,7 +1041,7 @@ action = model.setting_init_bank_account_action()
</field>
</record>
<menuitem id="action_account_reconcile_model_menu" parent="account.account_account_menu"
action="account.action_account_reconcile_model" sequence="100" />
action="account.action_account_reconcile_model" sequence="4" />
<menuitem
id="account_report_folder"
@@ -1209,7 +1284,7 @@ action = model.setting_init_bank_account_action()
</p>
</field>
</record>
<menuitem action="action_tax_form" id="menu_action_tax_form" parent="account_account_menu" sequence="2"/>
<menuitem action="action_tax_form" id="menu_action_tax_form" parent="account_invoicing_menu" sequence="2"/>
<!-- Tax group -->
<record id="view_tax_group_tree" model="ir.ui.view">
@@ -1384,7 +1459,7 @@ action = model.setting_init_bank_account_action()
</record>
<menuitem action="action_payment_term_form"
id="menu_action_payment_term_form" parent="account_management_menu" sequence="1"/>
id="menu_action_payment_term_form" parent="account_invoicing_menu" sequence="1"/>
<!-- Account Templates -->
@@ -1397,7 +1472,7 @@ action = model.setting_init_bank_account_action()
<field name="name"/>
<field name="code"/>
<newline/>
<field name="user_type_id" widget="selection"/>
<field name="user_type_id" widget="account_hierarchy_selection"/>
<field name="currency_id" options="{'no_create': True}" groups="base.group_multi_currency"/>
<field name="tag_ids" domain="[('applicability', '!=', 'taxes')]" widget="many2many_tags" context="{'default_applicability': 'accounts'}"/>
<field name="reconcile"/>
@@ -1731,7 +1806,7 @@ action = model.setting_init_bank_account_action()
<tree string="Products">
<field name="default_code"/>
<field name="name"/>
<field name="attribute_value_ids" widget="many2many_tags" groups="product.group_product_variant"/>
<field name="product_template_attribute_value_ids" widget="many2many_tags" groups="product.group_product_variant"/>
<field name="lst_price"/>
<field name="taxes_id" widget="many2many_tags"/>
<field name="supplier_taxes_id" widget="many2many_tags"/>
+3 -3
View File
@@ -152,7 +152,7 @@
<menuitem
action="action_account_fiscal_position_form"
id="menu_action_account_fiscal_position_form"
parent="account_account_menu" sequence="3"/>
parent="account_invoicing_menu" sequence="3"/>
<!--
Partners Extension
@@ -222,7 +222,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="view_mode">kanban,tree,form</field>
<field name="context">{'search_default_customer': 1,'res_partner_search_mode': 'customer', 'default_is_company': True}</field>
<field name="context">{'search_default_customer': 1,'res_partner_search_mode': 'customer', 'default_is_company': True, 'default_customer_rank': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new customer in your address book
@@ -237,7 +237,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="view_mode">kanban,tree,form</field>
<field name="context">{'search_default_supplier': 1,'res_partner_search_mode': 'supplier', 'default_is_company': True}</field>
<field name="context">{'search_default_supplier': 1,'res_partner_search_mode': 'supplier', 'default_is_company': True, 'default_supplier_rank': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new supplier in your address book
+2 -2
View File
@@ -27,9 +27,9 @@
<group name="accounting"/>
</page>
</page>
<field name="list_price" position="after">
<xpath expr="//div[@name='pricing']" position="after">
<field name="taxes_id" widget="many2many_tags" context="{'default_type_tax_use':'sale'}"/>
</field>
</xpath>
<group name="bill" position="inside">
<field name="supplier_taxes_id" widget="many2many_tags" context="{'default_type_tax_use':'purchase'}"/>
</group>
+1 -1
View File
@@ -182,7 +182,7 @@
<p t-if="o.fiscal_position_id.note" name="note">
<span t-field="o.fiscal_position_id.note"/>
</p>
<div id="qrcode" t-if="(o.partner_id.country_id.code in ['BE', 'AT', 'DE', 'FI', 'NL']) and (o.company_id.qr_code) and (o.currency_id.name == 'EUR') and (o.invoice_partner_bank_id.acc_number != False)">
<div id="qrcode" t-if="(o.company_id.qr_code) and (o.currency_id.name == 'EUR') and (o.invoice_partner_bank_id.acc_number != False)">
<p t-if="(o.invoice_partner_bank_id.qr_code_valid)">
<strong class="text-center">Scan me with your banking app.</strong><br /><br />
<img class="border border-dark rounded" t-att-src="o.invoice_partner_bank_id.build_qr_code_url(o.amount_residual,(o.ref) if (o.ref) else o.name)"/>
@@ -175,7 +175,7 @@
<div class="o_setting_right_pane">
<span class="o_form_label">Default Sending Options</span>
<div class="text-muted">
Those options will be checked by default
Those options will be selected by default when clicking "Send &amp; Print" on invoices
</div>
<div class="mt16">
<div class="content-group" id="send_default">
@@ -254,7 +254,7 @@
<div class="o_setting_right_pane">
<label for="group_cash_rounding"/>
<div class="text-muted">
Define the smallest coinage of the currency used to pay by cash.
Define the smallest coinage of the currency used to pay by cash
</div>
<div class="mt8">
<button name="%(account.rounding_list_action)d" icon="fa-arrow-right"
@@ -270,7 +270,7 @@
<div class="o_setting_right_pane" name="intrastat_right_pane">
<label for="module_account_intrastat"/>
<div class="text-muted">
Collect information and produce statistics on the trade in goods in Europe with intrastat.
Collect information and produce statistics on the trade in goods in Europe with intrastat
</div>
</div>
</div>
@@ -289,21 +289,6 @@
</div>
<h2>Customer Payments</h2>
<div class="row mt16 o_settings_container">
<div class="col-12 col-lg-6 o_setting_box" id="account_followup" title="This feature is useful if you issue a high amounts of invoices.">
<div class="o_setting_left_pane">
<field name="module_account_reports_followup" widget="upgrade_boolean"/>
</div>
<div class="o_setting_right_pane" id="account_reports_followup">
<label for="module_account_reports_followup"/>
<div class="text-muted">
Use follow-up levels and schedule actions
</div>
<div id="account_reports_followup" class="content-group" attrs="{'invisible': [('module_account_reports_followup', '=', False)]}">
<!--For completion by module-->
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane">
<field name="module_account_payment"/>
@@ -362,7 +347,7 @@
<div class="o_setting_left_pane">
<field name="module_account_invoice_extract" widget="upgrade_boolean"/>
</div>
<div class="o_setting_right_pane">
<div class="o_setting_right_pane" id="digitalizeocr">
<label for="module_account_invoice_extract"/>
<div class="text-muted">
Digitalize your scanned or PDF vendor bills with OCR and Artificial Intelligence
@@ -406,18 +391,16 @@
<t groups="account.group_account_user">
<h2>Bank &amp; Cash</h2>
<div class="row mt16 o_settings_container" id="bank_cash">
<div class="row mt16 o_settings_container" id="setup">
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="col-xs-12 col-md-6 o_setting_box">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<label for="account_bank_reconciliation_start"/>
<div class="text-muted">
The payments which have not been matched with a bank statement will not be shown in bank reconciliation data if they were made before this date.
The payments which have not been matched with a bank statement will not be shown in bank reconciliation data if they were made before this date
</div>
<field name="account_bank_reconciliation_start"/>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box" id="account_yodlee" title="Get your bank statements automatically imported every 4 hours, or in one-click, using Yodlee and Plaid services. Once installed, set “Bank Feeds” to “Bank Synchronization” in bank account settings. Then, click “Configure” on the online account to enter your bank credentials.">
<div class="o_setting_left_pane">
<field name="module_account_yodlee" widget="upgrade_boolean"/>
@@ -501,15 +484,7 @@
<div class="o_setting_right_pane">
<label for="group_analytic_accounting"/>
<div class="text-muted">
Track costs &amp; revenues by project, department, etc.
</div>
<div class="content-group" attrs="{'invisible': [('group_analytic_accounting', '=', False)]}">
<div class="mt8" id="analytic_account_link">
<button name="%(analytic.action_analytic_account_form)d" icon="fa-arrow-right" type="action" string="Analytic Accounts" class="btn-link"/>
</div>
<div class="mt8" id="analytic_account_groups_link">
<button name="%(analytic.account_analytic_group_action)d" icon="fa-arrow-right" type="action" string="Analytic Account Groups" class="btn-link"/>
</div>
Track costs &amp; revenues by project, department, etc
</div>
</div>
</div>
@@ -522,11 +497,6 @@
<div class="text-muted">
Allows to tag analytic entries and to manage analytic distributions
</div>
<div class="content-group" attrs="{'invisible': [('group_analytic_tags', '=', False)]}">
<div class="mt8">
<button name="%(analytic.account_analytic_tag_action)d" icon="fa-arrow-right" type="action" string="Analytic Tags" class="btn-link"/>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box" id="account_budget" title="This allows accountants to manage analytic and crossovered budgets. Once the master budgets and the budgets are defined, the project managers can set the planned amount on each analytic account." groups="account.group_account_user">
+1
View File
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import account_accrual_accounting
from . import account_unreconcile
from . import account_validate_account_move
from . import pos_box
@@ -0,0 +1,143 @@
# -*- coding: utf-8 -*-
from odoo import api, fields, models, _
from odoo.exceptions import UserError
class AccrualAccountingWizard(models.TransientModel):
_name = 'account.accrual.accounting.wizard'
_description = 'Create accrual entry.'
date = fields.Date(required=True)
company_id = fields.Many2one('res.company', required=True)
account_type = fields.Selection([('income', 'Revenue'), ('expense', 'Expense')])
active_move_line_ids = fields.Many2many('account.move.line')
journal_id = fields.Many2one('account.journal', required=True, related="company_id.accrual_default_journal_id", readonly=False)
expense_accrual_account = fields.Many2one('account.account', related="company_id.expense_accrual_account_id", readonly=False)
revenue_accrual_account = fields.Many2one('account.account', related="company_id.revenue_accrual_account_id", readonly=False)
percentage = fields.Float("Percentage", default=100.0)
total_amount = fields.Monetary(compute="_compute_total_amount", currency_field='company_currency_id')
company_currency_id = fields.Many2one('res.currency', related='company_id.currency_id')
@api.constrains('percentage')
def _constraint_percentage(self):
for record in self:
if not (0.0 < record.percentage <= 100.0):
raise UserError(_("Percentage must be between 0 and 100"))
@api.depends('percentage', 'active_move_line_ids')
def _compute_total_amount(self):
for record in self:
record.total_amount = sum(record.active_move_line_ids.mapped(lambda l: record.percentage * (l.debit + l.credit) / 100))
@api.model
def default_get(self, fields):
if self.env.context.get('active_model') != 'account.move.line' or not self.env.context.get('active_ids'):
raise UserError(_('This can only be used on journal items'))
rec = super(AccrualAccountingWizard, self).default_get(fields)
active_move_line_ids = self.env['account.move.line'].browse(self.env.context['active_ids'])
rec['active_move_line_ids'] = active_move_line_ids.ids
if any(move_line.reconciled for move_line in active_move_line_ids):
raise UserError(_('You can only change the period for items that are not yet reconciled.'))
if any(line.account_id.user_type_id != active_move_line_ids[0].account_id.user_type_id for line in active_move_line_ids):
raise UserError(_('All accounts on the lines must be from the same type.'))
if any(line.company_id != active_move_line_ids[0].company_id for line in active_move_line_ids):
raise UserError(_('All lines must be from the same company.'))
rec['company_id'] = active_move_line_ids[0].company_id.id
account_types_allowed = self.env.ref('account.data_account_type_expenses') + self.env.ref('account.data_account_type_revenue') + self.env.ref('account.data_account_type_other_income')
if active_move_line_ids[0].account_id.user_type_id not in account_types_allowed:
raise UserError(_('You can only change the period for items in these types of accounts: ') + ", ".join(account_types_allowed.mapped('name')))
rec['account_type'] = active_move_line_ids[0].account_id.user_type_id.internal_group
return rec
def amend_entries(self):
# gather the origin account on seleced journal items
origin_accounts = {}
for aml in self.active_move_line_ids:
origin_accounts[aml.id] = aml.account_id.id
# set the accrual account on the selected journal items
self.active_move_line_ids.write({'account_id': (self.revenue_accrual_account if self.account_type == 'income' else self.expense_accrual_account).id})
# create the accrual move(s) and reconcile accrual items together
for aml in self.active_move_line_ids:
reported_debit = aml.company_id.currency_id.round((self.percentage / 100) * aml.debit)
reported_credit = aml.company_id.currency_id.round((self.percentage / 100) * aml.credit)
ref = _('Accrual Adjusting Entry ({percent}% recognized) for invoice: {name}').format(percent=self.percentage, name=aml.move_id.name)
move_data = [{
'date': self.date,
'ref': ref,
'journal_id': self.journal_id.id,
'line_ids': [
(0, 0, {
'name': aml.name,
'debit': reported_debit,
'credit': reported_credit,
'account_id': origin_accounts[aml.id],
'partner_id': aml.partner_id.id,
}),
(0, 0, {
'name': ref,
'debit': reported_credit,
'credit': reported_debit,
'account_id': (self.revenue_accrual_account if self.account_type == 'income' else self.expense_accrual_account).id,
'partner_id': aml.partner_id.id,
}),
],
}]
message_data = [(_('Accrual Adjusting Entry ({percent}% recognized) for invoice:') + ' <a href=# data-oe-model=account.move data-oe-id={id}>{name}</a>').format(
percent=self.percentage,
id=aml.move_id.id,
name=aml.move_id.name,
)]
# in case the percentage to recognize is not 100%, another entry is created to keep the remaining balance in the same account at the original date
if self.percentage < 100:
ref = _('Accrual Adjusting Entry ({percent}% recognized) for invoice: {name}').format(percent=100 - self.percentage, name=aml.move_id.name)
move_data.append({
'date': aml.move_id.date,
'ref': ref,
'journal_id': self.journal_id.id,
'line_ids': [
(0, 0, {
'name': aml.name,
'debit': aml.debit - reported_debit,
'credit': aml.credit - reported_credit,
'account_id': origin_accounts[aml.id],
'partner_id': aml.partner_id.id,
}),
(0, 0, {
'name': ref,
'debit': aml.credit - reported_credit,
'credit': aml.debit - reported_debit,
'account_id': (self.revenue_accrual_account if self.account_type == 'income' else self.expense_accrual_account).id,
'partner_id': aml.partner_id.id,
}),
],
})
message_data.append((_('Accrual Adjusting Entry ({percent}% recognized) for invoice:') + ' <a href=# data-oe-model=account.move data-oe-id={id}>{name}</a>').format(
percent=self.percentage,
id=aml.move_id.id,
name=aml.move_id.name,
))
created_ids = self.env['account.move'].create(move_data)
created_ids.post()
for move, msg in zip(created_ids, message_data):
move.message_post(body=msg)
# reconcile journal items on the accrual account
to_reconcile = created_ids.line_ids.filtered(lambda line: line.account_id in (self.revenue_accrual_account + self.expense_accrual_account)) + aml
to_reconcile.reconcile()
# open the generated entries
action = {
'name': _('Generated Entries'),
'domain': [('id', 'in', created_ids.ids)],
'res_model': 'account.move',
'view_mode': 'tree,form',
'type': 'ir.actions.act_window',
'views': [(self.env.ref('account.view_move_tree').id, 'tree'), (False, 'form')],
}
if len(created_ids) == 1:
action.update({'view_mode': 'form', 'res_id': created_ids.id})
return action
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<record id="account_accrual_accounting_wizard_form_view" model="ir.ui.view">
<field name="name">account.accrual.accounting.wizard.form</field>
<field name="model">account.accrual.accounting.wizard</field>
<field name="arch" type="xml">
<form>
<field name="account_type" invisible="1"/>
<field name="company_id" invisible="1"/>
<group>
<group>
<field name="date" string="Recognize on"/>
<field name="expense_accrual_account" string="Accrued Account" attrs="{'invisible': [('account_type', '!=', 'expense')], 'required': [('account_type', '=', 'expense')]}"/>
<field name="revenue_accrual_account" string="Accrued Account" attrs="{'invisible': [('account_type', '!=', 'income')], 'required': [('account_type', '=', 'income')]}"/>
</group>
<group>
<field name="percentage" string="Percent (%)"/>
<field name="total_amount" string="Amount"/>
<field name="journal_id" domain="[('type', '=', 'general')]"/>
</group>
</group>
<footer>
<button string="Create Journal Entry" name="amend_entries" type="object" class="oe_highlight"/>
<button string="Cancel" class="btn btn-secondary" special="cancel"/>
</footer>
</form>
</field>
</record>
<record id="account_accrual_accounting_wizard_action" model="ir.actions.act_window">
<field name="name">Change Period for the expense/revenue recognition</field>
<field name="res_model">account.accrual.accounting.wizard</field>
<field name="view_mode">form</field>
<field name="target">new</field>
</record>
</data>
</odoo>
@@ -51,6 +51,17 @@ class AccountInvoiceSend(models.TransientModel):
self.composer_id.template_id = self.template_id.id
self.composer_id.onchange_template_id_wrapper()
@api.onchange('is_email')
def onchange_is_email(self):
if self.is_email:
if not self.composer_id:
res_ids = self._context.get('active_ids')
self.composer_id = self.env['mail.compose.message'].create({
'composition_mode': 'comment' if len(res_ids) == 1 else 'mass_mail',
'template_id': self.template_id.id
})
self.composer_id.onchange_template_id_wrapper()
@api.onchange('is_email')
def _compute_invoice_without_email(self):
for wizard in self:
@@ -10,7 +10,6 @@
<form string="Invoice send &amp; Print">
<!-- truly invisible fields for control and options -->
<field name="composition_mode" invisible="1"/>
<field name="composer_id" invisible="1"/>
<field name="invoice_ids" invisible="1"/>
<field name="email_from" invisible="1" />
<field name="mail_server_id" invisible="1"/>
@@ -22,7 +22,6 @@ Allows to automatically select analytic accounts based on criterions:
'security/ir.model.access.csv',
'security/account_analytic_default_security.xml',
'views/account_analytic_default_view.xml',
'views/res_config_settings_views.xml',
],
'installable': True,
}
+72 -51
View File
@@ -1,27 +1,25 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Mustafa Rawi <mustafa@cubexco.com>, 2018
# Akram Alfusayal <akram_ma@hotmail.com>, 2018
# amrnegm <amrnegm.01@gmail.com>, 2018
# Martin Trigaux, 2018
# hamza tayseer atieh <hamza.atieh@minervadata.com>, 2018
# Osoul <baruni@osoul.ly>, 2018
# Ghaith Gammar <g.gammar@saharaifs.net>, 2018
# Osama Ahmaro <osamaahmaro@gmail.com>, 2018
# Shaima Safar <shaima.safar@open-inside.com>, 2018
# sohbi ahmed <gestshb@gmail.com>, 2018
# Ahmed Yousif <ahmed.yousif@outlook.com>, 2018
# Hesham ELMAHDY, 2018
# Mustafa Rawi <mustafa@cubexco.com>, 2019
# Akram Alfusayal <akram_ma@hotmail.com>, 2019
# amrnegm <amrnegm.01@gmail.com>, 2019
# Martin Trigaux, 2019
# Osoul <baruni@osoul.ly>, 2019
# Ghaith Gammar <g.gammar@saharaifs.net>, 2019
# Osama Ahmaro <osamaahmaro@gmail.com>, 2019
# Shaima Safar <shaima.safar@open-inside.com>, 2019
# Ahmed Yousif <ahmed.yousif@outlook.com>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2018-09-18 09:49+0000\n"
"Last-Translator: Hesham ELMAHDY, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Ahmed Yousif <ahmed.yousif@outlook.com>, 2019\n"
"Language-Team: Arabic (https://www.transifex.com/odoo/teams/41243/ar/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -32,30 +30,38 @@ msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<i class=\"fa fa-calendar\"/> From"
msgstr "من"
msgstr "<i class=\"fa fa-calendar\"/> من"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<strong>Customer</strong>"
msgstr "العميل"
msgstr "<strong>العميل</strong>"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<strong>Product</strong>"
msgstr "<strong>المنتج</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "الحساب"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "الحسابات"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
"tag."
msgstr "إن الحساب التحليلي الفرضي يتطلب على الأقل حساب تحليلي أو وسم تحليلي"
msgstr ""
"يتطلب الإعداد التحليلي الافتراضي حسابًا تحليليًا أو وسمًا تحليليًا على "
"الأقل."
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_id
@@ -63,24 +69,29 @@ msgstr "إن الحساب التحليلي الفرضي يتطلب على الأ
msgid "Analytic Account"
msgstr "الحساب التحليلي"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_tree
msgid "Analytic Defaults"
msgstr "افتراضيات التحليل"
msgstr "الافتراضيات التحليلية"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_analytic_default
msgid "Analytic Distribution"
msgstr "تحليل التوزيع"
msgstr "التوزيع التحليلي"
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_product_default_list
#: model:ir.actions.act_window,name:account_analytic_default.analytic_rule_action_user
msgid "Analytic Rules"
msgstr "قواعد التحليل"
msgstr "القواعد التحليلية"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_tag_ids
@@ -91,7 +102,7 @@ msgstr "الوسوم التحليلية"
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__company_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Company"
msgstr "المؤسسة"
msgstr "الشركة"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
@@ -116,28 +127,28 @@ msgstr "القيم التحليلية الافتراضية"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__date_stop
msgid "Default end date for this Analytic Account."
msgstr "تاريخ الإنتهاء الإفتراضي لهذا الحساب التحليلي."
msgstr "تاريخ الإنتهاء الافتراضي لهذا الحساب التحليلي."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__date_start
msgid "Default start date for this Analytic Account."
msgstr "تاريخ البدء الإفتراضي لهذا الحساب التحليلي."
msgstr "تاريخ البدء الافتراضي لهذا الحساب التحليلي."
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__display_name
msgid "Display Name"
msgstr "اسم العرض"
msgstr "الاسم المعروض"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_stop
msgid "End Date"
msgstr "تاريخ الإنتهاء"
msgstr "تاريخ الانتهاء"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__sequence
msgid ""
"Gives the sequence order when displaying a list of analytic distribution"
msgstr "تعطي أمر التتابع عند عرض قائمة تحليل التوزيع"
msgstr "يحدد التتابع التسلسلي عند عرض قائمة التوزيعات التحليلية"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
@@ -147,12 +158,12 @@ msgstr "تجميع حسب"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__id
msgid "ID"
msgstr "المعرف"
msgstr "المُعرف"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "بند الفاتورة"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "عنصر اليومية"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
@@ -181,11 +192,6 @@ msgstr "الشريك"
msgid "Product"
msgstr "المنتج"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "سطر أمر المبيعات"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -193,9 +199,9 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"company, it will automatically take this as an analytic account)"
msgstr ""
"إختر الشركة التي ستستعمل الحساب التحليلي المحدد كإفتراضي في التحليل (مثلا "
"عند إنشاء فاتورة أو أمر مبيعات و تختار هذه الشركة ستأخذ هذا الحساب التحليلي "
"آليا.)"
"اختر المؤسسة التي ستستخدم الحساب التحليلي المحدد في الإعداد التحليلي "
"الافتراضي (مثلًا عند إنشاء فاتورة أو أمر مبيعات، وإذا تم اختيار هذه المؤسسة؛"
" سيتم استخدام هذا الحساب التحليلي تلقائياً)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__partner_id
@@ -204,9 +210,9 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"partner, it will automatically take this as an analytic account)"
msgstr ""
"إختر الشريك الذي سيستعمل الحساب التحليلي المحدد كإفتراضي في التحليل (مثلا "
"عند إنشاء فاتورة أو أمر مبيعات و تختار هذا الشريك سيأخذ هذا الحساب التحليلي "
"آليا.)"
"اختر الشريك الذي سيستخدم الحساب التحليلي المحدد في الإعداد التحليلي "
"الافتراضي (مثلًا عند إنشاء فاتورة أو أمر مبيعات، وإذا تم اختيار هذا الشريك؛ "
"فسيتم اختيار هذا الحساب التحليلي تلقائياً)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__product_id
@@ -215,25 +221,40 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"product, it will automatically take this as an analytic account)"
msgstr ""
"إختر المنتج الذي سيستعمل الحساب التحليلي المحدد كإفتراضي في التحليل (مثلا "
"عند إنشاء فاتورة أو أمر مبيعات و تختار هذا المنتج سيأخذ هذا الحساب التحليلي "
"آليا.)"
"اختر المنتج الذي سيستخدم الحساب التحليلي المحدد في الإعداد التحليلية "
"الافتراضي (مثلًا عند إنشاء فاتورة أو أمر مبيعات، وإذا تم اختيار هذا المنتج؛ "
"فسيتم اختيار هذا الحساب التحليلي تلقائياً)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__user_id
msgid ""
"Select a user which will use analytic account specified in analytic default."
msgstr "إختر المستخدم الذي سيستخدم الحساب التحليلي المحدد كإفتراضي."
msgstr ""
"اختر المستخدم الذي سيستخدم الحساب التحليلي المحدد في الإعداد التحليلي "
"الافتراضي."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
msgstr "التسلسل"
msgstr "المسلسل"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_start
msgid "Start Date"
msgstr "تاريخ البدء"
msgstr "تاريخ البداية"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "الوسوم"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
+62 -66
View File
@@ -1,19 +1,13 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Martin Trigaux, 2018
# Jan Horzinka <jan.horzinka@centrum.cz>, 2018
# Michal Veselý <michal@veselyberanek.net>, 2018
# trendspotter, 2018
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.2\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-03-22 14:10+0000\n"
"PO-Revision-Date: 2018-03-22 14:10+0000\n"
"Last-Translator: trendspotter, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Language-Team: Czech (https://www.transifex.com/odoo/teams/41243/cs/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -24,38 +18,47 @@ msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<i class=\"fa fa-calendar\"/> From"
msgstr "<i class=\"fa fa-calendar\"/>Od"
msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<strong>Customer</strong>"
msgstr "<strong>Zákazník</strong>"
msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<strong>Product</strong>"
msgstr "<strong>Produkt</strong>"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Účty"
msgstr ""
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
"tag."
msgstr ""
"Analytická výchozí hodnota vyžaduje alespoň analytický účet nebo analytickou"
" značku."
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Analytic Account"
msgstr "Analytický účet"
msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
@@ -63,123 +66,117 @@ msgstr "Analytický účet"
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_tree
msgid "Analytic Defaults"
msgstr "Analytické výchozí hodnoty"
msgstr ""
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_analytic_default
msgid "Analytic Distribution"
msgstr "Analytická distribuce"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_product_default_list
#: model:ir.actions.act_window,name:account_analytic_default.analytic_rule_action_partner
#: model:ir.actions.act_window,name:account_analytic_default.analytic_rule_action_user
msgid "Analytic Rules"
msgstr "Analytická pravidla"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_tag_ids
msgid "Analytic Tags"
msgstr "Analytické značky"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__company_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Company"
msgstr "Firma"
msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Conditions"
msgstr "Podmínky"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__create_uid
msgid "Created by"
msgstr "Vytvořil(a)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__create_date
msgid "Created on"
msgstr "Vytvořeno"
msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.res_config_settings_view_form
msgid "Default Analytic Values"
msgstr "Výchozí analytické hodnoty"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__date_stop
msgid "Default end date for this Analytic Account."
msgstr "Výchozí datum ukončení pro tento analytický účet."
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__date_start
msgid "Default start date for this Analytic Account."
msgstr "Výchozí datum zahájení tohoto analytického účtu."
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__display_name
msgid "Display Name"
msgstr "Zobrazovaný název"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_stop
msgid "End Date"
msgstr "Datum ukončení"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__sequence
msgid ""
"Gives the sequence order when displaying a list of analytic distribution"
msgstr "Udává pořadí sekvencí při zobrazování seznamu analytické distribuce"
msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Group By"
msgstr "Seskupit podle"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__id
msgid "ID"
msgstr "ID"
msgstr ""
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Řádek faktury"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
msgid "Last Modified on"
msgstr "Naposled změněno"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_uid
msgid "Last Updated by"
msgstr "Naposledy upraveno od"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_date
msgid "Last Updated on"
msgstr "Naposled upraveno"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__partner_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Partner"
msgstr "Kontakt"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__product_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Product"
msgstr "Výrobek"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Řádek potvrzení objednávky"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
@@ -188,10 +185,6 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"company, it will automatically take this as an analytic account)"
msgstr ""
"Vyberte společnost, která použije analytický účet specifikovaný ve výchozím "
"nastavení pro analýzu (např. Vytvoření nové zákaznické faktury nebo "
"objednávky prodeje, pokud tuto společnost vybereme, automaticky ji použije "
"jako analytický účet)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__partner_id
@@ -200,10 +193,6 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"partner, it will automatically take this as an analytic account)"
msgstr ""
"Vybrat partnera, který použije analytický účet uvedený ve výchozím nastavení"
" pro analýzu (např. Vytvoření nové zákaznické faktury nebo objednávky "
"odběru. Pokud tohoto partnera vybereme, automaticky jej použije jako "
"analytický účet)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__product_id
@@ -212,36 +201,43 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"product, it will automatically take this as an analytic account)"
msgstr ""
"Vybrat produkt, který použije analytický účet specifikovaný ve výchozím "
"nastavení pro analýzu (např. Vytvoření nové zákaznické faktury nebo "
"objednávky prodeje, pokud tento produkt vybereme, automaticky jej použijeme "
"jako analytický účet)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__user_id
msgid ""
"Select a user which will use analytic account specified in analytic default."
msgstr ""
"Vybrat uživatele, který použije analytický účet specifikovaný v analytických"
" výchozích nastaveních."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
msgstr "Číselná řada"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_start
msgid "Start Date"
msgstr "Datum zahájení"
msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "User"
msgstr "Uživatel"
msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "to"
msgstr "k"
msgstr ""
+45 -20
View File
@@ -1,16 +1,20 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Martin Trigaux, 2018
# Martin Trigaux, 2019
# Felix Schubert <felix.schubert@go-erp.com>, 2019
# Leon Grill <leg@odoo.com>, 2019
# Chris Egal <sodaswed@web.de>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2018-09-18 09:49+0000\n"
"Last-Translator: Martin Trigaux, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Chris Egal <sodaswed@web.de>, 2019\n"
"Language-Team: German (https://www.transifex.com/odoo/teams/41243/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -26,31 +30,44 @@ msgstr "<i class=\"fa fa-calendar\"/>"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<strong>Customer</strong>"
msgstr "<strong/>"
msgstr "<strong>Kunde</strong>"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<strong>Product</strong>"
msgstr "<strong>Produkt</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Konto"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Konten"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
"tag."
msgstr ""
"Eine Analytisch Vorgabe benötigt mindestens ein Analytisches Benutzerkonto "
"oder einen Analytisches Schlagwort"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Analytic Account"
msgstr "Analysekonto"
msgstr "Kostenstelle"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
@@ -139,19 +156,19 @@ msgid "ID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Rechungsposition"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Buchungszeile"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
msgid "Last Modified on"
msgstr "Zuletzt geändert am"
msgstr "Letzte Änderung am"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_uid
msgid "Last Updated by"
msgstr "Zuletzt aktualisiert durch"
msgstr "Zuletzt aktualisiert von"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_date
@@ -170,11 +187,6 @@ msgstr "Partner"
msgid "Product"
msgstr "Produkt"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Auftragsposition"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -217,16 +229,29 @@ msgid ""
"Select a user which will use analytic account specified in analytic default."
msgstr "Wählen Sie einen Benutzer mit der hinterlegten Standardkostenstelle"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
msgstr "Reihenfolge"
msgstr "Sequenz"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_start
msgid "Start Date"
msgstr "Startdatum"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Stichwörter"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
+40 -32
View File
@@ -1,30 +1,19 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Leonardo Chianea <noamixcontenidos@gmail.com>, 2016
# Ivan Nieto <ivan.n.s@tuta.io>, 2016
# Luis M. Ontalba <luis.martinez@tecnativa.com>, 2016
# Mateo Tibaquirá Palacios <nestormateo@gmail.com>, 2016
# José Vicente <txusev@gmail.com>, 2016
# Carles Antoli <carlesantoli@hotmail.com>, 2016
# Antonio Trueba, 2016
# Ana Juaristi <ajuaristio@gmail.com>, 2016
# oihane <oihanecruce@gmail.com>, 2016
# Martin Trigaux, 2016
# Luis M. Triana <luis.triana@jarsa.com.mx>, 2016
# Pedro M. Baeza <pedro.baeza@gmail.com>, 2017
# Nicolás Broggi <rnbroggi@gmail.com>, 2018
# JOSE ALEJANDRO ECHEVERRI VALENCIA <josealejandroeche@gmail.com>, 2018
# Martin Trigaux, 2019
# Pedro M. Baeza <pedro.baeza@gmail.com>, 2019
# JOSE ALEJANDRO ECHEVERRI VALENCIA <josealejandroeche@gmail.com>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2016-08-05 12:55+0000\n"
"Last-Translator: JOSE ALEJANDRO ECHEVERRI VALENCIA <josealejandroeche@gmail.com>, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: JOSE ALEJANDRO ECHEVERRI VALENCIA <josealejandroeche@gmail.com>, 2019\n"
"Language-Team: Spanish (https://www.transifex.com/odoo/teams/41243/es/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -47,20 +36,26 @@ msgstr "<strong>Cliente</strong>"
msgid "<strong>Product</strong>"
msgstr "<strong>Producto</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Cuenta"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Cuentas"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
"tag."
msgstr ""
"Un valor predeterminado analítico requiere al menos una cuenta analítica o "
"una etiqueta analítica."
"una etiqueta analítica. "
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_id
@@ -68,6 +63,11 @@ msgstr ""
msgid "Analytic Account"
msgstr "Cuenta analítica"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
@@ -79,7 +79,7 @@ msgstr "Análisis: Valores por defecto"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_analytic_default
msgid "Analytic Distribution"
msgstr "Distribución Analítica"
msgstr "Distribución analítica"
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_product_default_list
@@ -131,12 +131,12 @@ msgstr "Fecha de inicio por defecto para esta cuenta analítica"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__display_name
msgid "Display Name"
msgstr "Nombre a mostrar"
msgstr "Nombre mostrado"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_stop
msgid "End Date"
msgstr "Fecha finalización"
msgstr "Fecha final"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__sequence
@@ -157,9 +157,9 @@ msgid "ID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Linea de Factura"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Apunte contable"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
@@ -188,11 +188,6 @@ msgstr "Empresa"
msgid "Product"
msgstr "Producto"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Línea de pedido de venta"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -237,6 +232,14 @@ msgstr ""
"Seleccione un usuario que usará la cuenta analítica especificada en la "
"analítica por defecto."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
@@ -247,6 +250,11 @@ msgstr "Secuencia"
msgid "Start Date"
msgstr "Fecha de inicio"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Categorías"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
+39 -18
View File
@@ -1,17 +1,19 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Martin Trigaux, 2018
# Christophe CHAUVET <christophe.chauvet@gmail.com>, 2018
# Cécile Collart <cco@odoo.com>, 2019
# Christophe CHAUVET <christophe.chauvet@gmail.com>, 2019
# Martin Trigaux, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2018-09-18 09:49+0000\n"
"Last-Translator: Christophe CHAUVET <christophe.chauvet@gmail.com>, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Martin Trigaux, 2019\n"
"Language-Team: French (https://www.transifex.com/odoo/teams/41243/fr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -34,13 +36,19 @@ msgstr "<strong>Client</strong>"
msgid "<strong>Product</strong>"
msgstr "<strong>Article</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Compte"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Comptes"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
@@ -55,6 +63,11 @@ msgstr ""
msgid "Analytic Account"
msgstr "Compte analytique"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
@@ -118,7 +131,7 @@ msgstr "Date de début par défaut pour ce compte analytique"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__display_name
msgid "Display Name"
msgstr "Nom affiché"
msgstr "Afficher Nom"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_stop
@@ -144,14 +157,14 @@ msgid "ID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Ligne de facture"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Écriture comptable"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
msgid "Last Modified on"
msgstr "Dernière Modification le"
msgstr "Dernière modification le"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_uid
@@ -175,11 +188,6 @@ msgstr "Partenaire"
msgid "Product"
msgstr "Article"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Ligne de bons de commande"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -221,6 +229,14 @@ msgid ""
msgstr ""
"Choisissez un utilisateur qui utilisera le compte analytique par défaut"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
@@ -231,6 +247,11 @@ msgstr "Séquence"
msgid "Start Date"
msgstr "Date de début"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Étiquettes"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
+41 -23
View File
@@ -1,23 +1,22 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Jasmina Otročak <jasmina@uvid.hr>, 2017
# Karolina Tonković <karolina.tonkovic@storm.hr>, 2017
# Đurđica Žarković <durdica.zarkovic@storm.hr>, 2017
# Vladimir Olujić <olujic.vladimir@storm.hr>, 2017
# Martin Trigaux, 2017
# Tina Milas, 2017
# Martin Trigaux, 2019
# Bole <bole@dajmi5.com>, 2019
# Vladimir Olujić <olujic.vladimir@storm.hr>, 2019
# Đurđica Žarković <durdica.zarkovic@storm.hr>, 2019
# Jasmina Otročak <jasmina@uvid.hr>, 2019
# Tina Milas, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2016-08-05 12:55+0000\n"
"Last-Translator: Bole <bole@dajmi5.com>, 2019\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Tina Milas, 2019\n"
"Language-Team: Croatian (https://www.transifex.com/odoo/teams/41243/hr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -40,13 +39,19 @@ msgstr "<strong>Kupac</strong>"
msgid "<strong>Product</strong>"
msgstr "<strong>Proizvod</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Konto"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Konta"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
@@ -57,7 +62,12 @@ msgstr ""
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Analytic Account"
msgstr "Analitički konto"
msgstr "Konto analitike"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
@@ -102,7 +112,7 @@ msgstr "Kreirao"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__create_date
msgid "Created on"
msgstr "Datum kreiranja"
msgstr "Kreirano"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.res_config_settings_view_form
@@ -122,7 +132,7 @@ msgstr "zadani datum početka za ovaj analitički konto"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__display_name
msgid "Display Name"
msgstr "Naziv za prikaz"
msgstr "Naziv"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_stop
@@ -146,9 +156,9 @@ msgid "ID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Stavka računa"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Stavka dnevnika"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
@@ -177,11 +187,6 @@ msgstr "Partner"
msgid "Product"
msgstr "Proizvod"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Stavka prodajnog naloga"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -221,6 +226,14 @@ msgid ""
"Select a user which will use analytic account specified in analytic default."
msgstr "Odaberite korisnika koji će koristiti predodređeni analitički konto. "
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
@@ -231,6 +244,11 @@ msgstr "Sekvenca"
msgid "Start Date"
msgstr "Početni datum"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Oznake"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
+50 -28
View File
@@ -1,19 +1,20 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Martin Trigaux, 2017
# krnkris, 2018
# gezza <geza.nagy@oregional.hu>, 2018
# Martin Trigaux, 2019
# krnkris, 2019
# gezza <geza.nagy@oregional.hu>, 2019
# Ákos Nagy <akos.nagy@oregional.hu>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2016-08-05 12:55+0000\n"
"Last-Translator: gezza <geza.nagy@oregional.hu>, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Ákos Nagy <akos.nagy@oregional.hu>, 2019\n"
"Language-Team: Hungarian (https://www.transifex.com/odoo/teams/41243/hu/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -37,23 +38,36 @@ msgid "<strong>Product</strong>"
msgstr "<strong>Termék</strong>"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Számlák"
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Főkönyvi számla"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Főkönyvi számlák"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
"tag."
msgstr ""
"Alapértelmezett gyűjtőkódhoz szükség van legalább egy analitikus számlára "
"vagy analitikus címkére. "
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Analytic Account"
msgstr "Analitikus/elemző könyvelés"
msgstr "Analitikus számla"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
@@ -93,12 +107,12 @@ msgstr "Feltételek"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__create_uid
msgid "Created by"
msgstr "Készítette"
msgstr "Létrehozta"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__create_date
msgid "Created on"
msgstr "Létrehozás dátuma"
msgstr "Létrehozva"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.res_config_settings_view_form
@@ -139,27 +153,27 @@ msgstr "Csoportosítás"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__id
msgid "ID"
msgstr "Azonosító ID"
msgstr "Azonosító"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Számla tételsor"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Könyvelési napló tételsor"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
msgid "Last Modified on"
msgstr "Utoljára frissítve ekkor"
msgstr "Legutóbb frissítve"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_uid
msgid "Last Updated by"
msgstr "Utoljára frissítette"
msgstr "Frissítette"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_date
msgid "Last Updated on"
msgstr "Utoljára frissítve "
msgstr "Frissítve "
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__partner_id
@@ -173,11 +187,6 @@ msgstr "Partner"
msgid "Product"
msgstr "Termék"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Vásárlói megrendelés tételsor"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -222,6 +231,14 @@ msgstr ""
"Válasszon felhasználót aki az alapértelmezett gyüjttőkódban meghatározott "
"gyűjtőkódot fogja használni"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
@@ -232,6 +249,11 @@ msgstr "Sorszám"
msgid "Start Date"
msgstr "Kezdő dátum"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Címkék"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
@@ -241,4 +263,4 @@ msgstr "Felhasználó"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "to"
msgstr "ig"
msgstr "eddig"
+47 -25
View File
@@ -1,21 +1,24 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Sergio Zanchetta <primes2h@gmail.com>, 2018
# Martin Trigaux, 2018
# Luigi Di Naro <gigidn@gmail.com>, 2018
# Paolo Valier, 2018
# Marco Calcagni <mcalcagni@dinamicheaziendali.it>, 2018
# David Minneci <david@numeko.it>, 2018
# Martin Trigaux, 2019
# Lorenzo Battistini <lorenzo.battistini@agilebg.com>, 2019
# Luigi Di Naro <gigidn@gmail.com>, 2019
# Paolo Valier, 2019
# Marco Calcagni <mcalcagni@dinamicheaziendali.it>, 2019
# David Minneci <david@numeko.it>, 2019
# mymage <stefano.consolaro@mymage.it>, 2019
# Sergio Zanchetta <primes2h@gmail.com>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2018-09-18 09:49+0000\n"
"Last-Translator: David Minneci <david@numeko.it>, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Sergio Zanchetta <primes2h@gmail.com>, 2019\n"
"Language-Team: Italian (https://www.transifex.com/odoo/teams/41243/it/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -38,13 +41,19 @@ msgstr "<strong>Cliente</strong>"
msgid "<strong>Product</strong>"
msgstr "<strong>Prodotto</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Conto"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Conti"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
@@ -57,6 +66,11 @@ msgstr ""
msgid "Analytic Account"
msgstr "Conto analitico"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
@@ -79,7 +93,7 @@ msgstr "Regole Analitiche"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_tag_ids
msgid "Analytic Tags"
msgstr "Tag Analitici"
msgstr "Etichette analitiche"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__company_id
@@ -146,24 +160,24 @@ msgid "ID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Riga fattura"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Movimento contabile"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
msgid "Last Modified on"
msgstr "Data di ultima modifica"
msgstr "Ultima modifica il"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_uid
msgid "Last Updated by"
msgstr "Ultima modifica di"
msgstr "Ultimo aggiornamento di"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_date
msgid "Last Updated on"
msgstr "Ultima modifica il"
msgstr "Ultimo aggiornamento il"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__partner_id
@@ -177,11 +191,6 @@ msgstr "Partner"
msgid "Product"
msgstr "Prodotto"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Riga Ordine di Vendita"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -226,6 +235,14 @@ msgstr ""
"Seleziona un partner che utilizzerà il conto analitico specificato nelle "
"impostazioni analitiche predefinite."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
@@ -236,6 +253,11 @@ msgstr "Sequenza"
msgid "Start Date"
msgstr "Data inizio"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Etichette"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
@@ -245,4 +267,4 @@ msgstr "Utente"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "to"
msgstr "a"
msgstr "al"
+86 -49
View File
@@ -1,33 +1,36 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Martin Trigaux <mat@odoo.com>, 2017
# Audrius Palenskis <audrius.palenskis@gmail.com>, 2017
# UAB "Draugiški sprendimai" <transifex@draugiskisprendimai.lt>, 2017
# Anatolij <an@cq.lt>, 2017
# Antanas Muliuolis <an.muliuolis@gmail.com>, 2017
# digitouch UAB <digitouchagencyeur@gmail.com>, 2017
# Monika Raciunaite <monika.raciunaite@gmail.com>, 2017
# Martin Trigaux, 2019
# UAB "Draugiški sprendimai" <transifex@draugiskisprendimai.lt>, 2019
# Anatolij, 2019
# Silvija Butko <silvija.butko@gmail.com>, 2019
# Audrius Palenskis <audrius.palenskis@gmail.com>, 2019
# Antanas Muliuolis <an.muliuolis@gmail.com>, 2019
# Monika Raciunaite <monika.raciunaite@gmail.com>, 2019
# digitouch UAB <digitouchagencyeur@gmail.com>, 2019
# Linas Versada <linaskrisiukenas@gmail.com>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 10.saas~18\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-09-20 09:53+0000\n"
"PO-Revision-Date: 2017-09-20 09:53+0000\n"
"Last-Translator: Monika Raciunaite <monika.raciunaite@gmail.com>, 2017\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Linas Versada <linaskrisiukenas@gmail.com>, 2019\n"
"Language-Team: Lithuanian (https://www.transifex.com/odoo/teams/41243/lt/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Language: lt\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
"Plural-Forms: nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);\n"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<i class=\"fa fa-calendar\"/> From"
msgstr ""
msgstr "<i class=\"fa fa-calendar\"/> Nuo"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
@@ -39,17 +42,38 @@ msgstr "<strong>Klientas</strong>"
msgid "<strong>Product</strong>"
msgstr "<strong>Produktas</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Sąskaita"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Sąskaitos"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_analytic_id
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
"tag."
msgstr ""
"Numatytajai analitikai reikia bent vienos analitinės sąskaitos ar analitinės"
" žymos."
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Analytic Account"
msgstr "Analitinė sąskaita"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
@@ -65,13 +89,17 @@ msgstr "Analitinis paskirstymas"
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_product_default_list
#: model:ir.actions.act_window,name:account_analytic_default.analytic_rule_action_partner
#: model:ir.actions.act_window,name:account_analytic_default.analytic_rule_action_user
msgid "Analytic Rules"
msgstr "Analitinės taisyklės"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_company_id
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_tag_ids
msgid "Analytic Tags"
msgstr "Analitinės žymos"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__company_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Company"
msgstr "Įmonė"
@@ -82,45 +110,46 @@ msgid "Conditions"
msgstr "Sąlygos"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_create_uid
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__create_uid
msgid "Created by"
msgstr "Sukūrė"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_create_date
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__create_date
msgid "Created on"
msgstr "Sukurta"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.res_config_settings_view_form
msgid "Default Analytic Values"
msgstr ""
msgstr "Numatytosios analitinės reikšmės"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default_date_stop
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__date_stop
msgid "Default end date for this Analytic Account."
msgstr "Numatytoji pabaigos data šiai analitinei sąskaitai."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default_date_start
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__date_start
msgid "Default start date for this Analytic Account."
msgstr "Numatytoji pradžios data šiai analitinei sąskaitai."
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_display_name
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__display_name
msgid "Display Name"
msgstr "Vaizduojamas pavadinimas"
msgstr "Rodomas pavadinimas"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_date_stop
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_stop
msgid "End Date"
msgstr "Pabaigos data"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default_sequence
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__sequence
msgid ""
"Gives the sequence order when displaying a list of analytic distribution"
msgstr "Eilės tvarka, pagal kurią išdėstomas analitinio paskirstymo sąrašas."
msgstr ""
"Suteikia eilės tvarka, pagal kurią išdėstomas analitinio paskirstymo sąrašas"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
@@ -128,49 +157,44 @@ msgid "Group By"
msgstr "Grupuoti pagal"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_id
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__id
msgid "ID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Sąskaitos faktūros eilutė"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Žurnalo įrašas"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default___last_update
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
msgid "Last Modified on"
msgstr "Paskutinį kartą keista"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_write_uid
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_uid
msgid "Last Updated by"
msgstr "Paskutinį kartą atnaujino"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_write_date
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_date
msgid "Last Updated on"
msgstr "Paskutinį kartą atnaujinta"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_partner_id
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__partner_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Partner"
msgstr "Partneris"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_product_id
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__product_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Product"
msgstr "Produktas"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Pardavimo užsakymo eilutė"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default_company_id
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
"Select a company which will use analytic account specified in analytic "
"default (e.g. create new customer invoice or Sales order if we select this "
@@ -181,7 +205,7 @@ msgstr ""
"pasirenkama numatytoji analitinė sąskaita)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default_partner_id
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__partner_id
msgid ""
"Select a partner which will use analytic account specified in analytic "
"default (e.g. create new customer invoice or Sales order if we select this "
@@ -192,7 +216,7 @@ msgstr ""
"automatiškai pasirenkama numatytoji analitinė sąskaita)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default_product_id
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__product_id
msgid ""
"Select a product which will use analytic account specified in analytic "
"default (e.g. create new customer invoice or Sales order if we select this "
@@ -203,23 +227,36 @@ msgstr ""
"automatiškai pasirenkama numatytoji analitinė sąskaita)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default_user_id
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__user_id
msgid ""
"Select a user which will use analytic account specified in analytic default."
msgstr "Pasirinkite naudotoją, kuris naudos numatytąją analitinę sąskaitą."
msgstr "Pasirinkite vartotoją, kuris naudos numatytąją analitinę sąskaitą."
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_sequence
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
msgstr "Seka"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_date_start
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_start
msgid "Start Date"
msgstr "Pradžios data"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default_user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Žymos"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "User"
msgstr "Vartotojas"
+68 -47
View File
@@ -1,21 +1,19 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Martin Trigaux, 2018
# nasaaskii <nasaaskii@gmail.com>, 2018
# Khishigbat Ganbold <khishigbat@asterisk-tech.mn>, 2018
# Onii Onii <onii0223@yahoo.com>, 2018
# Baskhuu Lodoikhuu <baskhuujacara@gmail.com>, 2019
# Martin Trigaux, 2019
# nurbakhit nurka <nurbakhit@bumanit.mn>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2016-08-05 12:55+0000\n"
"Last-Translator: Baskhuu Lodoikhuu <baskhuujacara@gmail.com>, 2019\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: nurbakhit nurka <nurbakhit@bumanit.mn>, 2019\n"
"Language-Team: Mongolian (https://www.transifex.com/odoo/teams/41243/mn/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -26,7 +24,7 @@ msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<i class=\"fa fa-calendar\"/> From"
msgstr ""
msgstr "<i class=\"fa fa-calendar\"/> Эхлэх"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
@@ -36,7 +34,13 @@ msgstr "<strong>Захиалагч</strong>"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<strong>Product</strong>"
msgstr "Бараа"
msgstr "<strong>Бараа</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Данс"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
@@ -44,7 +48,7 @@ msgid "Accounts"
msgstr "Данс"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
@@ -59,6 +63,11 @@ msgstr ""
msgid "Analytic Account"
msgstr "Шинжилгээний данс"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
@@ -70,7 +79,7 @@ msgstr "Шинжилгээний анхны утгууд"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_analytic_default
msgid "Analytic Distribution"
msgstr "Шинжилгээний тархалт"
msgstr "Шинжилгээний хуваарилалт"
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_product_default_list
@@ -81,7 +90,7 @@ msgstr "Шинжилгээний дүрмүүд"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_tag_ids
msgid "Analytic Tags"
msgstr "Шинжилгээний Пайзууд"
msgstr "Шинжилгээний пайз"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__company_id
@@ -97,12 +106,12 @@ msgstr "Нөхцөлүүд"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__create_uid
msgid "Created by"
msgstr "Үүсгэгч"
msgstr "Үүсгэсэн этгээд"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__create_date
msgid "Created on"
msgstr "Үүсгэсэн"
msgstr "Үүсгэсэн огноо"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.res_config_settings_view_form
@@ -112,33 +121,34 @@ msgstr "Шинжилгээний анхны утгууд"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__date_stop
msgid "Default end date for this Analytic Account."
msgstr "Энэ Шинжилгээний дансны дуусах огнооны анхны утга."
msgstr "Энэ шинжилгээний дансны дуусах огнооны анхны утга."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__date_start
msgid "Default start date for this Analytic Account."
msgstr "Энэ Шинжилгээний дансны эхлэх огнооны анхны утга"
msgstr "Энэ шинжилгээний дансны эхлэх огнооны анхны утга"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__display_name
msgid "Display Name"
msgstr "Дэлгэцийн Нэр"
msgstr "Дэлгэрэнгүй нэр"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_stop
msgid "End Date"
msgstr "Дуусах Огноо"
msgstr "Дуусах огноо"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__sequence
msgid ""
"Gives the sequence order when displaying a list of analytic distribution"
msgstr "Шинжилгээний тархалтыг харуулахад хэрэглэгдэх дарааллын эрэмбийг өгнө"
msgstr ""
"Шинжилгээний хуваарилалтыг харуулахад хэрэглэгдэх дарааллын эрэмбийг өгнө"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Group By"
msgstr "Бүлэглэх"
msgstr "Бүлэглэлт"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__id
@@ -146,24 +156,24 @@ msgid "ID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Нэхэмжлэлийн мөр"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Журналын бичилт"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
msgid "Last Modified on"
msgstr "Сүүлийн засвар хийсэн огноо"
msgstr "Сүүлд зассан огноо"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_uid
msgid "Last Updated by"
msgstr "Сүүлийн засвар хийсэн"
msgstr "Сүүлд зассан этгээд"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_date
msgid "Last Updated on"
msgstr "Сүүлийн засвар хийсэн огноо"
msgstr "Сүүлд зассан огноо"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__partner_id
@@ -177,11 +187,6 @@ msgstr "Харилцагч"
msgid "Product"
msgstr "Бараа"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Борлуулалтын Захиалгын Мөр"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -189,9 +194,10 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"company, it will automatically take this as an analytic account)"
msgstr ""
"Шинжилгээний анхны утгад өгөгдсөн шинжилгээний дансыг хэрэглэх компанийг "
"сонго (ө.х. шинэ захиалагчийн нэхэмжлэл үүсгээд эсвэл борлуулалтын захиалга "
"үүсгээд энэ компанийг сонговол автоматаар энэ шинжилгээний дансыг авна)"
"Шинжилгээний анхны утгаар хэрэглэгдэх шинжилгээний данс нь аль компаных "
"байхыг сонгоно уу. (ө.х. энэ компани дээр шинээр захиалагчийн нэхэмжлэл "
"эсвэл борлуулалтын захиалга үүсгэхэд автоматаар энэ шинжилгээний данс "
"сонгогдоно)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__partner_id
@@ -200,9 +206,10 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"partner, it will automatically take this as an analytic account)"
msgstr ""
"Шинжилгээний анхны утгад өгөгдсөн шинжилгээний дансыг хэрэглэх харилцагч "
"сонго (ө.х. шинэ захиалагчийн нэхэмжлэл үүсгээд эсвэл борлуулалтын захиалга "
"үүсгээд энэ харилцагчийг сонговол автоматаар энэн шинжилгээний дансыг авна)"
"Шинжилгээний анхны утгаар хэрэглэгдэх шинжилгээний данс нь аль харилцагчынх "
"байхыг сонгоно уу. (ө.х. энэ харилцагчыг сонгож шинээр захиалагчийн "
"нэхэмжлэл эсвэл борлуулалтын захиалга үүсгэхэд автоматаар энэ шинжилгээний "
"данс сонгогдоно)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__product_id
@@ -211,27 +218,41 @@ msgid ""
"default (e.g. create new customer invoice or Sales order if we select this "
"product, it will automatically take this as an analytic account)"
msgstr ""
"Шинжилгээний анхны утгад өгөгдсөн шинжилгээний дансыг хэрэглэх барааг сонго "
"(ө.х. шинэ захиалагчийн нэхэмжлэл үүсгээд эсвэл борлуулалтын захиалга "
"үүсгээд хэрэв энэ барааг сонговол автоматаар энэ шинжилгээний дансыг авна)"
"Шинжилгээний анхны утгаар хэрэглэгдэх шинжилгээний данс нь аль бараатай "
"холбоотой байхыг сонгоно уу. (ө.х. энэ барааг сонгож шинээр захиалагчийн "
"нэхэмжлэл эсвэл борлуулалтын захиалга үүсгэхэд автоматаар энэ шинжилгээний "
"данс сонгогдоно)"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__user_id
msgid ""
"Select a user which will use analytic account specified in analytic default."
msgstr ""
"Шинжилгээний анхны утгад өгөгдсөн шинжилгээний дансыг хэрэглэх хэрэглэгчийг "
"сонго."
"Ямар хэрэглэгч энэ шинжилгээний дансыг анхны утга болгож ашиглахыг зааж өгнө"
" үү."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
msgstr "Дараалал"
msgstr "Дугаарлалт"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_start
msgid "Start Date"
msgstr "Эхлэх Огноо"
msgstr "Эхлэх огноо"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Пайз"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
@@ -242,4 +263,4 @@ msgstr "Хэрэглэгч"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "to"
msgstr "-"
msgstr "очих"
+38 -20
View File
@@ -1,18 +1,18 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Martin Trigaux, 2018
# Viktor Basso <viktor@voit.no>, 2018
# Jorunn D. Newth, 2018
# Martin Trigaux, 2019
# Marius Stedjan <marius@stedjan.com>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.2\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-03-22 14:10+0000\n"
"PO-Revision-Date: 2018-03-22 14:10+0000\n"
"Last-Translator: Jorunn D. Newth, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Marius Stedjan <marius@stedjan.com>, 2019\n"
"Language-Team: Norwegian Bokmål (https://www.transifex.com/odoo/teams/41243/nb/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -35,13 +35,19 @@ msgstr "<strong>Kunde</strong>"
msgid "<strong>Product</strong>"
msgstr "<strong>Produkt</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Konto"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Konti"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
@@ -54,6 +60,11 @@ msgstr ""
msgid "Analytic Account"
msgstr "Analytisk konto"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
@@ -69,7 +80,6 @@ msgstr "Analytisk distribusjon"
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_product_default_list
#: model:ir.actions.act_window,name:account_analytic_default.analytic_rule_action_partner
#: model:ir.actions.act_window,name:account_analytic_default.analytic_rule_action_user
msgid "Analytic Rules"
msgstr "Analytiske Regler"
@@ -123,7 +133,7 @@ msgstr "Visningsnavn"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_stop
msgid "End Date"
msgstr "Sluttdato"
msgstr "Avslutningsdato"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__sequence
@@ -139,12 +149,12 @@ msgstr "Grupper etter"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__id
msgid "ID"
msgstr "IDID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Fakturalinje"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Journal Elementer."
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
@@ -173,11 +183,6 @@ msgstr "Partner"
msgid "Product"
msgstr "Produkt"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Salgsordrelinje"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -210,6 +215,14 @@ msgstr ""
"Velg en bruker som vil bruke den analytisk kontoen som er angitt i analytisk"
" standard."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
@@ -220,6 +233,11 @@ msgstr "Sekvens"
msgid "Start Date"
msgstr "Startdato"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Tagger"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
+43 -26
View File
@@ -1,21 +1,19 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Erwin van der Ploeg <erwin@odooexperts.nl>, 2016
# Martin Trigaux, 2016
# Cas Vissers <casvissers@brahoo.nl>, 2017
# Eric Geens <ericgeens@yahoo.com>, 2018
# Yenthe Van Ginneken <yenthespam@gmail.com>, 2018
# Martin Trigaux, 2019
# Erwin van der Ploeg <erwin@odooexperts.nl>, 2019
# Yenthe Van Ginneken <yenthespam@gmail.com>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2016-08-05 12:55+0000\n"
"Last-Translator: Yenthe Van Ginneken <yenthespam@gmail.com>, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Yenthe Van Ginneken <yenthespam@gmail.com>, 2019\n"
"Language-Team: Dutch (https://www.transifex.com/odoo/teams/41243/nl/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -39,12 +37,18 @@ msgid "<strong>Product</strong>"
msgstr "<strong>Product</strong>"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Kostenplaatsen"
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Rekening"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Rekeningen"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
@@ -59,13 +63,18 @@ msgstr ""
msgid "Analytic Account"
msgstr "Kostenplaats"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_tree
msgid "Analytic Defaults"
msgstr "Kostenplaatsen standaarden"
msgstr "Standaard kostenplaatsen"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_analytic_default
@@ -81,13 +90,13 @@ msgstr "Kostenplaatsregels"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_tag_ids
msgid "Analytic Tags"
msgstr "Labels kostenplaats"
msgstr "Kostenplaatslabels"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__company_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Company"
msgstr "Bedijf"
msgstr "Bedrijf"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
@@ -107,7 +116,7 @@ msgstr "Aangemaakt op"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.res_config_settings_view_form
msgid "Default Analytic Values"
msgstr "Standaard analytische waardes"
msgstr "Standaard kostenplaats waardes"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__date_stop
@@ -146,9 +155,9 @@ msgid "ID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Factuurregel"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Boeking"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
@@ -177,11 +186,6 @@ msgstr "Relatie"
msgid "Product"
msgstr "Product"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Verkooporderregel"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -223,6 +227,14 @@ msgstr ""
"Selecteer een gebruiker welke gebruik zal maken van de kostenplaats, zoals "
"gespecificeerd in de kostenplaats standaarden."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
@@ -233,6 +245,11 @@ msgstr "Reeks"
msgid "Start Date"
msgstr "Startdatum"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Labels"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
+35 -16
View File
@@ -1,12 +1,10 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Paweł Wodyński <pw@myodoo.pl>, 2018
# Piotr Cierkosz <piotr.w.cierkosz@gmail.com>, 2019
# Martin Trigaux, 2019
# zbik2607 <darek@krokus.com.pl>, 2019
# Dariusz Żbikowski <darek@krokus.com.pl>, 2019
# Grzegorz Grzelak <grzegorz.grzelak@openglobe.pl>, 2019
# Judyta Kaźmierczak <judyta.kazmierczak@openglobe.pl>, 2019
# Mikołaj Dziurzyński <mikolaj.dziurzynski@openglobe.pl>, 2019
@@ -15,14 +13,16 @@
# Piotr Szlązak <szlazakpiotr@gmail.com>, 2019
# Marcin Młynarczyk <mlynarczyk@gmail.com>, 2019
# Andrzej Donczew <a.donczew@hadron.eu.com>, 2019
# Piotr Cierkosz <piotr.w.cierkosz@gmail.com>, 2019
# Paweł Wodyński <pw@myodoo.pl>, 2019
# Wiktor Kaźmierczak <wik92tor@wp.pl>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2016-08-05 12:55+0000\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Wiktor Kaźmierczak <wik92tor@wp.pl>, 2019\n"
"Language-Team: Polish (https://www.transifex.com/odoo/teams/41243/pl/)\n"
"MIME-Version: 1.0\n"
@@ -46,13 +46,19 @@ msgstr "<strong>Klient </strong>"
msgid "<strong>Product</strong>"
msgstr "<strong>Produkt</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Konto"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Konta"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
@@ -65,6 +71,11 @@ msgstr ""
msgid "Analytic Account"
msgstr "Konto analityczne"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
@@ -152,9 +163,9 @@ msgid "ID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Pozycja faktury"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Pozycja zapisu"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
@@ -183,11 +194,6 @@ msgstr "Kontrahent"
msgid "Product"
msgstr "Produkt"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Pozycja zamówienia sprzedaży"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -230,6 +236,14 @@ msgid ""
"Select a user which will use analytic account specified in analytic default."
msgstr "Wybierz użytkownika, dla którego to konto będzie domyślne."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
@@ -240,6 +254,11 @@ msgstr "Numeracja"
msgid "Start Date"
msgstr "Data Początkowa"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Znaczniki"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
+44 -23
View File
@@ -1,23 +1,25 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# grazziano <gra.negocia@gmail.com>, 2016
# Mateus Lopes <mateus1@gmail.com>, 2016
# Maicon Grahl <maicongrahl@hotmail.com>, 2017
# Martin Trigaux, 2017
# Anderson Fratuci <ander.frat@gmail.com>, 2017
# Adriel Kotviski <kotviski@gmail.com>, 2018
# Silmar <pinheirosilmar@gmail.com>, 2018
# Rodrigo de Almeida Sottomaior Macedo <rmsolucoeseminformatic4@gmail.com>, 2019
# Martin Trigaux, 2019
# Maicon Grahl <maicongrahl@hotmail.com>, 2019
# Mateus Lopes <mateus1@gmail.com>, 2019
# Adriel Kotviski <kotviski@gmail.com>, 2019
# Anderson Fratuci <ander.frat@gmail.com>, 2019
# grazziano <gra.negocia@gmail.com>, 2019
# André Augusto Firmino Cordeiro <a.cordeito@gmail.com>, 2019
# Silmar <pinheirosilmar@gmail.com>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2016-08-05 12:55+0000\n"
"Last-Translator: Silmar <pinheirosilmar@gmail.com>, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Silmar <pinheirosilmar@gmail.com>, 2019\n"
"Language-Team: Portuguese (Brazil) (https://www.transifex.com/odoo/teams/41243/pt_BR/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -40,13 +42,19 @@ msgstr "<strong>Cliente</strong>"
msgid "<strong>Product</strong>"
msgstr "<strong>Produto</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Conta"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Contas"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
@@ -61,6 +69,11 @@ msgstr ""
msgid "Analytic Account"
msgstr "Conta Analítica"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
@@ -124,7 +137,7 @@ msgstr "Data de início padrão para esta Conta Analítica"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__display_name
msgid "Display Name"
msgstr "Nome para Exibição"
msgstr "Nome exibido"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__date_stop
@@ -149,14 +162,14 @@ msgid "ID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Linha da Fatura"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Item de Diário"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
msgid "Last Modified on"
msgstr "Última Modificação em"
msgstr "Última modificação em"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__write_uid
@@ -180,11 +193,6 @@ msgstr "Parceiro"
msgid "Product"
msgstr "Produto"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Linha do Pedido de Vendas"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -229,6 +237,14 @@ msgstr ""
"Selecione um usuário que irá utilizar uma conta analítica especificada nos "
"padrões analíticos"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
@@ -239,6 +255,11 @@ msgstr "Seqüência"
msgid "Start Date"
msgstr "Data de Início"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Marcadores"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
+42 -21
View File
@@ -1,16 +1,18 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Martin Trigaux, 2018
# Martin Trigaux, 2019
# Vasiliy Korobatov <korobatov@gmail.com>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2018-09-18 09:49+0000\n"
"Last-Translator: Martin Trigaux, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Vasiliy Korobatov <korobatov@gmail.com>, 2019\n"
"Language-Team: Russian (https://www.transifex.com/odoo/teams/41243/ru/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -21,7 +23,7 @@ msgstr ""
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
msgid "<i class=\"fa fa-calendar\"/> From"
msgstr ""
msgstr "<i class=\"fa fa-clock-o\"/> От"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_kanban
@@ -34,12 +36,18 @@ msgid "<strong>Product</strong>"
msgstr "<strong>Продукт</strong>"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "счетах"
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Счёт"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Cчетах"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
@@ -52,6 +60,11 @@ msgstr ""
msgid "Analytic Account"
msgstr "Аналитический счёт"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
@@ -100,7 +113,7 @@ msgstr "Создан"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.res_config_settings_view_form
msgid "Default Analytic Values"
msgstr ""
msgstr "Аналитические значения по умолчанию"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__date_stop
@@ -131,7 +144,7 @@ msgstr "Определяет порядок вывода списка разне
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Group By"
msgstr "Группировать"
msgstr "Группировать по"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__id
@@ -139,9 +152,9 @@ msgid "ID"
msgstr "Номер"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Позиция счета"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Элемент журнала"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
@@ -170,11 +183,6 @@ msgstr "Партнёр"
msgid "Product"
msgstr "Продукт"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Строка заказа на продажу"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -216,6 +224,14 @@ msgid ""
msgstr ""
"Выберите пользователя, чей аналитический счёт по умолчанию будет использован"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
@@ -226,6 +242,11 @@ msgstr "Нумерация"
msgid "Start Date"
msgstr "Дата начала"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Теги"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
+45 -25
View File
@@ -1,24 +1,23 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * account_analytic_default
# * account_analytic_default
#
# Translators:
# Fırat Kaya <firat.kaya@mechsoft.com.tr>, 2017
# Ediz Duman <neps1192@gmail.com>, 2017
# gezgin biri <gezginbiri@hotmail.com>, 2017
# Martin Trigaux, 2017
# Kaya Zeren <kayazeren@gmail.com>, 2017
# Gökhan Erdoğdu <gokhan.erdogdu@mechsoft.com.tr>, 2017
# Ayhan KIZILTAN <akiziltan76@hotmail.com>, 2017
# Murat Kaplan <muratk@projetgrup.com>, 2018
# Kaya Zeren <kayazeren@gmail.com>, 2019
# Ayhan KIZILTAN <akiziltan76@hotmail.com>, 2019
# Martin Trigaux, 2019
# Levent Karakaş <levent@mektup.at>, 2019
# Murat Kaplan <muratk@projetgrup.com>, 2019
# Gökhan Erdoğdu <gokhan.erdogdu@mechsoft.com.tr>, 2019
# Umur Akın <umura@projetgrup.com>, 2019
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server saas~11.5\n"
"Project-Id-Version: Odoo Server saas~12.4\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-09-18 09:49+0000\n"
"PO-Revision-Date: 2016-08-05 12:55+0000\n"
"Last-Translator: Murat Kaplan <muratk@projetgrup.com>, 2018\n"
"POT-Creation-Date: 2019-08-12 11:31+0000\n"
"PO-Revision-Date: 2019-08-26 09:07+0000\n"
"Last-Translator: Umur Akın <umura@projetgrup.com>, 2019\n"
"Language-Team: Turkish (https://www.transifex.com/odoo/teams/41243/tr/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -41,18 +40,26 @@ msgstr "<strong>Müşteri</strong>"
msgid "<strong>Product</strong>"
msgstr "<strong>Ürün</strong>"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__account_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Account"
msgstr "Hesap"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Accounts"
msgstr "Hesaplar"
#. module: account_analytic_default
#: code:addons/account_analytic_default/models/account_analytic_default.py:27
#: code:addons/account_analytic_default/models/account_analytic_default.py:28
#, python-format
msgid ""
"An analytic default requires at least an analytic account or an analytic "
"tag."
msgstr ""
"Analitik bir varsayılan, en az bir analitik hesap veya bir analitik etiket "
"gerektirir."
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__analytic_id
@@ -60,13 +67,18 @@ msgstr ""
msgid "Analytic Account"
msgstr "Analitik Hesap"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Analytic Default Rule"
msgstr ""
#. module: account_analytic_default
#: model:ir.actions.act_window,name:account_analytic_default.action_analytic_default_list
#: model:ir.ui.menu,name:account_analytic_default.menu_analytic_default_list
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_tree
msgid "Analytic Defaults"
msgstr "Analitik Öndeğerleri"
msgstr "Analitik Varsayılanları"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_analytic_default
@@ -88,7 +100,7 @@ msgstr "Analitik Etiketleri"
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__company_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search
msgid "Company"
msgstr "Firma"
msgstr "Şirket"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
@@ -103,7 +115,7 @@ msgstr "Oluşturan"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__create_date
msgid "Created on"
msgstr "Oluşturulma zamanı"
msgstr "Oluşturulma"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.res_config_settings_view_form
@@ -147,9 +159,9 @@ msgid "ID"
msgstr "ID"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_account_invoice_line
msgid "Invoice Line"
msgstr "Fatura Satırı"
#: model:ir.model,name:account_analytic_default.model_account_move_line
msgid "Journal Item"
msgstr "Yevmiye Kalemleri"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default____last_update
@@ -178,11 +190,6 @@ msgstr "İş Ortağı"
msgid "Product"
msgstr "Ürün"
#. module: account_analytic_default
#: model:ir.model,name:account_analytic_default.model_sale_order_line
msgid "Sales Order Line"
msgstr "Satış Sipariş Satırı"
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__company_id
msgid ""
@@ -224,6 +231,14 @@ msgstr ""
"Analitik varsayılan da tanımlanan analitik hesabı kullanacak bir kullanıcı "
"seçin."
#. module: account_analytic_default
#: model:ir.model.fields,help:account_analytic_default.field_account_analytic_default__account_id
msgid ""
"Select an accounting account which will use analytic account specified in "
"analytic default (e.g. create new customer invoice or Sales order if we "
"select this account, it will automatically take this as an analytic account)"
msgstr ""
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__sequence
msgid "Sequence"
@@ -234,6 +249,11 @@ msgstr "Sıra"
msgid "Start Date"
msgstr "Başlangıç Tarihi"
#. module: account_analytic_default
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form
msgid "Tags"
msgstr "Etiketler"
#. module: account_analytic_default
#: model:ir.model.fields,field_description:account_analytic_default.field_account_analytic_default__user_id
#: model_terms:ir.ui.view,arch_db:account_analytic_default.view_account_analytic_default_form_search

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