Skip to content

Commit

Permalink
[IMP] sale_resource_booking (squashed)
Browse files Browse the repository at this point in the history
[IMP] sale_resource_booking: booking.product_id, Buttons (product variant -> booking -> sale order)

[FIX] sale_resource_booking: fix tests

[ADD] sale_resource_booking_product_variant

[IMP] sale_resource_booking_product_variant: documentation etc.

[FIX] sale_resource_booking_product_variant: search Booking Type

[FIX] sale_resource_booking_product_variant: text

[FIX] sale_resource_booking_product_variant: code is in sale_resource_booking

[IMP] sale_resource_booking: Types are connected with product variants. Set defaults on product.attribute form view.

[FIX] sale_resource_booking: many2one was missing comodel

[FIX] sale_resource_booking: migration

[IMP] sale_resource_booking: do not auto-assign combination if timeline is installed

[FIX] sale_resource_booking: pre-commit

[FIX] sale_resource_booking: a sale order may have multiple lines (sale_product_pack)

[IMP] sale_resource_booking: multiple order lines for one booking

[IMP] sale_resource_booking: when change type for booking, product gets selected when there is just one

[IMP] sale_resource_booking: raise UserError when trying to quote from booking with no product selected

sale_resource_booking: confirm sale order with bookings: show updated sale order

Return the sale order window action to show the correct status of the sale order

sale_resource_booking: add info to sale.order.line

A sale order line with a resource booking product and quantity == 1
will have correct resource_booking_id and its partner_id.

sale_resource_booking: tiny change to trigger tests

[FIX] sale_resource_booking: booking list changed partner_id to partner_ids

[FIX] sale_resource_booking: default_partner_ids (not default_partner_id)

[FIX] sale_resource_booking: Show the booking button Quote

[BUG] sale_resource_booking: create product.product

[FIX] sale_resource_booking: product inherit booking type from attribute value

[IMP] sale_resource_booking: Auto-assign booking type to product variant
  • Loading branch information
norlinhenrik committed Feb 2, 2025
1 parent 6b3f08e commit 15f912a
Show file tree
Hide file tree
Showing 21 changed files with 560 additions and 64 deletions.
27 changes: 17 additions & 10 deletions sale_resource_booking/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@
Sell resource bookings
======================

.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:53caa4a97c4e336c15b1653e5732251652d34b56672d215e7073a495495d52a3
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
Expand All @@ -14,16 +17,16 @@ Sell resource bookings
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--workflow-lightgray.png?logo=github
:target: https://github.com/OCA/sale-workflow/tree/15.0/sale_resource_booking
:target: https://github.com/OCA/sale-workflow/tree/16.0/sale_resource_booking
:alt: OCA/sale-workflow
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/sale-workflow-15-0/sale-workflow-15-0-sale_resource_booking
:target: https://translation.odoo-community.org/projects/sale-workflow-16-0/sale-workflow-16-0-sale_resource_booking
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png
:target: https://runbot.odoo-community.org/runbot/167/15.0
:alt: Try me on Runbot
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&target_branch=16.0
:alt: Try me on Runboat

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

This module extends the functionality of sale and resource bookings to support
creating pending resource bookings automatically when confirming a sale order
Expand Down Expand Up @@ -90,8 +93,8 @@ Bug Tracker

Bugs are tracked on `GitHub Issues <https://github.com/OCA/sale-workflow/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/sale-workflow/issues/new?body=module:%20sale_resource_booking%0Aversion:%2015.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/sale-workflow/issues/new?body=module:%20sale_resource_booking%0Aversion:%2016.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.

Expand All @@ -111,6 +114,10 @@ Contributors
* Jairo Llopis
* Stefan Ungureanu

* `Ows <https://www.ows.cloud>`_:

* Henrik Norlin

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

Expand All @@ -132,6 +139,6 @@ Current `maintainer <https://odoo-community.org/page/maintainer-role>`__:

|maintainer-Yajo|

This module is part of the `OCA/sale-workflow <https://github.com/OCA/sale-workflow/tree/15.0/sale_resource_booking>`_ project on GitHub.
This module is part of the `OCA/sale-workflow <https://github.com/OCA/sale-workflow/tree/16.0/sale_resource_booking>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
7 changes: 5 additions & 2 deletions sale_resource_booking/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

{
"name": "Sell resource bookings",
"name": "Sell Resource Bookings",
"summary": "Link resource bookings with sales",
"version": "16.0.1.0.0",
"version": "16.0.2.0.0",
"development_status": "Beta",
"category": "Appointments",
"website": "https://github.com/OCA/sale-workflow",
Expand All @@ -13,10 +13,13 @@
"license": "AGPL-3",
"depends": ["sale", "resource_booking", "web_ir_actions_act_multi"],
"data": [
"views/product_attribute_views.xml",
"views/product_product_views.xml",
"views/product_template_views.xml",
"views/resource_booking_type_views.xml",
"views/resource_booking_views.xml",
"views/sale_order_views.xml",
"views/menus.xml",
"wizards/resource_booking_sale_views.xml",
"wizards/sale_order_booking_confirm_views.xml",
"security/ir.model.access.csv",
Expand Down
47 changes: 47 additions & 0 deletions sale_resource_booking/migrations/16.0.2.0.0/pre-migration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from openupgradelib import openupgrade

xmlids_to_rename = [
(
"resource_booking_sale.resource_booking_type_form",
"resource_booking_sale.resource_booking_type_view_form",
),
(
"resource_booking_sale.resource_booking_form",
"resource_booking_sale.resource_booking_view_form",
),
]


def connect_resource_booking_type_with_product_variant(cr):
openupgrade.logged_query(
cr,
"""
ALTER TABLE product_product
ADD COLUMN resource_booking_type_id int4,
ADD COLUMN resource_booking_type_combination_rel_id int4;
""",
)
openupgrade.logged_query(
cr,
"""
UPDATE product_product p
SET
resource_booking_type_id = t.resource_booking_type_id,
resource_booking_type_combination_rel_id =
t.resource_booking_type_combination_rel_id
FROM product_template as t
WHERE p.product_tmpl_id = t.id
AND (t.resource_booking_type_id > 0
OR
t.resource_booking_type_combination_rel_id > 0
);
""",
)


@openupgrade.migrate(use_env=False)
def migrate(cr, version):

openupgrade.rename_xmlids(cr, xmlids_to_rename)

connect_resource_booking_type_with_product_variant(cr)
2 changes: 2 additions & 0 deletions sale_resource_booking/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from . import product_attribute_value
from . import product_product
from . import product_template
from . import resource_booking
from . import resource_booking_type
Expand Down
11 changes: 11 additions & 0 deletions sale_resource_booking/models/product_attribute_value.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from odoo import fields, models


class ProductAttributeValue(models.Model):
_inherit = "product.attribute.value"

resource_booking_type_ids = fields.Many2many(
comodel_name="resource.booking.type",
relation="resource_booking_type_product_attribute_value_rel",
readonly=True,
)
87 changes: 87 additions & 0 deletions sale_resource_booking/models/product_product.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import logging

from odoo import api, fields, models

_logger = logging.getLogger(__name__)


class ProductProduct(models.Model):
_inherit = "product.product"

def _default_resource_booking_type_id(self):
return self.product_tmpl_id.resource_booking_type_id

def _default_resource_booking_type_combination_rel_id(self):
return self.product_tmpl_id.resource_booking_type_combination_rel_id

def _compute_resource_booking_count(self):
for p in self:
p.resource_booking_count = len(p.resource_booking_ids)

Check warning on line 19 in sale_resource_booking/models/product_product.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/product_product.py#L19

Added line #L19 was not covered by tests

resource_booking_type_id = fields.Many2one(
"resource.booking.type",
string="Booking type",
index=True,
ondelete="restrict",
help="If set, one pending booking will be generated when sold.",
default=lambda self: self._default_resource_booking_type_id(),
)
resource_booking_type_combination_rel_id = fields.Many2one(
"resource.booking.type.combination.rel",
string="Resource combination",
index=True,
ondelete="restrict",
domain="[('type_id', '=', resource_booking_type_id)]",
help=(
"If set, the booking will be created with this resource combination. "
"Otherwise, the combination will be assigned automatically later, "
"when the requester schedules the booking."
),
default=lambda self: self._default_resource_booking_type_combination_rel_id(),
)
resource_booking_count = fields.Integer(
compute="_compute_resource_booking_count",
string="Booking Count",
)
resource_booking_ids = fields.One2many(
"resource.booking",
"product_id",
string="Bookings",
)

def action_view_resource_booking(self):
self.ensure_one()
action = self.env["ir.actions.actions"]._for_xml_id(

Check warning on line 54 in sale_resource_booking/models/product_product.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/product_product.py#L53-L54

Added lines #L53 - L54 were not covered by tests
"resource_booking.resource_booking_action"
)
installed_timeline = self._is_module_installed("resource_booking_timeline")
action["context"] = {

Check warning on line 58 in sale_resource_booking/models/product_product.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/product_product.py#L57-L58

Added lines #L57 - L58 were not covered by tests
"default_combination_auto_assign": False if installed_timeline else True,
"default_product_id": self.id,
"default_type_id": self.resource_booking_type_id.id,
}
# depends on partner_product_price
if "partner_id" in self._fields:
action["context"]["default_partner_ids"] = [self.partner_id.id]
return action

Check warning on line 66 in sale_resource_booking/models/product_product.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/product_product.py#L65-L66

Added lines #L65 - L66 were not covered by tests

@api.constrains("product_template_attribute_value_ids")
def _set_resource_booking_type_id(self):
for product in self:
# Booking Type
v = product.product_template_attribute_value_ids.product_attribute_value_id
if v:
booking_type = (
self.env["resource.booking.type"]
.search([("product_attribute_value_ids", "in", v.ids)])
.filtered(
lambda t: len(t.product_attribute_value_ids) == len(v.ids)
and set(t.product_attribute_value_ids.ids) == set(v.ids)
)
)
if booking_type and len(booking_type) == 1:
product.resource_booking_type_id = booking_type.id

def _is_module_installed(self, module_name):
module = self.env["ir.module.module"].search([("name", "=", module_name)])
return True if module and module.state == "installed" else False

Check warning on line 87 in sale_resource_booking/models/product_product.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/product_product.py#L86-L87

Added lines #L86 - L87 were not covered by tests
50 changes: 34 additions & 16 deletions sale_resource_booking/models/product_template.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,46 @@
# Copyright 2021 Tecnativa - Jairo Llopis
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
import logging

from odoo import fields, models
from odoo import api, fields, models

_logger = logging.getLogger(__name__)


class ProductTemplate(models.Model):
_inherit = "product.template"

@api.depends(
"product_variant_ids.resource_booking_type_id",
"product_variant_ids.resource_booking_type_combination_rel_id",
)
def _compute_resource_booking_type_and_combination_rel(self):
for tmpl in self:
_type = {v.resource_booking_type_id.id for v in tmpl.product_variant_ids}
combination = {

Check warning on line 18 in sale_resource_booking/models/product_template.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/product_template.py#L17-L18

Added lines #L17 - L18 were not covered by tests
v.resource_booking_type_combination_rel_id.id
for v in tmpl.product_variant_ids
}
tmpl.resource_booking_type_id = _type.pop() if len(_type) == 1 else None
tmpl.resource_booking_type_combination_rel_id = (

Check warning on line 23 in sale_resource_booking/models/product_template.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/product_template.py#L22-L23

Added lines #L22 - L23 were not covered by tests
combination.pop() if len(combination) == 1 else None
)

def _inverse_resource_booking_type_and_combination_rel(self):
for tmpl in self:
variants = tmpl.product_variant_ids
variants.resource_booking_type_id = tmpl.resource_booking_type_id
variants.resource_booking_type_combination_rel_id = (

Check warning on line 31 in sale_resource_booking/models/product_template.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/product_template.py#L29-L31

Added lines #L29 - L31 were not covered by tests
tmpl.resource_booking_type_combination_rel_id
)

resource_booking_type_id = fields.Many2one(
"resource.booking.type",
string="Booking type",
index=True,
ondelete="restrict",
help="If set, one pending booking will be generated when sold.",
compute="_compute_resource_booking_type_and_combination_rel",
inverse="_inverse_resource_booking_type_and_combination_rel",
store=False,
)
resource_booking_type_combination_rel_id = fields.Many2one(
"resource.booking.type.combination.rel",
string="Resource combination",
index=True,
ondelete="restrict",
domain="[('type_id', '=', resource_booking_type_id)]",
help=(
"If set, the booking will be created with this resource combination. "
"Otherwise, the combination will be assigned automatically later, "
"when the requester schedules the booking."
),
compute="_compute_resource_booking_type_and_combination_rel",
inverse="_inverse_resource_booking_type_and_combination_rel",
store=False,
)
43 changes: 42 additions & 1 deletion sale_resource_booking/models/resource_booking.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
# Copyright 2021 Tecnativa - Jairo Llopis
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).

from odoo import api, fields, models
from odoo import _, api, fields, models
from odoo.exceptions import UserError
from odoo.tests.common import Form


class ResourceBooking(models.Model):
Expand All @@ -15,6 +17,11 @@ class ResourceBooking(models.Model):
ondelete="cascade",
tracking=True,
)
sale_order_line_ids = fields.One2many(
"sale.order.line",
"resource_booking_id",
string="Sale order lines",
)
sale_order_id = fields.Many2one(
related="sale_order_line_id.order_id",
readonly=True,
Expand All @@ -29,6 +36,12 @@ class ResourceBooking(models.Model):
"the booking will not be able to become confirmed."
),
)
product_id = fields.Many2one(
"product.product",
string="Product",
context="{'default_resource_booking_type_id': type_id}",
domain="[('resource_booking_type_id', '=', type_id)]",
)

@api.depends(
"active", "meeting_id.attendee_ids.state", "sale_order_line_id.order_id.state"
Expand All @@ -50,3 +63,31 @@ def _compute_state(self):
# SO is not confirmed; neither is booking
one.state = "scheduled"
return result

@api.onchange("type_id")
def _onchange_type_id(self):
products = self.type_id.product_ids

Check warning on line 69 in sale_resource_booking/models/resource_booking.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/resource_booking.py#L69

Added line #L69 was not covered by tests
if len(products) == 1:
self.product_id = products

Check warning on line 71 in sale_resource_booking/models/resource_booking.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/resource_booking.py#L71

Added line #L71 was not covered by tests

def action_generate(self):
# Based on resource.booking.sale wizard
self.ensure_one()

Check warning on line 75 in sale_resource_booking/models/resource_booking.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/resource_booking.py#L75

Added line #L75 was not covered by tests
if not self.product_id:
raise UserError(_("You must select a product to create a sale order."))
so_form = Form(self.env["sale.order"])
so_form.partner_id = self.partner_id
with so_form.order_line.new() as sol_form:
sol_form.product_id = self.product_id
so = so_form.save() # create sale order and line(s)
self.sale_order_line_id = so.order_line.filtered(

Check warning on line 83 in sale_resource_booking/models/resource_booking.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/resource_booking.py#L77-L83

Added lines #L77 - L83 were not covered by tests
lambda l: l.product_id == self.product_id
).id
return {

Check warning on line 86 in sale_resource_booking/models/resource_booking.py

View check run for this annotation

Codecov / codecov/patch

sale_resource_booking/models/resource_booking.py#L86

Added line #L86 was not covered by tests
"res_id": so.id,
"res_model": "sale.order",
"target": "current",
"type": "ir.actions.act_window",
"view_mode": "form",
"views": [[False, "form"]],
}
Loading

0 comments on commit 15f912a

Please sign in to comment.