19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:32:43 +01:00
parent 4607ccbd2e
commit 825ff6514e
487 changed files with 184979 additions and 195262 deletions

View file

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError, UserError
from odoo.fields import Domain
class LunchOrder(models.Model):
@ -11,23 +12,22 @@ class LunchOrder(models.Model):
_order = 'id desc'
_display_name = 'product_id'
name = fields.Char(related='product_id.name', string="Product Name", store=True, readonly=True)
name = fields.Char(related='product_id.name', string="Product Name", readonly=True)
topping_ids_1 = fields.Many2many('lunch.topping', 'lunch_order_topping', 'order_id', 'topping_id', string='Extras 1', domain=[('topping_category', '=', 1)])
topping_ids_2 = fields.Many2many('lunch.topping', 'lunch_order_topping', 'order_id', 'topping_id', string='Extras 2', domain=[('topping_category', '=', 2)])
topping_ids_3 = fields.Many2many('lunch.topping', 'lunch_order_topping', 'order_id', 'topping_id', string='Extras 3', domain=[('topping_category', '=', 3)])
product_id = fields.Many2one('lunch.product', string="Product", required=True)
category_id = fields.Many2one(
string='Product Category', related='product_id.category_id', store=True)
date = fields.Date('Order Date', required=True, readonly=True,
states={'new': [('readonly', False)]},
date = fields.Date('Order Date', required=True, readonly=False,
default=fields.Date.context_today)
supplier_id = fields.Many2one(
string='Vendor', related='product_id.supplier_id', store=True, index=True)
available_today = fields.Boolean(related='supplier_id.available_today')
order_deadline_passed = fields.Boolean(related='supplier_id.order_deadline_passed')
user_id = fields.Many2one('res.users', 'User', readonly=True,
states={'new': [('readonly', False)]},
default=lambda self: self.env.uid)
available_on_date = fields.Boolean(compute='_compute_available_on_date')
order_deadline_passed = fields.Boolean(compute='_compute_order_deadline_passed')
user_id = fields.Many2one('res.users', 'User', default=lambda self: self.env.uid)
lunch_location_id = fields.Many2one('lunch.location', default=lambda self: self.env.user.last_lunch_location_id)
note = fields.Text('Notes')
price = fields.Monetary('Total Price', compute='_compute_total_price', readonly=True, store=True)
@ -59,6 +59,9 @@ class LunchOrder(models.Model):
available_toppings_2 = fields.Boolean(help='Are extras available for this product', compute='_compute_available_toppings')
available_toppings_3 = fields.Boolean(help='Are extras available for this product', compute='_compute_available_toppings')
display_reorder_button = fields.Boolean(compute='_compute_display_reorder_button')
display_add_button = fields.Boolean(compute='_compute_display_add_button')
_user_product_date = models.Index("(user_id, product_id, date)")
@api.depends('product_id')
def _compute_product_images(self):
@ -73,6 +76,22 @@ class LunchOrder(models.Model):
order.available_toppings_2 = bool(order.env['lunch.topping'].search_count([('supplier_id', '=', order.supplier_id.id), ('topping_category', '=', 2)]))
order.available_toppings_3 = bool(order.env['lunch.topping'].search_count([('supplier_id', '=', order.supplier_id.id), ('topping_category', '=', 3)]))
@api.depends('name')
def _compute_display_add_button(self):
new_orders = dict(self.env["lunch.order"]._read_group([
("date", "in", self.mapped("date")),
("user_id", "in", self.user_id.ids),
("state", "=", "new"),
], ['user_id'], ['id:recordset']))
for order in self:
user_new_orders = new_orders.get(order.user_id)
price = 0
if user_new_orders:
user_new_orders = user_new_orders.filtered(lambda lunch_order: lunch_order.date == order.date)
price = sum(order.price for order in user_new_orders)
wallet_amount = self.env['lunch.cashmove'].get_wallet_balance(order.user_id) - price
order.display_add_button = wallet_amount >= order.price
@api.depends_context('show_reorder_button')
@api.depends('state')
def _compute_display_reorder_button(self):
@ -80,26 +99,44 @@ class LunchOrder(models.Model):
for order in self:
order.display_reorder_button = show_button and order.state == 'confirmed' and order.supplier_id.available_today
def init(self):
self._cr.execute("""CREATE INDEX IF NOT EXISTS lunch_order_user_product_date ON %s (user_id, product_id, date)"""
% self._table)
@api.depends('date', 'supplier_id')
def _compute_available_on_date(self):
for order in self:
order.available_on_date = order.supplier_id._available_on_date(order.date)
@api.depends('supplier_id', 'date')
def _compute_order_deadline_passed(self):
today = fields.Date.context_today(self)
for order in self:
if order.date < today:
order.order_deadline_passed = True
elif order.date == today:
order.order_deadline_passed = order.supplier_id.order_deadline_passed
else:
order.order_deadline_passed = False
def _get_topping_ids(self, field, values):
return list(self._fields[field].convert_to_cache(values, self))
def _extract_toppings(self, values):
"""
If called in api.multi then it will pop topping_ids_1,2,3 from values
"""
if self.ids:
# TODO This is not taking into account all the toppings for each individual order, this is usually not a problem
# since in the interface you usually don't update more than one order at a time but this is a bug nonetheless
topping_1 = values.pop('topping_ids_1')[0][2] if 'topping_ids_1' in values else self[:1].topping_ids_1.ids
topping_2 = values.pop('topping_ids_2')[0][2] if 'topping_ids_2' in values else self[:1].topping_ids_2.ids
topping_3 = values.pop('topping_ids_3')[0][2] if 'topping_ids_3' in values else self[:1].topping_ids_3.ids
else:
topping_1 = values['topping_ids_1'][0][2] if 'topping_ids_1' in values else []
topping_2 = values['topping_ids_2'][0][2] if 'topping_ids_2' in values else []
topping_3 = values['topping_ids_3'][0][2] if 'topping_ids_3' in values else []
topping_ids = []
return topping_1 + topping_2 + topping_3
for i in range(1, 4):
topping_field = f'topping_ids_{i}'
topping_values = values.get(topping_field, False)
if self.ids:
# TODO This is not taking into account all the toppings for each individual order, this is usually not a problem
# since in the interface you usually don't update more than one order at a time but this is a bug nonetheless
topping_ids += self._get_topping_ids(topping_field, values.pop(topping_field)) \
if topping_values else self[:1][topping_field].ids
else:
topping_ids += self._get_topping_ids(topping_field, topping_values) if topping_values else []
return topping_ids
@api.constrains('topping_ids_1', 'topping_ids_2', 'topping_ids_3')
def _check_topping_quantity(self):
@ -126,8 +163,9 @@ class LunchOrder(models.Model):
lines = self._find_matching_lines({
**vals,
'toppings': self._extract_toppings(vals),
'state': 'new',
})
if lines.filtered(lambda l: l.state not in ['sent', 'confirmed']):
if lines:
# YTI FIXME This will update multiple lines in the case there are multiple
# matching lines which should not happen through the interface
lines.update_quantity(1)
@ -136,8 +174,10 @@ class LunchOrder(models.Model):
orders |= super().create(vals)
return orders
def write(self, values):
merge_needed = 'note' in values or 'topping_ids_1' in values or 'topping_ids_2' in values or 'topping_ids_3' in values
def write(self, vals):
values = vals
change_topping = 'topping_ids_1' in values or 'topping_ids_2' in values or 'topping_ids_3' in values
merge_needed = 'note' in values or change_topping or 'state' in values
default_location_id = self.env.user.last_lunch_location_id and self.env.user.last_lunch_location_id.id or False
if merge_needed:
@ -149,14 +189,16 @@ class LunchOrder(models.Model):
# This also forces us to invalidate the cache for topping_ids_2 and topping_ids_3 that
# could have changed through topping_ids_1 without the cache knowing about it
toppings = self._extract_toppings(values)
self.invalidate_model(['topping_ids_2', 'topping_ids_3'])
values['topping_ids_1'] = [(6, 0, toppings)]
if change_topping:
self.invalidate_model(['topping_ids_2', 'topping_ids_3'])
values['topping_ids_1'] = [(6, 0, toppings)]
matching_lines = self._find_matching_lines({
'user_id': values.get('user_id', line.user_id.id),
'product_id': values.get('product_id', line.product_id.id),
'note': values.get('note', line.note or False),
'toppings': toppings,
'lunch_location_id': values.get('lunch_location_id', default_location_id),
'state': values.get('state'),
})
if matching_lines:
lines_to_deactivate |= line
@ -171,10 +213,12 @@ class LunchOrder(models.Model):
domain = [
('user_id', '=', values.get('user_id', self.default_get(['user_id'])['user_id'])),
('product_id', '=', values.get('product_id', False)),
('date', '=', fields.Date.today()),
('date', '=', values.get('date', fields.Date.today())),
('note', '=', values.get('note', False)),
('lunch_location_id', '=', values.get('lunch_location_id', default_location_id)),
]
if values.get('state'):
domain = Domain.AND([domain, [('state', '=', values['state'])]])
toppings = values.get('toppings', [])
return self.search(domain).filtered(lambda line: (line.topping_ids_1 | line.topping_ids_2 | line.topping_ids_3).ids == toppings)
@ -210,19 +254,17 @@ class LunchOrder(models.Model):
self.env.flush_all()
for line in self:
if self.env['lunch.cashmove'].get_wallet_balance(line.user_id) < 0:
raise ValidationError(_('Your wallet does not contain enough money to order that. To add some money to your wallet, please contact your lunch manager.'))
raise ValidationError(_('Oh no! You dont have enough money in your wallet to order your selected lunch! Contact your lunch manager to add some money to your wallet.'))
def action_order(self):
for order in self:
if not order.supplier_id.available_today:
raise UserError(_('The vendor related to this order is not available today.'))
if not order.available_on_date:
raise UserError(_('The vendor related to this order is not available at the selected date.'))
if self.filtered(lambda line: not line.product_id.active):
raise ValidationError(_('Product is no longer available.'))
self.write({
'state': 'ordered',
})
for order in self:
order.lunch_location_id = order.user_id.last_lunch_location_id
self._check_wallet()
def action_reorder(self):