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
208 changes: 208 additions & 0 deletions spreadsheet_sale_calculator/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
.. image:: https://odoo-community.org/readme-banner-image
:target: https://odoo-community.org/get-involved?utm_source=readme
:alt: Odoo Community Association

===========================
Spreadsheet Sale Calculator
===========================

..
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! source digest: sha256:52516a3d5cfbe9c5492ee70a59cfabf88edf4b9e87807b5fc4417b4b8a2a57c9
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/license-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fspreadsheet-lightgray.png?logo=github
:target: https://github.com/OCA/spreadsheet/tree/19.0/spreadsheet_sale_calculator
:alt: OCA/spreadsheet
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png
:target: https://translation.odoo-community.org/projects/spreadsheet-19-0/spreadsheet-19-0-spreadsheet_sale_calculator
:alt: Translate me on Weblate
.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png
:target: https://runboat.odoo-community.org/builds?repo=OCA/spreadsheet&target_branch=19.0
:alt: Try me on Runboat

|badge1| |badge2| |badge3| |badge4| |badge5|

This module adds a **quote calculator** to quotations: an Odoo
spreadsheet, attached to the order, whose results are written straight
onto the order lines.

Many quotes depend on a calculation — square metres, weights, tiered
discounts, material breakdowns — that usually lives in a separate
spreadsheet and is copied back onto the order by hand. This module
brings that spreadsheet inside Odoo: you build the calculation once with
ordinary formulas, point its result cells at the order-line fields they
should feed (unit price, quantity, discount, description...), and push
the computed values onto the lines in a single click.

The usual way is to prepare the calculator once on a **quotation
template** and let every quote made from it reuse it, but you can also
attach one straight to a single order. Either way each quote gets its
own private copy, so a salesperson can adjust their own inputs without
ever touching the shared original.

The sync is one-way (spreadsheet → order lines) and triggered by hand,
so it never disturbs normal quoting and the spreadsheet stays completely
free-form.

It builds on **spreadsheet_field_linking**, which provides the
cell-to-field linking; this module adds the sale-specific tools: the
template calculator, the per-quote copy, and the smart button on the
order.

**Table of contents**

.. contents::
:local:

Usage
=====

The quote calculator is set up once on a quotation template, though,
then rides along on every quote made from that template. It works out of
the box — there is nothing to configure. Everything below happens with
ordinary spreadsheet formulas and the linking tools from
**spreadsheet_field_linking**.

Prepare the calculator on a quotation template
----------------------------------------------

Go to **Sales → Configuration → Quotation Templates** and open (or
create) a template, adding its lines as usual. In the **Quote
Calculator** field, create a new spreadsheet and open it — it starts
empty, ready for whatever calculation you need.

|image1|

Build your calculation with normal formulas: the inputs, the
intermediate steps, and the result cells you want to end up on the
order.

Then link each **result cell** to the order-line field it should feed —
unit price, quantity, discount, the product on a line, and so on.
Linking a cell to a field, and choosing which line it targets, is done
with the tools from **spreadsheet_field_linking**; see its documentation
for how. The mappings live inside the spreadsheet, so they travel with
every copy.

Attach a calculator to a quotation
----------------------------------

There are two ways to give an order a calculator:

- **From a quotation template** — on a new quotation, choose a
**quotation template** that carries a calculator and the order picks
it up automatically. This is the usual route, since one template
serves every quote made from it.
- **Directly on the order** — pick a spreadsheet in the **Quote
Calculator Template** field of the order itself, with no quotation
template involved. Handy for a one-off quote or an ad-hoc calculation.

|image2|

Either way a **Quote Calculator** smart button appears. Choosing the
template or the spreadsheet copies nothing on its own — it only points
the order at the calculator to use. The private copy is made when you
**first click the button**, which is why the button can show before any
spreadsheet exists yet. From then on the button just reopens that copy,
so your changes never affect the shared original or any other quote.

Run the calculator and write the values back
--------------------------------------------

Click the **Quote Calculator** smart button to open the editor and
adjust your input values.

|image3|

When you are happy with the result, click **Write to record** in the top
bar. For each linked cell the current value is read, checked against the
field's type, and written onto the matching order line; the workbook is
saved at the same time. Because the order lines are created from the
template lines in the same order, position ``1`` still points at the
first line after the quote is made, so nothing has to be re-mapped on
copy.

|image4|

Change or rebuild the calculator
--------------------------------

If you switch the quotation template — or the chosen calculator — after
a copy already exists, a **Rebuild Calculator** button appears next to
the field. It discards the current copy and rebuilds a fresh one from
the new template, which is handy when the template's calculator has been
improved. The inputs in the old copy are lost, so it asks for
confirmation first.

Good to know
------------

- The sync is one-way: the spreadsheet writes onto the order, never the
other way around.
- It only runs when you click **Write to record**, so editing the sheet
never changes the order on its own.
- The **Quote Calculator** button is what creates the order's private
copy, on its first click; selecting a template or spreadsheet only
sets which calculator to copy. That is why the button can appear while
no spreadsheet exists yet.
- An **empty** cell clears its field to the empty value (``0``, blank
text, no relation).
- Which fields can be reached, how line positions are counted, and when
a new line is created (or deliberately not) are all handled by
**spreadsheet_field_linking** — see its documentation for the details
and limitations.

.. |image1| image:: https://raw.githubusercontent.com/OCA/spreadsheet/19.0/spreadsheet_sale_calculator/static/description/quote_template_set_calculator_template.png
.. |image2| image:: https://raw.githubusercontent.com/OCA/spreadsheet/19.0/spreadsheet_sale_calculator/static/description/quotation_with_attached_calculator.png
.. |image3| image:: https://raw.githubusercontent.com/OCA/spreadsheet/19.0/spreadsheet_sale_calculator/static/description/calculator_edit_and_apply_values.png
.. |image4| image:: https://raw.githubusercontent.com/OCA/spreadsheet/19.0/spreadsheet_sale_calculator/static/description/calculator_reflected_values.png

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/OCA/spreadsheet/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us to smash it by providing a detailed and welcomed
`feedback <https://github.com/OCA/spreadsheet/issues/new?body=module:%20spreadsheet_sale_calculator%0Aversion:%2019.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Authors
-------

* arielbarreiros96

Contributors
------------

- `arielbarreiros96 <https://www.github.com/arielbarreiros96>`__

Maintainers
-----------

This module is maintained by the OCA.

.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org

OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.

This module is part of the `OCA/spreadsheet <https://github.com/OCA/spreadsheet/tree/19.0/spreadsheet_sale_calculator>`_ project on GitHub.

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.
1 change: 1 addition & 0 deletions spreadsheet_sale_calculator/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
19 changes: 19 additions & 0 deletions spreadsheet_sale_calculator/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright 2026 arielbarreiros96
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl-3.0).
{
"name": "Spreadsheet Sale Calculator",
"version": "19.0.3.0.0",
"summary": "Drive sale order line values from an embedded Odoo spreadsheet",
"author": "arielbarreiros96, Odoo Community Association (OCA)",
"website": "https://github.com/OCA/spreadsheet",
"license": "AGPL-3",
"category": "Sales",
"depends": ["sale_management", "spreadsheet_field_linking"],
"data": [
"security/spreadsheet_sale_calculator_groups.xml",
"views/sale_order_template_views.xml",
"views/sale_order_views.xml",
],
"installable": True,
"application": False,
}
114 changes: 114 additions & 0 deletions spreadsheet_sale_calculator/i18n/spreadsheet_sale_calculator.pot
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * spreadsheet_sale_calculator
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 19.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-31 17:35+0000\n"
"PO-Revision-Date: 2026-07-31 17:35+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"

#. module: spreadsheet_sale_calculator
#. odoo-python
#: code:addons/spreadsheet_sale_calculator/models/sale_order.py:0
msgid "%s Calculator"
msgstr ""

#. module: spreadsheet_sale_calculator
#. odoo-python
#: code:addons/spreadsheet_sale_calculator/models/sale_order.py:0
msgid "Cannot write calculator values into a cancelled order."
msgstr ""

#. module: spreadsheet_sale_calculator
#: model_terms:ir.ui.view,arch_db:spreadsheet_sale_calculator.view_order_form_spreadsheet_calculator
msgid ""
"Discard the current calculator and rebuild it from the selected template"
msgstr ""

#. module: spreadsheet_sale_calculator
#: model:ir.model.fields,field_description:spreadsheet_sale_calculator.field_sale_order__display_name
#: model:ir.model.fields,field_description:spreadsheet_sale_calculator.field_sale_order_template__display_name
#: model:ir.model.fields,field_description:spreadsheet_sale_calculator.field_spreadsheet_spreadsheet__display_name
msgid "Display Name"
msgstr ""

#. module: spreadsheet_sale_calculator
#: model:ir.model.fields,field_description:spreadsheet_sale_calculator.field_sale_order__show_update_calculator
msgid "Has Quote Calculator Template Changed"
msgstr ""

#. module: spreadsheet_sale_calculator
#: model:ir.model.fields,field_description:spreadsheet_sale_calculator.field_sale_order__id
#: model:ir.model.fields,field_description:spreadsheet_sale_calculator.field_sale_order_template__id
#: model:ir.model.fields,field_description:spreadsheet_sale_calculator.field_spreadsheet_spreadsheet__id
msgid "ID"
msgstr ""

#. module: spreadsheet_sale_calculator
#: model:ir.model,name:spreadsheet_sale_calculator.model_sale_order_template
msgid "Quotation Template"
msgstr ""

#. module: spreadsheet_sale_calculator
#: model:ir.model.fields,field_description:spreadsheet_sale_calculator.field_sale_order__calculator_spreadsheet_id
#: model:ir.model.fields,field_description:spreadsheet_sale_calculator.field_sale_order_template__quote_calculator_id
#: model_terms:ir.ui.view,arch_db:spreadsheet_sale_calculator.view_order_form_spreadsheet_calculator
msgid "Quote Calculator"
msgstr ""

#. module: spreadsheet_sale_calculator
#: model:ir.model.fields,field_description:spreadsheet_sale_calculator.field_sale_order__template_calculator_id
msgid "Quote Calculator Template"
msgstr ""

#. module: spreadsheet_sale_calculator
#: model_terms:ir.ui.view,arch_db:spreadsheet_sale_calculator.view_order_form_spreadsheet_calculator
msgid "Rebuild Calculator"
msgstr ""

#. module: spreadsheet_sale_calculator
#: model:ir.model,name:spreadsheet_sale_calculator.model_sale_order
msgid "Sales Order"
msgstr ""

#. module: spreadsheet_sale_calculator
#: model:ir.model,name:spreadsheet_sale_calculator.model_spreadsheet_spreadsheet
msgid "Spreadsheet"
msgstr ""

#. module: spreadsheet_sale_calculator
#: model:ir.model.fields,help:spreadsheet_sale_calculator.field_sale_order__template_calculator_id
msgid ""
"Spreadsheet copied as this order's quote calculator. Defaults to the one set"
" on the quotation template; pick another to override it."
msgstr ""

#. module: spreadsheet_sale_calculator
#. odoo-python
#: code:addons/spreadsheet_sale_calculator/models/sale_order.py:0
msgid ""
"This order has no quote calculator. Set one on its quotation template first."
msgstr ""

#. module: spreadsheet_sale_calculator
#. odoo-python
#: code:addons/spreadsheet_sale_calculator/models/sale_order.py:0
msgid ""
"This order is locked. Unlock it before writing calculator values into its "
"lines."
msgstr ""

#. module: spreadsheet_sale_calculator
#: model_terms:ir.ui.view,arch_db:spreadsheet_sale_calculator.view_order_form_spreadsheet_calculator
msgid ""
"This will discard the current quote calculator and rebuild it from the "
"selected template. Any changes made in it will be lost."
msgstr ""
3 changes: 3 additions & 0 deletions spreadsheet_sale_calculator/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import spreadsheet_spreadsheet
from . import sale_order
from . import sale_order_template
Loading
Loading