', 1)[-1]
+ for banned in ('class="row', 'class="col-', 'class="card'):
+ self.assertNotIn(
+ banned,
+ body,
+ f'{banned}" reintroduced into the waybill; it will stack in the PDF',
+ )
+
+ # ------------------------------------------------------------------
+ # content that had to go
+ # ------------------------------------------------------------------
+
+ def test_total_items_footer_is_gone(self):
+ """It counted move lines, not quantity — 1 for a 200-unit consignment."""
+ _request, picking = self._dispatch()
+ self.assertNotIn("Total Items", self._render(picking))
+
+ def test_picking_note_is_not_printed(self):
+ _request, picking = self._dispatch()
+ self.assertNotIn("NOTE_MUST_NOT_APPEAR", self._render(picking))
+
+ # ------------------------------------------------------------------
+ # content that had to change
+ # ------------------------------------------------------------------
+
+ def test_shipped_quantity_is_shown_alongside_demand(self):
+ """The waybill accompanies the goods, so it must state what is on board."""
+ _request, picking = self._dispatch(requested=200, shipped=180)
+ html = self._render(picking)
+
+ self.assertIn("Shipped", html)
+ self.assertIn("Demand", html)
+ self.assertIn("180.00", html, "picked quantity missing from the waybill")
+ self.assertIn("200.00", html, "demand should remain for reconciliation")
+
+ def test_destination_falls_back_to_the_location(self):
+ """partner_id is normally blank on a dispatch, which left TO empty."""
+ _request, picking = self._dispatch()
+ self.assertFalse(picking.partner_id, "precondition: no delivery address is set")
+
+ html = self._render(picking)
+
+ self.assertIn("TO (Destination)", html)
+ self.assertIn("Waybill Destination WH", html)
+ self.assertIn(picking.location_dest_id.complete_name, html)
+
+ def test_distribution_details_are_printed(self):
+ _request, picking = self._dispatch()
+ html = self._render(picking)
+
+ self.assertIn("Distribution Area", html)
+ self.assertIn(self.area.name, html)
+ self.assertIn("320", html, "estimated beneficiaries missing")
+ self.assertIn("Distribution Type", html)
+
+ def test_transaction_type_is_printed(self):
+ """One template serves dispatches and donation receipts; say which."""
+ _request, picking = self._dispatch()
+ self.assertIn(picking.drims_type_id.display, self._render(picking))
+
+ def test_vehicle_and_driver_rows_survive_being_empty(self):
+ """They are labels to write on, so the row must print regardless."""
+ _request, picking = self._dispatch()
+ picking.write({"vehicle_registration": False, "driver_name": False})
+
+ html = self._render(picking)
+
+ self.assertIn("Vehicle:", html)
+ self.assertIn("Driver:", html)
+
+ def test_request_row_shown_and_donation_row_hidden_for_a_dispatch(self):
+ """Only the one that applies to this transaction type."""
+ _request, picking = self._dispatch()
+ html = self._render(picking)
+
+ self.assertIn("Request:", html)
+ self.assertNotIn("Donation:", html)
+
+ # ------------------------------------------------------------------
+ # barcode
+ # ------------------------------------------------------------------
+
+ def test_barcode_is_embedded_not_fetched(self):
+ """Embedded so it does not depend on web.base.url being reachable.
+
+ A relative /report/barcode/ URL requires wkhtmltopdf to fetch over HTTP
+ from inside the rendering process, where web.base.url usually points at an
+ external host and port that cannot be reached — the barcode then vanishes
+ with no error.
+ """
+ _request, picking = self._dispatch()
+ html = self._render(picking)
+
+ self.assertNotIn("/report/barcode/", html, "barcode is being fetched over HTTP again")
+ self.assertIn("data:image/png;base64,", html)
+
+ def test_barcode_helper_returns_a_png_data_uri(self):
+ _request, picking = self._dispatch()
+
+ uri = picking._get_waybill_barcode_data_uri()
+
+ self.assertTrue(uri.startswith("data:image/png;base64,"))
+ self.assertGreater(len(uri), 200, "barcode payload looks empty")
+
+ def test_barcode_helper_is_falsy_without_a_waybill_number(self):
+ _request, picking = self._dispatch()
+ picking.waybill_number = False
+
+ self.assertFalse(picking._get_waybill_barcode_data_uri())
+
+ def test_waybill_still_renders_when_the_barcode_cannot_be_built(self):
+ """A missing renderPM backend must not stop a waybill printing."""
+ _request, picking = self._dispatch()
+
+ def boom(*args, **kwargs):
+ raise OSError("cannot import desired renderPM backend rlPyCairo")
+
+ self.patch(type(self.env["ir.actions.report"]), "barcode", boom)
+
+ self.assertFalse(picking._get_waybill_barcode_data_uri())
+ html = self._render(picking)
+ self.assertIn("WAYBILL", html)
+ self.assertIn(picking.waybill_number, html)
diff --git a/spp_drims/views/stock_move_views.xml b/spp_drims/views/stock_move_views.xml
new file mode 100644
index 000000000..fbe934335
--- /dev/null
+++ b/spp_drims/views/stock_move_views.xml
@@ -0,0 +1,81 @@
+
+
+
+
+
+
+ stock.move.form.drims
+ stock.move
+
+
+
+
+
+
+
+
+
+
+
+ stock.move.operations.form.drims
+ stock.move
+
+
+
+
+
+
+
+
+
+
+
+
+
+ stock.move.list.drims
+ stock.move
+
+
+
+
+
+
+
+
+
diff --git a/spp_drims/views/stock_picking_views.xml b/spp_drims/views/stock_picking_views.xml
index 5d1540ec5..13d539c91 100644
--- a/spp_drims/views/stock_picking_views.xml
+++ b/spp_drims/views/stock_picking_views.xml
@@ -117,6 +117,99 @@
state != 'done' or drims_type_id
+
+
+ state in ('done', 'cancel') or drims_type == 'request_dispatch'
+
+
+
+ picking_type_code == 'incoming' or drims_type == 'request_dispatch'
+
+
+
+
+
+ state in ['cancel', 'done'] or drims_type == 'request_dispatch'
+
+
+
+
+ (state != 'draft' and not additional) or move_lines_count > 0 or parent.drims_type == 'request_dispatch'
+
+
-
-
-
+
+
+ drims_type == 'request_dispatch'
+
+
+ drims_type == 'request_dispatch'
+
+
+
+
+
+
+
+
+
-
+
-
+
+
-