batch_picking_create_one_bill upgrades

- Default to zero is now functional
- Checkbox ("Picked" field) visible on move lines in the batch view
- Checking the Picked field marks the line green
- More tests written to validate functionality
This commit is contained in:
Marc Durepos 2025-02-14 12:08:17 -05:00
parent cc66512df2
commit b43f0f5c85
12 changed files with 180 additions and 53 deletions

View file

@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-
from . import models
from . import wizards
from . import wizard

View file

@ -1,10 +1,10 @@
# -*- coding: utf-8 -*-
{
'name': 'Batch Picking - Create One Bill',
'version': '18.0.1.0.0',
'category': 'Inventory/Purchase',
'summary': 'Créer une seule facture fournisseur pour tous les bons de commande d\'un batch picking',
'description': """
"name": "Batch Picking - Create One Bill",
"version": "18.0.1.0.0",
"category": "Inventory/Purchase",
"summary": "Créer une seule facture fournisseur pour tous les bons de commande d'un batch picking",
"description": """
Ce module permet de générer une seule facture fournisseur pour tous les bons de commande
associés à un batch picking.
@ -14,23 +14,24 @@
- Validation que tous les bons de commande proviennent du même fournisseur
- Suivi des factures créées directement depuis le batch
""",
'author': 'Pneumac',
'website': 'https://www.pneumac.ca',
'depends': [
'stock_picking_batch',
'purchase',
'purchase_stock',
'account',
'account_reports',
"author": "Pneumac",
"website": "https://www.pneumac.ca",
"depends": [
"stock_picking_batch",
"purchase",
"purchase_stock",
"account",
"account_reports",
],
'data': [
'security/ir.model.access.csv',
'wizards/create_bill_wizard_views.xml',
'wizards/merge_bill_wizard_views.xml',
'views/stock_picking_batch_views.xml',
"data": [
"security/ir.model.access.csv",
"wizard/create_bill_wizard_views.xml",
"wizard/merge_bill_wizard_views.xml",
"wizard/stock_picking_to_batch_views.xml",
"views/stock_picking_batch_views.xml",
],
'installable': True,
'application': False,
'auto_install': False,
'license': 'LGPL-3',
"installable": True,
"application": False,
"auto_install": False,
"license": "LGPL-3",
}

View file

@ -2,61 +2,81 @@
from odoo import models, fields, api
from odoo.exceptions import ValidationError
class StockPickingBatch(models.Model):
_inherit = 'stock.picking.batch'
_inherit = "stock.picking.batch"
@api.model_create_multi
def create(self, vals_list):
# Handle zero_quantity_default from context if not explicitly set in vals
for vals in vals_list:
if (
"zero_quantity_default" not in vals
and self.env.context.get("default_zero_quantity_default") is not None
):
vals["zero_quantity_default"] = self.env.context.get(
"default_zero_quantity_default"
)
return super().create(vals_list)
zero_quantity_default = fields.Boolean(
string='Quantités à zéro par défaut',
string="Quantités à zéro par défaut",
default=True,
help='Initialiser les quantités à zéro lors de la création du batch'
help="Initialiser les quantités à zéro lors de la création du batch",
)
invoice_ids = fields.Many2many(
'account.move',
string='Factures associées',
compute='_compute_invoice_ids',
store=True
"account.move",
string="Factures associées",
compute="_compute_invoice_ids",
store=True,
)
invoice_count = fields.Integer(
string='Nombre de factures',
compute='_compute_invoice_count',
string="Nombre de factures",
compute="_compute_invoice_count",
store=True,
compute_sudo=True
compute_sudo=True,
)
def _prepare_move_line_vals(self, **kwargs):
vals = super()._prepare_move_line_vals(**kwargs)
if self.zero_quantity_default:
vals['quantity'] = 0.0
vals["quantity"] = 0.0
return vals
@api.depends('picking_ids.move_ids.purchase_line_id.order_id.invoice_ids')
@api.depends("picking_ids.move_ids.purchase_line_id.order_id.invoice_ids")
def _compute_invoice_ids(self):
for batch in self:
purchase_orders = batch.picking_ids.move_ids.purchase_line_id.order_id
batch.invoice_ids = purchase_orders.invoice_ids
@api.depends('invoice_ids')
@api.depends("invoice_ids")
def _compute_invoice_count(self):
for batch in self:
batch.invoice_count = len(batch.invoice_ids)
def action_view_invoices(self):
self.ensure_one()
action = self.env['ir.actions.act_window']._for_xml_id(
'account.action_move_in_invoice_type'
action = self.env["ir.actions.act_window"]._for_xml_id(
"account.action_move_in_invoice_type"
)
if self.invoice_count == 1:
action['views'] = [(False, 'form')]
action['res_id'] = self.invoice_ids.id
action["views"] = [(False, "form")]
action["res_id"] = self.invoice_ids.id
else:
action['domain'] = [('id', 'in', self.invoice_ids.ids)]
action["domain"] = [("id", "in", self.invoice_ids.ids)]
return action
@api.constrains('picking_ids')
@api.constrains("picking_ids")
def _check_purchase_orders(self):
for batch in self:
partners = batch.picking_ids.purchase_id.partner_id
if len(partners) > 1:
raise ValidationError(
'Tous les bons de commande du batch doivent provenir du même fournisseur.'
"Tous les bons de commande du batch doivent provenir du même fournisseur."
)
def action_confirm(self):
"""Override to set zero quantity on move lines at confirmation of the batch"""
res = super().action_confirm()
self.filtered("zero_quantity_default").move_line_ids.write({"quantity": 0})
return res

View file

@ -251,3 +251,68 @@ class TestBatchPickingBill(TransactionCase):
],
}
)
def test_zero_quantity_default_from_wizard(self):
"""Test that zero_quantity_default is properly set when creating a batch from wizard"""
# Switch to warehouse user like in the parent test
self.env = self.env(user=self.warehouse_user)
pickings = (self.po1 + self.po2).picking_ids
self.assertTrue(pickings, "Purchase orders should have created pickings")
# Create batch through wizard
wizard = (
self.env["stock.picking.to.batch"]
.with_context(active_ids=pickings.ids, active_model="stock.picking")
.create(
{
"mode": "new",
"zero_quantity_default": True,
}
)
)
result = wizard.attach_pickings()
batch = self.env["stock.picking.batch"].browse(result["res_id"])
# Check that zero_quantity_default was properly set on the batch
self.assertTrue(
batch.zero_quantity_default,
"zero_quantity_default should be True on the created batch",
)
# Check that all move lines have quantity 0
for move_line in batch.move_line_ids:
self.assertEqual(
move_line.quantity,
0.0,
f"Move line for {move_line.product_id.name} should have quantity 0",
)
def test_zero_quantity_default_from_picking(self):
"""Test that zero_quantity_default works when adding picking to existing batch"""
# Switch to warehouse user like in the parent test
self.env = self.env(user=self.warehouse_user)
pickings = (self.po1 + self.po2).picking_ids
# Create batch directly
batch = self.env["stock.picking.batch"].create(
{
"zero_quantity_default": True,
}
)
# Add pickings to batch
pickings.write({"batch_id": batch.id})
# Confirm the batch to get the move lines set up
batch.action_confirm()
# Check that all move lines have quantity 0
for move_line in batch.move_line_ids:
self.assertEqual(
move_line.quantity,
0.0,
f"Move line for {move_line.product_id.name} should have quantity 0",
)

View file

@ -7,18 +7,10 @@
<field name="arch" type="xml">
<xpath expr="//header" position="inside">
<field name="id" invisible="1"/>
<button name="%(batch_picking_create_one_bill.action_create_batch_bill_wizard)d"
string="Créer Facture"
type="action"
class="btn-primary"
context="{'default_batch_id': id}"
invisible="state != 'done'"/>
<button name="%(batch_picking_create_one_bill.action_create_batch_bill_wizard)d" string="Créer Facture" type="action" class="btn-primary" context="{'default_batch_id': id}" invisible="state != 'done'"/>
</xpath>
<xpath expr="//div[@name='button_box']" position="inside">
<button class="oe_stat_button"
name="action_view_invoices"
type="object"
icon="fa-pencil-square-o">
<button class="oe_stat_button" name="action_view_invoices" type="object" icon="fa-pencil-square-o">
<field name="invoice_count" widget="statinfo" string="Factures"/>
</button>
</xpath>
@ -27,4 +19,19 @@
</xpath>
</field>
</record>
<!-- Inherit the move line tree view to add the Picked field -->
<record id="view_move_line_tree_inherit" model="ir.ui.view">
<field name="name">stock.move.line.tree.picked.inherit</field>
<field name="model">stock.move.line</field>
<field name="inherit_id" ref="stock_picking_batch.view_move_line_tree"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='tracking']" position="before">
<field name="picked" optional="show"/>
</xpath>
<xpath expr="//list" position="attributes">
<attribute name="decoration-success">picked</attribute>
</xpath>
</field>
</record>
</odoo>

View file

@ -1,3 +1,4 @@
# -*- coding: utf-8 -*-
from . import create_bill_wizard
from . import merge_bill_wizard
from . import stock_picking_to_batch

View file

@ -0,0 +1,20 @@
from odoo import _, fields, models
from odoo.exceptions import UserError
class StockPickingToBatch(models.TransientModel):
_inherit = "stock.picking.to.batch"
zero_quantity_default = fields.Boolean(
string="Zero Quantity by Default",
default=False,
help="If checked, the default quantity for new move lines will be 0 instead of the computed quantity.",
)
def attach_pickings(self):
self.ensure_one()
# Pass zero_quantity_default through context to be handled in batch create
return super(
StockPickingToBatch,
self.with_context(default_zero_quantity_default=self.zero_quantity_default),
).attach_pickings()

View file

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="stock_picking_to_batch_form_inherit" model="ir.ui.view">
<field name="name">stock.picking.to.batch.form.inherit</field>
<field name="model">stock.picking.to.batch</field>
<field name="inherit_id" ref="stock_picking_batch.stock_picking_to_batch_form"/>
<field name="arch" type="xml">
<field name="is_create_draft" position="after">
<field name="zero_quantity_default" invisible="mode != 'new'"/>
</field>
</field>
</record>
</odoo>