summaryrefslogtreecommitdiff
path: root/addons/delivery/models/delivery_grid.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/delivery/models/delivery_grid.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/delivery/models/delivery_grid.py')
-rw-r--r--addons/delivery/models/delivery_grid.py138
1 files changed, 138 insertions, 0 deletions
diff --git a/addons/delivery/models/delivery_grid.py b/addons/delivery/models/delivery_grid.py
new file mode 100644
index 00000000..5f52494d
--- /dev/null
+++ b/addons/delivery/models/delivery_grid.py
@@ -0,0 +1,138 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from odoo import models, fields, api, _
+from odoo.tools.safe_eval import safe_eval
+from odoo.exceptions import UserError, ValidationError
+
+
+class PriceRule(models.Model):
+ _name = "delivery.price.rule"
+ _description = "Delivery Price Rules"
+ _order = 'sequence, list_price, id'
+
+ @api.depends('variable', 'operator', 'max_value', 'list_base_price', 'list_price', 'variable_factor')
+ def _compute_name(self):
+ for rule in self:
+ name = 'if %s %s %.02f then' % (rule.variable, rule.operator, rule.max_value)
+ if rule.list_base_price and not rule.list_price:
+ name = '%s fixed price %.02f' % (name, rule.list_base_price)
+ elif rule.list_price and not rule.list_base_price:
+ name = '%s %.02f times %s' % (name, rule.list_price, rule.variable_factor)
+ else:
+ name = '%s fixed price %.02f plus %.02f times %s' % (name, rule.list_base_price, rule.list_price, rule.variable_factor)
+ rule.name = name
+
+ name = fields.Char(compute='_compute_name')
+ sequence = fields.Integer(required=True, default=10)
+ carrier_id = fields.Many2one('delivery.carrier', 'Carrier', required=True, ondelete='cascade')
+
+ variable = fields.Selection([('weight', 'Weight'), ('volume', 'Volume'), ('wv', 'Weight * Volume'), ('price', 'Price'), ('quantity', 'Quantity')], required=True, default='weight')
+ operator = fields.Selection([('==', '='), ('<=', '<='), ('<', '<'), ('>=', '>='), ('>', '>')], required=True, default='<=')
+ max_value = fields.Float('Maximum Value', required=True)
+ list_base_price = fields.Float(string='Sale Base Price', digits='Product Price', required=True, default=0.0)
+ list_price = fields.Float('Sale Price', digits='Product Price', required=True, default=0.0)
+ variable_factor = fields.Selection([('weight', 'Weight'), ('volume', 'Volume'), ('wv', 'Weight * Volume'), ('price', 'Price'), ('quantity', 'Quantity')], 'Variable Factor', required=True, default='weight')
+
+
+class ProviderGrid(models.Model):
+ _inherit = 'delivery.carrier'
+
+ delivery_type = fields.Selection(selection_add=[
+ ('base_on_rule', 'Based on Rules'),
+ ], ondelete={'base_on_rule': lambda recs: recs.write({
+ 'delivery_type': 'fixed', 'fixed_price': 0,
+ })})
+ price_rule_ids = fields.One2many('delivery.price.rule', 'carrier_id', 'Pricing Rules', copy=True)
+
+ def base_on_rule_rate_shipment(self, order):
+ carrier = self._match_address(order.partner_shipping_id)
+ if not carrier:
+ return {'success': False,
+ 'price': 0.0,
+ 'error_message': _('Error: this delivery method is not available for this address.'),
+ 'warning_message': False}
+
+ try:
+ price_unit = self._get_price_available(order)
+ except UserError as e:
+ return {'success': False,
+ 'price': 0.0,
+ 'error_message': e.args[0],
+ 'warning_message': False}
+ if order.company_id.currency_id.id != order.pricelist_id.currency_id.id:
+ price_unit = order.company_id.currency_id._convert(
+ price_unit, order.pricelist_id.currency_id, order.company_id, order.date_order or fields.Date.today())
+
+ return {'success': True,
+ 'price': price_unit,
+ 'error_message': False,
+ 'warning_message': False}
+
+ def _get_price_available(self, order):
+ self.ensure_one()
+ self = self.sudo()
+ order = order.sudo()
+ total = weight = volume = quantity = 0
+ total_delivery = 0.0
+ for line in order.order_line:
+ if line.state == 'cancel':
+ continue
+ if line.is_delivery:
+ total_delivery += line.price_total
+ if not line.product_id or line.is_delivery:
+ continue
+ qty = line.product_uom._compute_quantity(line.product_uom_qty, line.product_id.uom_id)
+ weight += (line.product_id.weight or 0.0) * qty
+ volume += (line.product_id.volume or 0.0) * qty
+ quantity += qty
+ total = (order.amount_total or 0.0) - total_delivery
+
+ total = order.currency_id._convert(
+ total, order.company_id.currency_id, order.company_id, order.date_order or fields.Date.today())
+
+ return self._get_price_from_picking(total, weight, volume, quantity)
+
+ def _get_price_dict(self, total, weight, volume, quantity):
+ '''Hook allowing to retrieve dict to be used in _get_price_from_picking() function.
+ Hook to be overridden when we need to add some field to product and use it in variable factor from price rules. '''
+ return {
+ 'price': total,
+ 'volume': volume,
+ 'weight': weight,
+ 'wv': volume * weight,
+ 'quantity': quantity
+ }
+
+ def _get_price_from_picking(self, total, weight, volume, quantity):
+ price = 0.0
+ criteria_found = False
+ price_dict = self._get_price_dict(total, weight, volume, quantity)
+ if self.free_over and total >= self.amount:
+ return 0
+ for line in self.price_rule_ids:
+ test = safe_eval(line.variable + line.operator + str(line.max_value), price_dict)
+ if test:
+ price = line.list_base_price + line.list_price * price_dict[line.variable_factor]
+ criteria_found = True
+ break
+ if not criteria_found:
+ raise UserError(_("No price rule matching this order; delivery cost cannot be computed."))
+
+ return price
+
+ def base_on_rule_send_shipping(self, pickings):
+ res = []
+ for p in pickings:
+ carrier = self._match_address(p.partner_id)
+ if not carrier:
+ raise ValidationError(_('There is no matching delivery rule.'))
+ res = res + [{'exact_price': p.carrier_id._get_price_available(p.sale_id) if p.sale_id else 0.0, # TODO cleanme
+ 'tracking_number': False}]
+ return res
+
+ def base_on_rule_get_tracking_link(self, picking):
+ return False
+
+ def base_on_rule_cancel_shipment(self, pickings):
+ raise NotImplementedError()