Skip to content

Commit

Permalink
Merge e54542d into db281b0
Browse files Browse the repository at this point in the history
  • Loading branch information
kongrattapong committed Aug 1, 2019
2 parents db281b0 + e54542d commit 05a74be
Show file tree
Hide file tree
Showing 20 changed files with 1,229 additions and 0 deletions.
88 changes: 88 additions & 0 deletions account_debitnote/README.rst
@@ -0,0 +1,88 @@
===========
Debit Notes
===========

.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Faccount--invoicing-lightgray.png?logo=github
:target: https://github.com/OCA/account-invoicing/tree/12.0/account_debitnote
:alt: OCA/account-invoicing
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/account-invoicing-12-0/account-invoicing-12-0-account_debitnote
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/95/12.0
:alt: Try me on Runbot

|badge1| |badge2| |badge3| |badge4| |badge5|

In some situations, You need to add some service charge or add some fees
you need to create debit note but in Invoicing don't have this module,
so I am interested to add this module.

**Table of contents**

.. contents::
:local:

Usage
=====

To use this module, you need to:

- Go to Invoicing -> Customers -> Invoices.
- Create a new invoice and the Validate.
- Click on Add Debit Note.
- Get Reason. (You can add Account Date, If not Default is the same as the invoice.)
- Click Add Debit Note, You will have a new one Invoice(Debit Note).

* You can also do the same thing in Vendors -> Bills

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/account-invoicing/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed
`feedback <https://github.com/OCA/account-invoicing/issues/new?body=module:%20account_debitnote%0Aversion:%2012.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
~~~~~~~

* Eocosft

Contributors
~~~~~~~~~~~~

* Rattapong Chokmasermkul <rattapongc@ecosoft.co.th>

Maintainers
~~~~~~~~~~~

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/account-invoicing <https://github.com/OCA/account-invoicing/tree/12.0/account_debitnote>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
5 changes: 5 additions & 0 deletions account_debitnote/__init__.py
@@ -0,0 +1,5 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import models
from . import wizard
21 changes: 21 additions & 0 deletions account_debitnote/__manifest__.py
@@ -0,0 +1,21 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
'name': 'Debit Notes',
'summary': """
Create debit note from invoice and vendor bill""",
'version': '12.0.1.0.0',
'website': 'https://github.com/OCA/account-invoicing',
'author': 'Eocosft,Odoo Community Association (OCA)',
'license': 'AGPL-3',
'depends': [
'account',
],
'data': [
'wizard/account_invoice_debitnote_view.xml',
'views/account_invoice_view.xml',
'views/account_view.xml',
],
'installable': True,
}
7 changes: 7 additions & 0 deletions account_debitnote/models/__init__.py
@@ -0,0 +1,7 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from . import account_invoice
from . import account
from . import ir_sequence
from . import account_move
120 changes: 120 additions & 0 deletions account_debitnote/models/account.py
@@ -0,0 +1,120 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import models, fields, api, _


class AccountJournal(models.Model):
_inherit = "account.journal"

debitnote_sequence_id = fields.Many2one(
comodel_name='ir.sequence',
string='Debit Note Entry Sequence',
help="""This field contains the information related to the numbering of
the debit note entries of this journal.""",
copy=False
)
debitnote_sequence_number_next = fields.Integer(
string='Debit Notes: Next Number',
help='The next sequence number will be used for the next debit note.',
compute='_compute_debitnote_seq_number_next',
inverse='_inverse_debitnote_seq_number_next'
)
debitnote_sequence = fields.Boolean(
string='Dedicated Debit Note Sequence',
help="""Check this box if you don't want to share the same sequence
for invoices and debit notes made from this journal""",
default=False
)

@api.depends('debitnote_sequence_id.use_date_range',
'debitnote_sequence_id.number_next_actual')
def _compute_debitnote_seq_number_next(self):
"""
Compute 'sequence_number_next' according to the current sequence
in use, an ir.sequence or an ir.sequence.date_range.
"""
for journal in self:
if journal.debitnote_sequence_id and journal.debitnote_sequence:
sequence = journal.debitnote_sequence_id.\
_get_current_sequence()
journal.debitnote_sequence_number_next = sequence.\
number_next_actual
else:
journal.debitnote_sequence_number_next = 1

@api.multi
def _inverse_debitnote_seq_number_next(self):
"""
Inverse 'debitnote_sequence_number_next' to edit
the current sequence next number.
"""
for journal in self:
if journal.debitnote_sequence_id and \
journal.debitnote_sequence and \
journal.debitnote_sequence_number_next:
sequence = journal.debitnote_sequence_id.\
_get_current_sequence()
sequence.number_next = journal.debitnote_sequence_number_next

@api.multi
def write(self, vals):
# create the relevant debitnote sequence
res = super().write(vals)
if vals.get('debitnote_sequence'):
for journal in self.filtered(((
lambda j: j.type in ('sale', 'purchase') and not
j.debitnote_sequence_id))):
journal_vals = {
'name': journal.name,
'company_id': journal.company_id.id,
'code': journal.code,
'debitnote_sequence_number_next':
vals.get('debitnote_sequence_number_next',
journal.debitnote_sequence_number_next),
}
journal.debitnote_sequence_id = self.sudo().\
_create_debitnote_sequence(journal_vals, debitnote=True).id
return res

@api.model
def _get_debitnote_sequence_prefix(self, code, debitnote=False):
prefix = code.upper()
if debitnote:
prefix = 'D' + prefix
return prefix + '/%(range_year)s/'

@api.model
def _create_debitnote_sequence(self, vals, debitnote=False):
""" Create new no_gap entry sequence for every new Journal"""
prefix = self._get_debitnote_sequence_prefix(vals['code'], debitnote)
seq_name = debitnote and vals['code'] + \
_(': Debitnote') or vals['code']
seq = {
'name': _('%s Sequence') % seq_name,
'implementation': 'no_gap',
'prefix': prefix,
'padding': 4,
'number_increment': 1,
'use_date_range': True,
}
if 'company_id' in vals:
seq['company_id'] = vals['company_id']
seq = self.env['ir.sequence'].create(seq)
seq_date_range = seq._get_current_sequence()
seq_date_range.number_next = debitnote and \
vals.get('debitnote_sequence_number_next', 1) or \
vals.get('sequence_number_next', 1)
return seq

@api.model
def create(self, vals):
if vals.get('type') in ('sale', 'purchase') and \
vals.get('debitnote_sequence') and not \
vals.get('debitnote_sequence_id'):
vals.update({'debitnote_sequence_id':
self.sudo()._create_debitnote_sequence
(vals, debitnote=True).id})
res = super().create(vals)

return res
128 changes: 128 additions & 0 deletions account_debitnote/models/account_invoice.py
@@ -0,0 +1,128 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import models, fields, api, _
from odoo.exceptions import ValidationError


class AccountInvoice(models.Model):
_inherit = 'account.invoice'

debit_invoice_id = fields.Many2one(
comodel_name='account.invoice',
string='Debit Note',
help="Reference to the origin invoice that create this debit note",
)
debit_invoice_ids = fields.One2many(
comodel_name='account.invoice',
inverse_name='debit_invoice_id',
string='Debit Notes',
readonly=True,
help="List all debit notes being created by this invoice",
)

@api.model
def _debitnote_cleanup_lines(self, lines):
"""
Convert records to dict of values suitable
for one2many line creation
:param list(browse_record) lines: records to convert
:return: list of command tuple for one2many line creation
[(0, 0, dict of valueis)]
"""
result = []
for line in lines:
values = {}
for name, field in line._fields.items():
if name in ['id', 'create_uid', 'create_date',
'write_uid', 'write_date']:
continue
elif field.type == 'many2one':
values[name] = line[name].id
elif field.type not in ['many2many', 'one2many']:
values[name] = line[name]
elif name == 'invoice_line_tax_ids':
values[name] = [(6, 0, line[name].ids)]
elif name == 'analytic_tag_ids':
values[name] = [(6, 0, line[name].ids)]
result.append((0, 0, values))
return result

@api.model
def _prepare_debitnote(self, invoice, date_invoice=None,
date=None, description=None, journal_id=None):
"""
Prepare the dict of values to create the new debit note
from the invoice.
This method may be overridden to implement custom debit note
generation (making sure to call super() to establish a clean
extension chain).
:param dict invoice: read of the invoice to create debit note
:param string invoice_date: debit note create date from the wizard
:param integer date: force account.period from the wizard
:param string description: description of
the debit note from the wizard
:param integer journal_id: account.journal from the wizard
:return: dict of value to create() the debit note
"""
values = {}
type_list = ['out_invoice', 'in_invoice']

if invoice.type not in type_list:
raise ValidationError(_('Can not create Debit Note'))

for field in ['name', 'reference', 'comment', 'date_due', 'partner_id',
'company_id', 'account_id', 'currency_id',
'payment_term_id', 'user_id', 'fiscal_position_id']:
if invoice._fields[field].type == 'many2one':
values[field] = invoice[field].id
else:
values[field] = invoice[field] or False

values['invoice_line_ids'] = \
self._debitnote_cleanup_lines((invoice.invoice_line_ids))
tax_lines = filter(lambda l: l['manual'], invoice.tax_line_ids)
tax_lines = self._debitnote_cleanup_lines(tax_lines)

if journal_id:
debitnote_journal = self.env['account.journal'].browse(
(journal_id))
elif invoice['type'] == 'in_invoice':
debitnote_journal = self.env['account.journal'].search(
[('type', '=', 'purchase')], limit=1)
else:
debitnote_journal = self.env['account.journal'].search(
[('type', '=', 'sale')], limit=1)

values['journal_id'] = debitnote_journal.id
values['type'] = invoice['type']
values['date_invoice'] = date_invoice or \
fields.Date.context_today((invoice))
values['state'] = 'draft'
values['number'] = False
values['origin'] = invoice.number
values['payment_term_id'] = False
values['debit_invoice_id'] = invoice.id

if date:
values['date'] = date
if description:
values['name'] = description
return values

@api.multi
@api.returns('self')
def debitnote(self, date_invoice=None, date=None,
description=None, journal_id=None):
new_invoice = []
for invoice in self:
invoice = self._prepare_debitnote(
invoice,
date_invoice=date_invoice,
date=date,
description=description,
journal_id=journal_id
)
new_invoice = self.create(invoice)
return new_invoice
13 changes: 13 additions & 0 deletions account_debitnote/models/account_move.py
@@ -0,0 +1,13 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import models, api


class AccountMove(models.Model):
_inherit = 'account.move'

@api.multi
def post(self, invoice=False):
self = self.with_context(ctx_invoice=invoice)
return super().post(invoice=invoice)

0 comments on commit 05a74be

Please sign in to comment.