summaryrefslogtreecommitdiff
path: root/addons/product_matrix/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_matrix/static
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/product_matrix/static')
-rw-r--r--addons/product_matrix/static/img/matrix_mycompany_tshirt.jpegbin0 -> 111742 bytes
-rw-r--r--addons/product_matrix/static/src/js/section_and_note_widget.js139
-rw-r--r--addons/product_matrix/static/src/scss/product_matrix.scss61
-rw-r--r--addons/product_matrix/static/src/xml/product_matrix.xml53
4 files changed, 253 insertions, 0 deletions
diff --git a/addons/product_matrix/static/img/matrix_mycompany_tshirt.jpeg b/addons/product_matrix/static/img/matrix_mycompany_tshirt.jpeg
new file mode 100644
index 00000000..b600989d
--- /dev/null
+++ b/addons/product_matrix/static/img/matrix_mycompany_tshirt.jpeg
Binary files differ
diff --git a/addons/product_matrix/static/src/js/section_and_note_widget.js b/addons/product_matrix/static/src/js/section_and_note_widget.js
new file mode 100644
index 00000000..650efbf2
--- /dev/null
+++ b/addons/product_matrix/static/src/js/section_and_note_widget.js
@@ -0,0 +1,139 @@
+odoo.define('product_matrix.section_and_note_widget', function (require) {
+
+var Dialog = require('web.Dialog');
+var core = require('web.core');
+var _t = core._t;
+var qweb = core.qweb;
+var fieldRegistry = require('web.field_registry');
+require('account.section_and_note_backend');
+
+var SectionAndNoteFieldOne2Many = fieldRegistry.get('section_and_note_one2many');
+
+SectionAndNoteFieldOne2Many.include({
+ custom_events: _.extend({}, SectionAndNoteFieldOne2Many.prototype.custom_events, {
+ open_matrix: '_openMatrix',
+ }),
+
+ /**
+ * Sends the matrix modifications to the server
+ * Through a change on an invisible non stored field.
+ *
+ * @param {List} list of changes in the matrix, to be applied to the order.
+ * {integer} quantity: float
+ * {List} ptav_ids: product.template.attribute.value ids
+ *
+ * @private
+ */
+ _applyGrid: function (changes, productTemplateId) {
+ // the getParent is to trigger the event on the form Controller instead of the one2many.
+ // If not, the one2many crashes on reset because it tries to find an operation in the event
+ // even if there isn't any.
+ // the only solution would be to use a custom event catched on a new controller
+ // on the so/po form (as a js_class).
+ this.trigger_up('field_changed', {
+ dataPointID: this.dataPointID,
+ changes: {
+ grid: JSON.stringify({changes: changes, product_template_id: productTemplateId}),
+ grid_update: true // to say that the changes to grid have to be applied to the SO.
+ },
+ viewType: 'form',
+ });
+ },
+
+ /**
+ * Catches the event asking for matrix opening
+ *
+ * @param {OdooEvent} ev various values needed to open the matrix
+ * {integer} data.product_template_id product.template id
+ * {list} data.editedCellAttributes list of product.template.attribute.value ids
+ * {bool} data.edit whether the line source should be deleted or not.
+ *
+ * @private
+ */
+ _openMatrix: function (ev) {
+ ev.stopPropagation();
+ var self = this;
+ var dataPointId = ev.data.dataPointId;
+ var productTemplateId = ev.data.product_template_id;
+ var editedCellAttributes = ev.data.editedCellAttributes;
+ if (!ev.data.edit) {
+ // remove the line used to open the matrix
+ this._setValue({operation: 'DELETE', ids: [dataPointId]});
+ }
+ // the getParent is to trigger the event on the form Controller instead of the one2many.
+ // If not, the one2many crashes on reset because it tries to find an operation in the event
+ // even if there isn't any.
+ // the only solution would be to use a custom event catched on a new controller
+ // on the so/po form (as a js_class).
+ this.trigger_up('field_changed', {
+ dataPointID: this.dataPointID,
+ changes: {
+ grid_product_tmpl_id: {id: productTemplateId}
+ },
+ viewType: 'form',
+ onSuccess: function () {
+ const gridInfo = self.recordData.grid;
+ self._openMatrixConfigurator(gridInfo, productTemplateId, editedCellAttributes);
+ }
+ });
+ },
+
+ /**
+ * Triggers Matrix Dialog opening
+ *
+ * @param {String} jsonInfo matrix dialog content
+ * @param {integer} productTemplateId product.template id
+ * @param {editedCellAttributes} list of product.template.attribute.value ids
+ * used to focus on the matrix cell representing the edited line.
+ *
+ * @private
+ */
+ _openMatrixConfigurator: function (jsonInfo, productTemplateId, editedCellAttributes) {
+ var self = this;
+ var infos = JSON.parse(jsonInfo);
+ var MatrixDialog = new Dialog(this, {
+ title: _t('Choose Product Variants'),
+ size: 'extra-large', // adapt size depending on matrix size?
+ $content: $(qweb.render(
+ 'product_matrix.matrix', {
+ header: infos.header,
+ rows: infos.matrix,
+ }
+ )),
+ buttons: [
+ {text: _t('Confirm'), classes: 'btn-primary', close: true, click: function (result) {
+ var $inputs = this.$('.o_matrix_input');
+ var matrixChanges = [];
+ _.each($inputs, function (matrixInput) {
+ if (matrixInput.value && matrixInput.value !== matrixInput.attributes.value.nodeValue) {
+ matrixChanges.push({
+ qty: parseFloat(matrixInput.value),
+ ptav_ids: matrixInput.attributes.ptav_ids.nodeValue.split(",").map(function (id) {
+ return parseInt(id);
+ }),
+ });
+ }
+ });
+ if (matrixChanges.length > 0) {
+ self._applyGrid(matrixChanges, productTemplateId);
+ }
+ }},
+ {text: _t('Close'), close: true},
+ ],
+ }).open();
+
+ MatrixDialog.opened(function () {
+ if (editedCellAttributes.length > 0) {
+ var str = editedCellAttributes.toString();
+ MatrixDialog.$content.find('.o_matrix_input').filter((k, v) => v.attributes.ptav_ids.nodeValue === str)[0].focus();
+ } else {
+ MatrixDialog.$content.find('.o_matrix_input:first()').focus();
+ }
+ });
+ },
+
+});
+
+return SectionAndNoteFieldOne2Many;
+
+});
diff --git a/addons/product_matrix/static/src/scss/product_matrix.scss b/addons/product_matrix/static/src/scss/product_matrix.scss
new file mode 100644
index 00000000..ead8137d
--- /dev/null
+++ b/addons/product_matrix/static/src/scss/product_matrix.scss
@@ -0,0 +1,61 @@
+.o_web_client .o_matrix_input_table {
+ cursor: default;
+
+ table {
+ margin-bottom: 0;
+ table-layout: fixed;
+ min-width: 100%;
+ width: auto;
+ max-width: none;
+ }
+ th, td {
+ border: 0 !important;
+ vertical-align: middle;
+ width: 5em;
+ }
+ .o_matrix_title_header {
+ width: 10em;
+ }
+ thead {
+ color: $o-main-text-color;
+ background-color: $o-brand-lightsecondary;
+ th {
+ text-align: center;
+ white-space: pre-line;
+ }
+ }
+ tbody {
+ background-color: $o-view-background-color;
+ text-align: right;
+ tr {
+ border-top: 1px solid $o-form-lightsecondary;
+ border-bottom: 1px solid $o-form-lightsecondary;
+ }
+ .o_matrix_input {
+ text-align: right;
+ border: none;
+ }
+ }
+ .o_matrix_text_muted{
+ color: lighten($o-main-text-color, 15%);
+ font-style: italic;
+ }
+
+ // ensure white background completely surrounds nocontent bubble
+ .o_matrix_nocontent_container {
+ overflow: auto;
+
+ .oe_view_nocontent_img_link {
+ padding:10px;
+ }
+ }
+}
+
+.o_product_variant_matrix {
+ .form-control {
+ &:focus {
+ box-shadow: none;
+ border: 1px solid $gray-400;
+ }
+ }
+}
diff --git a/addons/product_matrix/static/src/xml/product_matrix.xml b/addons/product_matrix/static/src/xml/product_matrix.xml
new file mode 100644
index 00000000..09fc7ba0
--- /dev/null
+++ b/addons/product_matrix/static/src/xml/product_matrix.xml
@@ -0,0 +1,53 @@
+<template>
+ <div t-name="product_matrix.matrix">
+ <table class="o_matrix_input_table o_product_variant_matrix table table-sm table-striped table-bordered">
+ <thead>
+ <tr>
+ <t t-foreach="header" t-as="column_header">
+ <th t-attf-class="o_matrix_title_header {{column_header_first?'text-left':'text-center'}}">
+ <span t-esc="column_header.name"/>
+ <t t-call="product_matrix.extra_price">
+ <t t-set="price" t-value="column_header.price"/>
+ </t>
+ </th>
+ </t>
+ </tr>
+ </thead>
+ <tbody>
+ <tr t-foreach="rows" t-as="row">
+ <t t-foreach="row" t-as="cell">
+ <td t-if="cell.name" class="text-left">
+ <strong t-esc="cell.name"/>
+ <t t-call="product_matrix.extra_price">
+ <t t-set="price" t-value="cell.price"/>
+ </t>
+ </td>
+ <td t-else="">
+ <div t-if="cell.is_possible_combination" class="input-group">
+ <input type="number"
+ class="o_matrix_input"
+ t-att-ptav_ids="cell.ptav_ids"
+ t-att-value="cell.qty"/>
+ </div>
+ <span t-else="" class="o_matrix_cell o_matrix_text_muted o_matrix_nocontent_container"> Not available </span>
+ </td>
+ </t>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ <span t-name="product_matrix.extra_price" t-if="price" class="badge badge-pill badge-secondary">
+ <!--
+ price_extra is displayed as catalog price instead of
+ price after pricelist because it is impossible to
+ compute. Indeed, the pricelist rule might depend on the
+ selected variant, so the price_extra will be different
+ depending on the selected combination. The price of an
+ attribute is therefore variable and it's not very
+ accurate to display it.
+ -->
+ <span class="variant_price_extra" style="white-space: nowrap;">
+ <t t-raw="price"/>
+ </span>
+ </span>
+</template>