summaryrefslogtreecommitdiff
path: root/addons/product/static
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/product/static
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/product/static')
-rw-r--r--addons/product/static/description/icon.pngbin0 -> 5400 bytes
-rw-r--r--addons/product/static/description/icon.svg1
-rw-r--r--addons/product/static/img/membership_0-image.jpgbin0 -> 3796 bytes
-rw-r--r--addons/product/static/img/membership_1-image.jpgbin0 -> 3158 bytes
-rw-r--r--addons/product/static/img/membership_2-image.jpgbin0 -> 3691 bytes
-rw-r--r--addons/product/static/img/product_chair.pngbin0 -> 32050 bytes
-rw-r--r--addons/product/static/img/product_lamp.pngbin0 -> 14167 bytes
-rw-r--r--addons/product/static/img/product_product_1-image.jpgbin0 -> 3969 bytes
-rw-r--r--addons/product/static/img/product_product_10-image.pngbin0 -> 20655 bytes
-rw-r--r--addons/product/static/img/product_product_11-image.pngbin0 -> 24286 bytes
-rw-r--r--addons/product/static/img/product_product_12-image.pngbin0 -> 28317 bytes
-rw-r--r--addons/product/static/img/product_product_13-image.pngbin0 -> 12454 bytes
-rw-r--r--addons/product/static/img/product_product_16-image.pngbin0 -> 77362 bytes
-rw-r--r--addons/product/static/img/product_product_20-image.pngbin0 -> 23325 bytes
-rw-r--r--addons/product/static/img/product_product_22-image.pngbin0 -> 17593 bytes
-rw-r--r--addons/product/static/img/product_product_24-image.pngbin0 -> 35809 bytes
-rw-r--r--addons/product/static/img/product_product_25-image.pngbin0 -> 49141 bytes
-rw-r--r--addons/product/static/img/product_product_27-image.pngbin0 -> 22309 bytes
-rw-r--r--addons/product/static/img/product_product_3-image.jpgbin0 -> 2947 bytes
-rw-r--r--addons/product/static/img/product_product_43-image.jpgbin0 -> 10796 bytes
-rw-r--r--addons/product/static/img/product_product_46-image.pngbin0 -> 34606 bytes
-rw-r--r--addons/product/static/img/product_product_5-image.pngbin0 -> 16584 bytes
-rw-r--r--addons/product/static/img/product_product_6-image.pngbin0 -> 22715 bytes
-rw-r--r--addons/product/static/img/product_product_7-image.pngbin0 -> 50657 bytes
-rw-r--r--addons/product/static/img/product_product_8-image.pngbin0 -> 17943 bytes
-rw-r--r--addons/product/static/img/product_product_9-image.pngbin0 -> 34588 bytes
-rw-r--r--addons/product/static/img/product_product_d01-image.pngbin0 -> 30015 bytes
-rw-r--r--addons/product/static/img/product_product_d03-image.pngbin0 -> 42437 bytes
-rw-r--r--addons/product/static/img/table01.pngbin0 -> 18385 bytes
-rw-r--r--addons/product/static/img/table02.pngbin0 -> 14067 bytes
-rw-r--r--addons/product/static/img/table03.pngbin0 -> 15542 bytes
-rw-r--r--addons/product/static/img/table04.pngbin0 -> 21610 bytes
-rw-r--r--addons/product/static/src/js/product_pricelist_report.js291
-rw-r--r--addons/product/static/src/xml/pricelist_report.xml51
-rw-r--r--addons/product/static/tests/product_pricelist_report_test.js146
-rw-r--r--addons/product/static/xls/product_pricelist.xlsbin0 -> 32768 bytes
-rw-r--r--addons/product/static/xls/product_supplierinfo.xlsbin0 -> 31744 bytes
-rw-r--r--addons/product/static/xls/product_template.xlsbin0 -> 36352 bytes
38 files changed, 489 insertions, 0 deletions
diff --git a/addons/product/static/description/icon.png b/addons/product/static/description/icon.png
new file mode 100644
index 00000000..2079879b
--- /dev/null
+++ b/addons/product/static/description/icon.png
Binary files differ
diff --git a/addons/product/static/description/icon.svg b/addons/product/static/description/icon.svg
new file mode 100644
index 00000000..2b0b6824
--- /dev/null
+++ b/addons/product/static/description/icon.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="70" height="70"><defs><path id="a" d="M4 0h61c4 0 5 1 5 5v60c0 4-1 5-5 5H4c-3 0-4-1-4-5V5c0-4 1-5 4-5z"/><linearGradient id="c" x1="100%" x2="0%" y1="0%" y2="100%"><stop offset="0%" stop-color="#B06161"/><stop offset="45.785%" stop-color="#984E4E"/><stop offset="100%" stop-color="#7C3838"/></linearGradient><path id="d" d="M48.466 42.033c0 .837-.277 1.548-.831 2.133L36.606 55.823c-.584.585-1.265.877-2.044.877-.793 0-1.467-.292-2.021-.877l-16.06-16.965c-.569-.585-1.051-1.382-1.448-2.393s-.595-1.935-.595-2.773v-9.857c0-.821.284-1.532.853-2.132.569-.6 1.243-.9 2.021-.9h9.344c.794 0 1.67.209 2.628.627.959.419 1.722.928 2.291 1.528l16.06 16.919c.554.616.83 1.335.83 2.156zM24.5 28.385c0-.838-.28-1.552-.842-2.145-.562-.592-1.24-.888-2.033-.888-.794 0-1.471.296-2.033.888-.561.593-.842 1.307-.842 2.145 0 .837.28 1.552.842 2.144.562.592 1.24.889 2.033.889.794 0 1.471-.297 2.033-.889.561-.592.842-1.307.842-2.144zm32.59 13.648c0 .837-.276 1.548-.83 2.133L45.23 55.823c-.584.585-1.265.877-2.044.877-.539 0-.98-.11-1.325-.332-.344-.22-.74-.576-1.19-1.066l10.557-11.136c.554-.585.83-1.296.83-2.133 0-.821-.276-1.54-.83-2.156l-16.06-16.919c-.57-.6-1.333-1.11-2.291-1.528-.958-.418-1.834-.628-2.628-.628h5.031c.794 0 1.67.21 2.628.628.959.419 1.722.928 2.291 1.528l16.06 16.919c.554.616.83 1.335.83 2.156z"/><path id="e" d="M48.466 40.033c0 .837-.277 1.548-.831 2.133L36.606 53.823c-.584.585-1.265.877-2.044.877-.793 0-1.467-.292-2.021-.877l-16.06-16.965c-.569-.585-1.051-1.382-1.448-2.393s-.595-1.935-.595-2.773v-9.857c0-.821.284-1.532.853-2.132.569-.6 1.243-.9 2.021-.9h9.344c.794 0 1.67.209 2.628.627.959.419 1.722.928 2.291 1.528l16.06 16.919c.554.616.83 1.335.83 2.156zM24.5 26.385c0-.838-.28-1.552-.842-2.145-.562-.592-1.24-.888-2.033-.888-.794 0-1.471.296-2.033.888-.561.593-.842 1.307-.842 2.145 0 .837.28 1.552.842 2.144.562.592 1.24.889 2.033.889.794 0 1.471-.297 2.033-.889.561-.592.842-1.307.842-2.144zm32.59 13.648c0 .837-.276 1.548-.83 2.133L45.23 53.823c-.584.585-1.265.877-2.044.877-.539 0-.98-.11-1.325-.332-.344-.22-.74-.576-1.19-1.066l10.557-11.136c.554-.585.83-1.296.83-2.133 0-.821-.276-1.54-.83-2.156l-16.06-16.919c-.57-.6-1.333-1.11-2.291-1.528-.958-.418-1.834-.628-2.628-.628h5.031c.794 0 1.67.21 2.628.628.959.419 1.722.928 2.291 1.528l16.06 16.919c.554.616.83 1.335.83 2.156z"/></defs><g fill="none" fill-rule="evenodd"><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><g mask="url(#b)"><path fill="url(#c)" d="M0 0H70V70H0z"/><path fill="#FFF" fill-opacity=".383" d="M4 1h61c2.667 0 4.333.667 5 2V0H0v3c.667-1.333 2-2 4-2z"/><path fill="#393939" d="M4 69c-2 0-4-1-4-4V33.916L16.402 19h19.682L56.79 41 39.224 69H4z" opacity=".324"/><path fill="#000" fill-opacity=".383" d="M4 69h61c2.667 0 4.333-1 5-3v4H0v-4c.667 2 2 3 4 3z"/><use fill="#000" fill-rule="nonzero" opacity=".3" xlink:href="#d"/><use fill="#FFF" fill-rule="nonzero" xlink:href="#e"/></g></g></svg> \ No newline at end of file
diff --git a/addons/product/static/img/membership_0-image.jpg b/addons/product/static/img/membership_0-image.jpg
new file mode 100644
index 00000000..f9723384
--- /dev/null
+++ b/addons/product/static/img/membership_0-image.jpg
Binary files differ
diff --git a/addons/product/static/img/membership_1-image.jpg b/addons/product/static/img/membership_1-image.jpg
new file mode 100644
index 00000000..ade87446
--- /dev/null
+++ b/addons/product/static/img/membership_1-image.jpg
Binary files differ
diff --git a/addons/product/static/img/membership_2-image.jpg b/addons/product/static/img/membership_2-image.jpg
new file mode 100644
index 00000000..ed6f4118
--- /dev/null
+++ b/addons/product/static/img/membership_2-image.jpg
Binary files differ
diff --git a/addons/product/static/img/product_chair.png b/addons/product/static/img/product_chair.png
new file mode 100644
index 00000000..5add5e91
--- /dev/null
+++ b/addons/product/static/img/product_chair.png
Binary files differ
diff --git a/addons/product/static/img/product_lamp.png b/addons/product/static/img/product_lamp.png
new file mode 100644
index 00000000..03e6bb60
--- /dev/null
+++ b/addons/product/static/img/product_lamp.png
Binary files differ
diff --git a/addons/product/static/img/product_product_1-image.jpg b/addons/product/static/img/product_product_1-image.jpg
new file mode 100644
index 00000000..7fc47569
--- /dev/null
+++ b/addons/product/static/img/product_product_1-image.jpg
Binary files differ
diff --git a/addons/product/static/img/product_product_10-image.png b/addons/product/static/img/product_product_10-image.png
new file mode 100644
index 00000000..a839c7fe
--- /dev/null
+++ b/addons/product/static/img/product_product_10-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_11-image.png b/addons/product/static/img/product_product_11-image.png
new file mode 100644
index 00000000..156e5ebd
--- /dev/null
+++ b/addons/product/static/img/product_product_11-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_12-image.png b/addons/product/static/img/product_product_12-image.png
new file mode 100644
index 00000000..d606721f
--- /dev/null
+++ b/addons/product/static/img/product_product_12-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_13-image.png b/addons/product/static/img/product_product_13-image.png
new file mode 100644
index 00000000..96baa3d9
--- /dev/null
+++ b/addons/product/static/img/product_product_13-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_16-image.png b/addons/product/static/img/product_product_16-image.png
new file mode 100644
index 00000000..dfbb75c9
--- /dev/null
+++ b/addons/product/static/img/product_product_16-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_20-image.png b/addons/product/static/img/product_product_20-image.png
new file mode 100644
index 00000000..59f670fe
--- /dev/null
+++ b/addons/product/static/img/product_product_20-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_22-image.png b/addons/product/static/img/product_product_22-image.png
new file mode 100644
index 00000000..aa581b69
--- /dev/null
+++ b/addons/product/static/img/product_product_22-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_24-image.png b/addons/product/static/img/product_product_24-image.png
new file mode 100644
index 00000000..f6a8ded9
--- /dev/null
+++ b/addons/product/static/img/product_product_24-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_25-image.png b/addons/product/static/img/product_product_25-image.png
new file mode 100644
index 00000000..947aa549
--- /dev/null
+++ b/addons/product/static/img/product_product_25-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_27-image.png b/addons/product/static/img/product_product_27-image.png
new file mode 100644
index 00000000..8c54433b
--- /dev/null
+++ b/addons/product/static/img/product_product_27-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_3-image.jpg b/addons/product/static/img/product_product_3-image.jpg
new file mode 100644
index 00000000..33884c0b
--- /dev/null
+++ b/addons/product/static/img/product_product_3-image.jpg
Binary files differ
diff --git a/addons/product/static/img/product_product_43-image.jpg b/addons/product/static/img/product_product_43-image.jpg
new file mode 100644
index 00000000..3bab8a3f
--- /dev/null
+++ b/addons/product/static/img/product_product_43-image.jpg
Binary files differ
diff --git a/addons/product/static/img/product_product_46-image.png b/addons/product/static/img/product_product_46-image.png
new file mode 100644
index 00000000..d9525984
--- /dev/null
+++ b/addons/product/static/img/product_product_46-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_5-image.png b/addons/product/static/img/product_product_5-image.png
new file mode 100644
index 00000000..53d161e2
--- /dev/null
+++ b/addons/product/static/img/product_product_5-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_6-image.png b/addons/product/static/img/product_product_6-image.png
new file mode 100644
index 00000000..a6c0299f
--- /dev/null
+++ b/addons/product/static/img/product_product_6-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_7-image.png b/addons/product/static/img/product_product_7-image.png
new file mode 100644
index 00000000..7ee0a189
--- /dev/null
+++ b/addons/product/static/img/product_product_7-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_8-image.png b/addons/product/static/img/product_product_8-image.png
new file mode 100644
index 00000000..acc3afcd
--- /dev/null
+++ b/addons/product/static/img/product_product_8-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_9-image.png b/addons/product/static/img/product_product_9-image.png
new file mode 100644
index 00000000..580f1c3c
--- /dev/null
+++ b/addons/product/static/img/product_product_9-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_d01-image.png b/addons/product/static/img/product_product_d01-image.png
new file mode 100644
index 00000000..28e1a8d5
--- /dev/null
+++ b/addons/product/static/img/product_product_d01-image.png
Binary files differ
diff --git a/addons/product/static/img/product_product_d03-image.png b/addons/product/static/img/product_product_d03-image.png
new file mode 100644
index 00000000..854660b5
--- /dev/null
+++ b/addons/product/static/img/product_product_d03-image.png
Binary files differ
diff --git a/addons/product/static/img/table01.png b/addons/product/static/img/table01.png
new file mode 100644
index 00000000..9aa8ef1d
--- /dev/null
+++ b/addons/product/static/img/table01.png
Binary files differ
diff --git a/addons/product/static/img/table02.png b/addons/product/static/img/table02.png
new file mode 100644
index 00000000..5291a47f
--- /dev/null
+++ b/addons/product/static/img/table02.png
Binary files differ
diff --git a/addons/product/static/img/table03.png b/addons/product/static/img/table03.png
new file mode 100644
index 00000000..9da4c637
--- /dev/null
+++ b/addons/product/static/img/table03.png
Binary files differ
diff --git a/addons/product/static/img/table04.png b/addons/product/static/img/table04.png
new file mode 100644
index 00000000..28fdd46b
--- /dev/null
+++ b/addons/product/static/img/table04.png
Binary files differ
diff --git a/addons/product/static/src/js/product_pricelist_report.js b/addons/product/static/src/js/product_pricelist_report.js
new file mode 100644
index 00000000..c040a190
--- /dev/null
+++ b/addons/product/static/src/js/product_pricelist_report.js
@@ -0,0 +1,291 @@
+odoo.define('product.generate_pricelist', function (require) {
+'use strict';
+
+var AbstractAction = require('web.AbstractAction');
+var core = require('web.core');
+var FieldMany2One = require('web.relational_fields').FieldMany2One;
+var StandaloneFieldManagerMixin = require('web.StandaloneFieldManagerMixin');
+var Widget = require('web.Widget');
+
+var QWeb = core.qweb;
+var _t = core._t;
+
+var QtyTagWidget = Widget.extend({
+ template: 'product.report_pricelist_qty',
+ events: {
+ 'click .o_remove_qty': '_onClickRemoveQty',
+ },
+ /**
+ * @override
+ */
+ init: function (parent, defaulQuantities) {
+ this._super.apply(this, arguments);
+ this.quantities = defaulQuantities;
+ this.MAX_QTY = 5;
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Add a quantity when add(+) button clicked.
+ *
+ * @private
+ */
+ _onClickAddQty: function () {
+ if (this.quantities.length >= this.MAX_QTY) {
+ this.do_notify(false, _.str.sprintf(
+ _t("At most %d quantities can be displayed simultaneously. Remove a selected quantity to add others."),
+ this.MAX_QTY
+ ));
+ return;
+ }
+ const qty = parseInt(this.$('.o_product_qty').val());
+ if (qty && qty > 0) {
+ // Check qty already exist
+ if (this.quantities.indexOf(qty) === -1) {
+ this.quantities.push(qty);
+ this.quantities = this.quantities.sort((a, b) => a - b);
+ this.trigger_up('qty_changed', {quantities: this.quantities});
+ this.renderElement();
+ } else {
+ this.displayNotification({
+ message: _.str.sprintf(_t("Quantity already present (%d)."), qty),
+ type: 'info'
+ });
+ }
+ } else {
+ this.do_notify(false, _t("Please enter a positive whole number"));
+ }
+ },
+ /**
+ * Remove quantity.
+ *
+ * @private
+ * @param {jQueryEvent} ev
+ */
+ _onClickRemoveQty: function (ev) {
+ const qty = parseInt($(ev.currentTarget).closest('.badge').data('qty'));
+ this.quantities = this.quantities.filter(q => q !== qty);
+ this.trigger_up('qty_changed', {quantities: this.quantities});
+ this.renderElement();
+ },
+});
+
+var GeneratePriceList = AbstractAction.extend(StandaloneFieldManagerMixin, {
+ hasControlPanel: true,
+ events: {
+ 'click .o_action': '_onClickAction',
+ 'submit form': '_onSubmitForm',
+ },
+ custom_events: Object.assign({}, StandaloneFieldManagerMixin.custom_events, {
+ field_changed: '_onFieldChanged',
+ qty_changed: '_onQtyChanged',
+ }),
+ /**
+ * @override
+ */
+ init: function (parent, params) {
+ this._super.apply(this, arguments);
+ StandaloneFieldManagerMixin.init.call(this);
+ this.context = params.context;
+ // in case the window got refreshed
+ if (params.params && params.params.active_ids && typeof(params.params.active_ids === 'string')) {
+ try {
+ this.context.active_ids = params.params.active_ids.split(',').map(id => parseInt(id));
+ this.context.active_model = params.params.active_model;
+ } catch(e) {
+ console.log('unable to load ids from the url fragment 🙁');
+ }
+ }
+ if (!this.context.active_model) {
+ // started without an active module, assume product templates
+ this.context.active_model = 'product.template';
+ }
+ this.context.quantities = [1, 5, 10];
+ },
+ /**
+ * @override
+ */
+ willStart: function () {
+ let getPricelit;
+ // started without a selected pricelist in context? just get the first one
+ if (this.context.default_pricelist) {
+ getPricelit = Promise.resolve([this.context.default_pricelist]);
+ } else {
+ getPricelit = this._rpc({
+ model: 'product.pricelist',
+ method: 'search',
+ args: [[]],
+ kwargs: {limit: 1}
+ })
+ }
+ const fieldSetup = getPricelit.then(pricelistIds => {
+ return this.model.makeRecord('report.product.report_pricelist', [{
+ name: 'pricelist_id',
+ type: 'many2one',
+ relation: 'product.pricelist',
+ value: pricelistIds[0],
+ }]);
+ }).then(recordID => {
+ const record = this.model.get(recordID);
+ this.many2one = new FieldMany2One(this, 'pricelist_id', record, {
+ mode: 'edit',
+ attrs: {
+ can_create: false,
+ can_write: false,
+ options: {no_open: true},
+ },
+ });
+ this._registerWidget(recordID, 'pricelist_id', this.many2one);
+ });
+ return Promise.all([fieldSetup, this._getHtml(), this._super()]);
+ },
+ /**
+ * @override
+ */
+ start: function () {
+ this.controlPanelProps.cp_content = this._renderComponent();
+ return this._super.apply(this, arguments).then(() => {
+ this.$('.o_content').html(this.reportHtml);
+ });
+ },
+ /**
+ * Include the current model (template/variant) in the state to allow refreshing without losing
+ * the proper context.
+ * @override
+ */
+ getState: function() {
+ return {
+ active_model: this.context.active_model,
+ };
+ },
+ getTitle: function() {
+ return _t('Pricelist Report');
+ },
+
+ //--------------------------------------------------------------------------
+ // Private
+ //--------------------------------------------------------------------------
+
+ /**
+ * Get template to display report.
+ *
+ * @private
+ * @returns {Promise}
+ */
+ _getHtml: function () {
+ return this._rpc({
+ model: 'report.product.report_pricelist',
+ method: 'get_html',
+ kwargs: {context: this.context},
+ }).then(result => {
+ this.reportHtml = result;
+ });
+ },
+ /**
+ * Reload report.
+ *
+ * @private
+ * @returns {Promise}
+ */
+ _reload: function () {
+ return this._getHtml().then(() => {
+ this.$('.o_content').html(this.reportHtml);
+ });
+ },
+ /**
+ * Render search view and print button.
+ *
+ * @private
+ */
+ _renderComponent: function () {
+ const $buttons = $('<button>', {
+ class: 'btn btn-primary',
+ text: _t("Print"),
+ }).on('click', this._onClickPrint.bind(this));
+
+ const $searchview = $(QWeb.render('product.report_pricelist_search'));
+ this.many2one.appendTo($searchview.find('.o_pricelist'));
+
+ this.qtyTagWidget = new QtyTagWidget(this, this.context.quantities);
+ this.qtyTagWidget.replace($searchview.find('.o_product_qty'));
+ return { $buttons, $searchview };
+ },
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Open form view of particular record when link clicked.
+ *
+ * @private
+ * @param {jQueryEvent} ev
+ */
+ _onClickAction: function (ev) {
+ ev.preventDefault();
+ this.do_action({
+ type: 'ir.actions.act_window',
+ res_model: $(ev.currentTarget).data('model'),
+ res_id: $(ev.currentTarget).data('res-id'),
+ views: [[false, 'form']],
+ target: 'self',
+ });
+ },
+ /**
+ * Print report in PDF when button clicked.
+ *
+ * @private
+ */
+ _onClickPrint: function () {
+ const reportName = _.str.sprintf('product.report_pricelist?active_model=%s&active_ids=%s&pricelist_id=%s&quantities=%s',
+ this.context.active_model,
+ this.context.active_ids,
+ this.context.pricelist_id || '',
+ this.context.quantities.toString() || '1',
+ );
+ return this.do_action({
+ type: 'ir.actions.report',
+ report_type: 'qweb-pdf',
+ report_name: reportName,
+ report_file: 'product.report_pricelist',
+ });
+ },
+ /**
+ * Reload report when pricelist changed.
+ *
+ * @override
+ */
+ _onFieldChanged: function (event) {
+ this.context.pricelist_id = event.data.changes.pricelist_id.id;
+ StandaloneFieldManagerMixin._onFieldChanged.apply(this, arguments);
+ this._reload();
+ },
+ /**
+ * Reload report when quantities changed.
+ *
+ * @private
+ * @param {OdooEvent} ev
+ * @param {integer[]} event.data.quantities
+ */
+ _onQtyChanged: function (ev) {
+ this.context.quantities = ev.data.quantities;
+ this._reload();
+ },
+ _onSubmitForm: function (ev) {
+ ev.preventDefault();
+ ev.stopPropagation();
+ this.qtyTagWidget._onClickAddQty();
+ },
+});
+
+core.action_registry.add('generate_pricelist', GeneratePriceList);
+
+return {
+ GeneratePriceList,
+ QtyTagWidget
+};
+
+});
diff --git a/addons/product/static/src/xml/pricelist_report.xml b/addons/product/static/src/xml/pricelist_report.xml
new file mode 100644
index 00000000..aff1c219
--- /dev/null
+++ b/addons/product/static/src/xml/pricelist_report.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<templates>
+
+ <t t-name="product.report_pricelist_qty">
+ <span>
+ <div class="input-group">
+ <input type="number" name="qty_to_add" class="o_input o_product_qty form-control text-right" value="1" min="1"/>
+ <div class="input-group-append">
+ <button class="btn btn-secondary o_add_qty text-right form-control" type="submit" title="Add a quantity">
+ <i class="fa fa-plus"/>
+ </button>
+ </div>
+ </div>
+ <span class="o_badges">
+ <t t-set="quantities" t-value="widget.quantities"/>
+ <t t-call="product.report_pricelist_qty_badges"/>
+ </span>
+ </span>
+ </t>
+
+ <t t-name="product.report_pricelist_search">
+ <form class="form-inline ml-4 o_pricelist_report_form">
+ <div class="form-group">
+ <label class="font-weight-bold">Pricelist:</label>
+ <div class="row">
+ <div class="col mr-4">
+ <span class="o_pricelist"/>
+ </div>
+ </div>
+ </div>
+ <div class="form-group">
+ <label class="font-weight-bold" for="qty_to_add">Quantities:</label>
+ <div class="row">
+ <div class="col">
+ <span class="o_product_qty"/>
+ </div>
+ </div>
+ </div>
+ </form>
+ </t>
+
+ <t t-name="product.report_pricelist_qty_badges">
+ <t t-foreach="quantities" t-as="qty">
+ <span class="badge badge-pill border" t-att-data-qty="qty">
+ <t t-esc="qty"/>
+ <i class="fa fa-close o_remove_qty" title="Remove quantity"/>
+ </span>
+ </t>
+ </t>
+
+</templates>
diff --git a/addons/product/static/tests/product_pricelist_report_test.js b/addons/product/static/tests/product_pricelist_report_test.js
new file mode 100644
index 00000000..b9eac3cf
--- /dev/null
+++ b/addons/product/static/tests/product_pricelist_report_test.js
@@ -0,0 +1,146 @@
+odoo.define('product.pricelist.report.tests', function (require) {
+"use strict";
+const core = require('web.core');
+const GeneratePriceList = require('product.generate_pricelist').GeneratePriceList;
+const NotificationService = require('web.NotificationService');
+const testUtils = require('web.test_utils');
+const createActionManager = testUtils.createActionManager;
+const testUtilsMock = require('web.test_utils_mock');
+
+QUnit.module('Product Pricelist', {
+ beforeEach: function () {
+ this.data = {
+ 'product.product': {
+ fields: {
+ id: {type: 'integer'}
+ },
+ records: [{
+ id: 42,
+ display_name: "Customizable Desk"
+ }]
+ },
+ 'product.pricelist': {
+ fields: {
+ id: {type: 'integer'}
+ },
+ records: [{
+ id: 1,
+ display_name: "Public Pricelist"
+ }, {
+ id: 2,
+ display_name: "Test"
+ }]
+ }
+ };
+ },
+}, function () {
+ QUnit.test('Pricelist Client Action', async function (assert) {
+ assert.expect(21);
+
+ const self = this;
+ let Qty = [1, 5, 10]; // default quantities
+ testUtils.mock.patch(GeneratePriceList, {
+ _onFieldChanged: function (event) {
+ assert.step('field_changed');
+ return this._super.apply(this, arguments);
+ },
+ _onQtyChanged: function (event) {
+ assert.deepEqual(event.data.quantities, Qty.sort((a, b) => a - b), "changed quantity should be same.");
+ assert.step('qty_changed');
+ return this._super.apply(this, arguments);
+ },
+ });
+
+ const actionManager = await createActionManager({
+ data: this.data,
+ mockRPC: function(route, args) {
+ if (route === '/web/dataset/call_kw/report.product.report_pricelist/get_html') {
+ return Promise.resolve("");
+ }
+ return this._super(route, args);
+ },
+ services: {
+ notification: NotificationService,
+ },
+ });
+
+ await actionManager.doAction({
+ id: 1,
+ name: 'Generate Pricelist',
+ tag: 'generate_pricelist',
+ type: 'ir.actions.client',
+ context: {
+ 'default_pricelist': 1,
+ 'active_ids': [42],
+ 'active_id': 42,
+ 'active_model': 'product.product'
+ }
+ });
+
+ // checking default pricelist
+ assert.strictEqual(actionManager.$('.o_field_many2one input').val(), "Public Pricelist",
+ "should have default pricelist");
+
+ // changing pricelist
+ await testUtils.fields.many2one.clickOpenDropdown("pricelist_id");
+ await testUtils.fields.many2one.clickItem("pricelist_id", "Test");
+
+ // check wherther pricelist value has been updated or not. along with that check default quantities should be there.
+ assert.strictEqual(actionManager.$('.o_field_many2one input').val(), "Test",
+ "After pricelist change, the pricelist_id field should be updated");
+ assert.strictEqual(actionManager.$('.o_badges > .badge').length, 3,
+ "There should be 3 default Quantities");
+
+ // existing quantity can not be added.
+ await testUtils.dom.click(actionManager.$('.o_add_qty'));
+ let notificationElement = document.body.querySelector('.o_notification_manager .o_notification.bg-info');
+ assert.strictEqual(notificationElement.querySelector('.o_notification_content').textContent,
+ "Quantity already present (1).", "Existing Quantity can not be added");
+
+ // adding few more quantities to check.
+ actionManager.$('.o_product_qty').val(2);
+ Qty.push(2);
+ await testUtils.dom.click(actionManager.$('.o_add_qty'));
+ actionManager.$('.o_product_qty').val(3);
+ Qty.push(3);
+ await testUtils.dom.click(actionManager.$('.o_add_qty'));
+
+ // should not be added more then 5 quantities.
+ actionManager.$('.o_product_qty').val(4);
+ await testUtils.dom.click(actionManager.$('.o_add_qty'));
+
+ notificationElement = document.body.querySelector('.o_notification_manager .o_notification.bg-warning');
+ assert.strictEqual(notificationElement.querySelector('.o_notification_content').textContent,
+ "At most 5 quantities can be displayed simultaneously. Remove a selected quantity to add others.",
+ "Can not add more then 5 quantities");
+
+ // removing all the quantities should work
+ Qty.pop(10);
+ await testUtils.dom.click(actionManager.$('.o_badges .badge:contains("10") .o_remove_qty'));
+ Qty.pop(5);
+ await testUtils.dom.click(actionManager.$('.o_badges .badge:contains("5") .o_remove_qty'));
+ Qty.pop(3);
+ await testUtils.dom.click(actionManager.$('.o_badges .badge:contains("3") .o_remove_qty'));
+ Qty.pop(2);
+ await testUtils.dom.click(actionManager.$('.o_badges .badge:contains("2") .o_remove_qty'));
+ Qty.pop(1);
+ await testUtils.dom.click(actionManager.$('.o_badges .badge:contains("1") .o_remove_qty'));
+
+ assert.verifySteps([
+ 'field_changed',
+ 'qty_changed',
+ 'qty_changed',
+ 'qty_changed',
+ 'qty_changed',
+ 'qty_changed',
+ 'qty_changed',
+ 'qty_changed'
+ ]);
+
+ testUtils.mock.unpatch(GeneratePriceList);
+ actionManager.destroy();
+ });
+}
+
+);
+});
diff --git a/addons/product/static/xls/product_pricelist.xls b/addons/product/static/xls/product_pricelist.xls
new file mode 100644
index 00000000..3eeac33c
--- /dev/null
+++ b/addons/product/static/xls/product_pricelist.xls
Binary files differ
diff --git a/addons/product/static/xls/product_supplierinfo.xls b/addons/product/static/xls/product_supplierinfo.xls
new file mode 100644
index 00000000..50a165c6
--- /dev/null
+++ b/addons/product/static/xls/product_supplierinfo.xls
Binary files differ
diff --git a/addons/product/static/xls/product_template.xls b/addons/product/static/xls/product_template.xls
new file mode 100644
index 00000000..a4667b13
--- /dev/null
+++ b/addons/product/static/xls/product_template.xls
Binary files differ