From aaba6b1a1ce0fb2f894b24cbbef8f52a4cca08a4 Mon Sep 17 00:00:00 2001 From: Borruso Date: Fri, 13 Sep 2024 12:13:53 +0200 Subject: [PATCH] [MIG] l10n_it_delivery_note: Migration to 18.0 --- l10n_it_delivery_note/__init__.py | 11 + l10n_it_delivery_note/__manifest__.py | 13 +- l10n_it_delivery_note/controllers/portal.py | 109 +-- .../data/delivery_note_data.xml | 55 ++ l10n_it_delivery_note/i18n/it.po | 16 - .../i18n/l10n_it_delivery_note.pot | 16 - .../migrations/14.0.3.0.0/post-migrate.py | 11 - l10n_it_delivery_note/models/__init__.py | 5 + l10n_it_delivery_note/models/res_company.py | 16 +- .../models/res_config_settings.py | 5 - .../models/stock_delivery_note.py | 55 +- .../models/stock_delivery_note_line.py | 2 +- .../models/stock_delivery_note_type.py | 209 ++++++ l10n_it_delivery_note/models/stock_picking.py | 14 - .../models/stock_picking_goods_appearance.py | 28 + .../stock_picking_transport_condition.py | 44 ++ .../models/stock_picking_transport_method.py | 28 + .../models/stock_picking_transport_reason.py | 28 + .../report/report_delivery_note.xml | 667 ++++++++---------- .../security/ir.model.access.csv | 41 +- .../security/ir_module_category.xml | 16 + l10n_it_delivery_note/security/ir_rule.xml | 8 + l10n_it_delivery_note/security/res_groups.xml | 11 +- l10n_it_delivery_note/security/res_users.xml | 24 +- l10n_it_delivery_note/static/src/img/DN.svg | 58 ++ .../src/js/stock_delivery_note_portal.js | 74 -- .../tests/delivery_note_common.py | 13 - .../tests/test_stock_delivery_note.py | 19 +- .../test_stock_delivery_note_invoicing.py | 111 ++- .../tests/test_stock_delivery_note_portal.py | 12 +- .../test_stock_delivery_note_sequence.py | 4 +- l10n_it_delivery_note/views/account_move.xml | 3 +- l10n_it_delivery_note/views/assets.xml | 26 - .../views/portal_my_delivery_notes.xml | 114 ++- .../views/portal_templates.xml | 22 +- .../views/res_config_settings.xml | 133 ++-- .../views/stock_delivery_note.xml | 219 +++--- .../views/stock_delivery_note_type.xml | 82 +++ l10n_it_delivery_note/views/stock_picking.xml | 156 ++-- .../views/stock_picking_goods_appearance.xml | 45 ++ .../stock_picking_transport_condition.xml | 56 ++ .../views/stock_picking_transport_method.xml | 45 ++ .../views/stock_picking_transport_reason.xml | 45 ++ .../wizard/delivery_note_create.py | 3 +- .../wizard/delivery_note_create.xml | 23 +- .../wizard/delivery_note_select.py | 3 +- .../wizard/delivery_note_select.xml | 32 +- .../wizard/sale_advance_payment_inv.xml | 24 +- 48 files changed, 1600 insertions(+), 1154 deletions(-) create mode 100644 l10n_it_delivery_note/data/delivery_note_data.xml delete mode 100644 l10n_it_delivery_note/migrations/14.0.3.0.0/post-migrate.py create mode 100644 l10n_it_delivery_note/models/stock_delivery_note_type.py create mode 100644 l10n_it_delivery_note/models/stock_picking_goods_appearance.py create mode 100644 l10n_it_delivery_note/models/stock_picking_transport_condition.py create mode 100644 l10n_it_delivery_note/models/stock_picking_transport_method.py create mode 100644 l10n_it_delivery_note/models/stock_picking_transport_reason.py create mode 100644 l10n_it_delivery_note/security/ir_module_category.xml create mode 100644 l10n_it_delivery_note/static/src/img/DN.svg delete mode 100644 l10n_it_delivery_note/static/src/js/stock_delivery_note_portal.js delete mode 100644 l10n_it_delivery_note/views/assets.xml create mode 100644 l10n_it_delivery_note/views/stock_delivery_note_type.xml create mode 100644 l10n_it_delivery_note/views/stock_picking_goods_appearance.xml create mode 100644 l10n_it_delivery_note/views/stock_picking_transport_condition.xml create mode 100644 l10n_it_delivery_note/views/stock_picking_transport_method.xml create mode 100644 l10n_it_delivery_note/views/stock_picking_transport_reason.xml diff --git a/l10n_it_delivery_note/__init__.py b/l10n_it_delivery_note/__init__.py index 0766bf98d4f0..c7907e2eed77 100644 --- a/l10n_it_delivery_note/__init__.py +++ b/l10n_it_delivery_note/__init__.py @@ -1,3 +1,14 @@ +# Copyright 2023 Nextev Srl + +def post_init_hook(env): + """ + Create DN types and their sequences after installing the module + if they're not already exist + """ + companies = env["res.company"].search([]) + for company in companies: + env["stock.delivery.note.type"].create_dn_types(company) + from . import controllers from . import mixins from . import models diff --git a/l10n_it_delivery_note/__manifest__.py b/l10n_it_delivery_note/__manifest__.py index c3b3d9f1807b..a0ad9b29a86a 100644 --- a/l10n_it_delivery_note/__manifest__.py +++ b/l10n_it_delivery_note/__manifest__.py @@ -13,29 +13,37 @@ "author": "Marco Calcagni, Gianmarco Conte, Link IT Europe Srl, " "Odoo Community Association (OCA)", "website": "https://github.com/OCA/l10n-italy", - "version": "16.0.1.4.5", + "version": "17.5.1.0.0", "category": "Localization/Italy", "license": "AGPL-3", "maintainers": ["MarcoCalcagni", "aleuffre", "renda-dev"], "depends": [ "delivery_carrier_partner", - "l10n_it_delivery_note_base", "mail", + "sale", "sale_stock", "stock_account", + "stock_delivery", "portal", "product", ], "data": [ "security/ir.model.access.csv", + "security/ir_module_category.xml", "security/ir_rule.xml", "security/res_groups.xml", "security/res_users.xml", + "data/delivery_note_data.xml", "report/report_delivery_note.xml", "views/account_move.xml", "views/res_config_settings.xml", "views/res_partner.xml", "views/sale_order.xml", + "views/stock_delivery_note_type.xml", + "views/stock_picking_goods_appearance.xml", + "views/stock_picking_transport_condition.xml", + "views/stock_picking_transport_method.xml", + "views/stock_picking_transport_reason.xml", "views/stock_delivery_note.xml", "views/stock_picking.xml", "views/portal_templates.xml", @@ -56,4 +64,5 @@ "l10n_it_delivery_note/static/src/scss/stock_delivery_note.scss", ], }, + "post_init_hook": "post_init_hook", } diff --git a/l10n_it_delivery_note/controllers/portal.py b/l10n_it_delivery_note/controllers/portal.py index 33fdbb835acd..415a1f347022 100644 --- a/l10n_it_delivery_note/controllers/portal.py +++ b/l10n_it_delivery_note/controllers/portal.py @@ -1,16 +1,13 @@ from odoo import _ +from odoo.addons.portal.controllers.portal import CustomerPortal, pager as portal_pager from odoo.exceptions import AccessError, MissingError +from odoo.osv.expression import OR from odoo.http import request, route -from odoo.addons.portal.controllers.portal import CustomerPortal -from odoo.addons.portal.controllers.portal import pager as portal_pager - class DNCustomerPortal(CustomerPortal): - def _get_delivery_note_domain(self, search_in=False): + def _get_delivery_note_domain(self): domain = [("state", "in", ["confirm", "invoiced", "done"])] - if search_in: - domain += search_in return domain def _prepare_home_portal_values(self, counters): @@ -27,13 +24,18 @@ def _prepare_home_portal_values(self, counters): values["dn_count"] = dn_count return values - @route( - ["/my/delivery-notes", "/my/delivery-notes/page/"], - type="http", - auth="user", - website=True, - ) - def portal_my_delivery_notes( + def _get_delivery_notes_searchbar_sortings(self): + return { + "date": {"label": _("Delivery Note Date"), "order": "date desc"}, + "name": {"label": _("Delivery Note #"), "order": "name"}, + } + + def _get_delivery_notes_searchbar_inputs(self): + return { + "name": {"input": "name", "label": _("Search in Description")}, + } + + def _prepare_my_delivery_notes_values( self, page=1, date_begin=None, @@ -41,47 +43,49 @@ def portal_my_delivery_notes( sortby=None, search="", search_in="name", - **kw, + **kwargs, ): values = self._prepare_portal_layout_values() DeliveryNote = request.env["stock.delivery.note"] - searchbar_sortings = { - "date": {"label": _("Delivery Note Date"), "order": "date desc"}, - "name": {"label": _("Delivery Note #"), "order": "name"}, - } - searchbar_inputs = { - "name": { - "input": "name", - "label": _('Search Name'), - "domain": [("name", "ilike", search)], - }, - } + url = "/my/delivery-notes" + _items_per_page = 100 - search_domain = searchbar_inputs[search_in]["domain"] if search_in else [] # default sortby order if not sortby: sortby = "date" + + searchbar_sortings = self._get_delivery_notes_searchbar_sortings() + searchbar_inputs = self._get_delivery_notes_searchbar_inputs() + sort_order = searchbar_sortings[sortby]["order"] + domain = self._get_delivery_note_domain() - # count for pager - dn_count = DeliveryNote.search_count( - self._get_delivery_note_domain(search_domain) - ) - # make pager - pager = portal_pager( - url="/my/delivery-notes", - url_args={"sortby": sortby, "search_in": search_in, "search": "search"}, - total=dn_count, + if date_begin and date_end: + domain += [("date", ">", date_begin), ("date", "<=", date_end)] + + if search and search_in: + search_domain = [] + if search_in == "name": + search_domain = OR([search_domain, [("name", "ilike", search)]]) + domain += search_domain + + pager_values = portal_pager( + url=url, + total=DeliveryNote.search_count(domain), page=page, - step=self._items_per_page, + step=_items_per_page, + url_args={ + "date_begin": date_begin, + "date_end": date_end, + "sortby": sortby, + "search_in": search_in, + "search": search, + }, ) - # search the count to display, according to the pager data + delivery_note = DeliveryNote.search( - self._get_delivery_note_domain(search_domain), - order=sort_order, - limit=self._items_per_page, - offset=pager["offset"], + domain, order=sort_order, limit=_items_per_page, offset=pager_values["offset"] ) values.update( @@ -89,8 +93,8 @@ def portal_my_delivery_notes( "date": date_begin, "delivery_notes": delivery_note, "page_name": "delivery_notes", - "pager": pager, - "default_url": "/my/delivery-notes", + "default_url": url, + "pager": pager_values, "searchbar_sortings": searchbar_sortings, "searchbar_inputs": searchbar_inputs, "search_in": search_in, @@ -98,6 +102,17 @@ def portal_my_delivery_notes( "sortby": sortby, } ) + return values + + @route( + ["/my/delivery-notes", "/my/delivery-notes/page/"], + type="http", + auth="user", + website=True, + ) + def portal_my_delivery_notes(self, **kwargs): + values = self._prepare_my_delivery_notes_values(**kwargs) + request.session["my_delivery_notes_history"] = values["delivery_notes"].ids[:100] return request.render("l10n_it_delivery_note.portal_my_delivery_notes", values) def _dn_get_page_view_values(self, dn, access_token, **kwargs): @@ -111,11 +126,11 @@ def _dn_get_page_view_values(self, dn, access_token, **kwargs): @route(["/my/delivery-notes/"], type="http", auth="user", website=True) def portal_my_delivery_note_detail( - self, dn_id, access_token=None, report_type=None, download=False, **kw + self, dn_id, access_token=None, report_type=None, download=False, **kwargs ): try: delivery_note_sudo = self._document_check_access( - "stock.delivery.note", dn_id, access_token + "stock.delivery.note", dn_id, access_token=access_token ) except (AccessError, MissingError): return request.redirect("/my") @@ -128,6 +143,8 @@ def portal_my_delivery_note_detail( download=download, ) - values = self._dn_get_page_view_values(delivery_note_sudo, access_token, **kw) + values = self._dn_get_page_view_values( + delivery_note_sudo, access_token, **kwargs + ) return request.render("l10n_it_delivery_note.portal_delivery_note_page", values) diff --git a/l10n_it_delivery_note/data/delivery_note_data.xml b/l10n_it_delivery_note/data/delivery_note_data.xml new file mode 100644 index 000000000000..3cc92f6f5318 --- /dev/null +++ b/l10n_it_delivery_note/data/delivery_note_data.xml @@ -0,0 +1,55 @@ + + + + + + + Carriage paid + + + Carriage forward + + + Charged in invoice + + + + + Box + + + Pallet + + + Bulk + + + Box / Pallet + + + + + Sale + + + Goods on approval + + + Returned + + + + + Sender + + + Recipient + + + Carrier + + + diff --git a/l10n_it_delivery_note/i18n/it.po b/l10n_it_delivery_note/i18n/it.po index d5f3d71bd924..4ae949496e1b 100644 --- a/l10n_it_delivery_note/i18n/it.po +++ b/l10n_it_delivery_note/i18n/it.po @@ -579,11 +579,6 @@ msgstr "Selettore DdT" msgid "Delivery Note Types" msgstr "Tipi DdT" -#. module: l10n_it_delivery_note -#: model:ir.model.fields,field_description:l10n_it_delivery_note.field_stock_picking__delivery_note_visible -msgid "Delivery Note Visible" -msgstr "DdT visibile" - #. module: l10n_it_delivery_note #: model:ir.actions.act_window,name:l10n_it_delivery_note.stock_delivery_note_action #: model:ir.model.fields,field_description:l10n_it_delivery_note.field_account_bank_statement_line__delivery_note_ids @@ -1759,17 +1754,6 @@ msgstr "UdM" msgid "Update to now" msgstr "Aggiorna ad adesso" -#. module: l10n_it_delivery_note -#: model:ir.model.fields,field_description:l10n_it_delivery_note.field_stock_picking__use_advanced_behaviour -msgid "Use Advanced Behaviour" -msgstr "Usa funzioni avanzate" - -#. module: l10n_it_delivery_note -#: model:ir.model.fields,field_description:l10n_it_delivery_note.field_res_config_settings__group_use_advanced_delivery_notes -#: model:res.groups,name:l10n_it_delivery_note.use_advanced_delivery_notes -msgid "Use Advanced DN Features" -msgstr "Usa Funzioni Avanzate DdT" - #. module: l10n_it_delivery_note #: model:ir.model.fields,field_description:l10n_it_delivery_note.field_stock_picking__use_delivery_note msgid "Use Delivery Note" diff --git a/l10n_it_delivery_note/i18n/l10n_it_delivery_note.pot b/l10n_it_delivery_note/i18n/l10n_it_delivery_note.pot index 55fc01525e43..4949419a66bc 100644 --- a/l10n_it_delivery_note/i18n/l10n_it_delivery_note.pot +++ b/l10n_it_delivery_note/i18n/l10n_it_delivery_note.pot @@ -549,11 +549,6 @@ msgstr "" msgid "Delivery Note Types" msgstr "" -#. module: l10n_it_delivery_note -#: model:ir.model.fields,field_description:l10n_it_delivery_note.field_stock_picking__delivery_note_visible -msgid "Delivery Note Visible" -msgstr "" - #. module: l10n_it_delivery_note #: model:ir.actions.act_window,name:l10n_it_delivery_note.stock_delivery_note_action #: model:ir.model.fields,field_description:l10n_it_delivery_note.field_account_bank_statement_line__delivery_note_ids @@ -1682,17 +1677,6 @@ msgstr "" msgid "Update to now" msgstr "" -#. module: l10n_it_delivery_note -#: model:ir.model.fields,field_description:l10n_it_delivery_note.field_stock_picking__use_advanced_behaviour -msgid "Use Advanced Behaviour" -msgstr "" - -#. module: l10n_it_delivery_note -#: model:ir.model.fields,field_description:l10n_it_delivery_note.field_res_config_settings__group_use_advanced_delivery_notes -#: model:res.groups,name:l10n_it_delivery_note.use_advanced_delivery_notes -msgid "Use Advanced DN Features" -msgstr "" - #. module: l10n_it_delivery_note #: model:ir.model.fields,field_description:l10n_it_delivery_note.field_stock_picking__use_delivery_note msgid "Use Delivery Note" diff --git a/l10n_it_delivery_note/migrations/14.0.3.0.0/post-migrate.py b/l10n_it_delivery_note/migrations/14.0.3.0.0/post-migrate.py deleted file mode 100644 index a7890e8513bf..000000000000 --- a/l10n_it_delivery_note/migrations/14.0.3.0.0/post-migrate.py +++ /dev/null @@ -1,11 +0,0 @@ -from openupgradelib import openupgrade - - -@openupgrade.migrate() -def migrate(env, version): - note_ids = env["stock.delivery.note"].search( - [("carrier_id", "!=", False), ("delivery_method_id", "!=", False)] - ) - - for note_id in note_ids: - note_id.delivery_method_id.write({"partner_id": note_id.carrier_id.id}) diff --git a/l10n_it_delivery_note/models/__init__.py b/l10n_it_delivery_note/models/__init__.py index cf8ebbf5ee2d..f732bb1338e3 100644 --- a/l10n_it_delivery_note/models/__init__.py +++ b/l10n_it_delivery_note/models/__init__.py @@ -2,6 +2,11 @@ from . import account_invoice_line from . import res_company from . import res_config_settings +from . import stock_delivery_note_type +from . import stock_picking_goods_appearance +from . import stock_picking_transport_condition +from . import stock_picking_transport_method +from . import stock_picking_transport_reason from . import res_partner from . import sale_order from . import sale_order_line diff --git a/l10n_it_delivery_note/models/res_company.py b/l10n_it_delivery_note/models/res_company.py index 729bafa3f378..ec55b7355f89 100644 --- a/l10n_it_delivery_note/models/res_company.py +++ b/l10n_it_delivery_note/models/res_company.py @@ -1,4 +1,7 @@ -from odoo import fields, models +# Copyright (c) 2023, Nextev Srl +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, fields, models class ResCompany(models.Model): @@ -20,3 +23,14 @@ class ResCompany(models.Model): "Display Delivery Method in Delivery Note Report", default=False, ) + + @api.model_create_multi + def create(self, vals): + """ + Create DN types and their sequences after companies creation + if they're not already existing + """ + res = super().create(vals) + for company in res: + self.env["stock.delivery.note.type"].sudo().create_dn_types(company) + return res diff --git a/l10n_it_delivery_note/models/res_config_settings.py b/l10n_it_delivery_note/models/res_config_settings.py index 7e953ba0d368..f7df6fed79e6 100644 --- a/l10n_it_delivery_note/models/res_config_settings.py +++ b/l10n_it_delivery_note/models/res_config_settings.py @@ -12,11 +12,6 @@ def _default_virtual_locations_root(self): "stock.stock_location_locations_virtual", raise_if_not_found=False ) - group_use_advanced_delivery_notes = fields.Boolean( - string="Use Advanced DN Features", - implied_group="l10n_it_delivery_note.use_advanced_delivery_notes", - ) - group_required_partner_ref = fields.Boolean( string="Make Partner Ref. in DN Mandatory", implied_group="l10n_it_delivery_note.group_required_partner_ref", diff --git a/l10n_it_delivery_note/models/stock_delivery_note.py b/l10n_it_delivery_note/models/stock_delivery_note.py index eade81493a06..9698ad2f98b0 100644 --- a/l10n_it_delivery_note/models/stock_delivery_note.py +++ b/l10n_it_delivery_note/models/stock_delivery_note.py @@ -27,9 +27,6 @@ LINE_DISPLAY_TYPES = [("line_section", "Section"), ("line_note", "Note")] DOMAIN_LINE_DISPLAY_TYPES = [t[0] for t in LINE_DISPLAY_TYPES] -DRAFT_EDITABLE_STATE = {"draft": [("readonly", False)]} -DONE_READONLY_STATE = {"done": [("readonly", True)]} - INVOICE_STATUSES = [ ("no", "Nothing to invoice"), ("to invoice", "To invoice"), @@ -94,7 +91,6 @@ def _domain_weight_uom(self): string="Partner reference", index=True, copy=False, - states=DONE_READONLY_STATE, tracking=True, ) @@ -109,7 +105,6 @@ def _domain_weight_uom(self): partner_sender_id = fields.Many2one( "res.partner", string="Sender", - states=DRAFT_EDITABLE_STATE, default=_default_company, readonly=True, required=True, @@ -120,7 +115,6 @@ def _domain_weight_uom(self): partner_id = fields.Many2one( "res.partner", string="Recipient", - states=DRAFT_EDITABLE_STATE, readonly=True, required=True, index=True, @@ -130,7 +124,6 @@ def _domain_weight_uom(self): partner_shipping_id = fields.Many2one( "res.partner", string="Shipping address", - states=DONE_READONLY_STATE, required=True, tracking=True, domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", @@ -139,22 +132,19 @@ def _domain_weight_uom(self): carrier_id = fields.Many2one( "res.partner", string="Carrier", - states=DONE_READONLY_STATE, tracking=True, ) delivery_method_id = fields.Many2one( "delivery.carrier", string="Delivery method", - states=DONE_READONLY_STATE, tracking=True, ) - date = fields.Date(states=DRAFT_EDITABLE_STATE, copy=False) + date = fields.Date(copy=False) type_id = fields.Many2one( "stock.delivery.note.type", string="Type", default=_default_type, - states=DRAFT_EDITABLE_STATE, readonly=True, required=True, index=True, @@ -165,69 +155,58 @@ def _domain_weight_uom(self): type_code = fields.Selection( string="Type of Operation", related="type_id.code", store=True ) - packages = fields.Integer(states=DONE_READONLY_STATE) - volume = fields.Float(states=DONE_READONLY_STATE) + packages = fields.Integer() + volume = fields.Float() volume_uom_id = fields.Many2one( "uom.uom", string="Volume UoM", default=_default_volume_uom, domain=_domain_volume_uom, - states=DONE_READONLY_STATE, ) gross_weight = fields.Float( string="Gross weight", store=True, readonly=False, compute="_compute_weights", - states=DONE_READONLY_STATE, ) gross_weight_uom_id = fields.Many2one( "uom.uom", string="Gross weight UoM", default=_default_weight_uom, domain=_domain_weight_uom, - states=DONE_READONLY_STATE, ) net_weight = fields.Float( string="Net weight", store=True, readonly=False, compute="_compute_weights", - states=DONE_READONLY_STATE, ) net_weight_uom_id = fields.Many2one( "uom.uom", string="Net weight UoM", default=_default_weight_uom, domain=_domain_weight_uom, - states=DONE_READONLY_STATE, ) transport_condition_id = fields.Many2one( "stock.picking.transport.condition", string="Condition of transport", - states=DONE_READONLY_STATE, ) goods_appearance_id = fields.Many2one( "stock.picking.goods.appearance", string="Appearance of goods", - states=DONE_READONLY_STATE, ) transport_reason_id = fields.Many2one( "stock.picking.transport.reason", string="Reason of transport", - states=DONE_READONLY_STATE, ) transport_method_id = fields.Many2one( "stock.picking.transport.method", string="Method of transport", - states=DONE_READONLY_STATE, ) - transport_datetime = fields.Datetime( - string="Transport date", states=DONE_READONLY_STATE - ) + transport_datetime = fields.Datetime(string="Transport date") line_ids = fields.One2many( "stock.delivery.note.line", "delivery_note_id", string="Lines" @@ -284,7 +263,7 @@ def _domain_weight_uom(self): print_prices = fields.Boolean( string="Show prices on printed DN", related="type_id.print_prices", store=True ) - note = fields.Html(string="Internal note", states=DONE_READONLY_STATE) + note = fields.Html(string="Internal note") can_change_number = fields.Boolean(compute="_compute_boolean_flags") show_product_information = fields.Boolean(compute="_compute_boolean_flags") @@ -299,22 +278,20 @@ def _domain_weight_uom(self): ] @api.depends("name", "partner_id", "partner_ref", "partner_id.display_name") - def name_get(self): - result = [] + def _compute_display_name(self): for note in self: if not note.name: - partner_name = note.partner_id.display_name - create_date = note.create_date.strftime(DATETIME_FORMAT) - name = f"{partner_name} - {create_date}" + name = f"{note.partner_id.display_name}" + if note.create_date: + create_date = note.create_date.strftime(DATETIME_FORMAT) + name += f" - {create_date}" else: name = note.name if note.partner_ref and note.type_code == "incoming": - name = f"{name} ({note.partner_ref})" - result.append((note.id, name)) - - return result + name += f" ({note.partner_ref})" + note.display_name = name @api.depends("state", "line_ids", "line_ids.invoice_status") def _compute_invoice_status(self): @@ -403,11 +380,11 @@ def _compute_sales(self): note.sales_transport_check = all([len(x) < 2 for x in [tc, ga, tr, tm]]) def _compute_boolean_flags(self): - can_change_number = self.user_has_groups( + can_change_number = self.env.user.has_group( "l10n_it_delivery_note.can_change_number" ) - show_product_information = self.user_has_groups( - "l10n_it_delivery_note_base.show_product_related_fields" + show_product_information = self.env.user.has_group( + "l10n_it_delivery_note.show_product_related_fields" ) for note in self: @@ -674,7 +651,7 @@ def _fix_quantities_to_invoice(self, lines, invoice_method): pickings_move_ids = self.mapped("picking_ids.move_ids") for line in pickings_lines.filtered(lambda line: len(line.move_ids) > 1): move_ids = line.move_ids & pickings_move_ids - qty_to_invoice = sum(move_ids.mapped("quantity_done")) + qty_to_invoice = sum(move_ids.mapped("quantity")) if qty_to_invoice < line.qty_to_invoice: cache[line] = line.fix_qty_to_invoice(qty_to_invoice) diff --git a/l10n_it_delivery_note/models/stock_delivery_note_line.py b/l10n_it_delivery_note/models/stock_delivery_note_line.py index 6809ab167346..715f72f0b6e9 100644 --- a/l10n_it_delivery_note/models/stock_delivery_note_line.py +++ b/l10n_it_delivery_note/models/stock_delivery_note_line.py @@ -141,7 +141,7 @@ def _prepare_detail_lines(self, moves): "move_id": move.id, "name": name, "product_id": move.product_id.id, - "product_qty": move.quantity_done, + "product_qty": move.quantity, "product_uom_id": move.product_uom.id, } diff --git a/l10n_it_delivery_note/models/stock_delivery_note_type.py b/l10n_it_delivery_note/models/stock_delivery_note_type.py new file mode 100644 index 000000000000..35f6db8876fa --- /dev/null +++ b/l10n_it_delivery_note/models/stock_delivery_note_type.py @@ -0,0 +1,209 @@ +# Copyright 2014-2019 Dinamiche Aziendali srl +# (http://www.dinamicheaziendali.it/) +# @author: Marco Calcagni +# @author: Gianmarco Conte +# @author: Giuseppe Borruso +# Copyright (c) 2020, Link IT Europe Srl +# @author: Matteo Bilotta +# Copyright (c) 2023, Nextev Srl +# @author: Nextev Srl +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import _, fields, models + +DELIVERY_NOTE_TYPE_CODES = [ + ("incoming", "Incoming"), + ("outgoing", "Outgoing"), + ("internal", "Internal"), +] +DOMAIN_DELIVERY_NOTE_TYPE_CODES = [s[0] for s in DELIVERY_NOTE_TYPE_CODES] + + +class StockDeliveryNoteType(models.Model): + _name = "stock.delivery.note.type" + _description = "Delivery Note Type" + _order = "sequence, name, id" + + active = fields.Boolean(default=True) + sequence = fields.Integer(index=True, default=10) + name = fields.Char(index=True, required=True, translate=True) + print_prices = fields.Boolean(string="Show prices on printed DN", default=False) + code = fields.Selection( + DELIVERY_NOTE_TYPE_CODES, + string="Type of Operation", + required=True, + default=DOMAIN_DELIVERY_NOTE_TYPE_CODES[1], + ) + + default_transport_condition_id = fields.Many2one( + "stock.picking.transport.condition", string="Condition of transport" + ) + default_goods_appearance_id = fields.Many2one( + "stock.picking.goods.appearance", string="Appearance of goods" + ) + default_transport_reason_id = fields.Many2one( + "stock.picking.transport.reason", string="Reason of transport" + ) + default_transport_method_id = fields.Many2one( + "stock.picking.transport.method", string="Method of transport" + ) + + transport_reason_inconsistency_ids = fields.Many2many( + "stock.picking.transport.reason", + string="Inconsistent reasons of transport", + ) + + sequence_id = fields.Many2one("ir.sequence", string="Numeration", required=True) + next_sequence_number = fields.Integer(related="sequence_id.number_next_actual") + company_id = fields.Many2one( + "res.company", string="Company", default=lambda self: self.env.company + ) + note = fields.Html(string="Internal note") + + _sql_constraints = [ + ( + "name_uniq", + "unique(name, company_id)", + "This delivery note type already exists!", + ) + ] + + def goto_sequence(self, **kwargs): + self.ensure_one() + + return { + "type": "ir.actions.act_window", + "res_model": "ir.sequence", + "res_id": self.sequence_id.id, + "views": [(False, "form")], + "view_mode": "form", + "target": "current", + **kwargs, + } + + def _get_dn_types_sequences_values(self, code, company_id): + """ + This method prepares values to create sequences + """ + res = {} + if code == "stock.delivery.note.din": + res = { + "name": _("Incoming DdT sequence"), + "code": f"stock.delivery.note.din.c{company_id.id}", + "prefix": f"DIN/C{company_id.id}/", + "implementation": "no_gap", + "padding": 5, + "company_id": company_id.id, + } + elif code == "stock.delivery.note.ddt": + res = { + "name": _("Outgoing DdT sequence"), + "code": f"stock.delivery.note.ddt.c{company_id.id}", + "prefix": f"DDT/C{company_id.id}/", + "implementation": "no_gap", + "padding": 5, + "company_id": company_id.id, + } + elif code == "stock.delivery.note.int": + res = { + "name": _("Internal DdT sequence"), + "code": f"stock.delivery.note.int.c{company_id.id}", + "prefix": f"INT/C{company_id.id}/", + "implementation": "no_gap", + "padding": 5, + "company_id": company_id.id, + } + return res + + def _check_existing_sequence_domain(self, code, company_id): + """ + This method sets domain to check if sequence already exists + """ + return [("code", "=", code), ("company_id", "=", company_id.id)] + + def _get_or_create_sequence(self, code, company_id): + """ + This method gets sequence id or creates a new one if it doesn't already exist + """ + sequence = self.env["ir.sequence"].search( + self._check_existing_sequence_domain(f"{code}.c{company_id.id}", company_id) + ) + if sequence: + return sequence.id + else: + return ( + self.env["ir.sequence"] + .create(self._get_dn_types_sequences_values(code, company_id)) + .id + ) + + def _check_existing_dn_type_domain(self, name, company_id): + """ + This method sets domain to check if dn type already exists + """ + return [("name", "=", name), ("company_id", "=", company_id.id)] + + def _set_or_create_dn_types( + self, name, sequence_code, print_prices, code, company_id + ): + """ + This method creates dn types and relative sequences if they don't + already exist + """ + dn_type = self.env["stock.delivery.note.type"].search( + self._check_existing_dn_type_domain(name, company_id) + ) + if not dn_type: + sequence_id = self._get_or_create_sequence(sequence_code, company_id) + self.env["stock.delivery.note.type"].create( + { + "name": name, + "sequence_id": sequence_id, + "print_prices": print_prices, + "code": code, + "company_id": company_id.id, + } + ) + + def _prepare_dn_types_vals(self, company_id): + """ + This method sets values needed to search and create dn types + """ + self._set_or_create_dn_types( + _("Incoming"), + "stock.delivery.note.din", + False, + "incoming", + company_id, + ) + self._set_or_create_dn_types( + _("Outgoing"), + "stock.delivery.note.ddt", + False, + "outgoing", + company_id, + ) + self._set_or_create_dn_types( + _("Outgoing (with prices)"), + "stock.delivery.note.ddt", + True, + "outgoing", + company_id, + ) + self._set_or_create_dn_types( + _("Internal transfer"), + "stock.delivery.note.int", + False, + "internal", + company_id, + ) + + def create_dn_types(self, company_id): + """ + This method creates DN types for the company in the input parameters. + It first checks if they already exist, if not it will create them and + then they'll be linked to their relative sequences (they'll be created + too if they not already exist). + """ + lang = company_id.partner_id.lang + self.with_context(lang=lang)._prepare_dn_types_vals(company_id) diff --git a/l10n_it_delivery_note/models/stock_picking.py b/l10n_it_delivery_note/models/stock_picking.py index 98cbd31451aa..f792914a277c 100644 --- a/l10n_it_delivery_note/models/stock_picking.py +++ b/l10n_it_delivery_note/models/stock_picking.py @@ -93,11 +93,9 @@ class StockPicking(models.Model): carrier_partner_id = fields.Many2one("res.partner", related="carrier_id.partner_id") use_delivery_note = fields.Boolean(compute="_compute_boolean_flags") - use_advanced_behaviour = fields.Boolean(compute="_compute_boolean_flags") delivery_note_exists = fields.Boolean(compute="_compute_boolean_flags") delivery_note_draft = fields.Boolean(compute="_compute_boolean_flags") delivery_note_readonly = fields.Boolean(compute="_compute_boolean_flags") - delivery_note_visible = fields.Boolean(compute="_compute_boolean_flags") can_be_invoiced = fields.Boolean(compute="_compute_boolean_flags") @property @@ -118,18 +116,12 @@ def _delivery_note_fields(self): def _compute_boolean_flags(self): from_delivery_note = self.env.context.get("from_delivery_note") - use_advanced_behaviour = self.user_has_groups( - "l10n_it_delivery_note.use_advanced_delivery_notes" - ) for picking in self: picking.use_delivery_note = ( not from_delivery_note and picking.state == DONE_PICKING_STATE ) - picking.delivery_note_visible = use_advanced_behaviour - picking.use_advanced_behaviour = use_advanced_behaviour - picking.delivery_note_draft = False picking.delivery_note_readonly = True picking.delivery_note_exists = False @@ -305,12 +297,6 @@ def _check_delivery_note_consistency(self): ) def _must_create_delivery_note(self): - use_advanced_behaviour = self.user_has_groups( - "l10n_it_delivery_note.use_advanced_delivery_notes" - ) - if use_advanced_behaviour: - return False - type_code = list(set(self.mapped("picking_type_code")))[0] if type_code == DOMAIN_PICKING_TYPES[0]: return False diff --git a/l10n_it_delivery_note/models/stock_picking_goods_appearance.py b/l10n_it_delivery_note/models/stock_picking_goods_appearance.py new file mode 100644 index 000000000000..6f18512457d0 --- /dev/null +++ b/l10n_it_delivery_note/models/stock_picking_goods_appearance.py @@ -0,0 +1,28 @@ +# Copyright 2014-2019 Dinamiche Aziendali srl +# (http://www.dinamicheaziendali.it/) +# @author: Marco Calcagni +# @author: Gianmarco Conte +# @author: Giuseppe Borruso +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class StockPickingGoodsAppearance(models.Model): + _name = "stock.picking.goods.appearance" + _description = "Appearance of Goods" + _order = "sequence, name, id" + + active = fields.Boolean(default=True) + sequence = fields.Integer(index=True, default=10) + name = fields.Char( + string="Appearance name", + index=True, + required=True, + translate=True, + ) + note = fields.Html(string="Internal note") + + _sql_constraints = [ + ("name_uniq", "unique(name)", "This appearance of goods already exists!") + ] diff --git a/l10n_it_delivery_note/models/stock_picking_transport_condition.py b/l10n_it_delivery_note/models/stock_picking_transport_condition.py new file mode 100644 index 000000000000..5484f924cca2 --- /dev/null +++ b/l10n_it_delivery_note/models/stock_picking_transport_condition.py @@ -0,0 +1,44 @@ +# Copyright 2014-2019 Dinamiche Aziendali srl +# (http://www.dinamicheaziendali.it/) +# @author: Marco Calcagni +# @author: Gianmarco Conte +# @author: Giuseppe Borruso +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + +PRICES_TO_SHOW = [("unit", "Unit price"), ("total", "Total price"), ("none", "None")] +DOMAIN_PRICES_TO_SHOW = [p[0] for p in PRICES_TO_SHOW] + + +class StockPickingTransportCondition(models.Model): + _name = "stock.picking.transport.condition" + _description = "Condition of Transport" + _order = "sequence, name, id" + + active = fields.Boolean(default=True) + sequence = fields.Integer(index=True, default=10) + name = fields.Char( + string="Condition name", + index=True, + required=True, + translate=True, + ) + price_to_show = fields.Selection( + PRICES_TO_SHOW, + string="Price to show", + required=True, + default=DOMAIN_PRICES_TO_SHOW[0], + ) + + # + # TODO: Capire come dev'essere utilizzato questo campo. + # Deve influenzare il comportamento del campo "prezzo" + # solo ed esclusivamente nelle stampe del DdT? + # + + note = fields.Html(string="Internal note") + + _sql_constraints = [ + ("name_uniq", "unique(name)", "This condition of transport already exists!") + ] diff --git a/l10n_it_delivery_note/models/stock_picking_transport_method.py b/l10n_it_delivery_note/models/stock_picking_transport_method.py new file mode 100644 index 000000000000..fb7acae3c709 --- /dev/null +++ b/l10n_it_delivery_note/models/stock_picking_transport_method.py @@ -0,0 +1,28 @@ +# Copyright 2014-2019 Dinamiche Aziendali srl +# (http://www.dinamicheaziendali.it/) +# @author: Marco Calcagni +# @author: Gianmarco Conte +# @author: Giuseppe Borruso +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class StockPickingTransportMethod(models.Model): + _name = "stock.picking.transport.method" + _description = "Method of Transport" + _order = "sequence, name, id" + + active = fields.Boolean(default=True) + sequence = fields.Integer(index=True, default=10) + name = fields.Char( + string="Method name", + index=True, + required=True, + translate=True, + ) + note = fields.Html(string="Internal note") + + _sql_constraints = [ + ("name_uniq", "unique(name)", "This method of transport already exists!") + ] diff --git a/l10n_it_delivery_note/models/stock_picking_transport_reason.py b/l10n_it_delivery_note/models/stock_picking_transport_reason.py new file mode 100644 index 000000000000..d490a16515ae --- /dev/null +++ b/l10n_it_delivery_note/models/stock_picking_transport_reason.py @@ -0,0 +1,28 @@ +# Copyright 2014-2019 Dinamiche Aziendali srl +# (http://www.dinamicheaziendali.it/) +# @author: Marco Calcagni +# @author: Gianmarco Conte +# @author: Giuseppe Borruso +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class StockPickingTransportReason(models.Model): + _name = "stock.picking.transport.reason" + _description = "Reason of Transport" + _order = "sequence, name, id" + + active = fields.Boolean(default=True) + sequence = fields.Integer(index=True, default=10) + name = fields.Char( + string="Reason name", + index=True, + required=True, + translate=True, + ) + note = fields.Html(string="Internal note") + + _sql_constraints = [ + ("name_uniq", "unique(name)", "This reason of transport already exists!") + ] diff --git a/l10n_it_delivery_note/report/report_delivery_note.xml b/l10n_it_delivery_note/report/report_delivery_note.xml index f942498c8ffc..7ac2ed16854c 100644 --- a/l10n_it_delivery_note/report/report_delivery_note.xml +++ b/l10n_it_delivery_note/report/report_delivery_note.xml @@ -7,397 +7,348 @@ @@ -405,9 +356,10 @@