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/sale_order.py | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/delivery/models/sale_order.py')
| -rw-r--r-- | addons/delivery/models/sale_order.py | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/addons/delivery/models/sale_order.py b/addons/delivery/models/sale_order.py new file mode 100644 index 00000000..89b8bdcf --- /dev/null +++ b/addons/delivery/models/sale_order.py @@ -0,0 +1,189 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import models, fields, api, _ +from odoo.exceptions import UserError + + +class SaleOrder(models.Model): + _inherit = 'sale.order' + + carrier_id = fields.Many2one('delivery.carrier', string="Delivery Method", domain="['|', ('company_id', '=', False), ('company_id', '=', company_id)]", help="Fill this field if you plan to invoice the shipping based on picking.") + delivery_message = fields.Char(readonly=True, copy=False) + delivery_rating_success = fields.Boolean(copy=False) + delivery_set = fields.Boolean(compute='_compute_delivery_state') + recompute_delivery_price = fields.Boolean('Delivery cost should be recomputed') + is_all_service = fields.Boolean("Service Product", compute="_compute_is_service_products") + + @api.depends('order_line') + def _compute_is_service_products(self): + for so in self: + so.is_all_service = all(line.product_id.type == 'service' for line in so.order_line) + + def _compute_amount_total_without_delivery(self): + self.ensure_one() + delivery_cost = sum([l.price_total for l in self.order_line if l.is_delivery]) + return self.amount_total - delivery_cost + + @api.depends('order_line') + def _compute_delivery_state(self): + for order in self: + order.delivery_set = any(line.is_delivery for line in order.order_line) + + @api.onchange('order_line', 'partner_id') + def onchange_order_line(self): + delivery_line = self.order_line.filtered('is_delivery') + if delivery_line: + self.recompute_delivery_price = True + + def _remove_delivery_line(self): + delivery_lines = self.env['sale.order.line'].search([('order_id', 'in', self.ids), ('is_delivery', '=', True)]) + if not delivery_lines: + return + to_delete = delivery_lines.filtered(lambda x: x.qty_invoiced == 0) + if not to_delete: + raise UserError( + _('You can not update the shipping costs on an order where it was already invoiced!\n\nThe following delivery lines (product, invoiced quantity and price) have already been processed:\n\n') + + '\n'.join(['- %s: %s x %s' % (line.product_id.with_context(display_default_code=False).display_name, line.qty_invoiced, line.price_unit) for line in delivery_lines]) + ) + to_delete.unlink() + + def set_delivery_line(self, carrier, amount): + + # Remove delivery products from the sales order + self._remove_delivery_line() + + for order in self: + order.carrier_id = carrier.id + order._create_delivery_line(carrier, amount) + return True + + def action_open_delivery_wizard(self): + view_id = self.env.ref('delivery.choose_delivery_carrier_view_form').id + if self.env.context.get('carrier_recompute'): + name = _('Update shipping cost') + carrier = self.carrier_id + else: + name = _('Add a shipping method') + carrier = ( + self.with_company(self.company_id).partner_shipping_id.property_delivery_carrier_id + or self.with_company(self.company_id).partner_shipping_id.commercial_partner_id.property_delivery_carrier_id + ) + return { + 'name': name, + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'res_model': 'choose.delivery.carrier', + 'view_id': view_id, + 'views': [(view_id, 'form')], + 'target': 'new', + 'context': { + 'default_order_id': self.id, + 'default_carrier_id': carrier.id, + } + } + + def _create_delivery_line(self, carrier, price_unit): + SaleOrderLine = self.env['sale.order.line'] + if self.partner_id: + # set delivery detail in the customer language + carrier = carrier.with_context(lang=self.partner_id.lang) + + # Apply fiscal position + taxes = carrier.product_id.taxes_id.filtered(lambda t: t.company_id.id == self.company_id.id) + taxes_ids = taxes.ids + if self.partner_id and self.fiscal_position_id: + taxes_ids = self.fiscal_position_id.map_tax(taxes, carrier.product_id, self.partner_id).ids + + # Create the sales order line + carrier_with_partner_lang = carrier.with_context(lang=self.partner_id.lang) + if carrier_with_partner_lang.product_id.description_sale: + so_description = '%s: %s' % (carrier_with_partner_lang.name, + carrier_with_partner_lang.product_id.description_sale) + else: + so_description = carrier_with_partner_lang.name + values = { + 'order_id': self.id, + 'name': so_description, + 'product_uom_qty': 1, + 'product_uom': carrier.product_id.uom_id.id, + 'product_id': carrier.product_id.id, + 'tax_id': [(6, 0, taxes_ids)], + 'is_delivery': True, + } + if carrier.invoice_policy == 'real': + values['price_unit'] = 0 + values['name'] += _(' (Estimated Cost: %s )', self._format_currency_amount(price_unit)) + else: + values['price_unit'] = price_unit + if carrier.free_over and self.currency_id.is_zero(price_unit) : + values['name'] += '\n' + 'Free Shipping' + if self.order_line: + values['sequence'] = self.order_line[-1].sequence + 1 + sol = SaleOrderLine.sudo().create(values) + return sol + + def _format_currency_amount(self, amount): + pre = post = u'' + if self.currency_id.position == 'before': + pre = u'{symbol}\N{NO-BREAK SPACE}'.format(symbol=self.currency_id.symbol or '') + else: + post = u'\N{NO-BREAK SPACE}{symbol}'.format(symbol=self.currency_id.symbol or '') + return u' {pre}{0}{post}'.format(amount, pre=pre, post=post) + + @api.depends('order_line.is_delivery', 'order_line.is_downpayment') + def _get_invoice_status(self): + super()._get_invoice_status() + for order in self: + if order.invoice_status in ['no', 'invoiced']: + continue + order_lines = order.order_line.filtered(lambda x: not x.is_delivery and not x.is_downpayment and not x.display_type) + if all(line.product_id.invoice_policy == 'delivery' and line.invoice_status == 'no' for line in order_lines): + order.invoice_status = 'no' + + def _get_estimated_weight(self): + self.ensure_one() + weight = 0.0 + for order_line in self.order_line.filtered(lambda l: l.product_id.type in ['product', 'consu'] and not l.is_delivery and not l.display_type): + weight += order_line.product_qty * order_line.product_id.weight + return weight + + +class SaleOrderLine(models.Model): + _inherit = 'sale.order.line' + + is_delivery = fields.Boolean(string="Is a Delivery", default=False) + product_qty = fields.Float(compute='_compute_product_qty', string='Product Qty', digits='Product Unit of Measure') + recompute_delivery_price = fields.Boolean(related='order_id.recompute_delivery_price') + + @api.depends('product_id', 'product_uom', 'product_uom_qty') + def _compute_product_qty(self): + for line in self: + if not line.product_id or not line.product_uom or not line.product_uom_qty: + line.product_qty = 0.0 + continue + line.product_qty = line.product_uom._compute_quantity(line.product_uom_qty, line.product_id.uom_id) + + def unlink(self): + for line in self: + if line.is_delivery: + line.order_id.carrier_id = False + super(SaleOrderLine, self).unlink() + + def _is_delivery(self): + self.ensure_one() + return self.is_delivery + + # override to allow deletion of delivery line in a confirmed order + def _check_line_unlink(self): + """ + Extend the allowed deletion policy of SO lines. + + Lines that are delivery lines can be deleted from a confirmed order. + + :rtype: recordset sale.order.line + :returns: set of lines that cannot be deleted + """ + + undeletable_lines = super()._check_line_unlink() + return undeletable_lines.filtered(lambda line: not line.is_delivery) |
