mirror of
https://gitlab.com/flectra-hq/flectra.git
synced 2026-11-02 20:30:20 -06:00
Merge branch 'master-upstream-patch-21022023' into 'master'
[PATCH] Upstream patch - 21022023 See merge request flectra-hq/flectra!948
This commit is contained in:
commit
7d8de9bd7f
7 files changed
+196
-19
No files matched your search
@@ -568,7 +568,7 @@ class MrpWorkorder(models.Model):
|
||||
|
||||
if self.product_tracking == 'serial':
|
||||
self.qty_producing = 1.0
|
||||
else:
|
||||
elif self.qty_producing == 0:
|
||||
self.qty_producing = self.qty_remaining
|
||||
|
||||
self.env['mrp.workcenter.productivity'].create(
|
||||
|
||||
@@ -398,8 +398,16 @@ class TestMrpOrder(TestMrpCommon):
|
||||
production = production_form.save()
|
||||
production.action_confirm()
|
||||
production.button_plan()
|
||||
production.workorder_ids[0].button_start()
|
||||
self.assertEqual(production.workorder_ids.qty_producing, 5, "Wrong quantity is suggested to produce.")
|
||||
|
||||
wo = production.workorder_ids[0]
|
||||
wo.button_start()
|
||||
self.assertEqual(wo.qty_producing, 5, "Wrong quantity is suggested to produce.")
|
||||
|
||||
# Simulate changing the qty_producing in the frontend
|
||||
wo.qty_producing = 4
|
||||
wo.button_pending()
|
||||
wo.button_start()
|
||||
self.assertEqual(wo.qty_producing, 4, "Changing the qty_producing in the frontend is not persisted")
|
||||
|
||||
def test_update_quantity_5(self):
|
||||
bom = self.env['mrp.bom'].create({
|
||||
|
||||
@@ -108,8 +108,8 @@ flectra.define('point_of_sale.ReceiptScreen', function (require) {
|
||||
const order_server_id = this.env.pos.validated_orders_name_server_id_map[orderName];
|
||||
if (!order_server_id) {
|
||||
this.showPopup('ErrorPopup', {
|
||||
title: 'Unsynced order',
|
||||
body: 'This order is not yet synced to server. Make sure it is synced then try again.',
|
||||
title: this.env._t('Unsynced order'),
|
||||
body: this.env._t('This order is not yet synced to server. Make sure it is synced then try again.'),
|
||||
});
|
||||
return Promise.reject();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,6 @@
|
||||
'views/pos_payment_method_views.xml',
|
||||
'views/point_of_sale_assets.xml',
|
||||
],
|
||||
'auto-install': True,
|
||||
'auto_install': True,
|
||||
'license': 'LGPL-3',
|
||||
}
|
||||
@@ -512,11 +512,30 @@ class Survey(models.Model):
|
||||
if self.questions_selection == 'random' and not self.session_state:
|
||||
result = user_input.predefined_question_ids
|
||||
else:
|
||||
result = self.question_and_page_ids.filtered(
|
||||
lambda question: not question.is_page or not is_html_empty(question.description))
|
||||
result = self._get_pages_and_questions_to_show()
|
||||
|
||||
return result
|
||||
|
||||
def _get_pages_and_questions_to_show(self):
|
||||
"""
|
||||
:return: survey.question recordset excluding invalid conditional questions and pages without description
|
||||
"""
|
||||
|
||||
self.ensure_one()
|
||||
invalid_questions = self.env['survey.question']
|
||||
questions_and_valid_pages = self.question_and_page_ids.filtered(
|
||||
lambda question: not question.is_page or not is_html_empty(question.description))
|
||||
for question in questions_and_valid_pages.filtered(lambda q: q.is_conditional).sorted():
|
||||
trigger = question.triggering_question_id
|
||||
if (trigger in invalid_questions
|
||||
or trigger.is_page
|
||||
or trigger.question_type not in ['simple_choice', 'multiple_choice']
|
||||
or not trigger.suggested_answer_ids
|
||||
or trigger.sequence > question.sequence
|
||||
or (trigger.sequence == question.sequence and trigger.id > question.id)):
|
||||
invalid_questions |= question
|
||||
return questions_and_valid_pages - invalid_questions
|
||||
|
||||
def _get_next_page_or_question(self, user_input, page_or_question_id, go_back=False):
|
||||
""" Generalized logic to retrieve the next question or page to show on the survey.
|
||||
It's based on the page_or_question_id parameter, that is usually the currently displayed question/page.
|
||||
|
||||
@@ -159,3 +159,139 @@ class TestSurveyInternals(common.TestSurveyCommon):
|
||||
|
||||
for question in questions:
|
||||
self._assert_skipped_question(question, survey_user)
|
||||
|
||||
def test_get_pages_and_questions_to_show(self):
|
||||
"""
|
||||
Tests the method `_get_pages_and_questions_to_show` - it takes a recordset of
|
||||
question.question from a survey.survey and returns a recordset without
|
||||
invalid conditional questions and pages without description
|
||||
|
||||
Structure of the test survey:
|
||||
|
||||
sequence | type | trigger | validity
|
||||
----------------------------------------------------------------------
|
||||
1 | page, no description | / | X
|
||||
2 | text_box | trigger is 6 | X
|
||||
3 | numerical_box | trigger is 2 | X
|
||||
4 | simple_choice | / | V
|
||||
5 | page, description | / | V
|
||||
6 | multiple_choice | / | V
|
||||
7 | multiple_choice, no answers | / | V
|
||||
8 | text_box | trigger is 6 | V
|
||||
9 | matrix | trigger is 5 | X
|
||||
10 | simple_choice | trigger is 7 | X
|
||||
11 | simple_choice, no answers | trigger is 8 | X
|
||||
12 | text_box | trigger is 11 | X
|
||||
"""
|
||||
|
||||
my_survey = self.env['survey.survey'].create({
|
||||
'title': 'my_survey',
|
||||
'questions_layout': 'page_per_question',
|
||||
'questions_selection': 'all',
|
||||
'access_mode': 'public',
|
||||
})
|
||||
[
|
||||
page_without_description,
|
||||
text_box_1,
|
||||
numerical_box,
|
||||
_simple_choice_1,
|
||||
page_with_description,
|
||||
multiple_choice_1,
|
||||
multiple_choice_2,
|
||||
text_box_2,
|
||||
matrix,
|
||||
simple_choice_2,
|
||||
simple_choice_3,
|
||||
text_box_3,
|
||||
] = self.env['survey.question'].create([{
|
||||
'title': 'no desc',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 1,
|
||||
'question_type': False,
|
||||
'is_page': True,
|
||||
'description': False,
|
||||
}, {
|
||||
'title': 'text_box with invalid trigger',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 2,
|
||||
'is_page': False,
|
||||
'question_type': 'simple_choice',
|
||||
}, {
|
||||
'title': 'numerical box with trigger that is invalid',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 3,
|
||||
'is_page': False,
|
||||
'question_type': 'numerical_box',
|
||||
}, {
|
||||
'title': 'valid simple_choice',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 4,
|
||||
'is_page': False,
|
||||
'question_type': 'simple_choice',
|
||||
'suggested_answer_ids': [(0, 0, {'value': 'a'})],
|
||||
}, {
|
||||
'title': 'with desc',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 5,
|
||||
'is_page': True,
|
||||
'question_type': False,
|
||||
'description': 'This page has a description',
|
||||
}, {
|
||||
'title': 'multiple choice not conditional',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 6,
|
||||
'is_page': False,
|
||||
'question_type': 'multiple_choice',
|
||||
'suggested_answer_ids': [(0, 0, {'value': 'a'})]
|
||||
}, {
|
||||
'title': 'multiple_choice with no answers',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 7,
|
||||
'is_page': False,
|
||||
'question_type': 'multiple_choice',
|
||||
}, {
|
||||
'title': 'text_box with valid trigger',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 8,
|
||||
'is_page': False,
|
||||
'question_type': 'text_box',
|
||||
}, {
|
||||
'title': 'matrix with invalid trigger (page)',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 9,
|
||||
'is_page': False,
|
||||
'question_type': 'matrix',
|
||||
}, {
|
||||
'title': 'simple choice w/ invalid trigger (no suggested_answer_ids)',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 10,
|
||||
'is_page': False,
|
||||
'question_type': 'simple_choice',
|
||||
}, {
|
||||
'title': 'text_box w/ invalid trigger (not a mcq)',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 11,
|
||||
'is_page': False,
|
||||
'question_type': 'simple_choice',
|
||||
'suggested_answer_ids': False,
|
||||
}, {
|
||||
'title': 'text_box w/ invalid trigger (suggested_answer_ids is False)',
|
||||
'survey_id': my_survey.id,
|
||||
'sequence': 12,
|
||||
'is_page': False,
|
||||
'question_type': 'text_box',
|
||||
}])
|
||||
text_box_1.write({'is_conditional': True, 'triggering_question_id': multiple_choice_1.id})
|
||||
numerical_box.write({'is_conditional': True, 'triggering_question_id': text_box_1.id})
|
||||
text_box_2.write({'is_conditional': True, 'triggering_question_id': multiple_choice_1.id})
|
||||
matrix.write({'is_conditional': True, 'triggering_question_id': page_with_description.id})
|
||||
simple_choice_2.write({'is_conditional': True, 'triggering_question_id': multiple_choice_2.id})
|
||||
simple_choice_3.write({'is_conditional': True, 'triggering_question_id': text_box_2.id})
|
||||
text_box_3.write({'is_conditional': True, 'triggering_question_id': simple_choice_3.id})
|
||||
|
||||
invalid_records = page_without_description + text_box_1 + numerical_box \
|
||||
+ matrix + simple_choice_2 + simple_choice_3 + text_box_3
|
||||
question_and_page_ids = my_survey.question_and_page_ids
|
||||
returned_questions_and_pages = my_survey._get_pages_and_questions_to_show()
|
||||
|
||||
self.assertEqual(question_and_page_ids - invalid_records, returned_questions_and_pages)
|
||||
@@ -735,16 +735,7 @@ var FieldDateRange = InputField.extend({
|
||||
_renderEdit: function () {
|
||||
this._super.apply(this, arguments);
|
||||
var self = this;
|
||||
var startDate;
|
||||
var endDate;
|
||||
if (this.relatedEndDate) {
|
||||
startDate = this._formatValue(this.value);
|
||||
endDate = this._formatValue(this.recordData[this.relatedEndDate]);
|
||||
}
|
||||
if (this.relatedStartDate) {
|
||||
startDate = this._formatValue(this.recordData[this.relatedStartDate]);
|
||||
endDate = this._formatValue(this.value);
|
||||
}
|
||||
const [startDate, endDate] = this._getDateRangeFromInputField();
|
||||
this.dateRangePickerOptions.startDate = startDate || moment();
|
||||
this.dateRangePickerOptions.endDate = endDate || moment();
|
||||
|
||||
@@ -785,16 +776,39 @@ var FieldDateRange = InputField.extend({
|
||||
},
|
||||
/**
|
||||
* Bind the scroll event handle when the daterangepicker is open.
|
||||
* Update the begin and end date with the dates from the input values
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onDateRangePickerShow() {
|
||||
const daterangepicker = this.$el.data('daterangepicker');
|
||||
this._onScroll = ev => {
|
||||
if (!config.device.isMobile && !this.$pickerContainer.get(0).contains(ev.target)) {
|
||||
this.$el.data('daterangepicker').hide();
|
||||
daterangepicker.hide();
|
||||
}
|
||||
};
|
||||
window.addEventListener('scroll', this._onScroll, true);
|
||||
const [startDate, endDate] = this._getDateRangeFromInputField();
|
||||
daterangepicker.setStartDate(startDate? startDate.utcOffset(session.getTZOffset(startDate)): moment());
|
||||
daterangepicker.setEndDate(endDate? endDate.utcOffset(session.getTZOffset(endDate)): moment());
|
||||
daterangepicker.updateView();
|
||||
},
|
||||
/**
|
||||
* Get the startDate and endDate of the daterangepicker from the input fields
|
||||
* @returns [Date (moment object), Date (moment object)]
|
||||
* @private
|
||||
*/
|
||||
_getDateRangeFromInputField() {
|
||||
let startDate, endDate;
|
||||
if (this.relatedEndDate) {
|
||||
startDate = this.value;
|
||||
endDate = this.recordData[this.relatedEndDate];
|
||||
}
|
||||
if (this.relatedStartDate) {
|
||||
startDate = this.recordData[this.relatedStartDate];
|
||||
endDate = this.value;
|
||||
}
|
||||
return [startDate, endDate];
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user