diff --git a/product_update_price_last_purchase/__init__.py b/product_update_price_last_purchase/__init__.py
index 2ed39cb..0650744 100644
--- a/product_update_price_last_purchase/__init__.py
+++ b/product_update_price_last_purchase/__init__.py
@@ -1,3 +1 @@
from . import models
-from . import report
-
diff --git a/product_update_price_last_purchase/__manifest__.py b/product_update_price_last_purchase/__manifest__.py
index 8e94770..1159df3 100644
--- a/product_update_price_last_purchase/__manifest__.py
+++ b/product_update_price_last_purchase/__manifest__.py
@@ -1,32 +1,29 @@
{
- 'name': 'Product Update Price From Last Purchase',
- 'version': "16.0.1.0.0",
- 'category': 'purchase',
- 'summary' : 'Product Update Price From Last Purchase',
- 'description' : """
+ "name": "Product Update Price From Last Purchase",
+ "version": "16.0.1.0.0",
+ "category": "purchase",
+ "summary": """"
Personaliza el comportamiento de Product para supermercados:
- * setea los impuestos del proveedor al mismo tipo que el impuesto de venta.
- * Actualiza el precio de venta según el precio de coste aplicado a una tarifa.
- * Filtro para productos actualizados el precio de coste.
+ * Campo que guarda el último precio de compra en vez de usar standard_price
+ y no afectar a la valoración de inventario.
+ * Actualiza el precio de venta según el último precio de coste aplicado a una tarifa.
+ * Filtro para productos actualizados el último precio de coste.
* Filtro para productos que necesitan etiqueta nueva.
- * Campo que guarda el último precio de compra en vez de usar standard_price y no afectar a la valoración de inventario.
- """,
- 'author': 'Criptomart',
- 'website': 'https://criptomart.net',
- 'license': 'AGPL-3',
- 'depends': [
- 'base',
- 'product',
- 'account',
- 'stock_account',
+ """,
+ "author": "Criptomart",
+ "website": "https://criptomart.net",
+ "license": "AGPL-3",
+ "depends": [
+ "account",
+ "stock_account",
+ "sale",
+ "product_margin_classification",
+ "product_print_category",
],
- 'data': [
- 'views/actions.xml',
- 'views/product_view.xml',
- 'data/report_paperformat.xml',
- 'report/report_product_shelf_tag.xml',
- #'report/report_product_barcode.xml',
- #'report/product_barcode.xml'
+ "data": [
+ "views/actions.xml",
+ "views/product_view.xml",
+ "views/res_config.xml",
],
- 'installable': True,
+ "installable": True,
}
diff --git a/product_update_price_last_purchase/data/report_paperformat.xml b/product_update_price_last_purchase/data/report_paperformat.xml
deleted file mode 100644
index 03e74be..0000000
--- a/product_update_price_last_purchase/data/report_paperformat.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
- Barcodes stickers format
-
- A4
- 0
- 0
- Portrait
- 10
- 5
- 8
- 8
-
- 0
- 75
-
-
-
diff --git a/product_update_price_last_purchase/models/__init__.py b/product_update_price_last_purchase/models/__init__.py
index e23f31b..6440ced 100644
--- a/product_update_price_last_purchase/models/__init__.py
+++ b/product_update_price_last_purchase/models/__init__.py
@@ -1,8 +1,4 @@
from . import product_template
from . import product_product
-from . import res_company
from . import res_config
-from . import ir_actions_report
from . import stock_move
-from . import product_pricelist
-from . import product_pricelist_item
diff --git a/product_update_price_last_purchase/models/ir_actions_report.py b/product_update_price_last_purchase/models/ir_actions_report.py
deleted file mode 100644
index 4faf6d1..0000000
--- a/product_update_price_last_purchase/models/ir_actions_report.py
+++ /dev/null
@@ -1,21 +0,0 @@
-import logging
-
-from odoo import api, fields, models
-
-_logger = logging.getLogger(__name__)
-
-class IrActionsReport(models.Model):
- _inherit = 'ir.actions.report'
-
- def render_qweb_pdf(self, res_ids=None, data=None):
- _logger.debug("render_qweb_pdf : %s -- %s" %(res_ids, data))
- if res_ids:
- Model = self.env[self.model]
- record_ids = Model.browse(res_ids)
- wk_record_ids = Model
- for record_id in record_ids:
- if self.report_name == "product.report_producttemplatelabel":
- record_id.to_print = False
- return super(IrActionsReport, self).render_qweb_pdf(res_ids, data)
-
-
diff --git a/product_update_price_last_purchase/models/product_pricelist.py b/product_update_price_last_purchase/models/product_pricelist.py
deleted file mode 100644
index 15ffb29..0000000
--- a/product_update_price_last_purchase/models/product_pricelist.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# Copyright (C) 2020: Criptomart (https://criptomart.net)
-# @author Santi Noreña ()
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-
-from odoo import api, models
-
-
-class ProductPricelist(models.Model):
- _inherit = 'product.pricelist'
-
- def _compute_price_rule(self, products_qty_partner, date=False, uom_id=False):
- ProductPricelistItem = self.env['product.pricelist.item']
- ProductProduct = self.env['product.product']
- res = super()._compute_price_rule(products_qty_partner, date=date, uom_id=uom_id)
- new_res = res.copy()
- item_id = []
- for product_id, values in res.items():
- if values[1]:
- item_id = values[1]
- if item_id:
- item = ProductPricelistItem.browse(item_id)
- if item.base == 'last_purchase_price':
- product = ProductProduct.browse(product_id)
- new_res[product_id] = (product.last_purchase_price, item_id)
- return new_res
diff --git a/product_update_price_last_purchase/models/product_pricelist_item.py b/product_update_price_last_purchase/models/product_pricelist_item.py
deleted file mode 100644
index 36f1b80..0000000
--- a/product_update_price_last_purchase/models/product_pricelist_item.py
+++ /dev/null
@@ -1,12 +0,0 @@
-# Copyright (C) 2020: Criptomart (https://criptomart.net)
-# @author Santi Noreña ()
-# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-
-from odoo import fields, models
-
-
-class ProductPricelistItem(models.Model):
- _inherit = 'product.pricelist.item'
-
- base = fields.Selection(selection_add=[
- ('last_purchase_price', 'Last purchase price')])
diff --git a/product_update_price_last_purchase/models/product_product.py b/product_update_price_last_purchase/models/product_product.py
index aa2d836..ca2d585 100644
--- a/product_update_price_last_purchase/models/product_product.py
+++ b/product_update_price_last_purchase/models/product_product.py
@@ -4,21 +4,54 @@
import logging
-from odoo import models, fields, api
+from odoo import api, fields, models
_logger = logging.getLogger(__name__)
+
class ProductProduct(models.Model):
_inherit = "product.product"
- def write(self, vals):
- if vals.get('last_purchase_price'):
- vals['list_price_updated'] = True
- return super(ProductProduct, self).write(vals)
+ @api.depends(
+ "standard_price",
+ "last_purchase_price_received",
+ "lst_price",
+ "margin_classification_id",
+ "margin_classification_id.markup",
+ "margin_classification_id.price_round",
+ "margin_classification_id.price_surcharge",
+ "product_tmpl_id.taxes_id",
+ "product_tmpl_id.list_price",
+ )
+ def _compute_theoretical_multi(self):
+ res = super()._compute_theoretical_multi()
+ for product in self:
+ if product.last_purchase_price_received != 0:
+ (
+ product.margin_state,
+ product.theoretical_price,
+ product.theoretical_difference,
+ ) = self._get_margin_info(
+ product.margin_classification_id,
+ product.taxes_id,
+ product.name,
+ product.last_purchase_price_received,
+ product.lst_price,
+ )
+ return res
+
+ def use_theoretical_price(self):
+ res = super().use_theoretical_price()
+ for product in self:
+ product.to_print_label = True
+ return res
class ProductPackaging(models.Model):
_inherit = "product.packaging"
- qty = fields.Float('Contained Quantity', help="The total number of products you can have per pallet or box.", digits='Product Unit of Measure')
-
+ qty = fields.Float(
+ "Contained Quantity",
+ help="The total number of products you can have per pallet or box.",
+ digits="Product Unit of Measure",
+ )
diff --git a/product_update_price_last_purchase/models/product_template.py b/product_update_price_last_purchase/models/product_template.py
index d94e7e1..a6c766e 100644
--- a/product_update_price_last_purchase/models/product_template.py
+++ b/product_update_price_last_purchase/models/product_template.py
@@ -3,136 +3,88 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import logging
-import math
-from odoo import exceptions, models, fields, api, _
-from odoo.exceptions import UserError
+from odoo import api, fields, models
_logger = logging.getLogger(__name__)
+MARGIN_STATE_SELECTION = [
+ ("correct", "Correct Margin"),
+ ("too_cheap", "Too Cheap"),
+ ("too_expensive", "Too Expensive"),
+]
+
+
class ProductTemplate(models.Model):
_inherit = "product.template"
- def _compute_theoritical_price(self):
- partner = self.env['res.users'].browse(self.env.uid).partner_id
- pricelist_obj = self.env['product.pricelist']
- pricelist_id = self.env['ir.config_parameter'].sudo().get_param('product_update_price_last_purchase.product_pricelist_automatic') or False
- pricelist = pricelist_obj.browse(int(pricelist_id))
- _logger.debug("Calculating price with PriceList : %s" %pricelist.name)
- if pricelist:
- for template in self:
- if template.name and template.id and template.product_variant_id and template.last_purchase_price_compute_type != 'manual_update':
- partial_price = pricelist.get_product_price(template.product_variant_id, "1", partner)
- _logger.debug("partial_price : %s" %partial_price)
- # Suma el IVA
- for tax in template.taxes_id:
- partial_price = partial_price * ( 1 + ( tax.amount / 100) )
- _logger.debug("partial_price after taxes : %s" %partial_price)
- # Redondea a 0,05 de precisión
- template.list_price = round(round(partial_price / 0.05) * 0.05, -int(math.floor(math.log10(0.05))))
- _logger.debug("final price : %s" %template.list_price)
- template.list_price_updated = False
- else:
- raise UserError(_('Not found a valid pricelist to compute sale price. Check configuration in General Settings.'))
- return False
-
- list_price = fields.Float(
- string="Sale price with VAT",
- help="Price calculated according to the configured pricelist, including VAT.",
- digits='Product Price'
+ margin_state = fields.Selection(
+ string="Theoretical Price State",
+ compute="_compute_theoretical_multi_template",
+ selection=MARGIN_STATE_SELECTION,
+ store=True,
)
- list_price_updated = fields.Boolean(
- string="Last purchase price updated",
- help="The last cost price has been updated and you need to update the selling price in the database, shelves and scales.",
- default=False,
- readonly=True
- )
-
- list_price_automatic = fields.Boolean(
- string="Automatic Sale Price",
- help="Automatic computation of the PVP from the cost price and the rate defined in the configuration.",
- default=True
- )
-
- to_print = fields.Boolean(
+ to_print_label = fields.Boolean(
string="To print label",
- help="The sale price has been updated on this product and needs to be updated on the shelf.",
+ help="""The sale price has been updated on this product
+ and needs to be updated on the shelf.""",
default=False,
- readonly=True
+ readonly=True,
)
- last_purchase_price = fields.Float(
+ last_purchase_price_received = fields.Float(
string="Last purchase price",
- help="The last price at which the product was purchased. It is used as the base price field for calculating the product sale price.",
- #readonly=True,
- digits='Product Price'
+ help="The last price at which the product was purchased. "
+ "It is used as the base price field for calculating the product sale price.",
+ readonly=True,
+ digits="Product Price",
)
-
- last_purchase_price_compute_type = fields.Selection([
- ('without_discounts', 'Without discounts'),
- ('with_discount', 'First discount'),
- ('with_three_discounts', 'Triple discount'),
- ('manual_update', 'Manual update')],
+
+ last_purchase_price_received_compute_type = fields.Selection(
+ [
+ ("without_discounts", "Without discounts"),
+ ("with_discount", "First discount"),
+ ("with_three_discounts", "Triple discount"),
+ ("manual_update", "Manual update"),
+ ],
string="Last purchase price calculation type",
- help='Choose whether discounts should influence the calculation of the last purchase price. Select Never update for manual configuration of cost and sale prices.\n'
- '\n* Without discounts: does not take into account discounts when updating the last purchase price.\n'
- '* First discount: take into account only first discount when updating the last purchase price.\n'
- '* Triple discount: take into account all discounts when updating the last purchase price. Needs "Purchase Triple Discount" OCA module.\n'
- '* Manual update: Select this for manual configuration of cost and sale price. The sales price will not be calculated automatically.',
- default='without_discounts',
- required=True
+ help="""
+ Choose whether discounts should influence the calculation of the last purchase price.
+ Select Never update for manual configuration of cost and sale prices.\n
+ * Without discounts: does not take into account discounts when updating
+ the last purchase price.\n
+ * First discount: take into account only first discount when updating
+ the last purchase price.\n
+ * Triple discount: take into account all discounts when updating
+ the last purchase price.
+ Needs "Purchase Triple Discount" OCA module.\n
+ * Manual update: Select this for manual configuration of cost and sale price.
+ The sales price will not be calculated automatically.
+ """,
+ default="without_discounts",
+ required=True,
)
- @api.model
- def create(self, vals):
- # Set supplier tax same than customer tax
- if vals.get('taxes_id'):
- tax = self.get_supplier_tax(vals.get('taxes_id'))
- vals['supplier_taxes_id'] = tax
- vals['list_price_updated'] = True
- return super(ProductTemplate, self).create(vals)
-
- def write(self, vals):
- # Set supplier tax same than customer tax
- if vals.get('taxes_id'):
- tax = self.get_supplier_tax(vals.get('taxes_id'))
- vals['supplier_taxes_id'] = tax
- # Mark if product needs list price update
- if vals.get('last_purchase_price'):
- vals['list_price_updated'] = True
- # Mark if product needs update the shelf tag
- if vals.get('list_price'):
- vals['to_print'] = True
- return super(ProductTemplate, self).write(vals)
-
- def get_supplier_tax(self, taxes_id):
- tax_obj = self.env['account.tax']
- tax_res = []
- if taxes_id:
- if "6, False, []" not in taxes_id:
- for tupla in taxes_id:
- a, b, c = tupla
- if c:
- for i in c:
- tax = tax_obj.browse(i)
- val = tax.amount
- if val == 21:
- record_id = self.env.ref('l10n_es.1_account_tax_template_p_iva21_bc').id
- elif val == 10:
- record_id = self.env.ref('l10n_es.1_account_tax_template_p_iva10_bc').id
- elif val == 4:
- record_id = self.env.ref('l10n_es.1_account_tax_template_p_iva4_bc').id
- else:
- record_id = self.env['account.tax'].search([
- ('amount','=', val),
- ('active','=', True),
- ('type_tax_use','=','purchase')
- ],
- limit=1).id
- tax_res.append(record_id)
-
- return [(6, 0, tax_res)]
-
-
-
+ @api.onchange(
+ "last_purchase_price_received",
+ "standard_price",
+ "taxes_id",
+ "margin_classification_id",
+ "list_price",
+ )
+ def _onchange_standard_price(self):
+ res = super()._onchange_standard_price()
+ if self.last_purchase_price_received != 0:
+ (
+ self.margin_state,
+ self.theoretical_price,
+ self.theoretical_difference,
+ ) = self.env["product.product"]._get_margin_info(
+ self.margin_classification_id,
+ self.taxes_id,
+ self.name,
+ self.last_purchase_price_received,
+ self.list_price,
+ )
+ return res
diff --git a/product_update_price_last_purchase/models/res_company.py b/product_update_price_last_purchase/models/res_company.py
deleted file mode 100644
index 4d7b39b..0000000
--- a/product_update_price_last_purchase/models/res_company.py
+++ /dev/null
@@ -1,17 +0,0 @@
-#import logging
-
-from odoo import models, fields, api
-
-#_logger = logging.getLogger(__name__)
-
-class ResCompany(models.Model):
- _inherit = "res.company"
-
- product_pricelist_automatic = fields.Many2one(
- comodel_name='product.pricelist',
- string='Pricelist applied to the automatic selling price',
- help='Rate that applies to all products that update the selling price automatically.',
- )
-
-
-
diff --git a/product_update_price_last_purchase/models/res_config.py b/product_update_price_last_purchase/models/res_config.py
index 5aa1510..a44ac0b 100644
--- a/product_update_price_last_purchase/models/res_config.py
+++ b/product_update_price_last_purchase/models/res_config.py
@@ -1,30 +1,12 @@
-from odoo import models, fields, api
+from odoo import fields, models
+
class ResConfigSettings(models.TransientModel):
- _inherit = 'res.config.settings'
-
- product_pricelist_automatic = fields.Many2one(
- related='company_id.product_pricelist_automatic',
- comodel_name='product.pricelist',
- string='Pricelist applied to automatic calculation of sales price',
- readonly=False,
- )
-
- @api.model
- def get_values(self):
- res = super(ResConfigSettings, self).get_values()
- config_obj = self.env["ir.config_parameter"]
- product_pricelist_automatic = config_obj.sudo().get_param(
- "product_update_price_last_purchase.product_pricelist_automatic", default=0)
- return res
-
- def set_values(self):
- super(ResConfigSettings, self).set_values()
- config_obj = self.env["ir.config_parameter"]
- config_obj.sudo().set_param(
- "product_update_price_last_purchase.product_pricelist_automatic",
- int(self.product_pricelist_automatic.id)
- )
-
-
+ _inherit = "res.config.settings"
+ product_pricelist_automatic = fields.Many2one(
+ required=False,
+ comodel_name="product.pricelist",
+ string="Pricelist applied to automatic calculation of sales price",
+ config_parameter="product_update_price_last_purchase.product_pricelist_automatic",
+ )
diff --git a/product_update_price_last_purchase/models/stock_move.py b/product_update_price_last_purchase/models/stock_move.py
index 41a0b5e..aad3091 100644
--- a/product_update_price_last_purchase/models/stock_move.py
+++ b/product_update_price_last_purchase/models/stock_move.py
@@ -5,28 +5,56 @@
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import logging
-import math
-from odoo import exceptions, models, fields, api, _
-from odoo.tools import float_is_zero, float_round, float_compare
+from odoo import models
+from odoo.tools import float_compare, float_is_zero, float_round
_logger = logging.getLogger(__name__)
class StockMove(models.Model):
- _inherit = 'stock.move'
+ _inherit = "stock.move"
def product_price_update_before_done(self):
- super(StockMove, self).product_price_update_before_done()
- for move in self.filtered(lambda move: move.location_id.usage == 'supplier'):
- if move.product_id.last_purchase_price_compute_type == 'with_three_discounts':
- price_updated = float_round(move.purchase_line_id.price_subtotal / move.purchase_line_id.product_qty, precision_digits=2)
- elif move.product_id.last_purchase_price_compute_type == 'with_discount':
- price_updated = float_round(move.purchase_line_id.price_unit * (1 - move.purchase_line_id.discount / 100), precision_digits=2)
+ res = super(StockMove, self).product_price_update_before_done()
+ for move in self.filtered(lambda move: move.location_id.usage == "supplier"):
+ if (
+ move.product_id.last_purchase_price_received_compute_type
+ == "with_three_discounts"
+ ):
+ price_updated = float_round(
+ move.purchase_line_id.price_subtotal
+ / move.purchase_line_id.product_qty,
+ precision_digits=2,
+ )
+ elif (
+ move.product_id.last_purchase_price_received_compute_type
+ == "with_discount"
+ ):
+ price_updated = float_round(
+ move.purchase_line_id.price_unit
+ * (1 - move.purchase_line_id.discount / 100),
+ precision_digits=2,
+ )
else:
price_updated = move.purchase_line_id.price_unit
-
- if float_compare(move.product_id.last_purchase_price, price_updated, precision_digits=2) and not float_is_zero(move.quantity_done, precision_digits=3):
- _logger.info("Update last_purchase_price: %s for product %s Previous price: %s" % (price_updated, move.product_id.default_code, move.product_id.last_purchase_price))
- # Write the last purchase price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products
- move.product_id.with_context(force_company=move.company_id.id).sudo().write({'last_purchase_price': price_updated})
+
+ if float_compare(
+ move.product_id.last_purchase_price_received,
+ price_updated,
+ precision_digits=2,
+ ) and not float_is_zero(move.quantity_done, precision_digits=3):
+ _logger.info(
+ "Update last_purchase_price_received: %s for product %s Previous price: %s"
+ % (
+ price_updated,
+ move.product_id.default_code,
+ move.product_id.last_purchase_price_received,
+ )
+ )
+ # Write last purchase price as SUPERUSER_ID
+ # warehouse manager may not have the right to write on products
+ move.product_id.with_company(move.company_id.id).sudo().write(
+ {"last_purchase_price_received": price_updated}
+ )
+ return res
diff --git a/product_update_price_last_purchase/report/product_barcode.xml b/product_update_price_last_purchase/report/product_barcode.xml
deleted file mode 100644
index 1cbce8c..0000000
--- a/product_update_price_last_purchase/report/product_barcode.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/product_update_price_last_purchase/report/report_product_barcode.xml b/product_update_price_last_purchase/report/report_product_barcode.xml
deleted file mode 100644
index e7a69fc..0000000
--- a/product_update_price_last_purchase/report/report_product_barcode.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
No barcode
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/product_update_price_last_purchase/report/report_product_shelf_tag.xml b/product_update_price_last_purchase/report/report_product_shelf_tag.xml
deleted file mode 100644
index 399d3d4..0000000
--- a/product_update_price_last_purchase/report/report_product_shelf_tag.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- /
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/product_update_price_last_purchase/views/actions.xml b/product_update_price_last_purchase/views/actions.xml
index b95ef88..04c6e36 100644
--- a/product_update_price_last_purchase/views/actions.xml
+++ b/product_update_price_last_purchase/views/actions.xml
@@ -1,24 +1,23 @@
-
+
-
Update Sales Price
-
-
+
+
code
- records._compute_theoritical_price()
+ records.use_theoretical_price()
-
-
diff --git a/product_update_price_last_purchase/views/product_view.xml b/product_update_price_last_purchase/views/product_view.xml
index 2201e36..e534cbf 100644
--- a/product_update_price_last_purchase/views/product_view.xml
+++ b/product_update_price_last_purchase/views/product_view.xml
@@ -1,91 +1,66 @@
-
+
-
+
-
-
- product.list.price.automatic.form
- product.template
- form
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ product.list.price.automatic.form
+ product.template
+ form
+
+
+
+
+
+
+
+
-
-
- product_update_price_last_purchase.res.config.settings.form
- res.config.settings
-
-
-
-
- Default pricelists for Coops
-
-
-
-
+
+ product.template.product.tree
+ product.template
+
+
+
+
+
+
+
+
-
-
- view.product.search.form.inherit.updated
- product.template
-
-
-
-
-
-
-
-
-
-
-
- product_update_price_last_purchase.product.search.form.inherit.tags
- product.template
-
-
-
-
-
-
-
-
+
+
+ view.product.search.form.inherit.updated
+ product.template
+
+
+
+
+
+
+
+
+
-
+
diff --git a/product_update_price_last_purchase/views/res_config.xml b/product_update_price_last_purchase/views/res_config.xml
new file mode 100644
index 0000000..1903939
--- /dev/null
+++ b/product_update_price_last_purchase/views/res_config.xml
@@ -0,0 +1,32 @@
+
+
+
+
+ product.update.price.last.purchase.res.config.settings.form
+ res.config.settings
+
+
+
+
+
+
+
+
+
+