Skip to content

Commit

Permalink
Merge PR #1267 into 14.0
Browse files Browse the repository at this point in the history
Signed-off-by sergiocorato
  • Loading branch information
OCA-git-bot committed Mar 5, 2024
2 parents d1b656a + 5a7400f commit 220570b
Show file tree
Hide file tree
Showing 16 changed files with 448 additions and 0 deletions.
98 changes: 98 additions & 0 deletions account_receipt_sale/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
from . import models
from . import wizard
from odoo import api, SUPERUSER_ID
from openupgradelib import openupgrade


def rename_old_italian_module(cr):

if not openupgrade.is_module_installed(cr, "l10n_it_corrispettivi"):
return

openupgrade.update_module_names(
cr,
[
("l10n_it_corrispettivi", "account_receipt_sale"),
],
merge_modules=True,
)

if openupgrade.column_exists(
cr, "account_move", "old_invoice_id"
) and openupgrade.column_exists(cr, "account_invoice", "corrispettivo"):
# l10n_it_corrispettivi handled sale receipts only
openupgrade.logged_query(
cr,
"UPDATE account_move m "
"SET move_type = 'out_receipt' "
"FROM account_invoice i "
"WHERE i.corrispettivo = true AND i.id = m.old_invoice_id",
)

if openupgrade.column_exists(cr, "account_journal", "corrispettivi"):
openupgrade.logged_query(
cr,
"UPDATE account_journal "
"SET receipts = true "
"WHERE corrispettivi = true",
)

if not openupgrade.is_module_installed(cr, "l10n_it_corrispettivi_sale"):
return

openupgrade.update_module_names(
cr,
[
("l10n_it_corrispettivi_sale", "account_receipt_sale"),
],
merge_modules=True,
)


def invert_receipt_refund_quantity(env):
"""Receipt Refunds are the same as normal Receipts
but with inverted Quantities."""
openupgrade.logged_query(
env.cr,
"UPDATE account_move_line l "
"SET quantity = -quantity "
"FROM account_move m "
"WHERE m.id = l.move_id "
"AND m.move_type IN ('out_receipt', 'in_receipt') "
"AND m.amount_total_signed < 0 "
"AND l.exclude_from_invoice_tab = false "
"AND (l.display_type NOT IN ('line_section', 'line_note') "
" OR display_type IS NULL) "
"AND l.quantity > 0",
)


def migrate_corrispettivi_data(cr, registry):
"""
Populate the new columns with data from corrispettivi modules.
"""
if openupgrade.column_exists(cr, "sale_order", "corrispettivi"):
openupgrade.logged_query(
cr,
"UPDATE sale_order " "SET receipts = true " "WHERE corrispettivi = true",
)

if openupgrade.column_exists(cr, "account_fiscal_position", "corrispettivi"):
openupgrade.logged_query(
cr,
"UPDATE account_fiscal_position "
"SET receipts = true "
"WHERE corrispettivi = true",
)

if openupgrade.column_exists(cr, "res_partner", "use_corrispettivi"):
openupgrade.logged_query(
cr,
"UPDATE res_partner "
"SET use_receipts = true "
"WHERE use_corrispettivi = true",
)

with api.Environment.manage():
env = api.Environment(cr, SUPERUSER_ID, {})
invert_receipt_refund_quantity(env)
35 changes: 35 additions & 0 deletions account_receipt_sale/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Copyright 2016-2022 Lorenzo Battistini
# Copyright 2018-2019 Simone Rubino
# Copyright 2019 Sergio Zanchetta (Associazione PNLUG - Gruppo Odoo)
# Copyright 2020 Giovanni Serra - GSLab.it
# Copyright 2023 Simone Rubino - TAKOBI
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
{
"name": "Receipts from sales",
"summary": "Generate receipts from sale orders",
"version": "14.0.1.0.1",
"development_status": "Beta",
"category": "Sales/Sales",
"website": "https://github.com/OCA/account-invoicing",
"author": "TAKOBI, Agile Business Group, Odoo Community Association (OCA)",
"maintainers": ["eLBati"],
"license": "AGPL-3",
"application": False,
"installable": True,
"preloadable": True,
"depends": [
"account_receipt_base",
"account_receipt_journal",
"sale",
],
"data": [
"views/sale_views.xml",
],
"pre_init_hook": "rename_old_italian_module",
"post_init_hook": "migrate_corrispettivi_data",
"external_dependencies": {
"python": [
"openupgradelib",
],
},
}
11 changes: 11 additions & 0 deletions account_receipt_sale/migrations/14.0.1.0.1/post-migrate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copyright 2023 Simone Rubino - TAKOBI
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from openupgradelib import openupgrade

from odoo.addons.account_receipt_sale import invert_receipt_refund_quantity


@openupgrade.migrate()
def migrate(env, version):
invert_receipt_refund_quantity(env)
1 change: 1 addition & 0 deletions account_receipt_sale/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import sale
172 changes: 172 additions & 0 deletions account_receipt_sale/models/sale.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
from odoo import api, fields, models


class SaleOrder(models.Model):
_inherit = "sale.order"
receipts = fields.Boolean()
receipt_ids = fields.Many2many(
comodel_name="account.move",
string="Receipts",
compute="_compute_receipt_ids",
readonly=True,
copy=False,
search="_search_receipt_ids",
)
receipt_count = fields.Integer(
string="Receipt Count",
compute="_compute_receipt_ids",
readonly=True,
)

@api.depends(
"order_line.invoice_lines",
)
def _compute_receipt_ids(self):
for order in self:
receipts = order.order_line.invoice_lines.move_id.filtered(
lambda r: r.move_type == "out_receipt"
)
order.receipt_ids = receipts
order.receipt_count = len(receipts)

def _search_receipt_ids(self, operator, value):
# Basically copied from _search_invoice_ids,
# just using out_receipt instead of out_invoice and out_refund
if operator == "in" and value:
self.env.cr.execute(
"""
SELECT array_agg(so.id)
FROM sale_order so
JOIN sale_order_line sol ON sol.order_id = so.id
JOIN sale_order_line_invoice_rel soli_rel ON soli_rel.order_line_id = sol.id
JOIN account_move_line aml ON aml.id = soli_rel.invoice_line_id
JOIN account_move am ON am.id = aml.move_id
WHERE
am.move_type = 'out_receipt' AND
am.id = ANY(%s)
""",
(list(value),),
)
so_ids = self.env.cr.fetchone()[0] or []
return [("id", "in", so_ids)]
elif operator == "=" and not value:
order_ids = self._search(
[
("order_line.invoice_lines.move_id.move_type", "=", "out_receipt"),
]
)
return [("id", "not in", order_ids)]
return [
"&",
("order_line.invoice_lines.move_id.move_type", "=", "out_receipt"),
("order_line.invoice_lines.move_id", operator, value),
]

def action_view_receipt(self):
# Basically the same as what happens in action_view_invoice
receipts = self.mapped("receipt_ids")
action = self.env["ir.actions.actions"]._for_xml_id(
"account.action_move_out_receipt_type"
)
if len(receipts) > 1:
action["domain"] = [("id", "in", receipts.ids)]
elif len(receipts) == 1:
form_view = [(self.env.ref("account.view_move_form").id, "form")]
if "views" in action:
action["views"] = form_view + [
(state, view) for state, view in action["views"] if view != "form"
]
else:
action["views"] = form_view
action["res_id"] = receipts.id
else:
action = {"type": "ir.actions.act_window_close"}

context = {
"default_move_type": "out_receipt",
}
if len(self) == 1:
context.update(
{
"default_partner_id": self.partner_id.id,
"default_partner_shipping_id": self.partner_shipping_id.id,
"default_invoice_payment_term_id": self.payment_term_id.id
or self.partner_id.property_payment_term_id.id
or self.env["account.move"]
.default_get(["invoice_payment_term_id"])
.get("invoice_payment_term_id"),
"default_invoice_origin": self.name,
"default_user_id": self.user_id.id,
}
)
action["context"] = context
return action

@api.onchange("partner_id")
def _onchange_partner_receipts_sale(self):
self.receipts = self.partner_id.use_receipts

@api.onchange("fiscal_position_id")
def _onchange_fiscal_position_id_receipts(self):
if self.fiscal_position_id:
self.receipts = self.fiscal_position_id.receipts

def _prepare_invoice(self):
invoice_values = super()._prepare_invoice()
if self.receipts:
invoice_values["move_type"] = "out_receipt"
self.env["account.move"]._update_receipts_journal([invoice_values])
return invoice_values

@api.model
def create(self, values):
order = super().create(values)
if "partner_id" in values and "receipts" not in values:
order._onchange_partner_receipts_sale()
if "fiscal_position_id" in values and "receipts" not in values:
order._onchange_fiscal_position_id_receipts()
return order

def write(self, values):
res = super().write(values)
if "partner_id" in values and "receipts" not in values:
for order in self:
order._onchange_partner_receipts_sale()
if "fiscal_position_id" in values and "receipts" not in values:
for order in self:
order._onchange_fiscal_position_id_receipts()
return res


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

def _compute_untaxed_amount_invoiced(self):
super()._compute_untaxed_amount_invoiced()
for line in self:
amount_receipt = 0.0
for invoice_line in line.invoice_lines:
if invoice_line.move_id.state == "posted":
invoice_date = (
invoice_line.move_id.invoice_date or fields.Date.today()
)
if invoice_line.move_id.move_type == "out_receipt":
amount_receipt += invoice_line.currency_id._convert(
invoice_line.price_subtotal,
line.currency_id,
line.company_id,
invoice_date,
)
line.untaxed_amount_invoiced += amount_receipt

def _get_invoice_qty(self):
super()._get_invoice_qty()
for line in self:
qty_receipt = 0.0
for invoice_line in line.invoice_lines:
if invoice_line.move_id.state != "cancel":
if invoice_line.move_id.move_type == "out_receipt":
qty_receipt += invoice_line.product_uom_id._compute_quantity(
invoice_line.quantity, line.product_uom
)
line.qty_invoiced += qty_receipt
2 changes: 2 additions & 0 deletions account_receipt_sale/readme/CONFIGURE.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Add your users to "Sale Receipt" group
- Go to Invoicing > Customers > Receipts
7 changes: 7 additions & 0 deletions account_receipt_sale/readme/CONTRIBUTORS.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
* Lorenzo Battistini
* Simone Rubino
* Sergio Zanchetta <https://github.com/primes2h>
* Giovanni Serra <[email protected]>
* `TAKOBI <https://takobi.online>`_:

* Simone Rubino <[email protected]>
1 change: 1 addition & 0 deletions account_receipt_sale/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Based on `account_receipt_journal`, this module allows to create receipts from sale orders.
1 change: 1 addition & 0 deletions account_receipt_sale/readme/HISTORY.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This module comes from modules `l10n_it_corrispettivi` and `l10n_it_corrispettivi_sale` of https://github.com/OCA/l10n-italy version 12.
1 change: 1 addition & 0 deletions account_receipt_sale/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import test_receipts
58 changes: 58 additions & 0 deletions account_receipt_sale/tests/test_receipts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2018 Simone Rubino
# Copyright 2022 Lorenzo Battistini
# Copyright 2023 Simone Rubino - TAKOBI
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo.tests import tagged

from odoo.addons.account_receipt_journal.tests.test_receipts import TestReceipts


@tagged("post_install", "-at_install")
class TestReceiptsSale(TestReceipts):
def setUp(self):
super(TestReceiptsSale, self).setUp()
partner_model = self.env["res.partner"]
self.fiscal_pos_model = self.env["account.fiscal.position"]
self.sale_model = self.env["sale.order"]
self.receipts_fiscal_position = self.fiscal_pos_model.create(
{
"name": "receipts fiscal position",
"receipts": True,
"company_id": self.env.user.company_id.id,
}
)
self.no_receipts_fiscal_position = self.fiscal_pos_model.create(
{
"name": "no receipts fiscal position",
"receipts": False,
"company_id": self.env.user.company_id.id,
}
)
self.no_receipts_partner = partner_model.create(
{
"name": "No receipts partner",
"use_receipts": False,
"property_account_position_id": self.no_receipts_fiscal_position.id,
}
)

def test_order_creation(self):
order_no_receipts = self.sale_model.create(
{
"partner_id": self.no_receipts_partner.id,
"fiscal_position_id": self.no_receipts_fiscal_position.id,
}
)
self.assertFalse(order_no_receipts.receipts)
order_receipts = self.sale_model.create(
{
"partner_id": self.no_receipts_partner.id,
"fiscal_position_id": self.receipts_fiscal_position.id,
}
)
self.assertTrue(order_receipts.receipts)

# testing write
order_no_receipts.fiscal_position_id = self.receipts_fiscal_position.id
self.assertTrue(order_no_receipts.receipts)
Loading

0 comments on commit 220570b

Please sign in to comment.