Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions stock_declared_value/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,14 @@
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
<<<<<<< 4c2d8e0553fb75520dc5a125a13f8d661c9521d2:stock_declared_value/models/__init__.py
from . import stock_picking_type
from . import stock_picking
||||||| b4f6d46b75d9a99effc4c4a9ed21ed015f5a7e6e:stock_voucher_ux/__init__.py
from . import models
from . import controllers
=======
from . import models
from . import controllers
from . import wizards
>>>>>>> 6671bcb365b7c136015ab09f79ba08a0f23a8f75:stock_voucher_ux/__init__.py
104 changes: 104 additions & 0 deletions stock_voucher_ux/models/stock_picking.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<<<<<<< HEAD
||||||| MERGE BASE
=======
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from odoo import _, api, fields, models
from odoo.exceptions import UserError


class StockPicking(models.Model):
_inherit = "stock.picking"

printed = fields.Boolean()

with_vouchers = fields.Boolean(
compute="_compute_with_vouchers",
)

next_voucher_number = fields.Integer(
"Next Voucher Number",
related="book_id.sequence_id.number_next_actual",
)

autoprinted = fields.Boolean(
related="book_id.autoprinted",
)

@api.depends("voucher_ids")
def _compute_with_vouchers(self):
for rec in self:
rec.with_vouchers = bool(self.voucher_ids)

def do_print_voucher(self):
self.printed = True
if self.book_id:
self.book_id = self.book_id.id
return super(StockPicking, self).do_print_voucher()

def do_print_and_assign(self):
if not self.book_id and self.picking_type_code != "incoming":
raise UserError("Primero debe seleccionar un talonario")
if self.autoprinted == False:
# Talonario preimpreso: la cantidad de remitos debe coincidir con las
# páginas REALES del reporte. No pre-asignamos por la estimación
# ``lines_per_voucher`` (subnumera: p. ej. asigna 3 cuando el remito
# tiene 5 páginas). Imprimimos con ``assign=True`` para que el
# controller cuente las páginas renderizadas, asigne los números y
# re-renderice el PDF ya con los números puestos.
self.printed = True
return self.with_context(assign=True).do_print_voucher()
else:
if self.book_id.sequence_to and int(self.next_voucher_number) > int(self.book_id.sequence_to):
raise UserError(
_(
"The voucher number %s exceeds the range specified in the CAI. Please update the range or use a different CAI with a different range.",
self.next_voucher_number,
)
)
self.assign_numbers(1, self.book_id)
return self.do_print_voucher()

def button_validate(self):
# Imprime el remito al validar sólo si el tipo de operación lo pide
# (``auto_print_delivery_slip``). Autoimpreso: ya numerado en
# ``_action_done``, sólo imprime. Preimpreso: numera al imprimir por
# páginas reales (mismo camino que "Imprimir Remito").
res = super().button_validate()
if (
len(self) == 1
and self.state == "done"
and self.book_required
and self.book_id
and self.picking_type_id.auto_print_delivery_slip
):
if self.autoprinted:
return self.do_print_voucher()
return self.do_print_and_assign()
return res

def _action_done(self):
# Los talonarios preimpresos (``autoprinted=False``) se numeran al
# IMPRIMIR según las páginas reales del reporte, no en la validación por
# la estimación ``lines_per_voucher``. Los autoimpresos se numeran acá al
# validar, pero sólo si el tipo de operación pide imprimir el remito al
# validar (``auto_print_delivery_slip``) — el remito reemplaza al recibo
# de entrega nativo. Sin ese flag el número se asigna al IMPRIMIR a mano.
res = super(StockPicking, self.with_context(do_not_assign_numbers=True))._action_done()
if self._context.get("do_not_assign_numbers"):
return res
for picking in self.filtered(
lambda p: p.book_required
and p.book_id
and p.book_id.autoprinted
and p.picking_type_id.auto_print_delivery_slip
):
picking.assign_numbers(picking.get_estimated_number_of_pages(), picking.book_id)
return res

def clean_voucher_data(self):
return super(StockPicking, self).clean_voucher_data()

>>>>>>> FORWARD PORTED
131 changes: 131 additions & 0 deletions stock_voucher_ux/tests/test_remito_preimpreso.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<<<<<<< HEAD
||||||| MERGE BASE
=======
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from odoo.tests.common import TransactionCase


class TestRemitoPreimpresoNumbering(TransactionCase):
"""Numeración de remitos según el tipo de talonario.

Preimpreso (``autoprinted=False``): NO se numera en la validación por la
estimación ``lines_per_voucher`` (subnumera). La cantidad se determina al
imprimir, según las páginas reales del reporte (controller).

Autoimpreso (``autoprinted=True``): se numera en la validación sólo si el
tipo de operación pide imprimir el remito al validar
(``auto_print_delivery_slip``) — el remito reemplaza al recibo de entrega
nativo. Sin ese flag no se numera al validar (se asigna al imprimir a mano).
"""

@classmethod
def setUpClass(cls):
super().setUpClass()
cls.sequence = cls.env["ir.sequence"].create(
{
"name": "Test stock voucher",
"code": "stock.voucher",
"prefix": "0001-",
"padding": 8,
"implementation": "no_gap",
}
)
cls.book_pre = cls.env["stock.book"].create(
{
"name": "Preimpreso test",
"sequence_id": cls.sequence.id,
"lines_per_voucher": 25,
"autoprinted": False,
}
)
cls.book_auto = cls.env["stock.book"].create(
{
"name": "Autoimpreso test",
"sequence_id": cls.sequence.id,
"lines_per_voucher": 0,
"autoprinted": True,
}
)
# Consumible no almacenable: la validación no requiere stock disponible.
cls.product = cls.env["product.product"].create(
{
"name": "Producto remito test",
"type": "consu",
}
)
cls.src = cls.env.ref("stock.stock_location_stock")
cls.dest = cls.env.ref("stock.stock_location_customers")

def _make_done_picking(self, book, auto_print=False):
picking_type = self.env.ref("stock.picking_type_out")
picking_type.write(
{
"book_required": True,
"book_id": book.id,
"voucher_required": False,
"auto_print_delivery_slip": auto_print,
}
)
picking = self.env["stock.picking"].create(
{
"picking_type_id": picking_type.id,
"location_id": self.src.id,
"location_dest_id": self.dest.id,
"book_id": book.id,
"move_ids": [
(
0,
0,
{
"name": self.product.name,
"product_id": self.product.id,
"product_uom_qty": 1.0,
"product_uom": self.product.uom_id.id,
"location_id": self.src.id,
"location_dest_id": self.dest.id,
},
)
],
}
)
picking.action_confirm()
for move in picking.move_ids:
move.quantity = move.product_uom_qty
picking.with_context(skip_sms=True).button_validate()
return picking

def test_preprinted_not_preassigned_on_validation(self):
picking = self._make_done_picking(self.book_pre)
self.assertEqual(picking.state, "done")
self.assertFalse(
picking.voucher_ids,
"Un talonario preimpreso no debe pre-numerarse por estimación en _action_done; "
"la numeración se hace al imprimir según páginas reales.",
)

def test_autoprinted_assigned_on_validation_with_flag(self):
# Con auto_print_delivery_slip el remito reemplaza al recibo de entrega
# y el autoimpreso se numera al validar.
picking = self._make_done_picking(self.book_auto, auto_print=True)
self.assertEqual(picking.state, "done")
self.assertEqual(
len(picking.voucher_ids),
1,
"Un talonario autoimpreso debe asignar un único remito en la validación "
"cuando el tipo de operación tiene auto_print_delivery_slip.",
)

def test_autoprinted_not_assigned_without_flag(self):
# Sin el flag, validar no numera: el número se asigna al imprimir a mano.
picking = self._make_done_picking(self.book_auto, auto_print=False)
self.assertEqual(picking.state, "done")
self.assertFalse(
picking.voucher_ids,
"Sin auto_print_delivery_slip, un talonario autoimpreso no debe numerarse "
"en la validación; el número se asigna al imprimir.",
)

>>>>>>> FORWARD PORTED
5 changes: 5 additions & 0 deletions stock_voucher_ux/wizards/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from . import stock_backorder_confirmation
24 changes: 24 additions & 0 deletions stock_voucher_ux/wizards/stock_backorder_confirmation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
##############################################################################
# For copyright and license notices, see __manifest__.py file in module root
# directory
##############################################################################
from odoo import models
from odoo.addons.stock_voucher.wizards.stock_backorder_confirmation import (
StockBackorderConfirmation as VoucherBackorderConfirmation,
)


class StockBackorderConfirmation(models.TransientModel):
_inherit = "stock.backorder.confirmation"

def process(self):
# En Odoo 18 el core re-ejecuta ``button_validate`` sobre los pickings al
# confirmar el backorder, y ese camino ya imprime el remito (respetando
# ``auto_print_delivery_slip`` y numerando el preimpreso con assign=True).
# Saltamos el override de ``stock_voucher``, que reimprimía con
# ``do_print_voucher`` sin assign (dejaba el preimpreso sin numerar) y
# devolvía una tupla que el cliente no ejecuta.
return super(VoucherBackorderConfirmation, self).process()

def process_cancel_backorder(self):
return super(VoucherBackorderConfirmation, self).process_cancel_backorder()
Loading