19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:30:27 +01:00
parent d1963a3c3a
commit 2d3ee4855a
7430 changed files with 2687981 additions and 2965473 deletions

View file

@ -0,0 +1,4 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import stock_forecasted

View file

@ -2,14 +2,12 @@
<odoo>
<data>
<record id="action_report_repair_order" model="ir.actions.report">
<field name="name">Quotation / Order</field>
<field name="name">Repair Order</field>
<field name="model">repair.order</field>
<field name="report_type">qweb-pdf</field>
<field name="report_name">repair.report_repairorder2</field>
<field name="report_file">repair.report_repairorder</field>
<field name="print_report_name">(
object.state == 'draft' and 'Repair Quotation - %s' % (object.name) or
'Repair Order - %s' % (object.name))</field>
<field name="print_report_name">('Repair Order - %s' % (object.name))</field>
<field name="binding_model_id" ref="model_repair_order"/>
<field name="binding_type">report</field>
</record>

View file

@ -5,148 +5,68 @@
<t t-set="o" t-value="doc"/>
<t t-call="web.external_layout">
<t t-set="o" t-value="o.with_context(lang=o.partner_id.lang)" />
<t t-set="information_block">
<strong t-if="o.address_id == o.partner_invoice_id">Invoice and shipping address:</strong>
<div t-if="o.partner_invoice_id">
<strong t-if="o.address_id != o.partner_invoice_id">Invoice address: </strong>
<div t-field="o.partner_invoice_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone", "vat"], "no_marker": True, "phone_icons": True}'/>
</div>
<t t-if="o.address_id != o.partner_invoice_id">
<strong>Shipping address :</strong>
<div t-field="o.address_id"
t-options='{"widget": "contact", "fields": ["address", "name", "phone", "vat"], "no_marker": True, "phone_icons": True}'/>
</t>
</t>
<t t-set="address">
<div t-field="o.partner_id"
t-options='{"widget": "contact", "fields": ["address", "name"], "no_marker": True}' />
</t>
<div class="page">
<div class="oe_structure"/>
<h2>
<span t-if="o.state != 'draft'">Repair Order #:</span>
<span t-if="o.state == 'draft'">Repair Quotation #:</span>
<span t-field="o.name"/>
<span>Repair Order #</span>
<span t-field="o.name">RO123456</span>
</h2>
<div id="informations" class="row mt32 mb32">
<div t-if="o.product_id.name" class="col-3 bm-2">
<strong>Product to Repair:</strong>
<p t-field="o.product_id.name" class="m-0"/>
<div class="oe_structure"/>
<div id="informations" class="row mb-3">
<div class="col-6">
<p t-if="o.partner_id" class="m-0">
<strong>Customer:</strong>
<span t-field="o.partner_id">John Doe</span>
</p>
<p t-if="o.product_id" class="m-0">
<strong>Product:</strong>
<span t-field="o.product_id">Laptop</span>
</p>
<p t-if="o.lot_id" class="m-0" groups="stock.group_production_lot">
<strong>Lot/Serial:</strong>
<span t-field="o.lot_id">L12345</span>
</p>
</div>
<div class="col-3 bm-2" groups="stock.group_production_lot">
<strong>Lot/Serial Number:</strong>
<t t-if="o.lot_id">
<span t-field="o.lot_id.name"/>
</t>
</div>
<div t-if="o.guarantee_limit" class="col-3 bm-2">
<strong>Warranty:</strong>
<p t-field="o.guarantee_limit" class="m-0"/>
</div>
<div class="col-3 bm-2">
<strong>Printing Date:</strong>
<p t-esc="datetime.datetime.now().strftime('%Y-%m-%d')" t-options="{'widget': 'date'}" class="m-0"/>
<div class="col-6">
<p class="m-0">
<strong>Status:</strong>
<span t-field="o.state">Pending</span>
</p>
<p t-if="o.user_id" class="m-0">
<strong>Responsible:</strong>
<span t-field="o.user_id">Jane Smith</span>
</p>
</div>
</div>
<table class="table table-sm o_main_table">
<div class="oe_structure"/>
<h2 class="mb-3 border-bottom border-2 border-dark">Parts</h2>
<table class="table table-borderless o_main_table">
<thead>
<tr>
<th>Description</th>
<th class="text-end">Quantity</th>
<t t-if="o.invoice_method != 'none'">
<th class="text-end">Unit Price</th>
<th class="text-center">Tax</th>
<th class="text-end">Price</th>
</t>
</tr>
</thead>
<tbody>
<t t-if="o.operations">
<tr class="bg-200 o_line_section"><td colspan="5"><strong>Parts</strong></td></tr>
<tr t-foreach="o.operations" t-as="line">
<td>
<p t-if="line.type == 'add'"><i>(Add)</i> <span t-field="line.name" /></p>
<p t-if="line.type == 'remove'">(<i>Remove</i>) <span t-field="line.name"/></p>
</td>
<td class="text-end">
<span t-field="line.product_uom_qty"/>
<span groups="uom.group_uom" t-field="line.product_uom.name"/>
</td>
<t t-if="(line.repair_id.invoice_method != 'none')">
<td class="text-end">
<span t-field="line.price_unit"/>
</td>
<td class="text-center">
<span t-esc="','.join(map( lambda x: x.description or x.name, line.tax_id))"/>
</td>
<td class="text-end o_price_total">
<span t-field="line.price_subtotal" t-options='{"widget": "monetary", "display_currency": o.pricelist_id.currency_id}'/>
</td>
</t>
</tr>
</t>
<t t-if="o.fees_lines">
<tr class="bg-200 o_line_section"><td colspan="5"><strong>Operations</strong></td></tr>
<tr t-foreach="o.fees_lines" t-as="fees">
<td>
<span t-field="fees.name"/>
</td>
<td class="text-end">
<span t-field="fees.product_uom_qty"/>
<span groups="uom.group_uom" t-field="fees.product_uom.name"/>
</td>
<t t-if="(fees.repair_id.invoice_method != 'none')">
<td class="text-end">
<span t-field="fees.price_unit"/>
</td>
<td class="text-center">
<span t-esc="','.join(map( lambda x: x.description or x.name, fees.tax_id))"/>
</td>
<td class="text-end o_price_total">
<span t-field="fees.price_subtotal"
t-options='{"widget": "monetary", "display_currency": o.pricelist_id.currency_id}'/>
</td>
</t>
</tr>
</t>
<tr t-foreach="o.move_ids" t-as="line">
<td>
<p t-if="line.repair_line_type == 'add'"><i>(Add)</i> <span t-field="line.product_id">Product A</span></p>
<p t-if="line.repair_line_type == 'remove'">(<i>Remove</i>) <span t-field="line.product_id">Product B</span></p>
<p t-if="line.repair_line_type == 'recycle'">(<i>Recycle</i>) <span t-field="line.product_id" data-oe-demo="Product C"/></p>
</td>
<td class="text-end">
<span t-field="line.product_uom_qty">5</span>
<span groups="uom.group_uom" t-field="line.product_uom.name">Units</span>
</td>
</tr>
</tbody>
</table>
<div id="total" class="row justify-content-end">
<div class="col-4">
<table class="table table-sm">
<t t-if="o.invoice_method !='none'">
<tr class="border-black o_subtotal">
<td><strong>Total Without Taxes</strong></td>
<td class="text-end">
<span t-field="o.amount_untaxed"
t-options='{"widget": "monetary", "display_currency": o.pricelist_id.currency_id}'/>
</td>
</tr>
<tr>
<td>Taxes</td>
<td class="text-end o_price_total">
<span t-field="o.amount_tax"
t-options='{"widget": "monetary", "display_currency": o.pricelist_id.currency_id}'/>
</td>
</tr>
<tr class="border-black o_total">
<td><strong>Total</strong></td>
<td class="text-end o_price_total">
<span t-field="o.amount_total"
t-options='{"widget": "monetary", "display_currency": o.pricelist_id.currency_id}'/>
</td>
</tr>
</t>
</table>
</div>
<div class="oe_structure"/>
<div t-if="o.internal_notes">
<h2 class="mb-3 border-bottom border-2 border-dark">Repair Notes</h2>
<span t-field="o.internal_notes">This is a repair note.</span>
</div>
<p t-field="o.quotation_notes"/>
<div class="oe_structure"/>
</div>
</t>

View file

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import models
class StockForecasted_Product_Product(models.AbstractModel):
_inherit = 'stock.forecasted_product_product'
def _get_reservation_data(self, move):
if move.repair_id and move.repair_line_type:
return False
return super()._get_reservation_data(move)
def _product_sale_domain(self, product_template_ids, product_ids):
"""
When a product's move is bind at the same time to a Repair Order
and to a Sale Order, only take the data into account once, as a RO
"""
sol_domain = super()._product_sale_domain(product_template_ids, product_ids)
move_domain = self._product_domain(product_template_ids, product_ids)
move_domain += [
('repair_id', '!=', False),
('sale_line_id', '!=', False),
('repair_line_type', '=', 'add')
]
sol_ids = self.env['stock.move']._read_group(move_domain, aggregates=['sale_line_id:array_agg'])[0][0]
sol_domain += [('id', 'not in', sol_ids)]
return sol_domain