Skip to content

Commit

Permalink
Merge bc2323d into d7f791b
Browse files Browse the repository at this point in the history
  • Loading branch information
Saran440 committed May 10, 2019
2 parents d7f791b + bc2323d commit 66d92c2
Show file tree
Hide file tree
Showing 19 changed files with 1,256 additions and 0 deletions.
98 changes: 98 additions & 0 deletions account_billing/README.rst
@@ -0,0 +1,98 @@
===============
Billing Process
===============

.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| 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
.. |badge2| image:: https://img.shields.io/badge/github-OCA%2Faccount--invoicing-lightgray.png?logo=github
:target: https://github.com/OCA/account-invoicing/tree/12.0-add-account_billing/account_billing
:alt: OCA/account-invoicing
.. |badge3| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/account-invoicing-12-0-add-account_billing/account-invoicing-12-0-add-account_billing-account_billing
:alt: Translate me on Weblate
.. |badge4| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/95/12.0-add-account_billing
:alt: Try me on Runbot

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

In some countries, there is a customary practice for companies to collect money
from their customers only once in a month. For example, the customer has 3 payments due in
a given month, the vendor or billing company should group all the due AR Invoices in a document
call Billing Document and issue it with all the invoices consolidated to the customer on the Billing Day.
The customer will be paying based on the payable amount shown in Billing Document in the following month.

This module use a new document called "Billing" to group these invoices together.

**Table of contents**

.. contents::
:local:

Usage
=====

To use this module, you have 2 ways:

1. Create new billing directly
Go to *Invoicing -> Customers or Vendors -> Billing*

2. Create billing from selected invoice(s)
#. Go to *Invoicing -> Customers or Vendors -> Invoices or Bills*
#. Create Invoice
#. On tree view select invoice and go to *Action -> Create Billing*

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_billing%0Aversion:%2012.0-add-account_billing%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
~~~~~~~

* Ecosoft

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

* Kitti U. <kittiu@ecosoft.co.th>
* Saran Lim. <saranl@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.

.. |maintainer-Saran440| image:: https://github.com/Saran440.png?size=40px
:target: https://github.com/Saran440
:alt: Saran440

Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-Saran440|

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

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

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

{
'name': 'Billing Process',
'summary': 'Group invoice as billing before payment',
'version': '12.0.1.0.0',
'author': 'Ecosoft,Odoo Community Association (OCA)',
'license': 'AGPL-3',
'website': 'https://github.com/OCA/account-invoicing/',
'category': 'Account',
'depends': ['account'],
'data': [
'data/account_billing_sequence.xml',
'security/ir.model.access.csv',
'views/account_billing.xml',
'views/account_invoice.xml',
'report/report_billing.xml',
'report/report.xml',
],
'installable': True,
'development_status': 'alpha',
'maintainers': ['Saran440'],
}
24 changes: 24 additions & 0 deletions account_billing/data/account_billing_sequence.xml
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo noupdate="1">
<record id="seq_account_customer_billing" model="ir.sequence">
<field name="name">Billing sequence</field>
<field name="code">account.customer.billing</field>
<field name="prefix">CUST.BIL/%(year)s/</field>
<field eval="1" name="number_next"/>
<field eval="1" name="number_increment"/>
<field eval="True" name="use_date_range"/>
<field eval="False" name="company_id"/>
<field name="padding">5</field>
</record>

<record id="seq_account_supplier_billing" model="ir.sequence">
<field name="name">Supplier Billing sequence</field>
<field name="code">account.supplier.billing</field>
<field name="prefix">SUPP.BIL/%(year)s/</field>
<field eval="1" name="number_next"/>
<field eval="1" name="number_increment"/>
<field eval="True" name="use_date_range"/>
<field eval="False" name="company_id"/>
<field name="padding">5</field>
</record>
</odoo>
5 changes: 5 additions & 0 deletions account_billing/models/__init__.py
@@ -0,0 +1,5 @@
# Copyright 2019 Ecosoft Co., Ltd (http://ecosoft.co.th/)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html)

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

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

MAP_INVOICE_TYPE_PARTNER_TYPE = {
'out_invoice': 'customer',
'in_invoice': 'supplier',
}


class AccountBilling(models.Model):
_name = 'account.billing'
_description = 'Account Billing'
_inherit = ['mail.thread']
_order = 'date desc, id desc'

name = fields.Char(
readonly=True,
copy=False,
help='Number of account.billing',
)
partner_id = fields.Many2one(
comodel_name='res.partner',
required=True,
default=lambda self: self._get_partner_id(),
help='Partner Information',
track_visibility='always',
)
date = fields.Date(
string='Billing Date',
readonly=True,
states={'draft': [('readonly', False)]},
default=fields.Date.context_today,
help='Effective date for accounting entries',
track_visibility='always',
)
due_date = fields.Date(
readonly=True,
states={'draft': [('readonly', False)]},
default=lambda self: fields.Date.context_today(self),
required=True,
track_visibility='always',
)
invoice_ids = fields.One2many(
comodel_name='account.invoice',
inverse_name='billing_id',
string='Invoices',
readonly=True,
states={'draft': [('readonly', False)]},
default=lambda self: self._context.get('active_ids', []),
)
invoice_related_count = fields.Integer(
string='# of Invoices',
compute='_compute_invoice_related_count',
help='Count invoice in billing',
)
state = fields.Selection(
[('draft', 'Draft'),
('cancel', 'Cancelled'),
('billed', 'Billed')],
string='Status',
readonly=True,
default='draft',
help="""
* The 'Draft' status is used when a user create a new billing\n
* The 'Billed' status is used when user confirmed billing,
billing number is generated\n
* The 'Cancelled' status is used when user billing is cancelled
""",
)
narration = fields.Text(
string='Notes',
readonly=True,
states={'draft': [('readonly', False)]},
help='Notes',
)
bill_type = fields.Selection(
[('out_invoice', 'Customer Invoice'),
('in_invoice', 'Vendor Bill')],
readonly=True,
states={'draft': [('readonly', False)]},
default=lambda self: self._context.get('bill_type', False),
help='Type of invoice',
)
currency_id = fields.Many2one(
comodel_name='res.currency',
string='Currency',
required=True,
default=lambda self: self._get_currency_id(),
help='Currency',
)

@api.model
def fields_view_get(self, view_id=None, view_type='form',
toolbar=False, submenu=False):
res = super(AccountBilling, self).fields_view_get(
view_id=view_id, view_type=view_type,
toolbar=toolbar, submenu=submenu)
invoices = self.env['account.invoice'].browse(
self._context.get('active_ids', []))
billing = invoices.mapped('billing_id')
if any(inv.state != 'open' for inv in invoices):
raise ValidationError(_('The billing cannot be processed '
'because the invoice is not open!'))
if billing:
raise ValidationError(_(
'Invoice: %s, already billed!') % ', '.join(
invoices.filtered(lambda l: l.billing_id).mapped('number')))
return res

@api.onchange('bill_type')
def _onchange_bill_type(self):
# Set partner_id domain
if self.bill_type:
return {'domain': {'partner_id': [
(MAP_INVOICE_TYPE_PARTNER_TYPE[self.bill_type], '=', True)]}}

@api.multi
def _get_partner_id(self):
partner_ids = self.env['account.invoice'].browse(
self._context.get('active_ids', [])).mapped('partner_id')
if len(partner_ids) > 1:
raise ValidationError(
_('Please select invoices with same partner'))
return partner_ids

@api.multi
def _get_currency_id(self):
currency_ids = self.env['account.invoice'].browse(
self._context.get('active_ids', [])).mapped('currency_id')
if len(currency_ids) > 1:
raise ValidationError(
_('Please select invoices with same currency'))
return currency_ids or self.env.user.company_id.currency_id

@api.multi
def _compute_invoice_related_count(self):
for billing in self:
invoice_ids = self.env['account.invoice'].search_count([
('id', 'in', billing.invoice_ids.ids)
])
billing.invoice_related_count = invoice_ids

@api.multi
def name_get(self):
result = []
for billing in self:
result.append((billing.id, (billing.name or 'Draft')))
return result

@api.multi
def validate_billing(self):
for rec in self:
if any(inv.state != 'open' for inv in rec.invoice_ids):
raise ValidationError(_('Billing cannot be processed because \
some invoices are not in state Open'))
# keep the number in case of a billing reset to draft
if not rec.name:
# Use the right sequence to set the name
if rec.bill_type == 'out_invoice':
sequence_code = 'account.customer.billing'
if rec.bill_type == 'in_invoice':
sequence_code = 'account.supplier.billing'
rec.name = self.env['ir.sequence'].with_context(
ir_sequence_date=rec.date).next_by_code(sequence_code)
rec.write({'state': 'billed'})
rec.message_post(body=_('Billing is billed.'))
return True

@api.multi
def action_cancel_draft(self):
for rec in self:
rec.write({'state': 'draft'})
rec.message_post(body=_('Billing is reset to draft'))
return True

@api.multi
def action_cancel(self):
for rec in self:
invoice_paid = rec.invoice_ids.filtered(
lambda l: l.state == 'paid')
if invoice_paid:
raise ValidationError(_("Invoice paid already."))
rec.write({'state': 'cancel'})
rec.invoice_ids.write({'billing_id': False})
self.message_post(body=_('Billing %s is cancelled') % rec.name)
return True

@api.multi
def invoice_relate_billing_tree_view(self):
self.ensure_one()
action = self.env.ref('account.action_invoice_tree1')
result = action.read()[0]
result.update({'domain': [('id', 'in', self.invoice_ids.ids)]})
return result
15 changes: 15 additions & 0 deletions account_billing/models/account_invoice.py
@@ -0,0 +1,15 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


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

billing_id = fields.Many2one(
comodel_name='account.billing',
string='Billing',
copy=False,
index=True,
help="Relationship between invoice and billing"
)
2 changes: 2 additions & 0 deletions account_billing/readme/CONTRIBUTORS.rst
@@ -0,0 +1,2 @@
* Kitti U. <kittiu@ecosoft.co.th>
* Saran Lim. <saranl@ecosoft.co.th>
7 changes: 7 additions & 0 deletions account_billing/readme/DESCRIPTION.rst
@@ -0,0 +1,7 @@
In some countries, there is a customary practice for companies to collect money
from their customers only once in a month. For example, the customer has 3 payments due in
a given month, the vendor or billing company should group all the due AR Invoices in a document
call Billing Document and issue it with all the invoices consolidated to the customer on the Billing Day.
The customer will be paying based on the payable amount shown in Billing Document in the following month.

This module use a new document called "Billing" to group these invoices together.
9 changes: 9 additions & 0 deletions account_billing/readme/USAGE.rst
@@ -0,0 +1,9 @@
To use this module, you have 2 ways:

1. Create new billing directly
Go to *Invoicing -> Customers or Vendors -> Billing*

2. Create billing from selected invoice(s)
#. Go to *Invoicing -> Customers or Vendors -> Invoices or Bills*
#. Create Invoice
#. On tree view select invoice and go to *Action -> Create Billing*

0 comments on commit 66d92c2

Please sign in to comment.