mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-08-19 01:34:43 -05:00
Merge branch 'master-upstream-patch-14122022' into 'master'
[PATCH] Upstream patch - 14122022 See merge request flectra-hq/flectra!876
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import json
|
||||
from collections import defaultdict
|
||||
|
||||
from flectra import models, fields, api, _
|
||||
from flectra.exceptions import UserError
|
||||
@@ -13,21 +14,31 @@ class StockQuantPackage(models.Model):
|
||||
|
||||
@api.depends('quant_ids')
|
||||
def _compute_weight(self):
|
||||
if self.env.context.get('picking_id'):
|
||||
package_weights = defaultdict(float)
|
||||
# Ordering by qty_done prevents the default ordering by groupby fields that can inject multiple Left Joins in the resulting query.
|
||||
res_groups = self.env['stock.move.line'].read_group(
|
||||
[('result_package_id', 'in', self.ids), ('product_id', '!=', False), ('picking_id', '=', self.env.context['picking_id'])],
|
||||
['id:count'],
|
||||
['result_package_id', 'product_id', 'product_uom_id', 'qty_done'],
|
||||
lazy=False, orderby='qty_done asc'
|
||||
)
|
||||
for res_group in res_groups:
|
||||
product_id = self.env['product.product'].browse(res_group['product_id'][0])
|
||||
product_uom_id = self.env['uom.uom'].browse(res_group['product_uom_id'][0])
|
||||
package_weights[res_group['result_package_id'][0]] += (
|
||||
res_group['__count']
|
||||
* product_uom_id._compute_quantity(res_group['qty_done'], product_id.uom_id)
|
||||
* product_id.weight
|
||||
)
|
||||
for package in self:
|
||||
weight = 0.0
|
||||
if self.env.context.get('picking_id'):
|
||||
# TODO: potential bottleneck: N packages = N queries, use groupby ?
|
||||
current_picking_move_line_ids = self.env['stock.move.line'].search([
|
||||
('result_package_id', '=', package.id),
|
||||
('picking_id', '=', self.env.context['picking_id'])
|
||||
])
|
||||
for ml in current_picking_move_line_ids:
|
||||
weight += ml.product_uom_id._compute_quantity(
|
||||
ml.qty_done, ml.product_id.uom_id) * ml.product_id.weight
|
||||
package.weight = package_weights[package.id]
|
||||
else:
|
||||
weight = 0.0
|
||||
for quant in package.quant_ids:
|
||||
weight += quant.quantity * quant.product_id.weight
|
||||
package.weight = weight
|
||||
package.weight = weight
|
||||
|
||||
def _get_default_weight_uom(self):
|
||||
return self.env['product.template']._get_weight_uom_name_from_ir_config_parameter()
|
||||
@@ -49,19 +60,32 @@ class StockPicking(models.Model):
|
||||
def _compute_packages(self):
|
||||
for package in self:
|
||||
packs = set()
|
||||
for move_line in package.move_line_ids:
|
||||
if move_line.result_package_id:
|
||||
packs.add(move_line.result_package_id.id)
|
||||
if self.env['stock.move.line'].search_count([('picking_id', '=', package.id), ('result_package_id', '!=', False)]):
|
||||
for move_line in package.move_line_ids:
|
||||
if move_line.result_package_id:
|
||||
packs.add(move_line.result_package_id.id)
|
||||
package.package_ids = list(packs)
|
||||
|
||||
@api.depends('move_line_ids', 'move_line_ids.result_package_id', 'move_line_ids.product_uom_id', 'move_line_ids.qty_done')
|
||||
def _compute_bulk_weight(self):
|
||||
picking_weights = defaultdict(float)
|
||||
# Ordering by qty_done prevents the default ordering by groupby fields that can inject multiple Left Joins in the resulting query.
|
||||
res_groups = self.env['stock.move.line'].read_group(
|
||||
[('picking_id', 'in', self.ids), ('product_id', '!=', False), ('result_package_id', '=', False)],
|
||||
['id:count'],
|
||||
['picking_id', 'product_id', 'product_uom_id', 'qty_done'],
|
||||
lazy=False, orderby='qty_done asc'
|
||||
)
|
||||
for res_group in res_groups:
|
||||
product_id = self.env['product.product'].browse(res_group['product_id'][0])
|
||||
product_uom_id = self.env['uom.uom'].browse(res_group['product_uom_id'][0])
|
||||
picking_weights[res_group['picking_id'][0]] += (
|
||||
res_group['__count']
|
||||
* product_uom_id._compute_quantity(res_group['qty_done'], product_id.uom_id)
|
||||
* product_id.weight
|
||||
)
|
||||
for picking in self:
|
||||
weight = 0.0
|
||||
for move_line in picking.move_line_ids:
|
||||
if move_line.product_id and not move_line.result_package_id:
|
||||
weight += move_line.product_uom_id._compute_quantity(move_line.qty_done, move_line.product_id.uom_id) * move_line.product_id.weight
|
||||
picking.weight_bulk = weight
|
||||
picking.weight_bulk = picking_weights[picking.id]
|
||||
|
||||
@api.depends('move_line_ids.result_package_id', 'move_line_ids.result_package_id.shipping_weight', 'weight_bulk')
|
||||
def _compute_shipping_weight(self):
|
||||
|
||||
@@ -110,7 +110,7 @@ class PaymentAcquirer(models.Model):
|
||||
help="Capture the amount from Flectra, when the delivery is completed.")
|
||||
journal_id = fields.Many2one(
|
||||
'account.journal', 'Payment Journal', domain="[('type', 'in', ['bank', 'cash']), ('company_id', '=', company_id)]",
|
||||
help="""Journal where the successful transactions will be posted""")
|
||||
help="""Journal where the successful transactions will be posted""", ondelete='restrict')
|
||||
check_validity = fields.Boolean(string="Verify Card Validity",
|
||||
help="""Trigger a transaction of 1 currency unit and its refund to check the validity of new credit cards entered in the customer portal.
|
||||
Without this check, the validity will be verified at the very first transaction.""")
|
||||
|
||||
@@ -8,8 +8,6 @@ from calendar import monthrange
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from dateutil.rrule import rrule, rruleset, DAILY, WEEKLY, MONTHLY, YEARLY, MO, TU, WE, TH, FR, SA, SU
|
||||
|
||||
import math
|
||||
|
||||
MONTHS = {
|
||||
'january': 31,
|
||||
'february': 28,
|
||||
@@ -140,8 +138,9 @@ class ProjectTaskRecurrence(models.Model):
|
||||
|
||||
@api.constrains('repeat_unit', 'repeat_on_month', 'repeat_day', 'repeat_type', 'repeat_until')
|
||||
def _check_repeat_until_month(self):
|
||||
if self.filtered(lambda r: r.repeat_type == 'until' and r.repeat_unit == 'month' and r.repeat_until and r.repeat_on_month == 'date' and int(r.repeat_day) > r.repeat_until.day):
|
||||
raise ValidationError('The end date should be after the day of the month')
|
||||
if self.filtered(lambda r: r.repeat_type == 'until' and r.repeat_unit == 'month' and r.repeat_until and r.repeat_on_month == 'date'
|
||||
and int(r.repeat_day) > r.repeat_until.day and monthrange(r.repeat_until.year, r.repeat_until.month)[1] != r.repeat_until.day):
|
||||
raise ValidationError('The end date should be after the day of the month or the last day of the month')
|
||||
|
||||
@api.model
|
||||
def _get_recurring_fields(self):
|
||||
@@ -179,16 +178,16 @@ class ProjectTaskRecurrence(models.Model):
|
||||
rrule_kwargs['freq'] = MONTHLY
|
||||
if repeat_on_month == 'date':
|
||||
start = date_start - relativedelta(days=1)
|
||||
if repeat_type == 'until' and repeat_until > date_start:
|
||||
delta = relativedelta(repeat_until, date_start)
|
||||
count = math.floor((delta.years * 12 + delta.months) / repeat_interval)
|
||||
for i in range(count):
|
||||
start = start.replace(day=min(repeat_day, monthrange(start.year, start.month)[1]))
|
||||
if start < date_start:
|
||||
# Ensure the next recurrence is in the future
|
||||
start += relativedelta(months=repeat_interval)
|
||||
start = start.replace(day=min(repeat_day, monthrange(start.year, start.month)[1]))
|
||||
if i == 0 and start < date_start:
|
||||
# Ensure the next recurrence is in the future
|
||||
start += relativedelta(months=repeat_interval)
|
||||
can_generate_date = (lambda: start <= repeat_until) if repeat_type == 'until' else (lambda: len(dates) < count)
|
||||
while can_generate_date():
|
||||
dates.append(start)
|
||||
start += relativedelta(months=repeat_interval)
|
||||
start = start.replace(day=min(repeat_day, monthrange(start.year, start.month)[1]))
|
||||
return dates
|
||||
elif repeat_unit == 'year':
|
||||
rrule_kwargs['freq'] = YEARLY
|
||||
|
||||
@@ -455,6 +455,69 @@ class TestProjectrecurrence(SavepointCase):
|
||||
self.assertEqual(dates[0], datetime(2020, 7, 3))
|
||||
self.assertEqual(dates[1], datetime(2021, 1, 3))
|
||||
|
||||
# Should generate a date at the last day of the current month
|
||||
dates = self.env['project.task.recurrence']._get_next_recurring_dates(
|
||||
date_start=date(2022, 2, 26),
|
||||
repeat_interval=1,
|
||||
repeat_unit='month',
|
||||
repeat_type='until',
|
||||
repeat_until=date(2022, 2, 28),
|
||||
repeat_on_month='date',
|
||||
repeat_on_year=False,
|
||||
weekdays=False,
|
||||
repeat_day=31,
|
||||
repeat_week=False,
|
||||
repeat_month=False,
|
||||
count=5)
|
||||
|
||||
self.assertEqual(len(dates), 1)
|
||||
self.assertEqual(dates[0], date(2022, 2, 28))
|
||||
|
||||
dates = self.env['project.task.recurrence']._get_next_recurring_dates(
|
||||
date_start=date(2022, 11, 26),
|
||||
repeat_interval=3,
|
||||
repeat_unit='month',
|
||||
repeat_type='until',
|
||||
repeat_until=date(2024, 2, 29),
|
||||
repeat_on_month='date',
|
||||
repeat_on_year=False,
|
||||
weekdays=False,
|
||||
repeat_day=25,
|
||||
repeat_week=False,
|
||||
repeat_month=False,
|
||||
count=5)
|
||||
|
||||
self.assertEqual(len(dates), 5)
|
||||
self.assertEqual(dates[0], date(2023, 2, 25))
|
||||
self.assertEqual(dates[1], date(2023, 5, 25))
|
||||
self.assertEqual(dates[2], date(2023, 8, 25))
|
||||
self.assertEqual(dates[3], date(2023, 11, 25))
|
||||
self.assertEqual(dates[4], date(2024, 2, 25))
|
||||
|
||||
# Use the exact same parameters than the previous test but with a repeat_day that is not passed yet
|
||||
# So we generate an additional date in the current month
|
||||
dates = self.env['project.task.recurrence']._get_next_recurring_dates(
|
||||
date_start=date(2022, 11, 26),
|
||||
repeat_interval=3,
|
||||
repeat_unit='month',
|
||||
repeat_type='until',
|
||||
repeat_until=date(2024, 2, 29),
|
||||
repeat_on_month='date',
|
||||
repeat_on_year=False,
|
||||
weekdays=False,
|
||||
repeat_day=31,
|
||||
repeat_week=False,
|
||||
repeat_month=False,
|
||||
count=5)
|
||||
|
||||
self.assertEqual(len(dates), 6)
|
||||
self.assertEqual(dates[0], date(2022, 11, 30))
|
||||
self.assertEqual(dates[1], date(2023, 2, 28))
|
||||
self.assertEqual(dates[2], date(2023, 5, 31))
|
||||
self.assertEqual(dates[3], date(2023, 8, 31))
|
||||
self.assertEqual(dates[4], date(2023, 11, 30))
|
||||
self.assertEqual(dates[5], date(2024, 2, 29))
|
||||
|
||||
def test_recurrence_next_dates_year(self):
|
||||
dates = self.env['project.task.recurrence']._get_next_recurring_dates(
|
||||
date_start=date(2020, 12, 1),
|
||||
|
||||
@@ -184,7 +184,7 @@ class MrpStockReport(models.TransientModel):
|
||||
lines = self._get_move_lines(move_line, line_id=line_id)
|
||||
for line in lines:
|
||||
unfoldable = False
|
||||
if line.consume_line_ids or ( line.lot_id and self._get_move_lines(line) and model != "stock.production.lot"):
|
||||
if line.consume_line_ids or (model != "stock.production.lot" and line.lot_id and self._get_move_lines(line)):
|
||||
unfoldable = True
|
||||
final_vals += self._make_dict_move(level, parent_id=line_id, move_line=line, unfoldable=unfoldable)
|
||||
return final_vals
|
||||
|
||||
Reference in New Issue
Block a user