dolibarr 25.0.0-alpha
modVariants.class.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2003 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2012 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2012 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2016 Marcos García <marcosgdf@gmail.com>
6 * Copyright (C) 2024-2026 Frédéric France <frederic.france@free.fr>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
29include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php';
30
31
36{
42 public function __construct($db)
43 {
44 global $conf;
45
46 $this->db = $db;
47
48 // Id for module (must be unique).
49 // Use here a free id (See in Home -> System information -> Dolibarr for list of used modules id).
50 $this->numero = 610;
51 // Key text used to identify module (for permissions, menus, etc...)
52 $this->rights_class = 'variants';
53
54 // Family can be 'crm','financial','hr','projects','products','ecm','technic','other'
55 // It is used to group modules in module setup page
56 $this->family = "products";
57 // Module position in the family on 2 digits ('01', '10', '20', ...)
58 $this->module_position = '50';
59 // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module)
60 $this->name = preg_replace('/^mod/i', '', get_class($this));
61 // Module description, used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module)
62 $this->description = 'Allows creating products variant based on new attributes';
63 // Possible values for version are: 'development', 'experimental', 'dolibarr' or version
64 $this->version = 'dolibarr';
65 // Key used in llx_const table to save module status enabled/disabled (where MYMODULE is value of property name of module in uppercase)
66 $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name);
67 // Name of image file used for this module.
68 // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue'
69 // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module'
70 $this->picto = 'product';
71
72 // Defined all module parts (triggers, login, substitutions, menus, css, etc...)
73 $this->module_parts = array();
74
75 // Data directories to create when module is enabled.
76 // Example: this->dirs = array("/variants/temp");
77 $this->dirs = array();
78
79 // Config pages. Put here list of php page, stored into variants/admin directory, to use to setup module.
80 $this->config_page_url = array('admin.php@variants');
81
82 // Dependencies
83 $this->hidden = false; // A condition to hide module
84 $this->depends = array('modProduct'); // List of module class names as string that must be enabled if this module is enabled
85 $this->requiredby = array(); // List of module ids to disable if this one is disabled
86 $this->conflictwith = array(); // List of module class names as string this module is in conflict with
87 $this->phpmin = array(7, 0); // Minimum version of PHP required by module
88 $this->need_dolibarr_version = array(3, 0); // Minimum version of Dolibarr required by module
89 $this->langfiles = array("products");
90
91 // Constants
92 $this->const = array();
93
94 // Array to add new pages in new tabs
95 $this->tabs = array(
96 // 'product:+combinations:Combinaciones:products:1:/variants/combinations.php?id=__ID__'
97 );
98
99 // Dictionaries
100 if (!isset($conf->variants->enabled)) {
101 $conf->variants = new stdClass();
102 $conf->variants->enabled = 0;
103 }
104 $this->dictionaries = array();
105
106 // Boxes
107 // Add here list of php file(s) stored in core/boxes that contains class to show a box.
108 $this->boxes = array(); // List of boxes
109
110 // Permissions
111 $this->rights = array(); // Permission array used by this module
112 $r = 0;
113
114 $this->rights[$r][0] = $this->numero + 1; // Permission id (must not be already used)
115 $this->rights[$r][1] = 'Read attributes of variants'; // Permission label
116 $this->rights[$r][4] = 'read'; // In php code, permission will be checked by test if ($user->rights->eventorganization->level1)
117 $r++;
118 $this->rights[$r][0] = $this->numero + 2; // Permission id (must not be already used)
119 $this->rights[$r][1] = 'Create/Update attributes of variants'; // Permission label
120 $this->rights[$r][4] = 'write'; // In php code, permission will be checked by test if ($user->rights->eventorganization->level1)
121 $r++;
122 $this->rights[$r][0] = $this->numero + 3; // Permission id (must not be already used)
123 $this->rights[$r][1] = 'Delete attributes of variants'; // Permission label
124 $this->rights[$r][4] = 'delete'; // In php code, permission will be checked by test if ($user->rights->eventorganization->level1)
125 $r++;
126
127 // Imports
128 //--------
129 // A variant spans 4 tables and the import engine handles one line of file as one record
130 // of one table, so the import is split into single table datasets. The upsert is the
131 // native import_updatekeys_array. Note that 'entity' is never declared: the engine adds
132 // it by itself for every table that has the column. import_permission is not declared
133 // either, it is dead code replaced by the global 'import run' permission.
134 $r = 0;
135
136 // Import of variant attributes
137 $r++;
138 $this->import_code[$r] = $this->rights_class.'_attribute';
139 $this->import_label[$r] = "VariantAttributes"; // Translation key
140 $this->import_icon[$r] = $this->picto;
141 $this->import_entities_array[$r] = array();
142 $this->import_tables_array[$r] = array('pa' => MAIN_DB_PREFIX.'product_attribute', 'extra' => MAIN_DB_PREFIX.'product_attribute_extrafields');
143 $this->import_fields_array[$r] = array(
144 'pa.ref' => "VariantAttributeRef*",
145 'pa.label' => "VariantAttributeLabel*",
146 'pa.ref_ext' => "VariantAttributeRefExt",
147 'pa.position' => "VariantAttributeRank"
148 );
149 // Add extra fields of the attribute
150 $keyforselect = 'product_attribute';
151 $keyforelement = 'productattribute';
152 $keyforaliasextra = 'extra';
153 include DOL_DOCUMENT_ROOT.'/core/extrafieldsinimport.inc.php';
154 $this->import_fieldshidden_array[$r] = array('extra.fk_object' => 'lastrowid-'.MAIN_DB_PREFIX.'product_attribute');
155 $this->import_examplevalues_array[$r] = array(
156 'pa.ref' => "COL",
157 'pa.label' => "Color",
158 'pa.ref_ext' => "",
159 'pa.position' => "10"
160 );
161 $this->import_convertvalue_array[$r] = array(
162 'pa.position' => array('rule' => 'zeroifnull')
163 );
164 $this->import_updatekeys_array[$r] = array('pa.ref' => 'VariantAttributeRef');
165
166 // Import of variant attribute values
167 $r++;
168 $this->import_code[$r] = $this->rights_class.'_value';
169 $this->import_label[$r] = "VariantAttributeValues"; // Translation key
170 $this->import_icon[$r] = $this->picto;
171 $this->import_entities_array[$r] = array();
172 $this->import_tables_array[$r] = array('pav' => MAIN_DB_PREFIX.'product_attribute_value', 'extra' => MAIN_DB_PREFIX.'product_attribute_value_extrafields');
173 $this->import_fields_array[$r] = array(
174 'pav.fk_product_attribute' => "VariantAttributeRef*",
175 'pav.ref' => "VariantValueRef*",
176 'pav.value' => "VariantValueLabel*",
177 'pav.position' => "VariantValueRank"
178 );
179 $this->import_convertvalue_array[$r] = array(
180 'pav.fk_product_attribute' => array('rule' => 'fetchidfromref', 'classfile' => '/variants/class/ProductAttribute.class.php', 'class' => 'ProductAttribute', 'method' => 'fetch', 'element' => 'ProductAttribute'),
181 'pav.position' => array('rule' => 'zeroifnull')
182 );
183 // Add extra fields of the attribute value
184 $keyforselect = 'product_attribute_value';
185 $keyforelement = 'productattributevalue';
186 $keyforaliasextra = 'extra';
187 include DOL_DOCUMENT_ROOT.'/core/extrafieldsinimport.inc.php';
188 $this->import_fieldshidden_array[$r] = array('extra.fk_object' => 'lastrowid-'.MAIN_DB_PREFIX.'product_attribute_value');
189 $this->import_examplevalues_array[$r] = array(
190 'pav.fk_product_attribute' => "ref:COL",
191 'pav.ref' => "BLUE",
192 'pav.value' => "Blue",
193 'pav.position' => "10"
194 );
195 $this->import_updatekeys_array[$r] = array('pav.fk_product_attribute' => 'VariantAttributeRef', 'pav.ref' => 'VariantValueRef');
196
197 // Import of variants (combinations). Both the parent and the child products must exist:
198 // this import creates the variant links, not the products themselves.
199 $r++;
200 $this->import_code[$r] = $this->rights_class.'_combination';
201 $this->import_label[$r] = "ProductCombinations"; // Translation key
202 $this->import_icon[$r] = $this->picto;
203 $this->import_entities_array[$r] = array();
204 $this->import_tables_array[$r] = array('pac' => MAIN_DB_PREFIX.'product_attribute_combination');
205 $this->import_fields_array[$r] = array(
206 'pac.fk_product_parent' => "ParentProductOfVariant*",
207 'pac.fk_product_child' => "VariantProductRef*",
208 'pac.variation_price' => "VariantPriceImpact",
209 'pac.variation_price_percentage' => "VariantPriceImpactIsPercent",
210 'pac.variation_weight' => "VariantWeightImpact",
211 'pac.variation_ref_ext' => "VariantRefExt"
212 );
213 $this->import_convertvalue_array[$r] = array(
214 'pac.fk_product_parent' => array('rule' => 'fetchidfromref', 'classfile' => '/product/class/product.class.php', 'class' => 'Product', 'method' => 'fetch', 'element' => 'Product'),
215 'pac.fk_product_child' => array('rule' => 'fetchidfromref', 'classfile' => '/product/class/product.class.php', 'class' => 'Product', 'method' => 'fetch', 'element' => 'Product'),
216 'pac.variation_price' => array('rule' => 'zeroifnull'),
217 'pac.variation_price_percentage' => array('rule' => 'zeroifnull'),
218 'pac.variation_weight' => array('rule' => 'zeroifnull')
219 );
220 // No 'rowid@table' regex on the foreign keys: the rule loads the whole target table into
221 // memory for every imported file, and the existence of the record is already enforced by
222 // the convertvalue rule for a ref, by the import trigger for an id, and by the foreign keys.
223 $this->import_regex_array[$r] = array(
224 'pac.variation_price_percentage' => '^[0-1]$'
225 );
226 // The engine reads a numeric value as an id, so a product whose ref is a number has to be
227 // prefixed with 'ref:'. The examples show the prefix on purpose.
228 $this->import_examplevalues_array[$r] = array(
229 'pac.fk_product_parent' => "ref:SHIRT (or the id of the parent product)",
230 'pac.fk_product_child' => "ref:SHIRT_BLUE_L (or the id of an existing product)",
231 'pac.variation_price' => "5.00",
232 'pac.variation_price_percentage' => "0",
233 'pac.variation_weight' => "0",
234 'pac.variation_ref_ext' => ""
235 );
236 $this->import_updatekeys_array[$r] = array('pac.fk_product_parent' => 'ParentProductOfVariant', 'pac.fk_product_child' => 'VariantProductRef');
237 // Preselected: a second row for the same (parent, child) is refused by the import trigger,
238 // so a plain insert would only ever fail. Note that imports/import.php cannot tell "no
239 // update key chosen" from "no choice made", so a preselection cannot be cancelled by the
240 // user: it is reserved to the tables where an insert has no meaning.
241 $this->import_preselected_updatekeys_array[$r] = array('pac.fk_product_parent', 'pac.fk_product_child');
242
243 // Import of the attribute values of each variant, one line per variant and attribute
244 $r++;
245 $this->import_code[$r] = $this->rights_class.'_combination2val';
246 $this->import_label[$r] = "VariantFeatures"; // Translation key
247 $this->import_icon[$r] = $this->picto;
248 $this->import_entities_array[$r] = array();
249 $this->import_tables_array[$r] = array('pac2v' => MAIN_DB_PREFIX.'product_attribute_combination2val');
250 $this->import_fields_array[$r] = array(
251 'pac2v.fk_prod_combination' => "VariantProductRef*",
252 'pac2v.fk_prod_attr' => "VariantAttributeRef*",
253 'pac2v.fk_prod_attr_val' => "VariantValueRef*"
254 );
255 $this->import_convertvalue_array[$r] = array(
256 'pac2v.fk_prod_combination' => array('rule' => 'fetchidfromref', 'classfile' => '/variants/class/ProductCombination.class.php', 'class' => 'ProductCombination', 'method' => 'fetch', 'element' => 'ProductCombination'),
257 'pac2v.fk_prod_attr' => array('rule' => 'fetchidfromref', 'classfile' => '/variants/class/ProductAttribute.class.php', 'class' => 'ProductAttribute', 'method' => 'fetch', 'element' => 'ProductAttribute'),
258 // A value ref is only unique for a given attribute, and fetchidfromref resolves every
259 // column without any context, so the value is resolved by a computed field that reads
260 // the attribute ref of the same line.
261 'pac2v.fk_prod_attr_val' => array('rule' => 'compute', 'type' => 'int', 'classfile' => '/variants/class/ProductCombination.class.php', 'class' => 'ProductCombination', 'method' => 'resolveAttributeValueId', 'element' => 'ProductCombination')
262 );
263 $this->import_examplevalues_array[$r] = array(
264 'pac2v.fk_prod_combination' => "ref:SHIRT_BLUE_L (ref of the variant product)",
265 'pac2v.fk_prod_attr' => "ref:COL",
266 'pac2v.fk_prod_attr_val' => "ref:BLUE"
267 );
268 $this->import_updatekeys_array[$r] = array('pac2v.fk_prod_combination' => 'VariantProductRef', 'pac2v.fk_prod_attr' => 'VariantAttributeRef');
269 // Preselected: the unique index of the table forbids a second value for the same attribute
270 $this->import_preselected_updatekeys_array[$r] = array('pac2v.fk_prod_combination', 'pac2v.fk_prod_attr');
271
272 // Import of the price impact of each price level
273 // PRODUIT_MULTIPRICES only: the whole propagation chain of the price levels
274 // (ProductCombination::create(), update(), fetch(), updateProperties()) tests this
275 // constant alone, so exposing the dataset under another one would write rows that
276 // never reach llx_product_price.
277 if (getDolGlobalString('PRODUIT_MULTIPRICES')) {
278 $r++;
279 $this->import_code[$r] = $this->rights_class.'_pricelevel';
280 $this->import_label[$r] = "VariantPriceLevels"; // Translation key
281 $this->import_icon[$r] = $this->picto;
282 $this->import_entities_array[$r] = array();
283 $this->import_tables_array[$r] = array('pacpl' => MAIN_DB_PREFIX.'product_attribute_combination_price_level');
284 $this->import_fields_array[$r] = array(
285 'pacpl.fk_product_attribute_combination' => "VariantProductRef*",
286 'pacpl.fk_price_level' => "VariantPriceLevel*",
287 'pacpl.variation_price' => "VariantPriceImpact",
288 'pacpl.variation_price_percentage' => "VariantPriceImpactIsPercent"
289 );
290 $this->import_convertvalue_array[$r] = array(
291 'pacpl.fk_product_attribute_combination' => array('rule' => 'fetchidfromref', 'classfile' => '/variants/class/ProductCombination.class.php', 'class' => 'ProductCombination', 'method' => 'fetch', 'element' => 'ProductCombination'),
292 'pacpl.variation_price' => array('rule' => 'zeroifnull'),
293 'pacpl.variation_price_percentage' => array('rule' => 'zeroifnull')
294 );
295 $this->import_regex_array[$r] = array(
296 'pacpl.fk_price_level' => '^[1-9][0-9]*$',
297 'pacpl.variation_price_percentage' => '^[0-1]$'
298 );
299 $this->import_examplevalues_array[$r] = array(
300 'pacpl.fk_product_attribute_combination' => "ref:SHIRT_BLUE_L (ref of the variant product)",
301 'pacpl.fk_price_level' => "1",
302 'pacpl.variation_price' => "5.00",
303 'pacpl.variation_price_percentage' => "0"
304 );
305 $this->import_updatekeys_array[$r] = array('pacpl.fk_product_attribute_combination' => 'VariantProductRef', 'pacpl.fk_price_level' => 'VariantPriceLevel');
306 // Preselected: the reconciliation of a variant already creates one row per price level,
307 // so a plain insert would always hit the unique index of the table.
308 $this->import_preselected_updatekeys_array[$r] = array('pacpl.fk_product_attribute_combination', 'pacpl.fk_price_level');
309 }
310
311 // Exports
312 //--------
313 $r = 0;
314
315 // Export of the attributes and their values
316 $r++;
317 $this->export_code[$r] = $this->rights_class.'_attribute';
318 $this->export_label[$r] = "VariantAttributes"; // Translation key
319 $this->export_icon[$r] = $this->picto;
320 $this->export_permission[$r] = array(array("variants", "read"), array("produit", "export"));
321 $this->export_fields_array[$r] = array(
322 'pa.rowid' => "Id",
323 'pa.ref' => "VariantAttributeRef",
324 'pa.label' => "VariantAttributeLabel",
325 'pa.ref_ext' => "VariantAttributeRefExt",
326 'pa.position' => "VariantAttributeRank",
327 'pav.ref' => "VariantValueRef",
328 'pav.value' => "VariantValueLabel",
329 'pav.position' => "VariantValueRank"
330 );
331 $this->export_TypeFields_array[$r] = array(
332 'pa.ref' => "Text",
333 'pa.label' => "Text",
334 'pa.ref_ext' => "Text",
335 'pa.position' => "Numeric",
336 'pav.ref' => "Text",
337 'pav.value' => "Text",
338 'pav.position' => "Numeric"
339 );
340 $this->export_entities_array[$r] = array(
341 'pa.rowid' => "productattribute",
342 'pa.ref' => "productattribute",
343 'pa.label' => "productattribute",
344 'pa.ref_ext' => "productattribute",
345 'pa.position' => "productattribute",
346 'pav.ref' => "productattributevalue",
347 'pav.value' => "productattributevalue",
348 'pav.position' => "productattributevalue"
349 );
350 $this->export_dependencies_array[$r] = array('productattributevalue' => 'pa.rowid');
351 $this->export_sql_start[$r] = 'SELECT DISTINCT ';
352 $this->export_sql_end[$r] = ' FROM '.MAIN_DB_PREFIX.'product_attribute as pa';
353 // An entity condition on a LEFT JOIN belongs to the ON, otherwise the attributes carrying
354 // no value at all disappear from the export.
355 $this->export_sql_end[$r] .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_attribute_value as pav ON pav.fk_product_attribute = pa.rowid AND pav.entity IN ('.getEntity('product').')';
356 $this->export_sql_end[$r] .= ' WHERE pa.entity IN ('.getEntity('product').')';
357 $this->export_sql_order[$r] = ' ORDER BY pa.position, pa.ref, pav.position, pav.ref';
358
359 // Export of the variants, one line per variant and feature
360 $r++;
361 $this->export_code[$r] = $this->rights_class.'_combination';
362 $this->export_label[$r] = "ProductCombinations"; // Translation key
363 $this->export_icon[$r] = $this->picto;
364 $this->export_permission[$r] = array(array("variants", "read"), array("produit", "export"));
365 $this->export_fields_array[$r] = array(
366 'p.ref' => "ParentProductOfVariant",
367 'p.label' => "ParentProductLabel",
368 'p2.ref' => "VariantProductRef",
369 'p2.label' => "VariantProductLabel",
370 'pac.variation_price' => "VariantPriceImpact",
371 'pac.variation_price_percentage' => "VariantPriceImpactIsPercent",
372 'pac.variation_weight' => "VariantWeightImpact",
373 'pac.variation_ref_ext' => "VariantRefExt",
374 'pa.ref' => "VariantAttributeRef",
375 'pa.label' => "VariantAttributeLabel",
376 'pav.ref' => "VariantValueRef",
377 'pav.value' => "VariantValueLabel"
378 );
379 $this->export_TypeFields_array[$r] = array(
380 'p.ref' => "Text",
381 'p.label' => "Text",
382 'p2.ref' => "Text",
383 'p2.label' => "Text",
384 'pac.variation_price' => "Numeric",
385 'pac.variation_price_percentage' => "Boolean",
386 'pac.variation_weight' => "Numeric",
387 'pac.variation_ref_ext' => "Text",
388 'pa.ref' => "Text",
389 'pa.label' => "Text",
390 'pav.ref' => "Text",
391 'pav.value' => "Text"
392 );
393 $this->export_entities_array[$r] = array(
394 'p.ref' => "product",
395 'p.label' => "product",
396 'p2.ref' => "productcombination",
397 'p2.label' => "productcombination",
398 'pac.variation_price' => "productcombination",
399 'pac.variation_price_percentage' => "productcombination",
400 'pac.variation_weight' => "productcombination",
401 'pac.variation_ref_ext' => "productcombination",
402 'pa.ref' => "productattribute",
403 'pa.label' => "productattribute",
404 'pav.ref' => "productattributevalue",
405 'pav.value' => "productattributevalue"
406 );
407 // p2.ref, not pac.rowid: export.php uses the dependency as a key of export_fields_array
408 // and only an exportable field can be auto selected. A product ref identifies a variant.
409 $this->export_dependencies_array[$r] = array('productattribute' => 'p2.ref', 'productattributevalue' => 'p2.ref');
410 $this->export_sql_start[$r] = 'SELECT DISTINCT ';
411 $this->export_sql_end[$r] = ' FROM '.MAIN_DB_PREFIX.'product_attribute_combination as pac';
412 $this->export_sql_end[$r] .= ' INNER JOIN '.MAIN_DB_PREFIX.'product as p ON p.rowid = pac.fk_product_parent';
413 $this->export_sql_end[$r] .= ' INNER JOIN '.MAIN_DB_PREFIX.'product as p2 ON p2.rowid = pac.fk_product_child';
414 $this->export_sql_end[$r] .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_attribute_combination2val as pac2v ON pac2v.fk_prod_combination = pac.rowid';
415 $this->export_sql_end[$r] .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_attribute as pa ON pa.rowid = pac2v.fk_prod_attr AND pa.entity IN ('.getEntity('product').')';
416 $this->export_sql_end[$r] .= ' LEFT JOIN '.MAIN_DB_PREFIX.'product_attribute_value as pav ON pav.rowid = pac2v.fk_prod_attr_val AND pav.entity IN ('.getEntity('product').')';
417 $this->export_sql_end[$r] .= ' WHERE p.entity IN ('.getEntity('product').')';
418 $this->export_sql_end[$r] .= ' AND p2.entity IN ('.getEntity('product').')';
419 // The combination carries its own entity, which may differ from the one of its products as
420 // soon as product sharing is enabled: it has to be filtered on its own. The link table
421 // pac2v holds no entity column, it is scoped through its combination.
422 $this->export_sql_end[$r] .= ' AND pac.entity IN ('.getEntity('product').')';
423 $this->export_sql_order[$r] = ' ORDER BY p.ref, p2.ref, pa.position, pa.ref';
424
425 // Export of the price impact per price level
426 // PRODUIT_MULTIPRICES only: the whole propagation chain of the price levels
427 // (ProductCombination::create(), update(), fetch(), updateProperties()) tests this
428 // constant alone, so exposing the dataset under another one would write rows that
429 // never reach llx_product_price.
430 if (getDolGlobalString('PRODUIT_MULTIPRICES')) {
431 $r++;
432 $this->export_code[$r] = $this->rights_class.'_pricelevel';
433 $this->export_label[$r] = "VariantPriceLevels"; // Translation key
434 $this->export_icon[$r] = $this->picto;
435 $this->export_permission[$r] = array(array("variants", "read"), array("produit", "export"));
436 $this->export_fields_array[$r] = array(
437 'p.ref' => "ParentProductOfVariant",
438 'p2.ref' => "VariantProductRef",
439 'pacpl.fk_price_level' => "VariantPriceLevel",
440 'pacpl.variation_price' => "VariantPriceImpact",
441 'pacpl.variation_price_percentage' => "VariantPriceImpactIsPercent"
442 );
443 $this->export_TypeFields_array[$r] = array(
444 'p.ref' => "Text",
445 'p2.ref' => "Text",
446 'pacpl.fk_price_level' => "Numeric",
447 'pacpl.variation_price' => "Numeric",
448 'pacpl.variation_price_percentage' => "Boolean"
449 );
450 $this->export_entities_array[$r] = array(
451 'p.ref' => "product",
452 'p2.ref' => "productcombination",
453 'pacpl.fk_price_level' => "productcombination",
454 'pacpl.variation_price' => "productcombination",
455 'pacpl.variation_price_percentage' => "productcombination"
456 );
457 $this->export_sql_start[$r] = 'SELECT DISTINCT ';
458 $this->export_sql_end[$r] = ' FROM '.MAIN_DB_PREFIX.'product_attribute_combination_price_level as pacpl';
459 $this->export_sql_end[$r] .= ' INNER JOIN '.MAIN_DB_PREFIX.'product_attribute_combination as pac ON pac.rowid = pacpl.fk_product_attribute_combination';
460 $this->export_sql_end[$r] .= ' INNER JOIN '.MAIN_DB_PREFIX.'product as p ON p.rowid = pac.fk_product_parent';
461 $this->export_sql_end[$r] .= ' INNER JOIN '.MAIN_DB_PREFIX.'product as p2 ON p2.rowid = pac.fk_product_child';
462 $this->export_sql_end[$r] .= ' WHERE p.entity IN ('.getEntity('product').')';
463 $this->export_sql_end[$r] .= ' AND p2.entity IN ('.getEntity('product').')';
464 // The price level table holds no entity column, it is scoped through its combination
465 $this->export_sql_end[$r] .= ' AND pac.entity IN ('.getEntity('product').')';
466 $this->export_sql_order[$r] = ' ORDER BY p.ref, p2.ref, pacpl.fk_price_level';
467 }
468 }
469
478 public function init($options = '')
479 {
480 $result = $this->_load_tables('/install/mysql/', 'variants');
481 if ($result < 0) {
482 // Do not activate module if error 'not allowed' returned when loading module SQL queries
483 // (the _load_table run sql with run_sql with the error allowed parameter set to 'default')
484 return -1;
485 }
486
487 // Permissions
488 $this->remove($options);
489
490 $sql = array();
491
492 return $this->_init($sql, $options);
493 }
494}
Class DolibarrModules.
_init($array_sql, $options='')
Enables a module.
_load_tables($reldir, $onlywithsuffix='')
Create tables and keys required by module:
Description and activation class for module Product variants.
init($options='')
Function called when module is enabled.
__construct($db)
Constructor.
print $script_file $mode $langs defaultlang(is_numeric($duration_value) ? " delay=". $duration_value :"").(is_numeric($duration_value2) ? " after cd cd cd description as description
Only used if Module[ID]Desc translation string is not found.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
getEntity($element, $shared=1, $currentobject=null)
Get list of entity id to use.
$conf browser version
Definition main.inc.php:229
$conf db name
Only used if Module[ID]Name translation string is not found.
Definition repair.php:140