bemade-addons/batch_picking_create_one_bill/wizard/create_bill_wizard.py
Marc Durepos b43f0f5c85 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
2025-02-14 12:13:57 -05:00

155 lines
5.7 KiB
Python

# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
class CreateBillWizard(models.TransientModel):
_name = 'create.bill.wizard'
_description = 'Wizard pour créer une facture groupée'
batch_id = fields.Many2one(
'stock.picking.batch',
required=True,
string='Batch de transferts',
default=lambda self: self._context.get('default_batch_id')
)
purchase_order_ids = fields.Many2many(
'purchase.order',
string='Bons de commande',
compute='_compute_purchase_orders',
store=True
)
partner_id = fields.Many2one(
'res.partner',
string='Fournisseur',
compute='_compute_partner',
store=True
)
invoice_ids = fields.Many2many(
'account.move',
string='Factures temporaires',
compute='_compute_invoice_ids',
)
merged_invoice_id = fields.Many2one(
'account.move',
string='Facture fusionnée'
)
@api.depends('batch_id')
def _compute_purchase_orders(self):
for wizard in self:
wizard.purchase_order_ids = wizard.batch_id.picking_ids.move_ids.purchase_line_id.order_id
@api.depends('purchase_order_ids')
def _compute_partner(self):
for wizard in self:
partners = wizard.purchase_order_ids.mapped('partner_id')
if len(partners) > 1:
raise ValidationError(_('Les bons de commande doivent provenir du même fournisseur'))
wizard.partner_id = partners and partners[0] or False
@api.depends('purchase_order_ids')
def _compute_invoice_ids(self):
for wizard in self:
wizard.invoice_ids = self.env['account.move'].search([
('id', 'in', wizard.purchase_order_ids.mapped('invoice_ids').ids),
('state', '=', 'draft')
])
def _create_invoices_from_pos(self):
"""Crée les factures pour chaque PO en utilisant la méthode standard d'Odoo"""
created_invoices = self.env['account.move']
for po in self.purchase_order_ids:
# Vérifie si le PO a des quantités reçues non facturées
if not any(line.qty_received > line.qty_invoiced for line in po.order_line):
continue
# Crée la facture en utilisant la méthode standard
invoice = po.action_create_invoice()
if isinstance(invoice, dict):
invoice = self.env['account.move'].browse(invoice.get('res_id'))
created_invoices |= invoice
return created_invoices
def _merge_invoices(self, invoices):
"""Fusionne plusieurs factures en une seule"""
if not invoices:
return False
# Crée une nouvelle facture
merged_invoice = self.env['account.move'].create({
'move_type': 'in_invoice',
'partner_id': self.partner_id.id,
'invoice_date': fields.Date.context_today(self),
'invoice_origin': ', '.join(self.purchase_order_ids.mapped('name')),
})
# Regroupe les lignes par produit
product_lines = {}
for invoice in invoices:
for line in invoice.invoice_line_ids:
key = (line.product_id.id, line.price_unit, tuple(line.tax_ids.ids))
if key not in product_lines:
product_lines[key] = {
'product_id': line.product_id.id,
'name': line.name,
'quantity': 0,
'price_unit': line.price_unit,
'tax_ids': line.tax_ids.ids,
'purchase_line_ids': [],
}
product_lines[key]['quantity'] += line.quantity
if line.purchase_line_id:
product_lines[key]['purchase_line_ids'].append(line.purchase_line_id.id)
# Crée les lignes dans la facture fusionnée
for line_vals in product_lines.values():
# Prépare les valeurs pour la ligne de facture
invoice_line_vals = {
'move_id': merged_invoice.id,
'product_id': line_vals['product_id'],
'name': line_vals['name'],
'quantity': line_vals['quantity'],
'price_unit': line_vals['price_unit'],
'tax_ids': [(6, 0, line_vals['tax_ids'])],
}
self.env['account.move.line'].create(invoice_line_vals)
# Supprime les factures originales
invoices.unlink()
return merged_invoice
def action_create_bill(self):
self.ensure_one()
if not self.purchase_order_ids:
raise ValidationError(_('Aucun bon de commande trouvé dans ce batch'))
# Vérifie que tous les PO ont le même fournisseur
partners = self.purchase_order_ids.mapped('partner_id')
if len(partners) > 1:
raise ValidationError(_(
'Les bons de commande sélectionnés ont des fournisseurs différents:\n%s'
) % '\n'.join(['- ' + p.name for p in partners]))
# Crée les factures individuelles
invoices = self._create_invoices_from_pos()
if not invoices:
raise ValidationError(_('Aucune quantité à facturer trouvée dans les bons de commande'))
# Ouvre le wizard de fusion
return {
'name': _('Fusion des factures'),
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'merge.bill.wizard',
'target': 'new',
'context': {
'default_invoice_ids': [(6, 0, invoices.ids)],
'default_partner_id': self.partner_id.id,
}
}