diff --git a/backend/app/plugins/wiaas/assets/js/wiaas-template-admin-selection.js b/backend/app/plugins/wiaas/assets/js/wiaas-template-admin-selection.js new file mode 100644 index 0000000..4a264db --- /dev/null +++ b/backend/app/plugins/wiaas/assets/js/wiaas-template-admin-selection.js @@ -0,0 +1,51 @@ +jQuery(document).ready(function ($) { + var $selectTemplate = $('#_select_template'); + var $container = $('#wiaas_selected_template_items_container'); + + $selectTemplate + + .on('change', function () { + var selectedTemplate = $selectTemplate.val(); + + var data = { + action: 'wiaas_select_template', + selected_template: selectedTemplate + }; + + + setTimeout(function () { + + $.post(woocommerce_admin_meta_boxes.ajax_url, data, function (response) { + + if ('' !== response.markup) { + $container.children("div").remove(); + $container.append(response.markup); + + } else { + $container.children("div").remove(); + } + + if (response.message !== '') { + window.alert(response.message); + } + + + }); + + }, 250); + }); + + var $product_type = $('#product-type'); + var $template_product_meta_box = $('#template_product_meta_box'); + $product_type.on('change', function () { + var selectedProductType = $product_type.val(); + + if (selectedProductType === 'bundle') { + $template_product_meta_box.show(); + } else { + $template_product_meta_box.hide(); + } + }); + + +}); \ No newline at end of file diff --git a/backend/app/plugins/wiaas/assets/js/wiaas-template-admin-write-panels.js b/backend/app/plugins/wiaas/assets/js/wiaas-template-admin-write-panels.js new file mode 100644 index 0000000..c12c4c2 --- /dev/null +++ b/backend/app/plugins/wiaas/assets/js/wiaas-template-admin-write-panels.js @@ -0,0 +1,332 @@ +jQuery(function ($) { + + var $edit_in_cart = $('.bundle_edit_in_cart'), + $group_mode_select = $('select#_wc_pb_group_mode'), + $bundled_products_panel = $('#bundled_product_data'), + $bundled_products_toolbar = $bundled_products_panel.find('.toolbar'), + $template_products_container_hardware = $('.wiaas-template-items_hardware'), + $template_products_container_software = $('.wiaas-template-items_software'), + $template_products_container_services = $('.wiaas-template-items_services'), + $template_products_container_isntallation = $('.wiaas-template-items_installation'), + + $template_products = $('.wc-bundled-item', + $template_products_container_services, + $template_products_container_software, + $template_products_container_hardware, + $template_products_container_isntallation), + + $template_search_hardware = $('#wiaastemplate_products_hardware'), + $template_search_software = $('#wiaastemplate_products_software'), + $template_search_services = $('#wiaastemplate_products_services'), + $template_search_installation = $('#wiaastemplate_products_installation'), + bundled_product_objects = {}, + bundled_products_add_count = $template_products.length, + block_params = { + message: null, + overlayCSS: { + background: '#fff', + opacity: 0.6 + } + }; + + $.fn.wc_bundles_select2 = function () { + $(document.body).trigger('wc-enhanced-select-init'); + }; + + // Bundle type move stock msg up. + $('.bundle_stock_msg').appendTo('._manage_stock_field .description'); + + // Simple type options are valid for bundles. + $('.show_if_simple:not(.hide_if_bundle)').addClass('show_if_bundle'); + + $('body').on('woocommerce-product-type-change', function (event, select_val) { + + if ('bundle' === select_val) { + + $('.show_if_external').hide(); + $('.show_if_bundle').show(); + + $('input#_manage_stock').change(); + + $('#_nyp').change(); + } + + }); + + $group_mode_select.change(function () { + if ($.inArray($group_mode_select.val(), wc_bundles_admin_params.group_modes_with_parent) === -1) { + $edit_in_cart.hide(); + } else { + $edit_in_cart.show(); + } + }); + + // Downloadable support. + $('input#_downloadable').change(function () { + $('select#product-type').change(); + }); + + // Trigger product type change. + $('select#product-type').change(); + + // Trigger group mode change. + $group_mode_select.change(); + + + init_event_handlers(); + + function init_event_handlers() { + + + $template_search_hardware + + .on('change', function () { + addSearchedProduct('hardware', $template_search_hardware, $template_products_container_hardware) + }); + + $template_search_software + + .on('change', function () { + addSearchedProduct('software', $template_search_software, $template_products_container_software) + }); + + + $template_search_installation + + .on('change', function () { + addSearchedProduct('services', $template_search_installation, $template_products_container_isntallation) + }); + + + $template_search_services + + .on('change', function () { + addSearchedProduct('installation', $template_search_services, $template_products_container_services) + }); + + + function addSearchedProduct(options, search, container) { + var bundled_product_ids = search.val(), + bundled_product_id = bundled_product_ids && bundled_product_ids.length > 0 ? bundled_product_ids.shift() : false; + + var template_category_title =search.text(); + + if (!bundled_product_id) { + return false; + } + + search.val([]).change(); + + $bundled_products_panel.block(block_params); + + bundled_products_add_count++; + + var data = { + action: 'wiaas_add_template_product', + post_id: woocommerce_admin_meta_boxes.post_id, + id: bundled_products_add_count, + title: template_category_title, + product_id: bundled_product_id, + security: wc_bundles_admin_params.add_bundled_product_nonce, + options: options, + }; + + setTimeout(function () { + + $.post(woocommerce_admin_meta_boxes.ajax_url, data, function (response) { + + if ('' !== response.markup) { + + container.append(response.markup); + + var $added = $('.wiaas-template-item', container).last(), + added_id = 'bundled_item_' + bundled_products_add_count; + + $added.data('bundled_item_id', added_id); + $added.wc_bundles_select2(); + + $bundled_products_panel.trigger('wc-bundles-added-bundled-product'); + + } else if (response.message !== '') { + window.alert(response.message); + } + + // Open and close to resolve "sticky" modal issue. + if ('yes' === wc_bundles_admin_params.is_wc_version_gte_3_2) { + search.selectWoo('open'); + search.selectWoo('close'); + } else { + search.select2('open'); + search.select2('close'); + } + search.text(''); + + $bundled_products_panel.unblock(); + + }); + + }, 250); + + return false; + } + + $template_products_container_isntallation + + // Remove Item. + .on('click', 'a.remove_row', function (e) { + + var $el = $(this).closest('.wc-bundled-item'), + el_id = $el.data('bundled_item_id'); + + $el.find('*').off(); + $el.remove(); + + delete bundled_product_objects[el_id]; + + $bundled_products_panel.triggerHandler('wc-bundled-products-changed'); + + e.preventDefault(); + + }); + + $template_products_container_hardware + + // Remove Item. + .on('click', 'a.remove_row', function (e) { + + var $el = $(this).closest('.wc-bundled-item'), + el_id = $el.data('bundled_item_id'); + + $el.find('*').off(); + $el.remove(); + + delete bundled_product_objects[el_id]; + + $bundled_products_panel.triggerHandler('wc-bundled-products-changed'); + + e.preventDefault(); + + }); + + $template_products_container_software + + // Remove Item. + .on('click', 'a.remove_row', function (e) { + + var $el = $(this).closest('.wc-bundled-item'), + el_id = $el.data('bundled_item_id'); + + $el.find('*').off(); + $el.remove(); + + delete bundled_product_objects[el_id]; + + $bundled_products_panel.triggerHandler('wc-bundled-products-changed'); + + e.preventDefault(); + + }); + + $template_products_container_services + + // Remove Item. + .on('click', 'a.remove_row', function (e) { + + var $el = $(this).closest('.wc-bundled-item'), + el_id = $el.data('bundled_item_id'); + + $el.find('*').off(); + $el.remove(); + + delete bundled_product_objects[el_id]; + + $bundled_products_panel.triggerHandler('wc-bundled-products-changed'); + + e.preventDefault(); + + }) + + } + + // Ajax product search box + $( ':input.wiaas-term-search' ).filter( ':not(.enhanced)' ).each( function() { + var select2_args = { + allowClear: $( this ).data( 'allow_clear' ) ? true : false, + placeholder: $( this ).data( 'placeholder' ), + minimumInputLength: $( this ).data( 'minimum_input_length' ) ? $( this ).data( 'minimum_input_length' ) : '3', + escapeMarkup: function( m ) { + return m; + }, + ajax: { + url: wc_enhanced_select_params.ajax_url, + dataType: 'json', + delay: 250, + data: function( params ) { + return { + term: params.term, + action: 'wiaas_template_category_search', + security: wc_enhanced_select_params.search_products_nonce, + exclude: $( this ).data( 'exclude' ), + include: $( this ).data( 'include' ), + limit: $( this ).data( 'limit' ) + }; + }, + processResults: function( data ) { + var terms = []; + if ( data ) { + $.each( data, function( id, text ) { + terms.push( { id: id, text: text } ); + }); + } + return { + results: terms + }; + }, + cache: true + } + }; + + // select2_args = $.extend( select2_args, getEnhancedSelectFormatString() ); + + $( this ).selectWoo( select2_args ).addClass( 'enhanced' ); + + if ( $( this ).data( 'sortable' ) ) { + var $select = $(this); + var $list = $( this ).next( '.select2-container' ).find( 'ul.select2-selection__rendered' ); + + $list.sortable({ + placeholder : 'ui-state-highlight select2-selection__choice', + forcePlaceholderSize: true, + items : 'li:not(.select2-search__field)', + tolerance : 'pointer', + stop: function() { + $( $list.find( '.select2-selection__choice' ).get().reverse() ).each( function() { + var id = $( this ).data( 'data' ).id; + var option = $select.find( 'option[value="' + id + '"]' )[0]; + $select.prepend( option ); + } ); + } + }); + // Keep multiselects ordered alphabetically if they are not sortable. + } else if ( $( this ).prop( 'multiple' ) ) { + $( this ).on( 'change', function(){ + var $children = $( this ).children(); + $children.sort(function(a, b){ + var atext = a.text.toLowerCase(); + var btext = b.text.toLowerCase(); + + if ( atext > btext ) { + return 1; + } + if ( atext < btext ) { + return -1; + } + return 0; + }); + $( this ).html( $children ); + }); + } + }); + +}); + diff --git a/backend/app/plugins/wiaas/includes/admin/package/views/html-package-types.php b/backend/app/plugins/wiaas/includes/admin/package/views/html-package-types.php index 57d44da..e225ebd 100644 --- a/backend/app/plugins/wiaas/includes/admin/package/views/html-package-types.php +++ b/backend/app/plugins/wiaas/includes/admin/package/views/html-package-types.php @@ -33,6 +33,8 @@ if ( ! defined( 'ABSPATH' ) ) { $(this).show(); $(this).removeClass('hidden'); $(this).removeClass('show_if_downloadable'); + $(this).addClass('show_if_simple'); + $(this).addClass('show_if_bundle'); $(this).find('._download_limit_field, ._download_expiry_field').hide(); }); diff --git a/backend/app/plugins/wiaas/includes/admin/template/class-wiaas-admin-template-selection.php b/backend/app/plugins/wiaas/includes/admin/template/class-wiaas-admin-template-selection.php new file mode 100644 index 0000000..e1012a6 --- /dev/null +++ b/backend/app/plugins/wiaas/includes/admin/template/class-wiaas-admin-template-selection.php @@ -0,0 +1,244 @@ +(optional)', 'cmb'), + 'Wiaas_Admin_Template_Selection::add_custom_content_meta_box', + 'product', + 'normal', + 'high' + ); + } + + + public static function add_custom_content_meta_box($post) { + + $value = get_post_meta($post->ID, '_select_template', true); + + if (empty($value)) { + $value = ''; + } + + $products = wc_get_products(array( + 'type' => 'wiaastemplate' + )); + $product_ids[''] = __('Select a template', 'wiaas'); + foreach ($products as $prod) { + $product_ids[$prod->id] = $prod->name; + } + woocommerce_wp_select(array( + 'id' => '_select_template', + 'options' => $product_ids, + 'value' => $value + )); + + ?> +
$template_products_hardware, + 'service' => $template_products_service, + 'installation' => $template_products_installation, + 'software' => $template_products_software + ); + + } + + public static function render_template_products($template_products) { + if (!empty($template_products)) { + + + foreach ($template_products as $item) { + + $product_id = $item['template_category_id']; + $title = $item['template_category_title']; + $quantity = $item['quantity']; + + include('views/html-wiaas-template-selection.php'); + + } + } + } + + public static function get_product_categories($category_meta) { + $category_objects = array(); + + + if (empty($category_meta)) { + return array(); + } + + foreach ($category_meta as $meta) { + + if (!empty($meta)) { + + + $category_template_id = $meta['template_category_id']; + + $template_category_object = new Wiaas_Template_Category_Object( + $category_template_id, + $meta['template_category_title'], + $meta['quantity']); + + $category_objects[$category_template_id] = $template_category_object; + } + + } + return empty($category_objects) ? null : $category_objects; + } + + public static function get_bundled_product_categories($bundled_items) { + + $template_category_objects = array(); + foreach ($bundled_items as $item_id => $item) { + $item_data = $item->get_data(); + $post_terms = wp_get_object_terms($item->get_product_id(), 'template_category', array('fields' => 'id=>name')); + + if (!empty($post_terms) && !is_wp_error($post_terms)) { + + $cat = ''; + $category_template_id = ''; + + foreach ($post_terms as $id => $term) { + $cat = $term; + $category_template_id = $id; + } + + $template_category_object = new Wiaas_Template_Category_Object( + $category_template_id, + $cat, + $item_data['quantity_max']); + $template_category_objects[$category_template_id] = $template_category_object; + + } + } + + return $template_category_objects; + } + + + function save_custom_content_meta_box($post_id) { + $selected_template = $_POST['_select_template']; + if (!empty($selected_template)) + update_post_meta($post_id, '_select_template', esc_attr($selected_template)); + else { + update_post_meta($post_id, '_select_template', ''); + } + + } + + public static function validate_bundle($product) { + + + if ($product->get_type() == 'bundle') { + $selected_template = $_POST['_select_template']; + $bundled_items = $product->get_bundled_items('view'); + $products_form_template = self::show_template_products($selected_template); + + $missing_categories = array(); + $insufficient_product_quantities = array(); + + + $categories_form_template = self::get_categories_from_templates($products_form_template); + $categories_form_bundle = self::get_bundled_product_categories($bundled_items); + $bundle_category_keys = array_keys($categories_form_bundle); + + + if (!empty($categories_form_template)) { + + foreach ($categories_form_template as $category) { + $template_cat_id = $category->template_category_id; + + + if (!in_array($template_cat_id, $bundle_category_keys)) { + + array_push($missing_categories, $category->name); + + } else { + + $product_from_bundle_quantity = $categories_form_bundle[$template_cat_id]->quantity; + $quantity_from_template = $category->quantity; + + if ((int)($quantity_from_template) !== $product_from_bundle_quantity) { + array_push($insufficient_product_quantities, $category->name); + } + } + } + } + + $categories_message = implode(',', $missing_categories); + $quantity_message = implode(',', $insufficient_product_quantities); + + if (!empty($missing_categories)) { + WC_PB_Meta_Box_Product_Data::add_admin_error(__(' WIAAS This product bundle does not correspond to selected template Categories missing: ' . $categories_message, 'woocommerce-product-bundles')); + } + + if (!empty($insufficient_product_quantities)) { + WC_PB_Meta_Box_Product_Data::add_admin_error(__(' WIAAS This product bundle does not correspond to selected template Categories with different quantities: ' . $quantity_message, 'woocommerce-product-bundles')); + } + } + + } + + public static function get_category_ids_form_bundle($product) { + $products_form_budnle = $product->get_bundled_data_items(); + $product_ids = array(); + + foreach ($products_form_budnle as $product) { + array_push($product_ids, $product->get_id()); + } + + return self::get_product_categories($product_ids); + + } +} + +Wiaas_Admin_Template_Selection::init(); diff --git a/backend/app/plugins/wiaas/includes/admin/template/class-wiaas-template-admin-ajax.php b/backend/app/plugins/wiaas/includes/admin/template/class-wiaas-template-admin-ajax.php new file mode 100644 index 0000000..656f0ef --- /dev/null +++ b/backend/app/plugins/wiaas/includes/admin/template/class-wiaas-template-admin-ajax.php @@ -0,0 +1,93 @@ + '', + 'message' => '' + ); + + $template_products = Wiaas_Admin_Template_Selection::show_template_products($selected_template_id); + + if (!empty($template_products)) { + ob_start(); + Wiaas_Admin_Template_Selection::render_template_products($template_products['hardware']); + Wiaas_Admin_Template_Selection::render_template_products($template_products['service']); + Wiaas_Admin_Template_Selection::render_template_products($template_products['installation']); + Wiaas_Admin_Template_Selection::render_template_products($template_products['software']); + + $response['markup'] = ob_get_clean(); + } + + wp_send_json($response); + } + + + /** + * Handles adding template categories to template via ajax. + */ + public static function ajax_add_wiaas_template_product() { + + check_ajax_referer('wc_bundles_add_bundled_product', 'security'); + + $loop = intval($_POST['id']); + $product_id = intval($_POST['product_id']); + $title = $_POST['title']; + $options = $_POST['options']; + + $response = array( + 'markup' => '', + 'message' => '' + ); + + ob_start(); + include('views/html-wiaas-template-product.php'); + $response['markup'] = ob_get_clean(); + + wp_send_json($response); + } + + /** + * + */ + public static function ajax_wiaas_template_category_search() { + + $term = ($_POST['term']); + $response = array(); + + $terms = get_terms(array( + 'taxonomy' => 'template_category', + 'name__like' => $term + )); + + foreach ($terms as $t) { + $response[$t->term_id] = $t->name; + } + + wp_send_json($response); + } +} + +Wiaas_Template_Admin_Ajax::init(); diff --git a/backend/app/plugins/wiaas/includes/admin/template/class-wiaas-template-products.php b/backend/app/plugins/wiaas/includes/admin/template/class-wiaas-template-products.php new file mode 100644 index 0000000..ddb5e54 --- /dev/null +++ b/backend/app/plugins/wiaas/includes/admin/template/class-wiaas-template-products.php @@ -0,0 +1,226 @@ + + __('Hardware', 'wiaastemplate_hardware'), + 'target' => 'wiaastemplate_options_hardware', + 'class' => array('show_if_wiaastemplate', 'show_if_wiaastemplate'), + ); + + $tabs['wiaastemplate_installation'] = array( + 'label' => __('Installation', 'wiaastemplate_isntallation'), + 'target' => 'wiaastemplate_options_installation', + 'class' => array('show_if_wiaastemplate', 'show_if_wiaastemplate'), + ); + + $tabs['wiaastemplate_services'] = array( + 'label' => __('Services', 'wiaastemplate_services'), + 'target' => 'wiaastemplate_options_services', + 'class' => array('show_if_wiaastemplate', 'show_if_wiaastemplate'), + ); + + $tabs['wiaastemplate_software'] = array( + 'label' => __('Software', 'wiaastemplate_software'), + 'target' => 'wiaastemplate_options_software', + 'class' => array('show_if_wiaastemplate', 'show_if_wiaastemplate'), + ); + + return $tabs; + + } + + public static function wiaastemplate_product_tab_content_all() { + + self::wiaastemplate_product_tab_content('hardware'); + self::wiaastemplate_product_tab_content('installation'); + self::wiaastemplate_product_tab_content('services'); + self::wiaastemplate_product_tab_content('software'); + } + + + /** + * Contents of the template options product tab. + */ + public static function wiaastemplate_product_tab_content($options) { + + global $post; + $template_items = get_post_meta($post->ID, '_template_items_' . $options, true); + + ?> +
' class='panel woocommerce_options_panel'> +
+ + + + +
$product_id, + 'template_category_title' => trim($product_title), + 'quantity' => $quantity + + ); + + $processed_template_data[$product_id] = $item_data; + + } + + update_post_meta($post_id, '_template_items_' . $option, $processed_template_data); + } + + public static function menu_sort_order($a, $b) { + if (isset($a['menu_order']) && isset($b['menu_order'])) { + return $a['menu_order'] - $b['menu_order']; + } else { + return isset($a['menu_order']) ? 1 : -1; + } + } + + + /** + * Hide Attributes data panel. + */ + function hide_attributes_data_panel($tabs) { + + $tabs['advanced']['class'][] = 'hide_if_simple_wiaastemplate hide_if_wiaastemplate'; + $tabs['shipping']['class'][] = 'hide_if_simple_wiaastemplate hide_if_wiaastemplate'; + $tabs['linked_product']['class'][] = 'hide_if_simple_wiaastemplate hide_if_wiaastemplate'; + $tabs['attribute']['class'][] = 'hide_if_simple_wiaastemplate hide_if_wiaastemplate'; + + return $tabs; + + } +} + +Wiaas_template::init(); + diff --git a/backend/app/plugins/wiaas/includes/admin/template/views/html-wiaas-template-product.php b/backend/app/plugins/wiaas/includes/admin/template/views/html-wiaas-template-product.php new file mode 100644 index 0000000..0c0e03d --- /dev/null +++ b/backend/app/plugins/wiaas/includes/admin/template/views/html-wiaas-template-product.php @@ -0,0 +1,36 @@ + +
+

+ + +

+
+ + +
'_product_quantity', + 'label' => __('Quantity', 'woocommerce'), + 'desc_tip' => 'true', + 'description' => __('Choose the quantity of product', 'woocommerce'), + 'type' => 'text', + 'name' => 'template_data_'.$options .'['. $loop.'][quantity]', + 'value' => $quantity + )); + + ?>
diff --git a/backend/app/plugins/wiaas/includes/admin/template/views/html-wiaas-template-selection.php b/backend/app/plugins/wiaas/includes/admin/template/views/html-wiaas-template-selection.php new file mode 100644 index 0000000..4c19b4e --- /dev/null +++ b/backend/app/plugins/wiaas/includes/admin/template/views/html-wiaas-template-selection.php @@ -0,0 +1,13 @@ + +
+

+ + [] +

+
template_category_id = $id; + $this->name = $title; + $this->quantity = $quant; + } + + public function get_quantity(){ + return $this->quantity; + } + +} \ No newline at end of file diff --git a/backend/app/plugins/wiaas/includes/templates/class-wiaas-template-category.php b/backend/app/plugins/wiaas/includes/templates/class-wiaas-template-category.php new file mode 100644 index 0000000..575f5e5 --- /dev/null +++ b/backend/app/plugins/wiaas/includes/templates/class-wiaas-template-category.php @@ -0,0 +1,93 @@ + _x( 'Template category', 'taxonomy general name', 'wiaas' ), + 'singular_name' => _x( 'Template category', 'taxonomy singular name', 'wiaas' ), + 'search_items' => __( 'Search Template categories', 'wiaas' ), + 'all_items' => __( 'All Template categories', 'wiaas' ), + 'parent_item' => __( 'Parent Template category', 'wiaas' ), + 'parent_item_colon' => __( 'Parent Template category:', 'wiaas' ), + 'edit_item' => __( 'Edit Template category', 'wiaas' ), + 'update_item' => __( 'Update Template category', 'wiaas' ), + 'add_new_item' => __( 'Add New Template category', 'wiaas' ), + 'new_item_name' => __( 'New Template category Name', 'wiaas' ), + 'menu_name' => __( 'Template category', 'wiaas' ), + ); + + $args = array( + 'hierarchical' => false, + 'labels' => $labels, + 'show_ui' => true, + 'show_admin_column' => true, + 'query_var' => true, + 'rewrite' => array( 'slug' => 'template_category' ), + ); + + register_taxonomy( 'template_category', array( 'product' ), $args ); + } + + /** + * Retrieve available wiaas Template categories + * @return array + */ + public static function get_available_template_categories() { + $types = get_terms( array( + 'taxonomy' => 'template_category', + 'hide_empty' => false, + ) ); + + return array_map(function($type) { + return $type->name; + }, $types); + } + + /** + * Retrieve Template category for provided package id + * @param $product_id + * + * @return null + */ + public static function get_template_category($product_id) { + $terms = wp_get_object_terms($product_id, 'template_category'); + $template_category = isset($terms[0]) ? $terms[0]->name : null; + return $template_category; + } + + /** + * Set Template category for provided package id + * @param $product_id + * @param $type + */ + public static function set_template_category($product_id, $type) { + + wp_delete_object_term_relationships( $product_id, 'template_category' ); + + if (isset($type)) { + wp_set_object_terms($product_id, $type, 'template_category', false); + } + } +} + +Wiaas_Template_Category::init(); \ No newline at end of file diff --git a/backend/app/plugins/wiaas/includes/templates/class-wiaas-wc-product-template.php b/backend/app/plugins/wiaas/includes/templates/class-wiaas-wc-product-template.php new file mode 100644 index 0000000..5080c6d --- /dev/null +++ b/backend/app/plugins/wiaas/includes/templates/class-wiaas-wc-product-template.php @@ -0,0 +1,46 @@ +