Initial commit: Sale packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:49 +02:00
commit 14e3d26998
6469 changed files with 2479670 additions and 0 deletions

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="digest_digest_view_form" model="ir.ui.view">
<field name="name">digest.digest.view.form.inherit.sale.order</field>
<field name="model">digest.digest</field>
<field name="priority">10</field>
<field name="inherit_id" ref="digest.digest_digest_view_form" />
<field name="arch" type="xml">
<group name="kpi_sales" position="attributes">
<attribute name="string">Sales</attribute>
<attribute name="groups">sales_team.group_sale_salesman_all_leads</attribute>
</group>
<group name="kpi_sales" position="inside">
<field name="kpi_all_sale_total"/>
</group>
</field>
</record>
</odoo>

View file

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.sale.management</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="sale.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='sale_config_online_confirmation_pay']" position="after">
<div class="col-12 col-lg-6 o_setting_box" id="standardized_offers_setting">
<div class="o_setting_left_pane">
<field name="group_sale_order_template"/>
<field name="module_sale_quotation_builder" invisible="1"/>
</div>
<div class="o_setting_right_pane">
<label for="group_sale_order_template"/>
<a href="https://www.odoo.com/documentation/16.0/applications/sales/sales/send_quotations/quote_template.html" title="Documentation" class="o_doc_link" target="_blank"></a>
<div class="text-muted">
Create standardized offers with default products
</div>
<div class="content-group" attrs="{'invisible': [('group_sale_order_template', '=', False)]}">
<div class="mt16">
<label for="company_so_template_id" class="o_light_label me-2"/>
<field name="company_so_template_id" class="oe_inline"/>
</div>
<div class="mt8">
<button name="%(sale_management.sale_order_template_action)d" icon="fa-arrow-right" type="action" string="Quotation Templates" class="btn-link"/>
</div>
</div>
</div>
</div>
<div class="col-12 col-lg-6 o_setting_box"
id="design_quotation_template_setting"
attrs="{'invisible': [('group_sale_order_template','=',False)]}">
<div class="o_setting_left_pane">
<field name="module_sale_quotation_builder"/>
</div>
<div class="o_setting_right_pane">
<label for="module_sale_quotation_builder"/>
<div class="text-muted">
Design your quotation templates using building blocks<br/>
<em attrs="{'invisible': [('module_sale_quotation_builder','=',False)]}">Warning: this option will install the Website app.</em>
</div>
</div>
</div>
</xpath>
</field>
</record>
<record id="res_config_settings_view_form_inherit_sale_management" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.sale.management</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="sale.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@data-key='sale_management']" position="attributes">
<attribute name="class">app_settings_block</attribute>
</xpath>
</field>
</record>
</odoo>

View file

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="sale.sale_menu_root" model="ir.ui.menu">
<field name="active" eval="True"/>
</record>
<menuitem id="sale_order_template_menu"
name="Quotation Templates"
action="sale_order_template_action"
parent="sale.menu_sales_config"
groups="sale_management.group_sale_order_template"
sequence="1"/>
</odoo>

View file

@ -0,0 +1,156 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="sale_order_template_view_search" model="ir.ui.view">
<field name="name">sale.order.template.search</field>
<field name="model">sale.order.template</field>
<field name="arch" type="xml">
<search string="Search Quotation Template">
<field name="name"/>
<filter string="Archived" name="inactive" domain="[('active','=', False)]"/>
<group expand="1" string="Group By">
<filter string="Company" name="company_id" context="{'group_by': 'company_id'}" groups="base.group_multi_company"/>
</group>
</search>
</field>
</record>
<record id="sale_order_template_view_form" model="ir.ui.view">
<field name="name">sale.order.template.form</field>
<field name="model">sale.order.template</field>
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Quotation Template">
<sheet>
<div name="button_box" class="oe_button_box"/>
<widget name="web_ribbon" title="Archived" bg_color="bg-danger" attrs="{'invisible': [('active', '=', True)]}"/>
<div class="oe_title" name="sale_order_template_title">
<label for="name" id="sale_order_template_title"/>
<h1>
<field name="name" placeholder="e.g. Standard Consultancy Package" class="d-block"/>
</h1>
</div>
<group>
<group name="sale_info">
<field name="active" invisible="1"/>
<label for="number_of_days" string="Quotation expires after"/>
<div id="number_of_days">
<field name="number_of_days" style="width: 3rem;"/>
<div class="d-inline-block">days</div>
</div>
<label for="require_signature" string="Online confirmation"/>
<div>
<field name="require_signature" class="oe_inline"/>
<span>Signature</span>
<field name="require_payment" class="oe_inline ms-3"/>
<span>Payment</span>
</div>
<field name="mail_template_id" context="{'default_model': 'sale.order'}"/>
<field name="company_id" options="{'no_create': True}" groups="base.group_multi_company"/>
</group>
</group>
<notebook name="main_book">
<page string="Lines" name="order_lines">
<field name="sale_order_template_line_ids" widget="section_and_note_one2many">
<form string="Quotation Template Lines">
<!--
We need the sequence field to be here for new lines to be added at the correct position.
TODO: at some point we want to fix this in the framework so that an invisible field is not required.
-->
<field name="sequence" invisible="1"/>
<field name="display_type" invisible="1"/>
<field name="product_uom_category_id" invisible="1"/>
<field name="company_id" invisible="1"/>
<group attrs="{'invisible': [('display_type', '!=', False)]}">
<group>
<field name="product_id" attrs="{'required': [('display_type', '=', False)]}"/>
<label for="product_uom_qty"/>
<div>
<field name="product_uom_qty" class="oe_inline"/>
</div>
</group>
</group>
<notebook colspan="4" name="description">
<page string="Description" name="order_description" attrs="{'invisible': [('display_type', '!=', False)]}">
<field name="name" />
</page>
<page string="Section" name="order_section" attrs="{'invisible': [('display_type', '!=', 'line_section')]}">
<field name="name" />
</page>
<page string="Note" name="order_note" attrs="{'invisible': [('display_type', '!=', 'line_note')]}">
<field name="name" />
</page>
</notebook>
</form>
<tree string="Quotation Template Lines" editable="bottom">
<control>
<create name="add_product_control" string="Add a product"/>
<create name="add_section_control" string="Add a section" context="{'default_display_type': 'line_section'}"/>
<create name="add_note_control" string="Add a note" context="{'default_display_type': 'line_note'}"/>
</control>
<field name="display_type" invisible="1"/>
<field name="company_id" invisible="1"/>
<field name="sequence" widget="handle"/>
<field name="product_id"/>
<field name="name"/>
<field name="product_uom_qty"/>
<field name="product_uom_category_id" invisible="1"/>
<field
name="product_uom_id"
groups="uom.group_uom"
attrs="{'required': [('display_type', '=', False)]}"
/>
</tree>
</field>
</page>
<page string="Optional Products" name="optional_products">
<field name="sale_order_template_option_ids">
<tree string="Quotation Template Lines" editable="bottom">
<field name="product_id"/>
<field name="name"/>
<field name="quantity"/>
<field name="product_uom_category_id" invisible="1"/>
<field name="uom_id" groups="uom.group_uom"/>
<field name="company_id" invisible="1"/>
</tree>
</field>
</page>
<page string="Terms &amp; Conditions" name="terms_and_conditions">
<field name="note" nolabel="1"
placeholder="The Administrator can set default Terms &amp; Conditions in Sales Settings. Terms set here will show up instead if you select this quotation template."/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record id="sale_order_template_view_tree" model="ir.ui.view">
<field name="name">sale.order.template.tree</field>
<field name="model">sale.order.template</field>
<field name="type">tree</field>
<field name="arch" type="xml">
<tree string="Quotation Template">
<field name="name"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<record id="sale_order_template_action" model="ir.actions.act_window">
<field name="name">Quotation Templates</field>
<field name="type">ir.actions.act_window</field>
<field name="res_model">sale.order.template</field>
<field name="view_mode">tree,form</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create your quotation template
</p><p>
Use templates to create polished, professional quotes in minutes.
Send these quotes by email and let your customers sign online.
Use cross-selling and discounts to push and boost your sales.
</p>
</field>
</record>
</odoo>

View file

@ -0,0 +1,112 @@
<?xml version="1.0"?>
<odoo>
<record id="sale_order_form_quote" model="ir.ui.view">
<field name="name">sale.order.form.inherit.sale_management</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<page name="order_lines" position="after">
<page string="Optional Products"
name="optional_products"
attrs="{'invisible': [('state', 'not in', ['draft', 'sent'])]}">
<field name="sale_order_option_ids" mode="tree,form,kanban">
<form string="Optional Products">
<group>
<field name="product_id"
domain="[('sale_ok', '=', True), '|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"/>
<field name="name"/>
<field name="quantity"/>
<field name="product_uom_category_id" invisible="1"/>
<field name="uom_id" groups="uom.group_uom"/>
<field name="price_unit"/>
<field name="discount" groups="product.group_discount_per_so_line"/>
<field name="is_present" />
</group>
</form>
<kanban class="o_kanban_mobile">
<field name="product_id"/>
<field name="quantity"/>
<field name="uom_id" groups="uom.group_uom"/>
<field name="price_unit"/>
<field name="is_present" />
<templates>
<t t-name="kanban-box">
<div class="oe_kanban_card oe_kanban_global_click">
<div class="row">
<div class="col-10">
<strong>
<span>
<t t-out="record.product_id.value"/>
</span>
</strong>
</div>
<div class="col-2">
<button name="button_add_to_order"
class="btn btn-link oe_link fa fa-shopping-cart"
title="Add to order lines"
type="object"
attrs="{'invisible': [('is_present', '=', True)]}"/>
</div>
</div>
<div class="row">
<div class="col-12 text-muted">
<span>
Quantity:
<t t-out="record.quantity.value"/>
<t t-out="record.uom_id.value" groups="uom.group_uom"/>
</span>
</div>
</div>
<div class="row">
<div class="col-12 text-muted">
<span>
Unit Price:
<t t-out="record.price_unit.value"/>
</span>
</div>
</div>
</div>
</t>
</templates>
</kanban>
<tree string="Sales Quotation Template Lines"
editable="bottom"
decoration-success="is_present == True">
<control>
<create name="add_product_control" string="Add a product"/>
</control>
<field name="sequence" widget="handle"/>
<field name="product_id"
domain="[('sale_ok', '=', True), '|', ('company_id', '=', False), ('company_id', '=', parent.company_id)]"/>
<field name="name" optional="show"/>
<field name="quantity"/>
<field name="uom_id" string="UoM" groups="uom.group_uom" optional="show"/>
<field name="product_uom_category_id" invisible="1"/>
<field name="price_unit"/>
<field name="discount"
string="Disc.%"
groups="product.group_discount_per_so_line"
optional="show"/>
<field name="is_present" invisible="1" />
<button name="button_add_to_order"
type="object"
class="oe_link"
icon="fa-shopping-cart"
title="Add to order lines"
attrs="{'invisible': [('is_present', '=', True)]}"/>
</tree>
</field>
</page>
</page>
<field name="partner_shipping_id" position="after">
<field name="sale_order_template_id"
options="{'no_create': True}"
groups="sale_management.group_sale_order_template"
/>
</field>
</field>
</record>
</odoo>

View file

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<template id="sale_order_portal_content_inherit_sale_management" name="Order Options" inherit_id="sale.sale_order_portal_content">
<xpath expr="//section[@id='details']//t[@t-set='display_discount']" position="after">
<t t-set="display_remove" t-value="sale_order.state in ('draft', 'sent') and any(line.sale_order_option_ids for line in sale_order.order_line)"/>
</xpath>
<xpath expr="//section[@id='details']//table[@id='sales_order_table']/thead/tr" position="inside">
<!-- add blank Tr in thead for layout conciseness -->
<th t-if="display_remove">
</th>
</xpath>
<xpath expr="//section[@id='details']//t[@t-if='not line.display_type']" position="inside">
<td class="text-center" t-if="display_remove">
<a t-att-data-line-id="line.id" t-att-data-unlink="True" href="#" class="mb8 js_update_line_json d-print-none" t-if="sale_order.state in ('draft', 'sent') and line.sale_order_option_ids" aria-label="Remove" title="Remove">
<span class="fa fa-trash-o"></span>
</a>
</td>
</xpath>
<xpath expr="//section[@id='signature']" position="after">
<t t-if="any((not option.is_present) for option in sale_order.sale_order_option_ids)">
<section>
<h3>Options</h3>
<t t-set="display_discount" t-value="True in [option.discount > 0 for option in sale_order.sale_order_option_ids]"/>
<table class="table table-sm">
<thead>
<tr>
<th class="text-start">Product</th>
<th t-if="display_discount" class="text-end">Disc.%
</th>
<th class="text-end">Unit Price</th>
<th t-if="sale_order.state in ['draft', 'sent'] and report_type == 'html'"></th>
</tr>
</thead>
<tbody>
<tr t-foreach="sale_order.sale_order_option_ids" t-as="option">
<t t-if="not option.is_present">
<td>
<div t-field="option.name"/>
</td>
<td t-if="display_discount" class="text-end">
<strong t-if="option.discount" class="text-info">
<t t-out="((option.discount % 1) and '%s' or '%d') % option.discount"/>%
</strong>
</td>
<td>
<strong class="text-end">
<div t-field="option.price_unit"
t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'
t-att-style="option.discount and 'text-decoration: line-through' or None"
t-att-class="option.discount and 'text-danger' or None"/>
<div t-if="option.discount">
<t t-out="(1-option.discount / 100.0) * option.price_unit" t-options='{"widget": "monetary", "display_currency": sale_order.pricelist_id.currency_id}'/>
</div>
</strong>
</td>
<td class="text-center" t-if="sale_order.state in ['draft', 'sent'] and report_type == 'html'">
<a t-att-data-option-id="option.id" href="#" class="mb8 js_add_optional_products d-print-none" aria-label="Add to cart" title="Add to cart">
<span class="fa fa-shopping-cart"/>
</a>
</td>
</t>
</tr>
</tbody>
</table>
</section>
</t>
</xpath>
<xpath expr="//section[@id='details']//div[@id='quote_qty']" position="replace">
<t t-if="sale_order.state in ['draft', 'sent'] and line.sale_order_option_ids">
<div class="input-group js_quantity_container pull-right">
<span class="d-print-none input-group-text d-none d-md-inline-block">
<a t-att-data-line-id="line.id" t-att-data-remove="True" href="#" class="js_update_line_json" aria-label="Remove one" title="Remove one">
<span class="fa fa-minus"/>
</a>
</span>
<!-- TODO add uom in this case too -->
<input type="text" class="js_quantity form-control" t-att-data-line-id="line.id" t-att-value="line.product_uom_qty"/>
<span class="d-print-none input-group-text d-none d-md-inline-block">
<a t-att-data-line-id="line.id" href="#" class="js_update_line_json" aria-label="Add one" title="Add one">
<span class="fa fa-plus"/>
</a>
</span>
</div>
</t>
<t t-else="">
<span t-field="line.product_uom_qty"/>
<span t-field="line.product_uom"/>
</t>
</xpath>
</template>
</odoo>