Skip to content

Commit

Permalink
[13.0]]ADD] Add acconut_invoicing_mode
Browse files Browse the repository at this point in the history
Add three modules helping on automatically invoicing customers.

The base module `account_invoice_base_invoicing_mode` does not actually
do anything but adds a selection field on partner to allow assigning an
invoicing mode to a customer.

The two other modules add specific invoicing mode.

The module `account_invoice_mode_monthly` creates monthly invoices for
customer on a specific day (configuration is in Accounting Settings)

The module `account_invoice_mode_at_shipping` creates invoices on the
shipping of the goods.

Those modules use queue_job to generate and validate invoices.
  • Loading branch information
TDu committed Jul 15, 2020
1 parent ec4bc92 commit e463d8f
Show file tree
Hide file tree
Showing 43 changed files with 739 additions and 0 deletions.
2 changes: 2 additions & 0 deletions account_invoice_base_invoicing_mode/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import tests
13 changes: 13 additions & 0 deletions account_invoice_base_invoicing_mode/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2020 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Account Invoice Base Invoicing Mode",
"version": "13.0.1.0.0",
"summary": "Base module for handling multiple invoicing mode",
"author": "Camptocamp, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/account-invoicing",
"license": "AGPL-3",
"category": "Accounting & Finance",
"depends": ["account", "queue_job", "sale"],
"data": ["views/res_partner.xml"],
}
4 changes: 4 additions & 0 deletions account_invoice_base_invoicing_mode/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import account_invoice
from . import queue_job
from . import res_partner
from . import sale_order
15 changes: 15 additions & 0 deletions account_invoice_base_invoicing_mode/models/account_invoice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

from odoo import models

from odoo.addons.queue_job.job import job, related_action


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

@job(default_channel="root.invoice_validation")
@related_action(action="related_action_open_invoice")
def _validate_invoice(self):
return self.action_post()
35 changes: 35 additions & 0 deletions account_invoice_base_invoicing_mode/models/queue_job.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

from odoo import _, models


class QueueJob(models.Model):
_inherit = "queue.job"

def related_action_open_invoice(self):
"""Open a form view with the invoice related to the job."""
self.ensure_one()
model_name = self.model_name
records = self.env[model_name].browse(self.record_ids).exists()
if not records:
return None
action = {
"name": _("Related Record"),
"type": "ir.actions.act_window",
"view_type": "form",
"view_mode": "form",
"res_model": records._name,
}
if len(records) == 1:
action["res_id"] = records.id
else:
action.update(
{
"name": _("Related Records"),
"view_mode": "tree,form",
"view_id": "account.view_invoice_tree",
"domain": [("id", "in", records.ids)],
}
)
return action
15 changes: 15 additions & 0 deletions account_invoice_base_invoicing_mode/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

from odoo import fields, models


class ResPartner(models.Model):
_inherit = "res.partner"

invoicing_mode = fields.Selection([("standard", "Standard")], default="standard")
one_invoice_per_order = fields.Boolean(
"One invoice per order",
default=False,
help="Do not group sale order into one invoice.",
)
15 changes: 15 additions & 0 deletions account_invoice_base_invoicing_mode/models/sale_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

from odoo import fields, models


class SaleOrder(models.Model):
_inherit = "sale.order"

invoicing_mode = fields.Selection(related="partner_invoice_id.invoicing_mode")

# def _create_invoices(self, grouped=False, final=False):
# # TODO : Anything specific to do here ? looks like not
# res = super()._create_invoices(grouped, final)
# return res
3 changes: 3 additions & 0 deletions account_invoice_base_invoicing_mode/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* `Camptocamp <https://www.camptocamp.com>`_:

* Thierry Ducrest <[email protected]>
9 changes: 9 additions & 0 deletions account_invoice_base_invoicing_mode/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
This is a base module for implementing different invoicing mode for customers.
It adds a selection field `invoicing_mode` in the Accounting tab of the partner
with a default value (Odoo standard invoicing mode).
But it serves no purpose installed on its own.

The following modules use it to install specific invoicing mode :

* `account_invoice_mode_at_shipping`
* `account_invoice_mode_monthly`
1 change: 1 addition & 0 deletions account_invoice_base_invoicing_mode/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_base_invoicing_mode
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)


from odoo.tests.common import SavepointCase


class TestBaseInvoicingMode(SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
16 changes: 16 additions & 0 deletions account_invoice_base_invoicing_mode/views/res_partner.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="view_partner_property_form" model="ir.ui.view">
<field name="name">view_partner_property_form_base_invoicing_mode</field>
<field name="model">res.partner</field>
<field name="inherit_id" ref="account.view_partner_property_form" />
<field name="arch" type="xml">
<xpath expr="//page[@name='accounting']/group" position="inside">
<group name="invoicing_mode">
<field name="invoicing_mode" />
<field name="one_invoice_per_order" />
</group>
</xpath>
</field>
</record>
</odoo>
2 changes: 2 additions & 0 deletions account_invoice_mode_at_shipping/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import tests
12 changes: 12 additions & 0 deletions account_invoice_mode_at_shipping/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright 2020 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Account Invoice Mode At Shipping",
"version": "13.0.1.0.0",
"summary": "Create invoices automatically when goods are shipped.",
"author": "Camptocamp, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/account-invoicing",
"license": "AGPL-3",
"category": "Accounting & Finance",
"depends": ["account", "account_invoice_base_invoicing_mode", "queue_job", "stock"],
}
2 changes: 2 additions & 0 deletions account_invoice_mode_at_shipping/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import res_partner
from . import stock_picking
10 changes: 10 additions & 0 deletions account_invoice_mode_at_shipping/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

from odoo import fields, models


class ResPartner(models.Model):
_inherit = "res.partner"

invoicing_mode = fields.Selection(selection_add=([("at_shipping", "At Shipping")]))
32 changes: 32 additions & 0 deletions account_invoice_mode_at_shipping/models/stock_picking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

from odoo import models

from odoo.addons.queue_job.job import job


class StockPicking(models.Model):
_inherit = "stock.picking"

def action_done(self):
res = super().action_done()
picking_to_invoice = self.filtered(
lambda r: r.sale_id.partner_invoice_id.invoicing_mode == "at_shipping"
and r.picking_type_code == "outgoing"
)
for picking in picking_to_invoice:
picking.with_delay()._invoicing_at_shipping()
return res

@job(default_channel="root.invoice_at_shipping")
def _invoicing_at_shipping(self):
self.ensure_one()
sale_order_ids = self._get_sales_order_to_invoice()
invoices = sale_order_ids._create_invoices()
for invoice in invoices:
invoice.with_delay()._validate_invoice()
return invoices

def _get_sales_order_to_invoice(self):
return self.sale_id
3 changes: 3 additions & 0 deletions account_invoice_mode_at_shipping/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
* `Camptocamp <https://www.camptocamp.com>`_:

* Thierry Ducrest <[email protected]>
4 changes: 4 additions & 0 deletions account_invoice_mode_at_shipping/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This module allows to select a `At shipping` invoicing mode for a customer.
It is based on `account_invoice_base_invoicing_mode`.
When this mode is selected the customer will be invoiced automatically on
delivery of the goods.
1 change: 1 addition & 0 deletions account_invoice_mode_at_shipping/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_invoice_mode_at_shipping
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

from odoo.tests.common import SavepointCase


class TestInvoiceModeAtShipping(SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.partner = cls.env.ref("base.res_partner_1")
cls.product = cls.env.ref("product.product_delivery_01")
cls.so1 = cls.env["sale.order"].create(
{
"partner_id": cls.partner.id,
"partner_invoice_id": cls.partner.id,
"partner_shipping_id": cls.partner.id,
"order_line": [
(
0,
0,
{
"name": "Line one",
"product_id": cls.product.id,
"product_uom_qty": 4,
"product_uom": cls.product.uom_id.id,
"price_unit": 123,
},
)
],
"pricelist_id": cls.env.ref("product.list0").id,
}
)
stock_location = cls.env.ref("stock.stock_location_stock")
inventory = cls.env["stock.inventory"].create(
{
"name": "Test Inventory",
"product_ids": [(6, 0, cls.product.ids)],
"state": "confirm",
"line_ids": [
(
0,
0,
{
"product_qty": 100,
"location_id": stock_location.id,
"product_id": cls.product.id,
"product_uom_id": cls.product.uom_id.id,
},
)
],
}
)
inventory.action_validate()

def test_invoice_created_at_shipping(self):
"""Check that an invoice is created when goods are shipped."""
self.partner.invoicing_mode = "at_shipping"
self.so1.action_confirm()
for picking in self.so1.picking_ids:
for line in picking.move_lines:
line.quantity_done = line.product_uom_qty
picking.action_assign()
picking.with_context(test_queue_job_no_delay=True).button_validate()
self.assertEqual(len(self.so1.invoice_ids), 1)
self.assertEqual(self.so1.invoice_ids.state, "posted")

def test_invoice_not_created_at_shipping(self):
"""Check that an invoice is created when goods are shipped."""
self.partner.invoicing_mode = "standard"
self.so1.action_confirm()
for picking in self.so1.picking_ids:
for line in picking.move_lines:
line.quantity_done = line.product_uom_qty
picking.action_assign()
picking.button_validate()
self.assertEqual(len(self.so1.invoice_ids), 0)
2 changes: 2 additions & 0 deletions account_invoice_mode_monthly/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from . import models
from . import tests
13 changes: 13 additions & 0 deletions account_invoice_mode_monthly/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2020 Camptocamp
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
{
"name": "Account Invoice Mode Monthly",
"version": "13.0.1.0.0",
"summary": "Create invoices automatically on a monthly basis.",
"author": "Camptocamp, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/account-invoicing",
"license": "AGPL-3",
"category": "Accounting & Finance",
"depends": ["account", "account_invoice_base_invoicing_mode", "queue_job", "sale"],
"data": ["data/ir_cron.xml", "views/res_config_settings_views.xml"],
}
18 changes: 18 additions & 0 deletions account_invoice_mode_monthly/data/ir_cron.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo noupdate="1">
<record forcecreate="True" id="ir_cron_generate_monthly_invoice" model="ir.cron">
<field name="name">Generate Monthly Invoices</field>
<field eval="True" name="active" />
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
<field name="model_id" ref="model_sale_order" />
<field name="code">model.cron_generate_montly_invoices()</field>
<field
name="nextcall"
eval="(DateTime.now().replace(hour=1,minute=0).strftime('%Y-%m-%d %H:%M:%S'))"
/>
</record>
</odoo>
4 changes: 4 additions & 0 deletions account_invoice_mode_monthly/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from . import res_company
from . import res_config_settings
from . import res_partner
from . import sale_order
21 changes: 21 additions & 0 deletions account_invoice_mode_monthly/models/res_company.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

from odoo import fields, models


class ResCompany(models.Model):
_inherit = "res.company"

invoicing_mode_monthly_day_todo = fields.Integer(
"Invoicing Day",
default="31",
help="Day of the month to execute the invoicing. For a number higher"
"than the number of days in a month, the invoicing will be"
"executed on the last day of the month.",
)
invoicing_mode_monthly_last_execution = fields.Datetime(
string="Last execution",
help="Last execution of monthly invoicing.",
readonly=True,
)
14 changes: 14 additions & 0 deletions account_invoice_mode_monthly/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
from odoo import fields, models


class ResConfigSettings(models.TransientModel):
_inherit = "res.config.settings"

res_invoicing_mode_monthly_day_todo = fields.Integer(
related="company_id.invoicing_mode_monthly_day_todo", readonly=False
)
invoicing_mode_monthly_last_execution = fields.Datetime(
related="company_id.invoicing_mode_monthly_last_execution", readonly=True
)
10 changes: 10 additions & 0 deletions account_invoice_mode_monthly/models/res_partner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright 2020 Camptocamp SA
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)

from odoo import fields, models


class ResPartner(models.Model):
_inherit = "res.partner"

invoicing_mode = fields.Selection(selection_add=([("monthly", "Monthly")]))
Loading

0 comments on commit e463d8f

Please sign in to comment.