This commit extends the delivery slip so that products added as a kit component to a stock.picking are grouped together by kit (or non-kit) when at least 1 kit exists. Kit grouping occurs for products from a kit without a package assigned. Non-kit section appears only when no packages are assigned. Implementation notes: - Sub-kits (i.e. kits within kits) of kits are purposely not included - Duplicate product names with different BOMs will be merged into one since there is no straightforward way to distinguish them within current db structure - There are some cases where this doesn't work as expected and may lead to components being grouped together under the same kit even if they are from different kits (e.g. kit1 has bolts and so does kit2 => on slip bolts will only show under kit1 section). Two cases where this happens is when kits are added before 'Operation Type' is specified and 'Operation Type = Manufacturing' This completes subsection 1 of overall Improve delivery slip task. Task: 2039720
235 lines
13 KiB
XML
235 lines
13 KiB
XML
<?xml version="1.0" encoding="UTF-8" ?>
|
|
<odoo>
|
|
<template id="report_delivery_document">
|
|
<t t-call="web.html_container">
|
|
<t t-call="web.external_layout">
|
|
<t t-set="o" t-value="o.with_context(lang=o.partner_id.lang)" />
|
|
<t t-set="partner" t-value="o.partner_id or (o.move_lines and o.move_lines[0].partner_id) or False"/>
|
|
<t t-if="partner" name="partner_header">
|
|
<t t-set="address">
|
|
<div t-esc="partner"
|
|
t-options='{"widget": "contact", "fields": ["address", "name", "phone"], "no_marker": True}'/>
|
|
</t>
|
|
</t>
|
|
|
|
<div class="page">
|
|
<h2>
|
|
<span t-field="o.name"/>
|
|
</h2>
|
|
<div class="row mt32 mb32">
|
|
<div t-if="o.origin" class="col-auto" name="div_origin">
|
|
<strong>Order:</strong>
|
|
<p t-field="o.origin"/>
|
|
</div>
|
|
<div t-if="o.state" class="col-auto" name="div_sched_date">
|
|
<strong>Shipping Date:</strong>
|
|
<t t-if="o.state == 'done'">
|
|
<p t-field="o.date_done"/>
|
|
</t>
|
|
<t t-if="o.state != 'done'">
|
|
<p t-field="o.scheduled_date"/>
|
|
</t>
|
|
</div>
|
|
</div>
|
|
<table class="table table-sm" t-if="o.state!='done'" name="stock_move_table">
|
|
<thead>
|
|
<tr>
|
|
<th name="th_sm_product"><strong>Product</strong></th>
|
|
<th name="th_sm_quantity"><strong>Quantity</strong></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<t t-set="lines" t-value="o.move_lines.filtered(lambda x: x.product_uom_qty)"/>
|
|
<tr t-foreach="lines" t-as="move">
|
|
<td>
|
|
<span t-field="move.product_id"/>
|
|
<p t-if="move.description_picking != move.product_id.name">
|
|
<span t-field="move.description_picking"/>
|
|
</p>
|
|
</td>
|
|
<td>
|
|
<span t-field="move.product_uom_qty"/>
|
|
<span t-field="move.product_uom"/>
|
|
</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
<table class="table table-sm mt48" t-if="o.move_line_ids and o.state=='done'" name="stock_move_line_table">
|
|
<t t-set="has_serial_number" t-value="False"/>
|
|
<t t-set="has_serial_number" t-value="o.move_line_ids.mapped('lot_id')" groups="stock.group_lot_on_delivery_slip"/>
|
|
<thead>
|
|
<tr>
|
|
<th name="th_sml_product"><strong>Product</strong></th>
|
|
<t name="lot_serial" t-if="has_serial_number">
|
|
<th>
|
|
Lot/Serial Number
|
|
</th>
|
|
</t>
|
|
<th name="th_sml_quantity" class="text-center"><strong>Quantity</strong></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- This part gets complicated with different use cases (additional use cases in extensions of this report):
|
|
1. If serial numbers are used and set to print on delivery slip => print lines as is, otherwise group them by overlapping
|
|
product + description + uom combinations
|
|
2. If any packages are assigned => split products up by package (or non-package) and then apply use case 1 -->
|
|
<!-- If has destination packages => create sections of corresponding products -->
|
|
<t t-if="o.has_packages" name="has_packages">
|
|
<t t-set="packages" t-value="o.move_line_ids.mapped('result_package_id')"/>
|
|
<t t-foreach="packages" t-as="package">
|
|
<t t-call="stock.stock_report_delivery_package_section_line"/>
|
|
<t t-set="package_move_lines" t-value="o.move_line_ids.filtered(lambda l: l.result_package_id == package)"/>
|
|
<!-- If printing lots/serial numbers => keep products in original lines -->
|
|
<t t-if="has_serial_number">
|
|
<tr t-foreach="package_move_lines" t-as="move_line">
|
|
<t t-call="stock.stock_report_delivery_has_serial_move_line"/>
|
|
</tr>
|
|
</t>
|
|
<!-- If not printing lots/serial numbers => merge lines with same product+description+uom -->
|
|
<t t-else="">
|
|
<t t-set="aggregated_lines" t-value="package_move_lines._get_aggregated_product_quantities()"/>
|
|
<t t-call="stock.stock_report_delivery_aggregated_move_lines"/>
|
|
</t>
|
|
</t>
|
|
<!-- Make sure we do another section for package-less products if they exist -->
|
|
<t t-set="move_lines" t-value="o.move_line_ids.filtered(lambda l: not l.result_package_id)"/>
|
|
<t t-if="move_lines" name="no_package_move_lines">
|
|
<t t-call="stock.stock_report_delivery_no_package_section_line" name="no_package_section"/>
|
|
<t t-if="has_serial_number">
|
|
<tr t-foreach="move_lines" t-as="move_line">
|
|
<t t-call="stock.stock_report_delivery_has_serial_move_line"/>
|
|
</tr>
|
|
</t>
|
|
<t t-else="">
|
|
<t t-set="aggregated_lines" t-value="move_lines._get_aggregated_product_quantities()"/>
|
|
<t t-if="aggregated_lines">
|
|
<t t-call="stock.stock_report_delivery_aggregated_move_lines"/>
|
|
</t>
|
|
</t>
|
|
</t>
|
|
</t>
|
|
<!-- No destination packages -->
|
|
<t t-else="">
|
|
<!-- If printing lots/serial numbers => keep products in original lines -->
|
|
<t t-if="has_serial_number">
|
|
<tr t-foreach="o.move_line_ids" t-as="move_line">
|
|
<t t-call="stock.stock_report_delivery_has_serial_move_line"/>
|
|
</tr>
|
|
</t>
|
|
<!-- If not printing lots/serial numbers => merge lines with same product -->
|
|
<t t-else="" name="aggregated_move_lines">
|
|
<t t-set="aggregated_lines" t-value="o.move_line_ids._get_aggregated_product_quantities()"/>
|
|
<t t-call="stock.stock_report_delivery_aggregated_move_lines"/>
|
|
</t>
|
|
</t>
|
|
</tbody>
|
|
</table>
|
|
<t t-set="backorders" t-value="o.backorder_ids.filtered(lambda x: x.state not in ('done', 'cancel'))"/>
|
|
<t t-if="o.backorder_ids and backorders">
|
|
<p>
|
|
<span>All items couldn't be shipped, the following items will be shipped as soon as they become available.</span>
|
|
</p>
|
|
<table class="table table-sm" name="stock_backorder_table">
|
|
<thead>
|
|
<tr>
|
|
<th name="th_sb_product"><strong>Product</strong></th>
|
|
<th name="th_sb_quantity" class="text-center"><strong>Quantity</strong></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<t t-foreach="backorders" t-as="backorder">
|
|
<t t-set="bo_lines" t-value="backorder.move_lines.filtered(lambda x: x.product_uom_qty)"/>
|
|
<tr t-foreach="bo_lines" t-as="bo_line">
|
|
<td>
|
|
<span t-field="bo_line.product_id"/>
|
|
<p t-if="bo_line.description_picking != bo_line.product_id.name">
|
|
<span t-field="bo_line.description_picking"/>
|
|
</p>
|
|
</td>
|
|
<td class="text-center">
|
|
<span t-field="bo_line.product_uom_qty"/>
|
|
<span t-field="bo_line.product_uom"/>
|
|
</td>
|
|
</tr>
|
|
</t>
|
|
</tbody>
|
|
</table>
|
|
</t>
|
|
|
|
<div t-if="o.signature" class="mt32 ml64 mr4" name="signature">
|
|
<div class="offset-8">
|
|
<strong>Signature</strong>
|
|
</div>
|
|
<div class="offset-8">
|
|
<img t-att-src="image_data_uri(o.signature)" style="max-height: 4cm; max-width: 8cm;"/>
|
|
</div>
|
|
<div class="offset-8 text-center">
|
|
<p t-field="o.partner_id.name"/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</t>
|
|
</t>
|
|
</template>
|
|
|
|
<!-- templates for easier extension + cut back on repeat code due to multiple conditionals -->
|
|
<!-- move line(s) printing for tables -->
|
|
<template id="stock_report_delivery_has_serial_move_line">
|
|
<td>
|
|
<span t-field="move_line.product_id"/>
|
|
<!-- this is an annoying workaround for the multiple types of descriptions (often auto-filled) that we do not want to print -->
|
|
<!-- this makes it so we can pre-filter the descriptions in inherited templates since we cannot extend the standard "if" condition -->
|
|
<!-- let's agree that pre-filtered descriptions will be set to "" -->
|
|
<t t-if="not description and description != ''">
|
|
<t t-set="description" t-value="move_line.move_id.description_picking"/>
|
|
</t>
|
|
<p t-if="description !='' and description != move_line.product_id.name">
|
|
<span t-esc="description"/>
|
|
</p>
|
|
</td>
|
|
<t t-if="has_serial_number" name="move_line_lot">
|
|
<td><span t-field="move_line.lot_id.name"/></td>
|
|
</t>
|
|
<td class="text-center" name="move_line_lot_qty_done">
|
|
<span t-field="move_line.qty_done"/>
|
|
<span t-field="move_line.product_uom_id"/>
|
|
</td>
|
|
</template>
|
|
<template id="stock_report_delivery_aggregated_move_lines">
|
|
<tr t-foreach="aggregated_lines" t-as="line">
|
|
<td>
|
|
<span t-esc="aggregated_lines[line]['name']"/>
|
|
<p t-if="aggregated_lines[line]['description']">
|
|
<span t-esc="aggregated_lines[line]['description']"/>
|
|
</p>
|
|
</td>
|
|
<td class="text-center" name="move_line_aggregated_qty_done">
|
|
<span t-esc="aggregated_lines[line]['qty_done']"/>
|
|
<span t-esc="aggregated_lines[line]['product_uom']"/>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
|
|
<!-- package related "section lines" -->
|
|
<template id="stock_report_delivery_package_section_line">
|
|
<tr t-att-class="'bg-200 font-weight-bold o_line_section'">
|
|
<td colspan="99" name="package_info">
|
|
<span t-field="package.name"/>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
<template id="stock_report_delivery_no_package_section_line">
|
|
<tr t-att-class="'bg-200 font-weight-bold o_line_section'">
|
|
<td colspan="99" name="no_package_info">
|
|
<span>Products with no package assigned</span>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
|
|
<template id="report_deliveryslip">
|
|
<t t-foreach="docs" t-as="o">
|
|
<t t-call="stock.report_delivery_document" t-lang="o.partner_id.lang"/>
|
|
</t>
|
|
</template>
|
|
</odoo>
|