diff --git a/addons/account_debit_note/__init__.py b/addons/account_debit_note/__init__.py
new file mode 100644
index 00000000000..2ae6446f9dc
--- /dev/null
+++ b/addons/account_debit_note/__init__.py
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import models
+from . import wizard
diff --git a/addons/account_debit_note/__manifest__.py b/addons/account_debit_note/__manifest__.py
new file mode 100644
index 00000000000..07a739af121
--- /dev/null
+++ b/addons/account_debit_note/__manifest__.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+{
+ 'name': 'Debit Notes',
+ 'version': '1.0',
+ 'category': 'Accounting/Accounting',
+ 'summary': 'Debit Notes',
+ 'description': """
+In a lot of countries, a debit note is used as an increase of the amounts of an existing invoice
+or in some specific cases to cancel a credit note.
+It is like a regular invoice, but we need to keep track of the link with the original invoice.
+The wizard used is similar as the one for the credit note.
+ """,
+ 'depends': ['account'],
+ 'data': [
+ 'wizard/account_debit_note_view.xml',
+ 'views/account_move_view.xml',
+ 'security/ir.model.access.csv',
+ ],
+ 'installable': True,
+ 'auto_install': False,
+}
diff --git a/addons/account_debit_note/i18n/account_debit_note.pot b/addons/account_debit_note/i18n/account_debit_note.pot
new file mode 100644
index 00000000000..f07668e4af9
--- /dev/null
+++ b/addons/account_debit_note/i18n/account_debit_note.pot
@@ -0,0 +1,165 @@
+# Translation of Odoo Server.
+# This file contains the translation of the following modules:
+# * account_debit_note
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: Odoo Server 13.0+e\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2020-02-14 09:23+0000\n"
+"PO-Revision-Date: 2020-02-14 09:23+0000\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: \n"
+"Plural-Forms: \n"
+
+#. module: account_debit_note
+#: model_terms:ir.ui.view,arch_db:account_debit_note.view_move_form_debit
+msgid "Debit Notes"
+msgstr ""
+
+#. module: account_debit_note
+#: model_terms:ir.ui.view,arch_db:account_debit_note.view_move_form_debit
+msgid "Add Debit Note"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model,name:account_debit_note.model_account_debit_note
+msgid "Add Debit Note wizard"
+msgstr ""
+
+#. module: account_debit_note
+#: model_terms:ir.ui.view,arch_db:account_debit_note.view_account_debit_note
+msgid "Cancel"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__copy_lines
+msgid "Copy Lines"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.actions.act_window,name:account_debit_note.action_view_account_move_debit
+#: model_terms:ir.ui.view,arch_db:account_debit_note.view_account_debit_note
+msgid "Create Debit Note"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__create_uid
+msgid "Created by"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__create_date
+msgid "Created on"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__date
+#: model_terms:ir.ui.view,arch_db:account_debit_note.view_account_debit_note
+msgid "Debit Note Date"
+msgstr ""
+
+#. module: account_debit_note
+#: code:addons/account_debit_note/models/account_move.py:0
+#: code:addons/account_debit_note/wizard/account_debit_note.py:0
+#: model:ir.model.fields,field_description:account_debit_note.field_account_move__debit_note_ids
+#, python-format
+msgid "Debit Notes"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__display_name
+msgid "Display Name"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__id
+msgid "ID"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,help:account_debit_note.field_account_debit_note__journal_id
+msgid "If empty, uses the journal of the journal entry to be debited."
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,help:account_debit_note.field_account_debit_note__copy_lines
+msgid ""
+"In case you need to do corrections for every line, it can be in handy to "
+"copy them. We won't copy them for debit notes from credit notes. "
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model,name:account_debit_note.model_account_move
+msgid "Journal Entries"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__journal_type
+msgid "Journal Type"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note____last_update
+msgid "Last Modified on"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__write_uid
+msgid "Last Updated by"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__write_date
+msgid "Last Updated on"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__move_ids
+msgid "Move"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__move_type
+msgid "Move Type"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_move__debit_note_count
+msgid "Number of Debit Notes"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_move__debit_origin_id
+msgid "Original Invoice Debited"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__reason
+msgid "Reason"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,help:account_debit_note.field_account_move__debit_note_ids
+msgid "The debit notes created for this invoice"
+msgstr ""
+
+#. module: account_debit_note
+#: code:addons/account_debit_note/wizard/account_debit_note.py:0
+#, python-format
+msgid "This debit note was created from:"
+msgstr ""
+
+#. module: account_debit_note
+#: model:ir.model.fields,field_description:account_debit_note.field_account_debit_note__journal_id
+msgid "Use Specific Journal"
+msgstr ""
+
+#. module: account_debit_note
+#: code:addons/account_debit_note/wizard/account_debit_note.py:0
+#, python-format
+msgid "You can only debit posted moves."
+msgstr ""
diff --git a/addons/account_debit_note/models/__init__.py b/addons/account_debit_note/models/__init__.py
new file mode 100644
index 00000000000..2184e77ab4a
--- /dev/null
+++ b/addons/account_debit_note/models/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import account_move
\ No newline at end of file
diff --git a/addons/account_debit_note/models/account_move.py b/addons/account_debit_note/models/account_move.py
new file mode 100644
index 00000000000..75b5768da14
--- /dev/null
+++ b/addons/account_debit_note/models/account_move.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models, fields, api, _
+
+class AccountMove(models.Model):
+ _inherit = "account.move"
+
+ debit_origin_id = fields.Many2one('account.move', 'Original Invoice Debited', readonly=True, copy=False)
+ debit_note_ids = fields.One2many('account.move', 'debit_origin_id', 'Debit Notes',
+ help="The debit notes created for this invoice")
+ debit_note_count = fields.Integer('Number of Debit Notes', compute='_compute_debit_count')
+
+ @api.depends('debit_note_ids')
+ def _compute_debit_count(self):
+ debit_data = self.env['account.move'].read_group([('debit_origin_id', 'in', self.ids)],
+ ['debit_origin_id'], ['debit_origin_id'])
+ data_map = {datum['debit_origin_id'][0]: datum['debit_origin_id_count'] for datum in debit_data}
+ for inv in self:
+ inv.debit_note_count = data_map.get(inv.id, 0.0)
+
+ def action_view_debit_notes(self):
+ self.ensure_one()
+ return {
+ 'type': 'ir.actions.act_window',
+ 'name': _('Debit Notes'),
+ 'res_model': 'account.move',
+ 'view_mode': 'tree,form',
+ 'domain': [('debit_origin_id', '=', self.id)],
+ }
diff --git a/addons/account_debit_note/security/ir.model.access.csv b/addons/account_debit_note/security/ir.model.access.csv
new file mode 100644
index 00000000000..2e015287121
--- /dev/null
+++ b/addons/account_debit_note/security/ir.model.access.csv
@@ -0,0 +1,2 @@
+"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink"
+"access_account_debit_note_user","account_debit_note_group_invoice","model_account_debit_note","account.group_account_invoice",1,1,1,0
diff --git a/addons/account_debit_note/tests/__init__.py b/addons/account_debit_note/tests/__init__.py
new file mode 100644
index 00000000000..2e857acab4d
--- /dev/null
+++ b/addons/account_debit_note/tests/__init__.py
@@ -0,0 +1,3 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+from . import test_out_debit_note
\ No newline at end of file
diff --git a/addons/account_debit_note/tests/test_out_debit_note.py b/addons/account_debit_note/tests/test_out_debit_note.py
new file mode 100644
index 00000000000..a184e3f65a2
--- /dev/null
+++ b/addons/account_debit_note/tests/test_out_debit_note.py
@@ -0,0 +1,46 @@
+# -*- coding: utf-8 -*-
+from odoo.addons.account.tests.common import AccountTestInvoicingCommon
+from odoo.tests import tagged
+from odoo import fields
+
+
+@tagged('post_install', '-at_install')
+class TestAccountDebitNote(AccountTestInvoicingCommon):
+
+ def test_00_debit_note_out_invoice(self):
+ """ Debit Note of a regular Customer Invoice"""
+ invoice = self.init_invoice('out_invoice')
+ invoice.post()
+ move_debit_note_wiz = self.env['account.debit.note'].with_context(active_model="account.move",
+ active_ids=invoice.ids).create({
+ 'date': fields.Date.from_string('2019-02-01'),
+ 'reason': 'no reason',
+ 'copy_lines': True,
+ })
+ move_debit_note_wiz.create_debit()
+
+ # Search for the original invoice
+ debit_note = self.env['account.move'].search([('debit_origin_id', '=', invoice.id)])
+ debit_note.ensure_one()
+ self.assertEqual(len(debit_note.invoice_line_ids), 2, "Should have copied the invoice lines")
+ self.assertEqual(debit_note.type, 'out_invoice', 'Type of debit note should be the same as the original invoice')
+ self.assertEqual(debit_note.state, 'draft', 'We should create debit notes in draft state')
+
+ def test_10_debit_note_in_refund(self):
+ """ Debit Note of a vendor refund (is a regular vendor bill) """
+ invoice = self.init_invoice('in_refund')
+ invoice.post()
+ move_debit_note_wiz = self.env['account.debit.note'].with_context(active_model="account.move",
+ active_ids=invoice.ids).create({
+ 'date': fields.Date.from_string('2019-02-01'),
+ 'reason': 'in order to cancel refund',
+ })
+ move_debit_note_wiz.create_debit()
+
+ # Search for the original invoice
+ debit_note = self.env['account.move'].search([('debit_origin_id', '=', invoice.id)])
+ debit_note.ensure_one()
+
+ self.assertFalse(debit_note.invoice_line_ids, 'We should not copy lines by default on debit notes')
+ self.assertEqual(debit_note.type, 'in_invoice', 'Type of debit note should not be refund anymore')
+ self.assertEqual(debit_note.state, 'draft', 'We should create debit notes in draft state')
\ No newline at end of file
diff --git a/addons/account_debit_note/views/account_move_view.xml b/addons/account_debit_note/views/account_move_view.xml
new file mode 100644
index 00000000000..6deffec1c07
--- /dev/null
+++ b/addons/account_debit_note/views/account_move_view.xml
@@ -0,0 +1,28 @@
+
+
+
+ account.move.form.debit
+ account.move
+
+
+
+
+
+
+
+
+
+
diff --git a/addons/account_debit_note/wizard/__init__.py b/addons/account_debit_note/wizard/__init__.py
new file mode 100644
index 00000000000..2048c309b0f
--- /dev/null
+++ b/addons/account_debit_note/wizard/__init__.py
@@ -0,0 +1,4 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from . import account_debit_note
\ No newline at end of file
diff --git a/addons/account_debit_note/wizard/account_debit_note.py b/addons/account_debit_note/wizard/account_debit_note.py
new file mode 100644
index 00000000000..af553426c12
--- /dev/null
+++ b/addons/account_debit_note/wizard/account_debit_note.py
@@ -0,0 +1,90 @@
+# -*- coding: utf-8 -*-
+from odoo import models, fields, api
+from odoo.tools.translate import _
+from odoo.exceptions import UserError
+
+
+class AccountDebitNote(models.TransientModel):
+ """
+ Add Debit Note wizard: when you want to correct an invoice with a positive amount.
+ Opposite of a Credit Note, but different from a regular invoice as you need the link to the original invoice.
+ In some cases, also used to cancel Credit Notes
+ """
+ _name = 'account.debit.note'
+ _description = 'Add Debit Note wizard'
+
+ move_ids = fields.Many2many('account.move', 'account_move_debit_move', 'debit_id', 'move_id',
+ domain=[('state', '=', 'posted')])
+ date = fields.Date(string='Debit Note Date', default=fields.Date.context_today, required=True)
+ reason = fields.Char(string='Reason')
+ journal_id = fields.Many2one('account.journal', string='Use Specific Journal',
+ help='If empty, uses the journal of the journal entry to be debited.')
+ copy_lines = fields.Boolean("Copy Lines",
+ help="In case you need to do corrections for every line, it can be in handy to copy them. "
+ "We won't copy them for debit notes from credit notes. ")
+ # computed fields
+ move_type = fields.Char(compute="_compute_from_moves")
+ journal_type = fields.Char(compute="_compute_from_moves")
+
+ @api.model
+ def default_get(self, fields):
+ res = super(AccountDebitNote, self).default_get(fields)
+ move_ids = self.env['account.move'].browse(self.env.context['active_ids']) if self.env.context.get('active_model') == 'account.move' else self.env['account.move']
+ if any(move.state != "posted" for move in move_ids):
+ raise UserError(_('You can only debit posted moves.'))
+ res['move_ids'] = [(6, 0, move_ids.ids)]
+ return res
+
+ @api.depends('move_ids')
+ def _compute_from_moves(self):
+ for record in self:
+ move_ids = record.move_ids
+ record.move_type = move_ids[0].type if len(move_ids) == 1 or not any(m.type != move_ids[0].type for m in move_ids) else False
+ record.journal_type = record.move_type in ['in_refund', 'in_invoice'] and 'purchase' or 'sale'
+
+ def _prepare_default_values(self, move):
+ if move.type in ('in_refund', 'out_refund'):
+ type = 'in_invoice' if move.type == 'in_refund' else 'out_invoice'
+ else:
+ type = move.type
+ default_values = {
+ 'ref': '%s, %s' % (move.name, self.reason) if self.reason else move.name,
+ 'date': self.date or move.date,
+ 'invoice_date': move.is_invoice(include_receipts=True) and (self.date or move.date) or False,
+ 'journal_id': self.journal_id and self.journal_id.id or move.journal_id.id,
+ 'invoice_payment_term_id': None,
+ 'debit_origin_id': move.id,
+ 'type': type,
+ }
+ if not self.copy_lines or move.type in [('in_refund', 'out_refund')]:
+ default_values['line_ids'] = [(5, 0, 0)]
+ return default_values
+
+ def create_debit(self):
+ self.ensure_one()
+ new_moves = self.env['account.move']
+ for move in self.move_ids.with_context(include_business_fields=True): #copy sale/purchase links
+ default_values = self._prepare_default_values(move)
+ new_move = move.with_context(internal_type='debit_note').copy(default=default_values) # Context key is used for l10n_latam_invoice_document for ar/cl/pe
+ move_msg = _(
+ "This debit note was created from:") + " %s" % (
+ move.id, move.name)
+ new_move.message_post(body=move_msg)
+ new_moves |= new_move
+
+ action = {
+ 'name': _('Debit Notes'),
+ 'type': 'ir.actions.act_window',
+ 'res_model': 'account.move',
+ }
+ if len(new_moves) == 1:
+ action.update({
+ 'view_mode': 'form',
+ 'res_id': new_moves.id,
+ })
+ else:
+ action.update({
+ 'view_mode': 'tree,form',
+ 'domain': [('id', 'in', new_moves.ids)],
+ })
+ return action
diff --git a/addons/account_debit_note/wizard/account_debit_note_view.xml b/addons/account_debit_note/wizard/account_debit_note_view.xml
new file mode 100644
index 00000000000..be21ca6a987
--- /dev/null
+++ b/addons/account_debit_note/wizard/account_debit_note_view.xml
@@ -0,0 +1,40 @@
+
+
+
+
+ account.debit.note.form
+ account.debit.note
+
+
+
+
+
+
+ Create Debit Note
+ account.debit.note
+ tree,form
+
+ new
+
+ list
+
+
+