Initial commit: Odoo 18.0-20251222 extra-addons
This commit is contained in:
2
sale_manual_delivery/wizard/__init__.py
Executable file
2
sale_manual_delivery/wizard/__init__.py
Executable file
@@ -0,0 +1,2 @@
|
||||
from . import manual_delivery
|
||||
from . import manual_delivery_line
|
||||
91
sale_manual_delivery/wizard/manual_delivery.py
Executable file
91
sale_manual_delivery/wizard/manual_delivery.py
Executable file
@@ -0,0 +1,91 @@
|
||||
# Copyright 2017 Denis Leemann, Camptocamp SA
|
||||
# Copyright 2021 Iván Todorovich, Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class ManualDelivery(models.TransientModel):
|
||||
_name = "manual.delivery"
|
||||
_description = "Manual Delivery"
|
||||
_order = "create_date desc"
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
res = super().default_get(fields)
|
||||
# Get lines from active_model if it's a sale.order / sale.order.line
|
||||
sale_lines = self.env["sale.order.line"]
|
||||
active_model = self.env.context["active_model"]
|
||||
if active_model == "sale.order.line":
|
||||
sale_ids = self.env.context["active_ids"] or []
|
||||
sale_lines = self.env["sale.order.line"].browse(sale_ids)
|
||||
elif active_model == "sale.order":
|
||||
sale_ids = self.env.context["active_ids"] or []
|
||||
sale_lines = self.env["sale.order"].browse(sale_ids).mapped("order_line")
|
||||
if len(sale_lines.mapped("order_id.partner_id")) > 1:
|
||||
raise UserError(_("Please select one partner at a time"))
|
||||
if sale_lines:
|
||||
# Get partner from those lines
|
||||
partner = sale_lines.mapped("order_id.partner_id")
|
||||
res["partner_id"] = partner.id
|
||||
res["commercial_partner_id"] = partner.commercial_partner_id.id
|
||||
# Convert to manual.delivery.lines
|
||||
res["line_ids"] = [
|
||||
(
|
||||
0,
|
||||
0,
|
||||
{
|
||||
"order_line_id": line.id,
|
||||
"name": line.name,
|
||||
"product_id": line.product_id.id,
|
||||
"qty_ordered": line.product_uom_qty,
|
||||
"qty_procured": line.qty_procured,
|
||||
"quantity": line.qty_to_procure,
|
||||
},
|
||||
)
|
||||
for line in sale_lines
|
||||
if line.qty_to_procure and line.product_id.type != "service"
|
||||
]
|
||||
return res
|
||||
|
||||
commercial_partner_id = fields.Many2one(
|
||||
"res.partner",
|
||||
required=True,
|
||||
readonly=True,
|
||||
ondelete="cascade",
|
||||
)
|
||||
partner_id = fields.Many2one(
|
||||
"res.partner",
|
||||
string="Delivery Address",
|
||||
domain="['|',"
|
||||
"('id', '=', commercial_partner_id),"
|
||||
"('parent_id', '=', commercial_partner_id)]",
|
||||
ondelete="cascade",
|
||||
)
|
||||
carrier_id = fields.Many2one(
|
||||
"delivery.carrier",
|
||||
string="Delivery Method",
|
||||
ondelete="cascade",
|
||||
)
|
||||
route_id = fields.Many2one(
|
||||
"stock.route",
|
||||
string="Use specific Route",
|
||||
domain=[("sale_selectable", "=", True)],
|
||||
ondelete="cascade",
|
||||
help="Leave it blank to use the same route that is in the sale line",
|
||||
)
|
||||
line_ids = fields.One2many(
|
||||
"manual.delivery.line",
|
||||
"manual_delivery_id",
|
||||
string="Lines to validate",
|
||||
)
|
||||
date_planned = fields.Datetime()
|
||||
|
||||
def confirm(self):
|
||||
"""Creates the manual procurements"""
|
||||
self.ensure_one()
|
||||
sale_order_lines = self.line_ids.mapped("order_line_id")
|
||||
sale_order_lines.with_context(
|
||||
sale_manual_delivery=self
|
||||
)._action_launch_stock_rule_manual()
|
||||
68
sale_manual_delivery/wizard/manual_delivery.xml
Executable file
68
sale_manual_delivery/wizard/manual_delivery.xml
Executable file
@@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id='manual_delivery_wizard_form' model='ir.ui.view'>
|
||||
<field name="name">manual.delivery.wizard.form</field>
|
||||
<field name="model">manual.delivery</field>
|
||||
<field name='arch' type='xml'>
|
||||
<form string="Create Manually Delivery" name="manual_procurment_form">
|
||||
<sheet>
|
||||
<group>
|
||||
<group>
|
||||
<field
|
||||
name="commercial_partner_id"
|
||||
invisible="1"
|
||||
force_save="1"
|
||||
/>
|
||||
<field name="partner_id" />
|
||||
<field name="date_planned" />
|
||||
</group>
|
||||
<group>
|
||||
<field name="carrier_id" />
|
||||
<field name="route_id" groups="stock.group_adv_location" />
|
||||
</group>
|
||||
</group>
|
||||
<field name='line_ids'>
|
||||
<list editable="bottom" create="0">
|
||||
<field
|
||||
name="order_line_id"
|
||||
column_invisible="1"
|
||||
force_save="1"
|
||||
/>
|
||||
<field name="product_id" />
|
||||
<field name="name" />
|
||||
<field name="qty_ordered" string="Ordered" />
|
||||
<field name="qty_procured" string="Procured" />
|
||||
<field name="quantity" />
|
||||
</list>
|
||||
</field>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button
|
||||
type="object"
|
||||
name="confirm"
|
||||
string="Confirm"
|
||||
class="btn-primary"
|
||||
/>
|
||||
<button string="Cancel" class="btn-default" special="cancel" />
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_wizard_manual_delivery" model="ir.actions.act_window">
|
||||
<field name="name">Create Manual Delivery</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">manual.delivery</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="binding_model_id" ref="sale.model_sale_order" />
|
||||
</record>
|
||||
<record id="action_wizard_manual_delivery_line" model="ir.actions.act_window">
|
||||
<field name="name">Create Manual Delivery</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">manual.delivery</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="binding_model_id" ref="sale.model_sale_order_line" />
|
||||
</record>
|
||||
</odoo>
|
||||
56
sale_manual_delivery/wizard/manual_delivery_line.py
Executable file
56
sale_manual_delivery/wizard/manual_delivery_line.py
Executable file
@@ -0,0 +1,56 @@
|
||||
# Copyright 2017 Denis Leemann, Camptocamp SA
|
||||
# Copyright 2021 Iván Todorovich, Camptocamp SA
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.tools import float_compare
|
||||
|
||||
|
||||
class ManualDeliveryLine(models.TransientModel):
|
||||
_name = "manual.delivery.line"
|
||||
_description = "Manual Delivery Line"
|
||||
|
||||
manual_delivery_id = fields.Many2one(
|
||||
"manual.delivery",
|
||||
string="Wizard",
|
||||
ondelete="cascade",
|
||||
required=True,
|
||||
readonly=True,
|
||||
)
|
||||
order_line_id = fields.Many2one(
|
||||
"sale.order.line",
|
||||
string="Sale Order Line",
|
||||
required=True,
|
||||
readonly=True,
|
||||
ondelete="cascade",
|
||||
)
|
||||
product_id = fields.Many2one(related="order_line_id.product_id")
|
||||
name = fields.Text(related="order_line_id.name")
|
||||
qty_ordered = fields.Float(
|
||||
string="Ordered",
|
||||
related="order_line_id.product_uom_qty",
|
||||
help="Quantity ordered in the related Sale Order",
|
||||
readonly=True,
|
||||
)
|
||||
qty_procured = fields.Float(related="order_line_id.qty_procured")
|
||||
quantity = fields.Float()
|
||||
|
||||
@api.constrains("quantity")
|
||||
def _check_quantity(self):
|
||||
"""Prevent delivering more than the ordered quantity"""
|
||||
if any(
|
||||
float_compare(
|
||||
line.quantity,
|
||||
line.qty_ordered - line.qty_procured,
|
||||
precision_rounding=line.product_id.uom_id.rounding,
|
||||
)
|
||||
> 0.00
|
||||
for line in self
|
||||
):
|
||||
raise ValidationError(
|
||||
_(
|
||||
"You can not deliver more than the remaining quantity. "
|
||||
"If you need to do so, please edit the sale order first."
|
||||
)
|
||||
)
|
||||
Reference in New Issue
Block a user