diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/delivery/models/delivery_grid.py | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/delivery/models/delivery_grid.py')
| -rw-r--r-- | addons/delivery/models/delivery_grid.py | 138 |
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() |
