product_sale_price_from_pricelist: add rounding method to compute theroritical price

This commit is contained in:
Luis 2026-04-09 12:48:23 +02:00
parent f775050ea8
commit 489eefefc7
7 changed files with 86 additions and 2 deletions

View file

@ -12,6 +12,7 @@ Automatically calculate and update product sale prices based on the last purchas
- Triple discount - Triple discount
- Manual update - Manual update
- **Tax-Aware Pricing**: Automatically includes tax calculations in pricing - **Tax-Aware Pricing**: Automatically includes tax calculations in pricing
- **Configurable Price Rounding**: Round the final theoretical price (after taxes) to a configurable step, with choice of rounding direction
- **UoM Conversion**: Handles different purchase and sale units of measure - **UoM Conversion**: Handles different purchase and sale units of measure
- **Batch Updates**: Update theoretical prices for multiple products - **Batch Updates**: Update theoretical prices for multiple products
- **Product Flags**: Mark products for price updates and track status - **Product Flags**: Mark products for price updates and track status
@ -23,7 +24,17 @@ Automatically calculate and update product sale prices based on the last purchas
- **Last purchase price**: Cost at which the product was last purchased - **Last purchase price**: Cost at which the product was last purchased
- **Last purchase price calculation type**: Choose how to apply discounts - **Last purchase price calculation type**: Choose how to apply discounts
- Mark **Last purchase price updated** when prices need to be reviewed - Mark **Last purchase price updated** when prices need to be reviewed
## Price Rounding
Pricelist can be configured to round the final theoretical price (after taxes) to a fixed step:
- **Sale Price Rounding Step**: Interval to round to (e.g. `0.05` rounds to the nearest 5 cents). Set to `0.00` to disable.
- **Sale Price Rounding Method**: Direction applied when rounding:
- **Always up (ceil)**: rounds to the next multiple of the step *(default)*
- **Always down (floor)**: rounds to the previous multiple of the step
- **Nearest (round)**: rounds to the closest multiple of the step
These settings are found on pricelist form under the **Sale Price Rounding** group.
## Price Calculation Types ## Price Calculation Types
- **Without Discounts**: Uses base purchase price without discounts - **Without Discounts**: Uses base purchase price without discounts

View file

@ -1,6 +1,6 @@
{ {
"name": "Product Sale Price from Pricelist", "name": "Product Sale Price from Pricelist",
"version": "16.0.1.0.0", "version": "16.0.1.1.0",
"category": "product", "category": "product",
"summary": "Set sale price from pricelist based on last purchase price", "summary": "Set sale price from pricelist based on last purchase price",
"description": """ "description": """

View file

@ -27,6 +27,31 @@ msgstr "Redondeo del precio de venta"
msgid "Round the theoretical sale price (after taxes) to the nearest multiple of this value. Set to 0.00 to disable rounding (e.g. 0.05 rounds to the nearest 5 cents)." msgid "Round the theoretical sale price (after taxes) to the nearest multiple of this value. Set to 0.00 to disable rounding (e.g. 0.05 rounds to the nearest 5 cents)."
msgstr "Redondea el precio de venta teórico (con impuestos) al múltiplo más cercano de este valor. Pon 0,00 para desactivar el redondeo (p. ej. 0,05 redondea al céntimo más cercano de 5)." msgstr "Redondea el precio de venta teórico (con impuestos) al múltiplo más cercano de este valor. Pon 0,00 para desactivar el redondeo (p. ej. 0,05 redondea al céntimo más cercano de 5)."
#. module: product_sale_price_from_pricelist
#: model:ir.model.fields,field_description:product_sale_price_from_pricelist.field_product_pricelist__price_rounding_method
msgid "Sale Price Rounding Method"
msgstr "Dirección del redondeo"
#. module: product_sale_price_from_pricelist
#: model:ir.model.fields,help:product_sale_price_from_pricelist.field_product_pricelist__price_rounding_method
msgid "Direction to apply when rounding the theoretical sale price to the configured step.\n* Always up: rounds to the next multiple (ceil).\n* Always down: rounds to the previous multiple (floor).\n* Nearest: rounds to the closest multiple (standard round)."
msgstr "Dirección a aplicar al redondear el precio de venta teórico al escalón configurado.\n* Siempre arriba: redondea al siguiente múltiplo (techo).\n* Siempre abajo: redondea al múltiplo anterior (suelo).\n* Más cercano: redondea al múltiplo más próximo (redondeo estándar)."
#. module: product_sale_price_from_pricelist
#: model:ir.model.fields.selection,name:product_sale_price_from_pricelist.selection__product_pricelist__price_rounding_method__up
msgid "Always up (ceil)"
msgstr "Siempre arriba (techo)"
#. module: product_sale_price_from_pricelist
#: model:ir.model.fields.selection,name:product_sale_price_from_pricelist.selection__product_pricelist__price_rounding_method__down
msgid "Always down (floor)"
msgstr "Siempre abajo (suelo)"
#. module: product_sale_price_from_pricelist
#: model:ir.model.fields.selection,name:product_sale_price_from_pricelist.selection__product_pricelist__price_rounding_method__round
msgid "Nearest (round)"
msgstr "Más cercano (redondeo)"
#. module: product_sale_price_from_pricelist #. module: product_sale_price_from_pricelist
#: model:ir.model.fields,field_description:product_sale_price_from_pricelist.field_product_product__configured_sale_margin #: model:ir.model.fields,field_description:product_sale_price_from_pricelist.field_product_product__configured_sale_margin
#: model:ir.model.fields,field_description:product_sale_price_from_pricelist.field_product_template__configured_sale_margin #: model:ir.model.fields,field_description:product_sale_price_from_pricelist.field_product_template__configured_sale_margin

View file

@ -25,6 +25,31 @@ msgstr ""
msgid "Round the theoretical sale price (after taxes) to the nearest multiple of this value. Set to 0.00 to disable rounding (e.g. 0.05 rounds to the nearest 5 cents)." msgid "Round the theoretical sale price (after taxes) to the nearest multiple of this value. Set to 0.00 to disable rounding (e.g. 0.05 rounds to the nearest 5 cents)."
msgstr "" msgstr ""
#. module: product_sale_price_from_pricelist
#: model:ir.model.fields,field_description:product_sale_price_from_pricelist.field_product_pricelist__price_rounding_method
msgid "Sale Price Rounding Method"
msgstr ""
#. module: product_sale_price_from_pricelist
#: model:ir.model.fields,help:product_sale_price_from_pricelist.field_product_pricelist__price_rounding_method
msgid "Direction to apply when rounding the theoretical sale price to the configured step.\n* Always up: rounds to the next multiple (ceil).\n* Always down: rounds to the previous multiple (floor).\n* Nearest: rounds to the closest multiple (standard round)."
msgstr ""
#. module: product_sale_price_from_pricelist
#: model:ir.model.fields.selection,name:product_sale_price_from_pricelist.selection__product_pricelist__price_rounding_method__up
msgid "Always up (ceil)"
msgstr ""
#. module: product_sale_price_from_pricelist
#: model:ir.model.fields.selection,name:product_sale_price_from_pricelist.selection__product_pricelist__price_rounding_method__down
msgid "Always down (floor)"
msgstr ""
#. module: product_sale_price_from_pricelist
#: model:ir.model.fields.selection,name:product_sale_price_from_pricelist.selection__product_pricelist__price_rounding_method__round
msgid "Nearest (round)"
msgstr ""
#. module: product_sale_price_from_pricelist #. module: product_sale_price_from_pricelist
#: model:ir.model.fields,field_description:product_sale_price_from_pricelist.field_product_product__configured_sale_margin #: model:ir.model.fields,field_description:product_sale_price_from_pricelist.field_product_product__configured_sale_margin
#: model:ir.model.fields,field_description:product_sale_price_from_pricelist.field_product_template__configured_sale_margin #: model:ir.model.fields,field_description:product_sale_price_from_pricelist.field_product_template__configured_sale_margin

View file

@ -19,6 +19,20 @@ class ProductPricelist(models.Model):
help="Round the theoretical sale price (after taxes) to the nearest multiple of this value. " help="Round the theoretical sale price (after taxes) to the nearest multiple of this value. "
"Set to 0.00 to disable rounding (e.g. 0.05 rounds to the nearest 5 cents).", "Set to 0.00 to disable rounding (e.g. 0.05 rounds to the nearest 5 cents).",
) )
price_rounding_method = fields.Selection(
[
("up", "Always up (ceil)"),
("down", "Always down (floor)"),
("round", "Nearest (round)"),
],
string="Sale Price Rounding Method",
default="round",
required=True,
help="Direction to apply when rounding the theoretical sale price to the configured step.\n"
"* Always up: rounds to the next multiple (ceil).\n"
"* Always down: rounds to the previous multiple (floor).\n"
"* Nearest: rounds to the closest multiple (standard round).",
)
def _compute_price_rule(self, products, qty, uom=None, date=False, **kwargs): def _compute_price_rule(self, products, qty, uom=None, date=False, **kwargs):
ProductPricelistItem = self.env["product.pricelist.item"] ProductPricelistItem = self.env["product.pricelist.item"]

View file

@ -130,7 +130,15 @@ class ProductTemplate(models.Model):
# Round to configurable step (defined on the pricelist) # Round to configurable step (defined on the pricelist)
step = pricelist.price_rounding_step step = pricelist.price_rounding_step
if step: if step:
price_with_taxes = math.ceil(price_with_taxes / step) * step method = pricelist.price_rounding_method
if method == "down":
price_with_taxes = (
math.floor(price_with_taxes / step) * step
)
elif method == "round":
price_with_taxes = round(price_with_taxes / step) * step
else: # "up" (default)
price_with_taxes = math.ceil(price_with_taxes / step) * step
template.write( template.write(
{ {

View file

@ -49,6 +49,7 @@
<xpath expr="//page[@name='pricelist_config']//group[@name='pricelist_availability']" position="after"> <xpath expr="//page[@name='pricelist_config']//group[@name='pricelist_availability']" position="after">
<group name="pricelist_rounding" string="Sale Price Rounding"> <group name="pricelist_rounding" string="Sale Price Rounding">
<field name="price_rounding_step" /> <field name="price_rounding_step" />
<field name="price_rounding_method" />
</group> </group>
</xpath> </xpath>
</field> </field>