质量模块和库存扫码
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
odoo.define('stock_barcode.RunningTourActionHelper', function(require) {
|
||||
"use strict";
|
||||
|
||||
var RunningTourActionHelper = require('web_tour.RunningTourActionHelper');
|
||||
|
||||
RunningTourActionHelper.include({
|
||||
_scan: function (element, barcode) {
|
||||
odoo.__DEBUG__.services['web.core'].bus.trigger('barcode_scanned', barcode, element);
|
||||
},
|
||||
scan: function(barcode, element) {
|
||||
this._scan(this._get_action_values(element), barcode);
|
||||
},
|
||||
});
|
||||
|
||||
const StepUtils = require('web_tour.TourStepUtils');
|
||||
StepUtils.include({
|
||||
closeModal() {
|
||||
return {
|
||||
trigger: '.btn.btn-primary',
|
||||
in_modal: true,
|
||||
};
|
||||
},
|
||||
confirmAddingUnreservedProduct() {
|
||||
return {
|
||||
trigger: '.btn-primary',
|
||||
extra_trigger: '.modal-title:contains("Add extra product?")',
|
||||
in_modal: true,
|
||||
};
|
||||
},
|
||||
validateBarcodeForm() {
|
||||
return [{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan O-BTN.validate'
|
||||
}, {
|
||||
trigger: '.o_notification.border-success',
|
||||
}];
|
||||
},
|
||||
discardBarcodeForm() {
|
||||
return [{
|
||||
content: "discard barcode form",
|
||||
trigger: '.o_discard',
|
||||
auto: true,
|
||||
}, {
|
||||
content: "wait to be back on the barcode lines",
|
||||
trigger: '.o_add_line',
|
||||
auto: true,
|
||||
run() {},
|
||||
}];
|
||||
},
|
||||
});
|
||||
|
||||
});
|
||||
290
stock_barcode/static/tests/tours/tour_helper_stock_barcode.js
Normal file
290
stock_barcode/static/tests/tours/tour_helper_stock_barcode.js
Normal file
@@ -0,0 +1,290 @@
|
||||
odoo.define('stock_barcode.tourHelper', function (require) {
|
||||
'use strict';
|
||||
|
||||
var tour = require('web_tour.tour');
|
||||
|
||||
function fail (errorMessage) {
|
||||
tour._consume_tour(tour.running_tour, errorMessage);
|
||||
}
|
||||
|
||||
function getLine (description) {
|
||||
var $res;
|
||||
$('.o_barcode_lines > .o_barcode_line').each(function () {
|
||||
var $line = $(this);
|
||||
const barcode = $line[0].dataset.barcode.trim();
|
||||
if (description.barcode === barcode) {
|
||||
if ($res) {
|
||||
$res = $res.add($line);
|
||||
} else {
|
||||
$res = $line;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (! $res) {
|
||||
fail('cannot get the line with the barcode ' + description.barcode);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
function getSubline(selector) {
|
||||
const $subline = $('.o_sublines .o_barcode_line' + selector);
|
||||
if ($subline.length === 0) {
|
||||
fail(`No subline was found for the selector "${selector}"`);
|
||||
} else if($subline.length > 1) {
|
||||
fail(`Multiple sublines were found for the selector "${selector}"`);
|
||||
}
|
||||
return $subline;
|
||||
}
|
||||
|
||||
function triggerKeydown(eventKey, shiftkey=false) {
|
||||
document.querySelector('.o_barcode_client_action')
|
||||
.dispatchEvent(new window.KeyboardEvent('keydown', { bubbles: true, key: eventKey, shiftKey: shiftkey}));
|
||||
}
|
||||
|
||||
function assert (current, expected, info) {
|
||||
if (current !== expected) {
|
||||
fail(info + ': "' + current + '" instead of "' + expected + '".');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a button on the given line is visible.
|
||||
*
|
||||
* @param {jQuerryElement} $line the line where we test the button visibility.
|
||||
* @param {string} buttonName could be 'add_quantity' or 'remove_unit'.
|
||||
* @param {boolean} [isVisible=true]
|
||||
*/
|
||||
function assertButtonIsVisible($line, buttonName, isVisible=true) {
|
||||
const $button = $line.find(`.o_${buttonName}`);
|
||||
assert($button.length, isVisible ? 1 : 0,
|
||||
isVisible ? `Buttons should be in the DOM` : "Button shouldn't be in the DOM");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a button on the given line is invisible.
|
||||
*
|
||||
* @param {jQuerryElement} $line the line where we test the button visibility.
|
||||
* @param {string} buttonName could be 'add_quantity' or 'remove_unit'.
|
||||
*/
|
||||
function assertButtonIsNotVisible ($line, buttonName) {
|
||||
assertButtonIsVisible($line, buttonName, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if both "Add unit" and "Add reserved remaining quantity" buttons are
|
||||
* displayed or not on the given line.
|
||||
*
|
||||
* @param {integer} lineIndex
|
||||
* @param {boolean} isVisible
|
||||
*/
|
||||
function assertLineButtonsAreVisible(lineIndex, isVisible, cssSelector='.o_line_button') {
|
||||
const $buttonAddQty = $(`.o_barcode_line:eq(${lineIndex}) ${cssSelector}`);
|
||||
const message = `Buttons must be ${(isVisible ? 'visible' : 'hidden')}`;
|
||||
assert($buttonAddQty.length > 0, isVisible, message);
|
||||
}
|
||||
|
||||
function assertValidateVisible (expected) {
|
||||
const validateButton = document.querySelector('.o_validate_page,.o_apply_page');
|
||||
assert(Boolean(validateButton), expected, 'Validate visible');
|
||||
}
|
||||
|
||||
function assertValidateEnabled (expected) {
|
||||
const validateButton = document.querySelector('.o_validate_page,.o_apply_page') || false;
|
||||
assert(validateButton && !validateButton.hasAttribute('disabled'), expected, 'Validate enabled');
|
||||
}
|
||||
|
||||
function assertValidateIsHighlighted (expected) {
|
||||
const validateButton = document.querySelector('.o_validate_page,.o_apply_page') || false;
|
||||
const isHighlighted = validateButton && validateButton.classList.contains('btn-success');
|
||||
assert(isHighlighted, expected, 'Validate button is highlighted');
|
||||
}
|
||||
|
||||
function assertLinesCount(expected) {
|
||||
const current = document.querySelectorAll('.o_barcode_lines > .o_barcode_line').length;
|
||||
assert(current, expected, `Should have ${expected} line(s)`);
|
||||
}
|
||||
|
||||
function assertScanMessage (expected) {
|
||||
const instruction = document.querySelector(`.o_scan_message`);
|
||||
const cssClass = instruction.classList[1];
|
||||
assert(cssClass, `o_${expected}`, "Not the right message displayed");
|
||||
}
|
||||
|
||||
function assertSublinesCount(expected) {
|
||||
const current = document.querySelectorAll('.o_sublines > .o_barcode_line').length;
|
||||
assert(current, expected, `Should have ${expected} subline(s), found ${current}`);
|
||||
}
|
||||
|
||||
function assertLineDestinationIsNotVisible(line) {
|
||||
const destinationElement = line.querySelector('.o_line_destination_location');
|
||||
if (destinationElement) {
|
||||
const product = line.querySelector('.product-label').innerText;
|
||||
fail(`The destination for line of the product ${product} should not be visible, "${destinationElement.innerText}" instead`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given line is going in the given location. Implies the destination is visible.
|
||||
* @param {Element} line
|
||||
* @param {string} location
|
||||
*/
|
||||
function assertLineDestinationLocation(line, location) {
|
||||
const destinationElement = line.querySelector('.o_line_destination_location');
|
||||
const product = line.querySelector('.product-label').innerText;
|
||||
if (!destinationElement) {
|
||||
fail(`The destination (${location}) for line of the product ${product} is not visible`);
|
||||
}
|
||||
assert(
|
||||
destinationElement.innerText, location,
|
||||
`The destination for line of product ${product} isn't in the right location`);
|
||||
}
|
||||
|
||||
function assertLineIsHighlighted ($line, expected) {
|
||||
assert($line.hasClass('o_highlight'), expected, 'line should be highlighted');
|
||||
}
|
||||
|
||||
function assertLineQty($line, expectedQuantity) {
|
||||
const lineNode = $line[0];
|
||||
if (!lineNode) {
|
||||
fail("Can't check the quantity: no line was given.");
|
||||
} else if (!lineNode.classList.contains('o_barcode_line')) {
|
||||
fail("Can't check the quantity: given element isn't a barcode line.");
|
||||
}
|
||||
const lineQuantity = lineNode.querySelector('.qty-done,.inventory_quantity').innerText;
|
||||
expectedQuantity = String(expectedQuantity);
|
||||
assert(lineQuantity, expectedQuantity, `Line's quantity is wrong`);
|
||||
}
|
||||
|
||||
function assertLineLocations(line, source=false, destination=false) {
|
||||
if (source) {
|
||||
assertLineSourceLocation(line, source);
|
||||
} else {
|
||||
assertLineSourceIsNotVisible(line);
|
||||
}
|
||||
if (destination) {
|
||||
assertLineDestinationLocation(line, destination);
|
||||
} else {
|
||||
assertLineDestinationIsNotVisible(line);
|
||||
}
|
||||
}
|
||||
|
||||
function assertLineProduct(line, productName) {
|
||||
const lineProduct = line.querySelector('.product-label').innerText;
|
||||
assert(lineProduct, productName, "No the expected product");
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the done quantity on the reserved quantity is what is expected.
|
||||
*
|
||||
* @param {integer} lineIndex
|
||||
* @param {string} textQty quantity on the line, formatted as "n / N"
|
||||
*/
|
||||
function assertLineQuantityOnReservedQty (lineIndex, textQty) {
|
||||
const $line = $('.o_barcode_line').eq(lineIndex);
|
||||
const qty = $line.find('.qty-done').text();
|
||||
const reserved = $line.find('.qty-done').next().text();
|
||||
const qtyText = reserved ? qty + ' ' + reserved : qty;
|
||||
assert(qtyText, textQty, 'Something wrong with the quantities');
|
||||
}
|
||||
|
||||
function assertLineSourceIsNotVisible(line) {
|
||||
const sourceElement = line.querySelector('.o_line_source_location');
|
||||
if (sourceElement) {
|
||||
const product = line.querySelector('.product-label').innerText;
|
||||
fail(`The location for line of the product ${product} should not be visible, "${sourceElement.innerText}" instead`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given line is in the given location. Implies the location is visible.
|
||||
* @param {Element} line
|
||||
* @param {string} location
|
||||
*/
|
||||
function assertLineSourceLocation(line, location) {
|
||||
const sourceElement = line.querySelector('.o_line_source_location');
|
||||
const product = line.querySelector('.product-label').innerText;
|
||||
if (!sourceElement) {
|
||||
fail(`The source (${location}) for line of the product ${product} is not visible`);
|
||||
}
|
||||
assert(
|
||||
sourceElement.innerText, location,
|
||||
`The source for line of product ${product} isn't in the right location`);
|
||||
}
|
||||
|
||||
function assertFormLocationSrc(expected) {
|
||||
var $location = $('.o_field_widget[name="location_id"] input');
|
||||
assert($location.val(), expected, 'Wrong source location');
|
||||
}
|
||||
|
||||
function assertFormLocationDest(expected) {
|
||||
var $location = $('.o_field_widget[name="location_dest_id"] input');
|
||||
assert($location.val(), expected, 'Wrong destination location');
|
||||
}
|
||||
|
||||
function assertFormQuantity(expected) {
|
||||
const quantityField = document.querySelector(
|
||||
'.o_field_widget[name="inventory_quantity"] input, .o_field_widget[name="qty_done"] input');
|
||||
assert(quantityField.value, expected, 'Wrong quantity');
|
||||
}
|
||||
|
||||
function assertErrorMessage(expected) {
|
||||
var $errorMessage = $('.o_notification_content').eq(-1);
|
||||
assert($errorMessage[0].innerText, expected, 'wrong or absent error message');
|
||||
}
|
||||
|
||||
function assertKanbanRecordsCount(expected) {
|
||||
const kanbanRecords = document.querySelectorAll(
|
||||
'.o_kanban_view .o_kanban_record:not(.o_kanban_ghost)');
|
||||
assert(kanbanRecords.length, expected, 'Wrong number of cards');
|
||||
}
|
||||
|
||||
function pressShift() {
|
||||
document.querySelector('.o_barcode_client_action').dispatchEvent(
|
||||
new window.KeyboardEvent(
|
||||
'keydown', { bubbles: true, key: 'Shift' },
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function releaseShift() {
|
||||
document.querySelector('.o_barcode_client_action').dispatchEvent(
|
||||
new window.KeyboardEvent(
|
||||
'keyup', { bubbles: true, key: 'Shift' },
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
assert: assert,
|
||||
assertButtonIsVisible: assertButtonIsVisible,
|
||||
assertButtonIsNotVisible: assertButtonIsNotVisible,
|
||||
assertLineButtonsAreVisible: assertLineButtonsAreVisible,
|
||||
assertLineDestinationIsNotVisible,
|
||||
assertLineDestinationLocation,
|
||||
assertLineLocations,
|
||||
assertLineSourceIsNotVisible,
|
||||
assertLineSourceLocation,
|
||||
assertErrorMessage: assertErrorMessage,
|
||||
assertFormLocationDest: assertFormLocationDest,
|
||||
assertFormLocationSrc: assertFormLocationSrc,
|
||||
assertFormQuantity,
|
||||
assertLinesCount: assertLinesCount,
|
||||
assertLineIsHighlighted: assertLineIsHighlighted,
|
||||
assertLineProduct,
|
||||
assertLineQty: assertLineQty,
|
||||
assertLineQuantityOnReservedQty: assertLineQuantityOnReservedQty,
|
||||
assertKanbanRecordsCount,
|
||||
assertScanMessage: assertScanMessage,
|
||||
assertSublinesCount,
|
||||
assertValidateEnabled: assertValidateEnabled,
|
||||
assertValidateIsHighlighted: assertValidateIsHighlighted,
|
||||
assertValidateVisible: assertValidateVisible,
|
||||
fail: fail,
|
||||
getLine: getLine,
|
||||
getSubline,
|
||||
pressShift: pressShift,
|
||||
releaseShift: releaseShift,
|
||||
triggerKeydown: triggerKeydown,
|
||||
};
|
||||
|
||||
});
|
||||
@@ -0,0 +1,651 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import helper from 'stock_barcode.tourHelper';
|
||||
import tour from 'web_tour.tour';
|
||||
|
||||
tour.register('test_inventory_adjustment', {test: true}, [
|
||||
|
||||
{
|
||||
trigger: '.button_inventory',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_scan_message.o_scan_product',
|
||||
run: function () {
|
||||
helper.assertScanMessage('scan_product');
|
||||
helper.assertValidateVisible(true);
|
||||
helper.assertValidateIsHighlighted(false);
|
||||
helper.assertValidateEnabled(false);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan product1',
|
||||
},
|
||||
{
|
||||
trigger: '.o_barcode_line',
|
||||
run: function () {
|
||||
// Checks the product code and name are on separate lines.
|
||||
const $line = helper.getLine({barcode: 'product1'});
|
||||
helper.assert($line.find('.o_barcode_line_details > .o_barcode_line_title > .o_barcode_product_ref').length, 1);
|
||||
helper.assert($line.find('.o_barcode_line_details .product-label').length, 1);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan product1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_edit',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_field_widget[name="inventory_quantity"]',
|
||||
run: function () {
|
||||
helper.assertFormQuantity('2');
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_save',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_line',
|
||||
run: function () {
|
||||
// Checks the product code and name are on separate lines.
|
||||
const $line = helper.getLine({barcode: 'product1'});
|
||||
helper.assert($line.find('.o_barcode_line_details > .o_barcode_line_title > .o_barcode_product_ref').length, 1);
|
||||
helper.assert($line.find('.o_barcode_line_details .product-label').length, 1);
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_add_line',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: ".o_field_widget[name=product_id] input",
|
||||
run: 'text product2',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: ".ui-menu-item > a:contains('product2')",
|
||||
},
|
||||
|
||||
{
|
||||
trigger: ".o_field_widget[name=inventory_quantity] input",
|
||||
run: 'text 2',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_save',
|
||||
},
|
||||
|
||||
{
|
||||
extra_trigger: '.o_scan_message.o_scan_product',
|
||||
trigger: '.o_barcode_line',
|
||||
run: 'scan O-BTN.validate',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_stock_barcode_main_menu',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_notification.border-success',
|
||||
run: function () {
|
||||
helper.assertErrorMessage('The inventory adjustment has been validated');
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
tour.register('test_inventory_adjustment_multi_location', {test: true}, [
|
||||
|
||||
{
|
||||
trigger: '.button_inventory',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan LOC-01-00-00'
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_scan_message:contains("WH/Stock")',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan product1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan product1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan product2',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan LOC-01-01-00'
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_scan_message:contains("WH/Stock/Section 1")',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan product2',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan LOC-01-02-00'
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_scan_message:contains("WH/Stock/Section 2")',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan product1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan O-BTN.validate',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_stock_barcode_main_menu',
|
||||
run: function () {
|
||||
helper.assertErrorMessage('The inventory adjustment has been validated');
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
tour.register('test_inventory_adjustment_tracked_product', {test: true}, [
|
||||
|
||||
{
|
||||
trigger: '.button_inventory',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan productlot1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("productlot1")',
|
||||
run: 'scan lot1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan lot1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_line.o_selected .qty-done:contains(2)',
|
||||
run: 'scan productserial1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("productserial1")',
|
||||
run: 'scan serial1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan serial1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_notification.border-danger',
|
||||
run: function () {
|
||||
// Check that other lines is correct
|
||||
let $line = helper.getLine({barcode: 'productserial1'});
|
||||
helper.assertLineQty($line, "1");
|
||||
helper.assert($line.find('.o_line_lot_name').text().trim(), 'serial1');
|
||||
$line = helper.getLine({barcode: 'productlot1'});
|
||||
helper.assertLineQty($line, "2");
|
||||
helper.assert($line.find('.o_line_lot_name').text().trim(), 'lot1');
|
||||
helper.assertErrorMessage('The scanned serial number is already used.');
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan serial2',
|
||||
},
|
||||
{ trigger: '.o_barcode_line.o_selected .btn.o_toggle_sublines .fa-caret-down' },
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("serial2")',
|
||||
run: 'scan productlot1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("productlot1")',
|
||||
run: 'scan lot1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_line .qty-done:contains(3)',
|
||||
run: 'scan productserial1',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("productserial1")',
|
||||
run: 'scan serial3',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: ':contains("productserial1") .o_sublines .o_barcode_line:contains("serial3")',
|
||||
run: function () {
|
||||
helper.assertLinesCount(2);
|
||||
helper.assertSublinesCount(3);
|
||||
},
|
||||
},
|
||||
|
||||
// Edit a line to trigger a save.
|
||||
{
|
||||
trigger: '.o_add_line',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_field_widget[name="product_id"]',
|
||||
},
|
||||
{
|
||||
trigger: '.o_discard',
|
||||
},
|
||||
|
||||
// Scan tracked by lots product, then scan new lots.
|
||||
{
|
||||
trigger: '.o_sublines .o_barcode_line:nth-child(3)',
|
||||
run: function () {
|
||||
helper.assertLinesCount(2);
|
||||
helper.assertSublinesCount(3);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan productlot1',
|
||||
},
|
||||
{
|
||||
trigger: '.o_barcode_line.o_selected:contains("productlot1")',
|
||||
run: 'scan lot2',
|
||||
},
|
||||
{ trigger: '.o_barcode_line.o_selected .btn.o_toggle_sublines .fa-caret-down' },
|
||||
{
|
||||
trigger: '.o_barcode_line .o_barcode_line:contains("lot2")',
|
||||
run: 'scan lot3',
|
||||
},
|
||||
|
||||
// Must have 6 lines in two groups: lot1, lot2, lot3 and serial1, serial2, serial3.
|
||||
// Grouped lines for `productlot1` should be unfolded.
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("productlot1") .o_sublines>.o_barcode_line.o_selected:contains("lot3")',
|
||||
run: function () {
|
||||
helper.assertLinesCount(2);
|
||||
helper.assertSublinesCount(3);
|
||||
}
|
||||
},
|
||||
...tour.stepUtils.validateBarcodeForm(),
|
||||
|
||||
{
|
||||
trigger: '.o_stock_barcode_main_menu',
|
||||
run: function () {
|
||||
helper.assertErrorMessage('The inventory adjustment has been validated');
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
tour.register('test_inventory_nomenclature', {test: true}, [
|
||||
|
||||
{
|
||||
trigger: '.button_inventory',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: function() {
|
||||
helper.assertScanMessage('scan_product');
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan 2145631123457', // 12.345 kg
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.product-label:contains("product_weight")'
|
||||
},
|
||||
...tour.stepUtils.validateBarcodeForm(),
|
||||
{
|
||||
trigger: '.o_stock_barcode_main_menu',
|
||||
run: function () {
|
||||
helper.assertErrorMessage('The inventory adjustment has been validated');
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
tour.register('test_inventory_package', {test: true}, [
|
||||
|
||||
{
|
||||
trigger: '.button_inventory',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan PACK001',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("product2") .o_edit',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '[name="inventory_quantity"] input',
|
||||
run: 'text 21'
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_save',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_apply_page',
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_notification.border-success',
|
||||
run: function () {
|
||||
helper.assertErrorMessage('The inventory adjustment has been validated');
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
trigger: '.o_stock_barcode_main_menu',
|
||||
},
|
||||
]);
|
||||
|
||||
tour.register('test_inventory_owner_scan_package', {test: true}, [
|
||||
{
|
||||
trigger: '.button_inventory',
|
||||
},
|
||||
{
|
||||
trigger: '.o_barcode_client_action',
|
||||
run: 'scan P00001',
|
||||
},
|
||||
{
|
||||
trigger: '.o_barcode_client_action:contains("P00001")',
|
||||
},
|
||||
{
|
||||
trigger: '.o_barcode_client_action:contains("Azure Interior")',
|
||||
},
|
||||
...tour.stepUtils.validateBarcodeForm(),
|
||||
]);
|
||||
|
||||
tour.register('test_inventory_using_buttons', {test: true}, [
|
||||
{ trigger: '.button_inventory' },
|
||||
|
||||
// Scans product 1: must have 1 quantity and buttons +1/-1 must be visible.
|
||||
{ trigger: '.o_barcode_client_action', run: 'scan product1' },
|
||||
{
|
||||
trigger: '.o_barcode_client_action .o_barcode_line',
|
||||
run: function () {
|
||||
helper.assertLinesCount(1);
|
||||
const $line = helper.getLine({barcode: 'product1'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQty($line, '1');
|
||||
helper.assertButtonIsVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsVisible($line, 'remove_unit');
|
||||
}
|
||||
},
|
||||
// Clicks on -1 button: must have 0 quantity, -1 still visible but disabled.
|
||||
{ trigger: '.o_remove_unit' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("0")',
|
||||
run: function () {
|
||||
helper.assertLinesCount(1);
|
||||
const $line = helper.getLine({barcode: 'product1'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQty($line, '0');
|
||||
helper.assertButtonIsVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsVisible($line, 'remove_unit');
|
||||
const decrementButton = document.querySelector('.o_line_button.o_remove_unit');
|
||||
helper.assert(decrementButton.hasAttribute('disabled'), true);
|
||||
}
|
||||
},
|
||||
// Clicks on +1 button: must have 1 quantity, -1 must be enabled now.
|
||||
{ trigger: '.o_add_quantity' },
|
||||
{
|
||||
trigger: '.o_barcode_line .qty-done:contains("1")',
|
||||
run: function () {
|
||||
helper.assertLinesCount(1);
|
||||
const $line = helper.getLine({barcode: 'product1'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQty($line, '1');
|
||||
helper.assertButtonIsVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsVisible($line, 'remove_unit');
|
||||
const decrementButton = document.querySelector('.o_line_button.o_remove_unit');
|
||||
helper.assert(decrementButton.hasAttribute('disabled'), false);
|
||||
}
|
||||
},
|
||||
|
||||
// Scans productserial1: must have 0 quantity, buttons must be hidden (a
|
||||
// line for a product tracked by SN doesn't have -1/+1 buttons).
|
||||
{ trigger: '.o_barcode_client_action', run: 'scan productserial1' },
|
||||
{
|
||||
trigger: '.o_barcode_client_action .o_barcode_line:nth-child(2)',
|
||||
run: function () {
|
||||
helper.assertLinesCount(2);
|
||||
const $line = helper.getLine({barcode: 'productserial1'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQty($line, '0');
|
||||
helper.assertButtonIsNotVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsNotVisible($line, 'remove_unit');
|
||||
const setButton = document.querySelector('.o_selected .o_line_button.o_set > .fa-check');
|
||||
helper.assert(Boolean(setButton), true);
|
||||
}
|
||||
},
|
||||
// Scans a serial number: must have 1 quantity, check button must display a "X".
|
||||
{ trigger: '.o_barcode_client_action', run: 'scan BNG-118' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("BNG-118")',
|
||||
run: function () {
|
||||
helper.assertLinesCount(2);
|
||||
const $line = helper.getLine({barcode: 'productserial1'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQty($line, '1');
|
||||
helper.assertButtonIsNotVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsNotVisible($line, 'remove_unit');
|
||||
const setButton = document.querySelector('.o_selected .o_line_button.o_set.o_difference');
|
||||
helper.assert(Boolean(setButton), true);
|
||||
}
|
||||
},
|
||||
// Clicks on set button: must set the inventory quantity equals to the quantity .
|
||||
{ trigger: '.o_barcode_line:contains("productserial1") .o_line_button.o_set' },
|
||||
{
|
||||
trigger: '.o_barcode_line.o_selected .fa-check',
|
||||
run: function () {
|
||||
helper.assertLinesCount(2);
|
||||
const $line = helper.getLine({barcode: 'productserial1'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQty($line, '0');
|
||||
helper.assertButtonIsNotVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsNotVisible($line, 'remove_unit');
|
||||
const goodQuantitySetButton = document.querySelector('.o_selected .o_line_button.o_set > .fa-check');
|
||||
helper.assert(Boolean(goodQuantitySetButton), true);
|
||||
const differenceSetButton = document.querySelector('.o_selected .o_line_button.o_set.o_difference');
|
||||
helper.assert(Boolean(differenceSetButton), false);
|
||||
}
|
||||
},
|
||||
// Clicks again on set button: must unset the quantity.
|
||||
{ trigger: '.o_barcode_line:contains("productserial1") .o_line_button.o_set' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("productserial1"):contains("?")',
|
||||
run: function () {
|
||||
helper.assertLinesCount(2);
|
||||
const $line = helper.getLine({barcode: 'productserial1'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQty($line, '?');
|
||||
helper.assertButtonIsNotVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsNotVisible($line, 'remove_unit');
|
||||
const goodQuantitySetButton = document.querySelector('.o_selected .o_line_button.o_set > .fa-check');
|
||||
helper.assert(Boolean(goodQuantitySetButton), false);
|
||||
const differenceSetButton = document.querySelector('.o_selected .o_line_button.o_set.o_difference');
|
||||
helper.assert(Boolean(differenceSetButton), false);
|
||||
const emptySetButton = document.querySelector('.o_selected .o_line_button.o_set');
|
||||
helper.assert(Boolean(emptySetButton), true);
|
||||
}
|
||||
},
|
||||
|
||||
// Scans productlot1: must have 0 quantity, buttons should be visible.
|
||||
{ trigger: '.o_barcode_client_action', run: 'scan productlot1' },
|
||||
{
|
||||
trigger: '.o_barcode_client_action .o_barcode_line:nth-child(3)',
|
||||
run: function () {
|
||||
helper.assertLinesCount(3);
|
||||
const $line = helper.getLine({barcode: 'productlot1'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQty($line, '0');
|
||||
helper.assertButtonIsVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsVisible($line, 'remove_unit');
|
||||
const decrementButton = document.querySelector('.o_line_button.o_remove_unit');
|
||||
helper.assert(decrementButton.hasAttribute('disabled'), true);
|
||||
}
|
||||
},
|
||||
// Scans a lot number: must have 1 quantity, buttons should still be visible.
|
||||
{ trigger: '.o_barcode_client_action', run: 'scan toto-42' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("toto-42")',
|
||||
run: function () {
|
||||
helper.assertLinesCount(3);
|
||||
const $line = helper.getLine({barcode: 'productlot1'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQty($line, '1');
|
||||
helper.assertButtonIsVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsVisible($line, 'remove_unit');
|
||||
const decrementButton = document.querySelector('.o_line_button.o_remove_unit');
|
||||
helper.assert(decrementButton.hasAttribute('disabled'), false);
|
||||
}
|
||||
},
|
||||
// Clicks on -1 button: must have 0 quantity, button -1 must be disabled again.
|
||||
{ trigger: '.o_barcode_line:contains("productlot1") .o_remove_unit' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("productlot1") .qty-done:contains("0")',
|
||||
run: function () {
|
||||
helper.assertLinesCount(3);
|
||||
const $line = helper.getLine({barcode: 'productlot1'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQty($line, '0');
|
||||
helper.assertButtonIsVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsVisible($line, 'remove_unit');
|
||||
const decrementButton = document.querySelector('.o_line_button.o_remove_unit');
|
||||
helper.assert(decrementButton.hasAttribute('disabled'), true);
|
||||
}
|
||||
},
|
||||
// Clicks on +1 button: must have 1 quantity, buttons must be visible.
|
||||
{ trigger: '.o_barcode_line:contains("productlot1") .o_add_quantity' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("productlot1") .qty-done:contains(1)',
|
||||
run: function () {
|
||||
helper.assertLinesCount(3);
|
||||
const $line = helper.getLine({barcode: 'productlot1'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQty($line, '1');
|
||||
helper.assertButtonIsVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsVisible($line, 'remove_unit');
|
||||
const decrementButton = document.querySelector('.o_line_button.o_remove_unit');
|
||||
helper.assert(decrementButton.hasAttribute('disabled'), false);
|
||||
}
|
||||
},
|
||||
|
||||
// Scans product2 => Should retrieve the quantity on hand and display 1/10.
|
||||
{ trigger: '.o_barcode_client_action', run: 'scan product2' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("product2")',
|
||||
run: function () {
|
||||
helper.assertLinesCount(4);
|
||||
const $line = helper.getLine({barcode: 'product2'});
|
||||
helper.assertLineIsHighlighted($line, true);
|
||||
helper.assertLineQuantityOnReservedQty(3, '1 / 10');
|
||||
helper.assertButtonIsVisible($line, 'add_quantity');
|
||||
helper.assertButtonIsVisible($line, 'remove_unit');
|
||||
const setButton = document.querySelector('.o_selected .o_line_button.o_set.o_difference');
|
||||
helper.assert(Boolean(setButton), true);
|
||||
}
|
||||
},
|
||||
// Clicks multiple time on the set quantity button and checks the save is rightly done.
|
||||
{ trigger: '.o_selected .o_line_button.o_set.o_difference' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("product2"):contains("?")',
|
||||
run: function () {
|
||||
const line = document.querySelector('.o_barcode_line[data-barcode=product2]');
|
||||
const qty = line.querySelector('.o_barcode_scanner_qty').textContent;
|
||||
helper.assert(qty, '?/ 10');
|
||||
}
|
||||
},
|
||||
// Goes to the quant form view to trigger a save then go back.
|
||||
{ trigger: '.o_selected .o_line_button.o_edit' },
|
||||
{ trigger: '.o_discard' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("product2"):contains("?")',
|
||||
run: function () {
|
||||
const line = document.querySelector('.o_barcode_line[data-barcode=product2]');
|
||||
const qty = line.querySelector('.o_barcode_scanner_qty').textContent;
|
||||
helper.assert(qty, '?/ 10');
|
||||
}
|
||||
},
|
||||
|
||||
// Clicks again, should pass from "? / 10" to "10 / 10"
|
||||
{ trigger: '.o_barcode_line:contains("product2") .o_line_button.o_set' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("product2") .qty-done:contains("10")',
|
||||
run: function () {
|
||||
const line = document.querySelector('.o_barcode_line[data-barcode=product2]');
|
||||
const qty = line.querySelector('.o_barcode_scanner_qty').textContent;
|
||||
helper.assert(qty, '10/ 10');
|
||||
}
|
||||
},
|
||||
// Goes to the quant form view to trigger a save then go back.
|
||||
{ trigger: '.o_barcode_line:contains("product2") .o_line_button.o_edit' },
|
||||
{ trigger: '.o_discard' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("product2") .qty-done:contains("10")',
|
||||
run: function () {
|
||||
const line = document.querySelector('.o_barcode_line[data-barcode=product2]');
|
||||
const qty = line.querySelector('.o_barcode_scanner_qty').textContent;
|
||||
helper.assert(qty, '10/ 10');
|
||||
}
|
||||
},
|
||||
|
||||
// Clicks again, should pass from "10 / 10" to "? / 10"
|
||||
{ trigger: '.o_barcode_line:contains("product2") .o_line_button.o_set .fa-check' },
|
||||
{
|
||||
trigger: '.o_barcode_line:contains("product2"):contains("?")',
|
||||
run: function () {
|
||||
const line = document.querySelector('.o_barcode_line[data-barcode=product2]');
|
||||
const qty = line.querySelector('.o_barcode_scanner_qty').textContent;
|
||||
helper.assert(qty, '?/ 10');
|
||||
}
|
||||
},
|
||||
|
||||
// Validates the inventory.
|
||||
{ trigger: '.o_apply_page' },
|
||||
{ trigger: '.o_notification.border-success' }
|
||||
]);
|
||||
3051
stock_barcode/static/tests/tours/tour_test_barcode_flows_picking.js
Normal file
3051
stock_barcode/static/tests/tours/tour_test_barcode_flows_picking.js
Normal file
File diff suppressed because it is too large
Load Diff
1211
stock_barcode/static/tests/tours/tour_test_barcode_gs1.js
Normal file
1211
stock_barcode/static/tests/tours/tour_test_barcode_gs1.js
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,77 @@
|
||||
odoo.define('stock_mobile_barcode.stock_picking_barcode_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
const { mock } = require('web.test_utils');
|
||||
const { createWebClient, doAction } = require('@web/../tests/webclient/helpers');
|
||||
const BarcodeScanner = require('@web/webclient/barcode/barcode_scanner');
|
||||
const { destroy, getFixture } = require("@web/../tests/helpers/utils");
|
||||
|
||||
QUnit.module('stock_mobile_barcode', {}, function () {
|
||||
|
||||
QUnit.module('Barcode', {
|
||||
beforeEach: function () {
|
||||
var self = this;
|
||||
|
||||
this.clientData = {
|
||||
action: {
|
||||
tag: 'stock_barcode_client_action',
|
||||
type: 'ir.actions.client',
|
||||
res_model: "stock.picking",
|
||||
context: {},
|
||||
},
|
||||
currentState: {
|
||||
actions: {},
|
||||
data: {
|
||||
records: {
|
||||
'barcode.nomenclature': [{
|
||||
id: 1,
|
||||
rule_ids: [],
|
||||
}],
|
||||
'stock.location': [],
|
||||
'stock.move.line': [],
|
||||
'stock.picking': [],
|
||||
},
|
||||
nomenclature_id: 1,
|
||||
},
|
||||
groups: {},
|
||||
},
|
||||
};
|
||||
this.mockRPC = function (route, args) {
|
||||
if (route === '/stock_barcode/get_barcode_data') {
|
||||
return Promise.resolve(self.clientData.currentState);
|
||||
} else if (route === '/stock_barcode/static/img/barcode.svg') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('scan barcode button in mobile device', async function (assert) {
|
||||
assert.expect(1);
|
||||
const pickingRecord = {
|
||||
id: 2,
|
||||
state: 'done',
|
||||
move_line_ids: [],
|
||||
};
|
||||
this.clientData.action.context.active_id = pickingRecord.id;
|
||||
this.clientData.currentState.data.records['stock.picking'].push(pickingRecord);
|
||||
this.clientData.currentState.groups.group_stock_multi_locations = false;
|
||||
|
||||
mock.patch(BarcodeScanner, {
|
||||
isBarcodeScannerSupported: () => true,
|
||||
scanBarcode: async () => {},
|
||||
});
|
||||
|
||||
const target = getFixture();
|
||||
|
||||
const webClient = await createWebClient({
|
||||
mockRPC: this.mockRPC,
|
||||
});
|
||||
await doAction(webClient, this.clientData.action);
|
||||
assert.containsOnce(target, '.o_stock_mobile_barcode');
|
||||
destroy(webClient);
|
||||
mock.unpatch(BarcodeScanner);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
odoo.define('stock_barcode.stock_picking_barcode_tests', function (require) {
|
||||
"use strict";
|
||||
|
||||
const { createWebClient, doAction } = require('@web/../tests/webclient/helpers');
|
||||
const { getFixture } = require("@web/../tests/helpers/utils");
|
||||
|
||||
QUnit.module('stock_barcode', {}, function () {
|
||||
|
||||
QUnit.module('Barcode', {
|
||||
beforeEach: function () {
|
||||
var self = this;
|
||||
|
||||
this.clientData = {
|
||||
action: {
|
||||
tag: 'stock_barcode_client_action',
|
||||
type: 'ir.actions.client',
|
||||
res_model: "stock.picking",
|
||||
context: {},
|
||||
},
|
||||
currentState: {
|
||||
actions: {},
|
||||
data: {
|
||||
records: {
|
||||
'barcode.nomenclature': [{
|
||||
id: 1,
|
||||
rule_ids: [],
|
||||
}],
|
||||
'stock.location': [],
|
||||
'stock.move.line': [],
|
||||
'stock.picking': [],
|
||||
},
|
||||
nomenclature_id: 1,
|
||||
},
|
||||
groups: {},
|
||||
},
|
||||
};
|
||||
this.mockRPC = function (route, args) {
|
||||
if (route === '/stock_barcode/get_barcode_data') {
|
||||
return Promise.resolve(self.clientData.currentState);
|
||||
} else if (route === '/stock_barcode/static/img/barcode.svg') {
|
||||
return Promise.resolve();
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
QUnit.test('exclamation-triangle when picking is done', async function (assert) {
|
||||
assert.expect(1);
|
||||
const pickingRecord = {
|
||||
id: 2,
|
||||
state: 'done',
|
||||
move_line_ids: [],
|
||||
};
|
||||
this.clientData.action.context.active_id = pickingRecord.id;
|
||||
this.clientData.currentState.data.records['stock.picking'].push(pickingRecord);
|
||||
const target = getFixture();
|
||||
const webClient = await createWebClient({
|
||||
mockRPC: this.mockRPC,
|
||||
});
|
||||
await doAction(webClient, this.clientData.action);
|
||||
assert.containsOnce(target, '.fa-5x.fa-exclamation-triangle:not(.d-none)', "Should have warning icon");
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user